diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts index 0048882bc..c29f69475 100644 --- a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts +++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts @@ -2,7 +2,7 @@ import { BytesPipe } from 'ngx-pipes' import { SortMeta } from 'primeng/api' import { Component, OnInit } from '@angular/core' import { ConfirmService, Notifier, RestPagination, RestTable, ServerService } from '@app/core' -import { peertubeLocalStorage } from '@app/helpers/peertube-web-storage' +import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { RedundancyService } from '@app/shared/shared-main' import { I18n } from '@ngx-translate/i18n-polyfill' import { VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts index e94c293ca..3242bcf46 100644 --- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts @@ -14,7 +14,7 @@ import { DomSanitizer } from '@angular/platform-browser' @Component({ selector: 'my-video-block-list', templateUrl: './video-block-list.component.html', - styleUrls: [ '../../../shared/shared-moderation/moderation.scss', '../../../shared/shared-abuse-list/abuse-list-table.component.scss', './video-block-list.component.scss' ] + styleUrls: [ '../../../shared/shared-moderation/moderation.scss', './video-block-list.component.scss' ] }) export class VideoBlockListComponent extends RestTable implements OnInit, AfterViewInit { blocklist: (VideoBlacklist & { reasonHtml?: string, embedHtml?: string })[] = [] diff --git a/client/src/app/+admin/system/jobs/jobs.component.ts b/client/src/app/+admin/system/jobs/jobs.component.ts index 38a78de33..ceb848976 100644 --- a/client/src/app/+admin/system/jobs/jobs.component.ts +++ b/client/src/app/+admin/system/jobs/jobs.component.ts @@ -1,7 +1,7 @@ import { SortMeta } from 'primeng/api' import { Component, OnInit } from '@angular/core' import { Notifier, RestPagination, RestTable } from '@app/core' -import { peertubeLocalStorage } from '@app/helpers/peertube-web-storage' +import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { I18n } from '@ngx-translate/i18n-polyfill' import { Job, JobState, JobType } from '@shared/models' import { JobStateClient } from '../../../../types/job-state-client.type' diff --git a/client/src/app/+videos/+video-watch/video-watch-playlist.component.ts b/client/src/app/+videos/+video-watch/video-watch-playlist.component.ts index 2c21be643..519ce2974 100644 --- a/client/src/app/+videos/+video-watch/video-watch-playlist.component.ts +++ b/client/src/app/+videos/+video-watch/video-watch-playlist.component.ts @@ -1,7 +1,7 @@ import { Component, Input } from '@angular/core' import { Router } from '@angular/router' import { AuthService, ComponentPagination, LocalStorageService, Notifier, SessionStorageService, UserService } from '@app/core' -import { peertubeLocalStorage, peertubeSessionStorage } from '@app/helpers/peertube-web-storage' +import { peertubeLocalStorage, peertubeSessionStorage } from '@root-helpers/peertube-web-storage' import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist' import { I18n } from '@ngx-translate/i18n-polyfill' import { VideoDetails, VideoPlaylistPrivacy } from '@shared/models' diff --git a/client/src/app/+videos/+video-watch/video-watch.component.ts b/client/src/app/+videos/+video-watch/video-watch.component.ts index e355faf25..bb0830d99 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.ts +++ b/client/src/app/+videos/+video-watch/video-watch.component.ts @@ -7,7 +7,8 @@ import { ActivatedRoute, Router } from '@angular/router' import { AuthService, AuthUser, ConfirmService, MarkdownService, Notifier, RestExtractor, ServerService, UserService } from '@app/core' import { HooksService } from '@app/core/plugins/hooks.service' import { RedirectService } from '@app/core/routing/redirect.service' -import { isXPercentInViewport, peertubeLocalStorage, scrollToTop } from '@app/helpers' +import { isXPercentInViewport, scrollToTop } from '@app/helpers' +import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { Video, VideoCaptionService, VideoDetails, VideoService } from '@app/shared/shared-main' import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription' import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index a62aa4870..dee7fd056 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -15,7 +15,8 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { I18n } from '@ngx-translate/i18n-polyfill' import { BroadcastMessageLevel, getShortLocale, is18nPath, ServerConfig, UserRole } from '@shared/models' import { MenuService } from './core/menu/menu.service' -import { peertubeLocalStorage, POP_STATE_MODAL_DISMISS } from './helpers' +import { POP_STATE_MODAL_DISMISS } from './helpers' +import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { InstanceService } from './shared/shared-instance' @Component({ diff --git a/client/src/app/core/auth/auth-user.model.ts b/client/src/app/core/auth/auth-user.model.ts index 88b730938..ee61ff881 100644 --- a/client/src/app/core/auth/auth-user.model.ts +++ b/client/src/app/core/auth/auth-user.model.ts @@ -1,7 +1,7 @@ import { Observable, of } from 'rxjs' import { map } from 'rxjs/operators' import { User } from '@app/core/users/user.model' -import { peertubeLocalStorage } from '@app/helpers/peertube-web-storage' +import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { hasUserRight, MyUser as ServerMyUserModel, @@ -12,66 +12,7 @@ import { UserRole, UserVideoQuota } from '@shared/models' - -export type TokenOptions = { - accessToken: string - refreshToken: string - tokenType: string -} - -// Private class only used by User -class Tokens { - private static KEYS = { - ACCESS_TOKEN: 'access_token', - REFRESH_TOKEN: 'refresh_token', - TOKEN_TYPE: 'token_type' - } - - accessToken: string - refreshToken: string - tokenType: string - - static load () { - const accessTokenLocalStorage = peertubeLocalStorage.getItem(this.KEYS.ACCESS_TOKEN) - const refreshTokenLocalStorage = peertubeLocalStorage.getItem(this.KEYS.REFRESH_TOKEN) - const tokenTypeLocalStorage = peertubeLocalStorage.getItem(this.KEYS.TOKEN_TYPE) - - if (accessTokenLocalStorage && refreshTokenLocalStorage && tokenTypeLocalStorage) { - return new Tokens({ - accessToken: accessTokenLocalStorage, - refreshToken: refreshTokenLocalStorage, - tokenType: tokenTypeLocalStorage - }) - } - - return null - } - - static flush () { - peertubeLocalStorage.removeItem(this.KEYS.ACCESS_TOKEN) - peertubeLocalStorage.removeItem(this.KEYS.REFRESH_TOKEN) - peertubeLocalStorage.removeItem(this.KEYS.TOKEN_TYPE) - } - - constructor (hash?: TokenOptions) { - if (hash) { - this.accessToken = hash.accessToken - this.refreshToken = hash.refreshToken - - if (hash.tokenType === 'bearer') { - this.tokenType = 'Bearer' - } else { - this.tokenType = hash.tokenType - } - } - } - - save () { - peertubeLocalStorage.setItem(Tokens.KEYS.ACCESS_TOKEN, this.accessToken) - peertubeLocalStorage.setItem(Tokens.KEYS.REFRESH_TOKEN, this.refreshToken) - peertubeLocalStorage.setItem(Tokens.KEYS.TOKEN_TYPE, this.tokenType) - } -} +import { TokenOptions, Tokens } from '../../../root-helpers/pure-auth-user.model' export class AuthUser extends User implements ServerMyUserModel { tokens: Tokens diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts index 94262b9aa..d3dc48267 100644 --- a/client/src/app/core/auth/auth.service.ts +++ b/client/src/app/core/auth/auth.service.ts @@ -5,7 +5,7 @@ import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http' import { Injectable } from '@angular/core' import { Router } from '@angular/router' import { Notifier } from '@app/core/notification/notifier.service' -import { objectToUrlEncoded, peertubeLocalStorage } from '@app/helpers' +import { objectToUrlEncoded, peertubeLocalStorage } from '@root-helpers/index' import { I18n } from '@ngx-translate/i18n-polyfill' import { MyUser as UserServerModel, OAuthClientLocal, User, UserLogin, UserRefreshToken } from '@shared/models' import { environment } from '../../../environments/environment' diff --git a/client/src/app/core/rest/rest-table.ts b/client/src/app/core/rest/rest-table.ts index e6328eddc..7e7e6f4f7 100644 --- a/client/src/app/core/rest/rest-table.ts +++ b/client/src/app/core/rest/rest-table.ts @@ -1,4 +1,4 @@ -import { peertubeLocalStorage } from '@app/helpers/peertube-web-storage' +import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { LazyLoadEvent, SortMeta } from 'primeng/api' import { RestPagination } from './rest-pagination' import { Subject } from 'rxjs' diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index 32a135203..c69e0919a 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts @@ -2,7 +2,8 @@ import { Observable, of, Subject } from 'rxjs' import { first, map, share, shareReplay, switchMap, tap } from 'rxjs/operators' import { HttpClient } from '@angular/common/http' import { Inject, Injectable, LOCALE_ID } from '@angular/core' -import { getDevLocale, isOnDevLocale, peertubeLocalStorage, sortBy } from '@app/helpers' +import { getDevLocale, isOnDevLocale, sortBy } from '@app/helpers' +import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { getCompleteLocale, isDefaultLocale, diff --git a/client/src/app/core/users/user.model.ts b/client/src/app/core/users/user.model.ts index 4256f370b..a94b35c46 100644 --- a/client/src/app/core/users/user.model.ts +++ b/client/src/app/core/users/user.model.ts @@ -10,23 +10,10 @@ import { UserRole, VideoChannel } from '@shared/models' +import { UserKeys } from '@root-helpers/user-keys' export class User implements UserServerModel { - static KEYS = { - ID: 'id', - ROLE: 'role', - EMAIL: 'email', - VIDEOS_HISTORY_ENABLED: 'videos-history-enabled', - USERNAME: 'username', - NSFW_POLICY: 'nsfw_policy', - WEBTORRENT_ENABLED: 'peertube-videojs-' + 'webtorrent_enabled', - AUTO_PLAY_VIDEO: 'auto_play_video', - SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO: 'auto_play_next_video', - AUTO_PLAY_VIDEO_PLAYLIST: 'auto_play_video_playlist', - THEME: 'theme', - LAST_ACTIVE_THEME: 'last_active_theme', - VIDEO_LANGUAGES: 'video_languages' - } + static KEYS = UserKeys id: number username: string diff --git a/client/src/app/core/wrappers/storage.service.ts b/client/src/app/core/wrappers/storage.service.ts index 9a60b9785..ad3aca6b8 100644 --- a/client/src/app/core/wrappers/storage.service.ts +++ b/client/src/app/core/wrappers/storage.service.ts @@ -1,7 +1,7 @@ import { Observable, Subject } from 'rxjs' import { filter } from 'rxjs/operators' import { Injectable } from '@angular/core' -import { peertubeLocalStorage, peertubeSessionStorage } from '@app/helpers' +import { peertubeLocalStorage, peertubeSessionStorage } from '@root-helpers/peertube-web-storage' abstract class StorageService { protected instance: Storage diff --git a/client/src/app/helpers/index.ts b/client/src/app/helpers/index.ts index 06806402e..cc61255ba 100644 --- a/client/src/app/helpers/index.ts +++ b/client/src/app/helpers/index.ts @@ -1,6 +1,5 @@ export * from './locales' export * from './constants' export * from './i18n-utils' -export * from './peertube-web-storage' export * from './utils' export * from './zone' diff --git a/client/src/app/helpers/utils.ts b/client/src/app/helpers/utils.ts index 8e9f72adb..825b6ca96 100644 --- a/client/src/app/helpers/utils.ts +++ b/client/src/app/helpers/utils.ts @@ -81,15 +81,6 @@ function immutableAssign (target: A, source: B) { return Object.assign({}, target, source) } -function objectToUrlEncoded (obj: any) { - const str: string[] = [] - for (const key of Object.keys(obj)) { - str.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key])) - } - - return str.join('&') -} - // Thanks: https://gist.github.com/ghinda/8442a57f22099bdb2e34 function objectToFormData (obj: any, form?: FormData, namespace?: string) { const fd = form || new FormData() @@ -207,7 +198,6 @@ export { sortBy, durationToString, lineFeedToHtml, - objectToUrlEncoded, getParameterByName, populateAsyncUserVideoChannels, getAbsoluteAPIUrl, diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.scss b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.scss index 7ed7c9e87..5da624963 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.scss +++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.scss @@ -1,98 +1,9 @@ -@import 'variables'; -@import 'mixins'; -@import 'miniature'; - -.table-video-link { - @include disable-outline; - - position: relative; - top: 3px; -} - -.table-comment-link, -.table-account-link { - @include disable-outline; - - color: var(--mainForegroundColor); - - ::ng-deep p:last-child { - margin: 0; - } -} - -.table-account-link { - display: flex; - flex-direction: column; -} - .comment-flagged-account, .account-flagged-handle { font-size: 11px; color: var(--greyForegroundColor); } -.table-video { - display: inline-flex; - - .table-video-image { - @include miniature-thumbnail; - - $image-height: 45px; - - height: $image-height; - width: #{(16/9) * $image-height}; - margin-right: 0.5rem; - border-radius: 2px; - border: none; - background: transparent; - display: inline-flex; - justify-content: center; - align-items: center; - position: relative; - - img { - height: 100%; - width: 100%; - border-radius: 2px; - } - - span { - color: pvar(--inputPlaceholderColor); - } - - .table-video-image-label { - @include static-thumbnail-overlay; - position: absolute; - border-radius: 3px; - font-size: 10px; - padding: 0 3px; - line-height: 1.3; - bottom: 2px; - right: 2px; - } - } - - .table-video-text { - display: inline-flex; - flex-direction: column; - justify-content: center; - font-size: 90%; - color: pvar(--mainForegroundColor); - line-height: 1rem; - - div .glyphicon { - font-size: 80%; - color: gray; - margin-left: 0.1rem; - } - - div + div { - color: var(--greyForegroundColor); - font-size: 11px; - } - } -} - .abuse-states .glyphicon-comment { margin-left: 0.5rem; } diff --git a/client/src/app/shared/shared-moderation/moderation.scss b/client/src/app/shared/shared-moderation/moderation.scss index c9f0d0c42..c57872bae 100644 --- a/client/src/app/shared/shared-moderation/moderation.scss +++ b/client/src/app/shared/shared-moderation/moderation.scss @@ -65,3 +65,88 @@ my-action-dropdown.show { display: block !important; } } + +.table-video-link { + @include disable-outline; + + position: relative; + top: 3px; +} + +.table-comment-link, +.table-account-link { + @include disable-outline; + + color: var(--mainForegroundColor); + + ::ng-deep p:last-child { + margin: 0; + } +} + +.table-account-link { + display: flex; + flex-direction: column; +} + +.table-video { + display: inline-flex; + + .table-video-image { + @include miniature-thumbnail; + + $image-height: 45px; + + height: $image-height; + width: #{(16/9) * $image-height}; + margin-right: 0.5rem; + border-radius: 2px; + border: none; + background: transparent; + display: inline-flex; + justify-content: center; + align-items: center; + position: relative; + + img { + height: 100%; + width: 100%; + border-radius: 2px; + } + + span { + color: pvar(--inputPlaceholderColor); + } + + .table-video-image-label { + @include static-thumbnail-overlay; + position: absolute; + border-radius: 3px; + font-size: 10px; + padding: 0 3px; + line-height: 1.3; + bottom: 2px; + right: 2px; + } + } + + .table-video-text { + display: inline-flex; + flex-direction: column; + justify-content: center; + font-size: 90%; + color: pvar(--mainForegroundColor); + line-height: 1rem; + + div .glyphicon { + font-size: 80%; + color: gray; + margin-left: 0.1rem; + } + + div + div { + color: var(--greyForegroundColor); + font-size: 11px; + } + } +} diff --git a/client/src/app/shared/shared-search/search.service.ts b/client/src/app/shared/shared-search/search.service.ts index 96b954c99..15c4a7012 100644 --- a/client/src/app/shared/shared-search/search.service.ts +++ b/client/src/app/shared/shared-search/search.service.ts @@ -3,7 +3,7 @@ import { catchError, map, switchMap } from 'rxjs/operators' import { HttpClient, HttpParams } from '@angular/common/http' import { Injectable } from '@angular/core' import { ComponentPaginationLight, RestExtractor, RestPagination, RestService } from '@app/core' -import { peertubeLocalStorage } from '@app/helpers' +import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { Video, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main' import { ResultList, SearchTargetType, Video as VideoServerModel, VideoChannel as VideoChannelServerModel } from '@shared/models' import { environment } from '../../../environments/environment' diff --git a/client/src/root-helpers/index.ts b/client/src/root-helpers/index.ts new file mode 100644 index 000000000..5ed4933f1 --- /dev/null +++ b/client/src/root-helpers/index.ts @@ -0,0 +1,4 @@ +export * from './peertube-web-storage' +export * from './utils' +export * from './user-keys' +export * from './pure-auth-user.model' diff --git a/client/src/app/helpers/peertube-web-storage.ts b/client/src/root-helpers/peertube-web-storage.ts similarity index 100% rename from client/src/app/helpers/peertube-web-storage.ts rename to client/src/root-helpers/peertube-web-storage.ts diff --git a/client/src/root-helpers/pure-auth-user.model.ts b/client/src/root-helpers/pure-auth-user.model.ts new file mode 100644 index 000000000..81226da01 --- /dev/null +++ b/client/src/root-helpers/pure-auth-user.model.ts @@ -0,0 +1,123 @@ +// pure version of auth-user, that doesn't import app packages +import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' +import { + MyUser as ServerMyUserModel, + MyUserSpecialPlaylist, + NSFWPolicyType, + UserRole +} from '@shared/models' +import { UserKeys } from '@root-helpers/user-keys' + +export type TokenOptions = { + accessToken: string + refreshToken: string + tokenType: string +} + +// Private class only used by User +export class Tokens { + private static KEYS = { + ACCESS_TOKEN: 'access_token', + REFRESH_TOKEN: 'refresh_token', + TOKEN_TYPE: 'token_type' + } + + accessToken: string + refreshToken: string + tokenType: string + + static load () { + const accessTokenLocalStorage = peertubeLocalStorage.getItem(this.KEYS.ACCESS_TOKEN) + const refreshTokenLocalStorage = peertubeLocalStorage.getItem(this.KEYS.REFRESH_TOKEN) + const tokenTypeLocalStorage = peertubeLocalStorage.getItem(this.KEYS.TOKEN_TYPE) + + if (accessTokenLocalStorage && refreshTokenLocalStorage && tokenTypeLocalStorage) { + return new Tokens({ + accessToken: accessTokenLocalStorage, + refreshToken: refreshTokenLocalStorage, + tokenType: tokenTypeLocalStorage + }) + } + + return null + } + + static flush () { + peertubeLocalStorage.removeItem(this.KEYS.ACCESS_TOKEN) + peertubeLocalStorage.removeItem(this.KEYS.REFRESH_TOKEN) + peertubeLocalStorage.removeItem(this.KEYS.TOKEN_TYPE) + } + + constructor (hash?: TokenOptions) { + if (hash) { + this.accessToken = hash.accessToken + this.refreshToken = hash.refreshToken + + if (hash.tokenType === 'bearer') { + this.tokenType = 'Bearer' + } else { + this.tokenType = hash.tokenType + } + } + } + + save () { + peertubeLocalStorage.setItem(Tokens.KEYS.ACCESS_TOKEN, this.accessToken) + peertubeLocalStorage.setItem(Tokens.KEYS.REFRESH_TOKEN, this.refreshToken) + peertubeLocalStorage.setItem(Tokens.KEYS.TOKEN_TYPE, this.tokenType) + } +} + +export class PureAuthUser { + tokens: Tokens + specialPlaylists: MyUserSpecialPlaylist[] + + canSeeVideosLink = true + + static load () { + const usernameLocalStorage = peertubeLocalStorage.getItem(UserKeys.USERNAME) + if (usernameLocalStorage) { + return new PureAuthUser( + { + id: parseInt(peertubeLocalStorage.getItem(UserKeys.ID), 10), + username: peertubeLocalStorage.getItem(UserKeys.USERNAME), + email: peertubeLocalStorage.getItem(UserKeys.EMAIL), + role: parseInt(peertubeLocalStorage.getItem(UserKeys.ROLE), 10) as UserRole, + nsfwPolicy: peertubeLocalStorage.getItem(UserKeys.NSFW_POLICY) as NSFWPolicyType, + webTorrentEnabled: peertubeLocalStorage.getItem(UserKeys.WEBTORRENT_ENABLED) === 'true', + autoPlayVideo: peertubeLocalStorage.getItem(UserKeys.AUTO_PLAY_VIDEO) === 'true', + videosHistoryEnabled: peertubeLocalStorage.getItem(UserKeys.VIDEOS_HISTORY_ENABLED) === 'true' + }, + Tokens.load() + ) + } + + return null + } + + constructor (userHash: Partial, hashTokens: TokenOptions) { + this.tokens = new Tokens(hashTokens) + this.specialPlaylists = userHash.specialPlaylists + } + + getAccessToken () { + return this.tokens.accessToken + } + + getRefreshToken () { + return this.tokens.refreshToken + } + + getTokenType () { + return this.tokens.tokenType + } + + refreshTokens (accessToken: string, refreshToken: string) { + this.tokens.accessToken = accessToken + this.tokens.refreshToken = refreshToken + } + + save () { + this.tokens.save() + } +} diff --git a/client/src/root-helpers/user-keys.ts b/client/src/root-helpers/user-keys.ts new file mode 100644 index 000000000..897be8c43 --- /dev/null +++ b/client/src/root-helpers/user-keys.ts @@ -0,0 +1,15 @@ +export const UserKeys = { + ID: 'id', + ROLE: 'role', + EMAIL: 'email', + VIDEOS_HISTORY_ENABLED: 'videos-history-enabled', + USERNAME: 'username', + NSFW_POLICY: 'nsfw_policy', + WEBTORRENT_ENABLED: 'peertube-videojs-' + 'webtorrent_enabled', + AUTO_PLAY_VIDEO: 'auto_play_video', + SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO: 'auto_play_next_video', + AUTO_PLAY_VIDEO_PLAYLIST: 'auto_play_video_playlist', + THEME: 'theme', + LAST_ACTIVE_THEME: 'last_active_theme', + VIDEO_LANGUAGES: 'video_languages' +} diff --git a/client/src/root-helpers/utils.ts b/client/src/root-helpers/utils.ts new file mode 100644 index 000000000..acfb565a3 --- /dev/null +++ b/client/src/root-helpers/utils.ts @@ -0,0 +1,12 @@ +function objectToUrlEncoded (obj: any) { + const str: string[] = [] + for (const key of Object.keys(obj)) { + str.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key])) + } + + return str.join('&') +} + +export { + objectToUrlEncoded +} diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index dca23ca7e..5bf38a04c 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts @@ -4,7 +4,8 @@ import { peertubeTranslate, ResultList, ServerConfig, - VideoDetails + VideoDetails, + UserRefreshToken } from '../../../../shared' import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model' import { @@ -17,7 +18,7 @@ import { PeerTubeEmbedApi } from './embed-api' import { TranslationsManager } from '../../assets/player/translations-manager' import videojs from 'video.js' import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings' -import { AuthUser } from '@app/core/auth/auth-user.model' +import { PureAuthUser, objectToUrlEncoded, peertubeLocalStorage } from '@root-helpers/index' type Translations = { [ id: string ]: string } @@ -43,8 +44,12 @@ export class PeerTubeEmbed { mode: PlayerMode scope = 'peertube' - user: AuthUser + user: PureAuthUser headers = new Headers() + LOCAL_STORAGE_OAUTH_CLIENT_KEYS = { + CLIENT_ID: 'client_id', + CLIENT_SECRET: 'client_secret' + } static async main () { const videoContainerId = 'video-container' @@ -60,12 +65,62 @@ export class PeerTubeEmbed { return window.location.origin + '/api/v1/videos/' + id } + refreshFetch (url: string, options?: Object) { + return fetch(url, options) + .then((res: Response) => { + if (res.status !== 401) return res + + // 401 unauthorized is not catch-ed, but then-ed + const error = res + + const refreshingTokenPromise = new Promise((resolve, reject) => { + const clientId: string = peertubeLocalStorage.getItem(this.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_ID) + const clientSecret: string = peertubeLocalStorage.getItem(this.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_SECRET) + const headers = new Headers() + headers.set('Content-Type', 'application/x-www-form-urlencoded') + const data = { + refresh_token: this.user.getRefreshToken(), + client_id: clientId, + client_secret: clientSecret, + response_type: 'code', + grant_type: 'refresh_token' + } + + fetch('/api/v1/users/token', { + headers, + method: 'POST', + body: objectToUrlEncoded(data) + }) + .then(res => res.json()) + .then((obj: UserRefreshToken) => { + this.user.refreshTokens(obj.access_token, obj.refresh_token) + this.user.save() + this.headers.set('Authorization', `${this.user.getTokenType()} ${this.user.getAccessToken()}`) + resolve() + }) + .catch((refreshTokenError: any) => { + reject(refreshTokenError) + }) + }) + + return refreshingTokenPromise + .catch(() => { + // If refreshing fails, continue with original error + throw error + }) + .then(() => fetch(url, { + ...options, + headers: this.headers + })) + }) + } + loadVideoInfo (videoId: string): Promise { - return fetch(this.getVideoUrl(videoId), { headers: this.headers }) + return this.refreshFetch(this.getVideoUrl(videoId), { headers: this.headers }) } loadVideoCaptions (videoId: string): Promise { - return fetch(this.getVideoUrl(videoId) + '/captions', { headers: this.headers }) + return fetch(this.getVideoUrl(videoId) + '/captions') } loadConfig (): Promise { @@ -115,7 +170,7 @@ export class PeerTubeEmbed { async init () { try { - this.user = AuthUser.load() + this.user = PureAuthUser.load() await this.initCore() } catch (e) { console.error(e) diff --git a/client/tsconfig.json b/client/tsconfig.json index 752f5b35f..a7b690c7b 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -28,6 +28,7 @@ "video.js": [ "node_modules/video.js/core" ], "@app/*": [ "src/app/*" ], "@shared/*": [ "../shared/*" ], + "@root-helpers/*": [ "src/root-helpers/*" ], "fs": [ "src/shims/noop.ts" ], "http": [ "src/shims/http.ts" ], "https": [ "src/shims/https.ts" ], diff --git a/client/webpack/webpack.video-embed.js b/client/webpack/webpack.video-embed.js index 319b00e5d..b6a1c4c05 100644 --- a/client/webpack/webpack.video-embed.js +++ b/client/webpack/webpack.video-embed.js @@ -28,7 +28,7 @@ module.exports = function () { alias: { 'video.js$': path.resolve('node_modules/video.js/core.js'), - '@app': path.resolve('src/app'), + '@root-helpers': path.resolve('src/root-helpers'), '@shared': path.resolve('../shared') } },