diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2017-05-22 20:58:25 +0200 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2017-05-25 17:32:16 +0200 |
commit | e02643f32e4c97ca307f8fc5b69be79c40d70a3b (patch) | |
tree | b7f6269913cd5a0e4f26a9461a043deb0c168be0 /server/models | |
parent | 65fcc3119c334b75dd13bcfdebf186afdc580a8f (diff) | |
download | PeerTube-e02643f32e4c97ca307f8fc5b69be79c40d70a3b.tar.gz PeerTube-e02643f32e4c97ca307f8fc5b69be79c40d70a3b.tar.zst PeerTube-e02643f32e4c97ca307f8fc5b69be79c40d70a3b.zip |
Type models
Diffstat (limited to 'server/models')
36 files changed, 1359 insertions, 543 deletions
diff --git a/server/models/application-interface.ts b/server/models/application-interface.ts new file mode 100644 index 000000000..826d25df0 --- /dev/null +++ b/server/models/application-interface.ts | |||
@@ -0,0 +1,23 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace ApplicationMethods { | ||
4 | export type LoadMigrationVersion = (callback: (err: Error, version: number) => void) => void | ||
5 | export type UpdateMigrationVersion = (newVersion: number, transaction: any, callback: any) => void | ||
6 | } | ||
7 | |||
8 | export interface ApplicationClass { | ||
9 | loadMigrationVersion: ApplicationMethods.LoadMigrationVersion | ||
10 | updateMigrationVersion: ApplicationMethods.UpdateMigrationVersion | ||
11 | } | ||
12 | |||
13 | export interface ApplicationAttributes { | ||
14 | migrationVersion: number | ||
15 | } | ||
16 | |||
17 | export interface ApplicationInstance extends ApplicationClass, ApplicationAttributes, Sequelize.Instance<ApplicationAttributes> { | ||
18 | id: number | ||
19 | createdAt: Date | ||
20 | updatedAt: Date | ||
21 | } | ||
22 | |||
23 | export interface ApplicationModel extends ApplicationClass, Sequelize.Model<ApplicationInstance, ApplicationAttributes> {} | ||
diff --git a/server/models/application.ts b/server/models/application.ts index 38a57e327..acd0dfbf2 100644 --- a/server/models/application.ts +++ b/server/models/application.ts | |||
@@ -1,5 +1,20 @@ | |||
1 | module.exports = function (sequelize, DataTypes) { | 1 | import * as Sequelize from 'sequelize' |
2 | const Application = sequelize.define('Application', | 2 | |
3 | import { addMethodsToModel } from './utils' | ||
4 | import { | ||
5 | ApplicationClass, | ||
6 | ApplicationAttributes, | ||
7 | ApplicationInstance, | ||
8 | |||
9 | ApplicationMethods | ||
10 | } from './application-interface' | ||
11 | |||
12 | let Application: Sequelize.Model<ApplicationInstance, ApplicationAttributes> | ||
13 | let loadMigrationVersion: ApplicationMethods.LoadMigrationVersion | ||
14 | let updateMigrationVersion: ApplicationMethods.UpdateMigrationVersion | ||
15 | |||
16 | export default function defineApplication (sequelize: Sequelize.Sequelize, DataTypes) { | ||
17 | Application = sequelize.define<ApplicationInstance, ApplicationAttributes>('Application', | ||
3 | { | 18 | { |
4 | migrationVersion: { | 19 | migrationVersion: { |
5 | type: DataTypes.INTEGER, | 20 | type: DataTypes.INTEGER, |
@@ -9,34 +24,31 @@ module.exports = function (sequelize, DataTypes) { | |||
9 | isInt: true | 24 | isInt: true |
10 | } | 25 | } |
11 | } | 26 | } |
12 | }, | ||
13 | { | ||
14 | classMethods: { | ||
15 | loadMigrationVersion, | ||
16 | updateMigrationVersion | ||
17 | } | ||
18 | } | 27 | } |
19 | ) | 28 | ) |
20 | 29 | ||
30 | const classMethods = [ loadMigrationVersion, updateMigrationVersion ] | ||
31 | addMethodsToModel(Application, classMethods) | ||
32 | |||
21 | return Application | 33 | return Application |
22 | } | 34 | } |
23 | 35 | ||
24 | // --------------------------------------------------------------------------- | 36 | // --------------------------------------------------------------------------- |
25 | 37 | ||
26 | function loadMigrationVersion (callback) { | 38 | loadMigrationVersion = function (callback: (err: Error, version: number) => void) { |
27 | const query = { | 39 | const query = { |
28 | attributes: [ 'migrationVersion' ] | 40 | attributes: [ 'migrationVersion' ] |
29 | } | 41 | } |
30 | 42 | ||
31 | return this.findOne(query).asCallback(function (err, data) { | 43 | return Application.findOne(query).asCallback(function (err, data) { |
32 | const version = data ? data.migrationVersion : null | 44 | const version = data ? data.migrationVersion : null |
33 | 45 | ||
34 | return callback(err, version) | 46 | return callback(err, version) |
35 | }) | 47 | }) |
36 | } | 48 | } |
37 | 49 | ||
38 | function updateMigrationVersion (newVersion, transaction, callback) { | 50 | updateMigrationVersion = function (newVersion: number, transaction: any, callback: any) { |
39 | const options: { where?: any, transaction?: any } = { | 51 | const options: Sequelize.UpdateOptions = { |
40 | where: {} | 52 | where: {} |
41 | } | 53 | } |
42 | 54 | ||
@@ -46,5 +58,5 @@ function updateMigrationVersion (newVersion, transaction, callback) { | |||
46 | options.transaction = transaction | 58 | options.transaction = transaction |
47 | } | 59 | } |
48 | 60 | ||
49 | return this.update({ migrationVersion: newVersion }, options).asCallback(callback) | 61 | return Application.update({ migrationVersion: newVersion }, options).asCallback(callback) |
50 | } | 62 | } |
diff --git a/server/models/author-interface.ts b/server/models/author-interface.ts new file mode 100644 index 000000000..d2475c3bd --- /dev/null +++ b/server/models/author-interface.ts | |||
@@ -0,0 +1,21 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace AuthorMethods { | ||
4 | export type FindOrCreateAuthor = (name, podId, userId, transaction, callback) => void | ||
5 | } | ||
6 | |||
7 | export interface AuthorClass { | ||
8 | findOrCreateAuthor: AuthorMethods.FindOrCreateAuthor | ||
9 | } | ||
10 | |||
11 | export interface AuthorAttributes { | ||
12 | name: string | ||
13 | } | ||
14 | |||
15 | export interface AuthorInstance extends AuthorClass, AuthorAttributes, Sequelize.Instance<AuthorAttributes> { | ||
16 | id: number | ||
17 | createdAt: Date | ||
18 | updatedAt: Date | ||
19 | } | ||
20 | |||
21 | export interface AuthorModel extends AuthorClass, Sequelize.Model<AuthorInstance, AuthorAttributes> {} | ||
diff --git a/server/models/author.ts b/server/models/author.ts index 4a7396929..b543d17a0 100644 --- a/server/models/author.ts +++ b/server/models/author.ts | |||
@@ -1,7 +1,21 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
1 | import { isUserUsernameValid } from '../helpers' | 3 | import { isUserUsernameValid } from '../helpers' |
2 | 4 | ||
3 | module.exports = function (sequelize, DataTypes) { | 5 | import { addMethodsToModel } from './utils' |
4 | const Author = sequelize.define('Author', | 6 | import { |
7 | AuthorClass, | ||
8 | AuthorInstance, | ||
9 | AuthorAttributes, | ||
10 | |||
11 | AuthorMethods | ||
12 | } from './author-interface' | ||
13 | |||
14 | let Author: Sequelize.Model<AuthorInstance, AuthorAttributes> | ||
15 | let findOrCreateAuthor: AuthorMethods.FindOrCreateAuthor | ||
16 | |||
17 | export default function defineAuthor (sequelize: Sequelize.Sequelize, DataTypes) { | ||
18 | Author = sequelize.define<AuthorInstance, AuthorAttributes>('Author', | ||
5 | { | 19 | { |
6 | name: { | 20 | name: { |
7 | type: DataTypes.STRING, | 21 | type: DataTypes.STRING, |
@@ -30,22 +44,20 @@ module.exports = function (sequelize, DataTypes) { | |||
30 | fields: [ 'name', 'podId' ], | 44 | fields: [ 'name', 'podId' ], |
31 | unique: true | 45 | unique: true |
32 | } | 46 | } |
33 | ], | 47 | ] |
34 | classMethods: { | ||
35 | associate, | ||
36 | |||
37 | findOrCreateAuthor | ||
38 | } | ||
39 | } | 48 | } |
40 | ) | 49 | ) |
41 | 50 | ||
51 | const classMethods = [ associate, findOrCreateAuthor ] | ||
52 | addMethodsToModel(Author, classMethods) | ||
53 | |||
42 | return Author | 54 | return Author |
43 | } | 55 | } |
44 | 56 | ||
45 | // --------------------------------------------------------------------------- | 57 | // --------------------------------------------------------------------------- |
46 | 58 | ||
47 | function associate (models) { | 59 | function associate (models) { |
48 | this.belongsTo(models.Pod, { | 60 | Author.belongsTo(models.Pod, { |
49 | foreignKey: { | 61 | foreignKey: { |
50 | name: 'podId', | 62 | name: 'podId', |
51 | allowNull: true | 63 | allowNull: true |
@@ -53,7 +65,7 @@ function associate (models) { | |||
53 | onDelete: 'cascade' | 65 | onDelete: 'cascade' |
54 | }) | 66 | }) |
55 | 67 | ||
56 | this.belongsTo(models.User, { | 68 | Author.belongsTo(models.User, { |
57 | foreignKey: { | 69 | foreignKey: { |
58 | name: 'userId', | 70 | name: 'userId', |
59 | allowNull: true | 71 | allowNull: true |
@@ -62,7 +74,7 @@ function associate (models) { | |||
62 | }) | 74 | }) |
63 | } | 75 | } |
64 | 76 | ||
65 | function findOrCreateAuthor (name, podId, userId, transaction, callback) { | 77 | findOrCreateAuthor = function (name, podId, userId, transaction, callback) { |
66 | if (!callback) { | 78 | if (!callback) { |
67 | callback = transaction | 79 | callback = transaction |
68 | transaction = null | 80 | transaction = null |
@@ -81,7 +93,7 @@ function findOrCreateAuthor (name, podId, userId, transaction, callback) { | |||
81 | 93 | ||
82 | if (transaction) query.transaction = transaction | 94 | if (transaction) query.transaction = transaction |
83 | 95 | ||
84 | this.findOrCreate(query).asCallback(function (err, result) { | 96 | Author.findOrCreate(query).asCallback(function (err, result) { |
85 | if (err) return callback(err) | 97 | if (err) return callback(err) |
86 | 98 | ||
87 | // [ instance, wasCreated ] | 99 | // [ instance, wasCreated ] |
diff --git a/server/models/index.ts b/server/models/index.ts new file mode 100644 index 000000000..432c0dc4a --- /dev/null +++ b/server/models/index.ts | |||
@@ -0,0 +1,17 @@ | |||
1 | export * from './application-interface' | ||
2 | export * from './author-interface' | ||
3 | export * from './job-interface' | ||
4 | export * from './oauth-client-interface' | ||
5 | export * from './oauth-token-interface' | ||
6 | export * from './pod-interface' | ||
7 | export * from './request-interface' | ||
8 | export * from './request-to-pod-interface' | ||
9 | export * from './request-video-event-interface' | ||
10 | export * from './request-video-qadu-interface' | ||
11 | export * from './tag-interface' | ||
12 | export * from './user-video-rate-interface' | ||
13 | export * from './user-interface' | ||
14 | export * from './video-abuse-interface' | ||
15 | export * from './video-blacklist-interface' | ||
16 | export * from './video-tag-interface' | ||
17 | export * from './video-interface' | ||
diff --git a/server/models/job-interface.ts b/server/models/job-interface.ts new file mode 100644 index 000000000..ad4e2d2b0 --- /dev/null +++ b/server/models/job-interface.ts | |||
@@ -0,0 +1,23 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace JobMethods { | ||
4 | export type ListWithLimit = (limit, state, callback) => void | ||
5 | } | ||
6 | |||
7 | export interface JobClass { | ||
8 | listWithLimit: JobMethods.ListWithLimit | ||
9 | } | ||
10 | |||
11 | export interface JobAttributes { | ||
12 | state: string | ||
13 | handlerName: string | ||
14 | handlerInputData: object | ||
15 | } | ||
16 | |||
17 | export interface JobInstance extends JobClass, JobAttributes, Sequelize.Instance<JobAttributes> { | ||
18 | id: number | ||
19 | createdAt: Date | ||
20 | updatedAt: Date | ||
21 | } | ||
22 | |||
23 | export interface JobModel extends JobClass, Sequelize.Model<JobInstance, JobAttributes> {} | ||
diff --git a/server/models/job.ts b/server/models/job.ts index 6843e399b..982b51499 100644 --- a/server/models/job.ts +++ b/server/models/job.ts | |||
@@ -1,11 +1,22 @@ | |||
1 | import { values } from 'lodash' | 1 | import { values } from 'lodash' |
2 | import * as Sequelize from 'sequelize' | ||
2 | 3 | ||
3 | import { JOB_STATES } from '../initializers' | 4 | import { JOB_STATES } from '../initializers' |
4 | 5 | ||
5 | // --------------------------------------------------------------------------- | 6 | import { addMethodsToModel } from './utils' |
7 | import { | ||
8 | JobClass, | ||
9 | JobInstance, | ||
10 | JobAttributes, | ||
11 | |||
12 | JobMethods | ||
13 | } from './job-interface' | ||
14 | |||
15 | let Job: Sequelize.Model<JobInstance, JobAttributes> | ||
16 | let listWithLimit: JobMethods.ListWithLimit | ||
6 | 17 | ||
7 | module.exports = function (sequelize, DataTypes) { | 18 | export default function defineJob (sequelize: Sequelize.Sequelize, DataTypes) { |
8 | const Job = sequelize.define('Job', | 19 | Job = sequelize.define<JobInstance, JobAttributes>('Job', |
9 | { | 20 | { |
10 | state: { | 21 | state: { |
11 | type: DataTypes.ENUM(values(JOB_STATES)), | 22 | type: DataTypes.ENUM(values(JOB_STATES)), |
@@ -25,19 +36,19 @@ module.exports = function (sequelize, DataTypes) { | |||
25 | { | 36 | { |
26 | fields: [ 'state' ] | 37 | fields: [ 'state' ] |
27 | } | 38 | } |
28 | ], | 39 | ] |
29 | classMethods: { | ||
30 | listWithLimit | ||
31 | } | ||
32 | } | 40 | } |
33 | ) | 41 | ) |
34 | 42 | ||
43 | const classMethods = [ listWithLimit ] | ||
44 | addMethodsToModel(Job, classMethods) | ||
45 | |||
35 | return Job | 46 | return Job |
36 | } | 47 | } |
37 | 48 | ||
38 | // --------------------------------------------------------------------------- | 49 | // --------------------------------------------------------------------------- |
39 | 50 | ||
40 | function listWithLimit (limit, state, callback) { | 51 | listWithLimit = function (limit, state, callback) { |
41 | const query = { | 52 | const query = { |
42 | order: [ | 53 | order: [ |
43 | [ 'id', 'ASC' ] | 54 | [ 'id', 'ASC' ] |
@@ -48,5 +59,5 @@ function listWithLimit (limit, state, callback) { | |||
48 | } | 59 | } |
49 | } | 60 | } |
50 | 61 | ||
51 | return this.findAll(query).asCallback(callback) | 62 | return Job.findAll(query).asCallback(callback) |
52 | } | 63 | } |
diff --git a/server/models/oauth-client-interface.ts b/server/models/oauth-client-interface.ts new file mode 100644 index 000000000..4efd6212a --- /dev/null +++ b/server/models/oauth-client-interface.ts | |||
@@ -0,0 +1,28 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace OAuthClientMethods { | ||
4 | export type CountTotal = (callback) => void | ||
5 | export type LoadFirstClient = (callback) => void | ||
6 | export type GetByIdAndSecret = (clientId, clientSecret) => void | ||
7 | } | ||
8 | |||
9 | export interface OAuthClientClass { | ||
10 | countTotal: OAuthClientMethods.CountTotal | ||
11 | loadFirstClient: OAuthClientMethods.LoadFirstClient | ||
12 | getByIdAndSecret: OAuthClientMethods.GetByIdAndSecret | ||
13 | } | ||
14 | |||
15 | export interface OAuthClientAttributes { | ||
16 | clientId: string | ||
17 | clientSecret: string | ||
18 | grants: string[] | ||
19 | redirectUris: string[] | ||
20 | } | ||
21 | |||
22 | export interface OAuthClientInstance extends OAuthClientClass, OAuthClientAttributes, Sequelize.Instance<OAuthClientAttributes> { | ||
23 | id: number | ||
24 | createdAt: Date | ||
25 | updatedAt: Date | ||
26 | } | ||
27 | |||
28 | export interface OAuthClientModel extends OAuthClientClass, Sequelize.Model<OAuthClientInstance, OAuthClientAttributes> {} | ||
diff --git a/server/models/oauth-client.ts b/server/models/oauth-client.ts index 3198a85ef..2cefb5cb9 100644 --- a/server/models/oauth-client.ts +++ b/server/models/oauth-client.ts | |||
@@ -1,5 +1,21 @@ | |||
1 | module.exports = function (sequelize, DataTypes) { | 1 | import * as Sequelize from 'sequelize' |
2 | const OAuthClient = sequelize.define('OAuthClient', | 2 | |
3 | import { addMethodsToModel } from './utils' | ||
4 | import { | ||
5 | OAuthClientClass, | ||
6 | OAuthClientInstance, | ||
7 | OAuthClientAttributes, | ||
8 | |||
9 | OAuthClientMethods | ||
10 | } from './oauth-client-interface' | ||
11 | |||
12 | let OAuthClient: Sequelize.Model<OAuthClientInstance, OAuthClientAttributes> | ||
13 | let countTotal: OAuthClientMethods.CountTotal | ||
14 | let loadFirstClient: OAuthClientMethods.LoadFirstClient | ||
15 | let getByIdAndSecret: OAuthClientMethods.GetByIdAndSecret | ||
16 | |||
17 | export default function (sequelize, DataTypes) { | ||
18 | OAuthClient = sequelize.define('OAuthClient', | ||
3 | { | 19 | { |
4 | clientId: { | 20 | clientId: { |
5 | type: DataTypes.STRING, | 21 | type: DataTypes.STRING, |
@@ -26,29 +42,40 @@ module.exports = function (sequelize, DataTypes) { | |||
26 | fields: [ 'clientId', 'clientSecret' ], | 42 | fields: [ 'clientId', 'clientSecret' ], |
27 | unique: true | 43 | unique: true |
28 | } | 44 | } |
29 | ], | 45 | ] |
30 | classMethods: { | ||
31 | countTotal, | ||
32 | getByIdAndSecret, | ||
33 | loadFirstClient | ||
34 | } | ||
35 | } | 46 | } |
36 | ) | 47 | ) |
37 | 48 | ||
49 | const classMethods = [ | ||
50 | associate, | ||
51 | |||
52 | countTotal, | ||
53 | getByIdAndSecret, | ||
54 | loadFirstClient | ||
55 | ] | ||
56 | addMethodsToModel(OAuthClient, classMethods) | ||
57 | |||
38 | return OAuthClient | 58 | return OAuthClient |
39 | } | 59 | } |
40 | 60 | ||
41 | // --------------------------------------------------------------------------- | 61 | // --------------------------------------------------------------------------- |
42 | 62 | ||
43 | function countTotal (callback) { | 63 | function associate (models) { |
44 | return this.count().asCallback(callback) | 64 | OAuthClient.hasMany(models.OAuthToken, { |
65 | foreignKey: 'oAuthClientId', | ||
66 | onDelete: 'cascade' | ||
67 | }) | ||
68 | } | ||
69 | |||
70 | countTotal = function (callback) { | ||
71 | return OAuthClient.count().asCallback(callback) | ||
45 | } | 72 | } |
46 | 73 | ||
47 | function loadFirstClient (callback) { | 74 | loadFirstClient = function (callback) { |
48 | return this.findOne().asCallback(callback) | 75 | return OAuthClient.findOne().asCallback(callback) |
49 | } | 76 | } |
50 | 77 | ||
51 | function getByIdAndSecret (clientId, clientSecret) { | 78 | getByIdAndSecret = function (clientId, clientSecret) { |
52 | const query = { | 79 | const query = { |
53 | where: { | 80 | where: { |
54 | clientId: clientId, | 81 | clientId: clientId, |
@@ -56,5 +83,5 @@ function getByIdAndSecret (clientId, clientSecret) { | |||
56 | } | 83 | } |
57 | } | 84 | } |
58 | 85 | ||
59 | return this.findOne(query) | 86 | return OAuthClient.findOne(query) |
60 | } | 87 | } |
diff --git a/server/models/oauth-token-interface.ts b/server/models/oauth-token-interface.ts new file mode 100644 index 000000000..a0cd1ffe7 --- /dev/null +++ b/server/models/oauth-token-interface.ts | |||
@@ -0,0 +1,34 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | import { UserModel } from './user-interface' | ||
4 | |||
5 | export namespace OAuthTokenMethods { | ||
6 | export type GetByRefreshTokenAndPopulateClient = (refreshToken) => void | ||
7 | export type GetByTokenAndPopulateUser = (bearerToken) => void | ||
8 | export type GetByRefreshTokenAndPopulateUser = (refreshToken) => any | ||
9 | export type RemoveByUserId = (userId, callback) => void | ||
10 | } | ||
11 | |||
12 | export interface OAuthTokenClass { | ||
13 | getByRefreshTokenAndPopulateClient: OAuthTokenMethods.GetByRefreshTokenAndPopulateClient | ||
14 | getByTokenAndPopulateUser: OAuthTokenMethods.GetByTokenAndPopulateUser | ||
15 | getByRefreshTokenAndPopulateUser: OAuthTokenMethods.GetByRefreshTokenAndPopulateUser | ||
16 | removeByUserId: OAuthTokenMethods.RemoveByUserId | ||
17 | } | ||
18 | |||
19 | export interface OAuthTokenAttributes { | ||
20 | accessToken: string | ||
21 | accessTokenExpiresAt: Date | ||
22 | refreshToken: string | ||
23 | refreshTokenExpiresAt: Date | ||
24 | |||
25 | User?: UserModel | ||
26 | } | ||
27 | |||
28 | export interface OAuthTokenInstance extends OAuthTokenClass, OAuthTokenAttributes, Sequelize.Instance<OAuthTokenAttributes> { | ||
29 | id: number | ||
30 | createdAt: Date | ||
31 | updatedAt: Date | ||
32 | } | ||
33 | |||
34 | export interface OAuthTokenModel extends OAuthTokenClass, Sequelize.Model<OAuthTokenInstance, OAuthTokenAttributes> {} | ||
diff --git a/server/models/oauth-token.ts b/server/models/oauth-token.ts index 74c9180eb..567df1c12 100644 --- a/server/models/oauth-token.ts +++ b/server/models/oauth-token.ts | |||
@@ -1,9 +1,24 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
1 | import { logger } from '../helpers' | 3 | import { logger } from '../helpers' |
2 | 4 | ||
3 | // --------------------------------------------------------------------------- | 5 | import { addMethodsToModel } from './utils' |
6 | import { | ||
7 | OAuthTokenClass, | ||
8 | OAuthTokenInstance, | ||
9 | OAuthTokenAttributes, | ||
10 | |||
11 | OAuthTokenMethods | ||
12 | } from './oauth-token-interface' | ||
13 | |||
14 | let OAuthToken: Sequelize.Model<OAuthTokenInstance, OAuthTokenAttributes> | ||
15 | let getByRefreshTokenAndPopulateClient: OAuthTokenMethods.GetByRefreshTokenAndPopulateClient | ||
16 | let getByTokenAndPopulateUser: OAuthTokenMethods.GetByTokenAndPopulateUser | ||
17 | let getByRefreshTokenAndPopulateUser: OAuthTokenMethods.GetByRefreshTokenAndPopulateUser | ||
18 | let removeByUserId: OAuthTokenMethods.RemoveByUserId | ||
4 | 19 | ||
5 | module.exports = function (sequelize, DataTypes) { | 20 | export default function (sequelize, DataTypes) { |
6 | const OAuthToken = sequelize.define('OAuthToken', | 21 | OAuthToken = sequelize.define('OAuthToken', |
7 | { | 22 | { |
8 | accessToken: { | 23 | accessToken: { |
9 | type: DataTypes.STRING, | 24 | type: DataTypes.STRING, |
@@ -38,25 +53,27 @@ module.exports = function (sequelize, DataTypes) { | |||
38 | { | 53 | { |
39 | fields: [ 'oAuthClientId' ] | 54 | fields: [ 'oAuthClientId' ] |
40 | } | 55 | } |
41 | ], | 56 | ] |
42 | classMethods: { | ||
43 | associate, | ||
44 | |||
45 | getByRefreshTokenAndPopulateClient, | ||
46 | getByTokenAndPopulateUser, | ||
47 | getByRefreshTokenAndPopulateUser, | ||
48 | removeByUserId | ||
49 | } | ||
50 | } | 57 | } |
51 | ) | 58 | ) |
52 | 59 | ||
60 | const classMethods = [ | ||
61 | associate, | ||
62 | |||
63 | getByRefreshTokenAndPopulateClient, | ||
64 | getByTokenAndPopulateUser, | ||
65 | getByRefreshTokenAndPopulateUser, | ||
66 | removeByUserId | ||
67 | ] | ||
68 | addMethodsToModel(OAuthToken, classMethods) | ||
69 | |||
53 | return OAuthToken | 70 | return OAuthToken |
54 | } | 71 | } |
55 | 72 | ||
56 | // --------------------------------------------------------------------------- | 73 | // --------------------------------------------------------------------------- |
57 | 74 | ||
58 | function associate (models) { | 75 | function associate (models) { |
59 | this.belongsTo(models.User, { | 76 | OAuthToken.belongsTo(models.User, { |
60 | foreignKey: { | 77 | foreignKey: { |
61 | name: 'userId', | 78 | name: 'userId', |
62 | allowNull: false | 79 | allowNull: false |
@@ -64,7 +81,7 @@ function associate (models) { | |||
64 | onDelete: 'cascade' | 81 | onDelete: 'cascade' |
65 | }) | 82 | }) |
66 | 83 | ||
67 | this.belongsTo(models.OAuthClient, { | 84 | OAuthToken.belongsTo(models.OAuthClient, { |
68 | foreignKey: { | 85 | foreignKey: { |
69 | name: 'oAuthClientId', | 86 | name: 'oAuthClientId', |
70 | allowNull: false | 87 | allowNull: false |
@@ -73,25 +90,25 @@ function associate (models) { | |||
73 | }) | 90 | }) |
74 | } | 91 | } |
75 | 92 | ||
76 | function getByRefreshTokenAndPopulateClient (refreshToken) { | 93 | getByRefreshTokenAndPopulateClient = function (refreshToken) { |
77 | const query = { | 94 | const query = { |
78 | where: { | 95 | where: { |
79 | refreshToken: refreshToken | 96 | refreshToken: refreshToken |
80 | }, | 97 | }, |
81 | include: [ this.associations.OAuthClient ] | 98 | include: [ OAuthToken['sequelize'].models.OAuthClient ] |
82 | } | 99 | } |
83 | 100 | ||
84 | return this.findOne(query).then(function (token) { | 101 | return OAuthToken.findOne(query).then(function (token) { |
85 | if (!token) return token | 102 | if (!token) return token |
86 | 103 | ||
87 | const tokenInfos = { | 104 | const tokenInfos = { |
88 | refreshToken: token.refreshToken, | 105 | refreshToken: token.refreshToken, |
89 | refreshTokenExpiresAt: token.refreshTokenExpiresAt, | 106 | refreshTokenExpiresAt: token.refreshTokenExpiresAt, |
90 | client: { | 107 | client: { |
91 | id: token.client.id | 108 | id: token['client'].id |
92 | }, | 109 | }, |
93 | user: { | 110 | user: { |
94 | id: token.user | 111 | id: token['user'] |
95 | } | 112 | } |
96 | } | 113 | } |
97 | 114 | ||
@@ -101,42 +118,42 @@ function getByRefreshTokenAndPopulateClient (refreshToken) { | |||
101 | }) | 118 | }) |
102 | } | 119 | } |
103 | 120 | ||
104 | function getByTokenAndPopulateUser (bearerToken) { | 121 | getByTokenAndPopulateUser = function (bearerToken) { |
105 | const query = { | 122 | const query = { |
106 | where: { | 123 | where: { |
107 | accessToken: bearerToken | 124 | accessToken: bearerToken |
108 | }, | 125 | }, |
109 | include: [ this.sequelize.models.User ] | 126 | include: [ OAuthToken['sequelize'].models.User ] |
110 | } | 127 | } |
111 | 128 | ||
112 | return this.findOne(query).then(function (token) { | 129 | return OAuthToken.findOne(query).then(function (token) { |
113 | if (token) token.user = token.User | 130 | if (token) token['user'] = token.User |
114 | 131 | ||
115 | return token | 132 | return token |
116 | }) | 133 | }) |
117 | } | 134 | } |
118 | 135 | ||
119 | function getByRefreshTokenAndPopulateUser (refreshToken) { | 136 | getByRefreshTokenAndPopulateUser = function (refreshToken) { |
120 | const query = { | 137 | const query = { |
121 | where: { | 138 | where: { |
122 | refreshToken: refreshToken | 139 | refreshToken: refreshToken |
123 | }, | 140 | }, |
124 | include: [ this.sequelize.models.User ] | 141 | include: [ OAuthToken['sequelize'].models.User ] |
125 | } | 142 | } |
126 | 143 | ||
127 | return this.findOne(query).then(function (token) { | 144 | return OAuthToken.findOne(query).then(function (token) { |
128 | token.user = token.User | 145 | token['user'] = token.User |
129 | 146 | ||
130 | return token | 147 | return token |
131 | }) | 148 | }) |
132 | } | 149 | } |
133 | 150 | ||
134 | function removeByUserId (userId, callback) { | 151 | removeByUserId = function (userId, callback) { |
135 | const query = { | 152 | const query = { |
136 | where: { | 153 | where: { |
137 | userId: userId | 154 | userId: userId |
138 | } | 155 | } |
139 | } | 156 | } |
140 | 157 | ||
141 | return this.destroy(query).asCallback(callback) | 158 | return OAuthToken.destroy(query).asCallback(callback) |
142 | } | 159 | } |
diff --git a/server/models/pod-interface.ts b/server/models/pod-interface.ts new file mode 100644 index 000000000..14c88bec6 --- /dev/null +++ b/server/models/pod-interface.ts | |||
@@ -0,0 +1,46 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace PodMethods { | ||
4 | export type ToFormatedJSON = () => void | ||
5 | |||
6 | export type CountAll = (callback) => void | ||
7 | export type IncrementScores = (ids, value, callback) => void | ||
8 | export type List = (callback) => void | ||
9 | export type ListAllIds = (transaction, callback) => void | ||
10 | export type ListRandomPodIdsWithRequest = (limit, tableWithPods, tableWithPodsJoins, callback) => void | ||
11 | export type ListBadPods = (callback) => void | ||
12 | export type Load = (id, callback) => void | ||
13 | export type LoadByHost = (host, callback) => void | ||
14 | export type RemoveAll = (callback) => void | ||
15 | export type UpdatePodsScore = (goodPods, badPods) => void | ||
16 | } | ||
17 | |||
18 | export interface PodClass { | ||
19 | countAll: PodMethods.CountAll | ||
20 | incrementScores: PodMethods.IncrementScores | ||
21 | list: PodMethods.List | ||
22 | listAllIds: PodMethods.ListAllIds | ||
23 | listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest | ||
24 | listBadPods: PodMethods.ListBadPods | ||
25 | load: PodMethods.Load | ||
26 | loadByHost: PodMethods.LoadByHost | ||
27 | removeAll: PodMethods.RemoveAll | ||
28 | updatePodsScore: PodMethods.UpdatePodsScore | ||
29 | } | ||
30 | |||
31 | export interface PodAttributes { | ||
32 | host?: string | ||
33 | publicKey?: string | ||
34 | score?: number | Sequelize.literal // Sequelize literal for 'score +' + value | ||
35 | email?: string | ||
36 | } | ||
37 | |||
38 | export interface PodInstance extends PodClass, PodAttributes, Sequelize.Instance<PodAttributes> { | ||
39 | id: number | ||
40 | createdAt: Date | ||
41 | updatedAt: Date | ||
42 | |||
43 | toFormatedJSON: PodMethods.ToFormatedJSON, | ||
44 | } | ||
45 | |||
46 | export interface PodModel extends PodClass, Sequelize.Model<PodInstance, PodAttributes> {} | ||
diff --git a/server/models/pod.ts b/server/models/pod.ts index 0e0262978..2df32e4a4 100644 --- a/server/models/pod.ts +++ b/server/models/pod.ts | |||
@@ -1,13 +1,34 @@ | |||
1 | import { each, waterfall } from 'async' | 1 | import { each, waterfall } from 'async' |
2 | import { map } from 'lodash' | 2 | import { map } from 'lodash' |
3 | import * as Sequelize from 'sequelize' | ||
3 | 4 | ||
4 | import { FRIEND_SCORE, PODS_SCORE } from '../initializers' | 5 | import { FRIEND_SCORE, PODS_SCORE } from '../initializers' |
5 | import { logger, isHostValid } from '../helpers' | 6 | import { logger, isHostValid } from '../helpers' |
6 | 7 | ||
7 | // --------------------------------------------------------------------------- | 8 | import { addMethodsToModel } from './utils' |
8 | 9 | import { | |
9 | module.exports = function (sequelize, DataTypes) { | 10 | PodClass, |
10 | const Pod = sequelize.define('Pod', | 11 | PodInstance, |
12 | PodAttributes, | ||
13 | |||
14 | PodMethods | ||
15 | } from './pod-interface' | ||
16 | |||
17 | let Pod: Sequelize.Model<PodInstance, PodAttributes> | ||
18 | let toFormatedJSON: PodMethods.ToFormatedJSON | ||
19 | let countAll: PodMethods.CountAll | ||
20 | let incrementScores: PodMethods.IncrementScores | ||
21 | let list: PodMethods.List | ||
22 | let listAllIds: PodMethods.ListAllIds | ||
23 | let listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest | ||
24 | let listBadPods: PodMethods.ListBadPods | ||
25 | let load: PodMethods.Load | ||
26 | let loadByHost: PodMethods.LoadByHost | ||
27 | let removeAll: PodMethods.RemoveAll | ||
28 | let updatePodsScore: PodMethods.UpdatePodsScore | ||
29 | |||
30 | export default function (sequelize, DataTypes) { | ||
31 | Pod = sequelize.define('Pod', | ||
11 | { | 32 | { |
12 | host: { | 33 | host: { |
13 | type: DataTypes.STRING, | 34 | type: DataTypes.STRING, |
@@ -49,33 +70,33 @@ module.exports = function (sequelize, DataTypes) { | |||
49 | { | 70 | { |
50 | fields: [ 'score' ] | 71 | fields: [ 'score' ] |
51 | } | 72 | } |
52 | ], | 73 | ] |
53 | classMethods: { | ||
54 | associate, | ||
55 | |||
56 | countAll, | ||
57 | incrementScores, | ||
58 | list, | ||
59 | listAllIds, | ||
60 | listRandomPodIdsWithRequest, | ||
61 | listBadPods, | ||
62 | load, | ||
63 | loadByHost, | ||
64 | updatePodsScore, | ||
65 | removeAll | ||
66 | }, | ||
67 | instanceMethods: { | ||
68 | toFormatedJSON | ||
69 | } | ||
70 | } | 74 | } |
71 | ) | 75 | ) |
72 | 76 | ||
77 | const classMethods = [ | ||
78 | associate, | ||
79 | |||
80 | countAll, | ||
81 | incrementScores, | ||
82 | list, | ||
83 | listAllIds, | ||
84 | listRandomPodIdsWithRequest, | ||
85 | listBadPods, | ||
86 | load, | ||
87 | loadByHost, | ||
88 | updatePodsScore, | ||
89 | removeAll | ||
90 | ] | ||
91 | const instanceMethods = [ toFormatedJSON ] | ||
92 | addMethodsToModel(Pod, classMethods, instanceMethods) | ||
93 | |||
73 | return Pod | 94 | return Pod |
74 | } | 95 | } |
75 | 96 | ||
76 | // ------------------------------ METHODS ------------------------------ | 97 | // ------------------------------ METHODS ------------------------------ |
77 | 98 | ||
78 | function toFormatedJSON () { | 99 | toFormatedJSON = function () { |
79 | const json = { | 100 | const json = { |
80 | id: this.id, | 101 | id: this.id, |
81 | host: this.host, | 102 | host: this.host, |
@@ -90,22 +111,22 @@ function toFormatedJSON () { | |||
90 | // ------------------------------ Statics ------------------------------ | 111 | // ------------------------------ Statics ------------------------------ |
91 | 112 | ||
92 | function associate (models) { | 113 | function associate (models) { |
93 | this.belongsToMany(models.Request, { | 114 | Pod.belongsToMany(models.Request, { |
94 | foreignKey: 'podId', | 115 | foreignKey: 'podId', |
95 | through: models.RequestToPod, | 116 | through: models.RequestToPod, |
96 | onDelete: 'cascade' | 117 | onDelete: 'cascade' |
97 | }) | 118 | }) |
98 | } | 119 | } |
99 | 120 | ||
100 | function countAll (callback) { | 121 | countAll = function (callback) { |
101 | return this.count().asCallback(callback) | 122 | return Pod.count().asCallback(callback) |
102 | } | 123 | } |
103 | 124 | ||
104 | function incrementScores (ids, value, callback) { | 125 | incrementScores = function (ids, value, callback) { |
105 | if (!callback) callback = function () { /* empty */ } | 126 | if (!callback) callback = function () { /* empty */ } |
106 | 127 | ||
107 | const update = { | 128 | const update = { |
108 | score: this.sequelize.literal('score +' + value) | 129 | score: Sequelize.literal('score +' + value) |
109 | } | 130 | } |
110 | 131 | ||
111 | const options = { | 132 | const options = { |
@@ -118,14 +139,14 @@ function incrementScores (ids, value, callback) { | |||
118 | validate: false | 139 | validate: false |
119 | } | 140 | } |
120 | 141 | ||
121 | return this.update(update, options).asCallback(callback) | 142 | return Pod.update(update, options).asCallback(callback) |
122 | } | 143 | } |
123 | 144 | ||
124 | function list (callback) { | 145 | list = function (callback) { |
125 | return this.findAll().asCallback(callback) | 146 | return Pod.findAll().asCallback(callback) |
126 | } | 147 | } |
127 | 148 | ||
128 | function listAllIds (transaction, callback) { | 149 | listAllIds = function (transaction, callback) { |
129 | if (!callback) { | 150 | if (!callback) { |
130 | callback = transaction | 151 | callback = transaction |
131 | transaction = null | 152 | transaction = null |
@@ -137,22 +158,20 @@ function listAllIds (transaction, callback) { | |||
137 | 158 | ||
138 | if (transaction) query.transaction = transaction | 159 | if (transaction) query.transaction = transaction |
139 | 160 | ||
140 | return this.findAll(query).asCallback(function (err, pods) { | 161 | return Pod.findAll(query).asCallback(function (err, pods) { |
141 | if (err) return callback(err) | 162 | if (err) return callback(err) |
142 | 163 | ||
143 | return callback(null, map(pods, 'id')) | 164 | return callback(null, map(pods, 'id')) |
144 | }) | 165 | }) |
145 | } | 166 | } |
146 | 167 | ||
147 | function listRandomPodIdsWithRequest (limit, tableWithPods, tableWithPodsJoins, callback) { | 168 | listRandomPodIdsWithRequest = function (limit, tableWithPods, tableWithPodsJoins, callback) { |
148 | if (!callback) { | 169 | if (!callback) { |
149 | callback = tableWithPodsJoins | 170 | callback = tableWithPodsJoins |
150 | tableWithPodsJoins = '' | 171 | tableWithPodsJoins = '' |
151 | } | 172 | } |
152 | 173 | ||
153 | const self = this | 174 | Pod.count().asCallback(function (err, count) { |
154 | |||
155 | self.count().asCallback(function (err, count) { | ||
156 | if (err) return callback(err) | 175 | if (err) return callback(err) |
157 | 176 | ||
158 | // Optimization... | 177 | // Optimization... |
@@ -171,13 +190,13 @@ function listRandomPodIdsWithRequest (limit, tableWithPods, tableWithPodsJoins, | |||
171 | where: { | 190 | where: { |
172 | id: { | 191 | id: { |
173 | $in: [ | 192 | $in: [ |
174 | this.sequelize.literal(`SELECT DISTINCT "${tableWithPods}"."podId" FROM "${tableWithPods}" ${tableWithPodsJoins}`) | 193 | Sequelize.literal(`SELECT DISTINCT "${tableWithPods}"."podId" FROM "${tableWithPods}" ${tableWithPodsJoins}`) |
175 | ] | 194 | ] |
176 | } | 195 | } |
177 | } | 196 | } |
178 | } | 197 | } |
179 | 198 | ||
180 | return this.findAll(query).asCallback(function (err, pods) { | 199 | return Pod.findAll(query).asCallback(function (err, pods) { |
181 | if (err) return callback(err) | 200 | if (err) return callback(err) |
182 | 201 | ||
183 | return callback(null, map(pods, 'id')) | 202 | return callback(null, map(pods, 'id')) |
@@ -185,49 +204,47 @@ function listRandomPodIdsWithRequest (limit, tableWithPods, tableWithPodsJoins, | |||
185 | }) | 204 | }) |
186 | } | 205 | } |
187 | 206 | ||
188 | function listBadPods (callback) { | 207 | listBadPods = function (callback) { |
189 | const query = { | 208 | const query = { |
190 | where: { | 209 | where: { |
191 | score: { $lte: 0 } | 210 | score: { $lte: 0 } |
192 | } | 211 | } |
193 | } | 212 | } |
194 | 213 | ||
195 | return this.findAll(query).asCallback(callback) | 214 | return Pod.findAll(query).asCallback(callback) |
196 | } | 215 | } |
197 | 216 | ||
198 | function load (id, callback) { | 217 | load = function (id, callback) { |
199 | return this.findById(id).asCallback(callback) | 218 | return Pod.findById(id).asCallback(callback) |
200 | } | 219 | } |
201 | 220 | ||
202 | function loadByHost (host, callback) { | 221 | loadByHost = function (host, callback) { |
203 | const query = { | 222 | const query = { |
204 | where: { | 223 | where: { |
205 | host: host | 224 | host: host |
206 | } | 225 | } |
207 | } | 226 | } |
208 | 227 | ||
209 | return this.findOne(query).asCallback(callback) | 228 | return Pod.findOne(query).asCallback(callback) |
210 | } | 229 | } |
211 | 230 | ||
212 | function removeAll (callback) { | 231 | removeAll = function (callback) { |
213 | return this.destroy().asCallback(callback) | 232 | return Pod.destroy().asCallback(callback) |
214 | } | 233 | } |
215 | 234 | ||
216 | function updatePodsScore (goodPods, badPods) { | 235 | updatePodsScore = function (goodPods, badPods) { |
217 | const self = this | ||
218 | |||
219 | logger.info('Updating %d good pods and %d bad pods scores.', goodPods.length, badPods.length) | 236 | logger.info('Updating %d good pods and %d bad pods scores.', goodPods.length, badPods.length) |
220 | 237 | ||
221 | if (goodPods.length !== 0) { | 238 | if (goodPods.length !== 0) { |
222 | this.incrementScores(goodPods, PODS_SCORE.BONUS, function (err) { | 239 | incrementScores(goodPods, PODS_SCORE.BONUS, function (err) { |
223 | if (err) logger.error('Cannot increment scores of good pods.', { error: err }) | 240 | if (err) logger.error('Cannot increment scores of good pods.', { error: err }) |
224 | }) | 241 | }) |
225 | } | 242 | } |
226 | 243 | ||
227 | if (badPods.length !== 0) { | 244 | if (badPods.length !== 0) { |
228 | this.incrementScores(badPods, PODS_SCORE.MALUS, function (err) { | 245 | incrementScores(badPods, PODS_SCORE.MALUS, function (err) { |
229 | if (err) logger.error('Cannot decrement scores of bad pods.', { error: err }) | 246 | if (err) logger.error('Cannot decrement scores of bad pods.', { error: err }) |
230 | removeBadPods.call(self) | 247 | removeBadPods() |
231 | }) | 248 | }) |
232 | } | 249 | } |
233 | } | 250 | } |
@@ -236,11 +253,9 @@ function updatePodsScore (goodPods, badPods) { | |||
236 | 253 | ||
237 | // Remove pods with a score of 0 (too many requests where they were unreachable) | 254 | // Remove pods with a score of 0 (too many requests where they were unreachable) |
238 | function removeBadPods () { | 255 | function removeBadPods () { |
239 | const self = this | ||
240 | |||
241 | waterfall([ | 256 | waterfall([ |
242 | function findBadPods (callback) { | 257 | function findBadPods (callback) { |
243 | self.sequelize.models.Pod.listBadPods(function (err, pods) { | 258 | listBadPods(function (err, pods) { |
244 | if (err) { | 259 | if (err) { |
245 | logger.error('Cannot find bad pods.', { error: err }) | 260 | logger.error('Cannot find bad pods.', { error: err }) |
246 | return callback(err) | 261 | return callback(err) |
diff --git a/server/models/request-interface.ts b/server/models/request-interface.ts new file mode 100644 index 000000000..2bba8ce7f --- /dev/null +++ b/server/models/request-interface.ts | |||
@@ -0,0 +1,32 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | import { PodAttributes } from './pod-interface' | ||
4 | |||
5 | export namespace RequestMethods { | ||
6 | export type CountTotalRequests = (callback) => void | ||
7 | export type ListWithLimitAndRandom = (limitPods, limitRequestsPerPod, callback) => void | ||
8 | export type RemoveWithEmptyTo = (callback) => void | ||
9 | export type RemoveAll = (callback) => void | ||
10 | } | ||
11 | |||
12 | export interface RequestClass { | ||
13 | countTotalRequests: RequestMethods.CountTotalRequests | ||
14 | listWithLimitAndRandom: RequestMethods.ListWithLimitAndRandom | ||
15 | removeWithEmptyTo: RequestMethods.RemoveWithEmptyTo | ||
16 | removeAll: RequestMethods.RemoveAll | ||
17 | } | ||
18 | |||
19 | export interface RequestAttributes { | ||
20 | request: object | ||
21 | endpoint: string | ||
22 | } | ||
23 | |||
24 | export interface RequestInstance extends Sequelize.Instance<RequestAttributes> { | ||
25 | id: number | ||
26 | createdAt: Date | ||
27 | updatedAt: Date | ||
28 | |||
29 | setPods: Sequelize.HasManySetAssociationsMixin<PodAttributes, number> | ||
30 | } | ||
31 | |||
32 | export interface RequestModel extends RequestClass, Sequelize.Model<RequestInstance, RequestAttributes> {} | ||
diff --git a/server/models/request-to-pod-interface.ts b/server/models/request-to-pod-interface.ts new file mode 100644 index 000000000..52116d6c4 --- /dev/null +++ b/server/models/request-to-pod-interface.ts | |||
@@ -0,0 +1,20 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace RequestToPodMethods { | ||
4 | export type RemoveByRequestIdsAndPod = (requestsIds, podId, callback) => void | ||
5 | } | ||
6 | |||
7 | export interface RequestToPodClass { | ||
8 | removeByRequestIdsAndPod: RequestToPodMethods.RemoveByRequestIdsAndPod | ||
9 | } | ||
10 | |||
11 | export interface RequestToPodAttributes { | ||
12 | } | ||
13 | |||
14 | export interface RequestToPodInstance extends Sequelize.Instance<RequestToPodAttributes> { | ||
15 | id: number | ||
16 | createdAt: Date | ||
17 | updatedAt: Date | ||
18 | } | ||
19 | |||
20 | export interface RequestToPodModel extends RequestToPodClass, Sequelize.Model<RequestToPodInstance, RequestToPodAttributes> {} | ||
diff --git a/server/models/request-to-pod.ts b/server/models/request-to-pod.ts index 479202e40..681f808b7 100644 --- a/server/models/request-to-pod.ts +++ b/server/models/request-to-pod.ts | |||
@@ -1,5 +1,19 @@ | |||
1 | module.exports = function (sequelize, DataTypes) { | 1 | import * as Sequelize from 'sequelize' |
2 | const RequestToPod = sequelize.define('RequestToPod', {}, { | 2 | |
3 | import { addMethodsToModel } from './utils' | ||
4 | import { | ||
5 | RequestToPodClass, | ||
6 | RequestToPodInstance, | ||
7 | RequestToPodAttributes, | ||
8 | |||
9 | RequestToPodMethods | ||
10 | } from './request-to-pod-interface' | ||
11 | |||
12 | let RequestToPod: Sequelize.Model<RequestToPodInstance, RequestToPodAttributes> | ||
13 | let removeByRequestIdsAndPod: RequestToPodMethods.RemoveByRequestIdsAndPod | ||
14 | |||
15 | export default function (sequelize, DataTypes) { | ||
16 | RequestToPod = sequelize.define('RequestToPod', {}, { | ||
3 | indexes: [ | 17 | indexes: [ |
4 | { | 18 | { |
5 | fields: [ 'requestId' ] | 19 | fields: [ 'requestId' ] |
@@ -11,18 +25,20 @@ module.exports = function (sequelize, DataTypes) { | |||
11 | fields: [ 'requestId', 'podId' ], | 25 | fields: [ 'requestId', 'podId' ], |
12 | unique: true | 26 | unique: true |
13 | } | 27 | } |
14 | ], | 28 | ] |
15 | classMethods: { | ||
16 | removeByRequestIdsAndPod | ||
17 | } | ||
18 | }) | 29 | }) |
19 | 30 | ||
31 | const classMethods = [ | ||
32 | removeByRequestIdsAndPod | ||
33 | ] | ||
34 | addMethodsToModel(RequestToPod, classMethods) | ||
35 | |||
20 | return RequestToPod | 36 | return RequestToPod |
21 | } | 37 | } |
22 | 38 | ||
23 | // --------------------------------------------------------------------------- | 39 | // --------------------------------------------------------------------------- |
24 | 40 | ||
25 | function removeByRequestIdsAndPod (requestsIds, podId, callback) { | 41 | removeByRequestIdsAndPod = function (requestsIds, podId, callback) { |
26 | if (!callback) callback = function () { /* empty */ } | 42 | if (!callback) callback = function () { /* empty */ } |
27 | 43 | ||
28 | const query = { | 44 | const query = { |
@@ -34,5 +50,5 @@ function removeByRequestIdsAndPod (requestsIds, podId, callback) { | |||
34 | } | 50 | } |
35 | } | 51 | } |
36 | 52 | ||
37 | this.destroy(query).asCallback(callback) | 53 | RequestToPod.destroy(query).asCallback(callback) |
38 | } | 54 | } |
diff --git a/server/models/request-video-event-interface.ts b/server/models/request-video-event-interface.ts new file mode 100644 index 000000000..a31c7108f --- /dev/null +++ b/server/models/request-video-event-interface.ts | |||
@@ -0,0 +1,26 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace RequestVideoEventMethods { | ||
4 | export type CountTotalRequests = (callback) => void | ||
5 | export type ListWithLimitAndRandom = (limitPods, limitRequestsPerPod, callback) => void | ||
6 | export type RemoveByRequestIdsAndPod = (ids, podId, callback) => void | ||
7 | export type RemoveAll = (callback) => void | ||
8 | } | ||
9 | |||
10 | export interface RequestVideoEventClass { | ||
11 | countTotalRequests: RequestVideoEventMethods.CountTotalRequests | ||
12 | listWithLimitAndRandom: RequestVideoEventMethods.ListWithLimitAndRandom | ||
13 | removeByRequestIdsAndPod: RequestVideoEventMethods.RemoveByRequestIdsAndPod | ||
14 | removeAll: RequestVideoEventMethods.RemoveAll | ||
15 | } | ||
16 | |||
17 | export interface RequestVideoEventAttributes { | ||
18 | type: string | ||
19 | count: number | ||
20 | } | ||
21 | |||
22 | export interface RequestVideoEventInstance extends Sequelize.Instance<RequestVideoEventAttributes> { | ||
23 | id: number | ||
24 | } | ||
25 | |||
26 | export interface RequestVideoEventModel extends RequestVideoEventClass, Sequelize.Model<RequestVideoEventInstance, RequestVideoEventAttributes> {} | ||
diff --git a/server/models/request-video-event.ts b/server/models/request-video-event.ts index c61525029..234e2a8a9 100644 --- a/server/models/request-video-event.ts +++ b/server/models/request-video-event.ts | |||
@@ -3,14 +3,28 @@ | |||
3 | */ | 3 | */ |
4 | 4 | ||
5 | import { values } from 'lodash' | 5 | import { values } from 'lodash' |
6 | import * as Sequelize from 'sequelize' | ||
6 | 7 | ||
7 | import { REQUEST_VIDEO_EVENT_TYPES } from '../initializers' | 8 | import { REQUEST_VIDEO_EVENT_TYPES } from '../initializers' |
8 | import { isVideoEventCountValid } from '../helpers' | 9 | import { isVideoEventCountValid } from '../helpers' |
9 | 10 | ||
10 | // --------------------------------------------------------------------------- | 11 | import { addMethodsToModel } from './utils' |
12 | import { | ||
13 | RequestVideoEventClass, | ||
14 | RequestVideoEventInstance, | ||
15 | RequestVideoEventAttributes, | ||
16 | |||
17 | RequestVideoEventMethods | ||
18 | } from './request-video-event-interface' | ||
19 | |||
20 | let RequestVideoEvent: Sequelize.Model<RequestVideoEventInstance, RequestVideoEventAttributes> | ||
21 | let countTotalRequests: RequestVideoEventMethods.CountTotalRequests | ||
22 | let listWithLimitAndRandom: RequestVideoEventMethods.ListWithLimitAndRandom | ||
23 | let removeByRequestIdsAndPod: RequestVideoEventMethods.RemoveByRequestIdsAndPod | ||
24 | let removeAll: RequestVideoEventMethods.RemoveAll | ||
11 | 25 | ||
12 | module.exports = function (sequelize, DataTypes) { | 26 | export default function (sequelize, DataTypes) { |
13 | const RequestVideoEvent = sequelize.define('RequestVideoEvent', | 27 | RequestVideoEvent = sequelize.define('RequestVideoEvent', |
14 | { | 28 | { |
15 | type: { | 29 | type: { |
16 | type: DataTypes.ENUM(values(REQUEST_VIDEO_EVENT_TYPES)), | 30 | type: DataTypes.ENUM(values(REQUEST_VIDEO_EVENT_TYPES)), |
@@ -33,26 +47,27 @@ module.exports = function (sequelize, DataTypes) { | |||
33 | { | 47 | { |
34 | fields: [ 'videoId' ] | 48 | fields: [ 'videoId' ] |
35 | } | 49 | } |
36 | ], | 50 | ] |
37 | classMethods: { | ||
38 | associate, | ||
39 | |||
40 | listWithLimitAndRandom, | ||
41 | |||
42 | countTotalRequests, | ||
43 | removeAll, | ||
44 | removeByRequestIdsAndPod | ||
45 | } | ||
46 | } | 51 | } |
47 | ) | 52 | ) |
48 | 53 | ||
54 | const classMethods = [ | ||
55 | associate, | ||
56 | |||
57 | listWithLimitAndRandom, | ||
58 | countTotalRequests, | ||
59 | removeAll, | ||
60 | removeByRequestIdsAndPod | ||
61 | ] | ||
62 | addMethodsToModel(RequestVideoEvent, classMethods) | ||
63 | |||
49 | return RequestVideoEvent | 64 | return RequestVideoEvent |
50 | } | 65 | } |
51 | 66 | ||
52 | // ------------------------------ STATICS ------------------------------ | 67 | // ------------------------------ STATICS ------------------------------ |
53 | 68 | ||
54 | function associate (models) { | 69 | function associate (models) { |
55 | this.belongsTo(models.Video, { | 70 | RequestVideoEvent.belongsTo(models.Video, { |
56 | foreignKey: { | 71 | foreignKey: { |
57 | name: 'videoId', | 72 | name: 'videoId', |
58 | allowNull: false | 73 | allowNull: false |
@@ -61,14 +76,13 @@ function associate (models) { | |||
61 | }) | 76 | }) |
62 | } | 77 | } |
63 | 78 | ||
64 | function countTotalRequests (callback) { | 79 | countTotalRequests = function (callback) { |
65 | const query = {} | 80 | const query = {} |
66 | return this.count(query).asCallback(callback) | 81 | return RequestVideoEvent.count(query).asCallback(callback) |
67 | } | 82 | } |
68 | 83 | ||
69 | function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { | 84 | listWithLimitAndRandom = function (limitPods, limitRequestsPerPod, callback) { |
70 | const self = this | 85 | const Pod = RequestVideoEvent['sequelize'].models.Pod |
71 | const Pod = this.sequelize.models.Pod | ||
72 | 86 | ||
73 | // We make a join between videos and authors to find the podId of our video event requests | 87 | // We make a join between videos and authors to find the podId of our video event requests |
74 | const podJoins = 'INNER JOIN "Videos" ON "Videos"."authorId" = "Authors"."id" ' + | 88 | const podJoins = 'INNER JOIN "Videos" ON "Videos"."authorId" = "Authors"."id" ' + |
@@ -86,13 +100,13 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { | |||
86 | ], | 100 | ], |
87 | include: [ | 101 | include: [ |
88 | { | 102 | { |
89 | model: self.sequelize.models.Video, | 103 | model: RequestVideoEvent['sequelize'].models.Video, |
90 | include: [ | 104 | include: [ |
91 | { | 105 | { |
92 | model: self.sequelize.models.Author, | 106 | model: RequestVideoEvent['sequelize'].models.Author, |
93 | include: [ | 107 | include: [ |
94 | { | 108 | { |
95 | model: self.sequelize.models.Pod, | 109 | model: RequestVideoEvent['sequelize'].models.Pod, |
96 | where: { | 110 | where: { |
97 | id: { | 111 | id: { |
98 | $in: podIds | 112 | $in: podIds |
@@ -106,7 +120,7 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { | |||
106 | ] | 120 | ] |
107 | } | 121 | } |
108 | 122 | ||
109 | self.findAll(query).asCallback(function (err, requests) { | 123 | RequestVideoEvent.findAll(query).asCallback(function (err, requests) { |
110 | if (err) return callback(err) | 124 | if (err) return callback(err) |
111 | 125 | ||
112 | const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) | 126 | const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) |
@@ -115,7 +129,7 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { | |||
115 | }) | 129 | }) |
116 | } | 130 | } |
117 | 131 | ||
118 | function removeByRequestIdsAndPod (ids, podId, callback) { | 132 | removeByRequestIdsAndPod = function (ids, podId, callback) { |
119 | const query = { | 133 | const query = { |
120 | where: { | 134 | where: { |
121 | id: { | 135 | id: { |
@@ -124,10 +138,10 @@ function removeByRequestIdsAndPod (ids, podId, callback) { | |||
124 | }, | 138 | }, |
125 | include: [ | 139 | include: [ |
126 | { | 140 | { |
127 | model: this.sequelize.models.Video, | 141 | model: RequestVideoEvent['sequelize'].models.Video, |
128 | include: [ | 142 | include: [ |
129 | { | 143 | { |
130 | model: this.sequelize.models.Author, | 144 | model: RequestVideoEvent['sequelize'].models.Author, |
131 | where: { | 145 | where: { |
132 | podId | 146 | podId |
133 | } | 147 | } |
@@ -137,12 +151,12 @@ function removeByRequestIdsAndPod (ids, podId, callback) { | |||
137 | ] | 151 | ] |
138 | } | 152 | } |
139 | 153 | ||
140 | this.destroy(query).asCallback(callback) | 154 | RequestVideoEvent.destroy(query).asCallback(callback) |
141 | } | 155 | } |
142 | 156 | ||
143 | function removeAll (callback) { | 157 | removeAll = function (callback) { |
144 | // Delete all requests | 158 | // Delete all requests |
145 | this.truncate({ cascade: true }).asCallback(callback) | 159 | RequestVideoEvent.truncate({ cascade: true }).asCallback(callback) |
146 | } | 160 | } |
147 | 161 | ||
148 | // --------------------------------------------------------------------------- | 162 | // --------------------------------------------------------------------------- |
diff --git a/server/models/request-video-qadu-interface.ts b/server/models/request-video-qadu-interface.ts new file mode 100644 index 000000000..6fe34ee91 --- /dev/null +++ b/server/models/request-video-qadu-interface.ts | |||
@@ -0,0 +1,25 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace RequestVideoQaduMethods { | ||
4 | export type CountTotalRequests = (callback) => void | ||
5 | export type ListWithLimitAndRandom = (limitPods, limitRequestsPerPod, callback) => void | ||
6 | export type RemoveByRequestIdsAndPod = (ids, podId, callback) => void | ||
7 | export type RemoveAll = (callback) => void | ||
8 | } | ||
9 | |||
10 | export interface RequestVideoQaduClass { | ||
11 | countTotalRequests: RequestVideoQaduMethods.CountTotalRequests | ||
12 | listWithLimitAndRandom: RequestVideoQaduMethods.ListWithLimitAndRandom | ||
13 | removeByRequestIdsAndPod: RequestVideoQaduMethods.RemoveByRequestIdsAndPod | ||
14 | removeAll: RequestVideoQaduMethods.RemoveAll | ||
15 | } | ||
16 | |||
17 | export interface RequestVideoQaduAttributes { | ||
18 | type: string | ||
19 | } | ||
20 | |||
21 | export interface RequestVideoQaduInstance extends Sequelize.Instance<RequestVideoQaduAttributes> { | ||
22 | id: number | ||
23 | } | ||
24 | |||
25 | export interface RequestVideoQaduModel extends RequestVideoQaduClass, Sequelize.Model<RequestVideoQaduInstance, RequestVideoQaduAttributes> {} | ||
diff --git a/server/models/request-video-qadu.ts b/server/models/request-video-qadu.ts index 2b1ed07c9..e914e06cd 100644 --- a/server/models/request-video-qadu.ts +++ b/server/models/request-video-qadu.ts | |||
@@ -10,13 +10,27 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | import { values } from 'lodash' | 12 | import { values } from 'lodash' |
13 | import * as Sequelize from 'sequelize' | ||
13 | 14 | ||
14 | import { REQUEST_VIDEO_QADU_TYPES } from '../initializers' | 15 | import { REQUEST_VIDEO_QADU_TYPES } from '../initializers' |
15 | 16 | ||
16 | // --------------------------------------------------------------------------- | 17 | import { addMethodsToModel } from './utils' |
18 | import { | ||
19 | RequestVideoQaduClass, | ||
20 | RequestVideoQaduInstance, | ||
21 | RequestVideoQaduAttributes, | ||
22 | |||
23 | RequestVideoQaduMethods | ||
24 | } from './request-video-qadu-interface' | ||
25 | |||
26 | let RequestVideoQadu: Sequelize.Model<RequestVideoQaduInstance, RequestVideoQaduAttributes> | ||
27 | let countTotalRequests: RequestVideoQaduMethods.CountTotalRequests | ||
28 | let listWithLimitAndRandom: RequestVideoQaduMethods.ListWithLimitAndRandom | ||
29 | let removeByRequestIdsAndPod: RequestVideoQaduMethods.RemoveByRequestIdsAndPod | ||
30 | let removeAll: RequestVideoQaduMethods.RemoveAll | ||
17 | 31 | ||
18 | module.exports = function (sequelize, DataTypes) { | 32 | export default function (sequelize, DataTypes) { |
19 | const RequestVideoQadu = sequelize.define('RequestVideoQadu', | 33 | RequestVideoQadu = sequelize.define('RequestVideoQadu', |
20 | { | 34 | { |
21 | type: { | 35 | type: { |
22 | type: DataTypes.ENUM(values(REQUEST_VIDEO_QADU_TYPES)), | 36 | type: DataTypes.ENUM(values(REQUEST_VIDEO_QADU_TYPES)), |
@@ -32,26 +46,27 @@ module.exports = function (sequelize, DataTypes) { | |||
32 | { | 46 | { |
33 | fields: [ 'videoId' ] | 47 | fields: [ 'videoId' ] |
34 | } | 48 | } |
35 | ], | 49 | ] |
36 | classMethods: { | ||
37 | associate, | ||
38 | |||
39 | listWithLimitAndRandom, | ||
40 | |||
41 | countTotalRequests, | ||
42 | removeAll, | ||
43 | removeByRequestIdsAndPod | ||
44 | } | ||
45 | } | 50 | } |
46 | ) | 51 | ) |
47 | 52 | ||
53 | const classMethods = [ | ||
54 | associate, | ||
55 | |||
56 | listWithLimitAndRandom, | ||
57 | countTotalRequests, | ||
58 | removeAll, | ||
59 | removeByRequestIdsAndPod | ||
60 | ] | ||
61 | addMethodsToModel(RequestVideoQadu, classMethods) | ||
62 | |||
48 | return RequestVideoQadu | 63 | return RequestVideoQadu |
49 | } | 64 | } |
50 | 65 | ||
51 | // ------------------------------ STATICS ------------------------------ | 66 | // ------------------------------ STATICS ------------------------------ |
52 | 67 | ||
53 | function associate (models) { | 68 | function associate (models) { |
54 | this.belongsTo(models.Pod, { | 69 | RequestVideoQadu.belongsTo(models.Pod, { |
55 | foreignKey: { | 70 | foreignKey: { |
56 | name: 'podId', | 71 | name: 'podId', |
57 | allowNull: false | 72 | allowNull: false |
@@ -59,7 +74,7 @@ function associate (models) { | |||
59 | onDelete: 'CASCADE' | 74 | onDelete: 'CASCADE' |
60 | }) | 75 | }) |
61 | 76 | ||
62 | this.belongsTo(models.Video, { | 77 | RequestVideoQadu.belongsTo(models.Video, { |
63 | foreignKey: { | 78 | foreignKey: { |
64 | name: 'videoId', | 79 | name: 'videoId', |
65 | allowNull: false | 80 | allowNull: false |
@@ -68,14 +83,13 @@ function associate (models) { | |||
68 | }) | 83 | }) |
69 | } | 84 | } |
70 | 85 | ||
71 | function countTotalRequests (callback) { | 86 | countTotalRequests = function (callback) { |
72 | const query = {} | 87 | const query = {} |
73 | return this.count(query).asCallback(callback) | 88 | return RequestVideoQadu.count(query).asCallback(callback) |
74 | } | 89 | } |
75 | 90 | ||
76 | function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { | 91 | listWithLimitAndRandom = function (limitPods, limitRequestsPerPod, callback) { |
77 | const self = this | 92 | const Pod = RequestVideoQadu['sequelize'].models.Pod |
78 | const Pod = this.sequelize.models.Pod | ||
79 | 93 | ||
80 | Pod.listRandomPodIdsWithRequest(limitPods, 'RequestVideoQadus', function (err, podIds) { | 94 | Pod.listRandomPodIdsWithRequest(limitPods, 'RequestVideoQadus', function (err, podIds) { |
81 | if (err) return callback(err) | 95 | if (err) return callback(err) |
@@ -86,7 +100,7 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { | |||
86 | const query = { | 100 | const query = { |
87 | include: [ | 101 | include: [ |
88 | { | 102 | { |
89 | model: self.sequelize.models.Pod, | 103 | model: RequestVideoQadu['sequelize'].models.Pod, |
90 | where: { | 104 | where: { |
91 | id: { | 105 | id: { |
92 | $in: podIds | 106 | $in: podIds |
@@ -94,12 +108,12 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { | |||
94 | } | 108 | } |
95 | }, | 109 | }, |
96 | { | 110 | { |
97 | model: self.sequelize.models.Video | 111 | model: RequestVideoQadu['sequelize'].models.Video |
98 | } | 112 | } |
99 | ] | 113 | ] |
100 | } | 114 | } |
101 | 115 | ||
102 | self.findAll(query).asCallback(function (err, requests) { | 116 | RequestVideoQadu.findAll(query).asCallback(function (err, requests) { |
103 | if (err) return callback(err) | 117 | if (err) return callback(err) |
104 | 118 | ||
105 | const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) | 119 | const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) |
@@ -108,7 +122,7 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { | |||
108 | }) | 122 | }) |
109 | } | 123 | } |
110 | 124 | ||
111 | function removeByRequestIdsAndPod (ids, podId, callback) { | 125 | removeByRequestIdsAndPod = function (ids, podId, callback) { |
112 | const query = { | 126 | const query = { |
113 | where: { | 127 | where: { |
114 | id: { | 128 | id: { |
@@ -118,12 +132,12 @@ function removeByRequestIdsAndPod (ids, podId, callback) { | |||
118 | } | 132 | } |
119 | } | 133 | } |
120 | 134 | ||
121 | this.destroy(query).asCallback(callback) | 135 | RequestVideoQadu.destroy(query).asCallback(callback) |
122 | } | 136 | } |
123 | 137 | ||
124 | function removeAll (callback) { | 138 | removeAll = function (callback) { |
125 | // Delete all requests | 139 | // Delete all requests |
126 | this.truncate({ cascade: true }).asCallback(callback) | 140 | RequestVideoQadu.truncate({ cascade: true }).asCallback(callback) |
127 | } | 141 | } |
128 | 142 | ||
129 | // --------------------------------------------------------------------------- | 143 | // --------------------------------------------------------------------------- |
diff --git a/server/models/request.ts b/server/models/request.ts index 672f79d11..18fa291fa 100644 --- a/server/models/request.ts +++ b/server/models/request.ts | |||
@@ -1,11 +1,25 @@ | |||
1 | import { values } from 'lodash' | 1 | import { values } from 'lodash' |
2 | import * as Sequelize from 'sequelize' | ||
2 | 3 | ||
3 | import { REQUEST_ENDPOINTS } from '../initializers' | 4 | import { REQUEST_ENDPOINTS } from '../initializers' |
4 | 5 | ||
5 | // --------------------------------------------------------------------------- | 6 | import { addMethodsToModel } from './utils' |
7 | import { | ||
8 | RequestClass, | ||
9 | RequestInstance, | ||
10 | RequestAttributes, | ||
11 | |||
12 | RequestMethods | ||
13 | } from './request-interface' | ||
14 | |||
15 | let Request: Sequelize.Model<RequestInstance, RequestAttributes> | ||
16 | let countTotalRequests: RequestMethods.CountTotalRequests | ||
17 | let listWithLimitAndRandom: RequestMethods.ListWithLimitAndRandom | ||
18 | let removeWithEmptyTo: RequestMethods.RemoveWithEmptyTo | ||
19 | let removeAll: RequestMethods.RemoveAll | ||
6 | 20 | ||
7 | module.exports = function (sequelize, DataTypes) { | 21 | export default function (sequelize, DataTypes) { |
8 | const Request = sequelize.define('Request', | 22 | Request = sequelize.define('Request', |
9 | { | 23 | { |
10 | request: { | 24 | request: { |
11 | type: DataTypes.JSON, | 25 | type: DataTypes.JSON, |
@@ -15,27 +29,27 @@ module.exports = function (sequelize, DataTypes) { | |||
15 | type: DataTypes.ENUM(values(REQUEST_ENDPOINTS)), | 29 | type: DataTypes.ENUM(values(REQUEST_ENDPOINTS)), |
16 | allowNull: false | 30 | allowNull: false |
17 | } | 31 | } |
18 | }, | ||
19 | { | ||
20 | classMethods: { | ||
21 | associate, | ||
22 | |||
23 | listWithLimitAndRandom, | ||
24 | |||
25 | countTotalRequests, | ||
26 | removeAll, | ||
27 | removeWithEmptyTo | ||
28 | } | ||
29 | } | 32 | } |
30 | ) | 33 | ) |
31 | 34 | ||
35 | const classMethods = [ | ||
36 | associate, | ||
37 | |||
38 | listWithLimitAndRandom, | ||
39 | |||
40 | countTotalRequests, | ||
41 | removeAll, | ||
42 | removeWithEmptyTo | ||
43 | ] | ||
44 | addMethodsToModel(Request, classMethods) | ||
45 | |||
32 | return Request | 46 | return Request |
33 | } | 47 | } |
34 | 48 | ||
35 | // ------------------------------ STATICS ------------------------------ | 49 | // ------------------------------ STATICS ------------------------------ |
36 | 50 | ||
37 | function associate (models) { | 51 | function associate (models) { |
38 | this.belongsToMany(models.Pod, { | 52 | Request.belongsToMany(models.Pod, { |
39 | foreignKey: { | 53 | foreignKey: { |
40 | name: 'requestId', | 54 | name: 'requestId', |
41 | allowNull: false | 55 | allowNull: false |
@@ -45,19 +59,18 @@ function associate (models) { | |||
45 | }) | 59 | }) |
46 | } | 60 | } |
47 | 61 | ||
48 | function countTotalRequests (callback) { | 62 | countTotalRequests = function (callback) { |
49 | // We need to include Pod because there are no cascade delete when a pod is removed | 63 | // We need to include Pod because there are no cascade delete when a pod is removed |
50 | // So we could count requests that do not have existing pod anymore | 64 | // So we could count requests that do not have existing pod anymore |
51 | const query = { | 65 | const query = { |
52 | include: [ this.sequelize.models.Pod ] | 66 | include: [ Request['sequelize'].models.Pod ] |
53 | } | 67 | } |
54 | 68 | ||
55 | return this.count(query).asCallback(callback) | 69 | return Request.count(query).asCallback(callback) |
56 | } | 70 | } |
57 | 71 | ||
58 | function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { | 72 | listWithLimitAndRandom = function (limitPods, limitRequestsPerPod, callback) { |
59 | const self = this | 73 | const Pod = Request['sequelize'].models.Pod |
60 | const Pod = this.sequelize.models.Pod | ||
61 | 74 | ||
62 | Pod.listRandomPodIdsWithRequest(limitPods, 'RequestToPods', function (err, podIds) { | 75 | Pod.listRandomPodIdsWithRequest(limitPods, 'RequestToPods', function (err, podIds) { |
63 | if (err) return callback(err) | 76 | if (err) return callback(err) |
@@ -73,7 +86,7 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { | |||
73 | ], | 86 | ], |
74 | include: [ | 87 | include: [ |
75 | { | 88 | { |
76 | model: self.sequelize.models.Pod, | 89 | model: Request['sequelize'].models.Pod, |
77 | where: { | 90 | where: { |
78 | id: { | 91 | id: { |
79 | $in: podIds | 92 | $in: podIds |
@@ -83,7 +96,7 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { | |||
83 | ] | 96 | ] |
84 | } | 97 | } |
85 | 98 | ||
86 | self.findAll(query).asCallback(function (err, requests) { | 99 | Request.findAll(query).asCallback(function (err, requests) { |
87 | if (err) return callback(err) | 100 | if (err) return callback(err) |
88 | 101 | ||
89 | const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) | 102 | const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) |
@@ -92,25 +105,25 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { | |||
92 | }) | 105 | }) |
93 | } | 106 | } |
94 | 107 | ||
95 | function removeAll (callback) { | 108 | removeAll = function (callback) { |
96 | // Delete all requests | 109 | // Delete all requests |
97 | this.truncate({ cascade: true }).asCallback(callback) | 110 | Request.truncate({ cascade: true }).asCallback(callback) |
98 | } | 111 | } |
99 | 112 | ||
100 | function removeWithEmptyTo (callback) { | 113 | removeWithEmptyTo = function (callback) { |
101 | if (!callback) callback = function () { /* empty */ } | 114 | if (!callback) callback = function () { /* empty */ } |
102 | 115 | ||
103 | const query = { | 116 | const query = { |
104 | where: { | 117 | where: { |
105 | id: { | 118 | id: { |
106 | $notIn: [ | 119 | $notIn: [ |
107 | this.sequelize.literal('SELECT "requestId" FROM "RequestToPods"') | 120 | Sequelize.literal('SELECT "requestId" FROM "RequestToPods"') |
108 | ] | 121 | ] |
109 | } | 122 | } |
110 | } | 123 | } |
111 | } | 124 | } |
112 | 125 | ||
113 | this.destroy(query).asCallback(callback) | 126 | Request.destroy(query).asCallback(callback) |
114 | } | 127 | } |
115 | 128 | ||
116 | // --------------------------------------------------------------------------- | 129 | // --------------------------------------------------------------------------- |
diff --git a/server/models/tag-interface.ts b/server/models/tag-interface.ts new file mode 100644 index 000000000..f96e1e9c5 --- /dev/null +++ b/server/models/tag-interface.ts | |||
@@ -0,0 +1,19 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace TagMethods { | ||
4 | export type FindOrCreateTags = (tags, transaction, callback) => void | ||
5 | } | ||
6 | |||
7 | export interface TagClass { | ||
8 | findOrCreateTags: TagMethods.FindOrCreateTags | ||
9 | } | ||
10 | |||
11 | export interface TagAttributes { | ||
12 | name: string | ||
13 | } | ||
14 | |||
15 | export interface TagInstance extends TagClass, TagAttributes, Sequelize.Instance<TagAttributes> { | ||
16 | id: number | ||
17 | } | ||
18 | |||
19 | export interface TagModel extends TagClass, Sequelize.Model<TagInstance, TagAttributes> {} | ||
diff --git a/server/models/tag.ts b/server/models/tag.ts index 85a0442d2..b2a9c9f81 100644 --- a/server/models/tag.ts +++ b/server/models/tag.ts | |||
@@ -1,9 +1,20 @@ | |||
1 | import { each } from 'async' | 1 | import { each } from 'async' |
2 | import * as Sequelize from 'sequelize' | ||
2 | 3 | ||
3 | // --------------------------------------------------------------------------- | 4 | import { addMethodsToModel } from './utils' |
5 | import { | ||
6 | TagClass, | ||
7 | TagInstance, | ||
8 | TagAttributes, | ||
9 | |||
10 | TagMethods | ||
11 | } from './tag-interface' | ||
4 | 12 | ||
5 | module.exports = function (sequelize, DataTypes) { | 13 | let Tag: Sequelize.Model<TagInstance, TagAttributes> |
6 | const Tag = sequelize.define('Tag', | 14 | let findOrCreateTags: TagMethods.FindOrCreateTags |
15 | |||
16 | export default function (sequelize, DataTypes) { | ||
17 | Tag = sequelize.define('Tag', | ||
7 | { | 18 | { |
8 | name: { | 19 | name: { |
9 | type: DataTypes.STRING, | 20 | type: DataTypes.STRING, |
@@ -17,35 +28,36 @@ module.exports = function (sequelize, DataTypes) { | |||
17 | fields: [ 'name' ], | 28 | fields: [ 'name' ], |
18 | unique: true | 29 | unique: true |
19 | } | 30 | } |
20 | ], | 31 | ] |
21 | classMethods: { | ||
22 | associate, | ||
23 | |||
24 | findOrCreateTags | ||
25 | } | ||
26 | } | 32 | } |
27 | ) | 33 | ) |
28 | 34 | ||
35 | const classMethods = [ | ||
36 | associate, | ||
37 | |||
38 | findOrCreateTags | ||
39 | ] | ||
40 | addMethodsToModel(Tag, classMethods) | ||
41 | |||
29 | return Tag | 42 | return Tag |
30 | } | 43 | } |
31 | 44 | ||
32 | // --------------------------------------------------------------------------- | 45 | // --------------------------------------------------------------------------- |
33 | 46 | ||
34 | function associate (models) { | 47 | function associate (models) { |
35 | this.belongsToMany(models.Video, { | 48 | Tag.belongsToMany(models.Video, { |
36 | foreignKey: 'tagId', | 49 | foreignKey: 'tagId', |
37 | through: models.VideoTag, | 50 | through: models.VideoTag, |
38 | onDelete: 'cascade' | 51 | onDelete: 'cascade' |
39 | }) | 52 | }) |
40 | } | 53 | } |
41 | 54 | ||
42 | function findOrCreateTags (tags, transaction, callback) { | 55 | findOrCreateTags = function (tags, transaction, callback) { |
43 | if (!callback) { | 56 | if (!callback) { |
44 | callback = transaction | 57 | callback = transaction |
45 | transaction = null | 58 | transaction = null |
46 | } | 59 | } |
47 | 60 | ||
48 | const self = this | ||
49 | const tagInstances = [] | 61 | const tagInstances = [] |
50 | 62 | ||
51 | each(tags, function (tag, callbackEach) { | 63 | each(tags, function (tag, callbackEach) { |
@@ -60,7 +72,7 @@ function findOrCreateTags (tags, transaction, callback) { | |||
60 | 72 | ||
61 | if (transaction) query.transaction = transaction | 73 | if (transaction) query.transaction = transaction |
62 | 74 | ||
63 | self.findOrCreate(query).asCallback(function (err, res) { | 75 | Tag.findOrCreate(query).asCallback(function (err, res) { |
64 | if (err) return callbackEach(err) | 76 | if (err) return callbackEach(err) |
65 | 77 | ||
66 | // res = [ tag, isCreated ] | 78 | // res = [ tag, isCreated ] |
diff --git a/server/models/user-interface.ts b/server/models/user-interface.ts new file mode 100644 index 000000000..a504f42a1 --- /dev/null +++ b/server/models/user-interface.ts | |||
@@ -0,0 +1,45 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace UserMethods { | ||
4 | export type IsPasswordMatch = (password, callback) => void | ||
5 | export type ToFormatedJSON = () => void | ||
6 | export type IsAdmin = () => boolean | ||
7 | |||
8 | export type CountTotal = (callback) => void | ||
9 | export type GetByUsername = (username) => any | ||
10 | export type List = (callback) => void | ||
11 | export type ListForApi = (start, count, sort, callback) => void | ||
12 | export type LoadById = (id, callback) => void | ||
13 | export type LoadByUsername = (username, callback) => void | ||
14 | export type LoadByUsernameOrEmail = (username, email, callback) => void | ||
15 | } | ||
16 | |||
17 | export interface UserClass { | ||
18 | isPasswordMatch: UserMethods.IsPasswordMatch, | ||
19 | toFormatedJSON: UserMethods.ToFormatedJSON, | ||
20 | isAdmin: UserMethods.IsAdmin, | ||
21 | |||
22 | countTotal: UserMethods.CountTotal, | ||
23 | getByUsername: UserMethods.GetByUsername, | ||
24 | list: UserMethods.List, | ||
25 | listForApi: UserMethods.ListForApi, | ||
26 | loadById: UserMethods.LoadById, | ||
27 | loadByUsername: UserMethods.LoadByUsername, | ||
28 | loadByUsernameOrEmail: UserMethods.LoadByUsernameOrEmail | ||
29 | } | ||
30 | |||
31 | export interface UserAttributes { | ||
32 | password: string | ||
33 | username: string | ||
34 | email: string | ||
35 | displayNSFW?: boolean | ||
36 | role: string | ||
37 | } | ||
38 | |||
39 | export interface UserInstance extends UserClass, UserAttributes, Sequelize.Instance<UserAttributes> { | ||
40 | id: number | ||
41 | createdAt: Date | ||
42 | updatedAt: Date | ||
43 | } | ||
44 | |||
45 | export interface UserModel extends UserClass, Sequelize.Model<UserInstance, UserAttributes> {} | ||
diff --git a/server/models/user-video-rate-interface.ts b/server/models/user-video-rate-interface.ts new file mode 100644 index 000000000..57d2e2b91 --- /dev/null +++ b/server/models/user-video-rate-interface.ts | |||
@@ -0,0 +1,21 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace UserVideoRateMethods { | ||
4 | export type Load = (userId, videoId, transaction, callback) => void | ||
5 | } | ||
6 | |||
7 | export interface UserVideoRateClass { | ||
8 | load: UserVideoRateMethods.Load | ||
9 | } | ||
10 | |||
11 | export interface UserVideoRateAttributes { | ||
12 | type: string | ||
13 | } | ||
14 | |||
15 | export interface UserVideoRateInstance extends Sequelize.Instance<UserVideoRateAttributes> { | ||
16 | id: number | ||
17 | createdAt: Date | ||
18 | updatedAt: Date | ||
19 | } | ||
20 | |||
21 | export interface UserVideoRateModel extends UserVideoRateClass, Sequelize.Model<UserVideoRateInstance, UserVideoRateAttributes> {} | ||
diff --git a/server/models/user-video-rate.ts b/server/models/user-video-rate.ts index 6603c7862..87886d8d0 100644 --- a/server/models/user-video-rate.ts +++ b/server/models/user-video-rate.ts | |||
@@ -3,13 +3,24 @@ | |||
3 | 3 | ||
4 | */ | 4 | */ |
5 | import { values } from 'lodash' | 5 | import { values } from 'lodash' |
6 | import * as Sequelize from 'sequelize' | ||
6 | 7 | ||
7 | import { VIDEO_RATE_TYPES } from '../initializers' | 8 | import { VIDEO_RATE_TYPES } from '../initializers' |
8 | 9 | ||
9 | // --------------------------------------------------------------------------- | 10 | import { addMethodsToModel } from './utils' |
11 | import { | ||
12 | UserVideoRateClass, | ||
13 | UserVideoRateInstance, | ||
14 | UserVideoRateAttributes, | ||
10 | 15 | ||
11 | module.exports = function (sequelize, DataTypes) { | 16 | UserVideoRateMethods |
12 | const UserVideoRate = sequelize.define('UserVideoRate', | 17 | } from './user-video-rate-interface' |
18 | |||
19 | let UserVideoRate: Sequelize.Model<UserVideoRateInstance, UserVideoRateAttributes> | ||
20 | let load: UserVideoRateMethods.Load | ||
21 | |||
22 | export default function (sequelize, DataTypes) { | ||
23 | UserVideoRate = sequelize.define('UserVideoRate', | ||
13 | { | 24 | { |
14 | type: { | 25 | type: { |
15 | type: DataTypes.ENUM(values(VIDEO_RATE_TYPES)), | 26 | type: DataTypes.ENUM(values(VIDEO_RATE_TYPES)), |
@@ -22,22 +33,24 @@ module.exports = function (sequelize, DataTypes) { | |||
22 | fields: [ 'videoId', 'userId', 'type' ], | 33 | fields: [ 'videoId', 'userId', 'type' ], |
23 | unique: true | 34 | unique: true |
24 | } | 35 | } |
25 | ], | 36 | ] |
26 | classMethods: { | ||
27 | associate, | ||
28 | |||
29 | load | ||
30 | } | ||
31 | } | 37 | } |
32 | ) | 38 | ) |
33 | 39 | ||
40 | const classMethods = [ | ||
41 | associate, | ||
42 | |||
43 | load | ||
44 | ] | ||
45 | addMethodsToModel(UserVideoRate, classMethods) | ||
46 | |||
34 | return UserVideoRate | 47 | return UserVideoRate |
35 | } | 48 | } |
36 | 49 | ||
37 | // ------------------------------ STATICS ------------------------------ | 50 | // ------------------------------ STATICS ------------------------------ |
38 | 51 | ||
39 | function associate (models) { | 52 | function associate (models) { |
40 | this.belongsTo(models.Video, { | 53 | UserVideoRate.belongsTo(models.Video, { |
41 | foreignKey: { | 54 | foreignKey: { |
42 | name: 'videoId', | 55 | name: 'videoId', |
43 | allowNull: false | 56 | allowNull: false |
@@ -45,7 +58,7 @@ function associate (models) { | |||
45 | onDelete: 'CASCADE' | 58 | onDelete: 'CASCADE' |
46 | }) | 59 | }) |
47 | 60 | ||
48 | this.belongsTo(models.User, { | 61 | UserVideoRate.belongsTo(models.User, { |
49 | foreignKey: { | 62 | foreignKey: { |
50 | name: 'userId', | 63 | name: 'userId', |
51 | allowNull: false | 64 | allowNull: false |
@@ -54,21 +67,14 @@ function associate (models) { | |||
54 | }) | 67 | }) |
55 | } | 68 | } |
56 | 69 | ||
57 | function load (userId, videoId, transaction, callback) { | 70 | load = function (userId, videoId, transaction, callback) { |
58 | if (!callback) { | 71 | const options: Sequelize.FindOptions = { |
59 | callback = transaction | ||
60 | transaction = null | ||
61 | } | ||
62 | |||
63 | const query = { | ||
64 | where: { | 72 | where: { |
65 | userId, | 73 | userId, |
66 | videoId | 74 | videoId |
67 | } | 75 | } |
68 | } | 76 | } |
69 | |||
70 | const options: any = {} | ||
71 | if (transaction) options.transaction = transaction | 77 | if (transaction) options.transaction = transaction |
72 | 78 | ||
73 | return this.findOne(query, options).asCallback(callback) | 79 | return UserVideoRate.findOne(options).asCallback(callback) |
74 | } | 80 | } |
diff --git a/server/models/user.ts b/server/models/user.ts index d63a50cc4..12ddaaeb7 100644 --- a/server/models/user.ts +++ b/server/models/user.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { values } from 'lodash' | 1 | import { values } from 'lodash' |
2 | import * as Sequelize from 'sequelize' | ||
2 | 3 | ||
3 | import { getSort } from './utils' | 4 | import { getSort } from './utils' |
4 | import { USER_ROLES } from '../initializers' | 5 | import { USER_ROLES } from '../initializers' |
@@ -10,10 +11,29 @@ import { | |||
10 | isUserDisplayNSFWValid | 11 | isUserDisplayNSFWValid |
11 | } from '../helpers' | 12 | } from '../helpers' |
12 | 13 | ||
13 | // --------------------------------------------------------------------------- | 14 | import { addMethodsToModel } from './utils' |
14 | 15 | import { | |
15 | module.exports = function (sequelize, DataTypes) { | 16 | UserClass, |
16 | const User = sequelize.define('User', | 17 | UserInstance, |
18 | UserAttributes, | ||
19 | |||
20 | UserMethods | ||
21 | } from './user-interface' | ||
22 | |||
23 | let User: Sequelize.Model<UserInstance, UserAttributes> | ||
24 | let isPasswordMatch: UserMethods.IsPasswordMatch | ||
25 | let toFormatedJSON: UserMethods.ToFormatedJSON | ||
26 | let isAdmin: UserMethods.IsAdmin | ||
27 | let countTotal: UserMethods.CountTotal | ||
28 | let getByUsername: UserMethods.GetByUsername | ||
29 | let list: UserMethods.List | ||
30 | let listForApi: UserMethods.ListForApi | ||
31 | let loadById: UserMethods.LoadById | ||
32 | let loadByUsername: UserMethods.LoadByUsername | ||
33 | let loadByUsernameOrEmail: UserMethods.LoadByUsernameOrEmail | ||
34 | |||
35 | export default function (sequelize, DataTypes) { | ||
36 | User = sequelize.define('User', | ||
17 | { | 37 | { |
18 | password: { | 38 | password: { |
19 | type: DataTypes.STRING, | 39 | type: DataTypes.STRING, |
@@ -69,22 +89,6 @@ module.exports = function (sequelize, DataTypes) { | |||
69 | unique: true | 89 | unique: true |
70 | } | 90 | } |
71 | ], | 91 | ], |
72 | classMethods: { | ||
73 | associate, | ||
74 | |||
75 | countTotal, | ||
76 | getByUsername, | ||
77 | list, | ||
78 | listForApi, | ||
79 | loadById, | ||
80 | loadByUsername, | ||
81 | loadByUsernameOrEmail | ||
82 | }, | ||
83 | instanceMethods: { | ||
84 | isPasswordMatch, | ||
85 | toFormatedJSON, | ||
86 | isAdmin | ||
87 | }, | ||
88 | hooks: { | 92 | hooks: { |
89 | beforeCreate: beforeCreateOrUpdate, | 93 | beforeCreate: beforeCreateOrUpdate, |
90 | beforeUpdate: beforeCreateOrUpdate | 94 | beforeUpdate: beforeCreateOrUpdate |
@@ -92,26 +96,46 @@ module.exports = function (sequelize, DataTypes) { | |||
92 | } | 96 | } |
93 | ) | 97 | ) |
94 | 98 | ||
99 | const classMethods = [ | ||
100 | associate, | ||
101 | |||
102 | countTotal, | ||
103 | getByUsername, | ||
104 | list, | ||
105 | listForApi, | ||
106 | loadById, | ||
107 | loadByUsername, | ||
108 | loadByUsernameOrEmail | ||
109 | ] | ||
110 | const instanceMethods = [ | ||
111 | isPasswordMatch, | ||
112 | toFormatedJSON, | ||
113 | isAdmin | ||
114 | ] | ||
115 | addMethodsToModel(User, classMethods, instanceMethods) | ||
116 | |||
95 | return User | 117 | return User |
96 | } | 118 | } |
97 | 119 | ||
98 | function beforeCreateOrUpdate (user, options, next) { | 120 | function beforeCreateOrUpdate (user, options) { |
99 | cryptPassword(user.password, function (err, hash) { | 121 | return new Promise(function (resolve, reject) { |
100 | if (err) return next(err) | 122 | cryptPassword(user.password, function (err, hash) { |
123 | if (err) return reject(err) | ||
101 | 124 | ||
102 | user.password = hash | 125 | user.password = hash |
103 | 126 | ||
104 | return next() | 127 | return resolve() |
128 | }) | ||
105 | }) | 129 | }) |
106 | } | 130 | } |
107 | 131 | ||
108 | // ------------------------------ METHODS ------------------------------ | 132 | // ------------------------------ METHODS ------------------------------ |
109 | 133 | ||
110 | function isPasswordMatch (password, callback) { | 134 | isPasswordMatch = function (password, callback) { |
111 | return comparePassword(password, this.password, callback) | 135 | return comparePassword(password, this.password, callback) |
112 | } | 136 | } |
113 | 137 | ||
114 | function toFormatedJSON () { | 138 | toFormatedJSON = function () { |
115 | return { | 139 | return { |
116 | id: this.id, | 140 | id: this.id, |
117 | username: this.username, | 141 | username: this.username, |
@@ -122,76 +146,76 @@ function toFormatedJSON () { | |||
122 | } | 146 | } |
123 | } | 147 | } |
124 | 148 | ||
125 | function isAdmin () { | 149 | isAdmin = function () { |
126 | return this.role === USER_ROLES.ADMIN | 150 | return this.role === USER_ROLES.ADMIN |
127 | } | 151 | } |
128 | 152 | ||
129 | // ------------------------------ STATICS ------------------------------ | 153 | // ------------------------------ STATICS ------------------------------ |
130 | 154 | ||
131 | function associate (models) { | 155 | function associate (models) { |
132 | this.hasOne(models.Author, { | 156 | User.hasOne(models.Author, { |
133 | foreignKey: 'userId', | 157 | foreignKey: 'userId', |
134 | onDelete: 'cascade' | 158 | onDelete: 'cascade' |
135 | }) | 159 | }) |
136 | 160 | ||
137 | this.hasMany(models.OAuthToken, { | 161 | User.hasMany(models.OAuthToken, { |
138 | foreignKey: 'userId', | 162 | foreignKey: 'userId', |
139 | onDelete: 'cascade' | 163 | onDelete: 'cascade' |
140 | }) | 164 | }) |
141 | } | 165 | } |
142 | 166 | ||
143 | function countTotal (callback) { | 167 | countTotal = function (callback) { |
144 | return this.count().asCallback(callback) | 168 | return this.count().asCallback(callback) |
145 | } | 169 | } |
146 | 170 | ||
147 | function getByUsername (username) { | 171 | getByUsername = function (username) { |
148 | const query = { | 172 | const query = { |
149 | where: { | 173 | where: { |
150 | username: username | 174 | username: username |
151 | } | 175 | } |
152 | } | 176 | } |
153 | 177 | ||
154 | return this.findOne(query) | 178 | return User.findOne(query) |
155 | } | 179 | } |
156 | 180 | ||
157 | function list (callback) { | 181 | list = function (callback) { |
158 | return this.find().asCallback(callback) | 182 | return User.find().asCallback(callback) |
159 | } | 183 | } |
160 | 184 | ||
161 | function listForApi (start, count, sort, callback) { | 185 | listForApi = function (start, count, sort, callback) { |
162 | const query = { | 186 | const query = { |
163 | offset: start, | 187 | offset: start, |
164 | limit: count, | 188 | limit: count, |
165 | order: [ getSort(sort) ] | 189 | order: [ getSort(sort) ] |
166 | } | 190 | } |
167 | 191 | ||
168 | return this.findAndCountAll(query).asCallback(function (err, result) { | 192 | return User.findAndCountAll(query).asCallback(function (err, result) { |
169 | if (err) return callback(err) | 193 | if (err) return callback(err) |
170 | 194 | ||
171 | return callback(null, result.rows, result.count) | 195 | return callback(null, result.rows, result.count) |
172 | }) | 196 | }) |
173 | } | 197 | } |
174 | 198 | ||
175 | function loadById (id, callback) { | 199 | loadById = function (id, callback) { |
176 | return this.findById(id).asCallback(callback) | 200 | return User.findById(id).asCallback(callback) |
177 | } | 201 | } |
178 | 202 | ||
179 | function loadByUsername (username, callback) { | 203 | loadByUsername = function (username, callback) { |
180 | const query = { | 204 | const query = { |
181 | where: { | 205 | where: { |
182 | username: username | 206 | username: username |
183 | } | 207 | } |
184 | } | 208 | } |
185 | 209 | ||
186 | return this.findOne(query).asCallback(callback) | 210 | return User.findOne(query).asCallback(callback) |
187 | } | 211 | } |
188 | 212 | ||
189 | function loadByUsernameOrEmail (username, email, callback) { | 213 | loadByUsernameOrEmail = function (username, email, callback) { |
190 | const query = { | 214 | const query = { |
191 | where: { | 215 | where: { |
192 | $or: [ { username }, { email } ] | 216 | $or: [ { username }, { email } ] |
193 | } | 217 | } |
194 | } | 218 | } |
195 | 219 | ||
196 | return this.findOne(query).asCallback(callback) | 220 | return User.findOne(query).asCallback(callback) |
197 | } | 221 | } |
diff --git a/server/models/utils.ts b/server/models/utils.ts index 601811913..fd84a9239 100644 --- a/server/models/utils.ts +++ b/server/models/utils.ts | |||
@@ -14,8 +14,14 @@ function getSort (value) { | |||
14 | return [ field, direction ] | 14 | return [ field, direction ] |
15 | } | 15 | } |
16 | 16 | ||
17 | function addMethodsToModel (model: any, classMethods: Function[], instanceMethods: Function[] = []) { | ||
18 | classMethods.forEach(m => model[m.name] = m) | ||
19 | instanceMethods.forEach(m => model.prototype[m.name] = m) | ||
20 | } | ||
21 | |||
17 | // --------------------------------------------------------------------------- | 22 | // --------------------------------------------------------------------------- |
18 | 23 | ||
19 | export { | 24 | export { |
25 | addMethodsToModel, | ||
20 | getSort | 26 | getSort |
21 | } | 27 | } |
diff --git a/server/models/video-abuse-interface.ts b/server/models/video-abuse-interface.ts new file mode 100644 index 000000000..9b77fc6f5 --- /dev/null +++ b/server/models/video-abuse-interface.ts | |||
@@ -0,0 +1,24 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace VideoAbuseMethods { | ||
4 | export type toFormatedJSON = () => void | ||
5 | |||
6 | export type ListForApi = (start, count, sort, callback) => void | ||
7 | } | ||
8 | |||
9 | export interface VideoAbuseClass { | ||
10 | listForApi: VideoAbuseMethods.ListForApi | ||
11 | } | ||
12 | |||
13 | export interface VideoAbuseAttributes { | ||
14 | reporterUsername: string | ||
15 | reason: string | ||
16 | } | ||
17 | |||
18 | export interface VideoAbuseInstance extends Sequelize.Instance<VideoAbuseAttributes> { | ||
19 | id: number | ||
20 | createdAt: Date | ||
21 | updatedAt: Date | ||
22 | } | ||
23 | |||
24 | export interface VideoAbuseModel extends VideoAbuseClass, Sequelize.Model<VideoAbuseInstance, VideoAbuseAttributes> {} | ||
diff --git a/server/models/video-abuse.ts b/server/models/video-abuse.ts index 2a18a293d..92168439c 100644 --- a/server/models/video-abuse.ts +++ b/server/models/video-abuse.ts | |||
@@ -1,9 +1,22 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
1 | import { CONFIG } from '../initializers' | 3 | import { CONFIG } from '../initializers' |
2 | import { isVideoAbuseReporterUsernameValid, isVideoAbuseReasonValid } from '../helpers' | 4 | import { isVideoAbuseReporterUsernameValid, isVideoAbuseReasonValid } from '../helpers' |
3 | import { getSort } from './utils' | ||
4 | 5 | ||
5 | module.exports = function (sequelize, DataTypes) { | 6 | import { addMethodsToModel, getSort } from './utils' |
6 | const VideoAbuse = sequelize.define('VideoAbuse', | 7 | import { |
8 | VideoAbuseClass, | ||
9 | VideoAbuseInstance, | ||
10 | VideoAbuseAttributes, | ||
11 | |||
12 | VideoAbuseMethods | ||
13 | } from './video-abuse-interface' | ||
14 | |||
15 | let VideoAbuse: Sequelize.Model<VideoAbuseInstance, VideoAbuseAttributes> | ||
16 | let listForApi: VideoAbuseMethods.ListForApi | ||
17 | |||
18 | export default function (sequelize, DataTypes) { | ||
19 | VideoAbuse = sequelize.define('VideoAbuse', | ||
7 | { | 20 | { |
8 | reporterUsername: { | 21 | reporterUsername: { |
9 | type: DataTypes.STRING, | 22 | type: DataTypes.STRING, |
@@ -34,25 +47,51 @@ module.exports = function (sequelize, DataTypes) { | |||
34 | { | 47 | { |
35 | fields: [ 'reporterPodId' ] | 48 | fields: [ 'reporterPodId' ] |
36 | } | 49 | } |
37 | ], | 50 | ] |
38 | classMethods: { | ||
39 | associate, | ||
40 | |||
41 | listForApi | ||
42 | }, | ||
43 | instanceMethods: { | ||
44 | toFormatedJSON | ||
45 | } | ||
46 | } | 51 | } |
47 | ) | 52 | ) |
48 | 53 | ||
54 | const classMethods = [ | ||
55 | associate, | ||
56 | |||
57 | listForApi | ||
58 | ] | ||
59 | const instanceMethods = [ | ||
60 | toFormatedJSON | ||
61 | ] | ||
62 | addMethodsToModel(VideoAbuse, classMethods, instanceMethods) | ||
63 | |||
49 | return VideoAbuse | 64 | return VideoAbuse |
50 | } | 65 | } |
51 | 66 | ||
52 | // --------------------------------------------------------------------------- | 67 | // ------------------------------ METHODS ------------------------------ |
68 | |||
69 | function toFormatedJSON () { | ||
70 | let reporterPodHost | ||
71 | |||
72 | if (this.Pod) { | ||
73 | reporterPodHost = this.Pod.host | ||
74 | } else { | ||
75 | // It means it's our video | ||
76 | reporterPodHost = CONFIG.WEBSERVER.HOST | ||
77 | } | ||
78 | |||
79 | const json = { | ||
80 | id: this.id, | ||
81 | reporterPodHost, | ||
82 | reason: this.reason, | ||
83 | reporterUsername: this.reporterUsername, | ||
84 | videoId: this.videoId, | ||
85 | createdAt: this.createdAt | ||
86 | } | ||
87 | |||
88 | return json | ||
89 | } | ||
90 | |||
91 | // ------------------------------ STATICS ------------------------------ | ||
53 | 92 | ||
54 | function associate (models) { | 93 | function associate (models) { |
55 | this.belongsTo(models.Pod, { | 94 | VideoAbuse.belongsTo(models.Pod, { |
56 | foreignKey: { | 95 | foreignKey: { |
57 | name: 'reporterPodId', | 96 | name: 'reporterPodId', |
58 | allowNull: true | 97 | allowNull: true |
@@ -60,7 +99,7 @@ function associate (models) { | |||
60 | onDelete: 'cascade' | 99 | onDelete: 'cascade' |
61 | }) | 100 | }) |
62 | 101 | ||
63 | this.belongsTo(models.Video, { | 102 | VideoAbuse.belongsTo(models.Video, { |
64 | foreignKey: { | 103 | foreignKey: { |
65 | name: 'videoId', | 104 | name: 'videoId', |
66 | allowNull: false | 105 | allowNull: false |
@@ -69,44 +108,24 @@ function associate (models) { | |||
69 | }) | 108 | }) |
70 | } | 109 | } |
71 | 110 | ||
72 | function listForApi (start, count, sort, callback) { | 111 | listForApi = function (start, count, sort, callback) { |
73 | const query = { | 112 | const query = { |
74 | offset: start, | 113 | offset: start, |
75 | limit: count, | 114 | limit: count, |
76 | order: [ getSort(sort) ], | 115 | order: [ getSort(sort) ], |
77 | include: [ | 116 | include: [ |
78 | { | 117 | { |
79 | model: this.sequelize.models.Pod, | 118 | model: VideoAbuse['sequelize'].models.Pod, |
80 | required: false | 119 | required: false |
81 | } | 120 | } |
82 | ] | 121 | ] |
83 | } | 122 | } |
84 | 123 | ||
85 | return this.findAndCountAll(query).asCallback(function (err, result) { | 124 | return VideoAbuse.findAndCountAll(query).asCallback(function (err, result) { |
86 | if (err) return callback(err) | 125 | if (err) return callback(err) |
87 | 126 | ||
88 | return callback(null, result.rows, result.count) | 127 | return callback(null, result.rows, result.count) |
89 | }) | 128 | }) |
90 | } | 129 | } |
91 | 130 | ||
92 | function toFormatedJSON () { | ||
93 | let reporterPodHost | ||
94 | |||
95 | if (this.Pod) { | ||
96 | reporterPodHost = this.Pod.host | ||
97 | } else { | ||
98 | // It means it's our video | ||
99 | reporterPodHost = CONFIG.WEBSERVER.HOST | ||
100 | } | ||
101 | |||
102 | const json = { | ||
103 | id: this.id, | ||
104 | reporterPodHost, | ||
105 | reason: this.reason, | ||
106 | reporterUsername: this.reporterUsername, | ||
107 | videoId: this.videoId, | ||
108 | createdAt: this.createdAt | ||
109 | } | ||
110 | 131 | ||
111 | return json | ||
112 | } | ||
diff --git a/server/models/video-blacklist-interface.ts b/server/models/video-blacklist-interface.ts new file mode 100644 index 000000000..ae2cd6748 --- /dev/null +++ b/server/models/video-blacklist-interface.ts | |||
@@ -0,0 +1,31 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace BlacklistedVideoMethods { | ||
4 | export type ToFormatedJSON = () => void | ||
5 | |||
6 | export type CountTotal = (callback) => void | ||
7 | export type List = (callback) => void | ||
8 | export type ListForApi = (start, count, sort, callback) => void | ||
9 | export type LoadById = (id, callback) => void | ||
10 | export type LoadByVideoId = (id, callback) => void | ||
11 | } | ||
12 | |||
13 | export interface BlacklistedVideoClass { | ||
14 | toFormatedJSON: BlacklistedVideoMethods.ToFormatedJSON | ||
15 | countTotal: BlacklistedVideoMethods.CountTotal | ||
16 | list: BlacklistedVideoMethods.List | ||
17 | listForApi: BlacklistedVideoMethods.ListForApi | ||
18 | loadById: BlacklistedVideoMethods.LoadById | ||
19 | loadByVideoId: BlacklistedVideoMethods.LoadByVideoId | ||
20 | } | ||
21 | |||
22 | export interface BlacklistedVideoAttributes { | ||
23 | } | ||
24 | |||
25 | export interface BlacklistedVideoInstance extends BlacklistedVideoClass, BlacklistedVideoAttributes, Sequelize.Instance<BlacklistedVideoAttributes> { | ||
26 | id: number | ||
27 | createdAt: Date | ||
28 | updatedAt: Date | ||
29 | } | ||
30 | |||
31 | export interface BlacklistedVideoModel extends BlacklistedVideoClass, Sequelize.Model<BlacklistedVideoInstance, BlacklistedVideoAttributes> {} | ||
diff --git a/server/models/video-blacklist.ts b/server/models/video-blacklist.ts index 1f00702c7..fe72d5d46 100644 --- a/server/models/video-blacklist.ts +++ b/server/models/video-blacklist.ts | |||
@@ -1,9 +1,24 @@ | |||
1 | import { getSort } from './utils' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | // --------------------------------------------------------------------------- | 3 | import { addMethodsToModel, getSort } from './utils' |
4 | 4 | import { | |
5 | module.exports = function (sequelize, DataTypes) { | 5 | BlacklistedVideoClass, |
6 | const BlacklistedVideo = sequelize.define('BlacklistedVideo', | 6 | BlacklistedVideoInstance, |
7 | BlacklistedVideoAttributes, | ||
8 | |||
9 | BlacklistedVideoMethods | ||
10 | } from './video-blacklist-interface' | ||
11 | |||
12 | let BlacklistedVideo: Sequelize.Model<BlacklistedVideoInstance, BlacklistedVideoAttributes> | ||
13 | let toFormatedJSON: BlacklistedVideoMethods.ToFormatedJSON | ||
14 | let countTotal: BlacklistedVideoMethods.CountTotal | ||
15 | let list: BlacklistedVideoMethods.List | ||
16 | let listForApi: BlacklistedVideoMethods.ListForApi | ||
17 | let loadById: BlacklistedVideoMethods.LoadById | ||
18 | let loadByVideoId: BlacklistedVideoMethods.LoadByVideoId | ||
19 | |||
20 | export default function (sequelize, DataTypes) { | ||
21 | BlacklistedVideo = sequelize.define('BlacklistedVideo', | ||
7 | {}, | 22 | {}, |
8 | { | 23 | { |
9 | indexes: [ | 24 | indexes: [ |
@@ -11,29 +26,30 @@ module.exports = function (sequelize, DataTypes) { | |||
11 | fields: [ 'videoId' ], | 26 | fields: [ 'videoId' ], |
12 | unique: true | 27 | unique: true |
13 | } | 28 | } |
14 | ], | 29 | ] |
15 | classMethods: { | ||
16 | associate, | ||
17 | |||
18 | countTotal, | ||
19 | list, | ||
20 | listForApi, | ||
21 | loadById, | ||
22 | loadByVideoId | ||
23 | }, | ||
24 | instanceMethods: { | ||
25 | toFormatedJSON | ||
26 | }, | ||
27 | hooks: {} | ||
28 | } | 30 | } |
29 | ) | 31 | ) |
30 | 32 | ||
33 | const classMethods = [ | ||
34 | associate, | ||
35 | |||
36 | countTotal, | ||
37 | list, | ||
38 | listForApi, | ||
39 | loadById, | ||
40 | loadByVideoId | ||
41 | ] | ||
42 | const instanceMethods = [ | ||
43 | toFormatedJSON | ||
44 | ] | ||
45 | addMethodsToModel(BlacklistedVideo, classMethods, instanceMethods) | ||
46 | |||
31 | return BlacklistedVideo | 47 | return BlacklistedVideo |
32 | } | 48 | } |
33 | 49 | ||
34 | // ------------------------------ METHODS ------------------------------ | 50 | // ------------------------------ METHODS ------------------------------ |
35 | 51 | ||
36 | function toFormatedJSON () { | 52 | toFormatedJSON = function () { |
37 | return { | 53 | return { |
38 | id: this.id, | 54 | id: this.id, |
39 | videoId: this.videoId, | 55 | videoId: this.videoId, |
@@ -44,44 +60,44 @@ function toFormatedJSON () { | |||
44 | // ------------------------------ STATICS ------------------------------ | 60 | // ------------------------------ STATICS ------------------------------ |
45 | 61 | ||
46 | function associate (models) { | 62 | function associate (models) { |
47 | this.belongsTo(models.Video, { | 63 | BlacklistedVideo.belongsTo(models.Video, { |
48 | foreignKey: 'videoId', | 64 | foreignKey: 'videoId', |
49 | onDelete: 'cascade' | 65 | onDelete: 'cascade' |
50 | }) | 66 | }) |
51 | } | 67 | } |
52 | 68 | ||
53 | function countTotal (callback) { | 69 | countTotal = function (callback) { |
54 | return this.count().asCallback(callback) | 70 | return BlacklistedVideo.count().asCallback(callback) |
55 | } | 71 | } |
56 | 72 | ||
57 | function list (callback) { | 73 | list = function (callback) { |
58 | return this.findAll().asCallback(callback) | 74 | return BlacklistedVideo.findAll().asCallback(callback) |
59 | } | 75 | } |
60 | 76 | ||
61 | function listForApi (start, count, sort, callback) { | 77 | listForApi = function (start, count, sort, callback) { |
62 | const query = { | 78 | const query = { |
63 | offset: start, | 79 | offset: start, |
64 | limit: count, | 80 | limit: count, |
65 | order: [ getSort(sort) ] | 81 | order: [ getSort(sort) ] |
66 | } | 82 | } |
67 | 83 | ||
68 | return this.findAndCountAll(query).asCallback(function (err, result) { | 84 | return BlacklistedVideo.findAndCountAll(query).asCallback(function (err, result) { |
69 | if (err) return callback(err) | 85 | if (err) return callback(err) |
70 | 86 | ||
71 | return callback(null, result.rows, result.count) | 87 | return callback(null, result.rows, result.count) |
72 | }) | 88 | }) |
73 | } | 89 | } |
74 | 90 | ||
75 | function loadById (id, callback) { | 91 | loadById = function (id, callback) { |
76 | return this.findById(id).asCallback(callback) | 92 | return BlacklistedVideo.findById(id).asCallback(callback) |
77 | } | 93 | } |
78 | 94 | ||
79 | function loadByVideoId (id, callback) { | 95 | loadByVideoId = function (id, callback) { |
80 | const query = { | 96 | const query = { |
81 | where: { | 97 | where: { |
82 | videoId: id | 98 | videoId: id |
83 | } | 99 | } |
84 | } | 100 | } |
85 | 101 | ||
86 | return this.find(query).asCallback(callback) | 102 | return BlacklistedVideo.find(query).asCallback(callback) |
87 | } | 103 | } |
diff --git a/server/models/video-interface.ts b/server/models/video-interface.ts new file mode 100644 index 000000000..b8dbeea35 --- /dev/null +++ b/server/models/video-interface.ts | |||
@@ -0,0 +1,75 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace VideoMethods { | ||
4 | export type GenerateMagnetUri = () => void | ||
5 | export type GetVideoFilename = () => void | ||
6 | export type GetThumbnailName = () => void | ||
7 | export type GetPreviewName = () => void | ||
8 | export type GetTorrentName = () => void | ||
9 | export type IsOwned = () => void | ||
10 | export type ToFormatedJSON = () => void | ||
11 | export type ToAddRemoteJSON = (callback) => void | ||
12 | export type ToUpdateRemoteJSON = (callback) => void | ||
13 | export type TranscodeVideofile = (callback) => void | ||
14 | |||
15 | export type GenerateThumbnailFromData = (video, thumbnailData, callback) => void | ||
16 | export type GetDurationFromFile = (videoPath, callback) => void | ||
17 | export type List = (callback) => void | ||
18 | export type ListForApi = (start, count, sort, callback) => void | ||
19 | export type LoadByHostAndRemoteId = (fromHost, remoteId, callback) => void | ||
20 | export type ListOwnedAndPopulateAuthorAndTags = (callback) => void | ||
21 | export type ListOwnedByAuthor = (author, callback) => void | ||
22 | export type Load = (id, callback) => void | ||
23 | export type LoadAndPopulateAuthor = (id, callback) => void | ||
24 | export type LoadAndPopulateAuthorAndPodAndTags = (id, callback) => void | ||
25 | export type SearchAndPopulateAuthorAndPodAndTags = (value, field, start, count, sort, callback) => void | ||
26 | } | ||
27 | |||
28 | export interface VideoClass { | ||
29 | generateMagnetUri: VideoMethods.GenerateMagnetUri | ||
30 | getVideoFilename: VideoMethods.GetVideoFilename | ||
31 | getThumbnailName: VideoMethods.GetThumbnailName | ||
32 | getPreviewName: VideoMethods.GetPreviewName | ||
33 | getTorrentName: VideoMethods.GetTorrentName | ||
34 | isOwned: VideoMethods.IsOwned | ||
35 | toFormatedJSON: VideoMethods.ToFormatedJSON | ||
36 | toAddRemoteJSON: VideoMethods.ToAddRemoteJSON | ||
37 | toUpdateRemoteJSON: VideoMethods.ToUpdateRemoteJSON | ||
38 | transcodeVideofile: VideoMethods.TranscodeVideofile | ||
39 | |||
40 | generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData | ||
41 | getDurationFromFile: VideoMethods.GetDurationFromFile | ||
42 | list: VideoMethods.List | ||
43 | listForApi: VideoMethods.ListForApi | ||
44 | loadByHostAndRemoteId: VideoMethods.LoadByHostAndRemoteId | ||
45 | listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags | ||
46 | listOwnedByAuthor: VideoMethods.ListOwnedByAuthor | ||
47 | load: VideoMethods.Load | ||
48 | loadAndPopulateAuthor: VideoMethods.LoadAndPopulateAuthor | ||
49 | loadAndPopulateAuthorAndPodAndTags: VideoMethods.LoadAndPopulateAuthorAndPodAndTags | ||
50 | searchAndPopulateAuthorAndPodAndTags: VideoMethods.SearchAndPopulateAuthorAndPodAndTags | ||
51 | } | ||
52 | |||
53 | export interface VideoAttributes { | ||
54 | name: string | ||
55 | extname: string | ||
56 | remoteId: string | ||
57 | category: number | ||
58 | licence: number | ||
59 | language: number | ||
60 | nsfw: boolean | ||
61 | description: string | ||
62 | infoHash?: string | ||
63 | duration: number | ||
64 | views?: number | ||
65 | likes?: number | ||
66 | dislikes?: number | ||
67 | } | ||
68 | |||
69 | export interface VideoInstance extends VideoClass, VideoAttributes, Sequelize.Instance<VideoAttributes> { | ||
70 | id: string | ||
71 | createdAt: Date | ||
72 | updatedAt: Date | ||
73 | } | ||
74 | |||
75 | export interface VideoModel extends VideoClass, Sequelize.Model<VideoInstance, VideoAttributes> {} | ||
diff --git a/server/models/video-tag-interface.ts b/server/models/video-tag-interface.ts new file mode 100644 index 000000000..468827b8c --- /dev/null +++ b/server/models/video-tag-interface.ts | |||
@@ -0,0 +1,18 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | export namespace VideoTagMethods { | ||
4 | } | ||
5 | |||
6 | export interface VideoTagClass { | ||
7 | } | ||
8 | |||
9 | export interface VideoTagAttributes { | ||
10 | } | ||
11 | |||
12 | export interface VideoTagInstance extends Sequelize.Instance<VideoTagAttributes> { | ||
13 | id: number | ||
14 | createdAt: Date | ||
15 | updatedAt: Date | ||
16 | } | ||
17 | |||
18 | export interface VideoTagModel extends VideoTagClass, Sequelize.Model<VideoTagInstance, VideoTagAttributes> {} | ||
diff --git a/server/models/video-tag.ts b/server/models/video-tag.ts index 83ff6053f..2ccaf820d 100644 --- a/server/models/video-tag.ts +++ b/server/models/video-tag.ts | |||
@@ -1,5 +1,18 @@ | |||
1 | module.exports = function (sequelize, DataTypes) { | 1 | import * as Sequelize from 'sequelize' |
2 | const VideoTag = sequelize.define('VideoTag', {}, { | 2 | |
3 | import { addMethodsToModel } from './utils' | ||
4 | import { | ||
5 | VideoTagClass, | ||
6 | VideoTagInstance, | ||
7 | VideoTagAttributes, | ||
8 | |||
9 | VideoTagMethods | ||
10 | } from './video-tag-interface' | ||
11 | |||
12 | let VideoTag: Sequelize.Model<VideoTagInstance, VideoTagAttributes> | ||
13 | |||
14 | export default function (sequelize, DataTypes) { | ||
15 | VideoTag = sequelize.define('VideoTag', {}, { | ||
3 | indexes: [ | 16 | indexes: [ |
4 | { | 17 | { |
5 | fields: [ 'videoId' ] | 18 | fields: [ 'videoId' ] |
diff --git a/server/models/video.ts b/server/models/video.ts index 1e29f1355..9284dfeba 100644 --- a/server/models/video.ts +++ b/server/models/video.ts | |||
@@ -8,8 +8,9 @@ import { map, values } from 'lodash' | |||
8 | import { parallel, series } from 'async' | 8 | import { parallel, series } from 'async' |
9 | import parseTorrent = require('parse-torrent') | 9 | import parseTorrent = require('parse-torrent') |
10 | import { join } from 'path' | 10 | import { join } from 'path' |
11 | import * as Sequelize from 'sequelize' | ||
11 | 12 | ||
12 | const db = require('../initializers/database') | 13 | import { database as db } from '../initializers/database' |
13 | import { | 14 | import { |
14 | logger, | 15 | logger, |
15 | isVideoNameValid, | 16 | isVideoNameValid, |
@@ -32,12 +33,42 @@ import { | |||
32 | THUMBNAILS_SIZE | 33 | THUMBNAILS_SIZE |
33 | } from '../initializers' | 34 | } from '../initializers' |
34 | import { JobScheduler, removeVideoToFriends } from '../lib' | 35 | import { JobScheduler, removeVideoToFriends } from '../lib' |
35 | import { getSort } from './utils' | ||
36 | 36 | ||
37 | // --------------------------------------------------------------------------- | 37 | import { addMethodsToModel, getSort } from './utils' |
38 | 38 | import { | |
39 | module.exports = function (sequelize, DataTypes) { | 39 | VideoClass, |
40 | const Video = sequelize.define('Video', | 40 | VideoInstance, |
41 | VideoAttributes, | ||
42 | |||
43 | VideoMethods | ||
44 | } from './video-interface' | ||
45 | |||
46 | let Video: Sequelize.Model<VideoInstance, VideoAttributes> | ||
47 | let generateMagnetUri: VideoMethods.GenerateMagnetUri | ||
48 | let getVideoFilename: VideoMethods.GetVideoFilename | ||
49 | let getThumbnailName: VideoMethods.GetThumbnailName | ||
50 | let getPreviewName: VideoMethods.GetPreviewName | ||
51 | let getTorrentName: VideoMethods.GetTorrentName | ||
52 | let isOwned: VideoMethods.IsOwned | ||
53 | let toFormatedJSON: VideoMethods.ToFormatedJSON | ||
54 | let toAddRemoteJSON: VideoMethods.ToAddRemoteJSON | ||
55 | let toUpdateRemoteJSON: VideoMethods.ToUpdateRemoteJSON | ||
56 | let transcodeVideofile: VideoMethods.TranscodeVideofile | ||
57 | |||
58 | let generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData | ||
59 | let getDurationFromFile: VideoMethods.GetDurationFromFile | ||
60 | let list: VideoMethods.List | ||
61 | let listForApi: VideoMethods.ListForApi | ||
62 | let loadByHostAndRemoteId: VideoMethods.LoadByHostAndRemoteId | ||
63 | let listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags | ||
64 | let listOwnedByAuthor: VideoMethods.ListOwnedByAuthor | ||
65 | let load: VideoMethods.Load | ||
66 | let loadAndPopulateAuthor: VideoMethods.LoadAndPopulateAuthor | ||
67 | let loadAndPopulateAuthorAndPodAndTags: VideoMethods.LoadAndPopulateAuthorAndPodAndTags | ||
68 | let searchAndPopulateAuthorAndPodAndTags: VideoMethods.SearchAndPopulateAuthorAndPodAndTags | ||
69 | |||
70 | export default function (sequelize, DataTypes) { | ||
71 | Video = sequelize.define('Video', | ||
41 | { | 72 | { |
42 | id: { | 73 | id: { |
43 | type: DataTypes.UUID, | 74 | type: DataTypes.UUID, |
@@ -194,34 +225,6 @@ module.exports = function (sequelize, DataTypes) { | |||
194 | fields: [ 'likes' ] | 225 | fields: [ 'likes' ] |
195 | } | 226 | } |
196 | ], | 227 | ], |
197 | classMethods: { | ||
198 | associate, | ||
199 | |||
200 | generateThumbnailFromData, | ||
201 | getDurationFromFile, | ||
202 | list, | ||
203 | listForApi, | ||
204 | listOwnedAndPopulateAuthorAndTags, | ||
205 | listOwnedByAuthor, | ||
206 | load, | ||
207 | loadByHostAndRemoteId, | ||
208 | loadAndPopulateAuthor, | ||
209 | loadAndPopulateAuthorAndPodAndTags, | ||
210 | searchAndPopulateAuthorAndPodAndTags | ||
211 | }, | ||
212 | instanceMethods: { | ||
213 | generateMagnetUri, | ||
214 | getVideoFilename, | ||
215 | getThumbnailName, | ||
216 | getPreviewName, | ||
217 | getTorrentName, | ||
218 | isOwned, | ||
219 | toFormatedJSON, | ||
220 | toAddRemoteJSON, | ||
221 | toUpdateRemoteJSON, | ||
222 | transcodeVideofile, | ||
223 | removeFromBlacklist | ||
224 | }, | ||
225 | hooks: { | 228 | hooks: { |
226 | beforeValidate, | 229 | beforeValidate, |
227 | beforeCreate, | 230 | beforeCreate, |
@@ -230,99 +233,139 @@ module.exports = function (sequelize, DataTypes) { | |||
230 | } | 233 | } |
231 | ) | 234 | ) |
232 | 235 | ||
236 | const classMethods = [ | ||
237 | associate, | ||
238 | |||
239 | generateThumbnailFromData, | ||
240 | getDurationFromFile, | ||
241 | list, | ||
242 | listForApi, | ||
243 | listOwnedAndPopulateAuthorAndTags, | ||
244 | listOwnedByAuthor, | ||
245 | load, | ||
246 | loadByHostAndRemoteId, | ||
247 | loadAndPopulateAuthor, | ||
248 | loadAndPopulateAuthorAndPodAndTags, | ||
249 | searchAndPopulateAuthorAndPodAndTags | ||
250 | ] | ||
251 | const instanceMethods = [ | ||
252 | generateMagnetUri, | ||
253 | getVideoFilename, | ||
254 | getThumbnailName, | ||
255 | getPreviewName, | ||
256 | getTorrentName, | ||
257 | isOwned, | ||
258 | toFormatedJSON, | ||
259 | toAddRemoteJSON, | ||
260 | toUpdateRemoteJSON, | ||
261 | transcodeVideofile, | ||
262 | removeFromBlacklist | ||
263 | ] | ||
264 | addMethodsToModel(Video, classMethods, instanceMethods) | ||
265 | |||
233 | return Video | 266 | return Video |
234 | } | 267 | } |
235 | 268 | ||
236 | function beforeValidate (video, options, next) { | 269 | function beforeValidate (video, options) { |
237 | // Put a fake infoHash if it does not exists yet | 270 | // Put a fake infoHash if it does not exists yet |
238 | if (video.isOwned() && !video.infoHash) { | 271 | if (video.isOwned() && !video.infoHash) { |
239 | // 40 hexa length | 272 | // 40 hexa length |
240 | video.infoHash = '0123456789abcdef0123456789abcdef01234567' | 273 | video.infoHash = '0123456789abcdef0123456789abcdef01234567' |
241 | } | 274 | } |
242 | |||
243 | return next(null) | ||
244 | } | 275 | } |
245 | 276 | ||
246 | function beforeCreate (video, options, next) { | 277 | function beforeCreate (video, options) { |
247 | const tasks = [] | 278 | return new Promise(function (resolve, reject) { |
248 | 279 | const tasks = [] | |
249 | if (video.isOwned()) { | ||
250 | const videoPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename()) | ||
251 | |||
252 | tasks.push( | ||
253 | function createVideoTorrent (callback) { | ||
254 | createTorrentFromVideo(video, videoPath, callback) | ||
255 | }, | ||
256 | |||
257 | function createVideoThumbnail (callback) { | ||
258 | createThumbnail(video, videoPath, callback) | ||
259 | }, | ||
260 | 280 | ||
261 | function createVideoPreview (callback) { | 281 | if (video.isOwned()) { |
262 | createPreview(video, videoPath, callback) | 282 | const videoPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename()) |
263 | } | ||
264 | ) | ||
265 | 283 | ||
266 | if (CONFIG.TRANSCODING.ENABLED === true) { | ||
267 | tasks.push( | 284 | tasks.push( |
268 | function createVideoTranscoderJob (callback) { | 285 | function createVideoTorrent (callback) { |
269 | const dataInput = { | 286 | createTorrentFromVideo(video, videoPath, callback) |
270 | id: video.id | 287 | }, |
271 | } | 288 | |
289 | function createVideoThumbnail (callback) { | ||
290 | createThumbnail(video, videoPath, callback) | ||
291 | }, | ||
272 | 292 | ||
273 | JobScheduler.Instance.createJob(options.transaction, 'videoTranscoder', dataInput, callback) | 293 | function createVideoPreview (callback) { |
294 | createPreview(video, videoPath, callback) | ||
274 | } | 295 | } |
275 | ) | 296 | ) |
276 | } | ||
277 | 297 | ||
278 | return parallel(tasks, next) | 298 | if (CONFIG.TRANSCODING.ENABLED === true) { |
279 | } | 299 | tasks.push( |
300 | function createVideoTranscoderJob (callback) { | ||
301 | const dataInput = { | ||
302 | id: video.id | ||
303 | } | ||
280 | 304 | ||
281 | return next() | 305 | JobScheduler.Instance.createJob(options.transaction, 'videoTranscoder', dataInput, callback) |
282 | } | 306 | } |
307 | ) | ||
308 | } | ||
283 | 309 | ||
284 | function afterDestroy (video, options, next) { | 310 | return parallel(tasks, function (err) { |
285 | const tasks = [] | 311 | if (err) return reject(err) |
286 | 312 | ||
287 | tasks.push( | 313 | return resolve() |
288 | function (callback) { | 314 | }) |
289 | removeThumbnail(video, callback) | ||
290 | } | 315 | } |
291 | ) | ||
292 | 316 | ||
293 | if (video.isOwned()) { | 317 | return resolve() |
318 | }) | ||
319 | } | ||
320 | |||
321 | function afterDestroy (video, options) { | ||
322 | return new Promise(function (resolve, reject) { | ||
323 | const tasks = [] | ||
324 | |||
294 | tasks.push( | 325 | tasks.push( |
295 | function removeVideoFile (callback) { | 326 | function (callback) { |
296 | removeFile(video, callback) | 327 | removeThumbnail(video, callback) |
297 | }, | 328 | } |
329 | ) | ||
298 | 330 | ||
299 | function removeVideoTorrent (callback) { | 331 | if (video.isOwned()) { |
300 | removeTorrent(video, callback) | 332 | tasks.push( |
301 | }, | 333 | function removeVideoFile (callback) { |
334 | removeFile(video, callback) | ||
335 | }, | ||
302 | 336 | ||
303 | function removeVideoPreview (callback) { | 337 | function removeVideoTorrent (callback) { |
304 | removePreview(video, callback) | 338 | removeTorrent(video, callback) |
305 | }, | 339 | }, |
306 | 340 | ||
307 | function removeVideoToFriends (callback) { | 341 | function removeVideoPreview (callback) { |
308 | const params = { | 342 | removePreview(video, callback) |
309 | remoteId: video.id | 343 | }, |
310 | } | ||
311 | 344 | ||
312 | removeVideoToFriends(params) | 345 | function notifyFriends (callback) { |
346 | const params = { | ||
347 | remoteId: video.id | ||
348 | } | ||
313 | 349 | ||
314 | return callback() | 350 | removeVideoToFriends(params) |
315 | } | ||
316 | ) | ||
317 | } | ||
318 | 351 | ||
319 | parallel(tasks, next) | 352 | return callback() |
353 | } | ||
354 | ) | ||
355 | } | ||
356 | |||
357 | parallel(tasks, function (err) { | ||
358 | if (err) return reject(err) | ||
359 | |||
360 | return resolve() | ||
361 | }) | ||
362 | }) | ||
320 | } | 363 | } |
321 | 364 | ||
322 | // ------------------------------ METHODS ------------------------------ | 365 | // ------------------------------ METHODS ------------------------------ |
323 | 366 | ||
324 | function associate (models) { | 367 | function associate (models) { |
325 | this.belongsTo(models.Author, { | 368 | Video.belongsTo(models.Author, { |
326 | foreignKey: { | 369 | foreignKey: { |
327 | name: 'authorId', | 370 | name: 'authorId', |
328 | allowNull: false | 371 | allowNull: false |
@@ -330,13 +373,13 @@ function associate (models) { | |||
330 | onDelete: 'cascade' | 373 | onDelete: 'cascade' |
331 | }) | 374 | }) |
332 | 375 | ||
333 | this.belongsToMany(models.Tag, { | 376 | Video.belongsToMany(models.Tag, { |
334 | foreignKey: 'videoId', | 377 | foreignKey: 'videoId', |
335 | through: models.VideoTag, | 378 | through: models.VideoTag, |
336 | onDelete: 'cascade' | 379 | onDelete: 'cascade' |
337 | }) | 380 | }) |
338 | 381 | ||
339 | this.hasMany(models.VideoAbuse, { | 382 | Video.hasMany(models.VideoAbuse, { |
340 | foreignKey: { | 383 | foreignKey: { |
341 | name: 'videoId', | 384 | name: 'videoId', |
342 | allowNull: false | 385 | allowNull: false |
@@ -345,7 +388,7 @@ function associate (models) { | |||
345 | }) | 388 | }) |
346 | } | 389 | } |
347 | 390 | ||
348 | function generateMagnetUri () { | 391 | generateMagnetUri = function () { |
349 | let baseUrlHttp | 392 | let baseUrlHttp |
350 | let baseUrlWs | 393 | let baseUrlWs |
351 | 394 | ||
@@ -372,18 +415,18 @@ function generateMagnetUri () { | |||
372 | return magnetUtil.encode(magnetHash) | 415 | return magnetUtil.encode(magnetHash) |
373 | } | 416 | } |
374 | 417 | ||
375 | function getVideoFilename () { | 418 | getVideoFilename = function () { |
376 | if (this.isOwned()) return this.id + this.extname | 419 | if (this.isOwned()) return this.id + this.extname |
377 | 420 | ||
378 | return this.remoteId + this.extname | 421 | return this.remoteId + this.extname |
379 | } | 422 | } |
380 | 423 | ||
381 | function getThumbnailName () { | 424 | getThumbnailName = function () { |
382 | // We always have a copy of the thumbnail | 425 | // We always have a copy of the thumbnail |
383 | return this.id + '.jpg' | 426 | return this.id + '.jpg' |
384 | } | 427 | } |
385 | 428 | ||
386 | function getPreviewName () { | 429 | getPreviewName = function () { |
387 | const extension = '.jpg' | 430 | const extension = '.jpg' |
388 | 431 | ||
389 | if (this.isOwned()) return this.id + extension | 432 | if (this.isOwned()) return this.id + extension |
@@ -391,7 +434,7 @@ function getPreviewName () { | |||
391 | return this.remoteId + extension | 434 | return this.remoteId + extension |
392 | } | 435 | } |
393 | 436 | ||
394 | function getTorrentName () { | 437 | getTorrentName = function () { |
395 | const extension = '.torrent' | 438 | const extension = '.torrent' |
396 | 439 | ||
397 | if (this.isOwned()) return this.id + extension | 440 | if (this.isOwned()) return this.id + extension |
@@ -399,11 +442,11 @@ function getTorrentName () { | |||
399 | return this.remoteId + extension | 442 | return this.remoteId + extension |
400 | } | 443 | } |
401 | 444 | ||
402 | function isOwned () { | 445 | isOwned = function () { |
403 | return this.remoteId === null | 446 | return this.remoteId === null |
404 | } | 447 | } |
405 | 448 | ||
406 | function toFormatedJSON () { | 449 | toFormatedJSON = function () { |
407 | let podHost | 450 | let podHost |
408 | 451 | ||
409 | if (this.Author.Pod) { | 452 | if (this.Author.Pod) { |
@@ -453,43 +496,41 @@ function toFormatedJSON () { | |||
453 | return json | 496 | return json |
454 | } | 497 | } |
455 | 498 | ||
456 | function toAddRemoteJSON (callback) { | 499 | toAddRemoteJSON = function (callback) { |
457 | const self = this | ||
458 | |||
459 | // Get thumbnail data to send to the other pod | 500 | // Get thumbnail data to send to the other pod |
460 | const thumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, this.getThumbnailName()) | 501 | const thumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, this.getThumbnailName()) |
461 | fs.readFile(thumbnailPath, function (err, thumbnailData) { | 502 | fs.readFile(thumbnailPath, (err, thumbnailData) => { |
462 | if (err) { | 503 | if (err) { |
463 | logger.error('Cannot read the thumbnail of the video') | 504 | logger.error('Cannot read the thumbnail of the video') |
464 | return callback(err) | 505 | return callback(err) |
465 | } | 506 | } |
466 | 507 | ||
467 | const remoteVideo = { | 508 | const remoteVideo = { |
468 | name: self.name, | 509 | name: this.name, |
469 | category: self.category, | 510 | category: this.category, |
470 | licence: self.licence, | 511 | licence: this.licence, |
471 | language: self.language, | 512 | language: this.language, |
472 | nsfw: self.nsfw, | 513 | nsfw: this.nsfw, |
473 | description: self.description, | 514 | description: this.description, |
474 | infoHash: self.infoHash, | 515 | infoHash: this.infoHash, |
475 | remoteId: self.id, | 516 | remoteId: this.id, |
476 | author: self.Author.name, | 517 | author: this.Author.name, |
477 | duration: self.duration, | 518 | duration: this.duration, |
478 | thumbnailData: thumbnailData.toString('binary'), | 519 | thumbnailData: thumbnailData.toString('binary'), |
479 | tags: map(self.Tags, 'name'), | 520 | tags: map(this.Tags, 'name'), |
480 | createdAt: self.createdAt, | 521 | createdAt: this.createdAt, |
481 | updatedAt: self.updatedAt, | 522 | updatedAt: this.updatedAt, |
482 | extname: self.extname, | 523 | extname: this.extname, |
483 | views: self.views, | 524 | views: this.views, |
484 | likes: self.likes, | 525 | likes: this.likes, |
485 | dislikes: self.dislikes | 526 | dislikes: this.dislikes |
486 | } | 527 | } |
487 | 528 | ||
488 | return callback(null, remoteVideo) | 529 | return callback(null, remoteVideo) |
489 | }) | 530 | }) |
490 | } | 531 | } |
491 | 532 | ||
492 | function toUpdateRemoteJSON (callback) { | 533 | toUpdateRemoteJSON = function (callback) { |
493 | const json = { | 534 | const json = { |
494 | name: this.name, | 535 | name: this.name, |
495 | category: this.category, | 536 | category: this.category, |
@@ -513,7 +554,7 @@ function toUpdateRemoteJSON (callback) { | |||
513 | return json | 554 | return json |
514 | } | 555 | } |
515 | 556 | ||
516 | function transcodeVideofile (finalCallback) { | 557 | transcodeVideofile = function (finalCallback) { |
517 | const video = this | 558 | const video = this |
518 | 559 | ||
519 | const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR | 560 | const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR |
@@ -568,7 +609,7 @@ function transcodeVideofile (finalCallback) { | |||
568 | 609 | ||
569 | // ------------------------------ STATICS ------------------------------ | 610 | // ------------------------------ STATICS ------------------------------ |
570 | 611 | ||
571 | function generateThumbnailFromData (video, thumbnailData, callback) { | 612 | generateThumbnailFromData = function (video, thumbnailData, callback) { |
572 | // Creating the thumbnail for a remote video | 613 | // Creating the thumbnail for a remote video |
573 | 614 | ||
574 | const thumbnailName = video.getThumbnailName() | 615 | const thumbnailName = video.getThumbnailName() |
@@ -580,7 +621,7 @@ function generateThumbnailFromData (video, thumbnailData, callback) { | |||
580 | }) | 621 | }) |
581 | } | 622 | } |
582 | 623 | ||
583 | function getDurationFromFile (videoPath, callback) { | 624 | getDurationFromFile = function (videoPath, callback) { |
584 | ffmpeg.ffprobe(videoPath, function (err, metadata) { | 625 | ffmpeg.ffprobe(videoPath, function (err, metadata) { |
585 | if (err) return callback(err) | 626 | if (err) return callback(err) |
586 | 627 | ||
@@ -588,46 +629,46 @@ function getDurationFromFile (videoPath, callback) { | |||
588 | }) | 629 | }) |
589 | } | 630 | } |
590 | 631 | ||
591 | function list (callback) { | 632 | list = function (callback) { |
592 | return this.findAll().asCallback(callback) | 633 | return Video.findAll().asCallback(callback) |
593 | } | 634 | } |
594 | 635 | ||
595 | function listForApi (start, count, sort, callback) { | 636 | listForApi = function (start, count, sort, callback) { |
596 | // Exclude Blakclisted videos from the list | 637 | // Exclude Blakclisted videos from the list |
597 | const query = { | 638 | const query = { |
639 | distinct: true, | ||
598 | offset: start, | 640 | offset: start, |
599 | limit: count, | 641 | limit: count, |
600 | distinct: true, // For the count, a video can have many tags | 642 | order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ], |
601 | order: [ getSort(sort), [ this.sequelize.models.Tag, 'name', 'ASC' ] ], | ||
602 | include: [ | 643 | include: [ |
603 | { | 644 | { |
604 | model: this.sequelize.models.Author, | 645 | model: Video['sequelize'].models.Author, |
605 | include: [ { model: this.sequelize.models.Pod, required: false } ] | 646 | include: [ { model: Video['sequelize'].models.Pod, required: false } ] |
606 | }, | 647 | }, |
607 | 648 | ||
608 | this.sequelize.models.Tag | 649 | Video['sequelize'].models.Tag |
609 | ], | 650 | ], |
610 | where: createBaseVideosWhere.call(this) | 651 | where: createBaseVideosWhere() |
611 | } | 652 | } |
612 | 653 | ||
613 | return this.findAndCountAll(query).asCallback(function (err, result) { | 654 | return Video.findAndCountAll(query).asCallback(function (err, result) { |
614 | if (err) return callback(err) | 655 | if (err) return callback(err) |
615 | 656 | ||
616 | return callback(null, result.rows, result.count) | 657 | return callback(null, result.rows, result.count) |
617 | }) | 658 | }) |
618 | } | 659 | } |
619 | 660 | ||
620 | function loadByHostAndRemoteId (fromHost, remoteId, callback) { | 661 | loadByHostAndRemoteId = function (fromHost, remoteId, callback) { |
621 | const query = { | 662 | const query = { |
622 | where: { | 663 | where: { |
623 | remoteId: remoteId | 664 | remoteId: remoteId |
624 | }, | 665 | }, |
625 | include: [ | 666 | include: [ |
626 | { | 667 | { |
627 | model: this.sequelize.models.Author, | 668 | model: Video['sequelize'].models.Author, |
628 | include: [ | 669 | include: [ |
629 | { | 670 | { |
630 | model: this.sequelize.models.Pod, | 671 | model: Video['sequelize'].models.Pod, |
631 | required: true, | 672 | required: true, |
632 | where: { | 673 | where: { |
633 | host: fromHost | 674 | host: fromHost |
@@ -638,29 +679,29 @@ function loadByHostAndRemoteId (fromHost, remoteId, callback) { | |||
638 | ] | 679 | ] |
639 | } | 680 | } |
640 | 681 | ||
641 | return this.findOne(query).asCallback(callback) | 682 | return Video.findOne(query).asCallback(callback) |
642 | } | 683 | } |
643 | 684 | ||
644 | function listOwnedAndPopulateAuthorAndTags (callback) { | 685 | listOwnedAndPopulateAuthorAndTags = function (callback) { |
645 | // If remoteId is null this is *our* video | 686 | // If remoteId is null this is *our* video |
646 | const query = { | 687 | const query = { |
647 | where: { | 688 | where: { |
648 | remoteId: null | 689 | remoteId: null |
649 | }, | 690 | }, |
650 | include: [ this.sequelize.models.Author, this.sequelize.models.Tag ] | 691 | include: [ Video['sequelize'].models.Author, Video['sequelize'].models.Tag ] |
651 | } | 692 | } |
652 | 693 | ||
653 | return this.findAll(query).asCallback(callback) | 694 | return Video.findAll(query).asCallback(callback) |
654 | } | 695 | } |
655 | 696 | ||
656 | function listOwnedByAuthor (author, callback) { | 697 | listOwnedByAuthor = function (author, callback) { |
657 | const query = { | 698 | const query = { |
658 | where: { | 699 | where: { |
659 | remoteId: null | 700 | remoteId: null |
660 | }, | 701 | }, |
661 | include: [ | 702 | include: [ |
662 | { | 703 | { |
663 | model: this.sequelize.models.Author, | 704 | model: Video['sequelize'].models.Author, |
664 | where: { | 705 | where: { |
665 | name: author | 706 | name: author |
666 | } | 707 | } |
@@ -668,58 +709,58 @@ function listOwnedByAuthor (author, callback) { | |||
668 | ] | 709 | ] |
669 | } | 710 | } |
670 | 711 | ||
671 | return this.findAll(query).asCallback(callback) | 712 | return Video.findAll(query).asCallback(callback) |
672 | } | 713 | } |
673 | 714 | ||
674 | function load (id, callback) { | 715 | load = function (id, callback) { |
675 | return this.findById(id).asCallback(callback) | 716 | return Video.findById(id).asCallback(callback) |
676 | } | 717 | } |
677 | 718 | ||
678 | function loadAndPopulateAuthor (id, callback) { | 719 | loadAndPopulateAuthor = function (id, callback) { |
679 | const options = { | 720 | const options = { |
680 | include: [ this.sequelize.models.Author ] | 721 | include: [ Video['sequelize'].models.Author ] |
681 | } | 722 | } |
682 | 723 | ||
683 | return this.findById(id, options).asCallback(callback) | 724 | return Video.findById(id, options).asCallback(callback) |
684 | } | 725 | } |
685 | 726 | ||
686 | function loadAndPopulateAuthorAndPodAndTags (id, callback) { | 727 | loadAndPopulateAuthorAndPodAndTags = function (id, callback) { |
687 | const options = { | 728 | const options = { |
688 | include: [ | 729 | include: [ |
689 | { | 730 | { |
690 | model: this.sequelize.models.Author, | 731 | model: Video['sequelize'].models.Author, |
691 | include: [ { model: this.sequelize.models.Pod, required: false } ] | 732 | include: [ { model: Video['sequelize'].models.Pod, required: false } ] |
692 | }, | 733 | }, |
693 | this.sequelize.models.Tag | 734 | Video['sequelize'].models.Tag |
694 | ] | 735 | ] |
695 | } | 736 | } |
696 | 737 | ||
697 | return this.findById(id, options).asCallback(callback) | 738 | return Video.findById(id, options).asCallback(callback) |
698 | } | 739 | } |
699 | 740 | ||
700 | function searchAndPopulateAuthorAndPodAndTags (value, field, start, count, sort, callback) { | 741 | searchAndPopulateAuthorAndPodAndTags = function (value, field, start, count, sort, callback) { |
701 | const podInclude: any = { | 742 | const podInclude: any = { |
702 | model: this.sequelize.models.Pod, | 743 | model: Video['sequelize'].models.Pod, |
703 | required: false | 744 | required: false |
704 | } | 745 | } |
705 | 746 | ||
706 | const authorInclude: any = { | 747 | const authorInclude: any = { |
707 | model: this.sequelize.models.Author, | 748 | model: Video['sequelize'].models.Author, |
708 | include: [ | 749 | include: [ |
709 | podInclude | 750 | podInclude |
710 | ] | 751 | ] |
711 | } | 752 | } |
712 | 753 | ||
713 | const tagInclude: any = { | 754 | const tagInclude: any = { |
714 | model: this.sequelize.models.Tag | 755 | model: Video['sequelize'].models.Tag |
715 | } | 756 | } |
716 | 757 | ||
717 | const query: any = { | 758 | const query: any = { |
718 | where: createBaseVideosWhere.call(this), | 759 | distinct: true, |
760 | where: createBaseVideosWhere(), | ||
719 | offset: start, | 761 | offset: start, |
720 | limit: count, | 762 | limit: count, |
721 | distinct: true, // For the count, a video can have many tags | 763 | order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ] |
722 | order: [ getSort(sort), [ this.sequelize.models.Tag, 'name', 'ASC' ] ] | ||
723 | } | 764 | } |
724 | 765 | ||
725 | // Make an exact search with the magnet | 766 | // Make an exact search with the magnet |
@@ -727,8 +768,8 @@ function searchAndPopulateAuthorAndPodAndTags (value, field, start, count, sort, | |||
727 | const infoHash = magnetUtil.decode(value).infoHash | 768 | const infoHash = magnetUtil.decode(value).infoHash |
728 | query.where.infoHash = infoHash | 769 | query.where.infoHash = infoHash |
729 | } else if (field === 'tags') { | 770 | } else if (field === 'tags') { |
730 | const escapedValue = this.sequelize.escape('%' + value + '%') | 771 | const escapedValue = Video['sequelize'].escape('%' + value + '%') |
731 | query.where.id.$in = this.sequelize.literal( | 772 | query.where.id.$in = Video['sequelize'].literal( |
732 | '(SELECT "VideoTags"."videoId" FROM "Tags" INNER JOIN "VideoTags" ON "Tags"."id" = "VideoTags"."tagId" WHERE name LIKE ' + escapedValue + ')' | 773 | '(SELECT "VideoTags"."videoId" FROM "Tags" INNER JOIN "VideoTags" ON "Tags"."id" = "VideoTags"."tagId" WHERE name LIKE ' + escapedValue + ')' |
733 | ) | 774 | ) |
734 | } else if (field === 'host') { | 775 | } else if (field === 'host') { |
@@ -758,10 +799,10 @@ function searchAndPopulateAuthorAndPodAndTags (value, field, start, count, sort, | |||
758 | ] | 799 | ] |
759 | 800 | ||
760 | if (tagInclude.where) { | 801 | if (tagInclude.where) { |
761 | // query.include.push([ this.sequelize.models.Tag ]) | 802 | // query.include.push([ Video['sequelize'].models.Tag ]) |
762 | } | 803 | } |
763 | 804 | ||
764 | return this.findAndCountAll(query).asCallback(function (err, result) { | 805 | return Video.findAndCountAll(query).asCallback(function (err, result) { |
765 | if (err) return callback(err) | 806 | if (err) return callback(err) |
766 | 807 | ||
767 | return callback(null, result.rows, result.count) | 808 | return callback(null, result.rows, result.count) |
@@ -773,7 +814,7 @@ function searchAndPopulateAuthorAndPodAndTags (value, field, start, count, sort, | |||
773 | function createBaseVideosWhere () { | 814 | function createBaseVideosWhere () { |
774 | return { | 815 | return { |
775 | id: { | 816 | id: { |
776 | $notIn: this.sequelize.literal( | 817 | $notIn: Video['sequelize'].literal( |
777 | '(SELECT "BlacklistedVideos"."videoId" FROM "BlacklistedVideos")' | 818 | '(SELECT "BlacklistedVideos"."videoId" FROM "BlacklistedVideos")' |
778 | ) | 819 | ) |
779 | } | 820 | } |