import * as Sequelize from 'sequelize'
import {
- isUserUsernameValid,
- isAccountPublicKeyValid,
- isAccountUrlValid,
- isAccountPrivateKeyValid,
+ activityPubContextify,
isAccountFollowersCountValid,
+ isAccountFollowersValid,
isAccountFollowingCountValid,
+ isAccountFollowingValid,
isAccountInboxValid,
isAccountOutboxValid,
+ isAccountPrivateKeyValid,
+ isAccountPublicKeyValid,
isAccountSharedInboxValid,
- isAccountFollowersValid,
- isAccountFollowingValid,
- activityPubContextify
+ isAccountUrlValid,
+ isUserUsernameValid
} from '../../helpers'
-
-import { addMethodsToModel, getSort } from '../utils'
-import {
- AccountInstance,
- AccountAttributes,
-
- AccountMethods
-} from './account-interface'
-import LoadApplication = AccountMethods.LoadApplication
+import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers/constants'
import { sendDeleteAccount } from '../../lib/activitypub/send-request'
+import { addMethodsToModel } from '../utils'
+import { AccountAttributes, AccountInstance, AccountMethods } from './account-interface'
+
let Account: Sequelize.Model<AccountInstance, AccountAttributes>
-let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID
+let loadAccountByServerAndUUID: AccountMethods.LoadAccountByServerAndUUID
let load: AccountMethods.Load
let loadApplication: AccountMethods.LoadApplication
let loadByUUID: AccountMethods.LoadByUUID
let loadByUrl: AccountMethods.LoadByUrl
-let loadLocalAccountByNameAndPod: AccountMethods.LoadLocalAccountByNameAndPod
+let loadLocalByName: AccountMethods.LoadLocalByName
+let loadByNameAndHost: AccountMethods.LoadByNameAndHost
let listOwned: AccountMethods.ListOwned
-let listAcceptedFollowerUrlsForApi: AccountMethods.ListAcceptedFollowerUrlsForApi
-let listAcceptedFollowingUrlsForApi: AccountMethods.ListAcceptedFollowingUrlsForApi
-let listFollowingForApi: AccountMethods.ListFollowingForApi
-let listFollowersForApi: AccountMethods.ListFollowersForApi
let isOwned: AccountMethods.IsOwned
let toActivityPubObject: AccountMethods.ToActivityPubObject
let toFormattedJSON: AccountMethods.ToFormattedJSON
type: DataTypes.STRING,
allowNull: false,
validate: {
- usernameValid: value => {
+ nameValid: value => {
const res = isUserUsernameValid(value)
- if (res === false) throw new Error('Username is not valid.')
+ if (res === false) throw new Error('Name is not valid.')
}
}
},
url: {
- type: DataTypes.STRING,
+ type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max),
allowNull: false,
validate: {
urlValid: value => {
}
},
publicKey: {
- type: DataTypes.STRING,
- allowNull: false,
+ type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.PUBLIC_KEY.max),
+ allowNull: true,
validate: {
publicKeyValid: value => {
const res = isAccountPublicKeyValid(value)
}
},
privateKey: {
- type: DataTypes.STRING,
- allowNull: false,
+ type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.PRIVATE_KEY.max),
+ allowNull: true,
validate: {
privateKeyValid: value => {
const res = isAccountPrivateKeyValid(value)
type: DataTypes.INTEGER,
allowNull: false,
validate: {
- followersCountValid: value => {
+ followingCountValid: value => {
const res = isAccountFollowingCountValid(value)
if (res === false) throw new Error('Following count is not valid.')
}
}
},
inboxUrl: {
- type: DataTypes.STRING,
+ type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max),
allowNull: false,
validate: {
inboxUrlValid: value => {
}
},
outboxUrl: {
- type: DataTypes.STRING,
+ type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max),
allowNull: false,
validate: {
outboxUrlValid: value => {
}
},
sharedInboxUrl: {
- type: DataTypes.STRING,
+ type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max),
allowNull: false,
validate: {
sharedInboxUrlValid: value => {
}
},
followersUrl: {
- type: DataTypes.STRING,
+ type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max),
allowNull: false,
validate: {
followersUrlValid: value => {
}
},
followingUrl: {
- type: DataTypes.STRING,
+ type: DataTypes.STRING(CONSTRAINTS_FIELDS.ACCOUNTS.URL.max),
allowNull: false,
validate: {
followingUrlValid: value => {
fields: [ 'name' ]
},
{
- fields: [ 'podId' ]
+ fields: [ 'serverId' ]
},
{
fields: [ 'userId' ],
unique: true
},
{
- fields: [ 'name', 'podId' ],
+ fields: [ 'name', 'serverId', 'applicationId' ],
unique: true
}
],
const classMethods = [
associate,
- loadAccountByPodAndUUID,
+ loadAccountByServerAndUUID,
loadApplication,
load,
loadByUUID,
loadByUrl,
- loadLocalAccountByNameAndPod,
- listOwned,
- listAcceptedFollowerUrlsForApi,
- listAcceptedFollowingUrlsForApi,
- listFollowingForApi,
- listFollowersForApi
+ loadLocalByName,
+ loadByNameAndHost,
+ listOwned
]
const instanceMethods = [
isOwned,
// ---------------------------------------------------------------------------
function associate (models) {
- Account.belongsTo(models.Pod, {
+ Account.belongsTo(models.Server, {
foreignKey: {
- name: 'podId',
+ name: 'serverId',
allowNull: true
},
onDelete: 'cascade'
Account.belongsTo(models.Application, {
foreignKey: {
- name: 'userId',
+ name: 'applicationId',
allowNull: true
},
onDelete: 'cascade'
hooks: true
})
- Account.hasMany(models.AccountFollower, {
+ Account.hasMany(models.AccountFollow, {
foreignKey: {
name: 'accountId',
allowNull: false
},
- as: 'following',
onDelete: 'cascade'
})
- Account.hasMany(models.AccountFollower, {
+ Account.hasMany(models.AccountFollow, {
foreignKey: {
name: 'targetAccountId',
allowNull: false
}
toFormattedJSON = function (this: AccountInstance) {
+ let host = CONFIG.WEBSERVER.HOST
+ let score: number
+
+ if (this.Server) {
+ host = this.Server.host
+ score = this.Server.score as number
+ }
+
const json = {
id: this.id,
- host: this.Pod.host,
- name: this.name
+ host,
+ score,
+ name: this.name,
+ createdAt: this.createdAt,
+ updatedAt: this.updatedAt
}
return json
}
toActivityPubObject = function (this: AccountInstance) {
- const type = this.podId ? 'Application' as 'Application' : 'Person' as 'Person'
+ const type = this.serverId ? 'Application' as 'Application' : 'Person' as 'Person'
const json = {
type,
}
isOwned = function (this: AccountInstance) {
- return this.podId === null
+ return this.serverId === null
}
getFollowerSharedInboxUrls = function (this: AccountInstance) {
attributes: [ 'sharedInboxUrl' ],
include: [
{
- model: Account['sequelize'].models.AccountFollower,
+ model: Account['sequelize'].models.AccountFollow,
+ required: true,
+ as: 'followers',
where: {
targetAccountId: this.id
}
}
getFollowingUrl = function (this: AccountInstance) {
- return this.url + '/followers'
+ return this.url + '/following'
}
getFollowersUrl = function (this: AccountInstance) {
listOwned = function () {
const query: Sequelize.FindOptions<AccountAttributes> = {
where: {
- podId: null
+ serverId: null
}
}
return Account.findAll(query)
}
-listAcceptedFollowerUrlsForApi = function (id: number, start: number, count?: number) {
- return createListAcceptedFollowForApiQuery('followers', id, start, count)
-}
-
-listAcceptedFollowingUrlsForApi = function (id: number, start: number, count?: number) {
- return createListAcceptedFollowForApiQuery('following', id, start, count)
-}
-
-listFollowingForApi = function (id: number, start: number, count: number, sort: string) {
- const query = {
- distinct: true,
- offset: start,
- limit: count,
- order: [ getSort(sort) ],
- include: [
- {
- model: Account['sequelize'].models.AccountFollow,
- required: true,
- as: 'following',
- include: [
- {
- model: Account['sequelize'].models.Account,
- as: 'following',
- required: true,
- include: [ Account['sequelize'].models.Pod ]
- }
- ]
- }
- ]
- }
-
- return Account.findAndCountAll(query).then(({ rows, count }) => {
- return {
- data: rows,
- total: count
- }
- })
-}
-
-listFollowersForApi = function (id: number, start: number, count: number, sort: string) {
- const query = {
- distinct: true,
- offset: start,
- limit: count,
- order: [ getSort(sort) ],
- include: [
- {
- model: Account['sequelize'].models.AccountFollow,
- required: true,
- as: 'followers',
- include: [
- {
- model: Account['sequelize'].models.Account,
- as: 'followers',
- required: true,
- include: [ Account['sequelize'].models.Pod ]
- }
- ]
- }
- ]
- }
-
- return Account.findAndCountAll(query).then(({ rows, count }) => {
- return {
- data: rows,
- total: count
- }
- })
-}
-
loadApplication = function () {
return Account.findOne({
include: [
{
- model: Account['sequelize'].model.Application,
+ model: Account['sequelize'].models.Application,
required: true
}
]
return Account.findOne(query)
}
-loadLocalAccountByNameAndPod = function (name: string, host: string) {
+loadLocalByName = function (name: string) {
const query: Sequelize.FindOptions<AccountAttributes> = {
where: {
name,
- userId: {
- [Sequelize.Op.ne]: null
- }
+ [Sequelize.Op.or]: [
+ {
+ userId: {
+ [Sequelize.Op.ne]: null
+ }
+ },
+ {
+ applicationId: {
+ [Sequelize.Op.ne]: null
+ }
+ }
+ ]
+ }
+ }
+
+ return Account.findOne(query)
+}
+
+loadByNameAndHost = function (name: string, host: string) {
+ const query: Sequelize.FindOptions<AccountAttributes> = {
+ where: {
+ name
},
include: [
{
- model: Account['sequelize'].models.Pod,
+ model: Account['sequelize'].models.Server,
+ required: true,
where: {
host
}
return Account.findOne(query)
}
-loadAccountByPodAndUUID = function (uuid: string, podId: number, transaction: Sequelize.Transaction) {
+loadAccountByServerAndUUID = function (uuid: string, serverId: number, transaction: Sequelize.Transaction) {
const query: Sequelize.FindOptions<AccountAttributes> = {
where: {
- podId,
+ serverId,
uuid
},
transaction
return Account.find(query)
}
-
-// ------------------------------ UTILS ------------------------------
-
-async function createListAcceptedFollowForApiQuery (type: 'followers' | 'following', id: number, start: number, count?: number) {
- let firstJoin: string
- let secondJoin: string
-
- if (type === 'followers') {
- firstJoin = 'targetAccountId'
- secondJoin = 'accountId'
- } else {
- firstJoin = 'accountId'
- secondJoin = 'targetAccountId'
- }
-
- const selections = [ '"Followers"."url" AS "url"', 'COUNT(*) AS "total"' ]
- const tasks: Promise<any>[] = []
-
- for (const selection of selections) {
- let query = 'SELECT ' + selection + ' FROM "Account" ' +
- 'INNER JOIN "AccountFollower" ON "AccountFollower"."' + firstJoin + '" = "Account"."id" ' +
- 'INNER JOIN "Account" AS "Follows" ON "Followers"."id" = "Follows"."' + secondJoin + '" ' +
- 'WHERE "Account"."id" = $id AND "AccountFollower"."state" = \'accepted\' ' +
- 'LIMIT ' + start
-
- if (count !== undefined) query += ', ' + count
-
- const options = {
- bind: { id },
- type: Sequelize.QueryTypes.SELECT
- }
- tasks.push(Account['sequelize'].query(query, options))
- }
-
- const [ followers, [ { total } ]] = await Promise.all(tasks)
- const urls: string[] = followers.map(f => f.url)
-
- return {
- data: urls,
- total: parseInt(total, 10)
- }
-}