mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 16:38:19 +01:00
Add interface to view post and user JSON data
This commit is contained in:
parent
342a8011f1
commit
db37510370
|
|
@ -260,7 +260,7 @@ export const createNewStatus = async (data: {
|
||||||
.join("\n");
|
.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
let status = await client.status.create({
|
const status = await client.status.create({
|
||||||
data: {
|
data: {
|
||||||
authorId: data.account.id,
|
authorId: data.account.id,
|
||||||
applicationId: data.application?.id,
|
applicationId: data.application?.id,
|
||||||
|
|
@ -290,12 +290,7 @@ export const createNewStatus = async (data: {
|
||||||
quotingPostId: data.quote?.id,
|
quotingPostId: data.quote?.id,
|
||||||
instanceId: data.account.instanceId || undefined,
|
instanceId: data.account.instanceId || undefined,
|
||||||
isReblog: false,
|
isReblog: false,
|
||||||
uri:
|
uri: data.uri || null,
|
||||||
data.uri ||
|
|
||||||
new URL(
|
|
||||||
`/statuses/FAKE-${crypto.randomUUID()}`,
|
|
||||||
config.http.base_url,
|
|
||||||
).toString(),
|
|
||||||
mentions: {
|
mentions: {
|
||||||
connect: mentions.map((mention) => {
|
connect: mentions.map((mention) => {
|
||||||
return {
|
return {
|
||||||
|
|
@ -307,22 +302,6 @@ export const createNewStatus = async (data: {
|
||||||
include: statusAndUserRelations,
|
include: statusAndUserRelations,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update URI
|
|
||||||
status = await client.status.update({
|
|
||||||
where: {
|
|
||||||
id: status.id,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
uri:
|
|
||||||
data.uri ||
|
|
||||||
new URL(
|
|
||||||
`/statuses/${status.id}`,
|
|
||||||
config.http.base_url,
|
|
||||||
).toString(),
|
|
||||||
},
|
|
||||||
include: statusAndUserRelations,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create notification
|
// Create notification
|
||||||
if (status.inReplyToPost) {
|
if (status.inReplyToPost) {
|
||||||
await client.notification.create({
|
await client.notification.create({
|
||||||
|
|
@ -503,9 +482,19 @@ export const statusToAPI = async (
|
||||||
sensitive: status.sensitive,
|
sensitive: status.sensitive,
|
||||||
spoiler_text: status.spoilerText,
|
spoiler_text: status.spoilerText,
|
||||||
tags: [],
|
tags: [],
|
||||||
uri: new URL(`/statuses/${status.id}`, config.http.base_url).toString(),
|
uri:
|
||||||
|
status.uri ||
|
||||||
|
new URL(
|
||||||
|
`/@${status.author.username}/${status.id}`,
|
||||||
|
config.http.base_url,
|
||||||
|
).toString(),
|
||||||
visibility: "public",
|
visibility: "public",
|
||||||
url: new URL(`/statuses/${status.id}`, config.http.base_url).toString(),
|
url:
|
||||||
|
status.uri ||
|
||||||
|
new URL(
|
||||||
|
`/@${status.author.username}/${status.id}`,
|
||||||
|
config.http.base_url,
|
||||||
|
).toString(),
|
||||||
bookmarked: false,
|
bookmarked: false,
|
||||||
quote: status.quotingPost
|
quote: status.quotingPost
|
||||||
? await statusToAPI(
|
? await statusToAPI(
|
||||||
|
|
@ -584,8 +573,8 @@ export const statusToLysand = (status: StatusWithRelations): Note => {
|
||||||
// TODO: Add attachments
|
// TODO: Add attachments
|
||||||
attachments: [],
|
attachments: [],
|
||||||
is_sensitive: status.sensitive,
|
is_sensitive: status.sensitive,
|
||||||
mentions: status.mentions.map((mention) => mention.uri),
|
mentions: status.mentions.map((mention) => mention.uri || ""),
|
||||||
quotes: status.quotingPost ? [status.quotingPost.uri] : [],
|
quotes: status.quotingPost ? [status.quotingPost.uri || ""] : [],
|
||||||
replies_to: status.inReplyToPostId ? [status.inReplyToPostId] : [],
|
replies_to: status.inReplyToPostId ? [status.inReplyToPostId] : [],
|
||||||
subject: status.spoilerText,
|
subject: status.spoilerText,
|
||||||
extensions: {
|
extensions: {
|
||||||
|
|
|
||||||
|
|
@ -262,7 +262,6 @@ export const createNewLocalUser = async (data: {
|
||||||
avatar: data.avatar ?? config.defaults.avatar,
|
avatar: data.avatar ?? config.defaults.avatar,
|
||||||
header: data.header ?? config.defaults.avatar,
|
header: data.header ?? config.defaults.avatar,
|
||||||
isAdmin: data.admin ?? false,
|
isAdmin: data.admin ?? false,
|
||||||
uri: "",
|
|
||||||
publicKey: keys.public_key,
|
publicKey: keys.public_key,
|
||||||
privateKey: keys.private_key,
|
privateKey: keys.private_key,
|
||||||
source: {
|
source: {
|
||||||
|
|
@ -273,20 +272,13 @@ export const createNewLocalUser = async (data: {
|
||||||
fields: [],
|
fields: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
include: userRelations,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add to Meilisearch
|
// Add to Meilisearch
|
||||||
await addUserToMeilisearch(user);
|
await addUserToMeilisearch(user);
|
||||||
|
|
||||||
return await client.user.update({
|
return user;
|
||||||
where: {
|
|
||||||
id: user.id,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
uri: new URL(`/users/${user.id}`, config.http.base_url).toString(),
|
|
||||||
},
|
|
||||||
include: userRelations,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -408,7 +400,9 @@ export const userToAPI = (
|
||||||
username: user.username,
|
username: user.username,
|
||||||
display_name: user.displayName,
|
display_name: user.displayName,
|
||||||
note: user.note,
|
note: user.note,
|
||||||
url: user.uri,
|
url:
|
||||||
|
user.uri ||
|
||||||
|
new URL(`/@${user.username}`, config.http.base_url).toString(),
|
||||||
avatar: getAvatarUrl(user, config),
|
avatar: getAvatarUrl(user, config),
|
||||||
header: getHeaderUrl(user, config),
|
header: getHeaderUrl(user, config),
|
||||||
locked: user.isLocked,
|
locked: user.isLocked,
|
||||||
|
|
@ -458,7 +452,7 @@ export const userToLysand = (user: UserWithRelations): LysandUser => {
|
||||||
return {
|
return {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
type: "User",
|
type: "User",
|
||||||
uri: user.uri,
|
uri: user.uri || "",
|
||||||
bio: [
|
bio: [
|
||||||
{
|
{
|
||||||
content: user.note,
|
content: user.note,
|
||||||
|
|
|
||||||
|
|
@ -61,10 +61,12 @@
|
||||||
"@types/jsonld": "^1.5.13",
|
"@types/jsonld": "^1.5.13",
|
||||||
"@typescript-eslint/eslint-plugin": "latest",
|
"@typescript-eslint/eslint-plugin": "latest",
|
||||||
"@unocss/cli": "latest",
|
"@unocss/cli": "latest",
|
||||||
|
"@unocss/transformer-directives": "^0.59.0",
|
||||||
"@vitejs/plugin-vue": "latest",
|
"@vitejs/plugin-vue": "latest",
|
||||||
"@vueuse/head": "^2.0.0",
|
"@vueuse/head": "^2.0.0",
|
||||||
"activitypub-types": "^1.0.3",
|
"activitypub-types": "^1.0.3",
|
||||||
"bun-types": "latest",
|
"bun-types": "latest",
|
||||||
|
"shiki": "^1.2.4",
|
||||||
"typescript": "latest",
|
"typescript": "latest",
|
||||||
"unocss": "latest",
|
"unocss": "latest",
|
||||||
"untyped": "^1.4.2",
|
"untyped": "^1.4.2",
|
||||||
|
|
|
||||||
65
pages/pages/[username]/[uuid].vue
Normal file
65
pages/pages/[username]/[uuid].vue
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex min-h-screen flex-col justify-center px-6 py-12 lg:px-8 relative">
|
||||||
|
<div class="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80" aria-hidden="true">
|
||||||
|
<div class="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
|
||||||
|
style="clip-path: polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)" />
|
||||||
|
</div>
|
||||||
|
<div class="code" v-html="code">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
import { getHighlighterCore } from "shiki/core";
|
||||||
|
import getWasm from "shiki/wasm";
|
||||||
|
|
||||||
|
const location = window.location;
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const data = await fetch(
|
||||||
|
new URL(`/api/v1/statuses/${route.params.uuid}`, location.origin),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.catch(() => ({
|
||||||
|
error: "Failed to fetch status (it probably doesn't exist)",
|
||||||
|
}));
|
||||||
|
|
||||||
|
const highlighter = await getHighlighterCore({
|
||||||
|
themes: [import("shiki/themes/rose-pine.mjs")],
|
||||||
|
langs: [import("shiki/langs/json.mjs")],
|
||||||
|
loadWasm: getWasm,
|
||||||
|
});
|
||||||
|
|
||||||
|
const code = highlighter.codeToHtml(JSON.stringify(data, null, 4), {
|
||||||
|
lang: "json",
|
||||||
|
theme: "rose-pine",
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.code pre:has(code) {
|
||||||
|
word-wrap: normal;
|
||||||
|
background: transparent;
|
||||||
|
-webkit-hyphens: none;
|
||||||
|
hyphens: none;
|
||||||
|
-moz-tab-size: 4;
|
||||||
|
-o-tab-size: 4;
|
||||||
|
tab-size: 4;
|
||||||
|
white-space: pre;
|
||||||
|
word-break: normal;
|
||||||
|
word-spacing: normal;
|
||||||
|
overflow-x: auto;
|
||||||
|
--at-apply: "ring-1 ring-white/10 mt-4 bg-white/5 px-4 py-3 rounded";
|
||||||
|
}
|
||||||
|
|
||||||
|
.code pre code {
|
||||||
|
--at-apply: "block p-0";
|
||||||
|
}
|
||||||
|
</style>
|
||||||
82
pages/pages/[username]/index.vue
Normal file
82
pages/pages/[username]/index.vue
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex min-h-screen flex-col justify-center px-6 py-12 lg:px-8 relative">
|
||||||
|
<div class="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80" aria-hidden="true">
|
||||||
|
<div class="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
|
||||||
|
style="clip-path: polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)" />
|
||||||
|
</div>
|
||||||
|
<div class="code" v-html="code">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
import { getHighlighterCore } from "shiki/core";
|
||||||
|
import getWasm from "shiki/wasm";
|
||||||
|
|
||||||
|
const location = window.location;
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const username = (route.params.username as string).replace("@", "");
|
||||||
|
|
||||||
|
const id = await fetch(
|
||||||
|
new URL(`/api/v1/accounts/search?q=${username}`, location.origin),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.catch(() => null);
|
||||||
|
|
||||||
|
let data = null;
|
||||||
|
|
||||||
|
if (id && id.length > 0) {
|
||||||
|
data = await fetch(
|
||||||
|
new URL(`/api/v1/accounts/${id[0].id}`, location.origin),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.catch(() => ({
|
||||||
|
error: "Failed to fetch user (it probably doesn't exist)",
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const highlighter = await getHighlighterCore({
|
||||||
|
themes: [import("shiki/themes/rose-pine.mjs")],
|
||||||
|
langs: [import("shiki/langs/json.mjs")],
|
||||||
|
loadWasm: getWasm,
|
||||||
|
});
|
||||||
|
|
||||||
|
const code = highlighter.codeToHtml(JSON.stringify(data, null, 4), {
|
||||||
|
lang: "json",
|
||||||
|
theme: "rose-pine",
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.code pre:has(code) {
|
||||||
|
word-wrap: normal;
|
||||||
|
background: transparent;
|
||||||
|
-webkit-hyphens: none;
|
||||||
|
hyphens: none;
|
||||||
|
-moz-tab-size: 4;
|
||||||
|
-o-tab-size: 4;
|
||||||
|
tab-size: 4;
|
||||||
|
white-space: pre;
|
||||||
|
word-break: normal;
|
||||||
|
word-spacing: normal;
|
||||||
|
overflow-x: auto;
|
||||||
|
--at-apply: "ring-1 ring-white/10 mt-4 bg-white/5 px-4 py-3 rounded";
|
||||||
|
}
|
||||||
|
|
||||||
|
.code pre code {
|
||||||
|
--at-apply: "block p-0";
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
<form class="space-y-6" method="POST"
|
<form class="space-y-6" method="POST"
|
||||||
:action="`/auth/login?redirect_uri=${redirect_uri}&response_type=${response_type}&client_id=${client_id}&scope=${scope}`">
|
:action="`/api/auth/login?redirect_uri=${redirect_uri}&response_type=${response_type}&client_id=${client_id}&scope=${scope}`">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="font-bold text-2xl text-center tracking-tight">Login to your account</h1>
|
<h1 class="font-bold text-2xl text-center tracking-tight">Login to your account</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
<form class="space-y-6" method="POST"
|
<form class="space-y-6" method="POST"
|
||||||
:action="`/auth/redirect?redirect_uri=${encodeURIComponent(redirect_uri)}&client_id=${client_id}&code=${code}`">
|
:action="`/api/auth/redirect?redirect_uri=${encodeURIComponent(redirect_uri)}&client_id=${client_id}&code=${code}`">
|
||||||
<div class="flex flex-col items-center gap-y-5">
|
<div class="flex flex-col items-center gap-y-5">
|
||||||
<h1 class="font-bold text-2xl text-center tracking-tight">Allow this application to access your
|
<h1 class="font-bold text-2xl text-center tracking-tight">Allow this application to access your
|
||||||
account?</h1>
|
account?</h1>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import authorizeVue from "./pages/oauth/authorize.vue";
|
||||||
import redirectVue from "./pages/oauth/redirect.vue";
|
import redirectVue from "./pages/oauth/redirect.vue";
|
||||||
import registerIndexVue from "./pages/register/index.vue";
|
import registerIndexVue from "./pages/register/index.vue";
|
||||||
import successVue from "./pages/register/success.vue";
|
import successVue from "./pages/register/success.vue";
|
||||||
|
import statusVue from "./pages/[username]/[uuid].vue";
|
||||||
|
import userVue from "./pages/[username]/index.vue";
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{ path: "/", component: indexVue },
|
{ path: "/", component: indexVue },
|
||||||
|
|
@ -11,4 +13,6 @@ export default [
|
||||||
{ path: "/oauth/redirect", component: redirectVue },
|
{ path: "/oauth/redirect", component: redirectVue },
|
||||||
{ path: "/register", component: registerIndexVue },
|
{ path: "/register", component: registerIndexVue },
|
||||||
{ path: "/register/success", component: successVue },
|
{ path: "/register/success", component: successVue },
|
||||||
|
{ path: "/:username/:uuid", component: statusVue },
|
||||||
|
{ path: "/:username", component: userVue },
|
||||||
] as RouteRecordRaw[];
|
] as RouteRecordRaw[];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Status" ALTER COLUMN "uri" DROP NOT NULL;
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "User" ALTER COLUMN "uri" DROP NOT NULL;
|
||||||
|
|
@ -104,7 +104,7 @@ 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())
|
||||||
|
|
@ -228,7 +228,7 @@ 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
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@ export const rawRoutes = {
|
||||||
"/api/v1/timelines/public": "./server/api/api/v1/timelines/public",
|
"/api/v1/timelines/public": "./server/api/api/v1/timelines/public",
|
||||||
"/api/v2/media": "./server/api/api/v2/media/index",
|
"/api/v2/media": "./server/api/api/v2/media/index",
|
||||||
"/api/v2/search": "./server/api/api/v2/search/index",
|
"/api/v2/search": "./server/api/api/v2/search/index",
|
||||||
"/auth/login": "./server/api/auth/login/index",
|
"/api/auth/login": "./server/api/api/auth/login/index",
|
||||||
"/auth/redirect": "./server/api/auth/redirect/index",
|
"/api/auth/redirect": "./server/api/api/auth/redirect/index",
|
||||||
"/nodeinfo/2.0": "./server/api/nodeinfo/2.0/index",
|
"/nodeinfo/2.0": "./server/api/nodeinfo/2.0/index",
|
||||||
"/oauth/authorize-external": "./server/api/oauth/authorize-external/index",
|
"/oauth/authorize-external": "./server/api/oauth/authorize-external/index",
|
||||||
"/oauth/providers": "./server/api/oauth/providers/index",
|
"/oauth/providers": "./server/api/oauth/providers/index",
|
||||||
|
|
|
||||||
41
server.ts
41
server.ts
|
|
@ -124,7 +124,7 @@ export const createServer = (
|
||||||
|
|
||||||
// Check for allowed requests
|
// Check for allowed requests
|
||||||
// @ts-expect-error Stupid error
|
// @ts-expect-error Stupid error
|
||||||
if (!meta.allowedMethods.includes(req.method as string)) {
|
if (!meta.allowedMethods.includes(req.method)) {
|
||||||
return errorResponse(
|
return errorResponse(
|
||||||
`Method not allowed: allowed methods are: ${meta.allowedMethods.join(
|
`Method not allowed: allowed methods are: ${meta.allowedMethods.join(
|
||||||
", ",
|
", ",
|
||||||
|
|
@ -137,18 +137,16 @@ export const createServer = (
|
||||||
const auth = await getFromRequest(req);
|
const auth = await getFromRequest(req);
|
||||||
|
|
||||||
// Check for authentication if required
|
// Check for authentication if required
|
||||||
if (meta.auth.required) {
|
if (
|
||||||
if (!auth.user) {
|
(meta.auth.required ||
|
||||||
return errorResponse("Unauthorized", 401);
|
(meta.auth.requiredOnMethods ?? []).includes(
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
// @ts-expect-error Stupid error
|
// @ts-expect-error Stupid error
|
||||||
(meta.auth.requiredOnMethods ?? []).includes(req.method)
|
req.method,
|
||||||
|
)) &&
|
||||||
|
!auth.user
|
||||||
) {
|
) {
|
||||||
if (!auth.user) {
|
|
||||||
return errorResponse("Unauthorized", 401);
|
return errorResponse("Unauthorized", 401);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let parsedRequest = {};
|
let parsedRequest = {};
|
||||||
|
|
||||||
|
|
@ -172,17 +170,17 @@ export const createServer = (
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (matchedRoute?.name === "/[...404]" || !matchedRoute) {
|
|
||||||
if (new URL(req.url).pathname.startsWith("/api")) {
|
if (new URL(req.url).pathname.startsWith("/api")) {
|
||||||
return errorResponse("Route not found", 404);
|
return errorResponse("Route not found", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proxy response from Vite at localhost:5173 if in development mode
|
// Proxy response from Vite at localhost:5173 if in development mode
|
||||||
if (isProd) {
|
if (isProd) {
|
||||||
|
let file = Bun.file("./pages/dist/index.html");
|
||||||
if (new URL(req.url).pathname.startsWith("/assets")) {
|
if (new URL(req.url).pathname.startsWith("/assets")) {
|
||||||
const file = Bun.file(
|
file = Bun.file(`./pages/dist${new URL(req.url).pathname}`);
|
||||||
`./pages/dist${new URL(req.url).pathname}`,
|
}
|
||||||
);
|
|
||||||
|
|
||||||
// Serve from pages/dist/assets
|
// Serve from pages/dist/assets
|
||||||
if (await file.exists()) {
|
if (await file.exists()) {
|
||||||
|
|
@ -192,22 +190,9 @@ export const createServer = (
|
||||||
}
|
}
|
||||||
return errorResponse("Asset not found", 404);
|
return errorResponse("Asset not found", 404);
|
||||||
}
|
}
|
||||||
if (new URL(req.url).pathname.startsWith("/api")) {
|
|
||||||
return errorResponse("Route not found", 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
const file = Bun.file("./pages/dist/index.html");
|
|
||||||
|
|
||||||
// Serve from pages/dist
|
|
||||||
return clientResponse(file, 200, {
|
|
||||||
"Content-Type": file.type,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const proxy = await fetch(
|
const proxy = await fetch(
|
||||||
req.url.replace(
|
req.url.replace(config.http.base_url, "http://localhost:5173"),
|
||||||
config.http.base_url,
|
|
||||||
"http://localhost:5173",
|
|
||||||
),
|
|
||||||
).catch(async (e) => {
|
).catch(async (e) => {
|
||||||
await logger.logError(
|
await logger.logError(
|
||||||
LogLevel.ERROR,
|
LogLevel.ERROR,
|
||||||
|
|
@ -232,8 +217,6 @@ export const createServer = (
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
return errorResponse("Route not found", 404);
|
|
||||||
}
|
|
||||||
return errorResponse("Route not found", 404);
|
return errorResponse("Route not found", 404);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -17,5 +17,5 @@ export const meta = applyConfig({
|
||||||
* Default catch-all route, returns a 404 error.
|
* Default catch-all route, returns a 404 error.
|
||||||
*/
|
*/
|
||||||
export default apiRoute(() => {
|
export default apiRoute(() => {
|
||||||
return errorResponse("This API route does not exist", 404);
|
return errorResponse("Route not found", 404);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ export const meta = applyConfig({
|
||||||
max: 4,
|
max: 4,
|
||||||
duration: 60,
|
duration: 60,
|
||||||
},
|
},
|
||||||
route: "/auth/login",
|
route: "/api/auth/login",
|
||||||
auth: {
|
auth: {
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
|
|
@ -8,7 +8,7 @@ export const meta = applyConfig({
|
||||||
max: 4,
|
max: 4,
|
||||||
duration: 60,
|
duration: 60,
|
||||||
},
|
},
|
||||||
route: "/auth/redirect",
|
route: "/api/auth/redirect",
|
||||||
auth: {
|
auth: {
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
|
|
@ -13,7 +13,7 @@ export const meta = applyConfig({
|
||||||
},
|
},
|
||||||
route: "/api/v1/accounts/:id",
|
route: "/api/v1/accounts/:id",
|
||||||
auth: {
|
auth: {
|
||||||
required: true,
|
required: false,
|
||||||
oauthPermissions: [],
|
oauthPermissions: [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ export const meta = applyConfig({
|
||||||
duration: 60,
|
duration: 60,
|
||||||
},
|
},
|
||||||
auth: {
|
auth: {
|
||||||
required: true,
|
required: false,
|
||||||
oauthPermissions: ["read:accounts"],
|
oauthPermissions: ["read:accounts"],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -25,11 +25,6 @@ export default apiRoute<{
|
||||||
following?: boolean;
|
following?: boolean;
|
||||||
}>(async (req, matchedRoute, extraData) => {
|
}>(async (req, matchedRoute, extraData) => {
|
||||||
// TODO: Add checks for disabled or not email verified accounts
|
// TODO: Add checks for disabled or not email verified accounts
|
||||||
|
|
||||||
const { user } = extraData.auth;
|
|
||||||
|
|
||||||
if (!user) return errorResponse("Unauthorized", 401);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
following = false,
|
following = false,
|
||||||
limit = 40,
|
limit = 40,
|
||||||
|
|
@ -37,6 +32,10 @@ export default apiRoute<{
|
||||||
q,
|
q,
|
||||||
} = extraData.parsedRequest;
|
} = extraData.parsedRequest;
|
||||||
|
|
||||||
|
const { user } = extraData.auth;
|
||||||
|
|
||||||
|
if (!user && following) return errorResponse("Unauthorized", 401);
|
||||||
|
|
||||||
if (limit < 1 || limit > 80) {
|
if (limit < 1 || limit > 80) {
|
||||||
return errorResponse("Limit must be between 1 and 80", 400);
|
return errorResponse("Limit must be between 1 and 80", 400);
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +59,7 @@ export default apiRoute<{
|
||||||
relationshipSubjects: following
|
relationshipSubjects: following
|
||||||
? {
|
? {
|
||||||
some: {
|
some: {
|
||||||
ownerId: user.id,
|
ownerId: user?.id,
|
||||||
following,
|
following,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ describe("API Tests", () => {
|
||||||
expect(account.statuses_count).toBe(0);
|
expect(account.statuses_count).toBe(0);
|
||||||
expect(account.note).toBe("");
|
expect(account.note).toBe("");
|
||||||
expect(account.url).toBe(
|
expect(account.url).toBe(
|
||||||
new URL(`/users/${user.id}`, config.http.base_url).toString(),
|
new URL(`/@${user.username}`, config.http.base_url).toString(),
|
||||||
);
|
);
|
||||||
expect(account.avatar).toBeDefined();
|
expect(account.avatar).toBeDefined();
|
||||||
expect(account.avatar_static).toBeDefined();
|
expect(account.avatar_static).toBeDefined();
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ describe("POST /api/v1/apps/", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("POST /auth/login/", () => {
|
describe("POST /api/auth/login/", () => {
|
||||||
test("should get a code", async () => {
|
test("should get a code", async () => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
||||||
|
|
@ -67,7 +67,7 @@ describe("POST /auth/login/", () => {
|
||||||
const response = await sendTestRequest(
|
const response = await sendTestRequest(
|
||||||
new Request(
|
new Request(
|
||||||
wrapRelativeUrl(
|
wrapRelativeUrl(
|
||||||
`/auth/login/?client_id=${client_id}&redirect_uri=https://example.com&response_type=code&scope=read+write`,
|
`/api/auth/login/?client_id=${client_id}&redirect_uri=https://example.com&response_type=code&scope=read+write`,
|
||||||
base_url,
|
base_url,
|
||||||
),
|
),
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import { presetForms } from "@julr/unocss-preset-forms";
|
import { presetForms } from "@julr/unocss-preset-forms";
|
||||||
|
import transformerDirectives from "@unocss/transformer-directives";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
defineConfig,
|
defineConfig,
|
||||||
presetTypography,
|
presetTypography,
|
||||||
|
|
@ -19,4 +21,5 @@ export default defineConfig({
|
||||||
presetWebFonts(),
|
presetWebFonts(),
|
||||||
presetForms(),
|
presetForms(),
|
||||||
],
|
],
|
||||||
|
transformers: [transformerDirectives()],
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue