From 16c016e8b1d5ca46343d3363f9a49e24c5d7c944 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 12 May 2021 14:09:04 +0200 Subject: [PATCH] Stricter models typing --- server/controllers/activitypub/utils.ts | 1 - server/controllers/api/users/index.ts | 22 ++++++++++++------- server/controllers/api/videos/import.ts | 9 +++++--- server/controllers/api/videos/index.ts | 4 ++-- server/helpers/database-utils.ts | 4 ++-- server/lib/activitypub/actor.ts | 3 +-- server/lib/job-queue/handlers/video-views.ts | 4 ++-- server/lib/video-channel.ts | 4 +--- server/lib/video.ts | 2 ++ server/models/abuse/abuse-message.ts | 3 ++- server/models/abuse/abuse.ts | 3 ++- server/models/abuse/video-abuse.ts | 3 ++- server/models/abuse/video-comment-abuse.ts | 3 ++- server/models/account/account-blocklist.ts | 3 ++- server/models/account/account-video-rate.ts | 3 ++- server/models/account/account.ts | 3 ++- server/models/actor/actor-follow.ts | 5 +++-- server/models/actor/actor-image.ts | 3 ++- server/models/actor/actor.ts | 3 ++- server/models/application/application.ts | 5 +++-- server/models/oauth/oauth-client.ts | 3 ++- server/models/oauth/oauth-token.ts | 3 ++- server/models/redundancy/video-redundancy.ts | 3 ++- server/models/server/plugin.ts | 3 ++- server/models/server/server-blocklist.ts | 3 ++- server/models/server/server.ts | 3 ++- server/models/server/tracker.ts | 3 ++- server/models/server/video-tracker.ts | 3 ++- .../models/user/user-notification-setting.ts | 3 ++- server/models/user/user-notification.ts | 3 ++- server/models/user/user-video-history.ts | 7 +++--- server/models/user/user.ts | 3 ++- server/models/utils.ts | 7 +++--- server/models/video/schedule-video-update.ts | 9 ++++---- server/models/video/tag.ts | 3 ++- server/models/video/thumbnail.ts | 3 ++- server/models/video/video-blacklist.ts | 3 ++- server/models/video/video-caption.ts | 3 ++- server/models/video/video-change-ownership.ts | 3 ++- server/models/video/video-channel.ts | 3 ++- server/models/video/video-comment.ts | 3 ++- server/models/video/video-file.ts | 3 ++- server/models/video/video-import.ts | 3 ++- server/models/video/video-live.ts | 3 ++- server/models/video/video-playlist-element.ts | 6 +++-- server/models/video/video-playlist.ts | 3 ++- server/models/video/video-query-builder.ts | 22 +++++++++---------- server/models/video/video-share.ts | 3 ++- .../models/video/video-streaming-playlist.ts | 3 ++- server/models/video/video-tag.ts | 3 ++- server/models/video/video-view.ts | 5 +++-- server/models/video/video.ts | 9 ++++---- server/types/sequelize.ts | 5 +++-- shared/core-utils/miscs/types.ts | 4 ++++ 54 files changed, 146 insertions(+), 93 deletions(-) diff --git a/server/controllers/activitypub/utils.ts b/server/controllers/activitypub/utils.ts index 599cf48ab..19bdd58eb 100644 --- a/server/controllers/activitypub/utils.ts +++ b/server/controllers/activitypub/utils.ts @@ -3,7 +3,6 @@ import * as express from 'express' function activityPubResponse (data: any, res: express.Response) { return res.type('application/activity+json; charset=utf-8') .json(data) - .end() } export { diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts index c655d1648..f384f0f28 100644 --- a/server/controllers/api/users/index.ts +++ b/server/controllers/api/users/index.ts @@ -323,14 +323,20 @@ async function updateUser (req: express.Request, res: express.Response) { const oldUserAuditView = new UserAuditView(userToUpdate.toFormattedJSON()) const roleChanged = body.role !== undefined && body.role !== userToUpdate.role - if (body.password !== undefined) userToUpdate.password = body.password - if (body.email !== undefined) userToUpdate.email = body.email - if (body.emailVerified !== undefined) userToUpdate.emailVerified = body.emailVerified - if (body.videoQuota !== undefined) userToUpdate.videoQuota = body.videoQuota - if (body.videoQuotaDaily !== undefined) userToUpdate.videoQuotaDaily = body.videoQuotaDaily - if (body.role !== undefined) userToUpdate.role = body.role - if (body.adminFlags !== undefined) userToUpdate.adminFlags = body.adminFlags - if (body.pluginAuth !== undefined) userToUpdate.pluginAuth = body.pluginAuth + const keysToUpdate: (keyof UserUpdate)[] = [ + 'password', + 'email', + 'emailVerified', + 'videoQuota', + 'videoQuotaDaily', + 'role', + 'adminFlags', + 'pluginAuth' + ] + + for (const key of keysToUpdate) { + if (body[key] !== undefined) userToUpdate.set(key, body[key]) + } const user = await userToUpdate.save() diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index 4ed58f978..2c225315c 100644 --- a/server/controllers/api/videos/import.ts +++ b/server/controllers/api/videos/import.ts @@ -5,6 +5,7 @@ import * as parseTorrent from 'parse-torrent' import { join } from 'path' import { getEnabledResolutions } from '@server/lib/config' import { setVideoTags } from '@server/lib/video' +import { FilteredModelAttributes } from '@server/types' import { MChannelAccountDefault, MThumbnail, @@ -15,7 +16,7 @@ import { MVideoThumbnail, MVideoWithBlacklistLight } from '@server/types/models' -import { MVideoImport, MVideoImportFormattable } from '@server/types/models/video/video-import' +import { MVideoImportFormattable } from '@server/types/models/video/video-import' import { ServerErrorCode, VideoImportCreate, VideoImportState, VideoPrivacy, VideoState } from '../../../../shared' import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' @@ -253,7 +254,9 @@ function buildVideo (channelId: number, body: VideoImportCreate, importData: You privacy: body.privacy || VideoPrivacy.PRIVATE, duration: 0, // duration will be set by the import job channelId: channelId, - originallyPublishedAt: body.originallyPublishedAt || importData.originallyPublishedAt + originallyPublishedAt: body.originallyPublishedAt + ? new Date(body.originallyPublishedAt) + : importData.originallyPublishedAt } const video = new VideoModel(videoData) video.url = getLocalVideoActivityPubUrl(video) @@ -317,7 +320,7 @@ async function insertIntoDB (parameters: { previewModel: MThumbnail videoChannel: MChannelAccountDefault tags: string[] - videoImportAttributes: Partial + videoImportAttributes: FilteredModelAttributes user: MUser }): Promise { const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index c32626d30..f5ce15074 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -308,7 +308,7 @@ async function addVideo (options: { if (videoInfo.scheduleUpdate) { await ScheduleVideoUpdateModel.create({ videoId: video.id, - updateAt: videoInfo.scheduleUpdate.updateAt, + updateAt: new Date(videoInfo.scheduleUpdate.updateAt), privacy: videoInfo.scheduleUpdate.privacy || null }, { transaction: t }) } @@ -435,7 +435,7 @@ async function updateVideo (req: express.Request, res: express.Response) { if (videoInfoToUpdate.scheduleUpdate) { await ScheduleVideoUpdateModel.upsert({ videoId: videoInstanceUpdated.id, - updateAt: videoInfoToUpdate.scheduleUpdate.updateAt, + updateAt: new Date(videoInfoToUpdate.scheduleUpdate.updateAt), privacy: videoInfoToUpdate.scheduleUpdate.privacy || null }, { transaction: t }) } else if (videoInfoToUpdate.scheduleUpdate === null) { diff --git a/server/helpers/database-utils.ts b/server/helpers/database-utils.ts index f9cb33aca..7befa2c49 100644 --- a/server/helpers/database-utils.ts +++ b/server/helpers/database-utils.ts @@ -68,7 +68,7 @@ function transactionRetryer (func: (err: any, data: T) => any) { }) } -function updateInstanceWithAnother > (instanceToUpdate: Model, baseInstance: Model) { +function updateInstanceWithAnother > (instanceToUpdate: T, baseInstance: U) { const obj = baseInstance.toJSON() for (const key of Object.keys(obj)) { @@ -88,7 +88,7 @@ function afterCommitIfTransaction (t: Transaction, fn: Function) { return fn() } -function deleteNonExistingModels > ( +function deleteNonExistingModels > ( fromDatabase: T[], newModels: T[], t: Transaction diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index 8865b6277..1bcee7ef9 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts @@ -132,12 +132,11 @@ async function getOrCreateActorAndServerAndModel ( return actorRefreshed } -function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) { +function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string) { return new ActorModel({ type, url, preferredUsername, - uuid, publicKey: null, privateKey: null, followersCount: 0, diff --git a/server/lib/job-queue/handlers/video-views.ts b/server/lib/job-queue/handlers/video-views.ts index 897235ec0..86d0a271f 100644 --- a/server/lib/job-queue/handlers/video-views.ts +++ b/server/lib/job-queue/handlers/video-views.ts @@ -36,8 +36,8 @@ async function processVideosViews () { } await VideoViewModel.create({ - startDate, - endDate, + startDate: new Date(startDate), + endDate: new Date(endDate), views, videoId }) diff --git a/server/lib/video-channel.ts b/server/lib/video-channel.ts index 0476cb2d5..d57e832fe 100644 --- a/server/lib/video-channel.ts +++ b/server/lib/video-channel.ts @@ -1,5 +1,4 @@ import * as Sequelize from 'sequelize' -import { v4 as uuidv4 } from 'uuid' import { VideoChannelCreate } from '../../shared/models' import { VideoModel } from '../models/video/video' import { VideoChannelModel } from '../models/video/video-channel' @@ -9,9 +8,8 @@ import { getLocalVideoChannelActivityPubUrl } from './activitypub/url' import { federateVideoIfNeeded } from './activitypub/videos' async function createLocalVideoChannel (videoChannelInfo: VideoChannelCreate, account: MAccountId, t: Sequelize.Transaction) { - const uuid = uuidv4() const url = getLocalVideoChannelActivityPubUrl(videoChannelInfo.name) - const actorInstance = buildActorInstance('Group', url, videoChannelInfo.name, uuid) + const actorInstance = buildActorInstance('Group', url, videoChannelInfo.name) const actorInstanceCreated = await actorInstance.save({ transaction: t }) diff --git a/server/lib/video.ts b/server/lib/video.ts index 21e4b7ff2..d26cf85cd 100644 --- a/server/lib/video.ts +++ b/server/lib/video.ts @@ -28,6 +28,8 @@ function buildLocalVideoFromReq (videoInfo: VideoCreate, channelId: number): Fil privacy: videoInfo.privacy || VideoPrivacy.PRIVATE, channelId: channelId, originallyPublishedAt: videoInfo.originallyPublishedAt + ? new Date(videoInfo.originallyPublishedAt) + : null } } diff --git a/server/models/abuse/abuse-message.ts b/server/models/abuse/abuse-message.ts index 7e51b3e07..2c5987e96 100644 --- a/server/models/abuse/abuse-message.ts +++ b/server/models/abuse/abuse-message.ts @@ -1,6 +1,7 @@ import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { isAbuseMessageValid } from '@server/helpers/custom-validators/abuses' import { MAbuseMessage, MAbuseMessageFormattable } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { AbuseMessage } from '@shared/models' import { AccountModel, ScopeNames as AccountScopeNames } from '../account/account' import { getSort, throwIfNotValid } from '../utils' @@ -17,7 +18,7 @@ import { AbuseModel } from './abuse' } ] }) -export class AbuseMessageModel extends Model { +export class AbuseMessageModel extends Model>> { @AllowNull(false) @Is('AbuseMessage', value => throwIfNotValid(value, isAbuseMessageValid, 'message')) diff --git a/server/models/abuse/abuse.ts b/server/models/abuse/abuse.ts index 262f364f1..ffe109c2f 100644 --- a/server/models/abuse/abuse.ts +++ b/server/models/abuse/abuse.ts @@ -16,6 +16,7 @@ import { UpdatedAt } from 'sequelize-typescript' import { isAbuseModerationCommentValid, isAbuseReasonValid, isAbuseStateValid } from '@server/helpers/custom-validators/abuses' +import { AttributesOnly } from '@shared/core-utils' import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse' import { AbuseFilter, @@ -187,7 +188,7 @@ export enum ScopeNames { } ] }) -export class AbuseModel extends Model { +export class AbuseModel extends Model>> { @AllowNull(false) @Default(null) diff --git a/server/models/abuse/video-abuse.ts b/server/models/abuse/video-abuse.ts index 90aa0695e..95bff50d0 100644 --- a/server/models/abuse/video-abuse.ts +++ b/server/models/abuse/video-abuse.ts @@ -1,4 +1,5 @@ import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' +import { AttributesOnly } from '@shared/core-utils' import { VideoDetails } from '@shared/models' import { VideoModel } from '../video/video' import { AbuseModel } from './abuse' @@ -14,7 +15,7 @@ import { AbuseModel } from './abuse' } ] }) -export class VideoAbuseModel extends Model { +export class VideoAbuseModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/abuse/video-comment-abuse.ts b/server/models/abuse/video-comment-abuse.ts index d3fce76a5..32cb2ca64 100644 --- a/server/models/abuse/video-comment-abuse.ts +++ b/server/models/abuse/video-comment-abuse.ts @@ -1,4 +1,5 @@ import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' +import { AttributesOnly } from '@shared/core-utils' import { VideoCommentModel } from '../video/video-comment' import { AbuseModel } from './abuse' @@ -13,7 +14,7 @@ import { AbuseModel } from './abuse' } ] }) -export class VideoCommentAbuseModel extends Model { +export class VideoCommentAbuseModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/account/account-blocklist.ts b/server/models/account/account-blocklist.ts index 9f3be22bd..b2375b006 100644 --- a/server/models/account/account-blocklist.ts +++ b/server/models/account/account-blocklist.ts @@ -1,6 +1,7 @@ import { Op } from 'sequelize' import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' import { MAccountBlocklist, MAccountBlocklistAccounts, MAccountBlocklistFormattable } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { AccountBlock } from '../../../shared/models' import { ActorModel } from '../actor/actor' import { ServerModel } from '../server/server' @@ -40,7 +41,7 @@ enum ScopeNames { } ] }) -export class AccountBlocklistModel extends Model { +export class AccountBlocklistModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/account/account-video-rate.ts b/server/models/account/account-video-rate.ts index 576a44576..ee6dbc6da 100644 --- a/server/models/account/account-video-rate.ts +++ b/server/models/account/account-video-rate.ts @@ -7,6 +7,7 @@ import { MAccountVideoRateAccountVideo, MAccountVideoRateFormattable } from '@server/types/models/video/video-rate' +import { AttributesOnly } from '@shared/core-utils' import { AccountVideoRate } from '../../../shared' import { VideoRateType } from '../../../shared/models/videos' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' @@ -42,7 +43,7 @@ import { AccountModel } from './account' } ] }) -export class AccountVideoRateModel extends Model { +export class AccountVideoRateModel extends Model>> { @AllowNull(false) @Column(DataType.ENUM(...values(VIDEO_RATE_TYPES))) diff --git a/server/models/account/account.ts b/server/models/account/account.ts index 7b2af706d..9db109bf8 100644 --- a/server/models/account/account.ts +++ b/server/models/account/account.ts @@ -17,6 +17,7 @@ import { UpdatedAt } from 'sequelize-typescript' import { ModelCache } from '@server/models/model-cache' +import { AttributesOnly } from '@shared/core-utils' import { Account, AccountSummary } from '../../../shared/models/actors' import { isAccountDescriptionValid } from '../../helpers/custom-validators/accounts' import { CONSTRAINTS_FIELDS, SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants' @@ -141,7 +142,7 @@ export type SummaryOptions = { } ] }) -export class AccountModel extends Model { +export class AccountModel extends Model>> { @AllowNull(false) @Column diff --git a/server/models/actor/actor-follow.ts b/server/models/actor/actor-follow.ts index 4c5f37620..3a09e51d6 100644 --- a/server/models/actor/actor-follow.ts +++ b/server/models/actor/actor-follow.ts @@ -28,6 +28,7 @@ import { MActorFollowFormattable, MActorFollowSubscriptions } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { ActivityPubActorType } from '@shared/models' import { FollowState } from '../../../shared/models/actors' import { ActorFollow } from '../../../shared/models/actors/follow.model' @@ -61,7 +62,7 @@ import { ActorModel, unusedActorAttributesForAPI } from './actor' } ] }) -export class ActorFollowModel extends Model { +export class ActorFollowModel extends Model>> { @AllowNull(false) @Column(DataType.ENUM(...values(FOLLOW_STATES))) @@ -619,7 +620,7 @@ export class ActorFollowModel extends Model { if (serverIds.length === 0) return const me = await getServerActor() - const serverIdsString = createSafeIn(ActorFollowModel, serverIds) + const serverIdsString = createSafeIn(ActorFollowModel.sequelize, serverIds) const query = `UPDATE "actorFollow" SET "score" = LEAST("score" + ${value}, ${ACTOR_FOLLOW_SCORE.MAX}) ` + 'WHERE id IN (' + diff --git a/server/models/actor/actor-image.ts b/server/models/actor/actor-image.ts index ae05b4969..a35f9edb0 100644 --- a/server/models/actor/actor-image.ts +++ b/server/models/actor/actor-image.ts @@ -2,6 +2,7 @@ import { remove } from 'fs-extra' import { join } from 'path' import { AfterDestroy, AllowNull, Column, CreatedAt, Default, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { MActorImageFormattable } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { ActorImageType } from '@shared/models' import { ActorImage } from '../../../shared/models/actors/actor-image.model' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' @@ -19,7 +20,7 @@ import { throwIfNotValid } from '../utils' } ] }) -export class ActorImageModel extends Model { +export class ActorImageModel extends Model>> { @AllowNull(false) @Column diff --git a/server/models/actor/actor.ts b/server/models/actor/actor.ts index 5cf6fb8f1..65c53f8f8 100644 --- a/server/models/actor/actor.ts +++ b/server/models/actor/actor.ts @@ -18,6 +18,7 @@ import { UpdatedAt } from 'sequelize-typescript' import { ModelCache } from '@server/models/model-cache' +import { AttributesOnly } from '@shared/core-utils' import { ActivityIconObject, ActivityPubActorType } from '../../../shared/models/activitypub' import { ActorImage } from '../../../shared/models/actors/actor-image.model' import { activityPubContextify } from '../../helpers/activitypub' @@ -159,7 +160,7 @@ export const unusedActorAttributesForAPI = [ } ] }) -export class ActorModel extends Model { +export class ActorModel extends Model>> { @AllowNull(false) @Column(DataType.ENUM(...values(ACTIVITY_PUB_ACTOR_TYPES))) diff --git a/server/models/application/application.ts b/server/models/application/application.ts index 21f8b1cbc..5531d134a 100644 --- a/server/models/application/application.ts +++ b/server/models/application/application.ts @@ -1,6 +1,7 @@ +import * as memoizee from 'memoizee' import { AllowNull, Column, Default, DefaultScope, HasOne, IsInt, Model, Table } from 'sequelize-typescript' +import { AttributesOnly } from '@shared/core-utils' import { AccountModel } from '../account/account' -import * as memoizee from 'memoizee' export const getServerActor = memoizee(async function () { const application = await ApplicationModel.load() @@ -24,7 +25,7 @@ export const getServerActor = memoizee(async function () { tableName: 'application', timestamps: false }) -export class ApplicationModel extends Model { +export class ApplicationModel extends Model>> { @AllowNull(false) @Default(0) diff --git a/server/models/oauth/oauth-client.ts b/server/models/oauth/oauth-client.ts index 8dbc1c2f5..890954bdb 100644 --- a/server/models/oauth/oauth-client.ts +++ b/server/models/oauth/oauth-client.ts @@ -1,4 +1,5 @@ import { AllowNull, Column, CreatedAt, DataType, HasMany, Model, Table, UpdatedAt } from 'sequelize-typescript' +import { AttributesOnly } from '@shared/core-utils' import { OAuthTokenModel } from './oauth-token' @Table({ @@ -14,7 +15,7 @@ import { OAuthTokenModel } from './oauth-token' } ] }) -export class OAuthClientModel extends Model { +export class OAuthClientModel extends Model>> { @AllowNull(false) @Column diff --git a/server/models/oauth/oauth-token.ts b/server/models/oauth/oauth-token.ts index aa512a985..af4b0ec42 100644 --- a/server/models/oauth/oauth-token.ts +++ b/server/models/oauth/oauth-token.ts @@ -15,6 +15,7 @@ import { import { TokensCache } from '@server/lib/auth/tokens-cache' import { MUserAccountId } from '@server/types/models' import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token' +import { AttributesOnly } from '@shared/core-utils' import { logger } from '../../helpers/logger' import { AccountModel } from '../account/account' import { ActorModel } from '../actor/actor' @@ -78,7 +79,7 @@ enum ScopeNames { } ] }) -export class OAuthTokenModel extends Model { +export class OAuthTokenModel extends Model>> { @AllowNull(false) @Column diff --git a/server/models/redundancy/video-redundancy.ts b/server/models/redundancy/video-redundancy.ts index b6538c8fd..ef780c2a4 100644 --- a/server/models/redundancy/video-redundancy.ts +++ b/server/models/redundancy/video-redundancy.ts @@ -16,6 +16,7 @@ import { } from 'sequelize-typescript' import { getServerActor } from '@server/models/application/application' import { MActor, MVideoForRedundancyAPI, MVideoRedundancy, MVideoRedundancyAP, MVideoRedundancyVideo } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { VideoRedundanciesTarget } from '@shared/models/redundancy/video-redundancies-filters.model' import { FileRedundancyInformation, @@ -84,7 +85,7 @@ export enum ScopeNames { } ] }) -export class VideoRedundancyModel extends Model { +export class VideoRedundancyModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/server/plugin.ts b/server/models/server/plugin.ts index 94c9b04bf..8bb9649da 100644 --- a/server/models/server/plugin.ts +++ b/server/models/server/plugin.ts @@ -1,6 +1,7 @@ import { FindAndCountOptions, json, QueryTypes } from 'sequelize' import { AllowNull, Column, CreatedAt, DataType, DefaultScope, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { MPlugin, MPluginFormattable } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { PeerTubePlugin, PluginType, RegisterServerSettingOptions } from '../../../shared/models' import { isPluginDescriptionValid, @@ -26,7 +27,7 @@ import { getSort, throwIfNotValid } from '../utils' } ] }) -export class PluginModel extends Model { +export class PluginModel extends Model>> { @AllowNull(false) @Is('PluginName', value => throwIfNotValid(value, isPluginNameValid, 'name')) diff --git a/server/models/server/server-blocklist.ts b/server/models/server/server-blocklist.ts index 4dc236537..b3579d589 100644 --- a/server/models/server/server-blocklist.ts +++ b/server/models/server/server-blocklist.ts @@ -1,6 +1,7 @@ import { Op } from 'sequelize' import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' import { MServerBlocklist, MServerBlocklistAccountServer, MServerBlocklistFormattable } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { ServerBlock } from '@shared/models' import { AccountModel } from '../account/account' import { getSort, searchAttribute } from '../utils' @@ -42,7 +43,7 @@ enum ScopeNames { } ] }) -export class ServerBlocklistModel extends Model { +export class ServerBlocklistModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/server/server.ts b/server/models/server/server.ts index fb4c15d97..25d9924fb 100644 --- a/server/models/server/server.ts +++ b/server/models/server/server.ts @@ -1,5 +1,6 @@ import { AllowNull, Column, CreatedAt, Default, HasMany, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { MServer, MServerFormattable } from '@server/types/models/server' +import { AttributesOnly } from '@shared/core-utils' import { isHostValid } from '../../helpers/custom-validators/servers' import { ActorModel } from '../actor/actor' import { throwIfNotValid } from '../utils' @@ -14,7 +15,7 @@ import { ServerBlocklistModel } from './server-blocklist' } ] }) -export class ServerModel extends Model { +export class ServerModel extends Model>> { @AllowNull(false) @Is('Host', value => throwIfNotValid(value, isHostValid, 'valid host')) diff --git a/server/models/server/tracker.ts b/server/models/server/tracker.ts index 97520f92d..c09fdd64b 100644 --- a/server/models/server/tracker.ts +++ b/server/models/server/tracker.ts @@ -1,6 +1,7 @@ import { AllowNull, BelongsToMany, Column, CreatedAt, Model, Table, UpdatedAt } from 'sequelize-typescript' import { Transaction } from 'sequelize/types' import { MTracker } from '@server/types/models/server/tracker' +import { AttributesOnly } from '@shared/core-utils' import { VideoModel } from '../video/video' import { VideoTrackerModel } from './video-tracker' @@ -13,7 +14,7 @@ import { VideoTrackerModel } from './video-tracker' } ] }) -export class TrackerModel extends Model { +export class TrackerModel extends Model>> { @AllowNull(false) @Column diff --git a/server/models/server/video-tracker.ts b/server/models/server/video-tracker.ts index 367bf0117..c49fbd1c6 100644 --- a/server/models/server/video-tracker.ts +++ b/server/models/server/video-tracker.ts @@ -1,4 +1,5 @@ import { Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' +import { AttributesOnly } from '@shared/core-utils' import { VideoModel } from '../video/video' import { TrackerModel } from './tracker' @@ -13,7 +14,7 @@ import { TrackerModel } from './tracker' } ] }) -export class VideoTrackerModel extends Model { +export class VideoTrackerModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/user/user-notification-setting.ts b/server/models/user/user-notification-setting.ts index 138051528..bee7d7851 100644 --- a/server/models/user/user-notification-setting.ts +++ b/server/models/user/user-notification-setting.ts @@ -14,6 +14,7 @@ import { } from 'sequelize-typescript' import { TokensCache } from '@server/lib/auth/tokens-cache' import { MNotificationSettingFormattable } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { UserNotificationSetting, UserNotificationSettingValue } from '../../../shared/models/users/user-notification-setting.model' import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications' import { throwIfNotValid } from '../utils' @@ -28,7 +29,7 @@ import { UserModel } from './user' } ] }) -export class UserNotificationSettingModel extends Model { +export class UserNotificationSettingModel extends Model>> { @AllowNull(false) @Default(null) diff --git a/server/models/user/user-notification.ts b/server/models/user/user-notification.ts index f7f9ac867..a7f84e9ca 100644 --- a/server/models/user/user-notification.ts +++ b/server/models/user/user-notification.ts @@ -1,6 +1,7 @@ import { FindOptions, ModelIndexesOptions, Op, WhereOptions } from 'sequelize' import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' import { UserNotificationIncludes, UserNotificationModelForApi } from '@server/types/models/user' +import { AttributesOnly } from '@shared/core-utils' import { UserNotification, UserNotificationType } from '../../../shared' import { isBooleanValid } from '../../helpers/custom-validators/misc' import { isUserNotificationTypeValid } from '../../helpers/custom-validators/user-notifications' @@ -286,7 +287,7 @@ function buildAccountInclude (required: boolean, withActor = false) { } ] as (ModelIndexesOptions & { where?: WhereOptions })[] }) -export class UserNotificationModel extends Model { +export class UserNotificationModel extends Model>> { @AllowNull(false) @Default(null) diff --git a/server/models/user/user-video-history.ts b/server/models/user/user-video-history.ts index 6be1d65ea..e3dc4a062 100644 --- a/server/models/user/user-video-history.ts +++ b/server/models/user/user-video-history.ts @@ -1,8 +1,9 @@ +import { DestroyOptions, Op, Transaction } from 'sequelize' import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, IsInt, Model, Table, UpdatedAt } from 'sequelize-typescript' +import { MUserAccountId, MUserId } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { VideoModel } from '../video/video' import { UserModel } from './user' -import { DestroyOptions, Op, Transaction } from 'sequelize' -import { MUserAccountId, MUserId } from '@server/types/models' @Table({ tableName: 'userVideoHistory', @@ -19,7 +20,7 @@ import { MUserAccountId, MUserId } from '@server/types/models' } ] }) -export class UserVideoHistoryModel extends Model { +export class UserVideoHistoryModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/user/user.ts b/server/models/user/user.ts index 8d2564e54..20696b1f4 100644 --- a/server/models/user/user.ts +++ b/server/models/user/user.ts @@ -31,6 +31,7 @@ import { MUserWithNotificationSetting, MVideoWithRights } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { hasUserRight, USER_ROLE_LABELS } from '../../../shared/core-utils/users' import { AbuseState, MyUser, UserRight, VideoPlaylistType, VideoPrivacy } from '../../../shared/models' import { User, UserRole } from '../../../shared/models/users' @@ -233,7 +234,7 @@ enum ScopeNames { } ] }) -export class UserModel extends Model { +export class UserModel extends Model>> { @AllowNull(true) @Is('UserPassword', value => throwIfNotValid(value, isUserPasswordValid, 'user password', true)) diff --git a/server/models/utils.ts b/server/models/utils.ts index ec51c66bf..e27625bc8 100644 --- a/server/models/utils.ts +++ b/server/models/utils.ts @@ -1,5 +1,4 @@ -import { literal, Op, OrderItem } from 'sequelize' -import { Model, Sequelize } from 'sequelize-typescript' +import { literal, Op, OrderItem, Sequelize } from 'sequelize' import { Col } from 'sequelize/types/lib/utils' import validator from 'validator' @@ -195,11 +194,11 @@ function parseAggregateResult (result: any) { return total } -const createSafeIn = (model: typeof Model, stringArr: (string | number)[]) => { +function createSafeIn (sequelize: Sequelize, stringArr: (string | number)[]) { return stringArr.map(t => { return t === null ? null - : model.sequelize.escape('' + t) + : sequelize.escape('' + t) }).join(', ') } diff --git a/server/models/video/schedule-video-update.ts b/server/models/video/schedule-video-update.ts index 22b08e91a..b0952c431 100644 --- a/server/models/video/schedule-video-update.ts +++ b/server/models/video/schedule-video-update.ts @@ -1,8 +1,9 @@ -import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' -import { ScopeNames as VideoScopeNames, VideoModel } from './video' -import { VideoPrivacy } from '../../../shared/models/videos' import { Op, Transaction } from 'sequelize' +import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' import { MScheduleVideoUpdateFormattable, MScheduleVideoUpdateVideoAll } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' +import { VideoPrivacy } from '../../../shared/models/videos' +import { ScopeNames as VideoScopeNames, VideoModel } from './video' @Table({ tableName: 'scheduleVideoUpdate', @@ -16,7 +17,7 @@ import { MScheduleVideoUpdateFormattable, MScheduleVideoUpdateVideoAll } from '@ } ] }) -export class ScheduleVideoUpdateModel extends Model { +export class ScheduleVideoUpdateModel extends Model>> { @AllowNull(false) @Default(null) diff --git a/server/models/video/tag.ts b/server/models/video/tag.ts index d04205703..c1eebe27f 100644 --- a/server/models/video/tag.ts +++ b/server/models/video/tag.ts @@ -1,6 +1,7 @@ import { col, fn, QueryTypes, Transaction } from 'sequelize' import { AllowNull, BelongsToMany, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { MTag } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { VideoPrivacy, VideoState } from '../../../shared/models/videos' import { isVideoTagValid } from '../../helpers/custom-validators/videos' import { throwIfNotValid } from '../utils' @@ -21,7 +22,7 @@ import { VideoTagModel } from './video-tag' } ] }) -export class TagModel extends Model { +export class TagModel extends Model>> { @AllowNull(false) @Is('VideoTag', value => throwIfNotValid(value, isVideoTagValid, 'tag')) diff --git a/server/models/video/thumbnail.ts b/server/models/video/thumbnail.ts index f1187c8d6..3388478d9 100644 --- a/server/models/video/thumbnail.ts +++ b/server/models/video/thumbnail.ts @@ -17,6 +17,7 @@ import { } from 'sequelize-typescript' import { afterCommitIfTransaction } from '@server/helpers/database-utils' import { MThumbnail, MThumbnailVideo, MVideo } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' import { logger } from '../../helpers/logger' import { CONFIG } from '../../initializers/config' @@ -40,7 +41,7 @@ import { VideoPlaylistModel } from './video-playlist' } ] }) -export class ThumbnailModel extends Model { +export class ThumbnailModel extends Model>> { @AllowNull(false) @Column diff --git a/server/models/video/video-blacklist.ts b/server/models/video/video-blacklist.ts index aa18896da..98f4ec9c5 100644 --- a/server/models/video/video-blacklist.ts +++ b/server/models/video/video-blacklist.ts @@ -1,6 +1,7 @@ import { FindOptions } from 'sequelize' import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { MVideoBlacklist, MVideoBlacklistFormattable } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { VideoBlacklist, VideoBlacklistType } from '../../../shared/models/videos' import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist' import { CONSTRAINTS_FIELDS } from '../../initializers/constants' @@ -18,7 +19,7 @@ import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } ] }) -export class VideoBlacklistModel extends Model { +export class VideoBlacklistModel extends Model>> { @AllowNull(true) @Is('VideoBlacklistReason', value => throwIfNotValid(value, isVideoBlacklistReasonValid, 'reason', true)) diff --git a/server/models/video/video-caption.ts b/server/models/video/video-caption.ts index bfdec73e9..d2c742b66 100644 --- a/server/models/video/video-caption.ts +++ b/server/models/video/video-caption.ts @@ -17,6 +17,7 @@ import { } from 'sequelize-typescript' import { v4 as uuidv4 } from 'uuid' import { MVideo, MVideoCaption, MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model' import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions' import { logger } from '../../helpers/logger' @@ -57,7 +58,7 @@ export enum ScopeNames { } ] }) -export class VideoCaptionModel extends Model { +export class VideoCaptionModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/video/video-change-ownership.ts b/server/models/video/video-change-ownership.ts index 298e8bfe2..7d20a954d 100644 --- a/server/models/video/video-change-ownership.ts +++ b/server/models/video/video-change-ownership.ts @@ -1,5 +1,6 @@ import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' import { MVideoChangeOwnershipFormattable, MVideoChangeOwnershipFull } from '@server/types/models/video/video-change-ownership' +import { AttributesOnly } from '@shared/core-utils' import { VideoChangeOwnership, VideoChangeOwnershipStatus } from '../../../shared/models/videos' import { AccountModel } from '../account/account' import { getSort } from '../utils' @@ -53,7 +54,7 @@ enum ScopeNames { ] } })) -export class VideoChangeOwnershipModel extends Model { +export class VideoChangeOwnershipModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index 8e4b78723..8c4357009 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts @@ -19,6 +19,7 @@ import { } from 'sequelize-typescript' import { setAsUpdated } from '@server/helpers/database-utils' import { MAccountActor } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { ActivityPubActor } from '../../../shared/models/activitypub' import { VideoChannel, VideoChannelSummary } from '../../../shared/models/videos' import { @@ -246,7 +247,7 @@ export type SummaryOptions = { } ] }) -export class VideoChannelModel extends Model { +export class VideoChannelModel extends Model>> { @AllowNull(false) @Is('VideoChannelName', value => throwIfNotValid(value, isVideoChannelNameValid, 'name')) diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index ffd324526..bdf5d86bc 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts @@ -16,6 +16,7 @@ import { } from 'sequelize-typescript' import { getServerActor } from '@server/models/application/application' import { MAccount, MAccountId, MUserAccountId } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { VideoPrivacy } from '@shared/models' import { ActivityTagObject, ActivityTombstoneObject } from '../../../shared/models/activitypub/objects/common-objects' import { VideoCommentObject } from '../../../shared/models/activitypub/objects/video-comment-object' @@ -173,7 +174,7 @@ export enum ScopeNames { } ] }) -export class VideoCommentModel extends Model { +export class VideoCommentModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/video/video-file.ts b/server/models/video/video-file.ts index 1ad796104..e3fa2f3d2 100644 --- a/server/models/video/video-file.ts +++ b/server/models/video/video-file.ts @@ -25,6 +25,7 @@ import { logger } from '@server/helpers/logger' import { extractVideo } from '@server/helpers/video' import { getTorrentFilePath } from '@server/lib/video-paths' import { MStreamingPlaylistVideo, MVideo, MVideoWithHost } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { isVideoFileExtnameValid, isVideoFileInfoHashValid, @@ -149,7 +150,7 @@ export enum ScopeNames { } ] }) -export class VideoFileModel extends Model { +export class VideoFileModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/video/video-import.ts b/server/models/video/video-import.ts index d8f09e1e5..5c73fb07c 100644 --- a/server/models/video/video-import.ts +++ b/server/models/video/video-import.ts @@ -15,6 +15,7 @@ import { } from 'sequelize-typescript' import { afterCommitIfTransaction } from '@server/helpers/database-utils' import { MVideoImportDefault, MVideoImportFormattable } from '@server/types/models/video/video-import' +import { AttributesOnly } from '@shared/core-utils' import { VideoImport, VideoImportState } from '../../../shared' import { isVideoImportStateValid, isVideoImportTargetUrlValid } from '../../helpers/custom-validators/video-imports' import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos' @@ -52,7 +53,7 @@ import { ScopeNames as VideoModelScopeNames, VideoModel } from './video' } ] }) -export class VideoImportModel extends Model { +export class VideoImportModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/video/video-live.ts b/server/models/video/video-live.ts index cb4a9b896..014491d50 100644 --- a/server/models/video/video-live.ts +++ b/server/models/video/video-live.ts @@ -1,6 +1,7 @@ import { AllowNull, BelongsTo, Column, CreatedAt, DataType, DefaultScope, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' import { WEBSERVER } from '@server/initializers/constants' import { MVideoLive, MVideoLiveVideo } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { LiveVideo, VideoState } from '@shared/models' import { VideoModel } from './video' import { VideoBlacklistModel } from './video-blacklist' @@ -28,7 +29,7 @@ import { VideoBlacklistModel } from './video-blacklist' } ] }) -export class VideoLiveModel extends Model { +export class VideoLiveModel extends Model>> { @AllowNull(true) @Column(DataType.STRING) diff --git a/server/models/video/video-playlist-element.ts b/server/models/video/video-playlist-element.ts index d2d7e2740..e6906cb19 100644 --- a/server/models/video/video-playlist-element.ts +++ b/server/models/video/video-playlist-element.ts @@ -32,6 +32,7 @@ import { AccountModel } from '../account/account' import { getSort, throwIfNotValid } from '../utils' import { ForAPIOptions, ScopeNames as VideoScopeNames, VideoModel } from './video' import { VideoPlaylistModel } from './video-playlist' +import { AttributesOnly } from '@shared/core-utils' @Table({ tableName: 'videoPlaylistElement', @@ -48,7 +49,7 @@ import { VideoPlaylistModel } from './video-playlist' } ] }) -export class VideoPlaylistElementModel extends Model { +export class VideoPlaylistElementModel extends Model>> { @CreatedAt createdAt: Date @@ -274,7 +275,8 @@ export class VideoPlaylistElementModel extends Model { validate: false // We use a literal to update the position } - return VideoPlaylistElementModel.update({ position: Sequelize.literal(`${newPosition} + "position" - ${firstPosition}`) }, query) + const positionQuery = Sequelize.literal(`${newPosition} + "position" - ${firstPosition}`) + return VideoPlaylistElementModel.update({ position: positionQuery as any }, query) } static increasePositionOf ( diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts index b48dd2945..c293287d3 100644 --- a/server/models/video/video-playlist.ts +++ b/server/models/video/video-playlist.ts @@ -19,6 +19,7 @@ import { } from 'sequelize-typescript' import { v4 as uuidv4 } from 'uuid' import { MAccountId, MChannelId } from '@server/types/models' +import { AttributesOnly } from '@shared/core-utils' import { ActivityIconObject } from '../../../shared/models/activitypub/objects' import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object' import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' @@ -221,7 +222,7 @@ type AvailableForListOptions = { } ] }) -export class VideoPlaylistModel extends Model { +export class VideoPlaylistModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/video/video-query-builder.ts b/server/models/video/video-query-builder.ts index 155afe64b..2aa5e65c8 100644 --- a/server/models/video/video-query-builder.ts +++ b/server/models/video/video-query-builder.ts @@ -1,9 +1,9 @@ -import { VideoFilter, VideoPrivacy, VideoState } from '@shared/models' -import { buildDirectionAndField, createSafeIn } from '@server/models/utils' -import { Model } from 'sequelize-typescript' -import { MUserAccountId, MUserId } from '@server/types/models' +import { Sequelize } from 'sequelize/types' import validator from 'validator' import { exists } from '@server/helpers/custom-validators/misc' +import { buildDirectionAndField, createSafeIn } from '@server/models/utils' +import { MUserAccountId, MUserId } from '@server/types/models' +import { VideoFilter, VideoPrivacy, VideoState } from '@shared/models' export type BuildVideosQueryOptions = { attributes?: string[] @@ -55,7 +55,7 @@ export type BuildVideosQueryOptions = { having?: string } -function buildListQuery (model: typeof Model, options: BuildVideosQueryOptions) { +function buildListQuery (sequelize: Sequelize, options: BuildVideosQueryOptions) { const and: string[] = [] const joins: string[] = [] const replacements: any = {} @@ -77,7 +77,7 @@ function buildListQuery (model: typeof Model, options: BuildVideosQueryOptions) const blockerIds = [ options.serverAccountId ] if (options.user) blockerIds.push(options.user.Account.id) - const inClause = createSafeIn(model, blockerIds) + const inClause = createSafeIn(sequelize, blockerIds) and.push( 'NOT EXISTS (' + @@ -179,7 +179,7 @@ function buildListQuery (model: typeof Model, options: BuildVideosQueryOptions) 'EXISTS (' + ' SELECT 1 FROM "videoTag" ' + ' INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + - ' WHERE lower("tag"."name") IN (' + createSafeIn(model, tagsOneOfLower) + ') ' + + ' WHERE lower("tag"."name") IN (' + createSafeIn(sequelize, tagsOneOfLower) + ') ' + ' AND "video"."id" = "videoTag"."videoId"' + ')' ) @@ -192,7 +192,7 @@ function buildListQuery (model: typeof Model, options: BuildVideosQueryOptions) 'EXISTS (' + ' SELECT 1 FROM "videoTag" ' + ' INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + - ' WHERE lower("tag"."name") IN (' + createSafeIn(model, tagsAllOfLower) + ') ' + + ' WHERE lower("tag"."name") IN (' + createSafeIn(sequelize, tagsAllOfLower) + ') ' + ' AND "video"."id" = "videoTag"."videoId" ' + ' GROUP BY "videoTag"."videoId" HAVING COUNT(*) = ' + tagsAllOfLower.length + ')' @@ -232,7 +232,7 @@ function buildListQuery (model: typeof Model, options: BuildVideosQueryOptions) languagesQueryParts.push( 'EXISTS (' + ' SELECT 1 FROM "videoCaption" WHERE "videoCaption"."language" ' + - ' IN (' + createSafeIn(model, languages) + ') AND ' + + ' IN (' + createSafeIn(sequelize, languages) + ') AND ' + ' "videoCaption"."videoId" = "video"."id"' + ')' ) @@ -345,8 +345,8 @@ function buildListQuery (model: typeof Model, options: BuildVideosQueryOptions) } if (options.search) { - const escapedSearch = model.sequelize.escape(options.search) - const escapedLikeSearch = model.sequelize.escape('%' + options.search + '%') + const escapedSearch = sequelize.escape(options.search) + const escapedLikeSearch = sequelize.escape('%' + options.search + '%') cte.push( '"trigramSearch" AS (' + diff --git a/server/models/video/video-share.ts b/server/models/video/video-share.ts index 99a24dbdf..505c305e2 100644 --- a/server/models/video/video-share.ts +++ b/server/models/video/video-share.ts @@ -1,5 +1,6 @@ import { literal, Op, QueryTypes, Transaction } from 'sequelize' import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' +import { AttributesOnly } from '@shared/core-utils' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' import { CONSTRAINTS_FIELDS } from '../../initializers/constants' import { MActorDefault } from '../../types/models' @@ -50,7 +51,7 @@ enum ScopeNames { } ] }) -export class VideoShareModel extends Model { +export class VideoShareModel extends Model>> { @AllowNull(false) @Is('VideoShareUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url')) diff --git a/server/models/video/video-streaming-playlist.ts b/server/models/video/video-streaming-playlist.ts index c9375b433..d627e8c9d 100644 --- a/server/models/video/video-streaming-playlist.ts +++ b/server/models/video/video-streaming-playlist.ts @@ -13,6 +13,7 @@ import { CONSTRAINTS_FIELDS, MEMOIZE_LENGTH, MEMOIZE_TTL, P2P_MEDIA_LOADER_PEER_ import { VideoRedundancyModel } from '../redundancy/video-redundancy' import { throwIfNotValid } from '../utils' import { VideoModel } from './video' +import { AttributesOnly } from '@shared/core-utils' @Table({ tableName: 'videoStreamingPlaylist', @@ -30,7 +31,7 @@ import { VideoModel } from './video' } ] }) -export class VideoStreamingPlaylistModel extends Model { +export class VideoStreamingPlaylistModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/video/video-tag.ts b/server/models/video/video-tag.ts index 5052b8c4d..1285d375b 100644 --- a/server/models/video/video-tag.ts +++ b/server/models/video/video-tag.ts @@ -1,4 +1,5 @@ import { Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' +import { AttributesOnly } from '@shared/core-utils' import { TagModel } from './tag' import { VideoModel } from './video' @@ -13,7 +14,7 @@ import { VideoModel } from './video' } ] }) -export class VideoTagModel extends Model { +export class VideoTagModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/video/video-view.ts b/server/models/video/video-view.ts index 992cf258a..dfc6296ce 100644 --- a/server/models/video/video-view.ts +++ b/server/models/video/video-view.ts @@ -1,6 +1,7 @@ +import * as Sequelize from 'sequelize' import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Model, Table } from 'sequelize-typescript' +import { AttributesOnly } from '@shared/core-utils' import { VideoModel } from './video' -import * as Sequelize from 'sequelize' @Table({ tableName: 'videoView', @@ -14,7 +15,7 @@ import * as Sequelize from 'sequelize' } ] }) -export class VideoViewModel extends Model { +export class VideoViewModel extends Model>> { @CreatedAt createdAt: Date diff --git a/server/models/video/video.ts b/server/models/video/video.ts index f8a099d9c..749ef7197 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts @@ -31,6 +31,7 @@ import { LiveManager } from '@server/lib/live-manager' import { getHLSDirectory, getVideoFilePath } from '@server/lib/video-paths' import { getServerActor } from '@server/models/application/application' import { ModelCache } from '@server/models/model-cache' +import { AttributesOnly } from '@shared/core-utils' import { VideoFile } from '@shared/models/videos/video-file.model' import { ResultList, UserRight, VideoPrivacy, VideoState } from '../../../shared' import { VideoObject } from '../../../shared/models/activitypub/objects' @@ -489,7 +490,7 @@ export type AvailableForListIDsOptions = { } ] }) -export class VideoModel extends Model { +export class VideoModel extends Model>> { @AllowNull(false) @Default(DataType.UUIDV4) @@ -1617,7 +1618,7 @@ export class VideoModel extends Model { includeLocalVideos: true } - const { query, replacements } = buildListQuery(VideoModel, queryOptions) + const { query, replacements } = buildListQuery(VideoModel.sequelize, queryOptions) return this.sequelize.query(query, { replacements, type: QueryTypes.SELECT }) .then(rows => rows.map(r => r[field])) @@ -1645,7 +1646,7 @@ export class VideoModel extends Model { if (countVideos !== true) return Promise.resolve(undefined) const countOptions = Object.assign({}, options, { isCount: true }) - const { query: queryCount, replacements: replacementsCount } = buildListQuery(VideoModel, countOptions) + const { query: queryCount, replacements: replacementsCount } = buildListQuery(VideoModel.sequelize, countOptions) return VideoModel.sequelize.query(queryCount, { replacements: replacementsCount, type: QueryTypes.SELECT }) .then(rows => rows.length !== 0 ? rows[0].total : 0) @@ -1654,7 +1655,7 @@ export class VideoModel extends Model { function getModels () { if (options.count === 0) return Promise.resolve([]) - const { query, replacements, order } = buildListQuery(VideoModel, options) + const { query, replacements, order } = buildListQuery(VideoModel.sequelize, options) const queryModels = wrapForAPIResults(query, replacements, options, order) return VideoModel.sequelize.query(queryModels, { replacements, type: QueryTypes.SELECT, nest: true }) diff --git a/server/types/sequelize.ts b/server/types/sequelize.ts index 9cd83612d..535113d01 100644 --- a/server/types/sequelize.ts +++ b/server/types/sequelize.ts @@ -1,4 +1,5 @@ -import { Model } from 'sequelize-typescript' +import { AttributesOnly } from '@shared/core-utils' +import { Model } from 'sequelize' // Thanks to sequelize-typescript: https://github.com/RobinBuschmann/sequelize-typescript @@ -9,7 +10,7 @@ export type Omit = { [P in Diff]: T[P] } export type RecursivePartial = { [P in keyof T]?: RecursivePartial } -export type FilteredModelAttributes> = RecursivePartial>> & { +export type FilteredModelAttributes> = Partial> & { id?: number | any createdAt?: Date | any updatedAt?: Date | any diff --git a/shared/core-utils/miscs/types.ts b/shared/core-utils/miscs/types.ts index bb64dc830..bd2a97b98 100644 --- a/shared/core-utils/miscs/types.ts +++ b/shared/core-utils/miscs/types.ts @@ -6,6 +6,10 @@ export type FunctionPropertyNames = { export type FunctionProperties = Pick> +export type AttributesOnly = { + [K in keyof T]: T[K] extends Function ? never : T[K] +} + export type PickWith = { [P in KT]: T[P] extends V ? V : never } -- 2.41.0