diff --git a/app/Http/Controllers/Administration/SettingsController.php b/app/Http/Controllers/Administration/SettingsController.php index 6307be8cce3..50b167c63cb 100644 --- a/app/Http/Controllers/Administration/SettingsController.php +++ b/app/Http/Controllers/Administration/SettingsController.php @@ -8,6 +8,7 @@ use App\Http\Requests\Settings\GetSetAllSettingsRequest; use App\Http\Requests\Settings\SetAlbumDecorationRequest; use App\Http\Requests\Settings\SetCSSSettingRequest; +use App\Http\Requests\Settings\SetJSSettingRequest; use App\Http\Requests\Settings\SetDefaultLicenseSettingRequest; use App\Http\Requests\Settings\SetDropboxKeySettingRequest; use App\Http\Requests\Settings\SetImageOverlaySettingRequest; @@ -333,6 +334,26 @@ public function setCSS(SetCSSSettingRequest $request): void } } + /** + * Takes the js input text and put it into `dist/custom.js`. + * This allows admins to actually execute custom js code on their + * Lychee-Laravel installation. + * + * @param SetJSSettingRequest $request + * + * @return void + * + * @throws InsufficientFilesystemPermissions + */ + public function setJS(SetJSSettingRequest $request): void + { + /** @var string $js */ + $js = $request->getSettingValue(); + if (Storage::disk('dist')->put('custom.js', $js) === false) { + throw new InsufficientFilesystemPermissions('Could not save JS'); + } + } + /** * Returns ALL settings. This is not filtered! * Fortunately, this is behind an admin middleware. diff --git a/app/Http/Requests/Settings/SetJSSettingRequest.php b/app/Http/Requests/Settings/SetJSSettingRequest.php new file mode 100644 index 00000000000..34392edc2de --- /dev/null +++ b/app/Http/Requests/Settings/SetJSSettingRequest.php @@ -0,0 +1,25 @@ + 'present|nullable|string']; + } + + /** + * {@inheritDoc} + */ + protected function processValidatedValues(array $values, array $files): void + { + $this->name = self::ATTRIBUTE; + $this->value = $values[self::ATTRIBUTE] ?? ''; + } +} \ No newline at end of file diff --git a/public/Lychee-front b/public/Lychee-front index 8e446585b2c..80ea38b07e7 160000 --- a/public/Lychee-front +++ b/public/Lychee-front @@ -1 +1 @@ -Subproject commit 8e446585b2ca179fec84421631c445fba1ee6e6e +Subproject commit 80ea38b07e78d83172509648faae12f1a805cf13 diff --git a/public/dist/custom.js b/public/dist/custom.js new file mode 100644 index 00000000000..cfee9c298ed --- /dev/null +++ b/public/dist/custom.js @@ -0,0 +1 @@ +console.log('sosua'); \ No newline at end of file diff --git a/public/dist/frontend.js b/public/dist/frontend.js index d3f396036a7..01916fabcfd 100644 --- a/public/dist/frontend.js +++ b/public/dist/frontend.js @@ -1166,6 +1166,44 @@ api.getCSS = function (url, callback) { error: errorHandler }); }; + +/** + * + * @param {string} url + * @param {APISuccessCB} callback + * @returns {void} + */ +api.getJS = function (url, callback) { + loadingBar.show(); + + /** + * The success handler + * @param {Object} data the decoded JSON object of the response + */ + var successHandler = function successHandler(data) { + setTimeout(loadingBar.hide, 100); + callback(data); + }; + + /** + * The error handler + * @param {XMLHttpRequest} jqXHR the jQuery XMLHttpRequest object, see {@link https://api.jquery.com/jQuery.ajax/#jqXHR}. + */ + var errorHandler = function errorHandler(jqXHR) { + api.onError(jqXHR, {}, null); + }; + $.ajax({ + type: "GET", + url: url, + data: {}, + dataType: "text", + headers: { + "X-XSRF-TOKEN": csrf.getCSRFCookieValue() + }, + success: successHandler, + error: errorHandler + }); +}; var csrf = {}; /** @@ -6087,7 +6125,7 @@ lychee.localizeStaticGuiElements = function () { // Footer var footer = document.querySelector("#lychee_footer"); footer.querySelector("p.home_copyright").textContent = lychee.footer_show_copyright ? sprintf(lychee.locale["FOOTER_COPYRIGHT"], lychee.site_owner, lychee.site_copyright_begin === lychee.site_copyright_end ? lychee.site_copyright_begin : lychee.site_copyright_begin + "–" + lychee.site_copyright_end) : ""; - footer.querySelector("p.personal_text").innerHTML = lychee.footer_additional_text; + footer.querySelector("p.personal_text").textContent = lychee.footer_additional_text; footer.querySelector("p.hosted_by a").textContent = lychee.locale["HOSTED_WITH_LYCHEE"]; /** @type {HTMLDivElement} */ var footerSocialMedia = footer.querySelector("div#home_socials"); @@ -7421,6 +7459,7 @@ lychee.locale = { SETTINGS_SUCCESS_MAP_DISPLAY_PUBLIC: "Map display settings for public albums updated", SETTINGS_SUCCESS_MAP_PROVIDER: "Map provider settings updated", SETTINGS_SUCCESS_CSS: "CSS updated", + SETTINGS_SUCCESS_JS: "JS updated", SETTINGS_SUCCESS_UPDATE: "Settings updated successfully", SETTINGS_DROPBOX_KEY: "Dropbox API Key", SETTINGS_ADVANCED_WARNING_EXPL: "Changing these advanced settings can be harmful to the stability, security and performance of this application. You should only modify them if you are sure of what you are doing.", @@ -7471,6 +7510,8 @@ lychee.locale = { LANG_TITLE: "Change Language", CSS_TEXT: "Personalize CSS:", CSS_TITLE: "Change CSS", + JS_TEXT: "Custom JS:", + JS_TITLE: "Change JS", PUBLIC_SEARCH_TEXT: "Public search allowed:", OVERLAY_TYPE: "Photo overlay:", OVERLAY_NONE: "None", @@ -10277,6 +10318,19 @@ settings.changeCSS = function () { }); }; +/** + * @returns {void} + */ +settings.changeJS = function () { + var params = { + js: $("#js").val() + }; + api.post("Settings::setJS", params, function () { + lychee.js = params.js; + loadingBar.show("success", lychee.locale["SETTINGS_SUCCESS_JS"]); + }); +}; + /** * @param {SettingsFormData} params * @returns {void} @@ -13705,6 +13759,7 @@ view.settings = { view.settings.content.setNSFWVisible(); view.settings.content.setNotification(); view.settings.content.setCSS(); + view.settings.content.setJS(); view.settings.content.moreButton(); } }, @@ -13881,11 +13936,22 @@ view.settings = { }); settings.bind("#basicModal__action_set_css", ".setCSS", settings.changeCSS); }, + /** + * @returns {void} + */ + setJS: function setJS() { + var msg = "\n\t\t\t
\n\t\t\t

".concat(lychee.locale["JS_TEXT"], "

\n\t\t\t\n\t\t\t
\n\t\t\t\t").concat(lychee.locale["JS_TITLE"], "\n\t\t\t
\n\t\t\t
"); + $(".settings_view").append(msg); + api.getJS("dist/custom.js", function (data) { + $("#js").html(data); + }); + settings.bind("#basicModal__action_set_js", ".setJS", settings.changeJS); + }, /** * @returns {void} */ moreButton: function moreButton() { - var msg = lychee.html(_templateObject61 || (_templateObject61 = _taggedTemplateLiteral(["\n\t\t\t
\n\t\t\t\t", "\n\t\t\t
\n\t\t\t"])), lychee.locale["MORE"]); + var msg = lychee.html(_templateObject61 || (_templateObject61 = _taggedTemplateLiteral(["\n\t\t\t
\n\t\t\t\t", "\n\t\t\t
\n\t\t\t"])), lychee.locale["MORE"]); $(".settings_view").append(msg); $("#basicModal__action_more").on("click", view.full_settings.init); } diff --git a/routes/api.php b/routes/api.php index ab399c463db..c9184aacbf6 100644 --- a/routes/api.php +++ b/routes/api.php @@ -174,6 +174,7 @@ Route::post('/Settings::setLocationShow', [Administration\SettingsController::class, 'setLocationShow']); Route::post('/Settings::setLocationShowPublic', [Administration\SettingsController::class, 'setLocationShowPublic']); Route::post('/Settings::setCSS', [Administration\SettingsController::class, 'setCSS']); +Route::post('/Settings::setJS', [Administration\SettingsController::class, 'setJS']); Route::post('/Settings::getAll', [Administration\SettingsController::class, 'getAll']); Route::post('/Settings::saveAll', [Administration\SettingsController::class, 'saveAll']); Route::post('/Settings::setAlbumDecoration', [Administration\SettingsController::class, 'setAlbumDecoration']); diff --git a/scripts/install_files.php b/scripts/install_files.php index 09c36bb5b09..132b6095df5 100644 --- a/scripts/install_files.php +++ b/scripts/install_files.php @@ -13,6 +13,9 @@ echo "\n{$YELLOW}creating file for CSS personalization$NO_COLOR" . PHP_EOL; touch('public/dist/user.css'); +echo "\n{$YELLOW}creating file for JS personalization$NO_COLOR" . PHP_EOL; +touch('public/dist/custom.js'); + echo "\n{$YELLOW}creating default SQLite database$NO_COLOR" . PHP_EOL; touch('database/database.sqlite'); @@ -23,4 +26,4 @@ } echo "\n{$ORANGE}To disable the call of composer and migration on pull add$NO_COLOR" . PHP_EOL; -echo "{$ORANGE}a file named '.NO_AUTO_COMPOSER_MIGRATE' in this directory.$NO_COLOR" . PHP_EOL; +echo "{$ORANGE}a file named '.NO_AUTO_COMPOSER_MIGRATE' in this directory.$NO_COLOR" . PHP_EOL; \ No newline at end of file