diff options
Diffstat (limited to 'server/models/video')
-rw-r--r-- | server/models/video/author-interface.ts | 29 | ||||
-rw-r--r-- | server/models/video/author.ts | 103 | ||||
-rw-r--r-- | server/models/video/index.ts | 1 | ||||
-rw-r--r-- | server/models/video/video-channel-interface.ts | 64 | ||||
-rw-r--r-- | server/models/video/video-channel.ts | 349 | ||||
-rw-r--r-- | server/models/video/video-interface.ts | 16 | ||||
-rw-r--r-- | server/models/video/video.ts | 180 |
7 files changed, 675 insertions, 67 deletions
diff --git a/server/models/video/author-interface.ts b/server/models/video/author-interface.ts index 52a00a1d3..fc69ff3c2 100644 --- a/server/models/video/author-interface.ts +++ b/server/models/video/author-interface.ts | |||
@@ -2,31 +2,44 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | import { PodInstance } from '../pod/pod-interface' | 4 | import { PodInstance } from '../pod/pod-interface' |
5 | import { RemoteVideoAuthorCreateData } from '../../../shared/models/pods/remote-video/remote-video-author-create-request.model' | ||
6 | import { VideoChannelInstance } from './video-channel-interface' | ||
5 | 7 | ||
6 | export namespace AuthorMethods { | 8 | export namespace AuthorMethods { |
7 | export type FindOrCreateAuthor = ( | 9 | export type Load = (id: number) => Promise<AuthorInstance> |
8 | name: string, | 10 | export type LoadByUUID = (uuid: string) => Promise<AuthorInstance> |
9 | podId: number, | 11 | export type LoadAuthorByPodAndUUID = (uuid: string, podId: number, transaction: Sequelize.Transaction) => Promise<AuthorInstance> |
10 | userId: number, | 12 | export type ListOwned = () => Promise<AuthorInstance[]> |
11 | transaction: Sequelize.Transaction | 13 | |
12 | ) => Promise<AuthorInstance> | 14 | export type ToAddRemoteJSON = (this: AuthorInstance) => RemoteVideoAuthorCreateData |
15 | export type IsOwned = (this: AuthorInstance) => boolean | ||
13 | } | 16 | } |
14 | 17 | ||
15 | export interface AuthorClass { | 18 | export interface AuthorClass { |
16 | findOrCreateAuthor: AuthorMethods.FindOrCreateAuthor | 19 | loadAuthorByPodAndUUID: AuthorMethods.LoadAuthorByPodAndUUID |
20 | load: AuthorMethods.Load | ||
21 | loadByUUID: AuthorMethods.LoadByUUID | ||
22 | listOwned: AuthorMethods.ListOwned | ||
17 | } | 23 | } |
18 | 24 | ||
19 | export interface AuthorAttributes { | 25 | export interface AuthorAttributes { |
20 | name: string | 26 | name: string |
27 | uuid?: string | ||
28 | |||
29 | podId?: number | ||
30 | userId?: number | ||
21 | } | 31 | } |
22 | 32 | ||
23 | export interface AuthorInstance extends AuthorClass, AuthorAttributes, Sequelize.Instance<AuthorAttributes> { | 33 | export interface AuthorInstance extends AuthorClass, AuthorAttributes, Sequelize.Instance<AuthorAttributes> { |
34 | isOwned: AuthorMethods.IsOwned | ||
35 | toAddRemoteJSON: AuthorMethods.ToAddRemoteJSON | ||
36 | |||
24 | id: number | 37 | id: number |
25 | createdAt: Date | 38 | createdAt: Date |
26 | updatedAt: Date | 39 | updatedAt: Date |
27 | 40 | ||
28 | podId: number | ||
29 | Pod: PodInstance | 41 | Pod: PodInstance |
42 | VideoChannels: VideoChannelInstance[] | ||
30 | } | 43 | } |
31 | 44 | ||
32 | export interface AuthorModel extends AuthorClass, Sequelize.Model<AuthorInstance, AuthorAttributes> {} | 45 | export interface AuthorModel extends AuthorClass, Sequelize.Model<AuthorInstance, AuthorAttributes> {} |
diff --git a/server/models/video/author.ts b/server/models/video/author.ts index fd0f44f6b..6f27ea7bd 100644 --- a/server/models/video/author.ts +++ b/server/models/video/author.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | import { isUserUsernameValid } from '../../helpers' | 3 | import { isUserUsernameValid } from '../../helpers' |
4 | import { removeVideoAuthorToFriends } from '../../lib' | ||
4 | 5 | ||
5 | import { addMethodsToModel } from '../utils' | 6 | import { addMethodsToModel } from '../utils' |
6 | import { | 7 | import { |
@@ -11,11 +12,24 @@ import { | |||
11 | } from './author-interface' | 12 | } from './author-interface' |
12 | 13 | ||
13 | let Author: Sequelize.Model<AuthorInstance, AuthorAttributes> | 14 | let Author: Sequelize.Model<AuthorInstance, AuthorAttributes> |
14 | let findOrCreateAuthor: AuthorMethods.FindOrCreateAuthor | 15 | let loadAuthorByPodAndUUID: AuthorMethods.LoadAuthorByPodAndUUID |
16 | let load: AuthorMethods.Load | ||
17 | let loadByUUID: AuthorMethods.LoadByUUID | ||
18 | let listOwned: AuthorMethods.ListOwned | ||
19 | let isOwned: AuthorMethods.IsOwned | ||
20 | let toAddRemoteJSON: AuthorMethods.ToAddRemoteJSON | ||
15 | 21 | ||
16 | export default function defineAuthor (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { | 22 | export default function defineAuthor (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { |
17 | Author = sequelize.define<AuthorInstance, AuthorAttributes>('Author', | 23 | Author = sequelize.define<AuthorInstance, AuthorAttributes>('Author', |
18 | { | 24 | { |
25 | uuid: { | ||
26 | type: DataTypes.UUID, | ||
27 | defaultValue: DataTypes.UUIDV4, | ||
28 | allowNull: false, | ||
29 | validate: { | ||
30 | isUUID: 4 | ||
31 | } | ||
32 | }, | ||
19 | name: { | 33 | name: { |
20 | type: DataTypes.STRING, | 34 | type: DataTypes.STRING, |
21 | allowNull: false, | 35 | allowNull: false, |
@@ -43,12 +57,23 @@ export default function defineAuthor (sequelize: Sequelize.Sequelize, DataTypes: | |||
43 | fields: [ 'name', 'podId' ], | 57 | fields: [ 'name', 'podId' ], |
44 | unique: true | 58 | unique: true |
45 | } | 59 | } |
46 | ] | 60 | ], |
61 | hooks: { afterDestroy } | ||
47 | } | 62 | } |
48 | ) | 63 | ) |
49 | 64 | ||
50 | const classMethods = [ associate, findOrCreateAuthor ] | 65 | const classMethods = [ |
51 | addMethodsToModel(Author, classMethods) | 66 | associate, |
67 | loadAuthorByPodAndUUID, | ||
68 | load, | ||
69 | loadByUUID, | ||
70 | listOwned | ||
71 | ] | ||
72 | const instanceMethods = [ | ||
73 | isOwned, | ||
74 | toAddRemoteJSON | ||
75 | ] | ||
76 | addMethodsToModel(Author, classMethods, instanceMethods) | ||
52 | 77 | ||
53 | return Author | 78 | return Author |
54 | } | 79 | } |
@@ -72,27 +97,75 @@ function associate (models) { | |||
72 | onDelete: 'cascade' | 97 | onDelete: 'cascade' |
73 | }) | 98 | }) |
74 | 99 | ||
75 | Author.hasMany(models.Video, { | 100 | Author.hasMany(models.VideoChannel, { |
76 | foreignKey: { | 101 | foreignKey: { |
77 | name: 'authorId', | 102 | name: 'authorId', |
78 | allowNull: false | 103 | allowNull: false |
79 | }, | 104 | }, |
80 | onDelete: 'cascade' | 105 | onDelete: 'cascade', |
106 | hooks: true | ||
81 | }) | 107 | }) |
82 | } | 108 | } |
83 | 109 | ||
84 | findOrCreateAuthor = function (name: string, podId: number, userId: number, transaction: Sequelize.Transaction) { | 110 | function afterDestroy (author: AuthorInstance, options: { transaction: Sequelize.Transaction }) { |
85 | const author = { | 111 | if (author.isOwned()) { |
86 | name, | 112 | const removeVideoAuthorToFriendsParams = { |
87 | podId, | 113 | uuid: author.uuid |
88 | userId | 114 | } |
115 | |||
116 | return removeVideoAuthorToFriends(removeVideoAuthorToFriendsParams, options.transaction) | ||
117 | } | ||
118 | |||
119 | return undefined | ||
120 | } | ||
121 | |||
122 | toAddRemoteJSON = function (this: AuthorInstance) { | ||
123 | const json = { | ||
124 | uuid: this.uuid, | ||
125 | name: this.name | ||
126 | } | ||
127 | |||
128 | return json | ||
129 | } | ||
130 | |||
131 | isOwned = function (this: AuthorInstance) { | ||
132 | return this.podId === null | ||
133 | } | ||
134 | |||
135 | // ------------------------------ STATICS ------------------------------ | ||
136 | |||
137 | listOwned = function () { | ||
138 | const query: Sequelize.FindOptions<AuthorAttributes> = { | ||
139 | where: { | ||
140 | podId: null | ||
141 | } | ||
142 | } | ||
143 | |||
144 | return Author.findAll(query) | ||
145 | } | ||
146 | |||
147 | load = function (id: number) { | ||
148 | return Author.findById(id) | ||
149 | } | ||
150 | |||
151 | loadByUUID = function (uuid: string) { | ||
152 | const query: Sequelize.FindOptions<AuthorAttributes> = { | ||
153 | where: { | ||
154 | uuid | ||
155 | } | ||
89 | } | 156 | } |
90 | 157 | ||
91 | const query: Sequelize.FindOrInitializeOptions<AuthorAttributes> = { | 158 | return Author.findOne(query) |
92 | where: author, | 159 | } |
93 | defaults: author, | 160 | |
161 | loadAuthorByPodAndUUID = function (uuid: string, podId: number, transaction: Sequelize.Transaction) { | ||
162 | const query: Sequelize.FindOptions<AuthorAttributes> = { | ||
163 | where: { | ||
164 | podId, | ||
165 | uuid | ||
166 | }, | ||
94 | transaction | 167 | transaction |
95 | } | 168 | } |
96 | 169 | ||
97 | return Author.findOrCreate(query).then(([ authorInstance ]) => authorInstance) | 170 | return Author.find(query) |
98 | } | 171 | } |
diff --git a/server/models/video/index.ts b/server/models/video/index.ts index 08b360376..dba6a5590 100644 --- a/server/models/video/index.ts +++ b/server/models/video/index.ts | |||
@@ -2,6 +2,7 @@ export * from './author-interface' | |||
2 | export * from './tag-interface' | 2 | export * from './tag-interface' |
3 | export * from './video-abuse-interface' | 3 | export * from './video-abuse-interface' |
4 | export * from './video-blacklist-interface' | 4 | export * from './video-blacklist-interface' |
5 | export * from './video-channel-interface' | ||
5 | export * from './video-tag-interface' | 6 | export * from './video-tag-interface' |
6 | export * from './video-file-interface' | 7 | export * from './video-file-interface' |
7 | export * from './video-interface' | 8 | export * from './video-interface' |
diff --git a/server/models/video/video-channel-interface.ts b/server/models/video/video-channel-interface.ts new file mode 100644 index 000000000..b8d3e0f42 --- /dev/null +++ b/server/models/video/video-channel-interface.ts | |||
@@ -0,0 +1,64 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | import * as Promise from 'bluebird' | ||
3 | |||
4 | import { ResultList, RemoteVideoChannelCreateData, RemoteVideoChannelUpdateData } from '../../../shared' | ||
5 | |||
6 | // Don't use barrel, import just what we need | ||
7 | import { VideoChannel as FormattedVideoChannel } from '../../../shared/models/videos/video-channel.model' | ||
8 | import { AuthorInstance } from './author-interface' | ||
9 | import { VideoInstance } from './video-interface' | ||
10 | |||
11 | export namespace VideoChannelMethods { | ||
12 | export type ToFormattedJSON = (this: VideoChannelInstance) => FormattedVideoChannel | ||
13 | export type ToAddRemoteJSON = (this: VideoChannelInstance) => RemoteVideoChannelCreateData | ||
14 | export type ToUpdateRemoteJSON = (this: VideoChannelInstance) => RemoteVideoChannelUpdateData | ||
15 | export type IsOwned = (this: VideoChannelInstance) => boolean | ||
16 | |||
17 | export type CountByAuthor = (authorId: number) => Promise<number> | ||
18 | export type ListOwned = () => Promise<VideoChannelInstance[]> | ||
19 | export type ListForApi = (start: number, count: number, sort: string) => Promise< ResultList<VideoChannelInstance> > | ||
20 | export type LoadByIdAndAuthor = (id: number, authorId: number) => Promise<VideoChannelInstance> | ||
21 | export type ListByAuthor = (authorId: number) => Promise< ResultList<VideoChannelInstance> > | ||
22 | export type LoadAndPopulateAuthor = (id: number) => Promise<VideoChannelInstance> | ||
23 | export type LoadByUUIDAndPopulateAuthor = (uuid: string) => Promise<VideoChannelInstance> | ||
24 | export type LoadByUUID = (uuid: string, t?: Sequelize.Transaction) => Promise<VideoChannelInstance> | ||
25 | export type LoadByHostAndUUID = (uuid: string, podHost: string, t?: Sequelize.Transaction) => Promise<VideoChannelInstance> | ||
26 | export type LoadAndPopulateAuthorAndVideos = (id: number) => Promise<VideoChannelInstance> | ||
27 | } | ||
28 | |||
29 | export interface VideoChannelClass { | ||
30 | countByAuthor: VideoChannelMethods.CountByAuthor | ||
31 | listForApi: VideoChannelMethods.ListForApi | ||
32 | listByAuthor: VideoChannelMethods.ListByAuthor | ||
33 | listOwned: VideoChannelMethods.ListOwned | ||
34 | loadByIdAndAuthor: VideoChannelMethods.LoadByIdAndAuthor | ||
35 | loadByUUID: VideoChannelMethods.LoadByUUID | ||
36 | loadByHostAndUUID: VideoChannelMethods.LoadByHostAndUUID | ||
37 | loadAndPopulateAuthor: VideoChannelMethods.LoadAndPopulateAuthor | ||
38 | loadByUUIDAndPopulateAuthor: VideoChannelMethods.LoadByUUIDAndPopulateAuthor | ||
39 | loadAndPopulateAuthorAndVideos: VideoChannelMethods.LoadAndPopulateAuthorAndVideos | ||
40 | } | ||
41 | |||
42 | export interface VideoChannelAttributes { | ||
43 | id?: number | ||
44 | uuid?: string | ||
45 | name: string | ||
46 | description: string | ||
47 | remote: boolean | ||
48 | |||
49 | Author?: AuthorInstance | ||
50 | Videos?: VideoInstance[] | ||
51 | } | ||
52 | |||
53 | export interface VideoChannelInstance extends VideoChannelClass, VideoChannelAttributes, Sequelize.Instance<VideoChannelAttributes> { | ||
54 | id: number | ||
55 | createdAt: Date | ||
56 | updatedAt: Date | ||
57 | |||
58 | isOwned: VideoChannelMethods.IsOwned | ||
59 | toFormattedJSON: VideoChannelMethods.ToFormattedJSON | ||
60 | toAddRemoteJSON: VideoChannelMethods.ToAddRemoteJSON | ||
61 | toUpdateRemoteJSON: VideoChannelMethods.ToUpdateRemoteJSON | ||
62 | } | ||
63 | |||
64 | export interface VideoChannelModel extends VideoChannelClass, Sequelize.Model<VideoChannelInstance, VideoChannelAttributes> {} | ||
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts new file mode 100644 index 000000000..e469383e9 --- /dev/null +++ b/server/models/video/video-channel.ts | |||
@@ -0,0 +1,349 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | import { isVideoChannelNameValid, isVideoChannelDescriptionValid } from '../../helpers' | ||
4 | import { removeVideoChannelToFriends } from '../../lib' | ||
5 | |||
6 | import { addMethodsToModel, getSort } from '../utils' | ||
7 | import { | ||
8 | VideoChannelInstance, | ||
9 | VideoChannelAttributes, | ||
10 | |||
11 | VideoChannelMethods | ||
12 | } from './video-channel-interface' | ||
13 | |||
14 | let VideoChannel: Sequelize.Model<VideoChannelInstance, VideoChannelAttributes> | ||
15 | let toFormattedJSON: VideoChannelMethods.ToFormattedJSON | ||
16 | let toAddRemoteJSON: VideoChannelMethods.ToAddRemoteJSON | ||
17 | let toUpdateRemoteJSON: VideoChannelMethods.ToUpdateRemoteJSON | ||
18 | let isOwned: VideoChannelMethods.IsOwned | ||
19 | let countByAuthor: VideoChannelMethods.CountByAuthor | ||
20 | let listOwned: VideoChannelMethods.ListOwned | ||
21 | let listForApi: VideoChannelMethods.ListForApi | ||
22 | let listByAuthor: VideoChannelMethods.ListByAuthor | ||
23 | let loadByIdAndAuthor: VideoChannelMethods.LoadByIdAndAuthor | ||
24 | let loadByUUID: VideoChannelMethods.LoadByUUID | ||
25 | let loadAndPopulateAuthor: VideoChannelMethods.LoadAndPopulateAuthor | ||
26 | let loadByUUIDAndPopulateAuthor: VideoChannelMethods.LoadByUUIDAndPopulateAuthor | ||
27 | let loadByHostAndUUID: VideoChannelMethods.LoadByHostAndUUID | ||
28 | let loadAndPopulateAuthorAndVideos: VideoChannelMethods.LoadAndPopulateAuthorAndVideos | ||
29 | |||
30 | export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { | ||
31 | VideoChannel = sequelize.define<VideoChannelInstance, VideoChannelAttributes>('VideoChannel', | ||
32 | { | ||
33 | uuid: { | ||
34 | type: DataTypes.UUID, | ||
35 | defaultValue: DataTypes.UUIDV4, | ||
36 | allowNull: false, | ||
37 | validate: { | ||
38 | isUUID: 4 | ||
39 | } | ||
40 | }, | ||
41 | name: { | ||
42 | type: DataTypes.STRING, | ||
43 | allowNull: false, | ||
44 | validate: { | ||
45 | nameValid: value => { | ||
46 | const res = isVideoChannelNameValid(value) | ||
47 | if (res === false) throw new Error('Video channel name is not valid.') | ||
48 | } | ||
49 | } | ||
50 | }, | ||
51 | description: { | ||
52 | type: DataTypes.STRING, | ||
53 | allowNull: true, | ||
54 | validate: { | ||
55 | descriptionValid: value => { | ||
56 | const res = isVideoChannelDescriptionValid(value) | ||
57 | if (res === false) throw new Error('Video channel description is not valid.') | ||
58 | } | ||
59 | } | ||
60 | }, | ||
61 | remote: { | ||
62 | type: DataTypes.BOOLEAN, | ||
63 | allowNull: false, | ||
64 | defaultValue: false | ||
65 | } | ||
66 | }, | ||
67 | { | ||
68 | indexes: [ | ||
69 | { | ||
70 | fields: [ 'authorId' ] | ||
71 | } | ||
72 | ], | ||
73 | hooks: { | ||
74 | afterDestroy | ||
75 | } | ||
76 | } | ||
77 | ) | ||
78 | |||
79 | const classMethods = [ | ||
80 | associate, | ||
81 | |||
82 | listForApi, | ||
83 | listByAuthor, | ||
84 | listOwned, | ||
85 | loadByIdAndAuthor, | ||
86 | loadAndPopulateAuthor, | ||
87 | loadByUUIDAndPopulateAuthor, | ||
88 | loadByUUID, | ||
89 | loadByHostAndUUID, | ||
90 | loadAndPopulateAuthorAndVideos, | ||
91 | countByAuthor | ||
92 | ] | ||
93 | const instanceMethods = [ | ||
94 | isOwned, | ||
95 | toFormattedJSON, | ||
96 | toAddRemoteJSON, | ||
97 | toUpdateRemoteJSON | ||
98 | ] | ||
99 | addMethodsToModel(VideoChannel, classMethods, instanceMethods) | ||
100 | |||
101 | return VideoChannel | ||
102 | } | ||
103 | |||
104 | // ------------------------------ METHODS ------------------------------ | ||
105 | |||
106 | isOwned = function (this: VideoChannelInstance) { | ||
107 | return this.remote === false | ||
108 | } | ||
109 | |||
110 | toFormattedJSON = function (this: VideoChannelInstance) { | ||
111 | const json = { | ||
112 | id: this.id, | ||
113 | uuid: this.uuid, | ||
114 | name: this.name, | ||
115 | description: this.description, | ||
116 | isLocal: this.isOwned(), | ||
117 | createdAt: this.createdAt, | ||
118 | updatedAt: this.updatedAt | ||
119 | } | ||
120 | |||
121 | if (this.Author !== undefined) { | ||
122 | json['owner'] = { | ||
123 | name: this.Author.name, | ||
124 | uuid: this.Author.uuid | ||
125 | } | ||
126 | } | ||
127 | |||
128 | if (Array.isArray(this.Videos)) { | ||
129 | json['videos'] = this.Videos.map(v => v.toFormattedJSON()) | ||
130 | } | ||
131 | |||
132 | return json | ||
133 | } | ||
134 | |||
135 | toAddRemoteJSON = function (this: VideoChannelInstance) { | ||
136 | const json = { | ||
137 | uuid: this.uuid, | ||
138 | name: this.name, | ||
139 | description: this.description, | ||
140 | createdAt: this.createdAt, | ||
141 | updatedAt: this.updatedAt, | ||
142 | ownerUUID: this.Author.uuid | ||
143 | } | ||
144 | |||
145 | return json | ||
146 | } | ||
147 | |||
148 | toUpdateRemoteJSON = function (this: VideoChannelInstance) { | ||
149 | const json = { | ||
150 | uuid: this.uuid, | ||
151 | name: this.name, | ||
152 | description: this.description, | ||
153 | createdAt: this.createdAt, | ||
154 | updatedAt: this.updatedAt, | ||
155 | ownerUUID: this.Author.uuid | ||
156 | } | ||
157 | |||
158 | return json | ||
159 | } | ||
160 | |||
161 | // ------------------------------ STATICS ------------------------------ | ||
162 | |||
163 | function associate (models) { | ||
164 | VideoChannel.belongsTo(models.Author, { | ||
165 | foreignKey: { | ||
166 | name: 'authorId', | ||
167 | allowNull: false | ||
168 | }, | ||
169 | onDelete: 'CASCADE' | ||
170 | }) | ||
171 | |||
172 | VideoChannel.hasMany(models.Video, { | ||
173 | foreignKey: { | ||
174 | name: 'channelId', | ||
175 | allowNull: false | ||
176 | }, | ||
177 | onDelete: 'CASCADE' | ||
178 | }) | ||
179 | } | ||
180 | |||
181 | function afterDestroy (videoChannel: VideoChannelInstance, options: { transaction: Sequelize.Transaction }) { | ||
182 | if (videoChannel.isOwned()) { | ||
183 | const removeVideoChannelToFriendsParams = { | ||
184 | uuid: videoChannel.uuid | ||
185 | } | ||
186 | |||
187 | return removeVideoChannelToFriends(removeVideoChannelToFriendsParams, options.transaction) | ||
188 | } | ||
189 | |||
190 | return undefined | ||
191 | } | ||
192 | |||
193 | countByAuthor = function (authorId: number) { | ||
194 | const query = { | ||
195 | where: { | ||
196 | authorId | ||
197 | } | ||
198 | } | ||
199 | |||
200 | return VideoChannel.count(query) | ||
201 | } | ||
202 | |||
203 | listOwned = function () { | ||
204 | const query = { | ||
205 | where: { | ||
206 | remote: false | ||
207 | }, | ||
208 | include: [ VideoChannel['sequelize'].models.Author ] | ||
209 | } | ||
210 | |||
211 | return VideoChannel.findAll(query) | ||
212 | } | ||
213 | |||
214 | listForApi = function (start: number, count: number, sort: string) { | ||
215 | const query = { | ||
216 | offset: start, | ||
217 | limit: count, | ||
218 | order: [ getSort(sort) ], | ||
219 | include: [ | ||
220 | { | ||
221 | model: VideoChannel['sequelize'].models.Author, | ||
222 | required: true, | ||
223 | include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] | ||
224 | } | ||
225 | ] | ||
226 | } | ||
227 | |||
228 | return VideoChannel.findAndCountAll(query).then(({ rows, count }) => { | ||
229 | return { total: count, data: rows } | ||
230 | }) | ||
231 | } | ||
232 | |||
233 | listByAuthor = function (authorId: number) { | ||
234 | const query = { | ||
235 | order: [ getSort('createdAt') ], | ||
236 | include: [ | ||
237 | { | ||
238 | model: VideoChannel['sequelize'].models.Author, | ||
239 | where: { | ||
240 | id: authorId | ||
241 | }, | ||
242 | required: true, | ||
243 | include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] | ||
244 | } | ||
245 | ] | ||
246 | } | ||
247 | |||
248 | return VideoChannel.findAndCountAll(query).then(({ rows, count }) => { | ||
249 | return { total: count, data: rows } | ||
250 | }) | ||
251 | } | ||
252 | |||
253 | loadByUUID = function (uuid: string, t?: Sequelize.Transaction) { | ||
254 | const query: Sequelize.FindOptions<VideoChannelAttributes> = { | ||
255 | where: { | ||
256 | uuid | ||
257 | } | ||
258 | } | ||
259 | |||
260 | if (t !== undefined) query.transaction = t | ||
261 | |||
262 | return VideoChannel.findOne(query) | ||
263 | } | ||
264 | |||
265 | loadByHostAndUUID = function (fromHost: string, uuid: string, t?: Sequelize.Transaction) { | ||
266 | const query: Sequelize.FindOptions<VideoChannelAttributes> = { | ||
267 | where: { | ||
268 | uuid | ||
269 | }, | ||
270 | include: [ | ||
271 | { | ||
272 | model: VideoChannel['sequelize'].models.Author, | ||
273 | include: [ | ||
274 | { | ||
275 | model: VideoChannel['sequelize'].models.Pod, | ||
276 | required: true, | ||
277 | where: { | ||
278 | host: fromHost | ||
279 | } | ||
280 | } | ||
281 | ] | ||
282 | } | ||
283 | ] | ||
284 | } | ||
285 | |||
286 | if (t !== undefined) query.transaction = t | ||
287 | |||
288 | return VideoChannel.findOne(query) | ||
289 | } | ||
290 | |||
291 | loadByIdAndAuthor = function (id: number, authorId: number) { | ||
292 | const options = { | ||
293 | where: { | ||
294 | id, | ||
295 | authorId | ||
296 | }, | ||
297 | include: [ | ||
298 | { | ||
299 | model: VideoChannel['sequelize'].models.Author, | ||
300 | include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] | ||
301 | } | ||
302 | ] | ||
303 | } | ||
304 | |||
305 | return VideoChannel.findOne(options) | ||
306 | } | ||
307 | |||
308 | loadAndPopulateAuthor = function (id: number) { | ||
309 | const options = { | ||
310 | include: [ | ||
311 | { | ||
312 | model: VideoChannel['sequelize'].models.Author, | ||
313 | include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] | ||
314 | } | ||
315 | ] | ||
316 | } | ||
317 | |||
318 | return VideoChannel.findById(id, options) | ||
319 | } | ||
320 | |||
321 | loadByUUIDAndPopulateAuthor = function (uuid: string) { | ||
322 | const options = { | ||
323 | where: { | ||
324 | uuid | ||
325 | }, | ||
326 | include: [ | ||
327 | { | ||
328 | model: VideoChannel['sequelize'].models.Author, | ||
329 | include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] | ||
330 | } | ||
331 | ] | ||
332 | } | ||
333 | |||
334 | return VideoChannel.findOne(options) | ||
335 | } | ||
336 | |||
337 | loadAndPopulateAuthorAndVideos = function (id: number) { | ||
338 | const options = { | ||
339 | include: [ | ||
340 | { | ||
341 | model: VideoChannel['sequelize'].models.Author, | ||
342 | include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] | ||
343 | }, | ||
344 | VideoChannel['sequelize'].models.Video | ||
345 | ] | ||
346 | } | ||
347 | |||
348 | return VideoChannel.findById(id, options) | ||
349 | } | ||
diff --git a/server/models/video/video-interface.ts b/server/models/video/video-interface.ts index 86ce84dd9..4b5ae08c2 100644 --- a/server/models/video/video-interface.ts +++ b/server/models/video/video-interface.ts | |||
@@ -6,16 +6,21 @@ import { TagAttributes, TagInstance } from './tag-interface' | |||
6 | import { VideoFileAttributes, VideoFileInstance } from './video-file-interface' | 6 | import { VideoFileAttributes, VideoFileInstance } from './video-file-interface' |
7 | 7 | ||
8 | // Don't use barrel, import just what we need | 8 | // Don't use barrel, import just what we need |
9 | import { Video as FormattedVideo } from '../../../shared/models/videos/video.model' | 9 | import { |
10 | Video as FormattedVideo, | ||
11 | VideoDetails as FormattedDetailsVideo | ||
12 | } from '../../../shared/models/videos/video.model' | ||
10 | import { RemoteVideoUpdateData } from '../../../shared/models/pods/remote-video/remote-video-update-request.model' | 13 | import { RemoteVideoUpdateData } from '../../../shared/models/pods/remote-video/remote-video-update-request.model' |
11 | import { RemoteVideoCreateData } from '../../../shared/models/pods/remote-video/remote-video-create-request.model' | 14 | import { RemoteVideoCreateData } from '../../../shared/models/pods/remote-video/remote-video-create-request.model' |
12 | import { ResultList } from '../../../shared/models/result-list.model' | 15 | import { ResultList } from '../../../shared/models/result-list.model' |
16 | import { VideoChannelInstance } from './video-channel-interface' | ||
13 | 17 | ||
14 | export namespace VideoMethods { | 18 | export namespace VideoMethods { |
15 | export type GetThumbnailName = (this: VideoInstance) => string | 19 | export type GetThumbnailName = (this: VideoInstance) => string |
16 | export type GetPreviewName = (this: VideoInstance) => string | 20 | export type GetPreviewName = (this: VideoInstance) => string |
17 | export type IsOwned = (this: VideoInstance) => boolean | 21 | export type IsOwned = (this: VideoInstance) => boolean |
18 | export type ToFormattedJSON = (this: VideoInstance) => FormattedVideo | 22 | export type ToFormattedJSON = (this: VideoInstance) => FormattedVideo |
23 | export type ToFormattedDetailsJSON = (this: VideoInstance) => FormattedDetailsVideo | ||
19 | 24 | ||
20 | export type GetOriginalFile = (this: VideoInstance) => VideoFileInstance | 25 | export type GetOriginalFile = (this: VideoInstance) => VideoFileInstance |
21 | export type GetTorrentFileName = (this: VideoInstance, videoFile: VideoFileInstance) => string | 26 | export type GetTorrentFileName = (this: VideoInstance, videoFile: VideoFileInstance) => string |
@@ -52,8 +57,8 @@ export namespace VideoMethods { | |||
52 | ) => Promise< ResultList<VideoInstance> > | 57 | ) => Promise< ResultList<VideoInstance> > |
53 | 58 | ||
54 | export type Load = (id: number) => Promise<VideoInstance> | 59 | export type Load = (id: number) => Promise<VideoInstance> |
55 | export type LoadByUUID = (uuid: string) => Promise<VideoInstance> | 60 | export type LoadByUUID = (uuid: string, t?: Sequelize.Transaction) => Promise<VideoInstance> |
56 | export type LoadByHostAndUUID = (fromHost: string, uuid: string) => Promise<VideoInstance> | 61 | export type LoadByHostAndUUID = (fromHost: string, uuid: string, t?: Sequelize.Transaction) => Promise<VideoInstance> |
57 | export type LoadAndPopulateAuthor = (id: number) => Promise<VideoInstance> | 62 | export type LoadAndPopulateAuthor = (id: number) => Promise<VideoInstance> |
58 | export type LoadAndPopulateAuthorAndPodAndTags = (id: number) => Promise<VideoInstance> | 63 | export type LoadAndPopulateAuthorAndPodAndTags = (id: number) => Promise<VideoInstance> |
59 | export type LoadByUUIDAndPopulateAuthorAndPodAndTags = (uuid: string) => Promise<VideoInstance> | 64 | export type LoadByUUIDAndPopulateAuthorAndPodAndTags = (uuid: string) => Promise<VideoInstance> |
@@ -94,7 +99,9 @@ export interface VideoAttributes { | |||
94 | dislikes?: number | 99 | dislikes?: number |
95 | remote: boolean | 100 | remote: boolean |
96 | 101 | ||
97 | Author?: AuthorInstance | 102 | channelId?: number |
103 | |||
104 | VideoChannel?: VideoChannelInstance | ||
98 | Tags?: TagInstance[] | 105 | Tags?: TagInstance[] |
99 | VideoFiles?: VideoFileInstance[] | 106 | VideoFiles?: VideoFileInstance[] |
100 | } | 107 | } |
@@ -121,6 +128,7 @@ export interface VideoInstance extends VideoClass, VideoAttributes, Sequelize.In | |||
121 | removeTorrent: VideoMethods.RemoveTorrent | 128 | removeTorrent: VideoMethods.RemoveTorrent |
122 | toAddRemoteJSON: VideoMethods.ToAddRemoteJSON | 129 | toAddRemoteJSON: VideoMethods.ToAddRemoteJSON |
123 | toFormattedJSON: VideoMethods.ToFormattedJSON | 130 | toFormattedJSON: VideoMethods.ToFormattedJSON |
131 | toFormattedDetailsJSON: VideoMethods.ToFormattedDetailsJSON | ||
124 | toUpdateRemoteJSON: VideoMethods.ToUpdateRemoteJSON | 132 | toUpdateRemoteJSON: VideoMethods.ToUpdateRemoteJSON |
125 | optimizeOriginalVideofile: VideoMethods.OptimizeOriginalVideofile | 133 | optimizeOriginalVideofile: VideoMethods.OptimizeOriginalVideofile |
126 | transcodeOriginalVideofile: VideoMethods.TranscodeOriginalVideofile | 134 | transcodeOriginalVideofile: VideoMethods.TranscodeOriginalVideofile |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 0b1af4d21..d9b976404 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -60,6 +60,7 @@ let getPreviewPath: VideoMethods.GetPreviewPath | |||
60 | let getTorrentFileName: VideoMethods.GetTorrentFileName | 60 | let getTorrentFileName: VideoMethods.GetTorrentFileName |
61 | let isOwned: VideoMethods.IsOwned | 61 | let isOwned: VideoMethods.IsOwned |
62 | let toFormattedJSON: VideoMethods.ToFormattedJSON | 62 | let toFormattedJSON: VideoMethods.ToFormattedJSON |
63 | let toFormattedDetailsJSON: VideoMethods.ToFormattedDetailsJSON | ||
63 | let toAddRemoteJSON: VideoMethods.ToAddRemoteJSON | 64 | let toAddRemoteJSON: VideoMethods.ToAddRemoteJSON |
64 | let toUpdateRemoteJSON: VideoMethods.ToUpdateRemoteJSON | 65 | let toUpdateRemoteJSON: VideoMethods.ToUpdateRemoteJSON |
65 | let optimizeOriginalVideofile: VideoMethods.OptimizeOriginalVideofile | 66 | let optimizeOriginalVideofile: VideoMethods.OptimizeOriginalVideofile |
@@ -206,9 +207,6 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da | |||
206 | { | 207 | { |
207 | indexes: [ | 208 | indexes: [ |
208 | { | 209 | { |
209 | fields: [ 'authorId' ] | ||
210 | }, | ||
211 | { | ||
212 | fields: [ 'name' ] | 210 | fields: [ 'name' ] |
213 | }, | 211 | }, |
214 | { | 212 | { |
@@ -225,6 +223,9 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da | |||
225 | }, | 223 | }, |
226 | { | 224 | { |
227 | fields: [ 'uuid' ] | 225 | fields: [ 'uuid' ] |
226 | }, | ||
227 | { | ||
228 | fields: [ 'channelId' ] | ||
228 | } | 229 | } |
229 | ], | 230 | ], |
230 | hooks: { | 231 | hooks: { |
@@ -268,6 +269,7 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da | |||
268 | removeTorrent, | 269 | removeTorrent, |
269 | toAddRemoteJSON, | 270 | toAddRemoteJSON, |
270 | toFormattedJSON, | 271 | toFormattedJSON, |
272 | toFormattedDetailsJSON, | ||
271 | toUpdateRemoteJSON, | 273 | toUpdateRemoteJSON, |
272 | optimizeOriginalVideofile, | 274 | optimizeOriginalVideofile, |
273 | transcodeOriginalVideofile, | 275 | transcodeOriginalVideofile, |
@@ -282,9 +284,9 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da | |||
282 | // ------------------------------ METHODS ------------------------------ | 284 | // ------------------------------ METHODS ------------------------------ |
283 | 285 | ||
284 | function associate (models) { | 286 | function associate (models) { |
285 | Video.belongsTo(models.Author, { | 287 | Video.belongsTo(models.VideoChannel, { |
286 | foreignKey: { | 288 | foreignKey: { |
287 | name: 'authorId', | 289 | name: 'channelId', |
288 | allowNull: false | 290 | allowNull: false |
289 | }, | 291 | }, |
290 | onDelete: 'cascade' | 292 | onDelete: 'cascade' |
@@ -439,8 +441,8 @@ getPreviewPath = function (this: VideoInstance) { | |||
439 | toFormattedJSON = function (this: VideoInstance) { | 441 | toFormattedJSON = function (this: VideoInstance) { |
440 | let podHost | 442 | let podHost |
441 | 443 | ||
442 | if (this.Author.Pod) { | 444 | if (this.VideoChannel.Author.Pod) { |
443 | podHost = this.Author.Pod.host | 445 | podHost = this.VideoChannel.Author.Pod.host |
444 | } else { | 446 | } else { |
445 | // It means it's our video | 447 | // It means it's our video |
446 | podHost = CONFIG.WEBSERVER.HOST | 448 | podHost = CONFIG.WEBSERVER.HOST |
@@ -472,7 +474,59 @@ toFormattedJSON = function (this: VideoInstance) { | |||
472 | description: this.description, | 474 | description: this.description, |
473 | podHost, | 475 | podHost, |
474 | isLocal: this.isOwned(), | 476 | isLocal: this.isOwned(), |
475 | author: this.Author.name, | 477 | author: this.VideoChannel.Author.name, |
478 | duration: this.duration, | ||
479 | views: this.views, | ||
480 | likes: this.likes, | ||
481 | dislikes: this.dislikes, | ||
482 | tags: map<TagInstance, string>(this.Tags, 'name'), | ||
483 | thumbnailPath: this.getThumbnailPath(), | ||
484 | previewPath: this.getPreviewPath(), | ||
485 | embedPath: this.getEmbedPath(), | ||
486 | createdAt: this.createdAt, | ||
487 | updatedAt: this.updatedAt | ||
488 | } | ||
489 | |||
490 | return json | ||
491 | } | ||
492 | |||
493 | toFormattedDetailsJSON = function (this: VideoInstance) { | ||
494 | let podHost | ||
495 | |||
496 | if (this.VideoChannel.Author.Pod) { | ||
497 | podHost = this.VideoChannel.Author.Pod.host | ||
498 | } else { | ||
499 | // It means it's our video | ||
500 | podHost = CONFIG.WEBSERVER.HOST | ||
501 | } | ||
502 | |||
503 | // Maybe our pod is not up to date and there are new categories since our version | ||
504 | let categoryLabel = VIDEO_CATEGORIES[this.category] | ||
505 | if (!categoryLabel) categoryLabel = 'Misc' | ||
506 | |||
507 | // Maybe our pod is not up to date and there are new licences since our version | ||
508 | let licenceLabel = VIDEO_LICENCES[this.licence] | ||
509 | if (!licenceLabel) licenceLabel = 'Unknown' | ||
510 | |||
511 | // Language is an optional attribute | ||
512 | let languageLabel = VIDEO_LANGUAGES[this.language] | ||
513 | if (!languageLabel) languageLabel = 'Unknown' | ||
514 | |||
515 | const json = { | ||
516 | id: this.id, | ||
517 | uuid: this.uuid, | ||
518 | name: this.name, | ||
519 | category: this.category, | ||
520 | categoryLabel, | ||
521 | licence: this.licence, | ||
522 | licenceLabel, | ||
523 | language: this.language, | ||
524 | languageLabel, | ||
525 | nsfw: this.nsfw, | ||
526 | description: this.description, | ||
527 | podHost, | ||
528 | isLocal: this.isOwned(), | ||
529 | author: this.VideoChannel.Author.name, | ||
476 | duration: this.duration, | 530 | duration: this.duration, |
477 | views: this.views, | 531 | views: this.views, |
478 | likes: this.likes, | 532 | likes: this.likes, |
@@ -483,6 +537,7 @@ toFormattedJSON = function (this: VideoInstance) { | |||
483 | embedPath: this.getEmbedPath(), | 537 | embedPath: this.getEmbedPath(), |
484 | createdAt: this.createdAt, | 538 | createdAt: this.createdAt, |
485 | updatedAt: this.updatedAt, | 539 | updatedAt: this.updatedAt, |
540 | channel: this.VideoChannel.toFormattedJSON(), | ||
486 | files: [] | 541 | files: [] |
487 | } | 542 | } |
488 | 543 | ||
@@ -525,7 +580,7 @@ toAddRemoteJSON = function (this: VideoInstance) { | |||
525 | language: this.language, | 580 | language: this.language, |
526 | nsfw: this.nsfw, | 581 | nsfw: this.nsfw, |
527 | description: this.description, | 582 | description: this.description, |
528 | author: this.Author.name, | 583 | channelUUID: this.VideoChannel.uuid, |
529 | duration: this.duration, | 584 | duration: this.duration, |
530 | thumbnailData: thumbnailData.toString('binary'), | 585 | thumbnailData: thumbnailData.toString('binary'), |
531 | tags: map<TagInstance, string>(this.Tags, 'name'), | 586 | tags: map<TagInstance, string>(this.Tags, 'name'), |
@@ -559,7 +614,6 @@ toUpdateRemoteJSON = function (this: VideoInstance) { | |||
559 | language: this.language, | 614 | language: this.language, |
560 | nsfw: this.nsfw, | 615 | nsfw: this.nsfw, |
561 | description: this.description, | 616 | description: this.description, |
562 | author: this.Author.name, | ||
563 | duration: this.duration, | 617 | duration: this.duration, |
564 | tags: map<TagInstance, string>(this.Tags, 'name'), | 618 | tags: map<TagInstance, string>(this.Tags, 'name'), |
565 | createdAt: this.createdAt, | 619 | createdAt: this.createdAt, |
@@ -723,8 +777,18 @@ listForApi = function (start: number, count: number, sort: string) { | |||
723 | order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ], | 777 | order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ], |
724 | include: [ | 778 | include: [ |
725 | { | 779 | { |
726 | model: Video['sequelize'].models.Author, | 780 | model: Video['sequelize'].models.VideoChannel, |
727 | include: [ { model: Video['sequelize'].models.Pod, required: false } ] | 781 | include: [ |
782 | { | ||
783 | model: Video['sequelize'].models.Author, | ||
784 | include: [ | ||
785 | { | ||
786 | model: Video['sequelize'].models.Pod, | ||
787 | required: false | ||
788 | } | ||
789 | ] | ||
790 | } | ||
791 | ] | ||
728 | }, | 792 | }, |
729 | Video['sequelize'].models.Tag, | 793 | Video['sequelize'].models.Tag, |
730 | Video['sequelize'].models.VideoFile | 794 | Video['sequelize'].models.VideoFile |
@@ -740,8 +804,8 @@ listForApi = function (start: number, count: number, sort: string) { | |||
740 | }) | 804 | }) |
741 | } | 805 | } |
742 | 806 | ||
743 | loadByHostAndUUID = function (fromHost: string, uuid: string) { | 807 | loadByHostAndUUID = function (fromHost: string, uuid: string, t?: Sequelize.Transaction) { |
744 | const query = { | 808 | const query: Sequelize.FindOptions<VideoAttributes> = { |
745 | where: { | 809 | where: { |
746 | uuid | 810 | uuid |
747 | }, | 811 | }, |
@@ -750,20 +814,27 @@ loadByHostAndUUID = function (fromHost: string, uuid: string) { | |||
750 | model: Video['sequelize'].models.VideoFile | 814 | model: Video['sequelize'].models.VideoFile |
751 | }, | 815 | }, |
752 | { | 816 | { |
753 | model: Video['sequelize'].models.Author, | 817 | model: Video['sequelize'].models.VideoChannel, |
754 | include: [ | 818 | include: [ |
755 | { | 819 | { |
756 | model: Video['sequelize'].models.Pod, | 820 | model: Video['sequelize'].models.Author, |
757 | required: true, | 821 | include: [ |
758 | where: { | 822 | { |
759 | host: fromHost | 823 | model: Video['sequelize'].models.Pod, |
760 | } | 824 | required: true, |
825 | where: { | ||
826 | host: fromHost | ||
827 | } | ||
828 | } | ||
829 | ] | ||
761 | } | 830 | } |
762 | ] | 831 | ] |
763 | } | 832 | } |
764 | ] | 833 | ] |
765 | } | 834 | } |
766 | 835 | ||
836 | if (t !== undefined) query.transaction = t | ||
837 | |||
767 | return Video.findOne(query) | 838 | return Video.findOne(query) |
768 | } | 839 | } |
769 | 840 | ||
@@ -774,7 +845,10 @@ listOwnedAndPopulateAuthorAndTags = function () { | |||
774 | }, | 845 | }, |
775 | include: [ | 846 | include: [ |
776 | Video['sequelize'].models.VideoFile, | 847 | Video['sequelize'].models.VideoFile, |
777 | Video['sequelize'].models.Author, | 848 | { |
849 | model: Video['sequelize'].models.VideoChannel, | ||
850 | include: [ Video['sequelize'].models.Author ] | ||
851 | }, | ||
778 | Video['sequelize'].models.Tag | 852 | Video['sequelize'].models.Tag |
779 | ] | 853 | ] |
780 | } | 854 | } |
@@ -792,10 +866,15 @@ listOwnedByAuthor = function (author: string) { | |||
792 | model: Video['sequelize'].models.VideoFile | 866 | model: Video['sequelize'].models.VideoFile |
793 | }, | 867 | }, |
794 | { | 868 | { |
795 | model: Video['sequelize'].models.Author, | 869 | model: Video['sequelize'].models.VideoChannel, |
796 | where: { | 870 | include: [ |
797 | name: author | 871 | { |
798 | } | 872 | model: Video['sequelize'].models.Author, |
873 | where: { | ||
874 | name: author | ||
875 | } | ||
876 | } | ||
877 | ] | ||
799 | } | 878 | } |
800 | ] | 879 | ] |
801 | } | 880 | } |
@@ -807,19 +886,28 @@ load = function (id: number) { | |||
807 | return Video.findById(id) | 886 | return Video.findById(id) |
808 | } | 887 | } |
809 | 888 | ||
810 | loadByUUID = function (uuid: string) { | 889 | loadByUUID = function (uuid: string, t?: Sequelize.Transaction) { |
811 | const query = { | 890 | const query: Sequelize.FindOptions<VideoAttributes> = { |
812 | where: { | 891 | where: { |
813 | uuid | 892 | uuid |
814 | }, | 893 | }, |
815 | include: [ Video['sequelize'].models.VideoFile ] | 894 | include: [ Video['sequelize'].models.VideoFile ] |
816 | } | 895 | } |
896 | |||
897 | if (t !== undefined) query.transaction = t | ||
898 | |||
817 | return Video.findOne(query) | 899 | return Video.findOne(query) |
818 | } | 900 | } |
819 | 901 | ||
820 | loadAndPopulateAuthor = function (id: number) { | 902 | loadAndPopulateAuthor = function (id: number) { |
821 | const options = { | 903 | const options = { |
822 | include: [ Video['sequelize'].models.VideoFile, Video['sequelize'].models.Author ] | 904 | include: [ |
905 | Video['sequelize'].models.VideoFile, | ||
906 | { | ||
907 | model: Video['sequelize'].models.VideoChannel, | ||
908 | include: [ Video['sequelize'].models.Author ] | ||
909 | } | ||
910 | ] | ||
823 | } | 911 | } |
824 | 912 | ||
825 | return Video.findById(id, options) | 913 | return Video.findById(id, options) |
@@ -829,8 +917,13 @@ loadAndPopulateAuthorAndPodAndTags = function (id: number) { | |||
829 | const options = { | 917 | const options = { |
830 | include: [ | 918 | include: [ |
831 | { | 919 | { |
832 | model: Video['sequelize'].models.Author, | 920 | model: Video['sequelize'].models.VideoChannel, |
833 | include: [ { model: Video['sequelize'].models.Pod, required: false } ] | 921 | include: [ |
922 | { | ||
923 | model: Video['sequelize'].models.Author, | ||
924 | include: [ { model: Video['sequelize'].models.Pod, required: false } ] | ||
925 | } | ||
926 | ] | ||
834 | }, | 927 | }, |
835 | Video['sequelize'].models.Tag, | 928 | Video['sequelize'].models.Tag, |
836 | Video['sequelize'].models.VideoFile | 929 | Video['sequelize'].models.VideoFile |
@@ -847,8 +940,13 @@ loadByUUIDAndPopulateAuthorAndPodAndTags = function (uuid: string) { | |||
847 | }, | 940 | }, |
848 | include: [ | 941 | include: [ |
849 | { | 942 | { |
850 | model: Video['sequelize'].models.Author, | 943 | model: Video['sequelize'].models.VideoChannel, |
851 | include: [ { model: Video['sequelize'].models.Pod, required: false } ] | 944 | include: [ |
945 | { | ||
946 | model: Video['sequelize'].models.Author, | ||
947 | include: [ { model: Video['sequelize'].models.Pod, required: false } ] | ||
948 | } | ||
949 | ] | ||
852 | }, | 950 | }, |
853 | Video['sequelize'].models.Tag, | 951 | Video['sequelize'].models.Tag, |
854 | Video['sequelize'].models.VideoFile | 952 | Video['sequelize'].models.VideoFile |
@@ -866,9 +964,13 @@ searchAndPopulateAuthorAndPodAndTags = function (value: string, field: string, s | |||
866 | 964 | ||
867 | const authorInclude: Sequelize.IncludeOptions = { | 965 | const authorInclude: Sequelize.IncludeOptions = { |
868 | model: Video['sequelize'].models.Author, | 966 | model: Video['sequelize'].models.Author, |
869 | include: [ | 967 | include: [ podInclude ] |
870 | podInclude | 968 | } |
871 | ] | 969 | |
970 | const videoChannelInclude: Sequelize.IncludeOptions = { | ||
971 | model: Video['sequelize'].models.VideoChannel, | ||
972 | include: [ authorInclude ], | ||
973 | required: true | ||
872 | } | 974 | } |
873 | 975 | ||
874 | const tagInclude: Sequelize.IncludeOptions = { | 976 | const tagInclude: Sequelize.IncludeOptions = { |
@@ -915,8 +1017,6 @@ searchAndPopulateAuthorAndPodAndTags = function (value: string, field: string, s | |||
915 | $iLike: '%' + value + '%' | 1017 | $iLike: '%' + value + '%' |
916 | } | 1018 | } |
917 | } | 1019 | } |
918 | |||
919 | // authorInclude.or = true | ||
920 | } else { | 1020 | } else { |
921 | query.where[field] = { | 1021 | query.where[field] = { |
922 | $iLike: '%' + value + '%' | 1022 | $iLike: '%' + value + '%' |
@@ -924,7 +1024,7 @@ searchAndPopulateAuthorAndPodAndTags = function (value: string, field: string, s | |||
924 | } | 1024 | } |
925 | 1025 | ||
926 | query.include = [ | 1026 | query.include = [ |
927 | authorInclude, tagInclude, videoFileInclude | 1027 | videoChannelInclude, tagInclude, videoFileInclude |
928 | ] | 1028 | ] |
929 | 1029 | ||
930 | return Video.findAndCountAll(query).then(({ rows, count }) => { | 1030 | return Video.findAndCountAll(query).then(({ rows, count }) => { |
@@ -955,8 +1055,8 @@ function getBaseUrls (video: VideoInstance) { | |||
955 | baseUrlHttp = CONFIG.WEBSERVER.URL | 1055 | baseUrlHttp = CONFIG.WEBSERVER.URL |
956 | baseUrlWs = CONFIG.WEBSERVER.WS + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT | 1056 | baseUrlWs = CONFIG.WEBSERVER.WS + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT |
957 | } else { | 1057 | } else { |
958 | baseUrlHttp = REMOTE_SCHEME.HTTP + '://' + video.Author.Pod.host | 1058 | baseUrlHttp = REMOTE_SCHEME.HTTP + '://' + video.VideoChannel.Author.Pod.host |
959 | baseUrlWs = REMOTE_SCHEME.WS + '://' + video.Author.Pod.host | 1059 | baseUrlWs = REMOTE_SCHEME.WS + '://' + video.VideoChannel.Author.Pod.host |
960 | } | 1060 | } |
961 | 1061 | ||
962 | return { baseUrlHttp, baseUrlWs } | 1062 | return { baseUrlHttp, baseUrlWs } |