]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/models/server/plugin.ts
Merge branch 'master' into develop
[github/Chocobozzz/PeerTube.git] / server / models / server / plugin.ts
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 }