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/key-spacing": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/ban-types": [
"error",
{

View File

@ -61,7 +61,7 @@ export function downloadFile (options: {
// ---------------------------------------------------------------------------
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",
"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",
"rules": {
"scss/at-import-no-partial-leading-underscore": null,
"color-hex-case": null,
"color-hex-length": null,
"selector-pseudo-element-no-unknown": [
true,
@ -19,10 +18,10 @@
"selector-max-compound-selectors": 9,
"selector-no-qualifying-type": null,
"scss/at-extend-no-missing-placeholder": null,
"number-leading-zero": null,
"rule-empty-line-before": null,
"selector-max-id": null,
"scss/at-function-pattern": null,
"scss/load-no-partial-leading-underscore": null,
"property-no-vendor-prefix": [
true,
{

View File

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

View File

@ -109,6 +109,7 @@
"linkifyjs": "^4.0.2",
"lodash-es": "^4.17.4",
"markdown-it": "14.0.0",
"markdown-it-emoji": "^3.0.0",
"mini-css-extract-plugin": "^2.2.0",
"ngx-uploadx": "^6.1.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 })
.pipe(
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.buildUniqId)),
map(res => this.restExtractor.applyToResultListData(res, this.prettyPrintData.bind(this))),
map(res => this.restExtractor.applyToResultListData(res, this.buildUniqId.bind(this))),
catchError(err => this.restExtractor.handleError(err))
)
}

View File

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

View File

@ -85,7 +85,7 @@ export class VideoCommentAddComponent extends FormReactive implements OnChanges,
getEmojiMarkupList () {
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 = []
for (const name of Object.keys(emojiMarkupObjectList)) {

View File

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

View File

@ -32,7 +32,7 @@ export class RestExtractor {
fieldsToConvert: string[] = [ 'createdAt' ],
format?: DateFormat
): 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) {

View File

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

View File

@ -244,8 +244,10 @@ export class MenuComponent implements OnInit, OnDestroy {
if (opened) {
window.addEventListener('scroll', onWindowScroll)
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)
} else {
// eslint-disable-next-line @typescript-eslint/unbound-method
document.querySelector('nav').removeEventListener('scroll', this.onMenuScrollEvent)
}
}

View File

@ -67,6 +67,7 @@ export class NotificationComponent implements OnInit, OnDestroy {
this.opened = true
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)
}
@ -74,6 +75,7 @@ export class NotificationComponent implements OnInit, OnDestroy {
this.loaded = false
this.opened = false
// eslint-disable-next-line @typescript-eslint/unbound-method
document.querySelector('nav').removeEventListener('scroll', this.onMenuScrollEvent)
}

View File

@ -41,12 +41,12 @@ export class VideoOwnershipService {
acceptOwnership (id: number, input: VideoChangeOwnershipAccept) {
const url = VideoOwnershipService.BASE_VIDEO_CHANGE_OWNERSHIP_URL + 'ownership/' + id + '/accept'
return this.authHttp.post(url, input)
.pipe(catchError(this.restExtractor.handleError))
.pipe(catchError(err => this.restExtractor.handleError(err)))
}
refuseOwnership (id: number) {
const url = VideoOwnershipService.BASE_VIDEO_CHANGE_OWNERSHIP_URL + 'ownership/' + id + '/refuse'
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
// or having multiple menus open
// eslint-disable-next-line @typescript-eslint/unbound-method
settingsMenuItem.on('click', videojs.bind(this, this.hideChildren))
// Whether to add or remove selected class on the settings sub menu element

View File

@ -6,4 +6,4 @@ interface NodeModule {
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"
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:
version "14.0.0"
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[]
if (Array.isArray(serversArg) === false) servers = [ serversArg as PeerTubeServer ]
else servers = serversArg as PeerTubeServer[]
if (Array.isArray(serversArg) === false) servers = [ serversArg ]
else servers = serversArg
const states: JobState[] = [ 'waiting', 'active' ]
if (!skipDelayed) states.push('delayed')

View File

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

View File

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

View File

@ -187,7 +187,7 @@ describe('Test users admin API validators', function () {
await makePostBodyRequest({
url: server.url,
path,
token: 'super token',
token: 'supertoken',
fields: baseCorrectParams,
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
})
@ -309,7 +309,7 @@ describe('Test users admin API validators', function () {
await makeGetRequest({
url: server.url,
path: path + userId,
token: 'super token',
token: 'supertoken',
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
})
})
@ -383,7 +383,7 @@ describe('Test users admin API validators', function () {
await makePutBodyRequest({
url: server.url,
path: path + userId,
token: 'super token',
token: 'supertoken',
fields,
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 () {
await command.remove({
token: 'fake token',
token: 'faketoken',
videoId: servers[0].store.videoCreated.uuid,
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
})
@ -258,7 +258,7 @@ describe('Test video blacklist API validators', function () {
const basePath = '/api/v1/videos/blacklist/'
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 () {

View File

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

View File

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

View File

@ -130,7 +130,7 @@ async function getVideos (
}, 'filter:api.overviews.videos.list.params')
const { data } = await Hooks.wrapPromiseFun(
VideoModel.listForApi,
VideoModel.listForApi.bind(VideoModel),
query,
'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')
const resultList = await Hooks.wrapPromiseFun(
VideoChannelModel.searchForApi,
VideoChannelModel.searchForApi.bind(VideoChannelModel),
apiOptions,
'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')
const resultList = await Hooks.wrapPromiseFun(
VideoPlaylistModel.searchForApi,
VideoPlaylistModel.searchForApi.bind(VideoPlaylistModel),
apiOptions,
'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')
const resultList = await Hooks.wrapPromiseFun(
VideoModel.searchAndPopulateAccountAndServer,
VideoModel.searchAndPopulateAccountAndServer.bind(VideoModel),
apiOptions,
'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')
const resultList = await Hooks.wrapPromiseFun(
VideoModel.listUserVideosForApi,
VideoModel.listUserVideosForApi.bind(VideoModel),
apiOptions,
'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')
const resultList = await Hooks.wrapPromiseFun(
VideoModel.listForApi,
VideoModel.listForApi.bind(VideoModel),
apiOptions,
'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')
const resultList = await Hooks.wrapPromiseFun(
VideoChannelModel.listForApi,
VideoChannelModel.listForApi.bind(VideoChannelModel),
apiOptions,
'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')
const resultList = await Hooks.wrapPromiseFun(
VideoModel.listForApi,
VideoModel.listForApi.bind(VideoModel),
apiOptions,
'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')
const resultList = await Hooks.wrapPromiseFun(
VideoPlaylistElementModel.listForApi,
VideoPlaylistElementModel.listForApi.bind(VideoPlaylistElementModel),
apiOptions,
'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')
resultList = await Hooks.wrapPromiseFun(
VideoCommentModel.listThreadsForApi,
VideoCommentModel.listThreadsForApi.bind(VideoCommentModel),
apiOptions,
'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')
resultList = await Hooks.wrapPromiseFun(
VideoCommentModel.listThreadCommentsForApi,
VideoCommentModel.listThreadCommentsForApi.bind(VideoCommentModel),
apiOptions,
'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')
const resultList = await Hooks.wrapPromiseFun(
VideoModel.listForApi,
VideoModel.listForApi.bind(VideoModel),
apiOptions,
'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) {
const video = res.locals.videoAll
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)
if (!videoFile) {

View File

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

View File

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

View File

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

View File

@ -95,7 +95,7 @@ type TaskProcessorOptions <T extends VideoStudioTaskPayload = VideoStudioTaskPay
outputPath: string
video: MVideo
task: T
lTags: { tags: string[] }
lTags: { tags: (string | number)[] }
}
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) }))
})
events.on('donePublish', sessionId => {
events.on('donePublish', (sessionId: string) => {
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)
@ -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
try {

View File

@ -11,7 +11,7 @@ import { getInternalUrl } from '../urls.js'
import { getClient } from './client.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 = {
BUCKET_NAME: string
@ -317,7 +317,7 @@ async function uploadToStorage (options: {
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
// For more information, see https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html
if (!response.Bucket) {

View File

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,10 @@
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 { MAbuseMessage, MAbuseMessageFormattable } from '@server/types/models/index.js'
import { AbuseMessage } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
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'
@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)
@Is('AbuseMessage', value => throwIfNotValid(value, isAbuseMessageValid, 'message'))

View File

@ -12,7 +12,6 @@ import {
UserVideoAbuse,
type AbuseStateType
} from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { isAbuseModerationCommentValid, isAbuseReasonValid, isAbuseStateValid } from '@server/helpers/custom-validators/abuses.js'
import invert from 'lodash-es/invert.js'
import { Op, QueryTypes, literal } from 'sequelize'
@ -25,9 +24,7 @@ import {
Default,
ForeignKey,
HasOne,
Is,
Model,
Scopes,
Is, Scopes,
Table,
UpdatedAt
} from 'sequelize-typescript'
@ -41,7 +38,7 @@ import {
MUserAccountId
} from '../../types/models/index.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 { VideoBlacklistModel } from '../video/video-blacklist.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)
@Default(null)

View File

@ -1,8 +1,8 @@
import { type VideoDetails } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
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 { VideoModel } from '../video/video.js'
import { AbuseModel } from './abuse.js'
import { SequelizeModel } from '../shared/index.js'
@Table({
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: Date

View File

@ -1,7 +1,7 @@
import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { BelongsTo, Column, CreatedAt, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript'
import { VideoCommentModel } from '../video/video-comment.js'
import { AbuseModel } from './abuse.js'
import { SequelizeModel } from '../shared/index.js'
@Table({
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: Date

View File

@ -1,12 +1,11 @@
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 { handlesToNameAndHost } from '@server/helpers/actors.js'
import { MAccountBlocklist, MAccountBlocklistFormattable } from '@server/types/models/index.js'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { ActorModel } from '../actor/actor.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 { 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: Date

View File

@ -1,5 +1,4 @@
import { AccountVideoRate, type VideoRateType } from '@peertube/peertube-models'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import {
MAccountVideoRate,
MAccountVideoRateAccountUrl,
@ -8,11 +7,11 @@ import {
MAccountVideoRateVideoUrl
} from '@server/types/models/index.js'
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 { CONSTRAINTS_FIELDS, VIDEO_RATE_TYPES } from '../../initializers/constants.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 { VideoModel } from '../video/video.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)
@Column(DataType.ENUM(...Object.values(VIDEO_RATE_TYPES)))

View File

@ -10,15 +10,12 @@ import {
DefaultScope,
ForeignKey,
HasMany,
Is,
Model,
Scopes,
Is, Scopes,
Table,
UpdatedAt
} from 'sequelize-typescript'
import { Account, AccountSummary } from '@peertube/peertube-models'
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 { CONSTRAINTS_FIELDS, SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants.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 { ServerBlocklistModel } from '../server/server-blocklist.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 { VideoChannelModel } from '../video/video-channel.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)
@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 { ActorModel } from '../actor/actor.js'
import { getServerActor } from '../application/application.js'
import { SequelizeModel } from '../shared/index.js'
@Table({
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)
@Column(DataType.TEXT)

View File

@ -1,5 +1,4 @@
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 { afterCommitIfTransaction } from '@server/helpers/database-utils.js'
import { getServerActor } from '@server/models/application/application.js'
@ -27,16 +26,14 @@ import {
ForeignKey,
Is,
IsInt,
Max,
Model,
Table,
Max, Table,
UpdatedAt
} from 'sequelize-typescript'
import { logger } from '../../helpers/logger.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 { 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 { VideoChannelModel } from '../video/video-channel.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)
@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 { getLowercaseExtension } from '@peertube/peertube-node-utils'
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
import { MActorId, MActorImage, MActorImageFormattable } from '@server/types/models/index.js'
import { remove } from 'fs-extra/esm'
import { join } from 'path'
@ -12,16 +11,14 @@ import {
CreatedAt,
Default,
ForeignKey,
Is,
Model,
Table,
Is, Table,
UpdatedAt
} from 'sequelize-typescript'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc.js'
import { logger } from '../../helpers/logger.js'
import { CONFIG } from '../../initializers/config.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'
@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)
@Column

View File

@ -17,9 +17,7 @@ import {
ForeignKey,
HasMany,
HasOne,
Is,
Model,
Scopes,
Is, Scopes,
Table,
UpdatedAt
} from 'sequelize-typescript'
@ -58,7 +56,7 @@ import {
import { AccountModel } from '../account/account.js'
import { getServerActor } from '../application/application.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 { VideoModel } from '../video/video.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)
@Column(DataType.ENUM(...Object.values(ACTIVITY_PUB_ACTOR_TYPES)))