1
0
Fork 0

Add ability to change the homepage

This commit is contained in:
Chocobozzz 2018-03-01 13:57:29 +01:00
parent a73c582e5b
commit 901637bb87
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
18 changed files with 108 additions and 18 deletions

View File

@ -37,6 +37,16 @@
</div> </div>
</div> </div>
<div class="form-group">
<label for="instanceDefaultClientRoute">Default client route</label>
<div class="peertube-select-container">
<select id="instanceDefaultClientRoute" formControlName="instanceDefaultClientRoute">
<option value="/videos/trending">Videos Trending</option>
<option value="/videos/recently-added">Videos Recently Added</option>
</select>
</div>
</div>
<div class="inner-form-title">Cache</div> <div class="inner-form-title">Cache</div>
<div class="form-group"> <div class="form-group">

View File

@ -46,6 +46,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
instanceName: '', instanceName: '',
instanceDescription: '', instanceDescription: '',
instanceTerms: '', instanceTerms: '',
instanceDefaultClientRoute: '',
cachePreviewsSize: '', cachePreviewsSize: '',
signupLimit: '', signupLimit: '',
adminEmail: '', adminEmail: '',
@ -85,6 +86,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
instanceName: [ '', INSTANCE_NAME.VALIDATORS ], instanceName: [ '', INSTANCE_NAME.VALIDATORS ],
instanceDescription: [ '' ], instanceDescription: [ '' ],
instanceTerms: [ '' ], instanceTerms: [ '' ],
instanceDefaultClientRoute: [ '' ],
cachePreviewsSize: [ '', CACHE_PREVIEWS_SIZE.VALIDATORS ], cachePreviewsSize: [ '', CACHE_PREVIEWS_SIZE.VALIDATORS ],
signupEnabled: [ ], signupEnabled: [ ],
signupLimit: [ '', SIGNUP_LIMIT.VALIDATORS ], signupLimit: [ '', SIGNUP_LIMIT.VALIDATORS ],
@ -153,11 +155,12 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
if (confirmRes === false) return if (confirmRes === false) return
} }
const data = { const data: CustomConfig = {
instance: { instance: {
name: this.form.value['instanceName'], name: this.form.value['instanceName'],
description: this.form.value['instanceDescription'], description: this.form.value['instanceDescription'],
terms: this.form.value['instanceTerms'], terms: this.form.value['instanceTerms'],
defaultClientRoute: this.form.value['instanceDefaultClientRoute'],
customizations: { customizations: {
javascript: this.form.value['customizationJavascript'], javascript: this.form.value['customizationJavascript'],
css: this.form.value['customizationCSS'] css: this.form.value['customizationCSS']
@ -213,6 +216,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
instanceName: this.customConfig.instance.name, instanceName: this.customConfig.instance.name,
instanceDescription: this.customConfig.instance.description, instanceDescription: this.customConfig.instance.description,
instanceTerms: this.customConfig.instance.terms, instanceTerms: this.customConfig.instance.terms,
instanceDefaultClientRoute: this.customConfig.instance.defaultClientRoute,
cachePreviewsSize: this.customConfig.cache.previews.size, cachePreviewsSize: this.customConfig.cache.previews.size,
signupEnabled: this.customConfig.signup.enabled, signupEnabled: this.customConfig.signup.enabled,
signupLimit: this.customConfig.signup.limit, signupLimit: this.customConfig.signup.limit,

View File

@ -1,14 +1,10 @@
import { NgModule } from '@angular/core' import { NgModule } from '@angular/core'
import { Routes, RouterModule } from '@angular/router' import { Routes, RouterModule } from '@angular/router'
import { RedirectService } from '@app/core/routing/redirect.service'
import { PreloadSelectedModulesList } from './core' import { PreloadSelectedModulesList } from './core'
const routes: Routes = [ const routes: Routes = [
{
path: '',
redirectTo: '/videos/trending',
pathMatch: 'full'
},
{ {
path: 'admin', path: 'admin',
loadChildren: './+admin/admin.module#AdminModule' loadChildren: './+admin/admin.module#AdminModule'
@ -22,7 +18,9 @@ const routes: Routes = [
preloadingStrategy: PreloadSelectedModulesList preloadingStrategy: PreloadSelectedModulesList
}) })
], ],
providers: [ PreloadSelectedModulesList ], providers: [
PreloadSelectedModulesList
],
exports: [ RouterModule ] exports: [ RouterModule ]
}) })
export class AppRoutingModule {} export class AppRoutingModule {}

View File

@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core' import { Component, OnInit } from '@angular/core'
import { DomSanitizer, SafeHtml } from '@angular/platform-browser' import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
import { GuardsCheckStart, Router } from '@angular/router' import { GuardsCheckStart, Router } from '@angular/router'
import { AuthService, ServerService } from '@app/core' import { AuthService, RedirectService, ServerService } from '@app/core'
import { isInSmallView } from '@app/shared/misc/utils' import { isInSmallView } from '@app/shared/misc/utils'
@Component({ @Component({
@ -31,7 +31,8 @@ export class AppComponent implements OnInit {
private router: Router, private router: Router,
private authService: AuthService, private authService: AuthService,
private serverService: ServerService, private serverService: ServerService,
private domSanitizer: DomSanitizer private domSanitizer: DomSanitizer,
private redirectService: RedirectService
) {} ) {}
get serverVersion () { get serverVersion () {
@ -43,6 +44,10 @@ export class AppComponent implements OnInit {
} }
ngOnInit () { ngOnInit () {
if (this.router.url === '/') {
this.redirectService.redirectToHomepage()
}
this.authService.loadClientCredentials() this.authService.loadClientCredentials()
if (this.authService.isLoggedIn()) { if (this.authService.isLoggedIn()) {

View File

@ -13,7 +13,7 @@ import { ModalModule } from 'ngx-bootstrap/modal'
import { AuthService } from './auth' import { AuthService } from './auth'
import { ConfirmComponent, ConfirmService } from './confirm' import { ConfirmComponent, ConfirmService } from './confirm'
import { throwIfAlreadyLoaded } from './module-import-guard' import { throwIfAlreadyLoaded } from './module-import-guard'
import { LoginGuard, UserRightGuard } from './routing' import { LoginGuard, RedirectService, UserRightGuard } from './routing'
import { ServerService } from './server' import { ServerService } from './server'
@NgModule({ @NgModule({
@ -48,7 +48,8 @@ import { ServerService } from './server'
ConfirmService, ConfirmService,
ServerService, ServerService,
LoginGuard, LoginGuard,
UserRightGuard UserRightGuard,
RedirectService
] ]
}) })
export class CoreModule { export class CoreModule {

View File

@ -1,3 +1,4 @@
export * from './login-guard.service' export * from './login-guard.service'
export * from './user-right-guard.service' export * from './user-right-guard.service'
export * from './preload-selected-modules-list' export * from './preload-selected-modules-list'
export * from './redirect.service'

View File

@ -0,0 +1,48 @@
import { Injectable } from '@angular/core'
import { Router } from '@angular/router'
import { ServerService } from '../server'
@Injectable()
export class RedirectService {
// Default route could change according to the instance configuration
static INIT_DEFAULT_ROUTE = '/videos/trending'
static DEFAULT_ROUTE = RedirectService.INIT_DEFAULT_ROUTE
constructor (
private router: Router,
private serverService: ServerService
) {
// The config is first loaded from the cache so try to get the default route
const config = this.serverService.getConfig()
if (config && config.instance && config.instance.defaultClientRoute) {
RedirectService.DEFAULT_ROUTE = config.instance.defaultClientRoute
}
this.serverService.configLoaded
.subscribe(() => {
const defaultRouteConfig = this.serverService.getConfig().instance.defaultClientRoute
if (defaultRouteConfig) {
RedirectService.DEFAULT_ROUTE = defaultRouteConfig
}
})
}
redirectToHomepage () {
console.log('Redirecting to %s...', RedirectService.DEFAULT_ROUTE)
this.router.navigate([ RedirectService.DEFAULT_ROUTE ])
.catch(() => {
console.error(
'Cannot navigate to %s, resetting default route to %s.',
RedirectService.DEFAULT_ROUTE,
RedirectService.INIT_DEFAULT_ROUTE
)
RedirectService.DEFAULT_ROUTE = RedirectService.INIT_DEFAULT_ROUTE
return this.router.navigate([ RedirectService.DEFAULT_ROUTE ])
})
}
}

View File

@ -21,6 +21,7 @@ export class ServerService {
private config: ServerConfig = { private config: ServerConfig = {
instance: { instance: {
name: 'PeerTube', name: 'PeerTube',
defaultClientRoute: '',
customizations: { customizations: {
javascript: '', javascript: '',
css: '' css: ''

View File

@ -1,9 +1,9 @@
import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core' import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { RedirectService } from '@app/core/routing/redirect.service'
import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component' import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component'
import { MetaService } from '@ngx-meta/core' import { MetaService } from '@ngx-meta/core'
import { NotificationsService } from 'angular2-notifications' import { NotificationsService } from 'angular2-notifications'
import { Observable } from 'rxjs/Observable'
import { Subscription } from 'rxjs/Subscription' import { Subscription } from 'rxjs/Subscription'
import * as videojs from 'video.js' import * as videojs from 'video.js'
import 'videojs-hotkeys' import 'videojs-hotkeys'
@ -64,7 +64,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private authService: AuthService, private authService: AuthService,
private notificationsService: NotificationsService, private notificationsService: NotificationsService,
private markdownService: MarkdownService, private markdownService: MarkdownService,
private zone: NgZone private zone: NgZone,
private redirectService: RedirectService
) {} ) {}
get user () { get user () {
@ -142,7 +143,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
.subscribe( .subscribe(
status => { status => {
this.notificationsService.success('Success', `Video ${this.video.name} had been blacklisted.`) this.notificationsService.success('Success', `Video ${this.video.name} had been blacklisted.`)
this.router.navigate(['/videos/list']) this.redirectService.redirectToHomepage()
}, },
error => this.notificationsService.error('Error', error.message) error => this.notificationsService.error('Error', error.message)
@ -247,7 +248,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
this.notificationsService.success('Success', `Video ${this.video.name} deleted.`) this.notificationsService.success('Success', `Video ${this.video.name} deleted.`)
// Go back to the video-list. // Go back to the video-list.
this.router.navigate([ '/videos/list' ]) this.redirectService.redirectToHomepage()
}, },
error => this.notificationsService.error('Error', error.message) error => this.notificationsService.error('Error', error.message)
@ -313,7 +314,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
'This video contains mature or explicit content. Are you sure you want to watch it?', 'This video contains mature or explicit content. Are you sure you want to watch it?',
'Mature or explicit content' 'Mature or explicit content'
) )
if (res === false) return this.router.navigate([ '/videos/list' ]) if (res === false) return this.redirectService.redirectToHomepage()
} }
if (!this.hasAlreadyAcceptedPrivacyConcern()) { if (!this.hasAlreadyAcceptedPrivacyConcern()) {
@ -323,7 +324,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
'Privacy concern', 'Privacy concern',
'I accept!' 'I accept!'
) )
if (res === false) return this.router.navigate([ '/videos/list' ]) if (res === false) return this.redirectService.redirectToHomepage()
} }
this.acceptedPrivacyConcern() this.acceptedPrivacyConcern()

View File

@ -74,6 +74,7 @@ instance:
name: 'PeerTube' name: 'PeerTube'
description: 'Welcome to this PeerTube instance!' # Support markdown description: 'Welcome to this PeerTube instance!' # Support markdown
terms: 'No terms for now.' # Support markdown terms: 'No terms for now.' # Support markdown
default_client_route: '/videos/trending'
customizations: customizations:
javascript: '' # Directly your JavaScript code (without <script> tags). Will be eval at runtime javascript: '' # Directly your JavaScript code (without <script> tags). Will be eval at runtime
css: '' # Directly your CSS code (without <style> tags). Will be injected at runtime css: '' # Directly your CSS code (without <style> tags). Will be injected at runtime

View File

@ -87,6 +87,7 @@ instance:
name: 'PeerTube' name: 'PeerTube'
description: '' # Support markdown description: '' # Support markdown
terms: '' # Support markdown terms: '' # Support markdown
default_client_route: '/videos/trending'
customizations: customizations:
javascript: '' # Directly your JavaScript code (without <script> tags). Will be eval at runtime javascript: '' # Directly your JavaScript code (without <script> tags). Will be eval at runtime
css: '' # Directly your CSS code (without <style> tags). Will be injected at runtime css: '' # Directly your CSS code (without <style> tags). Will be injected at runtime

View File

@ -44,6 +44,7 @@ async function getConfig (req: express.Request, res: express.Response, next: exp
const json: ServerConfig = { const json: ServerConfig = {
instance: { instance: {
name: CONFIG.INSTANCE.NAME, name: CONFIG.INSTANCE.NAME,
defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE,
customizations: { customizations: {
javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT, javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT,
css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS
@ -114,7 +115,9 @@ async function updateCustomConfig (req: express.Request, res: express.Response,
// Need to change the videoQuota key a little bit // Need to change the videoQuota key a little bit
const toUpdateJSON = omit(toUpdate, 'videoQuota') const toUpdateJSON = omit(toUpdate, 'videoQuota')
toUpdateJSON.user['video_quota'] = toUpdate.user.videoQuota toUpdateJSON.user['video_quota'] = toUpdate.user.videoQuota
toUpdateJSON.instance['default_client_route'] = toUpdate.instance.defaultClientRoute
delete toUpdate.user.videoQuota delete toUpdate.user.videoQuota
delete toUpdate.instance.defaultClientRoute
await writeFilePromise(CONFIG.CUSTOM_FILE, JSON.stringify(toUpdateJSON, undefined, 2)) await writeFilePromise(CONFIG.CUSTOM_FILE, JSON.stringify(toUpdateJSON, undefined, 2))
@ -138,6 +141,7 @@ function customConfig (): CustomConfig {
name: CONFIG.INSTANCE.NAME, name: CONFIG.INSTANCE.NAME,
description: CONFIG.INSTANCE.DESCRIPTION, description: CONFIG.INSTANCE.DESCRIPTION,
terms: CONFIG.INSTANCE.TERMS, terms: CONFIG.INSTANCE.TERMS,
defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE,
customizations: { customizations: {
css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS, css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS,
javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT

View File

@ -159,6 +159,7 @@ const CONFIG = {
get NAME () { return config.get<string>('instance.name') }, get NAME () { return config.get<string>('instance.name') },
get DESCRIPTION () { return config.get<string>('instance.description') }, get DESCRIPTION () { return config.get<string>('instance.description') },
get TERMS () { return config.get<string>('instance.terms') }, get TERMS () { return config.get<string>('instance.terms') },
get DEFAULT_CLIENT_ROUTE () { return config.get<string>('instance.default_client_route') },
CUSTOMIZATIONS: { CUSTOMIZATIONS: {
get JAVASCRIPT () { return config.get<string>('instance.customizations.javascript') }, get JAVASCRIPT () { return config.get<string>('instance.customizations.javascript') },
get CSS () { return config.get<string>('instance.customizations.css') } get CSS () { return config.get<string>('instance.customizations.css') }

View File

@ -5,6 +5,12 @@ import { logger } from '../../helpers/logger'
import { areValidationErrors } from './utils' import { areValidationErrors } from './utils'
const customConfigUpdateValidator = [ const customConfigUpdateValidator = [
body('instance.name').exists().withMessage('Should have a valid instance name'),
body('instance.description').exists().withMessage('Should have a valid instance description'),
body('instance.terms').exists().withMessage('Should have a valid instance terms'),
body('instance.defaultClientRoute').exists().withMessage('Should have a valid instance default client route'),
body('instance.customizations.css').exists().withMessage('Should have a valid instance CSS customization'),
body('instance.customizations.javascript').exists().withMessage('Should have a valid instance JavaScript customization'),
body('cache.previews.size').isInt().withMessage('Should have a valid previews size'), body('cache.previews.size').isInt().withMessage('Should have a valid previews size'),
body('signup.enabled').isBoolean().withMessage('Should have a valid signup enabled boolean'), body('signup.enabled').isBoolean().withMessage('Should have a valid signup enabled boolean'),
body('signup.limit').isInt().withMessage('Should have a valid signup limit'), body('signup.limit').isInt().withMessage('Should have a valid signup limit'),

View File

@ -18,6 +18,7 @@ describe('Test config API validators', function () {
name: 'PeerTube updated', name: 'PeerTube updated',
description: 'my super description', description: 'my super description',
terms: 'my super terms', terms: 'my super terms',
defaultClientRoute: '/videos/recently-added',
customizations: { customizations: {
javascript: 'alert("coucou")', javascript: 'alert("coucou")',
css: 'body { background-color: red; }' css: 'body { background-color: red; }'

View File

@ -54,6 +54,7 @@ describe('Test config', function () {
expect(data.instance.name).to.equal('PeerTube') expect(data.instance.name).to.equal('PeerTube')
expect(data.instance.description).to.equal('Welcome to this PeerTube instance!') expect(data.instance.description).to.equal('Welcome to this PeerTube instance!')
expect(data.instance.terms).to.equal('No terms for now.') expect(data.instance.terms).to.equal('No terms for now.')
expect(data.instance.defaultClientRoute).to.equal('/videos/trending')
expect(data.instance.customizations.css).to.be.empty expect(data.instance.customizations.css).to.be.empty
expect(data.instance.customizations.javascript).to.be.empty expect(data.instance.customizations.javascript).to.be.empty
expect(data.cache.previews.size).to.equal(1) expect(data.cache.previews.size).to.equal(1)
@ -76,6 +77,7 @@ describe('Test config', function () {
name: 'PeerTube updated', name: 'PeerTube updated',
description: 'my super description', description: 'my super description',
terms: 'my super terms', terms: 'my super terms',
defaultClientRoute: '/videos/recently-added',
customizations: { customizations: {
javascript: 'alert("coucou")', javascript: 'alert("coucou")',
css: 'body { background-color: red; }' css: 'body { background-color: red; }'
@ -116,6 +118,7 @@ describe('Test config', function () {
expect(data.instance.name).to.equal('PeerTube updated') expect(data.instance.name).to.equal('PeerTube updated')
expect(data.instance.description).to.equal('my super description') expect(data.instance.description).to.equal('my super description')
expect(data.instance.terms).to.equal('my super terms') expect(data.instance.terms).to.equal('my super terms')
expect(data.instance.defaultClientRoute).to.equal('/videos/recently-added')
expect(data.instance.customizations.javascript).to.equal('alert("coucou")') expect(data.instance.customizations.javascript).to.equal('alert("coucou")')
expect(data.instance.customizations.css).to.equal('body { background-color: red; }') expect(data.instance.customizations.css).to.equal('body { background-color: red; }')
expect(data.cache.previews.size).to.equal(2) expect(data.cache.previews.size).to.equal(2)
@ -145,6 +148,7 @@ describe('Test config', function () {
expect(data.instance.name).to.equal('PeerTube updated') expect(data.instance.name).to.equal('PeerTube updated')
expect(data.instance.description).to.equal('my super description') expect(data.instance.description).to.equal('my super description')
expect(data.instance.terms).to.equal('my super terms') expect(data.instance.terms).to.equal('my super terms')
expect(data.instance.defaultClientRoute).to.equal('/videos/recently-added')
expect(data.instance.customizations.javascript).to.equal('alert("coucou")') expect(data.instance.customizations.javascript).to.equal('alert("coucou")')
expect(data.instance.customizations.css).to.equal('body { background-color: red; }') expect(data.instance.customizations.css).to.equal('body { background-color: red; }')
expect(data.cache.previews.size).to.equal(2) expect(data.cache.previews.size).to.equal(2)
@ -181,6 +185,7 @@ describe('Test config', function () {
expect(data.instance.name).to.equal('PeerTube') expect(data.instance.name).to.equal('PeerTube')
expect(data.instance.description).to.equal('Welcome to this PeerTube instance!') expect(data.instance.description).to.equal('Welcome to this PeerTube instance!')
expect(data.instance.terms).to.equal('No terms for now.') expect(data.instance.terms).to.equal('No terms for now.')
expect(data.instance.defaultClientRoute).to.equal('/videos/trending')
expect(data.instance.customizations.css).to.be.empty expect(data.instance.customizations.css).to.be.empty
expect(data.instance.customizations.javascript).to.be.empty expect(data.instance.customizations.javascript).to.be.empty
expect(data.cache.previews.size).to.equal(1) expect(data.cache.previews.size).to.equal(1)

View File

@ -3,6 +3,7 @@ export interface CustomConfig {
name: string name: string
description: string description: string
terms: string terms: string
defaultClientRoute: string
customizations: { customizations: {
javascript?: string javascript?: string
css?: string css?: string

View File

@ -2,7 +2,8 @@ export interface ServerConfig {
serverVersion: string serverVersion: string
instance: { instance: {
name: string; name: string
defaultClientRoute: string
customizations: { customizations: {
javascript: string javascript: string
css: string css: string