aboutsummaryrefslogtreecommitdiffhomepage
path: root/shared
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-05-27 16:12:41 +0200
committerChocobozzz <me@florianbigard.com>2021-05-27 16:12:41 +0200
commit8f608a4cb22ab232cfab20665050764b38bac9c7 (patch)
tree6a6785aae79bf5939ad7b7a50a1bd8031268d2b4 /shared
parent030ccfce59a8cb8f2fee6ea8dd363ba635c5c5c2 (diff)
parentc215e627b575d2c4085ccb222f4ca8d0237b7552 (diff)
downloadPeerTube-8f608a4cb22ab232cfab20665050764b38bac9c7.tar.gz
PeerTube-8f608a4cb22ab232cfab20665050764b38bac9c7.tar.zst
PeerTube-8f608a4cb22ab232cfab20665050764b38bac9c7.zip
Merge branch 'develop' into shorter-URLs-channels-accounts
Diffstat (limited to 'shared')
-rw-r--r--shared/core-utils/miscs/http-methods.ts21
-rw-r--r--shared/core-utils/miscs/index.ts1
-rw-r--r--shared/core-utils/miscs/miscs.ts17
-rw-r--r--shared/core-utils/miscs/types.ts4
-rw-r--r--shared/core-utils/renderer/html.ts52
-rw-r--r--shared/extra-utils/custom-pages/custom-pages.ts31
-rw-r--r--shared/extra-utils/index.ts18
-rw-r--r--shared/extra-utils/server/config.ts15
-rw-r--r--shared/extra-utils/server/debug.ts18
-rw-r--r--shared/extra-utils/server/jobs.ts4
-rw-r--r--shared/extra-utils/server/plugins.ts4
-rw-r--r--shared/extra-utils/server/servers.ts5
-rw-r--r--shared/extra-utils/users/users.ts23
-rw-r--r--shared/extra-utils/videos/video-channels.ts11
-rw-r--r--shared/extra-utils/videos/videos.ts258
-rw-r--r--shared/models/activitypub/activitypub-actor.ts2
-rw-r--r--shared/models/actors/account.model.ts2
-rw-r--r--shared/models/actors/actor.model.ts1
-rw-r--r--shared/models/actors/custom-page.model.ts3
-rw-r--r--shared/models/actors/index.ts1
-rw-r--r--shared/models/custom-markup/custom-markup-data.model.ts28
-rw-r--r--shared/models/custom-markup/index.ts1
-rw-r--r--shared/models/index.ts1
-rw-r--r--shared/models/nodeinfo/index.ts1
-rw-r--r--shared/models/nodeinfo/nodeinfo.model.ts (renamed from shared/models/nodeinfo/index.d.ts)0
-rw-r--r--shared/models/overviews/index.ts2
-rw-r--r--shared/models/overviews/videos-overview.model.ts (renamed from shared/models/overviews/videos-overview.ts)0
-rw-r--r--shared/models/plugins/client/client-hook.model.ts (renamed from shared/models/plugins/client-hook.model.ts)0
-rw-r--r--shared/models/plugins/client/index.ts6
-rw-r--r--shared/models/plugins/client/plugin-client-scope.type.ts (renamed from shared/models/plugins/plugin-client-scope.type.ts)0
-rw-r--r--shared/models/plugins/client/plugin-element-placeholder.type.ts (renamed from shared/models/plugins/plugin-element-placeholder.type.ts)0
-rw-r--r--shared/models/plugins/client/register-client-form-field.model.ts (renamed from shared/models/plugins/register-client-form-field.model.ts)0
-rw-r--r--shared/models/plugins/client/register-client-hook.model.ts (renamed from shared/models/plugins/register-client-hook.model.ts)0
-rw-r--r--shared/models/plugins/client/register-client-settings-script.model.ts (renamed from shared/models/plugins/register-client-settings-script.model.ts)2
-rw-r--r--shared/models/plugins/index.ts28
-rw-r--r--shared/models/plugins/plugin-index/index.ts3
-rw-r--r--shared/models/plugins/plugin-index/peertube-plugin-index-list.model.ts (renamed from shared/models/plugins/peertube-plugin-index-list.model.ts)2
-rw-r--r--shared/models/plugins/plugin-index/peertube-plugin-index.model.ts (renamed from shared/models/plugins/peertube-plugin-index.model.ts)0
-rw-r--r--shared/models/plugins/plugin-index/peertube-plugin-latest-version.model.ts (renamed from shared/models/plugins/peertube-plugin-latest-version.model.ts)0
-rw-r--r--shared/models/plugins/plugin-package-json.model.ts2
-rw-r--r--shared/models/plugins/server/api/index.ts3
-rw-r--r--shared/models/plugins/server/api/install-plugin.model.ts (renamed from shared/models/plugins/install-plugin.model.ts)0
-rw-r--r--shared/models/plugins/server/api/manage-plugin.model.ts (renamed from shared/models/plugins/manage-plugin.model.ts)0
-rw-r--r--shared/models/plugins/server/api/peertube-plugin.model.ts (renamed from shared/models/plugins/peertube-plugin.model.ts)2
-rw-r--r--shared/models/plugins/server/index.ts6
-rw-r--r--shared/models/plugins/server/managers/index.ts9
-rw-r--r--shared/models/plugins/server/managers/plugin-playlist-privacy-manager.model.ts (renamed from shared/models/plugins/plugin-playlist-privacy-manager.model.ts)2
-rw-r--r--shared/models/plugins/server/managers/plugin-settings-manager.model.ts (renamed from shared/models/plugins/plugin-settings-manager.model.ts)0
-rw-r--r--shared/models/plugins/server/managers/plugin-storage-manager.model.ts (renamed from shared/models/plugins/plugin-storage-manager.model.ts)0
-rw-r--r--shared/models/plugins/server/managers/plugin-transcoding-manager.model.ts (renamed from shared/models/plugins/plugin-transcoding-manager.model.ts)2
-rw-r--r--shared/models/plugins/server/managers/plugin-video-category-manager.model.ts (renamed from shared/models/plugins/plugin-video-category-manager.model.ts)0
-rw-r--r--shared/models/plugins/server/managers/plugin-video-language-manager.model.ts (renamed from shared/models/plugins/plugin-video-language-manager.model.ts)0
-rw-r--r--shared/models/plugins/server/managers/plugin-video-licence-manager.model.ts (renamed from shared/models/plugins/plugin-video-licence-manager.model.ts)0
-rw-r--r--shared/models/plugins/server/managers/plugin-video-privacy-manager.model.ts (renamed from shared/models/plugins/plugin-video-privacy-manager.model.ts)2
-rw-r--r--shared/models/plugins/server/plugin-translation.model.ts (renamed from shared/models/plugins/plugin-translation.model.ts)0
-rw-r--r--shared/models/plugins/server/register-server-hook.model.ts (renamed from shared/models/plugins/register-server-hook.model.ts)0
-rw-r--r--shared/models/plugins/server/server-hook.model.ts (renamed from shared/models/plugins/server-hook.model.ts)0
-rw-r--r--shared/models/plugins/server/settings/index.ts2
-rw-r--r--shared/models/plugins/server/settings/public-server.setting.ts (renamed from shared/models/plugins/public-server.setting.ts)0
-rw-r--r--shared/models/plugins/server/settings/register-server-setting.model.ts (renamed from shared/models/plugins/register-server-setting.model.ts)2
-rw-r--r--shared/models/redundancy/index.ts3
-rw-r--r--shared/models/search/boolean-both-query.model.ts1
-rw-r--r--shared/models/server/debug.model.ts4
-rw-r--r--shared/models/server/server-config.model.ts6
-rw-r--r--shared/models/server/server-error-code.enum.ts1
-rw-r--r--shared/models/users/user-right.enum.ts1
-rw-r--r--shared/models/videos/change-ownership/index.ts3
-rw-r--r--shared/models/videos/change-ownership/video-change-ownership-accept.model.ts (renamed from shared/models/videos/video-change-ownership-accept.model.ts)0
-rw-r--r--shared/models/videos/change-ownership/video-change-ownership-create.model.ts (renamed from shared/models/videos/video-change-ownership-create.model.ts)0
-rw-r--r--shared/models/videos/change-ownership/video-change-ownership.model.ts (renamed from shared/models/videos/video-change-ownership.model.ts)4
-rw-r--r--shared/models/videos/channel/video-channel.model.ts3
-rw-r--r--shared/models/videos/comment/index.ts1
-rw-r--r--shared/models/videos/comment/video-comment.model.ts (renamed from shared/models/videos/video-comment.model.ts)2
-rw-r--r--shared/models/videos/index.ts12
-rw-r--r--shared/models/videos/video-file-metadata.model.ts (renamed from shared/models/videos/video-file-metadata.ts)0
-rw-r--r--shared/models/videos/video-file.model.ts2
76 files changed, 506 insertions, 134 deletions
diff --git a/shared/core-utils/miscs/http-methods.ts b/shared/core-utils/miscs/http-methods.ts
new file mode 100644
index 000000000..1cfa458b9
--- /dev/null
+++ b/shared/core-utils/miscs/http-methods.ts
@@ -0,0 +1,21 @@
1/** HTTP request method to indicate the desired action to be performed for a given resource. */
2export enum HttpMethod {
3 /** The CONNECT method establishes a tunnel to the server identified by the target resource. */
4 CONNECT = 'CONNECT',
5 /** The DELETE method deletes the specified resource. */
6 DELETE = 'DELETE',
7 /** The GET method requests a representation of the specified resource. Requests using GET should only retrieve data. */
8 GET = 'GET',
9 /** The HEAD method asks for a response identical to that of a GET request, but without the response body. */
10 HEAD = 'HEAD',
11 /** The OPTIONS method is used to describe the communication options for the target resource. */
12 OPTIONS = 'OPTIONS',
13 /** The PATCH method is used to apply partial modifications to a resource. */
14 PATCH = 'PATCH',
15 /** The POST method is used to submit an entity to the specified resource */
16 POST = 'POST',
17 /** The PUT method replaces all current representations of the target resource with the request payload. */
18 PUT = 'PUT',
19 /** The TRACE method performs a message loop-back test along the path to the target resource. */
20 TRACE = 'TRACE'
21}
diff --git a/shared/core-utils/miscs/index.ts b/shared/core-utils/miscs/index.ts
index 898fd4791..251df1de2 100644
--- a/shared/core-utils/miscs/index.ts
+++ b/shared/core-utils/miscs/index.ts
@@ -2,3 +2,4 @@ export * from './date'
2export * from './miscs' 2export * from './miscs'
3export * from './types' 3export * from './types'
4export * from './http-error-codes' 4export * from './http-error-codes'
5export * from './http-methods'
diff --git a/shared/core-utils/miscs/miscs.ts b/shared/core-utils/miscs/miscs.ts
index 71703faac..4780ca922 100644
--- a/shared/core-utils/miscs/miscs.ts
+++ b/shared/core-utils/miscs/miscs.ts
@@ -28,9 +28,24 @@ function isCatchable (value: any) {
28 return value && typeof value.catch === 'function' 28 return value && typeof value.catch === 'function'
29} 29}
30 30
31function sortObjectComparator (key: string, order: 'asc' | 'desc') {
32 return (a: any, b: any) => {
33 if (a[key] < b[key]) {
34 return order === 'asc' ? -1 : 1
35 }
36
37 if (a[key] > b[key]) {
38 return order === 'asc' ? 1 : -1
39 }
40
41 return 0
42 }
43}
44
31export { 45export {
32 randomInt, 46 randomInt,
33 compareSemVer, 47 compareSemVer,
34 isPromise, 48 isPromise,
35 isCatchable 49 isCatchable,
50 sortObjectComparator
36} 51}
diff --git a/shared/core-utils/miscs/types.ts b/shared/core-utils/miscs/types.ts
index bb64dc830..bd2a97b98 100644
--- a/shared/core-utils/miscs/types.ts
+++ b/shared/core-utils/miscs/types.ts
@@ -6,6 +6,10 @@ export type FunctionPropertyNames<T> = {
6 6
7export type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>> 7export type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>
8 8
9export type AttributesOnly<T> = {
10 [K in keyof T]: T[K] extends Function ? never : T[K]
11}
12
9export type PickWith<T, KT extends keyof T, V> = { 13export type PickWith<T, KT extends keyof T, V> = {
10 [P in KT]: T[P] extends V ? V : never 14 [P in KT]: T[P] extends V ? V : never
11} 15}
diff --git a/shared/core-utils/renderer/html.ts b/shared/core-utils/renderer/html.ts
index de4ad47ac..bbf8b3fbd 100644
--- a/shared/core-utils/renderer/html.ts
+++ b/shared/core-utils/renderer/html.ts
@@ -1,25 +1,45 @@
1export const SANITIZE_OPTIONS = { 1export function getSanitizeOptions () {
2 allowedTags: [ 'a', 'p', 'span', 'br', 'strong', 'em', 'ul', 'ol', 'li' ], 2 return {
3 allowedSchemes: [ 'http', 'https' ], 3 allowedTags: [ 'a', 'p', 'span', 'br', 'strong', 'em', 'ul', 'ol', 'li' ],
4 allowedAttributes: { 4 allowedSchemes: [ 'http', 'https' ],
5 a: [ 'href', 'class', 'target', 'rel' ] 5 allowedAttributes: {
6 }, 6 'a': [ 'href', 'class', 'target', 'rel' ],
7 transformTags: { 7 '*': [ 'data-*' ]
8 a: (tagName: string, attribs: any) => { 8 },
9 let rel = 'noopener noreferrer' 9 transformTags: {
10 if (attribs.rel === 'me') rel += ' me' 10 a: (tagName: string, attribs: any) => {
11 let rel = 'noopener noreferrer'
12 if (attribs.rel === 'me') rel += ' me'
11 13
12 return { 14 return {
13 tagName, 15 tagName,
14 attribs: Object.assign(attribs, { 16 attribs: Object.assign(attribs, {
15 target: '_blank', 17 target: '_blank',
16 rel 18 rel
17 }) 19 })
20 }
18 } 21 }
19 } 22 }
20 } 23 }
21} 24}
22 25
26export function getCustomMarkupSanitizeOptions (additionalAllowedTags: string[] = []) {
27 const base = getSanitizeOptions()
28
29 return {
30 allowedTags: [
31 ...base.allowedTags,
32 ...additionalAllowedTags,
33 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
34 ],
35 allowedSchemes: base.allowedSchemes,
36 allowedAttributes: {
37 ...base.allowedAttributes,
38 '*': [ 'data-*', 'style' ]
39 }
40 }
41}
42
23// Thanks: https://stackoverflow.com/a/12034334 43// Thanks: https://stackoverflow.com/a/12034334
24export function escapeHTML (stringParam: string) { 44export function escapeHTML (stringParam: string) {
25 if (!stringParam) return '' 45 if (!stringParam) return ''
diff --git a/shared/extra-utils/custom-pages/custom-pages.ts b/shared/extra-utils/custom-pages/custom-pages.ts
new file mode 100644
index 000000000..bf2d16c70
--- /dev/null
+++ b/shared/extra-utils/custom-pages/custom-pages.ts
@@ -0,0 +1,31 @@
1import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
2import { makeGetRequest, makePutBodyRequest } from '../requests/requests'
3
4function getInstanceHomepage (url: string, statusCodeExpected = HttpStatusCode.OK_200) {
5 const path = '/api/v1/custom-pages/homepage/instance'
6
7 return makeGetRequest({
8 url,
9 path,
10 statusCodeExpected
11 })
12}
13
14function updateInstanceHomepage (url: string, token: string, content: string) {
15 const path = '/api/v1/custom-pages/homepage/instance'
16
17 return makePutBodyRequest({
18 url,
19 path,
20 token,
21 fields: { content },
22 statusCodeExpected: HttpStatusCode.NO_CONTENT_204
23 })
24}
25
26// ---------------------------------------------------------------------------
27
28export {
29 getInstanceHomepage,
30 updateInstanceHomepage
31}
diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts
index 5c520d0c2..9f5b5bb28 100644
--- a/shared/extra-utils/index.ts
+++ b/shared/extra-utils/index.ts
@@ -1,16 +1,27 @@
1export * from './actors/actors' 1export * from './actors/actors'
2export * from './bulk/bulk' 2export * from './bulk/bulk'
3
3export * from './cli/cli' 4export * from './cli/cli'
5
6export * from './custom-pages/custom-pages'
7
4export * from './feeds/feeds' 8export * from './feeds/feeds'
9
5export * from './mock-servers/mock-instances-index' 10export * from './mock-servers/mock-instances-index'
6export * from './miscs/miscs' 11
12export * from './miscs/email'
7export * from './miscs/sql' 13export * from './miscs/sql'
14export * from './miscs/miscs'
8export * from './miscs/stubs' 15export * from './miscs/stubs'
16
9export * from './moderation/abuses' 17export * from './moderation/abuses'
10export * from './plugins/mock-blocklist' 18export * from './plugins/mock-blocklist'
19
11export * from './requests/check-api-params' 20export * from './requests/check-api-params'
12export * from './requests/requests' 21export * from './requests/requests'
22
13export * from './search/videos' 23export * from './search/videos'
24
14export * from './server/activitypub' 25export * from './server/activitypub'
15export * from './server/clients' 26export * from './server/clients'
16export * from './server/config' 27export * from './server/config'
@@ -19,9 +30,14 @@ export * from './server/follows'
19export * from './server/jobs' 30export * from './server/jobs'
20export * from './server/plugins' 31export * from './server/plugins'
21export * from './server/servers' 32export * from './server/servers'
33
22export * from './users/accounts' 34export * from './users/accounts'
35export * from './users/blocklist'
23export * from './users/login' 36export * from './users/login'
37export * from './users/user-notifications'
38export * from './users/user-subscriptions'
24export * from './users/users' 39export * from './users/users'
40
25export * from './videos/live' 41export * from './videos/live'
26export * from './videos/services' 42export * from './videos/services'
27export * from './videos/video-blacklist' 43export * from './videos/video-blacklist'
diff --git a/shared/extra-utils/server/config.ts b/shared/extra-utils/server/config.ts
index 026a5e61c..b70110852 100644
--- a/shared/extra-utils/server/config.ts
+++ b/shared/extra-utils/server/config.ts
@@ -223,6 +223,18 @@ function updateCustomSubConfig (url: string, token: string, newConfig: DeepParti
223 return updateCustomConfig(url, token, updateParams) 223 return updateCustomConfig(url, token, updateParams)
224} 224}
225 225
226function getCustomConfigResolutions (enabled: boolean) {
227 return {
228 '240p': enabled,
229 '360p': enabled,
230 '480p': enabled,
231 '720p': enabled,
232 '1080p': enabled,
233 '1440p': enabled,
234 '2160p': enabled
235 }
236}
237
226function deleteCustomConfig (url: string, token: string, statusCodeExpected = HttpStatusCode.OK_200) { 238function deleteCustomConfig (url: string, token: string, statusCodeExpected = HttpStatusCode.OK_200) {
227 const path = '/api/v1/config/custom' 239 const path = '/api/v1/config/custom'
228 240
@@ -242,5 +254,6 @@ export {
242 updateCustomConfig, 254 updateCustomConfig,
243 getAbout, 255 getAbout,
244 deleteCustomConfig, 256 deleteCustomConfig,
245 updateCustomSubConfig 257 updateCustomSubConfig,
258 getCustomConfigResolutions
246} 259}
diff --git a/shared/extra-utils/server/debug.ts b/shared/extra-utils/server/debug.ts
index 5cf80a5fb..f196812b7 100644
--- a/shared/extra-utils/server/debug.ts
+++ b/shared/extra-utils/server/debug.ts
@@ -1,5 +1,6 @@
1import { makeGetRequest } from '../requests/requests' 1import { makeGetRequest, makePostBodyRequest } from '../requests/requests'
2import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' 2import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes'
3import { SendDebugCommand } from '@shared/models'
3 4
4function getDebug (url: string, token: string) { 5function getDebug (url: string, token: string) {
5 const path = '/api/v1/server/debug' 6 const path = '/api/v1/server/debug'
@@ -12,8 +13,21 @@ function getDebug (url: string, token: string) {
12 }) 13 })
13} 14}
14 15
16function sendDebugCommand (url: string, token: string, body: SendDebugCommand) {
17 const path = '/api/v1/server/debug/run-command'
18
19 return makePostBodyRequest({
20 url,
21 path,
22 token,
23 fields: body,
24 statusCodeExpected: HttpStatusCode.NO_CONTENT_204
25 })
26}
27
15// --------------------------------------------------------------------------- 28// ---------------------------------------------------------------------------
16 29
17export { 30export {
18 getDebug 31 getDebug,
32 sendDebugCommand
19} 33}
diff --git a/shared/extra-utils/server/jobs.ts b/shared/extra-utils/server/jobs.ts
index 704929bd4..763374e03 100644
--- a/shared/extra-utils/server/jobs.ts
+++ b/shared/extra-utils/server/jobs.ts
@@ -55,7 +55,7 @@ function getJobsListPaginationAndSort (options: {
55async function waitJobs (serversArg: ServerInfo[] | ServerInfo) { 55async function waitJobs (serversArg: ServerInfo[] | ServerInfo) {
56 const pendingJobWait = process.env.NODE_PENDING_JOB_WAIT 56 const pendingJobWait = process.env.NODE_PENDING_JOB_WAIT
57 ? parseInt(process.env.NODE_PENDING_JOB_WAIT, 10) 57 ? parseInt(process.env.NODE_PENDING_JOB_WAIT, 10)
58 : 500 58 : 250
59 59
60 let servers: ServerInfo[] 60 let servers: ServerInfo[]
61 61
@@ -115,7 +115,7 @@ async function waitJobs (serversArg: ServerInfo[] | ServerInfo) {
115 } 115 }
116 116
117 if (pendingRequests) { 117 if (pendingRequests) {
118 await wait(1000) 118 await wait(pendingJobWait)
119 } 119 }
120 } while (pendingRequests) 120 } while (pendingRequests)
121} 121}
diff --git a/shared/extra-utils/server/plugins.ts b/shared/extra-utils/server/plugins.ts
index 864954ee7..d53e5b382 100644
--- a/shared/extra-utils/server/plugins.ts
+++ b/shared/extra-utils/server/plugins.ts
@@ -4,12 +4,12 @@ import { expect } from 'chai'
4import { readJSON, writeJSON } from 'fs-extra' 4import { readJSON, writeJSON } from 'fs-extra'
5import { join } from 'path' 5import { join } from 'path'
6import { RegisteredServerSettings } from '@shared/models' 6import { RegisteredServerSettings } from '@shared/models'
7import { PeertubePluginIndexList } from '../../models/plugins/peertube-plugin-index-list.model' 7import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
8import { PeertubePluginIndexList } from '../../models/plugins/plugin-index/peertube-plugin-index-list.model'
8import { PluginType } from '../../models/plugins/plugin.type' 9import { PluginType } from '../../models/plugins/plugin.type'
9import { buildServerDirectory, root } from '../miscs/miscs' 10import { buildServerDirectory, root } from '../miscs/miscs'
10import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' 11import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests'
11import { ServerInfo } from './servers' 12import { ServerInfo } from './servers'
12import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
13 13
14function listPlugins (parameters: { 14function listPlugins (parameters: {
15 url: string 15 url: string
diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts
index 779a3cc36..d04757470 100644
--- a/shared/extra-utils/server/servers.ts
+++ b/shared/extra-utils/server/servers.ts
@@ -45,9 +45,12 @@ interface ServerInfo {
45 uuid: string 45 uuid: string
46 name?: string 46 name?: string
47 url?: string 47 url?: string
48
48 account?: { 49 account?: {
49 name: string 50 name: string
50 } 51 }
52
53 embedPath?: string
51 } 54 }
52 55
53 remoteVideo?: { 56 remoteVideo?: {
@@ -274,7 +277,7 @@ async function reRunServer (server: ServerInfo, configOverride?: any) {
274} 277}
275 278
276async function checkTmpIsEmpty (server: ServerInfo) { 279async function checkTmpIsEmpty (server: ServerInfo) {
277 await checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css', 'hls' ]) 280 await checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css', 'hls', 'resumable-uploads' ])
278 281
279 if (await pathExists(join('test' + server.internalServerNumber, 'tmp', 'hls'))) { 282 if (await pathExists(join('test' + server.internalServerNumber, 'tmp', 'hls'))) {
280 await checkDirectoryIsEmpty(server, 'tmp/hls') 283 await checkDirectoryIsEmpty(server, 'tmp/hls')
diff --git a/shared/extra-utils/users/users.ts b/shared/extra-utils/users/users.ts
index 6040dd9c0..0f15962ad 100644
--- a/shared/extra-utils/users/users.ts
+++ b/shared/extra-utils/users/users.ts
@@ -1,5 +1,6 @@
1import { omit } from 'lodash' 1import { omit } from 'lodash'
2import * as request from 'supertest' 2import * as request from 'supertest'
3import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
3import { UserUpdateMe } from '../../models/users' 4import { UserUpdateMe } from '../../models/users'
4import { UserAdminFlag } from '../../models/users/user-flag.model' 5import { UserAdminFlag } from '../../models/users/user-flag.model'
5import { UserRegister } from '../../models/users/user-register.model' 6import { UserRegister } from '../../models/users/user-register.model'
@@ -7,9 +8,8 @@ import { UserRole } from '../../models/users/user-role'
7import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, updateImageRequest } from '../requests/requests' 8import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, updateImageRequest } from '../requests/requests'
8import { ServerInfo } from '../server/servers' 9import { ServerInfo } from '../server/servers'
9import { userLogin } from './login' 10import { userLogin } from './login'
10import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
11 11
12type CreateUserArgs = { 12function createUser (parameters: {
13 url: string 13 url: string
14 accessToken: string 14 accessToken: string
15 username: string 15 username: string
@@ -19,8 +19,7 @@ type CreateUserArgs = {
19 role?: UserRole 19 role?: UserRole
20 adminFlags?: UserAdminFlag 20 adminFlags?: UserAdminFlag
21 specialStatus?: number 21 specialStatus?: number
22} 22}) {
23function createUser (parameters: CreateUserArgs) {
24 const { 23 const {
25 url, 24 url,
26 accessToken, 25 accessToken,
@@ -52,6 +51,21 @@ function createUser (parameters: CreateUserArgs) {
52 .expect(specialStatus) 51 .expect(specialStatus)
53} 52}
54 53
54async function generateUser (server: ServerInfo, username: string) {
55 const password = 'my super password'
56 const resCreate = await createUser({ url: server.url, accessToken: server.accessToken, username: username, password: password })
57
58 const token = await userLogin(server, { username, password })
59
60 const resMe = await getMyUserInformation(server.url, token)
61
62 return {
63 token,
64 userId: resCreate.body.user.id,
65 userChannelId: resMe.body.videoChannels[0].id
66 }
67}
68
55async function generateUserAccessToken (server: ServerInfo, username: string) { 69async function generateUserAccessToken (server: ServerInfo, username: string) {
56 const password = 'my super password' 70 const password = 'my super password'
57 await createUser({ url: server.url, accessToken: server.accessToken, username: username, password: password }) 71 await createUser({ url: server.url, accessToken: server.accessToken, username: username, password: password })
@@ -393,6 +407,7 @@ export {
393 resetPassword, 407 resetPassword,
394 renewUserScopedTokens, 408 renewUserScopedTokens,
395 updateMyAvatar, 409 updateMyAvatar,
410 generateUser,
396 askSendVerifyEmail, 411 askSendVerifyEmail,
397 generateUserAccessToken, 412 generateUserAccessToken,
398 verifyEmail, 413 verifyEmail,
diff --git a/shared/extra-utils/videos/video-channels.ts b/shared/extra-utils/videos/video-channels.ts
index d0dfb5856..0aab93e52 100644
--- a/shared/extra-utils/videos/video-channels.ts
+++ b/shared/extra-utils/videos/video-channels.ts
@@ -5,7 +5,7 @@ import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-up
5import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model' 5import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model'
6import { makeDeleteRequest, makeGetRequest, updateImageRequest } from '../requests/requests' 6import { makeDeleteRequest, makeGetRequest, updateImageRequest } from '../requests/requests'
7import { ServerInfo } from '../server/servers' 7import { ServerInfo } from '../server/servers'
8import { User } from '../../models/users/user.model' 8import { MyUser, User } from '../../models/users/user.model'
9import { getMyUserInformation } from '../users/users' 9import { getMyUserInformation } from '../users/users'
10import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' 10import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
11 11
@@ -170,6 +170,12 @@ function setDefaultVideoChannel (servers: ServerInfo[]) {
170 return Promise.all(tasks) 170 return Promise.all(tasks)
171} 171}
172 172
173async function getDefaultVideoChannel (url: string, token: string) {
174 const res = await getMyUserInformation(url, token)
175
176 return (res.body as MyUser).videoChannels[0].id
177}
178
173// --------------------------------------------------------------------------- 179// ---------------------------------------------------------------------------
174 180
175export { 181export {
@@ -181,5 +187,6 @@ export {
181 deleteVideoChannel, 187 deleteVideoChannel,
182 getVideoChannel, 188 getVideoChannel,
183 setDefaultVideoChannel, 189 setDefaultVideoChannel,
184 deleteVideoChannelImage 190 deleteVideoChannelImage,
191 getDefaultVideoChannel
185} 192}
diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts
index a0143b0ef..e88256ac0 100644
--- a/shared/extra-utils/videos/videos.ts
+++ b/shared/extra-utils/videos/videos.ts
@@ -1,7 +1,8 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
2 2
3import { expect } from 'chai' 3import { expect } from 'chai'
4import { pathExists, readdir, readFile } from 'fs-extra' 4import { createReadStream, pathExists, readdir, readFile, stat } from 'fs-extra'
5import got, { Response as GotResponse } from 'got/dist/source'
5import * as parseTorrent from 'parse-torrent' 6import * as parseTorrent from 'parse-torrent'
6import { extname, join } from 'path' 7import { extname, join } from 'path'
7import * as request from 'supertest' 8import * as request from 'supertest'
@@ -42,6 +43,7 @@ type VideoAttributes = {
42 channelId?: number 43 channelId?: number
43 privacy?: VideoPrivacy 44 privacy?: VideoPrivacy
44 fixture?: string 45 fixture?: string
46 support?: string
45 thumbnailfile?: string 47 thumbnailfile?: string
46 previewfile?: string 48 previewfile?: string
47 scheduleUpdate?: { 49 scheduleUpdate?: {
@@ -364,8 +366,13 @@ async function checkVideoFilesWereRemoved (
364 } 366 }
365} 367}
366 368
367async function uploadVideo (url: string, accessToken: string, videoAttributesArg: VideoAttributes, specialStatus = HttpStatusCode.OK_200) { 369async function uploadVideo (
368 const path = '/api/v1/videos/upload' 370 url: string,
371 accessToken: string,
372 videoAttributesArg: VideoAttributes,
373 specialStatus = HttpStatusCode.OK_200,
374 mode: 'legacy' | 'resumable' = 'legacy'
375) {
369 let defaultChannelId = '1' 376 let defaultChannelId = '1'
370 377
371 try { 378 try {
@@ -391,74 +398,170 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg
391 fixture: 'video_short.webm' 398 fixture: 'video_short.webm'
392 }, videoAttributesArg) 399 }, videoAttributesArg)
393 400
401 const res = mode === 'legacy'
402 ? await buildLegacyUpload(url, accessToken, attributes, specialStatus)
403 : await buildResumeUpload(url, accessToken, attributes, specialStatus)
404
405 // Wait torrent generation
406 if (specialStatus === HttpStatusCode.OK_200) {
407 let video: VideoDetails
408 do {
409 const resVideo = await getVideoWithToken(url, accessToken, res.body.video.uuid)
410 video = resVideo.body
411
412 await wait(50)
413 } while (!video.files[0].torrentUrl)
414 }
415
416 return res
417}
418
419function checkUploadVideoParam (
420 url: string,
421 token: string,
422 attributes: Partial<VideoAttributes>,
423 specialStatus = HttpStatusCode.OK_200,
424 mode: 'legacy' | 'resumable' = 'legacy'
425) {
426 return mode === 'legacy'
427 ? buildLegacyUpload(url, token, attributes, specialStatus)
428 : buildResumeUpload(url, token, attributes, specialStatus)
429}
430
431async function buildLegacyUpload (url: string, token: string, attributes: VideoAttributes, specialStatus = HttpStatusCode.OK_200) {
432 const path = '/api/v1/videos/upload'
394 const req = request(url) 433 const req = request(url)
395 .post(path) 434 .post(path)
396 .set('Accept', 'application/json') 435 .set('Accept', 'application/json')
397 .set('Authorization', 'Bearer ' + accessToken) 436 .set('Authorization', 'Bearer ' + token)
398 .field('name', attributes.name)
399 .field('nsfw', JSON.stringify(attributes.nsfw))
400 .field('commentsEnabled', JSON.stringify(attributes.commentsEnabled))
401 .field('downloadEnabled', JSON.stringify(attributes.downloadEnabled))
402 .field('waitTranscoding', JSON.stringify(attributes.waitTranscoding))
403 .field('privacy', attributes.privacy.toString())
404 .field('channelId', attributes.channelId)
405
406 if (attributes.support !== undefined) {
407 req.field('support', attributes.support)
408 }
409 437
410 if (attributes.description !== undefined) { 438 buildUploadReq(req, attributes)
411 req.field('description', attributes.description)
412 }
413 if (attributes.language !== undefined) {
414 req.field('language', attributes.language.toString())
415 }
416 if (attributes.category !== undefined) {
417 req.field('category', attributes.category.toString())
418 }
419 if (attributes.licence !== undefined) {
420 req.field('licence', attributes.licence.toString())
421 }
422 439
423 const tags = attributes.tags || [] 440 if (attributes.fixture !== undefined) {
424 for (let i = 0; i < tags.length; i++) { 441 req.attach('videofile', buildAbsoluteFixturePath(attributes.fixture))
425 req.field('tags[' + i + ']', attributes.tags[i])
426 } 442 }
427 443
428 if (attributes.thumbnailfile !== undefined) { 444 return req.expect(specialStatus)
429 req.attach('thumbnailfile', buildAbsoluteFixturePath(attributes.thumbnailfile)) 445}
430 }
431 if (attributes.previewfile !== undefined) {
432 req.attach('previewfile', buildAbsoluteFixturePath(attributes.previewfile))
433 }
434 446
435 if (attributes.scheduleUpdate) { 447async function buildResumeUpload (url: string, token: string, attributes: VideoAttributes, specialStatus = HttpStatusCode.OK_200) {
436 req.field('scheduleUpdate[updateAt]', attributes.scheduleUpdate.updateAt) 448 let size = 0
449 let videoFilePath: string
450 let mimetype = 'video/mp4'
437 451
438 if (attributes.scheduleUpdate.privacy) { 452 if (attributes.fixture) {
439 req.field('scheduleUpdate[privacy]', attributes.scheduleUpdate.privacy) 453 videoFilePath = buildAbsoluteFixturePath(attributes.fixture)
454 size = (await stat(videoFilePath)).size
455
456 if (videoFilePath.endsWith('.mkv')) {
457 mimetype = 'video/x-matroska'
458 } else if (videoFilePath.endsWith('.webm')) {
459 mimetype = 'video/webm'
440 } 460 }
441 } 461 }
442 462
443 if (attributes.originallyPublishedAt !== undefined) { 463 const initializeSessionRes = await prepareResumableUpload({ url, token, attributes, size, mimetype })
444 req.field('originallyPublishedAt', attributes.originallyPublishedAt) 464 const initStatus = initializeSessionRes.status
465
466 if (videoFilePath && initStatus === HttpStatusCode.CREATED_201) {
467 const locationHeader = initializeSessionRes.header['location']
468 expect(locationHeader).to.not.be.undefined
469
470 const pathUploadId = locationHeader.split('?')[1]
471
472 return sendResumableChunks({ url, token, pathUploadId, videoFilePath, size, specialStatus })
445 } 473 }
446 474
447 const res = await req.attach('videofile', buildAbsoluteFixturePath(attributes.fixture)) 475 const expectedInitStatus = specialStatus === HttpStatusCode.OK_200
448 .expect(specialStatus) 476 ? HttpStatusCode.CREATED_201
477 : specialStatus
449 478
450 // Wait torrent generation 479 expect(initStatus).to.equal(expectedInitStatus)
451 if (specialStatus === HttpStatusCode.OK_200) {
452 let video: VideoDetails
453 do {
454 const resVideo = await getVideoWithToken(url, accessToken, res.body.video.uuid)
455 video = resVideo.body
456 480
457 await wait(50) 481 return initializeSessionRes
458 } while (!video.files[0].torrentUrl) 482}
483
484async function prepareResumableUpload (options: {
485 url: string
486 token: string
487 attributes: VideoAttributes
488 size: number
489 mimetype: string
490}) {
491 const { url, token, attributes, size, mimetype } = options
492
493 const path = '/api/v1/videos/upload-resumable'
494
495 const req = request(url)
496 .post(path)
497 .set('Authorization', 'Bearer ' + token)
498 .set('X-Upload-Content-Type', mimetype)
499 .set('X-Upload-Content-Length', size.toString())
500
501 buildUploadReq(req, attributes)
502
503 if (attributes.fixture) {
504 req.field('filename', attributes.fixture)
459 } 505 }
460 506
461 return res 507 return req
508}
509
510function sendResumableChunks (options: {
511 url: string
512 token: string
513 pathUploadId: string
514 videoFilePath: string
515 size: number
516 specialStatus?: HttpStatusCode
517 contentLength?: number
518 contentRangeBuilder?: (start: number, chunk: any) => string
519}) {
520 const { url, token, pathUploadId, videoFilePath, size, specialStatus, contentLength, contentRangeBuilder } = options
521
522 const expectedStatus = specialStatus || HttpStatusCode.OK_200
523
524 const path = '/api/v1/videos/upload-resumable'
525 let start = 0
526
527 const readable = createReadStream(videoFilePath, { highWaterMark: 8 * 1024 })
528 return new Promise<GotResponse>((resolve, reject) => {
529 readable.on('data', async function onData (chunk) {
530 readable.pause()
531
532 const headers = {
533 'Authorization': 'Bearer ' + token,
534 'Content-Type': 'application/octet-stream',
535 'Content-Range': contentRangeBuilder
536 ? contentRangeBuilder(start, chunk)
537 : `bytes ${start}-${start + chunk.length - 1}/${size}`,
538 'Content-Length': contentLength ? contentLength + '' : chunk.length + ''
539 }
540
541 const res = await got({
542 url,
543 method: 'put',
544 headers,
545 path: path + '?' + pathUploadId,
546 body: chunk,
547 responseType: 'json',
548 throwHttpErrors: false
549 })
550
551 start += chunk.length
552
553 if (res.statusCode === expectedStatus) {
554 return resolve(res)
555 }
556
557 if (res.statusCode !== HttpStatusCode.PERMANENT_REDIRECT_308) {
558 readable.off('data', onData)
559 return reject(new Error('Incorrect transient behaviour sending intermediary chunks'))
560 }
561
562 readable.resume()
563 })
564 })
462} 565}
463 566
464function updateVideo ( 567function updateVideo (
@@ -749,11 +852,13 @@ export {
749 getVideoWithToken, 852 getVideoWithToken,
750 getVideosList, 853 getVideosList,
751 removeAllVideos, 854 removeAllVideos,
855 checkUploadVideoParam,
752 getVideosListPagination, 856 getVideosListPagination,
753 getVideosListSort, 857 getVideosListSort,
754 removeVideo, 858 removeVideo,
755 getVideosListWithToken, 859 getVideosListWithToken,
756 uploadVideo, 860 uploadVideo,
861 sendResumableChunks,
757 getVideosWithFilters, 862 getVideosWithFilters,
758 uploadRandomVideoOnServers, 863 uploadRandomVideoOnServers,
759 updateVideo, 864 updateVideo,
@@ -767,5 +872,50 @@ export {
767 getMyVideosWithFilter, 872 getMyVideosWithFilter,
768 uploadVideoAndGetId, 873 uploadVideoAndGetId,
769 getLocalIdByUUID, 874 getLocalIdByUUID,
770 getVideoIdFromUUID 875 getVideoIdFromUUID,
876 prepareResumableUpload
877}
878
879// ---------------------------------------------------------------------------
880
881function buildUploadReq (req: request.Test, attributes: VideoAttributes) {
882
883 for (const key of [ 'name', 'support', 'channelId', 'description', 'originallyPublishedAt' ]) {
884 if (attributes[key] !== undefined) {
885 req.field(key, attributes[key])
886 }
887 }
888
889 for (const key of [ 'nsfw', 'commentsEnabled', 'downloadEnabled', 'waitTranscoding' ]) {
890 if (attributes[key] !== undefined) {
891 req.field(key, JSON.stringify(attributes[key]))
892 }
893 }
894
895 for (const key of [ 'language', 'privacy', 'category', 'licence' ]) {
896 if (attributes[key] !== undefined) {
897 req.field(key, attributes[key].toString())
898 }
899 }
900
901 const tags = attributes.tags || []
902 for (let i = 0; i < tags.length; i++) {
903 req.field('tags[' + i + ']', attributes.tags[i])
904 }
905
906 for (const key of [ 'thumbnailfile', 'previewfile' ]) {
907 if (attributes[key] !== undefined) {
908 req.attach(key, buildAbsoluteFixturePath(attributes[key]))
909 }
910 }
911
912 if (attributes.scheduleUpdate) {
913 if (attributes.scheduleUpdate.updateAt) {
914 req.field('scheduleUpdate[updateAt]', attributes.scheduleUpdate.updateAt)
915 }
916
917 if (attributes.scheduleUpdate.privacy) {
918 req.field('scheduleUpdate[privacy]', attributes.scheduleUpdate.privacy)
919 }
920 }
771} 921}
diff --git a/shared/models/activitypub/activitypub-actor.ts b/shared/models/activitypub/activitypub-actor.ts
index c59be3f3b..09d4f7402 100644
--- a/shared/models/activitypub/activitypub-actor.ts
+++ b/shared/models/activitypub/activitypub-actor.ts
@@ -29,4 +29,6 @@ export interface ActivityPubActor {
29 29
30 icon?: ActivityIconObject 30 icon?: ActivityIconObject
31 image?: ActivityIconObject 31 image?: ActivityIconObject
32
33 published?: string
32} 34}
diff --git a/shared/models/actors/account.model.ts b/shared/models/actors/account.model.ts
index 120dec271..f2138077e 100644
--- a/shared/models/actors/account.model.ts
+++ b/shared/models/actors/account.model.ts
@@ -5,6 +5,8 @@ export interface Account extends Actor {
5 displayName: string 5 displayName: string
6 description: string 6 description: string
7 7
8 updatedAt: Date | string
9
8 userId?: number 10 userId?: number
9} 11}
10 12
diff --git a/shared/models/actors/actor.model.ts b/shared/models/actors/actor.model.ts
index 7d9f35b10..fd0662331 100644
--- a/shared/models/actors/actor.model.ts
+++ b/shared/models/actors/actor.model.ts
@@ -8,6 +8,5 @@ export interface Actor {
8 followingCount: number 8 followingCount: number
9 followersCount: number 9 followersCount: number
10 createdAt: Date | string 10 createdAt: Date | string
11 updatedAt: Date | string
12 avatar?: ActorImage 11 avatar?: ActorImage
13} 12}
diff --git a/shared/models/actors/custom-page.model.ts b/shared/models/actors/custom-page.model.ts
new file mode 100644
index 000000000..1e33584c1
--- /dev/null
+++ b/shared/models/actors/custom-page.model.ts
@@ -0,0 +1,3 @@
1export interface CustomPage {
2 content: string
3}
diff --git a/shared/models/actors/index.ts b/shared/models/actors/index.ts
index 156f83248..e03f168cd 100644
--- a/shared/models/actors/index.ts
+++ b/shared/models/actors/index.ts
@@ -2,4 +2,5 @@ export * from './account.model'
2export * from './actor-image.model' 2export * from './actor-image.model'
3export * from './actor-image.type' 3export * from './actor-image.type'
4export * from './actor.model' 4export * from './actor.model'
5export * from './custom-page.model'
5export * from './follow.model' 6export * from './follow.model'
diff --git a/shared/models/custom-markup/custom-markup-data.model.ts b/shared/models/custom-markup/custom-markup-data.model.ts
new file mode 100644
index 000000000..af697428e
--- /dev/null
+++ b/shared/models/custom-markup/custom-markup-data.model.ts
@@ -0,0 +1,28 @@
1export type EmbedMarkupData = {
2 // Video or playlist uuid
3 uuid: string
4}
5
6export type VideoMiniatureMarkupData = {
7 // Video uuid
8 uuid: string
9}
10
11export type PlaylistMiniatureMarkupData = {
12 // Playlist uuid
13 uuid: string
14}
15
16export type ChannelMiniatureMarkupData = {
17 // Channel name (username)
18 name: string
19}
20
21export type VideosListMarkupData = {
22 title: string
23 description: string
24 sort: string
25 categoryOneOf: string // coma separated values
26 languageOneOf: string // coma separated values
27 count: string
28}
diff --git a/shared/models/custom-markup/index.ts b/shared/models/custom-markup/index.ts
new file mode 100644
index 000000000..2898dfa90
--- /dev/null
+++ b/shared/models/custom-markup/index.ts
@@ -0,0 +1 @@
export * from './custom-markup-data.model'
diff --git a/shared/models/index.ts b/shared/models/index.ts
index dff5fdf0e..4db1f234e 100644
--- a/shared/models/index.ts
+++ b/shared/models/index.ts
@@ -1,6 +1,7 @@
1export * from './activitypub' 1export * from './activitypub'
2export * from './actors' 2export * from './actors'
3export * from './moderation' 3export * from './moderation'
4export * from './custom-markup'
4export * from './bulk' 5export * from './bulk'
5export * from './redundancy' 6export * from './redundancy'
6export * from './users' 7export * from './users'
diff --git a/shared/models/nodeinfo/index.ts b/shared/models/nodeinfo/index.ts
new file mode 100644
index 000000000..faa64302a
--- /dev/null
+++ b/shared/models/nodeinfo/index.ts
@@ -0,0 +1 @@
export * from './nodeinfo.model'
diff --git a/shared/models/nodeinfo/index.d.ts b/shared/models/nodeinfo/nodeinfo.model.ts
index 336cb66d2..336cb66d2 100644
--- a/shared/models/nodeinfo/index.d.ts
+++ b/shared/models/nodeinfo/nodeinfo.model.ts
diff --git a/shared/models/overviews/index.ts b/shared/models/overviews/index.ts
index 376609efa..468507c6b 100644
--- a/shared/models/overviews/index.ts
+++ b/shared/models/overviews/index.ts
@@ -1 +1 @@
export * from './videos-overview' export * from './videos-overview.model'
diff --git a/shared/models/overviews/videos-overview.ts b/shared/models/overviews/videos-overview.model.ts
index 0f3cb4a52..0f3cb4a52 100644
--- a/shared/models/overviews/videos-overview.ts
+++ b/shared/models/overviews/videos-overview.model.ts
diff --git a/shared/models/plugins/client-hook.model.ts b/shared/models/plugins/client/client-hook.model.ts
index 620651051..620651051 100644
--- a/shared/models/plugins/client-hook.model.ts
+++ b/shared/models/plugins/client/client-hook.model.ts
diff --git a/shared/models/plugins/client/index.ts b/shared/models/plugins/client/index.ts
new file mode 100644
index 000000000..6dfc6351f
--- /dev/null
+++ b/shared/models/plugins/client/index.ts
@@ -0,0 +1,6 @@
1export * from './client-hook.model'
2export * from './plugin-client-scope.type'
3export * from './plugin-element-placeholder.type'
4export * from './register-client-form-field.model'
5export * from './register-client-hook.model'
6export * from './register-client-settings-script.model'
diff --git a/shared/models/plugins/plugin-client-scope.type.ts b/shared/models/plugins/client/plugin-client-scope.type.ts
index 8cc234ff2..8cc234ff2 100644
--- a/shared/models/plugins/plugin-client-scope.type.ts
+++ b/shared/models/plugins/client/plugin-client-scope.type.ts
diff --git a/shared/models/plugins/plugin-element-placeholder.type.ts b/shared/models/plugins/client/plugin-element-placeholder.type.ts
index 129099c62..129099c62 100644
--- a/shared/models/plugins/plugin-element-placeholder.type.ts
+++ b/shared/models/plugins/client/plugin-element-placeholder.type.ts
diff --git a/shared/models/plugins/register-client-form-field.model.ts b/shared/models/plugins/client/register-client-form-field.model.ts
index 2df071337..2df071337 100644
--- a/shared/models/plugins/register-client-form-field.model.ts
+++ b/shared/models/plugins/client/register-client-form-field.model.ts
diff --git a/shared/models/plugins/register-client-hook.model.ts b/shared/models/plugins/client/register-client-hook.model.ts
index 81047b21d..81047b21d 100644
--- a/shared/models/plugins/register-client-hook.model.ts
+++ b/shared/models/plugins/client/register-client-hook.model.ts
diff --git a/shared/models/plugins/register-client-settings-script.model.ts b/shared/models/plugins/client/register-client-settings-script.model.ts
index ac16af366..481ceef96 100644
--- a/shared/models/plugins/register-client-settings-script.model.ts
+++ b/shared/models/plugins/client/register-client-settings-script.model.ts
@@ -1,4 +1,4 @@
1import { RegisterServerSettingOptions } from "./register-server-setting.model" 1import { RegisterServerSettingOptions } from '../server'
2 2
3export interface RegisterClientSettingsScript { 3export interface RegisterClientSettingsScript {
4 isSettingHidden (options: { 4 isSettingHidden (options: {
diff --git a/shared/models/plugins/index.ts b/shared/models/plugins/index.ts
index 03b27f907..cbbe4916e 100644
--- a/shared/models/plugins/index.ts
+++ b/shared/models/plugins/index.ts
@@ -1,28 +1,6 @@
1export * from './client-hook.model' 1export * from './client'
2export * from './plugin-index'
3export * from './server'
2export * from './hook-type.enum' 4export * from './hook-type.enum'
3export * from './install-plugin.model'
4export * from './manage-plugin.model'
5export * from './peertube-plugin-index-list.model'
6export * from './peertube-plugin-index.model'
7export * from './peertube-plugin-latest-version.model'
8export * from './peertube-plugin.model'
9export * from './plugin-client-scope.type'
10export * from './plugin-element-placeholder.type'
11export * from './plugin-package-json.model' 5export * from './plugin-package-json.model'
12export * from './plugin-playlist-privacy-manager.model'
13export * from './plugin-settings-manager.model'
14export * from './plugin-storage-manager.model'
15export * from './plugin-transcoding-manager.model'
16export * from './plugin-translation.model'
17export * from './plugin-video-category-manager.model'
18export * from './plugin-video-language-manager.model'
19export * from './plugin-video-licence-manager.model'
20export * from './plugin-video-privacy-manager.model'
21export * from './plugin.type' 6export * from './plugin.type'
22export * from './public-server.setting'
23export * from './register-client-hook.model'
24export * from './register-client-settings-script.model'
25export * from './register-client-form-field.model'
26export * from './register-server-hook.model'
27export * from './register-server-setting.model'
28export * from './server-hook.model'
diff --git a/shared/models/plugins/plugin-index/index.ts b/shared/models/plugins/plugin-index/index.ts
new file mode 100644
index 000000000..913846638
--- /dev/null
+++ b/shared/models/plugins/plugin-index/index.ts
@@ -0,0 +1,3 @@
1export * from './peertube-plugin-index-list.model'
2export * from './peertube-plugin-index.model'
3export * from './peertube-plugin-latest-version.model'
diff --git a/shared/models/plugins/peertube-plugin-index-list.model.ts b/shared/models/plugins/plugin-index/peertube-plugin-index-list.model.ts
index 817bac31e..ecb46482e 100644
--- a/shared/models/plugins/peertube-plugin-index-list.model.ts
+++ b/shared/models/plugins/plugin-index/peertube-plugin-index-list.model.ts
@@ -1,4 +1,4 @@
1import { PluginType } from './plugin.type' 1import { PluginType } from '../plugin.type'
2 2
3export interface PeertubePluginIndexList { 3export interface PeertubePluginIndexList {
4 start: number 4 start: number
diff --git a/shared/models/plugins/peertube-plugin-index.model.ts b/shared/models/plugins/plugin-index/peertube-plugin-index.model.ts
index e91c8b4dc..e91c8b4dc 100644
--- a/shared/models/plugins/peertube-plugin-index.model.ts
+++ b/shared/models/plugins/plugin-index/peertube-plugin-index.model.ts
diff --git a/shared/models/plugins/peertube-plugin-latest-version.model.ts b/shared/models/plugins/plugin-index/peertube-plugin-latest-version.model.ts
index 811a64429..811a64429 100644
--- a/shared/models/plugins/peertube-plugin-latest-version.model.ts
+++ b/shared/models/plugins/plugin-index/peertube-plugin-latest-version.model.ts
diff --git a/shared/models/plugins/plugin-package-json.model.ts b/shared/models/plugins/plugin-package-json.model.ts
index c26e9ae5b..b2f92af80 100644
--- a/shared/models/plugins/plugin-package-json.model.ts
+++ b/shared/models/plugins/plugin-package-json.model.ts
@@ -1,4 +1,4 @@
1import { PluginClientScope } from './plugin-client-scope.type' 1import { PluginClientScope } from './client/plugin-client-scope.type'
2 2
3export type PluginTranslationPaths = { 3export type PluginTranslationPaths = {
4 [ locale: string ]: string 4 [ locale: string ]: string
diff --git a/shared/models/plugins/server/api/index.ts b/shared/models/plugins/server/api/index.ts
new file mode 100644
index 000000000..eb59a03f0
--- /dev/null
+++ b/shared/models/plugins/server/api/index.ts
@@ -0,0 +1,3 @@
1export * from './install-plugin.model'
2export * from './manage-plugin.model'
3export * from './peertube-plugin.model'
diff --git a/shared/models/plugins/install-plugin.model.ts b/shared/models/plugins/server/api/install-plugin.model.ts
index 5a268ebe1..5a268ebe1 100644
--- a/shared/models/plugins/install-plugin.model.ts
+++ b/shared/models/plugins/server/api/install-plugin.model.ts
diff --git a/shared/models/plugins/manage-plugin.model.ts b/shared/models/plugins/server/api/manage-plugin.model.ts
index 612b3056c..612b3056c 100644
--- a/shared/models/plugins/manage-plugin.model.ts
+++ b/shared/models/plugins/server/api/manage-plugin.model.ts
diff --git a/shared/models/plugins/peertube-plugin.model.ts b/shared/models/plugins/server/api/peertube-plugin.model.ts
index 2b0bb8cfa..54c383f57 100644
--- a/shared/models/plugins/peertube-plugin.model.ts
+++ b/shared/models/plugins/server/api/peertube-plugin.model.ts
@@ -1,4 +1,4 @@
1import { PluginType } from './plugin.type' 1import { PluginType } from '../../plugin.type'
2 2
3export interface PeerTubePlugin { 3export interface PeerTubePlugin {
4 name: string 4 name: string
diff --git a/shared/models/plugins/server/index.ts b/shared/models/plugins/server/index.ts
new file mode 100644
index 000000000..d3ff49d3b
--- /dev/null
+++ b/shared/models/plugins/server/index.ts
@@ -0,0 +1,6 @@
1export * from './api'
2export * from './managers'
3export * from './settings'
4export * from './plugin-translation.model'
5export * from './register-server-hook.model'
6export * from './server-hook.model'
diff --git a/shared/models/plugins/server/managers/index.ts b/shared/models/plugins/server/managers/index.ts
new file mode 100644
index 000000000..49365a854
--- /dev/null
+++ b/shared/models/plugins/server/managers/index.ts
@@ -0,0 +1,9 @@
1
2export * from './plugin-playlist-privacy-manager.model'
3export * from './plugin-settings-manager.model'
4export * from './plugin-storage-manager.model'
5export * from './plugin-transcoding-manager.model'
6export * from './plugin-video-category-manager.model'
7export * from './plugin-video-language-manager.model'
8export * from './plugin-video-licence-manager.model'
9export * from './plugin-video-privacy-manager.model'
diff --git a/shared/models/plugins/plugin-playlist-privacy-manager.model.ts b/shared/models/plugins/server/managers/plugin-playlist-privacy-manager.model.ts
index d1823ef4e..4703c0a8b 100644
--- a/shared/models/plugins/plugin-playlist-privacy-manager.model.ts
+++ b/shared/models/plugins/server/managers/plugin-playlist-privacy-manager.model.ts
@@ -1,4 +1,4 @@
1import { VideoPlaylistPrivacy } from '../videos/playlist/video-playlist-privacy.model' 1import { VideoPlaylistPrivacy } from '../../../videos/playlist/video-playlist-privacy.model'
2 2
3export interface PluginPlaylistPrivacyManager { 3export interface PluginPlaylistPrivacyManager {
4 // PUBLIC = 1, 4 // PUBLIC = 1,
diff --git a/shared/models/plugins/plugin-settings-manager.model.ts b/shared/models/plugins/server/managers/plugin-settings-manager.model.ts
index 3c28c0565..3c28c0565 100644
--- a/shared/models/plugins/plugin-settings-manager.model.ts
+++ b/shared/models/plugins/server/managers/plugin-settings-manager.model.ts
diff --git a/shared/models/plugins/plugin-storage-manager.model.ts b/shared/models/plugins/server/managers/plugin-storage-manager.model.ts
index 51567044a..51567044a 100644
--- a/shared/models/plugins/plugin-storage-manager.model.ts
+++ b/shared/models/plugins/server/managers/plugin-storage-manager.model.ts
diff --git a/shared/models/plugins/plugin-transcoding-manager.model.ts b/shared/models/plugins/server/managers/plugin-transcoding-manager.model.ts
index 8babccd4e..a0422a460 100644
--- a/shared/models/plugins/plugin-transcoding-manager.model.ts
+++ b/shared/models/plugins/server/managers/plugin-transcoding-manager.model.ts
@@ -1,4 +1,4 @@
1import { EncoderOptionsBuilder } from '../videos/video-transcoding.model' 1import { EncoderOptionsBuilder } from '../../../videos/video-transcoding.model'
2 2
3export interface PluginTranscodingManager { 3export interface PluginTranscodingManager {
4 addLiveProfile (encoder: string, profile: string, builder: EncoderOptionsBuilder): boolean 4 addLiveProfile (encoder: string, profile: string, builder: EncoderOptionsBuilder): boolean
diff --git a/shared/models/plugins/plugin-video-category-manager.model.ts b/shared/models/plugins/server/managers/plugin-video-category-manager.model.ts
index 201bfa979..201bfa979 100644
--- a/shared/models/plugins/plugin-video-category-manager.model.ts
+++ b/shared/models/plugins/server/managers/plugin-video-category-manager.model.ts
diff --git a/shared/models/plugins/plugin-video-language-manager.model.ts b/shared/models/plugins/server/managers/plugin-video-language-manager.model.ts
index 3fd577a79..3fd577a79 100644
--- a/shared/models/plugins/plugin-video-language-manager.model.ts
+++ b/shared/models/plugins/server/managers/plugin-video-language-manager.model.ts
diff --git a/shared/models/plugins/plugin-video-licence-manager.model.ts b/shared/models/plugins/server/managers/plugin-video-licence-manager.model.ts
index 82a634d3a..82a634d3a 100644
--- a/shared/models/plugins/plugin-video-licence-manager.model.ts
+++ b/shared/models/plugins/server/managers/plugin-video-licence-manager.model.ts
diff --git a/shared/models/plugins/plugin-video-privacy-manager.model.ts b/shared/models/plugins/server/managers/plugin-video-privacy-manager.model.ts
index 3ada99608..7717115e3 100644
--- a/shared/models/plugins/plugin-video-privacy-manager.model.ts
+++ b/shared/models/plugins/server/managers/plugin-video-privacy-manager.model.ts
@@ -1,4 +1,4 @@
1import { VideoPrivacy } from '../videos/video-privacy.enum' 1import { VideoPrivacy } from '../../../videos/video-privacy.enum'
2 2
3export interface PluginVideoPrivacyManager { 3export interface PluginVideoPrivacyManager {
4 // PUBLIC = 1 4 // PUBLIC = 1
diff --git a/shared/models/plugins/plugin-translation.model.ts b/shared/models/plugins/server/plugin-translation.model.ts
index a2dd8e560..a2dd8e560 100644
--- a/shared/models/plugins/plugin-translation.model.ts
+++ b/shared/models/plugins/server/plugin-translation.model.ts
diff --git a/shared/models/plugins/register-server-hook.model.ts b/shared/models/plugins/server/register-server-hook.model.ts
index 746fdc329..746fdc329 100644
--- a/shared/models/plugins/register-server-hook.model.ts
+++ b/shared/models/plugins/server/register-server-hook.model.ts
diff --git a/shared/models/plugins/server-hook.model.ts b/shared/models/plugins/server/server-hook.model.ts
index 88277af5a..88277af5a 100644
--- a/shared/models/plugins/server-hook.model.ts
+++ b/shared/models/plugins/server/server-hook.model.ts
diff --git a/shared/models/plugins/server/settings/index.ts b/shared/models/plugins/server/settings/index.ts
new file mode 100644
index 000000000..b456de019
--- /dev/null
+++ b/shared/models/plugins/server/settings/index.ts
@@ -0,0 +1,2 @@
1export * from './public-server.setting'
2export * from './register-server-setting.model'
diff --git a/shared/models/plugins/public-server.setting.ts b/shared/models/plugins/server/settings/public-server.setting.ts
index 9802c4d7d..9802c4d7d 100644
--- a/shared/models/plugins/public-server.setting.ts
+++ b/shared/models/plugins/server/settings/public-server.setting.ts
diff --git a/shared/models/plugins/register-server-setting.model.ts b/shared/models/plugins/server/settings/register-server-setting.model.ts
index 9f45c3c37..d9a798cac 100644
--- a/shared/models/plugins/register-server-setting.model.ts
+++ b/shared/models/plugins/server/settings/register-server-setting.model.ts
@@ -1,4 +1,4 @@
1import { RegisterClientFormFieldOptions } from './register-client-form-field.model' 1import { RegisterClientFormFieldOptions } from '../../client'
2 2
3export type RegisterServerSettingOptions = RegisterClientFormFieldOptions & { 3export type RegisterServerSettingOptions = RegisterClientFormFieldOptions & {
4 // If the setting is not private, anyone can view its value (client code included) 4 // If the setting is not private, anyone can view its value (client code included)
diff --git a/shared/models/redundancy/index.ts b/shared/models/redundancy/index.ts
index 649cc489f..641a5d625 100644
--- a/shared/models/redundancy/index.ts
+++ b/shared/models/redundancy/index.ts
@@ -1,3 +1,4 @@
1export * from './videos-redundancy-strategy.model'
2export * from './video-redundancies-filters.model' 1export * from './video-redundancies-filters.model'
2export * from './video-redundancy-config-filter.type'
3export * from './video-redundancy.model' 3export * from './video-redundancy.model'
4export * from './videos-redundancy-strategy.model'
diff --git a/shared/models/search/boolean-both-query.model.ts b/shared/models/search/boolean-both-query.model.ts
index 57b0e8d44..d6a438249 100644
--- a/shared/models/search/boolean-both-query.model.ts
+++ b/shared/models/search/boolean-both-query.model.ts
@@ -1 +1,2 @@
1export type BooleanBothQuery = 'true' | 'false' | 'both' 1export type BooleanBothQuery = 'true' | 'false' | 'both'
2export type BooleanQuery = 'true' | 'false'
diff --git a/shared/models/server/debug.model.ts b/shared/models/server/debug.model.ts
index 61cba6518..7ceff9137 100644
--- a/shared/models/server/debug.model.ts
+++ b/shared/models/server/debug.model.ts
@@ -1,3 +1,7 @@
1export interface Debug { 1export interface Debug {
2 ip: string 2 ip: string
3} 3}
4
5export interface SendDebugCommand {
6 command: 'remove-dandling-resumable-uploads'
7}
diff --git a/shared/models/server/server-config.model.ts b/shared/models/server/server-config.model.ts
index 85d84af44..1667bc0e2 100644
--- a/shared/models/server/server-config.model.ts
+++ b/shared/models/server/server-config.model.ts
@@ -214,4 +214,10 @@ export interface ServerConfig {
214 level: BroadcastMessageLevel 214 level: BroadcastMessageLevel
215 dismissable: boolean 215 dismissable: boolean
216 } 216 }
217
218 homepage: {
219 enabled: boolean
220 }
217} 221}
222
223export type HTMLServerConfig = Omit<ServerConfig, 'signup'>
diff --git a/shared/models/server/server-error-code.enum.ts b/shared/models/server/server-error-code.enum.ts
index c02b0e6c7..d17d958be 100644
--- a/shared/models/server/server-error-code.enum.ts
+++ b/shared/models/server/server-error-code.enum.ts
@@ -2,4 +2,5 @@ export const enum ServerErrorCode {
2 DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS = 1, 2 DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS = 1,
3 MAX_INSTANCE_LIVES_LIMIT_REACHED = 2, 3 MAX_INSTANCE_LIVES_LIMIT_REACHED = 2,
4 MAX_USER_LIVES_LIMIT_REACHED = 3, 4 MAX_USER_LIVES_LIMIT_REACHED = 3,
5 INCORRECT_FILES_IN_TORRENT = 4
5} 6}
diff --git a/shared/models/users/user-right.enum.ts b/shared/models/users/user-right.enum.ts
index bbedc9f00..950b22bad 100644
--- a/shared/models/users/user-right.enum.ts
+++ b/shared/models/users/user-right.enum.ts
@@ -16,6 +16,7 @@ export const enum UserRight {
16 MANAGE_JOBS, 16 MANAGE_JOBS,
17 17
18 MANAGE_CONFIGURATION, 18 MANAGE_CONFIGURATION,
19 MANAGE_INSTANCE_CUSTOM_PAGE,
19 20
20 MANAGE_ACCOUNTS_BLOCKLIST, 21 MANAGE_ACCOUNTS_BLOCKLIST,
21 MANAGE_SERVERS_BLOCKLIST, 22 MANAGE_SERVERS_BLOCKLIST,
diff --git a/shared/models/videos/change-ownership/index.ts b/shared/models/videos/change-ownership/index.ts
new file mode 100644
index 000000000..a942fb2cd
--- /dev/null
+++ b/shared/models/videos/change-ownership/index.ts
@@ -0,0 +1,3 @@
1export * from './video-change-ownership-accept.model'
2export * from './video-change-ownership-create.model'
3export * from './video-change-ownership.model'
diff --git a/shared/models/videos/video-change-ownership-accept.model.ts b/shared/models/videos/change-ownership/video-change-ownership-accept.model.ts
index f27247633..f27247633 100644
--- a/shared/models/videos/video-change-ownership-accept.model.ts
+++ b/shared/models/videos/change-ownership/video-change-ownership-accept.model.ts
diff --git a/shared/models/videos/video-change-ownership-create.model.ts b/shared/models/videos/change-ownership/video-change-ownership-create.model.ts
index 40fcca285..40fcca285 100644
--- a/shared/models/videos/video-change-ownership-create.model.ts
+++ b/shared/models/videos/change-ownership/video-change-ownership-create.model.ts
diff --git a/shared/models/videos/video-change-ownership.model.ts b/shared/models/videos/change-ownership/video-change-ownership.model.ts
index 669c7f3e7..3d31cad0a 100644
--- a/shared/models/videos/video-change-ownership.model.ts
+++ b/shared/models/videos/change-ownership/video-change-ownership.model.ts
@@ -1,5 +1,5 @@
1import { Account } from '../actors' 1import { Account } from '../../actors'
2import { Video } from './video.model' 2import { Video } from '../video.model'
3 3
4export interface VideoChangeOwnership { 4export interface VideoChangeOwnership {
5 id: number 5 id: number
diff --git a/shared/models/videos/channel/video-channel.model.ts b/shared/models/videos/channel/video-channel.model.ts
index 56517972d..5393f924d 100644
--- a/shared/models/videos/channel/video-channel.model.ts
+++ b/shared/models/videos/channel/video-channel.model.ts
@@ -11,6 +11,9 @@ export interface VideoChannel extends Actor {
11 description: string 11 description: string
12 support: string 12 support: string
13 isLocal: boolean 13 isLocal: boolean
14
15 updatedAt: Date | string
16
14 ownerAccount?: Account 17 ownerAccount?: Account
15 18
16 videosCount?: number 19 videosCount?: number
diff --git a/shared/models/videos/comment/index.ts b/shared/models/videos/comment/index.ts
new file mode 100644
index 000000000..7b9261a36
--- /dev/null
+++ b/shared/models/videos/comment/index.ts
@@ -0,0 +1 @@
export * from './video-comment.model'
diff --git a/shared/models/videos/video-comment.model.ts b/shared/models/videos/comment/video-comment.model.ts
index 9730a3f76..79c0e4c0a 100644
--- a/shared/models/videos/video-comment.model.ts
+++ b/shared/models/videos/comment/video-comment.model.ts
@@ -1,4 +1,4 @@
1import { Account } from '../actors' 1import { Account } from '../../actors'
2 2
3export interface VideoComment { 3export interface VideoComment {
4 id: number 4 id: number
diff --git a/shared/models/videos/index.ts b/shared/models/videos/index.ts
index fac3e0b2f..64f2c9df6 100644
--- a/shared/models/videos/index.ts
+++ b/shared/models/videos/index.ts
@@ -1,6 +1,8 @@
1export * from './blacklist' 1export * from './blacklist'
2export * from './caption' 2export * from './caption'
3export * from './change-ownership'
3export * from './channel' 4export * from './channel'
5export * from './comment'
4export * from './live' 6export * from './live'
5export * from './import' 7export * from './import'
6export * from './playlist' 8export * from './playlist'
@@ -10,17 +12,11 @@ export * from './nsfw-policy.type'
10 12
11export * from './thumbnail.type' 13export * from './thumbnail.type'
12 14
13export * from './video-change-ownership-accept.model'
14export * from './video-change-ownership-create.model'
15export * from './video-change-ownership.model'
16
17export * from './video-comment.model'
18export * from './video-constant.model' 15export * from './video-constant.model'
19export * from './video-create.model' 16export * from './video-create.model'
20export * from './video-file-metadata'
21export * from './video-file.model'
22 17
23export * from './live/live-video.model' 18export * from './video-file-metadata.model'
19export * from './video-file.model'
24 20
25export * from './video-privacy.enum' 21export * from './video-privacy.enum'
26export * from './video-query.type' 22export * from './video-query.type'
diff --git a/shared/models/videos/video-file-metadata.ts b/shared/models/videos/video-file-metadata.model.ts
index 8f527c0a7..8f527c0a7 100644
--- a/shared/models/videos/video-file-metadata.ts
+++ b/shared/models/videos/video-file-metadata.model.ts
diff --git a/shared/models/videos/video-file.model.ts b/shared/models/videos/video-file.model.ts
index 1e830b19c..28fce0aaf 100644
--- a/shared/models/videos/video-file.model.ts
+++ b/shared/models/videos/video-file.model.ts
@@ -1,5 +1,5 @@
1import { VideoConstant } from './video-constant.model' 1import { VideoConstant } from './video-constant.model'
2import { VideoFileMetadata } from './video-file-metadata' 2import { VideoFileMetadata } from './video-file-metadata.model'
3import { VideoResolution } from './video-resolution.enum' 3import { VideoResolution } from './video-resolution.enum'
4 4
5export interface VideoFile { 5export interface VideoFile {