aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGravatar hkcomori <hkcomori@gmail.com> 2024-06-06 03:58:19 +0900
committerGravatar GitHub <noreply@github.com> 2024-06-05 20:58:19 +0200
commit99b1d551e61adb5cbd014677f151f443b0c6c35f (patch)
tree852e0cad4c9ad908c1c969a88e290cb05ec5df85 /lib
parent4f60a42e6437196b5a67693e0666150bb7d51ae9 (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.php72
-rw-r--r--lib/core-extensions/UserCSS/configure.phtml20
-rw-r--r--lib/core-extensions/UserCSS/extension.php34
-rw-r--r--lib/core-extensions/UserCSS/i18n/de/ext.php7
-rw-r--r--lib/core-extensions/UserCSS/i18n/en/ext.php7
-rw-r--r--lib/core-extensions/UserCSS/i18n/fr/ext.php7
-rw-r--r--lib/core-extensions/UserCSS/i18n/ja/ext.php7
-rw-r--r--lib/core-extensions/UserCSS/metadata.json8
-rw-r--r--lib/core-extensions/UserJS/configure.phtml20
-rw-r--r--lib/core-extensions/UserJS/extension.php34
-rw-r--r--lib/core-extensions/UserJS/i18n/de/ext.php7
-rw-r--r--lib/core-extensions/UserJS/i18n/en/ext.php7
-rw-r--r--lib/core-extensions/UserJS/i18n/fr/ext.php7
-rw-r--r--lib/core-extensions/UserJS/i18n/ja/ext.php7
-rw-r--r--lib/core-extensions/UserJS/metadata.json8
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"
+}