]>
Commit | Line | Data |
---|---|---|
1 | import * as Sequelize from 'sequelize' | |
2 | import { | |
3 | AfterDestroy, AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, IFindOptions, Is, Model, Scopes, Table, | |
4 | UpdatedAt | |
5 | } from 'sequelize-typescript' | |
6 | import { VideoComment } from '../../../shared/models/videos/video-comment.model' | |
7 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub' | |
8 | import { CONSTRAINTS_FIELDS } from '../../initializers' | |
9 | import { AccountModel } from '../account/account' | |
10 | import { getSort, throwIfNotValid } from '../utils' | |
11 | import { VideoModel } from './video' | |
12 | ||
13 | enum ScopeNames { | |
14 | WITH_ACCOUNT = 'WITH_ACCOUNT' | |
15 | } | |
16 | ||
17 | @Scopes({ | |
18 | [ScopeNames.WITH_ACCOUNT]: { | |
19 | include: [ | |
20 | () => AccountModel | |
21 | ] | |
22 | } | |
23 | }) | |
24 | @Table({ | |
25 | tableName: 'videoComment', | |
26 | indexes: [ | |
27 | { | |
28 | fields: [ 'videoId' ] | |
29 | }, | |
30 | { | |
31 | fields: [ 'videoId', 'originCommentId' ] | |
32 | } | |
33 | ] | |
34 | }) | |
35 | export class VideoCommentModel extends Model<VideoCommentModel> { | |
36 | @CreatedAt | |
37 | createdAt: Date | |
38 | ||
39 | @UpdatedAt | |
40 | updatedAt: Date | |
41 | ||
42 | @AllowNull(false) | |
43 | @Is('VideoCommentUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url')) | |
44 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.URL.max)) | |
45 | url: string | |
46 | ||
47 | @AllowNull(false) | |
48 | @Column(DataType.TEXT) | |
49 | text: string | |
50 | ||
51 | @ForeignKey(() => VideoCommentModel) | |
52 | @Column | |
53 | originCommentId: number | |
54 | ||
55 | @BelongsTo(() => VideoCommentModel, { | |
56 | foreignKey: { | |
57 | allowNull: true | |
58 | }, | |
59 | onDelete: 'CASCADE' | |
60 | }) | |
61 | OriginVideoComment: VideoCommentModel | |
62 | ||
63 | @ForeignKey(() => VideoCommentModel) | |
64 | @Column | |
65 | inReplyToCommentId: number | |
66 | ||
67 | @BelongsTo(() => VideoCommentModel, { | |
68 | foreignKey: { | |
69 | allowNull: true | |
70 | }, | |
71 | onDelete: 'CASCADE' | |
72 | }) | |
73 | InReplyToVideoComment: VideoCommentModel | |
74 | ||
75 | @ForeignKey(() => VideoModel) | |
76 | @Column | |
77 | videoId: number | |
78 | ||
79 | @BelongsTo(() => VideoModel, { | |
80 | foreignKey: { | |
81 | allowNull: false | |
82 | }, | |
83 | onDelete: 'CASCADE' | |
84 | }) | |
85 | Video: VideoModel | |
86 | ||
87 | @ForeignKey(() => AccountModel) | |
88 | @Column | |
89 | accountId: number | |
90 | ||
91 | @BelongsTo(() => AccountModel, { | |
92 | foreignKey: { | |
93 | allowNull: false | |
94 | }, | |
95 | onDelete: 'CASCADE' | |
96 | }) | |
97 | Account: AccountModel | |
98 | ||
99 | @AfterDestroy | |
100 | static sendDeleteIfOwned (instance: VideoCommentModel) { | |
101 | // TODO | |
102 | return undefined | |
103 | } | |
104 | ||
105 | static loadById (id: number, t?: Sequelize.Transaction) { | |
106 | const query: IFindOptions<VideoCommentModel> = { | |
107 | where: { | |
108 | id | |
109 | } | |
110 | } | |
111 | ||
112 | if (t !== undefined) query.transaction = t | |
113 | ||
114 | return VideoCommentModel.findOne(query) | |
115 | } | |
116 | ||
117 | static loadByUrl (url: string, t?: Sequelize.Transaction) { | |
118 | const query: IFindOptions<VideoCommentModel> = { | |
119 | where: { | |
120 | url | |
121 | } | |
122 | } | |
123 | ||
124 | if (t !== undefined) query.transaction = t | |
125 | ||
126 | return VideoCommentModel.findOne(query) | |
127 | } | |
128 | ||
129 | static listThreadsForApi (videoId: number, start: number, count: number, sort: string) { | |
130 | const query = { | |
131 | offset: start, | |
132 | limit: count, | |
133 | order: [ getSort(sort) ], | |
134 | where: { | |
135 | videoId, | |
136 | inReplyToCommentId: null | |
137 | } | |
138 | } | |
139 | ||
140 | return VideoCommentModel | |
141 | .scope([ ScopeNames.WITH_ACCOUNT ]) | |
142 | .findAndCountAll(query) | |
143 | .then(({ rows, count }) => { | |
144 | return { total: count, data: rows } | |
145 | }) | |
146 | } | |
147 | ||
148 | static listThreadCommentsForApi (videoId: number, threadId: number) { | |
149 | const query = { | |
150 | order: [ [ 'id', 'ASC' ] ], | |
151 | where: { | |
152 | videoId, | |
153 | [ Sequelize.Op.or ]: [ | |
154 | { id: threadId }, | |
155 | { originCommentId: threadId } | |
156 | ] | |
157 | } | |
158 | } | |
159 | ||
160 | return VideoCommentModel | |
161 | .scope([ ScopeNames.WITH_ACCOUNT ]) | |
162 | .findAndCountAll(query) | |
163 | .then(({ rows, count }) => { | |
164 | return { total: count, data: rows } | |
165 | }) | |
166 | } | |
167 | ||
168 | toFormattedJSON () { | |
169 | return { | |
170 | id: this.id, | |
171 | url: this.url, | |
172 | text: this.text, | |
173 | threadId: this.originCommentId || this.id, | |
174 | inReplyToCommentId: this.inReplyToCommentId, | |
175 | videoId: this.videoId, | |
176 | createdAt: this.createdAt, | |
177 | updatedAt: this.updatedAt, | |
178 | account: { | |
179 | name: this.Account.name | |
180 | } | |
181 | } as VideoComment | |
182 | } | |
183 | } |