diff options
Diffstat (limited to 'server/models')
-rw-r--r-- | server/models/account/user-notification-setting.ts | 100 | ||||
-rw-r--r-- | server/models/account/user-notification.ts | 256 | ||||
-rw-r--r-- | server/models/account/user.ts | 101 | ||||
-rw-r--r-- | server/models/activitypub/actor-follow.ts | 14 | ||||
-rw-r--r-- | server/models/activitypub/actor.ts | 1 | ||||
-rw-r--r-- | server/models/video/video-abuse.ts | 5 | ||||
-rw-r--r-- | server/models/video/video-blacklist.ts | 10 | ||||
-rw-r--r-- | server/models/video/video-comment.ts | 4 | ||||
-rw-r--r-- | server/models/video/video.ts | 4 |
9 files changed, 466 insertions, 29 deletions
diff --git a/server/models/account/user-notification-setting.ts b/server/models/account/user-notification-setting.ts new file mode 100644 index 000000000..bc24b1e33 --- /dev/null +++ b/server/models/account/user-notification-setting.ts | |||
@@ -0,0 +1,100 @@ | |||
1 | import { | ||
2 | AfterDestroy, | ||
3 | AfterUpdate, | ||
4 | AllowNull, | ||
5 | BelongsTo, | ||
6 | Column, | ||
7 | CreatedAt, | ||
8 | Default, | ||
9 | ForeignKey, | ||
10 | Is, | ||
11 | Model, | ||
12 | Table, | ||
13 | UpdatedAt | ||
14 | } from 'sequelize-typescript' | ||
15 | import { throwIfNotValid } from '../utils' | ||
16 | import { UserModel } from './user' | ||
17 | import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications' | ||
18 | import { UserNotificationSetting, UserNotificationSettingValue } from '../../../shared/models/users/user-notification-setting.model' | ||
19 | import { clearCacheByUserId } from '../../lib/oauth-model' | ||
20 | |||
21 | @Table({ | ||
22 | tableName: 'userNotificationSetting', | ||
23 | indexes: [ | ||
24 | { | ||
25 | fields: [ 'userId' ], | ||
26 | unique: true | ||
27 | } | ||
28 | ] | ||
29 | }) | ||
30 | export class UserNotificationSettingModel extends Model<UserNotificationSettingModel> { | ||
31 | |||
32 | @AllowNull(false) | ||
33 | @Default(null) | ||
34 | @Is( | ||
35 | 'UserNotificationSettingNewVideoFromSubscription', | ||
36 | value => throwIfNotValid(value, isUserNotificationSettingValid, 'newVideoFromSubscription') | ||
37 | ) | ||
38 | @Column | ||
39 | newVideoFromSubscription: UserNotificationSettingValue | ||
40 | |||
41 | @AllowNull(false) | ||
42 | @Default(null) | ||
43 | @Is( | ||
44 | 'UserNotificationSettingNewCommentOnMyVideo', | ||
45 | value => throwIfNotValid(value, isUserNotificationSettingValid, 'newCommentOnMyVideo') | ||
46 | ) | ||
47 | @Column | ||
48 | newCommentOnMyVideo: UserNotificationSettingValue | ||
49 | |||
50 | @AllowNull(false) | ||
51 | @Default(null) | ||
52 | @Is( | ||
53 | 'UserNotificationSettingVideoAbuseAsModerator', | ||
54 | value => throwIfNotValid(value, isUserNotificationSettingValid, 'videoAbuseAsModerator') | ||
55 | ) | ||
56 | @Column | ||
57 | videoAbuseAsModerator: UserNotificationSettingValue | ||
58 | |||
59 | @AllowNull(false) | ||
60 | @Default(null) | ||
61 | @Is( | ||
62 | 'UserNotificationSettingBlacklistOnMyVideo', | ||
63 | value => throwIfNotValid(value, isUserNotificationSettingValid, 'blacklistOnMyVideo') | ||
64 | ) | ||
65 | @Column | ||
66 | blacklistOnMyVideo: UserNotificationSettingValue | ||
67 | |||
68 | @ForeignKey(() => UserModel) | ||
69 | @Column | ||
70 | userId: number | ||
71 | |||
72 | @BelongsTo(() => UserModel, { | ||
73 | foreignKey: { | ||
74 | allowNull: false | ||
75 | }, | ||
76 | onDelete: 'cascade' | ||
77 | }) | ||
78 | User: UserModel | ||
79 | |||
80 | @CreatedAt | ||
81 | createdAt: Date | ||
82 | |||
83 | @UpdatedAt | ||
84 | updatedAt: Date | ||
85 | |||
86 | @AfterUpdate | ||
87 | @AfterDestroy | ||
88 | static removeTokenCache (instance: UserNotificationSettingModel) { | ||
89 | return clearCacheByUserId(instance.userId) | ||
90 | } | ||
91 | |||
92 | toFormattedJSON (): UserNotificationSetting { | ||
93 | return { | ||
94 | newCommentOnMyVideo: this.newCommentOnMyVideo, | ||
95 | newVideoFromSubscription: this.newVideoFromSubscription, | ||
96 | videoAbuseAsModerator: this.videoAbuseAsModerator, | ||
97 | blacklistOnMyVideo: this.blacklistOnMyVideo | ||
98 | } | ||
99 | } | ||
100 | } | ||
diff --git a/server/models/account/user-notification.ts b/server/models/account/user-notification.ts new file mode 100644 index 000000000..e22f0d57f --- /dev/null +++ b/server/models/account/user-notification.ts | |||
@@ -0,0 +1,256 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' | ||
2 | import { UserNotification, UserNotificationType } from '../../../shared' | ||
3 | import { getSort, throwIfNotValid } from '../utils' | ||
4 | import { isBooleanValid } from '../../helpers/custom-validators/misc' | ||
5 | import { isUserNotificationTypeValid } from '../../helpers/custom-validators/user-notifications' | ||
6 | import { UserModel } from './user' | ||
7 | import { VideoModel } from '../video/video' | ||
8 | import { VideoCommentModel } from '../video/video-comment' | ||
9 | import { Op } from 'sequelize' | ||
10 | import { VideoChannelModel } from '../video/video-channel' | ||
11 | import { AccountModel } from './account' | ||
12 | import { VideoAbuseModel } from '../video/video-abuse' | ||
13 | import { VideoBlacklistModel } from '../video/video-blacklist' | ||
14 | |||
15 | enum ScopeNames { | ||
16 | WITH_ALL = 'WITH_ALL' | ||
17 | } | ||
18 | |||
19 | @Scopes({ | ||
20 | [ScopeNames.WITH_ALL]: { | ||
21 | include: [ | ||
22 | { | ||
23 | attributes: [ 'id', 'uuid', 'name' ], | ||
24 | model: () => VideoModel.unscoped(), | ||
25 | required: false, | ||
26 | include: [ | ||
27 | { | ||
28 | required: true, | ||
29 | attributes: [ 'id', 'name' ], | ||
30 | model: () => VideoChannelModel.unscoped() | ||
31 | } | ||
32 | ] | ||
33 | }, | ||
34 | { | ||
35 | attributes: [ 'id' ], | ||
36 | model: () => VideoCommentModel.unscoped(), | ||
37 | required: false, | ||
38 | include: [ | ||
39 | { | ||
40 | required: true, | ||
41 | attributes: [ 'id', 'name' ], | ||
42 | model: () => AccountModel.unscoped() | ||
43 | }, | ||
44 | { | ||
45 | required: true, | ||
46 | attributes: [ 'id', 'uuid', 'name' ], | ||
47 | model: () => VideoModel.unscoped() | ||
48 | } | ||
49 | ] | ||
50 | }, | ||
51 | { | ||
52 | attributes: [ 'id' ], | ||
53 | model: () => VideoAbuseModel.unscoped(), | ||
54 | required: false, | ||
55 | include: [ | ||
56 | { | ||
57 | required: true, | ||
58 | attributes: [ 'id', 'uuid', 'name' ], | ||
59 | model: () => VideoModel.unscoped() | ||
60 | } | ||
61 | ] | ||
62 | }, | ||
63 | { | ||
64 | attributes: [ 'id' ], | ||
65 | model: () => VideoBlacklistModel.unscoped(), | ||
66 | required: false, | ||
67 | include: [ | ||
68 | { | ||
69 | required: true, | ||
70 | attributes: [ 'id', 'uuid', 'name' ], | ||
71 | model: () => VideoModel.unscoped() | ||
72 | } | ||
73 | ] | ||
74 | } | ||
75 | ] | ||
76 | } | ||
77 | }) | ||
78 | @Table({ | ||
79 | tableName: 'userNotification', | ||
80 | indexes: [ | ||
81 | { | ||
82 | fields: [ 'videoId' ] | ||
83 | }, | ||
84 | { | ||
85 | fields: [ 'commentId' ] | ||
86 | } | ||
87 | ] | ||
88 | }) | ||
89 | export class UserNotificationModel extends Model<UserNotificationModel> { | ||
90 | |||
91 | @AllowNull(false) | ||
92 | @Default(null) | ||
93 | @Is('UserNotificationType', value => throwIfNotValid(value, isUserNotificationTypeValid, 'type')) | ||
94 | @Column | ||
95 | type: UserNotificationType | ||
96 | |||
97 | @AllowNull(false) | ||
98 | @Default(false) | ||
99 | @Is('UserNotificationRead', value => throwIfNotValid(value, isBooleanValid, 'read')) | ||
100 | @Column | ||
101 | read: boolean | ||
102 | |||
103 | @CreatedAt | ||
104 | createdAt: Date | ||
105 | |||
106 | @UpdatedAt | ||
107 | updatedAt: Date | ||
108 | |||
109 | @ForeignKey(() => UserModel) | ||
110 | @Column | ||
111 | userId: number | ||
112 | |||
113 | @BelongsTo(() => UserModel, { | ||
114 | foreignKey: { | ||
115 | allowNull: false | ||
116 | }, | ||
117 | onDelete: 'cascade' | ||
118 | }) | ||
119 | User: UserModel | ||
120 | |||
121 | @ForeignKey(() => VideoModel) | ||
122 | @Column | ||
123 | videoId: number | ||
124 | |||
125 | @BelongsTo(() => VideoModel, { | ||
126 | foreignKey: { | ||
127 | allowNull: true | ||
128 | }, | ||
129 | onDelete: 'cascade' | ||
130 | }) | ||
131 | Video: VideoModel | ||
132 | |||
133 | @ForeignKey(() => VideoCommentModel) | ||
134 | @Column | ||
135 | commentId: number | ||
136 | |||
137 | @BelongsTo(() => VideoCommentModel, { | ||
138 | foreignKey: { | ||
139 | allowNull: true | ||
140 | }, | ||
141 | onDelete: 'cascade' | ||
142 | }) | ||
143 | Comment: VideoCommentModel | ||
144 | |||
145 | @ForeignKey(() => VideoAbuseModel) | ||
146 | @Column | ||
147 | videoAbuseId: number | ||
148 | |||
149 | @BelongsTo(() => VideoAbuseModel, { | ||
150 | foreignKey: { | ||
151 | allowNull: true | ||
152 | }, | ||
153 | onDelete: 'cascade' | ||
154 | }) | ||
155 | VideoAbuse: VideoAbuseModel | ||
156 | |||
157 | @ForeignKey(() => VideoBlacklistModel) | ||
158 | @Column | ||
159 | videoBlacklistId: number | ||
160 | |||
161 | @BelongsTo(() => VideoBlacklistModel, { | ||
162 | foreignKey: { | ||
163 | allowNull: true | ||
164 | }, | ||
165 | onDelete: 'cascade' | ||
166 | }) | ||
167 | VideoBlacklist: VideoBlacklistModel | ||
168 | |||
169 | static listForApi (userId: number, start: number, count: number, sort: string) { | ||
170 | const query = { | ||
171 | offset: start, | ||
172 | limit: count, | ||
173 | order: getSort(sort), | ||
174 | where: { | ||
175 | userId | ||
176 | } | ||
177 | } | ||
178 | |||
179 | return UserNotificationModel.scope(ScopeNames.WITH_ALL) | ||
180 | .findAndCountAll(query) | ||
181 | .then(({ rows, count }) => { | ||
182 | return { | ||
183 | data: rows, | ||
184 | total: count | ||
185 | } | ||
186 | }) | ||
187 | } | ||
188 | |||
189 | static markAsRead (userId: number, notificationIds: number[]) { | ||
190 | const query = { | ||
191 | where: { | ||
192 | userId, | ||
193 | id: { | ||
194 | [Op.any]: notificationIds | ||
195 | } | ||
196 | } | ||
197 | } | ||
198 | |||
199 | return UserNotificationModel.update({ read: true }, query) | ||
200 | } | ||
201 | |||
202 | toFormattedJSON (): UserNotification { | ||
203 | const video = this.Video ? { | ||
204 | id: this.Video.id, | ||
205 | uuid: this.Video.uuid, | ||
206 | name: this.Video.name, | ||
207 | channel: { | ||
208 | id: this.Video.VideoChannel.id, | ||
209 | displayName: this.Video.VideoChannel.getDisplayName() | ||
210 | } | ||
211 | } : undefined | ||
212 | |||
213 | const comment = this.Comment ? { | ||
214 | id: this.Comment.id, | ||
215 | account: { | ||
216 | id: this.Comment.Account.id, | ||
217 | displayName: this.Comment.Account.getDisplayName() | ||
218 | }, | ||
219 | video: { | ||
220 | id: this.Comment.Video.id, | ||
221 | uuid: this.Comment.Video.uuid, | ||
222 | name: this.Comment.Video.name | ||
223 | } | ||
224 | } : undefined | ||
225 | |||
226 | const videoAbuse = this.VideoAbuse ? { | ||
227 | id: this.VideoAbuse.id, | ||
228 | video: { | ||
229 | id: this.VideoAbuse.Video.id, | ||
230 | uuid: this.VideoAbuse.Video.uuid, | ||
231 | name: this.VideoAbuse.Video.name | ||
232 | } | ||
233 | } : undefined | ||
234 | |||
235 | const videoBlacklist = this.VideoBlacklist ? { | ||
236 | id: this.VideoBlacklist.id, | ||
237 | video: { | ||
238 | id: this.VideoBlacklist.Video.id, | ||
239 | uuid: this.VideoBlacklist.Video.uuid, | ||
240 | name: this.VideoBlacklist.Video.name | ||
241 | } | ||
242 | } : undefined | ||
243 | |||
244 | return { | ||
245 | id: this.id, | ||
246 | type: this.type, | ||
247 | read: this.read, | ||
248 | video, | ||
249 | comment, | ||
250 | videoAbuse, | ||
251 | videoBlacklist, | ||
252 | createdAt: this.createdAt.toISOString(), | ||
253 | updatedAt: this.updatedAt.toISOString() | ||
254 | } | ||
255 | } | ||
256 | } | ||
diff --git a/server/models/account/user.ts b/server/models/account/user.ts index 180ced810..55ec14d05 100644 --- a/server/models/account/user.ts +++ b/server/models/account/user.ts | |||
@@ -32,8 +32,8 @@ import { | |||
32 | isUserUsernameValid, | 32 | isUserUsernameValid, |
33 | isUserVideoQuotaDailyValid, | 33 | isUserVideoQuotaDailyValid, |
34 | isUserVideoQuotaValid, | 34 | isUserVideoQuotaValid, |
35 | isUserWebTorrentEnabledValid, | 35 | isUserVideosHistoryEnabledValid, |
36 | isUserVideosHistoryEnabledValid | 36 | isUserWebTorrentEnabledValid |
37 | } from '../../helpers/custom-validators/users' | 37 | } from '../../helpers/custom-validators/users' |
38 | import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto' | 38 | import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto' |
39 | import { OAuthTokenModel } from '../oauth/oauth-token' | 39 | import { OAuthTokenModel } from '../oauth/oauth-token' |
@@ -44,6 +44,10 @@ import { NSFWPolicyType } from '../../../shared/models/videos/nsfw-policy.type' | |||
44 | import { values } from 'lodash' | 44 | import { values } from 'lodash' |
45 | import { NSFW_POLICY_TYPES } from '../../initializers' | 45 | import { NSFW_POLICY_TYPES } from '../../initializers' |
46 | import { clearCacheByUserId } from '../../lib/oauth-model' | 46 | import { clearCacheByUserId } from '../../lib/oauth-model' |
47 | import { UserNotificationSettingModel } from './user-notification-setting' | ||
48 | import { VideoModel } from '../video/video' | ||
49 | import { ActorModel } from '../activitypub/actor' | ||
50 | import { ActorFollowModel } from '../activitypub/actor-follow' | ||
47 | 51 | ||
48 | enum ScopeNames { | 52 | enum ScopeNames { |
49 | WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL' | 53 | WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL' |
@@ -54,6 +58,10 @@ enum ScopeNames { | |||
54 | { | 58 | { |
55 | model: () => AccountModel, | 59 | model: () => AccountModel, |
56 | required: true | 60 | required: true |
61 | }, | ||
62 | { | ||
63 | model: () => UserNotificationSettingModel, | ||
64 | required: true | ||
57 | } | 65 | } |
58 | ] | 66 | ] |
59 | }) | 67 | }) |
@@ -64,6 +72,10 @@ enum ScopeNames { | |||
64 | model: () => AccountModel, | 72 | model: () => AccountModel, |
65 | required: true, | 73 | required: true, |
66 | include: [ () => VideoChannelModel ] | 74 | include: [ () => VideoChannelModel ] |
75 | }, | ||
76 | { | ||
77 | model: () => UserNotificationSettingModel, | ||
78 | required: true | ||
67 | } | 79 | } |
68 | ] | 80 | ] |
69 | } | 81 | } |
@@ -167,6 +179,13 @@ export class UserModel extends Model<UserModel> { | |||
167 | }) | 179 | }) |
168 | Account: AccountModel | 180 | Account: AccountModel |
169 | 181 | ||
182 | @HasOne(() => UserNotificationSettingModel, { | ||
183 | foreignKey: 'userId', | ||
184 | onDelete: 'cascade', | ||
185 | hooks: true | ||
186 | }) | ||
187 | NotificationSetting: UserNotificationSettingModel | ||
188 | |||
170 | @HasMany(() => OAuthTokenModel, { | 189 | @HasMany(() => OAuthTokenModel, { |
171 | foreignKey: 'userId', | 190 | foreignKey: 'userId', |
172 | onDelete: 'cascade' | 191 | onDelete: 'cascade' |
@@ -249,13 +268,12 @@ export class UserModel extends Model<UserModel> { | |||
249 | }) | 268 | }) |
250 | } | 269 | } |
251 | 270 | ||
252 | static listEmailsWithRight (right: UserRight) { | 271 | static listWithRight (right: UserRight) { |
253 | const roles = Object.keys(USER_ROLE_LABELS) | 272 | const roles = Object.keys(USER_ROLE_LABELS) |
254 | .map(k => parseInt(k, 10) as UserRole) | 273 | .map(k => parseInt(k, 10) as UserRole) |
255 | .filter(role => hasUserRight(role, right)) | 274 | .filter(role => hasUserRight(role, right)) |
256 | 275 | ||
257 | const query = { | 276 | const query = { |
258 | attribute: [ 'email' ], | ||
259 | where: { | 277 | where: { |
260 | role: { | 278 | role: { |
261 | [Sequelize.Op.in]: roles | 279 | [Sequelize.Op.in]: roles |
@@ -263,9 +281,46 @@ export class UserModel extends Model<UserModel> { | |||
263 | } | 281 | } |
264 | } | 282 | } |
265 | 283 | ||
266 | return UserModel.unscoped() | 284 | return UserModel.findAll(query) |
267 | .findAll(query) | 285 | } |
268 | .then(u => u.map(u => u.email)) | 286 | |
287 | static listUserSubscribersOf (actorId: number) { | ||
288 | const query = { | ||
289 | include: [ | ||
290 | { | ||
291 | model: UserNotificationSettingModel.unscoped(), | ||
292 | required: true | ||
293 | }, | ||
294 | { | ||
295 | attributes: [ 'userId' ], | ||
296 | model: AccountModel.unscoped(), | ||
297 | required: true, | ||
298 | include: [ | ||
299 | { | ||
300 | attributes: [ ], | ||
301 | model: ActorModel.unscoped(), | ||
302 | required: true, | ||
303 | where: { | ||
304 | serverId: null | ||
305 | }, | ||
306 | include: [ | ||
307 | { | ||
308 | attributes: [ ], | ||
309 | as: 'ActorFollowings', | ||
310 | model: ActorFollowModel.unscoped(), | ||
311 | required: true, | ||
312 | where: { | ||
313 | targetActorId: actorId | ||
314 | } | ||
315 | } | ||
316 | ] | ||
317 | } | ||
318 | ] | ||
319 | } | ||
320 | ] | ||
321 | } | ||
322 | |||
323 | return UserModel.unscoped().findAll(query) | ||
269 | } | 324 | } |
270 | 325 | ||
271 | static loadById (id: number) { | 326 | static loadById (id: number) { |
@@ -314,6 +369,37 @@ export class UserModel extends Model<UserModel> { | |||
314 | return UserModel.findOne(query) | 369 | return UserModel.findOne(query) |
315 | } | 370 | } |
316 | 371 | ||
372 | static loadByVideoId (videoId: number) { | ||
373 | const query = { | ||
374 | include: [ | ||
375 | { | ||
376 | required: true, | ||
377 | attributes: [ 'id' ], | ||
378 | model: AccountModel.unscoped(), | ||
379 | include: [ | ||
380 | { | ||
381 | required: true, | ||
382 | attributes: [ 'id' ], | ||
383 | model: VideoChannelModel.unscoped(), | ||
384 | include: [ | ||
385 | { | ||
386 | required: true, | ||
387 | attributes: [ 'id' ], | ||
388 | model: VideoModel.unscoped(), | ||
389 | where: { | ||
390 | id: videoId | ||
391 | } | ||
392 | } | ||
393 | ] | ||
394 | } | ||
395 | ] | ||
396 | } | ||
397 | ] | ||
398 | } | ||
399 | |||
400 | return UserModel.findOne(query) | ||
401 | } | ||
402 | |||
317 | static getOriginalVideoFileTotalFromUser (user: UserModel) { | 403 | static getOriginalVideoFileTotalFromUser (user: UserModel) { |
318 | // Don't use sequelize because we need to use a sub query | 404 | // Don't use sequelize because we need to use a sub query |
319 | const query = UserModel.generateUserQuotaBaseSQL() | 405 | const query = UserModel.generateUserQuotaBaseSQL() |
@@ -380,6 +466,7 @@ export class UserModel extends Model<UserModel> { | |||
380 | blocked: this.blocked, | 466 | blocked: this.blocked, |
381 | blockedReason: this.blockedReason, | 467 | blockedReason: this.blockedReason, |
382 | account: this.Account.toFormattedJSON(), | 468 | account: this.Account.toFormattedJSON(), |
469 | notificationSettings: this.NotificationSetting ? this.NotificationSetting.toFormattedJSON() : undefined, | ||
383 | videoChannels: [], | 470 | videoChannels: [], |
384 | videoQuotaUsed: videoQuotaUsed !== undefined | 471 | videoQuotaUsed: videoQuotaUsed !== undefined |
385 | ? parseInt(videoQuotaUsed, 10) | 472 | ? parseInt(videoQuotaUsed, 10) |
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts index 994f791de..796e07a42 100644 --- a/server/models/activitypub/actor-follow.ts +++ b/server/models/activitypub/actor-follow.ts | |||
@@ -307,7 +307,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
307 | }) | 307 | }) |
308 | } | 308 | } |
309 | 309 | ||
310 | static listFollowersForApi (id: number, start: number, count: number, sort: string, search?: string) { | 310 | static listFollowersForApi (actorId: number, start: number, count: number, sort: string, search?: string) { |
311 | const query = { | 311 | const query = { |
312 | distinct: true, | 312 | distinct: true, |
313 | offset: start, | 313 | offset: start, |
@@ -335,7 +335,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
335 | as: 'ActorFollowing', | 335 | as: 'ActorFollowing', |
336 | required: true, | 336 | required: true, |
337 | where: { | 337 | where: { |
338 | id | 338 | id: actorId |
339 | } | 339 | } |
340 | } | 340 | } |
341 | ] | 341 | ] |
@@ -350,7 +350,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
350 | }) | 350 | }) |
351 | } | 351 | } |
352 | 352 | ||
353 | static listSubscriptionsForApi (id: number, start: number, count: number, sort: string) { | 353 | static listSubscriptionsForApi (actorId: number, start: number, count: number, sort: string) { |
354 | const query = { | 354 | const query = { |
355 | attributes: [], | 355 | attributes: [], |
356 | distinct: true, | 356 | distinct: true, |
@@ -358,7 +358,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
358 | limit: count, | 358 | limit: count, |
359 | order: getSort(sort), | 359 | order: getSort(sort), |
360 | where: { | 360 | where: { |
361 | actorId: id | 361 | actorId: actorId |
362 | }, | 362 | }, |
363 | include: [ | 363 | include: [ |
364 | { | 364 | { |
@@ -451,9 +451,9 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
451 | static updateFollowScore (inboxUrl: string, value: number, t?: Sequelize.Transaction) { | 451 | static updateFollowScore (inboxUrl: string, value: number, t?: Sequelize.Transaction) { |
452 | const query = `UPDATE "actorFollow" SET "score" = LEAST("score" + ${value}, ${ACTOR_FOLLOW_SCORE.MAX}) ` + | 452 | const query = `UPDATE "actorFollow" SET "score" = LEAST("score" + ${value}, ${ACTOR_FOLLOW_SCORE.MAX}) ` + |
453 | 'WHERE id IN (' + | 453 | 'WHERE id IN (' + |
454 | 'SELECT "actorFollow"."id" FROM "actorFollow" ' + | 454 | 'SELECT "actorFollow"."id" FROM "actorFollow" ' + |
455 | 'INNER JOIN "actor" ON "actor"."id" = "actorFollow"."actorId" ' + | 455 | 'INNER JOIN "actor" ON "actor"."id" = "actorFollow"."actorId" ' + |
456 | `WHERE "actor"."inboxUrl" = '${inboxUrl}' OR "actor"."sharedInboxUrl" = '${inboxUrl}'` + | 456 | `WHERE "actor"."inboxUrl" = '${inboxUrl}' OR "actor"."sharedInboxUrl" = '${inboxUrl}'` + |
457 | ')' | 457 | ')' |
458 | 458 | ||
459 | const options = { | 459 | const options = { |
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts index 12b83916e..dda57a8ba 100644 --- a/server/models/activitypub/actor.ts +++ b/server/models/activitypub/actor.ts | |||
@@ -219,6 +219,7 @@ export class ActorModel extends Model<ActorModel> { | |||
219 | name: 'actorId', | 219 | name: 'actorId', |
220 | allowNull: false | 220 | allowNull: false |
221 | }, | 221 | }, |
222 | as: 'ActorFollowings', | ||
222 | onDelete: 'cascade' | 223 | onDelete: 'cascade' |
223 | }) | 224 | }) |
224 | ActorFollowing: ActorFollowModel[] | 225 | ActorFollowing: ActorFollowModel[] |
diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts index dbb88ca45..4c9e2d05e 100644 --- a/server/models/video/video-abuse.ts +++ b/server/models/video/video-abuse.ts | |||
@@ -86,11 +86,6 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
86 | }) | 86 | }) |
87 | Video: VideoModel | 87 | Video: VideoModel |
88 | 88 | ||
89 | @AfterCreate | ||
90 | static sendEmailNotification (instance: VideoAbuseModel) { | ||
91 | return Emailer.Instance.addVideoAbuseReportJob(instance.videoId) | ||
92 | } | ||
93 | |||
94 | static loadByIdAndVideoId (id: number, videoId: number) { | 89 | static loadByIdAndVideoId (id: number, videoId: number) { |
95 | const query = { | 90 | const query = { |
96 | where: { | 91 | where: { |
diff --git a/server/models/video/video-blacklist.ts b/server/models/video/video-blacklist.ts index 67f7cd487..23e992685 100644 --- a/server/models/video/video-blacklist.ts +++ b/server/models/video/video-blacklist.ts | |||
@@ -53,16 +53,6 @@ export class VideoBlacklistModel extends Model<VideoBlacklistModel> { | |||
53 | }) | 53 | }) |
54 | Video: VideoModel | 54 | Video: VideoModel |
55 | 55 | ||
56 | @AfterCreate | ||
57 | static sendBlacklistEmailNotification (instance: VideoBlacklistModel) { | ||
58 | return Emailer.Instance.addVideoBlacklistReportJob(instance.videoId, instance.reason) | ||
59 | } | ||
60 | |||
61 | @AfterDestroy | ||
62 | static sendUnblacklistEmailNotification (instance: VideoBlacklistModel) { | ||
63 | return Emailer.Instance.addVideoUnblacklistReportJob(instance.videoId) | ||
64 | } | ||
65 | |||
66 | static listForApi (start: number, count: number, sort: SortType) { | 56 | static listForApi (start: number, count: number, sort: SortType) { |
67 | const query = { | 57 | const query = { |
68 | offset: start, | 58 | offset: start, |
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index dd6d08139..d8fc2a564 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts | |||
@@ -448,6 +448,10 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
448 | } | 448 | } |
449 | } | 449 | } |
450 | 450 | ||
451 | getCommentStaticPath () { | ||
452 | return this.Video.getWatchStaticPath() + ';threadId=' + this.getThreadId() | ||
453 | } | ||
454 | |||
451 | getThreadId (): number { | 455 | getThreadId (): number { |
452 | return this.originCommentId || this.id | 456 | return this.originCommentId || this.id |
453 | } | 457 | } |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index bcf327f32..fc200e5d1 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -1527,6 +1527,10 @@ export class VideoModel extends Model<VideoModel> { | |||
1527 | videoFile.infoHash = parsedTorrent.infoHash | 1527 | videoFile.infoHash = parsedTorrent.infoHash |
1528 | } | 1528 | } |
1529 | 1529 | ||
1530 | getWatchStaticPath () { | ||
1531 | return '/videos/watch/' + this.uuid | ||
1532 | } | ||
1533 | |||
1530 | getEmbedStaticPath () { | 1534 | getEmbedStaticPath () { |
1531 | return '/videos/embed/' + this.uuid | 1535 | return '/videos/embed/' + this.uuid |
1532 | } | 1536 | } |