1*0c0910bfSGreg Roach<?php 2*0c0910bfSGreg Roach 3*0c0910bfSGreg Roach/** 4*0c0910bfSGreg Roach * webtrees: online genealogy 5*0c0910bfSGreg Roach * Copyright (C) 2019 webtrees development team 6*0c0910bfSGreg Roach * This program is free software: you can redistribute it and/or modify 7*0c0910bfSGreg Roach * it under the terms of the GNU General Public License as published by 8*0c0910bfSGreg Roach * the Free Software Foundation, either version 3 of the License, or 9*0c0910bfSGreg Roach * (at your option) any later version. 10*0c0910bfSGreg Roach * This program is distributed in the hope that it will be useful, 11*0c0910bfSGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 12*0c0910bfSGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*0c0910bfSGreg Roach * GNU General Public License for more details. 14*0c0910bfSGreg Roach * You should have received a copy of the GNU General Public License 15*0c0910bfSGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 16*0c0910bfSGreg Roach */ 17*0c0910bfSGreg Roachdeclare(strict_types=1); 18*0c0910bfSGreg Roach 19*0c0910bfSGreg Roachnamespace Fisharebest\Webtrees\Http\RequestHandlers; 20*0c0910bfSGreg Roach 21*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Http\ViewResponseTrait; 22*0c0910bfSGreg Roachuse Fisharebest\Webtrees\I18N; 23*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\FamilyListModule; 24*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\IndividualListModule; 25*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\MediaListModule; 26*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleAnalyticsInterface; 27*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleBlockInterface; 28*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleChartInterface; 29*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleFooterInterface; 30*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleHistoricEventsInterface; 31*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleLanguageInterface; 32*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleListInterface; 33*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleMenuInterface; 34*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleReportInterface; 35*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleSidebarInterface; 36*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleTabInterface; 37*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\ModuleThemeInterface; 38*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\NoteListModule; 39*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\RepositoryListModule; 40*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Module\SourceListModule; 41*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Services\HousekeepingService; 42*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Services\ModuleService; 43*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Services\ServerCheckService; 44*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Services\TreeService; 45*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Services\UpgradeService; 46*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Services\UserService; 47*0c0910bfSGreg Roachuse Fisharebest\Webtrees\Webtrees; 48*0c0910bfSGreg Roachuse Illuminate\Database\Capsule\Manager as DB; 49*0c0910bfSGreg Roachuse Illuminate\Database\Query\Expression; 50*0c0910bfSGreg Roachuse Illuminate\Database\Query\JoinClause; 51*0c0910bfSGreg Roachuse Illuminate\Support\Collection; 52*0c0910bfSGreg Roachuse League\Flysystem\Adapter\Local; 53*0c0910bfSGreg Roachuse League\Flysystem\Filesystem; 54*0c0910bfSGreg Roachuse Psr\Http\Message\ResponseInterface; 55*0c0910bfSGreg Roachuse Psr\Http\Message\ServerRequestInterface; 56*0c0910bfSGreg Roachuse Psr\Http\Server\RequestHandlerInterface; 57*0c0910bfSGreg Roach 58*0c0910bfSGreg Roach/** 59*0c0910bfSGreg Roach * The control panel shows a summary of the site and links to admin functions. 60*0c0910bfSGreg Roach */ 61*0c0910bfSGreg Roachclass ControlPanel implements RequestHandlerInterface 62*0c0910bfSGreg Roach{ 63*0c0910bfSGreg Roach use ViewResponseTrait; 64*0c0910bfSGreg Roach 65*0c0910bfSGreg Roach /** @var ModuleService */ 66*0c0910bfSGreg Roach private $module_service; 67*0c0910bfSGreg Roach 68*0c0910bfSGreg Roach /** @var HousekeepingService */ 69*0c0910bfSGreg Roach private $housekeeping_service; 70*0c0910bfSGreg Roach 71*0c0910bfSGreg Roach /** @var ServerCheckService */ 72*0c0910bfSGreg Roach private $server_check_service; 73*0c0910bfSGreg Roach 74*0c0910bfSGreg Roach /** @var TreeService */ 75*0c0910bfSGreg Roach private $tree_service; 76*0c0910bfSGreg Roach 77*0c0910bfSGreg Roach /** @var UpgradeService */ 78*0c0910bfSGreg Roach private $upgrade_service; 79*0c0910bfSGreg Roach 80*0c0910bfSGreg Roach /** @var UserService */ 81*0c0910bfSGreg Roach private $user_service; 82*0c0910bfSGreg Roach 83*0c0910bfSGreg Roach /** 84*0c0910bfSGreg Roach * ControlPanel constructor. 85*0c0910bfSGreg Roach * 86*0c0910bfSGreg Roach * @param HousekeepingService $housekeeping_service 87*0c0910bfSGreg Roach * @param ModuleService $module_service 88*0c0910bfSGreg Roach * @param ServerCheckService $server_check_service 89*0c0910bfSGreg Roach * @param TreeService $tree_service 90*0c0910bfSGreg Roach * @param UpgradeService $upgrade_service 91*0c0910bfSGreg Roach * @param UserService $user_service 92*0c0910bfSGreg Roach */ 93*0c0910bfSGreg Roach public function __construct( 94*0c0910bfSGreg Roach HousekeepingService $housekeeping_service, 95*0c0910bfSGreg Roach ModuleService $module_service, 96*0c0910bfSGreg Roach ServerCheckService $server_check_service, 97*0c0910bfSGreg Roach TreeService $tree_service, 98*0c0910bfSGreg Roach UpgradeService $upgrade_service, 99*0c0910bfSGreg Roach UserService $user_service 100*0c0910bfSGreg Roach ) { 101*0c0910bfSGreg Roach $this->module_service = $module_service; 102*0c0910bfSGreg Roach $this->housekeeping_service = $housekeeping_service; 103*0c0910bfSGreg Roach $this->server_check_service = $server_check_service; 104*0c0910bfSGreg Roach $this->tree_service = $tree_service; 105*0c0910bfSGreg Roach $this->upgrade_service = $upgrade_service; 106*0c0910bfSGreg Roach $this->user_service = $user_service; 107*0c0910bfSGreg Roach } 108*0c0910bfSGreg Roach 109*0c0910bfSGreg Roach /** 110*0c0910bfSGreg Roach * @param ServerRequestInterface $request 111*0c0910bfSGreg Roach * 112*0c0910bfSGreg Roach * @return ResponseInterface 113*0c0910bfSGreg Roach */ 114*0c0910bfSGreg Roach public function handle(ServerRequestInterface $request): ResponseInterface 115*0c0910bfSGreg Roach { 116*0c0910bfSGreg Roach $this->layout = 'layouts/administration'; 117*0c0910bfSGreg Roach 118*0c0910bfSGreg Roach $filesystem = new Filesystem(new Local(Webtrees::ROOT_DIR)); 119*0c0910bfSGreg Roach $files_to_delete = $this->housekeeping_service->deleteOldWebtreesFiles($filesystem); 120*0c0910bfSGreg Roach 121*0c0910bfSGreg Roach return $this->viewResponse('admin/control-panel', [ 122*0c0910bfSGreg Roach 'title' => I18N::translate('Control panel'), 123*0c0910bfSGreg Roach 'server_errors' => $this->server_check_service->serverErrors(), 124*0c0910bfSGreg Roach 'server_warnings' => $this->server_check_service->serverWarnings(), 125*0c0910bfSGreg Roach 'latest_version' => $this->upgrade_service->latestVersion(), 126*0c0910bfSGreg Roach 'all_users' => $this->user_service->all(), 127*0c0910bfSGreg Roach 'administrators' => $this->user_service->administrators(), 128*0c0910bfSGreg Roach 'managers' => $this->user_service->managers(), 129*0c0910bfSGreg Roach 'moderators' => $this->user_service->moderators(), 130*0c0910bfSGreg Roach 'unapproved' => $this->user_service->unapproved(), 131*0c0910bfSGreg Roach 'unverified' => $this->user_service->unverified(), 132*0c0910bfSGreg Roach 'all_trees' => $this->tree_service->all(), 133*0c0910bfSGreg Roach 'changes' => $this->totalChanges(), 134*0c0910bfSGreg Roach 'individuals' => $this->totalIndividuals(), 135*0c0910bfSGreg Roach 'families' => $this->totalFamilies(), 136*0c0910bfSGreg Roach 'sources' => $this->totalSources(), 137*0c0910bfSGreg Roach 'media' => $this->totalMediaObjects(), 138*0c0910bfSGreg Roach 'repositories' => $this->totalRepositories(), 139*0c0910bfSGreg Roach 'notes' => $this->totalNotes(), 140*0c0910bfSGreg Roach 'individual_list_module' => $this->module_service->findByInterface(IndividualListModule::class)->first(), 141*0c0910bfSGreg Roach 'family_list_module' => $this->module_service->findByInterface(FamilyListModule::class)->first(), 142*0c0910bfSGreg Roach 'media_list_module' => $this->module_service->findByInterface(MediaListModule::class)->first(), 143*0c0910bfSGreg Roach 'note_list_module' => $this->module_service->findByInterface(NoteListModule::class)->first(), 144*0c0910bfSGreg Roach 'repository_list_module' => $this->module_service->findByInterface(RepositoryListModule::class)->first(), 145*0c0910bfSGreg Roach 'source_list_module' => $this->module_service->findByInterface(SourceListModule::class)->first(), 146*0c0910bfSGreg Roach 'files_to_delete' => $files_to_delete, 147*0c0910bfSGreg Roach 'all_modules_disabled' => $this->module_service->all(true), 148*0c0910bfSGreg Roach 'all_modules_enabled' => $this->module_service->all(), 149*0c0910bfSGreg Roach 'deleted_modules' => $this->module_service->deletedModules(), 150*0c0910bfSGreg Roach 'analytics_modules_disabled' => $this->module_service->findByInterface(ModuleAnalyticsInterface::class, true), 151*0c0910bfSGreg Roach 'analytics_modules_enabled' => $this->module_service->findByInterface(ModuleAnalyticsInterface::class), 152*0c0910bfSGreg Roach 'block_modules_disabled' => $this->module_service->findByInterface(ModuleBlockInterface::class, true), 153*0c0910bfSGreg Roach 'block_modules_enabled' => $this->module_service->findByInterface(ModuleBlockInterface::class), 154*0c0910bfSGreg Roach 'chart_modules_disabled' => $this->module_service->findByInterface(ModuleChartInterface::class, true), 155*0c0910bfSGreg Roach 'chart_modules_enabled' => $this->module_service->findByInterface(ModuleChartInterface::class), 156*0c0910bfSGreg Roach 'other_modules' => $this->module_service->otherModules(true), 157*0c0910bfSGreg Roach 'footer_modules_disabled' => $this->module_service->findByInterface(ModuleFooterInterface::class, true), 158*0c0910bfSGreg Roach 'footer_modules_enabled' => $this->module_service->findByInterface(ModuleFooterInterface::class), 159*0c0910bfSGreg Roach 'history_modules_disabled' => $this->module_service->findByInterface(ModuleHistoricEventsInterface::class, true), 160*0c0910bfSGreg Roach 'history_modules_enabled' => $this->module_service->findByInterface(ModuleHistoricEventsInterface::class), 161*0c0910bfSGreg Roach 'language_modules_disabled' => $this->module_service->findByInterface(ModuleLanguageInterface::class, true), 162*0c0910bfSGreg Roach 'language_modules_enabled' => $this->module_service->findByInterface(ModuleLanguageInterface::class), 163*0c0910bfSGreg Roach 'list_modules_disabled' => $this->module_service->findByInterface(ModuleListInterface::class, true), 164*0c0910bfSGreg Roach 'list_modules_enabled' => $this->module_service->findByInterface(ModuleListInterface::class), 165*0c0910bfSGreg Roach 'menu_modules_disabled' => $this->module_service->findByInterface(ModuleMenuInterface::class, true), 166*0c0910bfSGreg Roach 'menu_modules_enabled' => $this->module_service->findByInterface(ModuleMenuInterface::class), 167*0c0910bfSGreg Roach 'report_modules_disabled' => $this->module_service->findByInterface(ModuleReportInterface::class, true), 168*0c0910bfSGreg Roach 'report_modules_enabled' => $this->module_service->findByInterface(ModuleReportInterface::class), 169*0c0910bfSGreg Roach 'sidebar_modules_disabled' => $this->module_service->findByInterface(ModuleSidebarInterface::class, true), 170*0c0910bfSGreg Roach 'sidebar_modules_enabled' => $this->module_service->findByInterface(ModuleSidebarInterface::class), 171*0c0910bfSGreg Roach 'tab_modules_disabled' => $this->module_service->findByInterface(ModuleTabInterface::class, true), 172*0c0910bfSGreg Roach 'tab_modules_enabled' => $this->module_service->findByInterface(ModuleTabInterface::class), 173*0c0910bfSGreg Roach 'theme_modules_disabled' => $this->module_service->findByInterface(ModuleThemeInterface::class, true), 174*0c0910bfSGreg Roach 'theme_modules_enabled' => $this->module_service->findByInterface(ModuleThemeInterface::class), 175*0c0910bfSGreg Roach ]); 176*0c0910bfSGreg Roach } 177*0c0910bfSGreg Roach 178*0c0910bfSGreg Roach /** 179*0c0910bfSGreg Roach * Count the number of pending changes in each tree. 180*0c0910bfSGreg Roach * 181*0c0910bfSGreg Roach * @return string[] 182*0c0910bfSGreg Roach */ 183*0c0910bfSGreg Roach private function totalChanges(): array 184*0c0910bfSGreg Roach { 185*0c0910bfSGreg Roach return DB::table('gedcom') 186*0c0910bfSGreg Roach ->leftJoin('change', static function (JoinClause $join): void { 187*0c0910bfSGreg Roach $join 188*0c0910bfSGreg Roach ->on('change.gedcom_id', '=', 'gedcom.gedcom_id') 189*0c0910bfSGreg Roach ->where('change.status', '=', 'pending'); 190*0c0910bfSGreg Roach }) 191*0c0910bfSGreg Roach ->groupBy(['gedcom.gedcom_id']) 192*0c0910bfSGreg Roach ->pluck(new Expression('COUNT(change_id)'), 'gedcom.gedcom_id') 193*0c0910bfSGreg Roach ->all(); 194*0c0910bfSGreg Roach } 195*0c0910bfSGreg Roach 196*0c0910bfSGreg Roach /** 197*0c0910bfSGreg Roach * Count the number of individuals in each tree. 198*0c0910bfSGreg Roach * 199*0c0910bfSGreg Roach * @return Collection 200*0c0910bfSGreg Roach */ 201*0c0910bfSGreg Roach private function totalIndividuals(): Collection 202*0c0910bfSGreg Roach { 203*0c0910bfSGreg Roach return DB::table('gedcom') 204*0c0910bfSGreg Roach ->leftJoin('individuals', 'i_file', '=', 'gedcom_id') 205*0c0910bfSGreg Roach ->groupBy(['gedcom_id']) 206*0c0910bfSGreg Roach ->pluck(new Expression('COUNT(i_id)'), 'gedcom_id') 207*0c0910bfSGreg Roach ->map(static function (string $count) { 208*0c0910bfSGreg Roach return (int) $count; 209*0c0910bfSGreg Roach }); 210*0c0910bfSGreg Roach } 211*0c0910bfSGreg Roach 212*0c0910bfSGreg Roach /** 213*0c0910bfSGreg Roach * Count the number of families in each tree. 214*0c0910bfSGreg Roach * 215*0c0910bfSGreg Roach * @return Collection 216*0c0910bfSGreg Roach */ 217*0c0910bfSGreg Roach private function totalFamilies(): Collection 218*0c0910bfSGreg Roach { 219*0c0910bfSGreg Roach return DB::table('gedcom') 220*0c0910bfSGreg Roach ->leftJoin('families', 'f_file', '=', 'gedcom_id') 221*0c0910bfSGreg Roach ->groupBy(['gedcom_id']) 222*0c0910bfSGreg Roach ->pluck(new Expression('COUNT(f_id)'), 'gedcom_id') 223*0c0910bfSGreg Roach ->map(static function (string $count) { 224*0c0910bfSGreg Roach return (int) $count; 225*0c0910bfSGreg Roach }); 226*0c0910bfSGreg Roach } 227*0c0910bfSGreg Roach 228*0c0910bfSGreg Roach /** 229*0c0910bfSGreg Roach * Count the number of sources in each tree. 230*0c0910bfSGreg Roach * 231*0c0910bfSGreg Roach * @return Collection 232*0c0910bfSGreg Roach */ 233*0c0910bfSGreg Roach private function totalSources(): Collection 234*0c0910bfSGreg Roach { 235*0c0910bfSGreg Roach return DB::table('gedcom') 236*0c0910bfSGreg Roach ->leftJoin('sources', 's_file', '=', 'gedcom_id') 237*0c0910bfSGreg Roach ->groupBy(['gedcom_id']) 238*0c0910bfSGreg Roach ->pluck(new Expression('COUNT(s_id)'), 'gedcom_id') 239*0c0910bfSGreg Roach ->map(static function (string $count) { 240*0c0910bfSGreg Roach return (int) $count; 241*0c0910bfSGreg Roach }); 242*0c0910bfSGreg Roach } 243*0c0910bfSGreg Roach 244*0c0910bfSGreg Roach /** 245*0c0910bfSGreg Roach * Count the number of media objects in each tree. 246*0c0910bfSGreg Roach * 247*0c0910bfSGreg Roach * @return Collection 248*0c0910bfSGreg Roach */ 249*0c0910bfSGreg Roach private function totalMediaObjects(): Collection 250*0c0910bfSGreg Roach { 251*0c0910bfSGreg Roach return DB::table('gedcom') 252*0c0910bfSGreg Roach ->leftJoin('media', 'm_file', '=', 'gedcom_id') 253*0c0910bfSGreg Roach ->groupBy(['gedcom_id']) 254*0c0910bfSGreg Roach ->pluck(new Expression('COUNT(m_id)'), 'gedcom_id') 255*0c0910bfSGreg Roach ->map(static function (string $count) { 256*0c0910bfSGreg Roach return (int) $count; 257*0c0910bfSGreg Roach }); 258*0c0910bfSGreg Roach } 259*0c0910bfSGreg Roach 260*0c0910bfSGreg Roach /** 261*0c0910bfSGreg Roach * Count the number of repositorie in each tree. 262*0c0910bfSGreg Roach * 263*0c0910bfSGreg Roach * @return Collection 264*0c0910bfSGreg Roach */ 265*0c0910bfSGreg Roach private function totalRepositories(): Collection 266*0c0910bfSGreg Roach { 267*0c0910bfSGreg Roach return DB::table('gedcom') 268*0c0910bfSGreg Roach ->leftJoin('other', static function (JoinClause $join): void { 269*0c0910bfSGreg Roach $join 270*0c0910bfSGreg Roach ->on('o_file', '=', 'gedcom_id') 271*0c0910bfSGreg Roach ->where('o_type', '=', 'REPO'); 272*0c0910bfSGreg Roach }) 273*0c0910bfSGreg Roach ->groupBy(['gedcom_id']) 274*0c0910bfSGreg Roach ->pluck(new Expression('COUNT(o_id)'), 'gedcom_id') 275*0c0910bfSGreg Roach ->map(static function (string $count) { 276*0c0910bfSGreg Roach return (int) $count; 277*0c0910bfSGreg Roach }); 278*0c0910bfSGreg Roach } 279*0c0910bfSGreg Roach 280*0c0910bfSGreg Roach /** 281*0c0910bfSGreg Roach * Count the number of notes in each tree. 282*0c0910bfSGreg Roach * 283*0c0910bfSGreg Roach * @return Collection 284*0c0910bfSGreg Roach */ 285*0c0910bfSGreg Roach private function totalNotes(): Collection 286*0c0910bfSGreg Roach { 287*0c0910bfSGreg Roach return DB::table('gedcom') 288*0c0910bfSGreg Roach ->leftJoin('other', static function (JoinClause $join): void { 289*0c0910bfSGreg Roach $join 290*0c0910bfSGreg Roach ->on('o_file', '=', 'gedcom_id') 291*0c0910bfSGreg Roach ->where('o_type', '=', 'NOTE'); 292*0c0910bfSGreg Roach }) 293*0c0910bfSGreg Roach ->groupBy(['gedcom_id']) 294*0c0910bfSGreg Roach ->pluck(new Expression('COUNT(o_id)'), 'gedcom_id') 295*0c0910bfSGreg Roach ->map(static function (string $count) { 296*0c0910bfSGreg Roach return (int) $count; 297*0c0910bfSGreg Roach }); 298*0c0910bfSGreg Roach } 299*0c0910bfSGreg Roach} 300