mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
Slight refactoring, begin work on major moderation overhaul
This commit is contained in:
parent
e05dca9fc1
commit
2bc9ff51ea
|
|
@ -2,7 +2,7 @@
|
||||||
* Usage: TOKEN=your_token_here bun benchmark:timeline <request_count>
|
* Usage: TOKEN=your_token_here bun benchmark:timeline <request_count>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
|
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
|
|
|
||||||
443
classes/configmanager.ts
Normal file
443
classes/configmanager.ts
Normal file
|
|
@ -0,0 +1,443 @@
|
||||||
|
/**
|
||||||
|
* @file configmanager.ts
|
||||||
|
* @summary ConfigManager system to retrieve and modify system configuration
|
||||||
|
* @description Can read from a hand-written file, config.toml, or from a machine-saved file, config.internal.toml
|
||||||
|
* Fuses both and provides a way to retrieve individual values
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { parse, stringify } from "@iarna/toml";
|
||||||
|
import { deepMerge, deepMergeArray } from "@merge";
|
||||||
|
import chalk from "chalk";
|
||||||
|
|
||||||
|
const scanConfig = async () => {
|
||||||
|
const config = Bun.file(process.cwd() + "/config/config.toml");
|
||||||
|
|
||||||
|
if (!(await config.exists())) {
|
||||||
|
console.error(
|
||||||
|
`${chalk.red(`✗`)} ${chalk.bold(
|
||||||
|
"Error while reading config: "
|
||||||
|
)} Config file not found`
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse(await config.text()) as ConfigType;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Creates the internal config with nothing in it if it doesnt exist
|
||||||
|
const scanInternalConfig = async () => {
|
||||||
|
const config = Bun.file(process.cwd() + "/config/config.internal.toml");
|
||||||
|
|
||||||
|
if (!(await config.exists())) {
|
||||||
|
await Bun.write(config, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse(await config.text()) as ConfigType;
|
||||||
|
};
|
||||||
|
|
||||||
|
let config = await scanConfig();
|
||||||
|
const internalConfig = await scanInternalConfig();
|
||||||
|
|
||||||
|
export interface ConfigType {
|
||||||
|
database: {
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
database: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
redis: {
|
||||||
|
queue: {
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
password: string;
|
||||||
|
database: number | null;
|
||||||
|
};
|
||||||
|
cache: {
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
password: string;
|
||||||
|
database: number | null;
|
||||||
|
enabled: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
meilisearch: {
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
api_key: string;
|
||||||
|
enabled: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
signups: {
|
||||||
|
tos_url: string;
|
||||||
|
rules: string[];
|
||||||
|
registration: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
oidc: {
|
||||||
|
providers: {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
url: string;
|
||||||
|
client_id: string;
|
||||||
|
client_secret: string;
|
||||||
|
icon: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
http: {
|
||||||
|
base_url: string;
|
||||||
|
bind: string;
|
||||||
|
bind_port: string;
|
||||||
|
banned_ips: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
instance: {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
banner: string;
|
||||||
|
logo: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
smtp: {
|
||||||
|
server: string;
|
||||||
|
port: number;
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
tls: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
validation: {
|
||||||
|
max_displayname_size: number;
|
||||||
|
max_bio_size: number;
|
||||||
|
max_username_size: number;
|
||||||
|
max_note_size: number;
|
||||||
|
max_avatar_size: number;
|
||||||
|
max_header_size: number;
|
||||||
|
max_media_size: number;
|
||||||
|
max_media_attachments: number;
|
||||||
|
max_media_description_size: number;
|
||||||
|
max_poll_options: number;
|
||||||
|
max_poll_option_size: number;
|
||||||
|
min_poll_duration: number;
|
||||||
|
max_poll_duration: number;
|
||||||
|
|
||||||
|
username_blacklist: string[];
|
||||||
|
blacklist_tempmail: boolean;
|
||||||
|
email_blacklist: string[];
|
||||||
|
url_scheme_whitelist: string[];
|
||||||
|
|
||||||
|
enforce_mime_types: boolean;
|
||||||
|
allowed_mime_types: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
media: {
|
||||||
|
backend: string;
|
||||||
|
deduplicate_media: boolean;
|
||||||
|
conversion: {
|
||||||
|
convert_images: boolean;
|
||||||
|
convert_to: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
s3: {
|
||||||
|
endpoint: string;
|
||||||
|
access_key: string;
|
||||||
|
secret_access_key: string;
|
||||||
|
region: string;
|
||||||
|
bucket_name: string;
|
||||||
|
public_url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
defaults: {
|
||||||
|
visibility: string;
|
||||||
|
language: string;
|
||||||
|
avatar: string;
|
||||||
|
header: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
email: {
|
||||||
|
send_on_report: boolean;
|
||||||
|
send_on_suspend: boolean;
|
||||||
|
send_on_unsuspend: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
activitypub: {
|
||||||
|
use_tombstones: boolean;
|
||||||
|
reject_activities: string[];
|
||||||
|
force_followers_only: string[];
|
||||||
|
discard_reports: string[];
|
||||||
|
discard_deletes: string[];
|
||||||
|
discard_banners: string[];
|
||||||
|
discard_avatars: string[];
|
||||||
|
discard_updates: string[];
|
||||||
|
discard_follows: string[];
|
||||||
|
force_sensitive: string[];
|
||||||
|
remove_media: string[];
|
||||||
|
fetch_all_collection_members: boolean;
|
||||||
|
authorized_fetch: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
filters: {
|
||||||
|
note_filters: string[];
|
||||||
|
username_filters: string[];
|
||||||
|
displayname_filters: string[];
|
||||||
|
bio_filters: string[];
|
||||||
|
emoji_filters: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
logging: {
|
||||||
|
log_requests: boolean;
|
||||||
|
log_requests_verbose: boolean;
|
||||||
|
log_filters: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
ratelimits: {
|
||||||
|
duration_coeff: number;
|
||||||
|
max_coeff: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
custom_ratelimits: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
duration: number;
|
||||||
|
max: number;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const configDefaults: ConfigType = {
|
||||||
|
http: {
|
||||||
|
bind: "http://0.0.0.0",
|
||||||
|
bind_port: "8000",
|
||||||
|
base_url: "http://lysand.localhost:8000",
|
||||||
|
banned_ips: [],
|
||||||
|
},
|
||||||
|
database: {
|
||||||
|
host: "localhost",
|
||||||
|
port: 5432,
|
||||||
|
username: "postgres",
|
||||||
|
password: "postgres",
|
||||||
|
database: "lysand",
|
||||||
|
},
|
||||||
|
redis: {
|
||||||
|
queue: {
|
||||||
|
host: "localhost",
|
||||||
|
port: 6379,
|
||||||
|
password: "",
|
||||||
|
database: 0,
|
||||||
|
},
|
||||||
|
cache: {
|
||||||
|
host: "localhost",
|
||||||
|
port: 6379,
|
||||||
|
password: "",
|
||||||
|
database: 1,
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
meilisearch: {
|
||||||
|
host: "localhost",
|
||||||
|
port: 1491,
|
||||||
|
api_key: "",
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
signups: {
|
||||||
|
tos_url: "",
|
||||||
|
rules: [],
|
||||||
|
registration: false,
|
||||||
|
},
|
||||||
|
oidc: {
|
||||||
|
providers: [],
|
||||||
|
},
|
||||||
|
instance: {
|
||||||
|
banner: "",
|
||||||
|
description: "",
|
||||||
|
logo: "",
|
||||||
|
name: "",
|
||||||
|
},
|
||||||
|
smtp: {
|
||||||
|
password: "",
|
||||||
|
port: 465,
|
||||||
|
server: "",
|
||||||
|
tls: true,
|
||||||
|
username: "",
|
||||||
|
},
|
||||||
|
media: {
|
||||||
|
backend: "local",
|
||||||
|
deduplicate_media: true,
|
||||||
|
conversion: {
|
||||||
|
convert_images: false,
|
||||||
|
convert_to: "webp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
send_on_report: false,
|
||||||
|
send_on_suspend: false,
|
||||||
|
send_on_unsuspend: false,
|
||||||
|
},
|
||||||
|
s3: {
|
||||||
|
access_key: "",
|
||||||
|
bucket_name: "",
|
||||||
|
endpoint: "",
|
||||||
|
public_url: "",
|
||||||
|
region: "",
|
||||||
|
secret_access_key: "",
|
||||||
|
},
|
||||||
|
validation: {
|
||||||
|
max_displayname_size: 50,
|
||||||
|
max_bio_size: 6000,
|
||||||
|
max_note_size: 5000,
|
||||||
|
max_avatar_size: 5_000_000,
|
||||||
|
max_header_size: 5_000_000,
|
||||||
|
max_media_size: 40_000_000,
|
||||||
|
max_media_attachments: 10,
|
||||||
|
max_media_description_size: 1000,
|
||||||
|
max_poll_options: 20,
|
||||||
|
max_poll_option_size: 500,
|
||||||
|
min_poll_duration: 60,
|
||||||
|
max_poll_duration: 1893456000,
|
||||||
|
max_username_size: 30,
|
||||||
|
|
||||||
|
username_blacklist: [
|
||||||
|
".well-known",
|
||||||
|
"~",
|
||||||
|
"about",
|
||||||
|
"activities",
|
||||||
|
"api",
|
||||||
|
"auth",
|
||||||
|
"dev",
|
||||||
|
"inbox",
|
||||||
|
"internal",
|
||||||
|
"main",
|
||||||
|
"media",
|
||||||
|
"nodeinfo",
|
||||||
|
"notice",
|
||||||
|
"oauth",
|
||||||
|
"objects",
|
||||||
|
"proxy",
|
||||||
|
"push",
|
||||||
|
"registration",
|
||||||
|
"relay",
|
||||||
|
"settings",
|
||||||
|
"status",
|
||||||
|
"tag",
|
||||||
|
"users",
|
||||||
|
"web",
|
||||||
|
"search",
|
||||||
|
"mfa",
|
||||||
|
],
|
||||||
|
|
||||||
|
blacklist_tempmail: false,
|
||||||
|
|
||||||
|
email_blacklist: [],
|
||||||
|
|
||||||
|
url_scheme_whitelist: [
|
||||||
|
"http",
|
||||||
|
"https",
|
||||||
|
"ftp",
|
||||||
|
"dat",
|
||||||
|
"dweb",
|
||||||
|
"gopher",
|
||||||
|
"hyper",
|
||||||
|
"ipfs",
|
||||||
|
"ipns",
|
||||||
|
"irc",
|
||||||
|
"xmpp",
|
||||||
|
"ircs",
|
||||||
|
"magnet",
|
||||||
|
"mailto",
|
||||||
|
"mumble",
|
||||||
|
"ssb",
|
||||||
|
],
|
||||||
|
|
||||||
|
enforce_mime_types: false,
|
||||||
|
allowed_mime_types: [],
|
||||||
|
},
|
||||||
|
defaults: {
|
||||||
|
visibility: "public",
|
||||||
|
language: "en",
|
||||||
|
avatar: "",
|
||||||
|
header: "",
|
||||||
|
},
|
||||||
|
activitypub: {
|
||||||
|
use_tombstones: true,
|
||||||
|
reject_activities: [],
|
||||||
|
force_followers_only: [],
|
||||||
|
discard_reports: [],
|
||||||
|
discard_deletes: [],
|
||||||
|
discard_banners: [],
|
||||||
|
discard_avatars: [],
|
||||||
|
force_sensitive: [],
|
||||||
|
discard_updates: [],
|
||||||
|
discard_follows: [],
|
||||||
|
remove_media: [],
|
||||||
|
fetch_all_collection_members: false,
|
||||||
|
authorized_fetch: false,
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
note_filters: [],
|
||||||
|
username_filters: [],
|
||||||
|
displayname_filters: [],
|
||||||
|
bio_filters: [],
|
||||||
|
emoji_filters: [],
|
||||||
|
},
|
||||||
|
logging: {
|
||||||
|
log_requests: false,
|
||||||
|
log_requests_verbose: false,
|
||||||
|
log_filters: true,
|
||||||
|
},
|
||||||
|
ratelimits: {
|
||||||
|
duration_coeff: 1,
|
||||||
|
max_coeff: 1,
|
||||||
|
},
|
||||||
|
custom_ratelimits: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getConfig = () => {
|
||||||
|
// Deeply merge configDefaults, config and internalConfig
|
||||||
|
return deepMergeArray([
|
||||||
|
configDefaults,
|
||||||
|
config,
|
||||||
|
internalConfig,
|
||||||
|
]) as any as ConfigType;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the internal config
|
||||||
|
* @param newConfig Any part of ConfigType
|
||||||
|
*/
|
||||||
|
export const setConfig = async (newConfig: Partial<ConfigType>) => {
|
||||||
|
const newInternalConfig = deepMerge(internalConfig, newConfig);
|
||||||
|
|
||||||
|
// Prepend a warning comment and write the new TOML to the file
|
||||||
|
await Bun.write(
|
||||||
|
Bun.file(process.cwd() + "/config/config.internal.toml"),
|
||||||
|
`# This file is automatically generated. Do not modify it manually.\n${stringify(
|
||||||
|
newInternalConfig
|
||||||
|
)}`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getHost = () => {
|
||||||
|
const url = new URL(getConfig().http.base_url);
|
||||||
|
|
||||||
|
return url.host;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Refresh config every 5 seconds
|
||||||
|
setInterval(() => {
|
||||||
|
scanConfig()
|
||||||
|
.then(newConfig => {
|
||||||
|
if (newConfig !== config) {
|
||||||
|
config = newConfig;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.error(e);
|
||||||
|
});
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
export { config };
|
||||||
|
|
@ -4,7 +4,7 @@ import {
|
||||||
PutObjectCommand,
|
PutObjectCommand,
|
||||||
S3Client,
|
S3Client,
|
||||||
} from "@aws-sdk/client-s3";
|
} from "@aws-sdk/client-s3";
|
||||||
import type { ConfigType } from "@config";
|
import type { ConfigType } from "~classes/configmanager";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { exists, mkdir } from "fs/promises";
|
import { exists, mkdir } from "fs/promises";
|
||||||
class MediaBackend {
|
class MediaBackend {
|
||||||
|
|
|
||||||
2
cli.ts
2
cli.ts
|
|
@ -4,7 +4,7 @@ import { client } from "~database/datasource";
|
||||||
import { createNewLocalUser } from "~database/entities/User";
|
import { createNewLocalUser } from "~database/entities/User";
|
||||||
import Table from "cli-table";
|
import Table from "cli-table";
|
||||||
import { rebuildSearchIndexes, MeiliIndexType } from "@meilisearch";
|
import { rebuildSearchIndexes, MeiliIndexType } from "@meilisearch";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { uploadFile } from "~classes/media";
|
import { uploadFile } from "~classes/media";
|
||||||
import { getUrl } from "~database/entities/Attachment";
|
import { getUrl } from "~database/entities/Attachment";
|
||||||
import { mkdir, exists } from "fs/promises";
|
import { mkdir, exists } from "fs/promises";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import type { ConfigType } from "@config";
|
import type { ConfigType } from "~classes/configmanager";
|
||||||
import type { Attachment } from "@prisma/client";
|
import type { Attachment } from "@prisma/client";
|
||||||
import type { APIAsyncAttachment } from "~types/entities/async_attachment";
|
import type { APIAsyncAttachment } from "~types/entities/async_attachment";
|
||||||
import type { APIAttachment } from "~types/entities/attachment";
|
import type { APIAttachment } from "~types/entities/attachment";
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
import type { Like as LysandLike } from "~types/lysand/Object";
|
import type { Like as LysandLike } from "~types/lysand/Object";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import type { Like } from "@prisma/client";
|
import type { Like } from "@prisma/client";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
import type { UserWithRelations } from "./User";
|
import type { UserWithRelations } from "./User";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { Worker } from "bullmq";
|
import { Worker } from "bullmq";
|
||||||
import { client, federationQueue } from "~database/datasource";
|
import { client, federationQueue } from "~database/datasource";
|
||||||
import {
|
import {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import type { UserWithRelations } from "./User";
|
import type { UserWithRelations } from "./User";
|
||||||
import {
|
import {
|
||||||
fetchRemoteUser,
|
fetchRemoteUser,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import type { ConfigType } from "@config";
|
import type { ConfigType } from "~classes/configmanager";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import type { APIAccount } from "~types/entities/account";
|
import type { APIAccount } from "~types/entities/account";
|
||||||
import type { User as LysandUser } from "~types/lysand/Object";
|
import type { User as LysandUser } from "~types/lysand/Object";
|
||||||
import { htmlToText } from "html-to-text";
|
import { htmlToText } from "html-to-text";
|
||||||
|
|
|
||||||
2
index.ts
2
index.ts
|
|
@ -1,4 +1,4 @@
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { jsonResponse } from "@response";
|
import { jsonResponse } from "@response";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { appendFile } from "fs/promises";
|
import { appendFile } from "fs/promises";
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
// Proxies all `bunx prisma` commands with an environment variable
|
// Proxies all `bunx prisma` commands with an environment variable
|
||||||
|
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
|
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
|
|
||||||
process.stdout.write(
|
process.stdout.write(
|
||||||
`postgresql://${config.database.username}:${config.database.password}@${config.database.host}:${config.database.port}/${config.database.database}`
|
`postgresql://${config.database.username}:${config.database.password}@${config.database.host}:${config.database.port}/${config.database.database}\n`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Ends
|
||||||
|
process.exit(0);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Instance" ADD COLUMN "disableAutomoderation" BOOLEAN NOT NULL DEFAULT false;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "User" ADD COLUMN "disableAutomoderation" BOOLEAN NOT NULL DEFAULT false;
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "ModerationData" (
|
||||||
|
"id" UUID NOT NULL DEFAULT uuid_generate_v7(),
|
||||||
|
"statusId" UUID NOT NULL,
|
||||||
|
"creatorId" UUID NOT NULL,
|
||||||
|
"note" TEXT NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "ModerationData_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Flag" (
|
||||||
|
"id" UUID NOT NULL DEFAULT uuid_generate_v7(),
|
||||||
|
"statusId" UUID NOT NULL,
|
||||||
|
"userId" UUID NOT NULL,
|
||||||
|
"flagType" TEXT NOT NULL DEFAULT 'other',
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "Flag_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "ModerationData" ADD CONSTRAINT "ModerationData_statusId_fkey" FOREIGN KEY ("statusId") REFERENCES "Status"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "ModerationData" ADD CONSTRAINT "ModerationData_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Flag" ADD CONSTRAINT "Flag_statusId_fkey" FOREIGN KEY ("statusId") REFERENCES "Status"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "Flag" ADD CONSTRAINT "Flag_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
@ -37,14 +37,15 @@ model Emoji {
|
||||||
}
|
}
|
||||||
|
|
||||||
model Instance {
|
model Instance {
|
||||||
id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid
|
id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid
|
||||||
base_url String
|
base_url String
|
||||||
name String
|
name String
|
||||||
version String
|
version String
|
||||||
logo Json
|
logo Json
|
||||||
emojis Emoji[] // One to many relation with Emoji
|
emojis Emoji[] // One to many relation with Emoji
|
||||||
statuses Status[] // One to many relation with Status
|
statuses Status[] // One to many relation with Status
|
||||||
users User[] // One to many relation with User
|
users User[] // One to many relation with User
|
||||||
|
disableAutomoderation Boolean @default(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
model Like {
|
model Like {
|
||||||
|
|
@ -93,38 +94,62 @@ model Relationship {
|
||||||
}
|
}
|
||||||
|
|
||||||
model Status {
|
model Status {
|
||||||
id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid
|
id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid
|
||||||
uri String @unique
|
uri String @unique
|
||||||
author User @relation("UserStatuses", fields: [authorId], references: [id], onDelete: Cascade)
|
author User @relation("UserStatuses", fields: [authorId], references: [id], onDelete: Cascade)
|
||||||
authorId String @db.Uuid
|
authorId String @db.Uuid
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
reblog Status? @relation("StatusToStatus", fields: [reblogId], references: [id], onDelete: Cascade)
|
reblog Status? @relation("StatusToStatus", fields: [reblogId], references: [id], onDelete: Cascade)
|
||||||
reblogId String? @db.Uuid
|
reblogId String? @db.Uuid
|
||||||
isReblog Boolean
|
isReblog Boolean
|
||||||
content String @default("")
|
content String @default("")
|
||||||
contentType String @default("text/plain")
|
contentType String @default("text/plain")
|
||||||
contentSource String @default("")
|
contentSource String @default("")
|
||||||
visibility String
|
visibility String
|
||||||
inReplyToPost Status? @relation("StatusToStatusReply", fields: [inReplyToPostId], references: [id], onDelete: SetNull)
|
inReplyToPost Status? @relation("StatusToStatusReply", fields: [inReplyToPostId], references: [id], onDelete: SetNull)
|
||||||
inReplyToPostId String? @db.Uuid
|
inReplyToPostId String? @db.Uuid
|
||||||
quotingPost Status? @relation("StatusToStatusQuote", fields: [quotingPostId], references: [id], onDelete: SetNull)
|
quotingPost Status? @relation("StatusToStatusQuote", fields: [quotingPostId], references: [id], onDelete: SetNull)
|
||||||
quotingPostId String? @db.Uuid
|
quotingPostId String? @db.Uuid
|
||||||
instance Instance? @relation(fields: [instanceId], references: [id], onDelete: Cascade)
|
instance Instance? @relation(fields: [instanceId], references: [id], onDelete: Cascade)
|
||||||
instanceId String? @db.Uuid
|
instanceId String? @db.Uuid
|
||||||
sensitive Boolean
|
sensitive Boolean
|
||||||
spoilerText String @default("")
|
spoilerText String @default("")
|
||||||
application Application? @relation(fields: [applicationId], references: [id], onDelete: SetNull)
|
application Application? @relation(fields: [applicationId], references: [id], onDelete: SetNull)
|
||||||
applicationId String? @db.Uuid
|
applicationId String? @db.Uuid
|
||||||
emojis Emoji[] @relation
|
emojis Emoji[] @relation
|
||||||
mentions User[]
|
mentions User[]
|
||||||
likes Like[] @relation("LikedToStatus")
|
likes Like[] @relation("LikedToStatus")
|
||||||
reblogs Status[] @relation("StatusToStatus")
|
reblogs Status[] @relation("StatusToStatus")
|
||||||
replies Status[] @relation("StatusToStatusReply")
|
replies Status[] @relation("StatusToStatusReply")
|
||||||
quotes Status[] @relation("StatusToStatusQuote")
|
quotes Status[] @relation("StatusToStatusQuote")
|
||||||
pinnedBy User[] @relation("UserPinnedNotes")
|
pinnedBy User[] @relation("UserPinnedNotes")
|
||||||
attachments Attachment[]
|
attachments Attachment[]
|
||||||
relatedNotifications Notification[]
|
relatedNotifications Notification[]
|
||||||
|
flags Flag[]
|
||||||
|
moderationData ModerationData[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model ModerationData {
|
||||||
|
id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid
|
||||||
|
status Status @relation(fields: [statusId], references: [id], onDelete: Cascade)
|
||||||
|
statusId String @db.Uuid
|
||||||
|
creator User @relation(fields: [creatorId], references: [id], onDelete: Cascade)
|
||||||
|
creatorId String @db.Uuid
|
||||||
|
note String
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for moderation purposes
|
||||||
|
model Flag {
|
||||||
|
id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid
|
||||||
|
status Status @relation(fields: [statusId], references: [id], onDelete: Cascade)
|
||||||
|
statusId String @db.Uuid
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
userId String @db.Uuid
|
||||||
|
flagType String @default("other")
|
||||||
|
createdAt DateTime @default(now())
|
||||||
}
|
}
|
||||||
|
|
||||||
model Token {
|
model Token {
|
||||||
|
|
@ -179,39 +204,42 @@ model Notification {
|
||||||
}
|
}
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid
|
id String @id @default(dbgenerated("uuid_generate_v7()")) @db.Uuid
|
||||||
uri String @unique
|
uri String @unique
|
||||||
username String @unique
|
username String @unique
|
||||||
displayName String
|
displayName String
|
||||||
password String? // Nullable
|
password String? // Nullable
|
||||||
email String? @unique // Nullable
|
email String? @unique // Nullable
|
||||||
note String @default("")
|
note String @default("")
|
||||||
isAdmin Boolean @default(false)
|
isAdmin Boolean @default(false)
|
||||||
endpoints Json? // Nullable
|
endpoints Json? // Nullable
|
||||||
source Json
|
source Json
|
||||||
avatar String
|
avatar String
|
||||||
header String
|
header String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
isBot Boolean @default(false)
|
isBot Boolean @default(false)
|
||||||
isLocked Boolean @default(false)
|
isLocked Boolean @default(false)
|
||||||
isDiscoverable Boolean @default(false)
|
isDiscoverable Boolean @default(false)
|
||||||
sanctions String[] @default([])
|
sanctions String[] @default([])
|
||||||
publicKey String
|
publicKey String
|
||||||
privateKey String? // Nullable
|
privateKey String? // Nullable
|
||||||
relationships Relationship[] @relation("OwnerToRelationship") // One to many relation with Relationship
|
relationships Relationship[] @relation("OwnerToRelationship") // One to many relation with Relationship
|
||||||
relationshipSubjects Relationship[] @relation("SubjectToRelationship") // One to many relation with Relationship
|
relationshipSubjects Relationship[] @relation("SubjectToRelationship") // One to many relation with Relationship
|
||||||
instance Instance? @relation(fields: [instanceId], references: [id], onDelete: Cascade) // Many to one relation with Instance
|
instance Instance? @relation(fields: [instanceId], references: [id], onDelete: Cascade) // Many to one relation with Instance
|
||||||
instanceId String? @db.Uuid
|
instanceId String? @db.Uuid
|
||||||
pinnedNotes Status[] @relation("UserPinnedNotes") // Many to many relation with Status
|
pinnedNotes Status[] @relation("UserPinnedNotes") // Many to many relation with Status
|
||||||
emojis Emoji[] // Many to many relation with Emoji
|
emojis Emoji[] // Many to many relation with Emoji
|
||||||
statuses Status[] @relation("UserStatuses") // One to many relation with Status
|
statuses Status[] @relation("UserStatuses") // One to many relation with Status
|
||||||
tokens Token[] // One to many relation with Token
|
tokens Token[] // One to many relation with Token
|
||||||
likes Like[] @relation("UserLiked") // One to many relation with Like
|
likes Like[] @relation("UserLiked") // One to many relation with Like
|
||||||
statusesMentioned Status[] // Many to many relation with Status
|
statusesMentioned Status[] // Many to many relation with Status
|
||||||
notifications Notification[] // One to many relation with Notification
|
notifications Notification[] // One to many relation with Notification
|
||||||
notified Notification[] @relation("NotificationToNotified") // One to many relation with Notification
|
notified Notification[] @relation("NotificationToNotified") // One to many relation with Notification
|
||||||
linkedOpenIdAccounts OpenIdAccount[] // One to many relation with OpenIdAccount
|
linkedOpenIdAccounts OpenIdAccount[] // One to many relation with OpenIdAccount
|
||||||
|
flags Flag[] @relation
|
||||||
|
moderationData ModerationData[]
|
||||||
|
disableAutomoderation Boolean @default(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
model OpenIdAccount {
|
model OpenIdAccount {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { MatchedRoute } from "bun";
|
import { MatchedRoute } from "bun";
|
||||||
import { getConfig, getHost } from "@config";
|
import { getConfig, getHost } from "~classes/configmanager";
|
||||||
import { xmlResponse } from "@response";
|
import { xmlResponse } from "@response";
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { jsonResponse } from "@response";
|
import { jsonResponse } from "@response";
|
||||||
import { MatchedRoute } from "bun";
|
import { MatchedRoute } from "bun";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
|
|
||||||
export const meta = applyConfig({
|
export const meta = applyConfig({
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { MatchedRoute } from "bun";
|
import { MatchedRoute } from "bun";
|
||||||
import { getConfig, getHost } from "@config";
|
import { getConfig, getHost } from "~classes/configmanager";
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
|
|
||||||
export const meta = applyConfig({
|
export const meta = applyConfig({
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { errorResponse, jsonResponse } from "@response";
|
import { errorResponse, jsonResponse } from "@response";
|
||||||
import { MatchedRoute } from "bun";
|
import { MatchedRoute } from "bun";
|
||||||
import { getConfig, getHost } from "@config";
|
import { getConfig, getHost } from "~classes/configmanager";
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { parseRequest } from "@request";
|
import { parseRequest } from "@request";
|
||||||
import { jsonResponse } from "@response";
|
import { jsonResponse } from "@response";
|
||||||
import { tempmailDomains } from "@tempmail";
|
import { tempmailDomains } from "@tempmail";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { parseRequest } from "@request";
|
import { parseRequest } from "@request";
|
||||||
import { errorResponse, jsonResponse } from "@response";
|
import { errorResponse, jsonResponse } from "@response";
|
||||||
import {
|
import {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { jsonResponse } from "@response";
|
import { jsonResponse } from "@response";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
import { userRelations, userToAPI } from "~database/entities/User";
|
import { userRelations, userToAPI } from "~database/entities/User";
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { client } from "~database/datasource";
|
||||||
import { getFromRequest } from "~database/entities/User";
|
import { getFromRequest } from "~database/entities/User";
|
||||||
import type { APIRouteMeta } from "~types/api";
|
import type { APIRouteMeta } from "~types/api";
|
||||||
import { uploadFile } from "~classes/media";
|
import { uploadFile } from "~classes/media";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { attachmentToAPI, getUrl } from "~database/entities/Attachment";
|
import { attachmentToAPI, getUrl } from "~database/entities/Attachment";
|
||||||
import type { MatchedRoute } from "bun";
|
import type { MatchedRoute } from "bun";
|
||||||
import { parseRequest } from "@request";
|
import { parseRequest } from "@request";
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { getFromRequest } from "~database/entities/User";
|
||||||
import type { APIRouteMeta } from "~types/api";
|
import type { APIRouteMeta } from "~types/api";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { uploadFile } from "~classes/media";
|
import { uploadFile } from "~classes/media";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { attachmentToAPI, getUrl } from "~database/entities/Attachment";
|
import { attachmentToAPI, getUrl } from "~database/entities/Attachment";
|
||||||
|
|
||||||
export const meta: APIRouteMeta = applyConfig({
|
export const meta: APIRouteMeta = applyConfig({
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { parseRequest } from "@request";
|
import { parseRequest } from "@request";
|
||||||
import { errorResponse, jsonResponse } from "@response";
|
import { errorResponse, jsonResponse } from "@response";
|
||||||
import { sanitizeHtml } from "@sanitization";
|
import { sanitizeHtml } from "@sanitization";
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { parseRequest } from "@request";
|
import { parseRequest } from "@request";
|
||||||
import { errorResponse, jsonResponse } from "@response";
|
import { errorResponse, jsonResponse } from "@response";
|
||||||
import type { MatchedRoute } from "bun";
|
import type { MatchedRoute } from "bun";
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { parseRequest } from "@request";
|
import { parseRequest } from "@request";
|
||||||
import { errorResponse, jsonResponse } from "@response";
|
import { errorResponse, jsonResponse } from "@response";
|
||||||
import { sanitizeHtml } from "@sanitization";
|
import { sanitizeHtml } from "@sanitization";
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { getFromRequest } from "~database/entities/User";
|
||||||
import type { APIRouteMeta } from "~types/api";
|
import type { APIRouteMeta } from "~types/api";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { uploadFile } from "~classes/media";
|
import { uploadFile } from "~classes/media";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { attachmentToAPI, getUrl } from "~database/entities/Attachment";
|
import { attachmentToAPI, getUrl } from "~database/entities/Attachment";
|
||||||
|
|
||||||
export const meta: APIRouteMeta = applyConfig({
|
export const meta: APIRouteMeta = applyConfig({
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { MeiliIndexType, meilisearch } from "@meilisearch";
|
import { MeiliIndexType, meilisearch } from "@meilisearch";
|
||||||
import { parseRequest } from "@request";
|
import { parseRequest } from "@request";
|
||||||
import { errorResponse, jsonResponse } from "@response";
|
import { errorResponse, jsonResponse } from "@response";
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { oauthRedirectUri } from "@constants";
|
import { oauthRedirectUri } from "@constants";
|
||||||
import type { MatchedRoute } from "bun";
|
import type { MatchedRoute } from "bun";
|
||||||
import {
|
import {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { oauthRedirectUri } from "@constants";
|
import { oauthRedirectUri } from "@constants";
|
||||||
import type { MatchedRoute } from "bun";
|
import type { MatchedRoute } from "bun";
|
||||||
import { randomBytes } from "crypto";
|
import { randomBytes } from "crypto";
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { jsonResponse } from "@response";
|
import { jsonResponse } from "@response";
|
||||||
|
|
||||||
export const meta = applyConfig({
|
export const meta = applyConfig({
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { getBestContentType } from "@content_types";
|
import { getBestContentType } from "@content_types";
|
||||||
import { errorResponse, jsonResponse } from "@response";
|
import { errorResponse, jsonResponse } from "@response";
|
||||||
import type { MatchedRoute } from "bun";
|
import type { MatchedRoute } from "bun";
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { errorResponse, jsonResponse } from "@response";
|
import { errorResponse, jsonResponse } from "@response";
|
||||||
import type { MatchedRoute } from "bun";
|
import type { MatchedRoute } from "bun";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { jsonResponse } from "@response";
|
import { jsonResponse } from "@response";
|
||||||
import type { MatchedRoute } from "bun";
|
import type { MatchedRoute } from "bun";
|
||||||
import { getConfig, getHost } from "@config";
|
import { getConfig, getHost } from "~classes/configmanager";
|
||||||
import { applyConfig } from "@api";
|
import { applyConfig } from "@api";
|
||||||
import {
|
import {
|
||||||
statusAndUserRelations,
|
statusAndUserRelations,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import type { Token } from "@prisma/client";
|
import type { Token } from "@prisma/client";
|
||||||
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import type { Token } from "@prisma/client";
|
import type { Token } from "@prisma/client";
|
||||||
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import type { Token } from "@prisma/client";
|
import type { Token } from "@prisma/client";
|
||||||
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { type ConfigType, getConfig } from "@config";
|
import { type ConfigType, getConfig } from "~classes/configmanager";
|
||||||
import { afterAll, beforeAll, describe, expect, it } from "bun:test";
|
import { afterAll, beforeAll, describe, expect, it } from "bun:test";
|
||||||
import { LocalBackend, S3Backend } from "~classes/media";
|
import { LocalBackend, S3Backend } from "~classes/media";
|
||||||
import { unlink } from "fs/promises";
|
import { unlink } from "fs/promises";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import type { Application, Token } from "@prisma/client";
|
import type { Application, Token } from "@prisma/client";
|
||||||
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import type { APIRouteMeta } from "~types/api";
|
import type { APIRouteMeta } from "~types/api";
|
||||||
|
|
||||||
export const applyConfig = (routeMeta: APIRouteMeta) => {
|
export const applyConfig = (routeMeta: APIRouteMeta) => {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
|
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
import { Meilisearch } from "meilisearch";
|
import { Meilisearch } from "meilisearch";
|
||||||
|
|
|
||||||
16
utils/merge.ts
Normal file
16
utils/merge.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
export const deepMerge = (
|
||||||
|
target: Record<string, any>,
|
||||||
|
source: Record<string, any>
|
||||||
|
) => {
|
||||||
|
const result = { ...target, ...source };
|
||||||
|
for (const key of Object.keys(result)) {
|
||||||
|
result[key] =
|
||||||
|
typeof target[key] == "object" && typeof source[key] == "object"
|
||||||
|
? deepMerge(target[key], source[key])
|
||||||
|
: structuredClone(result[key]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deepMergeArray = (array: Record<string, any>[]) =>
|
||||||
|
array.reduce((ci, ni) => deepMerge(ci, ni), {});
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import type { Prisma } from "@prisma/client";
|
import type { Prisma } from "@prisma/client";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import Redis from "ioredis";
|
import Redis from "ioredis";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { getConfig } from "@config";
|
import { getConfig } from "~classes/configmanager";
|
||||||
import { sanitize } from "isomorphic-dompurify";
|
import { sanitize } from "isomorphic-dompurify";
|
||||||
|
|
||||||
export const sanitizeHtml = async (html: string) => {
|
export const sanitizeHtml = async (html: string) => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue