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