aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2018-08-24 10:31:56 +0200
committerChocobozzz <me@florianbigard.com>2018-08-27 09:41:54 +0200
commitaa55a4da422330fe2816f1764b64f6607a0ca4aa (patch)
tree39933a835cc13a685696178e374fe3ac8ba9003b
parentf37dc0dd14d9ce0b59c454c2c1b935fcbe9727e9 (diff)
downloadPeerTube-aa55a4da422330fe2816f1764b64f6607a0ca4aa.tar.gz
PeerTube-aa55a4da422330fe2816f1764b64f6607a0ca4aa.tar.zst
PeerTube-aa55a4da422330fe2816f1764b64f6607a0ca4aa.zip
Infinite scroll to list our subscriptions
-rw-r--r--client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.html2
-rw-r--r--client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts32
-rw-r--r--client/src/app/+my-account/my-account-video-imports/my-account-video-imports.component.html8
-rw-r--r--client/src/app/search/search.component.html2
-rw-r--r--client/src/app/search/search.component.ts14
-rw-r--r--client/src/app/shared/user-subscription/user-subscription.service.ts18
-rw-r--r--client/src/app/shared/video/infinite-scroller.directive.ts4
-rw-r--r--client/src/app/videos/+video-watch/comment/video-comments.component.html2
-rw-r--r--server/models/activitypub/actor-follow.ts10
-rw-r--r--server/models/activitypub/actor.ts42
10 files changed, 67 insertions, 67 deletions
diff --git a/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.html b/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.html
index 4c68cd1a5..3752de49f 100644
--- a/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.html
+++ b/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.html
@@ -1,4 +1,4 @@
1<div class="video-channels"> 1<div class="video-channels" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()">
2 <div *ngFor="let videoChannel of videoChannels" class="video-channel"> 2 <div *ngFor="let videoChannel of videoChannels" class="video-channel">
3 <a [routerLink]="[ '/video-channels', videoChannel.name ]"> 3 <a [routerLink]="[ '/video-channels', videoChannel.name ]">
4 <img [src]="videoChannel.avatarUrl" alt="Avatar" /> 4 <img [src]="videoChannel.avatarUrl" alt="Avatar" />
diff --git a/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts b/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts
index 9434b196f..9517a3705 100644
--- a/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts
+++ b/client/src/app/+my-account/my-account-subscriptions/my-account-subscriptions.component.ts
@@ -3,6 +3,7 @@ import { NotificationsService } from 'angular2-notifications'
3import { VideoChannel } from '@app/shared/video-channel/video-channel.model' 3import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
4import { I18n } from '@ngx-translate/i18n-polyfill' 4import { I18n } from '@ngx-translate/i18n-polyfill'
5import { UserSubscriptionService } from '@app/shared/user-subscription' 5import { UserSubscriptionService } from '@app/shared/user-subscription'
6import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
6 7
7@Component({ 8@Component({
8 selector: 'my-account-subscriptions', 9 selector: 'my-account-subscriptions',
@@ -12,6 +13,12 @@ import { UserSubscriptionService } from '@app/shared/user-subscription'
12export class MyAccountSubscriptionsComponent implements OnInit { 13export class MyAccountSubscriptionsComponent implements OnInit {
13 videoChannels: VideoChannel[] = [] 14 videoChannels: VideoChannel[] = []
14 15
16 pagination: ComponentPagination = {
17 currentPage: 1,
18 itemsPerPage: 10,
19 totalItems: null
20 }
21
15 constructor ( 22 constructor (
16 private userSubscriptionService: UserSubscriptionService, 23 private userSubscriptionService: UserSubscriptionService,
17 private notificationsService: NotificationsService, 24 private notificationsService: NotificationsService,
@@ -19,12 +26,27 @@ export class MyAccountSubscriptionsComponent implements OnInit {
19 ) {} 26 ) {}
20 27
21 ngOnInit () { 28 ngOnInit () {
22 this.userSubscriptionService.listSubscriptions() 29 this.loadSubscriptions()
23 .subscribe( 30 }
24 res => this.videoChannels = res.data, 31
32 loadSubscriptions () {
33 this.userSubscriptionService.listSubscriptions(this.pagination)
34 .subscribe(
35 res => {
36 this.videoChannels = this.videoChannels.concat(res.data)
37 this.pagination.totalItems = res.total
38 },
39
40 error => this.notificationsService.error(this.i18n('Error'), error.message)
41 )
42 }
43
44 onNearOfBottom () {
45 // Last page
46 if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return
25 47
26 error => this.notificationsService.error(this.i18n('Error'), error.message) 48 this.pagination.currentPage += 1
27 ) 49 this.loadSubscriptions()
28 } 50 }
29 51
30} 52}
diff --git a/client/src/app/+my-account/my-account-video-imports/my-account-video-imports.component.html b/client/src/app/+my-account/my-account-video-imports/my-account-video-imports.component.html
index b2b6c3d60..329948cb5 100644
--- a/client/src/app/+my-account/my-account-video-imports/my-account-video-imports.component.html
+++ b/client/src/app/+my-account/my-account-video-imports/my-account-video-imports.component.html
@@ -29,10 +29,10 @@
29 </td> 29 </td>
30 30
31 <td *ngIf="isVideoImportPending(videoImport)"> 31 <td *ngIf="isVideoImportPending(videoImport)">
32 {{ videoImport.video.name }} 32 {{ videoImport.video?.name }}
33 </td> 33 </td>
34 <td *ngIf="isVideoImportSuccess(videoImport)"> 34 <td *ngIf="isVideoImportSuccess(videoImport) && videoImport.video">
35 <a [href]="getVideoUrl(videoImport.video)" target="_blank" rel="noopener noreferrer">{{ videoImport.video.name }}</a> 35 <a [href]="getVideoUrl(videoImport.video)" target="_blank" rel="noopener noreferrer">{{ videoImport.video?.name }}</a>
36 </td> 36 </td>
37 <td *ngIf="isVideoImportFailed(videoImport)"></td> 37 <td *ngIf="isVideoImportFailed(videoImport)"></td>
38 38
@@ -40,7 +40,7 @@
40 <td>{{ videoImport.createdAt }}</td> 40 <td>{{ videoImport.createdAt }}</td>
41 41
42 <td class="action-cell"> 42 <td class="action-cell">
43 <my-edit-button *ngIf="isVideoImportSuccess(videoImport)" [routerLink]="getEditVideoUrl(videoImport.video)"></my-edit-button> 43 <my-edit-button *ngIf="isVideoImportSuccess(videoImport) && videoImport.video" [routerLink]="getEditVideoUrl(videoImport.video)"></my-edit-button>
44 </td> 44 </td>
45 </tr> 45 </tr>
46 </ng-template> 46 </ng-template>
diff --git a/client/src/app/search/search.component.html b/client/src/app/search/search.component.html
index 128cc52f5..83d014987 100644
--- a/client/src/app/search/search.component.html
+++ b/client/src/app/search/search.component.html
@@ -1,4 +1,4 @@
1<div myInfiniteScroller [autoLoading]="true" (nearOfBottom)="onNearOfBottom()" class="search-result"> 1<div myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" class="search-result">
2 <div class="results-header"> 2 <div class="results-header">
3 <div class="first-line"> 3 <div class="first-line">
4 <div class="results-counter" *ngIf="pagination.totalItems"> 4 <div class="results-counter" *ngIf="pagination.totalItems">
diff --git a/client/src/app/search/search.component.ts b/client/src/app/search/search.component.ts
index f88df6391..ed84e24d9 100644
--- a/client/src/app/search/search.component.ts
+++ b/client/src/app/search/search.component.ts
@@ -87,9 +87,17 @@ export class SearchComponent implements OnInit, OnDestroy {
87 .subscribe( 87 .subscribe(
88 ([ videosResult, videoChannelsResult ]) => { 88 ([ videosResult, videoChannelsResult ]) => {
89 this.videos = this.videos.concat(videosResult.videos) 89 this.videos = this.videos.concat(videosResult.videos)
90 this.pagination.totalItems = videosResult.totalVideos 90 this.pagination.totalItems = videosResult.totalVideos + videoChannelsResult.total
91 91
92 this.videoChannels = videoChannelsResult.data 92 this.videoChannels = this.videoChannels.concat(videoChannelsResult.data)
93
94 // Focus on channels
95 if (this.channelsPerPage !== 10 && this.videos.length < this.pagination.itemsPerPage) {
96 this.resetPagination()
97
98 this.channelsPerPage = 10
99 this.search()
100 }
93 }, 101 },
94 102
95 error => { 103 error => {
@@ -116,8 +124,10 @@ export class SearchComponent implements OnInit, OnDestroy {
116 private resetPagination () { 124 private resetPagination () {
117 this.pagination.currentPage = 1 125 this.pagination.currentPage = 1
118 this.pagination.totalItems = null 126 this.pagination.totalItems = null
127 this.channelsPerPage = 2
119 128
120 this.videos = [] 129 this.videos = []
130 this.videoChannels = []
121 } 131 }
122 132
123 private updateTitle () { 133 private updateTitle () {
diff --git a/client/src/app/shared/user-subscription/user-subscription.service.ts b/client/src/app/shared/user-subscription/user-subscription.service.ts
index cf622019f..3d05f071e 100644
--- a/client/src/app/shared/user-subscription/user-subscription.service.ts
+++ b/client/src/app/shared/user-subscription/user-subscription.service.ts
@@ -1,4 +1,4 @@
1import { bufferTime, catchError, filter, map, share, switchMap, tap } from 'rxjs/operators' 1import { bufferTime, catchError, filter, first, map, share, switchMap } from 'rxjs/operators'
2import { HttpClient, HttpParams } from '@angular/common/http' 2import { HttpClient, HttpParams } from '@angular/common/http'
3import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
4import { ResultList } from '../../../../../shared' 4import { ResultList } from '../../../../../shared'
@@ -8,6 +8,7 @@ import { Observable, ReplaySubject, Subject } from 'rxjs'
8import { VideoChannel } from '@app/shared/video-channel/video-channel.model' 8import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
9import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' 9import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
10import { VideoChannel as VideoChannelServer } from '../../../../../shared/models/videos' 10import { VideoChannel as VideoChannelServer } from '../../../../../shared/models/videos'
11import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
11 12
12type SubscriptionExistResult = { [ uri: string ]: boolean } 13type SubscriptionExistResult = { [ uri: string ]: boolean }
13 14
@@ -17,7 +18,7 @@ export class UserSubscriptionService {
17 18
18 // Use a replay subject because we "next" a value before subscribing 19 // Use a replay subject because we "next" a value before subscribing
19 private existsSubject: Subject<string> = new ReplaySubject(1) 20 private existsSubject: Subject<string> = new ReplaySubject(1)
20 private existsObservable: Observable<SubscriptionExistResult> 21 private readonly existsObservable: Observable<SubscriptionExistResult>
21 22
22 constructor ( 23 constructor (
23 private authHttp: HttpClient, 24 private authHttp: HttpClient,
@@ -25,7 +26,6 @@ export class UserSubscriptionService {
25 private restService: RestService 26 private restService: RestService
26 ) { 27 ) {
27 this.existsObservable = this.existsSubject.pipe( 28 this.existsObservable = this.existsSubject.pipe(
28 tap(u => console.log(u)),
29 bufferTime(500), 29 bufferTime(500),
30 filter(uris => uris.length !== 0), 30 filter(uris => uris.length !== 0),
31 switchMap(uris => this.areSubscriptionExist(uris)), 31 switchMap(uris => this.areSubscriptionExist(uris)),
@@ -54,10 +54,15 @@ export class UserSubscriptionService {
54 ) 54 )
55 } 55 }
56 56
57 listSubscriptions (): Observable<ResultList<VideoChannel>> { 57 listSubscriptions (componentPagination: ComponentPagination): Observable<ResultList<VideoChannel>> {
58 const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL 58 const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL
59 59
60 return this.authHttp.get<ResultList<VideoChannelServer>>(url) 60 const pagination = this.restService.componentPaginationToRestPagination(componentPagination)
61
62 let params = new HttpParams()
63 params = this.restService.addRestGetParams(params, pagination)
64
65 return this.authHttp.get<ResultList<VideoChannelServer>>(url, { params })
61 .pipe( 66 .pipe(
62 map(res => VideoChannelService.extractVideoChannels(res)), 67 map(res => VideoChannelService.extractVideoChannels(res)),
63 catchError(err => this.restExtractor.handleError(err)) 68 catchError(err => this.restExtractor.handleError(err))
@@ -67,11 +72,10 @@ export class UserSubscriptionService {
67 isSubscriptionExists (nameWithHost: string) { 72 isSubscriptionExists (nameWithHost: string) {
68 this.existsSubject.next(nameWithHost) 73 this.existsSubject.next(nameWithHost)
69 74
70 return this.existsObservable 75 return this.existsObservable.pipe(first())
71 } 76 }
72 77
73 private areSubscriptionExist (uris: string[]): Observable<SubscriptionExistResult> { 78 private areSubscriptionExist (uris: string[]): Observable<SubscriptionExistResult> {
74 console.log(uris)
75 const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL + '/exist' 79 const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL + '/exist'
76 let params = new HttpParams() 80 let params = new HttpParams()
77 81
diff --git a/client/src/app/shared/video/infinite-scroller.directive.ts b/client/src/app/shared/video/infinite-scroller.directive.ts
index 0448e2c23..4dc1f86e7 100644
--- a/client/src/app/shared/video/infinite-scroller.directive.ts
+++ b/client/src/app/shared/video/infinite-scroller.directive.ts
@@ -11,7 +11,7 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy {
11 @Input() containerHeight: number 11 @Input() containerHeight: number
12 @Input() pageHeight: number 12 @Input() pageHeight: number
13 @Input() percentLimit = 70 13 @Input() percentLimit = 70
14 @Input() autoLoading = false 14 @Input() autoInit = false
15 15
16 @Output() nearOfBottom = new EventEmitter<void>() 16 @Output() nearOfBottom = new EventEmitter<void>()
17 @Output() nearOfTop = new EventEmitter<void>() 17 @Output() nearOfTop = new EventEmitter<void>()
@@ -29,7 +29,7 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy {
29 } 29 }
30 30
31 ngOnInit () { 31 ngOnInit () {
32 if (this.autoLoading === true) return this.initialize() 32 if (this.autoInit === true) return this.initialize()
33 } 33 }
34 34
35 ngOnDestroy () { 35 ngOnDestroy () {
diff --git a/client/src/app/videos/+video-watch/comment/video-comments.component.html b/client/src/app/videos/+video-watch/comment/video-comments.component.html
index 8871980e9..bf6706ed3 100644
--- a/client/src/app/videos/+video-watch/comment/video-comments.component.html
+++ b/client/src/app/videos/+video-watch/comment/video-comments.component.html
@@ -21,7 +21,7 @@
21 <div 21 <div
22 class="comment-threads" 22 class="comment-threads"
23 myInfiniteScroller 23 myInfiniteScroller
24 [autoLoading]="true" 24 [autoInit]="true"
25 (nearOfBottom)="onNearOfBottom()" 25 (nearOfBottom)="onNearOfBottom()"
26 > 26 >
27 <div #commentHighlightBlock id="highlighted-comment"> 27 <div #commentHighlightBlock id="highlighted-comment">
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts
index 81fcf7001..ebb2d47c2 100644
--- a/server/models/activitypub/actor-follow.ts
+++ b/server/models/activitypub/actor-follow.ts
@@ -169,9 +169,6 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
169 169
170 static loadByActorAndTargetNameAndHostForAPI (actorId: number, targetName: string, targetHost: string, t?: Sequelize.Transaction) { 170 static loadByActorAndTargetNameAndHostForAPI (actorId: number, targetName: string, targetHost: string, t?: Sequelize.Transaction) {
171 const actorFollowingPartInclude: IIncludeOptions = { 171 const actorFollowingPartInclude: IIncludeOptions = {
172 attributes: {
173 exclude: unusedActorAttributesForAPI
174 },
175 model: ActorModel, 172 model: ActorModel,
176 required: true, 173 required: true,
177 as: 'ActorFollowing', 174 as: 'ActorFollowing',
@@ -203,7 +200,12 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
203 actorId 200 actorId
204 }, 201 },
205 include: [ 202 include: [
206 actorFollowingPartInclude 203 actorFollowingPartInclude,
204 {
205 model: ActorModel,
206 required: true,
207 as: 'ActorFollower'
208 }
207 ], 209 ],
208 transaction: t 210 transaction: t
209 } 211 }
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts
index ec0b4b2d9..e16bd5d79 100644
--- a/server/models/activitypub/actor.ts
+++ b/server/models/activitypub/actor.ts
@@ -49,7 +49,8 @@ export const unusedActorAttributesForAPI = [
49 'outboxUrl', 49 'outboxUrl',
50 'sharedInboxUrl', 50 'sharedInboxUrl',
51 'followersUrl', 51 'followersUrl',
52 'followingUrl' 52 'followingUrl',
53 'url'
53] 54]
54 55
55@DefaultScope({ 56@DefaultScope({
@@ -322,45 +323,6 @@ export class ActorModel extends Model<ActorModel> {
322 }) 323 })
323 } 324 }
324 325
325 static async getActorsFollowerSharedInboxUrls (actors: ActorModel[], t: Sequelize.Transaction) {
326 const query = {
327 // attribute: [],
328 where: {
329 id: {
330 [Sequelize.Op.in]: actors.map(a => a.id)
331 }
332 },
333 include: [
334 {
335 // attributes: [ ],
336 model: ActorFollowModel.unscoped(),
337 required: true,
338 as: 'ActorFollowers',
339 where: {
340 state: 'accepted'
341 },
342 include: [
343 {
344 attributes: [ 'sharedInboxUrl' ],
345 model: ActorModel.unscoped(),
346 as: 'ActorFollower',
347 required: true
348 }
349 ]
350 }
351 ],
352 transaction: t
353 }
354
355 const hash: { [ id: number ]: string[] } = {}
356 const res = await ActorModel.findAll(query)
357 for (const actor of res) {
358 hash[actor.id] = actor.ActorFollowers.map(follow => follow.ActorFollower.sharedInboxUrl)
359 }
360
361 return hash
362 }
363
364 toFormattedJSON () { 326 toFormattedJSON () {
365 let avatar: Avatar = null 327 let avatar: Avatar = null
366 if (this.Avatar) { 328 if (this.Avatar) {