mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
Add resolving of threads, mentions and quote posts
This commit is contained in:
parent
cf295a596a
commit
38a6f9a809
|
|
@ -23,7 +23,7 @@ import { applicationToAPI } from "./Application";
|
||||||
import { attachmentToAPI, attachmentToLysand } from "./Attachment";
|
import { attachmentToAPI, attachmentToLysand } from "./Attachment";
|
||||||
import { emojiToAPI, emojiToLysand, parseEmojis } from "./Emoji";
|
import { emojiToAPI, emojiToLysand, parseEmojis } from "./Emoji";
|
||||||
import type { UserWithRelations } from "./User";
|
import type { UserWithRelations } from "./User";
|
||||||
import { getUserUri, userToAPI } from "./User";
|
import { getUserUri, resolveUser, userToAPI } from "./User";
|
||||||
import { statusAndUserRelations, userRelations } from "./relations";
|
import { statusAndUserRelations, userRelations } from "./relations";
|
||||||
import { objectToInboxRequest } from "./Federation";
|
import { objectToInboxRequest } from "./Federation";
|
||||||
|
|
||||||
|
|
@ -58,9 +58,84 @@ export const isViewableByUser = (status: Status, user: User | null) => {
|
||||||
return user && (status.mentions as User[]).includes(user);
|
return user && (status.mentions as User[]).includes(user);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchFromRemote = async (
|
export const resolveStatus = async (
|
||||||
uri: string,
|
uri?: string,
|
||||||
): Promise<StatusWithRelations | null> => {};
|
providedNote?: Lysand.Note,
|
||||||
|
): Promise<StatusWithRelations> => {
|
||||||
|
if (!uri && !providedNote) {
|
||||||
|
throw new Error("No URI or note provided");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if status not already in database
|
||||||
|
const foundStatus = await client.status.findUnique({
|
||||||
|
where: {
|
||||||
|
uri: uri ?? providedNote?.uri,
|
||||||
|
},
|
||||||
|
include: statusAndUserRelations,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (foundStatus) return foundStatus;
|
||||||
|
|
||||||
|
let note: Lysand.Note | null = providedNote ?? null;
|
||||||
|
|
||||||
|
if (uri) {
|
||||||
|
if (!URL.canParse(uri)) {
|
||||||
|
throw new Error(`Invalid URI to parse ${uri}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(uri, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Accept: "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
note = (await response.json()) as Lysand.Note;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!note) {
|
||||||
|
throw new Error("No note was able to be fetched");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (note.type !== "Note") {
|
||||||
|
throw new Error("Invalid object type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!note.author) {
|
||||||
|
throw new Error("Invalid object author");
|
||||||
|
}
|
||||||
|
|
||||||
|
const author = await resolveUser(note.author);
|
||||||
|
|
||||||
|
if (!author) {
|
||||||
|
throw new Error("Invalid object author");
|
||||||
|
}
|
||||||
|
|
||||||
|
return await createNewStatus(
|
||||||
|
author,
|
||||||
|
note.content ?? {
|
||||||
|
"text/plain": {
|
||||||
|
content: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
note.visibility as APIStatus["visibility"],
|
||||||
|
note.is_sensitive ?? false,
|
||||||
|
note.subject ?? "",
|
||||||
|
[],
|
||||||
|
note.uri,
|
||||||
|
await Promise.all(
|
||||||
|
(note.mentions ?? [])
|
||||||
|
.map((mention) => resolveUser(mention))
|
||||||
|
.filter(
|
||||||
|
(mention) => mention !== null,
|
||||||
|
) as Promise<UserWithRelations>[],
|
||||||
|
),
|
||||||
|
// TODO: Add attachments
|
||||||
|
[],
|
||||||
|
note.replies_to ? await resolveStatus(note.replies_to) : undefined,
|
||||||
|
note.quotes ? await resolveStatus(note.quotes) : undefined,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all the ancestors of this post,
|
* Return all the ancestors of this post,
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,26 @@ export const resolveUser = async (uri: string) => {
|
||||||
|
|
||||||
if (foundUser) return foundUser;
|
if (foundUser) return foundUser;
|
||||||
|
|
||||||
|
// Check if URI is of a local user
|
||||||
|
if (uri.startsWith(config.http.base_url)) {
|
||||||
|
const uuid = uri.match(
|
||||||
|
/[0-9A-F]{8}-[0-9A-F]{4}-[7][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!uuid) {
|
||||||
|
throw new Error(
|
||||||
|
`URI ${uri} is of a local user, but it could not be parsed`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.user.findUnique({
|
||||||
|
where: {
|
||||||
|
id: uuid[0],
|
||||||
|
},
|
||||||
|
include: userRelations,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!URL.canParse(uri)) {
|
if (!URL.canParse(uri)) {
|
||||||
throw new Error(`Invalid URI to parse ${uri}`);
|
throw new Error(`Invalid URI to parse ${uri}`);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { errorResponse, response } from "@response";
|
||||||
import { client } from "~database/datasource";
|
import { client } from "~database/datasource";
|
||||||
import { userRelations } from "~database/entities/relations";
|
import { userRelations } from "~database/entities/relations";
|
||||||
import type * as Lysand from "lysand-types";
|
import type * as Lysand from "lysand-types";
|
||||||
import { createNewStatus } from "~database/entities/Status";
|
import { createNewStatus, resolveStatus } from "~database/entities/Status";
|
||||||
import type { APIStatus } from "~types/entities/status";
|
import type { APIStatus } from "~types/entities/status";
|
||||||
import {
|
import {
|
||||||
followAcceptToLysand,
|
followAcceptToLysand,
|
||||||
|
|
@ -132,27 +132,17 @@ export default apiRoute(async (req, matchedRoute, extraData) => {
|
||||||
return errorResponse("Author not found", 400);
|
return errorResponse("Author not found", 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
await createNewStatus(
|
const newStatus = await resolveStatus(undefined, note).catch(
|
||||||
account,
|
(e) => {
|
||||||
note.content ?? {
|
console.error(e);
|
||||||
"text/plain": {
|
return null;
|
||||||
content: "",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
note.visibility as APIStatus["visibility"],
|
|
||||||
note.is_sensitive ?? false,
|
|
||||||
note.subject ?? "",
|
|
||||||
[],
|
|
||||||
note.uri,
|
|
||||||
// TODO: Resolve mentions
|
|
||||||
[],
|
|
||||||
// TODO: Add attachments
|
|
||||||
[],
|
|
||||||
// TODO: Resolve replies and quoting
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!newStatus) {
|
||||||
|
return errorResponse("Failed to add status", 500);
|
||||||
|
}
|
||||||
|
|
||||||
return response("Note created", 201);
|
return response("Note created", 201);
|
||||||
}
|
}
|
||||||
case "Follow": {
|
case "Follow": {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue