Prechádzať zdrojové kódy

refactor: started creating station table, and a few fixes

Kristian Vos 2 mesiacov pred
rodič
commit
2c38e4fe45

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

@@ -26,7 +26,7 @@ export type ObjectIdType = string;
 // TODO move to a better spot
 // Strange behavior would result if we extended DataTypes.ABSTRACT because
 // it's a class wrapped in a Proxy by Utils.classToInvokable.
-export class OBJECTID extends DataTypes.ABSTRACT {
+export class OBJECTID extends DataTypes.ABSTRACT.prototype.constructor {
 	// Mandatory: set the type key
 	static key = "OBJECTID";
 

+ 100 - 0
backend/src/modules/DataModule/migrations/1726319296-create-stations-table.ts

@@ -0,0 +1,100 @@
+import { Sequelize, DataTypes } from "sequelize";
+import { MigrationParams } from "umzug";
+
+export const up = async ({
+	context: sequelize
+}: MigrationParams<Sequelize>) => {
+	await sequelize.getQueryInterface().createTable("stations", {
+		_id: {
+			// eslint-disable-next-line
+			// @ts-ignore 
+			type: DataTypes.OBJECTID,
+			primaryKey: true,
+			allowNull: false
+		},
+		name: {
+			type: DataTypes.STRING,
+			allowNull: false,
+			unique: true
+		},
+		type: {
+			type: DataTypes.ENUM("official", "community"),
+			allowNull: false
+		},
+		displayName: {
+			type: DataTypes.STRING,
+			allowNull: false,
+			unique: true
+		},
+		description: {
+			type: DataTypes.STRING,
+			allowNull: false
+		},
+		paused: {
+			type: DataTypes.BOOLEAN,
+			defaultValue: false,
+			allowNull: false
+		},
+		currentSongIndex: {
+			type: DataTypes.SMALLINT,
+			defaultValue: 0,
+			allowNull: false
+		},
+		timePaused: {
+			type: DataTypes.INTEGER,
+			defaultValue: 0,
+			allowNull: false
+		},
+		pausedAt: {
+			type: DataTypes.INTEGER,
+			defaultValue: 0,
+			allowNull: false
+		},
+		startedAt: {
+			type: DataTypes.INTEGER,
+			defaultValue: 0,
+			allowNull: false
+		},
+		privacy: {
+			type: DataTypes.ENUM("public", "unlisted", "private"),
+			defaultValue: "private",
+			allowNull: false
+		},
+		owner: {
+			// eslint-disable-next-line
+			// @ts-ignore
+			type: DataTypes.OBJECTID,
+			allowNull: true
+		},
+		theme: {
+			type: DataTypes.ENUM("blue", "purple", "teal", "orange", "red"),
+			defaultValue: "blue",
+			allowNull: false
+		},
+		skipVoteThreshold: {
+			type: DataTypes.SMALLINT,
+			defaultValue: 50,
+			allowNull: false
+		},
+		createdAt: DataTypes.DATE,
+		updatedAt: DataTypes.DATE
+	});
+
+	await sequelize.getQueryInterface().addConstraint("stations", {
+		type: "foreign key",
+		fields: ["owner"],
+		references: {
+			table: "users",
+			field: "_id"
+		},
+		onDelete: "RESTRICT",
+		onUpdate: "RESTRICT"
+	});
+	// TODO add other constraints/pivots
+};
+
+export const down = async ({
+	context: sequelize
+}: MigrationParams<Sequelize>) => {
+	await sequelize.getQueryInterface().dropTable("stations");
+};

+ 39 - 32
backend/src/modules/DataModule/models/Station.ts

@@ -93,27 +93,27 @@ export const schema = {
 		defaultValue: false,
 		allowNull: false
 	},
-	// // TODO currentSong
-	// currentSongIndex: {
-	// 	type: DataTypes.NUMBER,
-	// 	defaultValue: 0,
-	// 	allowNull: false
-	// },
-	// timePaused: {
-	// 	type: DataTypes.NUMBER,
-	// 	defaultValue: 0,
-	// 	allowNull: false
-	// },
-	// pausedAt: {
-	// 	type: DataTypes.NUMBER,
-	// 	defaultValue: 0,
-	// 	allowNull: false
-	// },
-	// startedAt: {
-	// 	type: DataTypes.NUMBER,
-	// 	defaultValue: 0,
-	// 	allowNull: false
-	// },
+	// TODO currentSong
+	currentSongIndex: {
+		type: DataTypes.SMALLINT, // TODO check if max is checked against, and if we need custom validation to not go over the max
+		defaultValue: 0,
+		allowNull: false
+	},
+	timePaused: {
+		type: DataTypes.INTEGER, // TODO do we need to care about 2038?
+		defaultValue: 0,
+		allowNull: false
+	},
+	pausedAt: {
+		type: DataTypes.INTEGER,
+		defaultValue: 0,
+		allowNull: false
+	},
+	startedAt: {
+		type: DataTypes.INTEGER,
+		defaultValue: 0,
+		allowNull: false
+	},
 	// playlist: {
 	// 	type: DataTypes.OBJECTID,
 	// 	allowNull: false
@@ -123,24 +123,24 @@ export const schema = {
 		defaultValue: StationPrivacy.PRIVATE,
 		allowNull: false
 	},
-	// // TODO queue
+	// TODO queue
 	// owner: { // Only used for community stations
 	// 	type: DataTypes.OBJECTID
-	// },
-	// // TODO requests
-	// // TODO autofill
+	// }, // TODO add validator to make sure owner is required for community stations, see https://sequelize.org/docs/v6/core-concepts/validations-and-constraints/#model-wide-validations
+	// TODO requests
+	// TODO autofill
 	theme: {
 		type: DataTypes.ENUM(...Object.values(StationTheme)),
 		defaultValue: StationTheme.BLUE,
 		allowNull: false
 	},
-	// // TODO blacklist
-	// // TODO djs
-	// skipVoteThreshold: {
-	// 	type: DataTypes.NUMBER,
-	// 	defaultValue: 50,
-	// 	allowNull: false
-	// },
+	// TODO blacklist
+	// TODO djs
+	skipVoteThreshold: {
+		type: DataTypes.SMALLINT,
+		defaultValue: 50,
+		allowNull: false
+	},
 
 	createdAt: DataTypes.DATE,
 	updatedAt: DataTypes.DATE,
@@ -149,6 +149,13 @@ export const schema = {
 		get() {
 			return `stations`;
 		}
+	},
+	// Temporary
+	djs: {
+		type: DataTypes.VIRTUAL,
+		get() {
+			return [];
+		}
 	}
 };
 

+ 7 - 0
backend/src/modules/DataModule/models/User.ts

@@ -130,6 +130,13 @@ export const schema = {
 		get() {
 			return `users`;
 		}
+	},
+	// Temporary
+	favoriteStations: {
+		type: DataTypes.VIRTUAL,
+		get() {
+			return [];
+		}
 	}
 };
 

+ 1 - 1
backend/src/modules/DataModule/permissions/modelPermissions/isOwner.ts

@@ -14,7 +14,7 @@ export default (
 	else if (Object.prototype.hasOwnProperty.call(model.dataValues, "owner"))
 		ownerAttribute = "owner";
 
-	if (ownerAttribute)
+	if (ownerAttribute && model.dataValues[ownerAttribute])
 		return (
 			model.dataValues[ownerAttribute].toString() === user._id.toString()
 		);