KI-AGENT: Ergänze Kalender-Abo für Mitarbeiterprofile

This commit is contained in:
2026-05-19 16:26:49 +02:00
parent f9d3f10eae
commit 167e9a40c3
7 changed files with 392 additions and 7 deletions

View File

@@ -14,6 +14,10 @@ import {
resolveTenantTeamIds,
syncProfileTeams,
} from "../utils/profileTeams";
import {
enrichProfileWithCalendarSubscription,
generateProfileCalendarSubscriptionToken,
} from "../utils/calendarSubscription";
export default async function authProfilesRoutes(server: FastifyInstance) {
@@ -38,7 +42,7 @@ export default async function authProfilesRoutes(server: FastifyInstance) {
return reply.code(404).send({ error: "User not found or not in tenant" });
}
return profile;
return enrichProfileWithCalendarSubscription(profile);
} catch (error) {
console.error("GET /profiles/:id ERROR:", error);
@@ -50,10 +54,11 @@ export default async function authProfilesRoutes(server: FastifyInstance) {
const cleaned: any = { ...body }
// ❌ Systemfelder entfernen
const forbidden = [
"id", "user_id", "tenant_id", "created_at", "updated_at",
"updatedAt", "updatedBy", "old_profile_id", "full_name",
"branch"
const forbidden = [
"id", "user_id", "tenant_id", "created_at", "updated_at",
"updatedAt", "updatedBy", "old_profile_id", "full_name",
"branch", "calendar_subscription_token",
"calendar_subscription_path", "calendar_subscription_url"
]
forbidden.forEach(f => delete cleaned[f])
@@ -146,7 +151,7 @@ export default async function authProfilesRoutes(server: FastifyInstance) {
const [profile] = profileWithBranches
? await enrichProfilesWithTeams(server, [profileWithBranches])
: [null]
return profile || updated[0]
return enrichProfileWithCalendarSubscription(profile || updated[0])
} catch (err) {
console.error("PUT /profiles/:id ERROR:", err)
@@ -159,4 +164,31 @@ export default async function authProfilesRoutes(server: FastifyInstance) {
return reply.code(500).send({ error: "Internal Server Error" })
}
})
server.post("/profiles/:id/calendar-subscription-token", async (req, reply) => {
try {
const tenantId = req.user?.tenant_id
if (!tenantId) {
return reply.code(400).send({ error: "No tenant selected" })
}
const { id } = req.params as { id: string }
const updatedProfile = await generateProfileCalendarSubscriptionToken(server, id, tenantId)
if (!updatedProfile) {
return reply.code(404).send({ error: "User not found or not in tenant" })
}
const profileWithBranches = await loadProfileWithBranches(server, id, tenantId)
const [profile] = profileWithBranches
? await enrichProfilesWithTeams(server, [profileWithBranches])
: [updatedProfile]
return enrichProfileWithCalendarSubscription(profile)
} catch (err) {
console.error("POST /profiles/:id/calendar-subscription-token ERROR:", err)
return reply.code(500).send({ error: "Internal Server Error" })
}
})
}

View File

@@ -1,8 +1,32 @@
import { FastifyRequest, FastifyReply, FastifyInstance } from 'fastify';
import { publicLinkService } from '../../modules/publiclinks.service';
import dayjs from 'dayjs'; // Falls nicht installiert: npm install dayjs
import { buildProfileCalendarSubscriptionFeed, loadProfileByCalendarSubscriptionToken } from '../../utils/calendarSubscription';
export default async function publiclinksNonAuthenticatedRoutes(server: FastifyInstance) {
server.get("/api/public/calendar/subscriptions/:token.ics", async (req, reply) => {
const { token } = req.params as { token: string }
try {
const profile = await loadProfileByCalendarSubscriptionToken(server, token)
if (!profile || !profile.active) {
return reply.code(404).send({ error: "Kalender-Abo nicht gefunden" })
}
const icsFeed = await buildProfileCalendarSubscriptionFeed(server, profile)
reply.header("Content-Type", "text/calendar; charset=utf-8")
reply.header("Content-Disposition", `inline; filename="fedeo-${profile.id}.ics"`)
reply.header("Cache-Control", "private, max-age=300")
return reply.send(icsFeed)
} catch (error: any) {
server.log.error(error)
return reply.code(500).send({ error: "Interner Server Fehler" })
}
})
server.get("/workflows/context/:token", async (req, reply) => {
const { token } = req.params as { token: string };
const pin = req.headers['x-public-pin'] as string | undefined;
@@ -49,4 +73,4 @@ export default async function publiclinksNonAuthenticatedRoutes(server: FastifyI
return reply.code(500).send({ error: "Fehler beim Speichern", details: error.message });
}
});
}
}