diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/plugins.ts | 28 | ||||
-rw-r--r-- | server/initializers/config.ts | 6 | ||||
-rw-r--r-- | server/initializers/constants.ts | 5 | ||||
-rw-r--r-- | server/lib/plugins/plugin-index.ts | 64 | ||||
-rw-r--r-- | server/lib/plugins/plugin-manager.ts | 4 | ||||
-rw-r--r-- | server/lib/schedulers/plugins-check-scheduler.ts | 60 | ||||
-rw-r--r-- | server/middlewares/validators/plugins.ts | 30 | ||||
-rw-r--r-- | server/middlewares/validators/sort.ts | 3 | ||||
-rw-r--r-- | server/models/server/plugin.ts | 19 |
9 files changed, 210 insertions, 9 deletions
diff --git a/server/controllers/api/plugins.ts b/server/controllers/api/plugins.ts index 14675fdf3..114cc49b6 100644 --- a/server/controllers/api/plugins.ts +++ b/server/controllers/api/plugins.ts | |||
@@ -8,12 +8,13 @@ import { | |||
8 | setDefaultPagination, | 8 | setDefaultPagination, |
9 | setDefaultSort | 9 | setDefaultSort |
10 | } from '../../middlewares' | 10 | } from '../../middlewares' |
11 | import { pluginsSortValidator } from '../../middlewares/validators' | 11 | import { availablePluginsSortValidator, pluginsSortValidator } from '../../middlewares/validators' |
12 | import { PluginModel } from '../../models/server/plugin' | 12 | import { PluginModel } from '../../models/server/plugin' |
13 | import { UserRight } from '../../../shared/models/users' | 13 | import { UserRight } from '../../../shared/models/users' |
14 | import { | 14 | import { |
15 | existingPluginValidator, | 15 | existingPluginValidator, |
16 | installOrUpdatePluginValidator, | 16 | installOrUpdatePluginValidator, |
17 | listAvailablePluginsValidator, | ||
17 | listPluginsValidator, | 18 | listPluginsValidator, |
18 | uninstallPluginValidator, | 19 | uninstallPluginValidator, |
19 | updatePluginSettingsValidator | 20 | updatePluginSettingsValidator |
@@ -22,9 +23,22 @@ import { PluginManager } from '../../lib/plugins/plugin-manager' | |||
22 | import { InstallOrUpdatePlugin } from '../../../shared/models/plugins/install-plugin.model' | 23 | import { InstallOrUpdatePlugin } from '../../../shared/models/plugins/install-plugin.model' |
23 | import { ManagePlugin } from '../../../shared/models/plugins/manage-plugin.model' | 24 | import { ManagePlugin } from '../../../shared/models/plugins/manage-plugin.model' |
24 | import { logger } from '../../helpers/logger' | 25 | import { logger } from '../../helpers/logger' |
26 | import { listAvailablePluginsFromIndex } from '../../lib/plugins/plugin-index' | ||
27 | import { PeertubePluginIndexList } from '../../../shared/models/plugins/peertube-plugin-index-list.model' | ||
25 | 28 | ||
26 | const pluginRouter = express.Router() | 29 | const pluginRouter = express.Router() |
27 | 30 | ||
31 | pluginRouter.get('/available', | ||
32 | authenticate, | ||
33 | ensureUserHasRight(UserRight.MANAGE_PLUGINS), | ||
34 | listAvailablePluginsValidator, | ||
35 | paginationValidator, | ||
36 | availablePluginsSortValidator, | ||
37 | setDefaultSort, | ||
38 | setDefaultPagination, | ||
39 | asyncMiddleware(listAvailablePlugins) | ||
40 | ) | ||
41 | |||
28 | pluginRouter.get('/', | 42 | pluginRouter.get('/', |
29 | authenticate, | 43 | authenticate, |
30 | ensureUserHasRight(UserRight.MANAGE_PLUGINS), | 44 | ensureUserHasRight(UserRight.MANAGE_PLUGINS), |
@@ -88,10 +102,10 @@ export { | |||
88 | // --------------------------------------------------------------------------- | 102 | // --------------------------------------------------------------------------- |
89 | 103 | ||
90 | async function listPlugins (req: express.Request, res: express.Response) { | 104 | async function listPlugins (req: express.Request, res: express.Response) { |
91 | const type = req.query.type | 105 | const pluginType = req.query.pluginType |
92 | 106 | ||
93 | const resultList = await PluginModel.listForApi({ | 107 | const resultList = await PluginModel.listForApi({ |
94 | type, | 108 | pluginType, |
95 | start: req.query.start, | 109 | start: req.query.start, |
96 | count: req.query.count, | 110 | count: req.query.count, |
97 | sort: req.query.sort | 111 | sort: req.query.sort |
@@ -160,3 +174,11 @@ async function updatePluginSettings (req: express.Request, res: express.Response | |||
160 | 174 | ||
161 | return res.sendStatus(204) | 175 | return res.sendStatus(204) |
162 | } | 176 | } |
177 | |||
178 | async function listAvailablePlugins (req: express.Request, res: express.Response) { | ||
179 | const query: PeertubePluginIndexList = req.query | ||
180 | |||
181 | const resultList = await listAvailablePluginsFromIndex(query) | ||
182 | |||
183 | return res.json(resultList) | ||
184 | } | ||
diff --git a/server/initializers/config.ts b/server/initializers/config.ts index dfc4bea21..2c1b30021 100644 --- a/server/initializers/config.ts +++ b/server/initializers/config.ts | |||
@@ -134,6 +134,12 @@ const CONFIG = { | |||
134 | } | 134 | } |
135 | } | 135 | } |
136 | }, | 136 | }, |
137 | PLUGINS: { | ||
138 | INDEX: { | ||
139 | ENABLED: config.get<boolean>('plugins.index.enabled'), | ||
140 | URL: config.get<boolean>('plugins.index.url') | ||
141 | } | ||
142 | }, | ||
137 | ADMIN: { | 143 | ADMIN: { |
138 | get EMAIL () { return config.get<string>('admin.email') } | 144 | get EMAIL () { return config.get<string>('admin.email') } |
139 | }, | 145 | }, |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 2d487a263..06e8c070b 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -64,7 +64,9 @@ const SORTABLE_COLUMNS = { | |||
64 | 64 | ||
65 | VIDEO_PLAYLISTS: [ 'displayName', 'createdAt', 'updatedAt' ], | 65 | VIDEO_PLAYLISTS: [ 'displayName', 'createdAt', 'updatedAt' ], |
66 | 66 | ||
67 | PLUGINS: [ 'name', 'createdAt', 'updatedAt' ] | 67 | PLUGINS: [ 'name', 'createdAt', 'updatedAt' ], |
68 | |||
69 | AVAILABLE_PLUGINS: [ 'npmName', 'popularity' ] | ||
68 | } | 70 | } |
69 | 71 | ||
70 | const OAUTH_LIFETIME = { | 72 | const OAUTH_LIFETIME = { |
@@ -165,6 +167,7 @@ const SCHEDULER_INTERVALS_MS = { | |||
165 | removeOldJobs: 60000 * 60, // 1 hour | 167 | removeOldJobs: 60000 * 60, // 1 hour |
166 | updateVideos: 60000, // 1 minute | 168 | updateVideos: 60000, // 1 minute |
167 | youtubeDLUpdate: 60000 * 60 * 24, // 1 day | 169 | youtubeDLUpdate: 60000 * 60 * 24, // 1 day |
170 | checkPlugins: 60000 * 60 * 24, // 1 day | ||
168 | removeOldViews: 60000 * 60 * 24, // 1 day | 171 | removeOldViews: 60000 * 60 * 24, // 1 day |
169 | removeOldHistory: 60000 * 60 * 24 // 1 day | 172 | removeOldHistory: 60000 * 60 * 24 // 1 day |
170 | } | 173 | } |
diff --git a/server/lib/plugins/plugin-index.ts b/server/lib/plugins/plugin-index.ts new file mode 100644 index 000000000..4a8a90ec8 --- /dev/null +++ b/server/lib/plugins/plugin-index.ts | |||
@@ -0,0 +1,64 @@ | |||
1 | import { doRequest } from '../../helpers/requests' | ||
2 | import { CONFIG } from '../../initializers/config' | ||
3 | import { | ||
4 | PeertubePluginLatestVersionRequest, | ||
5 | PeertubePluginLatestVersionResponse | ||
6 | } from '../../../shared/models/plugins/peertube-plugin-latest-version.model' | ||
7 | import { PeertubePluginIndexList } from '../../../shared/models/plugins/peertube-plugin-index-list.model' | ||
8 | import { ResultList } from '../../../shared/models' | ||
9 | import { PeerTubePluginIndex } from '../../../shared/models/plugins/peertube-plugin-index.model' | ||
10 | import { PluginModel } from '../../models/server/plugin' | ||
11 | import { PluginManager } from './plugin-manager' | ||
12 | import { logger } from '../../helpers/logger' | ||
13 | |||
14 | const packageJSON = require('../../../../package.json') | ||
15 | |||
16 | async function listAvailablePluginsFromIndex (options: PeertubePluginIndexList) { | ||
17 | const { start = 0, count = 20, search, sort = 'npmName', pluginType } = options | ||
18 | |||
19 | const qs: PeertubePluginIndexList = { | ||
20 | start, | ||
21 | count, | ||
22 | sort, | ||
23 | pluginType, | ||
24 | search, | ||
25 | currentPeerTubeEngine: packageJSON.version | ||
26 | } | ||
27 | |||
28 | const uri = CONFIG.PLUGINS.INDEX.URL + '/api/v1/plugins' | ||
29 | |||
30 | const { body } = await doRequest({ uri, qs, json: true }) | ||
31 | |||
32 | logger.debug('Got result from PeerTube index.', { body }) | ||
33 | |||
34 | await addInstanceInformation(body) | ||
35 | |||
36 | return body as ResultList<PeerTubePluginIndex> | ||
37 | } | ||
38 | |||
39 | async function addInstanceInformation (result: ResultList<PeerTubePluginIndex>) { | ||
40 | for (const d of result.data) { | ||
41 | d.installed = PluginManager.Instance.isRegistered(d.npmName) | ||
42 | d.name = PluginModel.normalizePluginName(d.npmName) | ||
43 | } | ||
44 | |||
45 | return result | ||
46 | } | ||
47 | |||
48 | async function getLatestPluginsVersion (npmNames: string[]): Promise<PeertubePluginLatestVersionResponse> { | ||
49 | const bodyRequest: PeertubePluginLatestVersionRequest = { | ||
50 | npmNames, | ||
51 | currentPeerTubeEngine: packageJSON.version | ||
52 | } | ||
53 | |||
54 | const uri = CONFIG.PLUGINS.INDEX.URL + '/api/v1/plugins/latest-version' | ||
55 | |||
56 | const { body } = await doRequest({ uri, body: bodyRequest }) | ||
57 | |||
58 | return body | ||
59 | } | ||
60 | |||
61 | export { | ||
62 | listAvailablePluginsFromIndex, | ||
63 | getLatestPluginsVersion | ||
64 | } | ||
diff --git a/server/lib/plugins/plugin-manager.ts b/server/lib/plugins/plugin-manager.ts index 7576b284c..9e4ec5adf 100644 --- a/server/lib/plugins/plugin-manager.ts +++ b/server/lib/plugins/plugin-manager.ts | |||
@@ -55,6 +55,10 @@ export class PluginManager { | |||
55 | 55 | ||
56 | // ###################### Getters ###################### | 56 | // ###################### Getters ###################### |
57 | 57 | ||
58 | isRegistered (npmName: string) { | ||
59 | return !!this.getRegisteredPluginOrTheme(npmName) | ||
60 | } | ||
61 | |||
58 | getRegisteredPluginOrTheme (npmName: string) { | 62 | getRegisteredPluginOrTheme (npmName: string) { |
59 | return this.registeredPlugins[npmName] | 63 | return this.registeredPlugins[npmName] |
60 | } | 64 | } |
diff --git a/server/lib/schedulers/plugins-check-scheduler.ts b/server/lib/schedulers/plugins-check-scheduler.ts new file mode 100644 index 000000000..9c60dbcd4 --- /dev/null +++ b/server/lib/schedulers/plugins-check-scheduler.ts | |||
@@ -0,0 +1,60 @@ | |||
1 | import { logger } from '../../helpers/logger' | ||
2 | import { AbstractScheduler } from './abstract-scheduler' | ||
3 | import { retryTransactionWrapper } from '../../helpers/database-utils' | ||
4 | import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' | ||
5 | import { CONFIG } from '../../initializers/config' | ||
6 | import { PluginModel } from '../../models/server/plugin' | ||
7 | import { chunk } from 'lodash' | ||
8 | import { getLatestPluginsVersion } from '../plugins/plugin-index' | ||
9 | import { compareSemVer } from '../../../shared/core-utils/miscs/miscs' | ||
10 | |||
11 | export class PluginsCheckScheduler extends AbstractScheduler { | ||
12 | |||
13 | private static instance: AbstractScheduler | ||
14 | |||
15 | protected schedulerIntervalMs = SCHEDULER_INTERVALS_MS.checkPlugins | ||
16 | |||
17 | private constructor () { | ||
18 | super() | ||
19 | } | ||
20 | |||
21 | protected async internalExecute () { | ||
22 | return retryTransactionWrapper(this.checkLatestPluginsVersion.bind(this)) | ||
23 | } | ||
24 | |||
25 | private async checkLatestPluginsVersion () { | ||
26 | if (CONFIG.PLUGINS.INDEX.ENABLED === false) return | ||
27 | |||
28 | logger.info('Checkin latest plugins version.') | ||
29 | |||
30 | const plugins = await PluginModel.listInstalled() | ||
31 | |||
32 | // Process 10 plugins in 1 HTTP request | ||
33 | const chunks = chunk(plugins, 10) | ||
34 | for (const chunk of chunks) { | ||
35 | // Find plugins according to their npm name | ||
36 | const pluginIndex: { [npmName: string]: PluginModel} = {} | ||
37 | for (const plugin of chunk) { | ||
38 | pluginIndex[PluginModel.buildNpmName(plugin.name, plugin.type)] = plugin | ||
39 | } | ||
40 | |||
41 | const npmNames = Object.keys(pluginIndex) | ||
42 | const results = await getLatestPluginsVersion(npmNames) | ||
43 | |||
44 | for (const result of results) { | ||
45 | const plugin = pluginIndex[result.npmName] | ||
46 | if (!result.latestVersion) continue | ||
47 | |||
48 | if (plugin.latestVersion !== result.latestVersion && compareSemVer(plugin.latestVersion, result.latestVersion) < 0) { | ||
49 | plugin.latestVersion = result.latestVersion | ||
50 | await plugin.save() | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | |||
55 | } | ||
56 | |||
57 | static get Instance () { | ||
58 | return this.instance || (this.instance = new this()) | ||
59 | } | ||
60 | } | ||
diff --git a/server/middlewares/validators/plugins.ts b/server/middlewares/validators/plugins.ts index 8103ec7d3..8cb3153aa 100644 --- a/server/middlewares/validators/plugins.ts +++ b/server/middlewares/validators/plugins.ts | |||
@@ -8,6 +8,7 @@ import { isBooleanValid, isSafePath } from '../../helpers/custom-validators/misc | |||
8 | import { PluginModel } from '../../models/server/plugin' | 8 | import { PluginModel } from '../../models/server/plugin' |
9 | import { InstallOrUpdatePlugin } from '../../../shared/models/plugins/install-plugin.model' | 9 | import { InstallOrUpdatePlugin } from '../../../shared/models/plugins/install-plugin.model' |
10 | import { PluginType } from '../../../shared/models/plugins/plugin.type' | 10 | import { PluginType } from '../../../shared/models/plugins/plugin.type' |
11 | import { CONFIG } from '../../initializers/config' | ||
11 | 12 | ||
12 | const servePluginStaticDirectoryValidator = (pluginType: PluginType) => [ | 13 | const servePluginStaticDirectoryValidator = (pluginType: PluginType) => [ |
13 | param('pluginName').custom(isPluginNameValid).withMessage('Should have a valid plugin name'), | 14 | param('pluginName').custom(isPluginNameValid).withMessage('Should have a valid plugin name'), |
@@ -33,7 +34,7 @@ const servePluginStaticDirectoryValidator = (pluginType: PluginType) => [ | |||
33 | ] | 34 | ] |
34 | 35 | ||
35 | const listPluginsValidator = [ | 36 | const listPluginsValidator = [ |
36 | query('type') | 37 | query('pluginType') |
37 | .optional() | 38 | .optional() |
38 | .custom(isPluginTypeValid).withMessage('Should have a valid plugin type'), | 39 | .custom(isPluginTypeValid).withMessage('Should have a valid plugin type'), |
39 | query('uninstalled') | 40 | query('uninstalled') |
@@ -119,12 +120,39 @@ const updatePluginSettingsValidator = [ | |||
119 | } | 120 | } |
120 | ] | 121 | ] |
121 | 122 | ||
123 | const listAvailablePluginsValidator = [ | ||
124 | query('sort') | ||
125 | .optional() | ||
126 | .exists().withMessage('Should have a valid sort'), | ||
127 | query('search') | ||
128 | .optional() | ||
129 | .exists().withMessage('Should have a valid search'), | ||
130 | query('pluginType') | ||
131 | .optional() | ||
132 | .custom(isPluginTypeValid).withMessage('Should have a valid plugin type'), | ||
133 | |||
134 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
135 | logger.debug('Checking enabledPluginValidator parameters', { parameters: req.query }) | ||
136 | |||
137 | if (areValidationErrors(req, res)) return | ||
138 | |||
139 | if (CONFIG.PLUGINS.INDEX.ENABLED === false) { | ||
140 | return res.status(400) | ||
141 | .json({ error: 'Plugin index is not enabled' }) | ||
142 | .end() | ||
143 | } | ||
144 | |||
145 | return next() | ||
146 | } | ||
147 | ] | ||
148 | |||
122 | // --------------------------------------------------------------------------- | 149 | // --------------------------------------------------------------------------- |
123 | 150 | ||
124 | export { | 151 | export { |
125 | servePluginStaticDirectoryValidator, | 152 | servePluginStaticDirectoryValidator, |
126 | updatePluginSettingsValidator, | 153 | updatePluginSettingsValidator, |
127 | uninstallPluginValidator, | 154 | uninstallPluginValidator, |
155 | listAvailablePluginsValidator, | ||
128 | existingPluginValidator, | 156 | existingPluginValidator, |
129 | installOrUpdatePluginValidator, | 157 | installOrUpdatePluginValidator, |
130 | listPluginsValidator | 158 | listPluginsValidator |
diff --git a/server/middlewares/validators/sort.ts b/server/middlewares/validators/sort.ts index 102db85cb..c75e701d6 100644 --- a/server/middlewares/validators/sort.ts +++ b/server/middlewares/validators/sort.ts | |||
@@ -22,6 +22,7 @@ const SORTABLE_SERVERS_BLOCKLIST_COLUMNS = createSortableColumns(SORTABLE_COLUMN | |||
22 | const SORTABLE_USER_NOTIFICATIONS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USER_NOTIFICATIONS) | 22 | const SORTABLE_USER_NOTIFICATIONS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USER_NOTIFICATIONS) |
23 | const SORTABLE_VIDEO_PLAYLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_PLAYLISTS) | 23 | const SORTABLE_VIDEO_PLAYLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_PLAYLISTS) |
24 | const SORTABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.PLUGINS) | 24 | const SORTABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.PLUGINS) |
25 | const SORTABLE_AVAILABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.AVAILABLE_PLUGINS) | ||
25 | 26 | ||
26 | const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) | 27 | const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) |
27 | const accountsSortValidator = checkSort(SORTABLE_ACCOUNTS_COLUMNS) | 28 | const accountsSortValidator = checkSort(SORTABLE_ACCOUNTS_COLUMNS) |
@@ -43,6 +44,7 @@ const serversBlocklistSortValidator = checkSort(SORTABLE_SERVERS_BLOCKLIST_COLUM | |||
43 | const userNotificationsSortValidator = checkSort(SORTABLE_USER_NOTIFICATIONS_COLUMNS) | 44 | const userNotificationsSortValidator = checkSort(SORTABLE_USER_NOTIFICATIONS_COLUMNS) |
44 | const videoPlaylistsSortValidator = checkSort(SORTABLE_VIDEO_PLAYLISTS_COLUMNS) | 45 | const videoPlaylistsSortValidator = checkSort(SORTABLE_VIDEO_PLAYLISTS_COLUMNS) |
45 | const pluginsSortValidator = checkSort(SORTABLE_PLUGINS_COLUMNS) | 46 | const pluginsSortValidator = checkSort(SORTABLE_PLUGINS_COLUMNS) |
47 | const availablePluginsSortValidator = checkSort(SORTABLE_AVAILABLE_PLUGINS_COLUMNS) | ||
46 | 48 | ||
47 | // --------------------------------------------------------------------------- | 49 | // --------------------------------------------------------------------------- |
48 | 50 | ||
@@ -61,6 +63,7 @@ export { | |||
61 | videoCommentThreadsSortValidator, | 63 | videoCommentThreadsSortValidator, |
62 | videoRatesSortValidator, | 64 | videoRatesSortValidator, |
63 | userSubscriptionsSortValidator, | 65 | userSubscriptionsSortValidator, |
66 | availablePluginsSortValidator, | ||
64 | videoChannelsSearchSortValidator, | 67 | videoChannelsSearchSortValidator, |
65 | accountsBlocklistSortValidator, | 68 | accountsBlocklistSortValidator, |
66 | serversBlocklistSortValidator, | 69 | serversBlocklistSortValidator, |
diff --git a/server/models/server/plugin.ts b/server/models/server/plugin.ts index bd3d7a81e..ba43713f6 100644 --- a/server/models/server/plugin.ts +++ b/server/models/server/plugin.ts | |||
@@ -10,6 +10,7 @@ import { | |||
10 | import { PluginType } from '../../../shared/models/plugins/plugin.type' | 10 | import { PluginType } from '../../../shared/models/plugins/plugin.type' |
11 | import { PeerTubePlugin } from '../../../shared/models/plugins/peertube-plugin.model' | 11 | import { PeerTubePlugin } from '../../../shared/models/plugins/peertube-plugin.model' |
12 | import { FindAndCountOptions, json } from 'sequelize' | 12 | import { FindAndCountOptions, json } from 'sequelize' |
13 | import { PeerTubePluginIndex } from '../../../shared/models/plugins/peertube-plugin-index.model' | ||
13 | 14 | ||
14 | @DefaultScope(() => ({ | 15 | @DefaultScope(() => ({ |
15 | attributes: { | 16 | attributes: { |
@@ -177,7 +178,7 @@ export class PluginModel extends Model<PluginModel> { | |||
177 | } | 178 | } |
178 | 179 | ||
179 | static listForApi (options: { | 180 | static listForApi (options: { |
180 | type?: PluginType, | 181 | pluginType?: PluginType, |
181 | uninstalled?: boolean, | 182 | uninstalled?: boolean, |
182 | start: number, | 183 | start: number, |
183 | count: number, | 184 | count: number, |
@@ -193,7 +194,7 @@ export class PluginModel extends Model<PluginModel> { | |||
193 | } | 194 | } |
194 | } | 195 | } |
195 | 196 | ||
196 | if (options.type) query.where['type'] = options.type | 197 | if (options.pluginType) query.where['type'] = options.pluginType |
197 | 198 | ||
198 | return PluginModel | 199 | return PluginModel |
199 | .findAndCountAll(query) | 200 | .findAndCountAll(query) |
@@ -202,8 +203,18 @@ export class PluginModel extends Model<PluginModel> { | |||
202 | }) | 203 | }) |
203 | } | 204 | } |
204 | 205 | ||
205 | static normalizePluginName (name: string) { | 206 | static listInstalled () { |
206 | return name.replace(/^peertube-((theme)|(plugin))-/, '') | 207 | const query = { |
208 | where: { | ||
209 | uninstalled: false | ||
210 | } | ||
211 | } | ||
212 | |||
213 | return PluginModel.findAll(query) | ||
214 | } | ||
215 | |||
216 | static normalizePluginName (npmName: string) { | ||
217 | return npmName.replace(/^peertube-((theme)|(plugin))-/, '') | ||
207 | } | 218 | } |
208 | 219 | ||
209 | static getTypeFromNpmName (npmName: string) { | 220 | static getTypeFromNpmName (npmName: string) { |