import { Transaction } from 'sequelize' import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript' import { MEvent } from '@server/types/models/index.js' import { VideoChannelModel } from './video-channel.js' import { SequelizeModel } from '../shared/index.js' export enum EventState { ACTIVE = 'active', DISABLED = 'disabled' } @Table({ tableName: 'event', indexes: [ { fields: [ 'channelId' ] }, { fields: [ 'state' ] }, { fields: [ 'startTime' ] } ] }) export class EventModel extends SequelizeModel { @AllowNull(false) @Column declare title: string @AllowNull(true) @Column(DataType.TEXT) declare description: string | null @AllowNull(false) @Column declare startTime: Date @AllowNull(false) @Column declare endTime: Date @AllowNull(true) @Column declare thumbnailFilename: string | null @AllowNull(true) @Column(DataType.BLOB) declare thumbnailData: Buffer | null @AllowNull(true) @Column declare thumbnailMimeType: string | null @AllowNull(true) @Column(DataType.BIGINT) declare thumbnailSize: number | null @AllowNull(true) @Column declare thumbnailEtag: string | null @AllowNull(true) @Column(DataType.TEXT) declare liveUrl: string | null @AllowNull(false) @Default(EventState.ACTIVE) @Column declare state: EventState @CreatedAt declare createdAt: Date @UpdatedAt declare updatedAt: Date @ForeignKey(() => VideoChannelModel) @Column declare channelId: number @BelongsTo(() => VideoChannelModel, { foreignKey: { allowNull: false }, onDelete: 'cascade' }) declare Channel: Awaited static listByChannelId (channelId: number, transaction?: Transaction) { const query = { where: { channelId }, order: [ [ 'startTime', 'DESC' ] ] as any, transaction } return EventModel.findAll(query) } static findByIdAndChannelId (eventId: number, channelId: number, transaction?: Transaction) { const query = { where: { id: eventId, channelId }, transaction } return EventModel.findOne(query) } static loadByThumbnailFilename (thumbnailFilename: string, transaction?: Transaction) { return EventModel.findOne({ where: { thumbnailFilename }, transaction }) } static listPublicEvents (limit?: number, states?: string[]) { const query: any = { order: [ [ 'startTime', 'DESC' ] ] as any, limit } // Only filter by state if explicitly provided; otherwise return all events if (states && states.length > 0) { query.where = { state: states } } return EventModel.findAll(query) } static async deleteByIdAndChannelId (eventId: number, channelId: number, transaction?: Transaction) { const event = await EventModel.findByIdAndChannelId(eventId, channelId, transaction) if (!event) return false await event.destroy({ transaction }) return true } static async updateEventState (eventId: number, newState: EventState, transaction?: Transaction) { const query = { where: { id: eventId }, transaction } return EventModel.update({ state: newState }, query) } toFormattedJSON (this: EventModel) { return { id: this.id, title: this.title, description: this.description, startTime: this.startTime.toISOString(), endTime: this.endTime.toISOString(), thumbnailFilename: this.thumbnailFilename, liveUrl: this.liveUrl, state: this.state, channelId: this.channelId, createdAt: this.createdAt.toISOString(), updatedAt: this.updatedAt.toISOString() } } toLogKeys (this: EventModel) { return { id: this.id, title: this.title, state: this.state, startTime: this.startTime, endTime: this.endTime, channelId: this.channelId } } }