Add more COMMENTS

This commit is contained in:
Jesse Wierzbinski 2023-09-28 08:19:21 -10:00
parent 1fb4600445
commit 8a8d15810b
8 changed files with 289 additions and 46 deletions

View file

@ -3,41 +3,57 @@ import { APIApplication } from "~types/entities/application";
import { Token } from "./Token";
/**
* Applications from clients
* Represents an application that can authenticate with the API.
*/
/**
* Represents an application that can authenticate with the API.
*/
@Entity({
name: "applications",
})
export class Application extends BaseEntity {
/** The unique identifier for this application. */
@PrimaryGeneratedColumn("uuid")
id!: string;
/** The name of this application. */
@Column("varchar")
name!: string;
/** The website associated with this application, if any. */
@Column("varchar", {
nullable: true,
})
website!: string | null;
/** The VAPID key associated with this application, if any. */
@Column("varchar", {
nullable: true,
})
vapid_key!: string | null;
/** The client ID associated with this application. */
@Column("varchar")
client_id!: string;
/** The secret associated with this application. */
@Column("varchar")
secret!: string;
/** The scopes associated with this application. */
@Column("varchar")
scopes = "read";
/** The redirect URIs associated with this application. */
@Column("varchar")
redirect_uris = "urn:ietf:wg:oauth:2.0:oob";
static async getFromToken(token: string) {
/**
* Retrieves the application associated with the given access token.
* @param token The access token to retrieve the application for.
* @returns The application associated with the given access token, or null if no such application exists.
*/
static async getFromToken(token: string): Promise<Application | null> {
const dbToken = await Token.findOne({
where: {
access_token: token,
@ -48,6 +64,10 @@ export class Application extends BaseEntity {
return dbToken?.application || null;
}
/**
* Converts this application to an API application.
* @returns The API application representation of this application.
*/
// eslint-disable-next-line @typescript-eslint/require-await
async toAPI(): Promise<APIApplication> {
return {

View file

@ -1,22 +1,41 @@
import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm";
import { APIEmoji } from "~types/entities/emoji";
/**
* Represents an emoji entity in the database.
*/
@Entity({
name: "emojis",
})
export class Emoji extends BaseEntity {
/**
* The unique identifier for the emoji.
*/
@PrimaryGeneratedColumn("uuid")
id!: string;
/**
* The shortcode for the emoji.
*/
@Column("varchar")
shortcode!: string;
/**
* The URL for the emoji.
*/
@Column("varchar")
url!: string;
/**
* Whether the emoji is visible in the picker.
*/
@Column("boolean")
visible_in_picker!: boolean;
/**
* Converts the emoji to an APIEmoji object.
* @returns The APIEmoji object.
*/
// eslint-disable-next-line @typescript-eslint/require-await
async toAPI(): Promise<APIEmoji> {
return {

View file

@ -8,16 +8,28 @@ import {
import { APIInstance } from "~types/entities/instance";
import { User } from "./User";
/**
* Represents an instance in the database.
*/
@Entity({
name: "instances",
})
export class Instance extends BaseEntity {
/**
* The unique identifier of the instance.
*/
@PrimaryGeneratedColumn("uuid")
id!: string;
/**
* The contact account associated with the instance.
*/
@ManyToOne(() => User, user => user.id)
contact_account!: User;
/**
* The configuration of the instance.
*/
@Column("jsonb", {
default: {
media_attachments: {
@ -43,6 +55,10 @@ export class Instance extends BaseEntity {
})
configuration!: APIInstance["configuration"];
/**
* Converts the instance to an API instance.
* @returns The API instance.
*/
async toAPI(): Promise<APIInstance> {
return {
uri: "",

View file

@ -8,18 +8,29 @@ import { APIAccount } from "~types/entities/account";
import { APIEmoji } from "~types/entities/emoji";
/**
* Stores an ActivityPub object as raw JSON-LD data
* Represents a raw ActivityPub object in the database.
*/
@Entity({
name: "objects",
})
export class RawObject extends BaseEntity {
/**
* The unique identifier of the object.
*/
@PrimaryGeneratedColumn("uuid")
id!: string;
/**
* The data associated with the object.
*/
@Column("jsonb")
data!: APObject;
/**
* Retrieves a RawObject instance by its ID.
* @param id The ID of the RawObject to retrieve.
* @returns A Promise that resolves to the RawObject instance, or undefined if not found.
*/
static async getById(id: string) {
return await RawObject.createQueryBuilder("object")
.where("object.data->>'id' = :id", {
@ -28,6 +39,10 @@ export class RawObject extends BaseEntity {
.getOne();
}
/**
* Parses the emojis associated with the object.
* @returns A Promise that resolves to an array of APIEmoji objects.
*/
// eslint-disable-next-line @typescript-eslint/require-await
async parseEmojis() {
const emojis = this.data.tag as {
@ -51,6 +66,10 @@ export class RawObject extends BaseEntity {
})) as APIEmoji[];
}
/**
* Converts the RawObject instance to an APIStatus object.
* @returns A Promise that resolves to the APIStatus object.
*/
async toAPI(): Promise<APIStatus> {
const mentions = (
await Promise.all(
@ -101,6 +120,10 @@ export class RawObject extends BaseEntity {
};
}
/**
* Determines whether the object is filtered based on the note filters in the configuration.
* @returns A Promise that resolves to a boolean indicating whether the object is filtered.
*/
async isObjectFiltered() {
const config = getConfig();
@ -130,6 +153,11 @@ export class RawObject extends BaseEntity {
return filter_result.includes(true);
}
/**
* Determines whether a RawObject instance with the given ID exists in the database.
* @param id The ID of the RawObject to check for existence.
* @returns A Promise that resolves to a boolean indicating whether the RawObject exists.
*/
static async exists(id: string) {
return !!(await RawObject.getById(id));
}

View file

@ -17,61 +17,85 @@ import { APIRelationship } from "~types/entities/relationship";
name: "relationships",
})
export class Relationship extends BaseEntity {
/** The unique identifier for the relationship. */
@PrimaryGeneratedColumn("uuid")
id!: string;
/** The user who owns the relationship. */
@ManyToOne(() => User, user => user.relationships)
owner!: User;
/** The user who is the subject of the relationship. */
@ManyToOne(() => User)
subject!: User;
/** Whether the owner is following the subject. */
@Column("boolean")
following!: boolean;
/** Whether the owner is showing reblogs from the subject. */
@Column("boolean")
showing_reblogs!: boolean;
/** Whether the owner is receiving notifications from the subject. */
@Column("boolean")
notifying!: boolean;
/** Whether the owner is followed by the subject. */
@Column("boolean")
followed_by!: boolean;
/** Whether the owner is blocking the subject. */
@Column("boolean")
blocking!: boolean;
/** Whether the owner is blocked by the subject. */
@Column("boolean")
blocked_by!: boolean;
/** Whether the owner is muting the subject. */
@Column("boolean")
muting!: boolean;
/** Whether the owner is muting notifications from the subject. */
@Column("boolean")
muting_notifications!: boolean;
/** Whether the owner has requested to follow the subject. */
@Column("boolean")
requested!: boolean;
/** Whether the owner is blocking the subject's domain. */
@Column("boolean")
domain_blocking!: boolean;
/** Whether the owner has endorsed the subject. */
@Column("boolean")
endorsed!: boolean;
/** The languages the owner has specified for the subject. */
@Column("jsonb")
languages!: string[];
/** A note the owner has added for the subject. */
@Column("varchar")
note!: string;
/** The date the relationship was created. */
@CreateDateColumn()
created_at!: Date;
/** The date the relationship was last updated. */
@UpdateDateColumn()
updated_at!: Date;
static async createNew(owner: User, other: User) {
/**
* Creates a new relationship between two users.
* @param owner The user who owns the relationship.
* @param other The user who is the subject of the relationship.
* @returns The newly created relationship.
*/
static async createNew(owner: User, other: User): Promise<Relationship> {
const newRela = new Relationship();
newRela.owner = owner;
newRela.subject = other;
@ -94,6 +118,10 @@ export class Relationship extends BaseEntity {
return newRela;
}
/**
* Converts the relationship to an API-friendly format.
* @returns The API-friendly relationship.
*/
// eslint-disable-next-line @typescript-eslint/require-await
async toAPI(): Promise<APIRelationship> {
return {

View file

@ -22,81 +22,137 @@ import { RawActor } from "./RawActor";
const config = getConfig();
/**
* Stores ActivityPub notes
* Represents a status (i.e. a post)
*/
@Entity({
name: "statuses",
})
export class Status extends BaseEntity {
/**
* The unique identifier for this status.
*/
@PrimaryGeneratedColumn("uuid")
id!: string;
/**
* The user account that created this status.
*/
@ManyToOne(() => User, user => user.id)
account!: User;
/**
* The date and time when this status was created.
*/
@CreateDateColumn()
created_at!: Date;
/**
* The date and time when this status was last updated.
*/
@UpdateDateColumn()
updated_at!: Date;
/**
* The status that this status is a reblog of, if any.
*/
@ManyToOne(() => Status, status => status.id, {
nullable: true,
})
reblog?: Status;
/**
* The raw object associated with this status.
*/
@ManyToOne(() => RawObject, {
nullable: true,
onDelete: "SET NULL",
})
object!: RawObject;
/**
* Whether this status is a reblog.
*/
@Column("boolean")
isReblog!: boolean;
/**
* The content of this status.
*/
@Column("varchar", {
default: "",
})
content!: string;
/**
* The visibility of this status.
*/
@Column("varchar")
visibility!: APIStatus["visibility"];
/**
* The raw object that this status is a reply to, if any.
*/
@ManyToOne(() => RawObject, {
nullable: true,
})
in_reply_to_post!: RawObject | null;
/**
* The raw actor that this status is a reply to, if any.
*/
@ManyToOne(() => RawActor, {
nullable: true,
})
in_reply_to_account!: RawActor | null;
/**
* Whether this status is sensitive.
*/
@Column("boolean")
sensitive!: boolean;
/**
* The spoiler text for this status.
*/
@Column("varchar", {
default: "",
})
spoiler_text!: string;
/**
* The application associated with this status, if any.
*/
@ManyToOne(() => Application, app => app.id, {
nullable: true,
})
application!: Application | null;
/**
* The emojis associated with this status.
*/
@ManyToMany(() => Emoji, emoji => emoji.id)
@JoinTable()
emojis!: Emoji[];
/**
* The activities that have liked this status.
*/
@ManyToMany(() => RawActivity, activity => activity.id)
@JoinTable()
likes!: RawActivity[];
/**
* The activities that have announced this status.
*/
@ManyToMany(() => RawActivity, activity => activity.id)
@JoinTable()
announces!: RawActivity[];
/**
* Removes this status from the database.
* @param options The options for removing this status.
* @returns A promise that resolves when the status has been removed.
*/
async remove(options?: RemoveOptions | undefined) {
// Delete object
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@ -105,6 +161,11 @@ export class Status extends BaseEntity {
return await super.remove(options);
}
/**
* Creates a new status and saves it to the database.
* @param data The data for the new status.
* @returns A promise that resolves with the new status.
*/
static async createNew(data: {
account: User;
application: Application | null;
@ -233,40 +294,11 @@ export class Status extends BaseEntity {
return newStatus;
}
/**
* Converts this status to an API status.
* @returns A promise that resolves with the API status.
*/
async toAPI(): Promise<APIStatus> {
return await this.object.toAPI();
/* return {
account: await this.account.toAPI(),
application: (await this.application?.toAPI()) ?? null,
bookmarked: false,
created_at: this.created_at.toISOString(),
emojis: await Promise.all(
this.emojis.map(async emoji => await emoji.toAPI())
),
favourited: false,
favourites_count: this.likes.length,
id: this.object.id,
in_reply_to_account_id: null,
in_reply_to_id: null,
language: null,
media_attachments: [],
mentions: [],
muted: false,
pinned: false,
poll: null,
reblog: this.isReblog ? (await this.reblog?.toAPI()) ?? null : null,
reblogged: false,
reblogs_count: this.announces.length,
replies_count: 0,
sensitive: false,
spoiler_text: "",
tags: [],
card: null,
content: this.content,
uri: `${config.http.base_url}/@${this.account.username}/${this.id}`,
url: `${config.http.base_url}/@${this.account.username}/${this.id}`,
visibility: "public",
quote: null,
}; */
}
}

View file

@ -9,35 +9,49 @@ import {
import { User } from "./User";
import { Application } from "./Application";
export enum TokenType {
BEARER = "Bearer",
}
/**
* Represents an access token for a user or application.
*/
@Entity({
name: "tokens",
})
export class Token extends BaseEntity {
/** The unique identifier for the token. */
@PrimaryGeneratedColumn("uuid")
id!: string;
/** The type of token. */
@Column("varchar")
token_type: TokenType = TokenType.BEARER;
/** The scope of the token. */
@Column("varchar")
scope!: string;
/** The access token string. */
@Column("varchar")
access_token!: string;
/** The authorization code used to obtain the token. */
@Column("varchar")
code!: string;
/** The date and time the token was created. */
@CreateDateColumn()
created_at!: Date;
/** The user associated with the token. */
@ManyToOne(() => User, user => user.id)
user!: User;
/** The application associated with the token. */
@ManyToOne(() => Application, application => application.id)
application!: Application;
}
/**
* The type of token.
*/
enum TokenType {
BEARER = "bearer",
}

View file

@ -24,72 +24,129 @@ import { Relationship } from "./Relationship";
const config = getConfig();
/**
* Represents a user in the database.
* Stores local and remote users
*/
@Entity({
name: "users",
})
export class User extends BaseEntity {
/**
* The unique identifier for the user.
*/
@PrimaryGeneratedColumn("uuid")
id!: string;
/**
* The username for the user.
*/
@Column("varchar", {
unique: true,
})
username!: string;
/**
* The display name for the user.
*/
@Column("varchar")
display_name!: string;
/**
* The password for the user.
*/
@Column("varchar")
password!: string;
/**
* The email address for the user.
*/
@Column("varchar", {
unique: true,
})
email!: string;
/**
* The note for the user.
*/
@Column("varchar", {
default: "",
})
note!: string;
/**
* Whether the user is an admin or not.
*/
@Column("boolean", {
default: false,
})
is_admin!: boolean;
/**
* The source for the user.
*/
@Column("jsonb")
source!: APISource;
/**
* The avatar for the user.
*/
@Column("varchar")
avatar!: string;
/**
* The header for the user.
*/
@Column("varchar")
header!: string;
/**
* The date the user was created.
*/
@CreateDateColumn()
created_at!: Date;
/**
* The date the user was last updated.
*/
@UpdateDateColumn()
updated_at!: Date;
/**
* The public key for the user.
*/
@Column("varchar")
public_key!: string;
/**
* The private key for the user.
*/
@Column("varchar")
private_key!: string;
/**
* The relationships for the user.
*/
@OneToMany(() => Relationship, relationship => relationship.owner)
relationships!: Relationship[];
/**
* The actor for the user.
*/
@ManyToOne(() => RawActor, actor => actor.id)
actor!: RawActor;
/**
* The pinned notes for the user.
*/
@ManyToMany(() => RawObject, object => object.id)
@JoinTable()
pinned_notes!: RawObject[];
/**
* Gets a user by actor ID.
* @param id The actor ID to search for.
* @returns The user with the given actor ID.
*/
static async getByActorId(id: string) {
return await User.createQueryBuilder("user")
// Objects is a many-to-many relationship
@ -103,6 +160,11 @@ export class User extends BaseEntity {
.getOne();
}
/**
* Creates a new user.
* @param data The data for the new user.
* @returns The newly created user.
*/
static async createNew(data: {
username: string;
display_name?: string;
@ -140,6 +202,11 @@ export class User extends BaseEntity {
return user;
}
/**
* 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.
*/
static async retrieveFromToken(access_token: string) {
if (!access_token) return null;
@ -160,6 +227,11 @@ export class User extends BaseEntity {
return token.user;
}
/**
* Gets the relationship to another user.
* @param other The other user to get the relationship to.
* @returns The relationship to the other user.
*/
async getRelationshipToOtherUser(other: User) {
const relationship = await Relationship.findOne({
where: {
@ -176,6 +248,11 @@ export class User extends BaseEntity {
return relationship;
}
/**
* Removes the user.
* @param options The options for removing the user.
* @returns The removed user.
*/
async remove(options?: RemoveOptions | undefined) {
// Clean up tokens
const tokens = await Token.findBy({
@ -210,6 +287,10 @@ export class User extends BaseEntity {
return await super.remove(options);
}
/**
* Gets the relationships for the user.
* @returns The relationships for the user.
*/
async getRelationships() {
const relationships = await Relationship.find({
where: {
@ -223,12 +304,14 @@ export class User extends BaseEntity {
return relationships;
}
/**
* Updates the actor for the user.
* @returns The updated actor.
*/
async updateActor() {
const config = getConfig();
// Check if actor exists
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
// Check is actor already exists
const actorExists = await RawActor.getByActorId(
`${config.http.base_url}/@${this.username}`
);
@ -278,6 +361,9 @@ export class User extends BaseEntity {
return actor;
}
/**
* Generates keys for the user.
*/
async generateKeys(): Promise<void> {
// openssl genrsa -out private.pem 2048
// openssl rsa -in private.pem -outform PEM -pubout -out public.pem