mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-03 09:49:20 +02:00

* feat(customBrowseVideosDefaultSort): update server config * feat(customBrowseVideosDefaultSort): update client admin-config-general component * feat(customBrowseVideosDefaultSort): add new consistency check to server checker-after-init * feat(customBrowseVideosDefaultSort): update config .yaml with more details about available options * feat(customBrowseVideosDefaultSort): refactor consistency check in server checker-after-init * feat(customBrowseVideosDefaultSort): client, add new select-videos-sort shared component * feat(customBrowseVideosDefaultSort): client, refactor admin-config-general component to use new select-videos-sort shared component * feat(customBrowseVideosDefaultSort): client, fix my-select-videos-sort width in admin-config-general * feat(customBrowseVideosDefaultSort): client, update video-filters-header scss * feat(customBrowseVideosDefaultSort): client, update videos-list-all component * feat(config): refactor checkBrowseVideosConfig logic into separate custom validator * feat(config): refactor isBrowseVideosDefaultSortValid to use template literals * feat(config): refactor isBrowseVideosDefaultSortValid * feat(config): add check for invalid browse videos config to customConfigUpdateValidator * feat(config): group browse-videos tests in describe block * feat(config): refactor to use client.browse_videos section, instead of browse.videos section * feat(config): add browse_videos default_scope config key (config and server changes) * feat(config): add browse_videos default_scope config key (client changes) * Reorder browse videos before videos * Fix i18n message --------- Co-authored-by: Chocobozzz <me@florianbigard.com>
433 lines
12 KiB
TypeScript
433 lines
12 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
|
import { omit } from '@peertube/peertube-core-utils'
|
|
import { ActorImageType, CustomConfig, HttpStatusCode, LogoType } from '@peertube/peertube-models'
|
|
import { buildAbsoluteFixturePath } from '@peertube/peertube-node-utils'
|
|
import {
|
|
cleanupTests,
|
|
createSingleServer,
|
|
makeDeleteRequest,
|
|
makeGetRequest,
|
|
makePutBodyRequest,
|
|
makeUploadRequest,
|
|
PeerTubeServer,
|
|
setAccessTokensToServers
|
|
} from '@peertube/peertube-server-commands'
|
|
import merge from 'lodash-es/merge.js'
|
|
import { DeepPartial } from '../../../../typescript-utils/src/types.js'
|
|
|
|
describe('Test config API validators', function () {
|
|
const path = '/api/v1/config/custom'
|
|
let server: PeerTubeServer
|
|
let userAccessToken: string
|
|
|
|
let updateParams: CustomConfig
|
|
|
|
// ---------------------------------------------------------------
|
|
|
|
before(async function () {
|
|
this.timeout(30000)
|
|
|
|
server = await createSingleServer(1)
|
|
|
|
await setAccessTokensToServers([ server ])
|
|
updateParams = await server.config.getCustomConfig()
|
|
|
|
const user = {
|
|
username: 'user1',
|
|
password: 'password'
|
|
}
|
|
await server.users.create({ username: user.username, password: user.password })
|
|
userAccessToken = await server.login.getAccessToken(user)
|
|
})
|
|
|
|
describe('When getting the configuration', function () {
|
|
it('Should fail without token', async function () {
|
|
await makeGetRequest({
|
|
url: server.url,
|
|
path,
|
|
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
|
})
|
|
})
|
|
|
|
it('Should fail if the user is not an administrator', async function () {
|
|
await makeGetRequest({
|
|
url: server.url,
|
|
path,
|
|
token: userAccessToken,
|
|
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('When updating the configuration', function () {
|
|
it('Should fail without token', async function () {
|
|
await makePutBodyRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: updateParams,
|
|
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
|
})
|
|
})
|
|
|
|
it('Should fail if the user is not an administrator', async function () {
|
|
await makePutBodyRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: updateParams,
|
|
token: userAccessToken,
|
|
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
|
})
|
|
})
|
|
|
|
it('Should fail if it misses a key', async function () {
|
|
const newUpdateParams = { ...updateParams, admin: omit(updateParams.admin, [ 'email' ]) }
|
|
|
|
await makePutBodyRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: newUpdateParams,
|
|
token: server.accessToken,
|
|
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
|
})
|
|
})
|
|
|
|
it('Should fail with a bad default NSFW policy', async function () {
|
|
const newUpdateParams = merge({}, updateParams, {
|
|
instance: {
|
|
defaultNSFWPolicy: 'hello'
|
|
}
|
|
})
|
|
|
|
await makePutBodyRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: newUpdateParams,
|
|
token: server.accessToken,
|
|
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
|
})
|
|
})
|
|
|
|
it('Should fail with a bad default comment policy', async function () {
|
|
const newUpdateParams = merge({}, updateParams, {
|
|
defaults: {
|
|
publish: {
|
|
commentsPolicy: 11
|
|
}
|
|
}
|
|
})
|
|
|
|
await makePutBodyRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: newUpdateParams,
|
|
token: server.accessToken,
|
|
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
|
})
|
|
})
|
|
|
|
it('Should fail if email disabled and signup requires email verification', async function () {
|
|
// opposite scenario - success when enable enabled - covered via tests/api/users/user-verification.ts
|
|
const newUpdateParams = merge({}, updateParams, {
|
|
signup: {
|
|
enabled: true,
|
|
limit: 5,
|
|
requiresApproval: true,
|
|
requiresEmailVerification: true
|
|
}
|
|
})
|
|
|
|
await makePutBodyRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: newUpdateParams,
|
|
token: server.accessToken,
|
|
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
|
})
|
|
})
|
|
|
|
it('Should fail with a disabled web videos & hls transcoding', async function () {
|
|
const newUpdateParams = merge({}, updateParams, {
|
|
transcoding: {
|
|
enabled: true,
|
|
hls: {
|
|
enabled: false
|
|
},
|
|
webVideos: {
|
|
enabled: false
|
|
}
|
|
}
|
|
})
|
|
|
|
await makePutBodyRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: newUpdateParams,
|
|
token: server.accessToken,
|
|
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
|
})
|
|
})
|
|
|
|
it('Should fail with a disabled http upload & enabled sync', async function () {
|
|
const newUpdateParams: CustomConfig = merge({}, {}, updateParams, {
|
|
import: {
|
|
videos: {
|
|
http: { enabled: false }
|
|
},
|
|
videoChannelSynchronization: { enabled: true }
|
|
}
|
|
})
|
|
|
|
await makePutBodyRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: newUpdateParams,
|
|
token: server.accessToken,
|
|
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
|
})
|
|
})
|
|
|
|
it('Should fail with an invalid search configuration', async function () {
|
|
const newUpdateParams = merge(
|
|
{},
|
|
{},
|
|
updateParams,
|
|
{
|
|
search: {
|
|
remoteUri: {
|
|
users: false
|
|
},
|
|
searchIndex: {
|
|
enabled: true
|
|
}
|
|
}
|
|
} satisfies DeepPartial<CustomConfig>
|
|
)
|
|
|
|
await makePutBodyRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: newUpdateParams,
|
|
token: server.accessToken,
|
|
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
|
})
|
|
})
|
|
|
|
it('Should succeed with the correct parameters', async function () {
|
|
await makePutBodyRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: updateParams,
|
|
token: server.accessToken,
|
|
expectedStatus: HttpStatusCode.OK_200
|
|
})
|
|
})
|
|
|
|
describe('Browse videos section', function () {
|
|
it('Should fail with an invalid default sort', async function () {
|
|
const newUpdateParams: CustomConfig = merge({}, {}, updateParams, {
|
|
client: {
|
|
browseVideos: {
|
|
defaultSort: 'hello'
|
|
}
|
|
}
|
|
})
|
|
|
|
await makePutBodyRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: newUpdateParams,
|
|
token: server.accessToken,
|
|
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
|
})
|
|
})
|
|
|
|
it('Should fail with a trending default sort & disabled trending algorithm', async function () {
|
|
const newUpdateParams: CustomConfig = merge({}, {}, updateParams, {
|
|
trending: {
|
|
videos: {
|
|
algorithms: {
|
|
enabled: [ 'hot', 'most-liked' ]
|
|
}
|
|
}
|
|
},
|
|
client: {
|
|
browseVideos: {
|
|
defaultSort: '-trending'
|
|
}
|
|
}
|
|
})
|
|
|
|
await makePutBodyRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: newUpdateParams,
|
|
token: server.accessToken,
|
|
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
|
})
|
|
})
|
|
|
|
it('Should fail with an invalid default scope', async function () {
|
|
const newUpdateParams: CustomConfig = merge({}, {}, updateParams, {
|
|
client: {
|
|
browseVideos: {
|
|
defaultScope: 'hello'
|
|
}
|
|
}
|
|
})
|
|
|
|
await makePutBodyRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: newUpdateParams,
|
|
token: server.accessToken,
|
|
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('When deleting the configuration', function () {
|
|
it('Should fail without token', async function () {
|
|
await makeDeleteRequest({
|
|
url: server.url,
|
|
path,
|
|
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
|
})
|
|
})
|
|
|
|
it('Should fail if the user is not an administrator', async function () {
|
|
await makeDeleteRequest({
|
|
url: server.url,
|
|
path,
|
|
token: userAccessToken,
|
|
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('Updating instance image/logo', function () {
|
|
const toTest = [
|
|
{ path: '/api/v1/config/instance-banner/pick', attachName: 'bannerfile' },
|
|
{ path: '/api/v1/config/instance-avatar/pick', attachName: 'avatarfile' },
|
|
{ path: '/api/v1/config/instance-logo/favicon/pick', attachName: 'logofile' },
|
|
{ path: '/api/v1/config/instance-logo/header-square/pick', attachName: 'logofile' },
|
|
{ path: '/api/v1/config/instance-logo/header-wide/pick', attachName: 'logofile' },
|
|
{ path: '/api/v1/config/instance-logo/opengraph/pick', attachName: 'logofile' }
|
|
]
|
|
|
|
it('Should fail with an incorrect input file', async function () {
|
|
for (const { attachName, path } of toTest) {
|
|
const attaches = { [attachName]: buildAbsoluteFixturePath('video_short.mp4') }
|
|
|
|
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields: {}, attaches })
|
|
}
|
|
})
|
|
|
|
it('Should fail with a big file', async function () {
|
|
for (const { attachName, path } of toTest) {
|
|
const attaches = { [attachName]: buildAbsoluteFixturePath('avatar-big.png') }
|
|
|
|
await makeUploadRequest({
|
|
url: server.url,
|
|
path,
|
|
token: server.accessToken,
|
|
fields: {},
|
|
attaches,
|
|
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
|
})
|
|
}
|
|
})
|
|
|
|
it('Should fail without token', async function () {
|
|
for (const { attachName, path } of toTest) {
|
|
const attaches = { [attachName]: buildAbsoluteFixturePath('avatar.png') }
|
|
|
|
await makeUploadRequest({
|
|
url: server.url,
|
|
path,
|
|
fields: {},
|
|
attaches,
|
|
expectedStatus: HttpStatusCode.UNAUTHORIZED_401
|
|
})
|
|
}
|
|
})
|
|
|
|
it('Should fail without the appropriate rights', async function () {
|
|
for (const { attachName, path } of toTest) {
|
|
const attaches = { [attachName]: buildAbsoluteFixturePath('avatar.png') }
|
|
|
|
await makeUploadRequest({
|
|
url: server.url,
|
|
path,
|
|
token: userAccessToken,
|
|
fields: {},
|
|
attaches,
|
|
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
|
})
|
|
}
|
|
})
|
|
|
|
it('Should succeed with the correct params', async function () {
|
|
for (const { attachName, path } of toTest) {
|
|
const attaches = { [attachName]: buildAbsoluteFixturePath('avatar.png') }
|
|
|
|
await makeUploadRequest({
|
|
url: server.url,
|
|
path,
|
|
token: server.accessToken,
|
|
fields: {},
|
|
attaches,
|
|
expectedStatus: HttpStatusCode.NO_CONTENT_204
|
|
})
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('Deleting instance image', function () {
|
|
const types = [ ActorImageType.BANNER, ActorImageType.AVATAR ]
|
|
|
|
it('Should fail without token', async function () {
|
|
for (const type of types) {
|
|
await server.config.deleteInstanceImage({ type, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
|
}
|
|
})
|
|
|
|
it('Should fail without the appropriate rights', async function () {
|
|
for (const type of types) {
|
|
await server.config.deleteInstanceImage({ type, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
|
}
|
|
})
|
|
|
|
it('Should succeed with the correct params', async function () {
|
|
for (const type of types) {
|
|
await server.config.deleteInstanceImage({ type })
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('Deleting instance logos', function () {
|
|
const types: LogoType[] = [ 'favicon', 'header-square', 'header-wide', 'opengraph' ]
|
|
|
|
it('Should fail without token', async function () {
|
|
for (const type of types) {
|
|
await server.config.deleteInstanceLogo({ type, token: null, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
|
|
}
|
|
})
|
|
|
|
it('Should fail without the appropriate rights', async function () {
|
|
for (const type of types) {
|
|
await server.config.deleteInstanceLogo({ type, token: userAccessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
|
|
}
|
|
})
|
|
|
|
it('Should succeed with the correct params', async function () {
|
|
for (const type of types) {
|
|
await server.config.deleteInstanceLogo({ type })
|
|
}
|
|
})
|
|
})
|
|
|
|
after(async function () {
|
|
await cleanupTests([ server ])
|
|
})
|
|
})
|