Reorganize client shared modules
[oweals/peertube.git] / client / src / app / videos / +video-watch / comment / video-comment.service.ts
1 import { Observable } from 'rxjs'
2 import { catchError, map } from 'rxjs/operators'
3 import { HttpClient, HttpParams } from '@angular/common/http'
4 import { Injectable } from '@angular/core'
5 import { ComponentPaginationLight, RestExtractor, RestService } from '@app/core'
6 import { objectLineFeedToHtml } from '@app/helpers'
7 import {
8   FeedFormat,
9   ResultList,
10   VideoComment as VideoCommentServerModel,
11   VideoCommentCreate,
12   VideoCommentThreadTree as VideoCommentThreadTreeServerModel
13 } from '@shared/models'
14 import { environment } from '../../../../environments/environment'
15 import { VideoCommentThreadTree } from './video-comment-thread-tree.model'
16 import { VideoComment } from './video-comment.model'
17
18 @Injectable()
19 export class VideoCommentService {
20   private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/'
21   private static BASE_FEEDS_URL = environment.apiUrl + '/feeds/video-comments.'
22
23   constructor (
24     private authHttp: HttpClient,
25     private restExtractor: RestExtractor,
26     private restService: RestService
27   ) {}
28
29   addCommentThread (videoId: number | string, comment: VideoCommentCreate) {
30     const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comment-threads'
31     const normalizedComment = objectLineFeedToHtml(comment, 'text')
32
33     return this.authHttp.post<{ comment: VideoCommentServerModel }>(url, normalizedComment)
34                .pipe(
35                   map(data => this.extractVideoComment(data.comment)),
36                   catchError(err => this.restExtractor.handleError(err))
37                )
38   }
39
40   addCommentReply (videoId: number | string, inReplyToCommentId: number, comment: VideoCommentCreate) {
41     const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comments/' + inReplyToCommentId
42     const normalizedComment = objectLineFeedToHtml(comment, 'text')
43
44     return this.authHttp.post<{ comment: VideoCommentServerModel }>(url, normalizedComment)
45                .pipe(
46                  map(data => this.extractVideoComment(data.comment)),
47                  catchError(err => this.restExtractor.handleError(err))
48                )
49   }
50
51   getVideoCommentThreads (parameters: {
52     videoId: number | string,
53     componentPagination: ComponentPaginationLight,
54     sort: string
55   }): Observable<ResultList<VideoComment>> {
56     const { videoId, componentPagination, sort } = parameters
57
58     const pagination = this.restService.componentPaginationToRestPagination(componentPagination)
59
60     let params = new HttpParams()
61     params = this.restService.addRestGetParams(params, pagination, sort)
62
63     const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comment-threads'
64     return this.authHttp.get<ResultList<VideoComment>>(url, { params })
65                .pipe(
66                  map(result => this.extractVideoComments(result)),
67                  catchError(err => this.restExtractor.handleError(err))
68                )
69   }
70
71   getVideoThreadComments (parameters: {
72     videoId: number | string,
73     threadId: number
74   }): Observable<VideoCommentThreadTree> {
75     const { videoId, threadId } = parameters
76     const url = `${VideoCommentService.BASE_VIDEO_URL + videoId}/comment-threads/${threadId}`
77
78     return this.authHttp
79                .get<VideoCommentThreadTreeServerModel>(url)
80                .pipe(
81                  map(tree => this.extractVideoCommentTree(tree)),
82                  catchError(err => this.restExtractor.handleError(err))
83                )
84   }
85
86   deleteVideoComment (videoId: number | string, commentId: number) {
87     const url = `${VideoCommentService.BASE_VIDEO_URL + videoId}/comments/${commentId}`
88
89     return this.authHttp
90                .delete(url)
91                .pipe(
92                  map(this.restExtractor.extractDataBool),
93                  catchError(err => this.restExtractor.handleError(err))
94                )
95   }
96
97   getVideoCommentsFeeds (videoUUID?: string) {
98     const feeds = [
99       {
100         format: FeedFormat.RSS,
101         label: 'rss 2.0',
102         url: VideoCommentService.BASE_FEEDS_URL + FeedFormat.RSS.toLowerCase()
103       },
104       {
105         format: FeedFormat.ATOM,
106         label: 'atom 1.0',
107         url: VideoCommentService.BASE_FEEDS_URL + FeedFormat.ATOM.toLowerCase()
108       },
109       {
110         format: FeedFormat.JSON,
111         label: 'json 1.0',
112         url: VideoCommentService.BASE_FEEDS_URL + FeedFormat.JSON.toLowerCase()
113       }
114     ]
115
116     if (videoUUID !== undefined) {
117       for (const feed of feeds) {
118         feed.url += '?videoId=' + videoUUID
119       }
120     }
121
122     return feeds
123   }
124
125   private extractVideoComment (videoComment: VideoCommentServerModel) {
126     return new VideoComment(videoComment)
127   }
128
129   private extractVideoComments (result: ResultList<VideoCommentServerModel>) {
130     const videoCommentsJson = result.data
131     const totalComments = result.total
132     const comments: VideoComment[] = []
133
134     for (const videoCommentJson of videoCommentsJson) {
135       comments.push(new VideoComment(videoCommentJson))
136     }
137
138     return { data: comments, total: totalComments }
139   }
140
141   private extractVideoCommentTree (tree: VideoCommentThreadTreeServerModel) {
142     if (!tree) return tree as VideoCommentThreadTree
143
144     tree.comment = new VideoComment(tree.comment)
145     tree.children.forEach(c => this.extractVideoCommentTree(c))
146
147     return tree as VideoCommentThreadTree
148   }
149 }