-import { PeerTubeHelpers } from '@server/types/plugins'
-import { sequelizeTypescript } from '@server/initializers/database'
+import * as express from 'express'
+import { join } from 'path'
import { buildLogger } from '@server/helpers/logger'
-import { VideoModel } from '@server/models/video/video'
+import { CONFIG } from '@server/initializers/config'
import { WEBSERVER } from '@server/initializers/constants'
-import { ServerModel } from '@server/models/server/server'
+import { sequelizeTypescript } from '@server/initializers/database'
+import { AccountModel } from '@server/models/account/account'
+import { AccountBlocklistModel } from '@server/models/account/account-blocklist'
import { getServerActor } from '@server/models/application/application'
-import { addServerInBlocklist, removeServerFromBlocklist, addAccountInBlocklist, removeAccountFromBlocklist } from '../blocklist'
+import { ServerModel } from '@server/models/server/server'
import { ServerBlocklistModel } from '@server/models/server/server-blocklist'
-import { AccountModel } from '@server/models/account/account'
-import { VideoBlacklistCreate } from '@shared/models'
-import { blacklistVideo, unblacklistVideo } from '../video-blacklist'
+import { VideoModel } from '@server/models/video/video'
import { VideoBlacklistModel } from '@server/models/video/video-blacklist'
-import { AccountBlocklistModel } from '@server/models/account/account-blocklist'
-import { getServerConfig } from '../config'
import { MPlugin } from '@server/types/models'
+import { PeerTubeHelpers } from '@server/types/plugins'
+import { VideoBlacklistCreate } from '@shared/models'
+import { addAccountInBlocklist, addServerInBlocklist, removeAccountFromBlocklist, removeServerFromBlocklist } from '../blocklist'
+import { getServerConfig } from '../config'
+import { blacklistVideo, unblacklistVideo } from '../video-blacklist'
function buildPluginHelpers (pluginModel: MPlugin, npmName: string): PeerTubeHelpers {
const logger = buildPluginLogger(npmName)
const moderation = buildModerationHelpers()
- const plugin = buildPluginRelatedHelpers(pluginModel)
+ const plugin = buildPluginRelatedHelpers(pluginModel, npmName)
+
+ const user = buildUserHelpers()
return {
logger,
config,
moderation,
plugin,
- server
+ server,
+ user
}
}
}
}
-function buildPluginRelatedHelpers (plugin: MPlugin) {
+function buildPluginRelatedHelpers (plugin: MPlugin, npmName: string) {
+ return {
+ getBaseStaticRoute: () => `/plugins/${plugin.name}/${plugin.version}/static/`,
+
+ getBaseRouterRoute: () => `/plugins/${plugin.name}/${plugin.version}/router/`,
+
+ getDataDirectoryPath: () => join(CONFIG.STORAGE.PLUGINS_DIR, 'data', npmName)
+ }
+}
+
+function buildUserHelpers () {
return {
- getBaseStaticRoute: () => `/plugins/${plugin.name}/${plugin.version}/static/`
+ getAuthUser: (res: express.Response) => res.locals.oauth?.token?.User
}
}
import decache from 'decache'
import * as express from 'express'
import { createReadStream, createWriteStream } from 'fs'
-import { outputFile, readJSON } from 'fs-extra'
+import { ensureDir, outputFile, readJSON } from 'fs-extra'
import { basename, join } from 'path'
import { MOAuthTokenUser, MUser } from '@server/types/models'
import { RegisterServerHookOptions } from '@shared/models/plugins/register-server-hook.model'
}
const { registerOptions, registerStore } = this.getRegisterHelpers(npmName, plugin)
+
+ await ensureDir(registerOptions.peertubeHelpers.plugin.getDataDirectoryPath())
+
library.register(registerOptions)
.catch(err => logger.error('Cannot register plugin %s.', npmName, { err }))
})
router.get('/static-route', async (req, res) => {
- const staticRoute = await peertubeHelpers.plugin.getBaseStaticRoute()
+ const staticRoute = peertubeHelpers.plugin.getBaseStaticRoute()
return res.json({ staticRoute })
})
+
+ router.get('/router-route', async (req, res) => {
+ const routerRoute = peertubeHelpers.plugin.getBaseRouterRoute()
+
+ return res.json({ routerRoute })
+ })
+
+ router.get('/user', async (req, res) => {
+ const user = peertubeHelpers.user.getAuthUser(res)
+
+ const isAdmin = user.role === 0
+ const isModerator = user.role === 1
+ const isUser = user.role === 2
+
+ return res.json({
+ username: user.username,
+ isAdmin,
+ isModerator,
+ isUser
+ })
+ })
}
}
+const fs = require('fs')
+const path = require('path')
+
async function register ({
storageManager,
- peertubeHelpers
+ peertubeHelpers,
+ getRouter
}) {
const { logger } = peertubeHelpers
const result = await storageManager.getData('superkey')
logger.info('superkey stored value is %s', result.value)
}
+
+ {
+ getRouter().get('/create-file', async (req, res) => {
+ const basePath = peertubeHelpers.plugin.getDataDirectoryPath()
+
+ fs.writeFile(path.join(basePath, 'Aladdin.txt'), 'Prince Ali', function (err) {
+ if (err) return res.sendStatus(500)
+
+ res.sendStatus(200)
+ })
+ })
+ }
}
async function unregister () {
expect(res.body.staticRoute).to.equal('/plugins/test-four/0.0.1/static/')
})
+
+ it('Should get the base static route', async function () {
+ const baseRouter = '/plugins/test-four/0.0.1/router/'
+
+ const res = await makeGetRequest({
+ url: servers[0].url,
+ path: baseRouter + 'router-route',
+ statusCodeExpected: HttpStatusCode.OK_200
+ })
+
+ expect(res.body.routerRoute).to.equal(baseRouter)
+ })
+ })
+
+ describe('User', function () {
+
+ it('Should not get a user if not authenticated', async function () {
+ const res = await makeGetRequest({
+ url: servers[0].url,
+ path: '/plugins/test-four/router/user',
+ statusCodeExpected: HttpStatusCode.OK_200
+ })
+
+ expect(res.body.user).to.be.undefined
+ })
+
+ it('Should get a user if authenticated', async function () {
+ const res = await makeGetRequest({
+ url: servers[0].url,
+ token: servers[0].accessToken,
+ path: '/plugins/test-four/router/user',
+ statusCodeExpected: HttpStatusCode.OK_200
+ })
+
+ expect(res.body.user).to.exist
+ expect(res.body.username).to.equal('root')
+ expect(res.body.isAdmin).to.be.true
+ expect(res.body.isModerator).to.be.false
+ expect(res.body.isUser).to.be.false
+ })
})
describe('Moderation', function () {
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
-import { getPluginTestPath, installPlugin, setAccessTokensToServers } from '../../../shared/extra-utils'
+import { expect } from 'chai'
+import { pathExists, readdir, readFile } from 'fs-extra'
+import { join } from 'path'
+import { HttpStatusCode } from '@shared/core-utils'
+import {
+ buildServerDirectory,
+ getPluginTestPath,
+ installPlugin,
+ makeGetRequest,
+ setAccessTokensToServers,
+ uninstallPlugin
+} from '../../../shared/extra-utils'
import { cleanupTests, flushAndRunServer, ServerInfo, waitUntilLog } from '../../../shared/extra-utils/server/servers'
describe('Test plugin storage', function () {
})
})
- it('Should correctly store a subkey', async function () {
- await waitUntilLog(server, 'superkey stored value is toto')
+ describe('DB storage', function () {
+
+ it('Should correctly store a subkey', async function () {
+ await waitUntilLog(server, 'superkey stored value is toto')
+ })
+ })
+
+ describe('Disk storage', function () {
+ let dataPath: string
+ let pluginDataPath: string
+
+ async function getFileContent () {
+ const files = await readdir(pluginDataPath)
+ expect(files).to.have.lengthOf(1)
+
+ return readFile(join(pluginDataPath, files[0]), 'utf8')
+ }
+
+ before(function () {
+ dataPath = buildServerDirectory(server, 'plugins/data')
+ pluginDataPath = join(dataPath, 'peertube-plugin-test-six')
+ })
+
+ it('Should have created the directory on install', async function () {
+ const dataPath = buildServerDirectory(server, 'plugins/data')
+ const pluginDataPath = join(dataPath, 'peertube-plugin-test-six')
+
+ expect(await pathExists(dataPath)).to.be.true
+ expect(await pathExists(pluginDataPath)).to.be.true
+ expect(await readdir(pluginDataPath)).to.have.lengthOf(0)
+ })
+
+ it('Should have created a file', async function () {
+ await makeGetRequest({
+ url: server.url,
+ token: server.accessToken,
+ path: '/plugins/test-six/router/create-file',
+ statusCodeExpected: HttpStatusCode.OK_200
+ })
+
+ const content = await getFileContent()
+ expect(content).to.equal('Prince Ali')
+ })
+
+ it('Should still have the file after an uninstallation', async function () {
+ await uninstallPlugin({
+ url: server.url,
+ accessToken: server.accessToken,
+ npmName: 'peertube-plugin-test-six'
+ })
+
+ const content = await getFileContent()
+ expect(content).to.equal('Prince Ali')
+ })
+
+ it('Should still have the file after the reinstallation', async function () {
+ await installPlugin({
+ url: server.url,
+ accessToken: server.accessToken,
+ path: getPluginTestPath('-six')
+ })
+
+ const content = await getFileContent()
+ expect(content).to.equal('Prince Ali')
+ })
})
after(async function () {
-import { Router } from 'express'
+import { Router, Response } from 'express'
import { Logger } from 'winston'
import { ActorModel } from '@server/models/activitypub/actor'
import {
RegisterServerHookOptions,
RegisterServerSettingOptions,
ServerConfig,
+ UserRole,
VideoBlacklistCreate
} from '@shared/models'
import { MVideoThumbnail } from '../models'
plugin: {
getBaseStaticRoute: () => string
+
+ getBaseRouterRoute: () => string
+
+ getDataDirectoryPath: () => string
+ }
+
+ user: {
+ getAuthUser: (response: Response) => {
+ id?: string
+ username: string
+ email: string
+ blocked: boolean
+ role: UserRole
+ } | undefined
}
}
Example:
```js
-function register (...) {
+function register ({
+ storageManager
+}) {
const value = await storageManager.getData('mykey')
await storageManager.storeData('mykey', { subkey: 'value' })
}
```
+You can also store files in the plugin data directory (`/{plugins-directory}/data/{npm-plugin-name}`).
+This directory and its content won't be deleted when your plugin is uninstalled/upgraded.
+
+```js
+function register ({
+ storageManager,
+ peertubeHelpers
+}) {
+ const basePath = peertubeHelpers.plugin.getDataDirectoryPath()
+
+ fs.writeFile(path.join(basePath, 'filename.txt'), 'content of my file', function (err) {
+ ...
+ })
+}
+```
+
#### Update video constants
You can add/delete video categories, licences or languages using the appropriate managers:
You can create custom routes using an [express Router](https://expressjs.com/en/4x/api.html#router) for your plugin:
```js
-function register (...) {
+function register ({
+ router
+}) {
const router = getRouter()
router.get('/ping', (req, res) => res.json({ message: 'pong' }))
+
+ // Users are automatically authenticated
+ router.get('/auth', (res, res) => {
+ const user = peertubeHelpers.user.getAuthUser(res)
+
+ const isAdmin = user.role === 0
+ const isModerator = user.role === 1
+ const isUser = user.role === 2
+
+ res.json({
+ username: user.username,
+ isAdmin,
+ isModerator,
+ isUser
+ })
+ })
}
```