From b4a7986c8a2e631cc2c747206b5814a69b941637 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Thu, 24 Apr 2025 16:49:16 +0200 Subject: [PATCH] move pwa manifest to backend --- Dockerfile | 1 + package-lock.json | 530 ++++++++++++++++++ package.json | 2 + src/assets/admin-logo.png | Bin 0 -> 35299 bytes src/assets/icon.png | Bin 0 -> 29706 bytes .../setting/settingCommandHandler.ts | 2 +- src/controller/publicController.ts | 138 ++++- src/data-source.ts | 2 +- src/entity/{ => management}/setting.ts | 0 src/helpers/fileSystemHelper.ts | 15 +- src/helpers/templateHelper.ts | 4 +- src/routes/public.ts | 25 +- src/routes/server.ts | 2 +- src/routes/setup.ts | 6 + src/service/management/settingService.ts | 2 +- src/type/settingTypes.ts | 6 + 16 files changed, 724 insertions(+), 11 deletions(-) create mode 100644 src/assets/admin-logo.png create mode 100644 src/assets/icon.png rename src/entity/{ => management}/setting.ts (100%) diff --git a/Dockerfile b/Dockerfile index 4846250..08f68ba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,6 +37,7 @@ RUN mkdir -p /app/files ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser COPY --from=build /app/src/templates /app/src/templates +COPY --from=build /app/src/assets /app/src/assets COPY --from=build /app/dist /app/dist COPY --from=build /app/node_modules /app/node_modules COPY --from=build /app/package.json /app/package.json diff --git a/package-lock.json b/package-lock.json index 6d738ff..ab0d1a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,8 @@ "qrcode": "^1.5.4", "reflect-metadata": "^0.2.2", "rss-parser": "^3.13.0", + "sharp": "^0.34.1", + "sharp-ico": "^0.1.5", "socket.io": "^4.7.5", "speakeasy": "^2.0.0", "sqlite3": "^5.1.7", @@ -86,6 +88,12 @@ "node": ">=6.9.0" } }, + "node_modules/@canvas/image-data": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@canvas/image-data/-/image-data-1.0.0.tgz", + "integrity": "sha512-BxOqI5LgsIQP1odU5KMwV9yoijleOPzHL18/YvNqF9KFSGF2K/DLlYAbDQsWqd/1nbaFuSkYD/191dpMtNh4vw==", + "license": "MIT" + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -99,6 +107,23 @@ "node": ">=12" } }, + "node_modules/@emnapi/runtime": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", + "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -106,6 +131,383 @@ "license": "MIT", "optional": true }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.1.tgz", + "integrity": "sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.1.0" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.1.tgz", + "integrity": "sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.1.0" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz", + "integrity": "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz", + "integrity": "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz", + "integrity": "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz", + "integrity": "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz", + "integrity": "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz", + "integrity": "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz", + "integrity": "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz", + "integrity": "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz", + "integrity": "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.1.tgz", + "integrity": "sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.1.0" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.1.tgz", + "integrity": "sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.1.0" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.1.tgz", + "integrity": "sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.1.0" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.1.tgz", + "integrity": "sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.1.0" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.1.tgz", + "integrity": "sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.1.tgz", + "integrity": "sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.1.0" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.1.tgz", + "integrity": "sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.4.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.1.tgz", + "integrity": "sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.1.tgz", + "integrity": "sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1361,6 +1763,19 @@ "node": ">=12" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "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", @@ -1379,6 +1794,16 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, + "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==", + "license": "MIT", + "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", @@ -1583,6 +2008,33 @@ "node": ">=0.10.0" } }, + "node_modules/decode-bmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/decode-bmp/-/decode-bmp-0.2.1.tgz", + "integrity": "sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA==", + "license": "MIT", + "dependencies": { + "@canvas/image-data": "^1.0.0", + "to-data-view": "^1.1.0" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/decode-ico": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/decode-ico/-/decode-ico-0.4.1.tgz", + "integrity": "sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA==", + "license": "MIT", + "dependencies": { + "@canvas/image-data": "^1.0.0", + "decode-bmp": "^0.2.0", + "to-data-view": "^1.1.0" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -2492,6 +2944,12 @@ "ms": "^2.0.0" } }, + "node_modules/ico-endec": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ico-endec/-/ico-endec-0.1.6.tgz", + "integrity": "sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==", + "license": "MPL-2.0" + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -4475,6 +4933,57 @@ "sha.js": "bin.js" } }, + "node_modules/sharp": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.1.tgz", + "integrity": "sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.7.1" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.1", + "@img/sharp-darwin-x64": "0.34.1", + "@img/sharp-libvips-darwin-arm64": "1.1.0", + "@img/sharp-libvips-darwin-x64": "1.1.0", + "@img/sharp-libvips-linux-arm": "1.1.0", + "@img/sharp-libvips-linux-arm64": "1.1.0", + "@img/sharp-libvips-linux-ppc64": "1.1.0", + "@img/sharp-libvips-linux-s390x": "1.1.0", + "@img/sharp-libvips-linux-x64": "1.1.0", + "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", + "@img/sharp-libvips-linuxmusl-x64": "1.1.0", + "@img/sharp-linux-arm": "0.34.1", + "@img/sharp-linux-arm64": "0.34.1", + "@img/sharp-linux-s390x": "0.34.1", + "@img/sharp-linux-x64": "0.34.1", + "@img/sharp-linuxmusl-arm64": "0.34.1", + "@img/sharp-linuxmusl-x64": "0.34.1", + "@img/sharp-wasm32": "0.34.1", + "@img/sharp-win32-ia32": "0.34.1", + "@img/sharp-win32-x64": "0.34.1" + } + }, + "node_modules/sharp-ico": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/sharp-ico/-/sharp-ico-0.1.5.tgz", + "integrity": "sha512-a3jODQl82NPp1d5OYb0wY+oFaPk7AvyxipIowCHk7pBsZCWgbe0yAkU2OOXdoH0ENyANhyOQbs9xkAiRHcF02Q==", + "license": "MIT", + "dependencies": { + "decode-ico": "*", + "ico-endec": "*", + "sharp": "*" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4620,6 +5129,21 @@ "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==", + "license": "MIT", + "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==", + "license": "MIT" + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -5104,6 +5628,12 @@ "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", "license": "MIT" }, + "node_modules/to-data-view": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/to-data-view/-/to-data-view-1.1.0.tgz", + "integrity": "sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==", + "license": "MIT" + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", diff --git a/package.json b/package.json index 0483b20..02fbe5a 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,8 @@ "qrcode": "^1.5.4", "reflect-metadata": "^0.2.2", "rss-parser": "^3.13.0", + "sharp": "^0.34.1", + "sharp-ico": "^0.1.5", "socket.io": "^4.7.5", "speakeasy": "^2.0.0", "sqlite3": "^5.1.7", diff --git a/src/assets/admin-logo.png b/src/assets/admin-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a2760bc868de85b44416af5d33796f9672566b06 GIT binary patch literal 35299 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 literal 0 HcmV?d00001 diff --git a/src/assets/icon.png b/src/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..39a8174e006b997c1611424429a4054898f06329 GIT binary patch literal 29706 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≺)pW(Xj0iUD9=)>b}h0bE(gjrZASiSc+14HmT^lVL;%luH}2lGmSD?^emY`v zzVJOg8!Y?|EDE%gswb~_VY=&#k|LK{SeMQk-sY2zq9aNKg`Yd&&R*~Mcqw{JFu^o0 zA~bIqp)8(+rb>-Z683<;)j>@$IpAs=|2Dxr!XQ{#0nU4Hfd<+S5cwx|c29iCX}1;M|XD9z3=pXyTeL$-ARkdJEzD8-~jwH^#scSdXg#(vh3t zJ0XhvvKzY1-4`L zP#jAu`;BaDT z=))CuF|rc6xO$|gP^?Ew4>QEb^d((!p`?}5U5OUPe+kk5c-ox9&-v?o62poD@$3bKQn=5< z4Q5mDKJ+%2zk!;Os&*ZA4*tn5M?r$mFTh^MsBkvg+cFwZ@)fZl)9e!3`vN54`q4!m zy+9+J2X1sm1K;dw0+RdnFiI4#;+S{uHpIO{FWyy{3u*5&R##1a z5IqyfRg?$1p1?Hgv@m*lIt8aeknLP5zHUg4f12SCV9cP)%z7D~%#@W|6I%LP{0-n#7X?)wqf*s(uqYHQ zJk-hWFL$CQBqJh@FZn2RB7Yv)!6^~4?&-;3L=Ld{@dyE#kO|dD3APnM_aDYRe zCfi%R$pEe5Wk78!_f;f@nMa7zy-#?vg49GlQfyM83F1$qbvs4_K!@Ju-ZmF8Xr8dR zyy_M=NT>;a`n!;7>)SuJ1p7oCG#KD8uSwlpfLY&=Z>Za1x+<_Eh6_Eb2=XIw)Z*_t zVl|_QD5AZc7F;c^M8bycHG=8kYcKspOfP>OIBaF6x*ZnLEy?(Q@Bil3`KhX1XzuZO zmE7e6j~~wHDAJ2q%>6t5r-k*i$dTP^=1j$8;OSK$OgbB{3H%1fT_1makoG@ED99ee z^=ka8g45jkZqwM`i<*oW@*M=#RK?N($-t2O*T1KH7 zAF6+sgmuoG`VAqOEibGC;doS%4HRWJutR|tSmnY%=MMv9!4angd2*U$P(V`ZT((Boq)RQd{UxUy0S3#Du>EXp^VBO%-wWlUMRI zf)^M4Z}4C%^}9Jf&Nxu*Ypqe`WRk`00t#d|oOMwsqqPdloT)_+@5iiU5x;CT79VNR zdLT4BqjSrd+9CWe2;B<&5h4_#D=v_1WoTg;<>S$q&S7qWmbb5qurnUH^QD@1UAa=56S&%?hIY5H zWDE}7KNl>9a02$~Vh4^23vmv}SIC~#gdS1mLj~yK65rEaRq8ym|3bRJpItfmUYl=` zwk?B$XO6qWZr`ZOb&N6XHO}he0`W~r=2FPiBcoxxjzkn3zzd9`2Na0u?qK3#di(jA zQD5OR4(Uhot{v#Tp?k7aU4;0yw|f$S*Z-vp@ zbEaSi5KK+zB88CeK|l0Ha<@c9zL2Nf(&qf<)h_Zj!5%nhLVsG%CjsH;#Q_o68r~F# zCB|@xo}kJ5+RhWwyplGC%SZ8W9OF6rzEyk*8Y^rmTCO+dPRZ}E>IWD~jhzzX#dsJ> zA<9zEs|e=J9Sxye^-(4Dr7(CgmOvC-C*vShBCjAYXK^LB)y4Jvws2SR;O4JF$U$qM zo9pCq$cSLdt6DLc*c1VQuCnhmuxXsB?@e2}U`8!7AbpWs_r>3v#tDJnkRpoFOkW)P z2OH&!IQ)=|xLQyz;Lhv#GRaAo7vMjFk<`$9wDoZSIz4{(qZ6^-XU98dv(FY?1 zIoICD@Q;nU1Avf5&yMo@LQWMTePAV$1jdi7xO(eJQWNOc`_j9dE2Ts)zO8N9? z%$Xr?GIgs37T9P=XhKfGg-6vIq+aS>iF&%ZBtTkbz7z4+uVm@NW3+3UBYLLECs@-B zAOC2oEPEBSx-wx@HT8q4Wn(qtH#LSlpo=S04l)-RKy_o!P-uk}<0>ccQ(CkGU*t0 zZR$%bXvKh$YxQFft!gq3GDzL?74E#$oauK9{AK3baERlg*$$R5gP$^G!VQOCuW7<~ zfNBLiUw2S=E*xp2V`*(?@G!s8aM#0vVb}r@cXV06So(Ar$Vmx0P8FXreS|jZvmEQC z9P)dja0Eunb9MLlG12QMqCY(hJMrU}7%q%@845Zzv#>sfu2m&jN57!6 zXA0g9Yp}WZrCtQgDTm`I!zZ_$TCBlO#JT+56vs$CS)P zs-&2fU;-S^ftQ)BNN%~ogINH=%+!q^RCw)ngvH$Zuje%Jix>#Sznv2iwf}zMN07kw z&8!ce>(1HWkh*SpWgD4l4*yX4Ni^<{Uj$VS#mqR;?@QIuHYnY1pZJ1*CUGeV2wJh- zY(7CaDmq0k+;BX)@YT>itBEeNdDN?g)Z<^vh;0{plDH*{p8WDqYc@a}P<4D*!Ql~o za;)tvSbS_+0`B3@-{l}xb2)>UeHu5?Ay{(x_X&|(IrMzbppT+?Cuxa!Q6RZgVgoSW zH0^^8^$^=HB^?+#T5L%y=H0G&G$L+N;}76HvtGCWGL<|6pjy_$2toCndP1VQ@&2Bb z!%HL`M0X^x+t3!Yk31FMyoN6^5**}_L8E1T=7Wfb7uJ%b>f0@UFjwx&pj53`*_LRU z8Qt~yW#8I+vHnHHD2E`~P7wx??WCT38h5-n6C==7kOR9en^d9~^K5EgMrMNI% z206tKS^tQCf5?O-iv?nZ5#DmlbR950U38XCZ~d&r>MSzRZ2L#xIUt!WRu%{sECB&$ zUw$^G;gxc|#v;@H@eguUlG-4ZuGJY}Jx|^vtA%#8%_MB(^1_cMWYio_?@vn~kEDe^PFeQ8NF=zOE zx$X)CD`_*ni{{ee7&fpTi+yAaRxST@OyO$Am6`5ONm=6f3tQoby_HmMN?+TXe(t8< zk#XCw$KBK1gLMX_%5-5+V)@9L_u+%mQ?+9yxG+5$7fOas932yU%@#nTm+%=uuZmhomvJ+VdBVcmmK`G1h$nHpUaKhmP*guK>|O4EUwj$toqi{hd6 z)X7R|llzjlD%&~aHlW9q?+k$JQa+Nsq^+ocS0;tA8eCA~Q$NwJj;cs5l6obP&5v%D z`+8w1$8#3}59xljDaRBsu4J(@E03byFaQG2(p!ZJ@hhvRg<(NEpaVAEamws#2p-hE z(sRi`tE0%XQJJ!`p4`GO;`_rQOfJ2xrX5#>j&0Y(5PHOLT+Zr>=)a>bCk~Cwd}F5e z5tKFtMv`+m*$4J|b`wLNw-_#*YN|y*i_}l*Zeo8X{7@t*cG7HB&e0wIhkG2;m>b!Y z8QMV-N_lc^nR7uA%-jB<+ZGNYd*m;Mqd~=UlZO6V@aNkjDyH zhUb;HE7_0?ffv|z%?ww|u0n<29d5Ge#oY0W!e8il+i=nh?_f|1&DKRVI}7(Y+eQPJ zv;_eqyV%T>-mq0r*0P-Nk!ej%%3^wU1xMk&@=vn;to1ONClSX(uc`EU&CAN%6-41X zGF3Qbg1L%$(C@#sz*a6ncARfGaLhhUXw8lOnQzG*XgzOC+h$qadl!bQV&qo<`z)H5 zdM{UIG|Ct4X-c?))SFOOHi)_RHRjB|nToZG zk)TmdnI+d-(jf8ACfS#Gu9Fh|WM&*oN_sDr!TYXtoePMBWQ!)9AGlJ0^C z8Fs{OZiXarajDtGUnE|R6^Y5GQCFn0yLt)$P!j+5MnGa$79YeWvS_v?$%odqe_u~+ z+ZfEo7|1ak^`NBw;uS*;VfcJ@aiAJ;vZ6Kf?Jcj5_C(VF`%f=MG3*xDDYwb2k11Pn zj=sNB`M_P-8cQpym_`ZBtk-+lM{Hr0-g$ek{>B*%wTfd0_0WsX$rjHH;b{M9J@Z*s)UNvqe*HHuq_^UEExr;(sVxcMyJ16f5-xrJ@Rv`AL(9s@ zlcvrw4onMe#o;)1V=P_8=)9y*k6eN(bX|9QTI*|2@fwI^C3>OUjdZz5#WmwtCJolp^q}-G|CcWSwmGWhur> z@_E2L9y88L{G#Lih3#$>?&5e%JgxJ{$_N(7 z!QW{(@$-{TOh!qNoB!6&*@5v=k${Wuo}wf-GSBiz5YAv(O*q{<>gDDGLT ze#V7ah!tS-2`0ak^Z;JsPPot5&HMlOFuf+7GxV?qUj)G82nkC*-)?NOY2vO~MV@5e z1by?n8HeD6a&yUW7TxO<>BR=oES3mtNE<6O5FGJGeIA+_GEMbR$ux`ngQ#=S2 zG)z8~_=@FYlo38N610`?#m$~G!@+=KANPV>yJd-_X%VLt7~sf0i!%=9iqj~ zZCGwMBp(&hU~L%3)1cD7nhu($P5j zemfpZmXY7j^>swJgk(jxiAht>s^12ab2)qbB73g)`-4R>N}CdeiH*w_;wp0ysgKv9 zolZ|I{?5_;>A)d38v8=+Q@eS$xz)&Y;ufXV=F+Kb)N`xkO7Uk?VjX7%t8UU?=NGE` z@grHMga?sH1lO{K`;W}1bZxV(Ro)-ShGwqbQl9y@T7c5RhmyI+w1!y1l0B$-ON$&+ zu8{5DCd=P3y~uD$3ne)Sn)^l#u4`P8q#=l$|2>8A9$VHyW#~y((YNxl1|si72IF4k zvYuSO=c<_QP}uoe;G4HU$m6Yb*F_DXxK+jr8mg90&<&;cpvL+bIr?Wzs|zO6sM2 z#Op}JSF4^b0WfJr8Z^XfvMp+|e=bF2&#GA{Vs>LoPAMi59JXS>CL*Z>h9 z{B+`Sd?-9fWvS!+4}oc7ADrW0l0eZEp<~hwA4~NUfUB|FDJ*@9sVvBd!knztPBFFf zC`H{=l}3}`l0U#(TqcdF`{12=y~4b1%c9i^v8)nTSC{Gof}iBf%?!YBC{1qTz5KkO z5maHQsmBr-hGN`w8wx$xd9IpZ!V?Z($un4G!1`cLHN5WaUlkD`{Z2llZ>W#<%=6jC zwR>jxGZNSi^?UoYgBSjCXy5%5-?YYQK0Sh;F)=-;4t!p=(S@#`DSfI-9apUDP|4v_ zjq@jlx|VZ*`@|<5;x_%2jXrIj@%164Z(rUs&{S_#@bS0c>rTG-9o0b@?DrCp$rryg z{I_gAA%EYCFIJNTHXk%o@8v6wqe}zLGaC9DQNDdNRtnK-p^W~3^*~xhohdq{Cnb6c z5y_Ow6?TMxZDOiPkm1=s?DC*2^CFzO&Y9;93S9ahCWW$AXleMRjJdZOiImcUMtI$#I@)ZQW^;B%btQ-2OE8pC&B8r`74- zhBL8a63V`=RBTL309ybDlcgH@Ryjn7)JAoFtWnEmn^nd%T$UG%utE2sFFJ?b*38qo z^>s*NSgH zT#Jd!`u9f>O%Ebd-~sZUO7E#Mz>=twsS-9YH?P>>1tOE>k`f(exGi5dcTPj==K3=)Sr zu=ci0l*y7i&Gvac;yi{{KgWyZNCMa3BFKzjvU4?WcOIV2=F7)#S;K+I-gdigOL~J1D%$ z6_&v_IU=cTDn~BKahx)jru4Bvp>70clFu;DGDJ!@q(3EXp&?bxr!|wQFyeX5p?{gY z2Rg;{VGU@gCKsj5U5XqheM;T`!0w^RH|6B8#QTSRk+sG)k!!fueY%3gSgXWm^t)+h zT<0H@yGo#wNyMiXRNcWq=>AO{_aq^pBdxnuv@J(+YDL+~QXBYj@*j0AGNvfsQhfQ$U%)bA*2Rz;t}u>cz%+;znIsOwn=}1HdX@82#~9wBl|F?4*?HV4P$- z$T=|lmGl)PHs5OfyIgtS9Z=;pQf-~;Up$(W-O6{*0Q&+mBDbFNU?O3#l zu`h^{#r<$(nbHtCrDcv=Hph8=_wI{e4GFO1Qf-CscAe{_@TRl3ey|t+<4bW?g7mQE5!0VLj|KPC?2;liKUhA950DpIpQgGWW&S zEldGim;KSqBp$1y3e&yyVCVy9aUT{(xFC&o0kD)2owg<9Cb#!O$nOcR?7I{Uf3IG6 zeW99tm*-37MIG7vB$52{JHjNZ?wSE0Hk zkeh@~;SlI5Et%YO$w4Y*j_bTNsWt0I{f12b7`BA8LBNVMr`==?26->{btA(aJTd{d zvz*OdasIf~MsiLzp+}PWHr@Ntxs!r_2$76$uEzx?9aTIg{gAavsk2|067D@2HH{UI zAKZCsB$7w>;p}4B^}#EBiM35p8-3K%0frH@)eL|>+ag0)kpidXoQ#OJ0#k+|z3Xd7 zYE6C-5q94$WiKr|v`W5@n=|QiN6w@_#`YQT(68~fD^9Ea#W*V^GoL`BKO!HDJ8LAi zz1v8|eHADyg222~g4r=bRf0zT^o2V!RlDNm-Yz|;@&6%==cA3x)MTG%UbdL~KP766>roZYn;>QD_b>-@nk7b9ce{lVTvW1J8v4-(KN zR_!S?(h?_X+mJ#Zd^>oH^@RC+CF!9~+cuZcxBIv3$j?KxeVs@_)F^g~L_<=C@0%vW z264)OU+LahZ!^}|UiLF1AEi|*V{!x85SUy=gV1Q3OTy$D4vMOEx~=fDQ&iW5^O17&sxA))0kRyqu6a-W%9->Z5cF*Vy=-0c(@~F zbo}~7o;2{<4LbS7`6zKnpLeUHog=!d$(jAk-$f-v-R#pF%)CA1RMNUR_}|ue-wtZorO0OL=*N@cxjIp7d5VNDzb?n|OP^E&=@sGcdheRl{=T&W-pcJa(@(Nh z)^;CQQIv;%q$*B-`#JJ!T9SWPE55Fl1l^^6kC@-TDRese;szm7B<}Eo zz{gnmRg#a`M)C6u!;f#gf}c zV>jhnt0|*g6L8)#R*R&Q70>pw{q0ZPe2~p@WCWq;d|gMfwVRbCLwgCIp6hE)W3b2Q z#gFtrMERL#nlMp@=OodOaO(I*5%CYiu;1cMPA02^`?P(eb1H+{M+ZykTt(?M528!> z5@e+N?+qJyBw#qSOGU9;g65+`W4W8+8nspYDW$l`-}Fmj{8R=8#Nr}P5dOUvISj+$ zI`P}jh?A|1sr%{UIHcxwH||}3sqL_7Cbs3~bkP2!JzWG7BuYqSzXR1NZrq?lyk>b~ zEx9E{l=!r-S7V3Hj@vVxo?#A$5FIELeUJNFk401MrVHwL?6}A9rJLyd{8JIwRK0=l zx^PnSrNL;v#^h9ofgo(cW6KWdDV$_%oK$QKB)oWot0IGod;PSJVgV##5^+7I#=1o$ zJoXNC5yhGuYO6~@^PrUgf;C3gDV^3oOYW_G6eeDx7$qxRm{P^YpFlMSJPxg=*ccAO zVkSC#n)SlbR)OqjKV_5hS1{-`Xvu1-lAe{r&OqVyp2EnA4tt*H5~u$YQ(HCS-oZ#2 zrQaoA*q;M@T|aTE;4$P)j9=B1e4&{7fG)k@E8K>3G4Qa}dp_I8U{!v?QTBMV!gCB~ zWbTNcuFWyL_k_CQBdC}<%K_DZ#O({lnm$W#tQ0`nS`oy`}P?x*>_jRa7^+Gk_X|AD%$ON9P zR)fLac;kbF5=o*W|~Qh{RKi zC?YjDElVts)g}STSN1?mwAVK=XsPn+TPptir<-8(^G9ub34s^`e-spa++D^)v0lDs zeMU{RPjmh6m29qdL5-hM3M`;IYIvtBy_{To9pV4wR`=}%vBi*g?S2tx*4eB#p! z!DLZOTHKgtvgB3^Qu@hen=^})yevMhr(f39RAy}$S@ i4} + */ +export async function getApplicationManifest(req: Request, res: Response): Promise { + const backendUrl = `${req.protocol}://${req.get("host")}`; + const frontenUrl = `${req.get("referer")}`; + + const manifest = { + id: "ff_admin_webapp", + lang: "de", + name: SettingHelper.getSetting("club.name"), + short_name: SettingHelper.getSetting("club.name"), + theme_color: "#990b00", + display: "standalone", + orientation: "portrait-primary", + start_url: frontenUrl, + icons: [ + { + src: `${backendUrl}/api/public/favicon.ico`, + sizes: "48x48", + type: "image/ico", + }, + { + src: `${backendUrl}/api/public/icon.png?width=512&height=512`, + sizes: "512x512", + type: "image/png", + }, + ], + }; + + res.set({ + "Access-Control-Allow-Origin": "*", + "Content-Type": "application/manifest+json", + }); + + res.json(manifest); +} + +/** + * @description get application Logo + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getApplicationLogo(req: Request, res: Response): Promise { + let setLogo = SettingHelper.getSetting("club.logo"); + + res.set({ + "Access-Control-Allow-Origin": "*", + "Cross-Origin-Resource-Policy": "cross-origin", + "Cross-Origin-Embedder-Policy": "credentialless", + "Timing-Allow-Origin": "*", + }); + + if (setLogo == "") { + res.sendFile(FileSystemHelper.readAssetFile("admin-logo.png", true)); + } else { + res.sendFile(FileSystemHelper.formatPath("/app/admin-logo.png")); + } +} + +/** + * @description get application Favicon + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getApplicationFavicon(req: Request, res: Response): Promise { + let icon = FileSystemHelper.readAssetFile("icon.png", true); + let setLogo = SettingHelper.getSetting("club.icon"); + + if (setLogo != "") { + icon = FileSystemHelper.formatPath("/app/icon.png"); + } + + let image = await sharp(icon) + .resize(48, 48, { + fit: "inside", + }) + .png() + .toBuffer(); + + let buffer = ico.encode([image]); + + res.set({ + "Access-Control-Allow-Origin": "*", + "Cross-Origin-Resource-Policy": "cross-origin", + "Cross-Origin-Embedder-Policy": "credentialless", + "Timing-Allow-Origin": "*", + }); + + res.setHeader("Content-Type", "image/x-icon"); + res.send(buffer); +} + +/** + * @description get application Icon + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getApplicationIcon(req: Request, res: Response): Promise { + const width = parseInt((req.query.width as string) ?? ""); + const height = parseInt((req.query.height as string) ?? ""); + + let icon = FileSystemHelper.readAssetFile("icon.png", true); + let setLogo = SettingHelper.getSetting("club.icon"); + + if (setLogo != "") { + icon = FileSystemHelper.formatPath("/app/icon.png"); + } + + let image = await sharp(icon) + .resize(width, height, { + fit: "inside", + }) + .png() + .toBuffer(); + + res.set({ + "Access-Control-Allow-Origin": "*", + "Cross-Origin-Resource-Policy": "cross-origin", + "Cross-Origin-Embedder-Policy": "credentialless", + "Timing-Allow-Origin": "*", + }); + + res.setHeader("Content-Type", "image/png"); + res.send(image); +} diff --git a/src/data-source.ts b/src/data-source.ts index d94d77f..2fabc96 100644 --- a/src/data-source.ts +++ b/src/data-source.ts @@ -50,7 +50,7 @@ import { TemplatesAndProtocolSort1742549956787 } from "./migrations/174254995678 import { QueryToUUID1742922178643 } from "./migrations/1742922178643-queryToUUID"; import { NewsletterColumnType1744351418751 } from "./migrations/1744351418751-newsletterColumnType"; import { QueryUpdatedAt1744795756230 } from "./migrations/1744795756230-QueryUpdatedAt"; -import { setting } from "./entity/setting"; +import { setting } from "./entity/management/setting"; import { SettingsFromEnv1745059495808 } from "./migrations/1745059495808-settingsFromEnv"; import { DB_HOST, DB_NAME, DB_PASSWORD, DB_PORT, DB_TYPE, DB_USERNAME } from "./env.defaults"; diff --git a/src/entity/setting.ts b/src/entity/management/setting.ts similarity index 100% rename from src/entity/setting.ts rename to src/entity/management/setting.ts diff --git a/src/helpers/fileSystemHelper.ts b/src/helpers/fileSystemHelper.ts index f77bef2..9bc409a 100644 --- a/src/helpers/fileSystemHelper.ts +++ b/src/helpers/fileSystemHelper.ts @@ -20,9 +20,20 @@ export abstract class FileSystemHelper { return readFileSync(this.formatPath(...filePath), "base64"); } + static readRootFile(filePath: string) { + return readFileSync(this.normalizePath(process.cwd(), filePath), "utf8"); + } + static readTemplateFile(filePath: string) { - this.createFolder(filePath); - return readFileSync(process.cwd() + filePath, "utf8"); + return readFileSync(this.normalizePath(process.cwd(), "src", "templates", filePath), "utf8"); + } + + static readAssetFile(filePath: string, returnPath: boolean = false) { + let path = this.normalizePath(process.cwd(), "src", "assets", filePath); + if (returnPath) { + return path; + } + return readFileSync(path, "utf8"); } static writeFile(filePath: string, filename: string, file: any) { diff --git a/src/helpers/templateHelper.ts b/src/helpers/templateHelper.ts index 3dc5ad8..dd77a74 100644 --- a/src/helpers/templateHelper.ts +++ b/src/helpers/templateHelper.ts @@ -9,10 +9,10 @@ export abstract class TemplateHelper { static getTemplateFromFile(template: string) { let tmpFile; try { - tmpFile = FileSystemHelper.readTemplateFile(`/src/templates/${template}.template.html`); + tmpFile = FileSystemHelper.readTemplateFile(`${template}.template.html`); } catch (err) { tmpFile = FileSystemHelper.readTemplateFile( - `/src/templates/${template.split(".")[template.split(".").length - 1]}.template.html` + `${template.split(".")[template.split(".").length - 1]}.template.html` ); } return tmpFile; diff --git a/src/routes/public.ts b/src/routes/public.ts index 49ec98a..d557dd7 100644 --- a/src/routes/public.ts +++ b/src/routes/public.ts @@ -1,5 +1,12 @@ import express from "express"; -import { getApplicationConfig, getCalendarItemsByTypes } from "../controller/publicController"; +import { + getApplicationConfig, + getApplicationFavicon, + getApplicationIcon, + getApplicationLogo, + getApplicationManifest, + getCalendarItemsByTypes, +} from "../controller/publicController"; var router = express.Router({ mergeParams: true }); @@ -11,4 +18,20 @@ router.get("/configuration", async (req, res) => { await getApplicationConfig(req, res); }); +router.get("/manifest.webmanifest", async (req, res) => { + await getApplicationManifest(req, res); +}); + +router.get("/applogo.png", async (req, res) => { + await getApplicationLogo(req, res); +}); + +router.get("/favicon.ico", async (req, res) => { + await getApplicationFavicon(req, res); +}); + +router.get("/icon.png", async (req, res) => { + await getApplicationIcon(req, res); +}); + export default router; diff --git a/src/routes/server.ts b/src/routes/server.ts index 964d207..782609d 100644 --- a/src/routes/server.ts +++ b/src/routes/server.ts @@ -5,7 +5,7 @@ import Parser from "rss-parser"; var router = express.Router({ mergeParams: true }); router.get("/version", async (req: Request, res: Response) => { - let serverPackage = FileSystemHelper.readTemplateFile("/package.json"); + let serverPackage = FileSystemHelper.readRootFile("/package.json"); let serverJson = JSON.parse(serverPackage); res.send({ name: serverJson.name, diff --git a/src/routes/setup.ts b/src/routes/setup.ts index 159e04e..36cd725 100644 --- a/src/routes/setup.ts +++ b/src/routes/setup.ts @@ -25,4 +25,10 @@ router.put("/", ParamaterPassCheckHelper.requiredIncludedMiddleware(["mail", "to await finishInvite(req, res, true); }); +/** + * TODO: + * set basic settings like clubname ... + * enable upload of images and icons: transform pwa-> 512x512 png / 48x48 ico + */ + export default router; diff --git a/src/service/management/settingService.ts b/src/service/management/settingService.ts index 1860065..4f9b5e2 100644 --- a/src/service/management/settingService.ts +++ b/src/service/management/settingService.ts @@ -1,5 +1,5 @@ import { dataSource } from "../../data-source"; -import { setting } from "../../entity/setting"; +import { setting } from "../../entity/management/setting"; import InternalException from "../../exceptions/internalException"; import { SettingString } from "../../type/settingTypes"; diff --git a/src/type/settingTypes.ts b/src/type/settingTypes.ts index 48ba231..8f131ee 100644 --- a/src/type/settingTypes.ts +++ b/src/type/settingTypes.ts @@ -2,6 +2,8 @@ import ms from "ms"; export type SettingTopic = "club" | "app" | "session" | "mail" | "backup" | "security"; export type SettingString = + | "club.icon" + | "club.logo" | "club.name" | "club.imprint" | "club.privacy" @@ -23,6 +25,8 @@ export type SettingTypeAtom = "longstring" | "string" | "ms" | "number" | "boole export type SettingType = SettingTypeAtom | `${SettingTypeAtom}/crypt` | `${SettingTypeAtom}/rand`; export type SettingValueMapping = { + "club.icon": string; + "club.logo": string; "club.name": string; "club.imprint": string; "club.privacy": string; @@ -54,6 +58,8 @@ export type SettingsSchema = { }; export const settingsType: SettingsSchema = { + "club.icon": { type: "string", optional: true }, + "club.logo": { type: "string", optional: true }, "club.name": { type: "string", default: "FF Admin" }, "club.imprint": { type: "url", optional: true }, "club.privacy": { type: "url", optional: true },