2023-09-29 01:58:05 +02:00
|
|
|
import { getConfig } from "@config";
|
2023-09-13 02:29:13 +02:00
|
|
|
import {
|
|
|
|
|
BaseEntity,
|
|
|
|
|
Column,
|
|
|
|
|
CreateDateColumn,
|
|
|
|
|
Entity,
|
2023-09-18 22:29:56 +02:00
|
|
|
JoinTable,
|
|
|
|
|
ManyToMany,
|
|
|
|
|
ManyToOne,
|
2023-09-22 05:18:05 +02:00
|
|
|
OneToMany,
|
2023-09-13 02:29:13 +02:00
|
|
|
PrimaryGeneratedColumn,
|
2023-09-27 01:08:05 +02:00
|
|
|
RemoveOptions,
|
2023-09-13 02:29:13 +02:00
|
|
|
UpdateDateColumn,
|
|
|
|
|
} from "typeorm";
|
2023-09-12 22:48:10 +02:00
|
|
|
import { APIAccount } from "~types/entities/account";
|
2023-09-18 22:29:56 +02:00
|
|
|
import { RawActor } from "./RawActor";
|
2023-10-08 22:20:42 +02:00
|
|
|
import { APActor, APOrderedCollectionPage } from "activitypub-types";
|
2023-09-20 02:16:50 +02:00
|
|
|
import { RawObject } from "./RawObject";
|
2023-09-22 03:09:14 +02:00
|
|
|
import { Token } from "./Token";
|
|
|
|
|
import { Status } from "./Status";
|
2023-09-22 04:15:12 +02:00
|
|
|
import { APISource } from "~types/entities/source";
|
2023-09-22 05:18:05 +02:00
|
|
|
import { Relationship } from "./Relationship";
|
2023-10-08 22:20:42 +02:00
|
|
|
import { Instance } from "./Instance";
|
2023-09-11 05:54:14 +02:00
|
|
|
|
2023-09-12 22:48:10 +02:00
|
|
|
/**
|
2023-09-28 20:19:21 +02:00
|
|
|
* Represents a user in the database.
|
2023-09-12 22:48:10 +02:00
|
|
|
* Stores local and remote users
|
|
|
|
|
*/
|
2023-09-11 05:31:08 +02:00
|
|
|
@Entity({
|
|
|
|
|
name: "users",
|
|
|
|
|
})
|
2023-09-12 22:48:10 +02:00
|
|
|
export class User extends BaseEntity {
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The unique identifier for the user.
|
|
|
|
|
*/
|
2023-09-11 05:31:08 +02:00
|
|
|
@PrimaryGeneratedColumn("uuid")
|
|
|
|
|
id!: string;
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The username for the user.
|
|
|
|
|
*/
|
2023-09-11 05:54:14 +02:00
|
|
|
@Column("varchar", {
|
|
|
|
|
unique: true,
|
|
|
|
|
})
|
2023-09-11 05:31:08 +02:00
|
|
|
username!: string;
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The display name for the user.
|
|
|
|
|
*/
|
2023-09-22 05:18:05 +02:00
|
|
|
@Column("varchar")
|
2023-09-13 07:30:45 +02:00
|
|
|
display_name!: string;
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The password for the user.
|
|
|
|
|
*/
|
2023-10-08 22:20:42 +02:00
|
|
|
@Column("varchar", {
|
|
|
|
|
nullable: true,
|
|
|
|
|
})
|
|
|
|
|
password!: string | null;
|
2023-09-11 05:31:08 +02:00
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The email address for the user.
|
|
|
|
|
*/
|
2023-09-11 05:54:14 +02:00
|
|
|
@Column("varchar", {
|
|
|
|
|
unique: true,
|
2023-10-08 22:20:42 +02:00
|
|
|
nullable: true,
|
2023-09-11 05:54:14 +02:00
|
|
|
})
|
2023-10-08 22:20:42 +02:00
|
|
|
email!: string | null;
|
2023-09-11 05:54:14 +02:00
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The note for the user.
|
|
|
|
|
*/
|
2023-09-11 05:54:14 +02:00
|
|
|
@Column("varchar", {
|
|
|
|
|
default: "",
|
|
|
|
|
})
|
2023-09-18 22:29:56 +02:00
|
|
|
note!: string;
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* Whether the user is an admin or not.
|
|
|
|
|
*/
|
2023-09-18 22:29:56 +02:00
|
|
|
@Column("boolean", {
|
|
|
|
|
default: false,
|
|
|
|
|
})
|
|
|
|
|
is_admin!: boolean;
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The source for the user.
|
|
|
|
|
*/
|
2023-09-22 04:15:12 +02:00
|
|
|
@Column("jsonb")
|
|
|
|
|
source!: APISource;
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The avatar for the user.
|
|
|
|
|
*/
|
2023-09-18 22:29:56 +02:00
|
|
|
@Column("varchar")
|
|
|
|
|
avatar!: string;
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The header for the user.
|
|
|
|
|
*/
|
2023-09-18 22:29:56 +02:00
|
|
|
@Column("varchar")
|
|
|
|
|
header!: string;
|
2023-09-11 05:54:14 +02:00
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The date the user was created.
|
|
|
|
|
*/
|
2023-09-11 05:31:08 +02:00
|
|
|
@CreateDateColumn()
|
|
|
|
|
created_at!: Date;
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The date the user was last updated.
|
|
|
|
|
*/
|
2023-09-11 05:31:08 +02:00
|
|
|
@UpdateDateColumn()
|
|
|
|
|
updated_at!: Date;
|
2023-09-11 05:54:14 +02:00
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The public key for the user.
|
|
|
|
|
*/
|
2023-09-18 07:38:08 +02:00
|
|
|
@Column("varchar")
|
|
|
|
|
public_key!: string;
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The private key for the user.
|
|
|
|
|
*/
|
2023-10-08 22:20:42 +02:00
|
|
|
@Column("varchar", {
|
|
|
|
|
nullable: true,
|
|
|
|
|
})
|
|
|
|
|
private_key!: string | null;
|
2023-09-18 07:38:08 +02:00
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The relationships for the user.
|
|
|
|
|
*/
|
2023-09-22 05:18:05 +02:00
|
|
|
@OneToMany(() => Relationship, relationship => relationship.owner)
|
|
|
|
|
relationships!: Relationship[];
|
|
|
|
|
|
2023-10-08 22:20:42 +02:00
|
|
|
/**
|
|
|
|
|
* User's instance, null if local user
|
|
|
|
|
*/
|
|
|
|
|
@ManyToOne(() => Instance, {
|
|
|
|
|
nullable: true,
|
|
|
|
|
})
|
|
|
|
|
instance!: Instance | null;
|
|
|
|
|
|
|
|
|
|
/** */
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The actor for the user.
|
|
|
|
|
*/
|
2023-09-18 22:29:56 +02:00
|
|
|
@ManyToOne(() => RawActor, actor => actor.id)
|
|
|
|
|
actor!: RawActor;
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* The pinned notes for the user.
|
|
|
|
|
*/
|
2023-09-20 02:16:50 +02:00
|
|
|
@ManyToMany(() => RawObject, object => object.id)
|
|
|
|
|
@JoinTable()
|
|
|
|
|
pinned_notes!: RawObject[];
|
|
|
|
|
|
2023-10-16 05:51:29 +02:00
|
|
|
static async getFromRequest(req: Request) {
|
|
|
|
|
// Check auth token
|
|
|
|
|
const token = req.headers.get("Authorization")?.split(" ")[1] || "";
|
|
|
|
|
|
|
|
|
|
return { user: await User.retrieveFromToken(token), token };
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-08 22:20:42 +02:00
|
|
|
/**
|
|
|
|
|
* Update this user data from its actor
|
|
|
|
|
* @returns The updated user.
|
|
|
|
|
*/
|
|
|
|
|
async updateFromActor() {
|
|
|
|
|
const actor = await this.actor.toAPIAccount();
|
|
|
|
|
|
|
|
|
|
this.username = actor.username;
|
|
|
|
|
this.display_name = actor.display_name;
|
|
|
|
|
this.note = actor.note;
|
|
|
|
|
this.avatar = actor.avatar;
|
|
|
|
|
this.header = actor.header;
|
|
|
|
|
this.avatar = actor.avatar;
|
|
|
|
|
|
|
|
|
|
return await this.save();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fetches the list of followers associated with the actor and updates the user's followers
|
|
|
|
|
*/
|
|
|
|
|
async fetchFollowers() {
|
|
|
|
|
let followers: APOrderedCollectionPage = await fetch(
|
|
|
|
|
`${this.actor.data.followers?.toString() ?? ""}?page=1`,
|
|
|
|
|
{
|
|
|
|
|
headers: { Accept: "application/activity+json" },
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let followersList = followers.orderedItems ?? [];
|
|
|
|
|
|
|
|
|
|
while (followers.type === "OrderedCollectionPage" && followers.next) {
|
|
|
|
|
followers = await fetch((followers.next as string).toString(), {
|
|
|
|
|
headers: { Accept: "application/activity+json" },
|
|
|
|
|
}).then(res => res.json());
|
|
|
|
|
|
|
|
|
|
followersList = {
|
|
|
|
|
...followersList,
|
|
|
|
|
...(followers.orderedItems ?? []),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: integrate followers
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* Gets a user by actor ID.
|
|
|
|
|
* @param id The actor ID to search for.
|
|
|
|
|
* @returns The user with the given actor ID.
|
|
|
|
|
*/
|
2023-09-18 22:29:56 +02:00
|
|
|
static async getByActorId(id: string) {
|
|
|
|
|
return await User.createQueryBuilder("user")
|
|
|
|
|
// Objects is a many-to-many relationship
|
|
|
|
|
.leftJoinAndSelect("user.actor", "actor")
|
2023-09-22 05:18:05 +02:00
|
|
|
.leftJoinAndSelect("user.relationships", "relationships")
|
2023-09-18 22:29:56 +02:00
|
|
|
.where("actor.data @> :data", {
|
|
|
|
|
data: JSON.stringify({
|
|
|
|
|
id,
|
|
|
|
|
}),
|
|
|
|
|
})
|
|
|
|
|
.getOne();
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
2023-10-08 22:20:42 +02:00
|
|
|
* Creates a new LOCAL user.
|
2023-09-28 20:19:21 +02:00
|
|
|
* @param data The data for the new user.
|
|
|
|
|
* @returns The newly created user.
|
|
|
|
|
*/
|
2023-10-08 22:20:42 +02:00
|
|
|
static async createNewLocal(data: {
|
2023-09-18 22:29:56 +02:00
|
|
|
username: string;
|
|
|
|
|
display_name?: string;
|
|
|
|
|
password: string;
|
|
|
|
|
email: string;
|
|
|
|
|
bio?: string;
|
|
|
|
|
avatar?: string;
|
|
|
|
|
header?: string;
|
|
|
|
|
}) {
|
|
|
|
|
const config = getConfig();
|
|
|
|
|
const user = new User();
|
|
|
|
|
|
|
|
|
|
user.username = data.username;
|
|
|
|
|
user.display_name = data.display_name ?? data.username;
|
|
|
|
|
user.password = await Bun.password.hash(data.password);
|
|
|
|
|
user.email = data.email;
|
|
|
|
|
user.note = data.bio ?? "";
|
|
|
|
|
user.avatar = data.avatar ?? config.defaults.avatar;
|
|
|
|
|
user.header = data.header ?? config.defaults.avatar;
|
|
|
|
|
|
2023-09-22 05:18:05 +02:00
|
|
|
user.relationships = [];
|
2023-10-08 22:20:42 +02:00
|
|
|
user.instance = null;
|
2023-09-22 05:18:05 +02:00
|
|
|
|
2023-09-22 04:15:12 +02:00
|
|
|
user.source = {
|
|
|
|
|
language: null,
|
|
|
|
|
note: "",
|
|
|
|
|
privacy: "public",
|
|
|
|
|
sensitive: false,
|
|
|
|
|
fields: [],
|
|
|
|
|
};
|
|
|
|
|
|
2023-09-18 22:29:56 +02:00
|
|
|
await user.generateKeys();
|
|
|
|
|
await user.updateActor();
|
|
|
|
|
|
|
|
|
|
await user.save();
|
|
|
|
|
return user;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* Retrieves a user from a token.
|
|
|
|
|
* @param access_token The access token to retrieve the user from.
|
|
|
|
|
* @returns The user associated with the given access token.
|
|
|
|
|
*/
|
2023-09-27 00:33:43 +02:00
|
|
|
static async retrieveFromToken(access_token: string) {
|
|
|
|
|
if (!access_token) return null;
|
|
|
|
|
|
|
|
|
|
const token = await Token.findOne({
|
|
|
|
|
where: {
|
|
|
|
|
access_token,
|
|
|
|
|
},
|
|
|
|
|
relations: {
|
|
|
|
|
user: {
|
|
|
|
|
relationships: true,
|
2023-09-27 20:45:07 +02:00
|
|
|
actor: true,
|
2023-09-27 00:33:43 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!token) return null;
|
|
|
|
|
|
|
|
|
|
return token.user;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* Gets the relationship to another user.
|
|
|
|
|
* @param other The other user to get the relationship to.
|
|
|
|
|
* @returns The relationship to the other user.
|
|
|
|
|
*/
|
2023-09-22 05:18:05 +02:00
|
|
|
async getRelationshipToOtherUser(other: User) {
|
|
|
|
|
const relationship = await Relationship.findOne({
|
|
|
|
|
where: {
|
|
|
|
|
owner: {
|
|
|
|
|
id: this.id,
|
|
|
|
|
},
|
|
|
|
|
subject: {
|
|
|
|
|
id: other.id,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
relations: ["owner", "subject"],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return relationship;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* Removes the user.
|
|
|
|
|
* @param options The options for removing the user.
|
|
|
|
|
* @returns The removed user.
|
|
|
|
|
*/
|
2023-09-27 01:08:05 +02:00
|
|
|
async remove(options?: RemoveOptions | undefined) {
|
2023-09-22 03:09:14 +02:00
|
|
|
// Clean up tokens
|
|
|
|
|
const tokens = await Token.findBy({
|
|
|
|
|
user: {
|
|
|
|
|
id: this.id,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2023-09-27 01:08:05 +02:00
|
|
|
const statuses = await Status.find({
|
|
|
|
|
where: {
|
|
|
|
|
account: {
|
|
|
|
|
id: this.id,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
relations: {
|
|
|
|
|
object: true,
|
2023-09-22 03:09:14 +02:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Delete both
|
|
|
|
|
await Promise.all(tokens.map(async token => await token.remove()));
|
|
|
|
|
|
|
|
|
|
await Promise.all(statuses.map(async status => await status.remove()));
|
2023-09-22 05:18:05 +02:00
|
|
|
|
|
|
|
|
// Get relationships
|
|
|
|
|
const relationships = await this.getRelationships();
|
|
|
|
|
// Delete them all
|
|
|
|
|
await Promise.all(
|
|
|
|
|
relationships.map(async relationship => await relationship.remove())
|
|
|
|
|
);
|
2023-09-27 01:08:05 +02:00
|
|
|
|
|
|
|
|
return await super.remove(options);
|
2023-09-22 05:18:05 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* Gets the relationships for the user.
|
|
|
|
|
* @returns The relationships for the user.
|
|
|
|
|
*/
|
2023-09-22 05:18:05 +02:00
|
|
|
async getRelationships() {
|
|
|
|
|
const relationships = await Relationship.find({
|
|
|
|
|
where: {
|
|
|
|
|
owner: {
|
|
|
|
|
id: this.id,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
relations: ["subject"],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return relationships;
|
2023-09-22 03:09:14 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* Updates the actor for the user.
|
|
|
|
|
* @returns The updated actor.
|
|
|
|
|
*/
|
2023-09-18 22:29:56 +02:00
|
|
|
async updateActor() {
|
2023-09-28 20:19:21 +02:00
|
|
|
const config = getConfig();
|
2023-09-27 20:45:07 +02:00
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
// Check if actor exists
|
2023-09-27 20:45:07 +02:00
|
|
|
const actorExists = await RawActor.getByActorId(
|
2023-10-16 08:04:03 +02:00
|
|
|
`${config.http.base_url}/users/${this.username}`
|
2023-09-27 20:45:07 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let actor: RawActor;
|
|
|
|
|
|
|
|
|
|
if (actorExists) {
|
|
|
|
|
actor = actorExists;
|
|
|
|
|
} else {
|
|
|
|
|
actor = new RawActor();
|
|
|
|
|
}
|
2023-09-18 22:29:56 +02:00
|
|
|
|
|
|
|
|
actor.data = {
|
|
|
|
|
"@context": [
|
|
|
|
|
"https://www.w3.org/ns/activitystreams",
|
|
|
|
|
"https://w3id.org/security/v1",
|
|
|
|
|
],
|
2023-10-16 08:04:03 +02:00
|
|
|
id: `${config.http.base_url}/users/${this.username}`,
|
2023-09-18 22:29:56 +02:00
|
|
|
type: "Person",
|
|
|
|
|
preferredUsername: this.username,
|
|
|
|
|
name: this.display_name,
|
2023-10-16 08:04:03 +02:00
|
|
|
inbox: `${config.http.base_url}/users/${this.username}/inbox`,
|
|
|
|
|
outbox: `${config.http.base_url}/users/${this.username}/outbox`,
|
|
|
|
|
followers: `${config.http.base_url}/users/${this.username}/followers`,
|
|
|
|
|
following: `${config.http.base_url}/users/${this.username}/following`,
|
2023-09-18 22:29:56 +02:00
|
|
|
manuallyApprovesFollowers: false,
|
|
|
|
|
summary: this.note,
|
|
|
|
|
icon: {
|
|
|
|
|
type: "Image",
|
|
|
|
|
url: this.avatar,
|
|
|
|
|
},
|
|
|
|
|
image: {
|
|
|
|
|
type: "Image",
|
|
|
|
|
url: this.header,
|
|
|
|
|
},
|
|
|
|
|
publicKey: {
|
2023-10-16 08:04:03 +02:00
|
|
|
id: `${config.http.base_url}/users/${this.username}/actor#main-key`,
|
|
|
|
|
owner: `${config.http.base_url}/users/${this.username}/actor`,
|
2023-09-18 22:29:56 +02:00
|
|
|
publicKeyPem: this.public_key,
|
|
|
|
|
},
|
|
|
|
|
} as APActor;
|
|
|
|
|
|
|
|
|
|
await actor.save();
|
|
|
|
|
|
|
|
|
|
this.actor = actor;
|
|
|
|
|
await this.save();
|
|
|
|
|
return actor;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-28 20:19:21 +02:00
|
|
|
/**
|
|
|
|
|
* Generates keys for the user.
|
|
|
|
|
*/
|
2023-09-18 07:38:08 +02:00
|
|
|
async generateKeys(): Promise<void> {
|
|
|
|
|
// openssl genrsa -out private.pem 2048
|
|
|
|
|
// openssl rsa -in private.pem -outform PEM -pubout -out public.pem
|
|
|
|
|
|
|
|
|
|
const keys = await crypto.subtle.generateKey(
|
|
|
|
|
{
|
|
|
|
|
name: "RSASSA-PKCS1-v1_5",
|
|
|
|
|
hash: "SHA-256",
|
|
|
|
|
modulusLength: 4096,
|
|
|
|
|
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
["sign", "verify"]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const privateKey = btoa(
|
|
|
|
|
String.fromCharCode.apply(null, [
|
|
|
|
|
...new Uint8Array(
|
2023-09-29 01:58:05 +02:00
|
|
|
// jesus help me what do these letters mean
|
2023-09-18 07:38:08 +02:00
|
|
|
await crypto.subtle.exportKey("pkcs8", keys.privateKey)
|
|
|
|
|
),
|
|
|
|
|
])
|
|
|
|
|
);
|
|
|
|
|
const publicKey = btoa(
|
|
|
|
|
String.fromCharCode(
|
|
|
|
|
...new Uint8Array(
|
2023-09-29 01:58:05 +02:00
|
|
|
// why is exporting a key so hard
|
2023-09-18 07:38:08 +02:00
|
|
|
await crypto.subtle.exportKey("spki", keys.publicKey)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Add header, footer and newlines later on
|
|
|
|
|
// These keys are PEM encrypted
|
|
|
|
|
this.private_key = privateKey;
|
|
|
|
|
this.public_key = publicKey;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-12 22:48:10 +02:00
|
|
|
// eslint-disable-next-line @typescript-eslint/require-await
|
2023-10-08 22:20:42 +02:00
|
|
|
async toAPI(isOwnAccount = false): Promise<APIAccount> {
|
|
|
|
|
const follower_count = await Relationship.count({
|
|
|
|
|
where: {
|
|
|
|
|
subject: {
|
|
|
|
|
id: this.id,
|
|
|
|
|
},
|
|
|
|
|
following: true,
|
|
|
|
|
},
|
|
|
|
|
relations: ["subject"],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const following_count = await Relationship.count({
|
|
|
|
|
where: {
|
|
|
|
|
owner: {
|
|
|
|
|
id: this.id,
|
|
|
|
|
},
|
|
|
|
|
following: true,
|
|
|
|
|
},
|
|
|
|
|
relations: ["owner"],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
...(await this.actor.toAPIAccount(isOwnAccount)),
|
|
|
|
|
id: this.id,
|
|
|
|
|
followers_count: follower_count,
|
|
|
|
|
following_count: following_count,
|
|
|
|
|
};
|
2023-09-11 05:54:14 +02:00
|
|
|
}
|
2023-09-13 02:29:13 +02:00
|
|
|
}
|