mirror of https://github.com/Chocobozzz/PeerTube
WIP plugins: move plugin CLI in peertube script
Install/uninstall/list plugins remotelypull/1987/head
parent
dba85a1e9e
commit
8d2be0ed7b
|
@ -32,8 +32,6 @@
|
||||||
"clean:server:test": "scripty",
|
"clean:server:test": "scripty",
|
||||||
"watch:client": "scripty",
|
"watch:client": "scripty",
|
||||||
"watch:server": "scripty",
|
"watch:server": "scripty",
|
||||||
"plugin:install": "node ./dist/scripts/plugin/install.js",
|
|
||||||
"plugin:uninstall": "node ./dist/scripts/plugin/uninstall.js",
|
|
||||||
"danger:clean:dev": "scripty",
|
"danger:clean:dev": "scripty",
|
||||||
"danger:clean:prod": "scripty",
|
"danger:clean:prod": "scripty",
|
||||||
"danger:clean:modules": "scripty",
|
"danger:clean:modules": "scripty",
|
||||||
|
@ -45,6 +43,7 @@
|
||||||
"dev": "scripty",
|
"dev": "scripty",
|
||||||
"dev:server": "scripty",
|
"dev:server": "scripty",
|
||||||
"dev:client": "scripty",
|
"dev:client": "scripty",
|
||||||
|
"dev:cli": "scripty",
|
||||||
"start": "node dist/server",
|
"start": "node dist/server",
|
||||||
"start:server": "node dist/server --no-client",
|
"start:server": "node dist/server --no-client",
|
||||||
"update-host": "node ./dist/scripts/update-host.js",
|
"update-host": "node ./dist/scripts/update-host.js",
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
rm -rf ./dist/server/tools/
|
||||||
|
|
||||||
|
(
|
||||||
|
cd ./server/tools
|
||||||
|
yarn install --pure-lockfile
|
||||||
|
)
|
||||||
|
|
||||||
|
mkdir -p "./dist/server/tools"
|
||||||
|
cp -r "./server/tools/node_modules" "./dist/server/tools"
|
||||||
|
|
||||||
|
npm run tsc -- --watch --project ./server/tools/tsconfig.json
|
|
@ -1,39 +0,0 @@
|
||||||
import { initDatabaseModels } from '../../server/initializers/database'
|
|
||||||
import * as program from 'commander'
|
|
||||||
import { PluginManager } from '../../server/lib/plugins/plugin-manager'
|
|
||||||
import { isAbsolute } from 'path'
|
|
||||||
|
|
||||||
program
|
|
||||||
.option('-n, --plugin-name [pluginName]', 'Plugin name to install')
|
|
||||||
.option('-v, --plugin-version [pluginVersion]', 'Plugin version to install')
|
|
||||||
.option('-p, --plugin-path [pluginPath]', 'Path of the plugin you want to install')
|
|
||||||
.parse(process.argv)
|
|
||||||
|
|
||||||
if (!program['pluginName'] && !program['pluginPath']) {
|
|
||||||
console.error('You need to specify a plugin name with the desired version, or a plugin path.')
|
|
||||||
process.exit(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (program['pluginName'] && !program['pluginVersion']) {
|
|
||||||
console.error('You need to specify a the version of the plugin you want to install.')
|
|
||||||
process.exit(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (program['pluginPath'] && !isAbsolute(program['pluginPath'])) {
|
|
||||||
console.error('Plugin path should be absolute.')
|
|
||||||
process.exit(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
run()
|
|
||||||
.then(() => process.exit(0))
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err)
|
|
||||||
process.exit(-1)
|
|
||||||
})
|
|
||||||
|
|
||||||
async function run () {
|
|
||||||
await initDatabaseModels(true)
|
|
||||||
|
|
||||||
const toInstall = program['pluginName'] || program['pluginPath']
|
|
||||||
await PluginManager.Instance.install(toInstall, program['pluginVersion'], !!program['pluginPath'])
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
import { initDatabaseModels } from '../../server/initializers/database'
|
|
||||||
import * as program from 'commander'
|
|
||||||
import { PluginManager } from '../../server/lib/plugins/plugin-manager'
|
|
||||||
import { isAbsolute } from 'path'
|
|
||||||
|
|
||||||
program
|
|
||||||
.option('-n, --package-name [packageName]', 'Package name to install')
|
|
||||||
.parse(process.argv)
|
|
||||||
|
|
||||||
if (!program['packageName']) {
|
|
||||||
console.error('You need to specify the plugin name.')
|
|
||||||
process.exit(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
run()
|
|
||||||
.then(() => process.exit(0))
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err)
|
|
||||||
process.exit(-1)
|
|
||||||
})
|
|
||||||
|
|
||||||
async function run () {
|
|
||||||
await initDatabaseModels(true)
|
|
||||||
|
|
||||||
const toUninstall = program['packageName']
|
|
||||||
await PluginManager.Instance.uninstall(toUninstall)
|
|
||||||
}
|
|
|
@ -21,6 +21,7 @@ import {
|
||||||
import { PluginManager } from '../../lib/plugins/plugin-manager'
|
import { PluginManager } from '../../lib/plugins/plugin-manager'
|
||||||
import { InstallPlugin } from '../../../shared/models/plugins/install-plugin.model'
|
import { InstallPlugin } from '../../../shared/models/plugins/install-plugin.model'
|
||||||
import { ManagePlugin } from '../../../shared/models/plugins/manage-plugin.model'
|
import { ManagePlugin } from '../../../shared/models/plugins/manage-plugin.model'
|
||||||
|
import { logger } from '../../helpers/logger'
|
||||||
|
|
||||||
const pluginRouter = express.Router()
|
const pluginRouter = express.Router()
|
||||||
|
|
||||||
|
@ -46,7 +47,7 @@ pluginRouter.get('/:npmName/registered-settings',
|
||||||
authenticate,
|
authenticate,
|
||||||
ensureUserHasRight(UserRight.MANAGE_PLUGINS),
|
ensureUserHasRight(UserRight.MANAGE_PLUGINS),
|
||||||
asyncMiddleware(existingPluginValidator),
|
asyncMiddleware(existingPluginValidator),
|
||||||
asyncMiddleware(getPluginRegisteredSettings)
|
getPluginRegisteredSettings
|
||||||
)
|
)
|
||||||
|
|
||||||
pluginRouter.put('/:npmName/settings',
|
pluginRouter.put('/:npmName/settings',
|
||||||
|
@ -101,7 +102,14 @@ function getPlugin (req: express.Request, res: express.Response) {
|
||||||
async function installPlugin (req: express.Request, res: express.Response) {
|
async function installPlugin (req: express.Request, res: express.Response) {
|
||||||
const body: InstallPlugin = req.body
|
const body: InstallPlugin = req.body
|
||||||
|
|
||||||
await PluginManager.Instance.install(body.npmName)
|
const fromDisk = !!body.path
|
||||||
|
const toInstall = body.npmName || body.path
|
||||||
|
try {
|
||||||
|
await PluginManager.Instance.install(toInstall, undefined, fromDisk)
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn('Cannot install plugin %s.', toInstall, { err })
|
||||||
|
return res.sendStatus(400)
|
||||||
|
}
|
||||||
|
|
||||||
return res.sendStatus(204)
|
return res.sendStatus(204)
|
||||||
}
|
}
|
||||||
|
@ -114,10 +122,10 @@ async function uninstallPlugin (req: express.Request, res: express.Response) {
|
||||||
return res.sendStatus(204)
|
return res.sendStatus(204)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getPluginRegisteredSettings (req: express.Request, res: express.Response) {
|
function getPluginRegisteredSettings (req: express.Request, res: express.Response) {
|
||||||
const plugin = res.locals.plugin
|
const plugin = res.locals.plugin
|
||||||
|
|
||||||
const settings = await PluginManager.Instance.getSettings(plugin.name)
|
const settings = PluginManager.Instance.getSettings(plugin.name)
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
settings
|
settings
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
import * as express from 'express'
|
|
||||||
import { join } from 'path'
|
|
||||||
import { RegisteredPlugin } from '../lib/plugins/plugin-manager'
|
|
||||||
import { serveThemeCSSValidator } from '../middlewares/validators/themes'
|
|
||||||
|
|
||||||
const themesRouter = express.Router()
|
|
||||||
|
|
||||||
themesRouter.get('/:themeName/:themeVersion/css/:staticEndpoint(*)',
|
|
||||||
serveThemeCSSValidator,
|
|
||||||
serveThemeCSSDirectory
|
|
||||||
)
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export {
|
|
||||||
themesRouter
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function serveThemeCSSDirectory (req: express.Request, res: express.Response) {
|
|
||||||
const plugin: RegisteredPlugin = res.locals.registeredPlugin
|
|
||||||
const staticEndpoint = req.params.staticEndpoint
|
|
||||||
|
|
||||||
if (plugin.css.includes(staticEndpoint) === false) {
|
|
||||||
return res.sendStatus(404)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.sendFile(join(plugin.path, staticEndpoint))
|
|
||||||
}
|
|
|
@ -3,7 +3,6 @@
|
||||||
Useful to avoid circular dependencies.
|
Useful to avoid circular dependencies.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as bcrypt from 'bcrypt'
|
|
||||||
import * as createTorrent from 'create-torrent'
|
import * as createTorrent from 'create-torrent'
|
||||||
import { createHash, HexBase64Latin1Encoding, pseudoRandomBytes } from 'crypto'
|
import { createHash, HexBase64Latin1Encoding, pseudoRandomBytes } from 'crypto'
|
||||||
import { isAbsolute, join } from 'path'
|
import { isAbsolute, join } from 'path'
|
||||||
|
@ -258,9 +257,6 @@ function promisify2WithVoid<T, U> (func: (arg1: T, arg2: U, cb: (err: any) => vo
|
||||||
const pseudoRandomBytesPromise = promisify1<number, Buffer>(pseudoRandomBytes)
|
const pseudoRandomBytesPromise = promisify1<number, Buffer>(pseudoRandomBytes)
|
||||||
const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey)
|
const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey)
|
||||||
const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey)
|
const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey)
|
||||||
const bcryptComparePromise = promisify2<any, string, boolean>(bcrypt.compare)
|
|
||||||
const bcryptGenSaltPromise = promisify1<number, string>(bcrypt.genSalt)
|
|
||||||
const bcryptHashPromise = promisify2<any, string | number, string>(bcrypt.hash)
|
|
||||||
const createTorrentPromise = promisify2<string, any, any>(createTorrent)
|
const createTorrentPromise = promisify2<string, any, any>(createTorrent)
|
||||||
const execPromise2 = promisify2<string, any, string>(exec)
|
const execPromise2 = promisify2<string, any, string>(exec)
|
||||||
const execPromise = promisify1<string, string>(exec)
|
const execPromise = promisify1<string, string>(exec)
|
||||||
|
@ -287,13 +283,11 @@ export {
|
||||||
|
|
||||||
promisify0,
|
promisify0,
|
||||||
promisify1,
|
promisify1,
|
||||||
|
promisify2,
|
||||||
|
|
||||||
pseudoRandomBytesPromise,
|
pseudoRandomBytesPromise,
|
||||||
createPrivateKey,
|
createPrivateKey,
|
||||||
getPublicKey,
|
getPublicKey,
|
||||||
bcryptComparePromise,
|
|
||||||
bcryptGenSaltPromise,
|
|
||||||
bcryptHashPromise,
|
|
||||||
createTorrentPromise,
|
createTorrentPromise,
|
||||||
execPromise2,
|
execPromise2,
|
||||||
execPromise
|
execPromise
|
||||||
|
|
|
@ -51,7 +51,9 @@ export {
|
||||||
|
|
||||||
function processVideoChannelExist (videoChannel: VideoChannelModel, res: express.Response) {
|
function processVideoChannelExist (videoChannel: VideoChannelModel, res: express.Response) {
|
||||||
if (!videoChannel) {
|
if (!videoChannel) {
|
||||||
``
|
res.status(404)
|
||||||
|
.json({ error: 'Video channel not found' })
|
||||||
|
.end()
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
import { Request } from 'express'
|
import { Request } from 'express'
|
||||||
import { BCRYPT_SALT_SIZE, HTTP_SIGNATURE, PRIVATE_RSA_KEY_SIZE } from '../initializers/constants'
|
import { BCRYPT_SALT_SIZE, HTTP_SIGNATURE, PRIVATE_RSA_KEY_SIZE } from '../initializers/constants'
|
||||||
import { ActorModel } from '../models/activitypub/actor'
|
import { ActorModel } from '../models/activitypub/actor'
|
||||||
import { bcryptComparePromise, bcryptGenSaltPromise, bcryptHashPromise, createPrivateKey, getPublicKey, sha256 } from './core-utils'
|
import { createPrivateKey, getPublicKey, promisify1, promisify2, sha256 } from './core-utils'
|
||||||
import { jsig, jsonld } from './custom-jsonld-signature'
|
import { jsig, jsonld } from './custom-jsonld-signature'
|
||||||
import { logger } from './logger'
|
import { logger } from './logger'
|
||||||
import { cloneDeep } from 'lodash'
|
import { cloneDeep } from 'lodash'
|
||||||
import { createVerify } from 'crypto'
|
import { createVerify } from 'crypto'
|
||||||
import { buildDigest } from '../lib/job-queue/handlers/utils/activitypub-http-utils'
|
import { buildDigest } from '../lib/job-queue/handlers/utils/activitypub-http-utils'
|
||||||
|
import * as bcrypt from 'bcrypt'
|
||||||
|
|
||||||
|
const bcryptComparePromise = promisify2<any, string, boolean>(bcrypt.compare)
|
||||||
|
const bcryptGenSaltPromise = promisify1<number, string>(bcrypt.genSalt)
|
||||||
|
const bcryptHashPromise = promisify2<any, string | number, string>(bcrypt.hash)
|
||||||
|
|
||||||
const httpSignature = require('http-signature')
|
const httpSignature = require('http-signature')
|
||||||
|
|
||||||
|
@ -147,3 +152,5 @@ export {
|
||||||
cryptPassword,
|
cryptPassword,
|
||||||
signJsonLDObject
|
signJsonLDObject
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { isPluginNameValid, isPluginTypeValid, isPluginVersionValid, isNpmPlugin
|
||||||
import { PluginManager } from '../../lib/plugins/plugin-manager'
|
import { PluginManager } from '../../lib/plugins/plugin-manager'
|
||||||
import { isBooleanValid, isSafePath } from '../../helpers/custom-validators/misc'
|
import { isBooleanValid, isSafePath } from '../../helpers/custom-validators/misc'
|
||||||
import { PluginModel } from '../../models/server/plugin'
|
import { PluginModel } from '../../models/server/plugin'
|
||||||
|
import { InstallPlugin } from '../../../shared/models/plugins/install-plugin.model'
|
||||||
|
|
||||||
const servePluginStaticDirectoryValidator = [
|
const servePluginStaticDirectoryValidator = [
|
||||||
param('pluginName').custom(isPluginNameValid).withMessage('Should have a valid plugin name'),
|
param('pluginName').custom(isPluginNameValid).withMessage('Should have a valid plugin name'),
|
||||||
|
@ -48,13 +49,25 @@ const listPluginsValidator = [
|
||||||
]
|
]
|
||||||
|
|
||||||
const installPluginValidator = [
|
const installPluginValidator = [
|
||||||
body('npmName').custom(isNpmPluginNameValid).withMessage('Should have a valid npm name'),
|
body('npmName')
|
||||||
|
.optional()
|
||||||
|
.custom(isNpmPluginNameValid).withMessage('Should have a valid npm name'),
|
||||||
|
body('path')
|
||||||
|
.optional()
|
||||||
|
.custom(isSafePath).withMessage('Should have a valid safe path'),
|
||||||
|
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
logger.debug('Checking installPluginValidator parameters', { parameters: req.body })
|
logger.debug('Checking installPluginValidator parameters', { parameters: req.body })
|
||||||
|
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
|
||||||
|
const body: InstallPlugin = req.body
|
||||||
|
if (!body.path && !body.npmName) {
|
||||||
|
return res.status(400)
|
||||||
|
.json({ error: 'Should have either a npmName or a path' })
|
||||||
|
.end()
|
||||||
|
}
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -142,15 +142,17 @@ export class PluginModel extends Model<PluginModel> {
|
||||||
count: number,
|
count: number,
|
||||||
sort: string
|
sort: string
|
||||||
}) {
|
}) {
|
||||||
|
const { uninstalled = false } = options
|
||||||
const query: FindAndCountOptions = {
|
const query: FindAndCountOptions = {
|
||||||
offset: options.start,
|
offset: options.start,
|
||||||
limit: options.count,
|
limit: options.count,
|
||||||
order: getSort(options.sort),
|
order: getSort(options.sort),
|
||||||
where: {}
|
where: {
|
||||||
|
uninstalled
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.type) query.where['type'] = options.type
|
if (options.type) query.where['type'] = options.type
|
||||||
if (options.uninstalled) query.where['uninstalled'] = options.uninstalled
|
|
||||||
|
|
||||||
return PluginModel
|
return PluginModel
|
||||||
.findAndCountAll(query)
|
.findAndCountAll(query)
|
||||||
|
|
|
@ -67,6 +67,8 @@ describe('Test ActivityPub video channels search', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should not find a remote video channel', async function () {
|
it('Should not find a remote video channel', async function () {
|
||||||
|
this.timeout(15000)
|
||||||
|
|
||||||
{
|
{
|
||||||
const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server3'
|
const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server3'
|
||||||
const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken)
|
const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { Netrc } from 'netrc-parser'
|
import { Netrc } from 'netrc-parser'
|
||||||
import { getAppNumber, isTestInstance } from '../helpers/core-utils'
|
import { getAppNumber, isTestInstance } from '../helpers/core-utils'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { getVideoChannel, root } from '../../shared/extra-utils'
|
import { root } from '../../shared/extra-utils/miscs/miscs'
|
||||||
|
import { getVideoChannel } from '../../shared/extra-utils/videos/video-channels'
|
||||||
import { Command } from 'commander'
|
import { Command } from 'commander'
|
||||||
import { VideoChannel, VideoPrivacy } from '../../shared/models/videos'
|
import { VideoChannel, VideoPrivacy } from '../../shared/models/videos'
|
||||||
|
|
||||||
|
@ -64,7 +65,11 @@ function deleteSettings () {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRemoteObjectOrDie (program: any, settings: Settings, netrc: Netrc) {
|
function getRemoteObjectOrDie (
|
||||||
|
program: any,
|
||||||
|
settings: Settings,
|
||||||
|
netrc: Netrc
|
||||||
|
): { url: string, username: string, password: string } {
|
||||||
if (!program['url'] || !program['username'] || !program['password']) {
|
if (!program['url'] || !program['username'] || !program['password']) {
|
||||||
// No remote and we don't have program parameters: quit
|
// No remote and we don't have program parameters: quit
|
||||||
if (settings.remotes.length === 0 || Object.keys(netrc.machines).length === 0) {
|
if (settings.remotes.length === 0 || Object.keys(netrc.machines).length === 0) {
|
||||||
|
@ -161,6 +166,13 @@ async function buildVideoAttributesFromCommander (url: string, command: Command,
|
||||||
return videoAttributes
|
return videoAttributes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getServerCredentials (program: any) {
|
||||||
|
return Promise.all([ getSettings(), getNetrc() ])
|
||||||
|
.then(([ settings, netrc ]) => {
|
||||||
|
return getRemoteObjectOrDie(program, settings, netrc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -172,6 +184,8 @@ export {
|
||||||
writeSettings,
|
writeSettings,
|
||||||
deleteSettings,
|
deleteSettings,
|
||||||
|
|
||||||
|
getServerCredentials,
|
||||||
|
|
||||||
buildCommonVideoOptions,
|
buildCommonVideoOptions,
|
||||||
buildVideoAttributesFromCommander
|
buildVideoAttributesFromCommander
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import * as program from 'commander'
|
import * as program from 'commander'
|
||||||
import * as prompt from 'prompt'
|
import * as prompt from 'prompt'
|
||||||
import { getSettings, writeSettings, getNetrc } from './cli'
|
import { getNetrc, getSettings, writeSettings } from './cli'
|
||||||
import { isHostValid } from '../helpers/custom-validators/servers'
|
|
||||||
import { isUserUsernameValid } from '../helpers/custom-validators/users'
|
import { isUserUsernameValid } from '../helpers/custom-validators/users'
|
||||||
|
import { getAccessToken, login } from '../../shared/extra-utils'
|
||||||
|
|
||||||
const Table = require('cli-table')
|
const Table = require('cli-table')
|
||||||
|
|
||||||
|
@ -76,6 +76,14 @@ program
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, async (_, result) => {
|
}, async (_, result) => {
|
||||||
|
// Check credentials
|
||||||
|
try {
|
||||||
|
await getAccessToken(result.url, result.username, result.password)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err.message)
|
||||||
|
process.exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
await setInstance(result.url, result.username, result.password, program['default'])
|
await setInstance(result.url, result.username, result.password, program['default'])
|
||||||
|
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
|
|
|
@ -11,7 +11,7 @@ import * as prompt from 'prompt'
|
||||||
import { remove } from 'fs-extra'
|
import { remove } from 'fs-extra'
|
||||||
import { sha256 } from '../helpers/core-utils'
|
import { sha256 } from '../helpers/core-utils'
|
||||||
import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl'
|
import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl'
|
||||||
import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getNetrc, getRemoteObjectOrDie, getSettings } from './cli'
|
import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getServerCredentials } from './cli'
|
||||||
|
|
||||||
type UserInfo = {
|
type UserInfo = {
|
||||||
username: string
|
username: string
|
||||||
|
@ -36,10 +36,8 @@ command
|
||||||
.option('-v, --verbose', 'Verbose mode')
|
.option('-v, --verbose', 'Verbose mode')
|
||||||
.parse(process.argv)
|
.parse(process.argv)
|
||||||
|
|
||||||
Promise.all([ getSettings(), getNetrc() ])
|
getServerCredentials(command)
|
||||||
.then(([ settings, netrc ]) => {
|
.then(({ url, username, password }) => {
|
||||||
const { url, username, password } = getRemoteObjectOrDie(program, settings, netrc)
|
|
||||||
|
|
||||||
if (!program[ 'targetUrl' ]) {
|
if (!program[ 'targetUrl' ]) {
|
||||||
console.error('--targetUrl field is required.')
|
console.error('--targetUrl field is required.')
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
import * as program from 'commander'
|
||||||
|
import { PluginType } from '../../shared/models/plugins/plugin.type'
|
||||||
|
import { getAccessToken } from '../../shared/extra-utils/users/login'
|
||||||
|
import { getMyUserInformation } from '../../shared/extra-utils/users/users'
|
||||||
|
import { installPlugin, listPlugins, uninstallPlugin } from '../../shared/extra-utils/server/plugins'
|
||||||
|
import { getServerCredentials } from './cli'
|
||||||
|
import { User, UserRole } from '../../shared/models/users'
|
||||||
|
import { PeerTubePlugin } from '../../shared/models/plugins/peertube-plugin.model'
|
||||||
|
import { isAbsolute } from 'path'
|
||||||
|
|
||||||
|
const Table = require('cli-table')
|
||||||
|
|
||||||
|
program
|
||||||
|
.name('plugins')
|
||||||
|
.usage('[command] [options]')
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('list')
|
||||||
|
.description('List installed plugins')
|
||||||
|
.option('-u, --url <url>', 'Server url')
|
||||||
|
.option('-U, --username <username>', 'Username')
|
||||||
|
.option('-p, --password <token>', 'Password')
|
||||||
|
.option('-t, --only-themes', 'List themes only')
|
||||||
|
.option('-P, --only-plugins', 'List plugins only')
|
||||||
|
.action(() => pluginsListCLI())
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('install')
|
||||||
|
.description('Install a plugin or a theme')
|
||||||
|
.option('-u, --url <url>', 'Server url')
|
||||||
|
.option('-U, --username <username>', 'Username')
|
||||||
|
.option('-p, --password <token>', 'Password')
|
||||||
|
.option('-P --path <path>', 'Install from a path')
|
||||||
|
.option('-n, --npm-name <npmName>', 'Install from npm')
|
||||||
|
.action((options) => installPluginCLI(options))
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('uninstall')
|
||||||
|
.description('Uninstall a plugin or a theme')
|
||||||
|
.option('-u, --url <url>', 'Server url')
|
||||||
|
.option('-U, --username <username>', 'Username')
|
||||||
|
.option('-p, --password <token>', 'Password')
|
||||||
|
.option('-n, --npm-name <npmName>', 'NPM plugin/theme name')
|
||||||
|
.action(options => uninstallPluginCLI(options))
|
||||||
|
|
||||||
|
if (!process.argv.slice(2).length) {
|
||||||
|
program.outputHelp()
|
||||||
|
}
|
||||||
|
|
||||||
|
program.parse(process.argv)
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
async function pluginsListCLI () {
|
||||||
|
const { url, username, password } = await getServerCredentials(program)
|
||||||
|
const accessToken = await getAdminTokenOrDie(url, username, password)
|
||||||
|
|
||||||
|
let type: PluginType
|
||||||
|
if (program['onlyThemes']) type = PluginType.THEME
|
||||||
|
if (program['onlyPlugins']) type = PluginType.PLUGIN
|
||||||
|
|
||||||
|
const res = await listPlugins({
|
||||||
|
url,
|
||||||
|
accessToken,
|
||||||
|
start: 0,
|
||||||
|
count: 100,
|
||||||
|
sort: 'name',
|
||||||
|
type
|
||||||
|
})
|
||||||
|
const plugins: PeerTubePlugin[] = res.body.data
|
||||||
|
|
||||||
|
const table = new Table({
|
||||||
|
head: ['name', 'version', 'homepage'],
|
||||||
|
colWidths: [ 50, 10, 50 ]
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const plugin of plugins) {
|
||||||
|
const npmName = plugin.type === PluginType.PLUGIN
|
||||||
|
? 'peertube-plugin-' + plugin.name
|
||||||
|
: 'peertube-theme-' + plugin.name
|
||||||
|
|
||||||
|
table.push([
|
||||||
|
npmName,
|
||||||
|
plugin.version,
|
||||||
|
plugin.homepage
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(table.toString())
|
||||||
|
process.exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function installPluginCLI (options: any) {
|
||||||
|
if (!options['path'] && !options['npmName']) {
|
||||||
|
console.error('You need to specify the npm name or the path of the plugin you want to install.\n')
|
||||||
|
program.outputHelp()
|
||||||
|
process.exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options['path'] && !isAbsolute(options['path'])) {
|
||||||
|
console.error('Path should be absolute.')
|
||||||
|
process.exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { url, username, password } = await getServerCredentials(options)
|
||||||
|
const accessToken = await getAdminTokenOrDie(url, username, password)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await installPlugin({
|
||||||
|
url,
|
||||||
|
accessToken,
|
||||||
|
npmName: options['npmName'],
|
||||||
|
path: options['path']
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Cannot install plugin.', err)
|
||||||
|
process.exit(-1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Plugin installed.')
|
||||||
|
process.exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function uninstallPluginCLI (options: any) {
|
||||||
|
if (!options['npmName']) {
|
||||||
|
console.error('You need to specify the npm name of the plugin/theme you want to uninstall.\n')
|
||||||
|
program.outputHelp()
|
||||||
|
process.exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { url, username, password } = await getServerCredentials(options)
|
||||||
|
const accessToken = await getAdminTokenOrDie(url, username, password)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await uninstallPlugin({
|
||||||
|
url,
|
||||||
|
accessToken,
|
||||||
|
npmName: options[ 'npmName' ]
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Cannot uninstall plugin.', err)
|
||||||
|
process.exit(-1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Plugin uninstalled.')
|
||||||
|
process.exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAdminTokenOrDie (url: string, username: string, password: string) {
|
||||||
|
const accessToken = await getAccessToken(url, username, password)
|
||||||
|
const resMe = await getMyUserInformation(url, accessToken)
|
||||||
|
const me: User = resMe.body
|
||||||
|
|
||||||
|
if (me.role !== UserRole.ADMINISTRATOR) {
|
||||||
|
console.error('Cannot list plugins if you are not administrator.')
|
||||||
|
process.exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return accessToken
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
import * as program from 'commander'
|
import * as program from 'commander'
|
||||||
import { access, constants } from 'fs-extra'
|
import { access, constants } from 'fs-extra'
|
||||||
import { isAbsolute } from 'path'
|
import { isAbsolute } from 'path'
|
||||||
import { getClient, login } from '../../shared/extra-utils'
|
import { getAccessToken } from '../../shared/extra-utils'
|
||||||
import { uploadVideo } from '../../shared/extra-utils/'
|
import { uploadVideo } from '../../shared/extra-utils/'
|
||||||
import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getNetrc, getRemoteObjectOrDie, getSettings } from './cli'
|
import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getServerCredentials } from './cli'
|
||||||
|
|
||||||
let command = program
|
let command = program
|
||||||
.name('upload')
|
.name('upload')
|
||||||
|
@ -11,7 +11,6 @@ let command = program
|
||||||
command = buildCommonVideoOptions(command)
|
command = buildCommonVideoOptions(command)
|
||||||
|
|
||||||
command
|
command
|
||||||
|
|
||||||
.option('-u, --url <url>', 'Server url')
|
.option('-u, --url <url>', 'Server url')
|
||||||
.option('-U, --username <username>', 'Username')
|
.option('-U, --username <username>', 'Username')
|
||||||
.option('-p, --password <token>', 'Password')
|
.option('-p, --password <token>', 'Password')
|
||||||
|
@ -20,10 +19,8 @@ command
|
||||||
.option('-f, --file <file>', 'Video absolute file path')
|
.option('-f, --file <file>', 'Video absolute file path')
|
||||||
.parse(process.argv)
|
.parse(process.argv)
|
||||||
|
|
||||||
Promise.all([ getSettings(), getNetrc() ])
|
getServerCredentials(command)
|
||||||
.then(([ settings, netrc ]) => {
|
.then(({ url, username, password }) => {
|
||||||
const { url, username, password } = getRemoteObjectOrDie(program, settings, netrc)
|
|
||||||
|
|
||||||
if (!program[ 'videoName' ] || !program[ 'file' ]) {
|
if (!program[ 'videoName' ] || !program[ 'file' ]) {
|
||||||
if (!program[ 'videoName' ]) console.error('--video-name is required.')
|
if (!program[ 'videoName' ]) console.error('--video-name is required.')
|
||||||
if (!program[ 'file' ]) console.error('--file is required.')
|
if (!program[ 'file' ]) console.error('--file is required.')
|
||||||
|
@ -43,21 +40,7 @@ Promise.all([ getSettings(), getNetrc() ])
|
||||||
})
|
})
|
||||||
|
|
||||||
async function run (url: string, username: string, password: string) {
|
async function run (url: string, username: string, password: string) {
|
||||||
const resClient = await getClient(url)
|
const accessToken = await getAccessToken(url, username, password)
|
||||||
const client = {
|
|
||||||
id: resClient.body.client_id,
|
|
||||||
secret: resClient.body.client_secret
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = { username, password }
|
|
||||||
|
|
||||||
let accessToken: string
|
|
||||||
try {
|
|
||||||
const res = await login(url, client, user)
|
|
||||||
accessToken = res.body.access_token
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error('Cannot authenticate. Please check your username/password.')
|
|
||||||
}
|
|
||||||
|
|
||||||
await access(program[ 'file' ], constants.F_OK)
|
await access(program[ 'file' ], constants.F_OK)
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,10 @@ program
|
||||||
.command('get-access-token', 'get a peertube access token', { noHelp: true }).alias('token')
|
.command('get-access-token', 'get a peertube access token', { noHelp: true }).alias('token')
|
||||||
.command('watch', 'watch a video in the terminal ✩°。⋆').alias('w')
|
.command('watch', 'watch a video in the terminal ✩°。⋆').alias('w')
|
||||||
.command('repl', 'initiate a REPL to access internals')
|
.command('repl', 'initiate a REPL to access internals')
|
||||||
|
.command('plugins [action]', 'manage plugins on a local instance').alias('p')
|
||||||
|
|
||||||
/* Not Yet Implemented */
|
/* Not Yet Implemented */
|
||||||
program
|
program
|
||||||
.command('plugins [action]',
|
|
||||||
'manage plugins on a local instance',
|
|
||||||
{ noHelp: true } as program.CommandOptions
|
|
||||||
).alias('p')
|
|
||||||
.command('diagnostic [action]',
|
.command('diagnostic [action]',
|
||||||
'like couple therapy, but for your instance',
|
'like couple therapy, but for your instance',
|
||||||
{ noHelp: true } as program.CommandOptions
|
{ noHelp: true } as program.CommandOptions
|
||||||
|
|
|
@ -11,6 +11,7 @@ export * from './server/follows'
|
||||||
export * from './requests/requests'
|
export * from './requests/requests'
|
||||||
export * from './requests/check-api-params'
|
export * from './requests/check-api-params'
|
||||||
export * from './server/servers'
|
export * from './server/servers'
|
||||||
|
export * from './server/plugins'
|
||||||
export * from './videos/services'
|
export * from './videos/services'
|
||||||
export * from './videos/video-playlists'
|
export * from './videos/video-playlists'
|
||||||
export * from './users/users'
|
export * from './users/users'
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { pathExists, readFile } from 'fs-extra'
|
||||||
import * as ffmpeg from 'fluent-ffmpeg'
|
import * as ffmpeg from 'fluent-ffmpeg'
|
||||||
|
|
||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
let webtorrent = new WebTorrent()
|
let webtorrent: WebTorrent.Instance
|
||||||
|
|
||||||
function immutableAssign <T, U> (target: T, source: U) {
|
function immutableAssign <T, U> (target: T, source: U) {
|
||||||
return Object.assign<{}, T, U>({}, target, source)
|
return Object.assign<{}, T, U>({}, target, source)
|
||||||
|
@ -27,6 +27,9 @@ function wait (milliseconds: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function webtorrentAdd (torrent: string, refreshWebTorrent = false) {
|
function webtorrentAdd (torrent: string, refreshWebTorrent = false) {
|
||||||
|
const WebTorrent = require('webtorrent')
|
||||||
|
|
||||||
|
if (!webtorrent) webtorrent = new WebTorrent()
|
||||||
if (refreshWebTorrent === true) webtorrent = new WebTorrent()
|
if (refreshWebTorrent === true) webtorrent = new WebTorrent()
|
||||||
|
|
||||||
return new Promise<WebTorrent.Torrent>(res => webtorrent.add(torrent, res))
|
return new Promise<WebTorrent.Torrent>(res => webtorrent.add(torrent, res))
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
import { makeGetRequest, makePostBodyRequest } from '../requests/requests'
|
||||||
|
import { PluginType } from '../../models/plugins/plugin.type'
|
||||||
|
|
||||||
|
function listPlugins (parameters: {
|
||||||
|
url: string,
|
||||||
|
accessToken: string,
|
||||||
|
start?: number,
|
||||||
|
count?: number,
|
||||||
|
sort?: string,
|
||||||
|
type?: PluginType,
|
||||||
|
expectedStatus?: number
|
||||||
|
}) {
|
||||||
|
const { url, accessToken, start, count, sort, type, expectedStatus = 200 } = parameters
|
||||||
|
const path = '/api/v1/plugins'
|
||||||
|
|
||||||
|
return makeGetRequest({
|
||||||
|
url,
|
||||||
|
path,
|
||||||
|
token: accessToken,
|
||||||
|
query: {
|
||||||
|
start,
|
||||||
|
count,
|
||||||
|
sort,
|
||||||
|
type
|
||||||
|
},
|
||||||
|
statusCodeExpected: expectedStatus
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPlugin (parameters: {
|
||||||
|
url: string,
|
||||||
|
accessToken: string,
|
||||||
|
npmName: string,
|
||||||
|
expectedStatus?: number
|
||||||
|
}) {
|
||||||
|
const { url, accessToken, npmName, expectedStatus = 200 } = parameters
|
||||||
|
const path = '/api/v1/plugins/' + npmName
|
||||||
|
|
||||||
|
return makeGetRequest({
|
||||||
|
url,
|
||||||
|
path,
|
||||||
|
token: accessToken,
|
||||||
|
statusCodeExpected: expectedStatus
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPluginSettings (parameters: {
|
||||||
|
url: string,
|
||||||
|
accessToken: string,
|
||||||
|
npmName: string,
|
||||||
|
expectedStatus?: number
|
||||||
|
}) {
|
||||||
|
const { url, accessToken, npmName, expectedStatus = 200 } = parameters
|
||||||
|
const path = '/api/v1/plugins/' + npmName + '/settings'
|
||||||
|
|
||||||
|
return makeGetRequest({
|
||||||
|
url,
|
||||||
|
path,
|
||||||
|
token: accessToken,
|
||||||
|
statusCodeExpected: expectedStatus
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPluginRegisteredSettings (parameters: {
|
||||||
|
url: string,
|
||||||
|
accessToken: string,
|
||||||
|
npmName: string,
|
||||||
|
expectedStatus?: number
|
||||||
|
}) {
|
||||||
|
const { url, accessToken, npmName, expectedStatus = 200 } = parameters
|
||||||
|
const path = '/api/v1/plugins/' + npmName + '/registered-settings'
|
||||||
|
|
||||||
|
return makeGetRequest({
|
||||||
|
url,
|
||||||
|
path,
|
||||||
|
token: accessToken,
|
||||||
|
statusCodeExpected: expectedStatus
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function installPlugin (parameters: {
|
||||||
|
url: string,
|
||||||
|
accessToken: string,
|
||||||
|
path?: string,
|
||||||
|
npmName?: string
|
||||||
|
expectedStatus?: number
|
||||||
|
}) {
|
||||||
|
const { url, accessToken, npmName, path, expectedStatus = 204 } = parameters
|
||||||
|
const apiPath = '/api/v1/plugins/install'
|
||||||
|
|
||||||
|
return makePostBodyRequest({
|
||||||
|
url,
|
||||||
|
path: apiPath,
|
||||||
|
token: accessToken,
|
||||||
|
fields: { npmName, path },
|
||||||
|
statusCodeExpected: expectedStatus
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function uninstallPlugin (parameters: {
|
||||||
|
url: string,
|
||||||
|
accessToken: string,
|
||||||
|
npmName: string
|
||||||
|
expectedStatus?: number
|
||||||
|
}) {
|
||||||
|
const { url, accessToken, npmName, expectedStatus = 204 } = parameters
|
||||||
|
const apiPath = '/api/v1/plugins/uninstall'
|
||||||
|
|
||||||
|
return makePostBodyRequest({
|
||||||
|
url,
|
||||||
|
path: apiPath,
|
||||||
|
token: accessToken,
|
||||||
|
fields: { npmName },
|
||||||
|
statusCodeExpected: expectedStatus
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
listPlugins,
|
||||||
|
installPlugin,
|
||||||
|
getPlugin,
|
||||||
|
uninstallPlugin,
|
||||||
|
getPluginSettings,
|
||||||
|
getPluginRegisteredSettings
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
import { ChildProcess, exec, fork } from 'child_process'
|
import { ChildProcess, exec, fork } from 'child_process'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { root, wait } from '../miscs/miscs'
|
import { root, wait } from '../miscs/miscs'
|
||||||
import { copy, readdir, readFile, remove } from 'fs-extra'
|
import { copy, pathExists, readdir, readFile, remove } from 'fs-extra'
|
||||||
import { existsSync } from 'fs'
|
import { existsSync } from 'fs'
|
||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import { VideoChannel } from '../../models/videos'
|
import { VideoChannel } from '../../models/videos'
|
||||||
|
@ -241,20 +241,22 @@ async function reRunServer (server: ServerInfo, configOverride?: any) {
|
||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkTmpIsEmpty (server: ServerInfo) {
|
function checkTmpIsEmpty (server: ServerInfo) {
|
||||||
return checkDirectoryIsEmpty(server, 'tmp')
|
return checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css' ])
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkDirectoryIsEmpty (server: ServerInfo, directory: string) {
|
async function checkDirectoryIsEmpty (server: ServerInfo, directory: string, exceptions: string[] = []) {
|
||||||
const testDirectory = 'test' + server.internalServerNumber
|
const testDirectory = 'test' + server.internalServerNumber
|
||||||
|
|
||||||
const directoryPath = join(root(), testDirectory, directory)
|
const directoryPath = join(root(), testDirectory, directory)
|
||||||
|
|
||||||
const directoryExists = existsSync(directoryPath)
|
const directoryExists = await pathExists(directoryPath)
|
||||||
expect(directoryExists).to.be.true
|
expect(directoryExists).to.be.true
|
||||||
|
|
||||||
const files = await readdir(directoryPath)
|
const files = await readdir(directoryPath)
|
||||||
expect(files).to.have.lengthOf(0)
|
const filtered = files.filter(f => exceptions.includes(f) === false)
|
||||||
|
|
||||||
|
expect(filtered).to.have.lengthOf(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
function killallServers (servers: ServerInfo[]) {
|
function killallServers (servers: ServerInfo[]) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import * as request from 'supertest'
|
import * as request from 'supertest'
|
||||||
|
|
||||||
import { ServerInfo } from '../server/servers'
|
import { ServerInfo } from '../server/servers'
|
||||||
|
import { getClient } from '../server/clients'
|
||||||
|
|
||||||
type Client = { id: string, secret: string }
|
type Client = { id: string, secret: string }
|
||||||
type User = { username: string, password: string }
|
type User = { username: string, password: string }
|
||||||
|
@ -38,6 +39,23 @@ async function userLogin (server: Server, user: User, expectedStatus = 200) {
|
||||||
return res.body.access_token as string
|
return res.body.access_token as string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getAccessToken (url: string, username: string, password: string) {
|
||||||
|
const resClient = await getClient(url)
|
||||||
|
const client = {
|
||||||
|
id: resClient.body.client_id,
|
||||||
|
secret: resClient.body.client_secret
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = { username, password }
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await login(url, client, user)
|
||||||
|
return res.body.access_token
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error('Cannot authenticate. Please check your username/password.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function setAccessTokensToServers (servers: ServerInfo[]) {
|
function setAccessTokensToServers (servers: ServerInfo[]) {
|
||||||
const tasks: Promise<any>[] = []
|
const tasks: Promise<any>[] = []
|
||||||
|
|
||||||
|
@ -55,6 +73,7 @@ export {
|
||||||
login,
|
login,
|
||||||
serverLogin,
|
serverLogin,
|
||||||
userLogin,
|
userLogin,
|
||||||
|
getAccessToken,
|
||||||
setAccessTokensToServers,
|
setAccessTokensToServers,
|
||||||
Server,
|
Server,
|
||||||
Client,
|
Client,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import * as request from 'supertest'
|
import * as request from 'supertest'
|
||||||
import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, updateAvatarRequest } from '../requests/requests'
|
import { makePostBodyRequest, makePutBodyRequest, updateAvatarRequest } from '../requests/requests'
|
||||||
|
|
||||||
import { UserCreate, UserRole } from '../../index'
|
|
||||||
import { NSFWPolicyType } from '../../models/videos/nsfw-policy.type'
|
import { NSFWPolicyType } from '../../models/videos/nsfw-policy.type'
|
||||||
import { ServerInfo, userLogin } from '..'
|
|
||||||
import { UserAdminFlag } from '../../models/users/user-flag.model'
|
import { UserAdminFlag } from '../../models/users/user-flag.model'
|
||||||
import { UserRegister } from '../../models/users/user-register.model'
|
import { UserRegister } from '../../models/users/user-register.model'
|
||||||
|
import { UserRole } from '../../models/users/user-role'
|
||||||
|
import { ServerInfo } from '../server/servers'
|
||||||
|
import { userLogin } from './login'
|
||||||
|
|
||||||
type CreateUserArgs = { url: string,
|
type CreateUserArgs = { url: string,
|
||||||
accessToken: string,
|
accessToken: string,
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import * as request from 'supertest'
|
import * as request from 'supertest'
|
||||||
import { VideoChannelCreate, VideoChannelUpdate } from '../../models/videos'
|
import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model'
|
||||||
|
import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model'
|
||||||
import { makeGetRequest, updateAvatarRequest } from '../requests/requests'
|
import { makeGetRequest, updateAvatarRequest } from '../requests/requests'
|
||||||
import { getMyUserInformation, ServerInfo } from '..'
|
import { ServerInfo } from '../server/servers'
|
||||||
import { User } from '../..'
|
import { User } from '../../models/users/user.model'
|
||||||
|
import { getMyUserInformation } from '../users/users'
|
||||||
|
|
||||||
function getVideoChannelsList (url: string, start: number, count: number, sort?: string) {
|
function getVideoChannelsList (url: string, start: number, count: number, sort?: string) {
|
||||||
const path = '/api/v1/video-channels'
|
const path = '/api/v1/video-channels'
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
export interface InstallPlugin {
|
export interface InstallPlugin {
|
||||||
npmName: string
|
npmName?: string
|
||||||
|
path?: string
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue