From 67ed6552b831df66713bac9e672738796128d33f Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 23 Jun 2020 14:10:17 +0200 Subject: Reorganize client shared modules --- client/src/app/shared/user-subscription/index.ts | 3 - .../remote-subscribe.component.html | 32 ---- .../remote-subscribe.component.scss | 6 - .../remote-subscribe.component.ts | 62 ------- .../subscribe-button.component.html | 67 ------- .../subscribe-button.component.scss | 112 ------------ .../subscribe-button.component.ts | 198 --------------------- .../user-subscription/user-subscription.service.ts | 163 ----------------- 8 files changed, 643 deletions(-) delete mode 100644 client/src/app/shared/user-subscription/index.ts delete mode 100644 client/src/app/shared/user-subscription/remote-subscribe.component.html delete mode 100644 client/src/app/shared/user-subscription/remote-subscribe.component.scss delete mode 100644 client/src/app/shared/user-subscription/remote-subscribe.component.ts delete mode 100644 client/src/app/shared/user-subscription/subscribe-button.component.html delete mode 100644 client/src/app/shared/user-subscription/subscribe-button.component.scss delete mode 100644 client/src/app/shared/user-subscription/subscribe-button.component.ts delete mode 100644 client/src/app/shared/user-subscription/user-subscription.service.ts (limited to 'client/src/app/shared/user-subscription') 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 @@ -export * from './user-subscription.service' -export * from './subscribe-button.component' -export * 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 @@ -
-
- -
- - - - - - - You can subscribe to the channel via any ActivityPub-capable fediverse instance.

- For instance with Mastodon or Pleroma you can type the channel URL in the search box and subscribe there. -
-
-
- - - - - You can interact with this via any ActivityPub-capable fediverse instance.

- For instance with Mastodon or Pleroma you can type the current URL in the search box and interact with it there. -
-
-
-
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 @@ -@import '_mixins'; - -.btn-remote-follow { - @include peertube-button; - @include orange-button; -} \ 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 @@ -import { Component, Input, OnInit } from '@angular/core' -import { FormReactive } from '@app/shared/forms/form-reactive' -import { - FormValidatorService, - UserValidatorsService -} from '@app/shared/forms/form-validators' - -@Component({ - selector: 'my-remote-subscribe', - templateUrl: './remote-subscribe.component.html', - styleUrls: ['./remote-subscribe.component.scss'] -}) -export class RemoteSubscribeComponent extends FormReactive implements OnInit { - @Input() uri: string - @Input() interact = false - @Input() showHelp = false - - constructor ( - protected formValidatorService: FormValidatorService, - private userValidatorsService: UserValidatorsService - ) { - super() - } - - ngOnInit () { - this.buildForm({ - text: this.userValidatorsService.USER_EMAIL - }) - } - - onValidKey () { - this.check() - if (!this.form.valid) return - - this.formValidated() - } - - formValidated () { - const address = this.form.value['text'] - const [ username, hostname ] = address.split('@') - - // Should not have CORS error because https://tools.ietf.org/html/rfc7033#section-5 - fetch(`https://${hostname}/.well-known/webfinger?resource=acct:${username}@${hostname}`) - .then(response => response.json()) - .then(data => new Promise((resolve, reject) => { - console.log(data) - - if (data && Array.isArray(data.links)) { - const link: { template: string } = data.links.find((link: any) => { - return link && typeof link.template === 'string' && link.rel === 'http://ostatus.org/schema/1.0/subscribe' - }) - - if (link && link.template.includes('{uri}')) { - resolve(link.template.replace('{uri}', encodeURIComponent(this.uri))) - } - } - reject() - })) - .then(window.open) - .catch(err => console.error(err)) - } -} 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 @@ -
- - - - - Subscribe - - Subscribe to all channels - {{ subscribeStatus(true).length }}/{{ subscribed.size }} - channels subscribed - - - - - {{ videoChannels[0].followersCount | myNumberFormatter }} - - - - - - - - - - - - -
- - - -
-
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 @@ -@import '_variables'; -@import '_mixins'; - -.btn-group-subscribe { - @include peertube-button; - @include disable-default-a-behaviour; - - float: right; - padding: 0; - - & > .btn, - & > .dropdown > .dropdown-toggle { - font-size: 15px; - } - - &:not(.big) { - white-space: nowrap; - } - - &.big { - height: 35px; - - & > button:first-child { - width: 175px; - } - - button .extra-text { - span:first-child { - line-height: 80%; - } - - span:not(:first-child) { - font-size: 75%; - } - } - } - - // Unlogged - & > .dropdown > .dropdown-toggle span { - padding-right: 3px; - } - - // Logged - & > .btn { - padding-right: 4px; - - & + .dropdown > button { - padding-left: 2px; - - &::after { - position: relative; - top: 1px; - } - } - } - - &.subscribe-button { - .btn { - @include orange-button; - font-weight: 600; - } - - span.followers-count { - padding-left: 5px; - } - } - &.unsubscribe-button { - .btn { - @include grey-button; - font-weight: 600; - } - } - - .dropdown-menu { - cursor: default; - - button { - cursor: pointer; - } - - .dropdown-item-neutral { - cursor: default; - - &:hover, - &:focus { - background-color: inherit; - } - } - } - - ::ng-deep form { - padding: 0.25rem 1rem; - } - - input { - @include peertube-input-text(100%); - } -} - -.extra-text { - display: flex; - flex-direction: column; - - span:first-child { - line-height: 75%; - } - - span:not(:first-child) { - font-size: 60%; - text-align: left; - } -} 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 @@ -import { Component, Input, OnInit, OnChanges } from '@angular/core' -import { Router } from '@angular/router' -import { AuthService, Notifier } from '@app/core' -import { UserSubscriptionService } from '@app/shared/user-subscription/user-subscription.service' -import { VideoChannel } from '@app/shared/video-channel/video-channel.model' -import { I18n } from '@ngx-translate/i18n-polyfill' -import { VideoService } from '@app/shared/video/video.service' -import { FeedFormat } from '../../../../../shared/models/feeds' -import { Account } from '@app/shared/account/account.model' -import { concat, forkJoin, merge } from 'rxjs' - -@Component({ - selector: 'my-subscribe-button', - templateUrl: './subscribe-button.component.html', - styleUrls: [ './subscribe-button.component.scss' ] -}) -export class SubscribeButtonComponent implements OnInit, OnChanges { - /** - * SubscribeButtonComponent can be used with a single VideoChannel passed as [VideoChannel], - * or with an account and a full list of that account's videoChannels. The latter is intended - * to allow mass un/subscription from an account's page, while keeping the channel-centric - * subscription model. - */ - @Input() account: Account - @Input() videoChannels: VideoChannel[] - @Input() displayFollowers = false - @Input() size: 'small' | 'normal' = 'normal' - - subscribed = new Map() - - constructor ( - private authService: AuthService, - private router: Router, - private notifier: Notifier, - private userSubscriptionService: UserSubscriptionService, - private i18n: I18n, - private videoService: VideoService - ) { } - - get handle () { - return this.account - ? this.account.nameWithHost - : this.videoChannel.name + '@' + this.videoChannel.host - } - - get channelHandle () { - return this.getChannelHandler(this.videoChannel) - } - - get uri () { - return this.account - ? this.account.url - : this.videoChannels[0].url - } - - get rssUri () { - const rssFeed = this.account - ? this.videoService - .getAccountFeedUrls(this.account.id) - .find(i => i.format === FeedFormat.RSS) - : this.videoService - .getVideoChannelFeedUrls(this.videoChannels[0].id) - .find(i => i.format === FeedFormat.RSS) - - return rssFeed.url - } - - get videoChannel () { - return this.videoChannels[0] - } - - get isAllChannelsSubscribed () { - return this.subscribeStatus(true).length === this.videoChannels.length - } - - get isAtLeastOneChannelSubscribed () { - return this.subscribeStatus(true).length > 0 - } - - get isBigButton () { - return this.isUserLoggedIn() && this.videoChannels.length > 1 && this.isAtLeastOneChannelSubscribed - } - - ngOnInit () { - this.loadSubscribedStatus() - } - - ngOnChanges () { - this.ngOnInit() - } - - subscribe () { - if (this.isUserLoggedIn()) { - return this.localSubscribe() - } - - return this.gotoLogin() - } - - localSubscribe () { - const subscribedStatus = this.subscribeStatus(false) - - const observableBatch = this.videoChannels - .map(videoChannel => this.getChannelHandler(videoChannel)) - .filter(handle => subscribedStatus.includes(handle)) - .map(handle => this.userSubscriptionService.addSubscription(handle)) - - forkJoin(observableBatch) - .subscribe( - () => { - this.notifier.success( - this.account - ? this.i18n( - 'Subscribed to all current channels of {{nameWithHost}}. You will be notified of all their new videos.', - { nameWithHost: this.account.displayName } - ) - : this.i18n( - 'Subscribed to {{nameWithHost}}. You will be notified of all their new videos.', - { nameWithHost: this.videoChannels[0].displayName } - ) - , - this.i18n('Subscribed') - ) - }, - - err => this.notifier.error(err.message) - ) - } - - unsubscribe () { - if (this.isUserLoggedIn()) { - this.localUnsubscribe() - } - } - - localUnsubscribe () { - const subscribeStatus = this.subscribeStatus(true) - - const observableBatch = this.videoChannels - .map(videoChannel => this.getChannelHandler(videoChannel)) - .filter(handle => subscribeStatus.includes(handle)) - .map(handle => this.userSubscriptionService.deleteSubscription(handle)) - - concat(...observableBatch) - .subscribe({ - complete: () => { - this.notifier.success( - this.account - ? this.i18n('Unsubscribed from all channels of {{nameWithHost}}', { nameWithHost: this.account.nameWithHost }) - : this.i18n('Unsubscribed from {{nameWithHost}}', { nameWithHost: this.videoChannels[ 0 ].nameWithHost }) - , - this.i18n('Unsubscribed') - ) - }, - - error: err => this.notifier.error(err.message) - }) - } - - isUserLoggedIn () { - return this.authService.isLoggedIn() - } - - gotoLogin () { - this.router.navigate([ '/login' ]) - } - - subscribeStatus (subscribed: boolean) { - const accumulator: string[] = [] - for (const [key, value] of this.subscribed.entries()) { - if (value === subscribed) accumulator.push(key) - } - - return accumulator - } - - private getChannelHandler (videoChannel: VideoChannel) { - return videoChannel.name + '@' + videoChannel.host - } - - private loadSubscribedStatus () { - if (!this.isUserLoggedIn()) return - - for (const videoChannel of this.videoChannels) { - const handle = this.getChannelHandler(videoChannel) - this.subscribed.set(handle, false) - - merge( - this.userSubscriptionService.listenToSubscriptionCacheChange(handle), - this.userSubscriptionService.doesSubscriptionExist(handle) - ).subscribe( - res => this.subscribed.set(handle, res), - - err => this.notifier.error(err.message) - ) - } - } -} 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 @@ -import { bufferTime, catchError, filter, map, observeOn, share, switchMap, tap } from 'rxjs/operators' -import { asyncScheduler, merge, Observable, of, ReplaySubject, Subject } from 'rxjs' -import { HttpClient, HttpParams } from '@angular/common/http' -import { Injectable, NgZone } from '@angular/core' -import { ResultList } from '../../../../../shared' -import { environment } from '../../../environments/environment' -import { RestExtractor, RestService } from '../rest' -import { VideoChannel } from '@app/shared/video-channel/video-channel.model' -import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' -import { VideoChannel as VideoChannelServer } from '../../../../../shared/models/videos' -import { ComponentPaginationLight } from '@app/shared/rest/component-pagination.model' -import { uniq } from 'lodash-es' -import * as debug from 'debug' -import { enterZone, leaveZone } from '@app/shared/rxjs/zone' - -const logger = debug('peertube:subscriptions:UserSubscriptionService') - -type SubscriptionExistResult = { [ uri: string ]: boolean } -type SubscriptionExistResultObservable = { [ uri: string ]: Observable } - -@Injectable() -export class UserSubscriptionService { - static BASE_USER_SUBSCRIPTIONS_URL = environment.apiUrl + '/api/v1/users/me/subscriptions' - - // Use a replay subject because we "next" a value before subscribing - private existsSubject = new ReplaySubject(1) - private readonly existsObservable: Observable - - private myAccountSubscriptionCache: SubscriptionExistResult = {} - private myAccountSubscriptionCacheObservable: SubscriptionExistResultObservable = {} - private myAccountSubscriptionCacheSubject = new Subject() - - constructor ( - private authHttp: HttpClient, - private restExtractor: RestExtractor, - private restService: RestService, - private ngZone: NgZone - ) { - this.existsObservable = merge( - this.existsSubject.pipe( - // We leave Angular zone so Protractor does not get stuck - bufferTime(500, leaveZone(this.ngZone, asyncScheduler)), - filter(uris => uris.length !== 0), - map(uris => uniq(uris)), - observeOn(enterZone(this.ngZone, asyncScheduler)), - switchMap(uris => this.doSubscriptionsExist(uris)), - share() - ), - - this.myAccountSubscriptionCacheSubject - ) - } - - /** - * Subscription part - */ - - deleteSubscription (nameWithHost: string) { - const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL + '/' + nameWithHost - - return this.authHttp.delete(url) - .pipe( - map(this.restExtractor.extractDataBool), - tap(() => { - this.myAccountSubscriptionCache[nameWithHost] = false - - this.myAccountSubscriptionCacheSubject.next(this.myAccountSubscriptionCache) - }), - catchError(err => this.restExtractor.handleError(err)) - ) - } - - addSubscription (nameWithHost: string) { - const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL - - const body = { uri: nameWithHost } - return this.authHttp.post(url, body) - .pipe( - map(this.restExtractor.extractDataBool), - tap(() => { - this.myAccountSubscriptionCache[nameWithHost] = true - - this.myAccountSubscriptionCacheSubject.next(this.myAccountSubscriptionCache) - }), - catchError(err => this.restExtractor.handleError(err)) - ) - } - - listSubscriptions (componentPagination: ComponentPaginationLight): Observable> { - const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL - - const pagination = this.restService.componentPaginationToRestPagination(componentPagination) - - let params = new HttpParams() - params = this.restService.addRestGetParams(params, pagination) - - return this.authHttp.get>(url, { params }) - .pipe( - map(res => VideoChannelService.extractVideoChannels(res)), - catchError(err => this.restExtractor.handleError(err)) - ) - } - - /** - * SubscriptionExist part - */ - - listenToMyAccountSubscriptionCacheSubject () { - return this.myAccountSubscriptionCacheSubject.asObservable() - } - - listenToSubscriptionCacheChange (nameWithHost: string) { - if (nameWithHost in this.myAccountSubscriptionCacheObservable) { - return this.myAccountSubscriptionCacheObservable[ nameWithHost ] - } - - const obs = this.existsObservable - .pipe( - filter(existsResult => existsResult[ nameWithHost ] !== undefined), - map(existsResult => existsResult[ nameWithHost ]) - ) - - this.myAccountSubscriptionCacheObservable[ nameWithHost ] = obs - return obs - } - - doesSubscriptionExist (nameWithHost: string) { - logger('Running subscription check for %d.', nameWithHost) - - if (nameWithHost in this.myAccountSubscriptionCache) { - logger('Found cache for %d.', nameWithHost) - - return of(this.myAccountSubscriptionCache[ nameWithHost ]) - } - - this.existsSubject.next(nameWithHost) - - logger('Fetching from network for %d.', nameWithHost) - return this.existsObservable.pipe( - filter(existsResult => existsResult[ nameWithHost ] !== undefined), - map(existsResult => existsResult[ nameWithHost ]), - tap(result => this.myAccountSubscriptionCache[ nameWithHost ] = result) - ) - } - - private doSubscriptionsExist (uris: string[]): Observable { - const url = UserSubscriptionService.BASE_USER_SUBSCRIPTIONS_URL + '/exist' - let params = new HttpParams() - - params = this.restService.addObjectParams(params, { uris }) - - return this.authHttp.get(url, { params }) - .pipe( - tap(res => { - this.myAccountSubscriptionCache = { - ...this.myAccountSubscriptionCache, - ...res - } - }), - catchError(err => this.restExtractor.handleError(err)) - ) - } -} -- cgit v1.2.3