From 8403d7e14ded801c3842a9b3fd87c3f6824c519e Mon Sep 17 00:00:00 2001 From: Elias Schneider Date: Wed, 8 Mar 2023 14:47:41 +0100 Subject: [PATCH] feat: ability to change logo in frontend --- README.md | 13 +- backend/package-lock.json | 463 +++++++++++++++++- backend/package.json | 3 + backend/src/config/config.controller.ts | 21 + backend/src/config/config.module.ts | 2 + backend/src/config/logo.service.ts | 32 ++ .../public/img/icons/icon-white-128x128.png | Bin 4364 -> 0 bytes frontend/public/img/opengraph.png | Bin 11799 -> 0 bytes .../admin/configuration/LogoConfigInput.tsx | 39 ++ frontend/src/pages/_document.tsx | 8 +- .../src/pages/admin/config/[category].tsx | 38 +- frontend/src/pages/admin/config/index.tsx | 15 - frontend/src/services/config.service.ts | 7 + 13 files changed, 596 insertions(+), 45 deletions(-) create mode 100644 backend/src/config/logo.service.ts delete mode 100644 frontend/public/img/icons/icon-white-128x128.png delete mode 100644 frontend/public/img/opengraph.png create mode 100644 frontend/src/components/admin/configuration/LogoConfigInput.tsx delete mode 100644 frontend/src/pages/admin/config/index.tsx diff --git a/README.md b/README.md index 6ad3014..e184339 100644 --- a/README.md +++ b/README.md @@ -96,18 +96,7 @@ docker compose up -d ### Custom branding -#### Name - -You can change the name of the app by visiting the admin configuration page and changing the `App Name`. - -#### Logo - -You can change the logo of the app by replacing the images in the `/data/images` (or with the standalone installation `/frontend/public/img`) folder with your own logo. The folder contains the following images: - -- `logo.png` - The logo in the header and home page -- `favicon.png` - The favicon -- `opengraph.png` - The image used for sharing on social media -- `icons/*` - The icons used for the PWA +You can change the name and the logo of the app by visiting the admin configuration page. ## 🖤 Contribute diff --git a/backend/package-lock.json b/backend/package-lock.json index 3b7e225..3b9aa91 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -37,6 +37,7 @@ "reflect-metadata": "^0.1.13", "rimraf": "^4.0.4", "rxjs": "^7.8.0", + "sharp": "^0.31.3", "ts-node": "^10.9.1" }, "devDependencies": { @@ -49,10 +50,12 @@ "@types/cron": "^2.0.0", "@types/express": "^4.17.15", "@types/mime-types": "^2.1.1", + "@types/multer": "^1.4.7", "@types/node": "^18.11.18", "@types/nodemailer": "^6.4.7", "@types/passport-jwt": "^3.0.8", "@types/qrcode-svg": "^1.1.1", + "@types/sharp": "^0.31.1", "@types/supertest": "^2.0.12", "@typescript-eslint/eslint-plugin": "^5.48.1", "@typescript-eslint/parser": "^5.48.1", @@ -1262,6 +1265,15 @@ "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", "dev": true }, + "node_modules/@types/multer": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", + "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/node": { "version": "18.11.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", @@ -1346,6 +1358,15 @@ "@types/node": "*" } }, + "node_modules/@types/sharp": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@types/sharp/-/sharp-0.31.1.tgz", + "integrity": "sha512-5nWwamN9ZFHXaYEincMSuza8nNfOof8nmO+mcI+Agx1uMUk4/pQnNIcix+9rLPXzKrm1pS34+6WRDbDV0Jn7ag==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/superagent": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.15.tgz", @@ -2495,6 +2516,18 @@ "node": ">=0.8" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2511,6 +2544,15 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -2813,6 +2855,28 @@ } } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3338,6 +3402,14 @@ "node": ">=0.8.x" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, "node_modules/express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -3856,6 +3928,11 @@ "assert-plus": "^1.0.0" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -4196,6 +4273,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, "node_modules/inquirer": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", @@ -4908,6 +4990,17 @@ "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4961,6 +5054,11 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -4980,6 +5078,11 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -5104,6 +5207,17 @@ "node": ">=10" } }, + "node_modules/node-abi": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.33.0.tgz", + "integrity": "sha512-7GGVawqyHF4pfd0YFybhv/eM9JwTtPqx0mAanQ146O3FlSh3pA24zf9IRQTOsfTSqXTNzPSP5iagAJ94jjuVog==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/node-abort-controller": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", @@ -5848,6 +5962,31 @@ "node": ">=10" } }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -5943,7 +6082,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -6031,6 +6169,28 @@ "node": ">= 0.8" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -6421,6 +6581,28 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/sharp": { + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.31.3.tgz", + "integrity": "sha512-XcR4+FCLBFKw1bdB+GEhnUNXNXvnt0tDo4WsBsraKymuo/IAuPuCBVAL2wIkUw2r/dwFW5Q5+g66Kwl2dgDFVg==", + "hasInstallScript": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.1", + "node-addon-api": "^5.0.0", + "prebuild-install": "^7.1.1", + "semver": "^7.3.8", + "simple-get": "^4.0.1", + "tar-fs": "^2.1.1", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6477,6 +6659,62 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -6709,6 +6947,22 @@ "node": ">= 10" } }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, "node_modules/tar-stream": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", @@ -7068,6 +7322,17 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", @@ -8523,6 +8788,15 @@ "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", "dev": true }, + "@types/multer": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", + "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, "@types/node": { "version": "18.11.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", @@ -8607,6 +8881,15 @@ "@types/node": "*" } }, + "@types/sharp": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@types/sharp/-/sharp-0.31.1.tgz", + "integrity": "sha512-5nWwamN9ZFHXaYEincMSuza8nNfOof8nmO+mcI+Agx1uMUk4/pQnNIcix+9rLPXzKrm1pS34+6WRDbDV0Jn7ag==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/superagent": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.15.tgz", @@ -9457,6 +9740,15 @@ "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true }, + "color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "requires": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -9470,6 +9762,15 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -9698,6 +9999,19 @@ "ms": "2.1.2" } }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -10092,6 +10406,11 @@ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, "express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -10501,6 +10820,11 @@ "assert-plus": "^1.0.0" } }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -10746,6 +11070,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, "inquirer": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", @@ -11302,6 +11631,11 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -11340,6 +11674,11 @@ "minimist": "^1.2.6" } }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -11356,6 +11695,11 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -11453,6 +11797,14 @@ } } }, + "node-abi": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.33.0.tgz", + "integrity": "sha512-7GGVawqyHF4pfd0YFybhv/eM9JwTtPqx0mAanQ146O3FlSh3pA24zf9IRQTOsfTSqXTNzPSP5iagAJ94jjuVog==", + "requires": { + "semver": "^7.3.5" + } + }, "node-abort-controller": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", @@ -12008,6 +12360,25 @@ "punycode": "^2.1.1" } }, + "prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -12071,7 +12442,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -12127,6 +12497,24 @@ "unpipe": "1.0.0" } }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" + } + } + }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -12423,6 +12811,21 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "sharp": { + "version": "0.31.3", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.31.3.tgz", + "integrity": "sha512-XcR4+FCLBFKw1bdB+GEhnUNXNXvnt0tDo4WsBsraKymuo/IAuPuCBVAL2wIkUw2r/dwFW5Q5+g66Kwl2dgDFVg==", + "requires": { + "color": "^4.2.3", + "detect-libc": "^2.0.1", + "node-addon-api": "^5.0.0", + "prebuild-install": "^7.1.1", + "semver": "^7.3.8", + "simple-get": "^4.0.1", + "tar-fs": "^2.1.1", + "tunnel-agent": "^0.6.0" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -12464,6 +12867,36 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -12644,6 +13077,24 @@ } } }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + }, + "dependencies": { + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + } + } + }, "tar-stream": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", @@ -12891,6 +13342,14 @@ } } }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", diff --git a/backend/package.json b/backend/package.json index 4b02023..c12ef09 100644 --- a/backend/package.json +++ b/backend/package.json @@ -42,6 +42,7 @@ "reflect-metadata": "^0.1.13", "rimraf": "^4.0.4", "rxjs": "^7.8.0", + "sharp": "^0.31.3", "ts-node": "^10.9.1" }, "devDependencies": { @@ -54,10 +55,12 @@ "@types/cron": "^2.0.0", "@types/express": "^4.17.15", "@types/mime-types": "^2.1.1", + "@types/multer": "^1.4.7", "@types/node": "^18.11.18", "@types/nodemailer": "^6.4.7", "@types/passport-jwt": "^3.0.8", "@types/qrcode-svg": "^1.1.1", + "@types/sharp": "^0.31.1", "@types/supertest": "^2.0.12", "@typescript-eslint/eslint-plugin": "^5.48.1", "@typescript-eslint/parser": "^5.48.1", diff --git a/backend/src/config/config.controller.ts b/backend/src/config/config.controller.ts index 486ac2e..683c0bf 100644 --- a/backend/src/config/config.controller.ts +++ b/backend/src/config/config.controller.ts @@ -1,12 +1,17 @@ import { Body, Controller, + FileTypeValidator, Get, Param, + ParseFilePipe, Patch, Post, + UploadedFile, UseGuards, + UseInterceptors, } from "@nestjs/common"; +import { FileInterceptor } from "@nestjs/platform-express"; import { SkipThrottle } from "@nestjs/throttler"; import { AdministratorGuard } from "src/auth/guard/isAdmin.guard"; import { JwtGuard } from "src/auth/guard/jwt.guard"; @@ -16,11 +21,13 @@ import { AdminConfigDTO } from "./dto/adminConfig.dto"; import { ConfigDTO } from "./dto/config.dto"; import { TestEmailDTO } from "./dto/testEmail.dto"; import UpdateConfigDTO from "./dto/updateConfig.dto"; +import { LogoService } from "./logo.service"; @Controller("configs") export class ConfigController { constructor( private configService: ConfigService, + private logoService: LogoService, private emailService: EmailService ) {} @@ -51,4 +58,18 @@ export class ConfigController { async testEmail(@Body() { email }: TestEmailDTO) { await this.emailService.sendTestMail(email); } + + @Post("admin/logo") + @UseInterceptors(FileInterceptor("file")) + @UseGuards(JwtGuard, AdministratorGuard) + async uploadLogo( + @UploadedFile( + new ParseFilePipe({ + validators: [new FileTypeValidator({ fileType: "image/png" })], + }) + ) + file: Express.Multer.File + ) { + return await this.logoService.create(file.buffer); + } } diff --git a/backend/src/config/config.module.ts b/backend/src/config/config.module.ts index c6f3140..5a84b24 100644 --- a/backend/src/config/config.module.ts +++ b/backend/src/config/config.module.ts @@ -3,6 +3,7 @@ import { EmailModule } from "src/email/email.module"; import { PrismaService } from "src/prisma/prisma.service"; import { ConfigController } from "./config.controller"; import { ConfigService } from "./config.service"; +import { LogoService } from "./logo.service"; @Global() @Module({ @@ -16,6 +17,7 @@ import { ConfigService } from "./config.service"; inject: [PrismaService], }, ConfigService, + LogoService, ], controllers: [ConfigController], exports: [ConfigService], diff --git a/backend/src/config/logo.service.ts b/backend/src/config/logo.service.ts new file mode 100644 index 0000000..5ad7cb3 --- /dev/null +++ b/backend/src/config/logo.service.ts @@ -0,0 +1,32 @@ +import { Injectable } from "@nestjs/common"; +import * as fs from "fs"; +import * as sharp from "sharp"; + +const IMAGES_PATH = "../frontend/public/img"; + +@Injectable() +export class LogoService { + async create(file: Buffer) { + fs.writeFileSync(`${IMAGES_PATH}/logo.png`, file, "binary"); + this.createFavicon(file); + this.createPWAIcons(file); + } + + async createFavicon(file: Buffer) { + const resized = await sharp(file).resize(16).toBuffer(); + fs.promises.writeFile(`${IMAGES_PATH}/favicon.ico`, resized, "binary"); + } + + async createPWAIcons(file: Buffer) { + const sizes = [72, 96, 128, 144, 152, 192, 384, 512]; + + for (const size of sizes) { + const resized = await sharp(file).resize(size).toBuffer(); + fs.promises.writeFile( + `${IMAGES_PATH}/icons/icon-${size}x${size}.png`, + resized, + "binary" + ); + } + } +} diff --git a/frontend/public/img/icons/icon-white-128x128.png b/frontend/public/img/icons/icon-white-128x128.png deleted file mode 100644 index 77a78fd70194f5bf4859f0bc03b8b347fa7eff0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4364 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 H$d~>Nn%i3% diff --git a/frontend/public/img/opengraph.png b/frontend/public/img/opengraph.png deleted file mode 100644 index ba000d2c9253164c892f8316035af62ddabe6d16..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11799 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

1&R^tTHf znQa4Q0+gXCZEa*?PF+%np-n|{#jyRuBZG|h8RtIKJ8}Q$XE0jrv5P@kihKt|jr4}^ znD4|5BmQYVr?S#?O(9ynfXrd0Vx`|(-V)K^ z0B9H@?Pwg|Y5H|B;;ufKX2VVpiyEHYl+7Kgh;yw%+1OPn8V_K{x8IaHpwK)0>vRXf z`}wN}U1xIGaq1V#Rbi2>B&+RGF44o)x=7#{YQ1{<+-IVRIvV7&d;eo2}f#MM7Z#ozAZY`#0I#o(TsV!Ke?O--~94 z{rjy8Nf?HPVy%wyZ)YO`qCsq!yq1yx^Ku1nkoGwA!Wtxi4tLmn_kdxOil={Wh=#O) zz>8FzJu#)Dg<+GFh|xKpM6m8OAd-5w{hnj}XaN~aYJD1V56HfmjnDQWS?}_oszP;3 zlS#cMCCtkS>=3hdPL@UoJF;%!29Lz;d$^I7=^~`yo%mD@EqM<@jQrOSP(@23W|hKQ z8-rHgXaCGg0P`0I^9hfVPL}D0 z9LLBr&6+?Z-QqCN5Y7TXe}*0>KURkw3qwHIMf!&v7b$MULNym{pId~3p%78UpuQd` z4^L`YYaR;4o~EQlA5kN>K$!}SE^{YBLlqev9iLCQY8lzq;0;U?+{(0s7}g*NRz)ot z(ZVd~fbBg6?b$|Y95n&>t738hLygHC4B3iZCGZ|R30G7E(1ziTWrD4Jga{i2jtOYi z2(-E~FnTj%URZQA3uCqs!~~{ze?Q zD2`=hp=jj>ji?}I(_|b%+C3y7d#i|i^{-olgF4)ez6z$Af;5w}m>?hagU` z9qC#^CM$PMJ9O9W(q`upX_yoZ zGyicqw*Q#w;}rbOfDe&ap&b;AwK}vvC`r{G2Qp)F%U2{p)NGppib-j;4trn@{^=;o zKOpk>G78Ecl#lKAUfBcXrB?|Awpx3IYj?2hbbqkMLkr;m-Ept3 z6{v2zoWxA~9BOnLKo=M6GldX%d32^~pm2&aTm!oK*w%S*{+iNIEOyEDHZcKof~FO8 zYLE`FpGdP+LJK+yA17itmouFqAAAh*6LcMK&PbyOo}Nb73Mb$YStIh@C^iANB+7*Y z4onYOQw9vvn+V}J@9ID4f zcbgNKAgrHy_jyC(OFjZyol}wwp zTe#)a<;i94XK>AjXdBfn3;G!}u^P=Y|1s^*w6}gp>*~ z&cgv6w$YeS#Smq%xmtLxQaT4-7>q|)i8u+}qmxUZW>dqf5v?8uyA2Yrq%x0^pTH;q z2wO6P)8GmL!YzOj7u38z)N%p51|=8Q55VyP)Tmb$zK;NHAjM@h1lj-u*jEd2b3cY} zR$Pt`T%VBhSuA_l*7xrk44+6Y_TCMgufo^Y$*OtfQqDBEfiu%~ogfrcPJv+REg-nL zV|wn1+9&C`twcdLWjYKq6dAyUzTAg8ZMzD?XemfZknV;xd^6jrsRO^I9N~JTdH=2@ zf%Yo)rchlC&S6y}ODwYPBseEvV@8HlDgUACqsbjBR?kLA=xvc5hJP*vA1Z*#{G#jO z#nM@_E6D=rG&iOTb2_yA4Y3M+iIs1lr#C+dZ~C=$sK^!cEIg z3LUDVBL2@1G4>IX^8WX)UE1H!Pe%hEYYhMbHy^p`L)VEyj=S1>O!^YZS^R(RTTV}= zBwb$~{!H#YX$--P@Z>$ARbh|?XX#J5HUzmf4#rDu@f#B;P6K#|ib$}(zZne-1|xkC zdIfv|LHxHr0RI2w8@xa<{@a&#v0DPM!l25;fANEQ=7P=|hB{{LR?#$C20+7ZqwXkI IC|N)KU(nTTH~;_u diff --git a/frontend/src/components/admin/configuration/LogoConfigInput.tsx b/frontend/src/components/admin/configuration/LogoConfigInput.tsx new file mode 100644 index 0000000..95f8729 --- /dev/null +++ b/frontend/src/components/admin/configuration/LogoConfigInput.tsx @@ -0,0 +1,39 @@ +import { Box, FileInput, Group, Stack, Text, Title } from "@mantine/core"; +import { useMediaQuery } from "@mantine/hooks"; +import { Dispatch, SetStateAction } from "react"; +import { TbUpload } from "react-icons/tb"; + +const LogoConfigInput = ({ + logo, + setLogo, +}: { + logo: File | null; + setLogo: Dispatch>; +}) => { + const isMobile = useMediaQuery("(max-width: 560px)"); + + return ( + + + Logo + + Change your logo by uploading a new image. The image must be a PNG and + should have the format 1:1. + + + + + } + value={logo} + onChange={(v) => setLogo(v)} + accept=".png" + placeholder="Pick image" + /> + + + ); +}; + +export default LogoConfigInput; diff --git a/frontend/src/pages/_document.tsx b/frontend/src/pages/_document.tsx index 2702a2a..841ebcc 100644 --- a/frontend/src/pages/_document.tsx +++ b/frontend/src/pages/_document.tsx @@ -12,14 +12,8 @@ export default class _Document extends Document { - + - - - diff --git a/frontend/src/pages/admin/config/[category].tsx b/frontend/src/pages/admin/config/[category].tsx index b66b85f..ea4ba6e 100644 --- a/frontend/src/pages/admin/config/[category].tsx +++ b/frontend/src/pages/admin/config/[category].tsx @@ -16,6 +16,7 @@ import { useEffect, useState } from "react"; import AdminConfigInput from "../../../components/admin/configuration/AdminConfigInput"; import ConfigurationHeader from "../../../components/admin/configuration/ConfigurationHeader"; import ConfigurationNavBar from "../../../components/admin/configuration/ConfigurationNavBar"; +import LogoConfigInput from "../../../components/admin/configuration/LogoConfigInput"; import TestEmailButton from "../../../components/admin/configuration/TestEmailButton"; import CenterLoader from "../../../components/core/CenterLoader"; import Meta from "../../../components/Meta"; @@ -36,22 +37,38 @@ export default function AppShellDemo() { const isMobile = useMediaQuery("(max-width: 560px)"); const config = useConfig(); - const categoryId = router.query.category as string; + const categoryId = (router.query.category as string | undefined) ?? "general"; const [configVariables, setConfigVariables] = useState(); const [updatedConfigVariables, setUpdatedConfigVariables] = useState< UpdateConfig[] >([]); + const [logo, setLogo] = useState(null); + const saveConfigVariables = async () => { - await configService - .updateMany(updatedConfigVariables) - .then(() => { - setUpdatedConfigVariables([]); - toast.success("Configurations updated successfully"); - }) - .catch(toast.axiosError); - config.refresh(); + if (logo) { + configService + .changeLogo(logo) + .then(() => { + setLogo(null); + toast.success( + "Logo updated successfully. It may take a few minutes to update on the website." + ); + }) + .catch(toast.axiosError); + } + + if (updatedConfigVariables.length > 0) { + await configService + .updateMany(updatedConfigVariables) + .then(() => { + setUpdatedConfigVariables([]); + toast.success("Configurations updated successfully"); + }) + .catch(toast.axiosError); + config.refresh(); + } }; const updateConfigVariable = (configVariable: UpdateConfig) => { @@ -129,6 +146,9 @@ export default function AppShellDemo() { ))} + {categoryId == "general" && ( + + )} {categoryId == "smtp" && ( diff --git a/frontend/src/pages/admin/config/index.tsx b/frontend/src/pages/admin/config/index.tsx deleted file mode 100644 index 5de1d44..0000000 --- a/frontend/src/pages/admin/config/index.tsx +++ /dev/null @@ -1,15 +0,0 @@ -export function getServerSideProps() { - return { - redirect: { - permanent: false, - destination: "/admin/config/general", - }, - props: {}, - }; -} - -const Config = () => { - return null; -}; - -export default Config; diff --git a/frontend/src/services/config.service.ts b/frontend/src/services/config.service.ts index f2da6f2..d2eff6e 100644 --- a/frontend/src/services/config.service.ts +++ b/frontend/src/services/config.service.ts @@ -46,6 +46,12 @@ const isNewReleaseAvailable = async () => { return response.tag_name.replace("v", "") != process.env.VERSION; }; +const changeLogo = async (file: File) => { + const form = new FormData(); + form.append("file", file); + + await api.post("/configs/admin/logo", form); +}; export default { list, getByCategory, @@ -54,4 +60,5 @@ export default { finishSetup, sendTestEmail, isNewReleaseAvailable, + changeLogo, };