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