diff options
| author | 2024-06-06 03:58:19 +0900 | |
|---|---|---|
| committer | 2024-06-05 20:58:19 +0200 | |
| commit | 99b1d551e61adb5cbd014677f151f443b0c6c35f (patch) | |
| tree | 852e0cad4c9ad908c1c969a88e290cb05ec5df85 /lib | |
| parent | 4f60a42e6437196b5a67693e0666150bb7d51ae9 (diff) | |
Add core extensions: UserCSS, UserJS (#6267)
* Copy CustomCSS and CustomJS
Original: FreshRSS/Extensions@9f21984
* Rename CustomCSS -> UserCSS
* Rename CustomJS -> UserJS
* Change metadata
The name is used for the directory where the configuration
is stored and should not contain spaces.
Since the name was changed, I reset the version number and
changed to semantic versioning.
* Change data directory
Changed the location of the configuration file to
the user data directory, because it is not `static`.
That way, the user's configurations are gathered
in the user directory, which makes it easier to backup them.
* Edit documentations
Remove procedures to install the extension
because it is no longer necessary.
* Fix wrong variables in the configuration page
Remove permission error indication because the storage location
is now in the user data directory managed by the application.
* Remove the `xExtension-` prefix for core extensions
* Set version to 1.0.0 for UserCSS, UserJS
* Refactoring
* Remove unused variables
* Remove version 0.0.1 in Changelog
Version 0.0.1 will not be merged, so only version 1.0.0 will remain.
* public getFileUrl
* Revert more protected
* Use entrypoint for extension user path instead of name
* Add space to extension name
* Add `#[\Override]`
* Add explains of User CSS and User JS to docs
* Remove README of User CSS and User JS
* Add migration code for extension user path
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Minz/Extension.php | 72 | ||||
| -rw-r--r-- | lib/core-extensions/UserCSS/configure.phtml | 20 | ||||
| -rw-r--r-- | lib/core-extensions/UserCSS/extension.php | 34 | ||||
| -rw-r--r-- | lib/core-extensions/UserCSS/i18n/de/ext.php | 7 | ||||
| -rw-r--r-- | lib/core-extensions/UserCSS/i18n/en/ext.php | 7 | ||||
| -rw-r--r-- | lib/core-extensions/UserCSS/i18n/fr/ext.php | 7 | ||||
| -rw-r--r-- | lib/core-extensions/UserCSS/i18n/ja/ext.php | 7 | ||||
| -rw-r--r-- | lib/core-extensions/UserCSS/metadata.json | 8 | ||||
| -rw-r--r-- | lib/core-extensions/UserJS/configure.phtml | 20 | ||||
| -rw-r--r-- | lib/core-extensions/UserJS/extension.php | 34 | ||||
| -rw-r--r-- | lib/core-extensions/UserJS/i18n/de/ext.php | 7 | ||||
| -rw-r--r-- | lib/core-extensions/UserJS/i18n/en/ext.php | 7 | ||||
| -rw-r--r-- | lib/core-extensions/UserJS/i18n/fr/ext.php | 7 | ||||
| -rw-r--r-- | lib/core-extensions/UserJS/i18n/ja/ext.php | 7 | ||||
| -rw-r--r-- | lib/core-extensions/UserJS/metadata.json | 8 |
15 files changed, 228 insertions, 24 deletions
diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index 15fae77a6..0069e21cb 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -80,7 +80,9 @@ abstract class Minz_Extension { * enabled by the extension manager). * @return void */ - abstract public function init(); + public function init() { + $this->migrateExtensionUserPath(); + } /** * Set the current extension to enable. @@ -118,7 +120,9 @@ abstract class Minz_Extension { * Handle the configure action. * @return void */ - public function handleConfigureAction() {} + public function handleConfigureAction() { + $this->migrateExtensionUserPath(); + } /** * Getters and setters. @@ -154,6 +158,32 @@ abstract class Minz_Extension { $this->type = $type; } + /** Return the user-specific, extension-specific, folder where this extension can save user-specific data */ + protected final function getExtensionUserPath(): string { + $username = Minz_User::name() ?: '_'; + return USERS_PATH . "/{$username}/extensions/{$this->getEntrypoint()}"; + } + + private function migrateExtensionUserPath(): void { + $username = Minz_User::name() ?: '_'; + $old_extension_user_path = USERS_PATH . "/{$username}/extensions/{$this->getName()}"; + $new_extension_user_path = $this->getExtensionUserPath(); + if (is_dir($old_extension_user_path)) { + rename($old_extension_user_path, $new_extension_user_path); + } + } + + /** Return whether a user-specific, extension-specific, file exists */ + protected final function hasFile(string $filename): bool { + return file_exists($this->getExtensionUserPath() . '/' . $filename); + } + + /** Return the user-specific, extension-specific, file content, or null if it does not exist */ + protected final function getFile(string $filename): ?string { + $content = @file_get_contents($this->getExtensionUserPath() . '/' . $filename); + return is_string($content) ? $content : null; + } + /** * Return the url for a given file. * @@ -172,8 +202,8 @@ abstract class Minz_Extension { if ($username == null) { return ''; } - $path = USERS_PATH . "/{$username}/extensions/{$this->getName()}/{$filename}"; - $file_name_url = urlencode("{$username}/extensions/{$this->getName()}/{$filename}"); + $path = $this->getExtensionUserPath() . "/{$filename}"; + $file_name_url = urlencode("{$username}/extensions/{$this->getEntrypoint()}/{$filename}"); $mtime = @filemtime($path); } @@ -185,21 +215,21 @@ abstract class Minz_Extension { * * @param string $base_name the base name of the controller. Final name will be FreshExtension_<base_name>_Controller. */ - public final function registerController(string $base_name): void { + protected final function registerController(string $base_name): void { Minz_Dispatcher::registerController($base_name, $this->path); } /** * Register the views in order to be accessible by the application. */ - public final function registerViews(): void { + protected final function registerViews(): void { Minz_View::addBasePathname($this->path); } /** * Register i18n files from ext_dir/i18n/ */ - public final function registerTranslates(): void { + protected final function registerTranslates(): void { $i18n_dir = $this->path . '/i18n'; Minz_Translate::registerPath($i18n_dir); } @@ -210,7 +240,7 @@ abstract class Minz_Extension { * @param string $hook_name the hook name (must exist). * @param callable $hook_function the function name to call (must be callable). */ - public final function registerHook(string $hook_name, $hook_function): void { + protected final function registerHook(string $hook_name, $hook_function): void { Minz_ExtensionManager::addHook($hook_name, $hook_function); } @@ -249,7 +279,7 @@ abstract class Minz_Extension { /** * @return array<string,mixed> */ - public final function getSystemConfiguration(): array { + protected final function getSystemConfiguration(): array { if ($this->isConfigurationEnabled('system') && $this->isExtensionConfigured('system')) { return FreshRSS_Context::systemConf()->extensions[$this->getName()]; } @@ -259,7 +289,7 @@ abstract class Minz_Extension { /** * @return array<string,mixed> */ - public final function getUserConfiguration(): array { + protected final function getUserConfiguration(): array { if ($this->isConfigurationEnabled('user') && $this->isExtensionConfigured('user')) { return FreshRSS_Context::userConf()->extensions[$this->getName()]; } @@ -324,13 +354,13 @@ abstract class Minz_Extension { } /** @param array<string,mixed> $configuration */ - public final function setSystemConfiguration(array $configuration): void { + protected final function setSystemConfiguration(array $configuration): void { $this->setConfiguration('system', $configuration); $this->system_configuration = $configuration; } /** @param array<string,mixed> $configuration */ - public final function setUserConfiguration(array $configuration): void { + protected final function setUserConfiguration(array $configuration): void { $this->setConfiguration('user', $configuration); $this->user_configuration = $configuration; } @@ -361,19 +391,18 @@ abstract class Minz_Extension { $conf->save(); } - public final function removeSystemConfiguration(): void { + protected final function removeSystemConfiguration(): void { $this->removeConfiguration('system'); $this->system_configuration = null; } - public final function removeUserConfiguration(): void { + protected final function removeUserConfiguration(): void { $this->removeConfiguration('user'); $this->user_configuration = null; } - public final function saveFile(string $filename, string $content): void { - $username = Minz_User::name(); - $path = USERS_PATH . "/{$username}/extensions/{$this->getName()}"; + protected final function saveFile(string $filename, string $content): void { + $path = $this->getExtensionUserPath(); if (!file_exists($path)) { mkdir($path, 0777, true); @@ -382,13 +411,8 @@ abstract class Minz_Extension { file_put_contents("{$path}/{$filename}", $content); } - public final function removeFile(string $filename): void { - $username = Minz_User::name(); - if ($username == null) { - return; - } - $path = USERS_PATH . "/{$username}/extensions/{$this->getName()}/{$filename}"; - + protected final function removeFile(string $filename): void { + $path = $path = $this->getExtensionUserPath() . '/' . $filename; if (file_exists($path)) { unlink($path); } diff --git a/lib/core-extensions/UserCSS/configure.phtml b/lib/core-extensions/UserCSS/configure.phtml new file mode 100644 index 000000000..22d4ea79a --- /dev/null +++ b/lib/core-extensions/UserCSS/configure.phtml @@ -0,0 +1,20 @@ +<?php + declare(strict_types=1); + /** @var UserCSSExtension $this */ +?> +<form action="<?= _url('extension', 'configure', 'e', urlencode($this->getName())); ?>" method="post"> + <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" /> + <div class="form-group"> + <label class="group-name" for="css-rules"><?= _t('ext.user_css.write_css') ?></label> + <div class="group-controls"> + <textarea name="css-rules" id="css-rules"><?= $this->css_rules ?></textarea> + </div> + </div> + + <div class="form-group form-actions"> + <div class="group-controls"> + <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button> + <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button> + </div> + </div> +</form> diff --git a/lib/core-extensions/UserCSS/extension.php b/lib/core-extensions/UserCSS/extension.php new file mode 100644 index 000000000..5343fd39a --- /dev/null +++ b/lib/core-extensions/UserCSS/extension.php @@ -0,0 +1,34 @@ +<?php +declare(strict_types=1); + +final class UserCSSExtension extends Minz_Extension { + public string $css_rules = ''; + private const FILENAME = 'style.css'; + + #[\Override] + public function init(): void { + parent::init(); + + $this->registerTranslates(); + if ($this->hasFile(self::FILENAME)) { + Minz_View::appendStyle($this->getFileUrl(self::FILENAME, 'css', false)); + } + } + + #[\Override] + public function handleConfigureAction(): void { + parent::init(); + + $this->registerTranslates(); + + if (Minz_Request::isPost()) { + $css_rules = html_entity_decode(Minz_Request::paramString('css-rules')); + $this->saveFile(self::FILENAME, $css_rules); + } + + $this->css_rules = ''; + if ($this->hasFile(self::FILENAME)) { + $this->css_rules = htmlentities($this->getFile(self::FILENAME) ?? ''); + } + } +} diff --git a/lib/core-extensions/UserCSS/i18n/de/ext.php b/lib/core-extensions/UserCSS/i18n/de/ext.php new file mode 100644 index 000000000..cafc5f2f0 --- /dev/null +++ b/lib/core-extensions/UserCSS/i18n/de/ext.php @@ -0,0 +1,7 @@ +<?php + +return array( + 'user_css' => array( + 'write_css' => 'Benutzerspezifische CSS Regeln', + ), +); diff --git a/lib/core-extensions/UserCSS/i18n/en/ext.php b/lib/core-extensions/UserCSS/i18n/en/ext.php new file mode 100644 index 000000000..b82cd8331 --- /dev/null +++ b/lib/core-extensions/UserCSS/i18n/en/ext.php @@ -0,0 +1,7 @@ +<?php + +return array( + 'user_css' => array( + 'write_css' => 'Additional CSS rules', + ), +); diff --git a/lib/core-extensions/UserCSS/i18n/fr/ext.php b/lib/core-extensions/UserCSS/i18n/fr/ext.php new file mode 100644 index 000000000..507d8be45 --- /dev/null +++ b/lib/core-extensions/UserCSS/i18n/fr/ext.php @@ -0,0 +1,7 @@ +<?php + +return array( + 'user_css' => array( + 'write_css' => 'Règles CSS supplémentaires', + ), +); diff --git a/lib/core-extensions/UserCSS/i18n/ja/ext.php b/lib/core-extensions/UserCSS/i18n/ja/ext.php new file mode 100644 index 000000000..ce8d17c78 --- /dev/null +++ b/lib/core-extensions/UserCSS/i18n/ja/ext.php @@ -0,0 +1,7 @@ +<?php + +return array( + 'user_css' => array( + 'write_css' => '追加のCSSルール', + ), +); diff --git a/lib/core-extensions/UserCSS/metadata.json b/lib/core-extensions/UserCSS/metadata.json new file mode 100644 index 000000000..2de79af8c --- /dev/null +++ b/lib/core-extensions/UserCSS/metadata.json @@ -0,0 +1,8 @@ +{ + "name": "User CSS", + "author": "hkcomori, Marien Fressinaud", + "description": "Give possibility to overwrite the CSS with a user-specific rules.", + "version": "1.0.0", + "entrypoint": "UserCSS", + "type": "user" +} diff --git a/lib/core-extensions/UserJS/configure.phtml b/lib/core-extensions/UserJS/configure.phtml new file mode 100644 index 000000000..88172679d --- /dev/null +++ b/lib/core-extensions/UserJS/configure.phtml @@ -0,0 +1,20 @@ +<?php + declare(strict_types=1); + /** @var UserJSExtension $this */ +?> +<form action="<?= _url('extension', 'configure', 'e', urlencode($this->getName())) ?>" method="post"> + <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" /> + <div class="form-group"> + <label class="group-name" for="js-rules"><?= _t('ext.user_js.write_js') ?></label> + <div class="group-controls"> + <textarea name="js-rules" id="js-rules"><?= $this->js_rules ?></textarea> + </div> + </div> + + <div class="form-group form-actions"> + <div class="group-controls"> + <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button> + <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button> + </div> + </div> +</form> diff --git a/lib/core-extensions/UserJS/extension.php b/lib/core-extensions/UserJS/extension.php new file mode 100644 index 000000000..a33114ec5 --- /dev/null +++ b/lib/core-extensions/UserJS/extension.php @@ -0,0 +1,34 @@ +<?php +declare(strict_types=1); + +final class UserJSExtension extends Minz_Extension { + public string $js_rules = ''; + private const FILENAME = 'script.js'; + + #[\Override] + public function init(): void { + parent::init(); + + $this->registerTranslates(); + if ($this->hasFile(self::FILENAME)) { + Minz_View::appendScript($this->getFileUrl(self::FILENAME, 'js', false)); + } + } + + #[\Override] + public function handleConfigureAction(): void { + parent::init(); + + $this->registerTranslates(); + + if (Minz_Request::isPost()) { + $js_rules = html_entity_decode(Minz_Request::paramString('js-rules')); + $this->saveFile(self::FILENAME, $js_rules); + } + + $this->js_rules = ''; + if ($this->hasFile(self::FILENAME)) { + $this->js_rules = htmlentities($this->getFile(self::FILENAME) ?? ''); + } + } +} diff --git a/lib/core-extensions/UserJS/i18n/de/ext.php b/lib/core-extensions/UserJS/i18n/de/ext.php new file mode 100644 index 000000000..be57c7553 --- /dev/null +++ b/lib/core-extensions/UserJS/i18n/de/ext.php @@ -0,0 +1,7 @@ +<?php + +return array( + 'user_js' => array( + 'write_js' => 'Benutzerspezifische Javascript Regeln', + ), +); diff --git a/lib/core-extensions/UserJS/i18n/en/ext.php b/lib/core-extensions/UserJS/i18n/en/ext.php new file mode 100644 index 000000000..1217a46fa --- /dev/null +++ b/lib/core-extensions/UserJS/i18n/en/ext.php @@ -0,0 +1,7 @@ +<?php + +return array( + 'user_js' => array( + 'write_js' => 'Additional JS', + ), +); diff --git a/lib/core-extensions/UserJS/i18n/fr/ext.php b/lib/core-extensions/UserJS/i18n/fr/ext.php new file mode 100644 index 000000000..c12e919d0 --- /dev/null +++ b/lib/core-extensions/UserJS/i18n/fr/ext.php @@ -0,0 +1,7 @@ +<?php + +return array( + 'user_js' => array( + 'write_js' => 'JS supplémentaires', + ), +); diff --git a/lib/core-extensions/UserJS/i18n/ja/ext.php b/lib/core-extensions/UserJS/i18n/ja/ext.php new file mode 100644 index 000000000..390ff6a2f --- /dev/null +++ b/lib/core-extensions/UserJS/i18n/ja/ext.php @@ -0,0 +1,7 @@ +<?php + +return array( + 'user_js' => array( + 'write_js' => '追加のJS', + ), +); diff --git a/lib/core-extensions/UserJS/metadata.json b/lib/core-extensions/UserJS/metadata.json new file mode 100644 index 000000000..d38958801 --- /dev/null +++ b/lib/core-extensions/UserJS/metadata.json @@ -0,0 +1,8 @@ +{ + "name": "User JS", + "author": "hkcomori, Frans de Jonge", + "description": "Apply user JS.", + "version": "1.0.0", + "entrypoint": "UserJS", + "type": "user" +} |
