]>
Commit | Line | Data |
---|---|---|
bc90883f | 1 | import * as Bluebird from 'bluebird' |
97b65ce5 | 2 | import { FindAndCountOptions, json, QueryTypes } from 'sequelize' |
ad91e700 | 3 | import { AllowNull, Column, CreatedAt, DataType, DefaultScope, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
26d6bf65 | 4 | import { MPlugin, MPluginFormattable } from '@server/types/models' |
bc90883f C |
5 | import { PeerTubePlugin } from '../../../shared/models/plugins/peertube-plugin.model' |
6 | import { PluginType } from '../../../shared/models/plugins/plugin.type' | |
7 | import { RegisterServerSettingOptions } from '../../../shared/models/plugins/register-server-setting.model' | |
345da516 | 8 | import { |
b5f919ac C |
9 | isPluginDescriptionValid, |
10 | isPluginHomepage, | |
345da516 C |
11 | isPluginNameValid, |
12 | isPluginTypeValid, | |
13 | isPluginVersionValid | |
14 | } from '../../helpers/custom-validators/plugins' | |
bc90883f | 15 | import { getSort, throwIfNotValid } from '../utils' |
ad91e700 C |
16 | |
17 | @DefaultScope(() => ({ | |
18 | attributes: { | |
19 | exclude: [ 'storage' ] | |
20 | } | |
21 | })) | |
345da516 C |
22 | |
23 | @Table({ | |
24 | tableName: 'plugin', | |
25 | indexes: [ | |
26 | { | |
dba85a1e | 27 | fields: [ 'name', 'type' ], |
345da516 C |
28 | unique: true |
29 | } | |
30 | ] | |
31 | }) | |
32 | export class PluginModel extends Model<PluginModel> { | |
33 | ||
34 | @AllowNull(false) | |
35 | @Is('PluginName', value => throwIfNotValid(value, isPluginNameValid, 'name')) | |
36 | @Column | |
37 | name: string | |
38 | ||
39 | @AllowNull(false) | |
40 | @Is('PluginType', value => throwIfNotValid(value, isPluginTypeValid, 'type')) | |
41 | @Column | |
42 | type: number | |
43 | ||
44 | @AllowNull(false) | |
45 | @Is('PluginVersion', value => throwIfNotValid(value, isPluginVersionValid, 'version')) | |
46 | @Column | |
47 | version: string | |
48 | ||
b5f919ac C |
49 | @AllowNull(true) |
50 | @Is('PluginLatestVersion', value => throwIfNotValid(value, isPluginVersionValid, 'version')) | |
51 | @Column | |
52 | latestVersion: string | |
53 | ||
345da516 C |
54 | @AllowNull(false) |
55 | @Column | |
56 | enabled: boolean | |
57 | ||
58 | @AllowNull(false) | |
59 | @Column | |
60 | uninstalled: boolean | |
61 | ||
62 | @AllowNull(false) | |
345da516 C |
63 | @Column |
64 | peertubeEngine: string | |
65 | ||
66 | @AllowNull(true) | |
67 | @Is('PluginDescription', value => throwIfNotValid(value, isPluginDescriptionValid, 'description')) | |
68 | @Column | |
69 | description: string | |
70 | ||
dba85a1e C |
71 | @AllowNull(false) |
72 | @Is('PluginHomepage', value => throwIfNotValid(value, isPluginHomepage, 'homepage')) | |
73 | @Column | |
74 | homepage: string | |
75 | ||
345da516 C |
76 | @AllowNull(true) |
77 | @Column(DataType.JSONB) | |
78 | settings: any | |
79 | ||
80 | @AllowNull(true) | |
81 | @Column(DataType.JSONB) | |
82 | storage: any | |
83 | ||
84 | @CreatedAt | |
85 | createdAt: Date | |
86 | ||
87 | @UpdatedAt | |
88 | updatedAt: Date | |
89 | ||
453e83ea | 90 | static listEnabledPluginsAndThemes (): Bluebird<MPlugin[]> { |
345da516 C |
91 | const query = { |
92 | where: { | |
93 | enabled: true, | |
94 | uninstalled: false | |
95 | } | |
96 | } | |
97 | ||
98 | return PluginModel.findAll(query) | |
99 | } | |
100 | ||
453e83ea | 101 | static loadByNpmName (npmName: string): Bluebird<MPlugin> { |
dba85a1e C |
102 | const name = this.normalizePluginName(npmName) |
103 | const type = this.getTypeFromNpmName(npmName) | |
104 | ||
2c053942 C |
105 | const query = { |
106 | where: { | |
dba85a1e C |
107 | name, |
108 | type | |
2c053942 C |
109 | } |
110 | } | |
111 | ||
112 | return PluginModel.findOne(query) | |
113 | } | |
114 | ||
bc90883f | 115 | static getSetting (pluginName: string, pluginType: PluginType, settingName: string, registeredSettings: RegisterServerSettingOptions[]) { |
ad91e700 C |
116 | const query = { |
117 | attributes: [ 'settings' ], | |
118 | where: { | |
b5f919ac C |
119 | name: pluginName, |
120 | type: pluginType | |
ad91e700 C |
121 | } |
122 | } | |
123 | ||
124 | return PluginModel.findOne(query) | |
b5f919ac | 125 | .then(p => { |
15b4bcdf | 126 | if (!p || !p.settings || p.settings === undefined) { |
bc90883f C |
127 | const registered = registeredSettings.find(s => s.name === settingName) |
128 | if (!registered || registered.default === undefined) return undefined | |
129 | ||
130 | return registered.default | |
131 | } | |
ad91e700 | 132 | |
b5f919ac | 133 | return p.settings[settingName] |
ad91e700 C |
134 | }) |
135 | } | |
136 | ||
bc90883f C |
137 | static getSettings ( |
138 | pluginName: string, | |
139 | pluginType: PluginType, | |
140 | settingNames: string[], | |
141 | registeredSettings: RegisterServerSettingOptions[] | |
142 | ) { | |
055cfb11 C |
143 | const query = { |
144 | attributes: [ 'settings' ], | |
145 | where: { | |
146 | name: pluginName, | |
147 | type: pluginType | |
148 | } | |
149 | } | |
150 | ||
151 | return PluginModel.findOne(query) | |
152 | .then(p => { | |
bc90883f | 153 | const result: { [settingName: string ]: string | boolean } = {} |
055cfb11 | 154 | |
bc90883f | 155 | for (const name of settingNames) { |
15b4bcdf | 156 | if (!p || !p.settings || p.settings[name] === undefined) { |
bc90883f | 157 | const registered = registeredSettings.find(s => s.name === name) |
055cfb11 | 158 | |
bc90883f C |
159 | if (registered?.default !== undefined) { |
160 | result[name] = registered.default | |
161 | } | |
162 | } else { | |
163 | result[name] = p.settings[name] | |
055cfb11 C |
164 | } |
165 | } | |
166 | ||
167 | return result | |
168 | }) | |
169 | } | |
170 | ||
b5f919ac | 171 | static setSetting (pluginName: string, pluginType: PluginType, settingName: string, settingValue: string) { |
f023a19c C |
172 | const query = { |
173 | where: { | |
b5f919ac C |
174 | name: pluginName, |
175 | type: pluginType | |
f023a19c C |
176 | } |
177 | } | |
178 | ||
ad91e700 C |
179 | const toSave = { |
180 | [`settings.${settingName}`]: settingValue | |
181 | } | |
182 | ||
183 | return PluginModel.update(toSave, query) | |
184 | .then(() => undefined) | |
185 | } | |
186 | ||
b2195faf C |
187 | static getData (pluginName: string, pluginType: PluginType, key: string) { |
188 | const query = { | |
189 | raw: true, | |
190 | attributes: [ [ json('storage.' + key), 'value' ] as any ], // FIXME: typings | |
191 | where: { | |
192 | name: pluginName, | |
193 | type: pluginType | |
194 | } | |
195 | } | |
196 | ||
197 | return PluginModel.findOne(query) | |
109d893f | 198 | .then((c: any) => { |
b2195faf | 199 | if (!c) return undefined |
9fa6ca16 C |
200 | const value = c.value |
201 | ||
202 | if (typeof value === 'string' && value.startsWith('{')) { | |
203 | try { | |
204 | return JSON.parse(value) | |
205 | } catch { | |
206 | return value | |
207 | } | |
208 | } | |
b2195faf C |
209 | |
210 | return c.value | |
211 | }) | |
212 | } | |
213 | ||
214 | static storeData (pluginName: string, pluginType: PluginType, key: string, data: any) { | |
97b65ce5 C |
215 | const query = 'UPDATE "plugin" SET "storage" = jsonb_set(coalesce("storage", \'{}\'), :key, :data::jsonb) ' + |
216 | 'WHERE "name" = :pluginName AND "type" = :pluginType' | |
b2195faf | 217 | |
97b65ce5 C |
218 | const jsonPath = '{' + key + '}' |
219 | ||
220 | const options = { | |
221 | replacements: { pluginName, pluginType, key: jsonPath, data: JSON.stringify(data) }, | |
222 | type: QueryTypes.UPDATE | |
b2195faf C |
223 | } |
224 | ||
97b65ce5 | 225 | return PluginModel.sequelize.query(query, options) |
b2195faf C |
226 | .then(() => undefined) |
227 | } | |
228 | ||
ad91e700 | 229 | static listForApi (options: { |
a1587156 C |
230 | pluginType?: PluginType |
231 | uninstalled?: boolean | |
232 | start: number | |
233 | count: number | |
ad91e700 C |
234 | sort: string |
235 | }) { | |
8d2be0ed | 236 | const { uninstalled = false } = options |
ad91e700 C |
237 | const query: FindAndCountOptions = { |
238 | offset: options.start, | |
239 | limit: options.count, | |
240 | order: getSort(options.sort), | |
8d2be0ed C |
241 | where: { |
242 | uninstalled | |
243 | } | |
ad91e700 C |
244 | } |
245 | ||
6702a1b2 | 246 | if (options.pluginType) query.where['type'] = options.pluginType |
ad91e700 C |
247 | |
248 | return PluginModel | |
453e83ea | 249 | .findAndCountAll<MPlugin>(query) |
ad91e700 C |
250 | .then(({ rows, count }) => { |
251 | return { total: count, data: rows } | |
252 | }) | |
253 | } | |
254 | ||
453e83ea | 255 | static listInstalled (): Bluebird<MPlugin[]> { |
6702a1b2 C |
256 | const query = { |
257 | where: { | |
258 | uninstalled: false | |
259 | } | |
260 | } | |
261 | ||
262 | return PluginModel.findAll(query) | |
263 | } | |
264 | ||
265 | static normalizePluginName (npmName: string) { | |
266 | return npmName.replace(/^peertube-((theme)|(plugin))-/, '') | |
dba85a1e C |
267 | } |
268 | ||
269 | static getTypeFromNpmName (npmName: string) { | |
270 | return npmName.startsWith('peertube-plugin-') | |
271 | ? PluginType.PLUGIN | |
272 | : PluginType.THEME | |
273 | } | |
274 | ||
b5f919ac C |
275 | static buildNpmName (name: string, type: PluginType) { |
276 | if (type === PluginType.THEME) return 'peertube-theme-' + name | |
277 | ||
278 | return 'peertube-plugin-' + name | |
279 | } | |
280 | ||
ba211e73 C |
281 | getPublicSettings (registeredSettings: RegisterServerSettingOptions[]) { |
282 | const result: { [ name: string ]: string } = {} | |
283 | const settings = this.settings || {} | |
284 | ||
285 | for (const r of registeredSettings) { | |
286 | if (r.private !== false) continue | |
287 | ||
288 | result[r.name] = settings[r.name] || r.default || null | |
289 | } | |
290 | ||
291 | return result | |
292 | } | |
293 | ||
1ca9f7c3 | 294 | toFormattedJSON (this: MPluginFormattable): PeerTubePlugin { |
ad91e700 C |
295 | return { |
296 | name: this.name, | |
297 | type: this.type, | |
298 | version: this.version, | |
b5f919ac | 299 | latestVersion: this.latestVersion, |
ad91e700 C |
300 | enabled: this.enabled, |
301 | uninstalled: this.uninstalled, | |
302 | peertubeEngine: this.peertubeEngine, | |
303 | description: this.description, | |
dba85a1e | 304 | homepage: this.homepage, |
ad91e700 C |
305 | settings: this.settings, |
306 | createdAt: this.createdAt, | |
307 | updatedAt: this.updatedAt | |
308 | } | |
f023a19c C |
309 | } |
310 | ||
345da516 | 311 | } |