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