This commit is contained in:
Chocobozzz 2024-02-22 10:12:04 +01:00
parent 780f17f116
commit 9e2700b89d
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
108 changed files with 315 additions and 359 deletions

View File

@ -118,6 +118,8 @@
"@typescript-eslint/consistent-type-exports": "off", "@typescript-eslint/consistent-type-exports": "off",
"@typescript-eslint/key-spacing": "off", "@typescript-eslint/key-spacing": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/ban-types": [ "@typescript-eslint/ban-types": [
"error", "error",
{ {

View File

@ -61,7 +61,7 @@ export function downloadFile (options: {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function getRequest (url: string) { function getRequest (url: string) {
if (url.startsWith('https://')) return https.request if (url.startsWith('https://')) return https.request.bind(https)
return http.request return http.request.bind(http)
} }

View File

@ -160,7 +160,11 @@
"error", "error",
"consistent-as-needed" "consistent-as-needed"
], ],
"no-constant-binary-expression": "error" "no-constant-binary-expression": "error",
"@typescript-eslint/unbound-method": [
"error",
{ "ignoreStatic": true }
]
} }
}, },
{ {

View File

@ -2,7 +2,6 @@
"extends": "stylelint-config-sass-guidelines", "extends": "stylelint-config-sass-guidelines",
"rules": { "rules": {
"scss/at-import-no-partial-leading-underscore": null, "scss/at-import-no-partial-leading-underscore": null,
"color-hex-case": null,
"color-hex-length": null, "color-hex-length": null,
"selector-pseudo-element-no-unknown": [ "selector-pseudo-element-no-unknown": [
true, true,
@ -19,10 +18,10 @@
"selector-max-compound-selectors": 9, "selector-max-compound-selectors": 9,
"selector-no-qualifying-type": null, "selector-no-qualifying-type": null,
"scss/at-extend-no-missing-placeholder": null, "scss/at-extend-no-missing-placeholder": null,
"number-leading-zero": null,
"rule-empty-line-before": null, "rule-empty-line-before": null,
"selector-max-id": null, "selector-max-id": null,
"scss/at-function-pattern": null, "scss/at-function-pattern": null,
"scss/load-no-partial-leading-underscore": null,
"property-no-vendor-prefix": [ "property-no-vendor-prefix": [
true, true,
{ {

View File

@ -51,15 +51,15 @@ describe('Videos list', () => {
async function checkCommonVideoListPages (policy: NSFWPolicy) { async function checkCommonVideoListPages (policy: NSFWPolicy) {
const promisesWithFilters = [ const promisesWithFilters = [
videoListPage.goOnRootAccount, videoListPage.goOnRootAccount.bind(videoListPage),
videoListPage.goOnLocal, videoListPage.goOnLocal.bind(videoListPage),
videoListPage.goOnRecentlyAdded, videoListPage.goOnRecentlyAdded.bind(videoListPage),
videoListPage.goOnTrending, videoListPage.goOnTrending.bind(videoListPage),
videoListPage.goOnRootChannel videoListPage.goOnRootChannel.bind(videoListPage)
] ]
for (const p of promisesWithFilters) { for (const p of promisesWithFilters) {
await p.call(videoListPage) await p()
const filter = await videoListPage.getNSFWFilter() const filter = await videoListPage.getNSFWFilter()
const filterText = await filter.getText() const filterText = await filter.getText()
@ -69,11 +69,11 @@ describe('Videos list', () => {
} }
const promisesWithoutFilters = [ const promisesWithoutFilters = [
videoListPage.goOnRootAccountChannels, videoListPage.goOnRootAccountChannels.bind(videoListPage),
videoListPage.goOnHomepage videoListPage.goOnHomepage.bind(videoListPage)
] ]
for (const p of promisesWithoutFilters) { for (const p of promisesWithoutFilters) {
await p.call(videoListPage) await p()
await checkNormalVideo() await checkNormalVideo()
await checkNSFWVideo(policy) await checkNSFWVideo(policy)

View File

@ -109,6 +109,7 @@
"linkifyjs": "^4.0.2", "linkifyjs": "^4.0.2",
"lodash-es": "^4.17.4", "lodash-es": "^4.17.4",
"markdown-it": "14.0.0", "markdown-it": "14.0.0",
"markdown-it-emoji": "^3.0.0",
"mini-css-extract-plugin": "^2.2.0", "mini-css-extract-plugin": "^2.2.0",
"ngx-uploadx": "^6.1.0", "ngx-uploadx": "^6.1.0",
"path-browserify": "^1.0.0", "path-browserify": "^1.0.0",

View File

@ -35,8 +35,8 @@ export class JobService {
return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL + `/${jobState || ''}`, { params }) return this.authHttp.get<ResultList<Job>>(JobService.BASE_JOB_URL + `/${jobState || ''}`, { params })
.pipe( .pipe(
map(res => this.restExtractor.convertResultListDateToHuman(res, [ 'createdAt', 'processedOn', 'finishedOn' ], 'precise')), map(res => this.restExtractor.convertResultListDateToHuman(res, [ 'createdAt', 'processedOn', 'finishedOn' ], 'precise')),
map(res => this.restExtractor.applyToResultListData(res, this.prettyPrintData)), map(res => this.restExtractor.applyToResultListData(res, this.prettyPrintData.bind(this))),
map(res => this.restExtractor.applyToResultListData(res, this.buildUniqId)), map(res => this.restExtractor.applyToResultListData(res, this.buildUniqId.bind(this))),
catchError(err => this.restExtractor.handleError(err)) catchError(err => this.restExtractor.handleError(err))
) )
} }

View File

@ -104,22 +104,22 @@ export class VideoRateComponent implements OnInit, OnChanges, OnDestroy {
private setRating (nextRating: UserVideoRateType) { private setRating (nextRating: UserVideoRateType) {
const ratingMethods: { [id in UserVideoRateType]: (id: string, videoPassword: string) => Observable<any> } = { const ratingMethods: { [id in UserVideoRateType]: (id: string, videoPassword: string) => Observable<any> } = {
like: this.videoService.setVideoLike, like: this.videoService.setVideoLike.bind(this.videoService),
dislike: this.videoService.setVideoDislike, dislike: this.videoService.setVideoDislike.bind(this.videoService),
none: this.videoService.unsetVideoLike none: this.videoService.unsetVideoLike.bind(this.videoService)
} }
ratingMethods[nextRating].call(this.videoService, this.video.uuid, this.videoPassword) ratingMethods[nextRating](this.video.uuid, this.videoPassword)
.subscribe({ .subscribe({
next: () => { next: () => {
// Update the video like attribute // Update the video like attribute
this.updateVideoRating(this.userRating, nextRating) this.updateVideoRating(this.userRating, nextRating)
this.userRating = nextRating this.userRating = nextRating
this.rateUpdated.emit(this.userRating) this.rateUpdated.emit(this.userRating)
}, },
error: err => this.notifier.error(err.message) error: err => this.notifier.error(err.message)
}) })
} }
private updateVideoRating (oldRating: UserVideoRateType, newRating: UserVideoRateType) { private updateVideoRating (oldRating: UserVideoRateType, newRating: UserVideoRateType) {

View File

@ -85,7 +85,7 @@ export class VideoCommentAddComponent extends FormReactive implements OnChanges,
getEmojiMarkupList () { getEmojiMarkupList () {
if (this.emojiMarkupList) return this.emojiMarkupList if (this.emojiMarkupList) return this.emojiMarkupList
const emojiMarkupObjectList = require('markdown-it-emoji/lib/data/light.json') const emojiMarkupObjectList = require('markdown-it-emoji/lib/data/light.mjs').default
this.emojiMarkupList = [] this.emojiMarkupList = []
for (const name of Object.keys(emojiMarkupObjectList)) { for (const name of Object.keys(emojiMarkupObjectList)) {

View File

@ -200,7 +200,7 @@ routes.push({
@NgModule({ @NgModule({
imports: [ imports: [
RouterModule.forRoot(routes, { RouterModule.forRoot(routes, {
useHash: Boolean(history.pushState) === false, useHash: false,
// Redefined in app component // Redefined in app component
scrollPositionRestoration: 'disabled', scrollPositionRestoration: 'disabled',
preloadingStrategy: PreloadSelectedModulesList, preloadingStrategy: PreloadSelectedModulesList,

View File

@ -32,7 +32,7 @@ export class RestExtractor {
fieldsToConvert: string[] = [ 'createdAt' ], fieldsToConvert: string[] = [ 'createdAt' ],
format?: DateFormat format?: DateFormat
): ResultList<T> { ): ResultList<T> {
return this.applyToResultListData(result, this.convertDateToHuman, [ fieldsToConvert, format ]) return this.applyToResultListData(result, this.convertDateToHuman.bind(this), [ fieldsToConvert, format ])
} }
convertDateToHuman (target: any, fieldsToConvert: string[], format?: DateFormat) { convertDateToHuman (target: any, fieldsToConvert: string[], format?: DateFormat) {

View File

@ -3,7 +3,7 @@ import { MenuService } from '../menu'
import { ScreenService } from '../wrappers' import { ScreenService } from '../wrappers'
abstract class MenuGuard { abstract class MenuGuard {
canDeactivate = this.canActivate canDeactivate = this.canActivate.bind(this)
constructor (protected menu: MenuService, protected screen: ScreenService, protected display: boolean) { constructor (protected menu: MenuService, protected screen: ScreenService, protected display: boolean) {

View File

@ -244,8 +244,10 @@ export class MenuComponent implements OnInit, OnDestroy {
if (opened) { if (opened) {
window.addEventListener('scroll', onWindowScroll) window.addEventListener('scroll', onWindowScroll)
document.querySelector('nav').scrollTo(0, 0) // Reset menu scroll to easy lock document.querySelector('nav').scrollTo(0, 0) // Reset menu scroll to easy lock
// eslint-disable-next-line @typescript-eslint/unbound-method
document.querySelector('nav').addEventListener('scroll', this.onMenuScrollEvent) document.querySelector('nav').addEventListener('scroll', this.onMenuScrollEvent)
} else { } else {
// eslint-disable-next-line @typescript-eslint/unbound-method
document.querySelector('nav').removeEventListener('scroll', this.onMenuScrollEvent) document.querySelector('nav').removeEventListener('scroll', this.onMenuScrollEvent)
} }
} }

View File

@ -67,6 +67,7 @@ export class NotificationComponent implements OnInit, OnDestroy {
this.opened = true this.opened = true
document.querySelector('nav').scrollTo(0, 0) // Reset menu scroll to easy lock document.querySelector('nav').scrollTo(0, 0) // Reset menu scroll to easy lock
// eslint-disable-next-line @typescript-eslint/unbound-method
document.querySelector('nav').addEventListener('scroll', this.onMenuScrollEvent) document.querySelector('nav').addEventListener('scroll', this.onMenuScrollEvent)
} }
@ -74,6 +75,7 @@ export class NotificationComponent implements OnInit, OnDestroy {
this.loaded = false this.loaded = false
this.opened = false this.opened = false
// eslint-disable-next-line @typescript-eslint/unbound-method
document.querySelector('nav').removeEventListener('scroll', this.onMenuScrollEvent) document.querySelector('nav').removeEventListener('scroll', this.onMenuScrollEvent)
} }

View File

@ -41,12 +41,12 @@ export class VideoOwnershipService {
acceptOwnership (id: number, input: VideoChangeOwnershipAccept) { acceptOwnership (id: number, input: VideoChangeOwnershipAccept) {
const url = VideoOwnershipService.BASE_VIDEO_CHANGE_OWNERSHIP_URL + 'ownership/' + id + '/accept' const url = VideoOwnershipService.BASE_VIDEO_CHANGE_OWNERSHIP_URL + 'ownership/' + id + '/accept'
return this.authHttp.post(url, input) return this.authHttp.post(url, input)
.pipe(catchError(this.restExtractor.handleError)) .pipe(catchError(err => this.restExtractor.handleError(err)))
} }
refuseOwnership (id: number) { refuseOwnership (id: number) {
const url = VideoOwnershipService.BASE_VIDEO_CHANGE_OWNERSHIP_URL + 'ownership/' + id + '/refuse' const url = VideoOwnershipService.BASE_VIDEO_CHANGE_OWNERSHIP_URL + 'ownership/' + id + '/refuse'
return this.authHttp.post(url, {}) return this.authHttp.post(url, {})
.pipe(catchError(this.restExtractor.handleError)) .pipe(catchError(err => this.restExtractor.handleError(err)))
} }
} }

View File

@ -244,6 +244,7 @@ class SettingsButton extends Button {
// Hide children to avoid sub menus stacking on top of each other // Hide children to avoid sub menus stacking on top of each other
// or having multiple menus open // or having multiple menus open
// eslint-disable-next-line @typescript-eslint/unbound-method
settingsMenuItem.on('click', videojs.bind(this, this.hideChildren)) settingsMenuItem.on('click', videojs.bind(this, this.hideChildren))
// Whether to add or remove selected class on the settings sub menu element // Whether to add or remove selected class on the settings sub menu element

View File

@ -6,4 +6,4 @@ interface NodeModule {
id: string id: string
} }
declare module 'markdown-it-emoji/light' declare module 'markdown-it-emoji/lib/light.mjs'

View File

@ -7555,6 +7555,11 @@ map-stream@~0.1.0:
resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194"
integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g== integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==
markdown-it-emoji@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/markdown-it-emoji/-/markdown-it-emoji-3.0.0.tgz#8475a04d671d7c93f931b76fb90c582768b7f0b5"
integrity sha512-+rUD93bXHubA4arpEZO3q80so0qgoFJEKRkRbjKX8RTdca89v2kfyF+xR3i2sQTwql9tpPZPOQN5B+PunspXRg==
markdown-it@14.0.0: markdown-it@14.0.0:
version "14.0.0" version "14.0.0"
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.0.0.tgz#b4b2ddeb0f925e88d981f84c183b59bac9e3741b" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.0.0.tgz#b4b2ddeb0f925e88d981f84c183b59bac9e3741b"

View File

@ -18,8 +18,8 @@ async function waitJobs (
let servers: PeerTubeServer[] let servers: PeerTubeServer[]
if (Array.isArray(serversArg) === false) servers = [ serversArg as PeerTubeServer ] if (Array.isArray(serversArg) === false) servers = [ serversArg ]
else servers = serversArg as PeerTubeServer[] else servers = serversArg
const states: JobState[] = [ 'waiting', 'active' ] const states: JobState[] = [ 'waiting', 'active' ]
if (!skipDelayed) states.push('delayed') if (!skipDelayed) states.push('delayed')

View File

@ -35,6 +35,7 @@ async function cleanupTests (servers: PeerTubeServer[]) {
for (const server of servers) { for (const server of servers) {
if (!server) continue if (!server) continue
// eslint-disable-next-line @typescript-eslint/no-floating-promises
p = p.concat(server.servers.cleanupTests()) p = p.concat(server.servers.cleanupTests())
} }

View File

@ -149,7 +149,7 @@ describe('Test my user API validators', function () {
await makePutBodyRequest({ await makePutBodyRequest({
url: server.url, url: server.url,
path: path + 'me', path: path + 'me',
token: 'super token', token: 'supertoken',
fields, fields,
expectedStatus: HttpStatusCode.UNAUTHORIZED_401 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
}) })

View File

@ -187,7 +187,7 @@ describe('Test users admin API validators', function () {
await makePostBodyRequest({ await makePostBodyRequest({
url: server.url, url: server.url,
path, path,
token: 'super token', token: 'supertoken',
fields: baseCorrectParams, fields: baseCorrectParams,
expectedStatus: HttpStatusCode.UNAUTHORIZED_401 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
}) })
@ -309,7 +309,7 @@ describe('Test users admin API validators', function () {
await makeGetRequest({ await makeGetRequest({
url: server.url, url: server.url,
path: path + userId, path: path + userId,
token: 'super token', token: 'supertoken',
expectedStatus: HttpStatusCode.UNAUTHORIZED_401 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
}) })
}) })
@ -383,7 +383,7 @@ describe('Test users admin API validators', function () {
await makePutBodyRequest({ await makePutBodyRequest({
url: server.url, url: server.url,
path: path + userId, path: path + userId,
token: 'super token', token: 'supertoken',
fields, fields,
expectedStatus: HttpStatusCode.UNAUTHORIZED_401 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
}) })

View File

@ -226,7 +226,7 @@ describe('Test video blacklist API validators', function () {
it('Should fail with a non authenticated user', async function () { it('Should fail with a non authenticated user', async function () {
await command.remove({ await command.remove({
token: 'fake token', token: 'faketoken',
videoId: servers[0].store.videoCreated.uuid, videoId: servers[0].store.videoCreated.uuid,
expectedStatus: HttpStatusCode.UNAUTHORIZED_401 expectedStatus: HttpStatusCode.UNAUTHORIZED_401
}) })
@ -258,7 +258,7 @@ describe('Test video blacklist API validators', function () {
const basePath = '/api/v1/videos/blacklist/' const basePath = '/api/v1/videos/blacklist/'
it('Should fail with a non authenticated user', async function () { it('Should fail with a non authenticated user', async function () {
await servers[0].blacklist.list({ token: 'fake token', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) await servers[0].blacklist.list({ token: 'faketoken', expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
}) })
it('Should fail with a non admin user', async function () { it('Should fail with a non admin user', async function () {

View File

@ -24,6 +24,7 @@ describe('Test video NSFW policy', function () {
let promises: Promise<ResultList<Video>>[] let promises: Promise<ResultList<Video>>[]
if (token) { if (token) {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
promises = [ promises = [
server.search.advancedVideoSearch({ token, search: { search: 'n', sort: '-publishedAt', ...query } }), server.search.advancedVideoSearch({ token, search: { search: 'n', sort: '-publishedAt', ...query } }),
server.videos.listWithToken({ token, ...query }), server.videos.listWithToken({ token, ...query }),
@ -34,13 +35,14 @@ describe('Test video NSFW policy', function () {
// Overviews do not support video filters // Overviews do not support video filters
if (!hasQuery) { if (!hasQuery) {
const p = server.overviews.getVideos({ page: 1, token }) const p = server.overviews.getVideos({ page: 1, token })
.then(res => createOverviewRes(res)) .then(res => createOverviewRes(res))
promises.push(p) promises.push(p)
} }
return Promise.all(promises) return Promise.all(promises)
} }
// eslint-disable-next-line @typescript-eslint/no-floating-promises
promises = [ promises = [
server.search.searchVideos({ search: 'n', sort: '-publishedAt' }), server.search.searchVideos({ search: 'n', sort: '-publishedAt' }),
server.videos.list(), server.videos.list(),
@ -51,7 +53,8 @@ describe('Test video NSFW policy', function () {
// Overviews do not support video filters // Overviews do not support video filters
if (!hasQuery) { if (!hasQuery) {
const p = server.overviews.getVideos({ page: 1 }) const p = server.overviews.getVideos({ page: 1 })
.then(res => createOverviewRes(res)) .then(res => createOverviewRes(res))
promises.push(p) promises.push(p)
} }

View File

@ -226,7 +226,7 @@ async function listAccountVideos (req: express.Request, res: express.Response) {
}, 'filter:api.accounts.videos.list.params') }, 'filter:api.accounts.videos.list.params')
const resultList = await Hooks.wrapPromiseFun( const resultList = await Hooks.wrapPromiseFun(
VideoModel.listForApi, VideoModel.listForApi.bind(VideoModel),
apiOptions, apiOptions,
'filter:api.accounts.videos.list.result' 'filter:api.accounts.videos.list.result'
) )

View File

@ -130,7 +130,7 @@ async function getVideos (
}, 'filter:api.overviews.videos.list.params') }, 'filter:api.overviews.videos.list.params')
const { data } = await Hooks.wrapPromiseFun( const { data } = await Hooks.wrapPromiseFun(
VideoModel.listForApi, VideoModel.listForApi.bind(VideoModel),
query, query,
'filter:api.overviews.videos.list.result' 'filter:api.overviews.videos.list.result'
) )

View File

@ -102,7 +102,7 @@ async function searchVideoChannelsDB (query: VideoChannelsSearchQueryAfterSaniti
}, 'filter:api.search.video-channels.local.list.params') }, 'filter:api.search.video-channels.local.list.params')
const resultList = await Hooks.wrapPromiseFun( const resultList = await Hooks.wrapPromiseFun(
VideoChannelModel.searchForApi, VideoChannelModel.searchForApi.bind(VideoChannelModel),
apiOptions, apiOptions,
'filter:api.search.video-channels.local.list.result' 'filter:api.search.video-channels.local.list.result'
) )

View File

@ -93,7 +93,7 @@ async function searchVideoPlaylistsDB (query: VideoPlaylistsSearchQueryAfterSani
}, 'filter:api.search.video-playlists.local.list.params') }, 'filter:api.search.video-playlists.local.list.params')
const resultList = await Hooks.wrapPromiseFun( const resultList = await Hooks.wrapPromiseFun(
VideoPlaylistModel.searchForApi, VideoPlaylistModel.searchForApi.bind(VideoPlaylistModel),
apiOptions, apiOptions,
'filter:api.search.video-playlists.local.list.result' 'filter:api.search.video-playlists.local.list.result'
) )

View File

@ -121,7 +121,7 @@ async function searchVideosDB (query: VideosSearchQueryAfterSanitize, req: expre
}, 'filter:api.search.videos.local.list.params') }, 'filter:api.search.videos.local.list.params')
const resultList = await Hooks.wrapPromiseFun( const resultList = await Hooks.wrapPromiseFun(
VideoModel.searchAndPopulateAccountAndServer, VideoModel.searchAndPopulateAccountAndServer.bind(VideoModel),
apiOptions, apiOptions,
'filter:api.search.videos.local.list.result' 'filter:api.search.videos.local.list.result'
) )

View File

@ -131,7 +131,7 @@ async function getUserVideos (req: express.Request, res: express.Response) {
}, 'filter:api.user.me.videos.list.params') }, 'filter:api.user.me.videos.list.params')
const resultList = await Hooks.wrapPromiseFun( const resultList = await Hooks.wrapPromiseFun(
VideoModel.listUserVideosForApi, VideoModel.listUserVideosForApi.bind(VideoModel),
apiOptions, apiOptions,
'filter:api.user.me.videos.list.result' 'filter:api.user.me.videos.list.result'
) )

View File

@ -184,7 +184,7 @@ async function getUserSubscriptionVideos (req: express.Request, res: express.Res
}, 'filter:api.user.me.subscription-videos.list.params') }, 'filter:api.user.me.subscription-videos.list.params')
const resultList = await Hooks.wrapPromiseFun( const resultList = await Hooks.wrapPromiseFun(
VideoModel.listForApi, VideoModel.listForApi.bind(VideoModel),
apiOptions, apiOptions,
'filter:api.user.me.subscription-videos.list.result' 'filter:api.user.me.subscription-videos.list.result'
) )

View File

@ -200,7 +200,7 @@ async function listVideoChannels (req: express.Request, res: express.Response) {
}, 'filter:api.video-channels.list.params') }, 'filter:api.video-channels.list.params')
const resultList = await Hooks.wrapPromiseFun( const resultList = await Hooks.wrapPromiseFun(
VideoChannelModel.listForApi, VideoChannelModel.listForApi.bind(VideoChannelModel),
apiOptions, apiOptions,
'filter:api.video-channels.list.result' 'filter:api.video-channels.list.result'
) )
@ -409,7 +409,7 @@ async function listVideoChannelVideos (req: express.Request, res: express.Respon
}, 'filter:api.video-channels.videos.list.params') }, 'filter:api.video-channels.videos.list.params')
const resultList = await Hooks.wrapPromiseFun( const resultList = await Hooks.wrapPromiseFun(
VideoModel.listForApi, VideoModel.listForApi.bind(VideoModel),
apiOptions, apiOptions,
'filter:api.video-channels.videos.list.result' 'filter:api.video-channels.videos.list.result'
) )

View File

@ -472,7 +472,7 @@ async function getVideoPlaylistVideos (req: express.Request, res: express.Respon
}, 'filter:api.video-playlist.videos.list.params') }, 'filter:api.video-playlist.videos.list.params')
const resultList = await Hooks.wrapPromiseFun( const resultList = await Hooks.wrapPromiseFun(
VideoPlaylistElementModel.listForApi, VideoPlaylistElementModel.listForApi.bind(VideoPlaylistElementModel),
apiOptions, apiOptions,
'filter:api.video-playlist.videos.list.result' 'filter:api.video-playlist.videos.list.result'
) )

View File

@ -128,7 +128,7 @@ async function listVideoThreads (req: express.Request, res: express.Response) {
}, 'filter:api.video-threads.list.params') }, 'filter:api.video-threads.list.params')
resultList = await Hooks.wrapPromiseFun( resultList = await Hooks.wrapPromiseFun(
VideoCommentModel.listThreadsForApi, VideoCommentModel.listThreadsForApi.bind(VideoCommentModel),
apiOptions, apiOptions,
'filter:api.video-threads.list.result' 'filter:api.video-threads.list.result'
) )
@ -160,7 +160,7 @@ async function listVideoThreadComments (req: express.Request, res: express.Respo
}, 'filter:api.video-thread-comments.list.params') }, 'filter:api.video-thread-comments.list.params')
resultList = await Hooks.wrapPromiseFun( resultList = await Hooks.wrapPromiseFun(
VideoCommentModel.listThreadCommentsForApi, VideoCommentModel.listThreadCommentsForApi.bind(VideoCommentModel),
apiOptions, apiOptions,
'filter:api.video-thread-comments.list.result' 'filter:api.video-thread-comments.list.result'
) )

View File

@ -194,7 +194,7 @@ async function listVideos (req: express.Request, res: express.Response) {
}, 'filter:api.videos.list.params') }, 'filter:api.videos.list.params')
const resultList = await Hooks.wrapPromiseFun( const resultList = await Hooks.wrapPromiseFun(
VideoModel.listForApi, VideoModel.listForApi.bind(VideoModel),
apiOptions, apiOptions,
'filter:api.videos.list.result' 'filter:api.videos.list.result'
) )

View File

@ -133,7 +133,7 @@ async function downloadVideoFile (req: express.Request, res: express.Response) {
async function downloadHLSVideoFile (req: express.Request, res: express.Response) { async function downloadHLSVideoFile (req: express.Request, res: express.Response) {
const video = res.locals.videoAll const video = res.locals.videoAll
const streamingPlaylist = getHLSPlaylist(video) const streamingPlaylist = getHLSPlaylist(video)
if (!streamingPlaylist) return res.status(HttpStatusCode.NOT_FOUND_404).end if (!streamingPlaylist) return res.sendStatus(HttpStatusCode.NOT_FOUND_404)
const videoFile = getVideoFile(req, streamingPlaylist.VideoFiles) const videoFile = getVideoFile(req, streamingPlaylist.VideoFiles)
if (!videoFile) { if (!videoFile) {

View File

@ -121,10 +121,10 @@ const bunyanLogger = {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
type LoggerTags = { tags: string[] } type LoggerTags = { tags: (string | number)[] }
type LoggerTagsFn = (...tags: string[]) => LoggerTags type LoggerTagsFn = (...tags: (string | number)[]) => LoggerTags
function loggerTagsFactory (...defaultTags: string[]): LoggerTagsFn { function loggerTagsFactory (...defaultTags: (string | number)[]): LoggerTagsFn {
return (...tags: string[]) => { return (...tags: (string | number)[]) => {
return { tags: defaultTags.concat(tags) } return { tags: defaultTags.concat(tags) }
} }
} }

View File

@ -14,7 +14,7 @@ export abstract class AbstractSimpleFileCache <T> {
protected abstract loadRemoteFile (key: string): Promise<GetFilePathResult> protected abstract loadRemoteFile (key: string): Promise<GetFilePathResult>
init (max: number, maxAge: number) { init (max: number, maxAge: number) {
this.getFilePath = memoizee(this.getFilePathImpl, { this.getFilePath = memoizee(this.getFilePathImpl.bind(this), {
maxAge, maxAge,
max, max,
promise: true, promise: true,

View File

@ -7,7 +7,7 @@ import { MVideoWithAllFiles } from '@server/types/models/index.js'
export async function moveToJob (options: { export async function moveToJob (options: {
jobId: string jobId: string
videoUUID: string videoUUID: string
loggerTags: string[] loggerTags: (number | string)[]
moveWebVideoFiles: (video: MVideoWithAllFiles) => Promise<void> moveWebVideoFiles: (video: MVideoWithAllFiles) => Promise<void>
moveHLSFiles: (video: MVideoWithAllFiles) => Promise<void> moveHLSFiles: (video: MVideoWithAllFiles) => Promise<void>

View File

@ -95,7 +95,7 @@ type TaskProcessorOptions <T extends VideoStudioTaskPayload = VideoStudioTaskPay
outputPath: string outputPath: string
video: MVideo video: MVideo
task: T task: T
lTags: { tags: string[] } lTags: { tags: (string | number)[] }
} }
const taskProcessors: { [id in VideoStudioTask['name']]: (options: TaskProcessorOptions) => Promise<any> } = { const taskProcessors: { [id in VideoStudioTask['name']]: (options: TaskProcessorOptions) => Promise<any> } = {

View File

@ -86,7 +86,7 @@ class LiveManager {
.catch(err => logger.error('Cannot handle sessions.', { err, ...lTags(sessionId) })) .catch(err => logger.error('Cannot handle sessions.', { err, ...lTags(sessionId) }))
}) })
events.on('donePublish', sessionId => { events.on('donePublish', (sessionId: string) => {
logger.info('Live session ended.', { sessionId, ...lTags(sessionId) }) logger.info('Live session ended.', { sessionId, ...lTags(sessionId) })
// Force session aborting, so we kill ffmpeg even if it still has data to process (slow CPU) // Force session aborting, so we kill ffmpeg even if it still has data to process (slow CPU)
@ -405,7 +405,7 @@ class LiveManager {
}) })
} }
private async publishAndFederateLive (live: MVideoLiveVideo, localLTags: { tags: string[] }) { private async publishAndFederateLive (live: MVideoLiveVideo, localLTags: { tags: (string | number)[] }) {
const videoId = live.videoId const videoId = live.videoId
try { try {

View File

@ -11,7 +11,7 @@ import { getInternalUrl } from '../urls.js'
import { getClient } from './client.js' import { getClient } from './client.js'
import { lTags } from './logger.js' import { lTags } from './logger.js'
import type { _Object, CompleteMultipartUploadCommandOutput, ObjectCannedACL, PutObjectCommandInput, S3Client } from '@aws-sdk/client-s3' import type { _Object, ObjectCannedACL, PutObjectCommandInput, S3Client } from '@aws-sdk/client-s3'
type BucketInfo = { type BucketInfo = {
BUCKET_NAME: string BUCKET_NAME: string
@ -317,7 +317,7 @@ async function uploadToStorage (options: {
params: input params: input
}) })
const response = (await parallelUploads3.done()) as CompleteMultipartUploadCommandOutput const response = await parallelUploads3.done()
// Check is needed even if the HTTP status code is 200 OK // Check is needed even if the HTTP status code is 200 OK
// For more information, see https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html // For more information, see https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html
if (!response.Bucket) { if (!response.Bucket) {

View File

@ -42,14 +42,16 @@ class PeerTubeSocket {
this.liveVideosNamespace = io.of('/live-videos') this.liveVideosNamespace = io.of('/live-videos')
.on('connection', socket => { .on('connection', socket => {
socket.on('subscribe', ({ videoId }) => { socket.on('subscribe', params => {
const videoId = params.videoId + ''
if (!isIdValid(videoId)) return if (!isIdValid(videoId)) return
/* eslint-disable @typescript-eslint/no-floating-promises */ /* eslint-disable @typescript-eslint/no-floating-promises */
socket.join(videoId) socket.join(videoId)
}) })
socket.on('unsubscribe', ({ videoId }) => { socket.on('unsubscribe', params => {
const videoId = params.videoId + ''
if (!isIdValid(videoId)) return if (!isIdValid(videoId)) return
/* eslint-disable @typescript-eslint/no-floating-promises */ /* eslint-disable @typescript-eslint/no-floating-promises */
@ -93,7 +95,7 @@ class PeerTubeSocket {
logger.debug('Sending video live new state notification of %s.', video.url, { state: video.state }) logger.debug('Sending video live new state notification of %s.', video.url, { state: video.state })
this.liveVideosNamespace this.liveVideosNamespace
.in(video.id) .in(video.id + '')
.emit(type, data) .emit(type, data)
} }
@ -104,7 +106,7 @@ class PeerTubeSocket {
logger.debug('Sending video live views update notification of %s.', video.url, { viewers: numViewers }) logger.debug('Sending video live views update notification of %s.', video.url, { viewers: numViewers })
this.liveVideosNamespace this.liveVideosNamespace
.in(video.id) .in(video.id + '')
.emit(type, data) .emit(type, data)
} }

View File

@ -15,7 +15,7 @@ function asyncMiddleware (fun: RequestPromiseHandler | RequestPromiseHandler[])
} }
try { try {
for (const f of (fun as RequestPromiseHandler[])) { for (const f of fun) {
await new Promise<void>((resolve, reject) => { await new Promise<void>((resolve, reject) => {
return asyncMiddleware(f)(req, res, err => { return asyncMiddleware(f)(req, res, err => {
if (err) return reject(err) if (err) return reject(err)

View File

@ -189,9 +189,9 @@ export class ApiCache {
const self = this const self = this
res.locals.apicache = { res.locals.apicache = {
write: res.write, write: res.write.bind(res),
writeHead: res.writeHead, writeHead: res.writeHead.bind(res),
end: res.end, end: res.end.bind(res),
cacheable: true, cacheable: true,
content: undefined, content: undefined,
headers: undefined headers: undefined

View File

@ -9,7 +9,7 @@ function areValidationErrors (
options: { options: {
omitLog?: boolean omitLog?: boolean
omitBodyLog?: boolean omitBodyLog?: boolean
tags?: string[] tags?: (number | string)[]
} = {}) { } = {}) {
const { omitLog = false, omitBodyLog = false, tags = [] } = options const { omitLog = false, omitBodyLog = false, tags = [] } = options

View File

@ -1,11 +1,10 @@
import { FindOptions } from 'sequelize' import { FindOptions } from 'sequelize'
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Table, UpdatedAt } from 'sequelize-typescript'
import { isAbuseMessageValid } from '@server/helpers/custom-validators/abuses.js' import { isAbuseMessageValid } from '@server/helpers/custom-validators/abuses.js'
import { MAbuseMessage, MAbuseMessageFormattable } from '@server/types/models/index.js' import { MAbuseMessage, MAbuseMessageFormattable } from '@server/types/models/index.js'
import { AbuseMessage } from '@peertube/peertube-models' import { AbuseMessage } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { AccountModel, ScopeNames as AccountScopeNames } from '../account/account.js' import { AccountModel, ScopeNames as AccountScopeNames } from '../account/account.js'
import { getSort, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, getSort, throwIfNotValid } from '../shared/index.js'
import { AbuseModel } from './abuse.js' import { AbuseModel } from './abuse.js'
@Table({ @Table({
@ -19,7 +18,7 @@ import { AbuseModel } from './abuse.js'
} }
] ]
}) })
export class AbuseMessageModel extends Model<Partial<AttributesOnly<AbuseMessageModel>>> { export class AbuseMessageModel extends SequelizeModel<AbuseMessageModel> {
@AllowNull(false) @AllowNull(false)
@Is('AbuseMessage', value => throwIfNotValid(value, isAbuseMessageValid, 'message')) @Is('AbuseMessage', value => throwIfNotValid(value, isAbuseMessageValid, 'message'))

View File

@ -12,7 +12,6 @@ import {
UserVideoAbuse, UserVideoAbuse,
type AbuseStateType type AbuseStateType
} from '@peertube/peertube-models' } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { isAbuseModerationCommentValid, isAbuseReasonValid, isAbuseStateValid } from '@server/helpers/custom-validators/abuses.js' import { isAbuseModerationCommentValid, isAbuseReasonValid, isAbuseStateValid } from '@server/helpers/custom-validators/abuses.js'
import invert from 'lodash-es/invert.js' import invert from 'lodash-es/invert.js'
import { Op, QueryTypes, literal } from 'sequelize' import { Op, QueryTypes, literal } from 'sequelize'
@ -25,9 +24,7 @@ import {
Default, Default,
ForeignKey, ForeignKey,
HasOne, HasOne,
Is, Is, Scopes,
Model,
Scopes,
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
@ -41,7 +38,7 @@ import {
MUserAccountId MUserAccountId
} from '../../types/models/index.js' } from '../../types/models/index.js'
import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions as AccountSummaryOptions } from '../account/account.js' import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions as AccountSummaryOptions } from '../account/account.js'
import { getSort, parseAggregateResult, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, getSort, parseAggregateResult, throwIfNotValid } from '../shared/index.js'
import { ThumbnailModel } from '../video/thumbnail.js' import { ThumbnailModel } from '../video/thumbnail.js'
import { VideoBlacklistModel } from '../video/video-blacklist.js' import { VideoBlacklistModel } from '../video/video-blacklist.js'
import { SummaryOptions as ChannelSummaryOptions, VideoChannelModel, ScopeNames as VideoChannelScopeNames } from '../video/video-channel.js' import { SummaryOptions as ChannelSummaryOptions, VideoChannelModel, ScopeNames as VideoChannelScopeNames } from '../video/video-channel.js'
@ -195,7 +192,7 @@ export enum ScopeNames {
} }
] ]
}) })
export class AbuseModel extends Model<Partial<AttributesOnly<AbuseModel>>> { export class AbuseModel extends SequelizeModel<AbuseModel> {
@AllowNull(false) @AllowNull(false)
@Default(null) @Default(null)

View File

@ -1,8 +1,8 @@
import { type VideoDetails } from '@peertube/peertube-models' import { type VideoDetails } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils' import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript'
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript'
import { VideoModel } from '../video/video.js' import { VideoModel } from '../video/video.js'
import { AbuseModel } from './abuse.js' import { AbuseModel } from './abuse.js'
import { SequelizeModel } from '../shared/index.js'
@Table({ @Table({
tableName: 'videoAbuse', tableName: 'videoAbuse',
@ -15,7 +15,7 @@ import { AbuseModel } from './abuse.js'
} }
] ]
}) })
export class VideoAbuseModel extends Model<Partial<AttributesOnly<VideoAbuseModel>>> { export class VideoAbuseModel extends SequelizeModel<VideoAbuseModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -1,7 +1,7 @@
import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' import { BelongsTo, Column, CreatedAt, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { VideoCommentModel } from '../video/video-comment.js' import { VideoCommentModel } from '../video/video-comment.js'
import { AbuseModel } from './abuse.js' import { AbuseModel } from './abuse.js'
import { SequelizeModel } from '../shared/index.js'
@Table({ @Table({
tableName: 'commentAbuse', tableName: 'commentAbuse',
@ -14,7 +14,7 @@ import { AbuseModel } from './abuse.js'
} }
] ]
}) })
export class VideoCommentAbuseModel extends Model<Partial<AttributesOnly<VideoCommentAbuseModel>>> { export class VideoCommentAbuseModel extends SequelizeModel<VideoCommentAbuseModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -1,12 +1,11 @@
import { FindOptions, Op, QueryTypes } from 'sequelize' import { FindOptions, Op, QueryTypes } from 'sequelize'
import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' import { BelongsTo, Column, CreatedAt, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript'
import { AccountBlock } from '@peertube/peertube-models' import { AccountBlock } from '@peertube/peertube-models'
import { handlesToNameAndHost } from '@server/helpers/actors.js' import { handlesToNameAndHost } from '@server/helpers/actors.js'
import { MAccountBlocklist, MAccountBlocklistFormattable } from '@server/types/models/index.js' import { MAccountBlocklist, MAccountBlocklistFormattable } from '@server/types/models/index.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { ActorModel } from '../actor/actor.js' import { ActorModel } from '../actor/actor.js'
import { ServerModel } from '../server/server.js' import { ServerModel } from '../server/server.js'
import { createSafeIn, getSort, searchAttribute } from '../shared/index.js' import { SequelizeModel, createSafeIn, getSort, searchAttribute } from '../shared/index.js'
import { AccountModel } from './account.js' import { AccountModel } from './account.js'
import { WEBSERVER } from '@server/initializers/constants.js' import { WEBSERVER } from '@server/initializers/constants.js'
@ -22,7 +21,7 @@ import { WEBSERVER } from '@server/initializers/constants.js'
} }
] ]
}) })
export class AccountBlocklistModel extends Model<Partial<AttributesOnly<AccountBlocklistModel>>> { export class AccountBlocklistModel extends SequelizeModel<AccountBlocklistModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -1,5 +1,4 @@
import { AccountVideoRate, type VideoRateType } from '@peertube/peertube-models' import { AccountVideoRate, type VideoRateType } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { import {
MAccountVideoRate, MAccountVideoRate,
MAccountVideoRateAccountUrl, MAccountVideoRateAccountUrl,
@ -8,11 +7,11 @@ import {
MAccountVideoRateVideoUrl MAccountVideoRateVideoUrl
} from '@server/types/models/index.js' } from '@server/types/models/index.js'
import { FindOptions, Op, QueryTypes, Transaction } from 'sequelize' import { FindOptions, Op, QueryTypes, Transaction } from 'sequelize'
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Table, UpdatedAt } from 'sequelize-typescript'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc.js' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc.js'
import { CONSTRAINTS_FIELDS, VIDEO_RATE_TYPES } from '../../initializers/constants.js' import { CONSTRAINTS_FIELDS, VIDEO_RATE_TYPES } from '../../initializers/constants.js'
import { ActorModel } from '../actor/actor.js' import { ActorModel } from '../actor/actor.js'
import { getSort, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, getSort, throwIfNotValid } from '../shared/index.js'
import { SummaryOptions, VideoChannelModel, ScopeNames as VideoChannelScopeNames } from '../video/video-channel.js' import { SummaryOptions, VideoChannelModel, ScopeNames as VideoChannelScopeNames } from '../video/video-channel.js'
import { VideoModel } from '../video/video.js' import { VideoModel } from '../video/video.js'
import { AccountModel } from './account.js' import { AccountModel } from './account.js'
@ -42,7 +41,7 @@ import { AccountModel } from './account.js'
} }
] ]
}) })
export class AccountVideoRateModel extends Model<Partial<AttributesOnly<AccountVideoRateModel>>> { export class AccountVideoRateModel extends SequelizeModel<AccountVideoRateModel> {
@AllowNull(false) @AllowNull(false)
@Column(DataType.ENUM(...Object.values(VIDEO_RATE_TYPES))) @Column(DataType.ENUM(...Object.values(VIDEO_RATE_TYPES)))

View File

@ -10,15 +10,12 @@ import {
DefaultScope, DefaultScope,
ForeignKey, ForeignKey,
HasMany, HasMany,
Is, Is, Scopes,
Model,
Scopes,
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { Account, AccountSummary } from '@peertube/peertube-models' import { Account, AccountSummary } from '@peertube/peertube-models'
import { ModelCache } from '@server/models/shared/model-cache.js' import { ModelCache } from '@server/models/shared/model-cache.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { isAccountDescriptionValid } from '../../helpers/custom-validators/accounts.js' import { isAccountDescriptionValid } from '../../helpers/custom-validators/accounts.js'
import { CONSTRAINTS_FIELDS, SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants.js' import { CONSTRAINTS_FIELDS, SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants.js'
import { sendDeleteActor } from '../../lib/activitypub/send/send-delete.js' import { sendDeleteActor } from '../../lib/activitypub/send/send-delete.js'
@ -36,7 +33,7 @@ import { ActorModel } from '../actor/actor.js'
import { ApplicationModel } from '../application/application.js' import { ApplicationModel } from '../application/application.js'
import { ServerBlocklistModel } from '../server/server-blocklist.js' import { ServerBlocklistModel } from '../server/server-blocklist.js'
import { ServerModel } from '../server/server.js' import { ServerModel } from '../server/server.js'
import { buildSQLAttributes, getSort, throwIfNotValid } from '../shared/index.js' import { buildSQLAttributes, getSort, SequelizeModel, throwIfNotValid } from '../shared/index.js'
import { UserModel } from '../user/user.js' import { UserModel } from '../user/user.js'
import { VideoChannelModel } from '../video/video-channel.js' import { VideoChannelModel } from '../video/video-channel.js'
import { VideoCommentModel } from '../video/video-comment.js' import { VideoCommentModel } from '../video/video-comment.js'
@ -144,7 +141,7 @@ export type SummaryOptions = {
} }
] ]
}) })
export class AccountModel extends Model<Partial<AttributesOnly<AccountModel>>> { export class AccountModel extends SequelizeModel<AccountModel> {
@AllowNull(false) @AllowNull(false)
@Column @Column

View File

@ -1,7 +1,8 @@
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript'
import { CustomPage } from '@peertube/peertube-models' import { CustomPage } from '@peertube/peertube-models'
import { ActorModel } from '../actor/actor.js' import { ActorModel } from '../actor/actor.js'
import { getServerActor } from '../application/application.js' import { getServerActor } from '../application/application.js'
import { SequelizeModel } from '../shared/index.js'
@Table({ @Table({
tableName: 'actorCustomPage', tableName: 'actorCustomPage',
@ -12,7 +13,7 @@ import { getServerActor } from '../application/application.js'
} }
] ]
}) })
export class ActorCustomPageModel extends Model { export class ActorCustomPageModel extends SequelizeModel<ActorCustomPageModel> {
@AllowNull(true) @AllowNull(true)
@Column(DataType.TEXT) @Column(DataType.TEXT)

View File

@ -1,5 +1,4 @@
import { ActorFollow, type FollowState } from '@peertube/peertube-models' import { ActorFollow, type FollowState } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { isActivityPubUrlValid } from '@server/helpers/custom-validators/activitypub/misc.js' import { isActivityPubUrlValid } from '@server/helpers/custom-validators/activitypub/misc.js'
import { afterCommitIfTransaction } from '@server/helpers/database-utils.js' import { afterCommitIfTransaction } from '@server/helpers/database-utils.js'
import { getServerActor } from '@server/models/application/application.js' import { getServerActor } from '@server/models/application/application.js'
@ -27,16 +26,14 @@ import {
ForeignKey, ForeignKey,
Is, Is,
IsInt, IsInt,
Max, Max, Table,
Model,
Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { logger } from '../../helpers/logger.js' import { logger } from '../../helpers/logger.js'
import { ACTOR_FOLLOW_SCORE, CONSTRAINTS_FIELDS, FOLLOW_STATES, SERVER_ACTOR_NAME, SORTABLE_COLUMNS } from '../../initializers/constants.js' import { ACTOR_FOLLOW_SCORE, CONSTRAINTS_FIELDS, FOLLOW_STATES, SERVER_ACTOR_NAME, SORTABLE_COLUMNS } from '../../initializers/constants.js'
import { AccountModel } from '../account/account.js' import { AccountModel } from '../account/account.js'
import { ServerModel } from '../server/server.js' import { ServerModel } from '../server/server.js'
import { buildSQLAttributes, createSafeIn, getSort, searchAttribute, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, buildSQLAttributes, createSafeIn, getSort, searchAttribute, throwIfNotValid } from '../shared/index.js'
import { doesExist } from '../shared/query.js' import { doesExist } from '../shared/query.js'
import { VideoChannelModel } from '../video/video-channel.js' import { VideoChannelModel } from '../video/video-channel.js'
import { ActorModel, unusedActorAttributesForAPI } from './actor.js' import { ActorModel, unusedActorAttributesForAPI } from './actor.js'
@ -65,7 +62,7 @@ import { InstanceListFollowingQueryBuilder, ListFollowingOptions } from './sql/i
} }
] ]
}) })
export class ActorFollowModel extends Model<Partial<AttributesOnly<ActorFollowModel>>> { export class ActorFollowModel extends SequelizeModel<ActorFollowModel> {
@AllowNull(false) @AllowNull(false)
@Column(DataType.ENUM(...Object.values(FOLLOW_STATES))) @Column(DataType.ENUM(...Object.values(FOLLOW_STATES)))

View File

@ -1,6 +1,5 @@
import { ActivityIconObject, ActorImage, ActorImageType, type ActorImageType_Type } from '@peertube/peertube-models' import { ActivityIconObject, ActorImage, ActorImageType, type ActorImageType_Type } from '@peertube/peertube-models'
import { getLowercaseExtension } from '@peertube/peertube-node-utils' import { getLowercaseExtension } from '@peertube/peertube-node-utils'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { MActorId, MActorImage, MActorImageFormattable } from '@server/types/models/index.js' import { MActorId, MActorImage, MActorImageFormattable } from '@server/types/models/index.js'
import { remove } from 'fs-extra/esm' import { remove } from 'fs-extra/esm'
import { join } from 'path' import { join } from 'path'
@ -12,16 +11,14 @@ import {
CreatedAt, CreatedAt,
Default, Default,
ForeignKey, ForeignKey,
Is, Is, Table,
Model,
Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc.js' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc.js'
import { logger } from '../../helpers/logger.js' import { logger } from '../../helpers/logger.js'
import { CONFIG } from '../../initializers/config.js' import { CONFIG } from '../../initializers/config.js'
import { LAZY_STATIC_PATHS, MIMETYPES, WEBSERVER } from '../../initializers/constants.js' import { LAZY_STATIC_PATHS, MIMETYPES, WEBSERVER } from '../../initializers/constants.js'
import { buildSQLAttributes, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, buildSQLAttributes, throwIfNotValid } from '../shared/index.js'
import { ActorModel } from './actor.js' import { ActorModel } from './actor.js'
@Table({ @Table({
@ -37,7 +34,7 @@ import { ActorModel } from './actor.js'
} }
] ]
}) })
export class ActorImageModel extends Model<Partial<AttributesOnly<ActorImageModel>>> { export class ActorImageModel extends SequelizeModel<ActorImageModel> {
@AllowNull(false) @AllowNull(false)
@Column @Column

View File

@ -17,9 +17,7 @@ import {
ForeignKey, ForeignKey,
HasMany, HasMany,
HasOne, HasOne,
Is, Is, Scopes,
Model,
Scopes,
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
@ -58,7 +56,7 @@ import {
import { AccountModel } from '../account/account.js' import { AccountModel } from '../account/account.js'
import { getServerActor } from '../application/application.js' import { getServerActor } from '../application/application.js'
import { ServerModel } from '../server/server.js' import { ServerModel } from '../server/server.js'
import { buildSQLAttributes, isOutdated, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, buildSQLAttributes, isOutdated, throwIfNotValid } from '../shared/index.js'
import { VideoChannelModel } from '../video/video-channel.js' import { VideoChannelModel } from '../video/video-channel.js'
import { VideoModel } from '../video/video.js' import { VideoModel } from '../video/video.js'
import { ActorFollowModel } from './actor-follow.js' import { ActorFollowModel } from './actor-follow.js'
@ -165,7 +163,7 @@ export const unusedActorAttributesForAPI: (keyof AttributesOnly<ActorModel>)[] =
} }
] ]
}) })
export class ActorModel extends Model<Partial<AttributesOnly<ActorModel>>> { export class ActorModel extends SequelizeModel<ActorModel> {
@AllowNull(false) @AllowNull(false)
@Column(DataType.ENUM(...Object.values(ACTIVITY_PUB_ACTOR_TYPES))) @Column(DataType.ENUM(...Object.values(ACTIVITY_PUB_ACTOR_TYPES)))

View File

@ -1,8 +1,8 @@
import memoizee from 'memoizee' import memoizee from 'memoizee'
import { AllowNull, Column, Default, DefaultScope, HasOne, IsInt, Model, Table } from 'sequelize-typescript' import { AllowNull, Column, Default, DefaultScope, HasOne, IsInt, Table } from 'sequelize-typescript'
import { getNodeABIVersion } from '@server/helpers/version.js' import { getNodeABIVersion } from '@server/helpers/version.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { AccountModel } from '../account/account.js' import { AccountModel } from '../account/account.js'
import { SequelizeModel } from '../shared/index.js'
export const getServerActor = memoizee(async function () { export const getServerActor = memoizee(async function () {
const application = await ApplicationModel.load() const application = await ApplicationModel.load()
@ -26,7 +26,7 @@ export const getServerActor = memoizee(async function () {
tableName: 'application', tableName: 'application',
timestamps: false timestamps: false
}) })
export class ApplicationModel extends Model<Partial<AttributesOnly<ApplicationModel>>> { export class ApplicationModel extends SequelizeModel<ApplicationModel> {
@AllowNull(false) @AllowNull(false)
@Default(0) @Default(0)

View File

@ -1,6 +1,6 @@
import { AllowNull, Column, CreatedAt, DataType, HasMany, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, Column, CreatedAt, DataType, HasMany, Table, UpdatedAt } from 'sequelize-typescript'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { OAuthTokenModel } from './oauth-token.js' import { OAuthTokenModel } from './oauth-token.js'
import { SequelizeModel } from '../shared/index.js'
@Table({ @Table({
tableName: 'oAuthClient', tableName: 'oAuthClient',
@ -15,7 +15,7 @@ import { OAuthTokenModel } from './oauth-token.js'
} }
] ]
}) })
export class OAuthClientModel extends Model<Partial<AttributesOnly<OAuthClientModel>>> { export class OAuthClientModel extends SequelizeModel<OAuthClientModel> {
@AllowNull(false) @AllowNull(false)
@Column @Column

View File

@ -6,21 +6,19 @@ import {
BelongsTo, BelongsTo,
Column, Column,
CreatedAt, CreatedAt,
ForeignKey, ForeignKey, Scopes,
Model,
Scopes,
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { TokensCache } from '@server/lib/auth/tokens-cache.js' import { TokensCache } from '@server/lib/auth/tokens-cache.js'
import { MUserAccountId } from '@server/types/models/index.js' import { MUserAccountId } from '@server/types/models/index.js'
import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token.js' import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { logger } from '../../helpers/logger.js' import { logger } from '../../helpers/logger.js'
import { AccountModel } from '../account/account.js' import { AccountModel } from '../account/account.js'
import { ActorModel } from '../actor/actor.js' import { ActorModel } from '../actor/actor.js'
import { UserModel } from '../user/user.js' import { UserModel } from '../user/user.js'
import { OAuthClientModel } from './oauth-client.js' import { OAuthClientModel } from './oauth-client.js'
import { SequelizeModel } from '../shared/index.js'
export type OAuthTokenInfo = { export type OAuthTokenInfo = {
refreshToken: string refreshToken: string
@ -80,7 +78,7 @@ enum ScopeNames {
} }
] ]
}) })
export class OAuthTokenModel extends Model<Partial<AttributesOnly<OAuthTokenModel>>> { export class OAuthTokenModel extends SequelizeModel<OAuthTokenModel> {
@AllowNull(false) @AllowNull(false)
@Column @Column

View File

@ -8,9 +8,7 @@ import {
CreatedAt, CreatedAt,
DataType, DataType,
ForeignKey, ForeignKey,
Is, Is, Scopes,
Model,
Scopes,
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
@ -26,7 +24,6 @@ import {
VideoRedundancyStrategyWithManual VideoRedundancyStrategyWithManual
} from '@peertube/peertube-models' } from '@peertube/peertube-models'
import { isTestInstance } from '@peertube/peertube-node-utils' import { isTestInstance } from '@peertube/peertube-node-utils'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { getServerActor } from '@server/models/application/application.js' import { getServerActor } from '@server/models/application/application.js'
import { MActor, MVideoForRedundancyAPI, MVideoRedundancy, MVideoRedundancyAP, MVideoRedundancyVideo } from '@server/types/models/index.js' import { MActor, MVideoForRedundancyAPI, MVideoRedundancy, MVideoRedundancyAP, MVideoRedundancyVideo } from '@server/types/models/index.js'
import { isActivityPubUrlValid, isUrlValid } from '../../helpers/custom-validators/activitypub/misc.js' import { isActivityPubUrlValid, isUrlValid } from '../../helpers/custom-validators/activitypub/misc.js'
@ -35,7 +32,7 @@ import { CONFIG } from '../../initializers/config.js'
import { CONSTRAINTS_FIELDS } from '../../initializers/constants.js' import { CONSTRAINTS_FIELDS } from '../../initializers/constants.js'
import { ActorModel } from '../actor/actor.js' import { ActorModel } from '../actor/actor.js'
import { ServerModel } from '../server/server.js' import { ServerModel } from '../server/server.js'
import { getSort, getVideoSort, parseAggregateResult, throwIfNotValid } from '../shared/index.js' import { getSort, getVideoSort, parseAggregateResult, SequelizeModel, throwIfNotValid } from '../shared/index.js'
import { ScheduleVideoUpdateModel } from '../video/schedule-video-update.js' import { ScheduleVideoUpdateModel } from '../video/schedule-video-update.js'
import { VideoChannelModel } from '../video/video-channel.js' import { VideoChannelModel } from '../video/video-channel.js'
import { VideoFileModel } from '../video/video-file.js' import { VideoFileModel } from '../video/video-file.js'
@ -92,7 +89,7 @@ export enum ScopeNames {
} }
] ]
}) })
export class VideoRedundancyModel extends Model<Partial<AttributesOnly<VideoRedundancyModel>>> { export class VideoRedundancyModel extends SequelizeModel<VideoRedundancyModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -7,7 +7,6 @@ import {
type RunnerJobStateType, type RunnerJobStateType,
type RunnerJobType type RunnerJobType
} from '@peertube/peertube-models' } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { isArray, isUUIDValid } from '@server/helpers/custom-validators/misc.js' import { isArray, isUUIDValid } from '@server/helpers/custom-validators/misc.js'
import { CONSTRAINTS_FIELDS, RUNNER_JOB_STATES } from '@server/initializers/constants.js' import { CONSTRAINTS_FIELDS, RUNNER_JOB_STATES } from '@server/initializers/constants.js'
import { MRunnerJob, MRunnerJobRunner, MRunnerJobRunnerParent } from '@server/types/models/runners/index.js' import { MRunnerJob, MRunnerJobRunner, MRunnerJobRunnerParent } from '@server/types/models/runners/index.js'
@ -20,13 +19,11 @@ import {
DataType, DataType,
Default, Default,
ForeignKey, ForeignKey,
IsUUID, IsUUID, Scopes,
Model,
Scopes,
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { getSort, searchAttribute } from '../shared/index.js' import { SequelizeModel, getSort, searchAttribute } from '../shared/index.js'
import { RunnerModel } from './runner.js' import { RunnerModel } from './runner.js'
enum ScopeNames { enum ScopeNames {
@ -68,7 +65,7 @@ enum ScopeNames {
} }
] ]
}) })
export class RunnerJobModel extends Model<Partial<AttributesOnly<RunnerJobModel>>> { export class RunnerJobModel extends SequelizeModel<RunnerJobModel> {
@AllowNull(false) @AllowNull(false)
@IsUUID(4) @IsUUID(4)

View File

@ -1,9 +1,8 @@
import { FindOptions, literal } from 'sequelize' import { FindOptions, literal } from 'sequelize'
import { AllowNull, Column, CreatedAt, HasMany, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, Column, CreatedAt, HasMany, Table, UpdatedAt } from 'sequelize-typescript'
import { MRunnerRegistrationToken } from '@server/types/models/runners/index.js' import { MRunnerRegistrationToken } from '@server/types/models/runners/index.js'
import { RunnerRegistrationToken } from '@peertube/peertube-models' import { RunnerRegistrationToken } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils' import { SequelizeModel, getSort } from '../shared/index.js'
import { getSort } from '../shared/index.js'
import { RunnerModel } from './runner.js' import { RunnerModel } from './runner.js'
/** /**
@ -21,7 +20,7 @@ import { RunnerModel } from './runner.js'
} }
] ]
}) })
export class RunnerRegistrationTokenModel extends Model<Partial<AttributesOnly<RunnerRegistrationTokenModel>>> { export class RunnerRegistrationTokenModel extends SequelizeModel<RunnerRegistrationTokenModel> {
@AllowNull(false) @AllowNull(false)
@Column @Column

View File

@ -1,9 +1,8 @@
import { FindOptions } from 'sequelize' import { FindOptions } from 'sequelize'
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript'
import { MRunner } from '@server/types/models/runners/index.js' import { MRunner } from '@server/types/models/runners/index.js'
import { Runner } from '@peertube/peertube-models' import { Runner } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils' import { SequelizeModel, getSort } from '../shared/index.js'
import { getSort } from '../shared/index.js'
import { RunnerRegistrationTokenModel } from './runner-registration-token.js' import { RunnerRegistrationTokenModel } from './runner-registration-token.js'
import { CONSTRAINTS_FIELDS } from '@server/initializers/constants.js' import { CONSTRAINTS_FIELDS } from '@server/initializers/constants.js'
@ -23,7 +22,7 @@ import { CONSTRAINTS_FIELDS } from '@server/initializers/constants.js'
} }
] ]
}) })
export class RunnerModel extends Model<Partial<AttributesOnly<RunnerModel>>> { export class RunnerModel extends SequelizeModel<RunnerModel> {
// Used to identify the appropriate runner when it uses the runner REST API // Used to identify the appropriate runner when it uses the runner REST API
@AllowNull(false) @AllowNull(false)

View File

@ -6,10 +6,9 @@ import {
SettingValue, SettingValue,
type PluginType_Type type PluginType_Type
} from '@peertube/peertube-models' } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { MPlugin, MPluginFormattable } from '@server/types/models/index.js' import { MPlugin, MPluginFormattable } from '@server/types/models/index.js'
import { FindAndCountOptions, json, QueryTypes } from 'sequelize' import { FindAndCountOptions, json, QueryTypes } from 'sequelize'
import { AllowNull, Column, CreatedAt, DataType, DefaultScope, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, Column, CreatedAt, DataType, DefaultScope, Is, Table, UpdatedAt } from 'sequelize-typescript'
import { import {
isPluginDescriptionValid, isPluginDescriptionValid,
isPluginHomepage, isPluginHomepage,
@ -18,7 +17,7 @@ import {
isPluginStableVersionValid, isPluginStableVersionValid,
isPluginTypeValid isPluginTypeValid
} from '../../helpers/custom-validators/plugins.js' } from '../../helpers/custom-validators/plugins.js'
import { getSort, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, getSort, throwIfNotValid } from '../shared/index.js'
@DefaultScope(() => ({ @DefaultScope(() => ({
attributes: { attributes: {
@ -35,7 +34,7 @@ import { getSort, throwIfNotValid } from '../shared/index.js'
} }
] ]
}) })
export class PluginModel extends Model<Partial<AttributesOnly<PluginModel>>> { export class PluginModel extends SequelizeModel<PluginModel> {
@AllowNull(false) @AllowNull(false)
@Is('PluginName', value => throwIfNotValid(value, isPluginNameValid, 'name')) @Is('PluginName', value => throwIfNotValid(value, isPluginNameValid, 'name'))

View File

@ -1,10 +1,9 @@
import { Op, QueryTypes } from 'sequelize' import { Op, QueryTypes } from 'sequelize'
import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' import { BelongsTo, Column, CreatedAt, ForeignKey, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
import { MServerBlocklist, MServerBlocklistAccountServer, MServerBlocklistFormattable } from '@server/types/models/index.js' import { MServerBlocklist, MServerBlocklistAccountServer, MServerBlocklistFormattable } from '@server/types/models/index.js'
import { ServerBlock } from '@peertube/peertube-models' import { ServerBlock } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { AccountModel } from '../account/account.js' import { AccountModel } from '../account/account.js'
import { createSafeIn, getSort, searchAttribute } from '../shared/index.js' import { SequelizeModel, createSafeIn, getSort, searchAttribute } from '../shared/index.js'
import { ServerModel } from './server.js' import { ServerModel } from './server.js'
enum ScopeNames { enum ScopeNames {
@ -43,7 +42,7 @@ enum ScopeNames {
} }
] ]
}) })
export class ServerBlocklistModel extends Model<Partial<AttributesOnly<ServerBlocklistModel>>> { export class ServerBlocklistModel extends SequelizeModel<ServerBlocklistModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -1,10 +1,9 @@
import { Transaction } from 'sequelize' import { Transaction } from 'sequelize'
import { AllowNull, Column, CreatedAt, Default, HasMany, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, Column, CreatedAt, Default, HasMany, Is, Table, UpdatedAt } from 'sequelize-typescript'
import { MServer, MServerFormattable } from '@server/types/models/server/index.js' import { MServer, MServerFormattable } from '@server/types/models/server/index.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { isHostValid } from '../../helpers/custom-validators/servers.js' import { isHostValid } from '../../helpers/custom-validators/servers.js'
import { ActorModel } from '../actor/actor.js' import { ActorModel } from '../actor/actor.js'
import { buildSQLAttributes, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, buildSQLAttributes, throwIfNotValid } from '../shared/index.js'
import { ServerBlocklistModel } from './server-blocklist.js' import { ServerBlocklistModel } from './server-blocklist.js'
@Table({ @Table({
@ -16,7 +15,7 @@ import { ServerBlocklistModel } from './server-blocklist.js'
} }
] ]
}) })
export class ServerModel extends Model<Partial<AttributesOnly<ServerModel>>> { export class ServerModel extends SequelizeModel<ServerModel> {
@AllowNull(false) @AllowNull(false)
@Is('Host', value => throwIfNotValid(value, isHostValid, 'valid host')) @Is('Host', value => throwIfNotValid(value, isHostValid, 'valid host'))

View File

@ -1,9 +1,9 @@
import { AllowNull, BelongsToMany, Column, CreatedAt, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsToMany, Column, CreatedAt, Table, UpdatedAt } from 'sequelize-typescript'
import { Transaction } from 'sequelize' import { Transaction } from 'sequelize'
import { MTracker } from '@server/types/models/server/tracker.js' import { MTracker } from '@server/types/models/server/tracker.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { VideoModel } from '../video/video.js' import { VideoModel } from '../video/video.js'
import { VideoTrackerModel } from './video-tracker.js' import { VideoTrackerModel } from './video-tracker.js'
import { SequelizeModel } from '../shared/sequelize-type.js'
@Table({ @Table({
tableName: 'tracker', tableName: 'tracker',
@ -14,7 +14,7 @@ import { VideoTrackerModel } from './video-tracker.js'
} }
] ]
}) })
export class TrackerModel extends Model<Partial<AttributesOnly<TrackerModel>>> { export class TrackerModel extends SequelizeModel<TrackerModel> {
@AllowNull(false) @AllowNull(false)
@Column @Column

View File

@ -1,7 +1,7 @@
import { Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' import { Column, CreatedAt, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { VideoModel } from '../video/video.js' import { VideoModel } from '../video/video.js'
import { TrackerModel } from './tracker.js' import { TrackerModel } from './tracker.js'
import { SequelizeModel } from '../shared/index.js'
@Table({ @Table({
tableName: 'videoTracker', tableName: 'videoTracker',
@ -14,7 +14,7 @@ import { TrackerModel } from './tracker.js'
} }
] ]
}) })
export class VideoTrackerModel extends Model<Partial<AttributesOnly<VideoTrackerModel>>> { export class VideoTrackerModel extends SequelizeModel<VideoTrackerModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -3,6 +3,7 @@ export * from './model-builder.js'
export * from './model-cache.js' export * from './model-cache.js'
export * from './query.js' export * from './query.js'
export * from './sequelize-helpers.js' export * from './sequelize-helpers.js'
export * from './sequelize-type.js'
export * from './sort.js' export * from './sort.js'
export * from './sql.js' export * from './sql.js'
export * from './update.js' export * from './update.js'

View File

@ -0,0 +1,6 @@
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { Model } from 'sequelize-typescript'
export abstract class SequelizeModel <T> extends Model<Partial<AttributesOnly<T>>> {
id: number
}

View File

@ -1,7 +1,6 @@
import { FindOptions, Op } from 'sequelize' import { FindOptions, Op } from 'sequelize'
import { AllowNull, BeforeDestroy, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BeforeDestroy, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript'
import { MUserAccountId, MUserExport } from '@server/types/models/index.js' import { MUserAccountId, MUserExport } from '@server/types/models/index.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { UserModel } from './user.js' import { UserModel } from './user.js'
import { getSort } from '../shared/sort.js' import { getSort } from '../shared/sort.js'
import { UserExportState, type UserExport, type UserExportStateType, type FileStorageType, FileStorage } from '@peertube/peertube-models' import { UserExportState, type UserExport, type UserExportStateType, type FileStorageType, FileStorage } from '@peertube/peertube-models'
@ -18,6 +17,7 @@ import { join } from 'path'
import jwt from 'jsonwebtoken' import jwt from 'jsonwebtoken'
import { CONFIG } from '@server/initializers/config.js' import { CONFIG } from '@server/initializers/config.js'
import { removeUserExportObjectStorage } from '@server/lib/object-storage/user-export.js' import { removeUserExportObjectStorage } from '@server/lib/object-storage/user-export.js'
import { SequelizeModel } from '../shared/sequelize-type.js'
@Table({ @Table({
tableName: 'userExport', tableName: 'userExport',
@ -31,7 +31,7 @@ import { removeUserExportObjectStorage } from '@server/lib/object-storage/user-e
} }
] ]
}) })
export class UserExportModel extends Model<Partial<AttributesOnly<UserExportModel>>> { export class UserExportModel extends SequelizeModel<UserExportModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -1,6 +1,6 @@
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript'
import { MUserImport } from '@server/types/models/index.js' import { MUserImport } from '@server/types/models/index.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils' import { SequelizeModel } from '../shared/index.js'
import { UserModel } from './user.js' import { UserModel } from './user.js'
import type { UserImportResultSummary, UserImportStateType } from '@peertube/peertube-models' import type { UserImportResultSummary, UserImportStateType } from '@peertube/peertube-models'
import { getSort } from '../shared/sort.js' import { getSort } from '../shared/sort.js'
@ -18,7 +18,7 @@ import { USER_IMPORT_STATES } from '@server/initializers/constants.js'
} }
] ]
}) })
export class UserImportModel extends Model<Partial<AttributesOnly<UserImportModel>>> { export class UserImportModel extends SequelizeModel<UserImportModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -1,5 +1,4 @@
import { type UserNotificationSetting, type UserNotificationSettingValueType } from '@peertube/peertube-models' import { type UserNotificationSetting, type UserNotificationSettingValueType } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { TokensCache } from '@server/lib/auth/tokens-cache.js' import { TokensCache } from '@server/lib/auth/tokens-cache.js'
import { MNotificationSettingFormattable } from '@server/types/models/index.js' import { MNotificationSettingFormattable } from '@server/types/models/index.js'
import { import {
@ -11,13 +10,11 @@ import {
CreatedAt, CreatedAt,
Default, Default,
ForeignKey, ForeignKey,
Is, Is, Table,
Model,
Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications.js' import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications.js'
import { throwIfNotValid } from '../shared/index.js' import { SequelizeModel, throwIfNotValid } from '../shared/index.js'
import { UserModel } from './user.js' import { UserModel } from './user.js'
@Table({ @Table({
@ -29,7 +26,7 @@ import { UserModel } from './user.js'
} }
] ]
}) })
export class UserNotificationSettingModel extends Model<Partial<AttributesOnly<UserNotificationSettingModel>>> { export class UserNotificationSettingModel extends SequelizeModel<UserNotificationSettingModel> {
@AllowNull(false) @AllowNull(false)
@Default(null) @Default(null)

View File

@ -1,11 +1,10 @@
import { forceNumber } from '@peertube/peertube-core-utils' import { forceNumber } from '@peertube/peertube-core-utils'
import { UserNotification, type UserNotificationType_Type } from '@peertube/peertube-models' import { UserNotification, type UserNotificationType_Type } from '@peertube/peertube-models'
import { uuidToShort } from '@peertube/peertube-node-utils' import { uuidToShort } from '@peertube/peertube-node-utils'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { getBiggestActorImage } from '@server/lib/actor-image.js' import { getBiggestActorImage } from '@server/lib/actor-image.js'
import { UserNotificationIncludes, UserNotificationModelForApi } from '@server/types/models/user/index.js' import { UserNotificationIncludes, UserNotificationModelForApi } from '@server/types/models/user/index.js'
import { ModelIndexesOptions, Op, WhereOptions } from 'sequelize' import { ModelIndexesOptions, Op, WhereOptions } from 'sequelize'
import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Is, Table, UpdatedAt } from 'sequelize-typescript'
import { isBooleanValid } from '../../helpers/custom-validators/misc.js' import { isBooleanValid } from '../../helpers/custom-validators/misc.js'
import { isUserNotificationTypeValid } from '../../helpers/custom-validators/user-notifications.js' import { isUserNotificationTypeValid } from '../../helpers/custom-validators/user-notifications.js'
import { AbuseModel } from '../abuse/abuse.js' import { AbuseModel } from '../abuse/abuse.js'
@ -13,7 +12,7 @@ import { AccountModel } from '../account/account.js'
import { ActorFollowModel } from '../actor/actor-follow.js' import { ActorFollowModel } from '../actor/actor-follow.js'
import { ApplicationModel } from '../application/application.js' import { ApplicationModel } from '../application/application.js'
import { PluginModel } from '../server/plugin.js' import { PluginModel } from '../server/plugin.js'
import { throwIfNotValid } from '../shared/index.js' import { SequelizeModel, throwIfNotValid } from '../shared/index.js'
import { VideoBlacklistModel } from '../video/video-blacklist.js' import { VideoBlacklistModel } from '../video/video-blacklist.js'
import { VideoCommentModel } from '../video/video-comment.js' import { VideoCommentModel } from '../video/video-comment.js'
import { VideoImportModel } from '../video/video-import.js' import { VideoImportModel } from '../video/video-import.js'
@ -110,7 +109,7 @@ import { UserModel } from './user.js'
} }
] as (ModelIndexesOptions & { where?: WhereOptions })[] ] as (ModelIndexesOptions & { where?: WhereOptions })[]
}) })
export class UserNotificationModel extends Model<Partial<AttributesOnly<UserNotificationModel>>> { export class UserNotificationModel extends SequelizeModel<UserNotificationModel> {
@AllowNull(false) @AllowNull(false)
@Default(null) @Default(null)

View File

@ -1,5 +1,4 @@
import { UserRegistration, type UserRegistrationStateType } from '@peertube/peertube-models' import { UserRegistration, type UserRegistrationStateType } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { import {
isRegistrationModerationResponseValid, isRegistrationModerationResponseValid,
isRegistrationReasonValid, isRegistrationReasonValid,
@ -19,13 +18,11 @@ import {
DataType, DataType,
ForeignKey, ForeignKey,
Is, Is,
IsEmail, IsEmail, Table,
Model,
Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { isUserDisplayNameValid, isUserEmailVerifiedValid, isUserPasswordValid } from '../../helpers/custom-validators/users.js' import { isUserDisplayNameValid, isUserEmailVerifiedValid, isUserPasswordValid } from '../../helpers/custom-validators/users.js'
import { getSort, parseAggregateResult, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, getSort, parseAggregateResult, throwIfNotValid } from '../shared/index.js'
import { UserModel } from './user.js' import { UserModel } from './user.js'
import { forceNumber } from '@peertube/peertube-core-utils' import { forceNumber } from '@peertube/peertube-core-utils'
@ -50,7 +47,7 @@ import { forceNumber } from '@peertube/peertube-core-utils'
} }
] ]
}) })
export class UserRegistrationModel extends Model<Partial<AttributesOnly<UserRegistrationModel>>> { export class UserRegistrationModel extends SequelizeModel<UserRegistrationModel> {
@AllowNull(false) @AllowNull(false)
@Is('RegistrationState', value => throwIfNotValid(value, isRegistrationStateValid, 'state')) @Is('RegistrationState', value => throwIfNotValid(value, isRegistrationStateValid, 'state'))

View File

@ -1,10 +1,10 @@
import { DestroyOptions, Op, Transaction } from 'sequelize' import { DestroyOptions, Op, Transaction } from 'sequelize'
import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, IsInt, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, IsInt, Table, UpdatedAt } from 'sequelize-typescript'
import { ResultList } from '@peertube/peertube-models' import { ResultList } from '@peertube/peertube-models'
import { MUserAccountId, MUserId } from '@server/types/models/index.js' import { MUserAccountId, MUserId } from '@server/types/models/index.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { VideoModel } from '../video/video.js' import { VideoModel } from '../video/video.js'
import { UserModel } from './user.js' import { UserModel } from './user.js'
import { SequelizeModel } from '../shared/sequelize-type.js'
@Table({ @Table({
tableName: 'userVideoHistory', tableName: 'userVideoHistory',
@ -21,7 +21,7 @@ import { UserModel } from './user.js'
} }
] ]
}) })
export class UserVideoHistoryModel extends Model<Partial<AttributesOnly<UserVideoHistoryModel>>> { export class UserVideoHistoryModel extends SequelizeModel<UserVideoHistoryModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -10,7 +10,6 @@ import {
type UserAdminFlagType, type UserAdminFlagType,
type UserRoleType type UserRoleType
} from '@peertube/peertube-models' } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { TokensCache } from '@server/lib/auth/tokens-cache.js' import { TokensCache } from '@server/lib/auth/tokens-cache.js'
import { LiveQuotaStore } from '@server/lib/live/index.js' import { LiveQuotaStore } from '@server/lib/live/index.js'
import { import {
@ -37,9 +36,7 @@ import {
HasOne, HasOne,
Is, Is,
IsEmail, IsEmail,
IsUUID, IsUUID, Scopes,
Model,
Scopes,
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
@ -70,7 +67,7 @@ import { ActorFollowModel } from '../actor/actor-follow.js'
import { ActorImageModel } from '../actor/actor-image.js' import { ActorImageModel } from '../actor/actor-image.js'
import { ActorModel } from '../actor/actor.js' import { ActorModel } from '../actor/actor.js'
import { OAuthTokenModel } from '../oauth/oauth-token.js' import { OAuthTokenModel } from '../oauth/oauth-token.js'
import { getAdminUsersSort, throwIfNotValid } from '../shared/index.js' import { getAdminUsersSort, SequelizeModel, throwIfNotValid } from '../shared/index.js'
import { VideoChannelModel } from '../video/video-channel.js' import { VideoChannelModel } from '../video/video-channel.js'
import { VideoImportModel } from '../video/video-import.js' import { VideoImportModel } from '../video/video-import.js'
import { VideoLiveModel } from '../video/video-live.js' import { VideoLiveModel } from '../video/video-live.js'
@ -278,7 +275,7 @@ enum ScopeNames {
} }
] ]
}) })
export class UserModel extends Model<Partial<AttributesOnly<UserModel>>> { export class UserModel extends SequelizeModel<UserModel> {
@AllowNull(true) @AllowNull(true)
@Is('UserPassword', value => throwIfNotValid(value, isUserPasswordValid, 'user password', true)) @Is('UserPassword', value => throwIfNotValid(value, isUserPasswordValid, 'user password', true))

View File

@ -1,9 +1,9 @@
import { Op, Transaction } from 'sequelize' import { Op, Transaction } from 'sequelize'
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript'
import { VideoPrivacy } from '@peertube/peertube-models' import { VideoPrivacy } from '@peertube/peertube-models'
import { MScheduleVideoUpdate, MScheduleVideoUpdateFormattable } from '@server/types/models/index.js' import { MScheduleVideoUpdate, MScheduleVideoUpdateFormattable } from '@server/types/models/index.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
import { SequelizeModel } from '../shared/index.js'
@Table({ @Table({
tableName: 'scheduleVideoUpdate', tableName: 'scheduleVideoUpdate',
@ -17,7 +17,7 @@ import { VideoModel } from './video.js'
} }
] ]
}) })
export class ScheduleVideoUpdateModel extends Model<Partial<AttributesOnly<ScheduleVideoUpdateModel>>> { export class ScheduleVideoUpdateModel extends SequelizeModel<ScheduleVideoUpdateModel> {
@AllowNull(false) @AllowNull(false)
@Default(null) @Default(null)

View File

@ -23,7 +23,7 @@ export interface ListVideoCommentsOptions {
isLocal?: boolean isLocal?: boolean
onLocalVideo?: boolean onLocalVideo?: boolean
onPublicVideo?: boolean onPublicVideo?: boolean
videoAccountOwnerId?: boolean videoAccountOwnerId?: number
search?: string search?: string
searchAccount?: string searchAccount?: string

View File

@ -1,14 +1,14 @@
import { remove } from 'fs-extra/esm' import { remove } from 'fs-extra/esm'
import { join } from 'path' import { join } from 'path'
import { AfterDestroy, AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AfterDestroy, AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript'
import { CONFIG } from '@server/initializers/config.js' import { CONFIG } from '@server/initializers/config.js'
import { MStoryboard, MStoryboardVideo, MVideo } from '@server/types/models/index.js' import { MStoryboard, MStoryboardVideo, MVideo } from '@server/types/models/index.js'
import { Storyboard } from '@peertube/peertube-models' import { Storyboard } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { logger } from '../../helpers/logger.js' import { logger } from '../../helpers/logger.js'
import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, WEBSERVER } from '../../initializers/constants.js' import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, WEBSERVER } from '../../initializers/constants.js'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
import { Transaction } from 'sequelize' import { Transaction } from 'sequelize'
import { SequelizeModel } from '../shared/index.js'
@Table({ @Table({
tableName: 'storyboard', tableName: 'storyboard',
@ -23,7 +23,7 @@ import { Transaction } from 'sequelize'
} }
] ]
}) })
export class StoryboardModel extends Model<Partial<AttributesOnly<StoryboardModel>>> { export class StoryboardModel extends SequelizeModel<StoryboardModel> {
@AllowNull(false) @AllowNull(false)
@Column @Column

View File

@ -1,10 +1,9 @@
import { col, fn, QueryTypes, Transaction } from 'sequelize' import { col, fn, QueryTypes, Transaction } from 'sequelize'
import { AllowNull, BelongsToMany, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsToMany, Column, CreatedAt, Is, Table, UpdatedAt } from 'sequelize-typescript'
import { VideoPrivacy, VideoState } from '@peertube/peertube-models' import { VideoPrivacy, VideoState } from '@peertube/peertube-models'
import { MTag } from '@server/types/models/index.js' import { MTag } from '@server/types/models/index.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { isVideoTagValid } from '../../helpers/custom-validators/videos.js' import { isVideoTagValid } from '../../helpers/custom-validators/videos.js'
import { throwIfNotValid } from '../shared/index.js' import { SequelizeModel, throwIfNotValid } from '../shared/index.js'
import { VideoTagModel } from './video-tag.js' import { VideoTagModel } from './video-tag.js'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
@ -22,7 +21,7 @@ import { VideoModel } from './video.js'
} }
] ]
}) })
export class TagModel extends Model<Partial<AttributesOnly<TagModel>>> { export class TagModel extends SequelizeModel<TagModel> {
@AllowNull(false) @AllowNull(false)
@Is('VideoTag', value => throwIfNotValid(value, isVideoTagValid, 'tag')) @Is('VideoTag', value => throwIfNotValid(value, isVideoTagValid, 'tag'))

View File

@ -1,5 +1,4 @@
import { ActivityIconObject, ThumbnailType, type ThumbnailType_Type } from '@peertube/peertube-models' import { ActivityIconObject, ThumbnailType, type ThumbnailType_Type } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { afterCommitIfTransaction } from '@server/helpers/database-utils.js' import { afterCommitIfTransaction } from '@server/helpers/database-utils.js'
import { MThumbnail, MThumbnailVideo, MVideo, MVideoPlaylist } from '@server/types/models/index.js' import { MThumbnail, MThumbnailVideo, MVideo, MVideoPlaylist } from '@server/types/models/index.js'
import { remove } from 'fs-extra/esm' import { remove } from 'fs-extra/esm'
@ -14,9 +13,7 @@ import {
CreatedAt, CreatedAt,
DataType, DataType,
Default, Default,
ForeignKey, ForeignKey, Table,
Model,
Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { logger } from '../../helpers/logger.js' import { logger } from '../../helpers/logger.js'
@ -24,6 +21,7 @@ import { CONFIG } from '../../initializers/config.js'
import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, WEBSERVER } from '../../initializers/constants.js' import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, WEBSERVER } from '../../initializers/constants.js'
import { VideoPlaylistModel } from './video-playlist.js' import { VideoPlaylistModel } from './video-playlist.js'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
import { SequelizeModel } from '../shared/sequelize-type.js'
@Table({ @Table({
tableName: 'thumbnail', tableName: 'thumbnail',
@ -41,7 +39,7 @@ import { VideoModel } from './video.js'
} }
] ]
}) })
export class ThumbnailModel extends Model<Partial<AttributesOnly<ThumbnailModel>>> { export class ThumbnailModel extends SequelizeModel<ThumbnailModel> {
@AllowNull(false) @AllowNull(false)
@Column @Column

View File

@ -1,11 +1,10 @@
import { VideoBlacklist, type VideoBlacklistType_Type } from '@peertube/peertube-models' import { VideoBlacklist, type VideoBlacklistType_Type } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { MVideoBlacklist, MVideoBlacklistFormattable } from '@server/types/models/index.js' import { MVideoBlacklist, MVideoBlacklistFormattable } from '@server/types/models/index.js'
import { FindOptions } from 'sequelize' import { FindOptions } from 'sequelize'
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Table, UpdatedAt } from 'sequelize-typescript'
import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist.js' import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist.js'
import { CONSTRAINTS_FIELDS } from '../../initializers/constants.js' import { CONSTRAINTS_FIELDS } from '../../initializers/constants.js'
import { getBlacklistSort, searchAttribute, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, getBlacklistSort, searchAttribute, throwIfNotValid } from '../shared/index.js'
import { ThumbnailModel } from './thumbnail.js' import { ThumbnailModel } from './thumbnail.js'
import { SummaryOptions, VideoChannelModel, ScopeNames as VideoChannelScopeNames } from './video-channel.js' import { SummaryOptions, VideoChannelModel, ScopeNames as VideoChannelScopeNames } from './video-channel.js'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
@ -19,7 +18,7 @@ import { VideoModel } from './video.js'
} }
] ]
}) })
export class VideoBlacklistModel extends Model<Partial<AttributesOnly<VideoBlacklistModel>>> { export class VideoBlacklistModel extends SequelizeModel<VideoBlacklistModel> {
@AllowNull(true) @AllowNull(true)
@Is('VideoBlacklistReason', value => throwIfNotValid(value, isVideoBlacklistReasonValid, 'reason', true)) @Is('VideoBlacklistReason', value => throwIfNotValid(value, isVideoBlacklistReasonValid, 'reason', true))

View File

@ -9,9 +9,7 @@ import {
CreatedAt, CreatedAt,
DataType, DataType,
ForeignKey, ForeignKey,
Is, Is, Scopes,
Model,
Scopes,
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
@ -24,12 +22,11 @@ import {
MVideoCaptionVideo MVideoCaptionVideo
} from '@server/types/models/index.js' } from '@server/types/models/index.js'
import { buildUUID } from '@peertube/peertube-node-utils' import { buildUUID } from '@peertube/peertube-node-utils'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions.js' import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions.js'
import { logger } from '../../helpers/logger.js' import { logger } from '../../helpers/logger.js'
import { CONFIG } from '../../initializers/config.js' import { CONFIG } from '../../initializers/config.js'
import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, VIDEO_LANGUAGES, WEBSERVER } from '../../initializers/constants.js' import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, VIDEO_LANGUAGES, WEBSERVER } from '../../initializers/constants.js'
import { buildWhereIdOrUUID, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, buildWhereIdOrUUID, throwIfNotValid } from '../shared/index.js'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
export enum ScopeNames { export enum ScopeNames {
@ -64,7 +61,7 @@ export enum ScopeNames {
} }
] ]
}) })
export class VideoCaptionModel extends Model<Partial<AttributesOnly<VideoCaptionModel>>> { export class VideoCaptionModel extends SequelizeModel<VideoCaptionModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -1,9 +1,8 @@
import { VideoChangeOwnership, type VideoChangeOwnershipStatusType } from '@peertube/peertube-models' import { VideoChangeOwnership, type VideoChangeOwnershipStatusType } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { MVideoChangeOwnershipFormattable, MVideoChangeOwnershipFull } from '@server/types/models/video/video-change-ownership.js' import { MVideoChangeOwnershipFormattable, MVideoChangeOwnershipFull } from '@server/types/models/video/video-change-ownership.js'
import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
import { AccountModel } from '../account/account.js' import { AccountModel } from '../account/account.js'
import { getSort } from '../shared/index.js' import { SequelizeModel, getSort } from '../shared/index.js'
import { VideoModel, ScopeNames as VideoScopeNames } from './video.js' import { VideoModel, ScopeNames as VideoScopeNames } from './video.js'
enum ScopeNames { enum ScopeNames {
@ -54,7 +53,7 @@ enum ScopeNames {
] ]
} }
})) }))
export class VideoChangeOwnershipModel extends Model<Partial<AttributesOnly<VideoChangeOwnershipModel>>> { export class VideoChangeOwnershipModel extends SequelizeModel<VideoChangeOwnershipModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -1,5 +1,4 @@
import { VideoChannelSync, VideoChannelSyncState, type VideoChannelSyncStateType } from '@peertube/peertube-models' import { VideoChannelSync, VideoChannelSyncState, type VideoChannelSyncStateType } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc.js' import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc.js'
import { isVideoChannelSyncStateValid } from '@server/helpers/custom-validators/video-channel-syncs.js' import { isVideoChannelSyncStateValid } from '@server/helpers/custom-validators/video-channel-syncs.js'
import { CONSTRAINTS_FIELDS, VIDEO_CHANNEL_SYNC_STATE } from '@server/initializers/constants.js' import { CONSTRAINTS_FIELDS, VIDEO_CHANNEL_SYNC_STATE } from '@server/initializers/constants.js'
@ -14,13 +13,11 @@ import {
Default, Default,
DefaultScope, DefaultScope,
ForeignKey, ForeignKey,
Is, Is, Table,
Model,
Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { AccountModel } from '../account/account.js' import { AccountModel } from '../account/account.js'
import { getChannelSyncSort, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, getChannelSyncSort, throwIfNotValid } from '../shared/index.js'
import { UserModel } from '../user/user.js' import { UserModel } from '../user/user.js'
import { VideoChannelModel } from './video-channel.js' import { VideoChannelModel } from './video-channel.js'
@ -40,7 +37,7 @@ import { VideoChannelModel } from './video-channel.js'
} }
] ]
}) })
export class VideoChannelSyncModel extends Model<Partial<AttributesOnly<VideoChannelSyncModel>>> { export class VideoChannelSyncModel extends SequelizeModel<VideoChannelSyncModel> {
@AllowNull(false) @AllowNull(false)
@Default(null) @Default(null)

View File

@ -1,6 +1,5 @@
import { forceNumber, pick } from '@peertube/peertube-core-utils' import { forceNumber, pick } from '@peertube/peertube-core-utils'
import { ActivityPubActor, VideoChannel, VideoChannelSummary } from '@peertube/peertube-models' import { ActivityPubActor, VideoChannel, VideoChannelSummary } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { CONFIG } from '@server/initializers/config.js' import { CONFIG } from '@server/initializers/config.js'
import { InternalEventEmitter } from '@server/lib/internal-event-emitter.js' import { InternalEventEmitter } from '@server/lib/internal-event-emitter.js'
import { MAccountHost } from '@server/types/models/index.js' import { MAccountHost } from '@server/types/models/index.js'
@ -19,9 +18,7 @@ import {
DefaultScope, DefaultScope,
ForeignKey, ForeignKey,
HasMany, HasMany,
Is, Is, Scopes,
Model,
Scopes,
Sequelize, Sequelize,
Table, Table,
UpdatedAt UpdatedAt
@ -47,6 +44,7 @@ import { ActorImageModel } from '../actor/actor-image.js'
import { ActorModel, unusedActorAttributesForAPI } from '../actor/actor.js' import { ActorModel, unusedActorAttributesForAPI } from '../actor/actor.js'
import { ServerModel } from '../server/server.js' import { ServerModel } from '../server/server.js'
import { import {
SequelizeModel,
buildServerIdsFollowedBy, buildServerIdsFollowedBy,
buildTrigramSearchIndex, buildTrigramSearchIndex,
createSimilarityAttribute, createSimilarityAttribute,
@ -352,7 +350,7 @@ export type SummaryOptions = {
} }
] ]
}) })
export class VideoChannelModel extends Model<Partial<AttributesOnly<VideoChannelModel>>> { export class VideoChannelModel extends SequelizeModel<VideoChannelModel> {
@AllowNull(false) @AllowNull(false)
@Is('VideoChannelName', value => throwIfNotValid(value, isVideoChannelDisplayNameValid, 'name')) @Is('VideoChannelName', value => throwIfNotValid(value, isVideoChannelDisplayNameValid, 'name'))

View File

@ -1,10 +1,10 @@
import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript'
import { MVideo, MVideoChapter } from '@server/types/models/index.js' import { MVideo, MVideoChapter } from '@server/types/models/index.js'
import { VideoChapter, VideoChapterObject } from '@peertube/peertube-models' import { VideoChapter, VideoChapterObject } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
import { Transaction } from 'sequelize' import { Transaction } from 'sequelize'
import { getSort } from '../shared/sort.js' import { getSort } from '../shared/sort.js'
import { SequelizeModel } from '../shared/sequelize-type.js'
@Table({ @Table({
tableName: 'videoChapter', tableName: 'videoChapter',
@ -15,7 +15,7 @@ import { getSort } from '../shared/sort.js'
} }
] ]
}) })
export class VideoChapterModel extends Model<Partial<AttributesOnly<VideoChapterModel>>> { export class VideoChapterModel extends SequelizeModel<VideoChapterModel> {
@AllowNull(false) @AllowNull(false)
@Column @Column

View File

@ -1,4 +1,4 @@
import { FindOptions, Op, Order, QueryTypes, Sequelize, Transaction } from 'sequelize' import { Op, Order, QueryTypes, Sequelize, Transaction } from 'sequelize'
import { import {
AllowNull, AllowNull,
BelongsTo, BelongsTo,
@ -7,9 +7,7 @@ import {
DataType, DataType,
ForeignKey, ForeignKey,
HasMany, HasMany,
Is, Is, Scopes,
Model,
Scopes,
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
@ -18,7 +16,6 @@ import { ActivityTagObject, ActivityTombstoneObject, VideoComment, VideoCommentA
import { extractMentions } from '@server/helpers/mentions.js' import { extractMentions } from '@server/helpers/mentions.js'
import { getServerActor } from '@server/models/application/application.js' import { getServerActor } from '@server/models/application/application.js'
import { MAccount, MAccountId, MUserAccountId } from '@server/types/models/index.js' import { MAccount, MAccountId, MUserAccountId } from '@server/types/models/index.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc.js' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc.js'
import { CONSTRAINTS_FIELDS } from '../../initializers/constants.js' import { CONSTRAINTS_FIELDS } from '../../initializers/constants.js'
import { import {
@ -38,7 +35,7 @@ import {
import { VideoCommentAbuseModel } from '../abuse/video-comment-abuse.js' import { VideoCommentAbuseModel } from '../abuse/video-comment-abuse.js'
import { AccountModel } from '../account/account.js' import { AccountModel } from '../account/account.js'
import { ActorModel } from '../actor/actor.js' import { ActorModel } from '../actor/actor.js'
import { buildLocalAccountIdsIn, buildSQLAttributes, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, buildLocalAccountIdsIn, buildSQLAttributes, throwIfNotValid } from '../shared/index.js'
import { ListVideoCommentsOptions, VideoCommentListQueryBuilder } from './sql/comment/video-comment-list-query-builder.js' import { ListVideoCommentsOptions, VideoCommentListQueryBuilder } from './sql/comment/video-comment-list-query-builder.js'
import { VideoChannelModel } from './video-channel.js' import { VideoChannelModel } from './video-channel.js'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
@ -123,7 +120,7 @@ export enum ScopeNames {
} }
] ]
}) })
export class VideoCommentModel extends Model<Partial<AttributesOnly<VideoCommentModel>>> { export class VideoCommentModel extends SequelizeModel<VideoCommentModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date
@ -216,46 +213,43 @@ export class VideoCommentModel extends Model<Partial<AttributesOnly<VideoComment
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
static loadById (id: number, t?: Transaction): Promise<MComment> { static loadById (id: number, transaction?: Transaction): Promise<MComment> {
const query: FindOptions = { const query = {
where: { where: {
id id
} },
transaction
} }
if (t !== undefined) query.transaction = t
return VideoCommentModel.findOne(query) return VideoCommentModel.findOne(query)
} }
static loadByIdAndPopulateVideoAndAccountAndReply (id: number, t?: Transaction): Promise<MCommentOwnerVideoReply> { static loadByIdAndPopulateVideoAndAccountAndReply (id: number, transaction?: Transaction): Promise<MCommentOwnerVideoReply> {
const query: FindOptions = { const query = {
where: { where: {
id id
} },
transaction
} }
if (t !== undefined) query.transaction = t
return VideoCommentModel return VideoCommentModel
.scope([ ScopeNames.WITH_VIDEO, ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_IN_REPLY_TO ]) .scope([ ScopeNames.WITH_VIDEO, ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_IN_REPLY_TO ])
.findOne(query) .findOne(query)
} }
static loadByUrlAndPopulateAccountAndVideo (url: string, t?: Transaction): Promise<MCommentOwnerVideo> { static loadByUrlAndPopulateAccountAndVideo (url: string, transaction?: Transaction): Promise<MCommentOwnerVideo> {
const query: FindOptions = { const query = {
where: { where: {
url url
} },
transaction
} }
if (t !== undefined) query.transaction = t
return VideoCommentModel.scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEO ]).findOne(query) return VideoCommentModel.scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEO ]).findOne(query)
} }
static loadByUrlAndPopulateReplyAndVideoUrlAndAccount (url: string, t?: Transaction): Promise<MCommentOwnerReplyVideoLight> { static loadByUrlAndPopulateReplyAndVideoUrlAndAccount (url: string, transaction?: Transaction): Promise<MCommentOwnerReplyVideoLight> {
const query: FindOptions = { const query = {
where: { where: {
url url
}, },
@ -264,11 +258,10 @@ export class VideoCommentModel extends Model<Partial<AttributesOnly<VideoComment
attributes: [ 'id', 'url' ], attributes: [ 'id', 'url' ],
model: VideoModel.unscoped() model: VideoModel.unscoped()
} }
] ],
transaction
} }
if (t !== undefined) query.transaction = t
return VideoCommentModel.scope([ ScopeNames.WITH_IN_REPLY_TO, ScopeNames.WITH_ACCOUNT ]).findOne(query) return VideoCommentModel.scope([ ScopeNames.WITH_IN_REPLY_TO, ScopeNames.WITH_ACCOUNT ]).findOne(query)
} }

View File

@ -1,5 +1,4 @@
import { ActivityVideoUrlObject, VideoResolution, FileStorage, type FileStorageType } from '@peertube/peertube-models' import { ActivityVideoUrlObject, VideoResolution, FileStorage, type FileStorageType } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { logger } from '@server/helpers/logger.js' import { logger } from '@server/helpers/logger.js'
import { extractVideo } from '@server/helpers/video.js' import { extractVideo } from '@server/helpers/video.js'
import { CONFIG } from '@server/initializers/config.js' import { CONFIG } from '@server/initializers/config.js'
@ -27,9 +26,7 @@ import {
DefaultScope, DefaultScope,
ForeignKey, ForeignKey,
HasMany, HasMany,
Is, Is, Scopes,
Model,
Scopes,
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
@ -51,7 +48,7 @@ import {
} from '../../initializers/constants.js' } from '../../initializers/constants.js'
import { MVideoFile, MVideoFileStreamingPlaylistVideo, MVideoFileVideo } from '../../types/models/video/video-file.js' import { MVideoFile, MVideoFileStreamingPlaylistVideo, MVideoFileVideo } from '../../types/models/video/video-file.js'
import { VideoRedundancyModel } from '../redundancy/video-redundancy.js' import { VideoRedundancyModel } from '../redundancy/video-redundancy.js'
import { doesExist, parseAggregateResult, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, doesExist, parseAggregateResult, throwIfNotValid } from '../shared/index.js'
import { VideoStreamingPlaylistModel } from './video-streaming-playlist.js' import { VideoStreamingPlaylistModel } from './video-streaming-playlist.js'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
import { getVideoFileMimeType } from '@server/lib/video-file.js' import { getVideoFileMimeType } from '@server/lib/video-file.js'
@ -158,7 +155,7 @@ export enum ScopeNames {
} }
] ]
}) })
export class VideoFileModel extends Model<Partial<AttributesOnly<VideoFileModel>>> { export class VideoFileModel extends SequelizeModel<VideoFileModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date
@ -257,7 +254,7 @@ export class VideoFileModel extends Model<Partial<AttributesOnly<VideoFileModel>
}) })
RedundancyVideos: Awaited<VideoRedundancyModel>[] RedundancyVideos: Awaited<VideoRedundancyModel>[]
static doesInfohashExistCached = memoizee(VideoFileModel.doesInfohashExist, { static doesInfohashExistCached = memoizee(VideoFileModel.doesInfohashExist.bind(VideoFileModel), {
promise: true, promise: true,
max: MEMOIZE_LENGTH.INFO_HASH_EXISTS, max: MEMOIZE_LENGTH.INFO_HASH_EXISTS,
maxAge: MEMOIZE_TTL.INFO_HASH_EXISTS maxAge: MEMOIZE_TTL.INFO_HASH_EXISTS

View File

@ -1,5 +1,4 @@
import { VideoImport, VideoImportState, type VideoImportStateType } from '@peertube/peertube-models' import { VideoImport, VideoImportState, type VideoImportStateType } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { afterCommitIfTransaction } from '@server/helpers/database-utils.js' import { afterCommitIfTransaction } from '@server/helpers/database-utils.js'
import { MVideoImportDefault, MVideoImportFormattable } from '@server/types/models/video/video-import.js' import { MVideoImportDefault, MVideoImportFormattable } from '@server/types/models/video/video-import.js'
import { IncludeOptions, Op, WhereOptions } from 'sequelize' import { IncludeOptions, Op, WhereOptions } from 'sequelize'
@ -13,15 +12,13 @@ import {
Default, Default,
DefaultScope, DefaultScope,
ForeignKey, ForeignKey,
Is, Is, Table,
Model,
Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { isVideoImportStateValid, isVideoImportTargetUrlValid } from '../../helpers/custom-validators/video-imports.js' import { isVideoImportStateValid, isVideoImportTargetUrlValid } from '../../helpers/custom-validators/video-imports.js'
import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos.js' import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos.js'
import { CONSTRAINTS_FIELDS, VIDEO_IMPORT_STATES } from '../../initializers/constants.js' import { CONSTRAINTS_FIELDS, VIDEO_IMPORT_STATES } from '../../initializers/constants.js'
import { getSort, searchAttribute, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, getSort, searchAttribute, throwIfNotValid } from '../shared/index.js'
import { UserModel } from '../user/user.js' import { UserModel } from '../user/user.js'
import { VideoChannelSyncModel } from './video-channel-sync.js' import { VideoChannelSyncModel } from './video-channel-sync.js'
import { VideoModel, ScopeNames as VideoModelScopeNames } from './video.js' import { VideoModel, ScopeNames as VideoModelScopeNames } from './video.js'
@ -63,7 +60,7 @@ const defaultVideoScope = () => {
} }
] ]
}) })
export class VideoImportModel extends Model<Partial<AttributesOnly<VideoImportModel>>> { export class VideoImportModel extends SequelizeModel<VideoImportModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -1,8 +1,8 @@
import { Op, QueryTypes, Transaction } from 'sequelize' import { Op, QueryTypes, Transaction } from 'sequelize'
import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, IsInt, Model, Table, Unique, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, IsInt, Table, Unique, UpdatedAt } from 'sequelize-typescript'
import { forceNumber } from '@peertube/peertube-core-utils' import { forceNumber } from '@peertube/peertube-core-utils'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
import { SequelizeModel } from '../shared/sequelize-type.js'
export type VideoJobInfoColumnType = 'pendingMove' | 'pendingTranscode' export type VideoJobInfoColumnType = 'pendingMove' | 'pendingTranscode'
@ -20,7 +20,7 @@ export type VideoJobInfoColumnType = 'pendingMove' | 'pendingTranscode'
] ]
}) })
export class VideoJobInfoModel extends Model<Partial<AttributesOnly<VideoJobInfoModel>>> { export class VideoJobInfoModel extends SequelizeModel<VideoJobInfoModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -2,13 +2,14 @@ import { type VideoPrivacyType } from '@peertube/peertube-models'
import { isVideoPrivacyValid } from '@server/helpers/custom-validators/videos.js' import { isVideoPrivacyValid } from '@server/helpers/custom-validators/videos.js'
import { MLiveReplaySetting } from '@server/types/models/video/video-live-replay-setting.js' import { MLiveReplaySetting } from '@server/types/models/video/video-live-replay-setting.js'
import { Transaction } from 'sequelize' import { Transaction } from 'sequelize'
import { AllowNull, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, Column, CreatedAt, Is, Table, UpdatedAt } from 'sequelize-typescript'
import { throwIfNotValid } from '../shared/sequelize-helpers.js' import { throwIfNotValid } from '../shared/sequelize-helpers.js'
import { SequelizeModel } from '../shared/index.js'
@Table({ @Table({
tableName: 'videoLiveReplaySetting' tableName: 'videoLiveReplaySetting'
}) })
export class VideoLiveReplaySettingModel extends Model<VideoLiveReplaySettingModel> { export class VideoLiveReplaySettingModel extends SequelizeModel<VideoLiveReplaySettingModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -10,14 +10,13 @@ import {
Column, Column,
CreatedAt, CreatedAt,
DataType, DataType,
ForeignKey, ForeignKey, Scopes,
Model,
Scopes,
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { VideoLiveReplaySettingModel } from './video-live-replay-setting.js' import { VideoLiveReplaySettingModel } from './video-live-replay-setting.js'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
import { SequelizeModel } from '../shared/index.js'
export enum ScopeNames { export enum ScopeNames {
WITH_REPLAY = 'WITH_REPLAY' WITH_REPLAY = 'WITH_REPLAY'
@ -54,7 +53,7 @@ export enum ScopeNames {
} }
] ]
}) })
export class VideoLiveSessionModel extends Model<Partial<AttributesOnly<VideoLiveSessionModel>>> { export class VideoLiveSessionModel extends SequelizeModel<VideoLiveSessionModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -1,5 +1,4 @@
import { LiveVideo, VideoState, type LiveVideoLatencyModeType } from '@peertube/peertube-models' import { LiveVideo, VideoState, type LiveVideoLatencyModeType } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { CONFIG } from '@server/initializers/config.js' import { CONFIG } from '@server/initializers/config.js'
import { WEBSERVER } from '@server/initializers/constants.js' import { WEBSERVER } from '@server/initializers/constants.js'
import { MVideoLive, MVideoLiveVideoWithSetting, MVideoLiveWithSetting } from '@server/types/models/index.js' import { MVideoLive, MVideoLiveVideoWithSetting, MVideoLiveWithSetting } from '@server/types/models/index.js'
@ -12,14 +11,13 @@ import {
CreatedAt, CreatedAt,
DataType, DataType,
DefaultScope, DefaultScope,
ForeignKey, ForeignKey, Table,
Model,
Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import { VideoBlacklistModel } from './video-blacklist.js' import { VideoBlacklistModel } from './video-blacklist.js'
import { VideoLiveReplaySettingModel } from './video-live-replay-setting.js' import { VideoLiveReplaySettingModel } from './video-live-replay-setting.js'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
import { SequelizeModel } from '../shared/index.js'
@DefaultScope(() => ({ @DefaultScope(() => ({
include: [ include: [
@ -52,7 +50,7 @@ import { VideoModel } from './video.js'
} }
] ]
}) })
export class VideoLiveModel extends Model<Partial<AttributesOnly<VideoLiveModel>>> { export class VideoLiveModel extends SequelizeModel<VideoLiveModel> {
@AllowNull(true) @AllowNull(true)
@Column(DataType.STRING) @Column(DataType.STRING)

View File

@ -1,9 +1,8 @@
import { AllowNull, BelongsTo, Column, CreatedAt, DefaultScope, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, DefaultScope, ForeignKey, Is, Table, UpdatedAt } from 'sequelize-typescript'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { ResultList, VideoPassword } from '@peertube/peertube-models' import { ResultList, VideoPassword } from '@peertube/peertube-models'
import { getSort, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, getSort, throwIfNotValid } from '../shared/index.js'
import { FindOptions, Transaction } from 'sequelize' import { Transaction } from 'sequelize'
import { MVideoPassword } from '@server/types/models/index.js' import { MVideoPassword } from '@server/types/models/index.js'
import { isPasswordValid } from '@server/helpers/custom-validators/videos.js' import { isPasswordValid } from '@server/helpers/custom-validators/videos.js'
import { pick } from '@peertube/peertube-core-utils' import { pick } from '@peertube/peertube-core-utils'
@ -25,7 +24,7 @@ import { pick } from '@peertube/peertube-core-utils'
} }
] ]
}) })
export class VideoPasswordModel extends Model<Partial<AttributesOnly<VideoPasswordModel>>> { export class VideoPasswordModel extends SequelizeModel<VideoPasswordModel> {
@AllowNull(false) @AllowNull(false)
@Is('VideoPassword', value => throwIfNotValid(value, isPasswordValid, 'videoPassword')) @Is('VideoPassword', value => throwIfNotValid(value, isPasswordValid, 'videoPassword'))
@ -51,7 +50,7 @@ export class VideoPasswordModel extends Model<Partial<AttributesOnly<VideoPasswo
Video: Awaited<VideoModel> Video: Awaited<VideoModel>
static async countByVideoId (videoId: number, t?: Transaction) { static async countByVideoId (videoId: number, t?: Transaction) {
const query: FindOptions = { const query = {
where: { where: {
videoId videoId
}, },
@ -63,7 +62,7 @@ export class VideoPasswordModel extends Model<Partial<AttributesOnly<VideoPasswo
static async loadByIdAndVideo (options: { id: number, videoId: number, t?: Transaction }): Promise<MVideoPassword> { static async loadByIdAndVideo (options: { id: number, videoId: number, t?: Transaction }): Promise<MVideoPassword> {
const { id, videoId, t } = options const { id, videoId, t } = options
const query: FindOptions = { const query = {
where: { where: {
id, id,
videoId videoId

View File

@ -9,9 +9,7 @@ import {
ForeignKey, ForeignKey,
Is, Is,
IsInt, IsInt,
Min, Min, Table,
Model,
Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
import validator from 'validator' import validator from 'validator'
@ -32,11 +30,10 @@ import {
MVideoPlaylistElementVideoThumbnail, MVideoPlaylistElementVideoThumbnail,
MVideoPlaylistElementVideoUrl MVideoPlaylistElementVideoUrl
} from '@server/types/models/video/video-playlist-element.js' } from '@server/types/models/video/video-playlist-element.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc.js' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc.js'
import { CONSTRAINTS_FIELDS } from '../../initializers/constants.js' import { CONSTRAINTS_FIELDS } from '../../initializers/constants.js'
import { AccountModel } from '../account/account.js' import { AccountModel } from '../account/account.js'
import { getSort, throwIfNotValid } from '../shared/index.js' import { SequelizeModel, getSort, throwIfNotValid } from '../shared/index.js'
import { VideoPlaylistModel } from './video-playlist.js' import { VideoPlaylistModel } from './video-playlist.js'
import { ForAPIOptions, ScopeNames as VideoScopeNames, VideoModel } from './video.js' import { ForAPIOptions, ScopeNames as VideoScopeNames, VideoModel } from './video.js'
@ -55,7 +52,7 @@ import { ForAPIOptions, ScopeNames as VideoScopeNames, VideoModel } from './vide
} }
] ]
}) })
export class VideoPlaylistElementModel extends Model<Partial<AttributesOnly<VideoPlaylistElementModel>>> { export class VideoPlaylistElementModel extends SequelizeModel<VideoPlaylistElementModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -9,7 +9,6 @@ import {
type VideoPlaylistType_Type type VideoPlaylistType_Type
} from '@peertube/peertube-models' } from '@peertube/peertube-models'
import { buildUUID, uuidToShort } from '@peertube/peertube-node-utils' import { buildUUID, uuidToShort } from '@peertube/peertube-node-utils'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { activityPubCollectionPagination } from '@server/lib/activitypub/collection.js' import { activityPubCollectionPagination } from '@server/lib/activitypub/collection.js'
import { MAccountId, MChannelId } from '@server/types/models/index.js' import { MAccountId, MChannelId } from '@server/types/models/index.js'
import { join } from 'path' import { join } from 'path'
@ -25,9 +24,7 @@ import {
HasMany, HasMany,
HasOne, HasOne,
Is, Is,
IsUUID, IsUUID, Scopes,
Model,
Scopes,
Table, Table,
UpdatedAt UpdatedAt
} from 'sequelize-typescript' } from 'sequelize-typescript'
@ -58,6 +55,7 @@ import {
import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions } from '../account/account.js' import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions } from '../account/account.js'
import { ActorModel } from '../actor/actor.js' import { ActorModel } from '../actor/actor.js'
import { import {
SequelizeModel,
buildServerIdsFollowedBy, buildServerIdsFollowedBy,
buildTrigramSearchIndex, buildTrigramSearchIndex,
buildWhereIdOrUUID, buildWhereIdOrUUID,
@ -287,7 +285,7 @@ function getVideoLengthSelect () {
} }
] ]
}) })
export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlaylistModel>>> { export class VideoPlaylistModel extends SequelizeModel<VideoPlaylistModel> {
@CreatedAt @CreatedAt
createdAt: Date createdAt: Date

View File

@ -1,13 +1,12 @@
import { literal, Op, QueryTypes, Transaction } from 'sequelize' import { literal, Op, QueryTypes, Transaction } from 'sequelize'
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
import { forceNumber } from '@peertube/peertube-core-utils' import { forceNumber } from '@peertube/peertube-core-utils'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc.js' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc.js'
import { CONSTRAINTS_FIELDS } from '../../initializers/constants.js' import { CONSTRAINTS_FIELDS } from '../../initializers/constants.js'
import { MActorDefault, MActorFollowersUrl, MActorId } from '../../types/models/index.js' import { MActorDefault, MActorFollowersUrl, MActorId } from '../../types/models/index.js'
import { MVideoShareActor, MVideoShareFull } from '../../types/models/video/index.js' import { MVideoShareActor, MVideoShareFull } from '../../types/models/video/index.js'
import { ActorModel } from '../actor/actor.js' import { ActorModel } from '../actor/actor.js'
import { buildLocalActorIdsIn, throwIfNotValid } from '../shared/index.js' import { buildLocalActorIdsIn, SequelizeModel, throwIfNotValid } from '../shared/index.js'
import { VideoModel } from './video.js' import { VideoModel } from './video.js'
enum ScopeNames { enum ScopeNames {
@ -52,7 +51,7 @@ enum ScopeNames {
} }
] ]
}) })
export class VideoShareModel extends Model<Partial<AttributesOnly<VideoShareModel>>> { export class VideoShareModel extends SequelizeModel<VideoShareModel> {
@AllowNull(false) @AllowNull(false)
@Is('VideoShareUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url')) @Is('VideoShareUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))

Some files were not shown because too many files have changed in this diff Show More