]>
Commit | Line | Data |
---|---|---|
1 | import { AllowNull, Column, CreatedAt, DataType, DefaultScope, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | |
2 | import { getSort, throwIfNotValid } from '../utils' | |
3 | import { | |
4 | isPluginDescriptionValid, | |
5 | isPluginHomepage, | |
6 | isPluginNameValid, | |
7 | isPluginTypeValid, | |
8 | isPluginVersionValid | |
9 | } from '../../helpers/custom-validators/plugins' | |
10 | import { PluginType } from '../../../shared/models/plugins/plugin.type' | |
11 | import { PeerTubePlugin } from '../../../shared/models/plugins/peertube-plugin.model' | |
12 | import { FindAndCountOptions, json } from 'sequelize' | |
13 | import { RegisterServerSettingOptions } from '../../../shared/models/plugins/register-server-setting.model' | |
14 | import * as Bluebird from 'bluebird' | |
15 | import { MPlugin, MPluginFormattable } from '@server/typings/models' | |
16 | ||
17 | @DefaultScope(() => ({ | |
18 | attributes: { | |
19 | exclude: [ 'storage' ] | |
20 | } | |
21 | })) | |
22 | ||
23 | @Table({ | |
24 | tableName: 'plugin', | |
25 | indexes: [ | |
26 | { | |
27 | fields: [ 'name', 'type' ], | |
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 | ||
49 | @AllowNull(true) | |
50 | @Is('PluginLatestVersion', value => throwIfNotValid(value, isPluginVersionValid, 'version')) | |
51 | @Column | |
52 | latestVersion: string | |
53 | ||
54 | @AllowNull(false) | |
55 | @Column | |
56 | enabled: boolean | |
57 | ||
58 | @AllowNull(false) | |
59 | @Column | |
60 | uninstalled: boolean | |
61 | ||
62 | @AllowNull(false) | |
63 | @Column | |
64 | peertubeEngine: string | |
65 | ||
66 | @AllowNull(true) | |
67 | @Is('PluginDescription', value => throwIfNotValid(value, isPluginDescriptionValid, 'description')) | |
68 | @Column | |
69 | description: string | |
70 | ||
71 | @AllowNull(false) | |
72 | @Is('PluginHomepage', value => throwIfNotValid(value, isPluginHomepage, 'homepage')) | |
73 | @Column | |
74 | homepage: string | |
75 | ||
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 | ||
90 | static listEnabledPluginsAndThemes (): Bluebird<MPlugin[]> { | |
91 | const query = { | |
92 | where: { | |
93 | enabled: true, | |
94 | uninstalled: false | |
95 | } | |
96 | } | |
97 | ||
98 | return PluginModel.findAll(query) | |
99 | } | |
100 | ||
101 | static loadByNpmName (npmName: string): Bluebird<MPlugin> { | |
102 | const name = this.normalizePluginName(npmName) | |
103 | const type = this.getTypeFromNpmName(npmName) | |
104 | ||
105 | const query = { | |
106 | where: { | |
107 | name, | |
108 | type | |
109 | } | |
110 | } | |
111 | ||
112 | return PluginModel.findOne(query) | |
113 | } | |
114 | ||
115 | static getSetting (pluginName: string, pluginType: PluginType, settingName: string) { | |
116 | const query = { | |
117 | attributes: [ 'settings' ], | |
118 | where: { | |
119 | name: pluginName, | |
120 | type: pluginType | |
121 | } | |
122 | } | |
123 | ||
124 | return PluginModel.findOne(query) | |
125 | .then(p => { | |
126 | if (!p || !p.settings) return undefined | |
127 | ||
128 | return p.settings[settingName] | |
129 | }) | |
130 | } | |
131 | ||
132 | static setSetting (pluginName: string, pluginType: PluginType, settingName: string, settingValue: string) { | |
133 | const query = { | |
134 | where: { | |
135 | name: pluginName, | |
136 | type: pluginType | |
137 | } | |
138 | } | |
139 | ||
140 | const toSave = { | |
141 | [`settings.${settingName}`]: settingValue | |
142 | } | |
143 | ||
144 | return PluginModel.update(toSave, query) | |
145 | .then(() => undefined) | |
146 | } | |
147 | ||
148 | static getData (pluginName: string, pluginType: PluginType, key: string) { | |
149 | const query = { | |
150 | raw: true, | |
151 | attributes: [ [ json('storage.' + key), 'value' ] as any ], // FIXME: typings | |
152 | where: { | |
153 | name: pluginName, | |
154 | type: pluginType | |
155 | } | |
156 | } | |
157 | ||
158 | return PluginModel.findOne(query) | |
159 | .then((c: any) => { | |
160 | if (!c) return undefined | |
161 | const value = c.value | |
162 | ||
163 | if (typeof value === 'string' && value.startsWith('{')) { | |
164 | try { | |
165 | return JSON.parse(value) | |
166 | } catch { | |
167 | return value | |
168 | } | |
169 | } | |
170 | ||
171 | return c.value | |
172 | }) | |
173 | } | |
174 | ||
175 | static storeData (pluginName: string, pluginType: PluginType, key: string, data: any) { | |
176 | const query = { | |
177 | where: { | |
178 | name: pluginName, | |
179 | type: pluginType | |
180 | } | |
181 | } | |
182 | ||
183 | const toSave = { | |
184 | [`storage.${key}`]: data | |
185 | } | |
186 | ||
187 | return PluginModel.update(toSave, query) | |
188 | .then(() => undefined) | |
189 | } | |
190 | ||
191 | static listForApi (options: { | |
192 | pluginType?: PluginType, | |
193 | uninstalled?: boolean, | |
194 | start: number, | |
195 | count: number, | |
196 | sort: string | |
197 | }) { | |
198 | const { uninstalled = false } = options | |
199 | const query: FindAndCountOptions = { | |
200 | offset: options.start, | |
201 | limit: options.count, | |
202 | order: getSort(options.sort), | |
203 | where: { | |
204 | uninstalled | |
205 | } | |
206 | } | |
207 | ||
208 | if (options.pluginType) query.where['type'] = options.pluginType | |
209 | ||
210 | return PluginModel | |
211 | .findAndCountAll<MPlugin>(query) | |
212 | .then(({ rows, count }) => { | |
213 | return { total: count, data: rows } | |
214 | }) | |
215 | } | |
216 | ||
217 | static listInstalled (): Bluebird<MPlugin[]> { | |
218 | const query = { | |
219 | where: { | |
220 | uninstalled: false | |
221 | } | |
222 | } | |
223 | ||
224 | return PluginModel.findAll(query) | |
225 | } | |
226 | ||
227 | static normalizePluginName (npmName: string) { | |
228 | return npmName.replace(/^peertube-((theme)|(plugin))-/, '') | |
229 | } | |
230 | ||
231 | static getTypeFromNpmName (npmName: string) { | |
232 | return npmName.startsWith('peertube-plugin-') | |
233 | ? PluginType.PLUGIN | |
234 | : PluginType.THEME | |
235 | } | |
236 | ||
237 | static buildNpmName (name: string, type: PluginType) { | |
238 | if (type === PluginType.THEME) return 'peertube-theme-' + name | |
239 | ||
240 | return 'peertube-plugin-' + name | |
241 | } | |
242 | ||
243 | getPublicSettings (registeredSettings: RegisterServerSettingOptions[]) { | |
244 | const result: { [ name: string ]: string } = {} | |
245 | const settings = this.settings || {} | |
246 | ||
247 | for (const r of registeredSettings) { | |
248 | if (r.private !== false) continue | |
249 | ||
250 | result[r.name] = settings[r.name] || r.default || null | |
251 | } | |
252 | ||
253 | return result | |
254 | } | |
255 | ||
256 | toFormattedJSON (this: MPluginFormattable): PeerTubePlugin { | |
257 | return { | |
258 | name: this.name, | |
259 | type: this.type, | |
260 | version: this.version, | |
261 | latestVersion: this.latestVersion, | |
262 | enabled: this.enabled, | |
263 | uninstalled: this.uninstalled, | |
264 | peertubeEngine: this.peertubeEngine, | |
265 | description: this.description, | |
266 | homepage: this.homepage, | |
267 | settings: this.settings, | |
268 | createdAt: this.createdAt, | |
269 | updatedAt: this.updatedAt | |
270 | } | |
271 | } | |
272 | ||
273 | } |