18c2e8227SGreg Roach<?php 28c2e8227SGreg Roach/** 38c2e8227SGreg Roach * webtrees: online genealogy 48fcd0d32SGreg Roach * Copyright (C) 2019 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 */ 16e7f56f2aSGreg Roachdeclare(strict_types=1); 17e7f56f2aSGreg Roach 1876692c8bSGreg Roachnamespace Fisharebest\Webtrees\Module; 1976692c8bSGreg Roach 200e62c4b8SGreg Roachuse Fisharebest\Webtrees\Auth; 210e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N; 220e62c4b8SGreg Roachuse Fisharebest\Webtrees\Individual; 230e62c4b8SGreg Roachuse Fisharebest\Webtrees\Menu; 240e62c4b8SGreg Roachuse Fisharebest\Webtrees\Tree; 254b92b602SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 266ccdf4f0SGreg Roachuse Psr\Http\Message\ResponseInterface; 276ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 28225e381fSGreg Roachuse stdClass; 298c2e8227SGreg Roach 308c2e8227SGreg Roach/** 318c2e8227SGreg Roach * Class StoriesModule 328c2e8227SGreg Roach */ 3337eb8894SGreg Roachclass StoriesModule extends AbstractModule implements ModuleConfigInterface, ModuleMenuInterface, ModuleTabInterface 34c1010edaSGreg Roach{ 3549a243cbSGreg Roach use ModuleTabTrait; 3649a243cbSGreg Roach use ModuleConfigTrait; 3749a243cbSGreg Roach use ModuleMenuTrait; 3849a243cbSGreg Roach 3949a243cbSGreg Roach /** @var int The default access level for this module. It can be changed in the control panel. */ 4049a243cbSGreg Roach protected $access_level = Auth::PRIV_HIDE; 4149a243cbSGreg Roach 42961ec755SGreg Roach /** 43961ec755SGreg Roach * A sentence describing what this module does. 44961ec755SGreg Roach * 45961ec755SGreg Roach * @return string 46961ec755SGreg Roach */ 4749a243cbSGreg Roach public function description(): string 48c1010edaSGreg Roach { 49bbb76c12SGreg Roach /* I18N: Description of the “Stories” module */ 50bbb76c12SGreg Roach return I18N::translate('Add narrative stories to individuals in the family tree.'); 518c2e8227SGreg Roach } 528c2e8227SGreg Roach 53aee13b6dSGreg Roach /** 5449a243cbSGreg Roach * The default position for this menu. It can be changed in the control panel. 55aee13b6dSGreg Roach * 5649a243cbSGreg Roach * @return int 57aee13b6dSGreg Roach */ 5849a243cbSGreg Roach public function defaultMenuOrder(): int 59c1010edaSGreg Roach { 60353b36abSGreg Roach return 7; 618c2e8227SGreg Roach } 628c2e8227SGreg Roach 6349a243cbSGreg Roach /** 6449a243cbSGreg Roach * The default position for this tab. It can be changed in the control panel. 6549a243cbSGreg Roach * 6649a243cbSGreg Roach * @return int 6749a243cbSGreg Roach */ 68cbf4b7faSGreg Roach public function defaultTabOrder(): int 69cbf4b7faSGreg Roach { 70fb7a0427SGreg Roach return 9; 718c2e8227SGreg Roach } 728c2e8227SGreg Roach 738c2e8227SGreg Roach /** {@inheritdoc} */ 749b34404bSGreg Roach public function getTabContent(Individual $individual): string 75c1010edaSGreg Roach { 7672ac996dSGreg Roach return view('modules/stories/tab', [ 7772ac996dSGreg Roach 'is_admin' => Auth::isAdmin(), 78225e381fSGreg Roach 'individual' => $individual, 79225e381fSGreg Roach 'stories' => $this->getStoriesForIndividual($individual), 80225e381fSGreg Roach ]); 818c2e8227SGreg Roach } 828c2e8227SGreg Roach 83225e381fSGreg Roach /** 84225e381fSGreg Roach * @param Individual $individual 85225e381fSGreg Roach * 86225e381fSGreg Roach * @return stdClass[] 87225e381fSGreg Roach */ 88c1010edaSGreg Roach private function getStoriesForIndividual(Individual $individual): array 89c1010edaSGreg Roach { 904b92b602SGreg Roach $block_ids = DB::table('block') 9126684e68SGreg Roach ->where('module_name', '=', $this->name()) 924b92b602SGreg Roach ->where('xref', '=', $individual->xref()) 934b92b602SGreg Roach ->where('gedcom_id', '=', $individual->tree()->id()) 944b92b602SGreg Roach ->pluck('block_id'); 95225e381fSGreg Roach 96225e381fSGreg Roach $stories = []; 97225e381fSGreg Roach foreach ($block_ids as $block_id) { 987d988ec3SGreg Roach $block_id = (int) $block_id; 997d988ec3SGreg Roach 100225e381fSGreg Roach // Only show this block for certain languages 101225e381fSGreg Roach $languages = $this->getBlockSetting($block_id, 'languages', ''); 10222d65e5aSGreg Roach if ($languages === '' || in_array(WT_LOCALE, explode(',', $languages), true)) { 103225e381fSGreg Roach $stories[] = (object) [ 104225e381fSGreg Roach 'block_id' => $block_id, 105225e381fSGreg Roach 'title' => $this->getBlockSetting($block_id, 'title'), 10672ac996dSGreg Roach 'story_body' => $this->getBlockSetting($block_id, 'story_body'), 107225e381fSGreg Roach ]; 108225e381fSGreg Roach } 109225e381fSGreg Roach } 110225e381fSGreg Roach 111225e381fSGreg Roach return $stories; 1128c2e8227SGreg Roach } 1138c2e8227SGreg Roach 1146ccdf4f0SGreg Roach /** {@inheritdoc} */ 1156ccdf4f0SGreg Roach public function hasTabContent(Individual $individual): bool 1166ccdf4f0SGreg Roach { 1176ccdf4f0SGreg Roach return Auth::isManager($individual->tree()) || !empty($this->getStoriesForIndividual($individual)); 1186ccdf4f0SGreg Roach } 1196ccdf4f0SGreg Roach 1206ccdf4f0SGreg Roach /** {@inheritdoc} */ 1216ccdf4f0SGreg Roach public function isGrayedOut(Individual $individual): bool 1226ccdf4f0SGreg Roach { 1236ccdf4f0SGreg Roach return !empty($this->getStoriesForIndividual($individual)); 1246ccdf4f0SGreg Roach } 1256ccdf4f0SGreg Roach 1266ccdf4f0SGreg Roach /** {@inheritdoc} */ 1276ccdf4f0SGreg Roach public function canLoadAjax(): bool 1286ccdf4f0SGreg Roach { 1296ccdf4f0SGreg Roach return false; 1306ccdf4f0SGreg Roach } 1316ccdf4f0SGreg Roach 1328c2e8227SGreg Roach /** 1330ee13198SGreg Roach * A menu, to be added to the main application menu. 1340ee13198SGreg Roach * 135aee13b6dSGreg Roach * @param Tree $tree 136aee13b6dSGreg Roach * 1370ee13198SGreg Roach * @return Menu|null 1380ee13198SGreg Roach */ 13946295629SGreg Roach public function getMenu(Tree $tree): ?Menu 140c1010edaSGreg Roach { 14149a243cbSGreg Roach $menu = new Menu($this->title(), route('module', [ 14226684e68SGreg Roach 'module' => $this->name(), 143c1010edaSGreg Roach 'action' => 'ShowList', 144aa6f03bbSGreg Roach 'ged' => $tree->name(), 145c1010edaSGreg Roach ]), 'menu-story'); 1468c2e8227SGreg Roach 1478c2e8227SGreg Roach return $menu; 1488c2e8227SGreg Roach } 14972ac996dSGreg Roach 15072ac996dSGreg Roach /** 1516ccdf4f0SGreg Roach * How should this module be identified in the control panel, etc.? 1526ccdf4f0SGreg Roach * 1536ccdf4f0SGreg Roach * @return string 1546ccdf4f0SGreg Roach */ 1556ccdf4f0SGreg Roach public function title(): string 1566ccdf4f0SGreg Roach { 1576ccdf4f0SGreg Roach /* I18N: Name of a module */ 1586ccdf4f0SGreg Roach return I18N::translate('Stories'); 1596ccdf4f0SGreg Roach } 1606ccdf4f0SGreg Roach 1616ccdf4f0SGreg Roach /** 162b6db7c1fSGreg Roach * @param Tree $tree 16372ac996dSGreg Roach * 1646ccdf4f0SGreg Roach * @return ResponseInterface 16572ac996dSGreg Roach */ 1666ccdf4f0SGreg Roach public function getAdminAction(Tree $tree): ResponseInterface 167c1010edaSGreg Roach { 16872ac996dSGreg Roach $this->layout = 'layouts/administration'; 16972ac996dSGreg Roach 1704b92b602SGreg Roach $stories = DB::table('block') 17126684e68SGreg Roach ->where('module_name', '=', $this->name()) 1724b92b602SGreg Roach ->where('gedcom_id', '=', $tree->id()) 1734b92b602SGreg Roach ->orderBy('xref') 1744b92b602SGreg Roach ->get(); 17572ac996dSGreg Roach 17672ac996dSGreg Roach foreach ($stories as $story) { 1775db543e1SGreg Roach $block_id = (int) $story->block_id; 1785db543e1SGreg Roach 17972ac996dSGreg Roach $story->individual = Individual::getInstance($story->xref, $tree); 1805db543e1SGreg Roach $story->title = $this->getBlockSetting($block_id, 'title'); 1815db543e1SGreg Roach $story->languages = $this->getBlockSetting($block_id, 'languages'); 18272ac996dSGreg Roach } 18372ac996dSGreg Roach 18472ac996dSGreg Roach return $this->viewResponse('modules/stories/config', [ 18572ac996dSGreg Roach 'stories' => $stories, 18649a243cbSGreg Roach 'title' => $this->title() . ' — ' . $tree->title(), 18772ac996dSGreg Roach 'tree' => $tree, 18872ac996dSGreg Roach 'tree_names' => Tree::getNameList(), 18972ac996dSGreg Roach ]); 19072ac996dSGreg Roach } 19172ac996dSGreg Roach 19272ac996dSGreg Roach /** 1936ccdf4f0SGreg Roach * @param ServerRequestInterface $request 194b6db7c1fSGreg Roach * @param Tree $tree 19572ac996dSGreg Roach * 1966ccdf4f0SGreg Roach * @return ResponseInterface 19772ac996dSGreg Roach */ 1986ccdf4f0SGreg Roach public function getAdminEditAction(ServerRequestInterface $request, Tree $tree): ResponseInterface 199c1010edaSGreg Roach { 20072ac996dSGreg Roach $this->layout = 'layouts/administration'; 20172ac996dSGreg Roach 202*b6b9dcc9SGreg Roach $block_id = (int) ($request->getQueryParams()['block_id'] ?? 0); 20372ac996dSGreg Roach 20472ac996dSGreg Roach if ($block_id === 0) { 20572ac996dSGreg Roach // Creating a new story 206*b6b9dcc9SGreg Roach $individual = null; 20772ac996dSGreg Roach $story_title = ''; 20872ac996dSGreg Roach $story_body = ''; 20972ac996dSGreg Roach $languages = []; 21072ac996dSGreg Roach 211cc13d6d8SGreg Roach $title = I18N::translate('Add a story') . ' — ' . e($tree->title()); 21272ac996dSGreg Roach } else { 21372ac996dSGreg Roach // Editing an existing story 2144b92b602SGreg Roach $xref = (string) DB::table('block') 2154b92b602SGreg Roach ->where('block_id', '=', $block_id) 2164b92b602SGreg Roach ->value('xref'); 21772ac996dSGreg Roach 21872ac996dSGreg Roach $individual = Individual::getInstance($xref, $tree); 21972ac996dSGreg Roach $story_title = $this->getBlockSetting($block_id, 'title', ''); 22072ac996dSGreg Roach $story_body = $this->getBlockSetting($block_id, 'story_body', ''); 22172ac996dSGreg Roach $languages = explode(',', $this->getBlockSetting($block_id, 'languages')); 22272ac996dSGreg Roach 223cc13d6d8SGreg Roach $title = I18N::translate('Edit the story') . ' — ' . e($tree->title()); 22472ac996dSGreg Roach } 22572ac996dSGreg Roach 22672ac996dSGreg Roach return $this->viewResponse('modules/stories/edit', [ 22772ac996dSGreg Roach 'block_id' => $block_id, 22872ac996dSGreg Roach 'languages' => $languages, 22972ac996dSGreg Roach 'story_body' => $story_body, 23072ac996dSGreg Roach 'story_title' => $story_title, 23172ac996dSGreg Roach 'title' => $title, 23272ac996dSGreg Roach 'tree' => $tree, 23372ac996dSGreg Roach 'individual' => $individual, 23472ac996dSGreg Roach ]); 23572ac996dSGreg Roach } 23672ac996dSGreg Roach 23772ac996dSGreg Roach /** 2386ccdf4f0SGreg Roach * @param ServerRequestInterface $request 239b6db7c1fSGreg Roach * @param Tree $tree 24072ac996dSGreg Roach * 2416ccdf4f0SGreg Roach * @return ResponseInterface 24272ac996dSGreg Roach */ 2436ccdf4f0SGreg Roach public function postAdminEditAction(ServerRequestInterface $request, Tree $tree): ResponseInterface 244c1010edaSGreg Roach { 245*b6b9dcc9SGreg Roach $block_id = (int) ($request->getQueryParams()['block_id'] ?? 0); 246*b6b9dcc9SGreg Roach 247*b6b9dcc9SGreg Roach $params = $request->getParsedBody(); 248*b6b9dcc9SGreg Roach 249*b6b9dcc9SGreg Roach $xref = $params['xref']; 250*b6b9dcc9SGreg Roach $story_body = $params['story_body']; 251*b6b9dcc9SGreg Roach $story_title = $params['story_title']; 252*b6b9dcc9SGreg Roach $languages = $params['languages'] ?? []; 25372ac996dSGreg Roach 25472ac996dSGreg Roach if ($block_id !== 0) { 2554b92b602SGreg Roach DB::table('block') 2564b92b602SGreg Roach ->where('block_id', '=', $block_id) 2574b92b602SGreg Roach ->update([ 2584b92b602SGreg Roach 'gedcom_id' => $tree->id(), 25972ac996dSGreg Roach 'xref' => $xref, 26072ac996dSGreg Roach ]); 26172ac996dSGreg Roach } else { 2624b92b602SGreg Roach DB::table('block')->insert([ 2634b92b602SGreg Roach 'gedcom_id' => $tree->id(), 26472ac996dSGreg Roach 'xref' => $xref, 26526684e68SGreg Roach 'module_name' => $this->name(), 2664b92b602SGreg Roach 'block_order' => 0, 26772ac996dSGreg Roach ]); 26872ac996dSGreg Roach 2694b92b602SGreg Roach $block_id = (int) DB::connection()->getPdo()->lastInsertId(); 27072ac996dSGreg Roach } 27172ac996dSGreg Roach 27272ac996dSGreg Roach $this->setBlockSetting($block_id, 'story_body', $story_body); 27372ac996dSGreg Roach $this->setBlockSetting($block_id, 'title', $story_title); 27472ac996dSGreg Roach $this->setBlockSetting($block_id, 'languages', implode(',', $languages)); 27572ac996dSGreg Roach 276c1010edaSGreg Roach $url = route('module', [ 27726684e68SGreg Roach 'module' => $this->name(), 278c1010edaSGreg Roach 'action' => 'Admin', 279aa6f03bbSGreg Roach 'ged' => $tree->name(), 280c1010edaSGreg Roach ]); 28172ac996dSGreg Roach 2826ccdf4f0SGreg Roach return redirect($url); 28372ac996dSGreg Roach } 28472ac996dSGreg Roach 28572ac996dSGreg Roach /** 2866ccdf4f0SGreg Roach * @param ServerRequestInterface $request 287b6db7c1fSGreg Roach * @param Tree $tree 28872ac996dSGreg Roach * 2896ccdf4f0SGreg Roach * @return ResponseInterface 29072ac996dSGreg Roach */ 2916ccdf4f0SGreg Roach public function postAdminDeleteAction(ServerRequestInterface $request, Tree $tree): ResponseInterface 292c1010edaSGreg Roach { 293*b6b9dcc9SGreg Roach $block_id = $request->getQueryParams()['block_id']; 29472ac996dSGreg Roach 2954b92b602SGreg Roach DB::table('block_setting') 2964b92b602SGreg Roach ->where('block_id', '=', $block_id) 2974b92b602SGreg Roach ->delete(); 29872ac996dSGreg Roach 2994b92b602SGreg Roach DB::table('block') 3004b92b602SGreg Roach ->where('block_id', '=', $block_id) 3014b92b602SGreg Roach ->delete(); 30272ac996dSGreg Roach 303c1010edaSGreg Roach $url = route('module', [ 30426684e68SGreg Roach 'module' => $this->name(), 305c1010edaSGreg Roach 'action' => 'Admin', 306aa6f03bbSGreg Roach 'ged' => $tree->name(), 307c1010edaSGreg Roach ]); 30872ac996dSGreg Roach 3096ccdf4f0SGreg Roach return redirect($url); 31072ac996dSGreg Roach } 31172ac996dSGreg Roach 31272ac996dSGreg Roach /** 313b6db7c1fSGreg Roach * @param Tree $tree 31472ac996dSGreg Roach * 3156ccdf4f0SGreg Roach * @return ResponseInterface 31672ac996dSGreg Roach */ 3176ccdf4f0SGreg Roach public function getShowListAction(Tree $tree): ResponseInterface 318c1010edaSGreg Roach { 3194b92b602SGreg Roach $stories = DB::table('block') 32026684e68SGreg Roach ->where('module_name', '=', $this->name()) 3214b92b602SGreg Roach ->where('gedcom_id', '=', $tree->id()) 3224b92b602SGreg Roach ->get() 3234b92b602SGreg Roach ->map(function (stdClass $story) use ($tree): stdClass { 3245db543e1SGreg Roach $block_id = (int) $story->block_id; 3255db543e1SGreg Roach 32672ac996dSGreg Roach $story->individual = Individual::getInstance($story->xref, $tree); 3275db543e1SGreg Roach $story->title = $this->getBlockSetting($block_id, 'title'); 3285db543e1SGreg Roach $story->languages = $this->getBlockSetting($block_id, 'languages'); 32972ac996dSGreg Roach 3304b92b602SGreg Roach return $story; 3310b5fd0a6SGreg Roach })->filter(static function (stdClass $story): bool { 33272ac996dSGreg Roach // Filter non-existant and private individuals. 3334b92b602SGreg Roach return $story->individual instanceof Individual && $story->individual->canShow(); 3340b5fd0a6SGreg Roach })->filter(static function (stdClass $story): bool { 33572ac996dSGreg Roach // Filter foreign languages. 33622d65e5aSGreg Roach return $story->languages === '' || in_array(WT_LOCALE, explode(',', $story->languages), true); 33772ac996dSGreg Roach }); 33872ac996dSGreg Roach 33972ac996dSGreg Roach return $this->viewResponse('modules/stories/list', [ 34072ac996dSGreg Roach 'stories' => $stories, 34149a243cbSGreg Roach 'title' => $this->title(), 34272ac996dSGreg Roach ]); 34372ac996dSGreg Roach } 3448c2e8227SGreg Roach} 345