Browse Source

refactor: further worked on the event system, with permissions for subscribing

Kristian Vos 1 month ago
parent
commit
d13cae1249

+ 3 - 1
backend/src/modules/DataModule/models/users/permissions.ts

@@ -174,7 +174,7 @@ const admin = {
 	// Frontend admin views
 	"admin.view.dataRequests": true,
 	"admin.view.statistics": true,
-	"admin.view.youtube": true
+	"admin.view.youtube": true,
 
 	// // Experimental SoundCloud
 	// ...(config.get("experimental.soundcloud")
@@ -190,6 +190,8 @@ const admin = {
 	// 			"youtube.getMissingChannels": true
 	// 	  }
 	// 	: {})
+
+	"event.model.news.created": true // WIP - regular users need to be able to subscribe to certain news subscribe events
 };
 
 const permissions: Record<

+ 20 - 9
backend/src/modules/EventsModule/jobs/Subscribe.ts

@@ -1,6 +1,9 @@
 import Job, { JobOptions } from "@/Job";
 import EventsModule from "@/modules/EventsModule";
 
+const channelRegex =
+	/^(?<moduleName>[a-z]+)\.(?<modelName>[A-z]+)\.(?<event>[A-z]+):?(?<modelId>[A-z0-9]+)?$/;
+
 export default class Subscribe extends Job {
 	protected static _hasPermission = true;
 
@@ -16,18 +19,26 @@ export default class Subscribe extends Job {
 			throw new Error("Channel must be a string");
 	}
 
-	protected override async _authorize() {}
+	protected override async _authorize() {
+		const { channel } = this._payload;
+
+		const { moduleName, modelName, event, modelId } =
+			channelRegex.exec(channel)?.groups ?? {};
 
-	// protected override async _authorize() {
-	// const [path, scope] = this._payload.channel.split(":");
+		let permission = `event.${channel}`;
 
-	// const EventClass = EventsModule.getEvent(path);
+		if (
+			moduleName === "data" &&
+			modelName &&
+			(modelId || event === "created")
+		) {
+			if (event === "created")
+				permission = `event.model.${modelName}.created`;
+			else permission = `data.${modelName}.findById.${modelId}`;
+		}
 
-	// const hasPermission = EventClass.hasPermission(
-	// 	this._context.getUser(),
-	// 	scope
-	// );
-	// }
+		await this._context.assertPermission(permission);
+	}
 
 	protected async _execute() {
 		const socketId = this._context.getSocketId();

+ 19 - 21
backend/src/modules/EventsModule/jobs/SubscribeMany.ts

@@ -2,7 +2,7 @@ import Job, { JobOptions } from "@/Job";
 import EventsModule from "@/modules/EventsModule";
 
 const channelRegex =
-	/^(?<moduleName>[a-z]+)\.(?<modelName>[A-z]+)\.(?<event>[A-z]+)\.?(?<modelId>[A-z0-9]+)?$/;
+	/^(?<moduleName>[a-z]+)\.(?<modelName>[A-z]+)\.(?<event>[A-z]+):?(?<modelId>[A-z0-9]+)?$/;
 
 export default class SubscribeMany extends Job {
 	protected static _hasPermission = true;
@@ -24,30 +24,28 @@ export default class SubscribeMany extends Job {
 		});
 	}
 
-	protected override async _authorize() {}
+	protected override async _authorize() {
+		const permissions = this._payload.channels.map((channel: string) => {
+			const { moduleName, modelName, event, modelId } =
+				channelRegex.exec(channel)?.groups ?? {};
 
-	// protected override async _authorize() {
-	// const permissions = this._payload.channels.map((channel: string) => {
-	// 	const { moduleName, modelName, event, modelId } =
-	// 		channelRegex.exec(channel)?.groups ?? {};
+			let permission = `event.${channel}`;
 
-	// 	let permission = `event.${channel}`;
+			if (
+				moduleName === "data" &&
+				modelName &&
+				(modelId || event === "created")
+			) {
+				if (event === "created")
+					permission = `event.model.${modelName}.created`;
+				else permission = `data.${modelName}.findById.${modelId}`;
+			}
 
-	// 	if (
-	// 		moduleName === "model" &&
-	// 		modelName &&
-	// 		(modelId || event === "created")
-	// 	) {
-	// 		if (event === "created")
-	// 			permission = `event.model.${modelName}.created`;
-	// 		else permission = `data.${modelName}.findById.${modelId}`;
-	// 	}
-
-	// 	return permission;
-	// });
+			return permission;
+		});
 
-	// await this._context.assertPermissions(permissions);
-	// }
+		await this._context.assertPermissions(permissions);
+	}
 
 	protected async _execute() {
 		const socketId = this._context.getSocketId();

+ 1 - 1
backend/src/modules/WebSocketModule.ts

@@ -13,7 +13,7 @@ import DataModule from "./DataModule";
 import { UserModel } from "./DataModule/models/users/schema";
 import { SessionModel } from "./DataModule/models/sessions/schema";
 import EventsModule from "./EventsModule";
-import assertEventDerived from "@/utils/assertEventDerived";
+// import assertEventDerived from "@/utils/assertEventDerived";
 
 export class WebSocketModule extends BaseModule {
 	private _httpServer?: Server;

+ 1 - 1
backend/src/utils/assertEventDerived.ts

@@ -1,7 +1,7 @@
 import Event from "@/modules/EventsModule/Event";
 
 // eslint-disable-next-line @typescript-eslint/ban-types
-export default (EventClass: Function) => {
+export default (EventClass: Event) => {
 	// Make sure the provided EventClass has Event as the parent somewhere as a parent. Not Event itself, as that constructor requires an additional constructor parameter
 	// So any class that extends Event, or that extends another class that extends Event, will be allowed.
 	let classPrototype = Object.getPrototypeOf(EventClass);