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\I18N; 210e62c4b8SGreg Roachuse Fisharebest\Webtrees\Menu; 220e62c4b8SGreg Roachuse Fisharebest\Webtrees\Tree; 23*77654037SGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 24*77654037SGreg Roachuse Illuminate\Database\Query\Builder; 25*77654037SGreg Roachuse Illuminate\Support\Collection; 268de50a4eSGreg Roachuse stdClass; 27aee13b6dSGreg Roachuse Symfony\Component\HttpFoundation\RedirectResponse; 28aee13b6dSGreg Roachuse Symfony\Component\HttpFoundation\Request; 29aee13b6dSGreg Roachuse Symfony\Component\HttpFoundation\Response; 308c2e8227SGreg Roach 318c2e8227SGreg Roach/** 328c2e8227SGreg Roach * Class FrequentlyAskedQuestionsModule 338c2e8227SGreg Roach */ 34c1010edaSGreg Roachclass FrequentlyAskedQuestionsModule extends AbstractModule implements ModuleMenuInterface, ModuleConfigInterface 35c1010edaSGreg Roach{ 368c2e8227SGreg Roach /** {@inheritdoc} */ 378f53f488SRico Sonntag public function getTitle(): string 38c1010edaSGreg Roach { 39bbb76c12SGreg Roach /* I18N: Name of a module. Abbreviation for “Frequently Asked Questions” */ 40bbb76c12SGreg Roach return I18N::translate('FAQ'); 418c2e8227SGreg Roach } 428c2e8227SGreg Roach 438c2e8227SGreg Roach /** {@inheritdoc} */ 448f53f488SRico Sonntag public function getDescription(): string 45c1010edaSGreg Roach { 46bbb76c12SGreg Roach /* I18N: Description of the “FAQ” module */ 47bbb76c12SGreg Roach return I18N::translate('A list of frequently asked questions and answers.'); 488c2e8227SGreg Roach } 498c2e8227SGreg Roach 5076692c8bSGreg Roach /** 51aee13b6dSGreg Roach * The URL to a page where the user can modify the configuration of this module. 5276692c8bSGreg Roach * 53aee13b6dSGreg Roach * @return string 5476692c8bSGreg Roach */ 558f53f488SRico Sonntag public function getConfigLink(): string 56c1010edaSGreg Roach { 57c1010edaSGreg Roach return route('module', [ 58c1010edaSGreg Roach 'module' => $this->getName(), 59c1010edaSGreg Roach 'action' => 'Admin', 60c1010edaSGreg Roach ]); 618c2e8227SGreg Roach } 628c2e8227SGreg Roach 638c2e8227SGreg Roach /** 640ee13198SGreg Roach * The user can re-order menus. Until they do, they are shown in this order. 650ee13198SGreg Roach * 660ee13198SGreg Roach * @return int 670ee13198SGreg Roach */ 688f53f488SRico Sonntag public function defaultMenuOrder(): int 69c1010edaSGreg Roach { 708c2e8227SGreg Roach return 40; 718c2e8227SGreg Roach } 728c2e8227SGreg Roach 730ee13198SGreg Roach /** 740ee13198SGreg Roach * A menu, to be added to the main application menu. 750ee13198SGreg Roach * 76aee13b6dSGreg Roach * @param Tree $tree 77aee13b6dSGreg Roach * 780ee13198SGreg Roach * @return Menu|null 790ee13198SGreg Roach */ 80c1010edaSGreg Roach public function getMenu(Tree $tree) 81c1010edaSGreg Roach { 82*77654037SGreg Roach if ($this->faqsExist($tree, WT_LOCALE)) { 83c1010edaSGreg Roach return new Menu($this->getTitle(), route('module', [ 84c1010edaSGreg Roach 'module' => 'faq', 85c1010edaSGreg Roach 'action' => 'Show', 86aa6f03bbSGreg Roach 'ged' => $tree->name(), 87c1010edaSGreg Roach ]), 'menu-help'); 888c2e8227SGreg Roach } 89b2ce94c6SRico Sonntag 90b2ce94c6SRico Sonntag return null; 918c2e8227SGreg Roach } 92aee13b6dSGreg Roach 93aee13b6dSGreg Roach /** 94b6db7c1fSGreg Roach * @param Tree $tree 95aee13b6dSGreg Roach * 96aee13b6dSGreg Roach * @return Response 97aee13b6dSGreg Roach */ 98b6db7c1fSGreg Roach public function getAdminAction(Tree $tree): Response 99c1010edaSGreg Roach { 100aee13b6dSGreg Roach $this->layout = 'layouts/administration'; 101aee13b6dSGreg Roach 102*77654037SGreg Roach $faqs = $this->faqsForTree($tree, ''); 103aee13b6dSGreg Roach 104*77654037SGreg Roach $min_block_order = DB::table('block') 105*77654037SGreg Roach ->where('module_name', '=', $this->getName()) 106*77654037SGreg Roach ->where(function (Builder $query) use ($tree): void { 107*77654037SGreg Roach $query 108*77654037SGreg Roach ->whereNull('gedcom_id') 109*77654037SGreg Roach ->orWhere('gedcom_id', '=', $tree->id()); 110*77654037SGreg Roach }) 111*77654037SGreg Roach ->min('block_order'); 112aee13b6dSGreg Roach 113*77654037SGreg Roach $max_block_order = DB::table('block') 114*77654037SGreg Roach ->where('module_name', '=', $this->getName()) 115*77654037SGreg Roach ->where(function (Builder $query) use ($tree): void { 116*77654037SGreg Roach $query 117*77654037SGreg Roach ->whereNull('gedcom_id') 118*77654037SGreg Roach ->orWhere('gedcom_id', '=', $tree->id()); 119*77654037SGreg Roach }) 120*77654037SGreg Roach ->max('block_order'); 121aee13b6dSGreg Roach 122cc13d6d8SGreg Roach $title = I18N::translate('Frequently asked questions') . ' — ' . $tree->title(); 123aee13b6dSGreg Roach 124aee13b6dSGreg Roach return $this->viewResponse('modules/faq/config', [ 125aee13b6dSGreg Roach 'faqs' => $faqs, 126aee13b6dSGreg Roach 'max_block_order' => $max_block_order, 127aee13b6dSGreg Roach 'min_block_order' => $min_block_order, 128aee13b6dSGreg Roach 'title' => $title, 129aee13b6dSGreg Roach 'tree' => $tree, 130aee13b6dSGreg Roach 'tree_names' => Tree::getNameList(), 131aee13b6dSGreg Roach ]); 132aee13b6dSGreg Roach } 133aee13b6dSGreg Roach 134aee13b6dSGreg Roach /** 135aee13b6dSGreg Roach * @param Request $request 136b6db7c1fSGreg Roach * @param Tree $tree 137aee13b6dSGreg Roach * 138aee13b6dSGreg Roach * @return RedirectResponse 139aee13b6dSGreg Roach */ 140b6db7c1fSGreg Roach public function postAdminDeleteAction(Request $request, Tree $tree): RedirectResponse 141c1010edaSGreg Roach { 142aee13b6dSGreg Roach $block_id = (int) $request->get('block_id'); 143aee13b6dSGreg Roach 144*77654037SGreg Roach DB::table('block_setting')->where('block_id', '=', $block_id)->delete(); 145aee13b6dSGreg Roach 146*77654037SGreg Roach DB::table('block')->where('block_id', '=', $block_id)->delete(); 147aee13b6dSGreg Roach 148c1010edaSGreg Roach $url = route('module', [ 149c1010edaSGreg Roach 'module' => 'faq', 150c1010edaSGreg Roach 'action' => 'Admin', 151aa6f03bbSGreg Roach 'ged' => $tree->name(), 152c1010edaSGreg Roach ]); 153aee13b6dSGreg Roach 154aee13b6dSGreg Roach return new RedirectResponse($url); 155aee13b6dSGreg Roach } 156aee13b6dSGreg Roach 157aee13b6dSGreg Roach /** 158aee13b6dSGreg Roach * @param Request $request 159b6db7c1fSGreg Roach * @param Tree $tree 160aee13b6dSGreg Roach * 161aee13b6dSGreg Roach * @return RedirectResponse 162aee13b6dSGreg Roach */ 163b6db7c1fSGreg Roach public function postAdminMoveDownAction(Request $request, Tree $tree): RedirectResponse 164c1010edaSGreg Roach { 165aee13b6dSGreg Roach $block_id = (int) $request->get('block_id'); 166aee13b6dSGreg Roach 167*77654037SGreg Roach $block_order = DB::table('block') 168*77654037SGreg Roach ->where('block_id', '=', $block_id) 169*77654037SGreg Roach ->value('block_order'); 170aee13b6dSGreg Roach 171*77654037SGreg Roach $swap_block = DB::table('block') 172*77654037SGreg Roach ->where('module_name', '=', $this->getName()) 173*77654037SGreg Roach ->where('block_order', '=', function (Builder $query) use ($block_order): void { 174*77654037SGreg Roach $query 175*77654037SGreg Roach ->from('block') 176*77654037SGreg Roach ->where('module_name', '=', $this->getName()) 177*77654037SGreg Roach ->where('block_order', '>', $block_order) 178*77654037SGreg Roach ->select(DB::raw('MIN(block_order)')); 179*77654037SGreg Roach }) 180*77654037SGreg Roach ->select(['block_order', 'block_id']) 181*77654037SGreg Roach ->first(); 182aee13b6dSGreg Roach 183aee13b6dSGreg Roach if ($swap_block !== null) { 184*77654037SGreg Roach DB::table('block') 185*77654037SGreg Roach ->where('block_id', '=', $block_id) 186*77654037SGreg Roach ->update([ 187aee13b6dSGreg Roach 'block_order' => $swap_block->block_order, 188aee13b6dSGreg Roach ]); 189*77654037SGreg Roach 190*77654037SGreg Roach DB::table('block') 191*77654037SGreg Roach ->where('block_id', '=', $swap_block->block_id) 192*77654037SGreg Roach ->update([ 193aee13b6dSGreg Roach 'block_order' => $block_order, 194aee13b6dSGreg Roach ]); 195aee13b6dSGreg Roach } 196aee13b6dSGreg Roach 197c1010edaSGreg Roach $url = route('module', [ 198c1010edaSGreg Roach 'module' => 'faq', 199c1010edaSGreg Roach 'action' => 'Admin', 200aa6f03bbSGreg Roach 'ged' => $tree->name(), 201c1010edaSGreg Roach ]); 202aee13b6dSGreg Roach 203aee13b6dSGreg Roach return new RedirectResponse($url); 204aee13b6dSGreg Roach } 205aee13b6dSGreg Roach 206aee13b6dSGreg Roach /** 207aee13b6dSGreg Roach * @param Request $request 208b6db7c1fSGreg Roach * @param Tree $tree 209aee13b6dSGreg Roach * 210aee13b6dSGreg Roach * @return RedirectResponse 211aee13b6dSGreg Roach */ 212b6db7c1fSGreg Roach public function postAdminMoveUpAction(Request $request, Tree $tree): RedirectResponse 213c1010edaSGreg Roach { 214aee13b6dSGreg Roach $block_id = (int) $request->get('block_id'); 215aee13b6dSGreg Roach 216*77654037SGreg Roach $block_order = DB::table('block') 217*77654037SGreg Roach ->where('block_id', '=', $block_id) 218*77654037SGreg Roach ->value('block_order'); 219aee13b6dSGreg Roach 220*77654037SGreg Roach $swap_block = DB::table('block') 221*77654037SGreg Roach ->where('module_name', '=', $this->getName()) 222*77654037SGreg Roach ->where('block_order', '=', function (Builder $query) use ($block_order): void { 223*77654037SGreg Roach $query 224*77654037SGreg Roach ->from('block') 225*77654037SGreg Roach ->where('module_name', '=', $this->getName()) 226*77654037SGreg Roach ->where('block_order', '<', $block_order) 227*77654037SGreg Roach ->select(DB::raw('MAX(block_order)')); 228*77654037SGreg Roach }) 229*77654037SGreg Roach ->select(['block_order', 'block_id']) 230*77654037SGreg Roach ->first(); 231aee13b6dSGreg Roach 232aee13b6dSGreg Roach if ($swap_block !== null) { 233*77654037SGreg Roach DB::table('block') 234*77654037SGreg Roach ->where('block_id', '=', $block_id) 235*77654037SGreg Roach ->update([ 236aee13b6dSGreg Roach 'block_order' => $swap_block->block_order, 237aee13b6dSGreg Roach ]); 238*77654037SGreg Roach 239*77654037SGreg Roach DB::table('block') 240*77654037SGreg Roach ->where('block_id', '=', $swap_block->block_id) 241*77654037SGreg Roach ->update([ 242aee13b6dSGreg Roach 'block_order' => $block_order, 243aee13b6dSGreg Roach ]); 244aee13b6dSGreg Roach } 245aee13b6dSGreg Roach 246c1010edaSGreg Roach $url = route('module', [ 247c1010edaSGreg Roach 'module' => 'faq', 248c1010edaSGreg Roach 'action' => 'Admin', 249aa6f03bbSGreg Roach 'ged' => $tree->name(), 250c1010edaSGreg Roach ]); 251aee13b6dSGreg Roach 252aee13b6dSGreg Roach return new RedirectResponse($url); 253aee13b6dSGreg Roach } 254aee13b6dSGreg Roach 255aee13b6dSGreg Roach /** 256aee13b6dSGreg Roach * @param Request $request 257b6db7c1fSGreg Roach * @param Tree $tree 258aee13b6dSGreg Roach * 259aee13b6dSGreg Roach * @return Response 260aee13b6dSGreg Roach */ 261b6db7c1fSGreg Roach public function getAdminEditAction(Request $request, Tree $tree): Response 262c1010edaSGreg Roach { 263aee13b6dSGreg Roach $this->layout = 'layouts/administration'; 264aee13b6dSGreg Roach 265aee13b6dSGreg Roach $block_id = (int) $request->get('block_id'); 266aee13b6dSGreg Roach 267aee13b6dSGreg Roach if ($block_id === 0) { 268aee13b6dSGreg Roach // Creating a new faq 269aee13b6dSGreg Roach $header = ''; 270aee13b6dSGreg Roach $faqbody = ''; 271*77654037SGreg Roach 272*77654037SGreg Roach $block_order = 1 + (int) DB::table('block') 273*77654037SGreg Roach ->where('module_name', '=', $this->getName()) 274*77654037SGreg Roach ->max('block_order'); 275*77654037SGreg Roach 276aee13b6dSGreg Roach $languages = []; 277aee13b6dSGreg Roach 278aee13b6dSGreg Roach $title = I18N::translate('Add an FAQ'); 279aee13b6dSGreg Roach } else { 280aee13b6dSGreg Roach // Editing an existing faq 281aee13b6dSGreg Roach $header = $this->getBlockSetting($block_id, 'header'); 282aee13b6dSGreg Roach $faqbody = $this->getBlockSetting($block_id, 'faqbody'); 283*77654037SGreg Roach 284*77654037SGreg Roach $block_order = DB::table('block') 285*77654037SGreg Roach ->where('block_id', '=', $block_id) 286*77654037SGreg Roach ->value('block_order'); 287*77654037SGreg Roach 288aee13b6dSGreg Roach $languages = explode(',', $this->getBlockSetting($block_id, 'languages')); 289aee13b6dSGreg Roach 290aee13b6dSGreg Roach $title = I18N::translate('Edit the FAQ'); 291aee13b6dSGreg Roach } 292aee13b6dSGreg Roach 293aee13b6dSGreg Roach return $this->viewResponse('modules/faq/edit', [ 294aee13b6dSGreg Roach 'block_id' => $block_id, 295aee13b6dSGreg Roach 'block_order' => $block_order, 296aee13b6dSGreg Roach 'header' => $header, 297aee13b6dSGreg Roach 'faqbody' => $faqbody, 298aee13b6dSGreg Roach 'languages' => $languages, 299aee13b6dSGreg Roach 'title' => $title, 300aee13b6dSGreg Roach 'tree' => $tree, 301*77654037SGreg Roach 'tree_names' => Tree::getIdList(), 302aee13b6dSGreg Roach ]); 303aee13b6dSGreg Roach } 304aee13b6dSGreg Roach 305aee13b6dSGreg Roach /** 306aee13b6dSGreg Roach * @param Request $request 307b6db7c1fSGreg Roach * @param Tree $tree 308aee13b6dSGreg Roach * 309aee13b6dSGreg Roach * @return RedirectResponse 310aee13b6dSGreg Roach */ 311b6db7c1fSGreg Roach public function postAdminEditAction(Request $request, Tree $tree): RedirectResponse 312c1010edaSGreg Roach { 313aee13b6dSGreg Roach $block_id = (int) $request->get('block_id'); 314aee13b6dSGreg Roach $faqbody = $request->get('faqbody', ''); 315aee13b6dSGreg Roach $header = $request->get('header', ''); 316aee13b6dSGreg Roach $languages = $request->get('languages', []); 317*77654037SGreg Roach $gedcom_id = (int) $request->get('gedcom_id') ?: null; 318*77654037SGreg Roach $block_order = (int) $request->get('block_order'); 319aee13b6dSGreg Roach 320aee13b6dSGreg Roach if ($block_id !== 0) { 321*77654037SGreg Roach DB::table('block') 322*77654037SGreg Roach ->where('block_id', '=', $block_id) 323*77654037SGreg Roach ->update([ 324*77654037SGreg Roach 'gedcom_id' => $gedcom_id, 325*77654037SGreg Roach 'block_order' => $block_order, 326aee13b6dSGreg Roach ]); 327aee13b6dSGreg Roach } else { 328*77654037SGreg Roach DB::table('block')->insert([ 329*77654037SGreg Roach 'gedcom_id' => $gedcom_id, 330aee13b6dSGreg Roach 'module_name' => $this->getName(), 331*77654037SGreg Roach 'block_order' => $block_order, 332aee13b6dSGreg Roach ]); 333aee13b6dSGreg Roach 334*77654037SGreg Roach $block_id = (int) DB::connection()->getPdo()->lastInsertId(); 335aee13b6dSGreg Roach } 336aee13b6dSGreg Roach 337aee13b6dSGreg Roach $this->setBlockSetting($block_id, 'faqbody', $faqbody); 338aee13b6dSGreg Roach $this->setBlockSetting($block_id, 'header', $header); 339aee13b6dSGreg Roach $this->setBlockSetting($block_id, 'languages', implode(',', $languages)); 340aee13b6dSGreg Roach 341c1010edaSGreg Roach $url = route('module', [ 342c1010edaSGreg Roach 'module' => 'faq', 343c1010edaSGreg Roach 'action' => 'Admin', 344aa6f03bbSGreg Roach 'ged' => $tree->name(), 345c1010edaSGreg Roach ]); 346aee13b6dSGreg Roach 347aee13b6dSGreg Roach return new RedirectResponse($url); 348aee13b6dSGreg Roach } 349aee13b6dSGreg Roach 350b998dbceSGreg Roach /** 351b6db7c1fSGreg Roach * @param Tree $tree 352b998dbceSGreg Roach * 353b998dbceSGreg Roach * @return Response 354b998dbceSGreg Roach */ 35538f9e88cSGreg Roach public function getShowAction(Tree $tree): Response 356c1010edaSGreg Roach { 3578de50a4eSGreg Roach // Filter foreign languages. 358*77654037SGreg Roach $faqs = $this->faqsForTree($tree) 359*77654037SGreg Roach ->filter(function (stdClass $faq): bool { 3608de50a4eSGreg Roach return $faq->languages === '' || in_array(WT_LOCALE, explode(',', $faq->languages)); 3618de50a4eSGreg Roach }); 362aee13b6dSGreg Roach 363aee13b6dSGreg Roach return $this->viewResponse('modules/faq/show', [ 3648de50a4eSGreg Roach 'faqs' => $faqs, 365aee13b6dSGreg Roach 'title' => I18N::translate('Frequently asked questions'), 3668de50a4eSGreg Roach 'tree' => $tree, 367aee13b6dSGreg Roach ]); 368aee13b6dSGreg Roach } 369*77654037SGreg Roach 370*77654037SGreg Roach /** 371*77654037SGreg Roach * @param Tree $tree 372*77654037SGreg Roach * 373*77654037SGreg Roach * @return Collection 374*77654037SGreg Roach */ 375*77654037SGreg Roach private function faqsForTree(Tree $tree): Collection 376*77654037SGreg Roach { 377*77654037SGreg Roach return DB::table('block') 378*77654037SGreg Roach ->join('block_setting AS bs1', 'bs1.block_id', '=', 'block.block_id') 379*77654037SGreg Roach ->join('block_setting AS bs2', 'bs2.block_id', '=', 'block.block_id') 380*77654037SGreg Roach ->join('block_setting AS bs3', 'bs3.block_id', '=', 'block.block_id') 381*77654037SGreg Roach ->where('module_name', '=', $this->getName()) 382*77654037SGreg Roach ->where('bs1.setting_name', '=', 'header') 383*77654037SGreg Roach ->where('bs2.setting_name', '=', 'faqbody') 384*77654037SGreg Roach ->where('bs3.setting_name', '=', 'languages') 385*77654037SGreg Roach ->where(function (Builder $query) use ($tree): void { 386*77654037SGreg Roach $query 387*77654037SGreg Roach ->whereNull('gedcom_id') 388*77654037SGreg Roach ->orWhere('gedcom_id', '=', $tree->id()); 389*77654037SGreg Roach }) 390*77654037SGreg Roach ->orderBy('block_order') 391*77654037SGreg Roach ->select(['block.block_id', 'block_order', 'gedcom_id', 'bs1.setting_value AS header', 'bs2.setting_value AS faqbody', 'bs3.setting_value AS languages']) 392*77654037SGreg Roach ->get(); 393*77654037SGreg Roach } 394*77654037SGreg Roach 395*77654037SGreg Roach /** 396*77654037SGreg Roach * @param Tree $tree 397*77654037SGreg Roach * @param string $language 398*77654037SGreg Roach * 399*77654037SGreg Roach * @return bool 400*77654037SGreg Roach */ 401*77654037SGreg Roach private function faqsExist(Tree $tree, string $language): bool 402*77654037SGreg Roach { 403*77654037SGreg Roach return DB::table('block') 404*77654037SGreg Roach ->join('block_setting', 'block_setting.block_id', '=', 'block.block_id') 405*77654037SGreg Roach ->where('module_name', '=', $this->getName()) 406*77654037SGreg Roach ->where('setting_name', '=', 'languages') 407*77654037SGreg Roach ->where(function (Builder $query) use ($tree): void { 408*77654037SGreg Roach $query 409*77654037SGreg Roach ->whereNull('gedcom_id') 410*77654037SGreg Roach ->orWhere('gedcom_id', '=', $tree->id()); 411*77654037SGreg Roach }) 412*77654037SGreg Roach ->select(['setting_value AS languages']) 413*77654037SGreg Roach ->get() 414*77654037SGreg Roach ->filter(function (stdClass $faq) use ($language): bool { 415*77654037SGreg Roach return $faq->languages === '' || in_array($language, explode(',', $faq->languages)); 416*77654037SGreg Roach }) 417*77654037SGreg Roach ->isNotEmpty(); 418*77654037SGreg Roach } 4198c2e8227SGreg Roach} 420