Verified Commit 2989628b authored by Chocobozzz's avatar Chocobozzz
Browse files

Use HTML config when possible

parent 8e08d415
...@@ -22,10 +22,10 @@ import { FormReactiveValidationMessages, FormValidatorService } from '@app/share ...@@ -22,10 +22,10 @@ import { FormReactiveValidationMessages, FormValidatorService } from '@app/share
import { InstanceService } from '@app/shared/shared-instance' import { InstanceService } from '@app/shared/shared-instance'
import { VideoCaptionEdit, VideoEdit, VideoService } from '@app/shared/shared-main' import { VideoCaptionEdit, VideoEdit, VideoService } from '@app/shared/shared-main'
import { import {
HTMLServerConfig,
LiveVideo, LiveVideo,
RegisterClientFormFieldOptions, RegisterClientFormFieldOptions,
RegisterClientVideoFieldOptions, RegisterClientVideoFieldOptions,
ServerConfig,
VideoConstant, VideoConstant,
VideoDetails, VideoDetails,
VideoPrivacy VideoPrivacy
...@@ -84,7 +84,7 @@ export class VideoEditComponent implements OnInit, OnDestroy { ...@@ -84,7 +84,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
calendarTimezone: string calendarTimezone: string
calendarDateFormat: string calendarDateFormat: string
serverConfig: ServerConfig serverConfig: HTMLServerConfig
pluginFields: PluginField[] = [] pluginFields: PluginField[] = []
...@@ -194,9 +194,8 @@ export class VideoEditComponent implements OnInit, OnDestroy { ...@@ -194,9 +194,8 @@ export class VideoEditComponent implements OnInit, OnDestroy {
} }
}) })
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig() this.serverConfig = this.serverService.getHTMLConfig()
.subscribe(config => this.serverConfig = config)
this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id) this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id)
......
...@@ -6,7 +6,7 @@ import { listUserChannels } from '@app/helpers' ...@@ -6,7 +6,7 @@ import { listUserChannels } from '@app/helpers'
import { FormReactive } from '@app/shared/shared-forms' import { FormReactive } from '@app/shared/shared-forms'
import { VideoCaptionEdit, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' import { VideoCaptionEdit, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
import { LoadingBarService } from '@ngx-loading-bar/core' import { LoadingBarService } from '@ngx-loading-bar/core'
import { ServerConfig, VideoConstant, VideoPrivacy } from '@shared/models' import { HTMLServerConfig, VideoConstant, VideoPrivacy } from '@shared/models'
@Directive() @Directive()
// tslint:disable-next-line: directive-class-suffix // tslint:disable-next-line: directive-class-suffix
...@@ -28,7 +28,7 @@ export abstract class VideoSend extends FormReactive implements OnInit { ...@@ -28,7 +28,7 @@ export abstract class VideoSend extends FormReactive implements OnInit {
protected serverService: ServerService protected serverService: ServerService
protected videoService: VideoService protected videoService: VideoService
protected videoCaptionService: VideoCaptionService protected videoCaptionService: VideoCaptionService
protected serverConfig: ServerConfig protected serverConfig: HTMLServerConfig
abstract canDeactivate (): CanComponentDeactivateResult abstract canDeactivate (): CanComponentDeactivateResult
...@@ -41,9 +41,7 @@ export abstract class VideoSend extends FormReactive implements OnInit { ...@@ -41,9 +41,7 @@ export abstract class VideoSend extends FormReactive implements OnInit {
this.firstStepChannelId = this.userVideoChannels[0].id this.firstStepChannelId = this.userVideoChannels[0].id
}) })
this.serverConfig = this.serverService.getTmpConfig() this.serverConfig = this.serverService.getHTMLConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.serverService.getVideoPrivacies() this.serverService.getVideoPrivacies()
.subscribe( .subscribe(
......
import { Component, HostListener, OnInit, ViewChild } from '@angular/core' import { Component, HostListener, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { AuthService, AuthUser, CanComponentDeactivate, ServerService } from '@app/core' import { AuthService, AuthUser, CanComponentDeactivate, ServerService } from '@app/core'
import { ServerConfig } from '@shared/models' import { HTMLServerConfig } from '@shared/models'
import { VideoEditType } from './shared/video-edit.type' import { VideoEditType } from './shared/video-edit.type'
import { VideoGoLiveComponent } from './video-add-components/video-go-live.component' import { VideoGoLiveComponent } from './video-add-components/video-go-live.component'
import { VideoImportTorrentComponent } from './video-add-components/video-import-torrent.component' import { VideoImportTorrentComponent } from './video-add-components/video-import-torrent.component'
...@@ -26,7 +26,7 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate { ...@@ -26,7 +26,7 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate {
activeNav: string activeNav: string
private serverConfig: ServerConfig private serverConfig: HTMLServerConfig
constructor ( constructor (
private auth: AuthService, private auth: AuthService,
...@@ -42,10 +42,7 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate { ...@@ -42,10 +42,7 @@ export class VideoAddComponent implements OnInit, CanComponentDeactivate {
ngOnInit () { ngOnInit () {
this.user = this.auth.getUser() this.user = this.auth.getUser()
this.serverConfig = this.serverService.getTmpConfig() this.serverConfig = this.serverService.getHTMLConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.user = this.auth.getUser() this.user = this.auth.getUser()
......
...@@ -4,7 +4,7 @@ import { Injectable } from '@angular/core' ...@@ -4,7 +4,7 @@ import { Injectable } from '@angular/core'
import { ServerService, UserService } from '@app/core' import { ServerService, UserService } from '@app/core'
import { Video, VideoService } from '@app/shared/shared-main' import { Video, VideoService } from '@app/shared/shared-main'
import { AdvancedSearch, SearchService } from '@app/shared/shared-search' import { AdvancedSearch, SearchService } from '@app/shared/shared-search'
import { ServerConfig } from '@shared/models' import { HTMLServerConfig } from '@shared/models'
import { RecommendationInfo } from './recommendation-info.model' import { RecommendationInfo } from './recommendation-info.model'
import { RecommendationService } from './recommendations.service' import { RecommendationService } from './recommendations.service'
...@@ -15,7 +15,7 @@ import { RecommendationService } from './recommendations.service' ...@@ -15,7 +15,7 @@ import { RecommendationService } from './recommendations.service'
export class RecentVideosRecommendationService implements RecommendationService { export class RecentVideosRecommendationService implements RecommendationService {
readonly pageSize = 5 readonly pageSize = 5
private config: ServerConfig private config: HTMLServerConfig
constructor ( constructor (
private videos: VideoService, private videos: VideoService,
...@@ -23,13 +23,11 @@ export class RecentVideosRecommendationService implements RecommendationService ...@@ -23,13 +23,11 @@ export class RecentVideosRecommendationService implements RecommendationService
private userService: UserService, private userService: UserService,
private serverService: ServerService private serverService: ServerService
) { ) {
this.config = this.serverService.getTmpConfig() this.config = this.serverService.getHTMLConfig()
this.serverService.getConfig()
.subscribe(config => this.config = config)
} }
getRecommendations (recommendation: RecommendationInfo): Observable<Video[]> { getRecommendations (recommendation: RecommendationInfo): Observable<Video[]> {
return this.fetchPage(1, recommendation) return this.fetchPage(1, recommendation)
.pipe( .pipe(
map(videos => { map(videos => {
......
...@@ -28,7 +28,15 @@ import { VideoActionsDisplayType, VideoDownloadComponent } from '@app/shared/sha ...@@ -28,7 +28,15 @@ import { VideoActionsDisplayType, VideoDownloadComponent } from '@app/shared/sha
import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist'
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
import { PeerTubeProblemDocument, ServerConfig, ServerErrorCode, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '@shared/models' import {
HTMLServerConfig,
PeerTubeProblemDocument,
ServerErrorCode,
UserVideoRateType,
VideoCaption,
VideoPrivacy,
VideoState
} from '@shared/models'
import { import {
cleanupVideoWatch, cleanupVideoWatch,
getStoredP2PEnabled, getStoredP2PEnabled,
...@@ -116,7 +124,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { ...@@ -116,7 +124,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private configSub: Subscription private configSub: Subscription
private liveVideosSub: Subscription private liveVideosSub: Subscription
private serverConfig: ServerConfig private serverConfig: HTMLServerConfig
constructor ( constructor (
private elementRef: ElementRef, private elementRef: ElementRef,
...@@ -163,21 +171,16 @@ export class VideoWatchComponent implements OnInit, OnDestroy { ...@@ -163,21 +171,16 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
PeertubePlayerManager.initState() PeertubePlayerManager.initState()
this.serverConfig = this.serverService.getTmpConfig() this.serverConfig = this.serverService.getHTMLConfig()
if (
this.configSub = this.serverService.getConfig() isWebRTCDisabled() ||
.subscribe(config => { this.serverConfig.tracker.enabled === false ||
this.serverConfig = config getStoredP2PEnabled() === false ||
peertubeLocalStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true'
) {
this.hasAlreadyAcceptedPrivacyConcern = true
}
if (
isWebRTCDisabled() ||
this.serverConfig.tracker.enabled === false ||
getStoredP2PEnabled() === false ||
peertubeLocalStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true'
) {
this.hasAlreadyAcceptedPrivacyConcern = true
}
})
this.paramsSub = this.route.params.subscribe(routeParams => { this.paramsSub = this.route.params.subscribe(routeParams => {
const videoId = routeParams[ 'videoId' ] const videoId = routeParams[ 'videoId' ]
......
import { Subscription } from 'rxjs'
import { Component, HostBinding, Inject, OnDestroy, OnInit } from '@angular/core' import { Component, HostBinding, Inject, OnDestroy, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router' import { ActivatedRoute, Router } from '@angular/router'
import { VideoListHeaderComponent } from '@app/shared/shared-video-miniature'
import { GlobalIconName } from '@app/shared/shared-icons'
import { ServerService } from '@app/core/server/server.service'
import { Subscription } from 'rxjs'
import { AuthService, RedirectService } from '@app/core' import { AuthService, RedirectService } from '@app/core'
import { ServerService } from '@app/core/server/server.service'
import { GlobalIconName } from '@app/shared/shared-icons'
import { VideoListHeaderComponent } from '@app/shared/shared-video-miniature'
interface VideoTrendingHeaderItem { interface VideoTrendingHeaderItem {
label: string label: string
...@@ -67,21 +67,19 @@ export class VideoTrendingHeaderComponent extends VideoListHeaderComponent imple ...@@ -67,21 +67,19 @@ export class VideoTrendingHeaderComponent extends VideoListHeaderComponent imple
} }
ngOnInit () { ngOnInit () {
this.serverService.getConfig() const serverConfig = this.serverService.getHTMLConfig()
.subscribe(config => { const algEnabled = serverConfig.trending.videos.algorithms.enabled
const algEnabled = config.trending.videos.algorithms.enabled
this.buttons = this.buttons.map(b => { this.buttons = this.buttons.map(b => {
b.hidden = !algEnabled.includes(b.value) b.hidden = !algEnabled.includes(b.value)
// Best is adapted by the user history so // Best is adapted by the user history so
if (b.value === 'best' && !this.auth.isLoggedIn()) { if (b.value === 'best' && !this.auth.isLoggedIn()) {
b.hidden = true b.hidden = true
} }
return b return b
}) })
})
this.algorithmChangeSub = this.route.queryParams.subscribe( this.algorithmChangeSub = this.route.queryParams.subscribe(
queryParams => { queryParams => {
......
import { Hotkey, HotkeysService } from 'angular2-hotkeys' import { Hotkey, HotkeysService } from 'angular2-hotkeys'
import { concat } from 'rxjs' import { concat } from 'rxjs'
import { filter, first, map, pairwise } from 'rxjs/operators' import { filter, first, map, pairwise, switchMap } from 'rxjs/operators'
import { DOCUMENT, PlatformLocation, ViewportScroller } from '@angular/common' import { DOCUMENT, PlatformLocation, ViewportScroller } from '@angular/common'
import { AfterViewInit, Component, Inject, LOCALE_ID, OnInit, ViewChild } from '@angular/core' import { AfterViewInit, Component, Inject, LOCALE_ID, OnInit, ViewChild } from '@angular/core'
import { DomSanitizer, SafeHtml } from '@angular/platform-browser' import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
...@@ -15,7 +15,7 @@ import { NgbConfig, NgbModal } from '@ng-bootstrap/ng-bootstrap' ...@@ -15,7 +15,7 @@ import { NgbConfig, NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { LoadingBarService } from '@ngx-loading-bar/core' import { LoadingBarService } from '@ngx-loading-bar/core'
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
import { getShortLocale, is18nPath } from '@shared/core-utils/i18n' import { getShortLocale, is18nPath } from '@shared/core-utils/i18n'
import { BroadcastMessageLevel, ServerConfig, UserRole } from '@shared/models' import { BroadcastMessageLevel, HTMLServerConfig, ServerConfig, UserRole } from '@shared/models'
import { MenuService } from './core/menu/menu.service' import { MenuService } from './core/menu/menu.service'
import { POP_STATE_MODAL_DISMISS } from './helpers' import { POP_STATE_MODAL_DISMISS } from './helpers'
import { InstanceService } from './shared/shared-instance' import { InstanceService } from './shared/shared-instance'
...@@ -35,7 +35,7 @@ export class AppComponent implements OnInit, AfterViewInit { ...@@ -35,7 +35,7 @@ export class AppComponent implements OnInit, AfterViewInit {
customCSS: SafeHtml customCSS: SafeHtml
broadcastMessage: { message: string, dismissable: boolean, class: string } | null = null broadcastMessage: { message: string, dismissable: boolean, class: string } | null = null
private serverConfig: ServerConfig private serverConfig: HTMLServerConfig
constructor ( constructor (
@Inject(DOCUMENT) private document: Document, @Inject(DOCUMENT) private document: Document,
...@@ -73,9 +73,7 @@ export class AppComponent implements OnInit, AfterViewInit { ...@@ -73,9 +73,7 @@ export class AppComponent implements OnInit, AfterViewInit {
ngOnInit () { ngOnInit () {
document.getElementById('incompatible-browser').className += ' browser-ok' document.getElementById('incompatible-browser').className += ' browser-ok'
this.serverConfig = this.serverService.getTmpConfig() this.serverConfig = this.serverService.getHTMLConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.loadPlugins() this.loadPlugins()
this.themeService.initialize() this.themeService.initialize()
...@@ -88,10 +86,21 @@ export class AppComponent implements OnInit, AfterViewInit { ...@@ -88,10 +86,21 @@ export class AppComponent implements OnInit, AfterViewInit {
} }
this.initRouteEvents() this.initRouteEvents()
this.injectJS() this.injectJS()
this.injectCSS() this.injectCSS()
this.injectBroadcastMessage() this.injectBroadcastMessage()
this.serverService.configReloaded
.subscribe(config => {
this.serverConfig = config
this.injectBroadcastMessage()
this.injectCSS()
// Don't reinject JS since it could conflict with existing one
})
this.initHotkeys() this.initHotkeys()
this.location.onPopState(() => this.modalService.dismissAll(POP_STATE_MODAL_DISMISS)) this.location.onPopState(() => this.modalService.dismissAll(POP_STATE_MODAL_DISMISS))
...@@ -208,69 +217,55 @@ export class AppComponent implements OnInit, AfterViewInit { ...@@ -208,69 +217,55 @@ export class AppComponent implements OnInit, AfterViewInit {
).subscribe(() => this.loadingBar.useRef().complete()) ).subscribe(() => this.loadingBar.useRef().complete())
} }
private injectBroadcastMessage () { private async injectBroadcastMessage () {
concat( this.broadcastMessage = null
this.serverService.getConfig().pipe(first()), this.screenService.isBroadcastMessageDisplayed = false
this.serverService.configReloaded
).subscribe(async config => {
this.broadcastMessage = null
this.screenService.isBroadcastMessageDisplayed = false
const messageConfig = config.broadcastMessage
if (messageConfig.enabled) { const messageConfig = this.serverConfig.broadcastMessage
// Already dismissed this message?
if (messageConfig.dismissable && localStorage.getItem(AppComponent.BROADCAST_MESSAGE_KEY) === messageConfig.message) {
return
}
const classes: { [id in BroadcastMessageLevel]: string } = { if (messageConfig.enabled) {
info: 'alert-info', // Already dismissed this message?
warning: 'alert-warning', if (messageConfig.dismissable && localStorage.getItem(AppComponent.BROADCAST_MESSAGE_KEY) === messageConfig.message) {
error: 'alert-danger' return
} }
this.broadcastMessage = { const classes: { [id in BroadcastMessageLevel]: string } = {
message: await this.markdownService.unsafeMarkdownToHTML(messageConfig.message, true), info: 'alert-info',
dismissable: messageConfig.dismissable, warning: 'alert-warning',
class: classes[messageConfig.level] error: 'alert-danger'
} }
this.screenService.isBroadcastMessageDisplayed = true this.broadcastMessage = {
message: await this.markdownService.unsafeMarkdownToHTML(messageConfig.message, true),
dismissable: messageConfig.dismissable,
class: classes[messageConfig.level]
} }
})
this.screenService.isBroadcastMessageDisplayed = true
}
} }
private injectJS () { private injectJS () {
// Inject JS // Inject JS
this.serverService.getConfig() if (this.serverConfig.instance.customizations.javascript) {
.subscribe(config => { try {
if (config.instance.customizations.javascript) { // tslint:disable:no-eval
try { eval(this.serverConfig.instance.customizations.javascript)
// tslint:disable:no-eval } catch (err) {
eval(config.instance.customizations.javascript) console.error('Cannot eval custom JavaScript.', err)
} catch (err) { }
console.error('Cannot eval custom JavaScript.', err) }
}
}
})
} }
private injectCSS () { private injectCSS () {
// Inject CSS if modified (admin config settings) const headStyle = document.querySelector('style.custom-css-style')
concat( if (headStyle) headStyle.parentNode.removeChild(headStyle)
this.serverService.getConfig().pipe(first()),
this.serverService.configReloaded // We test customCSS if the admin removed the css
).subscribe(config => { if (this.customCSS || this.serverConfig.instance.customizations.css) {
const headStyle = document.querySelector('style.custom-css-style') const styleTag = '<style>' + this.serverConfig.instance.customizations.css + '</style>'
if (headStyle) headStyle.parentNode.removeChild(headStyle) this.customCSS = this.domSanitizer.bypassSecurityTrustHtml(styleTag)
}
// We test customCSS if the admin removed the css
if (this.customCSS || config.instance.customizations.css) {
const styleTag = '<style>' + config.instance.customizations.css + '</style>'
this.customCSS = this.domSanitizer.bypassSecurityTrustHtml(styleTag)
}
})
} }
private async loadPlugins () { private async loadPlugins () {
...@@ -283,14 +278,18 @@ export class AppComponent implements OnInit, AfterViewInit { ...@@ -283,14 +278,18 @@ export class AppComponent implements OnInit, AfterViewInit {
this.authService.userInformationLoaded this.authService.userInformationLoaded
.pipe( .pipe(
map(() => this.authService.getUser()), map(() => this.authService.getUser()),
filter(user => user.role === UserRole.ADMINISTRATOR) filter(user => user.role === UserRole.ADMINISTRATOR),
).subscribe(user => setTimeout(() => this._openAdminModalsIfNeeded(user))) // setTimeout because of ngIf in template switchMap(user => {
return this.serverService.getConfig()
.pipe(map(serverConfig => ({ serverConfig, user })))
})
).subscribe(({ serverConfig, user }) => this._openAdminModalsIfNeeded(serverConfig, user))
} }
private async _openAdminModalsIfNeeded (user: User) { private async _openAdminModalsIfNeeded (serverConfig: ServerConfig, user: User) {
if (user.noWelcomeModal !== true) return this.welcomeModal.show() if (user.noWelcomeModal !== true) return this.welcomeModal.show()
if (user.noInstanceConfigWarningModal === true || !this.serverConfig.signup.allowed) return if (user.noInstanceConfigWarningModal === true || !serverConfig.signup.allowed) return
this.instanceService.getAbout() this.instanceService.getAbout()
.subscribe(about => { .subscribe(about => {
......
...@@ -27,7 +27,7 @@ import { SharedUserInterfaceSettingsModule } from './shared/shared-user-settings ...@@ -27,7 +27,7 @@ import { SharedUserInterfaceSettingsModule } from './shared/shared-user-settings
registerLocaleData(localeOc, 'oc') registerLocaleData(localeOc, 'oc')
export function loadConfigFactory (server: ServerService) { export function loadConfigFactory (server: ServerService) {
return () => server.loadConfig() return () => server.loadHTMLConfig()
} }
@NgModule({ @NgModule({
......
...@@ -3,7 +3,7 @@ import { debounceTime } from 'rxjs/operators' ...@@ -3,7 +3,7 @@ import { debounceTime } from 'rxjs/operators'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { GlobalIconName } from '@app/shared/shared-icons' import { GlobalIconName } from '@app/shared/shared-icons'
import { sortObjectComparator } from '@shared/core-utils/miscs/miscs' import { sortObjectComparator } from '@shared/core-utils/miscs/miscs'
import { ServerConfig } from '@shared/models/server' import { HTMLServerConfig } from '@shared/models/server'
import { ScreenService } from '../wrappers' import { ScreenService } from '../wrappers'
export type MenuLink = { export type MenuLink = {
...@@ -59,7 +59,7 @@ export class MenuService { ...@@ -59,7 +59,7 @@ export class MenuService {
this.isMenuDisplayed = window.innerWidth >= 800 && !this.isMenuChangedByUser