add changes

This commit is contained in:
AD2025
2025-11-12 23:06:27 +02:00
parent c664d0a341
commit ec6534fcc2
42 changed files with 11854 additions and 299 deletions

View File

@@ -0,0 +1,114 @@
const { v4: uuidv4 } = require('uuid');
module.exports = (sequelize, DataTypes) => {
const GuestSettings = sequelize.define('GuestSettings', {
id: {
type: DataTypes.CHAR(36),
primaryKey: true,
defaultValue: () => uuidv4(),
allowNull: false,
comment: 'UUID primary key'
},
maxQuizzes: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 3,
validate: {
min: {
args: [1],
msg: 'Maximum quizzes must be at least 1'
},
max: {
args: [50],
msg: 'Maximum quizzes cannot exceed 50'
}
},
field: 'max_quizzes',
comment: 'Maximum number of quizzes a guest can take'
},
expiryHours: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 24,
validate: {
min: {
args: [1],
msg: 'Expiry hours must be at least 1'
},
max: {
args: [168],
msg: 'Expiry hours cannot exceed 168 (7 days)'
}
},
field: 'expiry_hours',
comment: 'Guest session expiry time in hours'
},
publicCategories: {
type: DataTypes.JSON,
allowNull: false,
defaultValue: [],
get() {
const value = this.getDataValue('publicCategories');
if (typeof value === 'string') {
try {
return JSON.parse(value);
} catch (e) {
return [];
}
}
return value || [];
},
set(value) {
this.setDataValue('publicCategories', JSON.stringify(value));
},
field: 'public_categories',
comment: 'Array of category UUIDs accessible to guests'
},
featureRestrictions: {
type: DataTypes.JSON,
allowNull: false,
defaultValue: {
allowBookmarks: false,
allowReview: true,
allowPracticeMode: true,
allowTimedMode: false,
allowExamMode: false
},
get() {
const value = this.getDataValue('featureRestrictions');
if (typeof value === 'string') {
try {
return JSON.parse(value);
} catch (e) {
return {
allowBookmarks: false,
allowReview: true,
allowPracticeMode: true,
allowTimedMode: false,
allowExamMode: false
};
}
}
return value || {
allowBookmarks: false,
allowReview: true,
allowPracticeMode: true,
allowTimedMode: false,
allowExamMode: false
};
},
set(value) {
this.setDataValue('featureRestrictions', JSON.stringify(value));
},
field: 'feature_restrictions',
comment: 'Feature restrictions for guest users'
}
}, {
tableName: 'guest_settings',
timestamps: true,
underscored: true,
comment: 'System-wide guest user settings'
});
return GuestSettings;
};

View File

@@ -164,6 +164,32 @@ module.exports = (sequelize) => {
tableName: 'quiz_sessions',
timestamps: true,
underscored: true,
indexes: [
{
fields: ['user_id']
},
{
fields: ['guest_session_id']
},
{
fields: ['category_id']
},
{
fields: ['status']
},
{
fields: ['created_at']
},
{
fields: ['user_id', 'created_at']
},
{
fields: ['guest_session_id', 'created_at']
},
{
fields: ['category_id', 'status']
}
],
hooks: {
beforeValidate: (session) => {
// Generate UUID if not provided

View File

@@ -32,6 +32,21 @@ module.exports = (sequelize) => {
timestamps: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
indexes: [
{
fields: ['quiz_session_id']
},
{
fields: ['question_id']
},
{
fields: ['quiz_session_id', 'question_order']
},
{
unique: true,
fields: ['quiz_session_id', 'question_id']
}
],
hooks: {
beforeValidate: (quizSessionQuestion) => {
if (!quizSessionQuestion.id) {

View File

@@ -0,0 +1,96 @@
/**
* UserBookmark Model
* Junction table for user-saved questions
*/
const { DataTypes } = require('sequelize');
const { v4: uuidv4 } = require('uuid');
module.exports = (sequelize) => {
const UserBookmark = sequelize.define('UserBookmark', {
id: {
type: DataTypes.UUID,
defaultValue: () => uuidv4(),
primaryKey: true,
allowNull: false,
comment: 'Primary key UUID'
},
userId: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'users',
key: 'id'
},
onDelete: 'CASCADE',
comment: 'Reference to user who bookmarked'
},
questionId: {
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'questions',
key: 'id'
},
onDelete: 'CASCADE',
comment: 'Reference to bookmarked question'
},
notes: {
type: DataTypes.TEXT,
allowNull: true,
comment: 'Optional notes about the bookmark'
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
field: 'created_at',
comment: 'When the bookmark was created'
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
field: 'updated_at',
comment: 'When the bookmark was last updated'
}
}, {
tableName: 'user_bookmarks',
timestamps: true,
underscored: true,
indexes: [
{
unique: true,
fields: ['user_id', 'question_id'],
name: 'idx_user_question_unique'
},
{
fields: ['user_id'],
name: 'idx_user_bookmarks_user'
},
{
fields: ['question_id'],
name: 'idx_user_bookmarks_question'
},
{
fields: ['bookmarked_at'],
name: 'idx_user_bookmarks_date'
}
]
});
// Define associations
UserBookmark.associate = function(models) {
UserBookmark.belongsTo(models.User, {
foreignKey: 'userId',
as: 'User'
});
UserBookmark.belongsTo(models.Question, {
foreignKey: 'questionId',
as: 'Question'
});
};
return UserBookmark;
};