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
".concat(lychee.locale["JS_TEXT"], "
\n\t\t\t\n\t\t\t \n\t\t\t