diff --git a/src/routes.ts b/src/routes.ts index f1a23fa..558cd33 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -18,6 +18,7 @@ import { paymentRoutes } from "./payments/payment.route"; import { alertRoutes } from "./alert/alert.route"; import { analyticsRoutes } from "./analytics/analytics.routes"; import { eventRoutes } from "./events/events.route"; +import { userConfigRoutes } from "./userConfig/userConfig.route"; export default async function routes(fastify: FastifyInstance) { fastify.addHook("preHandler", authHandler); @@ -32,6 +33,7 @@ export default async function routes(fastify: FastifyInstance) { fastify.register(notificationRoutes, { prefix: "/notifications" }); fastify.register(mailProxyRoutes, { prefix: "/proxy" }); fastify.register(configRoutes, { prefix: "/config" }); + fastify.register(userConfigRoutes, { prefix: "/userConfig" }); fastify.register(viewRoutes, { prefix: "/views" }); fastify.register(processedRoutes, { prefix: "/processed" }); fastify.register(paymentRoutes, { prefix: "/payments" }); diff --git a/src/server.ts b/src/server.ts index ffa58ca..31aa7b2 100644 --- a/src/server.ts +++ b/src/server.ts @@ -24,6 +24,7 @@ import { processedSchemas } from "./processed/processed.schema"; import { cTaskSchemas } from "./ctask/ctask.schema"; import { paymentSchemas } from "./payments/payment.schema"; import { alertSchemas } from "./alert/alert.schema"; +import { userConfigSchemas } from "./userConfig/userConfig.schema"; const app = fastify({ logger: true, trustProxy: true }); @@ -56,6 +57,7 @@ for (const schema of [ ...notificationSchemas, ...noteSchemas, ...configSchemas, + ...userConfigSchemas, ...mailSchemas, ...viewSchemas, ...processedSchemas, diff --git a/src/user/user.service.ts b/src/user/user.service.ts index b23b982..11093c2 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -3,6 +3,7 @@ import { generateId, generateToken } from "../utils/id"; import { CreateUserInput, UpdateUserInput, userModel } from "./user.schema"; import { sendMail } from "../utils/mail"; import { AuthenticatedUser } from "../auth"; +import { createUserConfig } from "../userConfig/userConfig.service"; export const ErrUserNotFound = new Error("user not found"); export const ErrOpNotValid = new Error("operation is not valid"); @@ -41,6 +42,8 @@ export async function createUser( ...input, }); + await createUserConfig(newUser.id, newUser.tenantId); + const sent = await sendMail( input.email, "You have been invited to Quicker Permtis.", diff --git a/src/userConfig/userConfig.controller.ts b/src/userConfig/userConfig.controller.ts new file mode 100644 index 0000000..701af17 --- /dev/null +++ b/src/userConfig/userConfig.controller.ts @@ -0,0 +1,26 @@ +import { FastifyReply, FastifyRequest } from "fastify"; +import { getConfig, updateConfig } from "./userConfig.service"; +import { UpdateUserConfigInput } from "./userConfig.schema"; + +export async function getConfigHandler(req: FastifyRequest, res: FastifyReply) { + try { + const config = await getConfig(req.user); + return res.code(200).send(config); + } catch (err) { + return err; + } +} + +export async function updateConfigHandler( + req: FastifyRequest, + res: FastifyReply +) { + const input = req.body as UpdateUserConfigInput; + console.log(input); + try { + const updatedConfig = await updateConfig(input, req.user); + return res.code(200).send(updatedConfig); + } catch (err) { + return err; + } +} diff --git a/src/userConfig/userConfig.route.ts b/src/userConfig/userConfig.route.ts new file mode 100644 index 0000000..1e685df --- /dev/null +++ b/src/userConfig/userConfig.route.ts @@ -0,0 +1,26 @@ +import { FastifyInstance } from "fastify"; +import { getConfigHandler, updateConfigHandler } from "./userConfig.controller"; +import { $userConfig } from "./userConfig.schema"; + +export async function userConfigRoutes(fastify: FastifyInstance) { + fastify.get( + "/", + { + config: { requiredClaims: ["config:read"] }, + preHandler: [fastify.authorize], + }, + getConfigHandler + ); + + fastify.patch( + "/", + { + schema: { + body: $userConfig("updateUserConfigInput"), + }, + config: { requiredClaims: ["config:write"] }, + preHandler: [fastify.authorize], + }, + updateConfigHandler + ); +} diff --git a/src/userConfig/userConfig.schema.ts b/src/userConfig/userConfig.schema.ts new file mode 100644 index 0000000..42dd3dd --- /dev/null +++ b/src/userConfig/userConfig.schema.ts @@ -0,0 +1,30 @@ +import { buildJsonSchemas } from "fastify-zod"; +import mongoose from "mongoose"; +import { z } from "zod"; + +export const userConfigModel = mongoose.model( + "userConfig", + new mongoose.Schema({ + tenantId: String, + userId: { + type: mongoose.Types.ObjectId, + unique: true, + }, + config: Object, + }), + "userConfig" +); + +const updateUserConfigInput = z.object({ + config: z.record(z.string(), z.any()).optional(), +}); + +export type UpdateUserConfigInput = z.infer; + +export const { schemas: userConfigSchemas, $ref: $userConfig } = + buildJsonSchemas( + { + updateUserConfigInput, + }, + { $id: "userConfig" } + ); diff --git a/src/userConfig/userConfig.service.ts b/src/userConfig/userConfig.service.ts new file mode 100644 index 0000000..d00e729 --- /dev/null +++ b/src/userConfig/userConfig.service.ts @@ -0,0 +1,30 @@ +import { AuthenticatedUser } from "../auth"; +import { UpdateUserConfigInput, userConfigModel } from "./userConfig.schema"; + +export async function createUserConfig(userId: string, tenantId: string) { + await userConfigModel.create({ tenantId, userId, config: {} }); +} + +export async function getConfig(user: AuthenticatedUser) { + return await userConfigModel.findOne({ + tenantId: user.tenantId, + userId: user.userId, + }); +} + +export async function updateConfig( + input: UpdateUserConfigInput, + user: AuthenticatedUser +) { + return await userConfigModel.findOneAndUpdate( + { tenantId: user.tenantId, userId: user.userId }, + { + ...input, + }, + { new: true } + ); +} + +export async function deleteConfig(userId: string, tenantId: string) { + await userConfigModel.deleteOne({ userId: userId, tenantId: tenantId }); +}