Grocy api
All checks were successful
App Image CI / Build app image (push) Successful in 20s
NPM Audit Check / Check NPM audit (push) Successful in -2m11s

This commit is contained in:
2025-10-14 01:18:42 -05:00
parent c9715d22f6
commit 0e812e585c
6 changed files with 188 additions and 124 deletions

View File

@@ -1,10 +1,8 @@
import * as http from "http";
import crypto from 'crypto';
import express from 'express';
import session from 'express-session';
import ky from 'ky';
import express, { type Express } from 'express';
import bodyParser from 'body-parser';
import type { Express } from 'express';
import { type GrocyUser, type Grocy } from './Grocy.js';
interface WebConfig {
sessionSecret?: string;
@@ -23,39 +21,22 @@ class Web {
private _webserver: http.Server | null = null;
private app: Express | null = null;
private port: number;
private options: WebConfig;
// private options: WebConfig;
private grocy: Grocy;
constructor(options: WebConfig = {}) {
this.options = options;
constructor(options: WebConfig = {}, grocy: Grocy) {
// this.options = options;
this.port = notStupidParseInt(process.env['PORT']) || options['port'] as number || 8080;
this.grocy = grocy
}
initialize = async () => {
const options = this.options;
const sessionSecret = process.env['SESSIONSECRET'] || options.sessionSecret;
const app: Express = this.app = express();
if(!sessionSecret) {
console.error('sessionSecret is required.');
throw new Error('sessionSecret is required.');
}
app.set('trust proxy', 1);
app.set('view engine', 'ejs');
app.set('view options', { outputFunctionName: 'echo' });
app.use('/assets', express.static('assets', { maxAge: '30 days' }));
app.use(session({
name: 'sessionId',
secret: sessionSecret,
resave: true,
saveUninitialized: false,
store: undefined,
cookie: {
maxAge: notStupidParseInt(process.env['COOKIETTL']) || 1000 * 60 * 60 * 24 * 30, // 30 days
httpOnly: true,
secure: !!options.secure
}
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use((_req, res, next) => {
@@ -84,11 +65,45 @@ class Web {
});
});
app.get('/ky', async (_, res) => {
res.send(await (await ky.get('https://sanin.dev')).text());
app.get('/api/chores', async (_, res) => {
const chores = await this.grocy.chores();
const users: Record<string, GrocyUser> = {};
const missing: Set<number> = new Set();
chores.forEach(chore => {
if ('next_execution_assigned_user' in chore) {
users[chore.next_execution_assigned_to_user_id] = chore.next_execution_assigned_user
}
});
chores.forEach(chore => {
if (!(chore.next_execution_assigned_to_user_id in users) && typeof chore.next_execution_assigned_to_user_id === 'number') {
missing.add(chore.next_execution_assigned_to_user_id);
}
});
(await Promise.all([...missing].map(id => this.grocy.user(id)))).forEach(user => {
if (!user) {
return;
}
users[user.id] = user;
});
chores.forEach(chore => {
if (!('next_execution_assigned_user' in chore) && chore.next_execution_assigned_to_user_id in users) {
chore.next_execution_assigned_user = users[chore.next_execution_assigned_to_user_id] as GrocyUser;
}
});
res.send({
chores
});
});
this._webserver = this.app.listen(this.port, () => console.log(`archery is running on port ${this.port}`));
app.get('/api/users/:id', async (req, res) => {
const user = await this.grocy.user(parseInt(req.params.id))
res.send({
user
});
});
this._webserver = this.app.listen(this.port, () => console.log(`chore-chart is running on port ${this.port}`));
}
close = () => {