+import { FindAndCountOptions, json, QueryTypes } from 'sequelize'
import { AllowNull, Column, CreatedAt, DataType, DefaultScope, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
-import { getSort, throwIfNotValid } from '../utils'
+import { MPlugin, MPluginFormattable } from '@server/types/models'
+import { AttributesOnly } from '@shared/typescript-utils'
+import { PeerTubePlugin, PluginType, RegisterServerSettingOptions, SettingEntries, SettingValue } from '../../../shared/models'
import {
isPluginDescriptionValid,
isPluginHomepage,
isPluginTypeValid,
isPluginVersionValid
} from '../../helpers/custom-validators/plugins'
-import { PluginType } from '../../../shared/models/plugins/plugin.type'
-import { PeerTubePlugin } from '../../../shared/models/plugins/peertube-plugin.model'
-import { FindAndCountOptions, json } from 'sequelize'
-import { RegisterServerSettingOptions } from '../../../shared/models/plugins/register-server-setting.model'
+import { getSort, throwIfNotValid } from '../utils'
@DefaultScope(() => ({
attributes: {
}
]
})
-export class PluginModel extends Model<PluginModel> {
+export class PluginModel extends Model<Partial<AttributesOnly<PluginModel>>> {
@AllowNull(false)
@Is('PluginName', value => throwIfNotValid(value, isPluginNameValid, 'name'))
@UpdatedAt
updatedAt: Date
- static listEnabledPluginsAndThemes () {
+ static listEnabledPluginsAndThemes (): Promise<MPlugin[]> {
const query = {
where: {
enabled: true,
return PluginModel.findAll(query)
}
- static loadByNpmName (npmName: string) {
+ static loadByNpmName (npmName: string): Promise<MPlugin> {
const name = this.normalizePluginName(npmName)
const type = this.getTypeFromNpmName(npmName)
return PluginModel.findOne(query)
}
- static getSetting (pluginName: string, pluginType: PluginType, settingName: string) {
+ static getSetting (pluginName: string, pluginType: PluginType, settingName: string, registeredSettings: RegisterServerSettingOptions[]) {
const query = {
attributes: [ 'settings' ],
where: {
return PluginModel.findOne(query)
.then(p => {
- if (!p || !p.settings) return undefined
+ if (!p || !p.settings || p.settings === undefined) {
+ const registered = registeredSettings.find(s => s.name === settingName)
+ if (!registered || registered.default === undefined) return undefined
+
+ return registered.default
+ }
return p.settings[settingName]
})
}
- static setSetting (pluginName: string, pluginType: PluginType, settingName: string, settingValue: string) {
+ static getSettings (
+ pluginName: string,
+ pluginType: PluginType,
+ settingNames: string[],
+ registeredSettings: RegisterServerSettingOptions[]
+ ) {
+ const query = {
+ attributes: [ 'settings' ],
+ where: {
+ name: pluginName,
+ type: pluginType
+ }
+ }
+
+ return PluginModel.findOne(query)
+ .then(p => {
+ const result: SettingEntries = {}
+
+ for (const name of settingNames) {
+ if (!p || !p.settings || p.settings[name] === undefined) {
+ const registered = registeredSettings.find(s => s.name === name)
+
+ if (registered?.default !== undefined) {
+ result[name] = registered.default
+ }
+ } else {
+ result[name] = p.settings[name]
+ }
+ }
+
+ return result
+ })
+ }
+
+ static setSetting (pluginName: string, pluginType: PluginType, settingName: string, settingValue: SettingValue) {
const query = {
where: {
name: pluginName,
if (!c) return undefined
const value = c.value
- if (typeof value === 'string' && value.startsWith('{')) {
- try {
- return JSON.parse(value)
- } catch {
- return value
- }
+ try {
+ return JSON.parse(value)
+ } catch {
+ return value
}
-
- return c.value
})
}
static storeData (pluginName: string, pluginType: PluginType, key: string, data: any) {
- const query = {
- where: {
- name: pluginName,
- type: pluginType
- }
- }
+ const query = 'UPDATE "plugin" SET "storage" = jsonb_set(coalesce("storage", \'{}\'), :key, :data::jsonb) ' +
+ 'WHERE "name" = :pluginName AND "type" = :pluginType'
- const toSave = {
- [`storage.${key}`]: data
+ const jsonPath = '{' + key + '}'
+
+ const options = {
+ replacements: { pluginName, pluginType, key: jsonPath, data: JSON.stringify(data) },
+ type: QueryTypes.UPDATE
}
- return PluginModel.update(toSave, query)
+ return PluginModel.sequelize.query(query, options)
.then(() => undefined)
}
static listForApi (options: {
- pluginType?: PluginType,
- uninstalled?: boolean,
- start: number,
- count: number,
+ pluginType?: PluginType
+ uninstalled?: boolean
+ start: number
+ count: number
sort: string
}) {
const { uninstalled = false } = options
if (options.pluginType) query.where['type'] = options.pluginType
- return PluginModel
- .findAndCountAll(query)
- .then(({ rows, count }) => {
- return { total: count, data: rows }
- })
+ return Promise.all([
+ PluginModel.count(query),
+ PluginModel.findAll<MPlugin>(query)
+ ]).then(([ total, data ]) => ({ total, data }))
}
- static listInstalled () {
+ static listInstalled (): Promise<MPlugin[]> {
const query = {
where: {
uninstalled: false
}
getPublicSettings (registeredSettings: RegisterServerSettingOptions[]) {
- const result: { [ name: string ]: string } = {}
+ const result: SettingEntries = {}
const settings = this.settings || {}
for (const r of registeredSettings) {
if (r.private !== false) continue
- result[r.name] = settings[r.name] || r.default || null
+ result[r.name] = settings[r.name] ?? r.default ?? null
}
return result
}
- toFormattedJSON (): PeerTubePlugin {
+ toFormattedJSON (this: MPluginFormattable): PeerTubePlugin {
return {
name: this.name,
type: this.type,