X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fmodels%2Faccount%2Faccount.ts;h=619a598ddf15013d2d1eb34796c2280dedbb36d5;hb=6b5f72beda96d8b7e4d6329c4001827334de27dd;hp=0905a0fb2affe7a04a41afdacd7fe619c603712b;hpb=a15871560f80e07386c1dabb8370cd2664ecfd1f;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/models/account/account.ts b/server/models/account/account.ts index 0905a0fb2..619a598dd 100644 --- a/server/models/account/account.ts +++ b/server/models/account/account.ts @@ -1,3 +1,4 @@ +import { FindOptions, Includeable, IncludeOptions, Op, Transaction, WhereOptions } from 'sequelize' import { AllowNull, BeforeDestroy, @@ -15,32 +16,43 @@ import { Table, UpdatedAt } from 'sequelize-typescript' +import { ModelCache } from '@server/models/model-cache' +import { AttributesOnly } from '@shared/typescript-utils' import { Account, AccountSummary } from '../../../shared/models/actors' import { isAccountDescriptionValid } from '../../helpers/custom-validators/accounts' -import { sendDeleteActor } from '../../lib/activitypub/send' -import { ActorModel } from '../activitypub/actor' +import { CONSTRAINTS_FIELDS, SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants' +import { sendDeleteActor } from '../../lib/activitypub/send/send-delete' +import { + MAccount, + MAccountActor, + MAccountAP, + MAccountDefault, + MAccountFormattable, + MAccountSummaryFormattable, + MChannelActor +} from '../../types/models' +import { ActorModel } from '../actor/actor' +import { ActorFollowModel } from '../actor/actor-follow' +import { ActorImageModel } from '../actor/actor-image' import { ApplicationModel } from '../application/application' import { ServerModel } from '../server/server' +import { ServerBlocklistModel } from '../server/server-blocklist' +import { UserModel } from '../user/user' import { getSort, throwIfNotValid } from '../utils' +import { VideoModel } from '../video/video' import { VideoChannelModel } from '../video/video-channel' import { VideoCommentModel } from '../video/video-comment' -import { UserModel } from './user' -import { AvatarModel } from '../avatar/avatar' import { VideoPlaylistModel } from '../video/video-playlist' -import { CONSTRAINTS_FIELDS, SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants' -import { FindOptions, IncludeOptions, Op, Transaction, WhereOptions } from 'sequelize' import { AccountBlocklistModel } from './account-blocklist' -import { ServerBlocklistModel } from '../server/server-blocklist' -import { ActorFollowModel } from '../activitypub/actor-follow' -import { MAccountActor, MAccountDefault, MAccountSummaryFormattable, MAccountFormattable, MAccountAP } from '../../typings/models' -import * as Bluebird from 'bluebird' export enum ScopeNames { SUMMARY = 'SUMMARY' } export type SummaryOptions = { + actorRequired?: boolean // Default: true whereActor?: WhereOptions + whereServer?: WhereOptions withAccountBlockerIds?: number[] } @@ -54,39 +66,40 @@ export type SummaryOptions = { })) @Scopes(() => ({ [ScopeNames.SUMMARY]: (options: SummaryOptions = {}) => { - const whereActor = options.whereActor || undefined - const serverInclude: IncludeOptions = { attributes: [ 'host' ], model: ServerModel.unscoped(), - required: false + required: !!options.whereServer, + where: options.whereServer } - const query: FindOptions = { - attributes: [ 'id', 'name' ], - include: [ - { - attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ], - model: ActorModel.unscoped(), - required: true, - where: whereActor, - include: [ - serverInclude, + const queryInclude: Includeable[] = [ + { + attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ], + model: ActorModel.unscoped(), + required: options.actorRequired ?? true, + where: options.whereActor, + include: [ + serverInclude, - { - model: AvatarModel.unscoped(), - required: false - } - ] - } - ] + { + model: ActorImageModel.unscoped(), + as: 'Avatar', + required: false + } + ] + } + ] + + const query: FindOptions = { + attributes: [ 'id', 'name', 'actorId' ] } if (options.withAccountBlockerIds) { - query.include.push({ + queryInclude.push({ attributes: [ 'id' ], model: AccountBlocklistModel.unscoped(), - as: 'BlockedAccounts', + as: 'BlockedBy', required: false, where: { accountId: { @@ -109,6 +122,8 @@ export type SummaryOptions = { ] } + query.include = queryInclude + return query } })) @@ -127,7 +142,7 @@ export type SummaryOptions = { } ] }) -export class AccountModel extends Model { +export class AccountModel extends Model>> { @AllowNull(false) @Column @@ -213,12 +228,10 @@ export class AccountModel extends Model { name: 'targetAccountId', allowNull: false }, - as: 'BlockedAccounts', + as: 'BlockedBy', onDelete: 'CASCADE' }) - BlockedAccounts: AccountBlocklistModel[] - - private static cache: { [ id: string ]: any } = {} + BlockedBy: AccountBlocklistModel[] @BeforeDestroy static async sendDeleteIfOwned (instance: AccountModel, options) { @@ -227,6 +240,7 @@ export class AccountModel extends Model { } await ActorFollowModel.removeFollowsOf(instance.Actor.id, options.transaction) + if (instance.isOwned()) { return sendDeleteActor(instance.Actor, options.transaction) } @@ -234,11 +248,11 @@ export class AccountModel extends Model { return undefined } - static load (id: number, transaction?: Transaction): Bluebird { + static load (id: number, transaction?: Transaction): Promise { return AccountModel.findByPk(id, { transaction }) } - static loadByNameWithHost (nameWithHost: string): Bluebird { + static loadByNameWithHost (nameWithHost: string): Promise { const [ accountName, host ] = nameWithHost.split('@') if (!host || host === WEBSERVER.HOST) return AccountModel.loadLocalByName(accountName) @@ -246,49 +260,47 @@ export class AccountModel extends Model { return AccountModel.loadByNameAndHost(accountName, host) } - static loadLocalByName (name: string): Bluebird { - // The server actor never change, so we can easily cache it - if (name === SERVER_ACTOR_NAME && AccountModel.cache[name]) { - return Bluebird.resolve(AccountModel.cache[name]) - } - - const query = { - where: { - [Op.or]: [ - { - userId: { - [Op.ne]: null + static loadLocalByName (name: string): Promise { + const fun = () => { + const query = { + where: { + [Op.or]: [ + { + userId: { + [Op.ne]: null + } + }, + { + applicationId: { + [Op.ne]: null + } } - }, + ] + }, + include: [ { - applicationId: { - [Op.ne]: null + model: ActorModel, + required: true, + where: { + preferredUsername: name } } ] - }, - include: [ - { - model: ActorModel, - required: true, - where: { - preferredUsername: name - } - } - ] - } + } - return AccountModel.findOne(query) - .then(account => { - if (name === SERVER_ACTOR_NAME) { - AccountModel.cache[name] = account - } + return AccountModel.findOne(query) + } - return account - }) + return ModelCache.Instance.doCache({ + cacheType: 'local-account-name', + key: name, + fun, + // The server actor never change, so we can easily cache it + whitelist: () => name === SERVER_ACTOR_NAME + }) } - static loadByNameAndHost (name: string, host: string): Bluebird { + static loadByNameAndHost (name: string, host: string): Promise { const query = { include: [ { @@ -313,7 +325,7 @@ export class AccountModel extends Model { return AccountModel.findOne(query) } - static loadByUrl (url: string, transaction?: Transaction): Bluebird { + static loadByUrl (url: string, transaction?: Transaction): Promise { const query = { include: [ { @@ -346,7 +358,30 @@ export class AccountModel extends Model { }) } - static listLocalsForSitemap (sort: string): Bluebird { + static loadAccountIdFromVideo (videoId: number): Promise { + const query = { + include: [ + { + attributes: [ 'id', 'accountId' ], + model: VideoChannelModel.unscoped(), + required: true, + include: [ + { + attributes: [ 'id', 'channelId' ], + model: VideoModel.unscoped(), + where: { + id: videoId + } + } + ] + } + ] + } + + return AccountModel.findOne(query) + } + + static listLocalsForSitemap (sort: string): Promise { const query = { attributes: [ ], offset: 0, @@ -367,13 +402,16 @@ export class AccountModel extends Model { .findAll(query) } + getClientUrl () { + return WEBSERVER.URL + '/accounts/' + this.Actor.getIdentifier() + } + toFormattedJSON (this: MAccountFormattable): Account { const actor = this.Actor.toFormattedJSON() const account = { id: this.id, displayName: this.getDisplayName(), description: this.description, - createdAt: this.createdAt, updatedAt: this.updatedAt, userId: this.userId ? this.userId : undefined } @@ -414,7 +452,11 @@ export class AccountModel extends Model { return this.name } + getLocalUrl (this: MAccountActor | MChannelActor) { + return WEBSERVER.URL + `/accounts/` + this.Actor.preferredUsername + } + isBlocked () { - return this.BlockedAccounts && this.BlockedAccounts.length !== 0 + return this.BlockedBy && this.BlockedBy.length !== 0 } }