xref: /webtrees/app/Module/ModuleCustomTrait.php (revision 9ef73392e918bb739aaf4bae10ef7ee867ad703d)
1<?php
2/**
3 * webtrees: online genealogy
4 * Copyright (C) 2019 webtrees development team
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16declare(strict_types=1);
17
18namespace Fisharebest\Webtrees\Module;
19
20use Fisharebest\Webtrees\Carbon;
21use Illuminate\Support\Str;
22use Symfony\Component\HttpFoundation\Request;
23use Symfony\Component\HttpFoundation\Response;
24use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
25use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
26
27/**
28 * Trait ModuleCustomTrait - default implementation of ModuleCustomInterface
29 */
30trait ModuleCustomTrait
31{
32    /**
33     * The person or organisation who created this module.
34     *
35     * @return string
36     */
37    public function customModuleAuthorName(): string
38    {
39        return '';
40    }
41
42    /**
43     * The version of this module.
44     *
45     * @return string  e.g. '1.2.3'
46     */
47    public function customModuleVersion(): string
48    {
49        return '';
50    }
51
52    /**
53     * A URL that will provide the latest version of this module.
54     *
55     * @return string
56     */
57    public function customModuleLatestVersionUrl(): string
58    {
59        return '';
60    }
61
62    /**
63     * Where to get support for this module.  Perhaps a github respository?
64     *
65     * @return string
66     */
67    public function customModuleSupportUrl(): string
68    {
69        return '';
70    }
71
72    /**
73     * Additional/updated translations.
74     *
75     * @param string $language
76     *
77     * @return string[]
78     */
79    public function customTranslations(string $language): array
80    {
81        return [];
82    }
83
84
85    /**
86     * Where does this module store its resources
87     *
88     * @return string
89     */
90    public function resourceFolder(): string
91    {
92        return WT_ROOT . 'resources/';
93    }
94
95    /**
96     * Create a URL for an asset.
97     *
98     * @param string $asset e.g. "css/theme.css" or "img/banner.png"
99     *
100     * @return string
101     */
102    public function assetUrl(string $asset): string
103    {
104        $file = $this->resourceFolder() . $asset;
105
106        // Add the file's modification time to the URL, so we can set long expiry cache headers.
107        $hash = filemtime($file);
108
109        return route('module', [
110            'module' => $this->name(),
111            'action' => 'asset',
112            'asset'  => $asset,
113            'hash'   => $hash,
114        ]);
115    }
116
117    /**
118     * Serve a CSS/JS file.
119     *
120     * @param Request $request
121     *
122     * @return Response
123     */
124    public function getAssetAction(Request $request): Response
125    {
126        // The file being requested.  e.g. "css/theme.css"
127        $asset = $request->get('asset');
128
129        // Do not allow requests that try to access parent folders.
130        if (Str::contains($asset, '..')) {
131            throw new AccessDeniedHttpException($asset);
132        }
133
134        // Find the file for this asset.
135        // Note that we could also generate CSS files using views/templates.
136        // e.g. $file = view(....
137        $file = $this->resourceFolder() . $asset;
138
139        if (!file_exists($file)) {
140            throw new NotFoundHttpException($file);
141        }
142
143        $content     = file_get_contents($file);
144        $expiry_date = Carbon::now()->addYears(10);
145
146        $extension = pathinfo($asset, PATHINFO_EXTENSION);
147
148        $mime_types = [
149            'css'  => 'text/css',
150            'gif'  => 'image/gif',
151            'js'   => 'application/javascript',
152            'jpg'  => 'image/jpg',
153            'jpeg' => 'image/jpg',
154            'json' => 'application/json',
155            'png'  => 'image/png',
156            'txt'  => 'text/plain',
157        ];
158
159        $mime_type = $mime_types[$extension] ?? 'application/octet-stream';
160
161        $headers = [
162            'Content-Type' => $mime_type,
163        ];
164
165        $response = new Response($content, Response::HTTP_OK, $headers);
166
167        return $response
168            ->setExpires($expiry_date);
169    }
170}
171