aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/account
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/account')
-rw-r--r--server/models/account/account-follow.ts228
-rw-r--r--server/models/account/account.ts111
-rw-r--r--server/models/account/user.ts23
3 files changed, 38 insertions, 324 deletions
diff --git a/server/models/account/account-follow.ts b/server/models/account/account-follow.ts
deleted file mode 100644
index 975e7ee7d..000000000
--- a/server/models/account/account-follow.ts
+++ /dev/null
@@ -1,228 +0,0 @@
1import * as Bluebird from 'bluebird'
2import { values } from 'lodash'
3import * as Sequelize from 'sequelize'
4import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript'
5import { FollowState } from '../../../shared/models/accounts'
6import { FOLLOW_STATES } from '../../initializers/constants'
7import { ServerModel } from '../server/server'
8import { getSort } from '../utils'
9import { AccountModel } from './account'
10
11@Table({
12 tableName: 'accountFollow',
13 indexes: [
14 {
15 fields: [ 'accountId' ]
16 },
17 {
18 fields: [ 'targetAccountId' ]
19 },
20 {
21 fields: [ 'accountId', 'targetAccountId' ],
22 unique: true
23 }
24 ]
25})
26export class AccountFollowModel extends Model<AccountFollowModel> {
27
28 @AllowNull(false)
29 @Column(DataType.ENUM(values(FOLLOW_STATES)))
30 state: FollowState
31
32 @CreatedAt
33 createdAt: Date
34
35 @UpdatedAt
36 updatedAt: Date
37
38 @ForeignKey(() => AccountModel)
39 @Column
40 accountId: number
41
42 @BelongsTo(() => AccountModel, {
43 foreignKey: {
44 name: 'accountId',
45 allowNull: false
46 },
47 as: 'AccountFollower',
48 onDelete: 'CASCADE'
49 })
50 AccountFollower: AccountModel
51
52 @ForeignKey(() => AccountModel)
53 @Column
54 targetAccountId: number
55
56 @BelongsTo(() => AccountModel, {
57 foreignKey: {
58 name: 'targetAccountId',
59 allowNull: false
60 },
61 as: 'AccountFollowing',
62 onDelete: 'CASCADE'
63 })
64 AccountFollowing: AccountModel
65
66 static loadByAccountAndTarget (accountId: number, targetAccountId: number, t?: Sequelize.Transaction) {
67 const query = {
68 where: {
69 accountId,
70 targetAccountId
71 },
72 include: [
73 {
74 model: AccountModel,
75 required: true,
76 as: 'AccountFollower'
77 },
78 {
79 model: AccountModel,
80 required: true,
81 as: 'AccountFollowing'
82 }
83 ],
84 transaction: t
85 }
86
87 return AccountFollowModel.findOne(query)
88 }
89
90 static listFollowingForApi (id: number, start: number, count: number, sort: string) {
91 const query = {
92 distinct: true,
93 offset: start,
94 limit: count,
95 order: [ getSort(sort) ],
96 include: [
97 {
98 model: AccountModel,
99 required: true,
100 as: 'AccountFollower',
101 where: {
102 id
103 }
104 },
105 {
106 model: AccountModel,
107 as: 'AccountFollowing',
108 required: true,
109 include: [ ServerModel ]
110 }
111 ]
112 }
113
114 return AccountFollowModel.findAndCountAll(query)
115 .then(({ rows, count }) => {
116 return {
117 data: rows,
118 total: count
119 }
120 })
121 }
122
123 static listFollowersForApi (id: number, start: number, count: number, sort: string) {
124 const query = {
125 distinct: true,
126 offset: start,
127 limit: count,
128 order: [ getSort(sort) ],
129 include: [
130 {
131 model: AccountModel,
132 required: true,
133 as: 'AccountFollower',
134 include: [ ServerModel ]
135 },
136 {
137 model: AccountModel,
138 as: 'AccountFollowing',
139 required: true,
140 where: {
141 id
142 }
143 }
144 ]
145 }
146
147 return AccountFollowModel.findAndCountAll(query)
148 .then(({ rows, count }) => {
149 return {
150 data: rows,
151 total: count
152 }
153 })
154 }
155
156 static listAcceptedFollowerUrlsForApi (accountIds: number[], t: Sequelize.Transaction, start?: number, count?: number) {
157 return AccountFollowModel.createListAcceptedFollowForApiQuery('followers', accountIds, t, start, count)
158 }
159
160 static listAcceptedFollowerSharedInboxUrls (accountIds: number[], t: Sequelize.Transaction) {
161 return AccountFollowModel.createListAcceptedFollowForApiQuery('followers', accountIds, t, undefined, undefined, 'sharedInboxUrl')
162 }
163
164 static listAcceptedFollowingUrlsForApi (accountIds: number[], t: Sequelize.Transaction, start?: number, count?: number) {
165 return AccountFollowModel.createListAcceptedFollowForApiQuery('following', accountIds, t, start, count)
166 }
167
168 private static async createListAcceptedFollowForApiQuery (type: 'followers' | 'following',
169 accountIds: number[],
170 t: Sequelize.Transaction,
171 start?: number,
172 count?: number,
173 columnUrl = 'url') {
174 let firstJoin: string
175 let secondJoin: string
176
177 if (type === 'followers') {
178 firstJoin = 'targetAccountId'
179 secondJoin = 'accountId'
180 } else {
181 firstJoin = 'accountId'
182 secondJoin = 'targetAccountId'
183 }
184
185 const selections = [ '"Follows"."' + columnUrl + '" AS "url"', 'COUNT(*) AS "total"' ]
186 const tasks: Bluebird<any>[] = []
187
188 for (const selection of selections) {
189 let query = 'SELECT ' + selection + ' FROM "account" ' +
190 'INNER JOIN "accountFollow" ON "accountFollow"."' + firstJoin + '" = "account"."id" ' +
191 'INNER JOIN "account" AS "Follows" ON "accountFollow"."' + secondJoin + '" = "Follows"."id" ' +
192 'WHERE "account"."id" = ANY ($accountIds) AND "accountFollow"."state" = \'accepted\' '
193
194 if (count !== undefined) query += 'LIMIT ' + count
195 if (start !== undefined) query += ' OFFSET ' + start
196
197 const options = {
198 bind: { accountIds },
199 type: Sequelize.QueryTypes.SELECT,
200 transaction: t
201 }
202 tasks.push(AccountFollowModel.sequelize.query(query, options))
203 }
204
205 const [ followers, [ { total } ] ] = await
206 Promise.all(tasks)
207 const urls: string[] = followers.map(f => f.url)
208
209 return {
210 data: urls,
211 total: parseInt(total, 10)
212 }
213 }
214
215 toFormattedJSON () {
216 const follower = this.AccountFollower.toFormattedJSON()
217 const following = this.AccountFollowing.toFormattedJSON()
218
219 return {
220 id: this.id,
221 follower,
222 following,
223 state: this.state,
224 createdAt: this.createdAt,
225 updatedAt: this.updatedAt
226 }
227 }
228}
diff --git a/server/models/account/account.ts b/server/models/account/account.ts
index b26395fd4..1ee232537 100644
--- a/server/models/account/account.ts
+++ b/server/models/account/account.ts
@@ -5,18 +5,16 @@ import {
5 BelongsTo, 5 BelongsTo,
6 Column, 6 Column,
7 CreatedAt, 7 CreatedAt,
8 DataType, 8 DefaultScope,
9 Default,
10 ForeignKey, 9 ForeignKey,
11 HasMany, 10 HasMany,
12 Is, 11 Is,
13 IsUUID,
14 Model, 12 Model,
15 Table, 13 Table,
16 UpdatedAt 14 UpdatedAt
17} from 'sequelize-typescript' 15} from 'sequelize-typescript'
18import { isUserUsernameValid } from '../../helpers/custom-validators/users' 16import { isUserUsernameValid } from '../../helpers/custom-validators/users'
19import { sendDeleteAccount } from '../../lib/activitypub/send' 17import { sendDeleteActor } from '../../lib/activitypub/send'
20import { ActorModel } from '../activitypub/actor' 18import { ActorModel } from '../activitypub/actor'
21import { ApplicationModel } from '../application/application' 19import { ApplicationModel } from '../application/application'
22import { ServerModel } from '../server/server' 20import { ServerModel } from '../server/server'
@@ -24,31 +22,30 @@ import { throwIfNotValid } from '../utils'
24import { VideoChannelModel } from '../video/video-channel' 22import { VideoChannelModel } from '../video/video-channel'
25import { UserModel } from './user' 23import { UserModel } from './user'
26 24
27@Table({ 25@DefaultScope({
28 tableName: 'account', 26 include: [
29 indexes: [
30 {
31 fields: [ 'name' ]
32 },
33 {
34 fields: [ 'serverId' ]
35 },
36 {
37 fields: [ 'userId' ],
38 unique: true
39 },
40 {
41 fields: [ 'applicationId' ],
42 unique: true
43 },
44 { 27 {
45 fields: [ 'name', 'serverId', 'applicationId' ], 28 model: () => ActorModel,
46 unique: true 29 required: true,
30 include: [
31 {
32 model: () => ServerModel,
33 required: false
34 }
35 ]
47 } 36 }
48 ] 37 ]
49}) 38})
39@Table({
40 tableName: 'account'
41})
50export class AccountModel extends Model<AccountModel> { 42export class AccountModel extends Model<AccountModel> {
51 43
44 @AllowNull(false)
45 @Is('AccountName', value => throwIfNotValid(value, isUserUsernameValid, 'account name'))
46 @Column
47 name: string
48
52 @CreatedAt 49 @CreatedAt
53 createdAt: Date 50 createdAt: Date
54 51
@@ -89,7 +86,7 @@ export class AccountModel extends Model<AccountModel> {
89 }, 86 },
90 onDelete: 'cascade' 87 onDelete: 'cascade'
91 }) 88 })
92 Application: ApplicationModel 89 Account: ApplicationModel
93 90
94 @HasMany(() => VideoChannelModel, { 91 @HasMany(() => VideoChannelModel, {
95 foreignKey: { 92 foreignKey: {
@@ -103,32 +100,27 @@ export class AccountModel extends Model<AccountModel> {
103 @AfterDestroy 100 @AfterDestroy
104 static sendDeleteIfOwned (instance: AccountModel) { 101 static sendDeleteIfOwned (instance: AccountModel) {
105 if (instance.isOwned()) { 102 if (instance.isOwned()) {
106 return sendDeleteAccount(instance, undefined) 103 return sendDeleteActor(instance.Actor, undefined)
107 } 104 }
108 105
109 return undefined 106 return undefined
110 } 107 }
111 108
112 static loadApplication () {
113 return AccountModel.findOne({
114 include: [
115 {
116 model: ApplicationModel,
117 required: true
118 }
119 ]
120 })
121 }
122
123 static load (id: number) { 109 static load (id: number) {
124 return AccountModel.findById(id) 110 return AccountModel.findById(id)
125 } 111 }
126 112
127 static loadByUUID (uuid: string) { 113 static loadByUUID (uuid: string) {
128 const query = { 114 const query = {
129 where: { 115 include: [
130 uuid 116 {
131 } 117 model: ActorModel,
118 required: true,
119 where: {
120 uuid
121 }
122 }
123 ]
132 } 124 }
133 125
134 return AccountModel.findOne(query) 126 return AccountModel.findOne(query)
@@ -156,25 +148,6 @@ export class AccountModel extends Model<AccountModel> {
156 return AccountModel.findOne(query) 148 return AccountModel.findOne(query)
157 } 149 }
158 150
159 static loadByNameAndHost (name: string, host: string) {
160 const query = {
161 where: {
162 name
163 },
164 include: [
165 {
166 model: ServerModel,
167 required: true,
168 where: {
169 host
170 }
171 }
172 ]
173 }
174
175 return AccountModel.findOne(query)
176 }
177
178 static loadByUrl (url: string, transaction?: Sequelize.Transaction) { 151 static loadByUrl (url: string, transaction?: Sequelize.Transaction) {
179 const query = { 152 const query = {
180 include: [ 153 include: [
@@ -192,29 +165,11 @@ export class AccountModel extends Model<AccountModel> {
192 return AccountModel.findOne(query) 165 return AccountModel.findOne(query)
193 } 166 }
194 167
195 static listByFollowersUrls (followersUrls: string[], transaction?: Sequelize.Transaction) {
196 const query = {
197 include: [
198 {
199 model: ActorModel,
200 required: true,
201 where: {
202 followersUrl: {
203 [ Sequelize.Op.in ]: followersUrls
204 }
205 }
206 }
207 ],
208 transaction
209 }
210
211 return AccountModel.findAll(query)
212 }
213
214 toFormattedJSON () { 168 toFormattedJSON () {
215 const actor = this.Actor.toFormattedJSON() 169 const actor = this.Actor.toFormattedJSON()
216 const account = { 170 const account = {
217 id: this.id, 171 id: this.id,
172 name: this.name,
218 createdAt: this.createdAt, 173 createdAt: this.createdAt,
219 updatedAt: this.updatedAt 174 updatedAt: this.updatedAt
220 } 175 }
@@ -223,7 +178,7 @@ export class AccountModel extends Model<AccountModel> {
223 } 178 }
224 179
225 toActivityPubObject () { 180 toActivityPubObject () {
226 return this.Actor.toActivityPubObject(this.name, this.uuid, 'Account') 181 return this.Actor.toActivityPubObject(this.name, 'Account')
227 } 182 }
228 183
229 isOwned () { 184 isOwned () {
diff --git a/server/models/account/user.ts b/server/models/account/user.ts
index 70ed61e07..1d5759ea3 100644
--- a/server/models/account/user.ts
+++ b/server/models/account/user.ts
@@ -1,26 +1,13 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import { 2import {
3 AllowNull, 3 AllowNull, BeforeCreate, BeforeUpdate, Column, CreatedAt, DataType, Default, DefaultScope, HasMany, HasOne, Is, IsEmail, Model,
4 BeforeCreate, 4 Scopes, Table, UpdatedAt
5 BeforeUpdate,
6 Column, CreatedAt,
7 DataType,
8 Default, DefaultScope,
9 HasMany,
10 HasOne,
11 Is,
12 IsEmail,
13 Model, Scopes,
14 Table, UpdatedAt
15} from 'sequelize-typescript' 5} from 'sequelize-typescript'
16import { hasUserRight, USER_ROLE_LABELS, UserRight } from '../../../shared' 6import { hasUserRight, USER_ROLE_LABELS, UserRight } from '../../../shared'
7import { comparePassword, cryptPassword } from '../../helpers'
17import { 8import {
18 comparePassword, 9 isUserAutoPlayVideoValid, isUserDisplayNSFWValid, isUserPasswordValid, isUserRoleValid, isUserUsernameValid,
19 cryptPassword 10 isUserVideoQuotaValid
20} from '../../helpers'
21import {
22 isUserDisplayNSFWValid, isUserPasswordValid, isUserRoleValid, isUserUsernameValid,
23 isUserVideoQuotaValid, isUserAutoPlayVideoValid
24} from '../../helpers/custom-validators/users' 11} from '../../helpers/custom-validators/users'
25import { OAuthTokenModel } from '../oauth/oauth-token' 12import { OAuthTokenModel } from '../oauth/oauth-token'
26import { getSort, throwIfNotValid } from '../utils' 13import { getSort, throwIfNotValid } from '../utils'