xref: /webtrees/app/Module/StoriesModule.php (revision e5588fb099ce26dcdcb7faeb13861818cd9a4306)
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 */
32e2a378d3SGreg Roachclass StoriesModule extends AbstractModule implements ModuleTabInterface, ModuleConfigInterface, ModuleMenuInterface {
338c2e8227SGreg Roach	/** {@inheritdoc} */
348c2e8227SGreg Roach	public function getTitle() {
3572ac996dSGreg Roach		return /* I18N: Name of a module */
3672ac996dSGreg Roach			I18N::translate('Stories');
378c2e8227SGreg Roach	}
388c2e8227SGreg Roach
398c2e8227SGreg Roach	/** {@inheritdoc} */
408c2e8227SGreg Roach	public function getDescription() {
4172ac996dSGreg Roach		return /* I18N: Description of the “Stories” module */
4272ac996dSGreg Roach			I18N::translate('Add narrative stories to individuals in the family tree.');
438c2e8227SGreg Roach	}
448c2e8227SGreg Roach
45aee13b6dSGreg Roach	/**
46aee13b6dSGreg Roach	 * The URL to a page where the user can modify the configuration of this module.
47aee13b6dSGreg Roach	 *
48aee13b6dSGreg Roach	 * @return string
49aee13b6dSGreg Roach	 */
508c2e8227SGreg Roach	public function getConfigLink() {
5172ac996dSGreg Roach		return route('module', ['module' => $this->getName(), 'action' => 'Admin']);
528c2e8227SGreg Roach	}
538c2e8227SGreg Roach
548c2e8227SGreg Roach	/** {@inheritdoc} */
558c2e8227SGreg Roach	public function defaultTabOrder() {
568c2e8227SGreg Roach		return 55;
578c2e8227SGreg Roach	}
588c2e8227SGreg Roach
598c2e8227SGreg Roach	/** {@inheritdoc} */
60225e381fSGreg Roach	public function getTabContent(Individual $individual) {
6172ac996dSGreg Roach		return view('modules/stories/tab', [
6272ac996dSGreg Roach			'is_admin'   => Auth::isAdmin(),
63225e381fSGreg Roach			'individual' => $individual,
64225e381fSGreg Roach			'stories'    => $this->getStoriesForIndividual($individual),
65225e381fSGreg Roach		]);
668c2e8227SGreg Roach	}
678c2e8227SGreg Roach
688c2e8227SGreg Roach	/** {@inheritdoc} */
69225e381fSGreg Roach	public function hasTabContent(Individual $individual) {
70225e381fSGreg Roach		return Auth::isManager($individual->getTree()) || !empty($this->getStoriesForIndividual($individual));
718c2e8227SGreg Roach	}
728c2e8227SGreg Roach
738c2e8227SGreg Roach	/** {@inheritdoc} */
74225e381fSGreg Roach	public function isGrayedOut(Individual $individual) {
75225e381fSGreg Roach		return !empty($this->getStoriesForIndividual($individual));
768c2e8227SGreg Roach	}
778c2e8227SGreg Roach
788c2e8227SGreg Roach	/** {@inheritdoc} */
798c2e8227SGreg Roach	public function canLoadAjax() {
808c2e8227SGreg Roach		return false;
818c2e8227SGreg Roach	}
828c2e8227SGreg Roach
83225e381fSGreg Roach	/**
84225e381fSGreg Roach	 * @param Individual $individual
85225e381fSGreg Roach	 *
86225e381fSGreg Roach	 * @return stdClass[]
87225e381fSGreg Roach	 */
88225e381fSGreg Roach	private function getStoriesForIndividual(Individual $individual): array {
89225e381fSGreg Roach		$block_ids =
90225e381fSGreg Roach			Database::prepare(
91*e5588fb0SGreg Roach				"SELECT block_id" .
92225e381fSGreg Roach				" FROM `##block`" .
93225e381fSGreg Roach				" WHERE module_name = :module_name" .
94225e381fSGreg Roach				" AND xref          = :xref" .
95225e381fSGreg Roach				" AND gedcom_id     = :tree_id"
96225e381fSGreg Roach			)->execute([
97225e381fSGreg Roach				'module_name' => $this->getName(),
98225e381fSGreg Roach				'xref'        => $individual->getXref(),
99225e381fSGreg Roach				'tree_id'     => $individual->getTree()->getTreeId(),
100225e381fSGreg Roach			])->fetchOneColumn();
101225e381fSGreg Roach
102225e381fSGreg Roach		$stories = [];
103225e381fSGreg Roach		foreach ($block_ids as $block_id) {
104225e381fSGreg Roach			// Only show this block for certain languages
105225e381fSGreg Roach			$languages = $this->getBlockSetting($block_id, 'languages', '');
106225e381fSGreg Roach			if ($languages === '' || in_array(WT_LOCALE, explode(',', $languages))) {
107225e381fSGreg Roach				$stories[] = (object) [
108225e381fSGreg Roach					'block_id'   => $block_id,
109225e381fSGreg Roach					'title'      => $this->getBlockSetting($block_id, 'title'),
11072ac996dSGreg Roach					'story_body' => $this->getBlockSetting($block_id, 'story_body'),
111225e381fSGreg Roach				];
112225e381fSGreg Roach			}
113225e381fSGreg Roach		}
114225e381fSGreg Roach
115225e381fSGreg Roach		return $stories;
1168c2e8227SGreg Roach	}
1178c2e8227SGreg Roach
1188c2e8227SGreg Roach	/**
1190ee13198SGreg Roach	 * The user can re-order menus. Until they do, they are shown in this order.
1200ee13198SGreg Roach	 *
1210ee13198SGreg Roach	 * @return int
1220ee13198SGreg Roach	 */
1238c2e8227SGreg Roach	public function defaultMenuOrder() {
1248c2e8227SGreg Roach		return 30;
1258c2e8227SGreg Roach	}
1268c2e8227SGreg Roach
1270ee13198SGreg Roach	/**
1280ee13198SGreg Roach	 * What is the default access level for this module?
1290ee13198SGreg Roach	 *
1300ee13198SGreg Roach	 * Some modules are aimed at admins or managers, and are not generally shown to users.
1310ee13198SGreg Roach	 *
1320ee13198SGreg Roach	 * @return int
1330ee13198SGreg Roach	 */
1348c2e8227SGreg Roach	public function defaultAccessLevel() {
1354b9ff166SGreg Roach		return Auth::PRIV_HIDE;
1368c2e8227SGreg Roach	}
1378c2e8227SGreg Roach
1380ee13198SGreg Roach	/**
1390ee13198SGreg Roach	 * A menu, to be added to the main application menu.
1400ee13198SGreg Roach	 *
141aee13b6dSGreg Roach	 * @param Tree $tree
142aee13b6dSGreg Roach	 *
1430ee13198SGreg Roach	 * @return Menu|null
1440ee13198SGreg Roach	 */
145aee13b6dSGreg Roach	public function getMenu(Tree $tree) {
14672ac996dSGreg Roach		$menu = new Menu($this->getTitle(), e(route('module', ['module' => $this->getName(), 'action' => 'ShowList'])), 'menu-story');
1478c2e8227SGreg Roach
1488c2e8227SGreg Roach		return $menu;
1498c2e8227SGreg Roach	}
15072ac996dSGreg Roach
15172ac996dSGreg Roach	/**
15272ac996dSGreg Roach	 * @param Request $request
15372ac996dSGreg Roach	 *
15472ac996dSGreg Roach	 * @return Response
15572ac996dSGreg Roach	 */
15672ac996dSGreg Roach	public function getAdminAction(Request $request): Response {
15772ac996dSGreg Roach		/** @var Tree $tree */
15872ac996dSGreg Roach		$tree = $request->attributes->get('tree');
15972ac996dSGreg Roach
16072ac996dSGreg Roach		$this->layout = 'layouts/administration';
16172ac996dSGreg Roach
16272ac996dSGreg Roach		$stories = Database::prepare(
16372ac996dSGreg Roach			"SELECT block_id, xref, gedcom_id" .
16472ac996dSGreg Roach			" FROM `##block` b" .
16572ac996dSGreg Roach			" WHERE module_name = :module_name" .
16672ac996dSGreg Roach			" AND gedcom_id = :tree_id" .
16772ac996dSGreg Roach			" ORDER BY gedcom_id, xref"
16872ac996dSGreg Roach		)->execute([
16972ac996dSGreg Roach			'tree_id'     => $tree->getTreeId(),
17072ac996dSGreg Roach			'module_name' => $this->getName(),
17172ac996dSGreg Roach		])->fetchAll();
17272ac996dSGreg Roach
17372ac996dSGreg Roach		foreach ($stories as $story) {
17472ac996dSGreg Roach			$story->individual = Individual::getInstance($story->xref, $tree);
17572ac996dSGreg Roach			$story->title      = $this->getBlockSetting($story->block_id, 'title');
17672ac996dSGreg Roach			$story->languages  = $this->getBlockSetting($story->block_id, 'languages');
17772ac996dSGreg Roach		}
17872ac996dSGreg Roach
17972ac996dSGreg Roach		return $this->viewResponse('modules/stories/config', [
18072ac996dSGreg Roach			'stories'    => $stories,
18172ac996dSGreg Roach			'title'      => $this->getTitle() . ' — ' . $tree->getTitle(),
18272ac996dSGreg Roach			'tree'       => $tree,
18372ac996dSGreg Roach			'tree_names' => Tree::getNameList(),
18472ac996dSGreg Roach		]);
18572ac996dSGreg Roach	}
18672ac996dSGreg Roach
18772ac996dSGreg Roach	/**
18872ac996dSGreg Roach	 * @param Request $request
18972ac996dSGreg Roach	 *
19072ac996dSGreg Roach	 * @return Response
19172ac996dSGreg Roach	 */
19272ac996dSGreg Roach	public function getAdminEditAction(Request $request): Response {
19372ac996dSGreg Roach		/** @var Tree $tree */
19472ac996dSGreg Roach		$tree = $request->attributes->get('tree');
19572ac996dSGreg Roach
19672ac996dSGreg Roach		$this->layout = 'layouts/administration';
19772ac996dSGreg Roach
19872ac996dSGreg Roach		$block_id = (int) $request->get('block_id');
19972ac996dSGreg Roach
20072ac996dSGreg Roach		if ($block_id === 0) {
20172ac996dSGreg Roach			// Creating a new story
20272ac996dSGreg Roach			$individual  = Individual::getInstance($request->get('xref', ''), $tree);
20372ac996dSGreg Roach			$story_title = '';
20472ac996dSGreg Roach			$story_body  = '';
20572ac996dSGreg Roach			$languages   = [];
20672ac996dSGreg Roach
20772ac996dSGreg Roach			$title = I18N::translate('Add a story') . ' — ' . e($tree->getTitle());
20872ac996dSGreg Roach		} else {
20972ac996dSGreg Roach			// Editing an existing story
21072ac996dSGreg Roach			$xref = Database::prepare(
21172ac996dSGreg Roach				"SELECT xref FROM `##block` WHERE block_id = :block_id"
21272ac996dSGreg Roach			)->execute([
21372ac996dSGreg Roach				'block_id' => $block_id,
21472ac996dSGreg Roach			])->fetchOne();
21572ac996dSGreg Roach
21672ac996dSGreg Roach			$individual  = Individual::getInstance($xref, $tree);
21772ac996dSGreg Roach			$story_title = $this->getBlockSetting($block_id, 'title', '');
21872ac996dSGreg Roach			$story_body  = $this->getBlockSetting($block_id, 'story_body', '');
21972ac996dSGreg Roach			$languages   = explode(',', $this->getBlockSetting($block_id, 'languages'));
22072ac996dSGreg Roach
22172ac996dSGreg Roach			$title = I18N::translate('Edit the story') . ' — ' . e($tree->getTitle());
22272ac996dSGreg Roach		}
22372ac996dSGreg Roach
22472ac996dSGreg Roach		return $this->viewResponse('modules/stories/edit', [
22572ac996dSGreg Roach			'block_id'    => $block_id,
22672ac996dSGreg Roach			'languages'   => $languages,
22772ac996dSGreg Roach			'story_body'  => $story_body,
22872ac996dSGreg Roach			'story_title' => $story_title,
22972ac996dSGreg Roach			'title'       => $title,
23072ac996dSGreg Roach			'tree'        => $tree,
23172ac996dSGreg Roach			'individual'  => $individual,
23272ac996dSGreg Roach		]);
23372ac996dSGreg Roach	}
23472ac996dSGreg Roach
23572ac996dSGreg Roach	/**
23672ac996dSGreg Roach	 * @param Request $request
23772ac996dSGreg Roach	 *
23872ac996dSGreg Roach	 * @return RedirectResponse
23972ac996dSGreg Roach	 */
24072ac996dSGreg Roach	public function postAdminEditAction(Request $request): RedirectResponse {
24172ac996dSGreg Roach		/** @var Tree $tree */
24272ac996dSGreg Roach		$tree = $request->attributes->get('tree');
24372ac996dSGreg Roach
24472ac996dSGreg Roach		$block_id    = (int) $request->get('block_id');
24572ac996dSGreg Roach		$xref        = $request->get('xref', '');
24672ac996dSGreg Roach		$story_body  = $request->get('story_body', '');
24772ac996dSGreg Roach		$story_title = $request->get('story_title', '');
24872ac996dSGreg Roach		$languages   = $request->get('languages', []);
24972ac996dSGreg Roach
25072ac996dSGreg Roach		if ($block_id !== 0) {
25172ac996dSGreg Roach			Database::prepare(
25272ac996dSGreg Roach				"UPDATE `##block` SET gedcom_id = :tree_id, xref = :xref WHERE block_id = :block_id"
25372ac996dSGreg Roach			)->execute([
25472ac996dSGreg Roach				'tree_id'  => $tree->getTreeId(),
25572ac996dSGreg Roach				'xref'     => $xref,
25672ac996dSGreg Roach				'block_id' => $block_id,
25772ac996dSGreg Roach			]);
25872ac996dSGreg Roach		} else {
25972ac996dSGreg Roach			Database::prepare(
26072ac996dSGreg Roach				"INSERT INTO `##block` (gedcom_id, xref, module_name, block_order) VALUES (:tree_id, :xref, 'stories', 0)"
26172ac996dSGreg Roach			)->execute([
26272ac996dSGreg Roach				'tree_id' => $tree->getTreeId(),
26372ac996dSGreg Roach				'xref'    => $xref,
26472ac996dSGreg Roach			]);
26572ac996dSGreg Roach
26672ac996dSGreg Roach			$block_id = Database::getInstance()->lastInsertId();
26772ac996dSGreg Roach		}
26872ac996dSGreg Roach
26972ac996dSGreg Roach		$this->setBlockSetting($block_id, 'story_body', $story_body);
27072ac996dSGreg Roach		$this->setBlockSetting($block_id, 'title', $story_title);
27172ac996dSGreg Roach		$this->setBlockSetting($block_id, 'languages', implode(',', $languages));
27272ac996dSGreg Roach
27372ac996dSGreg Roach		$url = route('module', ['module' => 'stories', 'action' => 'Admin', 'ged' => $tree->getName()]);
27472ac996dSGreg Roach
27572ac996dSGreg Roach		return new RedirectResponse($url);
27672ac996dSGreg Roach	}
27772ac996dSGreg Roach
27872ac996dSGreg Roach	/**
27972ac996dSGreg Roach	 * @param Request $request
28072ac996dSGreg Roach	 *
28172ac996dSGreg Roach	 * @return Response
28272ac996dSGreg Roach	 */
28372ac996dSGreg Roach	public function postAdminDeleteAction(Request $request): Response {
28472ac996dSGreg Roach		/** @var Tree $tree */
28572ac996dSGreg Roach		$tree = $request->attributes->get('tree');
28672ac996dSGreg Roach
28772ac996dSGreg Roach		$block_id = (int) $request->get('block_id');
28872ac996dSGreg Roach
28972ac996dSGreg Roach		Database::prepare(
29072ac996dSGreg Roach			"DELETE FROM `##block_setting` WHERE block_id = :block_id"
29172ac996dSGreg Roach		)->execute([
29272ac996dSGreg Roach			'block_id' => $block_id,
29372ac996dSGreg Roach		]);
29472ac996dSGreg Roach
29572ac996dSGreg Roach		Database::prepare(
29672ac996dSGreg Roach			"DELETE FROM `##block` WHERE block_id = :block_id"
29772ac996dSGreg Roach		)->execute([
29872ac996dSGreg Roach			'block_id' => $block_id,
29972ac996dSGreg Roach		]);
30072ac996dSGreg Roach
30172ac996dSGreg Roach		$url = route('module', ['module' => 'stories', 'action' => 'Admin', 'ged' => $tree->getName()]);
30272ac996dSGreg Roach
30372ac996dSGreg Roach		return new RedirectResponse($url);
30472ac996dSGreg Roach	}
30572ac996dSGreg Roach
30672ac996dSGreg Roach	/**
30772ac996dSGreg Roach	 * @param Request $request
30872ac996dSGreg Roach	 *
30972ac996dSGreg Roach	 * @return Response
31072ac996dSGreg Roach	 */
31172ac996dSGreg Roach	public function getShowListAction(Request $request): Response {
31272ac996dSGreg Roach		/** @var Tree $tree
31372ac996dSGreg Roach		 */
31472ac996dSGreg Roach		$tree = $request->attributes->get('tree');
31572ac996dSGreg Roach
31672ac996dSGreg Roach		$stories = Database::prepare(
31772ac996dSGreg Roach			"SELECT block_id, xref" .
31872ac996dSGreg Roach			" FROM `##block` b" .
31972ac996dSGreg Roach			" WHERE module_name = :module_name" .
32072ac996dSGreg Roach			" AND gedcom_id = :tree_id" .
32172ac996dSGreg Roach			" ORDER BY xref"
32272ac996dSGreg Roach		)->execute([
32372ac996dSGreg Roach			'module_name' => $this->getName(),
32472ac996dSGreg Roach			'tree_id'     => $tree->getTreeId(),
32572ac996dSGreg Roach		])->fetchAll();
32672ac996dSGreg Roach
32772ac996dSGreg Roach		foreach ($stories as $story) {
32872ac996dSGreg Roach			$story->individual = Individual::getInstance($story->xref, $tree);
32972ac996dSGreg Roach			$story->title      = $this->getBlockSetting($story->block_id, 'title');
33072ac996dSGreg Roach			$story->languages  = $this->getBlockSetting($story->block_id, 'languages');
33172ac996dSGreg Roach		}
33272ac996dSGreg Roach
33372ac996dSGreg Roach		// Filter non-existant and private individuals.
33472ac996dSGreg Roach		$stories = array_filter($stories, function (stdClass $story) {
33572ac996dSGreg Roach			return $story->individual !== null && $story->individual->canShow();
33672ac996dSGreg Roach		});
33772ac996dSGreg Roach
33872ac996dSGreg Roach		// Filter foreign languages.
33972ac996dSGreg Roach		$stories = array_filter($stories, function (stdClass $story) {
340a44b57a9SGreg Roach			return $story->languages === '' || in_array(WT_LOCALE, explode(',', $story->languages));
34172ac996dSGreg Roach		});
34272ac996dSGreg Roach
34372ac996dSGreg Roach		return $this->viewResponse('modules/stories/list', [
34472ac996dSGreg Roach			'stories' => $stories,
34572ac996dSGreg Roach			'title'   => $this->getTitle(),
34672ac996dSGreg Roach		]);
34772ac996dSGreg Roach	}
3488c2e8227SGreg Roach}
349