aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models
diff options
context:
space:
mode:
Diffstat (limited to 'server/models')
-rw-r--r--server/models/account/account-interface.ts3
-rw-r--r--server/models/account/account.ts26
-rw-r--r--server/models/account/user.ts5
-rw-r--r--server/models/avatar/avatar-interface.ts16
-rw-r--r--server/models/avatar/avatar.ts24
-rw-r--r--server/models/avatar/index.ts1
-rw-r--r--server/models/index.ts1
-rw-r--r--server/models/video/video-interface.ts1
-rw-r--r--server/models/video/video.ts92
9 files changed, 118 insertions, 51 deletions
diff --git a/server/models/account/account-interface.ts b/server/models/account/account-interface.ts
index b369766dc..46fe068e3 100644
--- a/server/models/account/account-interface.ts
+++ b/server/models/account/account-interface.ts
@@ -1,6 +1,7 @@
1import * as Bluebird from 'bluebird' 1import * as Bluebird from 'bluebird'
2import * as Sequelize from 'sequelize' 2import * as Sequelize from 'sequelize'
3import { Account as FormattedAccount, ActivityPubActor } from '../../../shared' 3import { Account as FormattedAccount, ActivityPubActor } from '../../../shared'
4import { AvatarInstance } from '../avatar'
4import { ServerInstance } from '../server/server-interface' 5import { ServerInstance } from '../server/server-interface'
5import { VideoChannelInstance } from '../video/video-channel-interface' 6import { VideoChannelInstance } from '../video/video-channel-interface'
6 7
@@ -51,6 +52,7 @@ export interface AccountAttributes {
51 serverId?: number 52 serverId?: number
52 userId?: number 53 userId?: number
53 applicationId?: number 54 applicationId?: number
55 avatarId?: number
54} 56}
55 57
56export interface AccountInstance extends AccountClass, AccountAttributes, Sequelize.Instance<AccountAttributes> { 58export interface AccountInstance extends AccountClass, AccountAttributes, Sequelize.Instance<AccountAttributes> {
@@ -68,6 +70,7 @@ export interface AccountInstance extends AccountClass, AccountAttributes, Sequel
68 70
69 Server: ServerInstance 71 Server: ServerInstance
70 VideoChannels: VideoChannelInstance[] 72 VideoChannels: VideoChannelInstance[]
73 Avatar: AvatarInstance
71} 74}
72 75
73export interface AccountModel extends AccountClass, Sequelize.Model<AccountInstance, AccountAttributes> {} 76export interface AccountModel extends AccountClass, Sequelize.Model<AccountInstance, AccountAttributes> {}
diff --git a/server/models/account/account.ts b/server/models/account/account.ts
index 61a88524c..8b0819f39 100644
--- a/server/models/account/account.ts
+++ b/server/models/account/account.ts
@@ -1,4 +1,6 @@
1import { join } from 'path'
1import * as Sequelize from 'sequelize' 2import * as Sequelize from 'sequelize'
3import { Avatar } from '../../../shared/models/avatars/avatar.model'
2import { 4import {
3 activityPubContextify, 5 activityPubContextify,
4 isAccountFollowersCountValid, 6 isAccountFollowersCountValid,
@@ -8,6 +10,7 @@ import {
8 isUserUsernameValid 10 isUserUsernameValid
9} from '../../helpers' 11} from '../../helpers'
10import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' 12import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
13import { AVATARS_DIR } from '../../initializers'
11import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers/constants' 14import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers/constants'
12import { sendDeleteAccount } from '../../lib/activitypub/send/send-delete' 15import { sendDeleteAccount } from '../../lib/activitypub/send/send-delete'
13import { addMethodsToModel } from '../utils' 16import { addMethodsToModel } from '../utils'
@@ -252,6 +255,14 @@ function associate (models) {
252 as: 'followers', 255 as: 'followers',
253 onDelete: 'cascade' 256 onDelete: 'cascade'
254 }) 257 })
258
259 Account.hasOne(models.Avatar, {
260 foreignKey: {
261 name: 'avatarId',
262 allowNull: true
263 },
264 onDelete: 'cascade'
265 })
255} 266}
256 267
257function afterDestroy (account: AccountInstance) { 268function afterDestroy (account: AccountInstance) {
@@ -265,6 +276,15 @@ function afterDestroy (account: AccountInstance) {
265toFormattedJSON = function (this: AccountInstance) { 276toFormattedJSON = function (this: AccountInstance) {
266 let host = CONFIG.WEBSERVER.HOST 277 let host = CONFIG.WEBSERVER.HOST
267 let score: number 278 let score: number
279 let avatar: Avatar = null
280
281 if (this.Avatar) {
282 avatar = {
283 path: join(AVATARS_DIR.ACCOUNT, this.Avatar.filename),
284 createdAt: this.Avatar.createdAt,
285 updatedAt: this.Avatar.updatedAt
286 }
287 }
268 288
269 if (this.Server) { 289 if (this.Server) {
270 host = this.Server.host 290 host = this.Server.host
@@ -273,11 +293,15 @@ toFormattedJSON = function (this: AccountInstance) {
273 293
274 const json = { 294 const json = {
275 id: this.id, 295 id: this.id,
296 uuid: this.uuid,
276 host, 297 host,
277 score, 298 score,
278 name: this.name, 299 name: this.name,
300 followingCount: this.followingCount,
301 followersCount: this.followersCount,
279 createdAt: this.createdAt, 302 createdAt: this.createdAt,
280 updatedAt: this.updatedAt 303 updatedAt: this.updatedAt,
304 avatar
281 } 305 }
282 306
283 return json 307 return json
diff --git a/server/models/account/user.ts b/server/models/account/user.ts
index 8f7c9b013..3705947c0 100644
--- a/server/models/account/user.ts
+++ b/server/models/account/user.ts
@@ -157,10 +157,7 @@ toFormattedJSON = function (this: UserInstance) {
157 roleLabel: USER_ROLE_LABELS[this.role], 157 roleLabel: USER_ROLE_LABELS[this.role],
158 videoQuota: this.videoQuota, 158 videoQuota: this.videoQuota,
159 createdAt: this.createdAt, 159 createdAt: this.createdAt,
160 account: { 160 account: this.Account.toFormattedJSON()
161 id: this.Account.id,
162 uuid: this.Account.uuid
163 }
164 } 161 }
165 162
166 if (Array.isArray(this.Account.VideoChannels) === true) { 163 if (Array.isArray(this.Account.VideoChannels) === true) {
diff --git a/server/models/avatar/avatar-interface.ts b/server/models/avatar/avatar-interface.ts
new file mode 100644
index 000000000..4af2b87b7
--- /dev/null
+++ b/server/models/avatar/avatar-interface.ts
@@ -0,0 +1,16 @@
1import * as Sequelize from 'sequelize'
2
3export namespace AvatarMethods {}
4
5export interface AvatarClass {}
6
7export interface AvatarAttributes {
8 filename: string
9}
10
11export interface AvatarInstance extends AvatarClass, AvatarAttributes, Sequelize.Instance<AvatarAttributes> {
12 createdAt: Date
13 updatedAt: Date
14}
15
16export interface AvatarModel extends AvatarClass, Sequelize.Model<AvatarInstance, AvatarAttributes> {}
diff --git a/server/models/avatar/avatar.ts b/server/models/avatar/avatar.ts
new file mode 100644
index 000000000..96308fd5f
--- /dev/null
+++ b/server/models/avatar/avatar.ts
@@ -0,0 +1,24 @@
1import * as Sequelize from 'sequelize'
2import { addMethodsToModel } from '../utils'
3import { AvatarAttributes, AvatarInstance } from './avatar-interface'
4
5let Avatar: Sequelize.Model<AvatarInstance, AvatarAttributes>
6
7export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
8 Avatar = sequelize.define<AvatarInstance, AvatarAttributes>('Avatar',
9 {
10 filename: {
11 type: DataTypes.STRING,
12 allowNull: false
13 }
14 },
15 {}
16 )
17
18 const classMethods = []
19 addMethodsToModel(Avatar, classMethods)
20
21 return Avatar
22}
23
24// ------------------------------ Statics ------------------------------
diff --git a/server/models/avatar/index.ts b/server/models/avatar/index.ts
new file mode 100644
index 000000000..877aed1ce
--- /dev/null
+++ b/server/models/avatar/index.ts
@@ -0,0 +1 @@
export * from './avatar-interface'
diff --git a/server/models/index.ts b/server/models/index.ts
index 65faa5294..fedd97dd1 100644
--- a/server/models/index.ts
+++ b/server/models/index.ts
@@ -1,4 +1,5 @@
1export * from './application' 1export * from './application'
2export * from './avatar'
2export * from './job' 3export * from './job'
3export * from './oauth' 4export * from './oauth'
4export * from './server' 5export * from './server'
diff --git a/server/models/video/video-interface.ts b/server/models/video/video-interface.ts
index be140de86..2a63350af 100644
--- a/server/models/video/video-interface.ts
+++ b/server/models/video/video-interface.ts
@@ -50,7 +50,6 @@ export namespace VideoMethods {
50 export type ListUserVideosForApi = (userId: number, start: number, count: number, sort: string) => Bluebird< ResultList<VideoInstance> > 50 export type ListUserVideosForApi = (userId: number, start: number, count: number, sort: string) => Bluebird< ResultList<VideoInstance> >
51 export type SearchAndPopulateAccountAndServerAndTags = ( 51 export type SearchAndPopulateAccountAndServerAndTags = (
52 value: string, 52 value: string,
53 field: string,
54 start: number, 53 start: number,
55 count: number, 54 count: number,
56 sort: string 55 sort: string
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index f3469c1de..d46fdeebe 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -104,7 +104,8 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
104 }, 104 },
105 category: { 105 category: {
106 type: DataTypes.INTEGER, 106 type: DataTypes.INTEGER,
107 allowNull: false, 107 allowNull: true,
108 defaultValue: null,
108 validate: { 109 validate: {
109 categoryValid: value => { 110 categoryValid: value => {
110 const res = isVideoCategoryValid(value) 111 const res = isVideoCategoryValid(value)
@@ -114,7 +115,7 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
114 }, 115 },
115 licence: { 116 licence: {
116 type: DataTypes.INTEGER, 117 type: DataTypes.INTEGER,
117 allowNull: false, 118 allowNull: true,
118 defaultValue: null, 119 defaultValue: null,
119 validate: { 120 validate: {
120 licenceValid: value => { 121 licenceValid: value => {
@@ -126,6 +127,7 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
126 language: { 127 language: {
127 type: DataTypes.INTEGER, 128 type: DataTypes.INTEGER,
128 allowNull: true, 129 allowNull: true,
130 defaultValue: null,
129 validate: { 131 validate: {
130 languageValid: value => { 132 languageValid: value => {
131 const res = isVideoLanguageValid(value) 133 const res = isVideoLanguageValid(value)
@@ -155,7 +157,8 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
155 }, 157 },
156 description: { 158 description: {
157 type: DataTypes.STRING(CONSTRAINTS_FIELDS.VIDEOS.DESCRIPTION.max), 159 type: DataTypes.STRING(CONSTRAINTS_FIELDS.VIDEOS.DESCRIPTION.max),
158 allowNull: false, 160 allowNull: true,
161 defaultValue: null,
159 validate: { 162 validate: {
160 descriptionValid: value => { 163 descriptionValid: value => {
161 const res = isVideoDescriptionValid(value) 164 const res = isVideoDescriptionValid(value)
@@ -486,7 +489,7 @@ toFormattedJSON = function (this: VideoInstance) {
486 description: this.getTruncatedDescription(), 489 description: this.getTruncatedDescription(),
487 serverHost, 490 serverHost,
488 isLocal: this.isOwned(), 491 isLocal: this.isOwned(),
489 account: this.VideoChannel.Account.name, 492 accountName: this.VideoChannel.Account.name,
490 duration: this.duration, 493 duration: this.duration,
491 views: this.views, 494 views: this.views,
492 likes: this.likes, 495 likes: this.likes,
@@ -514,6 +517,7 @@ toFormattedDetailsJSON = function (this: VideoInstance) {
514 privacy: this.privacy, 517 privacy: this.privacy,
515 descriptionPath: this.getDescriptionPath(), 518 descriptionPath: this.getDescriptionPath(),
516 channel: this.VideoChannel.toFormattedJSON(), 519 channel: this.VideoChannel.toFormattedJSON(),
520 account: this.VideoChannel.Account.toFormattedJSON(),
517 files: [] 521 files: []
518 } 522 }
519 523
@@ -560,6 +564,22 @@ toActivityPubObject = function (this: VideoInstance) {
560 } 564 }
561 } 565 }
562 566
567 let category
568 if (this.category) {
569 category = {
570 identifier: this.category + '',
571 name: this.getCategoryLabel()
572 }
573 }
574
575 let licence
576 if (this.licence) {
577 licence = {
578 identifier: this.licence + '',
579 name: this.getLicenceLabel()
580 }
581 }
582
563 let likesObject 583 let likesObject
564 let dislikesObject 584 let dislikesObject
565 585
@@ -631,14 +651,8 @@ toActivityPubObject = function (this: VideoInstance) {
631 duration: 'PT' + this.duration + 'S', 651 duration: 'PT' + this.duration + 'S',
632 uuid: this.uuid, 652 uuid: this.uuid,
633 tag, 653 tag,
634 category: { 654 category,
635 identifier: this.category + '', 655 licence,
636 name: this.getCategoryLabel()
637 },
638 licence: {
639 identifier: this.licence + '',
640 name: this.getLicenceLabel()
641 },
642 language, 656 language,
643 views: this.views, 657 views: this.views,
644 nsfw: this.nsfw, 658 nsfw: this.nsfw,
@@ -663,6 +677,8 @@ toActivityPubObject = function (this: VideoInstance) {
663} 677}
664 678
665getTruncatedDescription = function (this: VideoInstance) { 679getTruncatedDescription = function (this: VideoInstance) {
680 if (!this.description) return null
681
666 const options = { 682 const options = {
667 length: CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max 683 length: CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max
668 } 684 }
@@ -753,8 +769,6 @@ getDescriptionPath = function (this: VideoInstance) {
753 769
754getCategoryLabel = function (this: VideoInstance) { 770getCategoryLabel = function (this: VideoInstance) {
755 let categoryLabel = VIDEO_CATEGORIES[this.category] 771 let categoryLabel = VIDEO_CATEGORIES[this.category]
756
757 // Maybe our server is not up to date and there are new categories since our version
758 if (!categoryLabel) categoryLabel = 'Misc' 772 if (!categoryLabel) categoryLabel = 'Misc'
759 773
760 return categoryLabel 774 return categoryLabel
@@ -762,15 +776,12 @@ getCategoryLabel = function (this: VideoInstance) {
762 776
763getLicenceLabel = function (this: VideoInstance) { 777getLicenceLabel = function (this: VideoInstance) {
764 let licenceLabel = VIDEO_LICENCES[this.licence] 778 let licenceLabel = VIDEO_LICENCES[this.licence]
765
766 // Maybe our server is not up to date and there are new licences since our version
767 if (!licenceLabel) licenceLabel = 'Unknown' 779 if (!licenceLabel) licenceLabel = 'Unknown'
768 780
769 return licenceLabel 781 return licenceLabel
770} 782}
771 783
772getLanguageLabel = function (this: VideoInstance) { 784getLanguageLabel = function (this: VideoInstance) {
773 // Language is an optional attribute
774 let languageLabel = VIDEO_LANGUAGES[this.language] 785 let languageLabel = VIDEO_LANGUAGES[this.language]
775 if (!languageLabel) languageLabel = 'Unknown' 786 if (!languageLabel) languageLabel = 'Unknown'
776 787
@@ -1070,7 +1081,7 @@ loadByUUIDAndPopulateAccountAndServerAndTags = function (uuid: string) {
1070 return Video.findOne(options) 1081 return Video.findOne(options)
1071} 1082}
1072 1083
1073searchAndPopulateAccountAndServerAndTags = function (value: string, field: string, start: number, count: number, sort: string) { 1084searchAndPopulateAccountAndServerAndTags = function (value: string, start: number, count: number, sort: string) {
1074 const serverInclude: Sequelize.IncludeOptions = { 1085 const serverInclude: Sequelize.IncludeOptions = {
1075 model: Video['sequelize'].models.Server, 1086 model: Video['sequelize'].models.Server,
1076 required: false 1087 required: false
@@ -1099,33 +1110,24 @@ searchAndPopulateAccountAndServerAndTags = function (value: string, field: strin
1099 order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ] 1110 order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ]
1100 } 1111 }
1101 1112
1102 if (field === 'tags') { 1113 // TODO: search on tags too
1103 const escapedValue = Video['sequelize'].escape('%' + value + '%') 1114 // const escapedValue = Video['sequelize'].escape('%' + value + '%')
1104 query.where['id'][Sequelize.Op.in] = Video['sequelize'].literal( 1115 // query.where['id'][Sequelize.Op.in] = Video['sequelize'].literal(
1105 `(SELECT "VideoTags"."videoId" 1116 // `(SELECT "VideoTags"."videoId"
1106 FROM "Tags" 1117 // FROM "Tags"
1107 INNER JOIN "VideoTags" ON "Tags"."id" = "VideoTags"."tagId" 1118 // INNER JOIN "VideoTags" ON "Tags"."id" = "VideoTags"."tagId"
1108 WHERE name ILIKE ${escapedValue} 1119 // WHERE name ILIKE ${escapedValue}
1109 )` 1120 // )`
1110 ) 1121 // )
1111 } else if (field === 'host') { 1122
1112 // FIXME: Include our server? (not stored in the database) 1123 // TODO: search on account too
1113 serverInclude.where = { 1124 // accountInclude.where = {
1114 host: { 1125 // name: {
1115 [Sequelize.Op.iLike]: '%' + value + '%' 1126 // [Sequelize.Op.iLike]: '%' + value + '%'
1116 } 1127 // }
1117 } 1128 // }
1118 serverInclude.required = true 1129 query.where['name'] = {
1119 } else if (field === 'account') { 1130 [Sequelize.Op.iLike]: '%' + value + '%'
1120 accountInclude.where = {
1121 name: {
1122 [Sequelize.Op.iLike]: '%' + value + '%'
1123 }
1124 }
1125 } else {
1126 query.where[field] = {
1127 [Sequelize.Op.iLike]: '%' + value + '%'
1128 }
1129 } 1131 }
1130 1132
1131 query.include = [ 1133 query.include = [