aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/shared/user-subscription
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2020-06-23 14:10:17 +0200
committerChocobozzz <chocobozzz@cpy.re>2020-06-23 16:00:49 +0200
commit67ed6552b831df66713bac9e672738796128d33f (patch)
tree59c97d41e0b49d75a90aa3de987968ab9b1ff447 /client/src/app/shared/user-subscription
parent0c4bacbff53bc732f5a2677d62a6ead7752e2405 (diff)
downloadPeerTube-67ed6552b831df66713bac9e672738796128d33f.tar.gz
PeerTube-67ed6552b831df66713bac9e672738796128d33f.tar.zst
PeerTube-67ed6552b831df66713bac9e672738796128d33f.zip
Reorganize client shared modules
Diffstat (limited to 'client/src/app/shared/user-subscription')
-rw-r--r--client/src/app/shared/user-subscription/index.ts3
-rw-r--r--client/src/app/shared/user-subscription/remote-subscribe.component.html32
-rw-r--r--client/src/app/shared/user-subscription/remote-subscribe.component.scss6
-rw-r--r--client/src/app/shared/user-subscription/remote-subscribe.component.ts62
-rw-r--r--client/src/app/shared/user-subscription/subscribe-button.component.html67
-rw-r--r--client/src/app/shared/user-subscription/subscribe-button.component.scss112
-rw-r--r--client/src/app/shared/user-subscription/subscribe-button.component.ts198
-rw-r--r--client/src/app/shared/user-subscription/user-subscription.service.ts163
8 files changed, 0 insertions, 643 deletions
diff --git a/client/src/app/shared/user-subscription/index.ts b/client/src/app/shared/user-subscription/index.ts
deleted file mode 100644
index e76940f7b..000000000
--- a/client/src/app/shared/user-subscription/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
1export * from './user-subscription.service'
2export * from './subscribe-button.component'
3export * from './remote-subscribe.component'
diff --git a/client/src/app/shared/user-subscription/remote-subscribe.component.html b/client/src/app/shared/user-subscription/remote-subscribe.component.html
deleted file mode 100644
index acfec0a8e..000000000
--- a/client/src/app/shared/user-subscription/remote-subscribe.component.html
+++ /dev/null
@@ -1,32 +0,0 @@
1<form novalidate [formGroup]="form" (ngSubmit)="formValidated()">
2 <div class="form-group mb-2">
3 <input type="email"
4 formControlName="text"
5 class="form-control"
6 (keyup.control.enter)="onValidKey()" (keyup.meta.enter)="onValidKey()"
7 placeholder="jane_doe@example.com">
8 </div>
9
10 <button type="submit" [disabled]="!form.valid" class="btn btn-sm btn-remote-follow" i18n>
11 <span *ngIf="!interact">Remote subscribe</span>
12 <span *ngIf="interact">Remote interact</span>
13 </button>
14
15 <my-help *ngIf="!interact && showHelp">
16 <ng-template ptTemplate="customHtml">
17 <ng-container i18n>
18 You can subscribe to the channel via any ActivityPub-capable fediverse instance.<br /><br />
19 For instance with Mastodon or Pleroma you can type the channel URL in the search box and subscribe there.
20 </ng-container>
21 </ng-template>
22 </my-help>
23
24 <my-help *ngIf="showHelp && interact">
25 <ng-template ptTemplate="customHtml">
26 <ng-container i18n>
27 You can interact with this via any ActivityPub-capable fediverse instance.<br /><br />
28 For instance with Mastodon or Pleroma you can type the current URL in the search box and interact with it there.
29 </ng-container>
30 </ng-template>
31 </my-help>
32</form>
diff --git a/client/src/app/shared/user-subscription/remote-subscribe.component.scss b/client/src/app/shared/user-subscription/remote-subscribe.component.scss
deleted file mode 100644
index 698c5866a..000000000
--- a/client/src/app/shared/user-subscription/remote-subscribe.component.scss
+++ /dev/null
@@ -1,6 +0,0 @@
1@import '_mixins';
2
3.btn-remote-follow {
4 @include peertube-button;
5 @include orange-button;
6} \ No newline at end of file
diff --git a/client/src/app/shared/user-subscription/remote-subscribe.component.ts b/client/src/app/shared/user-subscription/remote-subscribe.component.ts
deleted file mode 100644
index befdb7157..000000000
--- a/client/src/app/shared/user-subscription/remote-subscribe.component.ts
+++ /dev/null
@@ -1,62 +0,0 @@
1import { Component, Input, OnInit } from '@angular/core'
2import { FormReactive } from '@app/shared/forms/form-reactive'
3import {
4 FormValidatorService,
5 UserValidatorsService
6} from '@app/shared/forms/form-validators'
7
8@Component({
9 selector: 'my-remote-subscribe',
10 templateUrl: './remote-subscribe.component.html',
11 styleUrls: ['./remote-subscribe.component.scss']
12})
13export class RemoteSubscribeComponent extends FormReactive implements OnInit {
14 @Input() uri: string
15 @Input() interact = false
16 @Input() showHelp = false
17
18 constructor (
19 protected formValidatorService: FormValidatorService,
20 private userValidatorsService: UserValidatorsService
21 ) {
22 super()
23 }
24
25 ngOnInit () {
26 this.buildForm({
27 text: this.userValidatorsService.USER_EMAIL
28 })
29 }
30
31 onValidKey () {
32 this.check()
33 if (!this.form.valid) return
34
35 this.formValidated()
36 }
37
38 formValidated () {
39 const address = this.form.value['text']
40 const [ username, hostname ] = address.split('@')
41
42 // Should not have CORS error because https://tools.ietf.org/html/rfc7033#section-5
43 fetch(`https://${hostname}/.well-known/webfinger?resource=acct:${username}@${hostname}`)
44 .then(response => response.json())
45 .then(data => new Promise((resolve, reject) => {
46 console.log(data)
47
48 if (data && Array.isArray(data.links)) {
49 const link: { template: string } = data.links.find((link: any) => {
50 return link && typeof link.template === 'string' && link.rel === 'http://ostatus.org/schema/1.0/subscribe'
51 })
52
53 if (link && link.template.includes('{uri}')) {
54 resolve(link.template.replace('{uri}', encodeURIComponent(this.uri)))
55 }
56 }
57 reject()
58 }))
59 .then(window.open)
60 .catch(err => console.error(err))
61 }
62}
diff --git a/client/src/app/shared/user-subscription/subscribe-button.component.html b/client/src/app/shared/user-subscription/subscribe-button.component.html
deleted file mode 100644
index 85b3d1fdb..000000000
--- a/client/src/app/shared/user-subscription/subscribe-button.component.html
+++ /dev/null
@@ -1,67 +0,0 @@
1<div class="btn-group-subscribe btn-group"
2 [ngClass]="{'subscribe-button': !isAllChannelsSubscribed, 'unsubscribe-button': isAllChannelsSubscribed, 'big': isBigButton }">
3
4 <ng-template #userLoggedOut>
5 <span [ngClass]="{ 'extra-text': isAtLeastOneChannelSubscribed }">
6 <ng-container *ngIf="account; then multiple; else single"></ng-container>
7 <ng-template i18n #single>Subscribe</ng-template>
8 <ng-template #multiple>
9 <span i18n>Subscribe to all channels</span>
10 <span *ngIf="isAtLeastOneChannelSubscribed">{{ subscribeStatus(true).length }}/{{ subscribed.size }}
11 <ng-container i18n>channels subscribed</ng-container>
12 </span>
13 </ng-template>
14 </span>
15 <span *ngIf="!isBigButton && displayFollowers && videoChannels.length > 1 && videoChannel.followersCount !== 0" class="followers-count">
16 {{ videoChannels[0].followersCount | myNumberFormatter }}
17 </span>
18 </ng-template>
19
20 <ng-template #userLoggedIn>
21 <button *ngIf="!isAllChannelsSubscribed" type="button"
22 class="btn btn-sm" role="button"
23 (click)="subscribe()">
24 <ng-template [ngTemplateOutlet]="userLoggedOut"></ng-template>
25 </button>
26
27 <button
28 *ngIf="isAllChannelsSubscribed" type="button"
29 class="btn btn-sm" role="button"
30 (click)="unsubscribe()">
31 <ng-container i18n>{account + "", select, undefined {Unsubscribe} other {Unsubscribe from all channels}}</ng-container>
32 </button>
33 </ng-template>
34
35 <ng-container
36 *ngIf="isUserLoggedIn(); then userLoggedIn">
37 </ng-container>
38
39 <div class="btn-group" ngbDropdown autoClose="outside"
40 placement="bottom-right" role="group"
41 aria-label="Multiple ways to subscribe to the current channel">
42 <button class="btn btn-sm dropdown-toggle-split" ngbDropdownToggle>
43 <ng-container
44 *ngIf="!isUserLoggedIn(); then userLoggedOut">
45 </ng-container>
46 </button>
47
48 <div class="dropdown-menu" ngbDropdownMenu>
49
50 <h6 class="dropdown-header" i18n>Using an ActivityPub account</h6>
51
52 <button class="dropdown-item" (click)="subscribe()">
53 <span *ngIf="!isUserLoggedIn()" i18n>Subscribe with an account on this instance</span>
54 <span *ngIf="isUserLoggedIn()" i18n>Subscribe with your local account</span>
55 </button>
56
57 <button class="dropdown-item dropdown-item-neutral" i18n>Subscribe with a Mastodon account:</button>
58 <my-remote-subscribe [showHelp]="true" [uri]="uri"></my-remote-subscribe>
59
60 <div class="dropdown-divider"></div>
61
62 <h6 class="dropdown-header" i18n>Using a syndication feed</h6>
63 <a [href]="rssUri" target="_blank" class="dropdown-item" i18n>Subscribe via RSS</a>
64
65 </div>
66 </div>
67</div>
diff --git a/client/src/app/shared/user-subscription/subscribe-button.component.scss b/client/src/app/shared/user-subscription/subscribe-button.component.scss
deleted file mode 100644
index b739c5ae2..000000000
--- a/client/src/app/shared/user-subscription/subscribe-button.component.scss
+++ /dev/null
@@ -1,112 +0,0 @@
1@import '_variables';
2@import '_mixins';
3
4.btn-group-subscribe {
5 @include peertube-button;
6 @include disable-default-a-behaviour;
7
8 float: right;
9 padding: 0;
10
11 & > .btn,
12 & > .dropdown > .dropdown-toggle {
13 font-size: 15px;
14 }
15
16 &:not(.big) {
17 white-space: nowrap;
18 }
19
20 &.big {
21 height: 35px;
22
23 & > button:first-child {
24 width: 175px;
25 }
26
27 button .extra-text {
28 span:first-child {
29 line-height: 80%;
30 }
31
32 span:not(:first-child) {
33 font-size: 75%;
34 }
35 }
36 }
37
38 // Unlogged
39 & > .dropdown > .dropdown-toggle span {
40 padding-right: 3px;
41 }
42
43 // Logged
44 & > .btn {
45 padding-right: 4px;
46
47 & + .dropdown > button {
48 padding-left: 2px;
49
50 &::after {
51 position: relative;
52 top: 1px;
53 }
54 }
55 }
56
57 &.subscribe-button {
58 .btn {
59 @include orange-button;
60 font-weight: 600;
61 }
62
63 span.followers-count {
64 padding-left: 5px;
65 }
66 }
67 &.unsubscribe-button {
68 .btn {
69 @include grey-button;
70 font-weight: 600;
71 }
72 }
73
74 .dropdown-menu {
75 cursor: default;
76
77 button {
78 cursor: pointer;
79 }
80
81 .dropdown-item-neutral {
82 cursor: default;
83
84 &:hover,
85 &:focus {
86 background-color: inherit;
87 }
88 }
89 }
90
91 ::ng-deep form {
92 padding: 0.25rem 1rem;
93 }
94
95 input {
96 @include peertube-input-text(100%);
97 }
98}
99
100.extra-text {
101 display: flex;
102 flex-direction: column;
103
104 span:first-child {
105 line-height: 75%;
106 }
107
108 span:not(:first-child) {
109 font-size: 60%;
110 text-align: left;
111 }
112}
diff --git a/client/src/app/shared/user-subscription/subscribe-button.component.ts b/client/src/app/shared/user-subscription/subscribe-button.component.ts
deleted file mode 100644
index 947f34c85..000000000
--- a/client/src/app/shared/user-subscription/subscribe-button.component.ts
+++ /dev/null
@@ -1,198 +0,0 @@
1import { Component, Input, OnInit, OnChanges } from '@angular/core'
2import { Router } from '@angular/router'
3import { AuthService, Notifier } from '@app/core'
4import { UserSubscriptionService } from '@app/shared/user-subscription/user-subscription.service'
5import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
6import { I18n } from '@ngx-translate/i18n-polyfill'
7import { VideoService } from '@app/shared/video/video.service'
8import { FeedFormat } from '../../../../../shared/models/feeds'
9import { Account } from '@app/shared/account/account.model'
10import { concat, forkJoin, merge } from 'rxjs'
11
12@Component({
13 selector: 'my-subscribe-button',
14 templateUrl: './subscribe-button.component.html',
15 styleUrls: [ './subscribe-button.component.scss' ]
16})
17export class SubscribeButtonComponent implements OnInit, OnChanges {
18 /**
19 * SubscribeButtonComponent can be used with a single VideoChannel passed as [VideoChannel],
20 * or with an account and a full list of that account's videoChannels. The latter is intended
21 * to allow mass un/subscription from an account's page, while keeping the channel-centric
22 * subscription model.
23 */
24 @Input() account: Account
25 @Input() videoChannels: VideoChannel[]
26 @Input() displayFollowers = false
27 @Input() size: 'small' | 'normal' = 'normal'
28
29 subscribed = new Map<string, boolean>()
30
31 constructor (
32 private authService: AuthService,
33 private router: Router,
34 private notifier: Notifier,
35 private userSubscriptionService: UserSubscriptionService,
36 private i18n: I18n,
37 private videoService: VideoService
38 ) { }
39
40 get handle () {
41 return this.account
42 ? this.account.nameWithHost
43 : this.videoChannel.name + '@' + this.videoChannel.host
44 }
45
46 get channelHandle () {
47 return this.getChannelHandler(this.videoChannel)
48 }
49
50 get uri () {
51 return this.account
52 ? this.account.url
53 : this.videoChannels[0].url
54 }
55
56 get rssUri () {
57 const rssFeed = this.account
58 ? this.videoService
59 .getAccountFeedUrls(this.account.id)
60 .find(i => i.format === FeedFormat.RSS)
61 : this.videoService
62 .getVideoChannelFeedUrls(this.videoChannels[0].id)
63 .find(i => i.format === FeedFormat.RSS)
64
65 return rssFeed.url
66 }
67
68 get videoChannel () {
69 return this.videoChannels[0]
70 }
71
72 get isAllChannelsSubscribed () {
73 return this.subscribeStatus(true).length === this.videoChannels.length
74 }
75
76 get isAtLeastOneChannelSubscribed () {
77 return this.subscribeStatus(true).length > 0
78 }
79
80 get isBigButton () {
81 return this.isUserLoggedIn() && this.videoChannels.length > 1 && this.isAtLeastOneChannelSubscribed
82 }
83
84 ngOnInit () {
85 this.loadSubscribedStatus()
86 }
87
88 ngOnChanges () {
89 this.ngOnInit()
90 }
91
92 subscribe () {
93 if (this.isUserLoggedIn()) {
94 return this.localSubscribe()
95 }
96
97 return this.gotoLogin()
98 }
99
100 localSubscribe () {
101 const subscribedStatus = this.subscribeStatus(false)
102
103 const observableBatch = this.videoChannels
104 .map(videoChannel => this.getChannelHandler(videoChannel))
105 .filter(handle => subscribedStatus.includes(handle))
106 .map(handle => this.userSubscriptionService.addSubscription(handle))
107
108 forkJoin(observableBatch)
109 .subscribe(
110 () => {
111 this.notifier.success(
112 this.account
113 ? this.i18n(
114 'Subscribed to all current channels of {{nameWithHost}}. You will be notified of all their new videos.',
115 { nameWithHost: this.account.displayName }
116 )
117 : this.i18n(
118 'Subscribed to {{nameWithHost}}. You will be notified of all their new videos.',
119 { nameWithHost: this.videoChannels[0].displayName }
120 )
121 ,
122 this.i18n('Subscribed')
123 )
124 },
125
126 err => this.notifier.error(err.message)
127 )
128 }
129
130 unsubscribe () {
131 if (this.isUserLoggedIn()) {
132 this.localUnsubscribe()
133 }
134 }
135
136 localUnsubscribe () {
137 const subscribeStatus = this.subscribeStatus(true)
138
139 const observableBatch = this.videoChannels
140 .map(videoChannel => this.getChannelHandler(videoChannel))
141 .filter(handle => subscribeStatus.includes(handle))
142 .map(handle => this.userSubscriptionService.deleteSubscription(handle))
143
144 concat(...observableBatch)
145 .subscribe({
146 complete: () => {
147 this.notifier.success(
148 this.account
149 ? this.i18n('Unsubscribed from all channels of {{nameWithHost}}', { nameWithHost: this.account.nameWithHost })
150 : this.i18n('Unsubscribed from {{nameWithHost}}', { nameWithHost: this.videoChannels[ 0 ].nameWithHost })
151 ,
152 this.i18n('Unsubscribed')
153 )
154 },
155
156 error: err => this.notifier.error(err.message)
157 })
158 }
159
160 isUserLoggedIn () {
161 return this.authService.isLoggedIn()
162 }
163
164 gotoLogin () {
165 this.router.navigate([ '/login' ])
166 }
167
168 subscribeStatus (subscribed: boolean) {
169 const accumulator: string[] = []
170 for (const [key, value] of this.subscribed.entries()) {
171 if (value === subscribed) accumulator.push(key)
172 }
173
174 return accumulator
175 }
176
177 private getChannelHandler (videoChannel: VideoChannel) {
178 return videoChannel.name + '@' + videoChannel.host
179 }
180
181 private loadSubscribedStatus () {
182 if (!this.isUserLoggedIn()) return
183
184 for (const videoChannel of this.videoChannels) {
185 const handle = this.getChannelHandler(videoChannel)
186 this.subscribed.set(handle, false)
187
188 merge(
189 this.userSubscriptionService.listenToSubscriptionCacheChange(handle),
190 this.userSubscriptionService.doesSubscriptionExist(handle)
191 ).subscribe(
192 res => this.subscribed.set(handle, res),
193
194 err => this.notifier.error(err.message)
195 )
196 }
197 }
198}
diff --git a/client/src/app/shared/user-subscription/user-subscription.service.ts b/client/src/app/shared/user-subscription/user-subscription.service.ts
deleted file mode 100644
index 9af9ba23e..000000000
--- a/client/src/app/shared/user-subscription/user-subscription.service.ts
+++ /dev/null
@@ -1,163 +0,0 @@
1import { bufferTime, catchError, filter, map, observeOn, share, switchMap, tap } from 'rxjs/operators'
2import { asyncScheduler, merge, Observable, of, ReplaySubject, Subject } from 'rxjs'
3import { HttpClient, HttpParams } from '@angular/common/http'
4import { Injectable, NgZone } from '@angular/core'
5import { ResultList } from '../../../../../shared'
6import { environment } from '../../../environments/environment'
7import { RestExtractor, RestService } from '../rest'
8import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
9import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
10import { VideoChannel as VideoChannelServer } from '../../../../../shared/models/videos'
11import { ComponentPaginationLight } from '@app/shared/rest/component-pagination.model'
12import { uniq } from 'lodash-es'
13import * as debug from 'debug'
14import { enterZone, leaveZone } from '@app/shared/rxjs/zone'
15
16const logger = debug('peertube:subscriptions:UserSubscriptionService')
17
18type SubscriptionExistResult = { [ uri: string ]: boolean }
19type SubscriptionExistResultObservable = { [ uri: string ]: Observable<boolean> }
20
21@Injectable()
22export class UserSubscriptionService {
23 static BASE_USER_SUBSCRIPTIONS_URL = environment.apiUrl + '/api/v1/users/me/subscriptions'
24
25 // Use a replay subject because we "next" a value before subscribing
26 private existsSubject = new ReplaySubject<string>(1)
27 private readonly existsObservable: Observable<SubscriptionExistResult>
28
29 private myAccountSubscriptionCache: SubscriptionExistResult = {}
30 private myAccountSubscriptionCacheObservable: SubscriptionExistResultObservable = {}
31 private myAccountSubscriptionCacheSubject = new Subject<SubscriptionExistResult>()
32
33 constructor (
34 private authHttp: HttpClient,
35 private restExtractor: RestExtractor,
36 private restService: RestService,
37 private ngZone: NgZone
38 ) {
39 this.existsObservable = merge(
40 this.existsSubject.pipe(
41 // We leave Angular zone so Protractor does not get stuck
42 bufferTime(500, leaveZone(this.ngZone, asyncScheduler)),
43 filter(uris => uris.length !== 0),
44 map(uris => uniq(uris)),
45 observeOn(enterZone(this.ngZone, asyncScheduler)),
46 switchMap(uris => this.doSubscriptionsExist(uris)),
47 share()
48 ),
49
50 this.myAccountSubscriptionCacheSubject
51 )
52 }
53
54 /**
55 * Subscription part
56 */
57
58 deleteSubscription (nameWithHost: string) {
59 const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL + '/' + nameWithHost
60
61 return this.authHttp.delete(url)
62 .pipe(
63 map(this.restExtractor.extractDataBool),
64 tap(() => {
65 this.myAccountSubscriptionCache[nameWithHost] = false
66
67 this.myAccountSubscriptionCacheSubject.next(this.myAccountSubscriptionCache)
68 }),
69 catchError(err => this.restExtractor.handleError(err))
70 )
71 }
72
73 addSubscription (nameWithHost: string) {
74 const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL
75
76 const body = { uri: nameWithHost }
77 return this.authHttp.post(url, body)
78 .pipe(
79 map(this.restExtractor.extractDataBool),
80 tap(() => {
81 this.myAccountSubscriptionCache[nameWithHost] = true
82
83 this.myAccountSubscriptionCacheSubject.next(this.myAccountSubscriptionCache)
84 }),
85 catchError(err => this.restExtractor.handleError(err))
86 )
87 }
88
89 listSubscriptions (componentPagination: ComponentPaginationLight): Observable<ResultList<VideoChannel>> {
90 const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL
91
92 const pagination = this.restService.componentPaginationToRestPagination(componentPagination)
93
94 let params = new HttpParams()
95 params = this.restService.addRestGetParams(params, pagination)
96
97 return this.authHttp.get<ResultList<VideoChannelServer>>(url, { params })
98 .pipe(
99 map(res => VideoChannelService.extractVideoChannels(res)),
100 catchError(err => this.restExtractor.handleError(err))
101 )
102 }
103
104 /**
105 * SubscriptionExist part
106 */
107
108 listenToMyAccountSubscriptionCacheSubject () {
109 return this.myAccountSubscriptionCacheSubject.asObservable()
110 }
111
112 listenToSubscriptionCacheChange (nameWithHost: string) {
113 if (nameWithHost in this.myAccountSubscriptionCacheObservable) {
114 return this.myAccountSubscriptionCacheObservable[ nameWithHost ]
115 }
116
117 const obs = this.existsObservable
118 .pipe(
119 filter(existsResult => existsResult[ nameWithHost ] !== undefined),
120 map(existsResult => existsResult[ nameWithHost ])
121 )
122
123 this.myAccountSubscriptionCacheObservable[ nameWithHost ] = obs
124 return obs
125 }
126
127 doesSubscriptionExist (nameWithHost: string) {
128 logger('Running subscription check for %d.', nameWithHost)
129
130 if (nameWithHost in this.myAccountSubscriptionCache) {
131 logger('Found cache for %d.', nameWithHost)
132
133 return of(this.myAccountSubscriptionCache[ nameWithHost ])
134 }
135
136 this.existsSubject.next(nameWithHost)
137
138 logger('Fetching from network for %d.', nameWithHost)
139 return this.existsObservable.pipe(
140 filter(existsResult => existsResult[ nameWithHost ] !== undefined),
141 map(existsResult => existsResult[ nameWithHost ]),
142 tap(result => this.myAccountSubscriptionCache[ nameWithHost ] = result)
143 )
144 }
145
146 private doSubscriptionsExist (uris: string[]): Observable<SubscriptionExistResult> {
147 const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL + '/exist'
148 let params = new HttpParams()
149
150 params = this.restService.addObjectParams(params, { uris })
151
152 return this.authHttp.get<SubscriptionExistResult>(url, { params })
153 .pipe(
154 tap(res => {
155 this.myAccountSubscriptionCache = {
156 ...this.myAccountSubscriptionCache,
157 ...res
158 }
159 }),
160 catchError(err => this.restExtractor.handleError(err))
161 )
162 }
163}