diff options
15 files changed, 469 insertions, 226 deletions
diff --git a/scripts/ci.sh b/scripts/ci.sh index 07e37e0ee..7862888b8 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh | |||
@@ -47,11 +47,12 @@ if [ "$1" = "client" ]; then | |||
47 | 47 | ||
48 | feedsFiles=$(findTestFiles ./dist/server/tests/feeds) | 48 | feedsFiles=$(findTestFiles ./dist/server/tests/feeds) |
49 | helperFiles=$(findTestFiles ./dist/server/tests/helpers) | 49 | helperFiles=$(findTestFiles ./dist/server/tests/helpers) |
50 | libFiles=$(findTestFiles ./dist/server/tests/lib) | ||
50 | miscFiles="./dist/server/tests/client.js ./dist/server/tests/misc-endpoints.js" | 51 | miscFiles="./dist/server/tests/client.js ./dist/server/tests/misc-endpoints.js" |
51 | # Not in plugin task, it needs an index.html | 52 | # Not in plugin task, it needs an index.html |
52 | pluginFiles="./dist/server/tests/plugins/html-injection.js" | 53 | pluginFiles="./dist/server/tests/plugins/html-injection.js" |
53 | 54 | ||
54 | MOCHA_PARALLEL=true runTest "$1" 2 $feedsFiles $helperFiles $miscFiles $pluginFiles | 55 | MOCHA_PARALLEL=true runTest "$1" 2 $feedsFiles $helperFiles $miscFiles $pluginFiles $libFiles |
55 | elif [ "$1" = "cli-plugin" ]; then | 56 | elif [ "$1" = "cli-plugin" ]; then |
56 | npm run build:server | 57 | npm run build:server |
57 | npm run setup:cli | 58 | npm run setup:cli |
diff --git a/server/lib/plugins/register-helpers.ts b/server/lib/plugins/register-helpers.ts index 09275f9ba..af533effd 100644 --- a/server/lib/plugins/register-helpers.ts +++ b/server/lib/plugins/register-helpers.ts | |||
@@ -1,13 +1,7 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { logger } from '@server/helpers/logger' | 2 | import { logger } from '@server/helpers/logger' |
3 | import { | ||
4 | VIDEO_CATEGORIES, | ||
5 | VIDEO_LANGUAGES, | ||
6 | VIDEO_LICENCES, | ||
7 | VIDEO_PLAYLIST_PRIVACIES, | ||
8 | VIDEO_PRIVACIES | ||
9 | } from '@server/initializers/constants' | ||
10 | import { onExternalUserAuthenticated } from '@server/lib/auth/external-auth' | 3 | import { onExternalUserAuthenticated } from '@server/lib/auth/external-auth' |
4 | import { VideoConstantManagerFactory } from '@server/lib/plugins/video-constant-manager-factory' | ||
11 | import { PluginModel } from '@server/models/server/plugin' | 5 | import { PluginModel } from '@server/models/server/plugin' |
12 | import { | 6 | import { |
13 | RegisterServerAuthExternalOptions, | 7 | RegisterServerAuthExternalOptions, |
@@ -18,41 +12,18 @@ import { | |||
18 | } from '@server/types/plugins' | 12 | } from '@server/types/plugins' |
19 | import { | 13 | import { |
20 | EncoderOptionsBuilder, | 14 | EncoderOptionsBuilder, |
21 | PluginPlaylistPrivacyManager, | ||
22 | PluginSettingsManager, | 15 | PluginSettingsManager, |
23 | PluginStorageManager, | 16 | PluginStorageManager, |
24 | PluginVideoCategoryManager, | ||
25 | PluginVideoLanguageManager, | ||
26 | PluginVideoLicenceManager, | ||
27 | PluginVideoPrivacyManager, | ||
28 | RegisterServerHookOptions, | 17 | RegisterServerHookOptions, |
29 | RegisterServerSettingOptions, | 18 | RegisterServerSettingOptions, |
30 | serverHookObject | 19 | serverHookObject, |
20 | VideoPlaylistPrivacy, | ||
21 | VideoPrivacy | ||
31 | } from '@shared/models' | 22 | } from '@shared/models' |
32 | import { VideoTranscodingProfilesManager } from '../transcoding/video-transcoding-profiles' | 23 | import { VideoTranscodingProfilesManager } from '../transcoding/video-transcoding-profiles' |
33 | import { buildPluginHelpers } from './plugin-helpers-builder' | 24 | import { buildPluginHelpers } from './plugin-helpers-builder' |
34 | 25 | ||
35 | type AlterableVideoConstant = 'language' | 'licence' | 'category' | 'privacy' | 'playlistPrivacy' | ||
36 | type VideoConstant = { [key in number | string]: string } | ||
37 | |||
38 | type UpdatedVideoConstant = { | ||
39 | [name in AlterableVideoConstant]: { | ||
40 | [ npmName: string]: { | ||
41 | added: { key: number | string, label: string }[] | ||
42 | deleted: { key: number | string, label: string }[] | ||
43 | } | ||
44 | } | ||
45 | } | ||
46 | |||
47 | export class RegisterHelpers { | 26 | export class RegisterHelpers { |
48 | private readonly updatedVideoConstants: UpdatedVideoConstant = { | ||
49 | playlistPrivacy: { }, | ||
50 | privacy: { }, | ||
51 | language: { }, | ||
52 | licence: { }, | ||
53 | category: { } | ||
54 | } | ||
55 | |||
56 | private readonly transcodingProfiles: { | 27 | private readonly transcodingProfiles: { |
57 | [ npmName: string ]: { | 28 | [ npmName: string ]: { |
58 | type: 'vod' | 'live' | 29 | type: 'vod' | 'live' |
@@ -78,6 +49,7 @@ export class RegisterHelpers { | |||
78 | private readonly onSettingsChangeCallbacks: ((settings: any) => Promise<any>)[] = [] | 49 | private readonly onSettingsChangeCallbacks: ((settings: any) => Promise<any>)[] = [] |
79 | 50 | ||
80 | private readonly router: express.Router | 51 | private readonly router: express.Router |
52 | private readonly videoConstantManagerFactory: VideoConstantManagerFactory | ||
81 | 53 | ||
82 | constructor ( | 54 | constructor ( |
83 | private readonly npmName: string, | 55 | private readonly npmName: string, |
@@ -85,6 +57,7 @@ export class RegisterHelpers { | |||
85 | private readonly onHookAdded: (options: RegisterServerHookOptions) => void | 57 | private readonly onHookAdded: (options: RegisterServerHookOptions) => void |
86 | ) { | 58 | ) { |
87 | this.router = express.Router() | 59 | this.router = express.Router() |
60 | this.videoConstantManagerFactory = new VideoConstantManagerFactory(this.npmName) | ||
88 | } | 61 | } |
89 | 62 | ||
90 | buildRegisterHelpers (): RegisterServerOptions { | 63 | buildRegisterHelpers (): RegisterServerOptions { |
@@ -96,13 +69,13 @@ export class RegisterHelpers { | |||
96 | const settingsManager = this.buildSettingsManager() | 69 | const settingsManager = this.buildSettingsManager() |
97 | const storageManager = this.buildStorageManager() | 70 | const storageManager = this.buildStorageManager() |
98 | 71 | ||
99 | const videoLanguageManager = this.buildVideoLanguageManager() | 72 | const videoLanguageManager = this.videoConstantManagerFactory.createVideoConstantManager<string>('language') |
100 | 73 | ||
101 | const videoLicenceManager = this.buildVideoLicenceManager() | 74 | const videoLicenceManager = this.videoConstantManagerFactory.createVideoConstantManager<number>('licence') |
102 | const videoCategoryManager = this.buildVideoCategoryManager() | 75 | const videoCategoryManager = this.videoConstantManagerFactory.createVideoConstantManager<number>('category') |
103 | 76 | ||
104 | const videoPrivacyManager = this.buildVideoPrivacyManager() | 77 | const videoPrivacyManager = this.videoConstantManagerFactory.createVideoConstantManager<VideoPrivacy>('privacy') |
105 | const playlistPrivacyManager = this.buildPlaylistPrivacyManager() | 78 | const playlistPrivacyManager = this.videoConstantManagerFactory.createVideoConstantManager<VideoPlaylistPrivacy>('playlistPrivacy') |
106 | 79 | ||
107 | const transcodingManager = this.buildTranscodingManager() | 80 | const transcodingManager = this.buildTranscodingManager() |
108 | 81 | ||
@@ -122,12 +95,38 @@ export class RegisterHelpers { | |||
122 | settingsManager, | 95 | settingsManager, |
123 | storageManager, | 96 | storageManager, |
124 | 97 | ||
125 | videoLanguageManager, | 98 | videoLanguageManager: { |
126 | videoCategoryManager, | 99 | ...videoLanguageManager, |
127 | videoLicenceManager, | 100 | /** @deprecated use `addConstant` instead **/ |
101 | addLanguage: videoLanguageManager.addConstant, | ||
102 | /** @deprecated use `deleteConstant` instead **/ | ||
103 | deleteLanguage: videoLanguageManager.deleteConstant | ||
104 | }, | ||
105 | videoCategoryManager: { | ||
106 | ...videoCategoryManager, | ||
107 | /** @deprecated use `addConstant` instead **/ | ||
108 | addCategory: videoCategoryManager.addConstant, | ||
109 | /** @deprecated use `deleteConstant` instead **/ | ||
110 | deleteCategory: videoCategoryManager.deleteConstant | ||
111 | }, | ||
112 | videoLicenceManager: { | ||
113 | ...videoLicenceManager, | ||
114 | /** @deprecated use `addConstant` instead **/ | ||
115 | addLicence: videoLicenceManager.addConstant, | ||
116 | /** @deprecated use `deleteConstant` instead **/ | ||
117 | deleteLicence: videoLicenceManager.deleteConstant | ||
118 | }, | ||
128 | 119 | ||
129 | videoPrivacyManager, | 120 | videoPrivacyManager: { |
130 | playlistPrivacyManager, | 121 | ...videoPrivacyManager, |
122 | /** @deprecated use `deleteConstant` instead **/ | ||
123 | deletePrivacy: videoPrivacyManager.deleteConstant | ||
124 | }, | ||
125 | playlistPrivacyManager: { | ||
126 | ...playlistPrivacyManager, | ||
127 | /** @deprecated use `deleteConstant` instead **/ | ||
128 | deletePlaylistPrivacy: playlistPrivacyManager.deleteConstant | ||
129 | }, | ||
131 | 130 | ||
132 | transcodingManager, | 131 | transcodingManager, |
133 | 132 | ||
@@ -141,29 +140,7 @@ export class RegisterHelpers { | |||
141 | } | 140 | } |
142 | 141 | ||
143 | reinitVideoConstants (npmName: string) { | 142 | reinitVideoConstants (npmName: string) { |
144 | const hash = { | 143 | this.videoConstantManagerFactory.resetVideoConstants(npmName) |
145 | language: VIDEO_LANGUAGES, | ||
146 | licence: VIDEO_LICENCES, | ||
147 | category: VIDEO_CATEGORIES, | ||
148 | privacy: VIDEO_PRIVACIES, | ||
149 | playlistPrivacy: VIDEO_PLAYLIST_PRIVACIES | ||
150 | } | ||
151 | const types: AlterableVideoConstant[] = [ 'language', 'licence', 'category', 'privacy', 'playlistPrivacy' ] | ||
152 | |||
153 | for (const type of types) { | ||
154 | const updatedConstants = this.updatedVideoConstants[type][npmName] | ||
155 | if (!updatedConstants) continue | ||
156 | |||
157 | for (const added of updatedConstants.added) { | ||
158 | delete hash[type][added.key] | ||
159 | } | ||
160 | |||
161 | for (const deleted of updatedConstants.deleted) { | ||
162 | hash[type][deleted.key] = deleted.label | ||
163 | } | ||
164 | |||
165 | delete this.updatedVideoConstants[type][npmName] | ||
166 | } | ||
167 | } | 144 | } |
168 | 145 | ||
169 | reinitTranscodingProfilesAndEncoders (npmName: string) { | 146 | reinitTranscodingProfilesAndEncoders (npmName: string) { |
@@ -291,119 +268,6 @@ export class RegisterHelpers { | |||
291 | } | 268 | } |
292 | } | 269 | } |
293 | 270 | ||
294 | private buildVideoLanguageManager (): PluginVideoLanguageManager { | ||
295 | return { | ||
296 | addLanguage: (key: string, label: string) => { | ||
297 | return this.addConstant({ npmName: this.npmName, type: 'language', obj: VIDEO_LANGUAGES, key, label }) | ||
298 | }, | ||
299 | |||
300 | deleteLanguage: (key: string) => { | ||
301 | return this.deleteConstant({ npmName: this.npmName, type: 'language', obj: VIDEO_LANGUAGES, key }) | ||
302 | } | ||
303 | } | ||
304 | } | ||
305 | |||
306 | private buildVideoCategoryManager (): PluginVideoCategoryManager { | ||
307 | return { | ||
308 | addCategory: (key: number, label: string) => { | ||
309 | return this.addConstant({ npmName: this.npmName, type: 'category', obj: VIDEO_CATEGORIES, key, label }) | ||
310 | }, | ||
311 | |||
312 | deleteCategory: (key: number) => { | ||
313 | return this.deleteConstant({ npmName: this.npmName, type: 'category', obj: VIDEO_CATEGORIES, key }) | ||
314 | } | ||
315 | } | ||
316 | } | ||
317 | |||
318 | private buildVideoPrivacyManager (): PluginVideoPrivacyManager { | ||
319 | return { | ||
320 | deletePrivacy: (key: number) => { | ||
321 | return this.deleteConstant({ npmName: this.npmName, type: 'privacy', obj: VIDEO_PRIVACIES, key }) | ||
322 | } | ||
323 | } | ||
324 | } | ||
325 | |||
326 | private buildPlaylistPrivacyManager (): PluginPlaylistPrivacyManager { | ||
327 | return { | ||
328 | deletePlaylistPrivacy: (key: number) => { | ||
329 | return this.deleteConstant({ npmName: this.npmName, type: 'playlistPrivacy', obj: VIDEO_PLAYLIST_PRIVACIES, key }) | ||
330 | } | ||
331 | } | ||
332 | } | ||
333 | |||
334 | private buildVideoLicenceManager (): PluginVideoLicenceManager { | ||
335 | return { | ||
336 | addLicence: (key: number, label: string) => { | ||
337 | return this.addConstant({ npmName: this.npmName, type: 'licence', obj: VIDEO_LICENCES, key, label }) | ||
338 | }, | ||
339 | |||
340 | deleteLicence: (key: number) => { | ||
341 | return this.deleteConstant({ npmName: this.npmName, type: 'licence', obj: VIDEO_LICENCES, key }) | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | |||
346 | private addConstant<T extends string | number> (parameters: { | ||
347 | npmName: string | ||
348 | type: AlterableVideoConstant | ||
349 | obj: VideoConstant | ||
350 | key: T | ||
351 | label: string | ||
352 | }) { | ||
353 | const { npmName, type, obj, key, label } = parameters | ||
354 | |||
355 | if (obj[key]) { | ||
356 | logger.warn('Cannot add %s %s by plugin %s: key already exists.', type, npmName, key) | ||
357 | return false | ||
358 | } | ||
359 | |||
360 | if (!this.updatedVideoConstants[type][npmName]) { | ||
361 | this.updatedVideoConstants[type][npmName] = { | ||
362 | added: [], | ||
363 | deleted: [] | ||
364 | } | ||
365 | } | ||
366 | |||
367 | this.updatedVideoConstants[type][npmName].added.push({ key, label }) | ||
368 | obj[key] = label | ||
369 | |||
370 | return true | ||
371 | } | ||
372 | |||
373 | private deleteConstant<T extends string | number> (parameters: { | ||
374 | npmName: string | ||
375 | type: AlterableVideoConstant | ||
376 | obj: VideoConstant | ||
377 | key: T | ||
378 | }) { | ||
379 | const { npmName, type, obj, key } = parameters | ||
380 | |||
381 | if (!obj[key]) { | ||
382 | logger.warn('Cannot delete %s by plugin %s: key %s does not exist.', type, npmName, key) | ||
383 | return false | ||
384 | } | ||
385 | |||
386 | if (!this.updatedVideoConstants[type][npmName]) { | ||
387 | this.updatedVideoConstants[type][npmName] = { | ||
388 | added: [], | ||
389 | deleted: [] | ||
390 | } | ||
391 | } | ||
392 | |||
393 | const updatedConstants = this.updatedVideoConstants[type][npmName] | ||
394 | |||
395 | const alreadyAdded = updatedConstants.added.find(a => a.key === key) | ||
396 | if (alreadyAdded) { | ||
397 | updatedConstants.added.filter(a => a.key !== key) | ||
398 | } else if (obj[key]) { | ||
399 | updatedConstants.deleted.push({ key, label: obj[key] }) | ||
400 | } | ||
401 | |||
402 | delete obj[key] | ||
403 | |||
404 | return true | ||
405 | } | ||
406 | |||
407 | private buildTranscodingManager () { | 271 | private buildTranscodingManager () { |
408 | const self = this | 272 | const self = this |
409 | 273 | ||
diff --git a/server/lib/plugins/video-constant-manager-factory.ts b/server/lib/plugins/video-constant-manager-factory.ts new file mode 100644 index 000000000..f04dde29f --- /dev/null +++ b/server/lib/plugins/video-constant-manager-factory.ts | |||
@@ -0,0 +1,139 @@ | |||
1 | import { logger } from '@server/helpers/logger' | ||
2 | import { | ||
3 | VIDEO_CATEGORIES, | ||
4 | VIDEO_LANGUAGES, | ||
5 | VIDEO_LICENCES, | ||
6 | VIDEO_PLAYLIST_PRIVACIES, | ||
7 | VIDEO_PRIVACIES | ||
8 | } from '@server/initializers/constants' | ||
9 | import { ConstantManager } from '@shared/models/plugins/server/plugin-constant-manager.model' | ||
10 | |||
11 | type AlterableVideoConstant = 'language' | 'licence' | 'category' | 'privacy' | 'playlistPrivacy' | ||
12 | type VideoConstant = Record<number | string, string> | ||
13 | |||
14 | type UpdatedVideoConstant = { | ||
15 | [name in AlterableVideoConstant]: { | ||
16 | [ npmName: string]: { | ||
17 | added: VideoConstant[] | ||
18 | deleted: VideoConstant[] | ||
19 | } | ||
20 | } | ||
21 | } | ||
22 | |||
23 | const constantsHash: { [key in AlterableVideoConstant]: VideoConstant } = { | ||
24 | language: VIDEO_LANGUAGES, | ||
25 | licence: VIDEO_LICENCES, | ||
26 | category: VIDEO_CATEGORIES, | ||
27 | privacy: VIDEO_PRIVACIES, | ||
28 | playlistPrivacy: VIDEO_PLAYLIST_PRIVACIES | ||
29 | } | ||
30 | |||
31 | export class VideoConstantManagerFactory { | ||
32 | private readonly updatedVideoConstants: UpdatedVideoConstant = { | ||
33 | playlistPrivacy: { }, | ||
34 | privacy: { }, | ||
35 | language: { }, | ||
36 | licence: { }, | ||
37 | category: { } | ||
38 | } | ||
39 | |||
40 | constructor ( | ||
41 | private readonly npmName: string | ||
42 | ) {} | ||
43 | |||
44 | public resetVideoConstants (npmName: string) { | ||
45 | const types: AlterableVideoConstant[] = [ 'language', 'licence', 'category', 'privacy', 'playlistPrivacy' ] | ||
46 | for (const type of types) { | ||
47 | this.resetConstants({ npmName, type }) | ||
48 | } | ||
49 | } | ||
50 | |||
51 | private resetConstants (parameters: { npmName: string, type: AlterableVideoConstant }) { | ||
52 | const { npmName, type } = parameters | ||
53 | const updatedConstants = this.updatedVideoConstants[type][npmName] | ||
54 | |||
55 | if (!updatedConstants) return | ||
56 | |||
57 | for (const added of updatedConstants.added) { | ||
58 | delete constantsHash[type][added.key] | ||
59 | } | ||
60 | |||
61 | for (const deleted of updatedConstants.deleted) { | ||
62 | constantsHash[type][deleted.key] = deleted.label | ||
63 | } | ||
64 | |||
65 | delete this.updatedVideoConstants[type][npmName] | ||
66 | } | ||
67 | |||
68 | public createVideoConstantManager<K extends number | string>(type: AlterableVideoConstant): ConstantManager<K> { | ||
69 | const { npmName } = this | ||
70 | return { | ||
71 | addConstant: (key: K, label: string) => this.addConstant({ npmName, type, key, label }), | ||
72 | deleteConstant: (key: K) => this.deleteConstant({ npmName, type, key }), | ||
73 | getConstantValue: (key: K) => constantsHash[type][key], | ||
74 | getConstants: () => constantsHash[type] as Record<K, string>, | ||
75 | resetConstants: () => this.resetConstants({ npmName, type }) | ||
76 | } | ||
77 | } | ||
78 | |||
79 | private addConstant<T extends string | number> (parameters: { | ||
80 | npmName: string | ||
81 | type: AlterableVideoConstant | ||
82 | key: T | ||
83 | label: string | ||
84 | }) { | ||
85 | const { npmName, type, key, label } = parameters | ||
86 | const obj = constantsHash[type] | ||
87 | |||
88 | if (obj[key]) { | ||
89 | logger.warn('Cannot add %s %s by plugin %s: key already exists.', type, npmName, key) | ||
90 | return false | ||
91 | } | ||
92 | |||
93 | if (!this.updatedVideoConstants[type][npmName]) { | ||
94 | this.updatedVideoConstants[type][npmName] = { | ||
95 | added: [], | ||
96 | deleted: [] | ||
97 | } | ||
98 | } | ||
99 | |||
100 | this.updatedVideoConstants[type][npmName].added.push({ key: key, label } as VideoConstant) | ||
101 | obj[key] = label | ||
102 | |||
103 | return true | ||
104 | } | ||
105 | |||
106 | private deleteConstant<T extends string | number> (parameters: { | ||
107 | npmName: string | ||
108 | type: AlterableVideoConstant | ||
109 | key: T | ||
110 | }) { | ||
111 | const { npmName, type, key } = parameters | ||
112 | const obj = constantsHash[type] | ||
113 | |||
114 | if (!obj[key]) { | ||
115 | logger.warn('Cannot delete %s by plugin %s: key %s does not exist.', type, npmName, key) | ||
116 | return false | ||
117 | } | ||
118 | |||
119 | if (!this.updatedVideoConstants[type][npmName]) { | ||
120 | this.updatedVideoConstants[type][npmName] = { | ||
121 | added: [], | ||
122 | deleted: [] | ||
123 | } | ||
124 | } | ||
125 | |||
126 | const updatedConstants = this.updatedVideoConstants[type][npmName] | ||
127 | |||
128 | const alreadyAdded = updatedConstants.added.find(a => a.key === key) | ||
129 | if (alreadyAdded) { | ||
130 | updatedConstants.added.filter(a => a.key !== key) | ||
131 | } else if (obj[key]) { | ||
132 | updatedConstants.deleted.push({ key, label: obj[key] } as VideoConstant) | ||
133 | } | ||
134 | |||
135 | delete obj[key] | ||
136 | |||
137 | return true | ||
138 | } | ||
139 | } | ||
diff --git a/server/tests/fixtures/peertube-plugin-test-video-constants/main.js b/server/tests/fixtures/peertube-plugin-test-video-constants/main.js index 3e650e0a1..06527bd35 100644 --- a/server/tests/fixtures/peertube-plugin-test-video-constants/main.js +++ b/server/tests/fixtures/peertube-plugin-test-video-constants/main.js | |||
@@ -1,46 +1,46 @@ | |||
1 | async function register ({ | 1 | async function register ({ |
2 | registerHook, | ||
3 | registerSetting, | ||
4 | settingsManager, | ||
5 | storageManager, | ||
6 | videoCategoryManager, | 2 | videoCategoryManager, |
7 | videoLicenceManager, | 3 | videoLicenceManager, |
8 | videoLanguageManager, | 4 | videoLanguageManager, |
9 | videoPrivacyManager, | 5 | videoPrivacyManager, |
10 | playlistPrivacyManager | 6 | playlistPrivacyManager, |
7 | getRouter | ||
11 | }) { | 8 | }) { |
12 | videoLanguageManager.addLanguage('al_bhed', 'Al Bhed') | 9 | videoLanguageManager.addConstant('al_bhed', 'Al Bhed') |
13 | videoLanguageManager.addLanguage('al_bhed2', 'Al Bhed 2') | 10 | videoLanguageManager.addLanguage('al_bhed2', 'Al Bhed 2') |
14 | videoLanguageManager.addLanguage('al_bhed3', 'Al Bhed 3') | 11 | videoLanguageManager.addConstant('al_bhed3', 'Al Bhed 3') |
15 | videoLanguageManager.deleteLanguage('en') | 12 | videoLanguageManager.deleteConstant('en') |
16 | videoLanguageManager.deleteLanguage('fr') | 13 | videoLanguageManager.deleteLanguage('fr') |
17 | videoLanguageManager.deleteLanguage('al_bhed3') | 14 | videoLanguageManager.deleteConstant('al_bhed3') |
18 | 15 | ||
19 | videoCategoryManager.addCategory(42, 'Best category') | 16 | videoCategoryManager.addCategory(42, 'Best category') |
20 | videoCategoryManager.addCategory(43, 'High best category') | 17 | videoCategoryManager.addConstant(43, 'High best category') |
21 | videoCategoryManager.deleteCategory(1) // Music | 18 | videoCategoryManager.deleteConstant(1) // Music |
22 | videoCategoryManager.deleteCategory(2) // Films | 19 | videoCategoryManager.deleteCategory(2) // Films |
23 | 20 | ||
24 | videoLicenceManager.addLicence(42, 'Best licence') | 21 | videoLicenceManager.addLicence(42, 'Best licence') |
25 | videoLicenceManager.addLicence(43, 'High best licence') | 22 | videoLicenceManager.addConstant(43, 'High best licence') |
26 | videoLicenceManager.deleteLicence(1) // Attribution | 23 | videoLicenceManager.deleteConstant(1) // Attribution |
27 | videoLicenceManager.deleteLicence(7) // Public domain | 24 | videoLicenceManager.deleteConstant(7) // Public domain |
28 | 25 | ||
26 | videoPrivacyManager.deleteConstant(2) | ||
29 | videoPrivacyManager.deletePrivacy(2) | 27 | videoPrivacyManager.deletePrivacy(2) |
28 | playlistPrivacyManager.deleteConstant(3) | ||
30 | playlistPrivacyManager.deletePlaylistPrivacy(3) | 29 | playlistPrivacyManager.deletePlaylistPrivacy(3) |
31 | } | ||
32 | 30 | ||
33 | async function unregister () { | 31 | { |
34 | return | 32 | const router = getRouter() |
33 | router.get('/reset-categories', (req, res) => { | ||
34 | videoCategoryManager.resetConstants() | ||
35 | |||
36 | res.sendStatus(204) | ||
37 | }) | ||
38 | } | ||
35 | } | 39 | } |
36 | 40 | ||
41 | async function unregister () {} | ||
42 | |||
37 | module.exports = { | 43 | module.exports = { |
38 | register, | 44 | register, |
39 | unregister | 45 | unregister |
40 | } | 46 | } |
41 | |||
42 | // ############################################################################ | ||
43 | |||
44 | function addToCount (obj) { | ||
45 | return Object.assign({}, obj, { count: obj.count + 1 }) | ||
46 | } | ||
diff --git a/server/tests/index.ts b/server/tests/index.ts index 3fbd0ebbd..1718ac424 100644 --- a/server/tests/index.ts +++ b/server/tests/index.ts | |||
@@ -6,3 +6,4 @@ import './cli/' | |||
6 | import './api/' | 6 | import './api/' |
7 | import './plugins/' | 7 | import './plugins/' |
8 | import './helpers/' | 8 | import './helpers/' |
9 | import './lib/' | ||
diff --git a/server/tests/lib/index.ts b/server/tests/lib/index.ts new file mode 100644 index 000000000..a40df35fd --- /dev/null +++ b/server/tests/lib/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './video-constant-registry-factory' | |||
diff --git a/server/tests/lib/video-constant-registry-factory.ts b/server/tests/lib/video-constant-registry-factory.ts new file mode 100644 index 000000000..e26b286e1 --- /dev/null +++ b/server/tests/lib/video-constant-registry-factory.ts | |||
@@ -0,0 +1,155 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions */ | ||
2 | import 'mocha' | ||
3 | import { expect } from 'chai' | ||
4 | import { VideoConstantManagerFactory } from '@server/lib/plugins/video-constant-manager-factory' | ||
5 | import { | ||
6 | VIDEO_CATEGORIES, | ||
7 | VIDEO_LANGUAGES, | ||
8 | VIDEO_LICENCES, | ||
9 | VIDEO_PLAYLIST_PRIVACIES, | ||
10 | VIDEO_PRIVACIES | ||
11 | } from '@server/initializers/constants' | ||
12 | import { | ||
13 | VideoPlaylistPrivacy, | ||
14 | VideoPrivacy | ||
15 | } from '@shared/models' | ||
16 | |||
17 | describe('VideoConstantManagerFactory', function () { | ||
18 | const factory = new VideoConstantManagerFactory('peertube-plugin-constants') | ||
19 | |||
20 | afterEach(() => { | ||
21 | factory.resetVideoConstants('peertube-plugin-constants') | ||
22 | }) | ||
23 | |||
24 | describe('VideoCategoryManager', () => { | ||
25 | const videoCategoryManager = factory.createVideoConstantManager<number>('category') | ||
26 | |||
27 | it('Should be able to list all video category constants', () => { | ||
28 | const constants = videoCategoryManager.getConstants() | ||
29 | expect(constants).to.deep.equal(VIDEO_CATEGORIES) | ||
30 | }) | ||
31 | |||
32 | it('Should be able to delete a video category constant', () => { | ||
33 | const successfullyDeleted = videoCategoryManager.deleteConstant(1) | ||
34 | expect(successfullyDeleted).to.be.true | ||
35 | expect(videoCategoryManager.getConstantValue(1)).to.be.undefined | ||
36 | }) | ||
37 | |||
38 | it('Should be able to add a video category constant', () => { | ||
39 | const successfullyAdded = videoCategoryManager.addConstant(42, 'The meaning of life') | ||
40 | expect(successfullyAdded).to.be.true | ||
41 | expect(videoCategoryManager.getConstantValue(42)).to.equal('The meaning of life') | ||
42 | }) | ||
43 | |||
44 | it('Should be able to reset video category constants', () => { | ||
45 | videoCategoryManager.deleteConstant(1) | ||
46 | videoCategoryManager.resetConstants() | ||
47 | expect(videoCategoryManager.getConstantValue(1)).not.be.undefined | ||
48 | }) | ||
49 | }) | ||
50 | |||
51 | describe('VideoLicenceManager', () => { | ||
52 | const videoLicenceManager = factory.createVideoConstantManager<number>('licence') | ||
53 | it('Should be able to list all video licence constants', () => { | ||
54 | const constants = videoLicenceManager.getConstants() | ||
55 | expect(constants).to.deep.equal(VIDEO_LICENCES) | ||
56 | }) | ||
57 | |||
58 | it('Should be able to delete a video licence constant', () => { | ||
59 | const successfullyDeleted = videoLicenceManager.deleteConstant(1) | ||
60 | expect(successfullyDeleted).to.be.true | ||
61 | expect(videoLicenceManager.getConstantValue(1)).to.be.undefined | ||
62 | }) | ||
63 | |||
64 | it('Should be able to add a video licence constant', () => { | ||
65 | const successfullyAdded = videoLicenceManager.addConstant(42, 'European Union Public Licence') | ||
66 | expect(successfullyAdded).to.be.true | ||
67 | expect(videoLicenceManager.getConstantValue(42)).to.equal('European Union Public Licence') | ||
68 | }) | ||
69 | |||
70 | it('Should be able to reset video licence constants', () => { | ||
71 | videoLicenceManager.deleteConstant(1) | ||
72 | videoLicenceManager.resetConstants() | ||
73 | expect(videoLicenceManager.getConstantValue(1)).not.be.undefined | ||
74 | }) | ||
75 | }) | ||
76 | |||
77 | describe('PlaylistPrivacyManager', () => { | ||
78 | const playlistPrivacyManager = factory.createVideoConstantManager<VideoPlaylistPrivacy>('playlistPrivacy') | ||
79 | it('Should be able to list all video playlist privacy constants', () => { | ||
80 | const constants = playlistPrivacyManager.getConstants() | ||
81 | expect(constants).to.deep.equal(VIDEO_PLAYLIST_PRIVACIES) | ||
82 | }) | ||
83 | |||
84 | it('Should be able to delete a video playlist privacy constant', () => { | ||
85 | const successfullyDeleted = playlistPrivacyManager.deleteConstant(1) | ||
86 | expect(successfullyDeleted).to.be.true | ||
87 | expect(playlistPrivacyManager.getConstantValue(1)).to.be.undefined | ||
88 | }) | ||
89 | |||
90 | it('Should be able to add a video playlist privacy constant', () => { | ||
91 | const successfullyAdded = playlistPrivacyManager.addConstant(42, 'Friends only') | ||
92 | expect(successfullyAdded).to.be.true | ||
93 | expect(playlistPrivacyManager.getConstantValue(42)).to.equal('Friends only') | ||
94 | }) | ||
95 | |||
96 | it('Should be able to reset video playlist privacy constants', () => { | ||
97 | playlistPrivacyManager.deleteConstant(1) | ||
98 | playlistPrivacyManager.resetConstants() | ||
99 | expect(playlistPrivacyManager.getConstantValue(1)).not.be.undefined | ||
100 | }) | ||
101 | }) | ||
102 | |||
103 | describe('VideoPrivacyManager', () => { | ||
104 | const videoPrivacyManager = factory.createVideoConstantManager<VideoPrivacy>('privacy') | ||
105 | it('Should be able to list all video privacy constants', () => { | ||
106 | const constants = videoPrivacyManager.getConstants() | ||
107 | expect(constants).to.deep.equal(VIDEO_PRIVACIES) | ||
108 | }) | ||
109 | |||
110 | it('Should be able to delete a video privacy constant', () => { | ||
111 | const successfullyDeleted = videoPrivacyManager.deleteConstant(1) | ||
112 | expect(successfullyDeleted).to.be.true | ||
113 | expect(videoPrivacyManager.getConstantValue(1)).to.be.undefined | ||
114 | }) | ||
115 | |||
116 | it('Should be able to add a video privacy constant', () => { | ||
117 | const successfullyAdded = videoPrivacyManager.addConstant(42, 'Friends only') | ||
118 | expect(successfullyAdded).to.be.true | ||
119 | expect(videoPrivacyManager.getConstantValue(42)).to.equal('Friends only') | ||
120 | }) | ||
121 | |||
122 | it('Should be able to reset video privacy constants', () => { | ||
123 | videoPrivacyManager.deleteConstant(1) | ||
124 | videoPrivacyManager.resetConstants() | ||
125 | expect(videoPrivacyManager.getConstantValue(1)).not.be.undefined | ||
126 | }) | ||
127 | }) | ||
128 | |||
129 | describe('VideoLanguageManager', () => { | ||
130 | const videoLanguageManager = factory.createVideoConstantManager<string>('language') | ||
131 | it('Should be able to list all video language constants', () => { | ||
132 | const constants = videoLanguageManager.getConstants() | ||
133 | expect(constants).to.deep.equal(VIDEO_LANGUAGES) | ||
134 | }) | ||
135 | |||
136 | it('Should be able to add a video language constant', () => { | ||
137 | const successfullyAdded = videoLanguageManager.addConstant('fr', 'Fr occitan') | ||
138 | expect(successfullyAdded).to.be.true | ||
139 | expect(videoLanguageManager.getConstantValue('fr')).to.equal('Fr occitan') | ||
140 | }) | ||
141 | |||
142 | it('Should be able to delete a video language constant', () => { | ||
143 | videoLanguageManager.addConstant('fr', 'Fr occitan') | ||
144 | const successfullyDeleted = videoLanguageManager.deleteConstant('fr') | ||
145 | expect(successfullyDeleted).to.be.true | ||
146 | expect(videoLanguageManager.getConstantValue('fr')).to.be.undefined | ||
147 | }) | ||
148 | |||
149 | it('Should be able to reset video language constants', () => { | ||
150 | videoLanguageManager.addConstant('fr', 'Fr occitan') | ||
151 | videoLanguageManager.resetConstants() | ||
152 | expect(videoLanguageManager.getConstantValue('fr')).to.be.undefined | ||
153 | }) | ||
154 | }) | ||
155 | }) | ||
diff --git a/server/tests/plugins/video-constants.ts b/server/tests/plugins/video-constants.ts index eb014c596..7b1312f88 100644 --- a/server/tests/plugins/video-constants.ts +++ b/server/tests/plugins/video-constants.ts | |||
@@ -9,8 +9,11 @@ import { | |||
9 | getVideo, | 9 | getVideo, |
10 | getVideoCategories, | 10 | getVideoCategories, |
11 | getVideoLanguages, | 11 | getVideoLanguages, |
12 | getVideoLicences, getVideoPlaylistPrivacies, getVideoPrivacies, | 12 | getVideoLicences, |
13 | getVideoPlaylistPrivacies, | ||
14 | getVideoPrivacies, | ||
13 | installPlugin, | 15 | installPlugin, |
16 | makeGetRequest, | ||
14 | setAccessTokensToServers, | 17 | setAccessTokensToServers, |
15 | uninstallPlugin, | 18 | uninstallPlugin, |
16 | uploadVideo | 19 | uploadVideo |
@@ -173,6 +176,38 @@ describe('Test plugin altering video constants', function () { | |||
173 | } | 176 | } |
174 | }) | 177 | }) |
175 | 178 | ||
179 | it('Should be able to reset categories', async function () { | ||
180 | await installPlugin({ | ||
181 | url: server.url, | ||
182 | accessToken: server.accessToken, | ||
183 | path: getPluginTestPath('-video-constants') | ||
184 | }) | ||
185 | |||
186 | let { body: categories } = await getVideoCategories(server.url) | ||
187 | |||
188 | expect(categories[1]).to.not.exist | ||
189 | expect(categories[2]).to.not.exist | ||
190 | |||
191 | expect(categories[42]).to.exist | ||
192 | expect(categories[43]).to.exist | ||
193 | |||
194 | await makeGetRequest({ | ||
195 | url: server.url, | ||
196 | token: server.accessToken, | ||
197 | path: '/plugins/test-video-constants/router/reset-categories', | ||
198 | statusCodeExpected: HttpStatusCode.NO_CONTENT_204 | ||
199 | }) | ||
200 | |||
201 | const { body } = await getVideoCategories(server.url) | ||
202 | categories = body | ||
203 | |||
204 | expect(categories[1]).to.exist | ||
205 | expect(categories[2]).to.exist | ||
206 | |||
207 | expect(categories[42]).to.not.exist | ||
208 | expect(categories[43]).to.not.exist | ||
209 | }) | ||
210 | |||
176 | after(async function () { | 211 | after(async function () { |
177 | await cleanupTests([ server ]) | 212 | await cleanupTests([ server ]) |
178 | }) | 213 | }) |
diff --git a/shared/models/plugins/server/managers/plugin-playlist-privacy-manager.model.ts b/shared/models/plugins/server/managers/plugin-playlist-privacy-manager.model.ts index 4703c0a8b..5b3b37752 100644 --- a/shared/models/plugins/server/managers/plugin-playlist-privacy-manager.model.ts +++ b/shared/models/plugins/server/managers/plugin-playlist-privacy-manager.model.ts | |||
@@ -1,8 +1,12 @@ | |||
1 | import { VideoPlaylistPrivacy } from '../../../videos/playlist/video-playlist-privacy.model' | 1 | import { VideoPlaylistPrivacy } from '../../../videos/playlist/video-playlist-privacy.model' |
2 | import { ConstantManager } from '@shared/models/plugins/server/plugin-constant-manager.model' | ||
2 | 3 | ||
3 | export interface PluginPlaylistPrivacyManager { | 4 | export interface PluginPlaylistPrivacyManager extends ConstantManager<VideoPlaylistPrivacy> { |
4 | // PUBLIC = 1, | 5 | /** |
5 | // UNLISTED = 2, | 6 | * PUBLIC = 1, |
6 | // PRIVATE = 3 | 7 | * UNLISTED = 2, |
8 | * PRIVATE = 3 | ||
9 | * @deprecated use `deleteConstant` instead | ||
10 | */ | ||
7 | deletePlaylistPrivacy: (privacyKey: VideoPlaylistPrivacy) => boolean | 11 | deletePlaylistPrivacy: (privacyKey: VideoPlaylistPrivacy) => boolean |
8 | } | 12 | } |
diff --git a/shared/models/plugins/server/managers/plugin-video-category-manager.model.ts b/shared/models/plugins/server/managers/plugin-video-category-manager.model.ts index 201bfa979..069ad1476 100644 --- a/shared/models/plugins/server/managers/plugin-video-category-manager.model.ts +++ b/shared/models/plugins/server/managers/plugin-video-category-manager.model.ts | |||
@@ -1,5 +1,13 @@ | |||
1 | export interface PluginVideoCategoryManager { | 1 | import { ConstantManager } from '@shared/models/plugins/server/plugin-constant-manager.model' |
2 | |||
3 | export interface PluginVideoCategoryManager extends ConstantManager<number> { | ||
4 | /** | ||
5 | * @deprecated use `addConstant` instead | ||
6 | */ | ||
2 | addCategory: (categoryKey: number, categoryLabel: string) => boolean | 7 | addCategory: (categoryKey: number, categoryLabel: string) => boolean |
3 | 8 | ||
9 | /** | ||
10 | * @deprecated use `deleteConstant` instead | ||
11 | */ | ||
4 | deleteCategory: (categoryKey: number) => boolean | 12 | deleteCategory: (categoryKey: number) => boolean |
5 | } | 13 | } |
diff --git a/shared/models/plugins/server/managers/plugin-video-language-manager.model.ts b/shared/models/plugins/server/managers/plugin-video-language-manager.model.ts index 3fd577a79..969c6c670 100644 --- a/shared/models/plugins/server/managers/plugin-video-language-manager.model.ts +++ b/shared/models/plugins/server/managers/plugin-video-language-manager.model.ts | |||
@@ -1,5 +1,13 @@ | |||
1 | export interface PluginVideoLanguageManager { | 1 | import { ConstantManager } from '@shared/models/plugins/server/plugin-constant-manager.model' |
2 | |||
3 | export interface PluginVideoLanguageManager extends ConstantManager<string> { | ||
4 | /** | ||
5 | * @deprecated use `addConstant` instead | ||
6 | */ | ||
2 | addLanguage: (languageKey: string, languageLabel: string) => boolean | 7 | addLanguage: (languageKey: string, languageLabel: string) => boolean |
3 | 8 | ||
9 | /** | ||
10 | * @deprecated use `deleteConstant` instead | ||
11 | */ | ||
4 | deleteLanguage: (languageKey: string) => boolean | 12 | deleteLanguage: (languageKey: string) => boolean |
5 | } | 13 | } |
diff --git a/shared/models/plugins/server/managers/plugin-video-licence-manager.model.ts b/shared/models/plugins/server/managers/plugin-video-licence-manager.model.ts index 82a634d3a..900a49661 100644 --- a/shared/models/plugins/server/managers/plugin-video-licence-manager.model.ts +++ b/shared/models/plugins/server/managers/plugin-video-licence-manager.model.ts | |||
@@ -1,5 +1,13 @@ | |||
1 | export interface PluginVideoLicenceManager { | 1 | import { ConstantManager } from '@shared/models/plugins/server/plugin-constant-manager.model' |
2 | |||
3 | export interface PluginVideoLicenceManager extends ConstantManager<number> { | ||
4 | /** | ||
5 | * @deprecated use `addLicence` instead | ||
6 | */ | ||
2 | addLicence: (licenceKey: number, licenceLabel: string) => boolean | 7 | addLicence: (licenceKey: number, licenceLabel: string) => boolean |
3 | 8 | ||
9 | /** | ||
10 | * @deprecated use `deleteLicence` instead | ||
11 | */ | ||
4 | deleteLicence: (licenceKey: number) => boolean | 12 | deleteLicence: (licenceKey: number) => boolean |
5 | } | 13 | } |
diff --git a/shared/models/plugins/server/managers/plugin-video-privacy-manager.model.ts b/shared/models/plugins/server/managers/plugin-video-privacy-manager.model.ts index 7717115e3..e26e48a53 100644 --- a/shared/models/plugins/server/managers/plugin-video-privacy-manager.model.ts +++ b/shared/models/plugins/server/managers/plugin-video-privacy-manager.model.ts | |||
@@ -1,9 +1,13 @@ | |||
1 | import { VideoPrivacy } from '../../../videos/video-privacy.enum' | 1 | import { VideoPrivacy } from '../../../videos/video-privacy.enum' |
2 | import { ConstantManager } from '@shared/models/plugins/server/plugin-constant-manager.model' | ||
2 | 3 | ||
3 | export interface PluginVideoPrivacyManager { | 4 | export interface PluginVideoPrivacyManager extends ConstantManager<VideoPrivacy> { |
4 | // PUBLIC = 1 | 5 | /** |
5 | // UNLISTED = 2 | 6 | * PUBLIC = 1, |
6 | // PRIVATE = 3 | 7 | * UNLISTED = 2, |
7 | // INTERNAL = 4 | 8 | * PRIVATE = 3 |
9 | * INTERNAL = 4 | ||
10 | * @deprecated use `deleteConstant` instead | ||
11 | */ | ||
8 | deletePrivacy: (privacyKey: VideoPrivacy) => boolean | 12 | deletePrivacy: (privacyKey: VideoPrivacy) => boolean |
9 | } | 13 | } |
diff --git a/shared/models/plugins/server/plugin-constant-manager.model.ts b/shared/models/plugins/server/plugin-constant-manager.model.ts new file mode 100644 index 000000000..4de3ce38f --- /dev/null +++ b/shared/models/plugins/server/plugin-constant-manager.model.ts | |||
@@ -0,0 +1,7 @@ | |||
1 | export interface ConstantManager <K extends string | number> { | ||
2 | addConstant: (key: K, label: string) => boolean | ||
3 | deleteConstant: (key: K) => boolean | ||
4 | getConstantValue: (key: K) => string | ||
5 | getConstants: () => Record<K, string> | ||
6 | resetConstants: () => void | ||
7 | } | ||
diff --git a/support/doc/plugins/guide.md b/support/doc/plugins/guide.md index 568c0662f..85aaf9f02 100644 --- a/support/doc/plugins/guide.md +++ b/support/doc/plugins/guide.md | |||
@@ -234,21 +234,29 @@ function register ({ | |||
234 | 234 | ||
235 | #### Update video constants | 235 | #### Update video constants |
236 | 236 | ||
237 | You can add/delete video categories, licences or languages using the appropriate managers: | 237 | You can add/delete video categories, licences or languages using the appropriate constant managers: |
238 | 238 | ||
239 | ```js | 239 | ```js |
240 | function register (...) { | 240 | function register ({ |
241 | videoLanguageManager.addLanguage('al_bhed', 'Al Bhed') | 241 | videoLanguageManager, |
242 | videoLanguageManager.deleteLanguage('fr') | 242 | videoCategoryManager, |
243 | videoLicenceManager, | ||
244 | videoPrivacyManager, | ||
245 | playlistPrivacyManager | ||
246 | }) { | ||
247 | videoLanguageManager.addConstant('al_bhed', 'Al Bhed') | ||
248 | videoLanguageManager.deleteConstant('fr') | ||
243 | 249 | ||
244 | videoCategoryManager.addCategory(42, 'Best category') | 250 | videoCategoryManager.addConstant(42, 'Best category') |
245 | videoCategoryManager.deleteCategory(1) // Music | 251 | videoCategoryManager.deleteConstant(1) // Music |
252 | videoCategoryManager.resetConstants() // Reset to initial categories | ||
253 | videoCategoryManager.getConstants() // Retrieve all category constants | ||
246 | 254 | ||
247 | videoLicenceManager.addLicence(42, 'Best licence') | 255 | videoLicenceManager.addConstant(42, 'Best licence') |
248 | videoLicenceManager.deleteLicence(7) // Public domain | 256 | videoLicenceManager.deleteConstant(7) // Public domain |
249 | 257 | ||
250 | videoPrivacyManager.deletePrivacy(2) // Remove Unlisted video privacy | 258 | videoPrivacyManager.deleteConstant(2) // Remove Unlisted video privacy |
251 | playlistPrivacyManager.deletePlaylistPrivacy(3) // Remove Private video playlist privacy | 259 | playlistPrivacyManager.deleteConstant(3) // Remove Private video playlist privacy |
252 | } | 260 | } |
253 | ``` | 261 | ``` |
254 | 262 | ||