mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
85 lines
3.4 KiB
JavaScript
85 lines
3.4 KiB
JavaScript
/***********************************************************************************************************************************************************************
|
|
* File Name: completion_requirement_progress.mdl.js
|
|
* Type of Program: Model
|
|
* Description: Per-user tracking state for a CompletionRequirement, for the requirement types that need
|
|
* genuinely new storage (watch_percent's running progress_percent, watch_video/listen_audio's
|
|
* per-block progress_percent map, and manual_complete's completed flag — pass_quiz reads
|
|
* QuizAttempt.passed directly, and read_all_content reads CourseReadingProgress directly;
|
|
* neither needs a row here).
|
|
*
|
|
* CompletionRequirementProgress — UPSERT key: (requirement_id, user_id).
|
|
*
|
|
* Author: Kenneth Obsequio (@lash0000)
|
|
* Date Created: Jul. 14, 2026
|
|
***********************************************************************************************************************************************************************/
|
|
const { DataTypes } = require('sequelize');
|
|
const sequelize = require('../../config/db.config');
|
|
|
|
const CompletionRequirementProgress = sequelize.define('CompletionRequirementProgress', {
|
|
progress_id: {
|
|
type: DataTypes.UUID,
|
|
defaultValue: DataTypes.UUIDV4,
|
|
primaryKey: true,
|
|
},
|
|
requirement_id: {
|
|
type: DataTypes.UUID,
|
|
allowNull: false,
|
|
references: { model: 'completion_requirements', key: 'requirement_id' },
|
|
onDelete: 'CASCADE',
|
|
},
|
|
user_id: {
|
|
type: DataTypes.BIGINT,
|
|
allowNull: false,
|
|
references: { model: 'users', key: 'user_id' },
|
|
onDelete: 'CASCADE',
|
|
},
|
|
entity_type: {
|
|
type: DataTypes.ENUM('course', 'unit', 'lesson'),
|
|
allowNull: false,
|
|
comment: 'Denormalized from the requirement row to avoid a join on every read.',
|
|
},
|
|
entity_id: {
|
|
type: DataTypes.BIGINT,
|
|
allowNull: false,
|
|
comment: 'Denormalized from the requirement row.',
|
|
},
|
|
progress_percent: {
|
|
type: DataTypes.INTEGER,
|
|
allowNull: true,
|
|
comment: 'watch_percent only — running max % watched.',
|
|
},
|
|
block_progress: {
|
|
type: DataTypes.JSONB,
|
|
allowNull: true,
|
|
comment: 'watch_video/listen_audio only — { [block_id]: percent } running max per matching block; completed once every current block of that type is at 100.',
|
|
},
|
|
completed: {
|
|
type: DataTypes.BOOLEAN,
|
|
allowNull: false,
|
|
defaultValue: false,
|
|
},
|
|
completed_at: {
|
|
type: DataTypes.DATE,
|
|
allowNull: true,
|
|
},
|
|
|
|
// ── Audit trails ────────────────────────────────────────────────────────
|
|
createdBy: { type: DataTypes.BIGINT, allowNull: true },
|
|
updatedBy: { type: DataTypes.BIGINT, allowNull: true },
|
|
}, {
|
|
tableName: 'completion_requirement_progress',
|
|
timestamps: true,
|
|
paranoid: false, // progress rows are never soft-deleted, matches CourseReadingProgress
|
|
indexes: [
|
|
{
|
|
unique: true,
|
|
fields: ['requirement_id', 'user_id'],
|
|
name: 'uq_crp2_requirement_user',
|
|
},
|
|
{ fields: ['user_id'], name: 'idx_crp2_user_id' },
|
|
{ fields: ['entity_type', 'entity_id'], name: 'idx_crp2_entity_type_entity_id' },
|
|
],
|
|
});
|
|
|
|
module.exports = CompletionRequirementProgress;
|