diff --git a/README.md b/README.md index 6f3968fb..08afd971 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ Working endpoints are: - `/api/v1/statuses/:id` (`GET`, `DELETE`) - `/api/v1/statuses` - `/api/v1/apps` +- `/api/v1/instance` - `/api/v1/apps/verify_credentials` - `/oauth/authorize` - `/oauth/token` diff --git a/server/api/api/v1/instance/index.ts b/server/api/api/v1/instance/index.ts new file mode 100644 index 00000000..c53223f3 --- /dev/null +++ b/server/api/api/v1/instance/index.ts @@ -0,0 +1,60 @@ +import { getConfig } from "@config"; +import { jsonResponse } from "@response"; +import { Status } from "~database/entities/Status"; +import { User } from "~database/entities/User"; + +/** + * Creates a new user + */ +// eslint-disable-next-line @typescript-eslint/require-await +export default async (): Promise => { + const config = getConfig(); + + const statusCount = await Status.count(); + const userCount = await User.count(); + + // TODO: fill in more values + return jsonResponse({ + approval_required: false, + configuration: { + media_attachments: { + image_matrix_limit: 10, + image_size_limit: config.validation.max_media_size, + supported_mime_types: config.validation.allowed_mime_types, + video_frame_limit: 60, + video_matrix_limit: 10, + video_size_limit: config.validation.max_media_size, + }, + polls: { + max_characters_per_option: 100, + max_expiration: 60 * 60 * 24 * 365 * 100, // 100 years, + max_options: 40, + min_expiration: 60, + }, + statuses: { + characters_reserved_per_url: 0, + max_characters: config.validation.max_note_size, + max_media_attachments: config.validation.max_media_attachments, + }, + }, + description: "A test instance", + email: "", + invites_enabled: false, + registrations: true, + languages: ["en"], + rules: [], + stats: { + domain_count: 1, + status_count: statusCount, + user_count: userCount, + }, + thumbnail: "", + title: "Test Instance", + uri: new URL(config.http.base_url).hostname, + urls: { + streaming_api: "", + }, + version: "0.0.1", + max_toot_chars: config.validation.max_note_size, + }); +}; diff --git a/tests/api.test.ts b/tests/api.test.ts index 887c5b8b..15c2dfd2 100644 --- a/tests/api.test.ts +++ b/tests/api.test.ts @@ -8,6 +8,7 @@ import { RawActivity } from "~database/entities/RawActivity"; import { Token, TokenType } from "~database/entities/Token"; import { User } from "~database/entities/User"; import { APIAccount } from "~types/entities/account"; +import { APIInstance } from "~types/entities/instance"; import { APIRelationship } from "~types/entities/relationship"; import { APIStatus } from "~types/entities/status"; @@ -622,6 +623,40 @@ describe("DELETE /api/v1/statuses/:id", () => { }); }); +describe("GET /api/v1/instance", () => { + test("should return an APIInstance object", async () => { + const response = await fetch( + `${config.http.base_url}/api/v1/instance`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + } + ); + + expect(response.status).toBe(200); + expect(response.headers.get("content-type")).toBe("application/json"); + + const instance: APIInstance = await response.json(); + + expect(instance.uri).toBe(new URL(config.http.base_url).hostname); + expect(instance.title).toBeDefined(); + expect(instance.description).toBeDefined(); + expect(instance.email).toBeDefined(); + expect(instance.version).toBeDefined(); + expect(instance.urls).toBeDefined(); + expect(instance.stats).toBeDefined(); + expect(instance.thumbnail).toBeDefined(); + expect(instance.languages).toBeDefined(); + // Not implemented yet + // expect(instance.contact_account).toBeDefined(); + expect(instance.rules).toBeDefined(); + expect(instance.approval_required).toBeDefined(); + expect(instance.max_toot_chars).toBeDefined(); + }); +}); + afterAll(async () => { const activities = await RawActivity.createQueryBuilder("activity") .where("activity.data->>'actor' = :actor", { diff --git a/utils/config.ts b/utils/config.ts index 3ebdd360..dd0e19da 100644 --- a/utils/config.ts +++ b/utils/config.ts @@ -30,6 +30,8 @@ export interface ConfigType { blacklist_tempmail: boolean; email_blacklist: string[]; url_scheme_whitelist: string[]; + + allowed_mime_types: string[]; }; defaults: { @@ -142,6 +144,8 @@ export const configDefaults: ConfigType = { "mumble", "ssb", ], + + allowed_mime_types: [], }, defaults: { visibility: "public",