]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - client/src/app/shared/shared-video-comment/video-comment.service.ts
Refactor video views
[github/Chocobozzz/PeerTube.git] / client / src / app / shared / shared-video-comment / video-comment.service.ts
... / ...
CommitLineData
1import { SortMeta } from 'primeng/api'
2import { from, Observable } from 'rxjs'
3import { catchError, concatMap, map, toArray } from 'rxjs/operators'
4import { HttpClient, HttpParams } from '@angular/common/http'
5import { Injectable } from '@angular/core'
6import { ComponentPaginationLight, RestExtractor, RestPagination, RestService } from '@app/core'
7import { objectLineFeedToHtml } from '@app/helpers'
8import {
9 FeedFormat,
10 ResultList,
11 ThreadsResultList,
12 Video,
13 VideoComment as VideoCommentServerModel,
14 VideoCommentAdmin,
15 VideoCommentCreate,
16 VideoCommentThreadTree as VideoCommentThreadTreeServerModel
17} from '@shared/models'
18import { environment } from '../../../environments/environment'
19import { VideoCommentThreadTree } from './video-comment-thread-tree.model'
20import { VideoComment } from './video-comment.model'
21
22@Injectable()
23export class VideoCommentService {
24 static BASE_FEEDS_URL = environment.apiUrl + '/feeds/video-comments.'
25
26 private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/'
27
28 constructor (
29 private authHttp: HttpClient,
30 private restExtractor: RestExtractor,
31 private restService: RestService
32 ) {}
33
34 addCommentThread (videoId: number | string, comment: VideoCommentCreate) {
35 const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comment-threads'
36 const normalizedComment = objectLineFeedToHtml(comment, 'text')
37
38 return this.authHttp.post<{ comment: VideoCommentServerModel }>(url, normalizedComment)
39 .pipe(
40 map(data => this.extractVideoComment(data.comment)),
41 catchError(err => this.restExtractor.handleError(err))
42 )
43 }
44
45 addCommentReply (videoId: number | string, inReplyToCommentId: number, comment: VideoCommentCreate) {
46 const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comments/' + inReplyToCommentId
47 const normalizedComment = objectLineFeedToHtml(comment, 'text')
48
49 return this.authHttp.post<{ comment: VideoCommentServerModel }>(url, normalizedComment)
50 .pipe(
51 map(data => this.extractVideoComment(data.comment)),
52 catchError(err => this.restExtractor.handleError(err))
53 )
54 }
55
56 getAdminVideoComments (options: {
57 pagination: RestPagination
58 sort: SortMeta
59 search?: string
60 }): Observable<ResultList<VideoCommentAdmin>> {
61 const { pagination, sort, search } = options
62 const url = VideoCommentService.BASE_VIDEO_URL + 'comments'
63
64 let params = new HttpParams()
65 params = this.restService.addRestGetParams(params, pagination, sort)
66
67 if (search) {
68 params = this.buildParamsFromSearch(search, params)
69 }
70
71 return this.authHttp.get<ResultList<VideoCommentAdmin>>(url, { params })
72 .pipe(
73 catchError(res => this.restExtractor.handleError(res))
74 )
75 }
76
77 getVideoCommentThreads (parameters: {
78 videoId: number | string
79 componentPagination: ComponentPaginationLight
80 sort: string
81 }): Observable<ThreadsResultList<VideoComment>> {
82 const { videoId, componentPagination, sort } = parameters
83
84 const pagination = this.restService.componentToRestPagination(componentPagination)
85
86 let params = new HttpParams()
87 params = this.restService.addRestGetParams(params, pagination, sort)
88
89 const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comment-threads'
90 return this.authHttp.get<ThreadsResultList<VideoComment>>(url, { params })
91 .pipe(
92 map(result => this.extractVideoComments(result)),
93 catchError(err => this.restExtractor.handleError(err))
94 )
95 }
96
97 getVideoThreadComments (parameters: {
98 videoId: number | string
99 threadId: number
100 }): Observable<VideoCommentThreadTree> {
101 const { videoId, threadId } = parameters
102 const url = `${VideoCommentService.BASE_VIDEO_URL + videoId}/comment-threads/${threadId}`
103
104 return this.authHttp
105 .get<VideoCommentThreadTreeServerModel>(url)
106 .pipe(
107 map(tree => this.extractVideoCommentTree(tree)),
108 catchError(err => this.restExtractor.handleError(err))
109 )
110 }
111
112 deleteVideoComment (videoId: number | string, commentId: number) {
113 const url = `${VideoCommentService.BASE_VIDEO_URL + videoId}/comments/${commentId}`
114
115 return this.authHttp
116 .delete(url)
117 .pipe(
118 map(this.restExtractor.extractDataBool),
119 catchError(err => this.restExtractor.handleError(err))
120 )
121 }
122
123 deleteVideoComments (comments: { videoId: number | string, commentId: number }[]) {
124 return from(comments)
125 .pipe(
126 concatMap(c => this.deleteVideoComment(c.videoId, c.commentId)),
127 toArray()
128 )
129 }
130
131 getVideoCommentsFeeds (video: Pick<Video, 'uuid'>) {
132 const feeds = [
133 {
134 format: FeedFormat.RSS,
135 label: 'rss 2.0',
136 url: VideoCommentService.BASE_FEEDS_URL + FeedFormat.RSS.toLowerCase()
137 },
138 {
139 format: FeedFormat.ATOM,
140 label: 'atom 1.0',
141 url: VideoCommentService.BASE_FEEDS_URL + FeedFormat.ATOM.toLowerCase()
142 },
143 {
144 format: FeedFormat.JSON,
145 label: 'json 1.0',
146 url: VideoCommentService.BASE_FEEDS_URL + FeedFormat.JSON.toLowerCase()
147 }
148 ]
149
150 if (video !== undefined) {
151 for (const feed of feeds) {
152 feed.url += '?videoId=' + video.uuid
153 }
154 }
155
156 return feeds
157 }
158
159 private extractVideoComment (videoComment: VideoCommentServerModel) {
160 return new VideoComment(videoComment)
161 }
162
163 private extractVideoComments (result: ThreadsResultList<VideoCommentServerModel>) {
164 const videoCommentsJson = result.data
165 const totalComments = result.total
166 const comments: VideoComment[] = []
167
168 for (const videoCommentJson of videoCommentsJson) {
169 comments.push(new VideoComment(videoCommentJson))
170 }
171
172 return { data: comments, total: totalComments, totalNotDeletedComments: result.totalNotDeletedComments }
173 }
174
175 private extractVideoCommentTree (serverTree: VideoCommentThreadTreeServerModel): VideoCommentThreadTree {
176 if (!serverTree) return null
177
178 const tree = {
179 comment: new VideoComment(serverTree.comment),
180 children: serverTree.children.map(c => this.extractVideoCommentTree(c))
181 }
182
183 const hasDisplayedChildren = tree.children.length === 0
184 ? !tree.comment.isDeleted
185 : tree.children.some(c => c.hasDisplayedChildren)
186
187 return Object.assign(tree, { hasDisplayedChildren })
188 }
189
190 private buildParamsFromSearch (search: string, params: HttpParams) {
191 const filters = this.restService.parseQueryStringFilter(search, {
192 isLocal: {
193 prefix: 'local:',
194 isBoolean: true
195 },
196
197 searchAccount: { prefix: 'account:' },
198 searchVideo: { prefix: 'video:' }
199 })
200
201 return this.restService.addObjectParams(params, filters)
202 }
203}