-
We couldn't find any video tied to the URL {{ pathname }} you were looking for.
-
We couldn't find any resource tied to the URL {{ pathname }} you were looking for.
+
+ @if (type === 'video') {
+ You might need to login to see the video.
+ } @else {
+ You might need to login to see the resource.
+ }
+
+
+
+
{{ status }}.
+
I'm a teapot.
-
-
{{ status }}.
-
You are not authorized here.
-
-
-
You might need to login to see the video.
-
You might need to login to see the resource.
+
+ The requested entity body blends sweet bits with a mellow earthiness.
+
+
Sepia seems to like it.
+ } @else {
+
+ {{ status }}.
+ That's an error.
-
-
+
+ @if (type === 'video') {
+ We couldn't find any video tied to the URL {{ pathname }} you were looking for.
+ } @else {
+ We couldn't find any resource tied to the URL {{ pathname }} you were looking for.
+ }
+
-
-
{{ status }}.
-
You are not authorized here.
+
+
Possible reasons:
-
-
You might need to check your account is allowed by the video or instance owner.
-
You might need to check your account is allowed by the resource or instance owner.
+
+ - You may have used an outdated or broken link
+
+ -
+ @if (type === 'video') {
+ The video may have been moved or deleted
+ } @else {
+ The resource may have been moved or deleted
+ }
+
+
+ - You may have typed the address or URL incorrectly
+
+
-
-
-
-
{{ status }}.
-
I'm a teapot.
-
-
- The requested entity body blends sweet bits with a mellow earthiness.
-
-
Sepia seems to like it.
-
+ }
diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html
index c81d2ac65..1279f19b0 100644
--- a/client/src/app/app.component.html
+++ b/client/src/app/app.component.html
@@ -60,12 +60,12 @@
+
+
{{ message.summary }}
{{ message.detail }}
-
-
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts
index 736ee7359..52f9d420c 100644
--- a/client/src/app/app.component.ts
+++ b/client/src/app/app.component.ts
@@ -294,12 +294,12 @@ export class AppComponent implements OnInit, AfterViewInit {
// Admin modal
userSub.pipe(
filter(user => user.role.id === UserRole.ADMINISTRATOR)
- ).subscribe(user => this.openAdminModalsIfNeeded(user))
+ ).subscribe(user => setTimeout(() => this.openAdminModalsIfNeeded(user))) // Wait deferred modal creation in the view
// Account modal
userSub.pipe(
filter(user => user.role.id !== UserRole.ADMINISTRATOR)
- ).subscribe(user => this.openAccountModalsIfNeeded(user))
+ ).subscribe(user => setTimeout(() => this.openAccountModalsIfNeeded(user))) // Wait deferred modal creation in the view
}
private openAdminModalsIfNeeded (user: User) {
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts
index 341ff8637..1685e298e 100644
--- a/client/src/app/core/auth/auth.service.ts
+++ b/client/src/app/core/auth/auth.service.ts
@@ -1,15 +1,14 @@
-import { Hotkey, HotkeysService } from '@app/core'
-import { Observable, ReplaySubject, Subject, throwError as observableThrowError } from 'rxjs'
-import { catchError, map, mergeMap, share, tap } from 'rxjs/operators'
import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Router } from '@angular/router'
+import { Hotkey, HotkeysService } from '@app/core'
import { Notifier } from '@app/core/notification/notifier.service'
+import { HttpStatusCode, OAuthClientLocal, User, UserLogin, UserRefreshToken, MyUser as UserServerModel } from '@peertube/peertube-models'
import { logger, OAuthUserTokens, objectToUrlEncoded, peertubeLocalStorage } from '@root-helpers/index'
-import { HttpStatusCode, MyUser as UserServerModel, OAuthClientLocal, User, UserLogin, UserRefreshToken } from '@peertube/peertube-models'
+import { Observable, of, ReplaySubject, Subject, throwError } from 'rxjs'
+import { catchError, map, mergeMap, share, tap } from 'rxjs/operators'
import { environment } from '../../../environments/environment'
import { RestExtractor } from '../rest/rest-extractor.service'
-import { RedirectService } from '../routing'
import { AuthStatus } from './auth-status.model'
import { AuthUser } from './auth-user.model'
@@ -42,10 +41,9 @@ export class AuthService {
private clientSecret: string = peertubeLocalStorage.getItem(AuthService.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_SECRET)
private loginChanged: Subject
private user: AuthUser = null
- private refreshingTokenObservable: Observable
+ private refreshingTokenObservable: Observable
constructor (
- private redirectService: RedirectService,
private http: HttpClient,
private notifier: Notifier,
private hotkeysService: HotkeysService,
@@ -180,18 +178,20 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
logout () {
const authHeaderValue = this.getRequestHeaderValue()
- const headers = new HttpHeaders().set('Authorization', authHeaderValue)
- this.http.post<{ redirectUrl?: string }>(AuthService.BASE_REVOKE_TOKEN_URL, {}, { headers })
- .subscribe({
- next: res => {
- if (res.redirectUrl) {
- window.location.href = res.redirectUrl
- }
- },
+ const obs: Observable<{ redirectUrl?: string }> = authHeaderValue
+ ? this.http.post(AuthService.BASE_REVOKE_TOKEN_URL, {}, { headers: new HttpHeaders().set('Authorization', authHeaderValue) })
+ : of({})
- error: err => logger.error(err)
- })
+ obs.subscribe({
+ next: res => {
+ if (res.redirectUrl) {
+ window.location.href = res.redirectUrl
+ }
+ },
+
+ error: err => logger.error(err)
+ })
this.user = null
@@ -200,6 +200,7 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
refreshAccessToken () {
if (this.refreshingTokenObservable) return this.refreshingTokenObservable
+ if (!this.getAccessToken()) return throwError(() => new Error($localize`You need to reconnect`))
logger.info('Refreshing token...')
@@ -221,17 +222,13 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
this.refreshingTokenObservable = null
}),
catchError(err => {
- this.refreshingTokenObservable = null
-
- logger.error(err)
- logger.info('Cannot refresh token -> logout...')
+ logger.clientError(err)
this.logout()
- this.redirectService.redirectToLogin()
+ this.notifier.info($localize`Your authentication has expired, you need to reconnect.`, undefined, undefined, true)
+ this.refreshingTokenObservable = null
- return observableThrowError(() => ({
- error: $localize`You need to reconnect.`
- }))
+ return throwError(() => new Error($localize`You need to reconnect`))
}),
share()
)
diff --git a/client/src/app/core/routing/login-guard.service.ts b/client/src/app/core/routing/login-guard.service.ts
index ecb902625..be0ced881 100644
--- a/client/src/app/core/routing/login-guard.service.ts
+++ b/client/src/app/core/routing/login-guard.service.ts
@@ -14,7 +14,10 @@ export class LoginGuard {
canActivate (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (this.auth.isLoggedIn() === true) return true
- this.redirectService.redirectToLogin()
+ const err = new Error('') as any
+ err.status = 401
+
+ this.redirectService.replaceBy401(err)
return false
}
diff --git a/client/src/app/core/routing/redirect.service.ts b/client/src/app/core/routing/redirect.service.ts
index ca9c0cbf2..a278d147f 100644
--- a/client/src/app/core/routing/redirect.service.ts
+++ b/client/src/app/core/routing/redirect.service.ts
@@ -112,6 +112,10 @@ export class RedirectService {
else this.router.navigate([ '/login' ])
}
+ replaceBy401 (err: Error) {
+ this.router.navigate([ '/401' ], { state: { obj: err }, skipLocationChange: true })
+ }
+
private doRedirect (redirectUrl: string, fallbackRoute?: string) {
debugLogger('Redirecting on %s', redirectUrl)
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 9f293f628..33e767467 100644
--- a/client/src/app/core/routing/user-right-guard.service.ts
+++ b/client/src/app/core/routing/user-right-guard.service.ts
@@ -19,7 +19,11 @@ export class UserRightGuard {
if (user.hasRight(neededUserRight)) return true
}
- this.redirectService.redirectToLogin()
+ const err = new Error('') as any
+ err.status = 403
+
+ this.redirectService.replaceBy401(err)
+
return false
}
diff --git a/client/src/sass/primeng-custom.scss b/client/src/sass/primeng-custom.scss
index 55a802481..1f3cb7890 100644
--- a/client/src/sass/primeng-custom.scss
+++ b/client/src/sass/primeng-custom.scss
@@ -1088,7 +1088,7 @@ p-toast {
min-width: 200px;
.p-toast-icon-close {
- opacity: 0;
+ color: pvar(--greyForegroundColor);
position: absolute;
right: 5px;
top: 5px;
@@ -1097,10 +1097,6 @@ p-toast {
background: url('../assets/images/feather/x.svg') no-repeat;
background-size: contain;
}
-
- &:hover .p-toast-icon-close {
- opacity: .3;
- }
}
.p-toast-message {
@@ -1117,10 +1113,10 @@ p-toast {
display: flex;
align-items: center;
width: 100%;
- padding: 10px 20px;
+ padding: 10px;
.message {
- @include margin-right(20px);
+ @include margin-left(10px);
flex-grow: 1;