xref: /webtrees/app/Module/StoriesModule.php (revision 8f53f488f13e53e44dc48778e8f51ec9f91352dd)
18c2e8227SGreg Roach<?php
28c2e8227SGreg Roach/**
38c2e8227SGreg Roach * webtrees: online genealogy
41062a142SGreg Roach * Copyright (C) 2018 webtrees development team
58c2e8227SGreg Roach * This program is free software: you can redistribute it and/or modify
68c2e8227SGreg Roach * it under the terms of the GNU General Public License as published by
78c2e8227SGreg Roach * the Free Software Foundation, either version 3 of the License, or
88c2e8227SGreg Roach * (at your option) any later version.
98c2e8227SGreg Roach * This program is distributed in the hope that it will be useful,
108c2e8227SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
118c2e8227SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
128c2e8227SGreg Roach * GNU General Public License for more details.
138c2e8227SGreg Roach * You should have received a copy of the GNU General Public License
148c2e8227SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>.
158c2e8227SGreg Roach */
1676692c8bSGreg Roachnamespace Fisharebest\Webtrees\Module;
1776692c8bSGreg Roach
180e62c4b8SGreg Roachuse Fisharebest\Webtrees\Auth;
190e62c4b8SGreg Roachuse Fisharebest\Webtrees\Database;
200e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N;
210e62c4b8SGreg Roachuse Fisharebest\Webtrees\Individual;
220e62c4b8SGreg Roachuse Fisharebest\Webtrees\Menu;
230e62c4b8SGreg Roachuse Fisharebest\Webtrees\Tree;
24225e381fSGreg Roachuse stdClass;
2572ac996dSGreg Roachuse Symfony\Component\HttpFoundation\RedirectResponse;
2672ac996dSGreg Roachuse Symfony\Component\HttpFoundation\Request;
2772ac996dSGreg Roachuse Symfony\Component\HttpFoundation\Response;
288c2e8227SGreg Roach
298c2e8227SGreg Roach/**
308c2e8227SGreg Roach * Class StoriesModule
318c2e8227SGreg Roach */
32c1010edaSGreg Roachclass StoriesModule extends AbstractModule implements ModuleTabInterface, ModuleConfigInterface, ModuleMenuInterface
33c1010edaSGreg Roach{
348c2e8227SGreg Roach    /** {@inheritdoc} */
35*8f53f488SRico Sonntag    public function getTitle(): string
36c1010edaSGreg Roach    {
37bbb76c12SGreg Roach        /* I18N: Name of a module */
38bbb76c12SGreg Roach        return I18N::translate('Stories');
398c2e8227SGreg Roach    }
408c2e8227SGreg Roach
418c2e8227SGreg Roach    /** {@inheritdoc} */
42*8f53f488SRico Sonntag    public function getDescription(): string
43c1010edaSGreg Roach    {
44bbb76c12SGreg Roach        /* I18N: Description of the “Stories” module */
45bbb76c12SGreg Roach        return I18N::translate('Add narrative stories to individuals in the family tree.');
468c2e8227SGreg Roach    }
478c2e8227SGreg Roach
48aee13b6dSGreg Roach    /**
49aee13b6dSGreg Roach     * The URL to a page where the user can modify the configuration of this module.
50aee13b6dSGreg Roach     *
51aee13b6dSGreg Roach     * @return string
52aee13b6dSGreg Roach     */
53*8f53f488SRico Sonntag    public function getConfigLink(): string
54c1010edaSGreg Roach    {
55c1010edaSGreg Roach        return route('module', [
56c1010edaSGreg Roach            'module' => $this->getName(),
57c1010edaSGreg Roach            'action' => 'Admin',
58c1010edaSGreg Roach        ]);
598c2e8227SGreg Roach    }
608c2e8227SGreg Roach
618c2e8227SGreg Roach    /** {@inheritdoc} */
62c1010edaSGreg Roach    public function defaultTabOrder()
63c1010edaSGreg Roach    {
648c2e8227SGreg Roach        return 55;
658c2e8227SGreg Roach    }
668c2e8227SGreg Roach
678c2e8227SGreg Roach    /** {@inheritdoc} */
68c1010edaSGreg Roach    public function getTabContent(Individual $individual)
69c1010edaSGreg Roach    {
7072ac996dSGreg Roach        return view('modules/stories/tab', [
7172ac996dSGreg Roach            'is_admin'   => Auth::isAdmin(),
72225e381fSGreg Roach            'individual' => $individual,
73225e381fSGreg Roach            'stories'    => $this->getStoriesForIndividual($individual),
74225e381fSGreg Roach        ]);
758c2e8227SGreg Roach    }
768c2e8227SGreg Roach
778c2e8227SGreg Roach    /** {@inheritdoc} */
78c1010edaSGreg Roach    public function hasTabContent(Individual $individual)
79c1010edaSGreg Roach    {
80225e381fSGreg Roach        return Auth::isManager($individual->getTree()) || !empty($this->getStoriesForIndividual($individual));
818c2e8227SGreg Roach    }
828c2e8227SGreg Roach
838c2e8227SGreg Roach    /** {@inheritdoc} */
84c1010edaSGreg Roach    public function isGrayedOut(Individual $individual)
85c1010edaSGreg Roach    {
86225e381fSGreg Roach        return !empty($this->getStoriesForIndividual($individual));
878c2e8227SGreg Roach    }
888c2e8227SGreg Roach
898c2e8227SGreg Roach    /** {@inheritdoc} */
90c1010edaSGreg Roach    public function canLoadAjax()
91c1010edaSGreg Roach    {
928c2e8227SGreg Roach        return false;
938c2e8227SGreg Roach    }
948c2e8227SGreg Roach
95225e381fSGreg Roach    /**
96225e381fSGreg Roach     * @param Individual $individual
97225e381fSGreg Roach     *
98225e381fSGreg Roach     * @return stdClass[]
99225e381fSGreg Roach     */
100c1010edaSGreg Roach    private function getStoriesForIndividual(Individual $individual): array
101c1010edaSGreg Roach    {
102225e381fSGreg Roach        $block_ids =
103225e381fSGreg Roach            Database::prepare(
104e5588fb0SGreg Roach                "SELECT block_id" .
105225e381fSGreg Roach                " FROM `##block`" .
106225e381fSGreg Roach                " WHERE module_name = :module_name" .
107225e381fSGreg Roach                " AND xref          = :xref" .
108225e381fSGreg Roach                " AND gedcom_id     = :tree_id"
109225e381fSGreg Roach            )->execute([
110225e381fSGreg Roach                'module_name' => $this->getName(),
111225e381fSGreg Roach                'xref'        => $individual->getXref(),
112225e381fSGreg Roach                'tree_id'     => $individual->getTree()->getTreeId(),
113225e381fSGreg Roach            ])->fetchOneColumn();
114225e381fSGreg Roach
115225e381fSGreg Roach        $stories = [];
116225e381fSGreg Roach        foreach ($block_ids as $block_id) {
117225e381fSGreg Roach            // Only show this block for certain languages
118225e381fSGreg Roach            $languages = $this->getBlockSetting($block_id, 'languages', '');
119225e381fSGreg Roach            if ($languages === '' || in_array(WT_LOCALE, explode(',', $languages))) {
120225e381fSGreg Roach                $stories[] = (object)[
121225e381fSGreg Roach                    'block_id'   => $block_id,
122225e381fSGreg Roach                    'title'      => $this->getBlockSetting($block_id, 'title'),
12372ac996dSGreg Roach                    'story_body' => $this->getBlockSetting($block_id, 'story_body'),
124225e381fSGreg Roach                ];
125225e381fSGreg Roach            }
126225e381fSGreg Roach        }
127225e381fSGreg Roach
128225e381fSGreg Roach        return $stories;
1298c2e8227SGreg Roach    }
1308c2e8227SGreg Roach
1318c2e8227SGreg Roach    /**
1320ee13198SGreg Roach     * The user can re-order menus. Until they do, they are shown in this order.
1330ee13198SGreg Roach     *
1340ee13198SGreg Roach     * @return int
1350ee13198SGreg Roach     */
136*8f53f488SRico Sonntag    public function defaultMenuOrder(): int
137c1010edaSGreg Roach    {
1388c2e8227SGreg Roach        return 30;
1398c2e8227SGreg Roach    }
1408c2e8227SGreg Roach
1410ee13198SGreg Roach    /**
1420ee13198SGreg Roach     * What is the default access level for this module?
1430ee13198SGreg Roach     *
1440ee13198SGreg Roach     * Some modules are aimed at admins or managers, and are not generally shown to users.
1450ee13198SGreg Roach     *
1460ee13198SGreg Roach     * @return int
1470ee13198SGreg Roach     */
148*8f53f488SRico Sonntag    public function defaultAccessLevel(): int
149c1010edaSGreg Roach    {
1504b9ff166SGreg Roach        return Auth::PRIV_HIDE;
1518c2e8227SGreg Roach    }
1528c2e8227SGreg Roach
1530ee13198SGreg Roach    /**
1540ee13198SGreg Roach     * A menu, to be added to the main application menu.
1550ee13198SGreg Roach     *
156aee13b6dSGreg Roach     * @param Tree $tree
157aee13b6dSGreg Roach     *
1580ee13198SGreg Roach     * @return Menu|null
1590ee13198SGreg Roach     */
160c1010edaSGreg Roach    public function getMenu(Tree $tree)
161c1010edaSGreg Roach    {
162c1010edaSGreg Roach        $menu = new Menu($this->getTitle(), route('module', [
163c1010edaSGreg Roach            'module' => $this->getName(),
164c1010edaSGreg Roach            'action' => 'ShowList',
1658765c3bdSGreg Roach            'ged'    => $tree->getName(),
166c1010edaSGreg Roach        ]), 'menu-story');
1678c2e8227SGreg Roach
1688c2e8227SGreg Roach        return $menu;
1698c2e8227SGreg Roach    }
17072ac996dSGreg Roach
17172ac996dSGreg Roach    /**
172b6db7c1fSGreg Roach     * @param Tree $tree
17372ac996dSGreg Roach     *
17472ac996dSGreg Roach     * @return Response
17572ac996dSGreg Roach     */
176b6db7c1fSGreg Roach    public function getAdminAction(Tree $tree): Response
177c1010edaSGreg Roach    {
17872ac996dSGreg Roach        $this->layout = 'layouts/administration';
17972ac996dSGreg Roach
18072ac996dSGreg Roach        $stories = Database::prepare(
18172ac996dSGreg Roach            "SELECT block_id, xref, gedcom_id" .
18272ac996dSGreg Roach            " FROM `##block` b" .
18372ac996dSGreg Roach            " WHERE module_name = :module_name" .
18472ac996dSGreg Roach            " AND gedcom_id = :tree_id" .
18572ac996dSGreg Roach            " ORDER BY gedcom_id, xref"
18672ac996dSGreg Roach        )->execute([
18772ac996dSGreg Roach            'tree_id'     => $tree->getTreeId(),
18872ac996dSGreg Roach            'module_name' => $this->getName(),
18972ac996dSGreg Roach        ])->fetchAll();
19072ac996dSGreg Roach
19172ac996dSGreg Roach        foreach ($stories as $story) {
19272ac996dSGreg Roach            $story->individual = Individual::getInstance($story->xref, $tree);
19372ac996dSGreg Roach            $story->title      = $this->getBlockSetting($story->block_id, 'title');
19472ac996dSGreg Roach            $story->languages  = $this->getBlockSetting($story->block_id, 'languages');
19572ac996dSGreg Roach        }
19672ac996dSGreg Roach
19772ac996dSGreg Roach        return $this->viewResponse('modules/stories/config', [
19872ac996dSGreg Roach            'stories'    => $stories,
19972ac996dSGreg Roach            'title'      => $this->getTitle() . ' — ' . $tree->getTitle(),
20072ac996dSGreg Roach            'tree'       => $tree,
20172ac996dSGreg Roach            'tree_names' => Tree::getNameList(),
20272ac996dSGreg Roach        ]);
20372ac996dSGreg Roach    }
20472ac996dSGreg Roach
20572ac996dSGreg Roach    /**
20672ac996dSGreg Roach     * @param Request $request
207b6db7c1fSGreg Roach     * @param Tree    $tree
20872ac996dSGreg Roach     *
20972ac996dSGreg Roach     * @return Response
21072ac996dSGreg Roach     */
211b6db7c1fSGreg Roach    public function getAdminEditAction(Request $request, Tree $tree): Response
212c1010edaSGreg Roach    {
21372ac996dSGreg Roach        $this->layout = 'layouts/administration';
21472ac996dSGreg Roach
21572ac996dSGreg Roach        $block_id = (int)$request->get('block_id');
21672ac996dSGreg Roach
21772ac996dSGreg Roach        if ($block_id === 0) {
21872ac996dSGreg Roach            // Creating a new story
21972ac996dSGreg Roach            $individual  = Individual::getInstance($request->get('xref', ''), $tree);
22072ac996dSGreg Roach            $story_title = '';
22172ac996dSGreg Roach            $story_body  = '';
22272ac996dSGreg Roach            $languages   = [];
22372ac996dSGreg Roach
22472ac996dSGreg Roach            $title = I18N::translate('Add a story') . ' — ' . e($tree->getTitle());
22572ac996dSGreg Roach        } else {
22672ac996dSGreg Roach            // Editing an existing story
22772ac996dSGreg Roach            $xref = Database::prepare(
22872ac996dSGreg Roach                "SELECT xref FROM `##block` WHERE block_id = :block_id"
22972ac996dSGreg Roach            )->execute([
23072ac996dSGreg Roach                'block_id' => $block_id,
23172ac996dSGreg Roach            ])->fetchOne();
23272ac996dSGreg Roach
23372ac996dSGreg Roach            $individual  = Individual::getInstance($xref, $tree);
23472ac996dSGreg Roach            $story_title = $this->getBlockSetting($block_id, 'title', '');
23572ac996dSGreg Roach            $story_body  = $this->getBlockSetting($block_id, 'story_body', '');
23672ac996dSGreg Roach            $languages   = explode(',', $this->getBlockSetting($block_id, 'languages'));
23772ac996dSGreg Roach
23872ac996dSGreg Roach            $title = I18N::translate('Edit the story') . ' — ' . e($tree->getTitle());
23972ac996dSGreg Roach        }
24072ac996dSGreg Roach
24172ac996dSGreg Roach        return $this->viewResponse('modules/stories/edit', [
24272ac996dSGreg Roach            'block_id'    => $block_id,
24372ac996dSGreg Roach            'languages'   => $languages,
24472ac996dSGreg Roach            'story_body'  => $story_body,
24572ac996dSGreg Roach            'story_title' => $story_title,
24672ac996dSGreg Roach            'title'       => $title,
24772ac996dSGreg Roach            'tree'        => $tree,
24872ac996dSGreg Roach            'individual'  => $individual,
24972ac996dSGreg Roach        ]);
25072ac996dSGreg Roach    }
25172ac996dSGreg Roach
25272ac996dSGreg Roach    /**
25372ac996dSGreg Roach     * @param Request $request
254b6db7c1fSGreg Roach     * @param Tree    $tree
25572ac996dSGreg Roach     *
25672ac996dSGreg Roach     * @return RedirectResponse
25772ac996dSGreg Roach     */
258b6db7c1fSGreg Roach    public function postAdminEditAction(Request $request, Tree $tree): RedirectResponse
259c1010edaSGreg Roach    {
26072ac996dSGreg Roach        $block_id    = (int)$request->get('block_id');
26172ac996dSGreg Roach        $xref        = $request->get('xref', '');
26272ac996dSGreg Roach        $story_body  = $request->get('story_body', '');
26372ac996dSGreg Roach        $story_title = $request->get('story_title', '');
26472ac996dSGreg Roach        $languages   = $request->get('languages', []);
26572ac996dSGreg Roach
26672ac996dSGreg Roach        if ($block_id !== 0) {
26772ac996dSGreg Roach            Database::prepare(
26872ac996dSGreg Roach                "UPDATE `##block` SET gedcom_id = :tree_id, xref = :xref WHERE block_id = :block_id"
26972ac996dSGreg Roach            )->execute([
27072ac996dSGreg Roach                'tree_id'  => $tree->getTreeId(),
27172ac996dSGreg Roach                'xref'     => $xref,
27272ac996dSGreg Roach                'block_id' => $block_id,
27372ac996dSGreg Roach            ]);
27472ac996dSGreg Roach        } else {
27572ac996dSGreg Roach            Database::prepare(
27672ac996dSGreg Roach                "INSERT INTO `##block` (gedcom_id, xref, module_name, block_order) VALUES (:tree_id, :xref, 'stories', 0)"
27772ac996dSGreg Roach            )->execute([
27872ac996dSGreg Roach                'tree_id' => $tree->getTreeId(),
27972ac996dSGreg Roach                'xref'    => $xref,
28072ac996dSGreg Roach            ]);
28172ac996dSGreg Roach
28272ac996dSGreg Roach            $block_id = Database::getInstance()->lastInsertId();
28372ac996dSGreg Roach        }
28472ac996dSGreg Roach
28572ac996dSGreg Roach        $this->setBlockSetting($block_id, 'story_body', $story_body);
28672ac996dSGreg Roach        $this->setBlockSetting($block_id, 'title', $story_title);
28772ac996dSGreg Roach        $this->setBlockSetting($block_id, 'languages', implode(',', $languages));
28872ac996dSGreg Roach
289c1010edaSGreg Roach        $url = route('module', [
290c1010edaSGreg Roach            'module' => 'stories',
291c1010edaSGreg Roach            'action' => 'Admin',
292c1010edaSGreg Roach            'ged'    => $tree->getName(),
293c1010edaSGreg Roach        ]);
29472ac996dSGreg Roach
29572ac996dSGreg Roach        return new RedirectResponse($url);
29672ac996dSGreg Roach    }
29772ac996dSGreg Roach
29872ac996dSGreg Roach    /**
29972ac996dSGreg Roach     * @param Request $request
300b6db7c1fSGreg Roach     * @param Tree    $tree
30172ac996dSGreg Roach     *
30272ac996dSGreg Roach     * @return Response
30372ac996dSGreg Roach     */
304b6db7c1fSGreg Roach    public function postAdminDeleteAction(Request $request, Tree $tree): Response
305c1010edaSGreg Roach    {
30672ac996dSGreg Roach        $block_id = (int)$request->get('block_id');
30772ac996dSGreg Roach
30872ac996dSGreg Roach        Database::prepare(
30972ac996dSGreg Roach            "DELETE FROM `##block_setting` WHERE block_id = :block_id"
31072ac996dSGreg Roach        )->execute([
31172ac996dSGreg Roach            'block_id' => $block_id,
31272ac996dSGreg Roach        ]);
31372ac996dSGreg Roach
31472ac996dSGreg Roach        Database::prepare(
31572ac996dSGreg Roach            "DELETE FROM `##block` WHERE block_id = :block_id"
31672ac996dSGreg Roach        )->execute([
31772ac996dSGreg Roach            'block_id' => $block_id,
31872ac996dSGreg Roach        ]);
31972ac996dSGreg Roach
320c1010edaSGreg Roach        $url = route('module', [
321c1010edaSGreg Roach            'module' => 'stories',
322c1010edaSGreg Roach            'action' => 'Admin',
323c1010edaSGreg Roach            'ged'    => $tree->getName(),
324c1010edaSGreg Roach        ]);
32572ac996dSGreg Roach
32672ac996dSGreg Roach        return new RedirectResponse($url);
32772ac996dSGreg Roach    }
32872ac996dSGreg Roach
32972ac996dSGreg Roach    /**
330b6db7c1fSGreg Roach     * @param Tree $tree
33172ac996dSGreg Roach     *
33272ac996dSGreg Roach     * @return Response
33372ac996dSGreg Roach     */
334b6db7c1fSGreg Roach    public function getShowListAction(Tree $tree): Response
335c1010edaSGreg Roach    {
33672ac996dSGreg Roach        $stories = Database::prepare(
33772ac996dSGreg Roach            "SELECT block_id, xref" .
33872ac996dSGreg Roach            " FROM `##block` b" .
33972ac996dSGreg Roach            " WHERE module_name = :module_name" .
34072ac996dSGreg Roach            " AND gedcom_id = :tree_id" .
34172ac996dSGreg Roach            " ORDER BY xref"
34272ac996dSGreg Roach        )->execute([
34372ac996dSGreg Roach            'module_name' => $this->getName(),
34472ac996dSGreg Roach            'tree_id'     => $tree->getTreeId(),
34572ac996dSGreg Roach        ])->fetchAll();
34672ac996dSGreg Roach
34772ac996dSGreg Roach        foreach ($stories as $story) {
34872ac996dSGreg Roach            $story->individual = Individual::getInstance($story->xref, $tree);
34972ac996dSGreg Roach            $story->title      = $this->getBlockSetting($story->block_id, 'title');
35072ac996dSGreg Roach            $story->languages  = $this->getBlockSetting($story->block_id, 'languages');
35172ac996dSGreg Roach        }
35272ac996dSGreg Roach
35372ac996dSGreg Roach        // Filter non-existant and private individuals.
354492c7072SGreg Roach        $stories = array_filter($stories, function (stdClass $story): bool {
35572ac996dSGreg Roach            return $story->individual !== null && $story->individual->canShow();
35672ac996dSGreg Roach        });
35772ac996dSGreg Roach
35872ac996dSGreg Roach        // Filter foreign languages.
359492c7072SGreg Roach        $stories = array_filter($stories, function (stdClass $story): bool {
360a44b57a9SGreg Roach            return $story->languages === '' || in_array(WT_LOCALE, explode(',', $story->languages));
36172ac996dSGreg Roach        });
36272ac996dSGreg Roach
36372ac996dSGreg Roach        return $this->viewResponse('modules/stories/list', [
36472ac996dSGreg Roach            'stories' => $stories,
36572ac996dSGreg Roach            'title'   => $this->getTitle(),
36672ac996dSGreg Roach        ]);
36772ac996dSGreg Roach    }
3688c2e8227SGreg Roach}
369