feat: require calendar title configuration
This commit is contained in:
3
.env.example
Normal file
3
.env.example
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Lokale Entwicklung mit Docker Compose.
|
||||||
|
# Bei Installation über MPM den Kalendertitel in der Modul-Konfiguration setzen.
|
||||||
|
CALENDAR_TITLE=Mein Kalender
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
calendar-mvp-*.zip
|
calendar-mvp-*.zip
|
||||||
calendar-mvp-*.sha256
|
calendar-mvp-*.sha256
|
||||||
|
.env
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ Ein kleines, eigenständiges Kalender-Modul für MPM. Es zeigt einen Monatskalen
|
|||||||
|
|
||||||
MPM installiert das Repository als eigenen Compose-Stack. Der App-Container läuft mit Node.js 24, stellt Port `41002` nur intern bereit und lauscht auf `0.0.0.0`. Die SQLite-Datei liegt unter `MPM_MODULE_DATA_DIR` im persistenten MPM-Modulvolume und überlebt Container- sowie Modul-Neustarts.
|
MPM installiert das Repository als eigenen Compose-Stack. Der App-Container läuft mit Node.js 24, stellt Port `41002` nur intern bereit und lauscht auf `0.0.0.0`. Die SQLite-Datei liegt unter `MPM_MODULE_DATA_DIR` im persistenten MPM-Modulvolume und überlebt Container- sowie Modul-Neustarts.
|
||||||
|
|
||||||
|
## Konfiguration
|
||||||
|
|
||||||
|
Der Kalendertitel wird über `CALENDAR_TITLE` gesetzt. Für lokale Entwicklung `.env.example` nach `.env` kopieren. Bei einer Installation über MPM erscheint nach der Installation die Modul-Konfiguration; dort muss der Titel gesetzt werden. MPM übergibt den Wert an den App-Container, eine `.env`-Datei im Repository ist dafür nicht nötig.
|
||||||
|
|
||||||
## Installation über den MPM-Marketplace
|
## Installation über den MPM-Marketplace
|
||||||
|
|
||||||
Das öffentliche Repository kann mit der verbundenen Gitea-Instanz direkt aus dem Marketplace installiert werden. `module.json`, `compose.yml` und `Dockerfile` liegen im Repository-Stamm. MPM installiert den Standard-Branch; der Start erfolgt anschließend über die Modulverwaltung.
|
Das öffentliche Repository kann mit der verbundenen Gitea-Instanz direkt aus dem Marketplace installiert werden. `module.json`, `compose.yml` und `Dockerfile` liegen im Repository-Stamm. MPM installiert den Standard-Branch; der Start erfolgt anschließend über die Modulverwaltung.
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ const db = new DatabaseSync(path.join(dataDirectory, manifest.id + '.sqlite'));
|
|||||||
db.exec('CREATE TABLE IF NOT EXISTS events (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id TEXT NOT NULL, title TEXT NOT NULL CHECK(length(title)<=120), event_date TEXT NOT NULL, notes TEXT NOT NULL DEFAULT "" CHECK(length(notes)<=1000), created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP)');
|
db.exec('CREATE TABLE IF NOT EXISTS events (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id TEXT NOT NULL, title TEXT NOT NULL CHECK(length(title)<=120), event_date TEXT NOT NULL, notes TEXT NOT NULL DEFAULT "" CHECK(length(notes)<=1000), created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP)');
|
||||||
const listEvents = db.prepare('SELECT id,title,event_date,notes FROM events WHERE user_id=? AND event_date>=? AND event_date<? ORDER BY event_date,title');
|
const listEvents = db.prepare('SELECT id,title,event_date,notes FROM events WHERE user_id=? AND event_date>=? AND event_date<? ORDER BY event_date,title');
|
||||||
const insertEvent = db.prepare('INSERT INTO events(user_id,title,event_date,notes) VALUES(?,?,?,?)');
|
const insertEvent = db.prepare('INSERT INTO events(user_id,title,event_date,notes) VALUES(?,?,?,?)');
|
||||||
const html = fs.readFileSync(path.join(__dirname, '..', 'frontend', 'index.html'));
|
const calendarTitle = process.env.CALENDAR_TITLE?.trim();
|
||||||
|
if (!calendarTitle) throw new Error('CALENDAR_TITLE muss gesetzt werden');
|
||||||
|
const escapeHtml = (value) => value.replace(/[&<>"']/g, (character) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', "'": ''' })[character]);
|
||||||
|
const html = fs.readFileSync(path.join(__dirname, '..', 'frontend', 'index.html'), 'utf8').replaceAll('Mein Kalender', escapeHtml(calendarTitle));
|
||||||
function json(res, status, value) { res.writeHead(status, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }); res.end(JSON.stringify(value)); }
|
function json(res, status, value) { res.writeHead(status, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }); res.end(JSON.stringify(value)); }
|
||||||
async function bodyJson(req) { let data=''; for await (const chunk of req) { data+=chunk; if(data.length>16384) throw new Error('too large'); } return JSON.parse(data||'{}'); }
|
async function bodyJson(req) { let data=''; for await (const chunk of req) { data+=chunk; if(data.length>16384) throw new Error('too large'); } return JSON.parse(data||'{}'); }
|
||||||
const server = createModuleServer({manifest,logger,routes:async(req,res,{path:pathname,url,identity})=>{
|
const server = createModuleServer({manifest,logger,routes:async(req,res,{path:pathname,url,identity})=>{
|
||||||
|
|||||||
@@ -6,3 +6,5 @@ services:
|
|||||||
expose:
|
expose:
|
||||||
- "41002"
|
- "41002"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
CALENDAR_TITLE: "${CALENDAR_TITLE:?Set CALENDAR_TITLE in .env or MPM module configuration}"
|
||||||
|
|||||||
15
module.json
15
module.json
@@ -11,5 +11,18 @@
|
|||||||
"healthcheck": "/health",
|
"healthcheck": "/health",
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"composeFile": "compose.yml",
|
"composeFile": "compose.yml",
|
||||||
"appService": "app"
|
"appService": "app",
|
||||||
|
"configuration": [
|
||||||
|
{
|
||||||
|
"key": "CALENDAR_TITLE",
|
||||||
|
"label": "Kalendertitel",
|
||||||
|
"description": "Name, der oben in der Kalender-App angezeigt wird.",
|
||||||
|
"type": "text",
|
||||||
|
"secret": false,
|
||||||
|
"required": true,
|
||||||
|
"services": [
|
||||||
|
"app"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user