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-interface.ts8
-rw-r--r--server/models/account/account-follow.ts30
-rw-r--r--server/models/account/account-interface.ts24
-rw-r--r--server/models/account/account.ts138
4 files changed, 162 insertions, 38 deletions
diff --git a/server/models/account/account-follow-interface.ts b/server/models/account/account-follow-interface.ts
index 3be383649..efdff915e 100644
--- a/server/models/account/account-follow-interface.ts
+++ b/server/models/account/account-follow-interface.ts
@@ -1,17 +1,19 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Bluebird from 'bluebird'
3 3import { FollowState } from '../../../shared/models/accounts/follow.model'
4import { VideoRateType } from '../../../shared/models/videos/video-rate.type'
5 4
6export namespace AccountFollowMethods { 5export namespace AccountFollowMethods {
6 export type LoadByAccountAndTarget = (accountId: number, targetAccountId: number) => Bluebird<AccountFollowInstance>
7} 7}
8 8
9export interface AccountFollowClass { 9export interface AccountFollowClass {
10 loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget
10} 11}
11 12
12export interface AccountFollowAttributes { 13export interface AccountFollowAttributes {
13 accountId: number 14 accountId: number
14 targetAccountId: number 15 targetAccountId: number
16 state: FollowState
15} 17}
16 18
17export interface AccountFollowInstance extends AccountFollowClass, AccountFollowAttributes, Sequelize.Instance<AccountFollowAttributes> { 19export interface AccountFollowInstance extends AccountFollowClass, AccountFollowAttributes, Sequelize.Instance<AccountFollowAttributes> {
diff --git a/server/models/account/account-follow.ts b/server/models/account/account-follow.ts
index 9bf03b253..e6abc893a 100644
--- a/server/models/account/account-follow.ts
+++ b/server/models/account/account-follow.ts
@@ -1,18 +1,21 @@
1import { values } from 'lodash'
1import * as Sequelize from 'sequelize' 2import * as Sequelize from 'sequelize'
2 3
3import { addMethodsToModel } from '../utils' 4import { addMethodsToModel } from '../utils'
4import { 5import { AccountFollowAttributes, AccountFollowInstance, AccountFollowMethods } from './account-follow-interface'
5 AccountFollowInstance, 6import { FOLLOW_STATES } from '../../initializers/constants'
6 AccountFollowAttributes,
7
8 AccountFollowMethods
9} from './account-follow-interface'
10 7
11let AccountFollow: Sequelize.Model<AccountFollowInstance, AccountFollowAttributes> 8let AccountFollow: Sequelize.Model<AccountFollowInstance, AccountFollowAttributes>
9let loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget
12 10
13export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { 11export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
14 AccountFollow = sequelize.define<AccountFollowInstance, AccountFollowAttributes>('AccountFollow', 12 AccountFollow = sequelize.define<AccountFollowInstance, AccountFollowAttributes>('AccountFollow',
15 { }, 13 {
14 state: {
15 type: DataTypes.ENUM(values(FOLLOW_STATES)),
16 allowNull: false
17 }
18 },
16 { 19 {
17 indexes: [ 20 indexes: [
18 { 21 {
@@ -43,6 +46,7 @@ function associate (models) {
43 name: 'accountId', 46 name: 'accountId',
44 allowNull: false 47 allowNull: false
45 }, 48 },
49 as: 'followers',
46 onDelete: 'CASCADE' 50 onDelete: 'CASCADE'
47 }) 51 })
48 52
@@ -51,6 +55,18 @@ function associate (models) {
51 name: 'targetAccountId', 55 name: 'targetAccountId',
52 allowNull: false 56 allowNull: false
53 }, 57 },
58 as: 'following',
54 onDelete: 'CASCADE' 59 onDelete: 'CASCADE'
55 }) 60 })
56} 61}
62
63loadByAccountAndTarget = function (accountId: number, targetAccountId: number) {
64 const query = {
65 where: {
66 accountId,
67 targetAccountId
68 }
69 }
70
71 return AccountFollow.findOne(query)
72}
diff --git a/server/models/account/account-interface.ts b/server/models/account/account-interface.ts
index a662eb992..d49dfbe17 100644
--- a/server/models/account/account-interface.ts
+++ b/server/models/account/account-interface.ts
@@ -1,22 +1,26 @@
1import * as Sequelize from 'sequelize'
2import * as Bluebird from 'bluebird' 1import * as Bluebird from 'bluebird'
3 2import * as Sequelize from 'sequelize'
3import { Account as FormattedAccount, ActivityPubActor } from '../../../shared'
4import { ResultList } from '../../../shared/models/result-list.model'
4import { PodInstance } from '../pod/pod-interface' 5import { PodInstance } from '../pod/pod-interface'
5import { VideoChannelInstance } from '../video/video-channel-interface' 6import { VideoChannelInstance } from '../video/video-channel-interface'
6import { ActivityPubActor } from '../../../shared'
7import { ResultList } from '../../../shared/models/result-list.model'
8 7
9export namespace AccountMethods { 8export namespace AccountMethods {
9 export type LoadApplication = () => Bluebird<AccountInstance>
10
10 export type Load = (id: number) => Bluebird<AccountInstance> 11 export type Load = (id: number) => Bluebird<AccountInstance>
11 export type LoadByUUID = (uuid: string) => Bluebird<AccountInstance> 12 export type LoadByUUID = (uuid: string) => Bluebird<AccountInstance>
12 export type LoadByUrl = (url: string) => Bluebird<AccountInstance> 13 export type LoadByUrl = (url: string) => Bluebird<AccountInstance>
13 export type LoadAccountByPodAndUUID = (uuid: string, podId: number, transaction: Sequelize.Transaction) => Bluebird<AccountInstance> 14 export type LoadAccountByPodAndUUID = (uuid: string, podId: number, transaction: Sequelize.Transaction) => Bluebird<AccountInstance>
14 export type LoadLocalAccountByName = (name: string) => Bluebird<AccountInstance> 15 export type LoadLocalAccountByNameAndPod = (name: string, host: string) => Bluebird<AccountInstance>
15 export type ListOwned = () => Bluebird<AccountInstance[]> 16 export type ListOwned = () => Bluebird<AccountInstance[]>
16 export type ListFollowerUrlsForApi = (name: string, start: number, count?: number) => Promise< ResultList<string> > 17 export type ListFollowerUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> >
17 export type ListFollowingUrlsForApi = (name: string, start: number, count?: number) => Promise< ResultList<string> > 18 export type ListFollowingUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> >
19 export type ListFollowingForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
20 export type ListFollowersForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
18 21
19 export type ToActivityPubObject = (this: AccountInstance) => ActivityPubActor 22 export type ToActivityPubObject = (this: AccountInstance) => ActivityPubActor
23 export type ToFormattedJSON = (this: AccountInstance) => FormattedAccount
20 export type IsOwned = (this: AccountInstance) => boolean 24 export type IsOwned = (this: AccountInstance) => boolean
21 export type GetFollowerSharedInboxUrls = (this: AccountInstance) => Bluebird<string[]> 25 export type GetFollowerSharedInboxUrls = (this: AccountInstance) => Bluebird<string[]>
22 export type GetFollowingUrl = (this: AccountInstance) => string 26 export type GetFollowingUrl = (this: AccountInstance) => string
@@ -25,14 +29,17 @@ export namespace AccountMethods {
25} 29}
26 30
27export interface AccountClass { 31export interface AccountClass {
32 loadApplication: AccountMethods.LoadApplication
28 loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID 33 loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID
29 load: AccountMethods.Load 34 load: AccountMethods.Load
30 loadByUUID: AccountMethods.LoadByUUID 35 loadByUUID: AccountMethods.LoadByUUID
31 loadByUrl: AccountMethods.LoadByUrl 36 loadByUrl: AccountMethods.LoadByUrl
32 loadLocalAccountByName: AccountMethods.LoadLocalAccountByName 37 loadLocalAccountByNameAndPod: AccountMethods.LoadLocalAccountByNameAndPod
33 listOwned: AccountMethods.ListOwned 38 listOwned: AccountMethods.ListOwned
34 listFollowerUrlsForApi: AccountMethods.ListFollowerUrlsForApi 39 listFollowerUrlsForApi: AccountMethods.ListFollowerUrlsForApi
35 listFollowingUrlsForApi: AccountMethods.ListFollowingUrlsForApi 40 listFollowingUrlsForApi: AccountMethods.ListFollowingUrlsForApi
41 listFollowingForApi: AccountMethods.ListFollowingForApi
42 listFollowersForApi: AccountMethods.ListFollowersForApi
36} 43}
37 44
38export interface AccountAttributes { 45export interface AccountAttributes {
@@ -58,6 +65,7 @@ export interface AccountAttributes {
58export interface AccountInstance extends AccountClass, AccountAttributes, Sequelize.Instance<AccountAttributes> { 65export interface AccountInstance extends AccountClass, AccountAttributes, Sequelize.Instance<AccountAttributes> {
59 isOwned: AccountMethods.IsOwned 66 isOwned: AccountMethods.IsOwned
60 toActivityPubObject: AccountMethods.ToActivityPubObject 67 toActivityPubObject: AccountMethods.ToActivityPubObject
68 toFormattedJSON: AccountMethods.ToFormattedJSON
61 getFollowerSharedInboxUrls: AccountMethods.GetFollowerSharedInboxUrls 69 getFollowerSharedInboxUrls: AccountMethods.GetFollowerSharedInboxUrls
62 getFollowingUrl: AccountMethods.GetFollowingUrl 70 getFollowingUrl: AccountMethods.GetFollowingUrl
63 getFollowersUrl: AccountMethods.GetFollowersUrl 71 getFollowersUrl: AccountMethods.GetFollowersUrl
diff --git a/server/models/account/account.ts b/server/models/account/account.ts
index a79e13880..daf8f4703 100644
--- a/server/models/account/account.ts
+++ b/server/models/account/account.ts
@@ -15,25 +15,31 @@ import {
15 activityPubContextify 15 activityPubContextify
16} from '../../helpers' 16} from '../../helpers'
17 17
18import { addMethodsToModel } from '../utils' 18import { addMethodsToModel, getSort } from '../utils'
19import { 19import {
20 AccountInstance, 20 AccountInstance,
21 AccountAttributes, 21 AccountAttributes,
22 22
23 AccountMethods 23 AccountMethods
24} from './account-interface' 24} from './account-interface'
25import LoadApplication = AccountMethods.LoadApplication
26import { sendDeleteAccount } from '../../lib/activitypub/send-request'
25 27
26let Account: Sequelize.Model<AccountInstance, AccountAttributes> 28let Account: Sequelize.Model<AccountInstance, AccountAttributes>
27let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID 29let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID
28let load: AccountMethods.Load 30let load: AccountMethods.Load
31let loadApplication: AccountMethods.LoadApplication
29let loadByUUID: AccountMethods.LoadByUUID 32let loadByUUID: AccountMethods.LoadByUUID
30let loadByUrl: AccountMethods.LoadByUrl 33let loadByUrl: AccountMethods.LoadByUrl
31let loadLocalAccountByName: AccountMethods.LoadLocalAccountByName 34let loadLocalAccountByNameAndPod: AccountMethods.LoadLocalAccountByNameAndPod
32let listOwned: AccountMethods.ListOwned 35let listOwned: AccountMethods.ListOwned
33let listFollowerUrlsForApi: AccountMethods.ListFollowerUrlsForApi 36let listFollowerUrlsForApi: AccountMethods.ListFollowerUrlsForApi
34let listFollowingUrlsForApi: AccountMethods.ListFollowingUrlsForApi 37let listFollowingUrlsForApi: AccountMethods.ListFollowingUrlsForApi
38let listFollowingForApi: AccountMethods.ListFollowingForApi
39let listFollowersForApi: AccountMethods.ListFollowersForApi
35let isOwned: AccountMethods.IsOwned 40let isOwned: AccountMethods.IsOwned
36let toActivityPubObject: AccountMethods.ToActivityPubObject 41let toActivityPubObject: AccountMethods.ToActivityPubObject
42let toFormattedJSON: AccountMethods.ToFormattedJSON
37let getFollowerSharedInboxUrls: AccountMethods.GetFollowerSharedInboxUrls 43let getFollowerSharedInboxUrls: AccountMethods.GetFollowerSharedInboxUrls
38let getFollowingUrl: AccountMethods.GetFollowingUrl 44let getFollowingUrl: AccountMethods.GetFollowingUrl
39let getFollowersUrl: AccountMethods.GetFollowersUrl 45let getFollowersUrl: AccountMethods.GetFollowersUrl
@@ -189,16 +195,20 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
189 const classMethods = [ 195 const classMethods = [
190 associate, 196 associate,
191 loadAccountByPodAndUUID, 197 loadAccountByPodAndUUID,
198 loadApplication,
192 load, 199 load,
193 loadByUUID, 200 loadByUUID,
194 loadLocalAccountByName, 201 loadLocalAccountByNameAndPod,
195 listOwned, 202 listOwned,
196 listFollowerUrlsForApi, 203 listFollowerUrlsForApi,
197 listFollowingUrlsForApi 204 listFollowingUrlsForApi,
205 listFollowingForApi,
206 listFollowersForApi
198 ] 207 ]
199 const instanceMethods = [ 208 const instanceMethods = [
200 isOwned, 209 isOwned,
201 toActivityPubObject, 210 toActivityPubObject,
211 toFormattedJSON,
202 getFollowerSharedInboxUrls, 212 getFollowerSharedInboxUrls,
203 getFollowingUrl, 213 getFollowingUrl,
204 getFollowersUrl, 214 getFollowersUrl,
@@ -250,6 +260,7 @@ function associate (models) {
250 name: 'accountId', 260 name: 'accountId',
251 allowNull: false 261 allowNull: false
252 }, 262 },
263 as: 'following',
253 onDelete: 'cascade' 264 onDelete: 'cascade'
254 }) 265 })
255 266
@@ -258,23 +269,29 @@ function associate (models) {
258 name: 'targetAccountId', 269 name: 'targetAccountId',
259 allowNull: false 270 allowNull: false
260 }, 271 },
272 as: 'followers',
261 onDelete: 'cascade' 273 onDelete: 'cascade'
262 }) 274 })
263} 275}
264 276
265function afterDestroy (account: AccountInstance) { 277function afterDestroy (account: AccountInstance) {
266 if (account.isOwned()) { 278 if (account.isOwned()) {
267 const removeVideoAccountToFriendsParams = { 279 return sendDeleteAccount(account, undefined)
268 uuid: account.uuid
269 }
270
271 // FIXME: remove account in followers
272 // return removeVideoAccountToFriends(removeVideoAccountToFriendsParams)
273 } 280 }
274 281
275 return undefined 282 return undefined
276} 283}
277 284
285toFormattedJSON = function (this: AccountInstance) {
286 const json = {
287 id: this.id,
288 host: this.Pod.host,
289 name: this.name
290 }
291
292 return json
293}
294
278toActivityPubObject = function (this: AccountInstance) { 295toActivityPubObject = function (this: AccountInstance) {
279 const type = this.podId ? 'Application' as 'Application' : 'Person' as 'Person' 296 const type = this.podId ? 'Application' as 'Application' : 'Person' as 'Person'
280 297
@@ -347,12 +364,85 @@ listOwned = function () {
347 return Account.findAll(query) 364 return Account.findAll(query)
348} 365}
349 366
350listFollowerUrlsForApi = function (name: string, start: number, count?: number) { 367listFollowerUrlsForApi = function (id: number, start: number, count?: number) {
351 return createListFollowForApiQuery('followers', name, start, count) 368 return createListFollowForApiQuery('followers', id, start, count)
369}
370
371listFollowingUrlsForApi = function (id: number, start: number, count?: number) {
372 return createListFollowForApiQuery('following', id, start, count)
373}
374
375listFollowingForApi = function (id: number, start: number, count: number, sort: string) {
376 const query = {
377 distinct: true,
378 offset: start,
379 limit: count,
380 order: [ getSort(sort) ],
381 include: [
382 {
383 model: Account['sequelize'].models.AccountFollow,
384 required: true,
385 as: 'following',
386 include: [
387 {
388 model: Account['sequelize'].models.Account,
389 as: 'following',
390 required: true,
391 include: [ Account['sequelize'].models.Pod ]
392 }
393 ]
394 }
395 ]
396 }
397
398 return Account.findAndCountAll(query).then(({ rows, count }) => {
399 return {
400 data: rows,
401 total: count
402 }
403 })
404}
405
406listFollowersForApi = function (id: number, start: number, count: number, sort: string) {
407 const query = {
408 distinct: true,
409 offset: start,
410 limit: count,
411 order: [ getSort(sort) ],
412 include: [
413 {
414 model: Account['sequelize'].models.AccountFollow,
415 required: true,
416 as: 'followers',
417 include: [
418 {
419 model: Account['sequelize'].models.Account,
420 as: 'followers',
421 required: true,
422 include: [ Account['sequelize'].models.Pod ]
423 }
424 ]
425 }
426 ]
427 }
428
429 return Account.findAndCountAll(query).then(({ rows, count }) => {
430 return {
431 data: rows,
432 total: count
433 }
434 })
352} 435}
353 436
354listFollowingUrlsForApi = function (name: string, start: number, count?: number) { 437loadApplication = function () {
355 return createListFollowForApiQuery('following', name, start, count) 438 return Account.findOne({
439 include: [
440 {
441 model: Account['sequelize'].model.Application,
442 required: true
443 }
444 ]
445 })
356} 446}
357 447
358load = function (id: number) { 448load = function (id: number) {
@@ -369,14 +459,22 @@ loadByUUID = function (uuid: string) {
369 return Account.findOne(query) 459 return Account.findOne(query)
370} 460}
371 461
372loadLocalAccountByName = function (name: string) { 462loadLocalAccountByNameAndPod = function (name: string, host: string) {
373 const query: Sequelize.FindOptions<AccountAttributes> = { 463 const query: Sequelize.FindOptions<AccountAttributes> = {
374 where: { 464 where: {
375 name, 465 name,
376 userId: { 466 userId: {
377 [Sequelize.Op.ne]: null 467 [Sequelize.Op.ne]: null
378 } 468 }
379 } 469 },
470 include: [
471 {
472 model: Account['sequelize'].models.Pod,
473 where: {
474 host
475 }
476 }
477 ]
380 } 478 }
381 479
382 return Account.findOne(query) 480 return Account.findOne(query)
@@ -406,7 +504,7 @@ loadAccountByPodAndUUID = function (uuid: string, podId: number, transaction: Se
406 504
407// ------------------------------ UTILS ------------------------------ 505// ------------------------------ UTILS ------------------------------
408 506
409async function createListFollowForApiQuery (type: 'followers' | 'following', name: string, start: number, count?: number) { 507async function createListFollowForApiQuery (type: 'followers' | 'following', id: number, start: number, count?: number) {
410 let firstJoin: string 508 let firstJoin: string
411 let secondJoin: string 509 let secondJoin: string
412 510
@@ -424,14 +522,14 @@ async function createListFollowForApiQuery (type: 'followers' | 'following', nam
424 for (const selection of selections) { 522 for (const selection of selections) {
425 let query = 'SELECT ' + selection + ' FROM "Account" ' + 523 let query = 'SELECT ' + selection + ' FROM "Account" ' +
426 'INNER JOIN "AccountFollower" ON "AccountFollower"."' + firstJoin + '" = "Account"."id" ' + 524 'INNER JOIN "AccountFollower" ON "AccountFollower"."' + firstJoin + '" = "Account"."id" ' +
427 'INNER JOIN "Account" AS "Followers" ON "Followers"."id" = "AccountFollower"."' + secondJoin + '" ' + 525 'INNER JOIN "Account" AS "Follows" ON "Followers"."id" = "Follows"."' + secondJoin + '" ' +
428 'WHERE "Account"."name" = \'$name\' ' + 526 'WHERE "Account"."id" = $id ' +
429 'LIMIT ' + start 527 'LIMIT ' + start
430 528
431 if (count !== undefined) query += ', ' + count 529 if (count !== undefined) query += ', ' + count
432 530
433 const options = { 531 const options = {
434 bind: { name }, 532 bind: { id },
435 type: Sequelize.QueryTypes.SELECT 533 type: Sequelize.QueryTypes.SELECT
436 } 534 }
437 tasks.push(Account['sequelize'].query(query, options)) 535 tasks.push(Account['sequelize'].query(query, options))