aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/core
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/core')
-rw-r--r--client/src/app/core/auth/auth-user.model.ts14
-rw-r--r--client/src/app/core/auth/auth.service.ts18
-rw-r--r--client/src/app/core/auth/index.ts1
-rw-r--r--client/src/app/core/confirm/confirm.component.html25
-rw-r--r--client/src/app/core/confirm/confirm.component.scss17
-rw-r--r--client/src/app/core/confirm/confirm.component.ts68
-rw-r--r--client/src/app/core/confirm/index.ts1
-rw-r--r--client/src/app/core/core.module.ts25
-rw-r--r--client/src/app/core/index.ts1
-rw-r--r--client/src/app/core/notification/index.ts2
-rw-r--r--client/src/app/core/notification/notifier.service.ts41
-rw-r--r--client/src/app/core/notification/user-notification-socket.service.ts41
-rw-r--r--client/src/app/core/routing/login-guard.service.ts10
-rw-r--r--client/src/app/core/routing/redirect.service.ts21
-rw-r--r--client/src/app/core/routing/user-right-guard.service.ts2
-rw-r--r--client/src/app/core/server/server.service.ts23
-rw-r--r--client/src/app/core/theme/theme.service.ts4
17 files changed, 158 insertions, 156 deletions
diff --git a/client/src/app/core/auth/auth-user.model.ts b/client/src/app/core/auth/auth-user.model.ts
index 74ed1c580..abb11fdc2 100644
--- a/client/src/app/core/auth/auth-user.model.ts
+++ b/client/src/app/core/auth/auth-user.model.ts
@@ -1,8 +1,9 @@
1import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' 1import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
2import { UserRight } from '../../../../../shared/models/users/user-right.enum' 2import { UserRight } from '../../../../../shared/models/users/user-right.enum'
3import { User as ServerUserModel } from '../../../../../shared/models/users/user.model'
3// Do not use the barrel (dependency loop) 4// Do not use the barrel (dependency loop)
4import { hasUserRight, UserRole } from '../../../../../shared/models/users/user-role' 5import { hasUserRight, UserRole } from '../../../../../shared/models/users/user-role'
5import { User, UserConstructorHash } from '../../shared/users/user.model' 6import { User } from '../../shared/users/user.model'
6import { NSFWPolicyType } from '../../../../../shared/models/videos/nsfw-policy.type' 7import { NSFWPolicyType } from '../../../../../shared/models/videos/nsfw-policy.type'
7 8
8export type TokenOptions = { 9export type TokenOptions = {
@@ -70,8 +71,10 @@ export class AuthUser extends User {
70 ID: 'id', 71 ID: 'id',
71 ROLE: 'role', 72 ROLE: 'role',
72 EMAIL: 'email', 73 EMAIL: 'email',
74 VIDEOS_HISTORY_ENABLED: 'videos-history-enabled',
73 USERNAME: 'username', 75 USERNAME: 'username',
74 NSFW_POLICY: 'nsfw_policy', 76 NSFW_POLICY: 'nsfw_policy',
77 WEBTORRENT_ENABLED: 'peertube-videojs-' + 'webtorrent_enabled',
75 AUTO_PLAY_VIDEO: 'auto_play_video' 78 AUTO_PLAY_VIDEO: 'auto_play_video'
76 } 79 }
77 80
@@ -87,7 +90,9 @@ export class AuthUser extends User {
87 email: peertubeLocalStorage.getItem(this.KEYS.EMAIL), 90 email: peertubeLocalStorage.getItem(this.KEYS.EMAIL),
88 role: parseInt(peertubeLocalStorage.getItem(this.KEYS.ROLE), 10) as UserRole, 91 role: parseInt(peertubeLocalStorage.getItem(this.KEYS.ROLE), 10) as UserRole,
89 nsfwPolicy: peertubeLocalStorage.getItem(this.KEYS.NSFW_POLICY) as NSFWPolicyType, 92 nsfwPolicy: peertubeLocalStorage.getItem(this.KEYS.NSFW_POLICY) as NSFWPolicyType,
90 autoPlayVideo: peertubeLocalStorage.getItem(this.KEYS.AUTO_PLAY_VIDEO) === 'true' 93 webTorrentEnabled: peertubeLocalStorage.getItem(this.KEYS.WEBTORRENT_ENABLED) === 'true',
94 autoPlayVideo: peertubeLocalStorage.getItem(this.KEYS.AUTO_PLAY_VIDEO) === 'true',
95 videosHistoryEnabled: peertubeLocalStorage.getItem(this.KEYS.VIDEOS_HISTORY_ENABLED) === 'true'
91 }, 96 },
92 Tokens.load() 97 Tokens.load()
93 ) 98 )
@@ -101,12 +106,14 @@ export class AuthUser extends User {
101 peertubeLocalStorage.removeItem(this.KEYS.ID) 106 peertubeLocalStorage.removeItem(this.KEYS.ID)
102 peertubeLocalStorage.removeItem(this.KEYS.ROLE) 107 peertubeLocalStorage.removeItem(this.KEYS.ROLE)
103 peertubeLocalStorage.removeItem(this.KEYS.NSFW_POLICY) 108 peertubeLocalStorage.removeItem(this.KEYS.NSFW_POLICY)
109 peertubeLocalStorage.removeItem(this.KEYS.WEBTORRENT_ENABLED)
110 peertubeLocalStorage.removeItem(this.KEYS.VIDEOS_HISTORY_ENABLED)
104 peertubeLocalStorage.removeItem(this.KEYS.AUTO_PLAY_VIDEO) 111 peertubeLocalStorage.removeItem(this.KEYS.AUTO_PLAY_VIDEO)
105 peertubeLocalStorage.removeItem(this.KEYS.EMAIL) 112 peertubeLocalStorage.removeItem(this.KEYS.EMAIL)
106 Tokens.flush() 113 Tokens.flush()
107 } 114 }
108 115
109 constructor (userHash: UserConstructorHash, hashTokens: TokenOptions) { 116 constructor (userHash: Partial<ServerUserModel>, hashTokens: TokenOptions) {
110 super(userHash) 117 super(userHash)
111 this.tokens = new Tokens(hashTokens) 118 this.tokens = new Tokens(hashTokens)
112 } 119 }
@@ -138,6 +145,7 @@ export class AuthUser extends User {
138 peertubeLocalStorage.setItem(AuthUser.KEYS.EMAIL, this.email) 145 peertubeLocalStorage.setItem(AuthUser.KEYS.EMAIL, this.email)
139 peertubeLocalStorage.setItem(AuthUser.KEYS.ROLE, this.role.toString()) 146 peertubeLocalStorage.setItem(AuthUser.KEYS.ROLE, this.role.toString())
140 peertubeLocalStorage.setItem(AuthUser.KEYS.NSFW_POLICY, this.nsfwPolicy.toString()) 147 peertubeLocalStorage.setItem(AuthUser.KEYS.NSFW_POLICY, this.nsfwPolicy.toString())
148 peertubeLocalStorage.setItem(AuthUser.KEYS.WEBTORRENT_ENABLED, JSON.stringify(this.webTorrentEnabled))
141 peertubeLocalStorage.setItem(AuthUser.KEYS.AUTO_PLAY_VIDEO, JSON.stringify(this.autoPlayVideo)) 149 peertubeLocalStorage.setItem(AuthUser.KEYS.AUTO_PLAY_VIDEO, JSON.stringify(this.autoPlayVideo))
142 this.tokens.save() 150 this.tokens.save()
143 } 151 }
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts
index 9c36b946e..eaa822e0f 100644
--- a/client/src/app/core/auth/auth.service.ts
+++ b/client/src/app/core/auth/auth.service.ts
@@ -3,18 +3,18 @@ import { catchError, map, mergeMap, share, tap } from 'rxjs/operators'
3import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http' 3import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'
4import { Injectable } from '@angular/core' 4import { Injectable } from '@angular/core'
5import { Router } from '@angular/router' 5import { Router } from '@angular/router'
6import { NotificationsService } from 'angular2-notifications' 6import { Notifier } from '@app/core/notification/notifier.service'
7import { OAuthClientLocal, User as UserServerModel, UserRefreshToken } from '../../../../../shared' 7import { OAuthClientLocal, User as UserServerModel, UserRefreshToken } from '../../../../../shared'
8import { User } from '../../../../../shared/models/users' 8import { User } from '../../../../../shared/models/users'
9import { UserLogin } from '../../../../../shared/models/users/user-login.model' 9import { UserLogin } from '../../../../../shared/models/users/user-login.model'
10import { environment } from '../../../environments/environment' 10import { environment } from '../../../environments/environment'
11import { RestExtractor } from '../../shared/rest' 11import { RestExtractor } from '../../shared/rest/rest-extractor.service'
12import { AuthStatus } from './auth-status.model' 12import { AuthStatus } from './auth-status.model'
13import { AuthUser } from './auth-user.model' 13import { AuthUser } from './auth-user.model'
14import { objectToUrlEncoded } from '@app/shared/misc/utils' 14import { objectToUrlEncoded } from '@app/shared/misc/utils'
15import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' 15import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
16import { I18n } from '@ngx-translate/i18n-polyfill' 16import { I18n } from '@ngx-translate/i18n-polyfill'
17import { HotkeysService, Hotkey } from 'angular2-hotkeys' 17import { Hotkey, HotkeysService } from 'angular2-hotkeys'
18 18
19interface UserLoginWithUsername extends UserLogin { 19interface UserLoginWithUsername extends UserLogin {
20 access_token: string 20 access_token: string
@@ -38,7 +38,6 @@ export class AuthService {
38 loginChangedSource: Observable<AuthStatus> 38 loginChangedSource: Observable<AuthStatus>
39 userInformationLoaded = new ReplaySubject<boolean>(1) 39 userInformationLoaded = new ReplaySubject<boolean>(1)
40 hotkeys: Hotkey[] 40 hotkeys: Hotkey[]
41 redirectUrl: string
42 41
43 private clientId: string = peertubeLocalStorage.getItem(AuthService.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_ID) 42 private clientId: string = peertubeLocalStorage.getItem(AuthService.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_ID)
44 private clientSecret: string = peertubeLocalStorage.getItem(AuthService.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_SECRET) 43 private clientSecret: string = peertubeLocalStorage.getItem(AuthService.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_SECRET)
@@ -48,7 +47,7 @@ export class AuthService {
48 47
49 constructor ( 48 constructor (
50 private http: HttpClient, 49 private http: HttpClient,
51 private notificationsService: NotificationsService, 50 private notifier: Notifier,
52 private hotkeysService: HotkeysService, 51 private hotkeysService: HotkeysService,
53 private restExtractor: RestExtractor, 52 private restExtractor: RestExtractor,
54 private router: Router, 53 private router: Router,
@@ -106,9 +105,8 @@ export class AuthService {
106 ) 105 )
107 } 106 }
108 107
109 // We put a bigger timeout 108 // We put a bigger timeout: this is an important message
110 // This is an important message 109 this.notifier.error(errorMessage, this.i18n('Error'), 7000)
111 this.notificationsService.error(this.i18n('Error'), errorMessage, { timeOut: 7000 })
112 } 110 }
113 ) 111 )
114 } 112 }
@@ -178,8 +176,6 @@ export class AuthService {
178 this.setStatus(AuthStatus.LoggedOut) 176 this.setStatus(AuthStatus.LoggedOut)
179 177
180 this.hotkeysService.remove(this.hotkeys) 178 this.hotkeysService.remove(this.hotkeys)
181
182 this.redirectUrl = null
183 } 179 }
184 180
185 refreshAccessToken () { 181 refreshAccessToken () {
@@ -221,7 +217,7 @@ export class AuthService {
221 } 217 }
222 218
223 refreshUserInformation () { 219 refreshUserInformation () {
224 const obj = { 220 const obj: UserLoginWithUsername = {
225 access_token: this.user.getAccessToken(), 221 access_token: this.user.getAccessToken(),
226 refresh_token: null, 222 refresh_token: null,
227 token_type: this.user.getTokenType(), 223 token_type: this.user.getTokenType(),
diff --git a/client/src/app/core/auth/index.ts b/client/src/app/core/auth/index.ts
index bc7bfec0e..8e5caa7ed 100644
--- a/client/src/app/core/auth/index.ts
+++ b/client/src/app/core/auth/index.ts
@@ -1,4 +1,3 @@
1export * from './auth-status.model' 1export * from './auth-status.model'
2export * from './auth-user.model' 2export * from './auth-user.model'
3export * from './auth.service' 3export * from './auth.service'
4export * from '../routing/login-guard.service'
diff --git a/client/src/app/core/confirm/confirm.component.html b/client/src/app/core/confirm/confirm.component.html
deleted file mode 100644
index 43f0c6190..000000000
--- a/client/src/app/core/confirm/confirm.component.html
+++ /dev/null
@@ -1,25 +0,0 @@
1<ng-template #confirmModal let-close="close" let-dismiss="dismiss">
2
3 <div class="modal-header">
4 <h4 class="modal-title">{{ title }}</h4>
5 <span class="close" aria-label="Close" role="button" (click)="dismiss()"></span>
6 </div>
7
8 <div class="modal-body" >
9 <div [innerHtml]="message"></div>
10
11 <div *ngIf="inputLabel && expectedInputValue" class="form-group">
12 <label for="confirmInput">{{ inputLabel }}</label>
13 <input type="text" id="confirmInput" name="confirmInput" [(ngModel)]="inputValue" />
14 </div>
15 </div>
16
17 <div class="modal-footer inputs">
18 <span i18n class="action-button action-button-cancel" (click)="dismiss()" role="button">Cancel</span>
19
20 <input
21 type="submit" [value]="confirmButtonText" class="action-button-submit" [disabled]="isConfirmationDisabled()"
22 (click)="close()"
23 >
24 </div>
25</ng-template>
diff --git a/client/src/app/core/confirm/confirm.component.scss b/client/src/app/core/confirm/confirm.component.scss
deleted file mode 100644
index 93dd7926b..000000000
--- a/client/src/app/core/confirm/confirm.component.scss
+++ /dev/null
@@ -1,17 +0,0 @@
1@import '_variables';
2@import '_mixins';
3
4.button {
5 padding: 0 13px;
6}
7
8input[type=text] {
9 @include peertube-input-text(100%);
10 display: block;
11}
12
13.form-group {
14 margin: 20px 0;
15}
16
17
diff --git a/client/src/app/core/confirm/confirm.component.ts b/client/src/app/core/confirm/confirm.component.ts
deleted file mode 100644
index 5138b7848..000000000
--- a/client/src/app/core/confirm/confirm.component.ts
+++ /dev/null
@@ -1,68 +0,0 @@
1import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core'
2import { ConfirmService } from './confirm.service'
3import { I18n } from '@ngx-translate/i18n-polyfill'
4import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
5import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
6
7@Component({
8 selector: 'my-confirm',
9 templateUrl: './confirm.component.html',
10 styleUrls: [ './confirm.component.scss' ]
11})
12export class ConfirmComponent implements OnInit {
13 @ViewChild('confirmModal') confirmModal: ElementRef
14
15 title = ''
16 message = ''
17 expectedInputValue = ''
18 inputLabel = ''
19
20 inputValue = ''
21 confirmButtonText = ''
22
23 private openedModal: NgbModalRef
24
25 constructor (
26 private modalService: NgbModal,
27 private confirmService: ConfirmService,
28 private i18n: I18n
29 ) { }
30
31 ngOnInit () {
32 this.confirmService.showConfirm.subscribe(
33 ({ title, message, expectedInputValue, inputLabel, confirmButtonText }) => {
34 this.title = title
35 this.message = message
36
37 this.inputLabel = inputLabel
38 this.expectedInputValue = expectedInputValue
39
40 this.confirmButtonText = confirmButtonText || this.i18n('Confirm')
41
42 this.showModal()
43 }
44 )
45 }
46
47 @HostListener('document:keydown.enter')
48 confirm () {
49 if (this.openedModal) this.openedModal.close()
50 }
51
52 isConfirmationDisabled () {
53 // No input validation
54 if (!this.inputLabel || !this.expectedInputValue) return false
55
56 return this.expectedInputValue !== this.inputValue
57 }
58
59 showModal () {
60 this.inputValue = ''
61
62 this.openedModal = this.modalService.open(this.confirmModal)
63
64 this.openedModal.result
65 .then(() => this.confirmService.confirmResponse.next(true))
66 .catch(() => this.confirmService.confirmResponse.next(false))
67 }
68}
diff --git a/client/src/app/core/confirm/index.ts b/client/src/app/core/confirm/index.ts
index 44aabfc13..aca591e1a 100644
--- a/client/src/app/core/confirm/index.ts
+++ b/client/src/app/core/confirm/index.ts
@@ -1,2 +1 @@
1export * from './confirm.component'
2export * from './confirm.service' export * from './confirm.service'
diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts
index df2ec696d..4ef3b1e73 100644
--- a/client/src/app/core/core.module.ts
+++ b/client/src/app/core/core.module.ts
@@ -7,16 +7,18 @@ import { LoadingBarModule } from '@ngx-loading-bar/core'
7import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client' 7import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client'
8import { LoadingBarRouterModule } from '@ngx-loading-bar/router' 8import { LoadingBarRouterModule } from '@ngx-loading-bar/router'
9 9
10import { SimpleNotificationsModule } from 'angular2-notifications'
11
12import { AuthService } from './auth' 10import { AuthService } from './auth'
13import { ConfirmComponent, ConfirmService } from './confirm' 11import { ConfirmService } from './confirm'
14import { throwIfAlreadyLoaded } from './module-import-guard' 12import { throwIfAlreadyLoaded } from './module-import-guard'
15import { LoginGuard, RedirectService, UserRightGuard } from './routing' 13import { LoginGuard, RedirectService, UserRightGuard } from './routing'
16import { ServerService } from './server' 14import { ServerService } from './server'
17import { ThemeService } from './theme' 15import { ThemeService } from './theme'
18import { HotkeyModule } from 'angular2-hotkeys' 16import { HotkeyModule } from 'angular2-hotkeys'
19import { CheatSheetComponent } from '@app/core/hotkeys' 17import { CheatSheetComponent } from './hotkeys'
18import { ToastModule } from 'primeng/toast'
19import { Notifier } from './notification'
20import { MessageService } from 'primeng/api'
21import { UserNotificationSocket } from '@app/core/notification/user-notification-socket.service'
20 22
21@NgModule({ 23@NgModule({
22 imports: [ 24 imports: [
@@ -25,11 +27,10 @@ import { CheatSheetComponent } from '@app/core/hotkeys'
25 FormsModule, 27 FormsModule,
26 BrowserAnimationsModule, 28 BrowserAnimationsModule,
27 29
28 SimpleNotificationsModule.forRoot(),
29
30 LoadingBarHttpClientModule, 30 LoadingBarHttpClientModule,
31 LoadingBarRouterModule, 31 LoadingBarRouterModule,
32 LoadingBarModule.forRoot(), 32 LoadingBarModule,
33 ToastModule,
33 34
34 HotkeyModule.forRoot({ 35 HotkeyModule.forRoot({
35 cheatSheetCloseEsc: true 36 cheatSheetCloseEsc: true
@@ -37,16 +38,15 @@ import { CheatSheetComponent } from '@app/core/hotkeys'
37 ], 38 ],
38 39
39 declarations: [ 40 declarations: [
40 ConfirmComponent,
41 CheatSheetComponent 41 CheatSheetComponent
42 ], 42 ],
43 43
44 exports: [ 44 exports: [
45 SimpleNotificationsModule,
46 LoadingBarHttpClientModule, 45 LoadingBarHttpClientModule,
47 LoadingBarModule, 46 LoadingBarModule,
48 47
49 ConfirmComponent, 48 ToastModule,
49
50 CheatSheetComponent 50 CheatSheetComponent
51 ], 51 ],
52 52
@@ -57,7 +57,10 @@ import { CheatSheetComponent } from '@app/core/hotkeys'
57 ThemeService, 57 ThemeService,
58 LoginGuard, 58 LoginGuard,
59 UserRightGuard, 59 UserRightGuard,
60 RedirectService 60 RedirectService,
61 Notifier,
62 MessageService,
63 UserNotificationSocket
61 ] 64 ]
62}) 65})
63export class CoreModule { 66export class CoreModule {
diff --git a/client/src/app/core/index.ts b/client/src/app/core/index.ts
index 524589d74..f664aff41 100644
--- a/client/src/app/core/index.ts
+++ b/client/src/app/core/index.ts
@@ -2,6 +2,7 @@ export * from './auth'
2export * from './confirm' 2export * from './confirm'
3export * from './routing' 3export * from './routing'
4export * from './server' 4export * from './server'
5export * from './notification'
5export * from './theme' 6export * from './theme'
6 7
7export * from './core.module' 8export * from './core.module'
diff --git a/client/src/app/core/notification/index.ts b/client/src/app/core/notification/index.ts
new file mode 100644
index 000000000..3e8d9ea65
--- /dev/null
+++ b/client/src/app/core/notification/index.ts
@@ -0,0 +1,2 @@
1export * from './notifier.service'
2export * from './user-notification-socket.service'
diff --git a/client/src/app/core/notification/notifier.service.ts b/client/src/app/core/notification/notifier.service.ts
new file mode 100644
index 000000000..9833c65a0
--- /dev/null
+++ b/client/src/app/core/notification/notifier.service.ts
@@ -0,0 +1,41 @@
1import { Injectable } from '@angular/core'
2import { MessageService } from 'primeng/api'
3import { I18n } from '@ngx-translate/i18n-polyfill'
4
5@Injectable()
6export class Notifier {
7 readonly TIMEOUT = 5000
8
9 constructor (
10 private i18n: I18n,
11 private messageService: MessageService) {
12 }
13
14 info (text: string, title?: string, timeout?: number) {
15 if (!title) title = this.i18n('Info')
16
17 return this.notify('info', text, title, timeout)
18 }
19
20 error (text: string, title?: string, timeout?: number) {
21 if (!title) title = this.i18n('Error')
22
23 return this.notify('error', text, title, timeout)
24 }
25
26 success (text: string, title?: string, timeout?: number) {
27 if (!title) title = this.i18n('Success')
28
29 return this.notify('success', text, title, timeout)
30 }
31
32 private notify (severity: 'success' | 'info' | 'warn' | 'error', text: string, title: string, timeout?: number) {
33 this.messageService.add({
34 severity,
35 summary: title,
36 detail: text,
37 closable: true,
38 life: timeout || this.TIMEOUT
39 })
40 }
41}
diff --git a/client/src/app/core/notification/user-notification-socket.service.ts b/client/src/app/core/notification/user-notification-socket.service.ts
new file mode 100644
index 000000000..f367d9ae4
--- /dev/null
+++ b/client/src/app/core/notification/user-notification-socket.service.ts
@@ -0,0 +1,41 @@
1import { Injectable } from '@angular/core'
2import { environment } from '../../../environments/environment'
3import { UserNotification as UserNotificationServer } from '../../../../../shared'
4import { Subject } from 'rxjs'
5import * as io from 'socket.io-client'
6import { AuthService } from '../auth'
7
8export type NotificationEvent = 'new' | 'read' | 'read-all'
9
10@Injectable()
11export class UserNotificationSocket {
12 private notificationSubject = new Subject<{ type: NotificationEvent, notification?: UserNotificationServer }>()
13
14 private socket: SocketIOClient.Socket
15
16 constructor (
17 private auth: AuthService
18 ) {}
19
20 dispatch (type: NotificationEvent, notification?: UserNotificationServer) {
21 this.notificationSubject.next({ type, notification })
22 }
23
24 getMyNotificationsSocket () {
25 const socket = this.getSocket()
26
27 socket.on('new-notification', (n: UserNotificationServer) => this.dispatch('new', n))
28
29 return this.notificationSubject.asObservable()
30 }
31
32 private getSocket () {
33 if (this.socket) return this.socket
34
35 this.socket = io(environment.apiUrl + '/user-notifications', {
36 query: { accessToken: this.auth.getAccessToken() }
37 })
38
39 return this.socket
40 }
41}
diff --git a/client/src/app/core/routing/login-guard.service.ts b/client/src/app/core/routing/login-guard.service.ts
index 40ff8f505..7b1c37ee8 100644
--- a/client/src/app/core/routing/login-guard.service.ts
+++ b/client/src/app/core/routing/login-guard.service.ts
@@ -1,11 +1,5 @@
1import { Injectable } from '@angular/core' 1import { Injectable } from '@angular/core'
2import { 2import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router'
3 ActivatedRouteSnapshot,
4 CanActivateChild,
5 RouterStateSnapshot,
6 CanActivate,
7 Router
8} from '@angular/router'
9 3
10import { AuthService } from '../auth/auth.service' 4import { AuthService } from '../auth/auth.service'
11 5
@@ -20,8 +14,6 @@ export class LoginGuard implements CanActivate, CanActivateChild {
20 canActivate (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { 14 canActivate (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
21 if (this.auth.isLoggedIn() === true) return true 15 if (this.auth.isLoggedIn() === true) return true
22 16
23 this.auth.redirectUrl = state.url
24
25 this.router.navigate([ '/login' ]) 17 this.router.navigate([ '/login' ])
26 return false 18 return false
27 } 19 }
diff --git a/client/src/app/core/routing/redirect.service.ts b/client/src/app/core/routing/redirect.service.ts
index 1881be117..e1db4097b 100644
--- a/client/src/app/core/routing/redirect.service.ts
+++ b/client/src/app/core/routing/redirect.service.ts
@@ -1,5 +1,5 @@
1import { Injectable } from '@angular/core' 1import { Injectable } from '@angular/core'
2import { Router } from '@angular/router' 2import { NavigationEnd, Router } from '@angular/router'
3import { ServerService } from '../server' 3import { ServerService } from '../server'
4 4
5@Injectable() 5@Injectable()
@@ -8,6 +8,9 @@ export class RedirectService {
8 static INIT_DEFAULT_ROUTE = '/videos/trending' 8 static INIT_DEFAULT_ROUTE = '/videos/trending'
9 static DEFAULT_ROUTE = RedirectService.INIT_DEFAULT_ROUTE 9 static DEFAULT_ROUTE = RedirectService.INIT_DEFAULT_ROUTE
10 10
11 private previousUrl: string
12 private currentUrl: string
13
11 constructor ( 14 constructor (
12 private router: Router, 15 private router: Router,
13 private serverService: ServerService 16 private serverService: ServerService
@@ -18,6 +21,7 @@ export class RedirectService {
18 RedirectService.DEFAULT_ROUTE = config.instance.defaultClientRoute 21 RedirectService.DEFAULT_ROUTE = config.instance.defaultClientRoute
19 } 22 }
20 23
24 // Load default route
21 this.serverService.configLoaded 25 this.serverService.configLoaded
22 .subscribe(() => { 26 .subscribe(() => {
23 const defaultRouteConfig = this.serverService.getConfig().instance.defaultClientRoute 27 const defaultRouteConfig = this.serverService.getConfig().instance.defaultClientRoute
@@ -26,6 +30,21 @@ export class RedirectService {
26 RedirectService.DEFAULT_ROUTE = defaultRouteConfig 30 RedirectService.DEFAULT_ROUTE = defaultRouteConfig
27 } 31 }
28 }) 32 })
33
34 // Track previous url
35 this.currentUrl = this.router.url
36 router.events.subscribe(event => {
37 if (event instanceof NavigationEnd) {
38 this.previousUrl = this.currentUrl
39 this.currentUrl = event.url
40 }
41 })
42 }
43
44 redirectToPreviousRoute () {
45 if (this.previousUrl) return this.router.navigateByUrl(this.previousUrl)
46
47 return this.redirectToHomepage()
29 } 48 }
30 49
31 redirectToHomepage (skipLocationChange = false) { 50 redirectToHomepage (skipLocationChange = false) {
diff --git a/client/src/app/core/routing/user-right-guard.service.ts b/client/src/app/core/routing/user-right-guard.service.ts
index 65d029977..50c3d8c19 100644
--- a/client/src/app/core/routing/user-right-guard.service.ts
+++ b/client/src/app/core/routing/user-right-guard.service.ts
@@ -7,7 +7,7 @@ import {
7 Router 7 Router
8} from '@angular/router' 8} from '@angular/router'
9 9
10import { AuthService } from '../auth' 10import { AuthService } from '../auth/auth.service'
11 11
12@Injectable() 12@Injectable()
13export class UserRightGuard implements CanActivate, CanActivateChild { 13export class UserRightGuard implements CanActivate, CanActivateChild {
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts
index 2f1ef1fc2..c868ccdcc 100644
--- a/client/src/app/core/server/server.service.ts
+++ b/client/src/app/core/server/server.service.ts
@@ -13,6 +13,7 @@ import { sortBy } from '@app/shared/misc/utils'
13 13
14@Injectable() 14@Injectable()
15export class ServerService { 15export class ServerService {
16 private static BASE_SERVER_URL = environment.apiUrl + '/api/v1/server/'
16 private static BASE_CONFIG_URL = environment.apiUrl + '/api/v1/config/' 17 private static BASE_CONFIG_URL = environment.apiUrl + '/api/v1/config/'
17 private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/' 18 private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/'
18 private static BASE_LOCALE_URL = environment.apiUrl + '/client/locales/' 19 private static BASE_LOCALE_URL = environment.apiUrl + '/client/locales/'
@@ -37,6 +38,12 @@ export class ServerService {
37 css: '' 38 css: ''
38 } 39 }
39 }, 40 },
41 email: {
42 enabled: false
43 },
44 contactForm: {
45 enabled: false
46 },
40 serverVersion: 'Unknown', 47 serverVersion: 'Unknown',
41 signup: { 48 signup: {
42 allowed: false, 49 allowed: false,
@@ -44,7 +51,10 @@ export class ServerService {
44 requiresEmailVerification: false 51 requiresEmailVerification: false
45 }, 52 },
46 transcoding: { 53 transcoding: {
47 enabledResolutions: [] 54 enabledResolutions: [],
55 hls: {
56 enabled: false
57 }
48 }, 58 },
49 avatar: { 59 avatar: {
50 file: { 60 file: {
@@ -80,6 +90,11 @@ export class ServerService {
80 enabled: false 90 enabled: false
81 } 91 }
82 } 92 }
93 },
94 trending: {
95 videos: {
96 intervalDays: 0
97 }
83 } 98 }
84 } 99 }
85 private videoCategories: Array<VideoConstant<number>> = [] 100 private videoCategories: Array<VideoConstant<number>> = []
@@ -141,10 +156,6 @@ export class ServerService {
141 return this.videoPrivacies 156 return this.videoPrivacies
142 } 157 }
143 158
144 getAbout () {
145 return this.http.get<About>(ServerService.BASE_CONFIG_URL + '/about')
146 }
147
148 private loadVideoAttributeEnum ( 159 private loadVideoAttributeEnum (
149 attributeName: 'categories' | 'licences' | 'languages' | 'privacies', 160 attributeName: 'categories' | 'licences' | 'languages' | 'privacies',
150 hashToPopulate: VideoConstant<string | number>[], 161 hashToPopulate: VideoConstant<string | number>[],
@@ -154,7 +165,7 @@ export class ServerService {
154 this.localeObservable 165 this.localeObservable
155 .pipe( 166 .pipe(
156 switchMap(translations => { 167 switchMap(translations => {
157 return this.http.get(ServerService.BASE_VIDEO_URL + attributeName) 168 return this.http.get<{ [id: string]: string }>(ServerService.BASE_VIDEO_URL + attributeName)
158 .pipe(map(data => ({ data, translations }))) 169 .pipe(map(data => ({ data, translations })))
159 }) 170 })
160 ) 171 )
diff --git a/client/src/app/core/theme/theme.service.ts b/client/src/app/core/theme/theme.service.ts
index a6eef0898..50c19ecac 100644
--- a/client/src/app/core/theme/theme.service.ts
+++ b/client/src/app/core/theme/theme.service.ts
@@ -5,7 +5,7 @@ import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
5export class ThemeService { 5export class ThemeService {
6 private theme = document.querySelector('body') 6 private theme = document.querySelector('body')
7 private darkTheme = false 7 private darkTheme = false
8 private previousTheme = {} 8 private previousTheme: { [ id: string ]: string } = {}
9 9
10 constructor () { 10 constructor () {
11 // initialise the alternative theme with dark theme colors 11 // initialise the alternative theme with dark theme colors
@@ -33,7 +33,7 @@ export class ThemeService {
33 } 33 }
34 } 34 }
35 35
36 private switchProperty (property, newValue?) { 36 private switchProperty (property: string, newValue?: string) {
37 const propertyOldvalue = window.getComputedStyle(this.theme).getPropertyValue('--' + property) 37 const propertyOldvalue = window.getComputedStyle(this.theme).getPropertyValue('--' + property)
38 this.theme.style.setProperty('--' + property, (newValue) ? newValue : this.previousTheme[property]) 38 this.theme.style.setProperty('--' + property, (newValue) ? newValue : this.previousTheme[property])
39 this.previousTheme[property] = propertyOldvalue 39 this.previousTheme[property] = propertyOldvalue