mirror of
https://github.com/versia-pub/server.git
synced 2026-03-13 13:59:16 +01:00
refactor: 🚚 Organize code into sub-packages, instead of a single large package
This commit is contained in:
parent
79742f47dc
commit
a6d3ebbeef
366 changed files with 942 additions and 833 deletions
171
packages/plugin-kit/api-error.ts
Normal file
171
packages/plugin-kit/api-error.ts
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
import type { ContentfulStatusCode } from "hono/utils/http-status";
|
||||
import type { JSONObject } from "hono/utils/types";
|
||||
import type { DescribeRouteOptions } from "hono-openapi";
|
||||
import { resolver } from "hono-openapi/zod";
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* API Error
|
||||
*
|
||||
* Custom error class used to throw errors in the API. Includes a status code, a message and an optional description.
|
||||
* @extends Error
|
||||
*/
|
||||
export class ApiError extends Error {
|
||||
/**
|
||||
* @param {ContentfulStatusCode} status - The status code of the error
|
||||
* @param {string} message - The message of the error
|
||||
* @param {string | JSONObject} [details] - The description of the error
|
||||
*/
|
||||
public constructor(
|
||||
public status: ContentfulStatusCode,
|
||||
public override message: string,
|
||||
public details?: string | JSONObject,
|
||||
) {
|
||||
super(message);
|
||||
this.name = "ApiError";
|
||||
}
|
||||
|
||||
public static zodSchema = z.object({
|
||||
error: z.string(),
|
||||
details: z
|
||||
.string()
|
||||
.or(z.record(z.string(), z.string().or(z.number())))
|
||||
.optional(),
|
||||
});
|
||||
|
||||
public get schema(): NonNullable<
|
||||
DescribeRouteOptions["responses"]
|
||||
>[number] {
|
||||
return {
|
||||
description: this.message,
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(ApiError.zodSchema),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public static missingAuthentication(): ApiError {
|
||||
return new ApiError(
|
||||
401,
|
||||
"Missing authentication",
|
||||
"The Authorization header is missing or could not be parsed.",
|
||||
);
|
||||
}
|
||||
|
||||
public static forbidden(): ApiError {
|
||||
return new ApiError(
|
||||
403,
|
||||
"Missing permissions",
|
||||
"You do not have permission to access or modify this resource.",
|
||||
);
|
||||
}
|
||||
|
||||
public static notFound(): ApiError {
|
||||
return new ApiError(
|
||||
404,
|
||||
"Not found",
|
||||
"The requested resource could not be found.",
|
||||
);
|
||||
}
|
||||
|
||||
public static noteNotFound(): ApiError {
|
||||
return new ApiError(
|
||||
404,
|
||||
"Note not found",
|
||||
"The requested note could not be found.",
|
||||
);
|
||||
}
|
||||
|
||||
public static accountNotFound(): ApiError {
|
||||
return new ApiError(
|
||||
404,
|
||||
"Account not found",
|
||||
"The requested account could not be found.",
|
||||
);
|
||||
}
|
||||
|
||||
public static roleNotFound(): ApiError {
|
||||
return new ApiError(
|
||||
404,
|
||||
"Role not found",
|
||||
"The requested role could not be found.",
|
||||
);
|
||||
}
|
||||
|
||||
public static instanceNotFound(): ApiError {
|
||||
return new ApiError(
|
||||
404,
|
||||
"Instance not found",
|
||||
"The requested instance could not be found.",
|
||||
);
|
||||
}
|
||||
|
||||
public static likeNotFound(): ApiError {
|
||||
return new ApiError(
|
||||
404,
|
||||
"Like not found",
|
||||
"The requested like could not be found.",
|
||||
);
|
||||
}
|
||||
|
||||
public static pushSubscriptionNotFound(): ApiError {
|
||||
return new ApiError(
|
||||
404,
|
||||
"Push subscription not found",
|
||||
"No push subscription associated with this access token",
|
||||
);
|
||||
}
|
||||
|
||||
public static tokenNotFound(): ApiError {
|
||||
return new ApiError(
|
||||
404,
|
||||
"Token not found",
|
||||
"The requested token could not be found.",
|
||||
);
|
||||
}
|
||||
|
||||
public static mediaNotFound(): ApiError {
|
||||
return new ApiError(
|
||||
404,
|
||||
"Media not found",
|
||||
"The requested media could not be found.",
|
||||
);
|
||||
}
|
||||
|
||||
public static applicationNotFound(): ApiError {
|
||||
return new ApiError(
|
||||
404,
|
||||
"Application not found",
|
||||
"The requested application could not be found.",
|
||||
);
|
||||
}
|
||||
|
||||
public static emojiNotFound(): ApiError {
|
||||
return new ApiError(
|
||||
404,
|
||||
"Emoji not found",
|
||||
"The requested emoji could not be found.",
|
||||
);
|
||||
}
|
||||
|
||||
public static notificationNotFound(): ApiError {
|
||||
return new ApiError(
|
||||
404,
|
||||
"Notification not found",
|
||||
"The requested notification could not be found.",
|
||||
);
|
||||
}
|
||||
|
||||
public static validationFailed(): ApiError {
|
||||
return new ApiError(422, "Invalid values in request");
|
||||
}
|
||||
|
||||
public static internalServerError(): ApiError {
|
||||
return new ApiError(
|
||||
500,
|
||||
"Internal server error. This is likely a bug.",
|
||||
);
|
||||
}
|
||||
}
|
||||
164
packages/plugin-kit/db/application.ts
Normal file
164
packages/plugin-kit/db/application.ts
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
import type {
|
||||
Application as ApplicationSchema,
|
||||
CredentialApplication,
|
||||
} from "@versia/client/schemas";
|
||||
import { db, Token } from "@versia/kit/db";
|
||||
import { Applications } from "@versia/kit/tables";
|
||||
import {
|
||||
desc,
|
||||
eq,
|
||||
type InferInsertModel,
|
||||
type InferSelectModel,
|
||||
inArray,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import type { z } from "zod";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
||||
type ApplicationType = InferSelectModel<typeof Applications>;
|
||||
|
||||
export class Application extends BaseInterface<typeof Applications> {
|
||||
public static $type: ApplicationType;
|
||||
|
||||
public async reload(): Promise<void> {
|
||||
const reloaded = await Application.fromId(this.data.id);
|
||||
|
||||
if (!reloaded) {
|
||||
throw new Error("Failed to reload application");
|
||||
}
|
||||
|
||||
this.data = reloaded.data;
|
||||
}
|
||||
|
||||
public static async fromId(id: string | null): Promise<Application | null> {
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Application.fromSql(eq(Applications.id, id));
|
||||
}
|
||||
|
||||
public static async fromIds(ids: string[]): Promise<Application[]> {
|
||||
return await Application.manyFromSql(inArray(Applications.id, ids));
|
||||
}
|
||||
|
||||
public static async fromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Applications.id),
|
||||
): Promise<Application | null> {
|
||||
const found = await db.query.Applications.findFirst({
|
||||
where: sql,
|
||||
orderBy,
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
return new Application(found);
|
||||
}
|
||||
|
||||
public static async manyFromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Applications.id),
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
extra?: Parameters<typeof db.query.Applications.findMany>[0],
|
||||
): Promise<Application[]> {
|
||||
const found = await db.query.Applications.findMany({
|
||||
where: sql,
|
||||
orderBy,
|
||||
limit,
|
||||
offset,
|
||||
with: extra?.with,
|
||||
});
|
||||
|
||||
return found.map((s) => new Application(s));
|
||||
}
|
||||
|
||||
public static async getFromToken(
|
||||
token: string,
|
||||
): Promise<Application | null> {
|
||||
const result = await Token.fromAccessToken(token);
|
||||
|
||||
return result?.data.application
|
||||
? new Application(result.data.application)
|
||||
: null;
|
||||
}
|
||||
|
||||
public static fromClientId(clientId: string): Promise<Application | null> {
|
||||
return Application.fromSql(eq(Applications.clientId, clientId));
|
||||
}
|
||||
|
||||
public async update(
|
||||
newApplication: Partial<ApplicationType>,
|
||||
): Promise<ApplicationType> {
|
||||
await db
|
||||
.update(Applications)
|
||||
.set(newApplication)
|
||||
.where(eq(Applications.id, this.id));
|
||||
|
||||
const updated = await Application.fromId(this.data.id);
|
||||
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update application");
|
||||
}
|
||||
|
||||
this.data = updated.data;
|
||||
return updated.data;
|
||||
}
|
||||
|
||||
public save(): Promise<ApplicationType> {
|
||||
return this.update(this.data);
|
||||
}
|
||||
|
||||
public async delete(ids?: string[]): Promise<void> {
|
||||
if (Array.isArray(ids)) {
|
||||
await db.delete(Applications).where(inArray(Applications.id, ids));
|
||||
} else {
|
||||
await db.delete(Applications).where(eq(Applications.id, this.id));
|
||||
}
|
||||
}
|
||||
|
||||
public static async insert(
|
||||
data: InferInsertModel<typeof Applications>,
|
||||
): Promise<Application> {
|
||||
const inserted = (
|
||||
await db.insert(Applications).values(data).returning()
|
||||
)[0];
|
||||
|
||||
const application = await Application.fromId(inserted.id);
|
||||
|
||||
if (!application) {
|
||||
throw new Error("Failed to insert application");
|
||||
}
|
||||
|
||||
return application;
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
public toApi(): z.infer<typeof ApplicationSchema> {
|
||||
return {
|
||||
name: this.data.name,
|
||||
website: this.data.website,
|
||||
scopes: this.data.scopes.split(" "),
|
||||
redirect_uri: this.data.redirectUri,
|
||||
redirect_uris: this.data.redirectUri.split("\n"),
|
||||
};
|
||||
}
|
||||
|
||||
public toApiCredential(): z.infer<typeof CredentialApplication> {
|
||||
return {
|
||||
name: this.data.name,
|
||||
website: this.data.website,
|
||||
client_id: this.data.clientId,
|
||||
client_secret: this.data.secret,
|
||||
client_secret_expires_at: "0",
|
||||
scopes: this.data.scopes.split(" "),
|
||||
redirect_uri: this.data.redirectUri,
|
||||
redirect_uris: this.data.redirectUri.split("\n"),
|
||||
};
|
||||
}
|
||||
}
|
||||
54
packages/plugin-kit/db/base.ts
Normal file
54
packages/plugin-kit/db/base.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import type { InferModelFromColumns, InferSelectModel } from "drizzle-orm";
|
||||
import type { PgTableWithColumns } from "drizzle-orm/pg-core";
|
||||
|
||||
/**
|
||||
* BaseInterface is an abstract class that provides a common interface for all models.
|
||||
* It includes methods for saving, deleting, updating, and reloading data.
|
||||
*
|
||||
* @template Table - The type of the table with columns.
|
||||
* @template Columns - The type of the columns inferred from the table.
|
||||
*/
|
||||
export abstract class BaseInterface<
|
||||
// biome-ignore lint/suspicious/noExplicitAny: This is just an extended interface
|
||||
Table extends PgTableWithColumns<any>,
|
||||
Columns = InferModelFromColumns<Table["_"]["columns"]>,
|
||||
> {
|
||||
/**
|
||||
* Constructs a new instance of the BaseInterface.
|
||||
*
|
||||
* @param data - The data for the model.
|
||||
*/
|
||||
public constructor(public data: Columns) {}
|
||||
|
||||
/**
|
||||
* Saves the current state of the model to the database.
|
||||
*
|
||||
* @returns A promise that resolves with the saved model.
|
||||
*/
|
||||
public abstract save(): Promise<Columns>;
|
||||
|
||||
/**
|
||||
* Deletes the model from the database.
|
||||
*
|
||||
* @param ids - The ids of the models to delete. If not provided, the current model will be deleted.
|
||||
* @returns A promise that resolves when the deletion is complete.
|
||||
*/
|
||||
public abstract delete(ids?: string[]): Promise<void>;
|
||||
|
||||
/**
|
||||
* Updates the model with new data.
|
||||
*
|
||||
* @param newData - The new data for the model.
|
||||
* @returns A promise that resolves with the updated model.
|
||||
*/
|
||||
public abstract update(
|
||||
newData: Partial<InferSelectModel<Table>>,
|
||||
): Promise<Columns>;
|
||||
|
||||
/**
|
||||
* Reloads the model from the database.
|
||||
*
|
||||
* @returns A promise that resolves when the reloading is complete.
|
||||
*/
|
||||
public abstract reload(): Promise<void>;
|
||||
}
|
||||
238
packages/plugin-kit/db/emoji.ts
Normal file
238
packages/plugin-kit/db/emoji.ts
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
import {
|
||||
type CustomEmoji,
|
||||
emojiWithColonsRegex,
|
||||
emojiWithIdentifiersRegex,
|
||||
} from "@versia/client/schemas";
|
||||
import { db, type Instance, Media } from "@versia/kit/db";
|
||||
import { Emojis, type Instances, type Medias } from "@versia/kit/tables";
|
||||
import * as VersiaEntities from "@versia/sdk/entities";
|
||||
import type { ImageContentFormatSchema } from "@versia/sdk/schemas";
|
||||
import { randomUUIDv7 } from "bun";
|
||||
import {
|
||||
and,
|
||||
desc,
|
||||
eq,
|
||||
type InferInsertModel,
|
||||
type InferSelectModel,
|
||||
inArray,
|
||||
isNull,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import type { z } from "zod";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
||||
type EmojiType = InferSelectModel<typeof Emojis> & {
|
||||
media: InferSelectModel<typeof Medias>;
|
||||
instance: InferSelectModel<typeof Instances> | null;
|
||||
};
|
||||
|
||||
export class Emoji extends BaseInterface<typeof Emojis, EmojiType> {
|
||||
public static $type: EmojiType;
|
||||
public media: Media;
|
||||
|
||||
public constructor(data: EmojiType) {
|
||||
super(data);
|
||||
this.media = new Media(data.media);
|
||||
}
|
||||
|
||||
public async reload(): Promise<void> {
|
||||
const reloaded = await Emoji.fromId(this.data.id);
|
||||
|
||||
if (!reloaded) {
|
||||
throw new Error("Failed to reload emoji");
|
||||
}
|
||||
|
||||
this.data = reloaded.data;
|
||||
}
|
||||
|
||||
public static async fromId(id: string | null): Promise<Emoji | null> {
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Emoji.fromSql(eq(Emojis.id, id));
|
||||
}
|
||||
|
||||
public static async fromIds(ids: string[]): Promise<Emoji[]> {
|
||||
return await Emoji.manyFromSql(inArray(Emojis.id, ids));
|
||||
}
|
||||
|
||||
public static async fromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Emojis.id),
|
||||
): Promise<Emoji | null> {
|
||||
const found = await db.query.Emojis.findFirst({
|
||||
where: sql,
|
||||
orderBy,
|
||||
with: {
|
||||
instance: true,
|
||||
media: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
return new Emoji(found);
|
||||
}
|
||||
|
||||
public static async manyFromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Emojis.id),
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
extra?: Parameters<typeof db.query.Emojis.findMany>[0],
|
||||
): Promise<Emoji[]> {
|
||||
const found = await db.query.Emojis.findMany({
|
||||
where: sql,
|
||||
orderBy,
|
||||
limit,
|
||||
offset,
|
||||
with: { ...extra?.with, instance: true, media: true },
|
||||
});
|
||||
|
||||
return found.map((s) => new Emoji(s));
|
||||
}
|
||||
|
||||
public async update(newEmoji: Partial<EmojiType>): Promise<EmojiType> {
|
||||
await db.update(Emojis).set(newEmoji).where(eq(Emojis.id, this.id));
|
||||
|
||||
const updated = await Emoji.fromId(this.data.id);
|
||||
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update emoji");
|
||||
}
|
||||
|
||||
this.data = updated.data;
|
||||
return updated.data;
|
||||
}
|
||||
|
||||
public save(): Promise<EmojiType> {
|
||||
return this.update(this.data);
|
||||
}
|
||||
|
||||
public async delete(ids?: string[]): Promise<void> {
|
||||
if (Array.isArray(ids)) {
|
||||
await db.delete(Emojis).where(inArray(Emojis.id, ids));
|
||||
} else {
|
||||
await db.delete(Emojis).where(eq(Emojis.id, this.id));
|
||||
}
|
||||
}
|
||||
|
||||
public static async insert(
|
||||
data: InferInsertModel<typeof Emojis>,
|
||||
): Promise<Emoji> {
|
||||
const inserted = (await db.insert(Emojis).values(data).returning())[0];
|
||||
|
||||
const emoji = await Emoji.fromId(inserted.id);
|
||||
|
||||
if (!emoji) {
|
||||
throw new Error("Failed to insert emoji");
|
||||
}
|
||||
|
||||
return emoji;
|
||||
}
|
||||
|
||||
public static async fetchFromRemote(
|
||||
emojiToFetch: {
|
||||
name: string;
|
||||
url: z.infer<typeof ImageContentFormatSchema>;
|
||||
},
|
||||
instance: Instance,
|
||||
): Promise<Emoji> {
|
||||
const existingEmoji = await Emoji.fromSql(
|
||||
and(
|
||||
eq(Emojis.shortcode, emojiToFetch.name),
|
||||
eq(Emojis.instanceId, instance.id),
|
||||
),
|
||||
);
|
||||
|
||||
if (existingEmoji) {
|
||||
return existingEmoji;
|
||||
}
|
||||
|
||||
return await Emoji.fromVersia(emojiToFetch, instance);
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse emojis from text
|
||||
*
|
||||
* @param text The text to parse
|
||||
* @returns An array of emojis
|
||||
*/
|
||||
public static parseFromText(text: string): Promise<Emoji[]> {
|
||||
const matches = text.match(emojiWithColonsRegex);
|
||||
if (!matches || matches.length === 0) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
return Emoji.manyFromSql(
|
||||
and(
|
||||
inArray(
|
||||
Emojis.shortcode,
|
||||
matches.map((match) => match.replace(/:/g, "")),
|
||||
),
|
||||
isNull(Emojis.instanceId),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public toApi(): z.infer<typeof CustomEmoji> {
|
||||
return {
|
||||
id: this.id,
|
||||
shortcode: this.data.shortcode,
|
||||
static_url: this.media.getUrl().proxied,
|
||||
url: this.media.getUrl().proxied,
|
||||
visible_in_picker: this.data.visibleInPicker,
|
||||
category: this.data.category,
|
||||
global: this.data.ownerId === null,
|
||||
description:
|
||||
this.media.data.content[this.media.getPreferredMimeType()]
|
||||
.description ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
public toVersia(): {
|
||||
name: string;
|
||||
url: z.infer<typeof ImageContentFormatSchema>;
|
||||
} {
|
||||
return {
|
||||
name: `:${this.data.shortcode}:`,
|
||||
url: this.media.toVersia().data as z.infer<
|
||||
typeof ImageContentFormatSchema
|
||||
>,
|
||||
};
|
||||
}
|
||||
|
||||
public static async fromVersia(
|
||||
emoji: {
|
||||
name: string;
|
||||
url: z.infer<typeof ImageContentFormatSchema>;
|
||||
},
|
||||
instance: Instance,
|
||||
): Promise<Emoji> {
|
||||
// Extracts the shortcode from the emoji name (e.g. :shortcode: -> shortcode)
|
||||
const shortcode = [...emoji.name.matchAll(emojiWithIdentifiersRegex)][0]
|
||||
.groups.shortcode;
|
||||
|
||||
if (!shortcode) {
|
||||
throw new Error("Could not extract shortcode from emoji name");
|
||||
}
|
||||
|
||||
const media = await Media.fromVersia(
|
||||
new VersiaEntities.ImageContentFormat(emoji.url),
|
||||
);
|
||||
|
||||
return Emoji.insert({
|
||||
id: randomUUIDv7(),
|
||||
shortcode,
|
||||
mediaId: media.id,
|
||||
visibleInPicker: true,
|
||||
instanceId: instance.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
15
packages/plugin-kit/db/index.ts
Normal file
15
packages/plugin-kit/db/index.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
export { db, setupDatabase } from "../tables/db.ts";
|
||||
export { Application } from "./application.ts";
|
||||
export { Emoji } from "./emoji.ts";
|
||||
export { Instance } from "./instance.ts";
|
||||
export { Like } from "./like.ts";
|
||||
export { Media } from "./media.ts";
|
||||
export { Note } from "./note.ts";
|
||||
export { Notification } from "./notification.ts";
|
||||
export { PushSubscription } from "./pushsubscription.ts";
|
||||
export { Reaction } from "./reaction.ts";
|
||||
export { Relationship } from "./relationship.ts";
|
||||
export { Role } from "./role.ts";
|
||||
export { Timeline } from "./timeline.ts";
|
||||
export { Token } from "./token.ts";
|
||||
export { User } from "./user.ts";
|
||||
372
packages/plugin-kit/db/instance.ts
Normal file
372
packages/plugin-kit/db/instance.ts
Normal file
|
|
@ -0,0 +1,372 @@
|
|||
import { getLogger } from "@logtape/logtape";
|
||||
import { ApiError } from "@versia/kit";
|
||||
import { db } from "@versia/kit/db";
|
||||
import { Instances } from "@versia/kit/tables";
|
||||
import * as VersiaEntities from "@versia/sdk/entities";
|
||||
import { config } from "@versia-server/config";
|
||||
import { randomUUIDv7 } from "bun";
|
||||
import chalk from "chalk";
|
||||
import {
|
||||
desc,
|
||||
eq,
|
||||
type InferInsertModel,
|
||||
type InferSelectModel,
|
||||
inArray,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
import { User } from "./user.ts";
|
||||
|
||||
type InstanceType = InferSelectModel<typeof Instances>;
|
||||
|
||||
export class Instance extends BaseInterface<typeof Instances> {
|
||||
public static $type: InstanceType;
|
||||
|
||||
public async reload(): Promise<void> {
|
||||
const reloaded = await Instance.fromId(this.data.id);
|
||||
|
||||
if (!reloaded) {
|
||||
throw new Error("Failed to reload instance");
|
||||
}
|
||||
|
||||
this.data = reloaded.data;
|
||||
}
|
||||
|
||||
public static async fromId(id: string | null): Promise<Instance | null> {
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Instance.fromSql(eq(Instances.id, id));
|
||||
}
|
||||
|
||||
public static async fromIds(ids: string[]): Promise<Instance[]> {
|
||||
return await Instance.manyFromSql(inArray(Instances.id, ids));
|
||||
}
|
||||
|
||||
public static async fromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Instances.id),
|
||||
): Promise<Instance | null> {
|
||||
const found = await db.query.Instances.findFirst({
|
||||
where: sql,
|
||||
orderBy,
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
return new Instance(found);
|
||||
}
|
||||
|
||||
public static async manyFromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Instances.id),
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
extra?: Parameters<typeof db.query.Instances.findMany>[0],
|
||||
): Promise<Instance[]> {
|
||||
const found = await db.query.Instances.findMany({
|
||||
where: sql,
|
||||
orderBy,
|
||||
limit,
|
||||
offset,
|
||||
with: extra?.with,
|
||||
});
|
||||
|
||||
return found.map((s) => new Instance(s));
|
||||
}
|
||||
|
||||
public async update(
|
||||
newInstance: Partial<InstanceType>,
|
||||
): Promise<InstanceType> {
|
||||
await db
|
||||
.update(Instances)
|
||||
.set(newInstance)
|
||||
.where(eq(Instances.id, this.id));
|
||||
|
||||
const updated = await Instance.fromId(this.data.id);
|
||||
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update instance");
|
||||
}
|
||||
|
||||
this.data = updated.data;
|
||||
return updated.data;
|
||||
}
|
||||
|
||||
public save(): Promise<InstanceType> {
|
||||
return this.update(this.data);
|
||||
}
|
||||
|
||||
public async delete(ids?: string[]): Promise<void> {
|
||||
if (Array.isArray(ids)) {
|
||||
await db.delete(Instances).where(inArray(Instances.id, ids));
|
||||
} else {
|
||||
await db.delete(Instances).where(eq(Instances.id, this.id));
|
||||
}
|
||||
}
|
||||
|
||||
public static async fromUser(user: User): Promise<Instance | null> {
|
||||
if (!user.data.instanceId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Instance.fromId(user.data.instanceId);
|
||||
}
|
||||
|
||||
public static async insert(
|
||||
data: InferInsertModel<typeof Instances>,
|
||||
): Promise<Instance> {
|
||||
const inserted = (
|
||||
await db.insert(Instances).values(data).returning()
|
||||
)[0];
|
||||
|
||||
const instance = await Instance.fromId(inserted.id);
|
||||
|
||||
if (!instance) {
|
||||
throw new Error("Failed to insert instance");
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
public static async fetchMetadata(url: URL): Promise<{
|
||||
metadata: VersiaEntities.InstanceMetadata;
|
||||
protocol: "versia" | "activitypub";
|
||||
}> {
|
||||
const origin = new URL(url).origin;
|
||||
const wellKnownUrl = new URL("/.well-known/versia", origin);
|
||||
|
||||
try {
|
||||
const metadata = await User.federationRequester.fetchEntity(
|
||||
wellKnownUrl,
|
||||
VersiaEntities.InstanceMetadata,
|
||||
);
|
||||
|
||||
return { metadata, protocol: "versia" };
|
||||
} catch {
|
||||
// If the server doesn't have a Versia well-known endpoint, it's not a Versia instance
|
||||
// Try to resolve ActivityPub metadata instead
|
||||
const data = await Instance.fetchActivityPubMetadata(url);
|
||||
|
||||
if (!data) {
|
||||
throw new ApiError(
|
||||
404,
|
||||
`Instance at ${origin} is not reachable or does not exist`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
metadata: data,
|
||||
protocol: "activitypub",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static async fetchActivityPubMetadata(
|
||||
url: URL,
|
||||
): Promise<VersiaEntities.InstanceMetadata | null> {
|
||||
const origin = new URL(url).origin;
|
||||
const wellKnownUrl = new URL("/.well-known/nodeinfo", origin);
|
||||
|
||||
// Go to endpoint, then follow the links to the actual metadata
|
||||
|
||||
const logger = getLogger(["federation", "resolvers"]);
|
||||
|
||||
try {
|
||||
const { json, ok, status } = await fetch(wellKnownUrl, {
|
||||
// @ts-expect-error Bun extension
|
||||
proxy: config.http.proxy_address,
|
||||
});
|
||||
|
||||
if (!ok) {
|
||||
logger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
||||
origin,
|
||||
)} - HTTP ${status}`;
|
||||
return null;
|
||||
}
|
||||
|
||||
const wellKnown = (await json()) as {
|
||||
links: { rel: string; href: string }[];
|
||||
};
|
||||
|
||||
if (!wellKnown.links) {
|
||||
logger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
||||
origin,
|
||||
)} - No links found`;
|
||||
return null;
|
||||
}
|
||||
|
||||
const metadataUrl = wellKnown.links.find(
|
||||
(link: { rel: string }) =>
|
||||
link.rel ===
|
||||
"http://nodeinfo.diaspora.software/ns/schema/2.0",
|
||||
);
|
||||
|
||||
if (!metadataUrl) {
|
||||
logger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
||||
origin,
|
||||
)} - No metadata URL found`;
|
||||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
json: json2,
|
||||
ok: ok2,
|
||||
status: status2,
|
||||
} = await fetch(metadataUrl.href, {
|
||||
// @ts-expect-error Bun extension
|
||||
proxy: config.http.proxy_address,
|
||||
});
|
||||
|
||||
if (!ok2) {
|
||||
logger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
||||
origin,
|
||||
)} - HTTP ${status2}`;
|
||||
return null;
|
||||
}
|
||||
|
||||
const metadata = (await json2()) as {
|
||||
metadata: {
|
||||
nodeName?: string;
|
||||
title?: string;
|
||||
nodeDescription?: string;
|
||||
description?: string;
|
||||
};
|
||||
software: { version: string };
|
||||
};
|
||||
|
||||
return new VersiaEntities.InstanceMetadata({
|
||||
name:
|
||||
metadata.metadata.nodeName || metadata.metadata.title || "",
|
||||
description:
|
||||
metadata.metadata.nodeDescription ||
|
||||
metadata.metadata.description,
|
||||
type: "InstanceMetadata",
|
||||
software: {
|
||||
name: "Unknown ActivityPub software",
|
||||
version: metadata.software.version,
|
||||
},
|
||||
created_at: new Date().toISOString(),
|
||||
public_key: {
|
||||
key: "",
|
||||
algorithm: "ed25519",
|
||||
},
|
||||
host: new URL(url).host,
|
||||
compatibility: {
|
||||
extensions: [],
|
||||
versions: [],
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error`Failed to fetch ActivityPub metadata for instance ${chalk.bold(
|
||||
origin,
|
||||
)} - Error! ${error}`;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static resolveFromHost(host: string): Promise<Instance> {
|
||||
if (host.startsWith("http")) {
|
||||
const url = new URL(host);
|
||||
|
||||
return Instance.resolve(url);
|
||||
}
|
||||
|
||||
const url = new URL(`https://${host}`);
|
||||
|
||||
return Instance.resolve(url);
|
||||
}
|
||||
|
||||
public static async resolve(url: URL): Promise<Instance> {
|
||||
const host = url.host;
|
||||
|
||||
const existingInstance = await Instance.fromSql(
|
||||
eq(Instances.baseUrl, host),
|
||||
);
|
||||
|
||||
if (existingInstance) {
|
||||
return existingInstance;
|
||||
}
|
||||
|
||||
const output = await Instance.fetchMetadata(url);
|
||||
|
||||
const { metadata, protocol } = output;
|
||||
|
||||
return Instance.insert({
|
||||
id: randomUUIDv7(),
|
||||
baseUrl: host,
|
||||
name: metadata.data.name,
|
||||
version: metadata.data.software.version,
|
||||
logo: metadata.data.logo,
|
||||
protocol,
|
||||
publicKey: metadata.data.public_key,
|
||||
inbox: metadata.data.shared_inbox ?? null,
|
||||
extensions: metadata.data.extensions ?? null,
|
||||
});
|
||||
}
|
||||
|
||||
public async updateFromRemote(): Promise<Instance> {
|
||||
const logger = getLogger(["federation", "resolvers"]);
|
||||
|
||||
const output = await Instance.fetchMetadata(
|
||||
new URL(`https://${this.data.baseUrl}`),
|
||||
);
|
||||
|
||||
if (!output) {
|
||||
logger.error`Failed to update instance ${chalk.bold(
|
||||
this.data.baseUrl,
|
||||
)}`;
|
||||
throw new Error("Failed to update instance");
|
||||
}
|
||||
|
||||
const { metadata, protocol } = output;
|
||||
|
||||
await this.update({
|
||||
name: metadata.data.name,
|
||||
version: metadata.data.software.version,
|
||||
logo: metadata.data.logo,
|
||||
protocol,
|
||||
publicKey: metadata.data.public_key,
|
||||
inbox: metadata.data.shared_inbox ?? null,
|
||||
extensions: metadata.data.extensions ?? null,
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public async sendMessage(content: string): Promise<void> {
|
||||
const logger = getLogger(["federation", "messaging"]);
|
||||
|
||||
if (
|
||||
!this.data.extensions?.["pub.versia:instance_messaging"]?.endpoint
|
||||
) {
|
||||
logger.info`Instance ${chalk.gray(
|
||||
this.data.baseUrl,
|
||||
)} does not support Instance Messaging, skipping message`;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const endpoint = new URL(
|
||||
this.data.extensions["pub.versia:instance_messaging"].endpoint,
|
||||
);
|
||||
|
||||
await fetch(endpoint.href, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "text/plain",
|
||||
},
|
||||
body: content,
|
||||
});
|
||||
}
|
||||
|
||||
public static getCount(): Promise<number> {
|
||||
return db.$count(Instances);
|
||||
}
|
||||
}
|
||||
182
packages/plugin-kit/db/like.ts
Normal file
182
packages/plugin-kit/db/like.ts
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
import { db } from "@versia/kit/db";
|
||||
import {
|
||||
Likes,
|
||||
type Notes,
|
||||
Notifications,
|
||||
type Users,
|
||||
} from "@versia/kit/tables";
|
||||
import * as VersiaEntities from "@versia/sdk/entities";
|
||||
import { config } from "@versia-server/config";
|
||||
import {
|
||||
and,
|
||||
desc,
|
||||
eq,
|
||||
type InferInsertModel,
|
||||
type InferSelectModel,
|
||||
inArray,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
import { User } from "./user.ts";
|
||||
|
||||
type LikeType = InferSelectModel<typeof Likes> & {
|
||||
liker: InferSelectModel<typeof Users>;
|
||||
liked: InferSelectModel<typeof Notes>;
|
||||
};
|
||||
|
||||
export class Like extends BaseInterface<typeof Likes, LikeType> {
|
||||
public static $type: LikeType;
|
||||
|
||||
public async reload(): Promise<void> {
|
||||
const reloaded = await Like.fromId(this.data.id);
|
||||
|
||||
if (!reloaded) {
|
||||
throw new Error("Failed to reload like");
|
||||
}
|
||||
|
||||
this.data = reloaded.data;
|
||||
}
|
||||
|
||||
public static async fromId(id: string | null): Promise<Like | null> {
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Like.fromSql(eq(Likes.id, id));
|
||||
}
|
||||
|
||||
public static async fromIds(ids: string[]): Promise<Like[]> {
|
||||
return await Like.manyFromSql(inArray(Likes.id, ids));
|
||||
}
|
||||
|
||||
public static async fromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Likes.id),
|
||||
): Promise<Like | null> {
|
||||
const found = await db.query.Likes.findFirst({
|
||||
where: sql,
|
||||
orderBy,
|
||||
with: {
|
||||
liked: true,
|
||||
liker: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
return new Like(found);
|
||||
}
|
||||
|
||||
public static async manyFromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Likes.id),
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
extra?: Parameters<typeof db.query.Likes.findMany>[0],
|
||||
): Promise<Like[]> {
|
||||
const found = await db.query.Likes.findMany({
|
||||
where: sql,
|
||||
orderBy,
|
||||
limit,
|
||||
offset,
|
||||
with: {
|
||||
liked: true,
|
||||
liker: true,
|
||||
...extra?.with,
|
||||
},
|
||||
});
|
||||
|
||||
return found.map((s) => new Like(s));
|
||||
}
|
||||
|
||||
public async update(newRole: Partial<LikeType>): Promise<LikeType> {
|
||||
await db.update(Likes).set(newRole).where(eq(Likes.id, this.id));
|
||||
|
||||
const updated = await Like.fromId(this.data.id);
|
||||
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update like");
|
||||
}
|
||||
|
||||
return updated.data;
|
||||
}
|
||||
|
||||
public save(): Promise<LikeType> {
|
||||
return this.update(this.data);
|
||||
}
|
||||
|
||||
public async delete(): Promise<void> {
|
||||
await db.delete(Likes).where(eq(Likes.id, this.id));
|
||||
}
|
||||
|
||||
public static async insert(
|
||||
data: InferInsertModel<typeof Likes>,
|
||||
): Promise<Like> {
|
||||
const inserted = (await db.insert(Likes).values(data).returning())[0];
|
||||
|
||||
const like = await Like.fromId(inserted.id);
|
||||
|
||||
if (!like) {
|
||||
throw new Error("Failed to insert like");
|
||||
}
|
||||
|
||||
return like;
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
public async clearRelatedNotifications(): Promise<void> {
|
||||
await db
|
||||
.delete(Notifications)
|
||||
.where(
|
||||
and(
|
||||
eq(Notifications.accountId, this.id),
|
||||
eq(Notifications.type, "favourite"),
|
||||
eq(Notifications.notifiedId, this.data.liked.authorId),
|
||||
eq(Notifications.noteId, this.data.liked.id),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public getUri(): URL {
|
||||
return new URL(`/likes/${this.data.id}`, config.http.base_url);
|
||||
}
|
||||
|
||||
public toVersia(): VersiaEntities.Like {
|
||||
return new VersiaEntities.Like({
|
||||
id: this.data.id,
|
||||
author: User.getUri(
|
||||
this.data.liker.id,
|
||||
this.data.liker.uri ? new URL(this.data.liker.uri) : null,
|
||||
).href,
|
||||
type: "pub.versia:likes/Like",
|
||||
created_at: new Date(this.data.createdAt).toISOString(),
|
||||
liked: this.data.liked.uri
|
||||
? new URL(this.data.liked.uri).href
|
||||
: new URL(`/notes/${this.data.liked.id}`, config.http.base_url)
|
||||
.href,
|
||||
uri: this.getUri().href,
|
||||
});
|
||||
}
|
||||
|
||||
public unlikeToVersia(unliker?: User): VersiaEntities.Delete {
|
||||
return new VersiaEntities.Delete({
|
||||
type: "Delete",
|
||||
id: crypto.randomUUID(),
|
||||
created_at: new Date().toISOString(),
|
||||
author: User.getUri(
|
||||
unliker?.id ?? this.data.liker.id,
|
||||
unliker?.data.uri
|
||||
? new URL(unliker.data.uri)
|
||||
: this.data.liker.uri
|
||||
? new URL(this.data.liker.uri)
|
||||
: null,
|
||||
).href,
|
||||
deleted_type: "pub.versia:likes/Like",
|
||||
deleted: this.getUri().href,
|
||||
});
|
||||
}
|
||||
}
|
||||
555
packages/plugin-kit/db/media.ts
Normal file
555
packages/plugin-kit/db/media.ts
Normal file
|
|
@ -0,0 +1,555 @@
|
|||
import { join } from "node:path";
|
||||
import type { Attachment as AttachmentSchema } from "@versia/client/schemas";
|
||||
import { ApiError } from "@versia/kit";
|
||||
import { db } from "@versia/kit/db";
|
||||
import { Medias } from "@versia/kit/tables";
|
||||
import * as VersiaEntities from "@versia/sdk/entities";
|
||||
import type {
|
||||
ContentFormatSchema,
|
||||
ImageContentFormatSchema,
|
||||
} from "@versia/sdk/schemas";
|
||||
import { config, ProxiableUrl } from "@versia-server/config";
|
||||
import { MediaBackendType } from "@versia-server/config/schema";
|
||||
import { randomUUIDv7, S3Client, SHA256, write } from "bun";
|
||||
import {
|
||||
desc,
|
||||
eq,
|
||||
type InferInsertModel,
|
||||
type InferSelectModel,
|
||||
inArray,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import sharp from "sharp";
|
||||
import type { z } from "zod";
|
||||
import { mimeLookup } from "@/content_types.ts";
|
||||
import { getMediaHash } from "../../../classes/media/media-hasher.ts";
|
||||
import { MediaJobType, mediaQueue } from "../../../classes/queues/media.ts";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
||||
type MediaType = InferSelectModel<typeof Medias>;
|
||||
|
||||
export class Media extends BaseInterface<typeof Medias> {
|
||||
public static $type: MediaType;
|
||||
|
||||
public async reload(): Promise<void> {
|
||||
const reloaded = await Media.fromId(this.data.id);
|
||||
|
||||
if (!reloaded) {
|
||||
throw new Error("Failed to reload attachment");
|
||||
}
|
||||
|
||||
this.data = reloaded.data;
|
||||
}
|
||||
|
||||
public static async fromId(id: string | null): Promise<Media | null> {
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Media.fromSql(eq(Medias.id, id));
|
||||
}
|
||||
|
||||
public static async fromIds(ids: string[]): Promise<Media[]> {
|
||||
return await Media.manyFromSql(inArray(Medias.id, ids));
|
||||
}
|
||||
|
||||
public static async fromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Medias.id),
|
||||
): Promise<Media | null> {
|
||||
const found = await db.query.Medias.findFirst({
|
||||
where: sql,
|
||||
orderBy,
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
return new Media(found);
|
||||
}
|
||||
|
||||
public static async manyFromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Medias.id),
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
extra?: Parameters<typeof db.query.Medias.findMany>[0],
|
||||
): Promise<Media[]> {
|
||||
const found = await db.query.Medias.findMany({
|
||||
where: sql,
|
||||
orderBy,
|
||||
limit,
|
||||
offset,
|
||||
with: extra?.with,
|
||||
});
|
||||
|
||||
return found.map((s) => new Media(s));
|
||||
}
|
||||
|
||||
public async update(newAttachment: Partial<MediaType>): Promise<MediaType> {
|
||||
await db
|
||||
.update(Medias)
|
||||
.set(newAttachment)
|
||||
.where(eq(Medias.id, this.id));
|
||||
|
||||
const updated = await Media.fromId(this.data.id);
|
||||
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update attachment");
|
||||
}
|
||||
|
||||
this.data = updated.data;
|
||||
return updated.data;
|
||||
}
|
||||
|
||||
public save(): Promise<MediaType> {
|
||||
return this.update(this.data);
|
||||
}
|
||||
|
||||
public async delete(ids?: string[]): Promise<void> {
|
||||
if (Array.isArray(ids)) {
|
||||
await db.delete(Medias).where(inArray(Medias.id, ids));
|
||||
} else {
|
||||
await db.delete(Medias).where(eq(Medias.id, this.id));
|
||||
}
|
||||
|
||||
// TODO: Also delete the file from the media manager
|
||||
}
|
||||
|
||||
public static async insert(
|
||||
data: InferInsertModel<typeof Medias>,
|
||||
): Promise<Media> {
|
||||
const inserted = (await db.insert(Medias).values(data).returning())[0];
|
||||
|
||||
const attachment = await Media.fromId(inserted.id);
|
||||
|
||||
if (!attachment) {
|
||||
throw new Error("Failed to insert attachment");
|
||||
}
|
||||
|
||||
return attachment;
|
||||
}
|
||||
|
||||
private static async upload(file: File): Promise<{
|
||||
path: string;
|
||||
}> {
|
||||
const fileName = file.name ?? randomUUIDv7();
|
||||
const hash = await getMediaHash(file);
|
||||
|
||||
switch (config.media.backend) {
|
||||
case MediaBackendType.Local: {
|
||||
const path = join(config.media.uploads_path, hash, fileName);
|
||||
|
||||
await write(path, file);
|
||||
|
||||
return { path: join(hash, fileName) };
|
||||
}
|
||||
|
||||
case MediaBackendType.S3: {
|
||||
const path = join(hash, fileName);
|
||||
|
||||
if (!config.s3) {
|
||||
throw new ApiError(500, "S3 configuration missing");
|
||||
}
|
||||
|
||||
const client = new S3Client({
|
||||
endpoint: config.s3.endpoint.origin,
|
||||
region: config.s3.region,
|
||||
bucket: config.s3.bucket_name,
|
||||
accessKeyId: config.s3.access_key,
|
||||
secretAccessKey: config.s3.secret_access_key,
|
||||
virtualHostedStyle: !config.s3.path_style,
|
||||
});
|
||||
|
||||
await client.write(path, file);
|
||||
const finalPath = config.s3.path
|
||||
? join(config.s3.path, path)
|
||||
: path;
|
||||
|
||||
return { path: finalPath };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async fromFile(
|
||||
file: File,
|
||||
options?: {
|
||||
description?: string;
|
||||
thumbnail?: File;
|
||||
},
|
||||
): Promise<Media> {
|
||||
Media.checkFile(file);
|
||||
|
||||
const { path } = await Media.upload(file);
|
||||
|
||||
const url = Media.getUrl(path);
|
||||
|
||||
let thumbnailUrl: URL | null = null;
|
||||
|
||||
if (options?.thumbnail) {
|
||||
const { path } = await Media.upload(options.thumbnail);
|
||||
|
||||
thumbnailUrl = Media.getUrl(path);
|
||||
}
|
||||
|
||||
const content = await Media.fileToContentFormat(file, url, {
|
||||
description: options?.description,
|
||||
});
|
||||
const thumbnailContent =
|
||||
thumbnailUrl && options?.thumbnail
|
||||
? await Media.fileToContentFormat(
|
||||
options.thumbnail,
|
||||
thumbnailUrl,
|
||||
{
|
||||
description: options?.description,
|
||||
},
|
||||
)
|
||||
: undefined;
|
||||
|
||||
const newAttachment = await Media.insert({
|
||||
id: randomUUIDv7(),
|
||||
content,
|
||||
thumbnail: thumbnailContent as z.infer<
|
||||
typeof ImageContentFormatSchema
|
||||
>,
|
||||
});
|
||||
|
||||
if (config.media.conversion.convert_images) {
|
||||
await mediaQueue.add(MediaJobType.ConvertMedia, {
|
||||
attachmentId: newAttachment.id,
|
||||
filename: file.name,
|
||||
});
|
||||
}
|
||||
|
||||
await mediaQueue.add(MediaJobType.CalculateMetadata, {
|
||||
attachmentId: newAttachment.id,
|
||||
filename: file.name,
|
||||
});
|
||||
|
||||
return newAttachment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and adds a new media attachment from a URL
|
||||
* @param uri
|
||||
* @param options
|
||||
* @returns
|
||||
*/
|
||||
public static async fromUrl(
|
||||
uri: URL,
|
||||
options?: {
|
||||
description?: string;
|
||||
},
|
||||
): Promise<Media> {
|
||||
const mimeType = await mimeLookup(uri);
|
||||
|
||||
const content: z.infer<typeof ContentFormatSchema> = {
|
||||
[mimeType]: {
|
||||
content: uri.toString(),
|
||||
remote: true,
|
||||
description: options?.description,
|
||||
},
|
||||
};
|
||||
|
||||
const newAttachment = await Media.insert({
|
||||
id: randomUUIDv7(),
|
||||
content,
|
||||
});
|
||||
|
||||
await mediaQueue.add(MediaJobType.CalculateMetadata, {
|
||||
attachmentId: newAttachment.id,
|
||||
// CalculateMetadata doesn't use the filename, but the type is annoying
|
||||
// and requires it anyway
|
||||
filename: "blank",
|
||||
});
|
||||
|
||||
return newAttachment;
|
||||
}
|
||||
|
||||
private static checkFile(file: File): void {
|
||||
if (file.size > config.validation.media.max_bytes) {
|
||||
throw new ApiError(
|
||||
413,
|
||||
`File too large, max size is ${config.validation.media.max_bytes} bytes`,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
config.validation.media.allowed_mime_types.length > 0 &&
|
||||
!config.validation.media.allowed_mime_types.includes(file.type)
|
||||
) {
|
||||
throw new ApiError(
|
||||
415,
|
||||
`File type ${file.type} is not allowed`,
|
||||
`Allowed types: ${config.validation.media.allowed_mime_types.join(
|
||||
", ",
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async updateFromFile(file: File): Promise<void> {
|
||||
Media.checkFile(file);
|
||||
|
||||
const { path } = await Media.upload(file);
|
||||
|
||||
const url = Media.getUrl(path);
|
||||
|
||||
const content = await Media.fileToContentFormat(file, url, {
|
||||
description:
|
||||
this.data.content[Object.keys(this.data.content)[0]]
|
||||
.description || undefined,
|
||||
});
|
||||
|
||||
await this.update({
|
||||
content,
|
||||
});
|
||||
|
||||
await mediaQueue.add(MediaJobType.CalculateMetadata, {
|
||||
attachmentId: this.id,
|
||||
filename: file.name,
|
||||
});
|
||||
}
|
||||
|
||||
public async updateFromUrl(uri: URL): Promise<void> {
|
||||
const mimeType = await mimeLookup(uri);
|
||||
|
||||
const content: z.infer<typeof ContentFormatSchema> = {
|
||||
[mimeType]: {
|
||||
content: uri.toString(),
|
||||
remote: true,
|
||||
description:
|
||||
this.data.content[Object.keys(this.data.content)[0]]
|
||||
.description || undefined,
|
||||
},
|
||||
};
|
||||
|
||||
await this.update({
|
||||
content,
|
||||
});
|
||||
|
||||
await mediaQueue.add(MediaJobType.CalculateMetadata, {
|
||||
attachmentId: this.id,
|
||||
filename: "blank",
|
||||
});
|
||||
}
|
||||
|
||||
public async updateThumbnail(file: File): Promise<void> {
|
||||
Media.checkFile(file);
|
||||
|
||||
const { path } = await Media.upload(file);
|
||||
|
||||
const url = Media.getUrl(path);
|
||||
|
||||
const content = await Media.fileToContentFormat(file, url);
|
||||
|
||||
await this.update({
|
||||
thumbnail: content as z.infer<typeof ImageContentFormatSchema>,
|
||||
});
|
||||
}
|
||||
|
||||
public async updateMetadata(
|
||||
metadata: Partial<
|
||||
Omit<
|
||||
z.infer<typeof ContentFormatSchema>[keyof z.infer<
|
||||
typeof ContentFormatSchema
|
||||
>],
|
||||
"content"
|
||||
>
|
||||
>,
|
||||
): Promise<void> {
|
||||
const content = this.data.content;
|
||||
|
||||
for (const type of Object.keys(content)) {
|
||||
content[type] = {
|
||||
...content[type],
|
||||
...metadata,
|
||||
};
|
||||
}
|
||||
|
||||
await this.update({
|
||||
content,
|
||||
});
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
public static getUrl(name: string): URL {
|
||||
if (config.media.backend === MediaBackendType.Local) {
|
||||
return new URL(`/media/${name}`, config.http.base_url);
|
||||
}
|
||||
if (config.media.backend === MediaBackendType.S3) {
|
||||
return new URL(`/${name}`, config.s3?.public_url);
|
||||
}
|
||||
|
||||
throw new Error("Unknown media backend");
|
||||
}
|
||||
|
||||
public getUrl(): ProxiableUrl {
|
||||
const type = this.getPreferredMimeType();
|
||||
|
||||
return new ProxiableUrl(this.data.content[type]?.content ?? "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets favourite MIME type for the attachment
|
||||
* Uses a hardcoded list of preferred types, for images
|
||||
*
|
||||
* @returns {string} Preferred MIME type
|
||||
*/
|
||||
public getPreferredMimeType(): string {
|
||||
return Media.getPreferredMimeType(Object.keys(this.data.content));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets favourite MIME type from a list
|
||||
* Uses a hardcoded list of preferred types, for images
|
||||
*
|
||||
* @returns {string} Preferred MIME type
|
||||
*/
|
||||
public static getPreferredMimeType(types: string[]): string {
|
||||
const ranking = [
|
||||
"image/svg+xml",
|
||||
"image/avif",
|
||||
"image/jxl",
|
||||
"image/webp",
|
||||
"image/heif",
|
||||
"image/heif-sequence",
|
||||
"image/heic",
|
||||
"image/heic-sequence",
|
||||
"image/apng",
|
||||
"image/gif",
|
||||
"image/png",
|
||||
"image/jpeg",
|
||||
"image/bmp",
|
||||
];
|
||||
|
||||
return ranking.find((type) => types.includes(type)) ?? types[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps MIME type to Mastodon attachment type
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
public getMastodonType(): z.infer<typeof AttachmentSchema.shape.type> {
|
||||
const type = this.getPreferredMimeType();
|
||||
|
||||
if (type.startsWith("image/")) {
|
||||
return "image";
|
||||
}
|
||||
if (type.startsWith("video/")) {
|
||||
return "video";
|
||||
}
|
||||
if (type.startsWith("audio/")) {
|
||||
return "audio";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts metadata from a file and outputs as ContentFormat
|
||||
*
|
||||
* Does not calculate thumbhash (do this in a worker)
|
||||
* @param file
|
||||
* @param uri Uploaded file URI
|
||||
* @param options Extra metadata, such as description
|
||||
* @returns
|
||||
*/
|
||||
public static async fileToContentFormat(
|
||||
file: File,
|
||||
uri: URL,
|
||||
options?: Partial<{
|
||||
description: string;
|
||||
}>,
|
||||
): Promise<z.infer<typeof ContentFormatSchema>> {
|
||||
const buffer = await file.arrayBuffer();
|
||||
const isImage = file.type.startsWith("image/");
|
||||
const { width, height } = isImage ? await sharp(buffer).metadata() : {};
|
||||
const hash = new SHA256().update(file).digest("hex");
|
||||
|
||||
// Missing: fps, duration
|
||||
// Thumbhash should be added in a worker after the file is uploaded
|
||||
return {
|
||||
[file.type]: {
|
||||
content: uri.toString(),
|
||||
remote: true,
|
||||
hash: {
|
||||
sha256: hash,
|
||||
},
|
||||
width,
|
||||
height,
|
||||
description: options?.description,
|
||||
size: file.size,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public toApiMeta(): z.infer<typeof AttachmentSchema.shape.meta> {
|
||||
const type = this.getPreferredMimeType();
|
||||
const data = this.data.content[type];
|
||||
const size =
|
||||
data.width && data.height
|
||||
? `${data.width}x${data.height}`
|
||||
: undefined;
|
||||
const aspect =
|
||||
data.width && data.height ? data.width / data.height : undefined;
|
||||
|
||||
return {
|
||||
width: data.width || undefined,
|
||||
height: data.height || undefined,
|
||||
fps: data.fps || undefined,
|
||||
size,
|
||||
// Idk whether size or length is the right value
|
||||
duration: data.duration || undefined,
|
||||
// Versia doesn't have a concept of length in ContentFormat
|
||||
length: undefined,
|
||||
aspect,
|
||||
original: {
|
||||
width: data.width || undefined,
|
||||
height: data.height || undefined,
|
||||
size,
|
||||
aspect,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public toApi(): z.infer<typeof AttachmentSchema> {
|
||||
const type = this.getPreferredMimeType();
|
||||
const data = this.data.content[type];
|
||||
|
||||
// Thumbnail should only have a single MIME type
|
||||
const thumbnailData =
|
||||
this.data.thumbnail?.[Object.keys(this.data.thumbnail)[0]];
|
||||
|
||||
return {
|
||||
id: this.data.id,
|
||||
type: this.getMastodonType(),
|
||||
url: this.getUrl().proxied,
|
||||
remote_url: null,
|
||||
preview_url: thumbnailData?.content
|
||||
? new ProxiableUrl(thumbnailData.content).proxied
|
||||
: null,
|
||||
meta: this.toApiMeta(),
|
||||
description: data.description || null,
|
||||
blurhash: this.data.blurhash,
|
||||
};
|
||||
}
|
||||
|
||||
public toVersia(): VersiaEntities.ContentFormat {
|
||||
return new VersiaEntities.ContentFormat(this.data.content);
|
||||
}
|
||||
|
||||
public static fromVersia(
|
||||
contentFormat: VersiaEntities.ContentFormat,
|
||||
): Promise<Media> {
|
||||
return Media.insert({
|
||||
id: randomUUIDv7(),
|
||||
content: contentFormat.data,
|
||||
originalContent: contentFormat.data,
|
||||
});
|
||||
}
|
||||
}
|
||||
1007
packages/plugin-kit/db/note.ts
Normal file
1007
packages/plugin-kit/db/note.ts
Normal file
File diff suppressed because it is too large
Load diff
196
packages/plugin-kit/db/notification.ts
Normal file
196
packages/plugin-kit/db/notification.ts
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
import type { Notification as NotificationSchema } from "@versia/client/schemas";
|
||||
import { db, Note, User } from "@versia/kit/db";
|
||||
import { Notifications } from "@versia/kit/tables";
|
||||
import {
|
||||
desc,
|
||||
eq,
|
||||
type InferInsertModel,
|
||||
type InferSelectModel,
|
||||
inArray,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import type { z } from "zod";
|
||||
import {
|
||||
transformOutputToUserWithRelations,
|
||||
userRelations,
|
||||
} from "../../../classes/functions/user.ts";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
||||
export type NotificationType = InferSelectModel<typeof Notifications> & {
|
||||
status: typeof Note.$type | null;
|
||||
account: typeof User.$type;
|
||||
};
|
||||
|
||||
export class Notification extends BaseInterface<
|
||||
typeof Notifications,
|
||||
NotificationType
|
||||
> {
|
||||
public async reload(): Promise<void> {
|
||||
const reloaded = await Notification.fromId(this.data.id);
|
||||
|
||||
if (!reloaded) {
|
||||
throw new Error("Failed to reload notification");
|
||||
}
|
||||
|
||||
this.data = reloaded.data;
|
||||
}
|
||||
|
||||
public static async fromId(
|
||||
id: string | null,
|
||||
userId?: string,
|
||||
): Promise<Notification | null> {
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Notification.fromSql(
|
||||
eq(Notifications.id, id),
|
||||
undefined,
|
||||
userId,
|
||||
);
|
||||
}
|
||||
|
||||
public static async fromIds(
|
||||
ids: string[],
|
||||
userId?: string,
|
||||
): Promise<Notification[]> {
|
||||
return await Notification.manyFromSql(
|
||||
inArray(Notifications.id, ids),
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
userId,
|
||||
);
|
||||
}
|
||||
|
||||
public static async fromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Notifications.id),
|
||||
userId?: string,
|
||||
): Promise<Notification | null> {
|
||||
const found = await db.query.Notifications.findFirst({
|
||||
where: sql,
|
||||
orderBy,
|
||||
with: {
|
||||
account: {
|
||||
with: {
|
||||
...userRelations,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
return new Notification({
|
||||
...found,
|
||||
account: transformOutputToUserWithRelations(found.account),
|
||||
status: (await Note.fromId(found.noteId, userId))?.data ?? null,
|
||||
});
|
||||
}
|
||||
|
||||
public static async manyFromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Notifications.id),
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
extra?: Parameters<typeof db.query.Notifications.findMany>[0],
|
||||
userId?: string,
|
||||
): Promise<Notification[]> {
|
||||
const found = await db.query.Notifications.findMany({
|
||||
where: sql,
|
||||
orderBy,
|
||||
limit,
|
||||
offset,
|
||||
with: {
|
||||
...extra?.with,
|
||||
account: {
|
||||
with: {
|
||||
...userRelations,
|
||||
},
|
||||
},
|
||||
},
|
||||
extras: extra?.extras,
|
||||
});
|
||||
|
||||
return (
|
||||
await Promise.all(
|
||||
found.map(async (notif) => ({
|
||||
...notif,
|
||||
account: transformOutputToUserWithRelations(notif.account),
|
||||
status:
|
||||
(await Note.fromId(notif.noteId, userId))?.data ?? null,
|
||||
})),
|
||||
)
|
||||
).map((s) => new Notification(s));
|
||||
}
|
||||
|
||||
public async update(
|
||||
newAttachment: Partial<NotificationType>,
|
||||
): Promise<NotificationType> {
|
||||
await db
|
||||
.update(Notifications)
|
||||
.set(newAttachment)
|
||||
.where(eq(Notifications.id, this.id));
|
||||
|
||||
const updated = await Notification.fromId(this.data.id);
|
||||
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update notification");
|
||||
}
|
||||
|
||||
this.data = updated.data;
|
||||
return updated.data;
|
||||
}
|
||||
|
||||
public save(): Promise<NotificationType> {
|
||||
return this.update(this.data);
|
||||
}
|
||||
|
||||
public async delete(ids?: string[]): Promise<void> {
|
||||
if (Array.isArray(ids)) {
|
||||
await db
|
||||
.delete(Notifications)
|
||||
.where(inArray(Notifications.id, ids));
|
||||
} else {
|
||||
await db.delete(Notifications).where(eq(Notifications.id, this.id));
|
||||
}
|
||||
}
|
||||
|
||||
public static async insert(
|
||||
data: InferInsertModel<typeof Notifications>,
|
||||
): Promise<Notification> {
|
||||
const inserted = (
|
||||
await db.insert(Notifications).values(data).returning()
|
||||
)[0];
|
||||
|
||||
const notification = await Notification.fromId(inserted.id);
|
||||
|
||||
if (!notification) {
|
||||
throw new Error("Failed to insert notification");
|
||||
}
|
||||
|
||||
return notification;
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
public async toApi(): Promise<z.infer<typeof NotificationSchema>> {
|
||||
const account = new User(this.data.account);
|
||||
|
||||
return {
|
||||
account: account.toApi(),
|
||||
created_at: new Date(this.data.createdAt).toISOString(),
|
||||
id: this.data.id,
|
||||
type: this.data.type,
|
||||
status: this.data.status
|
||||
? await new Note(this.data.status).toApi(account)
|
||||
: undefined,
|
||||
group_key: `ungrouped-${this.data.id}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
190
packages/plugin-kit/db/pushsubscription.ts
Normal file
190
packages/plugin-kit/db/pushsubscription.ts
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
import type { WebPushSubscription as WebPushSubscriptionSchema } from "@versia/client/schemas";
|
||||
import { db, type Token, type User } from "@versia/kit/db";
|
||||
import { PushSubscriptions, Tokens } from "@versia/kit/tables";
|
||||
import {
|
||||
desc,
|
||||
eq,
|
||||
type InferInsertModel,
|
||||
type InferSelectModel,
|
||||
inArray,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import type { z } from "zod";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
||||
type PushSubscriptionType = InferSelectModel<typeof PushSubscriptions>;
|
||||
|
||||
export class PushSubscription extends BaseInterface<
|
||||
typeof PushSubscriptions,
|
||||
PushSubscriptionType
|
||||
> {
|
||||
public static $type: PushSubscriptionType;
|
||||
|
||||
public async reload(): Promise<void> {
|
||||
const reloaded = await PushSubscription.fromId(this.data.id);
|
||||
|
||||
if (!reloaded) {
|
||||
throw new Error("Failed to reload subscription");
|
||||
}
|
||||
|
||||
this.data = reloaded.data;
|
||||
}
|
||||
|
||||
public static async fromId(
|
||||
id: string | null,
|
||||
): Promise<PushSubscription | null> {
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await PushSubscription.fromSql(eq(PushSubscriptions.id, id));
|
||||
}
|
||||
|
||||
public static async fromIds(ids: string[]): Promise<PushSubscription[]> {
|
||||
return await PushSubscription.manyFromSql(
|
||||
inArray(PushSubscriptions.id, ids),
|
||||
);
|
||||
}
|
||||
|
||||
public static async fromToken(
|
||||
token: Token,
|
||||
): Promise<PushSubscription | null> {
|
||||
return await PushSubscription.fromSql(
|
||||
eq(PushSubscriptions.tokenId, token.id),
|
||||
);
|
||||
}
|
||||
|
||||
public static async manyFromUser(
|
||||
user: User,
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
): Promise<PushSubscription[]> {
|
||||
const found = await db
|
||||
.select()
|
||||
.from(PushSubscriptions)
|
||||
.leftJoin(Tokens, eq(Tokens.id, PushSubscriptions.tokenId))
|
||||
.where(eq(Tokens.userId, user.id))
|
||||
.limit(limit ?? 9e10)
|
||||
.offset(offset ?? 0);
|
||||
|
||||
return found.map((s) => new PushSubscription(s.PushSubscriptions));
|
||||
}
|
||||
|
||||
public static async fromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(PushSubscriptions.id),
|
||||
): Promise<PushSubscription | null> {
|
||||
const found = await db.query.PushSubscriptions.findFirst({
|
||||
where: sql,
|
||||
orderBy,
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
return new PushSubscription(found);
|
||||
}
|
||||
|
||||
public static async manyFromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(PushSubscriptions.id),
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
extra?: Parameters<typeof db.query.PushSubscriptions.findMany>[0],
|
||||
): Promise<PushSubscription[]> {
|
||||
const found = await db.query.PushSubscriptions.findMany({
|
||||
where: sql,
|
||||
orderBy,
|
||||
limit,
|
||||
offset,
|
||||
with: extra?.with,
|
||||
});
|
||||
|
||||
return found.map((s) => new PushSubscription(s));
|
||||
}
|
||||
|
||||
public async update(
|
||||
newSubscription: Partial<PushSubscriptionType>,
|
||||
): Promise<PushSubscriptionType> {
|
||||
await db
|
||||
.update(PushSubscriptions)
|
||||
.set(newSubscription)
|
||||
.where(eq(PushSubscriptions.id, this.id));
|
||||
|
||||
const updated = await PushSubscription.fromId(this.data.id);
|
||||
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update subscription");
|
||||
}
|
||||
|
||||
this.data = updated.data;
|
||||
return updated.data;
|
||||
}
|
||||
|
||||
public save(): Promise<PushSubscriptionType> {
|
||||
return this.update(this.data);
|
||||
}
|
||||
|
||||
public static async clearAllOfToken(token: Token): Promise<void> {
|
||||
await db
|
||||
.delete(PushSubscriptions)
|
||||
.where(eq(PushSubscriptions.tokenId, token.id));
|
||||
}
|
||||
|
||||
public async delete(ids?: string[]): Promise<void> {
|
||||
if (Array.isArray(ids)) {
|
||||
await db
|
||||
.delete(PushSubscriptions)
|
||||
.where(inArray(PushSubscriptions.id, ids));
|
||||
} else {
|
||||
await db
|
||||
.delete(PushSubscriptions)
|
||||
.where(eq(PushSubscriptions.id, this.id));
|
||||
}
|
||||
}
|
||||
|
||||
public static async insert(
|
||||
data: InferInsertModel<typeof PushSubscriptions>,
|
||||
): Promise<PushSubscription> {
|
||||
const inserted = (
|
||||
await db.insert(PushSubscriptions).values(data).returning()
|
||||
)[0];
|
||||
|
||||
const subscription = await PushSubscription.fromId(inserted.id);
|
||||
|
||||
if (!subscription) {
|
||||
throw new Error("Failed to insert subscription");
|
||||
}
|
||||
|
||||
return subscription;
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
public getAlerts(): z.infer<typeof WebPushSubscriptionSchema.shape.alerts> {
|
||||
return {
|
||||
mention: this.data.alerts.mention ?? false,
|
||||
favourite: this.data.alerts.favourite ?? false,
|
||||
reblog: this.data.alerts.reblog ?? false,
|
||||
follow: this.data.alerts.follow ?? false,
|
||||
poll: this.data.alerts.poll ?? false,
|
||||
follow_request: this.data.alerts.follow_request ?? false,
|
||||
status: this.data.alerts.status ?? false,
|
||||
update: this.data.alerts.update ?? false,
|
||||
"admin.sign_up": this.data.alerts["admin.sign_up"] ?? false,
|
||||
"admin.report": this.data.alerts["admin.report"] ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
public toApi(): z.infer<typeof WebPushSubscriptionSchema> {
|
||||
return {
|
||||
id: this.data.id,
|
||||
alerts: this.getAlerts(),
|
||||
endpoint: this.data.endpoint,
|
||||
// FIXME: Add real key
|
||||
server_key: "",
|
||||
};
|
||||
}
|
||||
}
|
||||
285
packages/plugin-kit/db/reaction.ts
Normal file
285
packages/plugin-kit/db/reaction.ts
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
import { db, Emoji, Instance, type Note, User } from "@versia/kit/db";
|
||||
import { type Notes, Reactions, type Users } from "@versia/kit/tables";
|
||||
import * as VersiaEntities from "@versia/sdk/entities";
|
||||
import { config } from "@versia-server/config";
|
||||
import { randomUUIDv7 } from "bun";
|
||||
import {
|
||||
and,
|
||||
desc,
|
||||
eq,
|
||||
type InferInsertModel,
|
||||
type InferSelectModel,
|
||||
inArray,
|
||||
isNull,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
||||
type ReactionType = InferSelectModel<typeof Reactions> & {
|
||||
emoji: typeof Emoji.$type | null;
|
||||
author: InferSelectModel<typeof Users>;
|
||||
note: InferSelectModel<typeof Notes>;
|
||||
};
|
||||
|
||||
export class Reaction extends BaseInterface<typeof Reactions, ReactionType> {
|
||||
public static $type: ReactionType;
|
||||
|
||||
public async reload(): Promise<void> {
|
||||
const reloaded = await Reaction.fromId(this.data.id);
|
||||
|
||||
if (!reloaded) {
|
||||
throw new Error("Failed to reload reaction");
|
||||
}
|
||||
|
||||
this.data = reloaded.data;
|
||||
}
|
||||
|
||||
public static async fromId(id: string | null): Promise<Reaction | null> {
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Reaction.fromSql(eq(Reactions.id, id));
|
||||
}
|
||||
|
||||
public static async fromIds(ids: string[]): Promise<Reaction[]> {
|
||||
return await Reaction.manyFromSql(inArray(Reactions.id, ids));
|
||||
}
|
||||
|
||||
public static async fromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Reactions.id),
|
||||
): Promise<Reaction | null> {
|
||||
const found = await db.query.Reactions.findFirst({
|
||||
where: sql,
|
||||
with: {
|
||||
emoji: {
|
||||
with: {
|
||||
instance: true,
|
||||
media: true,
|
||||
},
|
||||
},
|
||||
author: true,
|
||||
note: true,
|
||||
},
|
||||
orderBy,
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
return new Reaction(found);
|
||||
}
|
||||
|
||||
public static async manyFromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Reactions.id),
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
extra?: Parameters<typeof db.query.Reactions.findMany>[0],
|
||||
): Promise<Reaction[]> {
|
||||
const found = await db.query.Reactions.findMany({
|
||||
where: sql,
|
||||
orderBy,
|
||||
limit,
|
||||
offset,
|
||||
with: {
|
||||
...extra?.with,
|
||||
emoji: {
|
||||
with: {
|
||||
instance: true,
|
||||
media: true,
|
||||
},
|
||||
},
|
||||
author: true,
|
||||
note: true,
|
||||
},
|
||||
});
|
||||
|
||||
return found.map((s) => new Reaction(s));
|
||||
}
|
||||
|
||||
public async update(
|
||||
newReaction: Partial<ReactionType>,
|
||||
): Promise<ReactionType> {
|
||||
await db
|
||||
.update(Reactions)
|
||||
.set(newReaction)
|
||||
.where(eq(Reactions.id, this.id));
|
||||
|
||||
const updated = await Reaction.fromId(this.data.id);
|
||||
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update reaction");
|
||||
}
|
||||
|
||||
this.data = updated.data;
|
||||
return updated.data;
|
||||
}
|
||||
|
||||
public save(): Promise<ReactionType> {
|
||||
return this.update(this.data);
|
||||
}
|
||||
|
||||
public async delete(ids?: string[]): Promise<void> {
|
||||
if (Array.isArray(ids)) {
|
||||
await db.delete(Reactions).where(inArray(Reactions.id, ids));
|
||||
} else {
|
||||
await db.delete(Reactions).where(eq(Reactions.id, this.id));
|
||||
}
|
||||
}
|
||||
|
||||
public static async insert(
|
||||
data: InferInsertModel<typeof Reactions>,
|
||||
): Promise<Reaction> {
|
||||
// Needs one of emojiId or emojiText, but not both
|
||||
if (!(data.emojiId || data.emojiText)) {
|
||||
throw new Error("EmojiID or emojiText is required");
|
||||
}
|
||||
|
||||
if (data.emojiId && data.emojiText) {
|
||||
throw new Error("Cannot have both emojiId and emojiText");
|
||||
}
|
||||
|
||||
const inserted = (
|
||||
await db.insert(Reactions).values(data).returning()
|
||||
)[0];
|
||||
|
||||
const reaction = await Reaction.fromId(inserted.id);
|
||||
|
||||
if (!reaction) {
|
||||
throw new Error("Failed to insert reaction");
|
||||
}
|
||||
|
||||
return reaction;
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
public static fromEmoji(
|
||||
emoji: Emoji | string,
|
||||
author: User,
|
||||
note: Note,
|
||||
): Promise<Reaction | null> {
|
||||
if (emoji instanceof Emoji) {
|
||||
return Reaction.fromSql(
|
||||
and(
|
||||
eq(Reactions.authorId, author.id),
|
||||
eq(Reactions.noteId, note.id),
|
||||
isNull(Reactions.emojiText),
|
||||
eq(Reactions.emojiId, emoji.id),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Reaction.fromSql(
|
||||
and(
|
||||
eq(Reactions.authorId, author.id),
|
||||
eq(Reactions.noteId, note.id),
|
||||
eq(Reactions.emojiText, emoji),
|
||||
isNull(Reactions.emojiId),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public getUri(baseUrl: URL): URL {
|
||||
return this.data.uri
|
||||
? new URL(this.data.uri)
|
||||
: new URL(
|
||||
`/notes/${this.data.noteId}/reactions/${this.id}`,
|
||||
baseUrl,
|
||||
);
|
||||
}
|
||||
|
||||
public get local(): boolean {
|
||||
return this.data.author.instanceId === null;
|
||||
}
|
||||
|
||||
public hasCustomEmoji(): boolean {
|
||||
return !!this.data.emoji || !this.data.emojiText;
|
||||
}
|
||||
|
||||
public toVersia(): VersiaEntities.Reaction {
|
||||
if (!this.local) {
|
||||
throw new Error("Cannot convert a non-local reaction to Versia");
|
||||
}
|
||||
|
||||
return new VersiaEntities.Reaction({
|
||||
uri: this.getUri(config.http.base_url).href,
|
||||
type: "pub.versia:reactions/Reaction",
|
||||
author: User.getUri(
|
||||
this.data.authorId,
|
||||
this.data.author.uri ? new URL(this.data.author.uri) : null,
|
||||
).href,
|
||||
created_at: new Date(this.data.createdAt).toISOString(),
|
||||
id: this.id,
|
||||
object: this.data.note.uri
|
||||
? new URL(this.data.note.uri).href
|
||||
: new URL(`/notes/${this.data.noteId}`, config.http.base_url)
|
||||
.href,
|
||||
content: this.hasCustomEmoji()
|
||||
? `:${this.data.emoji?.shortcode}:`
|
||||
: this.data.emojiText || "",
|
||||
extensions: this.hasCustomEmoji()
|
||||
? {
|
||||
"pub.versia:custom_emojis": {
|
||||
emojis: [
|
||||
new Emoji(
|
||||
this.data.emoji as typeof Emoji.$type,
|
||||
).toVersia(),
|
||||
],
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
public toVersiaUnreact(): VersiaEntities.Delete {
|
||||
return new VersiaEntities.Delete({
|
||||
type: "Delete",
|
||||
id: crypto.randomUUID(),
|
||||
created_at: new Date().toISOString(),
|
||||
author: User.getUri(
|
||||
this.data.authorId,
|
||||
this.data.author.uri ? new URL(this.data.author.uri) : null,
|
||||
).href,
|
||||
deleted_type: "pub.versia:reactions/Reaction",
|
||||
deleted: this.getUri(config.http.base_url).href,
|
||||
});
|
||||
}
|
||||
|
||||
public static async fromVersia(
|
||||
reactionToConvert: VersiaEntities.Reaction,
|
||||
author: User,
|
||||
note: Note,
|
||||
): Promise<Reaction> {
|
||||
if (author.local) {
|
||||
throw new Error("Cannot process a reaction from a local user");
|
||||
}
|
||||
|
||||
const emojiEntity =
|
||||
reactionToConvert.data.extensions?.["pub.versia:custom_emojis"]
|
||||
?.emojis[0];
|
||||
const emoji = emojiEntity
|
||||
? await Emoji.fetchFromRemote(
|
||||
emojiEntity,
|
||||
new Instance(
|
||||
author.data.instance as NonNullable<
|
||||
(typeof User.$type)["instance"]
|
||||
>,
|
||||
),
|
||||
)
|
||||
: null;
|
||||
|
||||
return Reaction.insert({
|
||||
id: randomUUIDv7(),
|
||||
uri: reactionToConvert.data.uri,
|
||||
authorId: author.id,
|
||||
noteId: note.id,
|
||||
emojiId: emoji ? emoji.id : null,
|
||||
emojiText: emoji ? null : reactionToConvert.data.content,
|
||||
});
|
||||
}
|
||||
}
|
||||
353
packages/plugin-kit/db/relationship.ts
Normal file
353
packages/plugin-kit/db/relationship.ts
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
import type { Relationship as RelationshipSchema } from "@versia/client/schemas";
|
||||
import { db } from "@versia/kit/db";
|
||||
import { Relationships, Users } from "@versia/kit/tables";
|
||||
import { randomUUIDv7 } from "bun";
|
||||
import {
|
||||
and,
|
||||
desc,
|
||||
eq,
|
||||
type InferInsertModel,
|
||||
type InferSelectModel,
|
||||
inArray,
|
||||
type SQL,
|
||||
sql,
|
||||
} from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
import type { User } from "./user.ts";
|
||||
|
||||
type RelationshipType = InferSelectModel<typeof Relationships>;
|
||||
|
||||
type RelationshipWithOpposite = RelationshipType & {
|
||||
followedBy: boolean;
|
||||
blockedBy: boolean;
|
||||
requestedBy: boolean;
|
||||
};
|
||||
|
||||
export class Relationship extends BaseInterface<
|
||||
typeof Relationships,
|
||||
RelationshipWithOpposite
|
||||
> {
|
||||
public static schema = z.object({
|
||||
id: z.string(),
|
||||
blocked_by: z.boolean(),
|
||||
blocking: z.boolean(),
|
||||
domain_blocking: z.boolean(),
|
||||
endorsed: z.boolean(),
|
||||
followed_by: z.boolean(),
|
||||
following: z.boolean(),
|
||||
muting_notifications: z.boolean(),
|
||||
muting: z.boolean(),
|
||||
note: z.string().nullable(),
|
||||
notifying: z.boolean(),
|
||||
requested_by: z.boolean(),
|
||||
requested: z.boolean(),
|
||||
showing_reblogs: z.boolean(),
|
||||
});
|
||||
|
||||
public static $type: RelationshipWithOpposite;
|
||||
|
||||
public async reload(): Promise<void> {
|
||||
const reloaded = await Relationship.fromId(this.data.id);
|
||||
|
||||
if (!reloaded) {
|
||||
throw new Error("Failed to reload relationship");
|
||||
}
|
||||
|
||||
this.data = reloaded.data;
|
||||
}
|
||||
|
||||
public static async fromId(
|
||||
id: string | null,
|
||||
): Promise<Relationship | null> {
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Relationship.fromSql(eq(Relationships.id, id));
|
||||
}
|
||||
|
||||
public static async fromIds(ids: string[]): Promise<Relationship[]> {
|
||||
return await Relationship.manyFromSql(inArray(Relationships.id, ids));
|
||||
}
|
||||
|
||||
public static async fromOwnerAndSubject(
|
||||
owner: User,
|
||||
subject: User,
|
||||
): Promise<Relationship> {
|
||||
const found = await Relationship.fromSql(
|
||||
and(
|
||||
eq(Relationships.ownerId, owner.id),
|
||||
eq(Relationships.subjectId, subject.id),
|
||||
),
|
||||
);
|
||||
|
||||
if (!found) {
|
||||
// Create a new relationship if one doesn't exist
|
||||
return await Relationship.insert({
|
||||
id: randomUUIDv7(),
|
||||
ownerId: owner.id,
|
||||
subjectId: subject.id,
|
||||
languages: [],
|
||||
following: false,
|
||||
showingReblogs: false,
|
||||
notifying: false,
|
||||
blocking: false,
|
||||
muting: false,
|
||||
mutingNotifications: false,
|
||||
requested: false,
|
||||
domainBlocking: false,
|
||||
endorsed: false,
|
||||
note: "",
|
||||
});
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
public static async fromOwnerAndSubjects(
|
||||
owner: User,
|
||||
subjectIds: string[],
|
||||
): Promise<Relationship[]> {
|
||||
const found = await Relationship.manyFromSql(
|
||||
and(
|
||||
eq(Relationships.ownerId, owner.id),
|
||||
inArray(Relationships.subjectId, subjectIds),
|
||||
),
|
||||
);
|
||||
|
||||
const missingSubjectsIds = subjectIds.filter(
|
||||
(id) => !found.find((rel) => rel.data.subjectId === id),
|
||||
);
|
||||
|
||||
for (const subjectId of missingSubjectsIds) {
|
||||
await Relationship.insert({
|
||||
id: randomUUIDv7(),
|
||||
ownerId: owner.id,
|
||||
subjectId,
|
||||
languages: [],
|
||||
following: false,
|
||||
showingReblogs: false,
|
||||
notifying: false,
|
||||
blocking: false,
|
||||
muting: false,
|
||||
mutingNotifications: false,
|
||||
requested: false,
|
||||
domainBlocking: false,
|
||||
endorsed: false,
|
||||
note: "",
|
||||
});
|
||||
}
|
||||
|
||||
return await Relationship.manyFromSql(
|
||||
and(
|
||||
eq(Relationships.ownerId, owner.id),
|
||||
inArray(Relationships.subjectId, subjectIds),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public static async fromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Relationships.id),
|
||||
): Promise<Relationship | null> {
|
||||
const found = await db.query.Relationships.findFirst({
|
||||
where: sql,
|
||||
orderBy,
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const opposite = await Relationship.getOpposite(found);
|
||||
|
||||
return new Relationship({
|
||||
...found,
|
||||
followedBy: opposite.following,
|
||||
blockedBy: opposite.blocking,
|
||||
requestedBy: opposite.requested,
|
||||
});
|
||||
}
|
||||
|
||||
public static async manyFromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Relationships.id),
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
extra?: Parameters<typeof db.query.Relationships.findMany>[0],
|
||||
): Promise<Relationship[]> {
|
||||
const found = await db.query.Relationships.findMany({
|
||||
where: sql,
|
||||
orderBy,
|
||||
limit,
|
||||
offset,
|
||||
with: extra?.with,
|
||||
});
|
||||
|
||||
const opposites = await Promise.all(
|
||||
found.map((rel) => Relationship.getOpposite(rel)),
|
||||
);
|
||||
|
||||
return found.map((s, i) => {
|
||||
return new Relationship({
|
||||
...s,
|
||||
followedBy: opposites[i].following,
|
||||
blockedBy: opposites[i].blocking,
|
||||
requestedBy: opposites[i].requested,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static async getOpposite(oppositeTo: {
|
||||
subjectId: string;
|
||||
ownerId: string;
|
||||
}): Promise<RelationshipType> {
|
||||
let output = await db.query.Relationships.findFirst({
|
||||
where: (rel): SQL | undefined =>
|
||||
and(
|
||||
eq(rel.ownerId, oppositeTo.subjectId),
|
||||
eq(rel.subjectId, oppositeTo.ownerId),
|
||||
),
|
||||
});
|
||||
|
||||
// If the opposite relationship doesn't exist, create it
|
||||
if (!output) {
|
||||
output = (
|
||||
await db
|
||||
.insert(Relationships)
|
||||
.values({
|
||||
id: randomUUIDv7(),
|
||||
ownerId: oppositeTo.subjectId,
|
||||
subjectId: oppositeTo.ownerId,
|
||||
languages: [],
|
||||
following: false,
|
||||
showingReblogs: false,
|
||||
notifying: false,
|
||||
blocking: false,
|
||||
domainBlocking: false,
|
||||
endorsed: false,
|
||||
note: "",
|
||||
muting: false,
|
||||
mutingNotifications: false,
|
||||
requested: false,
|
||||
})
|
||||
.returning()
|
||||
)[0];
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public async update(
|
||||
newRelationship: Partial<RelationshipType>,
|
||||
): Promise<RelationshipWithOpposite> {
|
||||
await db
|
||||
.update(Relationships)
|
||||
.set(newRelationship)
|
||||
.where(eq(Relationships.id, this.id));
|
||||
|
||||
// If a user follows another user, update followerCount and followingCount
|
||||
if (newRelationship.following && !this.data.following) {
|
||||
await db
|
||||
.update(Users)
|
||||
.set({
|
||||
followingCount: sql`${Users.followingCount} + 1`,
|
||||
})
|
||||
.where(eq(Users.id, this.data.ownerId));
|
||||
|
||||
await db
|
||||
.update(Users)
|
||||
.set({
|
||||
followerCount: sql`${Users.followerCount} + 1`,
|
||||
})
|
||||
.where(eq(Users.id, this.data.subjectId));
|
||||
}
|
||||
|
||||
// If a user unfollows another user, update followerCount and followingCount
|
||||
if (!newRelationship.following && this.data.following) {
|
||||
await db
|
||||
.update(Users)
|
||||
.set({
|
||||
followingCount: sql`${Users.followingCount} - 1`,
|
||||
})
|
||||
.where(eq(Users.id, this.data.ownerId));
|
||||
|
||||
await db
|
||||
.update(Users)
|
||||
.set({
|
||||
followerCount: sql`${Users.followerCount} - 1`,
|
||||
})
|
||||
.where(eq(Users.id, this.data.subjectId));
|
||||
}
|
||||
|
||||
const updated = await Relationship.fromId(this.data.id);
|
||||
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update relationship");
|
||||
}
|
||||
|
||||
this.data = updated.data;
|
||||
return updated.data;
|
||||
}
|
||||
|
||||
public save(): Promise<RelationshipWithOpposite> {
|
||||
return this.update(this.data);
|
||||
}
|
||||
|
||||
public async delete(ids?: string[]): Promise<void> {
|
||||
if (Array.isArray(ids)) {
|
||||
await db
|
||||
.delete(Relationships)
|
||||
.where(inArray(Relationships.id, ids));
|
||||
} else {
|
||||
await db.delete(Relationships).where(eq(Relationships.id, this.id));
|
||||
}
|
||||
}
|
||||
|
||||
public static async insert(
|
||||
data: InferInsertModel<typeof Relationships>,
|
||||
): Promise<Relationship> {
|
||||
const inserted = (
|
||||
await db.insert(Relationships).values(data).returning()
|
||||
)[0];
|
||||
|
||||
const relationship = await Relationship.fromId(inserted.id);
|
||||
|
||||
if (!relationship) {
|
||||
throw new Error("Failed to insert relationship");
|
||||
}
|
||||
|
||||
// Create opposite relationship if necessary
|
||||
await Relationship.getOpposite({
|
||||
subjectId: relationship.data.subjectId,
|
||||
ownerId: relationship.data.ownerId,
|
||||
});
|
||||
|
||||
return relationship;
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
public toApi(): z.infer<typeof RelationshipSchema> {
|
||||
return {
|
||||
id: this.data.subjectId,
|
||||
blocked_by: this.data.blockedBy,
|
||||
blocking: this.data.blocking,
|
||||
domain_blocking: this.data.domainBlocking,
|
||||
endorsed: this.data.endorsed,
|
||||
followed_by: this.data.followedBy,
|
||||
following: this.data.following,
|
||||
muting_notifications: this.data.mutingNotifications,
|
||||
muting: this.data.muting,
|
||||
note: this.data.note,
|
||||
notifying: this.data.notifying,
|
||||
requested_by: this.data.requestedBy,
|
||||
requested: this.data.requested,
|
||||
showing_reblogs: this.data.showingReblogs,
|
||||
languages: this.data.languages ?? [],
|
||||
};
|
||||
}
|
||||
}
|
||||
225
packages/plugin-kit/db/role.ts
Normal file
225
packages/plugin-kit/db/role.ts
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
import type {
|
||||
RolePermission,
|
||||
Role as RoleSchema,
|
||||
} from "@versia/client/schemas";
|
||||
import { db } from "@versia/kit/db";
|
||||
import { Roles, RoleToUsers } from "@versia/kit/tables";
|
||||
import { config, ProxiableUrl } from "@versia-server/config";
|
||||
import {
|
||||
and,
|
||||
desc,
|
||||
eq,
|
||||
type InferInsertModel,
|
||||
type InferSelectModel,
|
||||
inArray,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import type { z } from "zod";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
||||
type RoleType = InferSelectModel<typeof Roles>;
|
||||
|
||||
export class Role extends BaseInterface<typeof Roles> {
|
||||
public static $type: RoleType;
|
||||
public static defaultRole = new Role({
|
||||
id: "default",
|
||||
name: "Default",
|
||||
permissions: config.permissions.default,
|
||||
priority: 0,
|
||||
description: "Default role for all users",
|
||||
visible: false,
|
||||
icon: null,
|
||||
});
|
||||
public static adminRole = new Role({
|
||||
id: "admin",
|
||||
name: "Admin",
|
||||
permissions: config.permissions.admin,
|
||||
priority: 2 ** 31 - 1,
|
||||
description: "Default role for all administrators",
|
||||
visible: false,
|
||||
icon: null,
|
||||
});
|
||||
|
||||
public async reload(): Promise<void> {
|
||||
const reloaded = await Role.fromId(this.data.id);
|
||||
|
||||
if (!reloaded) {
|
||||
throw new Error("Failed to reload role");
|
||||
}
|
||||
|
||||
this.data = reloaded.data;
|
||||
}
|
||||
|
||||
public static async fromId(id: string | null): Promise<Role | null> {
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Role.fromSql(eq(Roles.id, id));
|
||||
}
|
||||
|
||||
public static async fromIds(ids: string[]): Promise<Role[]> {
|
||||
return await Role.manyFromSql(inArray(Roles.id, ids));
|
||||
}
|
||||
|
||||
public static async fromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Roles.id),
|
||||
): Promise<Role | null> {
|
||||
const found = await db.query.Roles.findFirst({
|
||||
where: sql,
|
||||
orderBy,
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
return new Role(found);
|
||||
}
|
||||
|
||||
public static async getAll(): Promise<Role[]> {
|
||||
return (await Role.manyFromSql(undefined)).concat(
|
||||
Role.defaultRole,
|
||||
Role.adminRole,
|
||||
);
|
||||
}
|
||||
|
||||
public static async getUserRoles(
|
||||
userId: string,
|
||||
isAdmin: boolean,
|
||||
): Promise<Role[]> {
|
||||
return (
|
||||
await db.query.RoleToUsers.findMany({
|
||||
where: (role): SQL | undefined => eq(role.userId, userId),
|
||||
with: {
|
||||
role: true,
|
||||
user: {
|
||||
columns: {
|
||||
isAdmin: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
.map((r) => new Role(r.role))
|
||||
.concat(
|
||||
new Role({
|
||||
id: "default",
|
||||
name: "Default",
|
||||
permissions: config.permissions.default,
|
||||
priority: 0,
|
||||
description: "Default role for all users",
|
||||
visible: false,
|
||||
icon: null,
|
||||
}),
|
||||
)
|
||||
.concat(
|
||||
isAdmin
|
||||
? [
|
||||
new Role({
|
||||
id: "admin",
|
||||
name: "Admin",
|
||||
permissions: config.permissions.admin,
|
||||
priority: 2 ** 31 - 1,
|
||||
description:
|
||||
"Default role for all administrators",
|
||||
visible: false,
|
||||
icon: null,
|
||||
}),
|
||||
]
|
||||
: [],
|
||||
);
|
||||
}
|
||||
|
||||
public static async manyFromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Roles.id),
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
extra?: Parameters<typeof db.query.Roles.findMany>[0],
|
||||
): Promise<Role[]> {
|
||||
const found = await db.query.Roles.findMany({
|
||||
where: sql,
|
||||
orderBy,
|
||||
limit,
|
||||
offset,
|
||||
with: extra?.with,
|
||||
});
|
||||
|
||||
return found.map((s) => new Role(s));
|
||||
}
|
||||
|
||||
public async update(newRole: Partial<RoleType>): Promise<RoleType> {
|
||||
await db.update(Roles).set(newRole).where(eq(Roles.id, this.id));
|
||||
|
||||
const updated = await Role.fromId(this.data.id);
|
||||
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update role");
|
||||
}
|
||||
|
||||
return updated.data;
|
||||
}
|
||||
|
||||
public save(): Promise<RoleType> {
|
||||
return this.update(this.data);
|
||||
}
|
||||
|
||||
public async delete(ids?: string[]): Promise<void> {
|
||||
if (Array.isArray(ids)) {
|
||||
await db.delete(Roles).where(inArray(Roles.id, ids));
|
||||
} else {
|
||||
await db.delete(Roles).where(eq(Roles.id, this.id));
|
||||
}
|
||||
}
|
||||
|
||||
public static async insert(
|
||||
data: InferInsertModel<typeof Roles>,
|
||||
): Promise<Role> {
|
||||
const inserted = (await db.insert(Roles).values(data).returning())[0];
|
||||
|
||||
const role = await Role.fromId(inserted.id);
|
||||
|
||||
if (!role) {
|
||||
throw new Error("Failed to insert role");
|
||||
}
|
||||
|
||||
return role;
|
||||
}
|
||||
|
||||
public async linkUser(userId: string): Promise<void> {
|
||||
await db.insert(RoleToUsers).values({
|
||||
userId,
|
||||
roleId: this.id,
|
||||
});
|
||||
}
|
||||
|
||||
public async unlinkUser(userId: string): Promise<void> {
|
||||
await db
|
||||
.delete(RoleToUsers)
|
||||
.where(
|
||||
and(
|
||||
eq(RoleToUsers.roleId, this.id),
|
||||
eq(RoleToUsers.userId, userId),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
public toApi(): z.infer<typeof RoleSchema> {
|
||||
return {
|
||||
id: this.id,
|
||||
name: this.data.name,
|
||||
permissions: this.data.permissions as unknown as RolePermission[],
|
||||
priority: this.data.priority,
|
||||
description: this.data.description ?? undefined,
|
||||
visible: this.data.visible,
|
||||
icon: this.data.icon
|
||||
? new ProxiableUrl(this.data.icon).proxied
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
241
packages/plugin-kit/db/timeline.ts
Normal file
241
packages/plugin-kit/db/timeline.ts
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
import { Notes, Notifications, Users } from "@versia/kit/tables";
|
||||
import { config } from "@versia-server/config";
|
||||
import { gt, type SQL } from "drizzle-orm";
|
||||
import { Note } from "./note.ts";
|
||||
import { Notification } from "./notification.ts";
|
||||
import { User } from "./user.ts";
|
||||
|
||||
enum TimelineType {
|
||||
Note = "Note",
|
||||
User = "User",
|
||||
Notification = "Notification",
|
||||
}
|
||||
|
||||
export class Timeline<Type extends Note | User | Notification> {
|
||||
public constructor(private type: TimelineType) {}
|
||||
|
||||
public static getNoteTimeline(
|
||||
sql: SQL<unknown> | undefined,
|
||||
limit: number,
|
||||
url: URL,
|
||||
userId?: string,
|
||||
): Promise<{ link: string; objects: Note[] }> {
|
||||
return new Timeline<Note>(TimelineType.Note).fetchTimeline(
|
||||
sql,
|
||||
limit,
|
||||
url,
|
||||
userId,
|
||||
);
|
||||
}
|
||||
|
||||
public static getUserTimeline(
|
||||
sql: SQL<unknown> | undefined,
|
||||
limit: number,
|
||||
url: URL,
|
||||
): Promise<{ link: string; objects: User[] }> {
|
||||
return new Timeline<User>(TimelineType.User).fetchTimeline(
|
||||
sql,
|
||||
limit,
|
||||
url,
|
||||
);
|
||||
}
|
||||
|
||||
public static getNotificationTimeline(
|
||||
sql: SQL<unknown> | undefined,
|
||||
limit: number,
|
||||
url: URL,
|
||||
userId?: string,
|
||||
): Promise<{ link: string; objects: Notification[] }> {
|
||||
return new Timeline<Notification>(
|
||||
TimelineType.Notification,
|
||||
).fetchTimeline(sql, limit, url, userId);
|
||||
}
|
||||
|
||||
private async fetchObjects(
|
||||
sql: SQL<unknown> | undefined,
|
||||
limit: number,
|
||||
userId?: string,
|
||||
): Promise<Type[]> {
|
||||
switch (this.type) {
|
||||
case TimelineType.Note:
|
||||
return (await Note.manyFromSql(
|
||||
sql,
|
||||
undefined,
|
||||
limit,
|
||||
undefined,
|
||||
userId,
|
||||
)) as Type[];
|
||||
case TimelineType.User:
|
||||
return (await User.manyFromSql(
|
||||
sql,
|
||||
undefined,
|
||||
limit,
|
||||
)) as Type[];
|
||||
case TimelineType.Notification:
|
||||
return (await Notification.manyFromSql(
|
||||
sql,
|
||||
undefined,
|
||||
limit,
|
||||
undefined,
|
||||
undefined,
|
||||
userId,
|
||||
)) as Type[];
|
||||
}
|
||||
}
|
||||
|
||||
private async fetchLinkHeader(
|
||||
objects: Type[],
|
||||
url: URL,
|
||||
limit: number,
|
||||
): Promise<string> {
|
||||
const linkHeader: string[] = [];
|
||||
const urlWithoutQuery = new URL(url.pathname, config.http.base_url);
|
||||
|
||||
if (objects.length > 0) {
|
||||
switch (this.type) {
|
||||
case TimelineType.Note:
|
||||
linkHeader.push(
|
||||
...(await Timeline.fetchNoteLinkHeader(
|
||||
objects as Note[],
|
||||
urlWithoutQuery,
|
||||
limit,
|
||||
)),
|
||||
);
|
||||
break;
|
||||
case TimelineType.User:
|
||||
linkHeader.push(
|
||||
...(await Timeline.fetchUserLinkHeader(
|
||||
objects as User[],
|
||||
urlWithoutQuery,
|
||||
limit,
|
||||
)),
|
||||
);
|
||||
break;
|
||||
case TimelineType.Notification:
|
||||
linkHeader.push(
|
||||
...(await Timeline.fetchNotificationLinkHeader(
|
||||
objects as Notification[],
|
||||
urlWithoutQuery,
|
||||
limit,
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return linkHeader.join(", ");
|
||||
}
|
||||
|
||||
private static async fetchNoteLinkHeader(
|
||||
notes: Note[],
|
||||
urlWithoutQuery: URL,
|
||||
limit: number,
|
||||
): Promise<string[]> {
|
||||
const linkHeader: string[] = [];
|
||||
|
||||
const objectBefore = await Note.fromSql(gt(Notes.id, notes[0].data.id));
|
||||
if (objectBefore) {
|
||||
linkHeader.push(
|
||||
`<${urlWithoutQuery}?limit=${limit ?? 20}&min_id=${notes[0].data.id}>; rel="prev"`,
|
||||
);
|
||||
}
|
||||
|
||||
if (notes.length >= (limit ?? 20)) {
|
||||
const objectAfter = await Note.fromSql(
|
||||
gt(Notes.id, notes.at(-1)?.data.id ?? ""),
|
||||
);
|
||||
if (objectAfter) {
|
||||
linkHeader.push(
|
||||
`<${urlWithoutQuery}?limit=${limit ?? 20}&max_id=${notes.at(-1)?.data.id}>; rel="next"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return linkHeader;
|
||||
}
|
||||
|
||||
private static async fetchUserLinkHeader(
|
||||
users: User[],
|
||||
urlWithoutQuery: URL,
|
||||
limit: number,
|
||||
): Promise<string[]> {
|
||||
const linkHeader: string[] = [];
|
||||
|
||||
const objectBefore = await User.fromSql(gt(Users.id, users[0].id));
|
||||
if (objectBefore) {
|
||||
linkHeader.push(
|
||||
`<${urlWithoutQuery}?limit=${limit ?? 20}&min_id=${users[0].id}>; rel="prev"`,
|
||||
);
|
||||
}
|
||||
|
||||
if (users.length >= (limit ?? 20)) {
|
||||
const objectAfter = await User.fromSql(
|
||||
gt(Users.id, users.at(-1)?.id ?? ""),
|
||||
);
|
||||
if (objectAfter) {
|
||||
linkHeader.push(
|
||||
`<${urlWithoutQuery}?limit=${limit ?? 20}&max_id=${users.at(-1)?.id}>; rel="next"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return linkHeader;
|
||||
}
|
||||
|
||||
private static async fetchNotificationLinkHeader(
|
||||
notifications: Notification[],
|
||||
urlWithoutQuery: URL,
|
||||
limit: number,
|
||||
): Promise<string[]> {
|
||||
const linkHeader: string[] = [];
|
||||
|
||||
const objectBefore = await Notification.fromSql(
|
||||
gt(Notifications.id, notifications[0].data.id),
|
||||
);
|
||||
if (objectBefore) {
|
||||
linkHeader.push(
|
||||
`<${urlWithoutQuery}?limit=${limit ?? 20}&min_id=${notifications[0].data.id}>; rel="prev"`,
|
||||
);
|
||||
}
|
||||
|
||||
if (notifications.length >= (limit ?? 20)) {
|
||||
const objectAfter = await Notification.fromSql(
|
||||
gt(Notifications.id, notifications.at(-1)?.data.id ?? ""),
|
||||
);
|
||||
if (objectAfter) {
|
||||
linkHeader.push(
|
||||
`<${urlWithoutQuery}?limit=${limit ?? 20}&max_id=${notifications.at(-1)?.data.id}>; rel="next"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return linkHeader;
|
||||
}
|
||||
|
||||
private async fetchTimeline(
|
||||
sql: SQL<unknown> | undefined,
|
||||
limit: number,
|
||||
url: URL,
|
||||
userId?: string,
|
||||
): Promise<{ link: string; objects: Type[] }> {
|
||||
const objects = await this.fetchObjects(sql, limit, userId);
|
||||
const link = await this.fetchLinkHeader(objects, url, limit);
|
||||
|
||||
switch (this.type) {
|
||||
case TimelineType.Note:
|
||||
return {
|
||||
link,
|
||||
objects,
|
||||
};
|
||||
case TimelineType.User:
|
||||
return {
|
||||
link,
|
||||
objects,
|
||||
};
|
||||
case TimelineType.Notification:
|
||||
return {
|
||||
link,
|
||||
objects,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
166
packages/plugin-kit/db/token.ts
Normal file
166
packages/plugin-kit/db/token.ts
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
import type { Token as TokenSchema } from "@versia/client/schemas";
|
||||
import { type Application, db, User } from "@versia/kit/db";
|
||||
import { Tokens } from "@versia/kit/tables";
|
||||
import {
|
||||
desc,
|
||||
eq,
|
||||
type InferInsertModel,
|
||||
type InferSelectModel,
|
||||
inArray,
|
||||
type SQL,
|
||||
} from "drizzle-orm";
|
||||
import type { z } from "zod";
|
||||
import { BaseInterface } from "./base.ts";
|
||||
|
||||
type TokenType = InferSelectModel<typeof Tokens> & {
|
||||
application: typeof Application.$type | null;
|
||||
};
|
||||
|
||||
export class Token extends BaseInterface<typeof Tokens, TokenType> {
|
||||
public static $type: TokenType;
|
||||
|
||||
public async reload(): Promise<void> {
|
||||
const reloaded = await Token.fromId(this.data.id);
|
||||
|
||||
if (!reloaded) {
|
||||
throw new Error("Failed to reload token");
|
||||
}
|
||||
|
||||
this.data = reloaded.data;
|
||||
}
|
||||
|
||||
public static async fromId(id: string | null): Promise<Token | null> {
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await Token.fromSql(eq(Tokens.id, id));
|
||||
}
|
||||
|
||||
public static async fromIds(ids: string[]): Promise<Token[]> {
|
||||
return await Token.manyFromSql(inArray(Tokens.id, ids));
|
||||
}
|
||||
|
||||
public static async fromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Tokens.id),
|
||||
): Promise<Token | null> {
|
||||
const found = await db.query.Tokens.findFirst({
|
||||
where: sql,
|
||||
orderBy,
|
||||
with: {
|
||||
application: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
return null;
|
||||
}
|
||||
return new Token(found);
|
||||
}
|
||||
|
||||
public static async manyFromSql(
|
||||
sql: SQL<unknown> | undefined,
|
||||
orderBy: SQL<unknown> | undefined = desc(Tokens.id),
|
||||
limit?: number,
|
||||
offset?: number,
|
||||
extra?: Parameters<typeof db.query.Tokens.findMany>[0],
|
||||
): Promise<Token[]> {
|
||||
const found = await db.query.Tokens.findMany({
|
||||
where: sql,
|
||||
orderBy,
|
||||
limit,
|
||||
offset,
|
||||
with: {
|
||||
application: true,
|
||||
...extra?.with,
|
||||
},
|
||||
});
|
||||
|
||||
return found.map((s) => new Token(s));
|
||||
}
|
||||
|
||||
public async update(newAttachment: Partial<TokenType>): Promise<TokenType> {
|
||||
await db
|
||||
.update(Tokens)
|
||||
.set(newAttachment)
|
||||
.where(eq(Tokens.id, this.id));
|
||||
|
||||
const updated = await Token.fromId(this.data.id);
|
||||
|
||||
if (!updated) {
|
||||
throw new Error("Failed to update token");
|
||||
}
|
||||
|
||||
this.data = updated.data;
|
||||
return updated.data;
|
||||
}
|
||||
|
||||
public save(): Promise<TokenType> {
|
||||
return this.update(this.data);
|
||||
}
|
||||
|
||||
public async delete(ids?: string[]): Promise<void> {
|
||||
if (Array.isArray(ids)) {
|
||||
await db.delete(Tokens).where(inArray(Tokens.id, ids));
|
||||
} else {
|
||||
await db.delete(Tokens).where(eq(Tokens.id, this.id));
|
||||
}
|
||||
}
|
||||
|
||||
public static async insert(
|
||||
data: InferInsertModel<typeof Tokens>,
|
||||
): Promise<Token> {
|
||||
const inserted = (await db.insert(Tokens).values(data).returning())[0];
|
||||
|
||||
const token = await Token.fromId(inserted.id);
|
||||
|
||||
if (!token) {
|
||||
throw new Error("Failed to insert token");
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
public static async insertMany(
|
||||
data: InferInsertModel<typeof Tokens>[],
|
||||
): Promise<Token[]> {
|
||||
const inserted = await db.insert(Tokens).values(data).returning();
|
||||
|
||||
return await Token.fromIds(inserted.map((i) => i.id));
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
public static async fromAccessToken(
|
||||
accessToken: string,
|
||||
): Promise<Token | null> {
|
||||
return await Token.fromSql(eq(Tokens.accessToken, accessToken));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the associated user from this token
|
||||
*
|
||||
* @returns The user associated with this token
|
||||
*/
|
||||
public async getUser(): Promise<User | null> {
|
||||
if (!this.data.userId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await User.fromId(this.data.userId);
|
||||
}
|
||||
|
||||
public toApi(): z.infer<typeof TokenSchema> {
|
||||
return {
|
||||
access_token: this.data.accessToken,
|
||||
token_type: "Bearer",
|
||||
scope: this.data.scope,
|
||||
created_at: Math.floor(
|
||||
new Date(this.data.createdAt).getTime() / 1000,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
1491
packages/plugin-kit/db/user.ts
Normal file
1491
packages/plugin-kit/db/user.ts
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,15 +0,0 @@
|
|||
export { Application } from "~/classes/database/application.ts";
|
||||
export { Emoji } from "~/classes/database/emoji.ts";
|
||||
export { Instance } from "~/classes/database/instance.ts";
|
||||
export { Like } from "~/classes/database/like.ts";
|
||||
export { Media } from "~/classes/database/media";
|
||||
export { Note } from "~/classes/database/note.ts";
|
||||
export { Notification } from "~/classes/database/notification.ts";
|
||||
export { PushSubscription } from "~/classes/database/pushsubscription.ts";
|
||||
export { Reaction } from "~/classes/database/reaction.ts";
|
||||
export { Relationship } from "~/classes/database/relationship.ts";
|
||||
export { Role } from "~/classes/database/role.ts";
|
||||
export { Timeline } from "~/classes/database/timeline.ts";
|
||||
export { Token } from "~/classes/database/token.ts";
|
||||
export { User } from "~/classes/database/user.ts";
|
||||
export { db } from "~/drizzle/db.ts";
|
||||
|
|
@ -1 +0,0 @@
|
|||
export * from "drizzle-orm";
|
||||
|
|
@ -1 +0,0 @@
|
|||
export * from "~/drizzle/schema";
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
export { ApiError } from "./api-error.ts";
|
||||
export { Hooks } from "./hooks.ts";
|
||||
export { Plugin } from "./plugin.ts";
|
||||
export type { Manifest } from "./schema.ts";
|
||||
export { type Manifest, manifestSchema } from "./schema.ts";
|
||||
|
|
|
|||
|
|
@ -32,29 +32,38 @@
|
|||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"drizzle-orm": "^0.44.2",
|
||||
"hono": "^4.7.7",
|
||||
"mitt": "^3.0.1",
|
||||
"zod": "^3.24.2",
|
||||
"zod-to-json-schema": "^3.24.5",
|
||||
"zod-validation-error": "^3.4.0"
|
||||
"drizzle-orm": "catalog:",
|
||||
"hono": "catalog:",
|
||||
"mitt": "catalog:",
|
||||
"zod": "catalog:",
|
||||
"zod-to-json-schema": "catalog:",
|
||||
"zod-validation-error": "catalog:",
|
||||
"chalk": "catalog:",
|
||||
"@versia/client": "workspace:*",
|
||||
"@versia-server/config": "workspace:*",
|
||||
"@versia/sdk": "workspace:*",
|
||||
"html-to-text": "catalog:",
|
||||
"@logtape/logtape": "catalog:",
|
||||
"sharp": "catalog:",
|
||||
"magic-regexp": "catalog:",
|
||||
"altcha-lib": "catalog:",
|
||||
"hono-openapi": "catalog:"
|
||||
},
|
||||
"files": [
|
||||
"tables/migrations"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./index.ts",
|
||||
"default": "./index.ts"
|
||||
},
|
||||
"./db": {
|
||||
"import": "./exports/db.ts",
|
||||
"default": "./exports/db.ts"
|
||||
},
|
||||
"./drizzle": {
|
||||
"import": "./exports/drizzle.ts",
|
||||
"default": "./exports/drizzle.ts"
|
||||
"import": "./db/index.ts",
|
||||
"default": "./db/index.ts"
|
||||
},
|
||||
"./tables": {
|
||||
"import": "./exports/tables.ts",
|
||||
"default": "./exports/tables.ts"
|
||||
"import": "./tables/schema.ts",
|
||||
"default": "./tables/schema.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
81
packages/plugin-kit/tables/db.ts
Normal file
81
packages/plugin-kit/tables/db.ts
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import { getLogger } from "@logtape/logtape";
|
||||
import { config } from "@versia-server/config";
|
||||
import { SQL } from "bun";
|
||||
import chalk from "chalk";
|
||||
import { type BunSQLDatabase, drizzle } from "drizzle-orm/bun-sql";
|
||||
import { withReplicas } from "drizzle-orm/pg-core";
|
||||
import { migrate } from "drizzle-orm/postgres-js/migrator";
|
||||
import * as schema from "./schema.ts";
|
||||
|
||||
const primaryDb = new SQL({
|
||||
host: config.postgres.host,
|
||||
port: config.postgres.port,
|
||||
user: config.postgres.username,
|
||||
password: config.postgres.password,
|
||||
database: config.postgres.database,
|
||||
});
|
||||
|
||||
const replicas = config.postgres.replicas.map(
|
||||
(replica) =>
|
||||
new SQL({
|
||||
host: replica.host,
|
||||
port: replica.port,
|
||||
user: replica.username,
|
||||
password: replica.password,
|
||||
database: replica.database,
|
||||
}),
|
||||
);
|
||||
|
||||
export const db =
|
||||
(replicas.length ?? 0) > 0
|
||||
? withReplicas(
|
||||
drizzle(primaryDb, { schema }),
|
||||
replicas.map((r) => drizzle(r, { schema })) as [
|
||||
// biome-ignore lint/style/useNamingConvention: Required by drizzle-orm
|
||||
BunSQLDatabase<typeof schema> & { $client: SQL },
|
||||
// biome-ignore lint/style/useNamingConvention: Required by drizzle-orm
|
||||
...(BunSQLDatabase<typeof schema> & { $client: SQL })[],
|
||||
],
|
||||
)
|
||||
: drizzle(primaryDb, { schema });
|
||||
|
||||
export const setupDatabase = async (info = true): Promise<void> => {
|
||||
const logger = getLogger("database");
|
||||
|
||||
for (const dbPool of [primaryDb, ...replicas]) {
|
||||
try {
|
||||
await dbPool.connect();
|
||||
} catch (e) {
|
||||
if (
|
||||
(e as Error).message ===
|
||||
"Client has already been connected. You cannot reuse a client."
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.fatal`Failed to connect to database ${chalk.bold(
|
||||
// Index of the database in the array
|
||||
replicas.indexOf(dbPool) === -1
|
||||
? "primary"
|
||||
: `replica-${replicas.indexOf(dbPool)}`,
|
||||
)}. Please check your configuration.`;
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate the database
|
||||
info && logger.info`Migrating database...`;
|
||||
|
||||
try {
|
||||
await migrate(db, {
|
||||
migrationsFolder: "./packages/plugin-kit/tables/migrations",
|
||||
});
|
||||
} catch (e) {
|
||||
logger.fatal`Failed to migrate database. Please check your configuration.`;
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
info && logger.info`Database migrated`;
|
||||
};
|
||||
|
|
@ -0,0 +1,459 @@
|
|||
-- Current sql file was generated after introspecting the database
|
||||
-- If you want to run this migration please uncomment this code before executing migrations
|
||||
CREATE TABLE IF NOT EXISTS "_prisma_migrations" (
|
||||
"id" varchar(36) PRIMARY KEY NOT NULL,
|
||||
"checksum" varchar(64) NOT NULL,
|
||||
"finished_at" timestamp with time zone,
|
||||
"migration_name" varchar(255) NOT NULL,
|
||||
"logs" text,
|
||||
"rolled_back_at" timestamp with time zone,
|
||||
"started_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"applied_steps_count" integer DEFAULT 0 NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "Emoji" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"shortcode" text NOT NULL,
|
||||
"url" text NOT NULL,
|
||||
"visible_in_picker" boolean NOT NULL,
|
||||
"instanceId" uuid,
|
||||
"alt" text,
|
||||
"content_type" text NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "Like" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"likerId" uuid NOT NULL,
|
||||
"likedId" uuid NOT NULL,
|
||||
"createdAt" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "LysandObject" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"remote_id" text NOT NULL,
|
||||
"type" text NOT NULL,
|
||||
"uri" text NOT NULL,
|
||||
"created_at" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
"authorId" uuid,
|
||||
"extra_data" jsonb NOT NULL,
|
||||
"extensions" jsonb NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "Relationship" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"ownerId" uuid NOT NULL,
|
||||
"subjectId" uuid NOT NULL,
|
||||
"following" boolean NOT NULL,
|
||||
"showingReblogs" boolean NOT NULL,
|
||||
"notifying" boolean NOT NULL,
|
||||
"followedBy" boolean NOT NULL,
|
||||
"blocking" boolean NOT NULL,
|
||||
"blockedBy" boolean NOT NULL,
|
||||
"muting" boolean NOT NULL,
|
||||
"mutingNotifications" boolean NOT NULL,
|
||||
"requested" boolean NOT NULL,
|
||||
"domainBlocking" boolean NOT NULL,
|
||||
"endorsed" boolean NOT NULL,
|
||||
"languages" text[],
|
||||
"note" text NOT NULL,
|
||||
"createdAt" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
"updatedAt" timestamp(3) NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "Application" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"website" text,
|
||||
"vapid_key" text,
|
||||
"client_id" text NOT NULL,
|
||||
"secret" text NOT NULL,
|
||||
"scopes" text NOT NULL,
|
||||
"redirect_uris" text NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "Token" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"token_type" text NOT NULL,
|
||||
"scope" text NOT NULL,
|
||||
"access_token" text NOT NULL,
|
||||
"code" text NOT NULL,
|
||||
"created_at" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
"userId" uuid,
|
||||
"applicationId" uuid
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "_EmojiToUser" (
|
||||
"A" uuid NOT NULL,
|
||||
"B" uuid NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "_EmojiToStatus" (
|
||||
"A" uuid NOT NULL,
|
||||
"B" uuid NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "_StatusToUser" (
|
||||
"A" uuid NOT NULL,
|
||||
"B" uuid NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "_UserPinnedNotes" (
|
||||
"A" uuid NOT NULL,
|
||||
"B" uuid NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "Attachment" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"url" text NOT NULL,
|
||||
"remote_url" text,
|
||||
"thumbnail_url" text,
|
||||
"mime_type" text NOT NULL,
|
||||
"description" text,
|
||||
"blurhash" text,
|
||||
"sha256" text,
|
||||
"fps" integer,
|
||||
"duration" integer,
|
||||
"width" integer,
|
||||
"height" integer,
|
||||
"size" integer,
|
||||
"statusId" uuid
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "Notification" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"type" text NOT NULL,
|
||||
"createdAt" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
"notifiedId" uuid NOT NULL,
|
||||
"accountId" uuid NOT NULL,
|
||||
"statusId" uuid
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "Status" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"uri" text,
|
||||
"authorId" uuid NOT NULL,
|
||||
"createdAt" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
"updatedAt" timestamp(3) NOT NULL,
|
||||
"reblogId" uuid,
|
||||
"content" text DEFAULT '' NOT NULL,
|
||||
"contentType" text DEFAULT 'text/plain' NOT NULL,
|
||||
"visibility" text NOT NULL,
|
||||
"inReplyToPostId" uuid,
|
||||
"quotingPostId" uuid,
|
||||
"instanceId" uuid,
|
||||
"sensitive" boolean NOT NULL,
|
||||
"spoilerText" text DEFAULT '' NOT NULL,
|
||||
"applicationId" uuid,
|
||||
"contentSource" text DEFAULT '' NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "Instance" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"base_url" text NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"version" text NOT NULL,
|
||||
"logo" jsonb NOT NULL,
|
||||
"disableAutomoderation" boolean DEFAULT false NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "OpenIdAccount" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"userId" uuid,
|
||||
"serverId" text NOT NULL,
|
||||
"issuerId" text NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "User" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"uri" text,
|
||||
"username" text NOT NULL,
|
||||
"displayName" text NOT NULL,
|
||||
"password" text,
|
||||
"email" text,
|
||||
"note" text DEFAULT '' NOT NULL,
|
||||
"isAdmin" boolean DEFAULT false NOT NULL,
|
||||
"endpoints" jsonb,
|
||||
"source" jsonb NOT NULL,
|
||||
"avatar" text NOT NULL,
|
||||
"header" text NOT NULL,
|
||||
"createdAt" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
"updatedAt" timestamp(3) NOT NULL,
|
||||
"isBot" boolean DEFAULT false NOT NULL,
|
||||
"isLocked" boolean DEFAULT false NOT NULL,
|
||||
"isDiscoverable" boolean DEFAULT false NOT NULL,
|
||||
"sanctions" text[],
|
||||
"publicKey" text NOT NULL,
|
||||
"privateKey" text,
|
||||
"instanceId" uuid,
|
||||
"disableAutomoderation" boolean DEFAULT false NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "OpenIdLoginFlow" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"codeVerifier" text NOT NULL,
|
||||
"applicationId" uuid,
|
||||
"issuerId" text NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "Flag" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"flagType" text DEFAULT 'other' NOT NULL,
|
||||
"createdAt" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
"flaggeStatusId" uuid,
|
||||
"flaggedUserId" uuid
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "ModNote" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"notedStatusId" uuid,
|
||||
"notedUserId" uuid,
|
||||
"modId" uuid NOT NULL,
|
||||
"note" text NOT NULL,
|
||||
"createdAt" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "ModTag" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"taggedStatusId" uuid,
|
||||
"taggedUserId" uuid,
|
||||
"modId" uuid NOT NULL,
|
||||
"tag" text NOT NULL,
|
||||
"createdAt" timestamp(3) DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "LysandObject_remote_id_key" ON "LysandObject" ("remote_id");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "LysandObject_uri_key" ON "LysandObject" ("uri");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Application_client_id_key" ON "Application" ("client_id");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "_EmojiToUser_AB_unique" ON "_EmojiToUser" ("A","B");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "_EmojiToUser_B_index" ON "_EmojiToUser" ("B");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "_EmojiToStatus_AB_unique" ON "_EmojiToStatus" ("A","B");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "_EmojiToStatus_B_index" ON "_EmojiToStatus" ("B");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "_StatusToUser_AB_unique" ON "_StatusToUser" ("A","B");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "_StatusToUser_B_index" ON "_StatusToUser" ("B");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "_UserPinnedNotes_AB_unique" ON "_UserPinnedNotes" ("A","B");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "_UserPinnedNotes_B_index" ON "_UserPinnedNotes" ("B");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Status_uri_key" ON "Status" ("uri");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "User_uri_key" ON "User" ("uri");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "User_username_key" ON "User" ("username");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "User_email_key" ON "User" ("email");--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Emoji" ADD CONSTRAINT "Emoji_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "public"."Instance"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Like" ADD CONSTRAINT "Like_likerId_fkey" FOREIGN KEY ("likerId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Like" ADD CONSTRAINT "Like_likedId_fkey" FOREIGN KEY ("likedId") REFERENCES "public"."Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "LysandObject" ADD CONSTRAINT "LysandObject_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "public"."LysandObject"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Relationship" ADD CONSTRAINT "Relationship_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Relationship" ADD CONSTRAINT "Relationship_subjectId_fkey" FOREIGN KEY ("subjectId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Token" ADD CONSTRAINT "Token_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Token" ADD CONSTRAINT "Token_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "public"."Application"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_EmojiToUser" ADD CONSTRAINT "_EmojiToUser_A_fkey" FOREIGN KEY ("A") REFERENCES "public"."Emoji"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_EmojiToUser" ADD CONSTRAINT "_EmojiToUser_B_fkey" FOREIGN KEY ("B") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_EmojiToStatus" ADD CONSTRAINT "_EmojiToStatus_A_fkey" FOREIGN KEY ("A") REFERENCES "public"."Emoji"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_EmojiToStatus" ADD CONSTRAINT "_EmojiToStatus_B_fkey" FOREIGN KEY ("B") REFERENCES "public"."Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_StatusToUser" ADD CONSTRAINT "_StatusToUser_A_fkey" FOREIGN KEY ("A") REFERENCES "public"."Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_StatusToUser" ADD CONSTRAINT "_StatusToUser_B_fkey" FOREIGN KEY ("B") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_UserPinnedNotes" ADD CONSTRAINT "_UserPinnedNotes_A_fkey" FOREIGN KEY ("A") REFERENCES "public"."Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_UserPinnedNotes" ADD CONSTRAINT "_UserPinnedNotes_B_fkey" FOREIGN KEY ("B") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Attachment" ADD CONSTRAINT "Attachment_statusId_fkey" FOREIGN KEY ("statusId") REFERENCES "public"."Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_notifiedId_fkey" FOREIGN KEY ("notifiedId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_statusId_fkey" FOREIGN KEY ("statusId") REFERENCES "public"."Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Status" ADD CONSTRAINT "Status_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Status" ADD CONSTRAINT "Status_reblogId_fkey" FOREIGN KEY ("reblogId") REFERENCES "public"."Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Status" ADD CONSTRAINT "Status_inReplyToPostId_fkey" FOREIGN KEY ("inReplyToPostId") REFERENCES "public"."Status"("id") ON DELETE set null ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Status" ADD CONSTRAINT "Status_quotingPostId_fkey" FOREIGN KEY ("quotingPostId") REFERENCES "public"."Status"("id") ON DELETE set null ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Status" ADD CONSTRAINT "Status_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "public"."Instance"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Status" ADD CONSTRAINT "Status_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "public"."Application"("id") ON DELETE set null ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "OpenIdAccount" ADD CONSTRAINT "OpenIdAccount_userId_fkey" FOREIGN KEY ("userId") REFERENCES "public"."User"("id") ON DELETE set null ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "User" ADD CONSTRAINT "User_instanceId_fkey" FOREIGN KEY ("instanceId") REFERENCES "public"."Instance"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "OpenIdLoginFlow" ADD CONSTRAINT "OpenIdLoginFlow_applicationId_fkey" FOREIGN KEY ("applicationId") REFERENCES "public"."Application"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Flag" ADD CONSTRAINT "Flag_flaggeStatusId_fkey" FOREIGN KEY ("flaggeStatusId") REFERENCES "public"."Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Flag" ADD CONSTRAINT "Flag_flaggedUserId_fkey" FOREIGN KEY ("flaggedUserId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModNote" ADD CONSTRAINT "ModNote_notedStatusId_fkey" FOREIGN KEY ("notedStatusId") REFERENCES "public"."Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModNote" ADD CONSTRAINT "ModNote_notedUserId_fkey" FOREIGN KEY ("notedUserId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModNote" ADD CONSTRAINT "ModNote_modId_fkey" FOREIGN KEY ("modId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModTag" ADD CONSTRAINT "ModTag_taggedStatusId_fkey" FOREIGN KEY ("taggedStatusId") REFERENCES "public"."Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModTag" ADD CONSTRAINT "ModTag_taggedUserId_fkey" FOREIGN KEY ("taggedUserId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModTag" ADD CONSTRAINT "ModTag_modId_fkey" FOREIGN KEY ("modId") REFERENCES "public"."User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
|
@ -0,0 +1,292 @@
|
|||
DROP TABLE "_prisma_migrations";--> statement-breakpoint
|
||||
ALTER TABLE "Emoji" DROP CONSTRAINT "Emoji_instanceId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Like" DROP CONSTRAINT "Like_likerId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Like" DROP CONSTRAINT "Like_likedId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "LysandObject" DROP CONSTRAINT "LysandObject_authorId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Relationship" DROP CONSTRAINT "Relationship_ownerId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Relationship" DROP CONSTRAINT "Relationship_subjectId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Token" DROP CONSTRAINT "Token_userId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Token" DROP CONSTRAINT "Token_applicationId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "_EmojiToUser" DROP CONSTRAINT "_EmojiToUser_A_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "_EmojiToUser" DROP CONSTRAINT "_EmojiToUser_B_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "_EmojiToStatus" DROP CONSTRAINT "_EmojiToStatus_A_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "_EmojiToStatus" DROP CONSTRAINT "_EmojiToStatus_B_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "_StatusToUser" DROP CONSTRAINT "_StatusToUser_A_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "_StatusToUser" DROP CONSTRAINT "_StatusToUser_B_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "_UserPinnedNotes" DROP CONSTRAINT "_UserPinnedNotes_A_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "_UserPinnedNotes" DROP CONSTRAINT "_UserPinnedNotes_B_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Attachment" DROP CONSTRAINT "Attachment_statusId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Notification" DROP CONSTRAINT "Notification_notifiedId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Notification" DROP CONSTRAINT "Notification_accountId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Notification" DROP CONSTRAINT "Notification_statusId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Status" DROP CONSTRAINT "Status_authorId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Status" DROP CONSTRAINT "Status_instanceId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Status" DROP CONSTRAINT "Status_applicationId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Status" DROP CONSTRAINT "Status_reblogId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdAccount" DROP CONSTRAINT "OpenIdAccount_userId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "User" DROP CONSTRAINT "User_instanceId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdLoginFlow" DROP CONSTRAINT "OpenIdLoginFlow_applicationId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Flag" DROP CONSTRAINT "Flag_flaggeStatusId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Flag" DROP CONSTRAINT "Flag_flaggedUserId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "ModNote" DROP CONSTRAINT "ModNote_notedStatusId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "ModNote" DROP CONSTRAINT "ModNote_notedUserId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "ModNote" DROP CONSTRAINT "ModNote_modId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "ModTag" DROP CONSTRAINT "ModTag_taggedStatusId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "ModTag" DROP CONSTRAINT "ModTag_taggedUserId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "ModTag" DROP CONSTRAINT "ModTag_modId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Like" ALTER COLUMN "createdAt" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "LysandObject" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "Relationship" ALTER COLUMN "createdAt" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "Token" ALTER COLUMN "created_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "Notification" ALTER COLUMN "createdAt" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "Status" ALTER COLUMN "createdAt" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "User" ALTER COLUMN "createdAt" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "User" ALTER COLUMN "updatedAt" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "User" ALTER COLUMN "sanctions" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Flag" ALTER COLUMN "createdAt" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "ModNote" ALTER COLUMN "createdAt" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "ModTag" ALTER COLUMN "createdAt" SET DEFAULT now();--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Emoji" ADD CONSTRAINT "Emoji_instanceId_Instance_id_fk" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Like" ADD CONSTRAINT "Like_likerId_User_id_fk" FOREIGN KEY ("likerId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Like" ADD CONSTRAINT "Like_likedId_Status_id_fk" FOREIGN KEY ("likedId") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "LysandObject" ADD CONSTRAINT "LysandObject_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "LysandObject"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Relationship" ADD CONSTRAINT "Relationship_ownerId_User_id_fk" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Relationship" ADD CONSTRAINT "Relationship_subjectId_User_id_fk" FOREIGN KEY ("subjectId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Token" ADD CONSTRAINT "Token_userId_User_id_fk" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Token" ADD CONSTRAINT "Token_applicationId_Application_id_fk" FOREIGN KEY ("applicationId") REFERENCES "Application"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_EmojiToUser" ADD CONSTRAINT "_EmojiToUser_A_Emoji_id_fk" FOREIGN KEY ("A") REFERENCES "Emoji"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_EmojiToUser" ADD CONSTRAINT "_EmojiToUser_B_User_id_fk" FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_EmojiToStatus" ADD CONSTRAINT "_EmojiToStatus_A_Emoji_id_fk" FOREIGN KEY ("A") REFERENCES "Emoji"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_EmojiToStatus" ADD CONSTRAINT "_EmojiToStatus_B_Status_id_fk" FOREIGN KEY ("B") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_StatusToUser" ADD CONSTRAINT "_StatusToUser_A_Status_id_fk" FOREIGN KEY ("A") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_StatusToUser" ADD CONSTRAINT "_StatusToUser_B_User_id_fk" FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_UserPinnedNotes" ADD CONSTRAINT "_UserPinnedNotes_A_Status_id_fk" FOREIGN KEY ("A") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "_UserPinnedNotes" ADD CONSTRAINT "_UserPinnedNotes_B_User_id_fk" FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Attachment" ADD CONSTRAINT "Attachment_statusId_Status_id_fk" FOREIGN KEY ("statusId") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_notifiedId_User_id_fk" FOREIGN KEY ("notifiedId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_accountId_User_id_fk" FOREIGN KEY ("accountId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_statusId_Status_id_fk" FOREIGN KEY ("statusId") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Status" ADD CONSTRAINT "Status_authorId_User_id_fk" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Status" ADD CONSTRAINT "Status_instanceId_Instance_id_fk" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Status" ADD CONSTRAINT "Status_applicationId_Application_id_fk" FOREIGN KEY ("applicationId") REFERENCES "Application"("id") ON DELETE set null ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Status" ADD CONSTRAINT "Status_reblogId_fkey" FOREIGN KEY ("reblogId") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "OpenIdAccount" ADD CONSTRAINT "OpenIdAccount_userId_User_id_fk" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE set null ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "User" ADD CONSTRAINT "User_instanceId_Instance_id_fk" FOREIGN KEY ("instanceId") REFERENCES "Instance"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "OpenIdLoginFlow" ADD CONSTRAINT "OpenIdLoginFlow_applicationId_Application_id_fk" FOREIGN KEY ("applicationId") REFERENCES "Application"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Flag" ADD CONSTRAINT "Flag_flaggeStatusId_Status_id_fk" FOREIGN KEY ("flaggeStatusId") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Flag" ADD CONSTRAINT "Flag_flaggedUserId_User_id_fk" FOREIGN KEY ("flaggedUserId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModNote" ADD CONSTRAINT "ModNote_notedStatusId_Status_id_fk" FOREIGN KEY ("notedStatusId") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModNote" ADD CONSTRAINT "ModNote_notedUserId_User_id_fk" FOREIGN KEY ("notedUserId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModNote" ADD CONSTRAINT "ModNote_modId_User_id_fk" FOREIGN KEY ("modId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModTag" ADD CONSTRAINT "ModTag_taggedStatusId_Status_id_fk" FOREIGN KEY ("taggedStatusId") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModTag" ADD CONSTRAINT "ModTag_taggedUserId_User_id_fk" FOREIGN KEY ("taggedUserId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModTag" ADD CONSTRAINT "ModTag_modId_User_id_fk" FOREIGN KEY ("modId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
20
packages/plugin-kit/tables/migrations/0002_stiff_ares.sql
Normal file
20
packages/plugin-kit/tables/migrations/0002_stiff_ares.sql
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
ALTER TABLE "_StatusToUser" RENAME TO "StatusToMentions";--> statement-breakpoint
|
||||
ALTER TABLE "StatusToMentions" DROP CONSTRAINT "_StatusToUser_A_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "StatusToMentions" DROP CONSTRAINT "_StatusToUser_B_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "_StatusToUser_AB_unique";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "_StatusToUser_B_index";--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "StatusToMentions_A_B_index" ON "StatusToMentions" ("A","B");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "StatusToMentions_B_index" ON "StatusToMentions" ("B");--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "StatusToMentions" ADD CONSTRAINT "StatusToMentions_A_Status_id_fk" FOREIGN KEY ("A") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "StatusToMentions" ADD CONSTRAINT "StatusToMentions_B_User_id_fk" FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
21
packages/plugin-kit/tables/migrations/0003_spicy_arachne.sql
Normal file
21
packages/plugin-kit/tables/migrations/0003_spicy_arachne.sql
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
ALTER TABLE "StatusToMentions" RENAME COLUMN "A" TO "statusId";--> statement-breakpoint
|
||||
ALTER TABLE "StatusToMentions" RENAME COLUMN "B" TO "userId";--> statement-breakpoint
|
||||
ALTER TABLE "StatusToMentions" DROP CONSTRAINT "StatusToMentions_A_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "StatusToMentions" DROP CONSTRAINT "StatusToMentions_B_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "StatusToMentions_A_B_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "StatusToMentions_B_index";--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "StatusToMentions_statusId_userId_index" ON "StatusToMentions" ("statusId","userId");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "StatusToMentions_userId_index" ON "StatusToMentions" ("userId");--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "StatusToMentions" ADD CONSTRAINT "StatusToMentions_statusId_Status_id_fk" FOREIGN KEY ("statusId") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "StatusToMentions" ADD CONSTRAINT "StatusToMentions_userId_User_id_fk" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
57
packages/plugin-kit/tables/migrations/0004_burly_lockjaw.sql
Normal file
57
packages/plugin-kit/tables/migrations/0004_burly_lockjaw.sql
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
ALTER TABLE "_EmojiToStatus" RENAME TO "EmojiToStatus";--> statement-breakpoint
|
||||
ALTER TABLE "_UserPinnedNotes" RENAME TO "UserToPinnedNotes";--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToStatus" RENAME COLUMN "A" TO "emojiId";--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToStatus" RENAME COLUMN "B" TO "statusId";--> statement-breakpoint
|
||||
ALTER TABLE "UserToPinnedNotes" RENAME COLUMN "A" TO "userId";--> statement-breakpoint
|
||||
ALTER TABLE "UserToPinnedNotes" RENAME COLUMN "B" TO "statusId";--> statement-breakpoint
|
||||
ALTER TABLE "LysandObject" DROP CONSTRAINT "LysandObject_authorId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToStatus" DROP CONSTRAINT "_EmojiToStatus_A_Emoji_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToStatus" DROP CONSTRAINT "_EmojiToStatus_B_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "UserToPinnedNotes" DROP CONSTRAINT "_UserPinnedNotes_A_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "UserToPinnedNotes" DROP CONSTRAINT "_UserPinnedNotes_B_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "LysandObject_remote_id_key";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "LysandObject_uri_key";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "_EmojiToStatus_AB_unique";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "_EmojiToStatus_B_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "_UserPinnedNotes_AB_unique";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "_UserPinnedNotes_B_index";--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "LysandObject_remote_id_index" ON "LysandObject" ("remote_id");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "LysandObject_uri_index" ON "LysandObject" ("uri");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "EmojiToStatus_emojiId_statusId_index" ON "EmojiToStatus" ("emojiId","statusId");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "EmojiToStatus_statusId_index" ON "EmojiToStatus" ("statusId");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "UserToPinnedNotes_userId_statusId_index" ON "UserToPinnedNotes" ("userId","statusId");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "UserToPinnedNotes_statusId_index" ON "UserToPinnedNotes" ("statusId");--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "LysandObject" ADD CONSTRAINT "LysandObject_authorId_LysandObject_id_fk" FOREIGN KEY ("authorId") REFERENCES "LysandObject"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "EmojiToStatus" ADD CONSTRAINT "EmojiToStatus_emojiId_Emoji_id_fk" FOREIGN KEY ("emojiId") REFERENCES "Emoji"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "EmojiToStatus" ADD CONSTRAINT "EmojiToStatus_statusId_Status_id_fk" FOREIGN KEY ("statusId") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "UserToPinnedNotes" ADD CONSTRAINT "UserToPinnedNotes_userId_Status_id_fk" FOREIGN KEY ("userId") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "UserToPinnedNotes" ADD CONSTRAINT "UserToPinnedNotes_statusId_User_id_fk" FOREIGN KEY ("statusId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
40
packages/plugin-kit/tables/migrations/0005_sleepy_puma.sql
Normal file
40
packages/plugin-kit/tables/migrations/0005_sleepy_puma.sql
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
ALTER TABLE "Instance" RENAME COLUMN "disableAutomoderation" TO "disable_automoderation";--> statement-breakpoint
|
||||
ALTER TABLE "Relationship" RENAME COLUMN "showingReblogs" TO "showing_reblogs";--> statement-breakpoint
|
||||
ALTER TABLE "Relationship" RENAME COLUMN "followedBy" TO "followed_by";--> statement-breakpoint
|
||||
ALTER TABLE "Relationship" RENAME COLUMN "blockedBy" TO "blocked_by";--> statement-breakpoint
|
||||
ALTER TABLE "Relationship" RENAME COLUMN "mutingNotifications" TO "muting_notifications";--> statement-breakpoint
|
||||
ALTER TABLE "Relationship" RENAME COLUMN "domainBlocking" TO "domain_blocking";--> statement-breakpoint
|
||||
ALTER TABLE "Relationship" RENAME COLUMN "createdAt" TO "created_at";--> statement-breakpoint
|
||||
ALTER TABLE "Relationship" RENAME COLUMN "updatedAt" TO "updated_at";--> statement-breakpoint
|
||||
ALTER TABLE "Status" RENAME COLUMN "contentType" TO "content_type";--> statement-breakpoint
|
||||
ALTER TABLE "Status" RENAME COLUMN "spoilerText" TO "spoiler_text";--> statement-breakpoint
|
||||
ALTER TABLE "Status" RENAME COLUMN "contentSource" TO "content_source";--> statement-breakpoint
|
||||
ALTER TABLE "Status" DROP CONSTRAINT "Status_reblogId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Status" DROP CONSTRAINT "Status_inReplyToPostId_fkey";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Status" DROP CONSTRAINT "Status_quotingPostId_fkey";
|
||||
--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "Application_client_id_key";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "Status_uri_key";--> statement-breakpoint
|
||||
ALTER TABLE "Relationship" ALTER COLUMN "updated_at" SET DEFAULT now();--> statement-breakpoint
|
||||
ALTER TABLE "Status" ALTER COLUMN "updatedAt" SET DEFAULT now();--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Application_client_id_index" ON "Application" ("client_id");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Status_uri_index" ON "Status" ("uri");--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Status" ADD CONSTRAINT "Status_reblogId_Status_id_fk" FOREIGN KEY ("reblogId") REFERENCES "Status"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Status" ADD CONSTRAINT "Status_inReplyToPostId_Status_id_fk" FOREIGN KEY ("inReplyToPostId") REFERENCES "Status"("id") ON DELETE set null ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Status" ADD CONSTRAINT "Status_quotingPostId_Status_id_fk" FOREIGN KEY ("quotingPostId") REFERENCES "Status"("id") ON DELETE set null ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
46
packages/plugin-kit/tables/migrations/0006_messy_network.sql
Normal file
46
packages/plugin-kit/tables/migrations/0006_messy_network.sql
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
ALTER TABLE "_EmojiToUser" RENAME TO "EmojiToUser";--> statement-breakpoint
|
||||
ALTER TABLE "Flag" RENAME COLUMN "flagType" TO "flag_type";--> statement-breakpoint
|
||||
ALTER TABLE "Flag" RENAME COLUMN "createdAt" TO "created_at";--> statement-breakpoint
|
||||
ALTER TABLE "ModNote" RENAME COLUMN "createdAt" TO "created_at";--> statement-breakpoint
|
||||
ALTER TABLE "ModTag" RENAME COLUMN "createdAt" TO "created_at";--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdAccount" RENAME COLUMN "serverId" TO "server_id";--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdAccount" RENAME COLUMN "issuerId" TO "issuer_id";--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdLoginFlow" RENAME COLUMN "codeVerifier" TO "code_verifier";--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdLoginFlow" RENAME COLUMN "issuerId" TO "issuer_id";--> statement-breakpoint
|
||||
ALTER TABLE "User" RENAME COLUMN "displayName" TO "display_name";--> statement-breakpoint
|
||||
ALTER TABLE "User" RENAME COLUMN "isAdmin" TO "is_admin";--> statement-breakpoint
|
||||
ALTER TABLE "User" RENAME COLUMN "createdAt" TO "created_at";--> statement-breakpoint
|
||||
ALTER TABLE "User" RENAME COLUMN "updatedAt" TO "updated_at";--> statement-breakpoint
|
||||
ALTER TABLE "User" RENAME COLUMN "isBot" TO "is_bot";--> statement-breakpoint
|
||||
ALTER TABLE "User" RENAME COLUMN "isLocked" TO "is_locked";--> statement-breakpoint
|
||||
ALTER TABLE "User" RENAME COLUMN "isDiscoverable" TO "is_discoverable";--> statement-breakpoint
|
||||
ALTER TABLE "User" RENAME COLUMN "publicKey" TO "public_key";--> statement-breakpoint
|
||||
ALTER TABLE "User" RENAME COLUMN "privateKey" TO "private_key";--> statement-breakpoint
|
||||
ALTER TABLE "User" RENAME COLUMN "disableAutomoderation" TO "disable_automoderation";--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToUser" RENAME COLUMN "A" TO "emojiId";--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToUser" RENAME COLUMN "B" TO "userId";--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToUser" DROP CONSTRAINT "_EmojiToUser_A_Emoji_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToUser" DROP CONSTRAINT "_EmojiToUser_B_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "User_uri_key";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "User_username_key";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "User_email_key";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "_EmojiToUser_AB_unique";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "_EmojiToUser_B_index";--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "User_uri_index" ON "User" ("uri");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "User_username_index" ON "User" ("username");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "User_email_index" ON "User" ("email");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "EmojiToUser_emojiId_userId_index" ON "EmojiToUser" ("emojiId","userId");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "EmojiToUser_userId_index" ON "EmojiToUser" ("userId");--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "EmojiToUser" ADD CONSTRAINT "EmojiToUser_emojiId_Emoji_id_fk" FOREIGN KEY ("emojiId") REFERENCES "Emoji"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "EmojiToUser" ADD CONSTRAINT "EmojiToUser_userId_User_id_fk" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE "Status" DROP CONSTRAINT "Status_instanceId_Instance_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Status" DROP COLUMN IF EXISTS "instanceId";
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "Notification" ADD COLUMN "dismissed" boolean DEFAULT false NOT NULL;
|
||||
331
packages/plugin-kit/tables/migrations/0009_easy_slyde.sql
Normal file
331
packages/plugin-kit/tables/migrations/0009_easy_slyde.sql
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
ALTER TABLE "Application" RENAME TO "Applications";--> statement-breakpoint
|
||||
ALTER TABLE "Attachment" RENAME TO "Attachments";--> statement-breakpoint
|
||||
ALTER TABLE "Emoji" RENAME TO "Emojis";--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToStatus" RENAME TO "EmojiToNote";--> statement-breakpoint
|
||||
ALTER TABLE "Flag" RENAME TO "Flags";--> statement-breakpoint
|
||||
ALTER TABLE "Instance" RENAME TO "Instances";--> statement-breakpoint
|
||||
ALTER TABLE "Like" RENAME TO "Likes";--> statement-breakpoint
|
||||
ALTER TABLE "ModNote" RENAME TO "ModNotes";--> statement-breakpoint
|
||||
ALTER TABLE "ModTag" RENAME TO "ModTags";--> statement-breakpoint
|
||||
ALTER TABLE "Notification" RENAME TO "Notifications";--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdAccount" RENAME TO "OpenIdAccounts";--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdLoginFlow" RENAME TO "OpenIdLoginFlows";--> statement-breakpoint
|
||||
ALTER TABLE "Relationship" RENAME TO "Relationships";--> statement-breakpoint
|
||||
ALTER TABLE "Status" RENAME TO "Notes";--> statement-breakpoint
|
||||
ALTER TABLE "StatusToMentions" RENAME TO "NoteToMentions";--> statement-breakpoint
|
||||
ALTER TABLE "Token" RENAME TO "Tokens";--> statement-breakpoint
|
||||
ALTER TABLE "User" RENAME TO "Users";--> statement-breakpoint
|
||||
ALTER TABLE "UserToPinnedNotes" RENAME COLUMN "statusId" TO "noteId";--> statement-breakpoint
|
||||
ALTER TABLE "Attachments" RENAME COLUMN "statusId" TO "noteId";--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToNote" RENAME COLUMN "statusId" TO "noteId";--> statement-breakpoint
|
||||
ALTER TABLE "Flags" RENAME COLUMN "flaggeStatusId" TO "noteId";--> statement-breakpoint
|
||||
ALTER TABLE "Flags" RENAME COLUMN "flaggedUserId" TO "userId";--> statement-breakpoint
|
||||
ALTER TABLE "ModNotes" RENAME COLUMN "notedStatusId" TO "noteId";--> statement-breakpoint
|
||||
ALTER TABLE "ModNotes" RENAME COLUMN "notedUserId" TO "userId";--> statement-breakpoint
|
||||
ALTER TABLE "ModTags" RENAME COLUMN "taggedStatusId" TO "statusId";--> statement-breakpoint
|
||||
ALTER TABLE "ModTags" RENAME COLUMN "taggedUserId" TO "userId";--> statement-breakpoint
|
||||
ALTER TABLE "Notifications" RENAME COLUMN "statusId" TO "noteId";--> statement-breakpoint
|
||||
ALTER TABLE "Notes" RENAME COLUMN "inReplyToPostId" TO "replyId";--> statement-breakpoint
|
||||
ALTER TABLE "Notes" RENAME COLUMN "quotingPostId" TO "quoteId";--> statement-breakpoint
|
||||
ALTER TABLE "NoteToMentions" RENAME COLUMN "statusId" TO "noteId";--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToUser" DROP CONSTRAINT "EmojiToUser_emojiId_Emoji_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToUser" DROP CONSTRAINT "EmojiToUser_userId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "UserToPinnedNotes" DROP CONSTRAINT "UserToPinnedNotes_userId_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "UserToPinnedNotes" DROP CONSTRAINT "UserToPinnedNotes_statusId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Attachments" DROP CONSTRAINT "Attachment_statusId_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Emojis" DROP CONSTRAINT "Emoji_instanceId_Instance_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToNote" DROP CONSTRAINT "EmojiToStatus_emojiId_Emoji_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "EmojiToNote" DROP CONSTRAINT "EmojiToStatus_statusId_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Flags" DROP CONSTRAINT "Flag_flaggeStatusId_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Flags" DROP CONSTRAINT "Flag_flaggedUserId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Likes" DROP CONSTRAINT "Like_likerId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Likes" DROP CONSTRAINT "Like_likedId_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "ModNotes" DROP CONSTRAINT "ModNote_notedStatusId_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "ModNotes" DROP CONSTRAINT "ModNote_notedUserId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "ModNotes" DROP CONSTRAINT "ModNote_modId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "ModTags" DROP CONSTRAINT "ModTag_taggedStatusId_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "ModTags" DROP CONSTRAINT "ModTag_taggedUserId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "ModTags" DROP CONSTRAINT "ModTag_modId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Notifications" DROP CONSTRAINT "Notification_notifiedId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Notifications" DROP CONSTRAINT "Notification_accountId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Notifications" DROP CONSTRAINT "Notification_statusId_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdAccounts" DROP CONSTRAINT "OpenIdAccount_userId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdLoginFlows" DROP CONSTRAINT "OpenIdLoginFlow_applicationId_Application_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Relationships" DROP CONSTRAINT "Relationship_ownerId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Relationships" DROP CONSTRAINT "Relationship_subjectId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Notes" DROP CONSTRAINT "Status_authorId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Notes" DROP CONSTRAINT "Status_applicationId_Application_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Notes" DROP CONSTRAINT "Status_reblogId_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Notes" DROP CONSTRAINT "Status_inReplyToPostId_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Notes" DROP CONSTRAINT "Status_quotingPostId_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "NoteToMentions" DROP CONSTRAINT "StatusToMentions_statusId_Status_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "NoteToMentions" DROP CONSTRAINT "StatusToMentions_userId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Tokens" DROP CONSTRAINT "Token_userId_User_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Tokens" DROP CONSTRAINT "Token_applicationId_Application_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Users" DROP CONSTRAINT "User_instanceId_Instance_id_fk";
|
||||
--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "UserToPinnedNotes_userId_statusId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "UserToPinnedNotes_statusId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "Application_client_id_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "EmojiToStatus_emojiId_statusId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "EmojiToStatus_statusId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "Status_uri_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "StatusToMentions_statusId_userId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "StatusToMentions_userId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "User_uri_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "User_username_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "User_email_index";--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "UserToPinnedNotes_userId_noteId_index" ON "UserToPinnedNotes" ("userId","noteId");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "UserToPinnedNotes_noteId_index" ON "UserToPinnedNotes" ("noteId");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Applications_client_id_index" ON "Applications" ("client_id");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "EmojiToNote_emojiId_noteId_index" ON "EmojiToNote" ("emojiId","noteId");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "EmojiToNote_noteId_index" ON "EmojiToNote" ("noteId");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Notes_uri_index" ON "Notes" ("uri");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "NoteToMentions_noteId_userId_index" ON "NoteToMentions" ("noteId","userId");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "NoteToMentions_userId_index" ON "NoteToMentions" ("userId");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Users_uri_index" ON "Users" ("uri");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Users_username_index" ON "Users" ("username");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Users_email_index" ON "Users" ("email");--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "EmojiToUser" ADD CONSTRAINT "EmojiToUser_emojiId_Emojis_id_fk" FOREIGN KEY ("emojiId") REFERENCES "Emojis"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "EmojiToUser" ADD CONSTRAINT "EmojiToUser_userId_Users_id_fk" FOREIGN KEY ("userId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "UserToPinnedNotes" ADD CONSTRAINT "UserToPinnedNotes_userId_Notes_id_fk" FOREIGN KEY ("userId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "UserToPinnedNotes" ADD CONSTRAINT "UserToPinnedNotes_noteId_Users_id_fk" FOREIGN KEY ("noteId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Attachments" ADD CONSTRAINT "Attachments_noteId_Notes_id_fk" FOREIGN KEY ("noteId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Emojis" ADD CONSTRAINT "Emojis_instanceId_Instances_id_fk" FOREIGN KEY ("instanceId") REFERENCES "Instances"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "EmojiToNote" ADD CONSTRAINT "EmojiToNote_emojiId_Emojis_id_fk" FOREIGN KEY ("emojiId") REFERENCES "Emojis"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "EmojiToNote" ADD CONSTRAINT "EmojiToNote_noteId_Notes_id_fk" FOREIGN KEY ("noteId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Flags" ADD CONSTRAINT "Flags_noteId_Notes_id_fk" FOREIGN KEY ("noteId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Flags" ADD CONSTRAINT "Flags_userId_Users_id_fk" FOREIGN KEY ("userId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Likes" ADD CONSTRAINT "Likes_likerId_Users_id_fk" FOREIGN KEY ("likerId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Likes" ADD CONSTRAINT "Likes_likedId_Notes_id_fk" FOREIGN KEY ("likedId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModNotes" ADD CONSTRAINT "ModNotes_noteId_Notes_id_fk" FOREIGN KEY ("noteId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModNotes" ADD CONSTRAINT "ModNotes_userId_Users_id_fk" FOREIGN KEY ("userId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModNotes" ADD CONSTRAINT "ModNotes_modId_Users_id_fk" FOREIGN KEY ("modId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModTags" ADD CONSTRAINT "ModTags_statusId_Notes_id_fk" FOREIGN KEY ("statusId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModTags" ADD CONSTRAINT "ModTags_userId_Users_id_fk" FOREIGN KEY ("userId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModTags" ADD CONSTRAINT "ModTags_modId_Users_id_fk" FOREIGN KEY ("modId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notifications" ADD CONSTRAINT "Notifications_notifiedId_Users_id_fk" FOREIGN KEY ("notifiedId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notifications" ADD CONSTRAINT "Notifications_accountId_Users_id_fk" FOREIGN KEY ("accountId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notifications" ADD CONSTRAINT "Notifications_noteId_Notes_id_fk" FOREIGN KEY ("noteId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "OpenIdAccounts" ADD CONSTRAINT "OpenIdAccounts_userId_Users_id_fk" FOREIGN KEY ("userId") REFERENCES "Users"("id") ON DELETE set null ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "OpenIdLoginFlows" ADD CONSTRAINT "OpenIdLoginFlows_applicationId_Applications_id_fk" FOREIGN KEY ("applicationId") REFERENCES "Applications"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Relationships" ADD CONSTRAINT "Relationships_ownerId_Users_id_fk" FOREIGN KEY ("ownerId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Relationships" ADD CONSTRAINT "Relationships_subjectId_Users_id_fk" FOREIGN KEY ("subjectId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notes" ADD CONSTRAINT "Notes_authorId_Users_id_fk" FOREIGN KEY ("authorId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notes" ADD CONSTRAINT "Notes_applicationId_Applications_id_fk" FOREIGN KEY ("applicationId") REFERENCES "Applications"("id") ON DELETE set null ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notes" ADD CONSTRAINT "Notes_reblogId_Notes_id_fk" FOREIGN KEY ("reblogId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notes" ADD CONSTRAINT "Notes_replyId_Notes_id_fk" FOREIGN KEY ("replyId") REFERENCES "Notes"("id") ON DELETE set null ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notes" ADD CONSTRAINT "Notes_quoteId_Notes_id_fk" FOREIGN KEY ("quoteId") REFERENCES "Notes"("id") ON DELETE set null ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "NoteToMentions" ADD CONSTRAINT "NoteToMentions_noteId_Notes_id_fk" FOREIGN KEY ("noteId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "NoteToMentions" ADD CONSTRAINT "NoteToMentions_userId_Users_id_fk" FOREIGN KEY ("userId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Tokens" ADD CONSTRAINT "Tokens_userId_Users_id_fk" FOREIGN KEY ("userId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Tokens" ADD CONSTRAINT "Tokens_applicationId_Applications_id_fk" FOREIGN KEY ("applicationId") REFERENCES "Applications"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Users" ADD CONSTRAINT "Users_instanceId_Instances_id_fk" FOREIGN KEY ("instanceId") REFERENCES "Instances"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
ALTER TABLE "ModTags" RENAME COLUMN "statusId" TO "noteId";--> statement-breakpoint
|
||||
ALTER TABLE "ModTags" DROP CONSTRAINT "ModTags_statusId_Notes_id_fk";
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "ModTags" ADD CONSTRAINT "ModTags_noteId_Notes_id_fk" FOREIGN KEY ("noteId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
ALTER TABLE "UserToPinnedNotes" DROP CONSTRAINT "UserToPinnedNotes_userId_Notes_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "UserToPinnedNotes" DROP CONSTRAINT "UserToPinnedNotes_noteId_Users_id_fk";
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "UserToPinnedNotes" ADD CONSTRAINT "UserToPinnedNotes_userId_Users_id_fk" FOREIGN KEY ("userId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "UserToPinnedNotes" ADD CONSTRAINT "UserToPinnedNotes_noteId_Notes_id_fk" FOREIGN KEY ("noteId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
CREATE TABLE IF NOT EXISTS "Markers" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"noteId" uuid,
|
||||
"userId" uuid,
|
||||
"timeline" text NOT NULL,
|
||||
"created_at" timestamp(3) DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Markers" ADD CONSTRAINT "Markers_noteId_Notes_id_fk" FOREIGN KEY ("noteId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Markers" ADD CONSTRAINT "Markers_userId_Users_id_fk" FOREIGN KEY ("userId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
ALTER TABLE "Markers" ALTER COLUMN "userId" SET NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Markers" ADD COLUMN "notificationId" uuid;--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Markers" ADD CONSTRAINT "Markers_notificationId_Notifications_id_fk" FOREIGN KEY ("notificationId") REFERENCES "Notifications"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
CREATE TABLE IF NOT EXISTS "FilterKeywords" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"filterId" uuid NOT NULL,
|
||||
"keyword" text NOT NULL,
|
||||
"whole_word" boolean NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "Filters" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"userId" uuid NOT NULL,
|
||||
"context" text[],
|
||||
"title" text NOT NULL,
|
||||
"filter_action" text NOT NULL,
|
||||
"expires_at" timestamp(3),
|
||||
"created_at" timestamp(3) DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "FilterKeywords" ADD CONSTRAINT "FilterKeywords_filterId_Filters_id_fk" FOREIGN KEY ("filterId") REFERENCES "Filters"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Filters" ADD CONSTRAINT "Filters_userId_Users_id_fk" FOREIGN KEY ("userId") REFERENCES "Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
1
packages/plugin-kit/tables/migrations/0015_easy_mojo.sql
Normal file
1
packages/plugin-kit/tables/migrations/0015_easy_mojo.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "Tokens" ALTER COLUMN "userId" SET NOT NULL;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE "Applications" RENAME COLUMN "redirect_uris" TO "redirect_uri";--> statement-breakpoint
|
||||
ALTER TABLE "Tokens" ADD COLUMN "client_id" text NOT NULL DEFAULT '';--> statement-breakpoint
|
||||
ALTER TABLE "Tokens" ADD COLUMN "redirect_uri" text NOT NULL DEFAULT '';
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE "Tokens" ALTER COLUMN "code" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Tokens" ADD COLUMN "expires_at" timestamp(3);
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE "Tokens" ALTER COLUMN "client_id" SET DEFAULT '';
|
||||
ALTER TABLE "Tokens" ALTER COLUMN "redirect_uri" SET DEFAULT '';
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "Tokens" ADD COLUMN "id_token" text;
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "Users" ADD COLUMN "fields" jsonb DEFAULT '[]' NOT NULL;
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
ALTER TABLE "Notes" DROP CONSTRAINT "Notes_replyId_Notes_id_fk";
|
||||
--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "Notes_uri_index";--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Notes" ADD CONSTRAINT "Notes_replyId_Notes_id_fk" FOREIGN KEY ("replyId") REFERENCES "Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Notes" ADD CONSTRAINT "Notes_uri_unique" UNIQUE("uri");
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
ALTER TABLE "Emojis" ADD COLUMN "ownerId" uuid;--> statement-breakpoint
|
||||
ALTER TABLE "Emojis" ADD COLUMN "category" text;--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Emojis" ADD CONSTRAINT "Emojis_ownerId_Users_id_fk" FOREIGN KEY ("ownerId") REFERENCES "public"."Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE "Users" ADD COLUMN "email_verification_token" text;--> statement-breakpoint
|
||||
ALTER TABLE "Users" ADD COLUMN "password_reset_token" text;
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
CREATE TABLE IF NOT EXISTS "RoleToUsers" (
|
||||
"roleId" uuid NOT NULL,
|
||||
"userId" uuid NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "Roles" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"permissions" text[] NOT NULL,
|
||||
"priority" integer DEFAULT 0 NOT NULL,
|
||||
"description" text,
|
||||
"visible" boolean DEFAULT false NOT NULL,
|
||||
"icon" text
|
||||
);
|
||||
--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "Applications_client_id_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "EmojiToNote_emojiId_noteId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "EmojiToNote_noteId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "EmojiToUser_emojiId_userId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "EmojiToUser_userId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "LysandObject_remote_id_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "LysandObject_uri_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "NoteToMentions_noteId_userId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "NoteToMentions_userId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "UserToPinnedNotes_userId_noteId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "UserToPinnedNotes_noteId_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "Users_uri_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "Users_username_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "Users_email_index";--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "RoleToUsers" ADD CONSTRAINT "RoleToUsers_roleId_Roles_id_fk" FOREIGN KEY ("roleId") REFERENCES "public"."Roles"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "RoleToUsers" ADD CONSTRAINT "RoleToUsers_userId_Users_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Applications_client_id_index" ON "Applications" USING btree ("client_id");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "EmojiToNote_emojiId_noteId_index" ON "EmojiToNote" USING btree ("emojiId","noteId");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "EmojiToNote_noteId_index" ON "EmojiToNote" USING btree ("noteId");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "EmojiToUser_emojiId_userId_index" ON "EmojiToUser" USING btree ("emojiId","userId");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "EmojiToUser_userId_index" ON "EmojiToUser" USING btree ("userId");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "LysandObject_remote_id_index" ON "LysandObject" USING btree ("remote_id");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "LysandObject_uri_index" ON "LysandObject" USING btree ("uri");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "NoteToMentions_noteId_userId_index" ON "NoteToMentions" USING btree ("noteId","userId");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "NoteToMentions_userId_index" ON "NoteToMentions" USING btree ("userId");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "UserToPinnedNotes_userId_noteId_index" ON "UserToPinnedNotes" USING btree ("userId","noteId");--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "UserToPinnedNotes_noteId_index" ON "UserToPinnedNotes" USING btree ("noteId");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Users_uri_index" ON "Users" USING btree ("uri");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Users_username_index" ON "Users" USING btree ("username");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "Users_email_index" ON "Users" USING btree ("email");
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "Relationships" ADD COLUMN "requested_by" boolean DEFAULT false NOT NULL;
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
CREATE TABLE IF NOT EXISTS "CaptchaChallenges" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"challenge" jsonb NOT NULL,
|
||||
"expires_at" timestamp(3) DEFAULT NOW() + INTERVAL '5 minutes',
|
||||
"created_at" timestamp(3) DEFAULT now() NOT NULL
|
||||
);
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "CaptchaChallenges" RENAME TO "Challenges";
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE "Challenges" ALTER COLUMN "expires_at" SET NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Instances" ADD COLUMN "protocol" text DEFAULT 'lysand' NOT NULL;
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "Instances" ALTER COLUMN "logo" DROP NOT NULL;
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
DROP INDEX IF EXISTS "Users_username_index";--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "Users_username_index" ON "Users" USING btree ("username");
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE "Relationships" DROP COLUMN IF EXISTS "followed_by";--> statement-breakpoint
|
||||
ALTER TABLE "Relationships" DROP COLUMN IF EXISTS "blocked_by";--> statement-breakpoint
|
||||
ALTER TABLE "Relationships" DROP COLUMN IF EXISTS "requested_by";
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
ALTER TABLE "LysandObject" RENAME TO "VersiaObject";--> statement-breakpoint
|
||||
ALTER TABLE "VersiaObject" DROP CONSTRAINT "LysandObject_authorId_LysandObject_id_fk";
|
||||
--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "LysandObject_remote_id_index";--> statement-breakpoint
|
||||
DROP INDEX IF EXISTS "LysandObject_uri_index";--> statement-breakpoint
|
||||
ALTER TABLE "Instances" ALTER COLUMN "protocol" SET DEFAULT 'versia';--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "VersiaObject" ADD CONSTRAINT "VersiaObject_authorId_VersiaObject_id_fk" FOREIGN KEY ("authorId") REFERENCES "public"."VersiaObject"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "VersiaObject_remote_id_index" ON "VersiaObject" USING btree ("remote_id");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "VersiaObject_uri_index" ON "VersiaObject" USING btree ("uri");
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "Filters" ALTER COLUMN "context" SET NOT NULL;
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE "Likes" ADD COLUMN "uri" text;--> statement-breakpoint
|
||||
ALTER TABLE "Likes" ADD CONSTRAINT "Likes_uri_unique" UNIQUE("uri");
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "Instances" ADD COLUMN "public_key" jsonb;
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE "Instances" ADD COLUMN "inbox" text;--> statement-breakpoint
|
||||
ALTER TABLE "Instances" ADD COLUMN "extensions" jsonb;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
CREATE TABLE IF NOT EXISTS "Reaction" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"emojiId" uuid NOT NULL,
|
||||
"noteId" uuid NOT NULL,
|
||||
"authorId" uuid NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Reaction" ADD CONSTRAINT "Reaction_emojiId_Emojis_id_fk" FOREIGN KEY ("emojiId") REFERENCES "public"."Emojis"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Reaction" ADD CONSTRAINT "Reaction_noteId_Notes_id_fk" FOREIGN KEY ("noteId") REFERENCES "public"."Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Reaction" ADD CONSTRAINT "Reaction_authorId_Users_id_fk" FOREIGN KEY ("authorId") REFERENCES "public"."Users"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
ALTER TABLE "Reaction" ALTER COLUMN "emojiId" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Reaction" ADD COLUMN "uri" text;--> statement-breakpoint
|
||||
ALTER TABLE "Reaction" ADD COLUMN "emoji_text" text;--> statement-breakpoint
|
||||
ALTER TABLE "Reaction" ADD COLUMN "created_at" timestamp(3) DEFAULT now() NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Reaction" ADD COLUMN "update_at" timestamp(3) DEFAULT now() NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Reaction" ADD CONSTRAINT "Reaction_uri_unique" UNIQUE("uri");
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
ALTER TABLE "VersiaObject" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
DROP TABLE "VersiaObject" CASCADE;--> statement-breakpoint
|
||||
ALTER TABLE "Likes" RENAME COLUMN "createdAt" TO "created_at";--> statement-breakpoint
|
||||
ALTER TABLE "Notes" RENAME COLUMN "createdAt" TO "created_at";--> statement-breakpoint
|
||||
ALTER TABLE "Notes" RENAME COLUMN "updatedAt" TO "updated_at";--> statement-breakpoint
|
||||
ALTER TABLE "Notifications" RENAME COLUMN "createdAt" TO "created_at";--> statement-breakpoint
|
||||
ALTER TABLE "Reaction" RENAME COLUMN "update_at" TO "updated_at";--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdAccounts" DROP CONSTRAINT "OpenIdAccounts_userId_Users_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdAccounts" ADD CONSTRAINT "OpenIdAccounts_userId_Users_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."Users"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
|
||||
ALTER TABLE "Users" ADD CONSTRAINT "Users_uri_unique" UNIQUE("uri");
|
||||
14
packages/plugin-kit/tables/migrations/0040_good_nocturne.sql
Normal file
14
packages/plugin-kit/tables/migrations/0040_good_nocturne.sql
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
CREATE TABLE "PushSubscriptions" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"endpoint" text NOT NULL,
|
||||
"public_key" text NOT NULL,
|
||||
"auth_secret" text NOT NULL,
|
||||
"alerts" jsonb NOT NULL,
|
||||
"policy" text NOT NULL,
|
||||
"created_at" timestamp(3) DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp(3) DEFAULT now() NOT NULL,
|
||||
"tokenId" uuid NOT NULL,
|
||||
CONSTRAINT "PushSubscriptions_tokenId_unique" UNIQUE("tokenId")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "PushSubscriptions" ADD CONSTRAINT "PushSubscriptions_tokenId_Tokens_id_fk" FOREIGN KEY ("tokenId") REFERENCES "public"."Tokens"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
ALTER TABLE "Attachments" RENAME TO "Medias";--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP CONSTRAINT "Attachments_noteId_Notes_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Medias" ADD CONSTRAINT "Medias_noteId_Notes_id_fk" FOREIGN KEY ("noteId") REFERENCES "public"."Notes"("id") ON DELETE cascade ON UPDATE cascade;
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
CREATE TABLE "MediasToNote" (
|
||||
"mediaId" uuid NOT NULL,
|
||||
"noteId" uuid NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP CONSTRAINT "Medias_noteId_Notes_id_fk";
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "Medias" ADD COLUMN "content" jsonb NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Medias" ADD COLUMN "original_content" jsonb;--> statement-breakpoint
|
||||
ALTER TABLE "Medias" ADD COLUMN "thumbnail" jsonb;--> statement-breakpoint
|
||||
ALTER TABLE "MediasToNote" ADD CONSTRAINT "MediasToNote_mediaId_Medias_id_fk" FOREIGN KEY ("mediaId") REFERENCES "public"."Medias"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
|
||||
ALTER TABLE "MediasToNote" ADD CONSTRAINT "MediasToNote_noteId_Notes_id_fk" FOREIGN KEY ("noteId") REFERENCES "public"."Notes"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
|
||||
CREATE INDEX "MediasToNote_mediaId_index" ON "MediasToNote" USING btree ("mediaId");--> statement-breakpoint
|
||||
CREATE INDEX "MediasToNote_noteId_index" ON "MediasToNote" USING btree ("noteId");--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP COLUMN "url";--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP COLUMN "remote_url";--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP COLUMN "thumbnail_url";--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP COLUMN "mime_type";--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP COLUMN "description";--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP COLUMN "sha256";--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP COLUMN "fps";--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP COLUMN "duration";--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP COLUMN "width";--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP COLUMN "height";--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP COLUMN "size";--> statement-breakpoint
|
||||
ALTER TABLE "Medias" DROP COLUMN "noteId";
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
ALTER TABLE "Emojis" ADD COLUMN "mediaId" uuid;--> statement-breakpoint
|
||||
ALTER TABLE "Emojis" ADD CONSTRAINT "Emojis_mediaId_Medias_id_fk" FOREIGN KEY ("mediaId") REFERENCES "public"."Medias"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
|
||||
ALTER TABLE "Emojis" DROP COLUMN "url";--> statement-breakpoint
|
||||
ALTER TABLE "Emojis" DROP COLUMN "alt";--> statement-breakpoint
|
||||
ALTER TABLE "Emojis" DROP COLUMN "content_type";
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "Emojis" ALTER COLUMN "mediaId" SET NOT NULL;
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
ALTER TABLE "Users" ADD COLUMN "avatarId" uuid;--> statement-breakpoint
|
||||
ALTER TABLE "Users" ADD COLUMN "headerId" uuid;--> statement-breakpoint
|
||||
ALTER TABLE "Users" ADD CONSTRAINT "Users_avatarId_Medias_id_fk" FOREIGN KEY ("avatarId") REFERENCES "public"."Medias"("id") ON DELETE set null ON UPDATE cascade;--> statement-breakpoint
|
||||
ALTER TABLE "Users" ADD CONSTRAINT "Users_headerId_Medias_id_fk" FOREIGN KEY ("headerId") REFERENCES "public"."Medias"("id") ON DELETE set null ON UPDATE cascade;--> statement-breakpoint
|
||||
ALTER TABLE "Users" DROP COLUMN "avatar";--> statement-breakpoint
|
||||
ALTER TABLE "Users" DROP COLUMN "header";
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE "Users" ADD COLUMN "is_hiding_collections" boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Users" ADD COLUMN "is_indexable" boolean DEFAULT false NOT NULL;
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE "Users" ALTER COLUMN "is_indexable" SET DEFAULT true;
|
||||
22
packages/plugin-kit/tables/migrations/0048_chilly_vector.sql
Normal file
22
packages/plugin-kit/tables/migrations/0048_chilly_vector.sql
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
ALTER TABLE "Applications" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Challenges" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Emojis" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "FilterKeywords" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Filters" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Flags" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Instances" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Likes" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Markers" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Medias" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "ModNotes" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "ModTags" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Notes" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Notifications" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdAccounts" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "OpenIdLoginFlows" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "PushSubscriptions" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Reaction" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Relationships" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Roles" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Tokens" ALTER COLUMN "id" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "Users" ALTER COLUMN "id" DROP DEFAULT;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE "Notes" ALTER COLUMN "sensitive" SET DEFAULT false;--> statement-breakpoint
|
||||
ALTER TABLE "Users" ALTER COLUMN "display_name" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Users" ALTER COLUMN "source" DROP NOT NULL;
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
ALTER TABLE "Notes" ADD COLUMN "reblog_count" integer DEFAULT 0 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Notes" ADD COLUMN "like_count" integer DEFAULT 0 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Notes" ADD COLUMN "reply_count" integer DEFAULT 0 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Users" ADD COLUMN "follower_count" integer DEFAULT 0 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Users" ADD COLUMN "following_count" integer DEFAULT 0 NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "Users" ADD COLUMN "status_count" integer DEFAULT 0 NOT NULL;
|
||||
1843
packages/plugin-kit/tables/migrations/meta/0000_snapshot.json
Normal file
1843
packages/plugin-kit/tables/migrations/meta/0000_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1747
packages/plugin-kit/tables/migrations/meta/0001_snapshot.json
Normal file
1747
packages/plugin-kit/tables/migrations/meta/0001_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1747
packages/plugin-kit/tables/migrations/meta/0002_snapshot.json
Normal file
1747
packages/plugin-kit/tables/migrations/meta/0002_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1747
packages/plugin-kit/tables/migrations/meta/0003_snapshot.json
Normal file
1747
packages/plugin-kit/tables/migrations/meta/0003_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1747
packages/plugin-kit/tables/migrations/meta/0004_snapshot.json
Normal file
1747
packages/plugin-kit/tables/migrations/meta/0004_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1749
packages/plugin-kit/tables/migrations/meta/0005_snapshot.json
Normal file
1749
packages/plugin-kit/tables/migrations/meta/0005_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1749
packages/plugin-kit/tables/migrations/meta/0006_snapshot.json
Normal file
1749
packages/plugin-kit/tables/migrations/meta/0006_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1734
packages/plugin-kit/tables/migrations/meta/0007_snapshot.json
Normal file
1734
packages/plugin-kit/tables/migrations/meta/0007_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1741
packages/plugin-kit/tables/migrations/meta/0008_snapshot.json
Normal file
1741
packages/plugin-kit/tables/migrations/meta/0008_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1741
packages/plugin-kit/tables/migrations/meta/0009_snapshot.json
Normal file
1741
packages/plugin-kit/tables/migrations/meta/0009_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1741
packages/plugin-kit/tables/migrations/meta/0010_snapshot.json
Normal file
1741
packages/plugin-kit/tables/migrations/meta/0010_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1741
packages/plugin-kit/tables/migrations/meta/0011_snapshot.json
Normal file
1741
packages/plugin-kit/tables/migrations/meta/0011_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1802
packages/plugin-kit/tables/migrations/meta/0012_snapshot.json
Normal file
1802
packages/plugin-kit/tables/migrations/meta/0012_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1817
packages/plugin-kit/tables/migrations/meta/0013_snapshot.json
Normal file
1817
packages/plugin-kit/tables/migrations/meta/0013_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1926
packages/plugin-kit/tables/migrations/meta/0014_snapshot.json
Normal file
1926
packages/plugin-kit/tables/migrations/meta/0014_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1926
packages/plugin-kit/tables/migrations/meta/0015_snapshot.json
Normal file
1926
packages/plugin-kit/tables/migrations/meta/0015_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1940
packages/plugin-kit/tables/migrations/meta/0016_snapshot.json
Normal file
1940
packages/plugin-kit/tables/migrations/meta/0016_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1944
packages/plugin-kit/tables/migrations/meta/0017_snapshot.json
Normal file
1944
packages/plugin-kit/tables/migrations/meta/0017_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1946
packages/plugin-kit/tables/migrations/meta/0018_snapshot.json
Normal file
1946
packages/plugin-kit/tables/migrations/meta/0018_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1952
packages/plugin-kit/tables/migrations/meta/0019_snapshot.json
Normal file
1952
packages/plugin-kit/tables/migrations/meta/0019_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1959
packages/plugin-kit/tables/migrations/meta/0020_snapshot.json
Normal file
1959
packages/plugin-kit/tables/migrations/meta/0020_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1950
packages/plugin-kit/tables/migrations/meta/0021_snapshot.json
Normal file
1950
packages/plugin-kit/tables/migrations/meta/0021_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1971
packages/plugin-kit/tables/migrations/meta/0022_snapshot.json
Normal file
1971
packages/plugin-kit/tables/migrations/meta/0022_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
1983
packages/plugin-kit/tables/migrations/meta/0023_snapshot.json
Normal file
1983
packages/plugin-kit/tables/migrations/meta/0023_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
2093
packages/plugin-kit/tables/migrations/meta/0024_snapshot.json
Normal file
2093
packages/plugin-kit/tables/migrations/meta/0024_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
2100
packages/plugin-kit/tables/migrations/meta/0025_snapshot.json
Normal file
2100
packages/plugin-kit/tables/migrations/meta/0025_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue