move pwa manifest to backend
This commit is contained in:
parent
7aa9038a61
commit
b4a7986c8a
16 changed files with 724 additions and 11 deletions
BIN
src/assets/admin-logo.png
Normal file
BIN
src/assets/admin-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
src/assets/icon.png
Normal file
BIN
src/assets/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
|
@ -1,5 +1,5 @@
|
|||
import { dataSource } from "../../../data-source";
|
||||
import { setting } from "../../../entity/setting";
|
||||
import { setting } from "../../../entity/management/setting";
|
||||
import DatabaseActionException from "../../../exceptions/databaseActionException";
|
||||
import { StringHelper } from "../../../helpers/stringHelper";
|
||||
import { CreateOrUpdateSettingCommand, DeleteSettingCommand } from "./settingCommand";
|
||||
|
|
|
@ -2,12 +2,13 @@ import { Request, Response } from "express";
|
|||
import CalendarService from "../service/club/calendarService";
|
||||
import CalendarTypeService from "../service/configuration/calendarTypeService";
|
||||
import { calendar } from "../entity/club/calendar";
|
||||
import { createEvents } from "ics";
|
||||
import moment from "moment";
|
||||
import InternalException from "../exceptions/internalException";
|
||||
import CalendarFactory from "../factory/admin/club/calendar";
|
||||
import { CalendarHelper } from "../helpers/calendarHelper";
|
||||
import SettingHelper from "../helpers/settingsHelper";
|
||||
import sharp from "sharp";
|
||||
import ico from "sharp-ico";
|
||||
import { FileSystemHelper } from "../helpers/fileSystemHelper";
|
||||
|
||||
/**
|
||||
* @description get all calendar items by types or nscdr
|
||||
|
@ -71,3 +72,136 @@ export async function getApplicationConfig(req: Request, res: Response): Promise
|
|||
|
||||
res.json(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description get application Manifest
|
||||
* @param req {Request} Express req object
|
||||
* @param res {Response} Express res object
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
export async function getApplicationManifest(req: Request, res: Response): Promise<any> {
|
||||
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<any> {
|
||||
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<any> {
|
||||
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<any> {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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 },
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue