]>
Commit | Line | Data |
---|---|---|
9107d791 | 1 | import * as express from 'express' |
4a8d113b | 2 | import { logger } from '@server/helpers/logger' |
9107d791 C |
3 | import { |
4 | VIDEO_CATEGORIES, | |
5 | VIDEO_LANGUAGES, | |
6 | VIDEO_LICENCES, | |
7 | VIDEO_PLAYLIST_PRIVACIES, | |
8 | VIDEO_PRIVACIES | |
9 | } from '@server/initializers/constants' | |
4a8d113b | 10 | import { onExternalUserAuthenticated } from '@server/lib/auth' |
5e2b2e27 | 11 | import { PluginModel } from '@server/models/server/plugin' |
9107d791 C |
12 | import { |
13 | RegisterServerAuthExternalOptions, | |
14 | RegisterServerAuthExternalResult, | |
15 | RegisterServerAuthPassOptions, | |
67ed6552 C |
16 | RegisterServerExternalAuthenticatedResult, |
17 | RegisterServerOptions | |
18 | } from '@server/types/plugins' | |
19 | import { | |
20 | PluginPlaylistPrivacyManager, | |
21 | PluginSettingsManager, | |
22 | PluginStorageManager, | |
23 | PluginVideoCategoryManager, | |
24 | PluginVideoLanguageManager, | |
25 | PluginVideoLicenceManager, | |
26 | PluginVideoPrivacyManager, | |
27 | RegisterServerHookOptions, | |
28 | RegisterServerSettingOptions | |
29 | } from '@shared/models' | |
4a8d113b | 30 | import { serverHookObject } from '@shared/models/plugins/server-hook.model' |
4a8d113b | 31 | import { buildPluginHelpers } from './plugin-helpers' |
5e2b2e27 | 32 | |
b3af2601 | 33 | type AlterableVideoConstant = 'language' | 'licence' | 'category' | 'privacy' | 'playlistPrivacy' |
5e2b2e27 C |
34 | type VideoConstant = { [key in number | string]: string } |
35 | ||
36 | type UpdatedVideoConstant = { | |
37 | [name in AlterableVideoConstant]: { | |
38 | added: { key: number | string, label: string }[] | |
39 | deleted: { key: number | string, label: string }[] | |
40 | } | |
41 | } | |
42 | ||
43 | export class RegisterHelpersStore { | |
44 | private readonly updatedVideoConstants: UpdatedVideoConstant = { | |
b3af2601 C |
45 | playlistPrivacy: { added: [], deleted: [] }, |
46 | privacy: { added: [], deleted: [] }, | |
5e2b2e27 C |
47 | language: { added: [], deleted: [] }, |
48 | licence: { added: [], deleted: [] }, | |
49 | category: { added: [], deleted: [] } | |
50 | } | |
51 | ||
52 | private readonly settings: RegisterServerSettingOptions[] = [] | |
53 | ||
a4995eb7 C |
54 | private idAndPassAuths: RegisterServerAuthPassOptions[] = [] |
55 | private externalAuths: RegisterServerAuthExternalOptions[] = [] | |
7fed6375 | 56 | |
a5896799 C |
57 | private readonly onSettingsChangeCallbacks: ((settings: any) => void)[] = [] |
58 | ||
5e2b2e27 C |
59 | private readonly router: express.Router |
60 | ||
61 | constructor ( | |
62 | private readonly npmName: string, | |
63 | private readonly plugin: PluginModel, | |
64 | private readonly onHookAdded: (options: RegisterServerHookOptions) => void | |
65 | ) { | |
66 | this.router = express.Router() | |
67 | } | |
68 | ||
69 | buildRegisterHelpers (): RegisterServerOptions { | |
70 | const registerHook = this.buildRegisterHook() | |
71 | const registerSetting = this.buildRegisterSetting() | |
72 | ||
73 | const getRouter = this.buildGetRouter() | |
74 | ||
75 | const settingsManager = this.buildSettingsManager() | |
76 | const storageManager = this.buildStorageManager() | |
77 | ||
78 | const videoLanguageManager = this.buildVideoLanguageManager() | |
79 | ||
80 | const videoLicenceManager = this.buildVideoLicenceManager() | |
81 | const videoCategoryManager = this.buildVideoCategoryManager() | |
82 | ||
b3af2601 C |
83 | const videoPrivacyManager = this.buildVideoPrivacyManager() |
84 | const playlistPrivacyManager = this.buildPlaylistPrivacyManager() | |
85 | ||
7fed6375 C |
86 | const registerIdAndPassAuth = this.buildRegisterIdAndPassAuth() |
87 | const registerExternalAuth = this.buildRegisterExternalAuth() | |
a4995eb7 C |
88 | const unregisterIdAndPassAuth = this.buildUnregisterIdAndPassAuth() |
89 | const unregisterExternalAuth = this.buildUnregisterExternalAuth() | |
7fed6375 | 90 | |
5e2b2e27 C |
91 | const peertubeHelpers = buildPluginHelpers(this.npmName) |
92 | ||
93 | return { | |
94 | registerHook, | |
95 | registerSetting, | |
96 | ||
97 | getRouter, | |
98 | ||
99 | settingsManager, | |
100 | storageManager, | |
101 | ||
102 | videoLanguageManager, | |
103 | videoCategoryManager, | |
104 | videoLicenceManager, | |
105 | ||
b3af2601 C |
106 | videoPrivacyManager, |
107 | playlistPrivacyManager, | |
108 | ||
7fed6375 C |
109 | registerIdAndPassAuth, |
110 | registerExternalAuth, | |
a4995eb7 C |
111 | unregisterIdAndPassAuth, |
112 | unregisterExternalAuth, | |
7fed6375 | 113 | |
5e2b2e27 C |
114 | peertubeHelpers |
115 | } | |
116 | } | |
117 | ||
118 | reinitVideoConstants (npmName: string) { | |
119 | const hash = { | |
120 | language: VIDEO_LANGUAGES, | |
121 | licence: VIDEO_LICENCES, | |
b3af2601 C |
122 | category: VIDEO_CATEGORIES, |
123 | privacy: VIDEO_PRIVACIES, | |
124 | playlistPrivacy: VIDEO_PLAYLIST_PRIVACIES | |
5e2b2e27 | 125 | } |
b3af2601 | 126 | const types: AlterableVideoConstant[] = [ 'language', 'licence', 'category', 'privacy', 'playlistPrivacy' ] |
5e2b2e27 C |
127 | |
128 | for (const type of types) { | |
129 | const updatedConstants = this.updatedVideoConstants[type][npmName] | |
130 | if (!updatedConstants) continue | |
131 | ||
132 | for (const added of updatedConstants.added) { | |
133 | delete hash[type][added.key] | |
134 | } | |
135 | ||
136 | for (const deleted of updatedConstants.deleted) { | |
137 | hash[type][deleted.key] = deleted.label | |
138 | } | |
139 | ||
140 | delete this.updatedVideoConstants[type][npmName] | |
141 | } | |
142 | } | |
143 | ||
144 | getSettings () { | |
145 | return this.settings | |
146 | } | |
147 | ||
148 | getRouter () { | |
149 | return this.router | |
150 | } | |
151 | ||
7fed6375 C |
152 | getIdAndPassAuths () { |
153 | return this.idAndPassAuths | |
154 | } | |
155 | ||
156 | getExternalAuths () { | |
157 | return this.externalAuths | |
158 | } | |
159 | ||
a5896799 C |
160 | getOnSettingsChangedCallbacks () { |
161 | return this.onSettingsChangeCallbacks | |
162 | } | |
163 | ||
5e2b2e27 C |
164 | private buildGetRouter () { |
165 | return () => this.router | |
166 | } | |
167 | ||
168 | private buildRegisterSetting () { | |
169 | return (options: RegisterServerSettingOptions) => { | |
170 | this.settings.push(options) | |
171 | } | |
172 | } | |
173 | ||
174 | private buildRegisterHook () { | |
175 | return (options: RegisterServerHookOptions) => { | |
176 | if (serverHookObject[options.target] !== true) { | |
177 | logger.warn('Unknown hook %s of plugin %s. Skipping.', options.target, this.npmName) | |
178 | return | |
179 | } | |
180 | ||
181 | return this.onHookAdded(options) | |
182 | } | |
183 | } | |
184 | ||
7fed6375 C |
185 | private buildRegisterIdAndPassAuth () { |
186 | return (options: RegisterServerAuthPassOptions) => { | |
e1c55031 | 187 | if (!options.authName || typeof options.getWeight !== 'function' || typeof options.login !== 'function') { |
a4995eb7 | 188 | logger.error('Cannot register auth plugin %s: authName, getWeight or login are not valid.', this.npmName, { options }) |
e1c55031 C |
189 | return |
190 | } | |
191 | ||
7fed6375 C |
192 | this.idAndPassAuths.push(options) |
193 | } | |
194 | } | |
195 | ||
196 | private buildRegisterExternalAuth () { | |
197 | const self = this | |
198 | ||
199 | return (options: RegisterServerAuthExternalOptions) => { | |
a5896799 | 200 | if (!options.authName || typeof options.authDisplayName !== 'function' || typeof options.onAuthRequest !== 'function') { |
a4995eb7 | 201 | logger.error('Cannot register auth plugin %s: authName, authDisplayName or onAuthRequest are not valid.', this.npmName, { options }) |
9107d791 C |
202 | return |
203 | } | |
204 | ||
7fed6375 C |
205 | this.externalAuths.push(options) |
206 | ||
207 | return { | |
4a8d113b C |
208 | userAuthenticated (result: RegisterServerExternalAuthenticatedResult): void { |
209 | onExternalUserAuthenticated({ | |
210 | npmName: self.npmName, | |
211 | authName: options.authName, | |
212 | authResult: result | |
213 | }).catch(err => { | |
214 | logger.error('Cannot execute onExternalUserAuthenticated.', { npmName: self.npmName, authName: options.authName, err }) | |
215 | }) | |
7fed6375 C |
216 | } |
217 | } as RegisterServerAuthExternalResult | |
218 | } | |
219 | } | |
220 | ||
a4995eb7 C |
221 | private buildUnregisterExternalAuth () { |
222 | return (authName: string) => { | |
223 | this.externalAuths = this.externalAuths.filter(a => a.authName !== authName) | |
224 | } | |
225 | } | |
226 | ||
227 | private buildUnregisterIdAndPassAuth () { | |
228 | return (authName: string) => { | |
229 | this.idAndPassAuths = this.idAndPassAuths.filter(a => a.authName !== authName) | |
230 | } | |
231 | } | |
232 | ||
5e2b2e27 C |
233 | private buildSettingsManager (): PluginSettingsManager { |
234 | return { | |
bc90883f | 235 | getSetting: (name: string) => PluginModel.getSetting(this.plugin.name, this.plugin.type, name, this.settings), |
5e2b2e27 | 236 | |
bc90883f | 237 | getSettings: (names: string[]) => PluginModel.getSettings(this.plugin.name, this.plugin.type, names, this.settings), |
055cfb11 | 238 | |
a5896799 C |
239 | setSetting: (name: string, value: string) => PluginModel.setSetting(this.plugin.name, this.plugin.type, name, value), |
240 | ||
241 | onSettingsChange: (cb: (settings: any) => void) => this.onSettingsChangeCallbacks.push(cb) | |
5e2b2e27 C |
242 | } |
243 | } | |
244 | ||
245 | private buildStorageManager (): PluginStorageManager { | |
246 | return { | |
247 | getData: (key: string) => PluginModel.getData(this.plugin.name, this.plugin.type, key), | |
248 | ||
249 | storeData: (key: string, data: any) => PluginModel.storeData(this.plugin.name, this.plugin.type, key, data) | |
250 | } | |
251 | } | |
252 | ||
253 | private buildVideoLanguageManager (): PluginVideoLanguageManager { | |
254 | return { | |
255 | addLanguage: (key: string, label: string) => { | |
256 | return this.addConstant({ npmName: this.npmName, type: 'language', obj: VIDEO_LANGUAGES, key, label }) | |
257 | }, | |
258 | ||
259 | deleteLanguage: (key: string) => { | |
260 | return this.deleteConstant({ npmName: this.npmName, type: 'language', obj: VIDEO_LANGUAGES, key }) | |
261 | } | |
262 | } | |
263 | } | |
264 | ||
265 | private buildVideoCategoryManager (): PluginVideoCategoryManager { | |
266 | return { | |
267 | addCategory: (key: number, label: string) => { | |
268 | return this.addConstant({ npmName: this.npmName, type: 'category', obj: VIDEO_CATEGORIES, key, label }) | |
269 | }, | |
270 | ||
271 | deleteCategory: (key: number) => { | |
272 | return this.deleteConstant({ npmName: this.npmName, type: 'category', obj: VIDEO_CATEGORIES, key }) | |
273 | } | |
274 | } | |
275 | } | |
276 | ||
b3af2601 C |
277 | private buildVideoPrivacyManager (): PluginVideoPrivacyManager { |
278 | return { | |
279 | deletePrivacy: (key: number) => { | |
280 | return this.deleteConstant({ npmName: this.npmName, type: 'privacy', obj: VIDEO_PRIVACIES, key }) | |
281 | } | |
282 | } | |
283 | } | |
284 | ||
285 | private buildPlaylistPrivacyManager (): PluginPlaylistPrivacyManager { | |
286 | return { | |
287 | deletePlaylistPrivacy: (key: number) => { | |
288 | return this.deleteConstant({ npmName: this.npmName, type: 'playlistPrivacy', obj: VIDEO_PLAYLIST_PRIVACIES, key }) | |
289 | } | |
290 | } | |
291 | } | |
292 | ||
5e2b2e27 C |
293 | private buildVideoLicenceManager (): PluginVideoLicenceManager { |
294 | return { | |
295 | addLicence: (key: number, label: string) => { | |
296 | return this.addConstant({ npmName: this.npmName, type: 'licence', obj: VIDEO_LICENCES, key, label }) | |
297 | }, | |
298 | ||
299 | deleteLicence: (key: number) => { | |
300 | return this.deleteConstant({ npmName: this.npmName, type: 'licence', obj: VIDEO_LICENCES, key }) | |
301 | } | |
302 | } | |
303 | } | |
304 | ||
305 | private addConstant<T extends string | number> (parameters: { | |
306 | npmName: string | |
307 | type: AlterableVideoConstant | |
308 | obj: VideoConstant | |
309 | key: T | |
310 | label: string | |
311 | }) { | |
312 | const { npmName, type, obj, key, label } = parameters | |
313 | ||
314 | if (obj[key]) { | |
315 | logger.warn('Cannot add %s %s by plugin %s: key already exists.', type, npmName, key) | |
316 | return false | |
317 | } | |
318 | ||
319 | if (!this.updatedVideoConstants[type][npmName]) { | |
320 | this.updatedVideoConstants[type][npmName] = { | |
321 | added: [], | |
322 | deleted: [] | |
323 | } | |
324 | } | |
325 | ||
326 | this.updatedVideoConstants[type][npmName].added.push({ key, label }) | |
327 | obj[key] = label | |
328 | ||
329 | return true | |
330 | } | |
331 | ||
332 | private deleteConstant<T extends string | number> (parameters: { | |
333 | npmName: string | |
334 | type: AlterableVideoConstant | |
335 | obj: VideoConstant | |
336 | key: T | |
337 | }) { | |
338 | const { npmName, type, obj, key } = parameters | |
339 | ||
340 | if (!obj[key]) { | |
341 | logger.warn('Cannot delete %s %s by plugin %s: key does not exist.', type, npmName, key) | |
342 | return false | |
343 | } | |
344 | ||
345 | if (!this.updatedVideoConstants[type][npmName]) { | |
346 | this.updatedVideoConstants[type][npmName] = { | |
347 | added: [], | |
348 | deleted: [] | |
349 | } | |
350 | } | |
351 | ||
352 | this.updatedVideoConstants[type][npmName].deleted.push({ key, label: obj[key] }) | |
353 | delete obj[key] | |
354 | ||
355 | return true | |
356 | } | |
357 | } |