diff options
Diffstat (limited to 'server/models')
-rw-r--r-- | server/models/account/account-blocklist.ts | 15 | ||||
-rw-r--r-- | server/models/account/user-notification-setting.ts | 22 | ||||
-rw-r--r-- | server/models/account/user-notification.ts | 150 | ||||
-rw-r--r-- | server/models/account/user.ts | 24 | ||||
-rw-r--r-- | server/models/video/video-file.ts | 2 | ||||
-rw-r--r-- | server/models/video/video-import.ts | 4 | ||||
-rw-r--r-- | server/models/video/video.ts | 10 |
7 files changed, 165 insertions, 62 deletions
diff --git a/server/models/account/account-blocklist.ts b/server/models/account/account-blocklist.ts index fa2819235..54ac290c4 100644 --- a/server/models/account/account-blocklist.ts +++ b/server/models/account/account-blocklist.ts | |||
@@ -72,6 +72,21 @@ export class AccountBlocklistModel extends Model<AccountBlocklistModel> { | |||
72 | }) | 72 | }) |
73 | BlockedAccount: AccountModel | 73 | BlockedAccount: AccountModel |
74 | 74 | ||
75 | static isAccountMutedBy (accountId: number, targetAccountId: number) { | ||
76 | const query = { | ||
77 | attributes: [ 'id' ], | ||
78 | where: { | ||
79 | accountId, | ||
80 | targetAccountId | ||
81 | }, | ||
82 | raw: true | ||
83 | } | ||
84 | |||
85 | return AccountBlocklistModel.unscoped() | ||
86 | .findOne(query) | ||
87 | .then(a => !!a) | ||
88 | } | ||
89 | |||
75 | static loadByAccountAndTarget (accountId: number, targetAccountId: number) { | 90 | static loadByAccountAndTarget (accountId: number, targetAccountId: number) { |
76 | const query = { | 91 | const query = { |
77 | where: { | 92 | where: { |
diff --git a/server/models/account/user-notification-setting.ts b/server/models/account/user-notification-setting.ts index bc24b1e33..6470defa7 100644 --- a/server/models/account/user-notification-setting.ts +++ b/server/models/account/user-notification-setting.ts | |||
@@ -65,6 +65,24 @@ export class UserNotificationSettingModel extends Model<UserNotificationSettingM | |||
65 | @Column | 65 | @Column |
66 | blacklistOnMyVideo: UserNotificationSettingValue | 66 | blacklistOnMyVideo: UserNotificationSettingValue |
67 | 67 | ||
68 | @AllowNull(false) | ||
69 | @Default(null) | ||
70 | @Is( | ||
71 | 'UserNotificationSettingMyVideoPublished', | ||
72 | value => throwIfNotValid(value, isUserNotificationSettingValid, 'myVideoPublished') | ||
73 | ) | ||
74 | @Column | ||
75 | myVideoPublished: UserNotificationSettingValue | ||
76 | |||
77 | @AllowNull(false) | ||
78 | @Default(null) | ||
79 | @Is( | ||
80 | 'UserNotificationSettingMyVideoImportFinished', | ||
81 | value => throwIfNotValid(value, isUserNotificationSettingValid, 'myVideoImportFinished') | ||
82 | ) | ||
83 | @Column | ||
84 | myVideoImportFinished: UserNotificationSettingValue | ||
85 | |||
68 | @ForeignKey(() => UserModel) | 86 | @ForeignKey(() => UserModel) |
69 | @Column | 87 | @Column |
70 | userId: number | 88 | userId: number |
@@ -94,7 +112,9 @@ export class UserNotificationSettingModel extends Model<UserNotificationSettingM | |||
94 | newCommentOnMyVideo: this.newCommentOnMyVideo, | 112 | newCommentOnMyVideo: this.newCommentOnMyVideo, |
95 | newVideoFromSubscription: this.newVideoFromSubscription, | 113 | newVideoFromSubscription: this.newVideoFromSubscription, |
96 | videoAbuseAsModerator: this.videoAbuseAsModerator, | 114 | videoAbuseAsModerator: this.videoAbuseAsModerator, |
97 | blacklistOnMyVideo: this.blacklistOnMyVideo | 115 | blacklistOnMyVideo: this.blacklistOnMyVideo, |
116 | myVideoPublished: this.myVideoPublished, | ||
117 | myVideoImportFinished: this.myVideoImportFinished | ||
98 | } | 118 | } |
99 | } | 119 | } |
100 | } | 120 | } |
diff --git a/server/models/account/user-notification.ts b/server/models/account/user-notification.ts index e22f0d57f..251244374 100644 --- a/server/models/account/user-notification.ts +++ b/server/models/account/user-notification.ts | |||
@@ -1,4 +1,17 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { |
2 | AllowNull, | ||
3 | BelongsTo, | ||
4 | Column, | ||
5 | CreatedAt, | ||
6 | Default, | ||
7 | ForeignKey, | ||
8 | IFindOptions, | ||
9 | Is, | ||
10 | Model, | ||
11 | Scopes, | ||
12 | Table, | ||
13 | UpdatedAt | ||
14 | } from 'sequelize-typescript' | ||
2 | import { UserNotification, UserNotificationType } from '../../../shared' | 15 | import { UserNotification, UserNotificationType } from '../../../shared' |
3 | import { getSort, throwIfNotValid } from '../utils' | 16 | import { getSort, throwIfNotValid } from '../utils' |
4 | import { isBooleanValid } from '../../helpers/custom-validators/misc' | 17 | import { isBooleanValid } from '../../helpers/custom-validators/misc' |
@@ -11,66 +24,68 @@ import { VideoChannelModel } from '../video/video-channel' | |||
11 | import { AccountModel } from './account' | 24 | import { AccountModel } from './account' |
12 | import { VideoAbuseModel } from '../video/video-abuse' | 25 | import { VideoAbuseModel } from '../video/video-abuse' |
13 | import { VideoBlacklistModel } from '../video/video-blacklist' | 26 | import { VideoBlacklistModel } from '../video/video-blacklist' |
27 | import { VideoImportModel } from '../video/video-import' | ||
14 | 28 | ||
15 | enum ScopeNames { | 29 | enum ScopeNames { |
16 | WITH_ALL = 'WITH_ALL' | 30 | WITH_ALL = 'WITH_ALL' |
17 | } | 31 | } |
18 | 32 | ||
33 | function buildVideoInclude (required: boolean) { | ||
34 | return { | ||
35 | attributes: [ 'id', 'uuid', 'name' ], | ||
36 | model: () => VideoModel.unscoped(), | ||
37 | required | ||
38 | } | ||
39 | } | ||
40 | |||
41 | function buildChannelInclude () { | ||
42 | return { | ||
43 | required: true, | ||
44 | attributes: [ 'id', 'name' ], | ||
45 | model: () => VideoChannelModel.unscoped() | ||
46 | } | ||
47 | } | ||
48 | |||
49 | function buildAccountInclude () { | ||
50 | return { | ||
51 | required: true, | ||
52 | attributes: [ 'id', 'name' ], | ||
53 | model: () => AccountModel.unscoped() | ||
54 | } | ||
55 | } | ||
56 | |||
19 | @Scopes({ | 57 | @Scopes({ |
20 | [ScopeNames.WITH_ALL]: { | 58 | [ScopeNames.WITH_ALL]: { |
21 | include: [ | 59 | include: [ |
60 | Object.assign(buildVideoInclude(false), { | ||
61 | include: [ buildChannelInclude() ] | ||
62 | }), | ||
22 | { | 63 | { |
23 | attributes: [ 'id', 'uuid', 'name' ], | 64 | attributes: [ 'id', 'originCommentId' ], |
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(), | 65 | model: () => VideoCommentModel.unscoped(), |
37 | required: false, | 66 | required: false, |
38 | include: [ | 67 | include: [ |
39 | { | 68 | buildAccountInclude(), |
40 | required: true, | 69 | buildVideoInclude(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 | ] | 70 | ] |
50 | }, | 71 | }, |
51 | { | 72 | { |
52 | attributes: [ 'id' ], | 73 | attributes: [ 'id' ], |
53 | model: () => VideoAbuseModel.unscoped(), | 74 | model: () => VideoAbuseModel.unscoped(), |
54 | required: false, | 75 | required: false, |
55 | include: [ | 76 | include: [ buildVideoInclude(true) ] |
56 | { | ||
57 | required: true, | ||
58 | attributes: [ 'id', 'uuid', 'name' ], | ||
59 | model: () => VideoModel.unscoped() | ||
60 | } | ||
61 | ] | ||
62 | }, | 77 | }, |
63 | { | 78 | { |
64 | attributes: [ 'id' ], | 79 | attributes: [ 'id' ], |
65 | model: () => VideoBlacklistModel.unscoped(), | 80 | model: () => VideoBlacklistModel.unscoped(), |
66 | required: false, | 81 | required: false, |
67 | include: [ | 82 | include: [ buildVideoInclude(true) ] |
68 | { | 83 | }, |
69 | required: true, | 84 | { |
70 | attributes: [ 'id', 'uuid', 'name' ], | 85 | attributes: [ 'id', 'magnetUri', 'targetUrl', 'torrentName' ], |
71 | model: () => VideoModel.unscoped() | 86 | model: () => VideoImportModel.unscoped(), |
72 | } | 87 | required: false, |
73 | ] | 88 | include: [ buildVideoInclude(false) ] |
74 | } | 89 | } |
75 | ] | 90 | ] |
76 | } | 91 | } |
@@ -166,8 +181,20 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
166 | }) | 181 | }) |
167 | VideoBlacklist: VideoBlacklistModel | 182 | VideoBlacklist: VideoBlacklistModel |
168 | 183 | ||
169 | static listForApi (userId: number, start: number, count: number, sort: string) { | 184 | @ForeignKey(() => VideoImportModel) |
170 | const query = { | 185 | @Column |
186 | videoImportId: number | ||
187 | |||
188 | @BelongsTo(() => VideoImportModel, { | ||
189 | foreignKey: { | ||
190 | allowNull: true | ||
191 | }, | ||
192 | onDelete: 'cascade' | ||
193 | }) | ||
194 | VideoImport: VideoImportModel | ||
195 | |||
196 | static listForApi (userId: number, start: number, count: number, sort: string, unread?: boolean) { | ||
197 | const query: IFindOptions<UserNotificationModel> = { | ||
171 | offset: start, | 198 | offset: start, |
172 | limit: count, | 199 | limit: count, |
173 | order: getSort(sort), | 200 | order: getSort(sort), |
@@ -176,6 +203,8 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
176 | } | 203 | } |
177 | } | 204 | } |
178 | 205 | ||
206 | if (unread !== undefined) query.where['read'] = !unread | ||
207 | |||
179 | return UserNotificationModel.scope(ScopeNames.WITH_ALL) | 208 | return UserNotificationModel.scope(ScopeNames.WITH_ALL) |
180 | .findAndCountAll(query) | 209 | .findAndCountAll(query) |
181 | .then(({ rows, count }) => { | 210 | .then(({ rows, count }) => { |
@@ -200,45 +229,39 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
200 | } | 229 | } |
201 | 230 | ||
202 | toFormattedJSON (): UserNotification { | 231 | toFormattedJSON (): UserNotification { |
203 | const video = this.Video ? { | 232 | const video = this.Video ? Object.assign(this.formatVideo(this.Video), { |
204 | id: this.Video.id, | ||
205 | uuid: this.Video.uuid, | ||
206 | name: this.Video.name, | ||
207 | channel: { | 233 | channel: { |
208 | id: this.Video.VideoChannel.id, | 234 | id: this.Video.VideoChannel.id, |
209 | displayName: this.Video.VideoChannel.getDisplayName() | 235 | displayName: this.Video.VideoChannel.getDisplayName() |
210 | } | 236 | } |
237 | }) : undefined | ||
238 | |||
239 | const videoImport = this.VideoImport ? { | ||
240 | id: this.VideoImport.id, | ||
241 | video: this.VideoImport.Video ? this.formatVideo(this.VideoImport.Video) : undefined, | ||
242 | torrentName: this.VideoImport.torrentName, | ||
243 | magnetUri: this.VideoImport.magnetUri, | ||
244 | targetUrl: this.VideoImport.targetUrl | ||
211 | } : undefined | 245 | } : undefined |
212 | 246 | ||
213 | const comment = this.Comment ? { | 247 | const comment = this.Comment ? { |
214 | id: this.Comment.id, | 248 | id: this.Comment.id, |
249 | threadId: this.Comment.getThreadId(), | ||
215 | account: { | 250 | account: { |
216 | id: this.Comment.Account.id, | 251 | id: this.Comment.Account.id, |
217 | displayName: this.Comment.Account.getDisplayName() | 252 | displayName: this.Comment.Account.getDisplayName() |
218 | }, | 253 | }, |
219 | video: { | 254 | video: this.formatVideo(this.Comment.Video) |
220 | id: this.Comment.Video.id, | ||
221 | uuid: this.Comment.Video.uuid, | ||
222 | name: this.Comment.Video.name | ||
223 | } | ||
224 | } : undefined | 255 | } : undefined |
225 | 256 | ||
226 | const videoAbuse = this.VideoAbuse ? { | 257 | const videoAbuse = this.VideoAbuse ? { |
227 | id: this.VideoAbuse.id, | 258 | id: this.VideoAbuse.id, |
228 | video: { | 259 | video: this.formatVideo(this.VideoAbuse.Video) |
229 | id: this.VideoAbuse.Video.id, | ||
230 | uuid: this.VideoAbuse.Video.uuid, | ||
231 | name: this.VideoAbuse.Video.name | ||
232 | } | ||
233 | } : undefined | 260 | } : undefined |
234 | 261 | ||
235 | const videoBlacklist = this.VideoBlacklist ? { | 262 | const videoBlacklist = this.VideoBlacklist ? { |
236 | id: this.VideoBlacklist.id, | 263 | id: this.VideoBlacklist.id, |
237 | video: { | 264 | video: this.formatVideo(this.VideoBlacklist.Video) |
238 | id: this.VideoBlacklist.Video.id, | ||
239 | uuid: this.VideoBlacklist.Video.uuid, | ||
240 | name: this.VideoBlacklist.Video.name | ||
241 | } | ||
242 | } : undefined | 265 | } : undefined |
243 | 266 | ||
244 | return { | 267 | return { |
@@ -246,6 +269,7 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
246 | type: this.type, | 269 | type: this.type, |
247 | read: this.read, | 270 | read: this.read, |
248 | video, | 271 | video, |
272 | videoImport, | ||
249 | comment, | 273 | comment, |
250 | videoAbuse, | 274 | videoAbuse, |
251 | videoBlacklist, | 275 | videoBlacklist, |
@@ -253,4 +277,12 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
253 | updatedAt: this.updatedAt.toISOString() | 277 | updatedAt: this.updatedAt.toISOString() |
254 | } | 278 | } |
255 | } | 279 | } |
280 | |||
281 | private formatVideo (video: VideoModel) { | ||
282 | return { | ||
283 | id: video.id, | ||
284 | uuid: video.uuid, | ||
285 | name: video.name | ||
286 | } | ||
287 | } | ||
256 | } | 288 | } |
diff --git a/server/models/account/user.ts b/server/models/account/user.ts index 55ec14d05..33f56f641 100644 --- a/server/models/account/user.ts +++ b/server/models/account/user.ts | |||
@@ -48,6 +48,7 @@ import { UserNotificationSettingModel } from './user-notification-setting' | |||
48 | import { VideoModel } from '../video/video' | 48 | import { VideoModel } from '../video/video' |
49 | import { ActorModel } from '../activitypub/actor' | 49 | import { ActorModel } from '../activitypub/actor' |
50 | import { ActorFollowModel } from '../activitypub/actor-follow' | 50 | import { ActorFollowModel } from '../activitypub/actor-follow' |
51 | import { VideoImportModel } from '../video/video-import' | ||
51 | 52 | ||
52 | enum ScopeNames { | 53 | enum ScopeNames { |
53 | WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL' | 54 | WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL' |
@@ -186,6 +187,12 @@ export class UserModel extends Model<UserModel> { | |||
186 | }) | 187 | }) |
187 | NotificationSetting: UserNotificationSettingModel | 188 | NotificationSetting: UserNotificationSettingModel |
188 | 189 | ||
190 | @HasMany(() => VideoImportModel, { | ||
191 | foreignKey: 'userId', | ||
192 | onDelete: 'cascade' | ||
193 | }) | ||
194 | VideoImports: VideoImportModel[] | ||
195 | |||
189 | @HasMany(() => OAuthTokenModel, { | 196 | @HasMany(() => OAuthTokenModel, { |
190 | foreignKey: 'userId', | 197 | foreignKey: 'userId', |
191 | onDelete: 'cascade' | 198 | onDelete: 'cascade' |
@@ -400,6 +407,23 @@ export class UserModel extends Model<UserModel> { | |||
400 | return UserModel.findOne(query) | 407 | return UserModel.findOne(query) |
401 | } | 408 | } |
402 | 409 | ||
410 | static loadByVideoImportId (videoImportId: number) { | ||
411 | const query = { | ||
412 | include: [ | ||
413 | { | ||
414 | required: true, | ||
415 | attributes: [ 'id' ], | ||
416 | model: VideoImportModel.unscoped(), | ||
417 | where: { | ||
418 | id: videoImportId | ||
419 | } | ||
420 | } | ||
421 | ] | ||
422 | } | ||
423 | |||
424 | return UserModel.findOne(query) | ||
425 | } | ||
426 | |||
403 | static getOriginalVideoFileTotalFromUser (user: UserModel) { | 427 | static getOriginalVideoFileTotalFromUser (user: UserModel) { |
404 | // Don't use sequelize because we need to use a sub query | 428 | // Don't use sequelize because we need to use a sub query |
405 | const query = UserModel.generateUserQuotaBaseSQL() | 429 | const query = UserModel.generateUserQuotaBaseSQL() |
diff --git a/server/models/video/video-file.ts b/server/models/video/video-file.ts index 3fd2d5a99..0fd868cd6 100644 --- a/server/models/video/video-file.ts +++ b/server/models/video/video-file.ts | |||
@@ -1,4 +1,3 @@ | |||
1 | import { values } from 'lodash' | ||
2 | import { | 1 | import { |
3 | AllowNull, | 2 | AllowNull, |
4 | BelongsTo, | 3 | BelongsTo, |
@@ -20,7 +19,6 @@ import { | |||
20 | isVideoFileSizeValid, | 19 | isVideoFileSizeValid, |
21 | isVideoFPSResolutionValid | 20 | isVideoFPSResolutionValid |
22 | } from '../../helpers/custom-validators/videos' | 21 | } from '../../helpers/custom-validators/videos' |
23 | import { CONSTRAINTS_FIELDS } from '../../initializers' | ||
24 | import { throwIfNotValid } from '../utils' | 22 | import { throwIfNotValid } from '../utils' |
25 | import { VideoModel } from './video' | 23 | import { VideoModel } from './video' |
26 | import * as Sequelize from 'sequelize' | 24 | import * as Sequelize from 'sequelize' |
diff --git a/server/models/video/video-import.ts b/server/models/video/video-import.ts index 8d442b3f8..c723e57c0 100644 --- a/server/models/video/video-import.ts +++ b/server/models/video/video-import.ts | |||
@@ -144,6 +144,10 @@ export class VideoImportModel extends Model<VideoImportModel> { | |||
144 | }) | 144 | }) |
145 | } | 145 | } |
146 | 146 | ||
147 | getTargetIdentifier () { | ||
148 | return this.targetUrl || this.magnetUri || this.torrentName | ||
149 | } | ||
150 | |||
147 | toFormattedJSON (): VideoImport { | 151 | toFormattedJSON (): VideoImport { |
148 | const videoFormatOptions = { | 152 | const videoFormatOptions = { |
149 | completeDescription: true, | 153 | completeDescription: true, |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index fc200e5d1..80a6c7832 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -94,6 +94,7 @@ import { | |||
94 | import * as validator from 'validator' | 94 | import * as validator from 'validator' |
95 | import { UserVideoHistoryModel } from '../account/user-video-history' | 95 | import { UserVideoHistoryModel } from '../account/user-video-history' |
96 | import { UserModel } from '../account/user' | 96 | import { UserModel } from '../account/user' |
97 | import { VideoImportModel } from './video-import' | ||
97 | 98 | ||
98 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation | 99 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation |
99 | const indexes: Sequelize.DefineIndexesOptions[] = [ | 100 | const indexes: Sequelize.DefineIndexesOptions[] = [ |
@@ -785,6 +786,15 @@ export class VideoModel extends Model<VideoModel> { | |||
785 | }) | 786 | }) |
786 | VideoBlacklist: VideoBlacklistModel | 787 | VideoBlacklist: VideoBlacklistModel |
787 | 788 | ||
789 | @HasOne(() => VideoImportModel, { | ||
790 | foreignKey: { | ||
791 | name: 'videoId', | ||
792 | allowNull: true | ||
793 | }, | ||
794 | onDelete: 'set null' | ||
795 | }) | ||
796 | VideoImport: VideoImportModel | ||
797 | |||
788 | @HasMany(() => VideoCaptionModel, { | 798 | @HasMany(() => VideoCaptionModel, { |
789 | foreignKey: { | 799 | foreignKey: { |
790 | name: 'videoId', | 800 | name: 'videoId', |