Ability for admins to set default upload values
This commit is contained in:
parent
a6f919e455
commit
3cf68b869d
31 changed files with 467 additions and 89 deletions
|
@ -21,6 +21,24 @@ export class VideoWatchPage {
|
||||||
return this.getVideoNameElement().then(e => e.getText())
|
return this.getVideoNameElement().then(e => e.getText())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPrivacy () {
|
||||||
|
return $('.attribute-privacy .attribute-value').getText()
|
||||||
|
}
|
||||||
|
|
||||||
|
getLicence () {
|
||||||
|
return $('.attribute-licence .attribute-value').getText()
|
||||||
|
}
|
||||||
|
|
||||||
|
async isDownloadEnabled () {
|
||||||
|
await this.clickOnMoreDropdownIcon()
|
||||||
|
|
||||||
|
return $('.dropdown-item .icon-download').isExisting()
|
||||||
|
}
|
||||||
|
|
||||||
|
areCommentsEnabled () {
|
||||||
|
return $('my-video-comment-add').isExisting()
|
||||||
|
}
|
||||||
|
|
||||||
async goOnAssociatedEmbed () {
|
async goOnAssociatedEmbed () {
|
||||||
let url = await browser.getUrl()
|
let url = await browser.getUrl()
|
||||||
url = url.replace('/w/', '/videos/embed/')
|
url = url.replace('/w/', '/videos/embed/')
|
||||||
|
@ -38,10 +56,8 @@ export class VideoWatchPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
async clickOnUpdate () {
|
async clickOnUpdate () {
|
||||||
const dropdown = $('my-video-actions-dropdown .action-button')
|
await this.clickOnMoreDropdownIcon()
|
||||||
await dropdown.click()
|
|
||||||
|
|
||||||
await $('.dropdown-menu.show .dropdown-item').waitForDisplayed()
|
|
||||||
const items = await $$('.dropdown-menu.show .dropdown-item')
|
const items = await $$('.dropdown-menu.show .dropdown-item')
|
||||||
|
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
|
@ -86,6 +102,13 @@ export class VideoWatchPage {
|
||||||
}, { timeout: maxTime })
|
}, { timeout: maxTime })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async clickOnMoreDropdownIcon () {
|
||||||
|
const dropdown = $('my-video-actions-dropdown .action-button')
|
||||||
|
await dropdown.click()
|
||||||
|
|
||||||
|
await $('.dropdown-menu.show .dropdown-item').waitForDisplayed()
|
||||||
|
}
|
||||||
|
|
||||||
private async getVideoNameElement () {
|
private async getVideoNameElement () {
|
||||||
// We have 2 video info name block, pick the first that is not empty
|
// We have 2 video info name block, pick the first that is not empty
|
||||||
const elem = async () => {
|
const elem = async () => {
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { LoginPage } from '../po/login.po'
|
||||||
|
import { VideoUploadPage } from '../po/video-upload.po'
|
||||||
|
import { VideoWatchPage } from '../po/video-watch.po'
|
||||||
|
import { isMobileDevice, isSafari, waitServerUp } from '../utils'
|
||||||
|
|
||||||
|
describe('Custom server defaults', () => {
|
||||||
|
let videoUploadPage: VideoUploadPage
|
||||||
|
let loginPage: LoginPage
|
||||||
|
let videoWatchPage: VideoWatchPage
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
await waitServerUp()
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
loginPage = new LoginPage()
|
||||||
|
videoUploadPage = new VideoUploadPage()
|
||||||
|
videoWatchPage = new VideoWatchPage(isMobileDevice(), isSafari())
|
||||||
|
|
||||||
|
await browser.maximizeWindow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should upload a video with custom default values', async function () {
|
||||||
|
await loginPage.loginAsRootUser()
|
||||||
|
await videoUploadPage.navigateTo()
|
||||||
|
await videoUploadPage.uploadVideo()
|
||||||
|
await videoUploadPage.validSecondUploadStep('video')
|
||||||
|
|
||||||
|
await videoWatchPage.waitWatchVideoName('video')
|
||||||
|
|
||||||
|
expect(await videoWatchPage.getPrivacy()).toBe('Internal')
|
||||||
|
expect(await videoWatchPage.getLicence()).toBe('Attribution - Non Commercial')
|
||||||
|
expect(await videoWatchPage.isDownloadEnabled()).toBeFalsy()
|
||||||
|
expect(await videoWatchPage.areCommentsEnabled()).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
|
@ -4,6 +4,7 @@ import { MyAccountPage } from '../po/my-account'
|
||||||
import { VideoListPage } from '../po/video-list.po'
|
import { VideoListPage } from '../po/video-list.po'
|
||||||
import { VideoSearchPage } from '../po/video-search.po'
|
import { VideoSearchPage } from '../po/video-search.po'
|
||||||
import { VideoUploadPage } from '../po/video-upload.po'
|
import { VideoUploadPage } from '../po/video-upload.po'
|
||||||
|
import { VideoWatchPage } from '../po/video-watch.po'
|
||||||
import { NSFWPolicy } from '../types/common'
|
import { NSFWPolicy } from '../types/common'
|
||||||
import { isMobileDevice, isSafari, waitServerUp } from '../utils'
|
import { isMobileDevice, isSafari, waitServerUp } from '../utils'
|
||||||
|
|
||||||
|
@ -14,6 +15,7 @@ describe('Videos list', () => {
|
||||||
let loginPage: LoginPage
|
let loginPage: LoginPage
|
||||||
let myAccountPage: MyAccountPage
|
let myAccountPage: MyAccountPage
|
||||||
let videoSearchPage: VideoSearchPage
|
let videoSearchPage: VideoSearchPage
|
||||||
|
let videoWatchPage: VideoWatchPage
|
||||||
|
|
||||||
const seed = Math.random()
|
const seed = Math.random()
|
||||||
const nsfwVideo = seed + ' - nsfw'
|
const nsfwVideo = seed + ' - nsfw'
|
||||||
|
@ -108,6 +110,7 @@ describe('Videos list', () => {
|
||||||
videoUploadPage = new VideoUploadPage()
|
videoUploadPage = new VideoUploadPage()
|
||||||
myAccountPage = new MyAccountPage()
|
myAccountPage = new MyAccountPage()
|
||||||
videoSearchPage = new VideoSearchPage()
|
videoSearchPage = new VideoSearchPage()
|
||||||
|
videoWatchPage = new VideoWatchPage(isMobileDevice(), isSafari())
|
||||||
|
|
||||||
await browser.maximizeWindow()
|
await browser.maximizeWindow()
|
||||||
})
|
})
|
||||||
|
@ -191,5 +194,26 @@ describe('Videos list', () => {
|
||||||
await checkCommonVideoListPages('display')
|
await checkCommonVideoListPages('display')
|
||||||
await checkSearchPage('display')
|
await checkSearchPage('display')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
await loginPage.logout()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Default upload values', function () {
|
||||||
|
|
||||||
|
it('Should have default video values', async function () {
|
||||||
|
await loginPage.loginAsRootUser()
|
||||||
|
await videoUploadPage.navigateTo()
|
||||||
|
await videoUploadPage.uploadVideo()
|
||||||
|
await videoUploadPage.validSecondUploadStep('video')
|
||||||
|
|
||||||
|
await videoWatchPage.waitWatchVideoName('video')
|
||||||
|
|
||||||
|
expect(await videoWatchPage.getPrivacy()).toBe('Public')
|
||||||
|
expect(await videoWatchPage.getLicence()).toBe('Unknown')
|
||||||
|
expect(await videoWatchPage.isDownloadEnabled()).toBeTruthy()
|
||||||
|
expect(await videoWatchPage.areCommentsEnabled()).toBeTruthy()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
64
client/e2e/src/utils/hooks.ts
Normal file
64
client/e2e/src/utils/hooks.ts
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
import { ChildProcessWithoutNullStreams } from 'child_process'
|
||||||
|
import { basename } from 'path'
|
||||||
|
import { runCommand, runServer } from './server'
|
||||||
|
|
||||||
|
let appInstance: string
|
||||||
|
let app: ChildProcessWithoutNullStreams
|
||||||
|
|
||||||
|
async function beforeLocalSuite (suite: any) {
|
||||||
|
const config = buildConfig(suite.file)
|
||||||
|
|
||||||
|
await runCommand('npm run clean:server:test -- ' + appInstance)
|
||||||
|
app = runServer(appInstance, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
function afterLocalSuite () {
|
||||||
|
app.kill()
|
||||||
|
app = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeLocalSession (config: { baseUrl: string }, capabilities: { browserName: string }) {
|
||||||
|
appInstance = capabilities['browserName'] === 'chrome' ? '1' : '2'
|
||||||
|
config.baseUrl = 'http://localhost:900' + appInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onBrowserStackPrepare () {
|
||||||
|
const appInstance = '1'
|
||||||
|
|
||||||
|
await runCommand('npm run clean:server:test -- ' + appInstance)
|
||||||
|
app = runServer(appInstance)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBrowserStackComplete () {
|
||||||
|
app.kill()
|
||||||
|
app = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
beforeLocalSession,
|
||||||
|
afterLocalSuite,
|
||||||
|
beforeLocalSuite,
|
||||||
|
onBrowserStackPrepare,
|
||||||
|
onBrowserStackComplete
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function buildConfig (suiteFile: string = undefined) {
|
||||||
|
const filename = basename(suiteFile)
|
||||||
|
|
||||||
|
if (filename === 'custom-server-defaults.e2e-spec.ts') {
|
||||||
|
return {
|
||||||
|
defaults: {
|
||||||
|
publish: {
|
||||||
|
download_enabled: false,
|
||||||
|
comments_enabled: false,
|
||||||
|
privacy: 4,
|
||||||
|
licence: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
export * from './common'
|
export * from './common'
|
||||||
export * from './elements'
|
export * from './elements'
|
||||||
|
export * from './hooks'
|
||||||
|
export * from './server'
|
||||||
export * from './urls'
|
export * from './urls'
|
||||||
|
|
63
client/e2e/src/utils/server.ts
Normal file
63
client/e2e/src/utils/server.ts
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import { exec, spawn } from 'child_process'
|
||||||
|
import { join, resolve } from 'path'
|
||||||
|
|
||||||
|
function runServer (appInstance: string, config: any = {}) {
|
||||||
|
const env = Object.create(process.env)
|
||||||
|
env['NODE_ENV'] = 'test'
|
||||||
|
env['NODE_APP_INSTANCE'] = appInstance
|
||||||
|
|
||||||
|
env['NODE_CONFIG'] = JSON.stringify({
|
||||||
|
rates_limit: {
|
||||||
|
api: {
|
||||||
|
max: 5000
|
||||||
|
},
|
||||||
|
login: {
|
||||||
|
max: 5000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
log: {
|
||||||
|
level: 'warn'
|
||||||
|
},
|
||||||
|
signup: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
transcoding: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
|
||||||
|
...config
|
||||||
|
})
|
||||||
|
|
||||||
|
const forkOptions = {
|
||||||
|
env,
|
||||||
|
cwd: getRootCWD(),
|
||||||
|
detached: false
|
||||||
|
}
|
||||||
|
|
||||||
|
const p = spawn('node', [ join('dist', 'server.js') ], forkOptions)
|
||||||
|
p.stderr.on('data', data => console.error(data.toString()))
|
||||||
|
p.stdout.on('data', data => console.error(data.toString()))
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
function runCommand (command: string) {
|
||||||
|
return new Promise<void>((res, rej) => {
|
||||||
|
const p = exec(command, { cwd: getRootCWD() })
|
||||||
|
|
||||||
|
p.stderr.on('data', data => console.error(data.toString()))
|
||||||
|
p.on('error', err => rej(err))
|
||||||
|
p.on('exit', () => res())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
runServer,
|
||||||
|
runCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function getRootCWD () {
|
||||||
|
return resolve('../..')
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { onBrowserStackComplete, onBrowserStackPrepare } from './src/utils'
|
||||||
import { config as mainConfig } from './wdio.main.conf'
|
import { config as mainConfig } from './wdio.main.conf'
|
||||||
|
|
||||||
const user = process.env.BROWSERSTACK_USER
|
const user = process.env.BROWSERSTACK_USER
|
||||||
|
@ -114,6 +115,10 @@ module.exports = {
|
||||||
if (capabilities['bstack:options'].realMobile === true) {
|
if (capabilities['bstack:options'].realMobile === true) {
|
||||||
capabilities['bstack:options'].local = false
|
capabilities['bstack:options'].local = false
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
onPrepare: onBrowserStackPrepare,
|
||||||
|
onComplete: onBrowserStackComplete
|
||||||
|
|
||||||
} as WebdriverIO.Config
|
} as WebdriverIO.Config
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { afterLocalSuite, beforeLocalSuite, beforeLocalSession } from './src/utils'
|
||||||
import { config as mainConfig } from './wdio.main.conf'
|
import { config as mainConfig } from './wdio.main.conf'
|
||||||
|
|
||||||
const prefs = {
|
const prefs = {
|
||||||
|
@ -21,12 +22,16 @@ module.exports = {
|
||||||
browserName: 'chrome',
|
browserName: 'chrome',
|
||||||
acceptInsecureCerts: true,
|
acceptInsecureCerts: true,
|
||||||
'goog:chromeOptions': {
|
'goog:chromeOptions': {
|
||||||
args: [ '--headless', '--disable-gpu', '--window-size=1280,1024' ],
|
args: [ '--disable-gpu', '--window-size=1280,1024' ],
|
||||||
prefs
|
prefs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
services: [ 'chromedriver' ]
|
services: [ 'chromedriver' ],
|
||||||
|
|
||||||
|
beforeSession: beforeLocalSession,
|
||||||
|
beforeSuite: beforeLocalSuite,
|
||||||
|
afterSuite: afterLocalSuite
|
||||||
} as WebdriverIO.Config
|
} as WebdriverIO.Config
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { afterLocalSuite, beforeLocalSession, beforeLocalSuite } from './src/utils'
|
||||||
import { config as mainConfig } from './wdio.main.conf'
|
import { config as mainConfig } from './wdio.main.conf'
|
||||||
|
|
||||||
const prefs = {
|
const prefs = {
|
||||||
|
@ -11,7 +12,7 @@ module.exports = {
|
||||||
|
|
||||||
runner: 'local',
|
runner: 'local',
|
||||||
|
|
||||||
maxInstances: 2,
|
maxInstancesPerCapability: 1,
|
||||||
|
|
||||||
capabilities: [
|
capabilities: [
|
||||||
{
|
{
|
||||||
|
@ -34,12 +35,8 @@ module.exports = {
|
||||||
|
|
||||||
services: [ 'chromedriver', 'geckodriver' ],
|
services: [ 'chromedriver', 'geckodriver' ],
|
||||||
|
|
||||||
beforeSession: function (config, capabilities) {
|
beforeSession: beforeLocalSession,
|
||||||
if (capabilities['browserName'] === 'chrome') {
|
beforeSuite: beforeLocalSuite,
|
||||||
config.baseUrl = 'http://localhost:9001'
|
afterSuite: afterLocalSuite
|
||||||
} else {
|
|
||||||
config.baseUrl = 'http://localhost:9002'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} as WebdriverIO.Config
|
} as WebdriverIO.Config
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,9 +110,10 @@ export class VideoEditComponent implements OnInit, OnDestroy {
|
||||||
updateForm () {
|
updateForm () {
|
||||||
const defaultValues: any = {
|
const defaultValues: any = {
|
||||||
nsfw: 'false',
|
nsfw: 'false',
|
||||||
commentsEnabled: 'true',
|
commentsEnabled: this.serverConfig.defaults.publish.commentsEnabled,
|
||||||
downloadEnabled: 'true',
|
downloadEnabled: this.serverConfig.defaults.publish.downloadEnabled,
|
||||||
waitTranscoding: 'true',
|
waitTranscoding: 'true',
|
||||||
|
licence: this.serverConfig.defaults.publish.licence,
|
||||||
tags: []
|
tags: []
|
||||||
}
|
}
|
||||||
const obj: any = {
|
const obj: any = {
|
||||||
|
@ -160,6 +161,8 @@ export class VideoEditComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
|
this.serverConfig = this.serverService.getHTMLConfig()
|
||||||
|
|
||||||
this.updateForm()
|
this.updateForm()
|
||||||
|
|
||||||
this.pluginService.ensurePluginsAreLoaded('video-edit')
|
this.pluginService.ensurePluginsAreLoaded('video-edit')
|
||||||
|
@ -200,8 +203,6 @@ export class VideoEditComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.serverConfig = this.serverService.getHTMLConfig()
|
|
||||||
|
|
||||||
this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id)
|
this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id)
|
||||||
|
|
||||||
this.ngZone.runOutsideAngular(() => {
|
this.ngZone.runOutsideAngular(() => {
|
||||||
|
|
|
@ -70,8 +70,6 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterView
|
||||||
privacy: this.highestPrivacy,
|
privacy: this.highestPrivacy,
|
||||||
nsfw: this.serverConfig.instance.isNSFW,
|
nsfw: this.serverConfig.instance.isNSFW,
|
||||||
waitTranscoding: true,
|
waitTranscoding: true,
|
||||||
commentsEnabled: true,
|
|
||||||
downloadEnabled: true,
|
|
||||||
permanentLive: this.firstStepPermanentLive,
|
permanentLive: this.firstStepPermanentLive,
|
||||||
saveReplay: this.firstStepPermanentLive === false && this.isReplayAllowed(),
|
saveReplay: this.firstStepPermanentLive === false && this.isReplayAllowed(),
|
||||||
channelId: this.firstStepChannelId
|
channelId: this.firstStepChannelId
|
||||||
|
|
|
@ -81,8 +81,6 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Af
|
||||||
const videoUpdate: VideoUpdate = {
|
const videoUpdate: VideoUpdate = {
|
||||||
privacy: this.highestPrivacy,
|
privacy: this.highestPrivacy,
|
||||||
waitTranscoding: false,
|
waitTranscoding: false,
|
||||||
commentsEnabled: true,
|
|
||||||
downloadEnabled: true,
|
|
||||||
channelId: this.firstStepChannelId
|
channelId: this.firstStepChannelId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,8 +68,6 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, AfterV
|
||||||
const videoUpdate: VideoUpdate = {
|
const videoUpdate: VideoUpdate = {
|
||||||
privacy: this.highestPrivacy,
|
privacy: this.highestPrivacy,
|
||||||
waitTranscoding: false,
|
waitTranscoding: false,
|
||||||
commentsEnabled: true,
|
|
||||||
downloadEnabled: true,
|
|
||||||
channelId: this.firstStepChannelId
|
channelId: this.firstStepChannelId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,9 @@ export abstract class VideoSend extends FormReactive implements OnInit {
|
||||||
this.serverService.getVideoPrivacies()
|
this.serverService.getVideoPrivacies()
|
||||||
.subscribe(
|
.subscribe(
|
||||||
privacies => {
|
privacies => {
|
||||||
const { videoPrivacies, defaultPrivacyId } = this.videoService.explainedPrivacyLabels(privacies)
|
const defaultPrivacy = this.serverConfig.defaults.publish.privacy
|
||||||
|
|
||||||
|
const { videoPrivacies, defaultPrivacyId } = this.videoService.explainedPrivacyLabels(privacies, defaultPrivacy)
|
||||||
|
|
||||||
this.videoPrivacies = videoPrivacies
|
this.videoPrivacies = videoPrivacies
|
||||||
this.firstStepPrivacyId = defaultPrivacyId
|
this.firstStepPrivacyId = defaultPrivacyId
|
||||||
|
|
|
@ -277,8 +277,6 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
|
||||||
private uploadFile (file: File, previewfile?: File) {
|
private uploadFile (file: File, previewfile?: File) {
|
||||||
const metadata = {
|
const metadata = {
|
||||||
waitTranscoding: true,
|
waitTranscoding: true,
|
||||||
commentsEnabled: true,
|
|
||||||
downloadEnabled: true,
|
|
||||||
channelId: this.firstStepChannelId,
|
channelId: this.firstStepChannelId,
|
||||||
nsfw: this.serverConfig.instance.isNSFW,
|
nsfw: this.serverConfig.instance.isNSFW,
|
||||||
privacy: this.highestPrivacy.toString(),
|
privacy: this.highestPrivacy.toString(),
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
<ng-container *ngIf="!isUserLoggedIn && !video.isLive">
|
<ng-container *ngIf="!isUserLoggedIn && !video.isLive">
|
||||||
<button
|
<button
|
||||||
*ngIf="isVideoDownloadable()" class="action-button action-button-save"
|
*ngIf="isVideoDownloadable()" class="action-button action-button-download"
|
||||||
(click)="showDownloadModal()" (keydown.enter)="showDownloadModal()"
|
(click)="showDownloadModal()" (keydown.enter)="showDownloadModal()"
|
||||||
>
|
>
|
||||||
<my-global-icon iconName="download" aria-hidden="true"></my-global-icon>
|
<my-global-icon iconName="download" aria-hidden="true"></my-global-icon>
|
||||||
|
|
|
@ -49,7 +49,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.action-button-save {
|
&.action-button-save,
|
||||||
|
&.action-button-download {
|
||||||
my-global-icon {
|
my-global-icon {
|
||||||
top: 0 !important;
|
top: 0 !important;
|
||||||
right: -1px;
|
right: -1px;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<div class="attribute">
|
<div class="attribute attribute-privacy">
|
||||||
<span i18n class="attribute-label">Privacy</span>
|
<span i18n class="attribute-label">Privacy</span>
|
||||||
<span class="attribute-value">{{ video.privacy.label }}</span>
|
<span class="attribute-value">{{ video.privacy.label }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="video.isLocal === false" class="attribute">
|
<div *ngIf="video.isLocal === false" class="attribute attribute-origin">
|
||||||
<span i18n class="attribute-label">Origin</span>
|
<span i18n class="attribute-label">Origin</span>
|
||||||
<a
|
<a
|
||||||
class="attribute-value" target="_blank" rel="noopener noreferrer"
|
class="attribute-value" target="_blank" rel="noopener noreferrer"
|
||||||
|
@ -16,12 +16,12 @@
|
||||||
></a>
|
></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="!!video.originallyPublishedAt" class="attribute">
|
<div *ngIf="!!video.originallyPublishedAt" class="attribute attribute-originally-published-at">
|
||||||
<span i18n class="attribute-label">Originally published</span>
|
<span i18n class="attribute-label">Originally published</span>
|
||||||
<span class="attribute-value">{{ video.originallyPublishedAt | date: 'dd MMMM yyyy' }}</span>
|
<span class="attribute-value">{{ video.originallyPublishedAt | date: 'dd MMMM yyyy' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="attribute">
|
<div class="attribute attribute-category">
|
||||||
<span i18n class="attribute-label">Category</span>
|
<span i18n class="attribute-label">Category</span>
|
||||||
<span *ngIf="!video.category.id" class="attribute-value">{{ video.category.label }}</span>
|
<span *ngIf="!video.category.id" class="attribute-value">{{ video.category.label }}</span>
|
||||||
<a
|
<a
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
>{{ video.category.label }}</a>
|
>{{ video.category.label }}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="attribute">
|
<div class="attribute attribute-licence">
|
||||||
<span i18n class="attribute-label">Licence</span>
|
<span i18n class="attribute-label">Licence</span>
|
||||||
<span *ngIf="!video.licence.id" class="attribute-value">{{ video.licence.label }}</span>
|
<span *ngIf="!video.licence.id" class="attribute-value">{{ video.licence.label }}</span>
|
||||||
<a
|
<a
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
>{{ video.licence.label }}</a>
|
>{{ video.licence.label }}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="attribute">
|
<div class="attribute attribute-language">
|
||||||
<span i18n class="attribute-label">Language</span>
|
<span i18n class="attribute-label">Language</span>
|
||||||
<span *ngIf="!video.language.id" class="attribute-value">{{ video.language.label }}</span>
|
<span *ngIf="!video.language.id" class="attribute-value">{{ video.language.label }}</span>
|
||||||
<a
|
<a
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
>{{ tag }}</a>
|
>{{ tag }}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="attribute" *ngIf="!video.isLive">
|
<div class="attribute attribute-duration" *ngIf="!video.isLive">
|
||||||
<span i18n class="attribute-label">Duration</span>
|
<span i18n class="attribute-label">Duration</span>
|
||||||
<span class="attribute-value">{{ video.duration | myDurationFormatter }}</span>
|
<span class="attribute-value">{{ video.duration | myDurationFormatter }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -75,18 +75,22 @@ email:
|
||||||
subject:
|
subject:
|
||||||
prefix: '[PeerTube]'
|
prefix: '[PeerTube]'
|
||||||
|
|
||||||
# PeerTube client/interface configuration
|
# Update default PeerTube values
|
||||||
client:
|
# Set by API when the field is not provided and put as default value in client
|
||||||
videos:
|
defaults:
|
||||||
miniature:
|
# Change default values when publishing a video (upload/import/go Live)
|
||||||
# By default PeerTube client displays author username
|
publish:
|
||||||
prefer_author_display_name: false
|
download_enabled: true
|
||||||
|
|
||||||
menu:
|
comments_enabled: true
|
||||||
login:
|
|
||||||
# If you enable only one external auth plugin
|
# public = 1, unlisted = 2, private = 3, internal = 4
|
||||||
# You can automatically redirect your users on this external platform when they click on the login button
|
privacy: 1
|
||||||
redirect_on_single_external_auth: false
|
|
||||||
|
# CC-BY = 1, CC-SA = 2, CC-ND = 3, CC-NC = 4, CC-NC-SA = 5, CC-NC-ND = 6, Public Domain = 7
|
||||||
|
# You can also choose a custom licence value added by a plugin
|
||||||
|
# No licence by default
|
||||||
|
licence: null
|
||||||
|
|
||||||
# From the project root directory
|
# From the project root directory
|
||||||
storage:
|
storage:
|
||||||
|
@ -587,3 +591,16 @@ search:
|
||||||
disable_local_search: false
|
disable_local_search: false
|
||||||
# If you did not disable local search, you can decide to use the search index by default
|
# If you did not disable local search, you can decide to use the search index by default
|
||||||
is_default_search: false
|
is_default_search: false
|
||||||
|
|
||||||
|
# PeerTube client/interface configuration
|
||||||
|
client:
|
||||||
|
videos:
|
||||||
|
miniature:
|
||||||
|
# By default PeerTube client displays author username
|
||||||
|
prefer_author_display_name: false
|
||||||
|
|
||||||
|
menu:
|
||||||
|
login:
|
||||||
|
# If you enable only one external auth plugin
|
||||||
|
# You can automatically redirect your users on this external platform when they click on the login button
|
||||||
|
redirect_on_single_external_auth: false
|
||||||
|
|
|
@ -73,18 +73,22 @@ email:
|
||||||
subject:
|
subject:
|
||||||
prefix: '[PeerTube]'
|
prefix: '[PeerTube]'
|
||||||
|
|
||||||
# PeerTube client/interface configuration
|
# Update default PeerTube values
|
||||||
client:
|
# Set by API when the field is not provided and put as default value in client
|
||||||
videos:
|
defaults:
|
||||||
miniature:
|
# Change default values when publishing a video (upload/import/go Live)
|
||||||
# By default PeerTube client displays author username
|
publish:
|
||||||
prefer_author_display_name: false
|
download_enabled: true
|
||||||
|
|
||||||
menu:
|
comments_enabled: true
|
||||||
login:
|
|
||||||
# If you enable only one external auth plugin
|
# public = 1, unlisted = 2, private = 3, internal = 4
|
||||||
# You can automatically redirect your users on this external platform when they click on the login button
|
privacy: 1
|
||||||
redirect_on_single_external_auth: false
|
|
||||||
|
# CC-BY = 1, CC-SA = 2, CC-ND = 3, CC-NC = 4, CC-NC-SA = 5, CC-NC-ND = 6, Public Domain = 7
|
||||||
|
# You can also choose a custom licence value added by a plugin
|
||||||
|
# No licence by default
|
||||||
|
licence: null
|
||||||
|
|
||||||
# From the project root directory
|
# From the project root directory
|
||||||
storage:
|
storage:
|
||||||
|
@ -597,3 +601,16 @@ search:
|
||||||
disable_local_search: false
|
disable_local_search: false
|
||||||
# If you did not disable local search, you can decide to use the search index by default
|
# If you did not disable local search, you can decide to use the search index by default
|
||||||
is_default_search: false
|
is_default_search: false
|
||||||
|
|
||||||
|
# PeerTube client/interface configuration
|
||||||
|
client:
|
||||||
|
videos:
|
||||||
|
miniature:
|
||||||
|
# By default PeerTube client displays author username
|
||||||
|
prefer_author_display_name: false
|
||||||
|
|
||||||
|
menu:
|
||||||
|
login:
|
||||||
|
# If you enable only one external auth plugin
|
||||||
|
# You can automatically redirect your users on this external platform when they click on the login button
|
||||||
|
redirect_on_single_external_auth: false
|
||||||
|
|
|
@ -2,8 +2,4 @@
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
npm run clean:server:test
|
cd client/e2e && ../node_modules/.bin/wdio run ./wdio.browserstack.conf.ts
|
||||||
|
|
||||||
npm run concurrently -- -k -s first \
|
|
||||||
"cd client/e2e && ../node_modules/.bin/wdio run ./wdio.browserstack.conf.ts" \
|
|
||||||
"NODE_ENV=test NODE_APP_INSTANCE=1 NODE_CONFIG='{ \"rates_limit\": { \"api\": { \"max\": 5000 }, \"login\": { \"max\": 5000 } }, \"log\": { \"level\": \"warn\" }, \"signup\": { \"enabled\": false } }' node dist/server"
|
|
||||||
|
|
|
@ -2,16 +2,6 @@
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
npm run clean:server:test
|
cd client/e2e
|
||||||
|
|
||||||
config="{"
|
../node_modules/.bin/wdio run ./wdio.local.conf.ts
|
||||||
config+=" \"rates_limit\": { \"api\": { \"max\": 5000 }, \"login\": { \"max\": 5000 } }"
|
|
||||||
config+=", \"log\": { \"level\": \"warn\" }"
|
|
||||||
config+=", \"signup\": { \"enabled\": false }"
|
|
||||||
config+=", \"transcoding\": { \"enabled\": false }"
|
|
||||||
config+="}"
|
|
||||||
|
|
||||||
npm run concurrently -- -k -s first \
|
|
||||||
"cd client/e2e && ../node_modules/.bin/wdio run ./wdio.local.conf.ts" \
|
|
||||||
"NODE_ENV=test NODE_CONFIG='$config' NODE_APP_INSTANCE=1 node dist/server" \
|
|
||||||
"NODE_ENV=test NODE_CONFIG='$config' NODE_APP_INSTANCE=2 node dist/server"
|
|
||||||
|
|
|
@ -216,10 +216,10 @@ async function buildVideo (channelId: number, body: VideoImportCreate, importDat
|
||||||
name: body.name || importData.name || 'Unknown name',
|
name: body.name || importData.name || 'Unknown name',
|
||||||
remote: false,
|
remote: false,
|
||||||
category: body.category || importData.category,
|
category: body.category || importData.category,
|
||||||
licence: body.licence || importData.licence,
|
licence: body.licence ?? importData.licence ?? CONFIG.DEFAULTS.PUBLISH.LICENCE,
|
||||||
language: body.language || importData.language,
|
language: body.language || importData.language,
|
||||||
commentsEnabled: body.commentsEnabled !== false, // If the value is not "false", the default is "true"
|
commentsEnabled: body.commentsEnabled ?? CONFIG.DEFAULTS.PUBLISH.COMMENTS_ENABLED,
|
||||||
downloadEnabled: body.downloadEnabled !== false,
|
downloadEnabled: body.downloadEnabled ?? CONFIG.DEFAULTS.PUBLISH.DOWNLOAD_ENABLED,
|
||||||
waitTranscoding: body.waitTranscoding || false,
|
waitTranscoding: body.waitTranscoding || false,
|
||||||
state: VideoState.TO_IMPORT,
|
state: VideoState.TO_IMPORT,
|
||||||
nsfw: body.nsfw || importData.nsfw || false,
|
nsfw: body.nsfw || importData.nsfw || false,
|
||||||
|
|
|
@ -34,6 +34,7 @@ function checkMissedConfig () {
|
||||||
'import.videos.http.enabled', 'import.videos.torrent.enabled', 'import.videos.concurrency', 'auto_blacklist.videos.of_users.enabled',
|
'import.videos.http.enabled', 'import.videos.torrent.enabled', 'import.videos.concurrency', 'auto_blacklist.videos.of_users.enabled',
|
||||||
'trending.videos.interval_days',
|
'trending.videos.interval_days',
|
||||||
'client.videos.miniature.prefer_author_display_name', 'client.menu.login.redirect_on_single_external_auth',
|
'client.videos.miniature.prefer_author_display_name', 'client.menu.login.redirect_on_single_external_auth',
|
||||||
|
'defaults.publish.download_enabled', 'defaults.publish.comments_enabled', 'defaults.publish.privacy', 'defaults.publish.licence',
|
||||||
'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route',
|
'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route',
|
||||||
'instance.is_nsfw', 'instance.default_nsfw_policy', 'instance.robots', 'instance.securitytxt',
|
'instance.is_nsfw', 'instance.default_nsfw_policy', 'instance.robots', 'instance.securitytxt',
|
||||||
'services.twitter.username', 'services.twitter.whitelisted',
|
'services.twitter.username', 'services.twitter.whitelisted',
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { dirname, join } from 'path'
|
||||||
import { decacheModule } from '@server/helpers/decache'
|
import { decacheModule } from '@server/helpers/decache'
|
||||||
import { VideoRedundancyConfigFilter } from '@shared/models/redundancy/video-redundancy-config-filter.type'
|
import { VideoRedundancyConfigFilter } from '@shared/models/redundancy/video-redundancy-config-filter.type'
|
||||||
import { BroadcastMessageLevel } from '@shared/models/server'
|
import { BroadcastMessageLevel } from '@shared/models/server'
|
||||||
import { VideosRedundancyStrategy } from '../../shared/models'
|
import { VideoPrivacy, VideosRedundancyStrategy } from '../../shared/models'
|
||||||
import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type'
|
import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type'
|
||||||
import { buildPath, parseBytes, parseDurationToMs, root } from '../helpers/core-utils'
|
import { buildPath, parseBytes, parseDurationToMs, root } from '../helpers/core-utils'
|
||||||
|
|
||||||
|
@ -71,6 +71,15 @@ const CONFIG = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
DEFAULTS: {
|
||||||
|
PUBLISH: {
|
||||||
|
DOWNLOAD_ENABLED: config.get<boolean>('defaults.publish.download_enabled'),
|
||||||
|
COMMENTS_ENABLED: config.get<boolean>('defaults.publish.comments_enabled'),
|
||||||
|
PRIVACY: config.get<VideoPrivacy>('defaults.publish.privacy'),
|
||||||
|
LICENCE: config.get<number>('defaults.publish.licence')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
STORAGE: {
|
STORAGE: {
|
||||||
TMP_DIR: buildPath(config.get<string>('storage.tmp')),
|
TMP_DIR: buildPath(config.get<string>('storage.tmp')),
|
||||||
BIN_DIR: buildPath(config.get<string>('storage.bin')),
|
BIN_DIR: buildPath(config.get<string>('storage.bin')),
|
||||||
|
|
|
@ -55,6 +55,15 @@ class ServerConfigManager {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
defaults: {
|
||||||
|
publish: {
|
||||||
|
downloadEnabled: CONFIG.DEFAULTS.PUBLISH.DOWNLOAD_ENABLED,
|
||||||
|
commentsEnabled: CONFIG.DEFAULTS.PUBLISH.COMMENTS_ENABLED,
|
||||||
|
privacy: CONFIG.DEFAULTS.PUBLISH.PRIVACY,
|
||||||
|
licence: CONFIG.DEFAULTS.PUBLISH.LICENCE
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
webadmin: {
|
webadmin: {
|
||||||
configuration: {
|
configuration: {
|
||||||
edition: {
|
edition: {
|
||||||
|
|
|
@ -9,16 +9,17 @@ import { MThumbnail, MUserId, MVideoFile, MVideoTag, MVideoThumbnail, MVideoUUID
|
||||||
import { ThumbnailType, VideoCreate, VideoPrivacy, VideoTranscodingPayload } from '@shared/models'
|
import { ThumbnailType, VideoCreate, VideoPrivacy, VideoTranscodingPayload } from '@shared/models'
|
||||||
import { CreateJobOptions, JobQueue } from './job-queue/job-queue'
|
import { CreateJobOptions, JobQueue } from './job-queue/job-queue'
|
||||||
import { updateVideoMiniatureFromExisting } from './thumbnail'
|
import { updateVideoMiniatureFromExisting } from './thumbnail'
|
||||||
|
import { CONFIG } from '@server/initializers/config'
|
||||||
|
|
||||||
function buildLocalVideoFromReq (videoInfo: VideoCreate, channelId: number): FilteredModelAttributes<VideoModel> {
|
function buildLocalVideoFromReq (videoInfo: VideoCreate, channelId: number): FilteredModelAttributes<VideoModel> {
|
||||||
return {
|
return {
|
||||||
name: videoInfo.name,
|
name: videoInfo.name,
|
||||||
remote: false,
|
remote: false,
|
||||||
category: videoInfo.category,
|
category: videoInfo.category,
|
||||||
licence: videoInfo.licence,
|
licence: videoInfo.licence ?? CONFIG.DEFAULTS.PUBLISH.LICENCE,
|
||||||
language: videoInfo.language,
|
language: videoInfo.language,
|
||||||
commentsEnabled: videoInfo.commentsEnabled !== false, // If the value is not "false", the default is "true"
|
commentsEnabled: videoInfo.commentsEnabled ?? CONFIG.DEFAULTS.PUBLISH.COMMENTS_ENABLED,
|
||||||
downloadEnabled: videoInfo.downloadEnabled !== false,
|
downloadEnabled: videoInfo.downloadEnabled ?? CONFIG.DEFAULTS.PUBLISH.DOWNLOAD_ENABLED,
|
||||||
waitTranscoding: videoInfo.waitTranscoding || false,
|
waitTranscoding: videoInfo.waitTranscoding || false,
|
||||||
nsfw: videoInfo.nsfw || false,
|
nsfw: videoInfo.nsfw || false,
|
||||||
description: videoInfo.description,
|
description: videoInfo.description,
|
||||||
|
|
116
server/tests/api/server/config-defaults.ts
Normal file
116
server/tests/api/server/config-defaults.ts
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||||
|
|
||||||
|
import 'mocha'
|
||||||
|
import * as chai from 'chai'
|
||||||
|
import { cleanupTests, createSingleServer, FIXTURE_URLS, PeerTubeServer, setAccessTokensToServers, setDefaultVideoChannel } from '@shared/extra-utils'
|
||||||
|
import { VideoDetails, VideoPrivacy } from '@shared/models'
|
||||||
|
|
||||||
|
const expect = chai.expect
|
||||||
|
|
||||||
|
describe('Test config defaults', function () {
|
||||||
|
let server: PeerTubeServer
|
||||||
|
let channelId: number
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
this.timeout(30000)
|
||||||
|
|
||||||
|
const overrideConfig = {
|
||||||
|
defaults: {
|
||||||
|
publish: {
|
||||||
|
comments_enabled: false,
|
||||||
|
download_enabled: false,
|
||||||
|
privacy: VideoPrivacy.INTERNAL,
|
||||||
|
licence: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server = await createSingleServer(1, overrideConfig)
|
||||||
|
await setAccessTokensToServers([ server ])
|
||||||
|
await setDefaultVideoChannel([ server ])
|
||||||
|
|
||||||
|
channelId = server.store.channel.id
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Default publish values', function () {
|
||||||
|
const attributes = {
|
||||||
|
name: 'video',
|
||||||
|
downloadEnabled: undefined,
|
||||||
|
commentsEnabled: undefined,
|
||||||
|
licence: undefined,
|
||||||
|
privacy: VideoPrivacy.PUBLIC // Privacy is mandatory for server
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkVideo (video: VideoDetails) {
|
||||||
|
expect(video.downloadEnabled).to.be.false
|
||||||
|
expect(video.commentsEnabled).to.be.false
|
||||||
|
expect(video.licence.id).to.equal(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
await server.config.disableTranscoding()
|
||||||
|
await server.config.enableImports()
|
||||||
|
await server.config.enableLive({ allowReplay: false, transcoding: false })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should have the correct server configuration', async function () {
|
||||||
|
const config = await server.config.getConfig()
|
||||||
|
|
||||||
|
expect(config.defaults.publish.commentsEnabled).to.be.false
|
||||||
|
expect(config.defaults.publish.downloadEnabled).to.be.false
|
||||||
|
expect(config.defaults.publish.licence).to.equal(4)
|
||||||
|
expect(config.defaults.publish.privacy).to.equal(VideoPrivacy.INTERNAL)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should respect default values when uploading a video', async function () {
|
||||||
|
for (const mode of [ 'legacy' as 'legacy', 'resumable' as 'resumable' ]) {
|
||||||
|
const { id } = await server.videos.upload({ attributes, mode })
|
||||||
|
|
||||||
|
const video = await server.videos.get({ id })
|
||||||
|
checkVideo(video)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should respect default values when importing a video using URL', async function () {
|
||||||
|
const { video: { id } } = await server.imports.importVideo({
|
||||||
|
attributes: {
|
||||||
|
...attributes,
|
||||||
|
channelId,
|
||||||
|
targetUrl: FIXTURE_URLS.goodVideo
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const video = await server.videos.get({ id })
|
||||||
|
checkVideo(video)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should respect default values when importing a video using magnet URI', async function () {
|
||||||
|
const { video: { id } } = await server.imports.importVideo({
|
||||||
|
attributes: {
|
||||||
|
...attributes,
|
||||||
|
channelId,
|
||||||
|
magnetUri: FIXTURE_URLS.magnet
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const video = await server.videos.get({ id })
|
||||||
|
checkVideo(video)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should respect default values when creating a live', async function () {
|
||||||
|
const { id } = await server.live.create({
|
||||||
|
fields: {
|
||||||
|
...attributes,
|
||||||
|
channelId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const video = await server.videos.get({ id })
|
||||||
|
checkVideo(video)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async function () {
|
||||||
|
await cleanupTests([ server ])
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,4 +1,6 @@
|
||||||
import './auto-follows'
|
import './auto-follows'
|
||||||
|
import './bulk'
|
||||||
|
import './config-defaults'
|
||||||
import './config'
|
import './config'
|
||||||
import './contact-form'
|
import './contact-form'
|
||||||
import './email'
|
import './email'
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { VideoPrivacy } from '../videos/video-privacy.enum'
|
||||||
import { ClientScript } from '../plugins/plugin-package-json.model'
|
import { ClientScript } from '../plugins/plugin-package-json.model'
|
||||||
import { NSFWPolicyType } from '../videos/nsfw-policy.type'
|
import { NSFWPolicyType } from '../videos/nsfw-policy.type'
|
||||||
import { BroadcastMessageLevel } from './broadcast-message-level.type'
|
import { BroadcastMessageLevel } from './broadcast-message-level.type'
|
||||||
|
@ -47,6 +48,15 @@ export interface ServerConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaults: {
|
||||||
|
publish: {
|
||||||
|
downloadEnabled: boolean
|
||||||
|
commentsEnabled: boolean
|
||||||
|
privacy: VideoPrivacy
|
||||||
|
licence: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
webadmin: {
|
webadmin: {
|
||||||
configuration: {
|
configuration: {
|
||||||
edition: {
|
edition: {
|
||||||
|
|
|
@ -88,13 +88,7 @@ $ BROWSERSTACK_USER=your_user BROWSERSTACK_KEY=your_key npm run e2e:browserstack
|
||||||
|
|
||||||
### Add E2E tests
|
### Add E2E tests
|
||||||
|
|
||||||
To add E2E tests and quickly run tests using a local Chrome, first create a test instance:
|
To add E2E tests and quickly run tests using a local Chrome:
|
||||||
|
|
||||||
```bash
|
|
||||||
$ npm run clean:server:test && NODE_APP_INSTANCE=1 NODE_ENV=test npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, just run your suite using:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ cd client/e2e
|
$ cd client/e2e
|
||||||
|
|
Loading…
Reference in a new issue