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 20*46295629SGreg Roachuse Fisharebest\Webtrees\GedcomRecord; 210e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N; 220e62c4b8SGreg Roachuse Fisharebest\Webtrees\Menu; 230e62c4b8SGreg Roachuse Fisharebest\Webtrees\Tree; 2477654037SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 2577654037SGreg Roachuse Illuminate\Database\Query\Builder; 2677654037SGreg Roachuse Illuminate\Support\Collection; 278de50a4eSGreg Roachuse stdClass; 28aee13b6dSGreg Roachuse Symfony\Component\HttpFoundation\RedirectResponse; 29aee13b6dSGreg Roachuse Symfony\Component\HttpFoundation\Request; 30aee13b6dSGreg Roachuse Symfony\Component\HttpFoundation\Response; 318c2e8227SGreg Roach 328c2e8227SGreg Roach/** 338c2e8227SGreg Roach * Class FrequentlyAskedQuestionsModule 348c2e8227SGreg Roach */ 3549a243cbSGreg Roachclass FrequentlyAskedQuestionsModule extends AbstractModule implements ModuleInterface, ModuleConfigInterface, ModuleMenuInterface 36c1010edaSGreg Roach{ 3749a243cbSGreg Roach use ModuleConfigTrait; 3849a243cbSGreg Roach use ModuleMenuTrait; 3949a243cbSGreg Roach 408c2e8227SGreg Roach /** {@inheritdoc} */ 4149a243cbSGreg Roach public function title(): string 42c1010edaSGreg Roach { 43bbb76c12SGreg Roach /* I18N: Name of a module. Abbreviation for “Frequently Asked Questions” */ 44bbb76c12SGreg Roach return I18N::translate('FAQ'); 458c2e8227SGreg Roach } 468c2e8227SGreg Roach 478c2e8227SGreg Roach /** {@inheritdoc} */ 4849a243cbSGreg Roach public function description(): string 49c1010edaSGreg Roach { 50bbb76c12SGreg Roach /* I18N: Description of the “FAQ” module */ 51bbb76c12SGreg Roach return I18N::translate('A list of frequently asked questions and answers.'); 528c2e8227SGreg Roach } 538c2e8227SGreg Roach 5476692c8bSGreg Roach /** 5549a243cbSGreg Roach * The default position for this menu. It can be changed in the control panel. 560ee13198SGreg Roach * 570ee13198SGreg Roach * @return int 580ee13198SGreg Roach */ 598f53f488SRico Sonntag public function defaultMenuOrder(): int 60c1010edaSGreg Roach { 61*46295629SGreg Roach return 80; 628c2e8227SGreg Roach } 638c2e8227SGreg Roach 640ee13198SGreg Roach /** 650ee13198SGreg Roach * A menu, to be added to the main application menu. 660ee13198SGreg Roach * 67aee13b6dSGreg Roach * @param Tree $tree 68aee13b6dSGreg Roach * 690ee13198SGreg Roach * @return Menu|null 700ee13198SGreg Roach */ 71*46295629SGreg Roach public function getMenu(Tree $tree): ?Menu 72c1010edaSGreg Roach { 7377654037SGreg Roach if ($this->faqsExist($tree, WT_LOCALE)) { 7449a243cbSGreg Roach return new Menu($this->title(), route('module', [ 7549a243cbSGreg Roach 'module' => $this->getName(), 76c1010edaSGreg Roach 'action' => 'Show', 77aa6f03bbSGreg Roach 'ged' => $tree->name(), 78c1010edaSGreg Roach ]), 'menu-help'); 798c2e8227SGreg Roach } 80b2ce94c6SRico Sonntag 81b2ce94c6SRico Sonntag return null; 828c2e8227SGreg Roach } 83aee13b6dSGreg Roach 84aee13b6dSGreg Roach /** 85b6db7c1fSGreg Roach * @param Tree $tree 86aee13b6dSGreg Roach * 87aee13b6dSGreg Roach * @return Response 88aee13b6dSGreg Roach */ 89b6db7c1fSGreg Roach public function getAdminAction(Tree $tree): Response 90c1010edaSGreg Roach { 91aee13b6dSGreg Roach $this->layout = 'layouts/administration'; 92aee13b6dSGreg Roach 9326348dcdSGreg Roach $faqs = $this->faqsForTree($tree); 94aee13b6dSGreg Roach 9577654037SGreg Roach $min_block_order = DB::table('block') 9677654037SGreg Roach ->where('module_name', '=', $this->getName()) 9777654037SGreg Roach ->where(function (Builder $query) use ($tree): void { 9877654037SGreg Roach $query 9977654037SGreg Roach ->whereNull('gedcom_id') 10077654037SGreg Roach ->orWhere('gedcom_id', '=', $tree->id()); 10177654037SGreg Roach }) 10277654037SGreg Roach ->min('block_order'); 103aee13b6dSGreg Roach 10477654037SGreg Roach $max_block_order = DB::table('block') 10577654037SGreg Roach ->where('module_name', '=', $this->getName()) 10677654037SGreg Roach ->where(function (Builder $query) use ($tree): void { 10777654037SGreg Roach $query 10877654037SGreg Roach ->whereNull('gedcom_id') 10977654037SGreg Roach ->orWhere('gedcom_id', '=', $tree->id()); 11077654037SGreg Roach }) 11177654037SGreg Roach ->max('block_order'); 112aee13b6dSGreg Roach 113cc13d6d8SGreg Roach $title = I18N::translate('Frequently asked questions') . ' — ' . $tree->title(); 114aee13b6dSGreg Roach 115aee13b6dSGreg Roach return $this->viewResponse('modules/faq/config', [ 116aee13b6dSGreg Roach 'faqs' => $faqs, 117aee13b6dSGreg Roach 'max_block_order' => $max_block_order, 118aee13b6dSGreg Roach 'min_block_order' => $min_block_order, 119aee13b6dSGreg Roach 'title' => $title, 120aee13b6dSGreg Roach 'tree' => $tree, 121aee13b6dSGreg Roach 'tree_names' => Tree::getNameList(), 122aee13b6dSGreg Roach ]); 123aee13b6dSGreg Roach } 124aee13b6dSGreg Roach 125aee13b6dSGreg Roach /** 126aee13b6dSGreg Roach * @param Request $request 127b6db7c1fSGreg Roach * @param Tree $tree 128aee13b6dSGreg Roach * 129aee13b6dSGreg Roach * @return RedirectResponse 130aee13b6dSGreg Roach */ 131b6db7c1fSGreg Roach public function postAdminDeleteAction(Request $request, Tree $tree): RedirectResponse 132c1010edaSGreg Roach { 133aee13b6dSGreg Roach $block_id = (int) $request->get('block_id'); 134aee13b6dSGreg Roach 13577654037SGreg Roach DB::table('block_setting')->where('block_id', '=', $block_id)->delete(); 136aee13b6dSGreg Roach 13777654037SGreg Roach DB::table('block')->where('block_id', '=', $block_id)->delete(); 138aee13b6dSGreg Roach 139c1010edaSGreg Roach $url = route('module', [ 14049a243cbSGreg Roach 'module' => $this->getName(), 141c1010edaSGreg Roach 'action' => 'Admin', 142aa6f03bbSGreg Roach 'ged' => $tree->name(), 143c1010edaSGreg Roach ]); 144aee13b6dSGreg Roach 145aee13b6dSGreg Roach return new RedirectResponse($url); 146aee13b6dSGreg Roach } 147aee13b6dSGreg Roach 148aee13b6dSGreg Roach /** 149aee13b6dSGreg Roach * @param Request $request 150b6db7c1fSGreg Roach * @param Tree $tree 151aee13b6dSGreg Roach * 152aee13b6dSGreg Roach * @return RedirectResponse 153aee13b6dSGreg Roach */ 154b6db7c1fSGreg Roach public function postAdminMoveDownAction(Request $request, Tree $tree): RedirectResponse 155c1010edaSGreg Roach { 156aee13b6dSGreg Roach $block_id = (int) $request->get('block_id'); 157aee13b6dSGreg Roach 15877654037SGreg Roach $block_order = DB::table('block') 15977654037SGreg Roach ->where('block_id', '=', $block_id) 16077654037SGreg Roach ->value('block_order'); 161aee13b6dSGreg Roach 16277654037SGreg Roach $swap_block = DB::table('block') 16377654037SGreg Roach ->where('module_name', '=', $this->getName()) 16477654037SGreg Roach ->where('block_order', '=', function (Builder $query) use ($block_order): void { 16577654037SGreg Roach $query 16677654037SGreg Roach ->from('block') 16777654037SGreg Roach ->where('module_name', '=', $this->getName()) 16877654037SGreg Roach ->where('block_order', '>', $block_order) 16977654037SGreg Roach ->select(DB::raw('MIN(block_order)')); 17077654037SGreg Roach }) 17177654037SGreg Roach ->select(['block_order', 'block_id']) 17277654037SGreg Roach ->first(); 173aee13b6dSGreg Roach 174aee13b6dSGreg Roach if ($swap_block !== null) { 17577654037SGreg Roach DB::table('block') 17677654037SGreg Roach ->where('block_id', '=', $block_id) 17777654037SGreg Roach ->update([ 178aee13b6dSGreg Roach 'block_order' => $swap_block->block_order, 179aee13b6dSGreg Roach ]); 18077654037SGreg Roach 18177654037SGreg Roach DB::table('block') 18277654037SGreg Roach ->where('block_id', '=', $swap_block->block_id) 18377654037SGreg Roach ->update([ 184aee13b6dSGreg Roach 'block_order' => $block_order, 185aee13b6dSGreg Roach ]); 186aee13b6dSGreg Roach } 187aee13b6dSGreg Roach 188c1010edaSGreg Roach $url = route('module', [ 18949a243cbSGreg Roach 'module' => $this->getName(), 190c1010edaSGreg Roach 'action' => 'Admin', 191aa6f03bbSGreg Roach 'ged' => $tree->name(), 192c1010edaSGreg Roach ]); 193aee13b6dSGreg Roach 194aee13b6dSGreg Roach return new RedirectResponse($url); 195aee13b6dSGreg Roach } 196aee13b6dSGreg Roach 197aee13b6dSGreg Roach /** 198aee13b6dSGreg Roach * @param Request $request 199b6db7c1fSGreg Roach * @param Tree $tree 200aee13b6dSGreg Roach * 201aee13b6dSGreg Roach * @return RedirectResponse 202aee13b6dSGreg Roach */ 203b6db7c1fSGreg Roach public function postAdminMoveUpAction(Request $request, Tree $tree): RedirectResponse 204c1010edaSGreg Roach { 205aee13b6dSGreg Roach $block_id = (int) $request->get('block_id'); 206aee13b6dSGreg Roach 20777654037SGreg Roach $block_order = DB::table('block') 20877654037SGreg Roach ->where('block_id', '=', $block_id) 20977654037SGreg Roach ->value('block_order'); 210aee13b6dSGreg Roach 21177654037SGreg Roach $swap_block = DB::table('block') 21277654037SGreg Roach ->where('module_name', '=', $this->getName()) 21377654037SGreg Roach ->where('block_order', '=', function (Builder $query) use ($block_order): void { 21477654037SGreg Roach $query 21577654037SGreg Roach ->from('block') 21677654037SGreg Roach ->where('module_name', '=', $this->getName()) 21777654037SGreg Roach ->where('block_order', '<', $block_order) 21877654037SGreg Roach ->select(DB::raw('MAX(block_order)')); 21977654037SGreg Roach }) 22077654037SGreg Roach ->select(['block_order', 'block_id']) 22177654037SGreg Roach ->first(); 222aee13b6dSGreg Roach 223aee13b6dSGreg Roach if ($swap_block !== null) { 22477654037SGreg Roach DB::table('block') 22577654037SGreg Roach ->where('block_id', '=', $block_id) 22677654037SGreg Roach ->update([ 227aee13b6dSGreg Roach 'block_order' => $swap_block->block_order, 228aee13b6dSGreg Roach ]); 22977654037SGreg Roach 23077654037SGreg Roach DB::table('block') 23177654037SGreg Roach ->where('block_id', '=', $swap_block->block_id) 23277654037SGreg Roach ->update([ 233aee13b6dSGreg Roach 'block_order' => $block_order, 234aee13b6dSGreg Roach ]); 235aee13b6dSGreg Roach } 236aee13b6dSGreg Roach 237c1010edaSGreg Roach $url = route('module', [ 23849a243cbSGreg Roach 'module' => $this->getName(), 239c1010edaSGreg Roach 'action' => 'Admin', 240aa6f03bbSGreg Roach 'ged' => $tree->name(), 241c1010edaSGreg Roach ]); 242aee13b6dSGreg Roach 243aee13b6dSGreg Roach return new RedirectResponse($url); 244aee13b6dSGreg Roach } 245aee13b6dSGreg Roach 246aee13b6dSGreg Roach /** 247aee13b6dSGreg Roach * @param Request $request 248b6db7c1fSGreg Roach * @param Tree $tree 249aee13b6dSGreg Roach * 250aee13b6dSGreg Roach * @return Response 251aee13b6dSGreg Roach */ 252b6db7c1fSGreg Roach public function getAdminEditAction(Request $request, Tree $tree): Response 253c1010edaSGreg Roach { 254aee13b6dSGreg Roach $this->layout = 'layouts/administration'; 255aee13b6dSGreg Roach 256aee13b6dSGreg Roach $block_id = (int) $request->get('block_id'); 257aee13b6dSGreg Roach 258aee13b6dSGreg Roach if ($block_id === 0) { 259aee13b6dSGreg Roach // Creating a new faq 260aee13b6dSGreg Roach $header = ''; 261aee13b6dSGreg Roach $faqbody = ''; 26277654037SGreg Roach 26377654037SGreg Roach $block_order = 1 + (int) DB::table('block') 26477654037SGreg Roach ->where('module_name', '=', $this->getName()) 26577654037SGreg Roach ->max('block_order'); 26677654037SGreg Roach 267aee13b6dSGreg Roach $languages = []; 268aee13b6dSGreg Roach 269aee13b6dSGreg Roach $title = I18N::translate('Add an FAQ'); 270aee13b6dSGreg Roach } else { 271aee13b6dSGreg Roach // Editing an existing faq 272aee13b6dSGreg Roach $header = $this->getBlockSetting($block_id, 'header'); 273aee13b6dSGreg Roach $faqbody = $this->getBlockSetting($block_id, 'faqbody'); 27477654037SGreg Roach 27577654037SGreg Roach $block_order = DB::table('block') 27677654037SGreg Roach ->where('block_id', '=', $block_id) 27777654037SGreg Roach ->value('block_order'); 27877654037SGreg Roach 279aee13b6dSGreg Roach $languages = explode(',', $this->getBlockSetting($block_id, 'languages')); 280aee13b6dSGreg Roach 281aee13b6dSGreg Roach $title = I18N::translate('Edit the FAQ'); 282aee13b6dSGreg Roach } 283aee13b6dSGreg Roach 284aee13b6dSGreg Roach return $this->viewResponse('modules/faq/edit', [ 285aee13b6dSGreg Roach 'block_id' => $block_id, 286aee13b6dSGreg Roach 'block_order' => $block_order, 287aee13b6dSGreg Roach 'header' => $header, 288aee13b6dSGreg Roach 'faqbody' => $faqbody, 289aee13b6dSGreg Roach 'languages' => $languages, 290aee13b6dSGreg Roach 'title' => $title, 291aee13b6dSGreg Roach 'tree' => $tree, 29277654037SGreg Roach 'tree_names' => Tree::getIdList(), 293aee13b6dSGreg Roach ]); 294aee13b6dSGreg Roach } 295aee13b6dSGreg Roach 296aee13b6dSGreg Roach /** 297aee13b6dSGreg Roach * @param Request $request 298b6db7c1fSGreg Roach * @param Tree $tree 299aee13b6dSGreg Roach * 300aee13b6dSGreg Roach * @return RedirectResponse 301aee13b6dSGreg Roach */ 302b6db7c1fSGreg Roach public function postAdminEditAction(Request $request, Tree $tree): RedirectResponse 303c1010edaSGreg Roach { 304aee13b6dSGreg Roach $block_id = (int) $request->get('block_id'); 305aee13b6dSGreg Roach $faqbody = $request->get('faqbody', ''); 306aee13b6dSGreg Roach $header = $request->get('header', ''); 307aee13b6dSGreg Roach $languages = $request->get('languages', []); 30877654037SGreg Roach $gedcom_id = (int) $request->get('gedcom_id') ?: null; 30977654037SGreg Roach $block_order = (int) $request->get('block_order'); 310aee13b6dSGreg Roach 311aee13b6dSGreg Roach if ($block_id !== 0) { 31277654037SGreg Roach DB::table('block') 31377654037SGreg Roach ->where('block_id', '=', $block_id) 31477654037SGreg Roach ->update([ 31577654037SGreg Roach 'gedcom_id' => $gedcom_id, 31677654037SGreg Roach 'block_order' => $block_order, 317aee13b6dSGreg Roach ]); 318aee13b6dSGreg Roach } else { 31977654037SGreg Roach DB::table('block')->insert([ 32077654037SGreg Roach 'gedcom_id' => $gedcom_id, 321aee13b6dSGreg Roach 'module_name' => $this->getName(), 32277654037SGreg Roach 'block_order' => $block_order, 323aee13b6dSGreg Roach ]); 324aee13b6dSGreg Roach 32577654037SGreg Roach $block_id = (int) DB::connection()->getPdo()->lastInsertId(); 326aee13b6dSGreg Roach } 327aee13b6dSGreg Roach 328aee13b6dSGreg Roach $this->setBlockSetting($block_id, 'faqbody', $faqbody); 329aee13b6dSGreg Roach $this->setBlockSetting($block_id, 'header', $header); 330aee13b6dSGreg Roach $this->setBlockSetting($block_id, 'languages', implode(',', $languages)); 331aee13b6dSGreg Roach 332c1010edaSGreg Roach $url = route('module', [ 33349a243cbSGreg Roach 'module' => $this->getName(), 334c1010edaSGreg Roach 'action' => 'Admin', 335aa6f03bbSGreg Roach 'ged' => $tree->name(), 336c1010edaSGreg Roach ]); 337aee13b6dSGreg Roach 338aee13b6dSGreg Roach return new RedirectResponse($url); 339aee13b6dSGreg Roach } 340aee13b6dSGreg Roach 341b998dbceSGreg Roach /** 342b6db7c1fSGreg Roach * @param Tree $tree 343b998dbceSGreg Roach * 344b998dbceSGreg Roach * @return Response 345b998dbceSGreg Roach */ 34638f9e88cSGreg Roach public function getShowAction(Tree $tree): Response 347c1010edaSGreg Roach { 3488de50a4eSGreg Roach // Filter foreign languages. 34977654037SGreg Roach $faqs = $this->faqsForTree($tree) 35077654037SGreg Roach ->filter(function (stdClass $faq): bool { 3518de50a4eSGreg Roach return $faq->languages === '' || in_array(WT_LOCALE, explode(',', $faq->languages)); 3528de50a4eSGreg Roach }); 353aee13b6dSGreg Roach 354aee13b6dSGreg Roach return $this->viewResponse('modules/faq/show', [ 3558de50a4eSGreg Roach 'faqs' => $faqs, 356aee13b6dSGreg Roach 'title' => I18N::translate('Frequently asked questions'), 3578de50a4eSGreg Roach 'tree' => $tree, 358aee13b6dSGreg Roach ]); 359aee13b6dSGreg Roach } 36077654037SGreg Roach 36177654037SGreg Roach /** 36277654037SGreg Roach * @param Tree $tree 36377654037SGreg Roach * 36477654037SGreg Roach * @return Collection 36577654037SGreg Roach */ 36677654037SGreg Roach private function faqsForTree(Tree $tree): Collection 36777654037SGreg Roach { 36877654037SGreg Roach return DB::table('block') 36977654037SGreg Roach ->join('block_setting AS bs1', 'bs1.block_id', '=', 'block.block_id') 37077654037SGreg Roach ->join('block_setting AS bs2', 'bs2.block_id', '=', 'block.block_id') 37177654037SGreg Roach ->join('block_setting AS bs3', 'bs3.block_id', '=', 'block.block_id') 37277654037SGreg Roach ->where('module_name', '=', $this->getName()) 37377654037SGreg Roach ->where('bs1.setting_name', '=', 'header') 37477654037SGreg Roach ->where('bs2.setting_name', '=', 'faqbody') 37577654037SGreg Roach ->where('bs3.setting_name', '=', 'languages') 37677654037SGreg Roach ->where(function (Builder $query) use ($tree): void { 37777654037SGreg Roach $query 37877654037SGreg Roach ->whereNull('gedcom_id') 37977654037SGreg Roach ->orWhere('gedcom_id', '=', $tree->id()); 38077654037SGreg Roach }) 38177654037SGreg Roach ->orderBy('block_order') 38277654037SGreg Roach ->select(['block.block_id', 'block_order', 'gedcom_id', 'bs1.setting_value AS header', 'bs2.setting_value AS faqbody', 'bs3.setting_value AS languages']) 38377654037SGreg Roach ->get(); 38477654037SGreg Roach } 38577654037SGreg Roach 38677654037SGreg Roach /** 38777654037SGreg Roach * @param Tree $tree 38877654037SGreg Roach * @param string $language 38977654037SGreg Roach * 39077654037SGreg Roach * @return bool 39177654037SGreg Roach */ 39277654037SGreg Roach private function faqsExist(Tree $tree, string $language): bool 39377654037SGreg Roach { 39477654037SGreg Roach return DB::table('block') 39577654037SGreg Roach ->join('block_setting', 'block_setting.block_id', '=', 'block.block_id') 39677654037SGreg Roach ->where('module_name', '=', $this->getName()) 39777654037SGreg Roach ->where('setting_name', '=', 'languages') 39877654037SGreg Roach ->where(function (Builder $query) use ($tree): void { 39977654037SGreg Roach $query 40077654037SGreg Roach ->whereNull('gedcom_id') 40177654037SGreg Roach ->orWhere('gedcom_id', '=', $tree->id()); 40277654037SGreg Roach }) 40377654037SGreg Roach ->select(['setting_value AS languages']) 40477654037SGreg Roach ->get() 40577654037SGreg Roach ->filter(function (stdClass $faq) use ($language): bool { 40677654037SGreg Roach return $faq->languages === '' || in_array($language, explode(',', $faq->languages)); 40777654037SGreg Roach }) 40877654037SGreg Roach ->isNotEmpty(); 40977654037SGreg Roach } 4108c2e8227SGreg Roach} 411