Begin support for external auths
[oweals/peertube.git] / client / src / app / core / server / server.service.ts
1 import { first, map, share, shareReplay, switchMap, tap } from 'rxjs/operators'
2 import { HttpClient } from '@angular/common/http'
3 import { Inject, Injectable, LOCALE_ID } from '@angular/core'
4 import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage'
5 import { Observable, of, Subject } from 'rxjs'
6 import { getCompleteLocale, ServerConfig } from '../../../../../shared'
7 import { environment } from '../../../environments/environment'
8 import { VideoConstant } from '../../../../../shared/models/videos'
9 import { isDefaultLocale, peertubeTranslate } from '../../../../../shared/models/i18n'
10 import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
11 import { sortBy } from '@app/shared/misc/utils'
12 import { ServerStats } from '@shared/models/server'
13
14 @Injectable()
15 export class ServerService {
16   private static BASE_CONFIG_URL = environment.apiUrl + '/api/v1/config/'
17   private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/'
18   private static BASE_VIDEO_PLAYLIST_URL = environment.apiUrl + '/api/v1/video-playlists/'
19   private static BASE_LOCALE_URL = environment.apiUrl + '/client/locales/'
20   private static BASE_STATS_URL = environment.apiUrl + '/api/v1/server/stats'
21
22   private static CONFIG_LOCAL_STORAGE_KEY = 'server-config'
23
24   configReloaded = new Subject<void>()
25
26   private localeObservable: Observable<any>
27   private videoLicensesObservable: Observable<VideoConstant<number>[]>
28   private videoCategoriesObservable: Observable<VideoConstant<number>[]>
29   private videoPrivaciesObservable: Observable<VideoConstant<number>[]>
30   private videoPlaylistPrivaciesObservable: Observable<VideoConstant<number>[]>
31   private videoLanguagesObservable: Observable<VideoConstant<string>[]>
32   private configObservable: Observable<ServerConfig>
33
34   private configReset = false
35
36   private configLoaded = false
37   private config: ServerConfig = {
38     instance: {
39       name: 'PeerTube',
40       shortDescription: 'PeerTube, a federated (ActivityPub) video streaming platform  ' +
41                         'using P2P (BitTorrent) directly in the web browser with WebTorrent and Angular.',
42       defaultClientRoute: '',
43       isNSFW: false,
44       defaultNSFWPolicy: 'do_not_list' as 'do_not_list',
45       customizations: {
46         javascript: '',
47         css: ''
48       }
49     },
50     search: {
51       remoteUri: {
52         users: true,
53         anonymous: false
54       }
55     },
56     plugin: {
57       registered: [],
58       registeredExternalAuths: [],
59       registeredIdAndPassAuths: []
60     },
61     theme: {
62       registered: [],
63       default: 'default'
64     },
65     email: {
66       enabled: false
67     },
68     contactForm: {
69       enabled: false
70     },
71     serverVersion: 'Unknown',
72     signup: {
73       allowed: false,
74       allowedForCurrentIP: false,
75       requiresEmailVerification: false
76     },
77     transcoding: {
78       enabledResolutions: [],
79       hls: {
80         enabled: false
81       },
82       webtorrent: {
83         enabled: true
84       }
85     },
86     avatar: {
87       file: {
88         size: { max: 0 },
89         extensions: []
90       }
91     },
92     video: {
93       image: {
94         size: { max: 0 },
95         extensions: []
96       },
97       file: {
98         extensions: []
99       }
100     },
101     videoCaption: {
102       file: {
103         size: { max: 0 },
104         extensions: []
105       }
106     },
107     user: {
108       videoQuota: -1,
109       videoQuotaDaily: -1
110     },
111     import: {
112       videos: {
113         http: {
114           enabled: false
115         },
116         torrent: {
117           enabled: false
118         }
119       }
120     },
121     trending: {
122       videos: {
123         intervalDays: 0
124       }
125     },
126     autoBlacklist: {
127       videos: {
128         ofUsers: {
129           enabled: false
130         }
131       }
132     },
133     tracker: {
134       enabled: true
135     },
136     followings: {
137       instance: {
138         autoFollowIndex: {
139           indexUrl: 'https://instances.joinpeertube.org'
140         }
141       }
142     }
143   }
144
145   constructor (
146     private http: HttpClient,
147     @Inject(LOCALE_ID) private localeId: string
148   ) {
149     this.loadConfigLocally()
150   }
151
152   getServerVersionAndCommit () {
153     const serverVersion = this.config.serverVersion
154     const commit = this.config.serverCommit || ''
155
156     let result = serverVersion
157     if (commit) result += '...' + commit
158
159     return result
160   }
161
162   resetConfig () {
163     this.configLoaded = false
164     this.configReset = true
165   }
166
167   getConfig () {
168     if (this.configLoaded) return of(this.config)
169
170     if (!this.configObservable) {
171       this.configObservable = this.http.get<ServerConfig>(ServerService.BASE_CONFIG_URL)
172                                   .pipe(
173                                     tap(config => this.saveConfigLocally(config)),
174                                     tap(config => {
175                                       this.config = config
176                                       this.configLoaded = true
177                                     }),
178                                     tap(() => {
179                                       if (this.configReset) {
180                                         this.configReloaded.next()
181                                         this.configReset = false
182                                       }
183                                     }),
184                                     share()
185                                   )
186     }
187
188     return this.configObservable
189   }
190
191   getTmpConfig () {
192     return this.config
193   }
194
195   getVideoCategories () {
196     if (!this.videoCategoriesObservable) {
197       this.videoCategoriesObservable = this.loadAttributeEnum<number>(ServerService.BASE_VIDEO_URL, 'categories', true)
198     }
199
200     return this.videoCategoriesObservable.pipe(first())
201   }
202
203   getVideoLicences () {
204     if (!this.videoLicensesObservable) {
205       this.videoLicensesObservable = this.loadAttributeEnum<number>(ServerService.BASE_VIDEO_URL, 'licences')
206     }
207
208     return this.videoLicensesObservable.pipe(first())
209   }
210
211   getVideoLanguages () {
212     if (!this.videoLanguagesObservable) {
213       this.videoLanguagesObservable = this.loadAttributeEnum<string>(ServerService.BASE_VIDEO_URL, 'languages', true)
214     }
215
216     return this.videoLanguagesObservable.pipe(first())
217   }
218
219   getVideoPrivacies () {
220     if (!this.videoPrivaciesObservable) {
221       this.videoPrivaciesObservable = this.loadAttributeEnum<number>(ServerService.BASE_VIDEO_URL, 'privacies')
222     }
223
224     return this.videoPrivaciesObservable.pipe(first())
225   }
226
227   getVideoPlaylistPrivacies () {
228     if (!this.videoPlaylistPrivaciesObservable) {
229       this.videoPlaylistPrivaciesObservable = this.loadAttributeEnum<number>(ServerService.BASE_VIDEO_PLAYLIST_URL, 'privacies')
230     }
231
232     return this.videoPlaylistPrivaciesObservable.pipe(first())
233   }
234
235   getServerLocale () {
236     if (!this.localeObservable) {
237       const completeLocale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId)
238
239       // Default locale, nothing to translate
240       if (isDefaultLocale(completeLocale)) {
241         this.localeObservable = of({}).pipe(shareReplay())
242       } else {
243         this.localeObservable = this.http
244                                     .get(ServerService.BASE_LOCALE_URL + completeLocale + '/server.json')
245                                     .pipe(shareReplay())
246       }
247     }
248
249     return this.localeObservable.pipe(first())
250   }
251
252   getServerStats () {
253     return this.http.get<ServerStats>(ServerService.BASE_STATS_URL)
254   }
255
256   private loadAttributeEnum <T extends string | number> (
257     baseUrl: string,
258     attributeName: 'categories' | 'licences' | 'languages' | 'privacies',
259     sort = false
260   ) {
261     return this.getServerLocale()
262                .pipe(
263                  switchMap(translations => {
264                    return this.http.get<{ [ id: string ]: string }>(baseUrl + attributeName)
265                               .pipe(map(data => ({ data, translations })))
266                  }),
267                  map(({ data, translations }) => {
268                    const hashToPopulate: VideoConstant<T>[] = Object.keys(data)
269                                                                     .map(dataKey => {
270                                                                       const label = data[ dataKey ]
271
272                                                                       const id = attributeName === 'languages'
273                                                                         ? dataKey as T
274                                                                         : parseInt(dataKey, 10) as T
275
276                                                                       return {
277                                                                         id,
278                                                                         label: peertubeTranslate(label, translations)
279                                                                       }
280                                                                     })
281
282                    if (sort === true) sortBy(hashToPopulate, 'label')
283
284                    return hashToPopulate
285                  }),
286                  shareReplay()
287                )
288   }
289
290   private saveConfigLocally (config: ServerConfig) {
291     peertubeLocalStorage.setItem(ServerService.CONFIG_LOCAL_STORAGE_KEY, JSON.stringify(config))
292   }
293
294   private loadConfigLocally () {
295     const configString = peertubeLocalStorage.getItem(ServerService.CONFIG_LOCAL_STORAGE_KEY)
296
297     if (configString) {
298       try {
299         const parsed = JSON.parse(configString)
300         Object.assign(this.config, parsed)
301       } catch (err) {
302         console.error('Cannot parse config saved in local storage.', err)
303       }
304     }
305   }
306 }