Fix anonymous nsfw policy
authorChocobozzz <me@florianbigard.com>
Tue, 16 Jun 2020 09:00:35 +0000 (11:00 +0200)
committerChocobozzz <me@florianbigard.com>
Tue, 16 Jun 2020 09:26:46 +0000 (11:26 +0200)
23 files changed:
client/src/app/+accounts/account-video-channels/account-video-channels.component.html
client/src/app/+accounts/account-video-channels/account-video-channels.component.ts
client/src/app/+my-account/my-account-history/my-account-history.component.html
client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts
client/src/app/app.component.ts
client/src/app/modal/quick-settings-modal.component.html
client/src/app/modal/quick-settings-modal.component.ts
client/src/app/search/search.component.html
client/src/app/search/search.component.ts
client/src/app/shared/users/user.service.ts
client/src/app/shared/video/abstract-video-list.html
client/src/app/shared/video/abstract-video-list.ts
client/src/app/shared/video/video.service.ts
client/src/app/videos/+video-watch/video-watch.component.html
client/src/app/videos/recommendations/recent-videos-recommendation.service.ts
client/src/app/videos/recommendations/recommended-videos.component.html
client/src/app/videos/recommendations/recommended-videos.component.ts
client/src/app/videos/video-list/video-local.component.ts
client/src/app/videos/video-list/video-most-liked.component.ts
client/src/app/videos/video-list/video-overview.component.html
client/src/app/videos/video-list/video-overview.component.ts
client/src/app/videos/video-list/video-recently-added.component.ts
client/src/app/videos/video-list/video-trending.component.ts

index 73bac5f1dbc199f3d51598e933879388c44082b6..5dbb341d25b6450323652478470f3bc9d50671db 100644 (file)
@@ -21,7 +21,7 @@
 
         <my-video-miniature
           *ngFor="let video of getVideosOf(videoChannel)"
-          [video]="video" [user]="user" [displayVideoActions]="true"
+          [video]="video" [user]="userMiniature" [displayVideoActions]="true"
         ></my-video-miniature>
       </div>
 
index 5572064c1c95c9e96cde71311cecd5c569c4b704..2e5c5aae216f33f3a8adfd1368607f0c028dd6a4 100644 (file)
@@ -1,17 +1,17 @@
+import { from, Subject, Subscription } from 'rxjs'
+import { concatMap, map, switchMap, tap } from 'rxjs/operators'
 import { Component, OnDestroy, OnInit } from '@angular/core'
-import { ActivatedRoute } from '@angular/router'
+import { UserService } from '@app/shared'
 import { Account } from '@app/shared/account/account.model'
 import { AccountService } from '@app/shared/account/account.service'
-import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
-import { concatMap, map, switchMap, tap } from 'rxjs/operators'
-import { from, Subject, Subscription } from 'rxjs'
+import { ScreenService } from '@app/shared/misc/screen.service'
+import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
 import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
+import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
+import { VideoSortField } from '@app/shared/video/sort-field.type'
 import { Video } from '@app/shared/video/video.model'
-import { AuthService } from '@app/core'
 import { VideoService } from '@app/shared/video/video.service'
-import { VideoSortField } from '@app/shared/video/sort-field.type'
-import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
-import { ScreenService } from '@app/shared/misc/screen.service'
+import { User } from '@shared/models'
 
 @Component({
   selector: 'my-account-video-channels',
@@ -38,21 +38,18 @@ export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
 
   onChannelDataSubject = new Subject<any>()
 
+  userMiniature: User
+
   private accountSub: Subscription
 
   constructor (
-    private route: ActivatedRoute,
-    private authService: AuthService,
     private accountService: AccountService,
     private videoChannelService: VideoChannelService,
     private videoService: VideoService,
-    private screenService: ScreenService
+    private screenService: ScreenService,
+    private userService: UserService
   ) { }
 
-  get user () {
-    return this.authService.getUser()
-  }
-
   ngOnInit () {
     // Parent get the account for us
     this.accountSub = this.accountService.accountLoaded
@@ -61,6 +58,9 @@ export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
 
           this.loadMoreChannels()
         })
+
+    this.userService.getAnonymousOrLoggedUser()
+      .subscribe(user => this.userMiniature = user)
   }
 
   ngOnDestroy () {
index 6b94d5477c0a87d163826831c04369a649ba33aa..cfa5ca636950e0961bab6cf4d2df02c135fe0769 100644 (file)
@@ -18,6 +18,7 @@
   <div class="video" *ngFor="let video of videos">
     <my-video-miniature
       [video]="video" [displayAsRow]="true"
-      (videoRemoved)="removeVideoFromArray(video)" (videoBlocked)="removeVideoFromArray(video)"></my-video-miniature>
+      (videoRemoved)="removeVideoFromArray(video)" (videoBlocked)="removeVideoFromArray(video)"
+    ></my-video-miniature>
   </div>
 </div>
index 6df47d11cb2f79ce29d2395138f98c9c63e51c88..5749701e83bb8cdbaab589a4498a3f551844b264 100644 (file)
@@ -77,7 +77,7 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
     const newPagination = immutableAssign(this.pagination, { currentPage: page })
 
     return this.videoService
-               .getVideoChannelVideos(this.videoChannel, newPagination, this.sort)
+               .getVideoChannelVideos(this.videoChannel, newPagination, this.sort, this.nsfwPolicy)
                .pipe(
                  tap(({ total }) => {
                    this.titlePage = this.i18n(`{total, plural, =1 {Published 1 video} other {Published {{total}} videos}}`, { total })
index 5541f555822d2fcf4ea495ac632959c42e48106b..c77dc97deb2b78c685034a8ea16384dd7f262806 100644 (file)
@@ -123,7 +123,6 @@ export class AppComponent implements OnInit, AfterViewInit {
     const scrollEvent = eventsObs.pipe(filter((e: Event): e is Scroll => e instanceof Scroll))
 
     scrollEvent.subscribe(e => {
-      console.log(e)
       if (e.position) {
         return this.viewportScroller.scrollToPosition(e.position)
       }
index e2ea51b929845a2ff1d7738f0d52aeab31da2c3d..188a51173facde430d88901dbd5fc258a6778bd4 100644 (file)
@@ -3,11 +3,15 @@
     <h4 i18n class="modal-title">Settings</h4>
     <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
   </div>
-  
+
   <div class="modal-body">
     <div i18n class="mb-4 quick-settings-title">Display settings</div>
 
-    <my-account-video-settings *ngIf="!isUserLoggedIn()" [user]="user" [userInformationLoaded]="userInformationLoaded" [reactiveUpdate]="true" [notifyOnUpdate]="true">
+    <my-account-video-settings
+      *ngIf="!isUserLoggedIn()"
+      [user]="user" [userInformationLoaded]="userInformationLoaded" [reactiveUpdate]="true" [notifyOnUpdate]="true"
+    >
+
       <ng-container ngProjectAs="inner-title">
         <div i18n class="mb-4 mt-4 quick-settings-title">Video settings</div>
       </ng-container>
@@ -15,6 +19,9 @@
 
     <div i18n class="mb-4 mt-4 quick-settings-title">Interface settings</div>
 
-    <my-account-interface-settings *ngIf="!isUserLoggedIn()" [user]="user" [userInformationLoaded]="userInformationLoaded" [reactiveUpdate]="true" [notifyOnUpdate]="true"></my-account-interface-settings>
+    <my-account-interface-settings
+      *ngIf="!isUserLoggedIn()"
+      [user]="user" [userInformationLoaded]="userInformationLoaded" [reactiveUpdate]="true" [notifyOnUpdate]="true"
+    ></my-account-interface-settings>
   </div>
 </ng-template>
index 41d6c9f4763b9337431d123da1acb78ed2104cc3..155794d1b1769050b445eb20ca77991e021ff20e 100644 (file)
@@ -32,9 +32,11 @@ export class QuickSettingsModalComponent extends FormReactive implements OnInit
 
   ngOnInit () {
     this.user = this.userService.getAnonymousUser()
-    this.localStorageService.watch().subscribe(
-      () => this.user = this.userService.getAnonymousUser()
-    )
+    this.localStorageService.watch()
+      .subscribe(
+        () => this.user = this.userService.getAnonymousUser()
+      )
+
     this.userInformationLoaded.next(true)
 
     this.authService.loginChangedSource
index 6acdedf92b3157d3569a763ed1bba595ede44921..9bff024ad872963199c1b38f3b8949ac317e5818 100644 (file)
@@ -53,7 +53,7 @@
 
     <div *ngIf="isVideo(result)" class="entry video">
       <my-video-miniature
-        [video]="result" [user]="user" [displayAsRow]="true" [displayVideoActions]="!hideActions()"
+        [video]="result" [user]="userMiniature" [displayAsRow]="true" [displayVideoActions]="!hideActions()"
         [displayOptions]="videoDisplayOptions" [useLazyLoadUrl]="advancedSearch.searchTarget === 'search-index'"
         (videoBlocked)="removeVideoFromArray(result)" (videoRemoved)="removeVideoFromArray(result)"
       ></my-video-miniature>
index eea015c2e5969ce82deb299edd26fac37774a97c..bed5de79e5f40e84691faf853c0f432ed2fd8b75 100644 (file)
@@ -5,6 +5,7 @@ import { AuthService, Notifier, ServerService } from '@app/core'
 import { HooksService } from '@app/core/plugins/hooks.service'
 import { AdvancedSearch } from '@app/search/advanced-search.model'
 import { SearchService } from '@app/search/search.service'
+import { UserService } from '@app/shared'
 import { immutableAssign } from '@app/shared/misc/utils'
 import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
 import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
@@ -12,7 +13,7 @@ import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.compo
 import { Video } from '@app/shared/video/video.model'
 import { MetaService } from '@ngx-meta/core'
 import { I18n } from '@ngx-translate/i18n-polyfill'
-import { ServerConfig } from '@shared/models'
+import { ServerConfig, User } from '@shared/models'
 import { SearchTargetType } from '@shared/models/search/search-target-query.model'
 
 @Component({
@@ -46,6 +47,8 @@ export class SearchComponent implements OnInit, OnDestroy {
   errorMessage: string
   serverConfig: ServerConfig
 
+  userMiniature: User
+
   private subActivatedRoute: Subscription
   private isInitialLoad = false // set to false to show the search filters on first arrival
   private firstSearch = true
@@ -62,14 +65,11 @@ export class SearchComponent implements OnInit, OnDestroy {
     private notifier: Notifier,
     private searchService: SearchService,
     private authService: AuthService,
+    private userService: UserService,
     private hooks: HooksService,
     private serverService: ServerService
   ) { }
 
-  get user () {
-    return this.authService.getUser()
-  }
-
   ngOnInit () {
     this.serverService.getConfig()
       .subscribe(config => this.serverConfig = config)
@@ -103,6 +103,9 @@ export class SearchComponent implements OnInit, OnDestroy {
       err => this.notifier.error(err.text)
     )
 
+    this.userService.getAnonymousOrLoggedUser()
+      .subscribe(user => this.userMiniature = user)
+
     this.hooks.runAction('action:search.init', 'search')
   }
 
index 7c1ae5799c0758b758b1372aa018cf5036cd7912..de1c8ec94da165601a8f343d80b359c5f98c7748 100644 (file)
@@ -1,19 +1,20 @@
-import { from, Observable } from 'rxjs'
-import { catchError, concatMap, map, shareReplay, toArray } from 'rxjs/operators'
+import { has } from 'lodash-es'
+import { BytesPipe } from 'ngx-pipes'
+import { SortMeta } from 'primeng/api'
+import { from, Observable, of } from 'rxjs'
+import { catchError, concatMap, first, map, shareReplay, toArray, throttleTime, filter } from 'rxjs/operators'
 import { HttpClient, HttpParams } from '@angular/common/http'
 import { Injectable } from '@angular/core'
-import { ResultList, User as UserServerModel, UserCreate, UserRole, UserUpdate, UserUpdateMe, UserVideoQuota } from '../../../../../shared'
-import { environment } from '../../../environments/environment'
-import { RestExtractor, RestPagination, RestService } from '../rest'
-import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
-import { SortMeta } from 'primeng/api'
-import { BytesPipe } from 'ngx-pipes'
+import { AuthService } from '@app/core/auth'
 import { I18n } from '@ngx-translate/i18n-polyfill'
 import { UserRegister } from '@shared/models/users/user-register.model'
-import { User } from './user.model'
 import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type'
-import { has } from 'lodash-es'
+import { ResultList, User as UserServerModel, UserCreate, UserRole, UserUpdate, UserUpdateMe, UserVideoQuota } from '../../../../../shared'
+import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
+import { environment } from '../../../environments/environment'
 import { LocalStorageService, SessionStorageService } from '../misc/storage.service'
+import { RestExtractor, RestPagination, RestService } from '../rest'
+import { User } from './user.model'
 
 @Injectable()
 export class UserService {
@@ -25,6 +26,7 @@ export class UserService {
 
   constructor (
     private authHttp: HttpClient,
+    private authService: AuthService,
     private restExtractor: RestExtractor,
     private restService: RestService,
     private localStorageService: LocalStorageService,
@@ -94,6 +96,21 @@ export class UserService {
     }
   }
 
+  listenAnonymousUpdate () {
+    return this.localStorageService.watch([
+      User.KEYS.NSFW_POLICY,
+      User.KEYS.WEBTORRENT_ENABLED,
+      User.KEYS.AUTO_PLAY_VIDEO,
+      User.KEYS.AUTO_PLAY_VIDEO_PLAYLIST,
+      User.KEYS.THEME,
+      User.KEYS.VIDEO_LANGUAGES
+    ]).pipe(
+      throttleTime(200),
+      filter(() => this.authService.isLoggedIn() !== true),
+      map(() => this.getAnonymousUser())
+    )
+  }
+
   deleteMe () {
     const url = UserService.BASE_USERS_URL + 'me'
 
@@ -241,7 +258,7 @@ export class UserService {
   }
 
   getAnonymousUser () {
-    let videoLanguages
+    let videoLanguages: string[]
 
     try {
       videoLanguages = JSON.parse(this.localStorageService.getItem(User.KEYS.VIDEO_LANGUAGES))
@@ -313,6 +330,18 @@ export class UserService {
       )
   }
 
+  getAnonymousOrLoggedUser () {
+    if (!this.authService.isLoggedIn()) {
+      return of(this.getAnonymousUser())
+    }
+
+    return this.authService.userInformationLoaded
+        .pipe(
+          first(),
+          map(() => this.authService.getUser())
+        )
+  }
+
   private formatUser (user: UserServerModel) {
     let videoQuota
     if (user.videoQuota === -1) {
index 548370843b484e0e81fd4724a3334bb91683c5f9..1e919ee720be64816dfb30845bbe0c2a8491ddf0 100644 (file)
@@ -38,7 +38,7 @@
       <div class="video-wrapper">
         <my-video-miniature
           [fitWidth]="true"
-          [video]="video" [user]="user" [ownerDisplayType]="ownerDisplayType"
+          [video]="video" [user]="userMiniature" [ownerDisplayType]="ownerDisplayType"
           [displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions"
           (videoBlocked)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)"
         >
index 76aa683fcb13c772b0b10d40bd5171e9a28d2251..0bc339ff60c023ad99192d3ccd746aab27449fb3 100644 (file)
@@ -1,22 +1,23 @@
-import { debounceTime, first, tap, throttleTime } from 'rxjs/operators'
+import { fromEvent, Observable, of, Subject, Subscription } from 'rxjs'
+import { debounceTime, tap, throttleTime, switchMap } from 'rxjs/operators'
 import { OnDestroy, OnInit } from '@angular/core'
 import { ActivatedRoute, Router } from '@angular/router'
-import { fromEvent, Observable, of, Subject, Subscription } from 'rxjs'
-import { AuthService } from '../../core/auth'
-import { ComponentPaginationLight } from '../rest/component-pagination.model'
-import { VideoSortField } from './sort-field.type'
-import { Video } from './video.model'
-import { ScreenService } from '@app/shared/misc/screen.service'
-import { MiniatureDisplayOptions, OwnerDisplayType } from '@app/shared/video/video-miniature.component'
-import { Syndication } from '@app/shared/video/syndication.model'
 import { Notifier, ServerService } from '@app/core'
 import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
+import { GlobalIconName } from '@app/shared/images/global-icon.component'
+import { ScreenService } from '@app/shared/misc/screen.service'
+import { Syndication } from '@app/shared/video/syndication.model'
+import { MiniatureDisplayOptions, OwnerDisplayType } from '@app/shared/video/video-miniature.component'
 import { I18n } from '@ngx-translate/i18n-polyfill'
 import { isLastMonth, isLastWeek, isToday, isYesterday } from '@shared/core-utils/miscs/date'
 import { ServerConfig } from '@shared/models'
-import { GlobalIconName } from '@app/shared/images/global-icon.component'
-import { UserService, User } from '../users'
+import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type'
+import { AuthService } from '../../core/auth'
 import { LocalStorageService } from '../misc/storage.service'
+import { ComponentPaginationLight } from '../rest/component-pagination.model'
+import { User, UserService } from '../users'
+import { VideoSortField } from './sort-field.type'
+import { Video } from './video.model'
 
 enum GroupDate {
   UNKNOWN = 0,
@@ -34,14 +35,15 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
   }
   sort: VideoSortField = '-publishedAt'
 
-  categoryOneOf?: number
+  categoryOneOf?: number[]
   languageOneOf?: string[]
+  nsfwPolicy?: NSFWPolicyType
   defaultSort: VideoSortField = '-publishedAt'
 
   syndicationItems: Syndication[] = []
 
   loadOnInit = true
-  useUserVideoLanguagePreferences = false
+  useUserVideoPreferences = false
   ownerDisplayType: OwnerDisplayType = 'account'
   displayModerationBlock = false
   titleTooltip: string
@@ -71,6 +73,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
 
   onDataSubject = new Subject<any[]>()
 
+  userMiniature: User
+
   protected serverConfig: ServerConfig
 
   protected abstract notifier: Notifier
@@ -96,10 +100,6 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
 
   abstract generateSyndicationList (): void
 
-  get user () {
-    return this.authService.getUser()
-  }
-
   ngOnInit () {
     this.serverConfig = this.serverService.getTmpConfig()
     this.serverService.getConfig()
@@ -124,21 +124,17 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
 
     this.calcPageSizes()
 
-    const loadUserObservable = this.loadUserVideoLanguagesIfNeeded()
+    const loadUserObservable = this.loadUserAndSettings()
 
     if (this.loadOnInit === true) {
       loadUserObservable.subscribe(() => this.loadMoreVideos())
     }
 
-    this.storageService.watch([
-      User.KEYS.NSFW_POLICY,
-      User.KEYS.VIDEO_LANGUAGES
-    ]).pipe(throttleTime(200)).subscribe(
-      () => {
-        this.loadUserVideoLanguagesIfNeeded()
+    this.userService.listenAnonymousUpdate()
+      .pipe(switchMap(() => this.loadUserAndSettings()))
+      .subscribe(() => {
         if (this.hasDoneFirstQuery) this.reloadVideos()
-      }
-    )
+      })
 
     // Display avatar in mobile view
     if (this.screenService.isInMobileView()) {
@@ -298,20 +294,15 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
     this.router.navigate([ path ], { queryParams, replaceUrl: true, queryParamsHandling: 'merge' })
   }
 
-  private loadUserVideoLanguagesIfNeeded () {
-    if (!this.useUserVideoLanguagePreferences) {
-      return of(true)
-    }
+  private loadUserAndSettings () {
+    return this.userService.getAnonymousOrLoggedUser()
+      .pipe(tap(user => {
+        this.userMiniature = user
 
-    if (!this.authService.isLoggedIn()) {
-      this.languageOneOf = this.userService.getAnonymousUser().videoLanguages
-      return of(true)
-    }
+        if (!this.useUserVideoPreferences) return
 
-    return this.authService.userInformationLoaded
-        .pipe(
-          first(),
-          tap(() => this.languageOneOf = this.user.videoLanguages)
-        )
+        this.languageOneOf = user.videoLanguages
+        this.nsfwPolicy = user.nsfwPolicy
+      }))
   }
 }
index 3aaf1499000a8dcbb10efd725861a1f24c8fc069..d66a1f809990ac78b9029551e833428d23b3fd6d 100644 (file)
@@ -39,8 +39,9 @@ export interface VideosProvider {
     videoPagination: ComponentPaginationLight,
     sort: VideoSortField,
     filter?: VideoFilter,
-    categoryOneOf?: number,
+    categoryOneOf?: number[],
     languageOneOf?: string[]
+    nsfwPolicy: NSFWPolicyType
   }): Observable<ResultList<Video>>
 }
 
@@ -161,13 +162,18 @@ export class VideoService implements VideosProvider {
   getVideoChannelVideos (
     videoChannel: VideoChannel,
     videoPagination: ComponentPaginationLight,
-    sort: VideoSortField
+    sort: VideoSortField,
+    nsfwPolicy?: NSFWPolicyType
   ): Observable<ResultList<Video>> {
     const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
 
     let params = new HttpParams()
     params = this.restService.addRestGetParams(params, pagination, sort)
 
+    if (nsfwPolicy) {
+      params = params.set('nsfw', this.nsfwPolicyToParam(nsfwPolicy))
+    }
+
     return this.authHttp
                .get<ResultList<Video>>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.nameWithHost + '/videos', { params })
                .pipe(
@@ -201,12 +207,12 @@ export class VideoService implements VideosProvider {
     videoPagination: ComponentPaginationLight,
     sort: VideoSortField,
     filter?: VideoFilter,
-    categoryOneOf?: number,
+    categoryOneOf?: number[],
     languageOneOf?: string[],
     skipCount?: boolean,
-    nsfw?: boolean
+    nsfwPolicy?: NSFWPolicyType
   }): Observable<ResultList<Video>> {
-    const { videoPagination, sort, filter, categoryOneOf, languageOneOf, skipCount, nsfw } = parameters
+    const { videoPagination, sort, filter, categoryOneOf, languageOneOf, skipCount, nsfwPolicy } = parameters
 
     const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
 
@@ -214,16 +220,10 @@ export class VideoService implements VideosProvider {
     params = this.restService.addRestGetParams(params, pagination, sort)
 
     if (filter) params = params.set('filter', filter)
-    if (categoryOneOf) params = params.set('categoryOneOf', categoryOneOf + '')
     if (skipCount) params = params.set('skipCount', skipCount + '')
 
-    if (nsfw) {
-      params = params.set('nsfw', nsfw + '')
-    } else {
-      const nsfwPolicy = this.authService.isLoggedIn()
-        ? this.authService.getUser().nsfwPolicy
-        : this.userService.getAnonymousUser().nsfwPolicy
-      if (this.nsfwPolicyToFilter(nsfwPolicy)) params.set('nsfw', 'false')
+    if (nsfwPolicy) {
+      params = params.set('nsfw', this.nsfwPolicyToParam(nsfwPolicy))
     }
 
     if (languageOneOf) {
@@ -232,6 +232,12 @@ export class VideoService implements VideosProvider {
       }
     }
 
+    if (categoryOneOf) {
+      for (const c of categoryOneOf) {
+        params = params.append('categoryOneOf[]', c + '')
+      }
+    }
+
     return this.authHttp
                .get<ResultList<Video>>(VideoService.BASE_VIDEO_URL, { params })
                .pipe(
@@ -268,12 +274,16 @@ export class VideoService implements VideosProvider {
     return feeds
   }
 
-  getVideoFeedUrls (sort: VideoSortField, filter?: VideoFilter, categoryOneOf?: number) {
+  getVideoFeedUrls (sort: VideoSortField, filter?: VideoFilter, categoryOneOf?: number[]) {
     let params = this.restService.addRestGetParams(new HttpParams(), undefined, sort)
 
     if (filter) params = params.set('filter', filter)
 
-    if (categoryOneOf) params = params.set('categoryOneOf', categoryOneOf + '')
+    if (categoryOneOf) {
+      for (const c of categoryOneOf) {
+        params = params.append('categoryOneOf[]', c + '')
+      }
+    }
 
     return this.buildBaseFeedUrls(params)
   }
@@ -377,6 +387,12 @@ export class VideoService implements VideosProvider {
     return base.filter(o => !!privacies.find(p => p.id === o.id))
   }
 
+  nsfwPolicyToParam (nsfwPolicy: NSFWPolicyType) {
+    return nsfwPolicy === 'do_not_list'
+      ? 'false'
+      : 'both'
+  }
+
   private setVideoRate (id: number, rateType: UserVideoRateType) {
     const url = VideoService.BASE_VIDEO_URL + id + '/rate'
     const body: UserVideoRateUpdate = {
@@ -390,8 +406,4 @@ export class VideoService implements VideosProvider {
                  catchError(err => this.restExtractor.handleError(err))
                )
   }
-
-  private nsfwPolicyToFilter (policy: NSFWPolicyType) {
-    return policy === 'do_not_list'
-  }
 }
index 589aba603b74198d3aaa782401ad86a0cc2dcab5..89e696fe98cc587b1223271ba78a6b822ac25308 100644 (file)
     </div>
 
     <my-recommended-videos
-        [inputRecommendation]="{ uuid: video.uuid, tags: video.tags }"
-        [user]="user"
-        [playlist]="playlist"
-        (gotRecommendations)="onRecommendations($event)"
+      [inputRecommendation]="{ uuid: video.uuid, tags: video.tags }"
+      [user]="user"
+      [playlist]="playlist"
+      (gotRecommendations)="onRecommendations($event)"
     ></my-recommended-videos>
   </div>
 
index f06c35f9a90a02e48147774e4028df088ee3a742..0abf938b73a0eed64f75026c78bc6e554b3a4215 100644 (file)
@@ -1,15 +1,15 @@
-import { Injectable, OnInit } from '@angular/core'
-import { RecommendationService } from '@app/videos/recommendations/recommendations.service'
-import { Video } from '@app/shared/video/video.model'
-import { RecommendationInfo } from '@app/shared/video/recommendation-info.model'
-import { VideoService } from '@app/shared/video/video.service'
-import { map, switchMap } from 'rxjs/operators'
 import { Observable, of } from 'rxjs'
-import { SearchService } from '@app/search/search.service'
-import { AdvancedSearch } from '@app/search/advanced-search.model'
+import { map, switchMap } from 'rxjs/operators'
+import { Injectable } from '@angular/core'
 import { ServerService } from '@app/core'
+import { AdvancedSearch } from '@app/search/advanced-search.model'
+import { SearchService } from '@app/search/search.service'
+import { UserService } from '@app/shared'
+import { RecommendationInfo } from '@app/shared/video/recommendation-info.model'
+import { Video } from '@app/shared/video/video.model'
+import { VideoService } from '@app/shared/video/video.service'
+import { RecommendationService } from '@app/videos/recommendations/recommendations.service'
 import { ServerConfig } from '@shared/models'
-import { truncate } from 'lodash'
 
 /**
  * Provides "recommendations" by providing the most recently uploaded videos.
@@ -23,13 +23,14 @@ export class RecentVideosRecommendationService implements RecommendationService
   constructor (
     private videos: VideoService,
     private searchService: SearchService,
+    private userService: UserService,
     private serverService: ServerService
   ) {
     this.config = this.serverService.getTmpConfig()
 
     this.serverService.getConfig()
      .subscribe(config => this.config = config)
-   }
+  }
 
   getRecommendations (recommendation: RecommendationInfo): Observable<Video[]> {
     return this.fetchPage(1, recommendation)
@@ -55,20 +56,29 @@ export class RecentVideosRecommendationService implements RecommendationService
       return defaultSubscription
     }
 
-    const params = {
-      search: '',
-      componentPagination: pagination,
-      advancedSearch: new AdvancedSearch({ tagsOneOf: recommendation.tags.join(','), sort: '-createdAt', searchTarget: 'local' })
-    }
-
-    return this.searchService.searchVideos(params)
-               .pipe(
-                 map(v => v.data),
-                 switchMap(videos => {
-                   if (videos.length <= 1) return defaultSubscription
+    return this.userService.getAnonymousOrLoggedUser()
+      .pipe(
+        map(user => {
+          return {
+            search: '',
+            componentPagination: pagination,
+            advancedSearch: new AdvancedSearch({
+              tagsOneOf: recommendation.tags.join(','),
+              sort: '-createdAt',
+              searchTarget: 'local',
+              nsfw: user.nsfwPolicy
+                ? this.videos.nsfwPolicyToParam(user.nsfwPolicy)
+                : undefined
+            })
+          }
+        }),
+        switchMap(params => this.searchService.searchVideos(params)),
+        map(v => v.data),
+        switchMap(videos => {
+          if (videos.length <= 1) return defaultSubscription
 
-                   return of(videos)
-                 })
-               )
+          return of(videos)
+        })
+      )
   }
 }
index 17e19c083f25a039aaadbe4d80557e6071c98f72..0467cabf5810cda7c9ae1cd2b4f15ba917c4c709 100644 (file)
     </div>
 
     <ng-container *ngFor="let video of (videos$ | async); let i = index; let length = count">
-      <my-video-miniature 
-        [displayOptions]="displayOptions" [video]="video" [user]="user"
+      <my-video-miniature
+        [displayOptions]="displayOptions" [video]="video" [user]="userMiniature"
         (videoBlocked)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()">
       </my-video-miniature>
-      
+
       <hr *ngIf="!playlist && i == 0 && length > 1" />
     </ng-container>
   </ng-container>
index d4a5df19a05cd01146b48bd75aeb116035f8741d..a6f3bce3d36b01cbe066a218b4a91a6bc864fd79 100644 (file)
@@ -1,24 +1,23 @@
-import { Component, Input, Output, OnChanges, EventEmitter } from '@angular/core'
 import { Observable } from 'rxjs'
-import { Video } from '@app/shared/video/video.model'
+import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'
+import { AuthService, Notifier } from '@app/core'
+import { User } from '@app/shared'
+import { SessionStorageService } from '@app/shared/misc/storage.service'
+import { UserService } from '@app/shared/users/user.service'
 import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
 import { RecommendationInfo } from '@app/shared/video/recommendation-info.model'
+import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component'
+import { Video } from '@app/shared/video/video.model'
 import { RecommendedVideosStore } from '@app/videos/recommendations/recommended-videos.store'
-import { User } from '@app/shared'
-import { AuthService, Notifier } from '@app/core'
-import { UserService } from '@app/shared/users/user.service'
 import { I18n } from '@ngx-translate/i18n-polyfill'
-import { SessionStorageService } from '@app/shared/misc/storage.service'
-import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component'
 
 @Component({
   selector: 'my-recommended-videos',
   templateUrl: './recommended-videos.component.html',
   styleUrls: [ './recommended-videos.component.scss' ]
 })
-export class RecommendedVideosComponent implements OnChanges {
+export class RecommendedVideosComponent implements OnInit, OnChanges {
   @Input() inputRecommendation: RecommendationInfo
-  @Input() user: User
   @Input() playlist: VideoPlaylist
   @Output() gotRecommendations = new EventEmitter<Video[]>()
 
@@ -32,6 +31,8 @@ export class RecommendedVideosComponent implements OnChanges {
     avatar: true
   }
 
+  userMiniature: User
+
   readonly hasVideos$: Observable<boolean>
   readonly videos$: Observable<Video[]>
 
@@ -59,7 +60,12 @@ export class RecommendedVideosComponent implements OnChanges {
     this.autoPlayNextVideoTooltip = this.i18n('When active, the next video is automatically played after the current one.')
   }
 
-  public ngOnChanges (): void {
+  ngOnInit () {
+    this.userService.getAnonymousOrLoggedUser()
+      .subscribe(user => this.userMiniature = user)
+  }
+
+  ngOnChanges () {
     if (this.inputRecommendation) {
       this.store.requestNewRecommendations(this.inputRecommendation)
     }
index 757b0e498fe54c808d3b523ef9308fda4679b141..960523cd709e1a7c4c1f72afcc47852986e49417 100644 (file)
@@ -24,7 +24,7 @@ export class VideoLocalComponent extends AbstractVideoList implements OnInit, On
   sort = '-publishedAt' as VideoSortField
   filter: VideoFilter = 'local'
 
-  useUserVideoLanguagePreferences = true
+  useUserVideoPreferences = true
 
   constructor (
     protected i18n: I18n,
@@ -67,6 +67,7 @@ export class VideoLocalComponent extends AbstractVideoList implements OnInit, On
       filter: this.filter,
       categoryOneOf: this.categoryOneOf,
       languageOneOf: this.languageOneOf,
+      nsfwPolicy: this.nsfwPolicy,
       skipCount: true
     }
 
index b69fad05f4890fe9bc238acecb29f3201ce6c436..cc91a2330204eba13b0b06dbcfb8b69333b8b52e 100644 (file)
@@ -21,7 +21,7 @@ export class VideoMostLikedComponent extends AbstractVideoList implements OnInit
   titlePage: string
   defaultSort: VideoSortField = '-likes'
 
-  useUserVideoLanguagePreferences = true
+  useUserVideoPreferences = true
 
   constructor (
     protected i18n: I18n,
@@ -55,6 +55,7 @@ export class VideoMostLikedComponent extends AbstractVideoList implements OnInit
       sort: this.sort,
       categoryOneOf: this.categoryOneOf,
       languageOneOf: this.languageOneOf,
+      nsfwPolicy: this.nsfwPolicy,
       skipCount: true
     }
 
index 19d03b5c596d92c53ab36eceaf0293718a8b9757..6de2fc2926066ce9d304183592b48407ceda7421 100644 (file)
@@ -14,7 +14,7 @@
         </h1>
 
         <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)">
-          <my-video-miniature [video]="video" [fitWidth]="true" [user]="user" [displayVideoActions]="false">
+          <my-video-miniature [video]="video" [fitWidth]="true" [user]="userMiniature" [displayVideoActions]="false">
           </my-video-miniature>
         </div>
       </div>
@@ -25,7 +25,7 @@
         </h2>
 
         <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)">
-          <my-video-miniature [video]="video" [fitWidth]="true" [user]="user" [displayVideoActions]="false">
+          <my-video-miniature [video]="video" [fitWidth]="true" [user]="userMiniature" [displayVideoActions]="false">
           </my-video-miniature>
         </div>
       </div>
@@ -40,7 +40,7 @@
         </div>
 
         <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)">
-          <my-video-miniature [video]="video" [fitWidth]="true" [user]="user" [displayVideoActions]="false">
+          <my-video-miniature [video]="video" [fitWidth]="true" [user]="userMiniature" [displayVideoActions]="false">
           </my-video-miniature>
         </div>
       </div>
index 101073949c24a66b409919d65bfb8007b7b36a65..8ff8400db14c33255a76e25d1b70f1e540d92360 100644 (file)
@@ -1,11 +1,11 @@
+import { Subject } from 'rxjs'
 import { Component, OnInit } from '@angular/core'
-import { AuthService, Notifier } from '@app/core'
-import { I18n } from '@ngx-translate/i18n-polyfill'
-import { VideosOverview } from '@app/shared/overview/videos-overview.model'
+import { Notifier } from '@app/core'
+import { User, UserService } from '@app/shared'
+import { ScreenService } from '@app/shared/misc/screen.service'
 import { OverviewService } from '@app/shared/overview'
+import { VideosOverview } from '@app/shared/overview/videos-overview.model'
 import { Video } from '@app/shared/video/video.model'
-import { ScreenService } from '@app/shared/misc/screen.service'
-import { Subject } from 'rxjs'
 
 @Component({
   selector: 'my-video-overview',
@@ -18,6 +18,8 @@ export class VideoOverviewComponent implements OnInit {
   overviews: VideosOverview[] = []
   notResults = false
 
+  userMiniature: User
+
   private loaded = false
   private currentPage = 1
   private maxPage = 20
@@ -25,19 +27,20 @@ export class VideoOverviewComponent implements OnInit {
   private isLoading = false
 
   constructor (
-    private i18n: I18n,
     private notifier: Notifier,
-    private authService: AuthService,
+    private userService: UserService,
     private overviewService: OverviewService,
     private screenService: ScreenService
   ) { }
 
-  get user () {
-    return this.authService.getUser()
-  }
-
   ngOnInit () {
     this.loadMoreResults()
+
+    this.userService.getAnonymousOrLoggedUser()
+      .subscribe(user => this.userMiniature = user)
+
+    this.userService.listenAnonymousUpdate()
+      .subscribe(user => this.userMiniature = user)
   }
 
   buildVideoChannelBy (object: { videos: Video[] }) {
index c1ddd4fd469bcda00e93cbe70668d0c57c82edf1..9f57a61e344bce45422711ef8cb0c6964ed49bb4 100644 (file)
@@ -22,7 +22,7 @@ export class VideoRecentlyAddedComponent extends AbstractVideoList implements On
   sort: VideoSortField = '-publishedAt'
   groupByDate = true
 
-  useUserVideoLanguagePreferences = true
+  useUserVideoPreferences = true
 
   constructor (
     protected i18n: I18n,
@@ -59,6 +59,7 @@ export class VideoRecentlyAddedComponent extends AbstractVideoList implements On
       sort: this.sort,
       categoryOneOf: this.categoryOneOf,
       languageOneOf: this.languageOneOf,
+      nsfwPolicy: this.nsfwPolicy,
       skipCount: true
     }
 
index fbe0522771dd2c7181ebe0bb6c0ad18c55d45880..62e0f4e690c64037b1ac16d574426fe2850b9833 100644 (file)
@@ -21,7 +21,7 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit,
   titlePage: string
   defaultSort: VideoSortField = '-trending'
 
-  useUserVideoLanguagePreferences = true
+  useUserVideoPreferences = true
 
   constructor (
     protected i18n: I18n,
@@ -72,6 +72,7 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit,
       sort: this.sort,
       categoryOneOf: this.categoryOneOf,
       languageOneOf: this.languageOneOf,
+      nsfwPolicy: this.nsfwPolicy,
       skipCount: true
     }