mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 16:38:19 +01:00
More tests, make Delete objects work
This commit is contained in:
parent
76b1b8c3b4
commit
bc6873422f
|
|
@ -13,6 +13,7 @@ import {
|
||||||
APUpdate,
|
APUpdate,
|
||||||
} from "activitypub-types";
|
} from "activitypub-types";
|
||||||
import { MatchedRoute } from "bun";
|
import { MatchedRoute } from "bun";
|
||||||
|
import { appendFile } from "fs/promises";
|
||||||
import { RawActivity } from "~database/entities/RawActivity";
|
import { RawActivity } from "~database/entities/RawActivity";
|
||||||
import { RawObject } from "~database/entities/RawObject";
|
import { RawObject } from "~database/entities/RawObject";
|
||||||
|
|
||||||
|
|
@ -43,24 +44,49 @@ export default async (
|
||||||
// TODO: Add authentication
|
// TODO: Add authentication
|
||||||
|
|
||||||
// Check is Activity already exists
|
// Check is Activity already exists
|
||||||
const exists = await RawActivity.findOneBy({
|
const exists = await RawActivity.createQueryBuilder("activity")
|
||||||
data: {
|
.where("activity.data->>'id' = :id", {
|
||||||
id: body.id,
|
id: body.id,
|
||||||
},
|
})
|
||||||
});
|
.getOne();
|
||||||
|
|
||||||
if (exists) return errorResponse("Activity already exists", 409);
|
if (exists) return errorResponse("Activity already exists", 409);
|
||||||
|
|
||||||
// Check if object already exists
|
// Check if object already exists
|
||||||
const objectExists = await RawObject.findOneBy({
|
const objectExists = await RawObject.createQueryBuilder("object")
|
||||||
data: {
|
.where("object.data->>'id' = :id", {
|
||||||
id: (body.object as APObject).id,
|
id: (body.object as APObject).id,
|
||||||
},
|
})
|
||||||
});
|
.getOne();
|
||||||
|
|
||||||
if (objectExists)
|
if (objectExists)
|
||||||
return errorResponse("Object already exists", 409);
|
return errorResponse("Object already exists", 409);
|
||||||
|
|
||||||
|
// Check if object body contains any filtered terms
|
||||||
|
const filter_result = await Promise.all(
|
||||||
|
config.filters.note_filters.map(async filter => {
|
||||||
|
if (
|
||||||
|
(body.object as APObject).type === "Note" &&
|
||||||
|
(body.object as APObject).content?.match(filter)
|
||||||
|
) {
|
||||||
|
// Log filter
|
||||||
|
|
||||||
|
if (config.logging.log_filters)
|
||||||
|
await appendFile(
|
||||||
|
process.cwd() + "/logs/filters.log",
|
||||||
|
`${new Date().toISOString()} Filtered note content: "${(
|
||||||
|
body.object as APObject
|
||||||
|
).content?.replaceAll("\n", " ")}" (ID: ${
|
||||||
|
(body.object as APObject).id
|
||||||
|
}) based on rule: ${filter}\n`
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
if (filter_result.includes(true)) return jsonResponse({});
|
||||||
|
|
||||||
const activity = new RawActivity();
|
const activity = new RawActivity();
|
||||||
const object = new RawObject();
|
const object = new RawObject();
|
||||||
|
|
||||||
|
|
@ -109,19 +135,23 @@ export default async (
|
||||||
// Delete the object from database
|
// Delete the object from database
|
||||||
// TODO: Add authentication
|
// TODO: Add authentication
|
||||||
|
|
||||||
const object = await RawObject.findOneBy({
|
const object = await RawObject.createQueryBuilder("object")
|
||||||
data: {
|
.where("object.data->>'id' = :id", {
|
||||||
id: (body.object as RawObject).id,
|
id: (body.object as APObject).id,
|
||||||
},
|
})
|
||||||
});
|
.getOne();
|
||||||
|
|
||||||
if (!object) return errorResponse("Object not found", 404);
|
if (!object) return errorResponse("Object not found", 404);
|
||||||
|
|
||||||
const activities = await RawActivity.findBy({
|
const activities = await RawActivity.createQueryBuilder("activity")
|
||||||
objects: {
|
// Objects is a many-to-many relationship
|
||||||
id: (body.object as RawObject).id,
|
.leftJoinAndSelect("activity.objects", "objects")
|
||||||
},
|
.where("objects.data @> :data", {
|
||||||
});
|
data: JSON.stringify({
|
||||||
|
id: object.id,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.getMany();
|
||||||
|
|
||||||
if (config.activitypub.use_tombstones) {
|
if (config.activitypub.use_tombstones) {
|
||||||
object.data = {
|
object.data = {
|
||||||
|
|
@ -146,6 +176,18 @@ export default async (
|
||||||
|
|
||||||
await object.remove();
|
await object.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store the Delete event in the database
|
||||||
|
const activity = new RawActivity();
|
||||||
|
activity.data = {
|
||||||
|
...body,
|
||||||
|
object: undefined,
|
||||||
|
};
|
||||||
|
activity.objects = config.activitypub.use_tombstones
|
||||||
|
? [object]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
await activity.save();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "Accept" as APAccept: {
|
case "Accept" as APAccept: {
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ describe("POST /@test/inbox", () => {
|
||||||
"@context": "https://www.w3.org/ns/activitystreams",
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
id: "https://example.com/notes/1",
|
id: "https://example.com/notes/1",
|
||||||
type: "Note",
|
type: "Note",
|
||||||
content: "This note has been deleted!",
|
content: "This note has been edited!",
|
||||||
summary: null,
|
summary: null,
|
||||||
inReplyTo: null,
|
inReplyTo: null,
|
||||||
published: "2021-01-01T00:00:00.000Z",
|
published: "2021-01-01T00:00:00.000Z",
|
||||||
|
|
@ -204,7 +204,12 @@ describe("POST /@test/inbox", () => {
|
||||||
published: "2021-01-03T00:00:00.000Z",
|
published: "2021-01-03T00:00:00.000Z",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(activity?.objects).toHaveLength(0);
|
// Can be 0 or 1 length depending on whether config.activitypub.use_tombstone is true or false
|
||||||
|
if (config.activitypub.use_tombstones) {
|
||||||
|
expect(activity?.objects).toHaveLength(1);
|
||||||
|
} else {
|
||||||
|
expect(activity?.objects).toHaveLength(0);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue