mirror of https://github.com/LemmyNet/lemmy.git
Merge branch 'main' into markdown-link-rule
commit
6232fa0279
|
@ -20,6 +20,8 @@ query_testing/**/reports/*.json
|
||||||
api_tests/node_modules
|
api_tests/node_modules
|
||||||
api_tests/.yalc
|
api_tests/.yalc
|
||||||
api_tests/yalc.lock
|
api_tests/yalc.lock
|
||||||
|
api_tests/test.png
|
||||||
|
api_tests/pict-rs
|
||||||
|
|
||||||
# pictrs data
|
# pictrs data
|
||||||
pictrs/
|
pictrs/
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# See https://github.com/woodpecker-ci/woodpecker/issues/1677
|
# See https://github.com/woodpecker-ci/woodpecker/issues/1677
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
- &rust_image "rust:1.72.1"
|
- &rust_image "rust:1.74.0"
|
||||||
- &slow_check_paths
|
- &slow_check_paths
|
||||||
- path:
|
- path:
|
||||||
# rust source code
|
# rust source code
|
||||||
|
@ -163,21 +163,7 @@ steps:
|
||||||
commands:
|
commands:
|
||||||
# when adding new clippy lints, make sure to also add them in scripts/lint.sh
|
# when adding new clippy lints, make sure to also add them in scripts/lint.sh
|
||||||
- rustup component add clippy
|
- rustup component add clippy
|
||||||
- cargo clippy --workspace --tests --all-targets --features console --
|
- cargo clippy --workspace --tests --all-targets --features console -- -D warnings
|
||||||
-D warnings -D deprecated -D clippy::perf -D clippy::complexity
|
|
||||||
-D clippy::style -D clippy::correctness -D clippy::suspicious
|
|
||||||
-D clippy::dbg_macro -D clippy::inefficient_to_string
|
|
||||||
-D clippy::items-after-statements -D clippy::implicit_clone
|
|
||||||
-D clippy::cast_lossless -D clippy::manual_string_new
|
|
||||||
-D clippy::redundant_closure_for_method_calls
|
|
||||||
-D clippy::unused_self
|
|
||||||
-A clippy::uninlined_format_args
|
|
||||||
-D clippy::get_first
|
|
||||||
-D clippy::explicit_into_iter_loop
|
|
||||||
-D clippy::explicit_iter_loop
|
|
||||||
-D clippy::needless_collect
|
|
||||||
-D clippy::unwrap_used
|
|
||||||
-D clippy::indexing_slicing
|
|
||||||
when: *slow_check_paths
|
when: *slow_check_paths
|
||||||
|
|
||||||
cargo_build:
|
cargo_build:
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
51
Cargo.toml
51
Cargo.toml
|
@ -1,5 +1,5 @@
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.19.0-rc.4"
|
version = "0.19.0-rc.6"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A link aggregator for the fediverse"
|
description = "A link aggregator for the fediverse"
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
|
@ -20,6 +20,9 @@ repository.workspace = true
|
||||||
[lib]
|
[lib]
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = 0
|
debug = 0
|
||||||
lto = "thin"
|
lto = "thin"
|
||||||
|
@ -58,18 +61,40 @@ members = [
|
||||||
"crates/federate",
|
"crates/federate",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[workspace.lints.clippy]
|
||||||
|
cast_lossless = "deny"
|
||||||
|
complexity = "deny"
|
||||||
|
correctness = "deny"
|
||||||
|
dbg_macro = "deny"
|
||||||
|
explicit_into_iter_loop = "deny"
|
||||||
|
explicit_iter_loop = "deny"
|
||||||
|
get_first = "deny"
|
||||||
|
implicit_clone = "deny"
|
||||||
|
indexing_slicing = "deny"
|
||||||
|
inefficient_to_string = "deny"
|
||||||
|
items-after-statements = "deny"
|
||||||
|
manual_string_new = "deny"
|
||||||
|
needless_collect = "deny"
|
||||||
|
perf = "deny"
|
||||||
|
redundant_closure_for_method_calls = "deny"
|
||||||
|
style = "deny"
|
||||||
|
suspicious = "deny"
|
||||||
|
uninlined_format_args = "allow"
|
||||||
|
unused_self = "deny"
|
||||||
|
unwrap_used = "deny"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
lemmy_api = { version = "=0.19.0-rc.4", path = "./crates/api" }
|
lemmy_api = { version = "=0.19.0-rc.6", path = "./crates/api" }
|
||||||
lemmy_api_crud = { version = "=0.19.0-rc.4", path = "./crates/api_crud" }
|
lemmy_api_crud = { version = "=0.19.0-rc.6", path = "./crates/api_crud" }
|
||||||
lemmy_apub = { version = "=0.19.0-rc.4", path = "./crates/apub" }
|
lemmy_apub = { version = "=0.19.0-rc.6", path = "./crates/apub" }
|
||||||
lemmy_utils = { version = "=0.19.0-rc.4", path = "./crates/utils" }
|
lemmy_utils = { version = "=0.19.0-rc.6", path = "./crates/utils" }
|
||||||
lemmy_db_schema = { version = "=0.19.0-rc.4", path = "./crates/db_schema" }
|
lemmy_db_schema = { version = "=0.19.0-rc.6", path = "./crates/db_schema" }
|
||||||
lemmy_api_common = { version = "=0.19.0-rc.4", path = "./crates/api_common" }
|
lemmy_api_common = { version = "=0.19.0-rc.6", path = "./crates/api_common" }
|
||||||
lemmy_routes = { version = "=0.19.0-rc.4", path = "./crates/routes" }
|
lemmy_routes = { version = "=0.19.0-rc.6", path = "./crates/routes" }
|
||||||
lemmy_db_views = { version = "=0.19.0-rc.4", path = "./crates/db_views" }
|
lemmy_db_views = { version = "=0.19.0-rc.6", path = "./crates/db_views" }
|
||||||
lemmy_db_views_actor = { version = "=0.19.0-rc.4", path = "./crates/db_views_actor" }
|
lemmy_db_views_actor = { version = "=0.19.0-rc.6", path = "./crates/db_views_actor" }
|
||||||
lemmy_db_views_moderator = { version = "=0.19.0-rc.4", path = "./crates/db_views_moderator" }
|
lemmy_db_views_moderator = { version = "=0.19.0-rc.6", path = "./crates/db_views_moderator" }
|
||||||
activitypub_federation = { version = "0.5.0-beta.4", default-features = false, features = [
|
activitypub_federation = { version = "0.5.0-beta.5", default-features = false, features = [
|
||||||
"actix-web",
|
"actix-web",
|
||||||
] }
|
] }
|
||||||
diesel = "2.1.3"
|
diesel = "2.1.3"
|
||||||
|
@ -137,7 +162,7 @@ lemmy_utils = { workspace = true }
|
||||||
lemmy_db_schema = { workspace = true }
|
lemmy_db_schema = { workspace = true }
|
||||||
lemmy_api_common = { workspace = true }
|
lemmy_api_common = { workspace = true }
|
||||||
lemmy_routes = { workspace = true }
|
lemmy_routes = { workspace = true }
|
||||||
lemmy_federate = { version = "0.19.0-rc.4", path = "crates/federate" }
|
lemmy_federate = { version = "0.19.0-rc.6", path = "crates/federate" }
|
||||||
activitypub_federation = { workspace = true }
|
activitypub_federation = { workspace = true }
|
||||||
diesel = { workspace = true }
|
diesel = { workspace = true }
|
||||||
diesel-async = { workspace = true }
|
diesel-async = { workspace = true }
|
||||||
|
|
|
@ -9,17 +9,25 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src && prettier --check 'src/**/*.ts'",
|
"lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src && prettier --check 'src/**/*.ts'",
|
||||||
"fix": "prettier --write src && eslint --fix src",
|
"fix": "prettier --write src && eslint --fix src",
|
||||||
"api-test": "jest -i follow.spec.ts && jest -i post.spec.ts && jest -i comment.spec.ts && jest -i private_message.spec.ts && jest -i user.spec.ts && jest -i community.spec.ts"
|
"api-test": "jest -i follow.spec.ts && jest -i post.spec.ts && jest -i comment.spec.ts && jest -i private_message.spec.ts && jest -i user.spec.ts && jest -i community.spec.ts && jest -i image.spec.ts",
|
||||||
|
"api-test-follow": "jest -i follow.spec.ts",
|
||||||
|
"api-test-comment": "jest -i comment.spec.ts",
|
||||||
|
"api-test-post": "jest -i post.spec.ts",
|
||||||
|
"api-test-user": "jest -i user.spec.ts",
|
||||||
|
"api-test-community": "jest -i community.spec.ts",
|
||||||
|
"api-test-private-message": "jest -i private_message.spec.ts",
|
||||||
|
"api-test-image": "jest -i image.spec.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.6",
|
"@types/jest": "^29.5.8",
|
||||||
"@types/node": "^20.8.7",
|
"@types/node": "^20.9.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.8.0",
|
"@typescript-eslint/eslint-plugin": "^6.10.0",
|
||||||
"@typescript-eslint/parser": "^6.8.0",
|
"@typescript-eslint/parser": "^6.10.0",
|
||||||
"eslint": "^8.52.0",
|
"download-file-sync": "^1.0.4",
|
||||||
|
"eslint": "^8.53.0",
|
||||||
"eslint-plugin-prettier": "^5.0.1",
|
"eslint-plugin-prettier": "^5.0.1",
|
||||||
"jest": "^29.5.0",
|
"jest": "^29.5.0",
|
||||||
"lemmy-js-client": "0.19.0-rc.12",
|
"lemmy-js-client": "0.19.0-alpha.18",
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.0",
|
||||||
"typescript": "^5.0.4"
|
"typescript": "^5.0.4"
|
||||||
|
|
Binary file not shown.
|
@ -8,6 +8,18 @@ export RUST_LOG="warn,lemmy_server=debug,lemmy_federate=debug,lemmy_api=debug,le
|
||||||
|
|
||||||
export LEMMY_TEST_FAST_FEDERATION=1 # by default, the persistent federation queue has delays in the scale of 30s-5min
|
export LEMMY_TEST_FAST_FEDERATION=1 # by default, the persistent federation queue has delays in the scale of 30s-5min
|
||||||
|
|
||||||
|
# pictrs setup
|
||||||
|
if ! [ -f "pict-rs" ]; then
|
||||||
|
curl "https://git.asonix.dog/asonix/pict-rs/releases/download/v0.5.0-beta.2/pict-rs-linux-amd64" -o api_tests/pict-rs
|
||||||
|
chmod +x api_tests/pict-rs
|
||||||
|
fi
|
||||||
|
./api_tests/pict-rs \
|
||||||
|
run -a 0.0.0.0:8080 \
|
||||||
|
--danger-dummy-mode \
|
||||||
|
--api-key "my-pictrs-key" \
|
||||||
|
filesystem -p /tmp/pictrs/files \
|
||||||
|
sled -p /tmp/pictrs/sled-repo 2>&1 &
|
||||||
|
|
||||||
for INSTANCE in lemmy_alpha lemmy_beta lemmy_gamma lemmy_delta lemmy_epsilon; do
|
for INSTANCE in lemmy_alpha lemmy_beta lemmy_gamma lemmy_delta lemmy_epsilon; do
|
||||||
echo "DB URL: ${LEMMY_DATABASE_URL} INSTANCE: $INSTANCE"
|
echo "DB URL: ${LEMMY_DATABASE_URL} INSTANCE: $INSTANCE"
|
||||||
psql "${LEMMY_DATABASE_URL}/lemmy" -c "DROP DATABASE IF EXISTS $INSTANCE"
|
psql "${LEMMY_DATABASE_URL}/lemmy" -c "DROP DATABASE IF EXISTS $INSTANCE"
|
||||||
|
|
|
@ -14,6 +14,8 @@ yarn
|
||||||
yarn api-test || true
|
yarn api-test || true
|
||||||
|
|
||||||
killall -s1 lemmy_server || true
|
killall -s1 lemmy_server || true
|
||||||
|
killall -s1 pict-rs || true
|
||||||
for INSTANCE in lemmy_alpha lemmy_beta lemmy_gamma lemmy_delta lemmy_epsilon; do
|
for INSTANCE in lemmy_alpha lemmy_beta lemmy_gamma lemmy_delta lemmy_epsilon; do
|
||||||
psql "$LEMMY_DATABASE_URL" -c "DROP DATABASE $INSTANCE"
|
psql "$LEMMY_DATABASE_URL" -c "DROP DATABASE $INSTANCE"
|
||||||
done
|
done
|
||||||
|
rm -r /tmp/pictrs
|
||||||
|
|
|
@ -35,9 +35,10 @@ import {
|
||||||
waitForPost,
|
waitForPost,
|
||||||
alphaUrl,
|
alphaUrl,
|
||||||
followCommunity,
|
followCommunity,
|
||||||
|
blockCommunity,
|
||||||
|
delay,
|
||||||
} from "./shared";
|
} from "./shared";
|
||||||
import { CommentView } from "lemmy-js-client/dist/types/CommentView";
|
import { CommentView, CommunityView } from "lemmy-js-client";
|
||||||
import { CommunityView } from "lemmy-js-client";
|
|
||||||
import { LemmyHttp } from "lemmy-js-client";
|
import { LemmyHttp } from "lemmy-js-client";
|
||||||
|
|
||||||
let betaCommunity: CommunityView | undefined;
|
let betaCommunity: CommunityView | undefined;
|
||||||
|
@ -53,8 +54,8 @@ beforeAll(async () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(() => {
|
||||||
await unfollows();
|
unfollows();
|
||||||
});
|
});
|
||||||
|
|
||||||
function assertCommentFederation(
|
function assertCommentFederation(
|
||||||
|
@ -93,7 +94,9 @@ test("Create a comment", async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Create a comment in a non-existent post", async () => {
|
test("Create a comment in a non-existent post", async () => {
|
||||||
await expect(createComment(alpha, -1)).rejects.toBe("couldnt_find_post");
|
await expect(createComment(alpha, -1)).rejects.toStrictEqual(
|
||||||
|
Error("couldnt_find_post"),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Update a comment", async () => {
|
test("Update a comment", async () => {
|
||||||
|
@ -142,7 +145,7 @@ test("Delete a comment", async () => {
|
||||||
await waitUntil(
|
await waitUntil(
|
||||||
() =>
|
() =>
|
||||||
resolveComment(gamma, commentRes.comment_view.comment).catch(e => e),
|
resolveComment(gamma, commentRes.comment_view.comment).catch(e => e),
|
||||||
r => r !== "couldnt_find_object",
|
r => r.message !== "couldnt_find_object",
|
||||||
)
|
)
|
||||||
).comment;
|
).comment;
|
||||||
if (!gammaComment) {
|
if (!gammaComment) {
|
||||||
|
@ -159,13 +162,13 @@ test("Delete a comment", async () => {
|
||||||
// Make sure that comment is undefined on beta
|
// Make sure that comment is undefined on beta
|
||||||
await waitUntil(
|
await waitUntil(
|
||||||
() => resolveComment(beta, commentRes.comment_view.comment).catch(e => e),
|
() => resolveComment(beta, commentRes.comment_view.comment).catch(e => e),
|
||||||
e => e === "couldnt_find_object",
|
e => e.message == "couldnt_find_object",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Make sure that comment is undefined on gamma after delete
|
// Make sure that comment is undefined on gamma after delete
|
||||||
await waitUntil(
|
await waitUntil(
|
||||||
() => resolveComment(gamma, commentRes.comment_view.comment).catch(e => e),
|
() => resolveComment(gamma, commentRes.comment_view.comment).catch(e => e),
|
||||||
e => e === "couldnt_find_object",
|
e => e.message === "couldnt_find_object",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test undeleting the comment
|
// Test undeleting the comment
|
||||||
|
@ -180,7 +183,7 @@ test("Delete a comment", async () => {
|
||||||
let betaComment2 = (
|
let betaComment2 = (
|
||||||
await waitUntil(
|
await waitUntil(
|
||||||
() => resolveComment(beta, commentRes.comment_view.comment).catch(e => e),
|
() => resolveComment(beta, commentRes.comment_view.comment).catch(e => e),
|
||||||
e => e !== "couldnt_find_object",
|
e => e.message !== "couldnt_find_object",
|
||||||
)
|
)
|
||||||
).comment;
|
).comment;
|
||||||
expect(betaComment2?.comment.deleted).toBe(false);
|
expect(betaComment2?.comment.deleted).toBe(false);
|
||||||
|
@ -227,10 +230,7 @@ test.skip("Remove a comment from admin and community on the same instance", asyn
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Remove a comment from admin and community on different instance", async () => {
|
test("Remove a comment from admin and community on different instance", async () => {
|
||||||
let alpha_user = await registerUser(alpha);
|
let newAlphaApi = await registerUser(alpha, alphaUrl);
|
||||||
let newAlphaApi = new LemmyHttp(alphaUrl, {
|
|
||||||
headers: { Authorization: `Bearer ${alpha_user.jwt ?? ""}` },
|
|
||||||
});
|
|
||||||
|
|
||||||
// New alpha user creates a community, post, and comment.
|
// New alpha user creates a community, post, and comment.
|
||||||
let newCommunity = await createCommunity(newAlphaApi);
|
let newCommunity = await createCommunity(newAlphaApi);
|
||||||
|
@ -740,3 +740,47 @@ test("Report a comment", async () => {
|
||||||
);
|
);
|
||||||
expect(betaReport.reason).toBe(alphaReport.reason);
|
expect(betaReport.reason).toBe(alphaReport.reason);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Dont send a comment reply to a blocked community", async () => {
|
||||||
|
let newCommunity = await createCommunity(beta);
|
||||||
|
let newCommunityId = newCommunity.community_view.community.id;
|
||||||
|
|
||||||
|
// Create a post on beta
|
||||||
|
let betaPost = await createPost(beta, newCommunityId);
|
||||||
|
|
||||||
|
let alphaPost = (await resolvePost(alpha, betaPost.post_view.post))!.post;
|
||||||
|
if (!alphaPost) {
|
||||||
|
throw "unable to locate post on alpha";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check beta's inbox count
|
||||||
|
let unreadCount = await getUnreadCount(beta);
|
||||||
|
expect(unreadCount.replies).toBe(1);
|
||||||
|
|
||||||
|
// Beta blocks the new beta community
|
||||||
|
let blockRes = await blockCommunity(beta, newCommunityId, true);
|
||||||
|
expect(blockRes.blocked).toBe(true);
|
||||||
|
delay();
|
||||||
|
|
||||||
|
// Alpha creates a comment
|
||||||
|
let commentRes = await createComment(alpha, alphaPost.post.id);
|
||||||
|
expect(commentRes.comment_view.comment.content).toBeDefined();
|
||||||
|
let alphaComment = await resolveComment(
|
||||||
|
beta,
|
||||||
|
commentRes.comment_view.comment,
|
||||||
|
);
|
||||||
|
if (!alphaComment) {
|
||||||
|
throw "Missing alpha comment before block";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check beta's inbox count, make sure it stays the same
|
||||||
|
unreadCount = await getUnreadCount(beta);
|
||||||
|
expect(unreadCount.replies).toBe(1);
|
||||||
|
|
||||||
|
let replies = await getReplies(beta);
|
||||||
|
expect(replies.replies.length).toBe(1);
|
||||||
|
|
||||||
|
// Unblock the community
|
||||||
|
blockRes = await blockCommunity(beta, newCommunityId, false);
|
||||||
|
expect(blockRes.blocked).toBe(false);
|
||||||
|
});
|
||||||
|
|
|
@ -34,9 +34,7 @@ import {
|
||||||
} from "./shared";
|
} from "./shared";
|
||||||
import { EditSite, LemmyHttp } from "lemmy-js-client";
|
import { EditSite, LemmyHttp } from "lemmy-js-client";
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(setupLogins);
|
||||||
await setupLogins();
|
|
||||||
});
|
|
||||||
|
|
||||||
function assertCommunityFederation(
|
function assertCommunityFederation(
|
||||||
communityOne?: CommunityView,
|
communityOne?: CommunityView,
|
||||||
|
@ -66,8 +64,8 @@ test("Create community", async () => {
|
||||||
|
|
||||||
// A dupe check
|
// A dupe check
|
||||||
let prevName = communityRes.community_view.community.name;
|
let prevName = communityRes.community_view.community.name;
|
||||||
await expect(createCommunity(alpha, prevName)).rejects.toBe(
|
await expect(createCommunity(alpha, prevName)).rejects.toStrictEqual(
|
||||||
"community_already_exists",
|
Error("community_already_exists"),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Cache the community on beta, make sure it has the other fields
|
// Cache the community on beta, make sure it has the other fields
|
||||||
|
@ -253,10 +251,7 @@ test("Admin actions in remote community are not federated to origin", async () =
|
||||||
|
|
||||||
test("moderator view", async () => {
|
test("moderator view", async () => {
|
||||||
// register a new user with their own community on alpha and post to it
|
// register a new user with their own community on alpha and post to it
|
||||||
let registerUserRes = await registerUser(alpha);
|
let otherUser = await registerUser(alpha, alphaUrl);
|
||||||
let otherUser = new LemmyHttp(alphaUrl, {
|
|
||||||
headers: { Authorization: `Bearer ${registerUserRes.jwt ?? ""}` },
|
|
||||||
});
|
|
||||||
|
|
||||||
let otherCommunity = (await createCommunity(otherUser)).community_view;
|
let otherCommunity = (await createCommunity(otherUser)).community_view;
|
||||||
expect(otherCommunity.community.name).toBeDefined();
|
expect(otherCommunity.community.name).toBeDefined();
|
||||||
|
@ -333,8 +328,8 @@ test("Get community for different casing on domain", async () => {
|
||||||
|
|
||||||
// A dupe check
|
// A dupe check
|
||||||
let prevName = communityRes.community_view.community.name;
|
let prevName = communityRes.community_view.community.name;
|
||||||
await expect(createCommunity(alpha, prevName)).rejects.toBe(
|
await expect(createCommunity(alpha, prevName)).rejects.toStrictEqual(
|
||||||
"community_already_exists",
|
Error("community_already_exists"),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Cache the community on beta, make sure it has the other fields
|
// Cache the community on beta, make sure it has the other fields
|
||||||
|
|
|
@ -8,14 +8,33 @@ import {
|
||||||
unfollowRemotes,
|
unfollowRemotes,
|
||||||
getSite,
|
getSite,
|
||||||
waitUntil,
|
waitUntil,
|
||||||
|
beta,
|
||||||
|
betaUrl,
|
||||||
|
registerUser,
|
||||||
} from "./shared";
|
} from "./shared";
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(setupLogins);
|
||||||
await setupLogins();
|
|
||||||
|
afterAll(() => {
|
||||||
|
unfollowRemotes(alpha);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
test("Follow local community", async () => {
|
||||||
await unfollowRemotes(alpha);
|
let user = await registerUser(beta, betaUrl);
|
||||||
|
|
||||||
|
let community = (await resolveBetaCommunity(user)).community!;
|
||||||
|
expect(community.counts.subscribers).toBe(1);
|
||||||
|
let follow = await followCommunity(user, true, community.community.id);
|
||||||
|
|
||||||
|
// Make sure the follow response went through
|
||||||
|
expect(follow.community_view.community.local).toBe(true);
|
||||||
|
expect(follow.community_view.subscribed).toBe("Subscribed");
|
||||||
|
expect(follow.community_view.counts.subscribers).toBe(2);
|
||||||
|
|
||||||
|
// Test an unfollow
|
||||||
|
let unfollow = await followCommunity(user, false, community.community.id);
|
||||||
|
expect(unfollow.community_view.subscribed).toBe("NotSubscribed");
|
||||||
|
expect(unfollow.community_view.counts.subscribers).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Follow federated community", async () => {
|
test("Follow federated community", async () => {
|
||||||
|
@ -23,7 +42,8 @@ test("Follow federated community", async () => {
|
||||||
if (!betaCommunity) {
|
if (!betaCommunity) {
|
||||||
throw "Missing beta community";
|
throw "Missing beta community";
|
||||||
}
|
}
|
||||||
await followCommunity(alpha, true, betaCommunity.community.id);
|
let follow = await followCommunity(alpha, true, betaCommunity.community.id);
|
||||||
|
expect(follow.community_view.subscribed).toBe("Pending");
|
||||||
betaCommunity = (
|
betaCommunity = (
|
||||||
await waitUntil(
|
await waitUntil(
|
||||||
() => resolveBetaCommunity(alpha),
|
() => resolveBetaCommunity(alpha),
|
||||||
|
@ -36,6 +56,10 @@ test("Follow federated community", async () => {
|
||||||
expect(betaCommunity?.community.name).toBe("main");
|
expect(betaCommunity?.community.name).toBe("main");
|
||||||
expect(betaCommunity?.subscribed).toBe("Subscribed");
|
expect(betaCommunity?.subscribed).toBe("Subscribed");
|
||||||
|
|
||||||
|
// check that unfollow was federated
|
||||||
|
let communityOnBeta1 = await resolveBetaCommunity(beta);
|
||||||
|
expect(communityOnBeta1.community?.counts.subscribers).toBe(2);
|
||||||
|
|
||||||
// Check it from local
|
// Check it from local
|
||||||
let site = await getSite(alpha);
|
let site = await getSite(alpha);
|
||||||
let remoteCommunityId = site.my_user?.follows.find(
|
let remoteCommunityId = site.my_user?.follows.find(
|
||||||
|
@ -55,4 +79,8 @@ test("Follow federated community", async () => {
|
||||||
// Make sure you are unsubbed locally
|
// Make sure you are unsubbed locally
|
||||||
let siteUnfollowCheck = await getSite(alpha);
|
let siteUnfollowCheck = await getSite(alpha);
|
||||||
expect(siteUnfollowCheck.my_user?.follows.length).toBe(1);
|
expect(siteUnfollowCheck.my_user?.follows.length).toBe(1);
|
||||||
|
|
||||||
|
// check that unfollow was federated
|
||||||
|
let communityOnBeta2 = await resolveBetaCommunity(beta);
|
||||||
|
expect(communityOnBeta2.community?.counts.subscribers).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
jest.setTimeout(120000);
|
||||||
|
|
||||||
|
import {
|
||||||
|
UploadImage,
|
||||||
|
DeleteImage,
|
||||||
|
PurgePerson,
|
||||||
|
PurgePost,
|
||||||
|
} from "lemmy-js-client";
|
||||||
|
import {
|
||||||
|
alpha,
|
||||||
|
alphaUrl,
|
||||||
|
beta,
|
||||||
|
betaUrl,
|
||||||
|
createPost,
|
||||||
|
getSite,
|
||||||
|
registerUser,
|
||||||
|
resolveBetaCommunity,
|
||||||
|
setupLogins,
|
||||||
|
unfollowRemotes,
|
||||||
|
} from "./shared";
|
||||||
|
import fs = require("fs");
|
||||||
|
const downloadFileSync = require("download-file-sync");
|
||||||
|
|
||||||
|
beforeAll(setupLogins);
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
unfollowRemotes(alpha);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Upload image and delete it", async () => {
|
||||||
|
// upload test image
|
||||||
|
const upload_image = fs.readFileSync("test.png");
|
||||||
|
const upload_form: UploadImage = {
|
||||||
|
image: upload_image,
|
||||||
|
};
|
||||||
|
const upload = await alpha.uploadImage(upload_form);
|
||||||
|
expect(upload.files![0].file).toBeDefined();
|
||||||
|
expect(upload.files![0].delete_token).toBeDefined();
|
||||||
|
expect(upload.url).toBeDefined();
|
||||||
|
expect(upload.delete_url).toBeDefined();
|
||||||
|
|
||||||
|
// ensure that image download is working. theres probably a better way to do this
|
||||||
|
const content = downloadFileSync(upload.url);
|
||||||
|
expect(content.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
// delete image
|
||||||
|
const delete_form: DeleteImage = {
|
||||||
|
token: upload.files![0].delete_token,
|
||||||
|
filename: upload.files![0].file,
|
||||||
|
};
|
||||||
|
const delete_ = await alpha.deleteImage(delete_form);
|
||||||
|
expect(delete_).toBe(true);
|
||||||
|
|
||||||
|
// ensure that image is deleted
|
||||||
|
const content2 = downloadFileSync(upload.url);
|
||||||
|
expect(content2).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Purge user, uploaded image removed", async () => {
|
||||||
|
let user = await registerUser(alpha, alphaUrl);
|
||||||
|
|
||||||
|
// upload test image
|
||||||
|
const upload_image = fs.readFileSync("test.png");
|
||||||
|
const upload_form: UploadImage = {
|
||||||
|
image: upload_image,
|
||||||
|
};
|
||||||
|
const upload = await user.uploadImage(upload_form);
|
||||||
|
expect(upload.files![0].file).toBeDefined();
|
||||||
|
expect(upload.files![0].delete_token).toBeDefined();
|
||||||
|
expect(upload.url).toBeDefined();
|
||||||
|
expect(upload.delete_url).toBeDefined();
|
||||||
|
|
||||||
|
// ensure that image download is working. theres probably a better way to do this
|
||||||
|
const content = downloadFileSync(upload.url);
|
||||||
|
expect(content.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
// purge user
|
||||||
|
let site = await getSite(user);
|
||||||
|
const purge_form: PurgePerson = {
|
||||||
|
person_id: site.my_user!.local_user_view.person.id,
|
||||||
|
};
|
||||||
|
const delete_ = await alpha.purgePerson(purge_form);
|
||||||
|
expect(delete_.success).toBe(true);
|
||||||
|
|
||||||
|
// ensure that image is deleted
|
||||||
|
const content2 = downloadFileSync(upload.url);
|
||||||
|
expect(content2).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Purge post, linked image removed", async () => {
|
||||||
|
let user = await registerUser(beta, betaUrl);
|
||||||
|
|
||||||
|
// upload test image
|
||||||
|
const upload_image = fs.readFileSync("test.png");
|
||||||
|
const upload_form: UploadImage = {
|
||||||
|
image: upload_image,
|
||||||
|
};
|
||||||
|
const upload = await user.uploadImage(upload_form);
|
||||||
|
expect(upload.files![0].file).toBeDefined();
|
||||||
|
expect(upload.files![0].delete_token).toBeDefined();
|
||||||
|
expect(upload.url).toBeDefined();
|
||||||
|
expect(upload.delete_url).toBeDefined();
|
||||||
|
|
||||||
|
// ensure that image download is working. theres probably a better way to do this
|
||||||
|
const content = downloadFileSync(upload.url);
|
||||||
|
expect(content.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
let community = await resolveBetaCommunity(user);
|
||||||
|
let post = await createPost(
|
||||||
|
user,
|
||||||
|
community.community!.community.id,
|
||||||
|
upload.url,
|
||||||
|
);
|
||||||
|
expect(post.post_view.post.url).toBe(upload.url);
|
||||||
|
|
||||||
|
// purge post
|
||||||
|
const purge_form: PurgePost = {
|
||||||
|
post_id: post.post_view.post.id,
|
||||||
|
};
|
||||||
|
const delete_ = await beta.purgePost(purge_form);
|
||||||
|
expect(delete_.success).toBe(true);
|
||||||
|
|
||||||
|
// ensure that image is deleted
|
||||||
|
const content2 = downloadFileSync(upload.url);
|
||||||
|
expect(content2).toBe("");
|
||||||
|
});
|
|
@ -50,8 +50,8 @@ beforeAll(async () => {
|
||||||
await unfollows();
|
await unfollows();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(() => {
|
||||||
await unfollows();
|
unfollows();
|
||||||
});
|
});
|
||||||
|
|
||||||
function assertPostFederation(postOne?: PostView, postTwo?: PostView) {
|
function assertPostFederation(postOne?: PostView, postTwo?: PostView) {
|
||||||
|
@ -96,18 +96,20 @@ test("Create a post", async () => {
|
||||||
assertPostFederation(betaPost, postRes.post_view);
|
assertPostFederation(betaPost, postRes.post_view);
|
||||||
|
|
||||||
// Delta only follows beta, so it should not see an alpha ap_id
|
// Delta only follows beta, so it should not see an alpha ap_id
|
||||||
await expect(resolvePost(delta, postRes.post_view.post)).rejects.toBe(
|
await expect(
|
||||||
"couldnt_find_object",
|
resolvePost(delta, postRes.post_view.post),
|
||||||
);
|
).rejects.toStrictEqual(Error("couldnt_find_object"));
|
||||||
|
|
||||||
// Epsilon has alpha blocked, it should not see the alpha post
|
// Epsilon has alpha blocked, it should not see the alpha post
|
||||||
await expect(resolvePost(epsilon, postRes.post_view.post)).rejects.toBe(
|
await expect(
|
||||||
"couldnt_find_object",
|
resolvePost(epsilon, postRes.post_view.post),
|
||||||
);
|
).rejects.toStrictEqual(Error("couldnt_find_object"));
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Create a post in a non-existent community", async () => {
|
test("Create a post in a non-existent community", async () => {
|
||||||
await expect(createPost(alpha, -2)).rejects.toBe("couldnt_find_community");
|
await expect(createPost(alpha, -2)).rejects.toStrictEqual(
|
||||||
|
Error("couldnt_find_community"),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Unlike a post", async () => {
|
test("Unlike a post", async () => {
|
||||||
|
@ -157,8 +159,8 @@ test("Update a post", async () => {
|
||||||
assertPostFederation(betaPost, updatedPost.post_view);
|
assertPostFederation(betaPost, updatedPost.post_view);
|
||||||
|
|
||||||
// Make sure lemmy beta cannot update the post
|
// Make sure lemmy beta cannot update the post
|
||||||
await expect(editPost(beta, betaPost.post)).rejects.toBe(
|
await expect(editPost(beta, betaPost.post)).rejects.toStrictEqual(
|
||||||
"no_post_edit_allowed",
|
Error("no_post_edit_allowed"),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -226,7 +228,9 @@ test("Lock a post", async () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Try to make a new comment there, on alpha
|
// Try to make a new comment there, on alpha
|
||||||
await expect(createComment(alpha, alphaPost1.post.id)).rejects.toBe("locked");
|
await expect(createComment(alpha, alphaPost1.post.id)).rejects.toStrictEqual(
|
||||||
|
Error("locked"),
|
||||||
|
);
|
||||||
|
|
||||||
// Unlock a post
|
// Unlock a post
|
||||||
let unlockedPost = await lockPost(beta, false, betaPost1.post);
|
let unlockedPost = await lockPost(beta, false, betaPost1.post);
|
||||||
|
@ -281,8 +285,8 @@ test("Delete a post", async () => {
|
||||||
assertPostFederation(betaPost2, undeletedPost.post_view);
|
assertPostFederation(betaPost2, undeletedPost.post_view);
|
||||||
|
|
||||||
// Make sure lemmy beta cannot delete the post
|
// Make sure lemmy beta cannot delete the post
|
||||||
await expect(deletePost(beta, true, betaPost2.post)).rejects.toBe(
|
await expect(deletePost(beta, true, betaPost2.post)).rejects.toStrictEqual(
|
||||||
"no_post_edit_allowed",
|
Error("no_post_edit_allowed"),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -386,11 +390,7 @@ test("Enforce site ban for federated user", async () => {
|
||||||
throw "Missing beta community";
|
throw "Missing beta community";
|
||||||
}
|
}
|
||||||
// create a test user
|
// create a test user
|
||||||
let alphaUserJwt = await registerUser(alpha);
|
let alpha_user = await registerUser(alpha, alphaUrl);
|
||||||
expect(alphaUserJwt).toBeDefined();
|
|
||||||
let alpha_user = new LemmyHttp(alphaUrl, {
|
|
||||||
headers: { Authorization: `Bearer ${alphaUserJwt.jwt ?? ""}` },
|
|
||||||
});
|
|
||||||
let alphaUserPerson = (await getSite(alpha_user)).my_user?.local_user_view
|
let alphaUserPerson = (await getSite(alpha_user)).my_user?.local_user_view
|
||||||
.person;
|
.person;
|
||||||
let alphaUserActorId = alphaUserPerson?.actor_id;
|
let alphaUserActorId = alphaUserPerson?.actor_id;
|
||||||
|
@ -483,12 +483,12 @@ test.skip("Enforce community ban for federated user", async () => {
|
||||||
|
|
||||||
// ensure that the post by alpha got removed
|
// ensure that the post by alpha got removed
|
||||||
await expect(getPost(alpha, searchBeta1.posts[0].post.id)).rejects.toBe(
|
await expect(getPost(alpha, searchBeta1.posts[0].post.id)).rejects.toBe(
|
||||||
"unknown",
|
Error("unknown"),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Alpha tries to make post on beta, but it fails because of ban
|
// Alpha tries to make post on beta, but it fails because of ban
|
||||||
await expect(createPost(alpha, betaCommunity.community.id)).rejects.toBe(
|
await expect(createPost(alpha, betaCommunity.community.id)).rejects.toBe(
|
||||||
"banned_from_community",
|
Error("banned_from_community"),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Unban alpha
|
// Unban alpha
|
||||||
|
|
|
@ -20,8 +20,8 @@ beforeAll(async () => {
|
||||||
recipient_id = 3;
|
recipient_id = 3;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(() => {
|
||||||
await unfollowRemotes(alpha);
|
unfollowRemotes(alpha);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Create a private message", async () => {
|
test("Create a private message", async () => {
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
import {
|
import {
|
||||||
|
BlockCommunity,
|
||||||
|
BlockCommunityResponse,
|
||||||
BlockInstance,
|
BlockInstance,
|
||||||
BlockInstanceResponse,
|
BlockInstanceResponse,
|
||||||
|
CommunityId,
|
||||||
GetReplies,
|
GetReplies,
|
||||||
GetRepliesResponse,
|
GetRepliesResponse,
|
||||||
GetUnreadCountResponse,
|
GetUnreadCountResponse,
|
||||||
InstanceId,
|
InstanceId,
|
||||||
LemmyHttp,
|
LemmyHttp,
|
||||||
PostView,
|
PostView,
|
||||||
|
SuccessResponse,
|
||||||
} from "lemmy-js-client";
|
} from "lemmy-js-client";
|
||||||
import { CreatePost } from "lemmy-js-client/dist/types/CreatePost";
|
import { CreatePost } from "lemmy-js-client/dist/types/CreatePost";
|
||||||
import { DeletePost } from "lemmy-js-client/dist/types/DeletePost";
|
import { DeletePost } from "lemmy-js-client/dist/types/DeletePost";
|
||||||
|
@ -55,7 +59,6 @@ import { Register } from "lemmy-js-client/dist/types/Register";
|
||||||
import { SaveUserSettings } from "lemmy-js-client/dist/types/SaveUserSettings";
|
import { SaveUserSettings } from "lemmy-js-client/dist/types/SaveUserSettings";
|
||||||
import { DeleteAccount } from "lemmy-js-client/dist/types/DeleteAccount";
|
import { DeleteAccount } from "lemmy-js-client/dist/types/DeleteAccount";
|
||||||
import { GetSiteResponse } from "lemmy-js-client/dist/types/GetSiteResponse";
|
import { GetSiteResponse } from "lemmy-js-client/dist/types/GetSiteResponse";
|
||||||
import { DeleteAccountResponse } from "lemmy-js-client/dist/types/DeleteAccountResponse";
|
|
||||||
import { PrivateMessagesResponse } from "lemmy-js-client/dist/types/PrivateMessagesResponse";
|
import { PrivateMessagesResponse } from "lemmy-js-client/dist/types/PrivateMessagesResponse";
|
||||||
import { GetPrivateMessages } from "lemmy-js-client/dist/types/GetPrivateMessages";
|
import { GetPrivateMessages } from "lemmy-js-client/dist/types/GetPrivateMessages";
|
||||||
import { PostReportResponse } from "lemmy-js-client/dist/types/PostReportResponse";
|
import { PostReportResponse } from "lemmy-js-client/dist/types/PostReportResponse";
|
||||||
|
@ -193,12 +196,11 @@ export async function setupLogins() {
|
||||||
export async function createPost(
|
export async function createPost(
|
||||||
api: LemmyHttp,
|
api: LemmyHttp,
|
||||||
community_id: number,
|
community_id: number,
|
||||||
|
// use example.com for consistent title and embed description
|
||||||
|
url: string = "https://example.com/",
|
||||||
): Promise<PostResponse> {
|
): Promise<PostResponse> {
|
||||||
let name = randomString(5);
|
let name = randomString(5);
|
||||||
let body = randomString(10);
|
let body = randomString(10);
|
||||||
// switch from google.com to example.com for consistent title (embed_title and embed_description)
|
|
||||||
// google switches description when a google doodle appears
|
|
||||||
let url = "https://example.com/";
|
|
||||||
let form: CreatePost = {
|
let form: CreatePost = {
|
||||||
name,
|
name,
|
||||||
url,
|
url,
|
||||||
|
@ -287,6 +289,7 @@ export async function searchPostLocal(
|
||||||
q: post.name,
|
q: post.name,
|
||||||
type_: "Posts",
|
type_: "Posts",
|
||||||
sort: "TopAll",
|
sort: "TopAll",
|
||||||
|
listing_type: "All",
|
||||||
};
|
};
|
||||||
return api.search(form);
|
return api.search(form);
|
||||||
}
|
}
|
||||||
|
@ -422,8 +425,9 @@ export async function followCommunity(
|
||||||
};
|
};
|
||||||
const res = await api.followCommunity(form);
|
const res = await api.followCommunity(form);
|
||||||
await waitUntil(
|
await waitUntil(
|
||||||
() => resolveCommunity(api, res.community_view.community.actor_id),
|
() => getCommunity(api, res.community_view.community.id),
|
||||||
g => g.community?.subscribed === (follow ? "Subscribed" : "NotSubscribed"),
|
g =>
|
||||||
|
g.community_view.subscribed === (follow ? "Subscribed" : "NotSubscribed"),
|
||||||
);
|
);
|
||||||
// wait FOLLOW_ADDITIONS_RECHECK_DELAY (there's no API to wait for this currently)
|
// wait FOLLOW_ADDITIONS_RECHECK_DELAY (there's no API to wait for this currently)
|
||||||
await delay(2000);
|
await delay(2000);
|
||||||
|
@ -610,15 +614,22 @@ export async function deletePrivateMessage(
|
||||||
|
|
||||||
export async function registerUser(
|
export async function registerUser(
|
||||||
api: LemmyHttp,
|
api: LemmyHttp,
|
||||||
|
url: string,
|
||||||
username: string = randomString(5),
|
username: string = randomString(5),
|
||||||
): Promise<LoginResponse> {
|
): Promise<LemmyHttp> {
|
||||||
let form: Register = {
|
let form: Register = {
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
password_verify: password,
|
password_verify: password,
|
||||||
show_nsfw: true,
|
show_nsfw: true,
|
||||||
};
|
};
|
||||||
return api.register(form);
|
let login_response = await api.register(form);
|
||||||
|
|
||||||
|
expect(login_response.jwt).toBeDefined();
|
||||||
|
let lemmy_http = new LemmyHttp(url, {
|
||||||
|
headers: { Authorization: `Bearer ${login_response.jwt ?? ""}` },
|
||||||
|
});
|
||||||
|
return lemmy_http;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loginUser(
|
export async function loginUser(
|
||||||
|
@ -634,7 +645,7 @@ export async function loginUser(
|
||||||
|
|
||||||
export async function saveUserSettingsBio(
|
export async function saveUserSettingsBio(
|
||||||
api: LemmyHttp,
|
api: LemmyHttp,
|
||||||
): Promise<LoginResponse> {
|
): Promise<SuccessResponse> {
|
||||||
let form: SaveUserSettings = {
|
let form: SaveUserSettings = {
|
||||||
show_nsfw: true,
|
show_nsfw: true,
|
||||||
blur_nsfw: false,
|
blur_nsfw: false,
|
||||||
|
@ -652,7 +663,7 @@ export async function saveUserSettingsBio(
|
||||||
|
|
||||||
export async function saveUserSettingsFederated(
|
export async function saveUserSettingsFederated(
|
||||||
api: LemmyHttp,
|
api: LemmyHttp,
|
||||||
): Promise<LoginResponse> {
|
): Promise<SuccessResponse> {
|
||||||
let avatar = "https://image.flaticon.com/icons/png/512/35/35896.png";
|
let avatar = "https://image.flaticon.com/icons/png/512/35/35896.png";
|
||||||
let banner = "https://image.flaticon.com/icons/png/512/36/35896.png";
|
let banner = "https://image.flaticon.com/icons/png/512/36/35896.png";
|
||||||
let bio = "a changed bio";
|
let bio = "a changed bio";
|
||||||
|
@ -676,7 +687,7 @@ export async function saveUserSettingsFederated(
|
||||||
export async function saveUserSettings(
|
export async function saveUserSettings(
|
||||||
api: LemmyHttp,
|
api: LemmyHttp,
|
||||||
form: SaveUserSettings,
|
form: SaveUserSettings,
|
||||||
): Promise<LoginResponse> {
|
): Promise<SuccessResponse> {
|
||||||
return api.saveUserSettings(form);
|
return api.saveUserSettings(form);
|
||||||
}
|
}
|
||||||
export async function getPersonDetails(
|
export async function getPersonDetails(
|
||||||
|
@ -689,9 +700,7 @@ export async function getPersonDetails(
|
||||||
return api.getPersonDetails(form);
|
return api.getPersonDetails(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteUser(
|
export async function deleteUser(api: LemmyHttp): Promise<SuccessResponse> {
|
||||||
api: LemmyHttp,
|
|
||||||
): Promise<DeleteAccountResponse> {
|
|
||||||
let form: DeleteAccount = {
|
let form: DeleteAccount = {
|
||||||
delete_content: true,
|
delete_content: true,
|
||||||
password,
|
password,
|
||||||
|
@ -796,6 +805,18 @@ export function blockInstance(
|
||||||
return api.blockInstance(form);
|
return api.blockInstance(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function blockCommunity(
|
||||||
|
api: LemmyHttp,
|
||||||
|
community_id: CommunityId,
|
||||||
|
block: boolean,
|
||||||
|
): Promise<BlockCommunityResponse> {
|
||||||
|
let form: BlockCommunity = {
|
||||||
|
community_id,
|
||||||
|
block,
|
||||||
|
};
|
||||||
|
return api.blockCommunity(form);
|
||||||
|
}
|
||||||
|
|
||||||
export function delay(millis = 500) {
|
export function delay(millis = 500) {
|
||||||
return new Promise(resolve => setTimeout(resolve, millis));
|
return new Promise(resolve => setTimeout(resolve, millis));
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,19 +12,17 @@ import {
|
||||||
createComment,
|
createComment,
|
||||||
resolveBetaCommunity,
|
resolveBetaCommunity,
|
||||||
deleteUser,
|
deleteUser,
|
||||||
resolvePost,
|
|
||||||
resolveComment,
|
|
||||||
saveUserSettingsFederated,
|
saveUserSettingsFederated,
|
||||||
setupLogins,
|
setupLogins,
|
||||||
alphaUrl,
|
alphaUrl,
|
||||||
saveUserSettings,
|
saveUserSettings,
|
||||||
|
getPost,
|
||||||
|
getComments,
|
||||||
} from "./shared";
|
} from "./shared";
|
||||||
import { LemmyHttp, SaveUserSettings } from "lemmy-js-client";
|
import { LemmyHttp, SaveUserSettings } from "lemmy-js-client";
|
||||||
import { GetPosts } from "lemmy-js-client/dist/types/GetPosts";
|
import { GetPosts } from "lemmy-js-client/dist/types/GetPosts";
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(setupLogins);
|
||||||
await setupLogins();
|
|
||||||
});
|
|
||||||
|
|
||||||
let apShortname: string;
|
let apShortname: string;
|
||||||
|
|
||||||
|
@ -39,11 +37,7 @@ function assertUserFederation(userOne?: PersonView, userTwo?: PersonView) {
|
||||||
}
|
}
|
||||||
|
|
||||||
test("Create user", async () => {
|
test("Create user", async () => {
|
||||||
let userRes = await registerUser(alpha);
|
let user = await registerUser(alpha, alphaUrl);
|
||||||
expect(userRes.jwt).toBeDefined();
|
|
||||||
let user = new LemmyHttp(alphaUrl, {
|
|
||||||
headers: { Authorization: `Bearer ${userRes.jwt ?? ""}` },
|
|
||||||
});
|
|
||||||
|
|
||||||
let site = await getSite(user);
|
let site = await getSite(user);
|
||||||
expect(site.my_user).toBeDefined();
|
expect(site.my_user).toBeDefined();
|
||||||
|
@ -70,11 +64,7 @@ test("Set some user settings, check that they are federated", async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Delete user", async () => {
|
test("Delete user", async () => {
|
||||||
let userRes = await registerUser(alpha);
|
let user = await registerUser(alpha, alphaUrl);
|
||||||
expect(userRes.jwt).toBeDefined();
|
|
||||||
let user = new LemmyHttp(alphaUrl, {
|
|
||||||
headers: { Authorization: `Bearer ${userRes.jwt ?? ""}` },
|
|
||||||
});
|
|
||||||
|
|
||||||
// make a local post and comment
|
// make a local post and comment
|
||||||
let alphaCommunity = (await resolveCommunity(user, "!main@lemmy-alpha:8541"))
|
let alphaCommunity = (await resolveCommunity(user, "!main@lemmy-alpha:8541"))
|
||||||
|
@ -103,18 +93,22 @@ test("Delete user", async () => {
|
||||||
|
|
||||||
await deleteUser(user);
|
await deleteUser(user);
|
||||||
|
|
||||||
await expect(resolvePost(alpha, localPost)).rejects.toBe(
|
// check that posts and comments are marked as deleted on other instances.
|
||||||
"couldnt_find_object",
|
// use get methods to avoid refetching from origin instance
|
||||||
|
expect((await getPost(alpha, localPost.id)).post_view.post.deleted).toBe(
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
await expect(resolveComment(alpha, localComment)).rejects.toBe(
|
expect((await getPost(alpha, remotePost.id)).post_view.post.deleted).toBe(
|
||||||
"couldnt_find_object",
|
true,
|
||||||
);
|
|
||||||
await expect(resolvePost(alpha, remotePost)).rejects.toBe(
|
|
||||||
"couldnt_find_object",
|
|
||||||
);
|
|
||||||
await expect(resolveComment(alpha, remoteComment)).rejects.toBe(
|
|
||||||
"couldnt_find_object",
|
|
||||||
);
|
);
|
||||||
|
expect(
|
||||||
|
(await getComments(alpha, localComment.post_id)).comments[0].comment
|
||||||
|
.deleted,
|
||||||
|
).toBe(true);
|
||||||
|
expect(
|
||||||
|
(await getComments(alpha, remoteComment.post_id)).comments[0].comment
|
||||||
|
.deleted,
|
||||||
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Requests with invalid auth should be treated as unauthenticated", async () => {
|
test("Requests with invalid auth should be treated as unauthenticated", async () => {
|
||||||
|
@ -131,11 +125,7 @@ test("Requests with invalid auth should be treated as unauthenticated", async ()
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Create user with Arabic name", async () => {
|
test("Create user with Arabic name", async () => {
|
||||||
let userRes = await registerUser(alpha, "تجريب");
|
let user = await registerUser(alpha, alphaUrl, "تجريب");
|
||||||
expect(userRes.jwt).toBeDefined();
|
|
||||||
let user = new LemmyHttp(alphaUrl, {
|
|
||||||
headers: { Authorization: `Bearer ${userRes.jwt ?? ""}` },
|
|
||||||
});
|
|
||||||
|
|
||||||
let site = await getSite(user);
|
let site = await getSite(user);
|
||||||
expect(site.my_user).toBeDefined();
|
expect(site.my_user).toBeDefined();
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
|
@ -314,10 +314,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.1.tgz#449dfa81a57a1d755b09aa58d826c1262e4283b4"
|
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.1.tgz#449dfa81a57a1d755b09aa58d826c1262e4283b4"
|
||||||
integrity sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==
|
integrity sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==
|
||||||
|
|
||||||
"@eslint/eslintrc@^2.1.2":
|
"@eslint/eslintrc@^2.1.3":
|
||||||
version "2.1.2"
|
version "2.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396"
|
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.3.tgz#797470a75fe0fbd5a53350ee715e85e87baff22d"
|
||||||
integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==
|
integrity sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv "^6.12.4"
|
ajv "^6.12.4"
|
||||||
debug "^4.3.2"
|
debug "^4.3.2"
|
||||||
|
@ -329,10 +329,10 @@
|
||||||
minimatch "^3.1.2"
|
minimatch "^3.1.2"
|
||||||
strip-json-comments "^3.1.1"
|
strip-json-comments "^3.1.1"
|
||||||
|
|
||||||
"@eslint/js@8.52.0":
|
"@eslint/js@8.53.0":
|
||||||
version "8.52.0"
|
version "8.53.0"
|
||||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.52.0.tgz#78fe5f117840f69dc4a353adf9b9cd926353378c"
|
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.53.0.tgz#bea56f2ed2b5baea164348ff4d5a879f6f81f20d"
|
||||||
integrity sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==
|
integrity sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==
|
||||||
|
|
||||||
"@humanwhocodes/config-array@^0.11.13":
|
"@humanwhocodes/config-array@^0.11.13":
|
||||||
version "0.11.13"
|
version "0.11.13"
|
||||||
|
@ -704,10 +704,10 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/istanbul-lib-report" "*"
|
"@types/istanbul-lib-report" "*"
|
||||||
|
|
||||||
"@types/jest@^29.5.6":
|
"@types/jest@^29.5.8":
|
||||||
version "29.5.6"
|
version "29.5.8"
|
||||||
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.6.tgz#f4cf7ef1b5b0bfc1aa744e41b24d9cc52533130b"
|
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.8.tgz#ed5c256fe2bc7c38b1915ee5ef1ff24a3427e120"
|
||||||
integrity sha512-/t9NnzkOpXb4Nfvg17ieHE6EeSjDS2SGSpNYfoLbUAeL/EOueU/RSdOWFpfQTXBEM7BguYW1XQ0EbM+6RlIh6w==
|
integrity sha512-fXEFTxMV2Co8ZF5aYFJv+YeA08RTYJfhtN5c9JSv/mFEMe+xxjufCb+PHL+bJcMs/ebPUsBu+UNTEz+ydXrR6g==
|
||||||
dependencies:
|
dependencies:
|
||||||
expect "^29.0.0"
|
expect "^29.0.0"
|
||||||
pretty-format "^29.0.0"
|
pretty-format "^29.0.0"
|
||||||
|
@ -722,12 +722,12 @@
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.0.tgz#10ddf0119cf20028781c06d7115562934e53f745"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.0.tgz#10ddf0119cf20028781c06d7115562934e53f745"
|
||||||
integrity sha512-LzcWltT83s1bthcvjBmiBvGJiiUe84NWRHkw+ZV6Fr41z2FbIzvc815dk2nQ3RAKMuN2fkenM/z3Xv2QzEpYxQ==
|
integrity sha512-LzcWltT83s1bthcvjBmiBvGJiiUe84NWRHkw+ZV6Fr41z2FbIzvc815dk2nQ3RAKMuN2fkenM/z3Xv2QzEpYxQ==
|
||||||
|
|
||||||
"@types/node@^20.8.7":
|
"@types/node@^20.9.0":
|
||||||
version "20.8.7"
|
version "20.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.7.tgz#ad23827850843de973096edfc5abc9e922492a25"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.0.tgz#bfcdc230583aeb891cf51e73cfdaacdd8deae298"
|
||||||
integrity sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==
|
integrity sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types "~5.25.1"
|
undici-types "~5.26.4"
|
||||||
|
|
||||||
"@types/semver@^7.5.0":
|
"@types/semver@^7.5.0":
|
||||||
version "7.5.3"
|
version "7.5.3"
|
||||||
|
@ -751,16 +751,16 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/yargs-parser" "*"
|
"@types/yargs-parser" "*"
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@^6.8.0":
|
"@typescript-eslint/eslint-plugin@^6.10.0":
|
||||||
version "6.8.0"
|
version "6.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz#06abe4265e7c82f20ade2dcc0e3403c32d4f148b"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.10.0.tgz#cfe2bd34e26d2289212946b96ab19dcad64b661a"
|
||||||
integrity sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw==
|
integrity sha512-uoLj4g2OTL8rfUQVx2AFO1hp/zja1wABJq77P6IclQs6I/m9GLrm7jCdgzZkvWdDCQf1uEvoa8s8CupsgWQgVg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/regexpp" "^4.5.1"
|
"@eslint-community/regexpp" "^4.5.1"
|
||||||
"@typescript-eslint/scope-manager" "6.8.0"
|
"@typescript-eslint/scope-manager" "6.10.0"
|
||||||
"@typescript-eslint/type-utils" "6.8.0"
|
"@typescript-eslint/type-utils" "6.10.0"
|
||||||
"@typescript-eslint/utils" "6.8.0"
|
"@typescript-eslint/utils" "6.10.0"
|
||||||
"@typescript-eslint/visitor-keys" "6.8.0"
|
"@typescript-eslint/visitor-keys" "6.10.0"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
graphemer "^1.4.0"
|
graphemer "^1.4.0"
|
||||||
ignore "^5.2.4"
|
ignore "^5.2.4"
|
||||||
|
@ -768,72 +768,72 @@
|
||||||
semver "^7.5.4"
|
semver "^7.5.4"
|
||||||
ts-api-utils "^1.0.1"
|
ts-api-utils "^1.0.1"
|
||||||
|
|
||||||
"@typescript-eslint/parser@^6.8.0":
|
"@typescript-eslint/parser@^6.10.0":
|
||||||
version "6.8.0"
|
version "6.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.8.0.tgz#bb2a969d583db242f1ee64467542f8b05c2e28cb"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.10.0.tgz#578af79ae7273193b0b6b61a742a2bc8e02f875a"
|
||||||
integrity sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg==
|
integrity sha512-+sZwIj+s+io9ozSxIWbNB5873OSdfeBEH/FR0re14WLI6BaKuSOnnwCJ2foUiu8uXf4dRp1UqHP0vrZ1zXGrog==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/scope-manager" "6.8.0"
|
"@typescript-eslint/scope-manager" "6.10.0"
|
||||||
"@typescript-eslint/types" "6.8.0"
|
"@typescript-eslint/types" "6.10.0"
|
||||||
"@typescript-eslint/typescript-estree" "6.8.0"
|
"@typescript-eslint/typescript-estree" "6.10.0"
|
||||||
"@typescript-eslint/visitor-keys" "6.8.0"
|
"@typescript-eslint/visitor-keys" "6.10.0"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager@6.8.0":
|
"@typescript-eslint/scope-manager@6.10.0":
|
||||||
version "6.8.0"
|
version "6.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.8.0.tgz#5cac7977385cde068ab30686889dd59879811efd"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.10.0.tgz#b0276118b13d16f72809e3cecc86a72c93708540"
|
||||||
integrity sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g==
|
integrity sha512-TN/plV7dzqqC2iPNf1KrxozDgZs53Gfgg5ZHyw8erd6jd5Ta/JIEcdCheXFt9b1NYb93a1wmIIVW/2gLkombDg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "6.8.0"
|
"@typescript-eslint/types" "6.10.0"
|
||||||
"@typescript-eslint/visitor-keys" "6.8.0"
|
"@typescript-eslint/visitor-keys" "6.10.0"
|
||||||
|
|
||||||
"@typescript-eslint/type-utils@6.8.0":
|
"@typescript-eslint/type-utils@6.10.0":
|
||||||
version "6.8.0"
|
version "6.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.8.0.tgz#50365e44918ca0fd159844b5d6ea96789731e11f"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz#1007faede067c78bdbcef2e8abb31437e163e2e1"
|
||||||
integrity sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g==
|
integrity sha512-wYpPs3hgTFblMYwbYWPT3eZtaDOjbLyIYuqpwuLBBqhLiuvJ+9sEp2gNRJEtR5N/c9G1uTtQQL5AhV0fEPJYcg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/typescript-estree" "6.8.0"
|
"@typescript-eslint/typescript-estree" "6.10.0"
|
||||||
"@typescript-eslint/utils" "6.8.0"
|
"@typescript-eslint/utils" "6.10.0"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
ts-api-utils "^1.0.1"
|
ts-api-utils "^1.0.1"
|
||||||
|
|
||||||
"@typescript-eslint/types@6.8.0":
|
"@typescript-eslint/types@6.10.0":
|
||||||
version "6.8.0"
|
version "6.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.8.0.tgz#1ab5d4fe1d613e3f65f6684026ade6b94f7e3ded"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.10.0.tgz#f4f0a84aeb2ac546f21a66c6e0da92420e921367"
|
||||||
integrity sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ==
|
integrity sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg==
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@6.8.0":
|
"@typescript-eslint/typescript-estree@6.10.0":
|
||||||
version "6.8.0"
|
version "6.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.8.0.tgz#9565f15e0cd12f55cf5aa0dfb130a6cb0d436ba1"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.10.0.tgz#667381eed6f723a1a8ad7590a31f312e31e07697"
|
||||||
integrity sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg==
|
integrity sha512-ek0Eyuy6P15LJVeghbWhSrBCj/vJpPXXR+EpaRZqou7achUWL8IdYnMSC5WHAeTWswYQuP2hAZgij/bC9fanBg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "6.8.0"
|
"@typescript-eslint/types" "6.10.0"
|
||||||
"@typescript-eslint/visitor-keys" "6.8.0"
|
"@typescript-eslint/visitor-keys" "6.10.0"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
globby "^11.1.0"
|
globby "^11.1.0"
|
||||||
is-glob "^4.0.3"
|
is-glob "^4.0.3"
|
||||||
semver "^7.5.4"
|
semver "^7.5.4"
|
||||||
ts-api-utils "^1.0.1"
|
ts-api-utils "^1.0.1"
|
||||||
|
|
||||||
"@typescript-eslint/utils@6.8.0":
|
"@typescript-eslint/utils@6.10.0":
|
||||||
version "6.8.0"
|
version "6.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.8.0.tgz#d42939c2074c6b59844d0982ce26a51d136c4029"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.10.0.tgz#4d76062d94413c30e402c9b0df8c14aef8d77336"
|
||||||
integrity sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q==
|
integrity sha512-v+pJ1/RcVyRc0o4wAGux9x42RHmAjIGzPRo538Z8M1tVx6HOnoQBCX/NoadHQlZeC+QO2yr4nNSFWOoraZCAyg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/eslint-utils" "^4.4.0"
|
"@eslint-community/eslint-utils" "^4.4.0"
|
||||||
"@types/json-schema" "^7.0.12"
|
"@types/json-schema" "^7.0.12"
|
||||||
"@types/semver" "^7.5.0"
|
"@types/semver" "^7.5.0"
|
||||||
"@typescript-eslint/scope-manager" "6.8.0"
|
"@typescript-eslint/scope-manager" "6.10.0"
|
||||||
"@typescript-eslint/types" "6.8.0"
|
"@typescript-eslint/types" "6.10.0"
|
||||||
"@typescript-eslint/typescript-estree" "6.8.0"
|
"@typescript-eslint/typescript-estree" "6.10.0"
|
||||||
semver "^7.5.4"
|
semver "^7.5.4"
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@6.8.0":
|
"@typescript-eslint/visitor-keys@6.10.0":
|
||||||
version "6.8.0"
|
version "6.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.8.0.tgz#cffebed56ae99c45eba901c378a6447b06be58b8"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.10.0.tgz#b9eaf855a1ac7e95633ae1073af43d451e8f84e3"
|
||||||
integrity sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg==
|
integrity sha512-xMGluxQIEtOM7bqFCo+rCMh5fqI+ZxV5RUUOa29iVPz1OgCZrtc7rFnz5cLUazlkPKYqX+75iuDq7m0HQ48nCg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "6.8.0"
|
"@typescript-eslint/types" "6.10.0"
|
||||||
eslint-visitor-keys "^3.4.1"
|
eslint-visitor-keys "^3.4.1"
|
||||||
|
|
||||||
"@ungap/structured-clone@^1.2.0":
|
"@ungap/structured-clone@^1.2.0":
|
||||||
|
@ -1270,6 +1270,11 @@ doctrine@^3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
|
|
||||||
|
download-file-sync@^1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/download-file-sync/-/download-file-sync-1.0.4.tgz#d3e3c543f836f41039455b9034c72e355b036019"
|
||||||
|
integrity sha512-vH92qNH508jZZA12HQNq/aiMDfagr4JvjFiI17Bi8oYjsxwv5ZVIi7iHkYmUXxOQUr90tcVX+8EPePjAqG1Y0w==
|
||||||
|
|
||||||
electron-to-chromium@^1.4.535:
|
electron-to-chromium@^1.4.535:
|
||||||
version "1.4.537"
|
version "1.4.537"
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.537.tgz#aac4101db53066be1e49baedd000a26bc754adc9"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.537.tgz#aac4101db53066be1e49baedd000a26bc754adc9"
|
||||||
|
@ -1333,15 +1338,15 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4
|
||||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
|
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
|
||||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||||
|
|
||||||
eslint@^8.52.0:
|
eslint@^8.53.0:
|
||||||
version "8.52.0"
|
version "8.53.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.52.0.tgz#d0cd4a1fac06427a61ef9242b9353f36ea7062fc"
|
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.53.0.tgz#14f2c8244298fcae1f46945459577413ba2697ce"
|
||||||
integrity sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==
|
integrity sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/eslint-utils" "^4.2.0"
|
"@eslint-community/eslint-utils" "^4.2.0"
|
||||||
"@eslint-community/regexpp" "^4.6.1"
|
"@eslint-community/regexpp" "^4.6.1"
|
||||||
"@eslint/eslintrc" "^2.1.2"
|
"@eslint/eslintrc" "^2.1.3"
|
||||||
"@eslint/js" "8.52.0"
|
"@eslint/js" "8.53.0"
|
||||||
"@humanwhocodes/config-array" "^0.11.13"
|
"@humanwhocodes/config-array" "^0.11.13"
|
||||||
"@humanwhocodes/module-importer" "^1.0.1"
|
"@humanwhocodes/module-importer" "^1.0.1"
|
||||||
"@nodelib/fs.walk" "^1.2.8"
|
"@nodelib/fs.walk" "^1.2.8"
|
||||||
|
@ -2281,10 +2286,10 @@ kleur@^3.0.3:
|
||||||
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
|
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
|
||||||
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
|
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
|
||||||
|
|
||||||
lemmy-js-client@0.19.0-rc.12:
|
lemmy-js-client@0.19.0-alpha.18:
|
||||||
version "0.19.0-rc.12"
|
version "0.19.0-alpha.18"
|
||||||
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.19.0-rc.12.tgz#e3bd4e21b1966d583ab790ef70ece8394b012b48"
|
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.19.0-alpha.18.tgz#f94841681cabdf9d5c4ce7048eacb57557f68724"
|
||||||
integrity sha512-1iu2fW9vlb3TrI+QR/ODP3+5pWZB0rUqL1wH09IzomDXohCqoQvfmXpwArmgF4Eq8GZgjkcfeMDC2gMrfw/i7Q==
|
integrity sha512-cKJfKKnjK+ijk0Yd6ydtne3Y4FILp2RbQg05pCru9n6PCyPAa85eQL4QxPB1PPed20ckSZRcHLcnr/bYFDgpaw==
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-fetch "^3.1.5"
|
cross-fetch "^3.1.5"
|
||||||
form-data "^4.0.0"
|
form-data "^4.0.0"
|
||||||
|
@ -2952,10 +2957,10 @@ typescript@^5.0.4:
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78"
|
||||||
integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
|
integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
|
||||||
|
|
||||||
undici-types@~5.25.1:
|
undici-types@~5.26.4:
|
||||||
version "5.25.3"
|
version "5.26.5"
|
||||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.25.3.tgz#e044115914c85f0bcbb229f346ab739f064998c3"
|
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
|
||||||
integrity sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==
|
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
||||||
|
|
||||||
untildify@^4.0.0:
|
untildify@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
url: "http://localhost:8080/"
|
url: "http://localhost:8080/"
|
||||||
# Set a custom pictrs API key. ( Required for deleting images )
|
# Set a custom pictrs API key. ( Required for deleting images )
|
||||||
api_key: "string"
|
api_key: "string"
|
||||||
|
<<<<<<< HEAD
|
||||||
# If enabled, all images from remote domains are rewritten to pass through `/api/v3/image_proxy`.
|
# If enabled, all images from remote domains are rewritten to pass through `/api/v3/image_proxy`.
|
||||||
# This improves privacy as users don't expose their IP to untrusted servers, and decreases load
|
# This improves privacy as users don't expose their IP to untrusted servers, and decreases load
|
||||||
# on other servers. However it causes more load for the local server.
|
# on other servers. However it causes more load for the local server.
|
||||||
|
@ -59,6 +60,19 @@
|
||||||
# hotlinking is allowed. If that is the case for your instance, make sure that `image_proxy` and
|
# hotlinking is allowed. If that is the case for your instance, make sure that `image_proxy` and
|
||||||
# `cache_external_link_previews` are both disabled.
|
# `cache_external_link_previews` are both disabled.
|
||||||
cache_external_link_previews: true
|
cache_external_link_previews: true
|
||||||
|
=======
|
||||||
|
# By default the thumbnails for external links are stored in pict-rs. This ensures that they
|
||||||
|
# can be reliably retrieved and can be resized using pict-rs APIs. However it also increases
|
||||||
|
# storage usage. In case this is disabled, the Opengraph image is directly returned as
|
||||||
|
# thumbnail.
|
||||||
|
#
|
||||||
|
# In some countries it is forbidden to copy preview images from newspaper articles and only
|
||||||
|
# hotlinking is allowed. If that is the case for your instance, make sure that this setting is
|
||||||
|
# disabled.
|
||||||
|
cache_external_link_previews: true
|
||||||
|
# Timeout for uploading images to pictrs (in seconds)
|
||||||
|
upload_timeout: 30
|
||||||
|
>>>>>>> main
|
||||||
}
|
}
|
||||||
# Email sending configuration. All options except login/password are mandatory
|
# Email sending configuration. All options except login/password are mandatory
|
||||||
email: {
|
email: {
|
||||||
|
|
|
@ -13,6 +13,9 @@ name = "lemmy_api"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_utils = { workspace = true }
|
lemmy_utils = { workspace = true }
|
||||||
lemmy_db_schema = { workspace = true, features = ["full"] }
|
lemmy_db_schema = { workspace = true, features = ["full"] }
|
||||||
|
|
|
@ -2,7 +2,7 @@ use actix_web::web::{Data, Json, Query};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
comment::{ListCommentReports, ListCommentReportsResponse},
|
comment::{ListCommentReports, ListCommentReportsResponse},
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
utils::check_community_mod_action_opt,
|
utils::check_community_mod_of_any_or_admin_action,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::{comment_report_view::CommentReportQuery, structs::LocalUserView};
|
use lemmy_db_views::{comment_report_view::CommentReportQuery, structs::LocalUserView};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::LemmyError;
|
||||||
|
@ -18,7 +18,7 @@ pub async fn list_comment_reports(
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
let unresolved_only = data.unresolved_only.unwrap_or_default();
|
let unresolved_only = data.unresolved_only.unwrap_or_default();
|
||||||
|
|
||||||
check_community_mod_action_opt(&local_user_view, community_id, &mut context.pool()).await?;
|
check_community_mod_of_any_or_admin_action(&local_user_view, &mut context.pool()).await?;
|
||||||
|
|
||||||
let page = data.page;
|
let page = data.page;
|
||||||
let limit = data.limit;
|
let limit = data.limit;
|
||||||
|
|
|
@ -45,18 +45,19 @@ pub async fn follow_community(
|
||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?;
|
.with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if !data.follow {
|
|
||||||
CommunityFollower::unfollow(&mut context.pool(), &community_follower_form)
|
CommunityFollower::unfollow(&mut context.pool(), &community_follower_form)
|
||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?;
|
.with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !community.local {
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::FollowCommunity(community, local_user_view.person.clone(), data.follow),
|
SendActivityData::FollowCommunity(community, local_user_view.person.clone(), data.follow),
|
||||||
&context,
|
&context,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
|
|
|
@ -46,11 +46,11 @@ pub async fn ban_from_site(
|
||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateUser)?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateUser)?;
|
||||||
|
|
||||||
let local_user_id = LocalUserView::read_person(&mut context.pool(), data.person_id)
|
// if its a local user, invalidate logins
|
||||||
.await?
|
let local_user = LocalUserView::read_person(&mut context.pool(), data.person_id).await;
|
||||||
.local_user
|
if let Ok(local_user) = local_user {
|
||||||
.id;
|
LoginToken::invalidate_all(&mut context.pool(), local_user.local_user.id).await?;
|
||||||
LoginToken::invalidate_all(&mut context.pool(), local_user_id).await?;
|
}
|
||||||
|
|
||||||
// Remove their data if that's desired
|
// Remove their data if that's desired
|
||||||
let remove_data = data.remove_data.unwrap_or(false);
|
let remove_data = data.remove_data.unwrap_or(false);
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
use crate::check_totp_2fa_valid;
|
use crate::check_totp_2fa_valid;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
http::StatusCode,
|
|
||||||
web::{Data, Json},
|
web::{Data, Json},
|
||||||
HttpRequest,
|
HttpRequest,
|
||||||
HttpResponse,
|
|
||||||
};
|
};
|
||||||
use bcrypt::verify;
|
use bcrypt::verify;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
claims::Claims,
|
claims::Claims,
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
person::{Login, LoginResponse},
|
person::{Login, LoginResponse},
|
||||||
utils::{check_user_valid, create_login_cookie},
|
utils::check_user_valid,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{local_site::LocalSite, registration_application::RegistrationApplication},
|
source::{local_site::LocalSite, registration_application::RegistrationApplication},
|
||||||
|
@ -25,7 +23,7 @@ pub async fn login(
|
||||||
data: Json<Login>,
|
data: Json<Login>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<Json<LoginResponse>, LemmyError> {
|
||||||
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
||||||
|
|
||||||
// Fetch that username / email
|
// Fetch that username / email
|
||||||
|
@ -65,15 +63,11 @@ pub async fn login(
|
||||||
|
|
||||||
let jwt = Claims::generate(local_user_view.local_user.id, req, &context).await?;
|
let jwt = Claims::generate(local_user_view.local_user.id, req, &context).await?;
|
||||||
|
|
||||||
let json = LoginResponse {
|
Ok(Json(LoginResponse {
|
||||||
jwt: Some(jwt.clone()),
|
jwt: Some(jwt.clone()),
|
||||||
verify_email_sent: false,
|
verify_email_sent: false,
|
||||||
registration_created: false,
|
registration_created: false,
|
||||||
};
|
}))
|
||||||
|
|
||||||
let mut res = HttpResponse::build(StatusCode::OK).json(json);
|
|
||||||
res.add_cookie(&create_login_cookie(jwt))?;
|
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn check_registration_application(
|
async fn check_registration_application(
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use actix_web::web::{Data, Json};
|
use actix_web::web::{Data, Json, Query};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
person::{GetReportCount, GetReportCountResponse},
|
person::{GetReportCount, GetReportCountResponse},
|
||||||
utils::check_community_mod_action_opt,
|
utils::check_community_mod_of_any_or_admin_action,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{
|
use lemmy_db_views::structs::{
|
||||||
CommentReportView,
|
CommentReportView,
|
||||||
|
@ -14,7 +14,7 @@ use lemmy_utils::error::LemmyError;
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
pub async fn report_count(
|
pub async fn report_count(
|
||||||
data: Json<GetReportCount>,
|
data: Query<GetReportCount>,
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: LocalUserView,
|
local_user_view: LocalUserView,
|
||||||
) -> Result<Json<GetReportCountResponse>, LemmyError> {
|
) -> Result<Json<GetReportCountResponse>, LemmyError> {
|
||||||
|
@ -22,7 +22,7 @@ pub async fn report_count(
|
||||||
let admin = local_user_view.local_user.admin;
|
let admin = local_user_view.local_user.admin;
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
|
|
||||||
check_community_mod_action_opt(&local_user_view, community_id, &mut context.pool()).await?;
|
check_community_mod_of_any_or_admin_action(&local_user_view, &mut context.pool()).await?;
|
||||||
|
|
||||||
let comment_reports =
|
let comment_reports =
|
||||||
CommentReportView::get_report_count(&mut context.pool(), person_id, admin, community_id)
|
CommentReportView::get_report_count(&mut context.pool(), person_id, admin, community_id)
|
||||||
|
|
|
@ -2,7 +2,7 @@ use actix_web::web::{Data, Json, Query};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
post::{ListPostReports, ListPostReportsResponse},
|
post::{ListPostReports, ListPostReportsResponse},
|
||||||
utils::check_community_mod_action_opt,
|
utils::check_community_mod_of_any_or_admin_action,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::{post_report_view::PostReportQuery, structs::LocalUserView};
|
use lemmy_db_views::{post_report_view::PostReportQuery, structs::LocalUserView};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::LemmyError;
|
||||||
|
@ -18,7 +18,7 @@ pub async fn list_post_reports(
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
let unresolved_only = data.unresolved_only.unwrap_or_default();
|
let unresolved_only = data.unresolved_only.unwrap_or_default();
|
||||||
|
|
||||||
check_community_mod_action_opt(&local_user_view, community_id, &mut context.pool()).await?;
|
check_community_mod_of_any_or_admin_action(&local_user_view, &mut context.pool()).await?;
|
||||||
|
|
||||||
let page = data.page;
|
let page = data.page;
|
||||||
let limit = data.limit;
|
let limit = data.limit;
|
||||||
|
|
|
@ -2,7 +2,7 @@ use actix_web::web::{Data, Json, Query};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
site::{GetModlog, GetModlogResponse},
|
site::{GetModlog, GetModlogResponse},
|
||||||
utils::{check_community_mod_action_opt, check_private_instance, is_admin},
|
utils::{check_community_mod_of_any_or_admin_action, check_private_instance},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{source::local_site::LocalSite, ModlogActionType};
|
use lemmy_db_schema::{source::local_site::LocalSite, ModlogActionType};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
|
@ -41,11 +41,9 @@ pub async fn get_mod_log(
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
|
|
||||||
let is_mod_or_admin = if let Some(local_user_view) = local_user_view {
|
let is_mod_or_admin = if let Some(local_user_view) = local_user_view {
|
||||||
let is_mod = community_id.is_some()
|
check_community_mod_of_any_or_admin_action(&local_user_view, &mut context.pool())
|
||||||
&& check_community_mod_action_opt(&local_user_view, community_id, &mut context.pool())
|
|
||||||
.await
|
.await
|
||||||
.is_ok();
|
.is_ok()
|
||||||
is_mod || is_admin(&local_user_view).is_ok()
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
images::LocalImage,
|
images::LocalImage,
|
||||||
moderator::{AdminPurgePerson, AdminPurgePersonForm},
|
moderator::{AdminPurgePerson, AdminPurgePersonForm},
|
||||||
person::Person,
|
person::{Person, PersonUpdateForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
|
@ -29,7 +29,7 @@ pub async fn purge_person(
|
||||||
// Read the person to get their images
|
// Read the person to get their images
|
||||||
let person_id = data.person_id;
|
let person_id = data.person_id;
|
||||||
|
|
||||||
let local_user = LocalUserView::read_person(&mut context.pool(), person_id).await?;
|
if let Ok(local_user) = LocalUserView::read_person(&mut context.pool(), person_id).await {
|
||||||
let pictrs_uploads =
|
let pictrs_uploads =
|
||||||
LocalImage::get_all_by_local_user_id(&mut context.pool(), &local_user.local_user.id).await?;
|
LocalImage::get_all_by_local_user_id(&mut context.pool(), &local_user.local_user.id).await?;
|
||||||
|
|
||||||
|
@ -38,8 +38,20 @@ pub async fn purge_person(
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Person::delete(&mut context.pool(), person_id).await?;
|
// Clear profile data.
|
||||||
|
Person::delete_account(&mut context.pool(), person_id).await?;
|
||||||
|
// Keep person record, but mark as banned to prevent login or refetching from home instance.
|
||||||
|
Person::update(
|
||||||
|
&mut context.pool(),
|
||||||
|
person_id,
|
||||||
|
&PersonUpdateForm {
|
||||||
|
banned: Some(true),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Mod tables
|
// Mod tables
|
||||||
let form = AdminPurgePersonForm {
|
let form = AdminPurgePersonForm {
|
||||||
|
|
|
@ -13,6 +13,9 @@ name = "lemmy_api_common"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
full = [
|
full = [
|
||||||
"tracing",
|
"tracing",
|
||||||
|
|
|
@ -3,7 +3,12 @@ use crate::{
|
||||||
community::CommunityResponse,
|
community::CommunityResponse,
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
post::PostResponse,
|
post::PostResponse,
|
||||||
utils::{check_person_block, get_interface_language, is_mod_or_admin, send_email_to_user},
|
utils::{
|
||||||
|
check_person_instance_community_block,
|
||||||
|
get_interface_language,
|
||||||
|
is_mod_or_admin,
|
||||||
|
send_email_to_user,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
@ -95,6 +100,8 @@ pub async fn send_local_notifs(
|
||||||
let mut recipient_ids = Vec::new();
|
let mut recipient_ids = Vec::new();
|
||||||
let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname());
|
let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname());
|
||||||
|
|
||||||
|
let community_id = post.community_id;
|
||||||
|
|
||||||
// Send the local mentions
|
// Send the local mentions
|
||||||
for mention in mentions
|
for mention in mentions
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -142,13 +149,18 @@ pub async fn send_local_notifs(
|
||||||
// Get the parent commenter local_user
|
// Get the parent commenter local_user
|
||||||
let parent_creator_id = parent_comment.creator_id;
|
let parent_creator_id = parent_comment.creator_id;
|
||||||
|
|
||||||
// Only add to recipients if that person isn't blocked
|
let check_blocks = check_person_instance_community_block(
|
||||||
let creator_blocked = check_person_block(person.id, parent_creator_id, &mut context.pool())
|
person.id,
|
||||||
|
parent_creator_id,
|
||||||
|
person.instance_id,
|
||||||
|
community_id,
|
||||||
|
&mut context.pool(),
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.is_err();
|
.is_err();
|
||||||
|
|
||||||
// Don't send a notif to yourself
|
// Don't send a notif to yourself
|
||||||
if parent_comment.creator_id != person.id && !creator_blocked {
|
if parent_comment.creator_id != person.id && !check_blocks {
|
||||||
let user_view = LocalUserView::read_person(&mut context.pool(), parent_creator_id).await;
|
let user_view = LocalUserView::read_person(&mut context.pool(), parent_creator_id).await;
|
||||||
if let Ok(parent_user_view) = user_view {
|
if let Ok(parent_user_view) = user_view {
|
||||||
recipient_ids.push(parent_user_view.local_user.id);
|
recipient_ids.push(parent_user_view.local_user.id);
|
||||||
|
@ -179,13 +191,17 @@ pub async fn send_local_notifs(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If there's no parent, its the post creator
|
let check_blocks = check_person_instance_community_block(
|
||||||
// Only add to recipients if that person isn't blocked
|
person.id,
|
||||||
let creator_blocked = check_person_block(person.id, post.creator_id, &mut context.pool())
|
post.creator_id,
|
||||||
|
person.instance_id,
|
||||||
|
community_id,
|
||||||
|
&mut context.pool(),
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.is_err();
|
.is_err();
|
||||||
|
|
||||||
if post.creator_id != person.id && !creator_blocked {
|
if post.creator_id != person.id && !check_blocks {
|
||||||
let creator_id = post.creator_id;
|
let creator_id = post.creator_id;
|
||||||
let parent_user = LocalUserView::read_person(&mut context.pool(), creator_id).await;
|
let parent_user = LocalUserView::read_person(&mut context.pool(), creator_id).await;
|
||||||
if let Ok(parent_user_view) = parent_user {
|
if let Ok(parent_user_view) = parent_user {
|
||||||
|
|
|
@ -115,9 +115,6 @@ pub struct SaveUserSettings {
|
||||||
pub show_bot_accounts: Option<bool>,
|
pub show_bot_accounts: Option<bool>,
|
||||||
/// Whether to show read posts.
|
/// Whether to show read posts.
|
||||||
pub show_read_posts: Option<bool>,
|
pub show_read_posts: Option<bool>,
|
||||||
/// Whether to show notifications for new posts.
|
|
||||||
// TODO notifs need to be reworked.
|
|
||||||
pub show_new_post_notifs: Option<bool>,
|
|
||||||
/// A list of languages you are able to see discussion in.
|
/// A list of languages you are able to see discussion in.
|
||||||
pub discussion_languages: Option<Vec<LanguageId>>,
|
pub discussion_languages: Option<Vec<LanguageId>>,
|
||||||
/// Open links in a new tab
|
/// Open links in a new tab
|
||||||
|
|
|
@ -328,6 +328,7 @@ pub struct FederatedInstances {
|
||||||
pub blocked: Vec<InstanceWithFederationState>,
|
pub blocked: Vec<InstanceWithFederationState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(TS))]
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
@ -350,6 +351,7 @@ impl From<FederationQueueState> for ReadableFederationState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(TS))]
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
request::purge_image_from_pictrs,
|
request::purge_image_from_pictrs,
|
||||||
sensitive::Sensitive,
|
|
||||||
site::{FederatedInstances, InstanceWithFederationState},
|
site::{FederatedInstances, InstanceWithFederationState},
|
||||||
};
|
};
|
||||||
use actix_web::cookie::{Cookie, SameSite};
|
|
||||||
use anyhow::Context;
|
|
||||||
use chrono::{DateTime, Days, Local, TimeZone, Utc};
|
use chrono::{DateTime, Days, Local, TimeZone, Utc};
|
||||||
use enum_map::{enum_map, EnumMap};
|
use enum_map::{enum_map, EnumMap};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
newtypes::{CommunityId, DbUrl, PersonId, PostId},
|
newtypes::{CommunityId, DbUrl, InstanceId, PersonId, PostId},
|
||||||
source::{
|
source::{
|
||||||
comment::{Comment, CommentUpdateForm},
|
comment::{Comment, CommentUpdateForm},
|
||||||
community::{Community, CommunityModerator, CommunityUpdateForm},
|
community::{Community, CommunityModerator, CommunityUpdateForm},
|
||||||
|
community_block::CommunityBlock,
|
||||||
email_verification::{EmailVerification, EmailVerificationForm},
|
email_verification::{EmailVerification, EmailVerificationForm},
|
||||||
images::RemoteImage,
|
images::RemoteImage,
|
||||||
instance::Instance,
|
instance::Instance,
|
||||||
|
instance_block::InstanceBlock,
|
||||||
local_site::LocalSite,
|
local_site::LocalSite,
|
||||||
local_site_rate_limit::LocalSiteRateLimit,
|
local_site_rate_limit::LocalSiteRateLimit,
|
||||||
password_reset_request::PasswordResetRequest,
|
password_reset_request::PasswordResetRequest,
|
||||||
|
@ -35,7 +34,6 @@ use lemmy_db_views_actor::structs::{
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
email::{send_email, translations::Lang},
|
email::{send_email, translations::Lang},
|
||||||
error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult},
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||||
location_info,
|
|
||||||
rate_limit::{ActionType, BucketConfig},
|
rate_limit::{ActionType, BucketConfig},
|
||||||
settings::structs::Settings,
|
settings::structs::Settings,
|
||||||
utils::{
|
utils::{
|
||||||
|
@ -85,6 +83,26 @@ pub async fn is_mod_or_admin_opt(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check that a person is either a mod of any community, or an admin
|
||||||
|
///
|
||||||
|
/// Should only be used for read operations
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
pub async fn check_community_mod_of_any_or_admin_action(
|
||||||
|
local_user_view: &LocalUserView,
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
) -> LemmyResult<()> {
|
||||||
|
let person = &local_user_view.person;
|
||||||
|
|
||||||
|
check_user_valid(person)?;
|
||||||
|
|
||||||
|
let is_mod_of_any_or_admin = CommunityView::is_mod_of_any_or_admin(pool, person.id).await?;
|
||||||
|
if !is_mod_of_any_or_admin {
|
||||||
|
Err(LemmyErrorType::NotAModOrAdmin)?
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> {
|
pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> {
|
||||||
check_user_valid(&local_user_view.person)?;
|
check_user_valid(&local_user_view.person)?;
|
||||||
if !local_user_view.local_user.admin {
|
if !local_user_view.local_user.admin {
|
||||||
|
@ -206,19 +224,6 @@ pub async fn check_community_mod_action(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn check_community_mod_action_opt(
|
|
||||||
local_user_view: &LocalUserView,
|
|
||||||
community_id: Option<CommunityId>,
|
|
||||||
pool: &mut DbPool<'_>,
|
|
||||||
) -> LemmyResult<()> {
|
|
||||||
if let Some(community_id) = community_id {
|
|
||||||
check_community_mod_action(&local_user_view.person, community_id, false, pool).await?;
|
|
||||||
} else {
|
|
||||||
is_admin(local_user_view)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn check_post_deleted_or_removed(post: &Post) -> Result<(), LemmyError> {
|
pub fn check_post_deleted_or_removed(post: &Post) -> Result<(), LemmyError> {
|
||||||
if post.deleted || post.removed {
|
if post.deleted || post.removed {
|
||||||
Err(LemmyErrorType::Deleted)?
|
Err(LemmyErrorType::Deleted)?
|
||||||
|
@ -227,15 +232,14 @@ pub fn check_post_deleted_or_removed(post: &Post) -> Result<(), LemmyError> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Throws an error if a recipient has blocked a person.
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn check_person_block(
|
pub async fn check_person_block(
|
||||||
my_id: PersonId,
|
my_id: PersonId,
|
||||||
potential_blocker_id: PersonId,
|
potential_blocker_id: PersonId,
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let is_blocked = PersonBlock::read(pool, potential_blocker_id, my_id)
|
let is_blocked = PersonBlock::read(pool, potential_blocker_id, my_id).await?;
|
||||||
.await
|
|
||||||
.is_ok();
|
|
||||||
if is_blocked {
|
if is_blocked {
|
||||||
Err(LemmyErrorType::PersonIsBlocked)?
|
Err(LemmyErrorType::PersonIsBlocked)?
|
||||||
} else {
|
} else {
|
||||||
|
@ -243,6 +247,50 @@ pub async fn check_person_block(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Throws an error if a recipient has blocked a community.
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
async fn check_community_block(
|
||||||
|
community_id: CommunityId,
|
||||||
|
person_id: PersonId,
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
let is_blocked = CommunityBlock::read(pool, person_id, community_id).await?;
|
||||||
|
if is_blocked {
|
||||||
|
Err(LemmyErrorType::CommunityIsBlocked)?
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Throws an error if a recipient has blocked an instance.
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
async fn check_instance_block(
|
||||||
|
instance_id: InstanceId,
|
||||||
|
person_id: PersonId,
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
let is_blocked = InstanceBlock::read(pool, person_id, instance_id).await?;
|
||||||
|
if is_blocked {
|
||||||
|
Err(LemmyErrorType::InstanceIsBlocked)?
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
pub async fn check_person_instance_community_block(
|
||||||
|
my_id: PersonId,
|
||||||
|
potential_blocker_id: PersonId,
|
||||||
|
instance_id: InstanceId,
|
||||||
|
community_id: CommunityId,
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
check_person_block(my_id, potential_blocker_id, pool).await?;
|
||||||
|
check_instance_block(instance_id, potential_blocker_id, pool).await?;
|
||||||
|
check_community_block(community_id, potential_blocker_id, pool).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub fn check_downvotes_enabled(score: i16, local_site: &LocalSite) -> Result<(), LemmyError> {
|
pub fn check_downvotes_enabled(score: i16, local_site: &LocalSite) -> Result<(), LemmyError> {
|
||||||
if score == -1 && !local_site.enable_downvotes {
|
if score == -1 && !local_site.enable_downvotes {
|
||||||
|
@ -748,24 +796,8 @@ pub fn generate_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
|
||||||
Ok(Url::parse(&format!("{actor_id}/inbox"))?.into())
|
Ok(Url::parse(&format!("{actor_id}/inbox"))?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_site_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, ParseError> {
|
pub fn generate_shared_inbox_url(settings: &Settings) -> Result<DbUrl, LemmyError> {
|
||||||
let mut actor_id: Url = actor_id.clone().into();
|
let url = format!("{}/inbox", settings.get_protocol_and_hostname());
|
||||||
actor_id.set_path("site_inbox");
|
|
||||||
Ok(actor_id.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_shared_inbox_url(actor_id: &DbUrl) -> Result<DbUrl, LemmyError> {
|
|
||||||
let actor_id: Url = actor_id.clone().into();
|
|
||||||
let url = format!(
|
|
||||||
"{}://{}{}/inbox",
|
|
||||||
&actor_id.scheme(),
|
|
||||||
&actor_id.host_str().context(location_info!())?,
|
|
||||||
if let Some(port) = actor_id.port() {
|
|
||||||
format!(":{port}")
|
|
||||||
} else {
|
|
||||||
String::new()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
Ok(Url::parse(&url)?.into())
|
Ok(Url::parse(&url)?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,14 +813,6 @@ pub fn generate_moderators_url(community_id: &DbUrl) -> Result<DbUrl, LemmyError
|
||||||
Ok(Url::parse(&format!("{community_id}/moderators"))?.into())
|
Ok(Url::parse(&format!("{community_id}/moderators"))?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_login_cookie(jwt: Sensitive<String>) -> Cookie<'static> {
|
|
||||||
let mut cookie = Cookie::new(AUTH_COOKIE_NAME, jwt.into_inner());
|
|
||||||
cookie.set_secure(true);
|
|
||||||
cookie.set_same_site(SameSite::Lax);
|
|
||||||
cookie.set_http_only(true);
|
|
||||||
cookie
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ensure that ban/block expiry is in valid range. If its in past, throw error. If its more
|
/// Ensure that ban/block expiry is in valid range. If its in past, throw error. If its more
|
||||||
/// than 10 years in future, convert to permanent ban. Otherwise return the same value.
|
/// than 10 years in future, convert to permanent ban. Otherwise return the same value.
|
||||||
pub fn check_expire_time(expires_unix_opt: Option<i64>) -> LemmyResult<Option<DateTime<Utc>>> {
|
pub fn check_expire_time(expires_unix_opt: Option<i64>) -> LemmyResult<Option<DateTime<Utc>>> {
|
||||||
|
|
|
@ -8,6 +8,9 @@ homepage.workspace = true
|
||||||
documentation.workspace = true
|
documentation.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_utils = { workspace = true }
|
lemmy_utils = { workspace = true }
|
||||||
lemmy_db_schema = { workspace = true, features = ["full"] }
|
lemmy_db_schema = { workspace = true, features = ["full"] }
|
||||||
|
|
|
@ -91,7 +91,7 @@ pub async fn create_community(
|
||||||
.public_key(keypair.public_key)
|
.public_key(keypair.public_key)
|
||||||
.followers_url(Some(generate_followers_url(&community_actor_id)?))
|
.followers_url(Some(generate_followers_url(&community_actor_id)?))
|
||||||
.inbox_url(Some(generate_inbox_url(&community_actor_id)?))
|
.inbox_url(Some(generate_inbox_url(&community_actor_id)?))
|
||||||
.shared_inbox_url(Some(generate_shared_inbox_url(&community_actor_id)?))
|
.shared_inbox_url(Some(generate_shared_inbox_url(context.settings())?))
|
||||||
.posting_restricted_to_mods(data.posting_restricted_to_mods)
|
.posting_restricted_to_mods(data.posting_restricted_to_mods)
|
||||||
.instance_id(site_view.site.instance_id)
|
.instance_id(site_view.site.instance_id)
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -5,7 +5,7 @@ use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
site::{CreateSite, SiteResponse},
|
site::{CreateSite, SiteResponse},
|
||||||
utils::{
|
utils::{
|
||||||
generate_site_inbox_url,
|
generate_shared_inbox_url,
|
||||||
is_admin,
|
is_admin,
|
||||||
local_site_rate_limit_to_rate_limit_config,
|
local_site_rate_limit_to_rate_limit_config,
|
||||||
local_site_to_slur_regex,
|
local_site_to_slur_regex,
|
||||||
|
@ -54,7 +54,7 @@ pub async fn create_site(
|
||||||
validate_create_payload(&local_site, &data)?;
|
validate_create_payload(&local_site, &data)?;
|
||||||
|
|
||||||
let actor_id: DbUrl = Url::parse(&context.settings().get_protocol_and_hostname())?.into();
|
let actor_id: DbUrl = Url::parse(&context.settings().get_protocol_and_hostname())?.into();
|
||||||
let inbox_url = Some(generate_site_inbox_url(&actor_id)?);
|
let inbox_url = Some(generate_shared_inbox_url(context.settings())?);
|
||||||
let keypair = generate_actor_keypair()?;
|
let keypair = generate_actor_keypair()?;
|
||||||
|
|
||||||
let slur_regex = local_site_to_slur_regex(&local_site);
|
let slur_regex = local_site_to_slur_regex(&local_site);
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use activitypub_federation::{config::Data, http_signatures::generate_actor_keypair};
|
use activitypub_federation::{config::Data, http_signatures::generate_actor_keypair};
|
||||||
use actix_web::{http::StatusCode, web::Json, HttpRequest, HttpResponse, HttpResponseBuilder};
|
use actix_web::{web::Json, HttpRequest};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
claims::Claims,
|
claims::Claims,
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
person::{LoginResponse, Register},
|
person::{LoginResponse, Register},
|
||||||
utils::{
|
utils::{
|
||||||
create_login_cookie,
|
|
||||||
generate_inbox_url,
|
generate_inbox_url,
|
||||||
generate_local_apub_endpoint,
|
generate_local_apub_endpoint,
|
||||||
generate_shared_inbox_url,
|
generate_shared_inbox_url,
|
||||||
|
@ -42,7 +41,7 @@ pub async fn register(
|
||||||
data: Json<Register>,
|
data: Json<Register>,
|
||||||
req: HttpRequest,
|
req: HttpRequest,
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<Json<LoginResponse>, LemmyError> {
|
||||||
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
||||||
let local_site = site_view.local_site;
|
let local_site = site_view.local_site;
|
||||||
let require_registration_application =
|
let require_registration_application =
|
||||||
|
@ -114,7 +113,7 @@ pub async fn register(
|
||||||
.private_key(Some(actor_keypair.private_key))
|
.private_key(Some(actor_keypair.private_key))
|
||||||
.public_key(actor_keypair.public_key)
|
.public_key(actor_keypair.public_key)
|
||||||
.inbox_url(Some(generate_inbox_url(&actor_id)?))
|
.inbox_url(Some(generate_inbox_url(&actor_id)?))
|
||||||
.shared_inbox_url(Some(generate_shared_inbox_url(&actor_id)?))
|
.shared_inbox_url(Some(generate_shared_inbox_url(context.settings())?))
|
||||||
.instance_id(site_view.site.instance_id)
|
.instance_id(site_view.site.instance_id)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -158,7 +157,6 @@ pub async fn register(
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut res = HttpResponseBuilder::new(StatusCode::OK);
|
|
||||||
let mut login_response = LoginResponse {
|
let mut login_response = LoginResponse {
|
||||||
jwt: None,
|
jwt: None,
|
||||||
registration_created: false,
|
registration_created: false,
|
||||||
|
@ -170,7 +168,6 @@ pub async fn register(
|
||||||
|| (!require_registration_application && !local_site.require_email_verification)
|
|| (!require_registration_application && !local_site.require_email_verification)
|
||||||
{
|
{
|
||||||
let jwt = Claims::generate(inserted_local_user.id, req, &context).await?;
|
let jwt = Claims::generate(inserted_local_user.id, req, &context).await?;
|
||||||
res.cookie(create_login_cookie(jwt.clone()));
|
|
||||||
login_response.jwt = Some(jwt);
|
login_response.jwt = Some(jwt);
|
||||||
} else {
|
} else {
|
||||||
if local_site.require_email_verification {
|
if local_site.require_email_verification {
|
||||||
|
@ -201,5 +198,5 @@ pub async fn register(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(res.json(login_response))
|
Ok(Json(login_response))
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@ name = "lemmy_apub"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_utils = { workspace = true }
|
lemmy_utils = { workspace = true }
|
||||||
lemmy_db_schema = { workspace = true, features = ["full"] }
|
lemmy_db_schema = { workspace = true, features = ["full"] }
|
||||||
|
|
|
@ -66,7 +66,14 @@ impl ActivityHandler for Delete {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
} else {
|
} else {
|
||||||
receive_delete_action(self.object.id(), &self.actor, true, context).await
|
receive_delete_action(
|
||||||
|
self.object.id(),
|
||||||
|
&self.actor,
|
||||||
|
true,
|
||||||
|
self.remove_data,
|
||||||
|
context,
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,6 +101,7 @@ impl Delete {
|
||||||
summary,
|
summary,
|
||||||
id,
|
id,
|
||||||
audience: community.map(|c| c.actor_id.clone().into()),
|
audience: community.map(|c| c.actor_id.clone().into()),
|
||||||
|
remove_data: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,6 +172,7 @@ pub(in crate::activities) async fn receive_remove_action(
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
DeletableObjects::PrivateMessage(_) => unimplemented!(),
|
DeletableObjects::PrivateMessage(_) => unimplemented!(),
|
||||||
|
DeletableObjects::Person { .. } => unimplemented!(),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
use crate::{
|
|
||||||
activities::{generate_activity_id, send_lemmy_activity, verify_is_public, verify_person},
|
|
||||||
insert_received_activity,
|
|
||||||
objects::person::ApubPerson,
|
|
||||||
protocol::activities::deletion::delete_user::DeleteUser,
|
|
||||||
};
|
|
||||||
use activitypub_federation::{
|
|
||||||
config::Data,
|
|
||||||
kinds::{activity::DeleteType, public},
|
|
||||||
protocol::verification::verify_urls_match,
|
|
||||||
traits::{ActivityHandler, Actor},
|
|
||||||
};
|
|
||||||
use lemmy_api_common::{context::LemmyContext, utils::purge_user_account};
|
|
||||||
use lemmy_db_schema::source::{activity::ActivitySendTargets, person::Person};
|
|
||||||
use lemmy_utils::error::LemmyError;
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
pub async fn delete_user(
|
|
||||||
person: Person,
|
|
||||||
delete_content: bool,
|
|
||||||
context: Data<LemmyContext>,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let actor: ApubPerson = person.into();
|
|
||||||
|
|
||||||
let id = generate_activity_id(
|
|
||||||
DeleteType::Delete,
|
|
||||||
&context.settings().get_protocol_and_hostname(),
|
|
||||||
)?;
|
|
||||||
let delete = DeleteUser {
|
|
||||||
actor: actor.id().into(),
|
|
||||||
to: vec![public()],
|
|
||||||
object: actor.id().into(),
|
|
||||||
kind: DeleteType::Delete,
|
|
||||||
id: id.clone(),
|
|
||||||
cc: vec![],
|
|
||||||
remove_data: Some(delete_content),
|
|
||||||
};
|
|
||||||
|
|
||||||
let inboxes = ActivitySendTargets::to_all_instances();
|
|
||||||
|
|
||||||
send_lemmy_activity(&context, delete, &actor, inboxes, true).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This can be separate from Delete activity because it doesn't need to be handled in shared inbox
|
|
||||||
/// (cause instance actor doesn't have shared inbox).
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl ActivityHandler for DeleteUser {
|
|
||||||
type DataType = LemmyContext;
|
|
||||||
type Error = LemmyError;
|
|
||||||
|
|
||||||
fn id(&self) -> &Url {
|
|
||||||
&self.id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn actor(&self) -> &Url {
|
|
||||||
self.actor.inner()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
|
|
||||||
insert_received_activity(&self.id, context).await?;
|
|
||||||
verify_is_public(&self.to, &[])?;
|
|
||||||
verify_person(&self.actor, context).await?;
|
|
||||||
verify_urls_match(self.actor.inner(), self.object.inner())?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn receive(self, context: &Data<Self::DataType>) -> Result<(), LemmyError> {
|
|
||||||
let actor = self.actor.dereference(context).await?;
|
|
||||||
if self.remove_data.unwrap_or(false) {
|
|
||||||
purge_user_account(actor.id, context).await?;
|
|
||||||
} else {
|
|
||||||
Person::delete_account(&mut context.pool(), actor.id).await?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -24,10 +24,10 @@ use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
fetch::object_id::ObjectId,
|
fetch::object_id::ObjectId,
|
||||||
kinds::public,
|
kinds::public,
|
||||||
protocol::verification::verify_domains_match,
|
protocol::verification::{verify_domains_match, verify_urls_match},
|
||||||
traits::{Actor, Object},
|
traits::{Actor, Object},
|
||||||
};
|
};
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::{context::LemmyContext, utils::purge_user_account};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
newtypes::CommunityId,
|
newtypes::CommunityId,
|
||||||
source::{
|
source::{
|
||||||
|
@ -45,7 +45,6 @@ use std::ops::Deref;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub mod delete;
|
pub mod delete;
|
||||||
pub mod delete_user;
|
|
||||||
pub mod undo_delete;
|
pub mod undo_delete;
|
||||||
|
|
||||||
/// Parameter `reason` being set indicates that this is a removal by a mod. If its unset, this
|
/// Parameter `reason` being set indicates that this is a removal by a mod. If its unset, this
|
||||||
|
@ -135,8 +134,26 @@ pub(crate) async fn send_apub_delete_private_message(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn send_apub_delete_user(
|
||||||
|
person: Person,
|
||||||
|
remove_data: bool,
|
||||||
|
context: Data<LemmyContext>,
|
||||||
|
) -> Result<(), LemmyError> {
|
||||||
|
let person: ApubPerson = person.into();
|
||||||
|
|
||||||
|
let deletable = DeletableObjects::Person(person.clone());
|
||||||
|
let mut delete: Delete = Delete::new(&person, deletable, public(), None, None, &context)?;
|
||||||
|
delete.remove_data = Some(remove_data);
|
||||||
|
|
||||||
|
let inboxes = ActivitySendTargets::to_all_instances();
|
||||||
|
|
||||||
|
send_lemmy_activity(&context, delete, &person, inboxes, true).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub enum DeletableObjects {
|
pub enum DeletableObjects {
|
||||||
Community(ApubCommunity),
|
Community(ApubCommunity),
|
||||||
|
Person(ApubPerson),
|
||||||
Comment(ApubComment),
|
Comment(ApubComment),
|
||||||
Post(ApubPost),
|
Post(ApubPost),
|
||||||
PrivateMessage(ApubPrivateMessage),
|
PrivateMessage(ApubPrivateMessage),
|
||||||
|
@ -151,6 +168,9 @@ impl DeletableObjects {
|
||||||
if let Some(c) = ApubCommunity::read_from_id(ap_id.clone(), context).await? {
|
if let Some(c) = ApubCommunity::read_from_id(ap_id.clone(), context).await? {
|
||||||
return Ok(DeletableObjects::Community(c));
|
return Ok(DeletableObjects::Community(c));
|
||||||
}
|
}
|
||||||
|
if let Some(p) = ApubPerson::read_from_id(ap_id.clone(), context).await? {
|
||||||
|
return Ok(DeletableObjects::Person(p));
|
||||||
|
}
|
||||||
if let Some(p) = ApubPost::read_from_id(ap_id.clone(), context).await? {
|
if let Some(p) = ApubPost::read_from_id(ap_id.clone(), context).await? {
|
||||||
return Ok(DeletableObjects::Post(p));
|
return Ok(DeletableObjects::Post(p));
|
||||||
}
|
}
|
||||||
|
@ -166,6 +186,7 @@ impl DeletableObjects {
|
||||||
pub(crate) fn id(&self) -> Url {
|
pub(crate) fn id(&self) -> Url {
|
||||||
match self {
|
match self {
|
||||||
DeletableObjects::Community(c) => c.id(),
|
DeletableObjects::Community(c) => c.id(),
|
||||||
|
DeletableObjects::Person(p) => p.id(),
|
||||||
DeletableObjects::Comment(c) => c.ap_id.clone().into(),
|
DeletableObjects::Comment(c) => c.ap_id.clone().into(),
|
||||||
DeletableObjects::Post(p) => p.ap_id.clone().into(),
|
DeletableObjects::Post(p) => p.ap_id.clone().into(),
|
||||||
DeletableObjects::PrivateMessage(p) => p.ap_id.clone().into(),
|
DeletableObjects::PrivateMessage(p) => p.ap_id.clone().into(),
|
||||||
|
@ -191,6 +212,11 @@ pub(in crate::activities) async fn verify_delete_activity(
|
||||||
// community deletion is always a mod (or admin) action
|
// community deletion is always a mod (or admin) action
|
||||||
verify_mod_action(&activity.actor, &community, context).await?;
|
verify_mod_action(&activity.actor, &community, context).await?;
|
||||||
}
|
}
|
||||||
|
DeletableObjects::Person(person) => {
|
||||||
|
verify_is_public(&activity.to, &[])?;
|
||||||
|
verify_person(&activity.actor, context).await?;
|
||||||
|
verify_urls_match(person.actor_id.inner(), activity.object.id())?;
|
||||||
|
}
|
||||||
DeletableObjects::Post(p) => {
|
DeletableObjects::Post(p) => {
|
||||||
verify_is_public(&activity.to, &[])?;
|
verify_is_public(&activity.to, &[])?;
|
||||||
verify_delete_post_or_comment(
|
verify_delete_post_or_comment(
|
||||||
|
@ -245,6 +271,7 @@ async fn receive_delete_action(
|
||||||
object: &Url,
|
object: &Url,
|
||||||
actor: &ObjectId<ApubPerson>,
|
actor: &ObjectId<ApubPerson>,
|
||||||
deleted: bool,
|
deleted: bool,
|
||||||
|
do_purge_user_account: Option<bool>,
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
match DeletableObjects::read_from_db(object, context).await? {
|
match DeletableObjects::read_from_db(object, context).await? {
|
||||||
|
@ -266,6 +293,13 @@ async fn receive_delete_action(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
DeletableObjects::Person(person) => {
|
||||||
|
if do_purge_user_account.unwrap_or(false) {
|
||||||
|
purge_user_account(person.id, context).await?;
|
||||||
|
} else {
|
||||||
|
Person::delete_account(&mut context.pool(), person.id).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
DeletableObjects::Post(post) => {
|
DeletableObjects::Post(post) => {
|
||||||
if deleted != post.deleted {
|
if deleted != post.deleted {
|
||||||
Post::update(
|
Post::update(
|
||||||
|
|
|
@ -58,7 +58,7 @@ impl ActivityHandler for UndoDelete {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
} else {
|
} else {
|
||||||
receive_delete_action(self.object.object.id(), &self.actor, false, context).await
|
receive_delete_action(self.object.object.id(), &self.actor, false, None, context).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,6 +156,7 @@ impl UndoDelete {
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
DeletableObjects::PrivateMessage(_) => unimplemented!(),
|
DeletableObjects::PrivateMessage(_) => unimplemented!(),
|
||||||
|
DeletableObjects::Person { .. } => unimplemented!(),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,15 +52,6 @@ impl Follow {
|
||||||
community: &ApubCommunity,
|
community: &ApubCommunity,
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let community_follower_form = CommunityFollowerForm {
|
|
||||||
community_id: community.id,
|
|
||||||
person_id: actor.id,
|
|
||||||
pending: true,
|
|
||||||
};
|
|
||||||
CommunityFollower::follow(&mut context.pool(), &community_follower_form)
|
|
||||||
.await
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
let follow = Follow::new(actor, community, context)?;
|
let follow = Follow::new(actor, community, context)?;
|
||||||
let inbox = if community.local {
|
let inbox = if community.local {
|
||||||
ActivitySendTargets::empty()
|
ActivitySendTargets::empty()
|
||||||
|
|
|
@ -9,10 +9,10 @@ use crate::{
|
||||||
},
|
},
|
||||||
create_or_update::private_message::send_create_or_update_pm,
|
create_or_update::private_message::send_create_or_update_pm,
|
||||||
deletion::{
|
deletion::{
|
||||||
delete_user::delete_user,
|
|
||||||
send_apub_delete_in_community,
|
send_apub_delete_in_community,
|
||||||
send_apub_delete_in_community_new,
|
send_apub_delete_in_community_new,
|
||||||
send_apub_delete_private_message,
|
send_apub_delete_private_message,
|
||||||
|
send_apub_delete_user,
|
||||||
DeletableObjects,
|
DeletableObjects,
|
||||||
},
|
},
|
||||||
voting::send_like_activity,
|
voting::send_like_activity,
|
||||||
|
@ -330,7 +330,7 @@ pub async fn match_outgoing_activities(
|
||||||
DeletePrivateMessage(person, pm, deleted) => {
|
DeletePrivateMessage(person, pm, deleted) => {
|
||||||
send_apub_delete_private_message(&person.into(), pm, deleted, context).await
|
send_apub_delete_private_message(&person.into(), pm, deleted, context).await
|
||||||
}
|
}
|
||||||
DeleteUser(person, delete_content) => delete_user(person, delete_content, context).await,
|
DeleteUser(person, remove_data) => send_apub_delete_user(person, remove_data, context).await,
|
||||||
CreateReport(url, actor, community, reason) => {
|
CreateReport(url, actor, community, reason) => {
|
||||||
Report::send(ObjectId::from(url), actor, community, reason, context).await
|
Report::send(ObjectId::from(url), actor, community, reason, context).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use crate::{
|
||||||
note::CreateOrUpdateNote,
|
note::CreateOrUpdateNote,
|
||||||
page::CreateOrUpdatePage,
|
page::CreateOrUpdatePage,
|
||||||
},
|
},
|
||||||
deletion::{delete::Delete, delete_user::DeleteUser, undo_delete::UndoDelete},
|
deletion::{delete::Delete, undo_delete::UndoDelete},
|
||||||
following::{accept::AcceptFollow, follow::Follow, undo_follow::UndoFollow},
|
following::{accept::AcceptFollow, follow::Follow, undo_follow::UndoFollow},
|
||||||
voting::{undo_vote::UndoVote, vote::Vote},
|
voting::{undo_vote::UndoVote, vote::Vote},
|
||||||
},
|
},
|
||||||
|
@ -98,16 +98,6 @@ pub enum AnnouncableActivities {
|
||||||
Page(Page),
|
Page(Page),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
#[enum_delegate::implement(ActivityHandler)]
|
|
||||||
#[allow(clippy::enum_variant_names)]
|
|
||||||
pub enum SiteInboxActivities {
|
|
||||||
BlockUser(BlockUser),
|
|
||||||
UndoBlockUser(UndoBlockUser),
|
|
||||||
DeleteUser(DeleteUser),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl InCommunity for AnnouncableActivities {
|
impl InCommunity for AnnouncableActivities {
|
||||||
#[tracing::instrument(skip(self, context))]
|
#[tracing::instrument(skip(self, context))]
|
||||||
|
@ -134,44 +124,43 @@ impl InCommunity for AnnouncableActivities {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
#![allow(clippy::indexing_slicing)]
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
activity_lists::{GroupInboxActivities, PersonInboxActivities, SiteInboxActivities},
|
activity_lists::{GroupInboxActivities, PersonInboxActivities, SharedInboxActivities},
|
||||||
protocol::tests::{test_json, test_parse_lemmy_item},
|
protocol::tests::{test_json, test_parse_lemmy_item},
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_group_inbox() {
|
fn test_group_inbox() -> LemmyResult<()> {
|
||||||
test_parse_lemmy_item::<GroupInboxActivities>("assets/lemmy/activities/following/follow.json")
|
test_parse_lemmy_item::<GroupInboxActivities>("assets/lemmy/activities/following/follow.json")?;
|
||||||
.unwrap();
|
|
||||||
test_parse_lemmy_item::<GroupInboxActivities>(
|
test_parse_lemmy_item::<GroupInboxActivities>(
|
||||||
"assets/lemmy/activities/create_or_update/create_note.json",
|
"assets/lemmy/activities/create_or_update/create_note.json",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_person_inbox() {
|
fn test_person_inbox() -> LemmyResult<()> {
|
||||||
test_parse_lemmy_item::<PersonInboxActivities>("assets/lemmy/activities/following/accept.json")
|
test_parse_lemmy_item::<PersonInboxActivities>(
|
||||||
.unwrap();
|
"assets/lemmy/activities/following/accept.json",
|
||||||
|
)?;
|
||||||
test_parse_lemmy_item::<PersonInboxActivities>(
|
test_parse_lemmy_item::<PersonInboxActivities>(
|
||||||
"assets/lemmy/activities/create_or_update/create_note.json",
|
"assets/lemmy/activities/create_or_update/create_note.json",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
test_parse_lemmy_item::<PersonInboxActivities>(
|
test_parse_lemmy_item::<PersonInboxActivities>(
|
||||||
"assets/lemmy/activities/create_or_update/create_private_message.json",
|
"assets/lemmy/activities/create_or_update/create_private_message.json",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
test_json::<PersonInboxActivities>("assets/mastodon/activities/follow.json")?;
|
||||||
test_json::<PersonInboxActivities>("assets/mastodon/activities/follow.json").unwrap();
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_site_inbox() {
|
fn test_shared_inbox() -> LemmyResult<()> {
|
||||||
test_parse_lemmy_item::<SiteInboxActivities>(
|
test_parse_lemmy_item::<SharedInboxActivities>(
|
||||||
"assets/lemmy/activities/deletion/delete_user.json",
|
"assets/lemmy/activities/deletion/delete_user.json",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ use lemmy_db_schema::{
|
||||||
comment::{CommentSaved, CommentSavedForm},
|
comment::{CommentSaved, CommentSavedForm},
|
||||||
community::{CommunityFollower, CommunityFollowerForm},
|
community::{CommunityFollower, CommunityFollowerForm},
|
||||||
community_block::{CommunityBlock, CommunityBlockForm},
|
community_block::{CommunityBlock, CommunityBlockForm},
|
||||||
|
instance::Instance,
|
||||||
|
instance_block::{InstanceBlock, InstanceBlockForm},
|
||||||
local_user::{LocalUser, LocalUserUpdateForm},
|
local_user::{LocalUser, LocalUserUpdateForm},
|
||||||
person::{Person, PersonUpdateForm},
|
person::{Person, PersonUpdateForm},
|
||||||
person_block::{PersonBlock, PersonBlockForm},
|
person_block::{PersonBlock, PersonBlockForm},
|
||||||
|
@ -58,6 +60,8 @@ pub struct UserSettingsBackup {
|
||||||
pub blocked_communities: Vec<ObjectId<ApubCommunity>>,
|
pub blocked_communities: Vec<ObjectId<ApubCommunity>>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub blocked_users: Vec<ObjectId<ApubPerson>>,
|
pub blocked_users: Vec<ObjectId<ApubPerson>>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub blocked_instances: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
|
@ -78,6 +82,7 @@ pub async fn export_settings(
|
||||||
settings: Some(local_user_view.local_user),
|
settings: Some(local_user_view.local_user),
|
||||||
followed_communities: vec_into(lists.followed_communities),
|
followed_communities: vec_into(lists.followed_communities),
|
||||||
blocked_communities: vec_into(lists.blocked_communities),
|
blocked_communities: vec_into(lists.blocked_communities),
|
||||||
|
blocked_instances: lists.blocked_instances,
|
||||||
blocked_users: lists.blocked_users.into_iter().map(Into::into).collect(),
|
blocked_users: lists.blocked_users.into_iter().map(Into::into).collect(),
|
||||||
saved_posts: lists.saved_posts.into_iter().map(Into::into).collect(),
|
saved_posts: lists.saved_posts.into_iter().map(Into::into).collect(),
|
||||||
saved_comments: lists.saved_comments.into_iter().map(Into::into).collect(),
|
saved_comments: lists.saved_comments.into_iter().map(Into::into).collect(),
|
||||||
|
@ -130,6 +135,7 @@ pub async fn import_settings(
|
||||||
let url_count = data.followed_communities.len()
|
let url_count = data.followed_communities.len()
|
||||||
+ data.blocked_communities.len()
|
+ data.blocked_communities.len()
|
||||||
+ data.blocked_users.len()
|
+ data.blocked_users.len()
|
||||||
|
+ data.blocked_instances.len()
|
||||||
+ data.saved_posts.len()
|
+ data.saved_posts.len()
|
||||||
+ data.saved_comments.len();
|
+ data.saved_comments.len();
|
||||||
if url_count > MAX_API_PARAM_ELEMENTS {
|
if url_count > MAX_API_PARAM_ELEMENTS {
|
||||||
|
@ -269,6 +275,19 @@ pub async fn import_settings(
|
||||||
LemmyResult::Ok(())
|
LemmyResult::Ok(())
|
||||||
}))
|
}))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
try_join_all(data.blocked_instances.iter().map(|domain| async {
|
||||||
|
// dont fetch unknown blocked objects from home server
|
||||||
|
let instance = Instance::read_or_create(&mut context.pool(), domain.clone()).await?;
|
||||||
|
let form = InstanceBlockForm {
|
||||||
|
person_id,
|
||||||
|
instance_id: instance.id,
|
||||||
|
};
|
||||||
|
InstanceBlock::block(&mut context.pool(), &form).await?;
|
||||||
|
LemmyResult::Ok(())
|
||||||
|
}))
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -277,7 +296,6 @@ pub async fn import_settings(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
#![allow(clippy::indexing_slicing)]
|
||||||
|
|
||||||
use crate::api::user_settings_backup::{export_settings, import_settings};
|
use crate::api::user_settings_backup::{export_settings, import_settings};
|
||||||
|
@ -294,7 +312,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
use lemmy_db_views_actor::structs::CommunityFollowerView;
|
use lemmy_db_views_actor::structs::CommunityFollowerView;
|
||||||
use lemmy_utils::error::LemmyErrorType;
|
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
@ -303,10 +321,8 @@ mod tests {
|
||||||
name: String,
|
name: String,
|
||||||
bio: Option<String>,
|
bio: Option<String>,
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
) -> LocalUserView {
|
) -> LemmyResult<LocalUserView> {
|
||||||
let instance = Instance::read_or_create(&mut context.pool(), "example.com".to_string())
|
let instance = Instance::read_or_create(&mut context.pool(), "example.com".to_string()).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let person_form = PersonInsertForm::builder()
|
let person_form = PersonInsertForm::builder()
|
||||||
.name(name.clone())
|
.name(name.clone())
|
||||||
.display_name(Some(name.clone()))
|
.display_name(Some(name.clone()))
|
||||||
|
@ -314,63 +330,49 @@ mod tests {
|
||||||
.public_key("asd".to_string())
|
.public_key("asd".to_string())
|
||||||
.instance_id(instance.id)
|
.instance_id(instance.id)
|
||||||
.build();
|
.build();
|
||||||
let person = Person::create(&mut context.pool(), &person_form)
|
let person = Person::create(&mut context.pool(), &person_form).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let user_form = LocalUserInsertForm::builder()
|
let user_form = LocalUserInsertForm::builder()
|
||||||
.person_id(person.id)
|
.person_id(person.id)
|
||||||
.password_encrypted("pass".to_string())
|
.password_encrypted("pass".to_string())
|
||||||
.build();
|
.build();
|
||||||
let local_user = LocalUser::create(&mut context.pool(), &user_form)
|
let local_user = LocalUser::create(&mut context.pool(), &user_form).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
LocalUserView::read(&mut context.pool(), local_user.id)
|
Ok(LocalUserView::read(&mut context.pool(), local_user.id).await?)
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_settings_export_import() {
|
async fn test_settings_export_import() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
|
|
||||||
let export_user = create_user("hanna".to_string(), Some("my bio".to_string()), &context).await;
|
let export_user =
|
||||||
|
create_user("hanna".to_string(), Some("my bio".to_string()), &context).await?;
|
||||||
|
|
||||||
let community_form = CommunityInsertForm::builder()
|
let community_form = CommunityInsertForm::builder()
|
||||||
.name("testcom".to_string())
|
.name("testcom".to_string())
|
||||||
.title("testcom".to_string())
|
.title("testcom".to_string())
|
||||||
.instance_id(export_user.person.instance_id)
|
.instance_id(export_user.person.instance_id)
|
||||||
.build();
|
.build();
|
||||||
let community = Community::create(&mut context.pool(), &community_form)
|
let community = Community::create(&mut context.pool(), &community_form).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let follower_form = CommunityFollowerForm {
|
let follower_form = CommunityFollowerForm {
|
||||||
community_id: community.id,
|
community_id: community.id,
|
||||||
person_id: export_user.person.id,
|
person_id: export_user.person.id,
|
||||||
pending: false,
|
pending: false,
|
||||||
};
|
};
|
||||||
CommunityFollower::follow(&mut context.pool(), &follower_form)
|
CommunityFollower::follow(&mut context.pool(), &follower_form).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let backup = export_settings(export_user.clone(), context.reset_request_count())
|
let backup = export_settings(export_user.clone(), context.reset_request_count()).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let import_user = create_user("charles".to_string(), None, &context).await;
|
let import_user = create_user("charles".to_string(), None, &context).await?;
|
||||||
|
|
||||||
import_settings(backup, import_user.clone(), context.reset_request_count())
|
import_settings(backup, import_user.clone(), context.reset_request_count()).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// wait for background task to finish
|
// wait for background task to finish
|
||||||
sleep(Duration::from_millis(1000)).await;
|
sleep(Duration::from_millis(1000)).await;
|
||||||
|
|
||||||
let import_user_updated = LocalUserView::read(&mut context.pool(), import_user.local_user.id)
|
let import_user_updated =
|
||||||
.await
|
LocalUserView::read(&mut context.pool(), import_user.local_user.id).await?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
export_user.person.display_name,
|
export_user.person.display_name,
|
||||||
|
@ -378,61 +380,49 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert_eq!(export_user.person.bio, import_user_updated.person.bio);
|
assert_eq!(export_user.person.bio, import_user_updated.person.bio);
|
||||||
|
|
||||||
let follows = CommunityFollowerView::for_person(&mut context.pool(), import_user.person.id)
|
let follows =
|
||||||
.await
|
CommunityFollowerView::for_person(&mut context.pool(), import_user.person.id).await?;
|
||||||
.unwrap();
|
|
||||||
assert_eq!(follows.len(), 1);
|
assert_eq!(follows.len(), 1);
|
||||||
assert_eq!(follows[0].community.actor_id, community.actor_id);
|
assert_eq!(follows[0].community.actor_id, community.actor_id);
|
||||||
|
|
||||||
LocalUser::delete(&mut context.pool(), export_user.local_user.id)
|
LocalUser::delete(&mut context.pool(), export_user.local_user.id).await?;
|
||||||
.await
|
LocalUser::delete(&mut context.pool(), import_user.local_user.id).await?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
LocalUser::delete(&mut context.pool(), import_user.local_user.id)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn disallow_large_backup() {
|
async fn disallow_large_backup() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
|
|
||||||
let export_user = create_user("hanna".to_string(), Some("my bio".to_string()), &context).await;
|
let export_user =
|
||||||
|
create_user("hanna".to_string(), Some("my bio".to_string()), &context).await?;
|
||||||
|
|
||||||
let mut backup = export_settings(export_user.clone(), context.reset_request_count())
|
let mut backup = export_settings(export_user.clone(), context.reset_request_count()).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
for _ in 0..251 {
|
for _ in 0..251 {
|
||||||
backup
|
backup
|
||||||
.followed_communities
|
.followed_communities
|
||||||
.push("http://example.com".parse().unwrap());
|
.push("http://example.com".parse()?);
|
||||||
backup
|
backup
|
||||||
.blocked_communities
|
.blocked_communities
|
||||||
.push("http://example2.com".parse().unwrap());
|
.push("http://example2.com".parse()?);
|
||||||
backup
|
backup.saved_posts.push("http://example3.com".parse()?);
|
||||||
.saved_posts
|
backup.saved_comments.push("http://example4.com".parse()?);
|
||||||
.push("http://example3.com".parse().unwrap());
|
|
||||||
backup
|
|
||||||
.saved_comments
|
|
||||||
.push("http://example4.com".parse().unwrap());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let import_user = create_user("charles".to_string(), None, &context).await;
|
let import_user = create_user("charles".to_string(), None, &context).await?;
|
||||||
|
|
||||||
let imported =
|
let imported =
|
||||||
import_settings(backup, import_user.clone(), context.reset_request_count()).await;
|
import_settings(backup, import_user.clone(), context.reset_request_count()).await;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
imported.err().unwrap().error_type,
|
imported.err().map(|e| e.error_type),
|
||||||
LemmyErrorType::TooManyItems
|
Some(LemmyErrorType::TooManyItems)
|
||||||
);
|
);
|
||||||
|
|
||||||
LocalUser::delete(&mut context.pool(), export_user.local_user.id)
|
LocalUser::delete(&mut context.pool(), export_user.local_user.id).await?;
|
||||||
.await
|
LocalUser::delete(&mut context.pool(), import_user.local_user.id).await?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
LocalUser::delete(&mut context.pool(), import_user.local_user.id)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,6 @@ impl Collection for ApubCommunityModerators {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
#![allow(clippy::indexing_slicing)]
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -119,20 +118,19 @@ mod tests {
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_parse_lemmy_community_moderators() {
|
async fn test_parse_lemmy_community_moderators() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
let (new_mod, site) = parse_lemmy_person(&context).await;
|
let (new_mod, site) = parse_lemmy_person(&context).await?;
|
||||||
let community = parse_lemmy_community(&context).await;
|
let community = parse_lemmy_community(&context).await?;
|
||||||
let community_id = community.id;
|
let community_id = community.id;
|
||||||
|
|
||||||
let inserted_instance =
|
let inserted_instance =
|
||||||
Instance::read_or_create(&mut context.pool(), "my_domain.tld".to_string())
|
Instance::read_or_create(&mut context.pool(), "my_domain.tld".to_string()).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let old_mod = PersonInsertForm::builder()
|
let old_mod = PersonInsertForm::builder()
|
||||||
.name("holly".into())
|
.name("holly".into())
|
||||||
|
@ -140,49 +138,34 @@ mod tests {
|
||||||
.instance_id(inserted_instance.id)
|
.instance_id(inserted_instance.id)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let old_mod = Person::create(&mut context.pool(), &old_mod).await.unwrap();
|
let old_mod = Person::create(&mut context.pool(), &old_mod).await?;
|
||||||
let community_moderator_form = CommunityModeratorForm {
|
let community_moderator_form = CommunityModeratorForm {
|
||||||
community_id: community.id,
|
community_id: community.id,
|
||||||
person_id: old_mod.id,
|
person_id: old_mod.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
CommunityModerator::join(&mut context.pool(), &community_moderator_form)
|
CommunityModerator::join(&mut context.pool(), &community_moderator_form).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(site.actor_id.to_string(), "https://enterprise.lemmy.ml/");
|
assert_eq!(site.actor_id.to_string(), "https://enterprise.lemmy.ml/");
|
||||||
|
|
||||||
let json: GroupModerators =
|
let json: GroupModerators =
|
||||||
file_to_json_object("assets/lemmy/collections/group_moderators.json").unwrap();
|
file_to_json_object("assets/lemmy/collections/group_moderators.json")?;
|
||||||
let url = Url::parse("https://enterprise.lemmy.ml/c/tenforward").unwrap();
|
let url = Url::parse("https://enterprise.lemmy.ml/c/tenforward")?;
|
||||||
ApubCommunityModerators::verify(&json, &url, &context)
|
ApubCommunityModerators::verify(&json, &url, &context).await?;
|
||||||
.await
|
ApubCommunityModerators::from_json(json, &community, &context).await?;
|
||||||
.unwrap();
|
|
||||||
ApubCommunityModerators::from_json(json, &community, &context)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(context.request_count(), 0);
|
assert_eq!(context.request_count(), 0);
|
||||||
|
|
||||||
let current_moderators =
|
let current_moderators =
|
||||||
CommunityModeratorView::for_community(&mut context.pool(), community_id)
|
CommunityModeratorView::for_community(&mut context.pool(), community_id).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(current_moderators.len(), 1);
|
assert_eq!(current_moderators.len(), 1);
|
||||||
assert_eq!(current_moderators[0].moderator.id, new_mod.id);
|
assert_eq!(current_moderators[0].moderator.id, new_mod.id);
|
||||||
|
|
||||||
Person::delete(&mut context.pool(), old_mod.id)
|
Person::delete(&mut context.pool(), old_mod.id).await?;
|
||||||
.await
|
Person::delete(&mut context.pool(), new_mod.id).await?;
|
||||||
.unwrap();
|
Community::delete(&mut context.pool(), community.id).await?;
|
||||||
Person::delete(&mut context.pool(), new_mod.id)
|
Site::delete(&mut context.pool(), site.id).await?;
|
||||||
.await
|
Instance::delete(&mut context.pool(), inserted_instance.id).await?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
Community::delete(&mut context.pool(), community.id)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
Site::delete(&mut context.pool(), site.id).await.unwrap();
|
|
||||||
Instance::delete(&mut context.pool(), inserted_instance.id)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::http::{
|
||||||
person::{get_apub_person_http, get_apub_person_outbox, person_inbox},
|
person::{get_apub_person_http, get_apub_person_outbox, person_inbox},
|
||||||
post::get_apub_post,
|
post::get_apub_post,
|
||||||
shared_inbox,
|
shared_inbox,
|
||||||
site::{get_apub_site_http, get_apub_site_inbox, get_apub_site_outbox},
|
site::{get_apub_site_http, get_apub_site_outbox},
|
||||||
};
|
};
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
guard::{Guard, GuardContext},
|
guard::{Guard, GuardContext},
|
||||||
|
@ -58,8 +58,7 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||||
.guard(InboxRequestGuard)
|
.guard(InboxRequestGuard)
|
||||||
.route("/c/{community_name}/inbox", web::post().to(community_inbox))
|
.route("/c/{community_name}/inbox", web::post().to(community_inbox))
|
||||||
.route("/u/{user_name}/inbox", web::post().to(person_inbox))
|
.route("/u/{user_name}/inbox", web::post().to(person_inbox))
|
||||||
.route("/inbox", web::post().to(shared_inbox))
|
.route("/inbox", web::post().to(shared_inbox)),
|
||||||
.route("/site_inbox", web::post().to(get_apub_site_inbox)),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
activity_lists::SiteInboxActivities,
|
|
||||||
http::create_apub_response,
|
http::create_apub_response,
|
||||||
objects::{instance::ApubSite, person::ApubPerson},
|
objects::instance::ApubSite,
|
||||||
protocol::collections::empty_outbox::EmptyOutbox,
|
protocol::collections::empty_outbox::EmptyOutbox,
|
||||||
};
|
};
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{config::Data, traits::Object};
|
||||||
actix_web::inbox::receive_activity,
|
use actix_web::HttpResponse;
|
||||||
config::Data,
|
|
||||||
protocol::context::WithContext,
|
|
||||||
traits::Object,
|
|
||||||
};
|
|
||||||
use actix_web::{web::Bytes, HttpRequest, HttpResponse};
|
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_db_views::structs::SiteView;
|
use lemmy_db_views::structs::SiteView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::LemmyError;
|
||||||
|
@ -36,15 +30,3 @@ pub(crate) async fn get_apub_site_outbox(
|
||||||
let outbox = EmptyOutbox::new(Url::parse(&outbox_id)?)?;
|
let outbox = EmptyOutbox::new(Url::parse(&outbox_id)?)?;
|
||||||
create_apub_response(&outbox)
|
create_apub_response(&outbox)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
|
||||||
pub async fn get_apub_site_inbox(
|
|
||||||
request: HttpRequest,
|
|
||||||
body: Bytes,
|
|
||||||
data: Data<LemmyContext>,
|
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
|
||||||
receive_activity::<WithContext<SiteInboxActivities>, ApubPerson, LemmyContext>(
|
|
||||||
request, body, &data,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use crate::fetcher::post_or_comment::PostOrComment;
|
use crate::fetcher::post_or_comment::PostOrComment;
|
||||||
use activitypub_federation::config::{Data, UrlVerifier};
|
use activitypub_federation::{
|
||||||
use anyhow::anyhow;
|
config::{Data, UrlVerifier},
|
||||||
|
error::Error as ActivityPubError,
|
||||||
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
@ -39,7 +41,7 @@ pub struct VerifyUrlData(pub ActualDbPool);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl UrlVerifier for VerifyUrlData {
|
impl UrlVerifier for VerifyUrlData {
|
||||||
async fn verify(&self, url: &Url) -> Result<(), anyhow::Error> {
|
async fn verify(&self, url: &Url) -> Result<(), ActivityPubError> {
|
||||||
let local_site_data = local_site_data_cached(&mut (&self.0).into())
|
let local_site_data = local_site_data_cached(&mut (&self.0).into())
|
||||||
.await
|
.await
|
||||||
.expect("read local site data");
|
.expect("read local site data");
|
||||||
|
@ -47,16 +49,16 @@ impl UrlVerifier for VerifyUrlData {
|
||||||
LemmyError {
|
LemmyError {
|
||||||
error_type: LemmyErrorType::FederationDisabled,
|
error_type: LemmyErrorType::FederationDisabled,
|
||||||
..
|
..
|
||||||
} => anyhow!("Federation disabled"),
|
} => ActivityPubError::Other("Federation disabled".into()),
|
||||||
LemmyError {
|
LemmyError {
|
||||||
error_type: LemmyErrorType::DomainBlocked(domain),
|
error_type: LemmyErrorType::DomainBlocked(domain),
|
||||||
..
|
..
|
||||||
} => anyhow!("Domain {domain:?} is blocked"),
|
} => ActivityPubError::Other(format!("Domain {domain:?} is blocked")),
|
||||||
LemmyError {
|
LemmyError {
|
||||||
error_type: LemmyErrorType::DomainNotInAllowList(domain),
|
error_type: LemmyErrorType::DomainNotInAllowList(domain),
|
||||||
..
|
..
|
||||||
} => anyhow!("Domain {domain:?} is not in allowlist"),
|
} => ActivityPubError::Other(format!("Domain {domain:?} is not in allowlist")),
|
||||||
_ => anyhow!("Failed validating apub id"),
|
_ => ActivityPubError::Other("Failed validating apub id".into()),
|
||||||
})?;
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,9 +186,6 @@ impl Object for ApubComment {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{
|
objects::{
|
||||||
|
@ -202,46 +199,45 @@ pub(crate) mod tests {
|
||||||
use assert_json_diff::assert_json_include;
|
use assert_json_diff::assert_json_include;
|
||||||
use html2md::parse_html;
|
use html2md::parse_html;
|
||||||
use lemmy_db_schema::source::site::Site;
|
use lemmy_db_schema::source::site::Site;
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
async fn prepare_comment_test(
|
async fn prepare_comment_test(
|
||||||
url: &Url,
|
url: &Url,
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
) -> (ApubPerson, ApubCommunity, ApubPost, ApubSite) {
|
) -> LemmyResult<(ApubPerson, ApubCommunity, ApubPost, ApubSite)> {
|
||||||
// use separate counter so this doesnt affect tests
|
// use separate counter so this doesnt affect tests
|
||||||
let context2 = context.reset_request_count();
|
let context2 = context.reset_request_count();
|
||||||
let (person, site) = parse_lemmy_person(&context2).await;
|
let (person, site) = parse_lemmy_person(&context2).await?;
|
||||||
let community = parse_lemmy_community(&context2).await;
|
let community = parse_lemmy_community(&context2).await?;
|
||||||
let post_json = file_to_json_object("assets/lemmy/objects/page.json").unwrap();
|
let post_json = file_to_json_object("assets/lemmy/objects/page.json")?;
|
||||||
ApubPost::verify(&post_json, url, &context2).await.unwrap();
|
ApubPost::verify(&post_json, url, &context2).await?;
|
||||||
let post = ApubPost::from_json(post_json, &context2).await.unwrap();
|
let post = ApubPost::from_json(post_json, &context2).await?;
|
||||||
(person, community, post, site)
|
Ok((person, community, post, site))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn cleanup(data: (ApubPerson, ApubCommunity, ApubPost, ApubSite), context: &LemmyContext) {
|
async fn cleanup(
|
||||||
Post::delete(&mut context.pool(), data.2.id).await.unwrap();
|
data: (ApubPerson, ApubCommunity, ApubPost, ApubSite),
|
||||||
Community::delete(&mut context.pool(), data.1.id)
|
context: &LemmyContext,
|
||||||
.await
|
) -> LemmyResult<()> {
|
||||||
.unwrap();
|
Post::delete(&mut context.pool(), data.2.id).await?;
|
||||||
Person::delete(&mut context.pool(), data.0.id)
|
Community::delete(&mut context.pool(), data.1.id).await?;
|
||||||
.await
|
Person::delete(&mut context.pool(), data.0.id).await?;
|
||||||
.unwrap();
|
Site::delete(&mut context.pool(), data.3.id).await?;
|
||||||
Site::delete(&mut context.pool(), data.3.id).await.unwrap();
|
LocalSite::delete(&mut context.pool()).await?;
|
||||||
LocalSite::delete(&mut context.pool()).await.unwrap();
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
pub(crate) async fn test_parse_lemmy_comment() {
|
pub(crate) async fn test_parse_lemmy_comment() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
let url = Url::parse("https://enterprise.lemmy.ml/comment/38741").unwrap();
|
let url = Url::parse("https://enterprise.lemmy.ml/comment/38741")?;
|
||||||
let data = prepare_comment_test(&url, &context).await;
|
let data = prepare_comment_test(&url, &context).await?;
|
||||||
|
|
||||||
let json: Note = file_to_json_object("assets/lemmy/objects/note.json").unwrap();
|
let json: Note = file_to_json_object("assets/lemmy/objects/note.json")?;
|
||||||
ApubComment::verify(&json, &url, &context).await.unwrap();
|
ApubComment::verify(&json, &url, &context).await?;
|
||||||
let comment = ApubComment::from_json(json.clone(), &context)
|
let comment = ApubComment::from_json(json.clone(), &context).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(comment.ap_id, url.into());
|
assert_eq!(comment.ap_id, url.into());
|
||||||
assert_eq!(comment.content.len(), 14);
|
assert_eq!(comment.content.len(), 14);
|
||||||
|
@ -249,45 +245,38 @@ pub(crate) mod tests {
|
||||||
assert_eq!(context.request_count(), 0);
|
assert_eq!(context.request_count(), 0);
|
||||||
|
|
||||||
let comment_id = comment.id;
|
let comment_id = comment.id;
|
||||||
let to_apub = comment.into_json(&context).await.unwrap();
|
let to_apub = comment.into_json(&context).await?;
|
||||||
assert_json_include!(actual: json, expected: to_apub);
|
assert_json_include!(actual: json, expected: to_apub);
|
||||||
|
|
||||||
Comment::delete(&mut context.pool(), comment_id)
|
Comment::delete(&mut context.pool(), comment_id).await?;
|
||||||
.await
|
cleanup(data, &context).await?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
cleanup(data, &context).await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_parse_pleroma_comment() {
|
async fn test_parse_pleroma_comment() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
let url = Url::parse("https://enterprise.lemmy.ml/comment/38741").unwrap();
|
let url = Url::parse("https://enterprise.lemmy.ml/comment/38741")?;
|
||||||
let data = prepare_comment_test(&url, &context).await;
|
let data = prepare_comment_test(&url, &context).await?;
|
||||||
|
|
||||||
let pleroma_url =
|
let pleroma_url =
|
||||||
Url::parse("https://queer.hacktivis.me/objects/8d4973f4-53de-49cd-8c27-df160e16a9c2")
|
Url::parse("https://queer.hacktivis.me/objects/8d4973f4-53de-49cd-8c27-df160e16a9c2")?;
|
||||||
.unwrap();
|
let person_json = file_to_json_object("assets/pleroma/objects/person.json")?;
|
||||||
let person_json = file_to_json_object("assets/pleroma/objects/person.json").unwrap();
|
ApubPerson::verify(&person_json, &pleroma_url, &context).await?;
|
||||||
ApubPerson::verify(&person_json, &pleroma_url, &context)
|
ApubPerson::from_json(person_json, &context).await?;
|
||||||
.await
|
let json = file_to_json_object("assets/pleroma/objects/note.json")?;
|
||||||
.unwrap();
|
ApubComment::verify(&json, &pleroma_url, &context).await?;
|
||||||
ApubPerson::from_json(person_json, &context).await.unwrap();
|
let comment = ApubComment::from_json(json, &context).await?;
|
||||||
let json = file_to_json_object("assets/pleroma/objects/note.json").unwrap();
|
|
||||||
ApubComment::verify(&json, &pleroma_url, &context)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let comment = ApubComment::from_json(json, &context).await.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(comment.ap_id, pleroma_url.into());
|
assert_eq!(comment.ap_id, pleroma_url.into());
|
||||||
assert_eq!(comment.content.len(), 64);
|
assert_eq!(comment.content.len(), 64);
|
||||||
assert!(!comment.local);
|
assert!(!comment.local);
|
||||||
assert_eq!(context.request_count(), 1);
|
assert_eq!(context.request_count(), 1);
|
||||||
|
|
||||||
Comment::delete(&mut context.pool(), comment.id)
|
Comment::delete(&mut context.pool(), comment.id).await?;
|
||||||
.await
|
cleanup(data, &context).await?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
cleanup(data, &context).await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -256,9 +256,6 @@ impl ApubCommunity {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::instance::tests::parse_lemmy_instance,
|
objects::instance::tests::parse_lemmy_instance,
|
||||||
|
@ -266,41 +263,44 @@ pub(crate) mod tests {
|
||||||
};
|
};
|
||||||
use activitypub_federation::fetch::collection_id::CollectionId;
|
use activitypub_federation::fetch::collection_id::CollectionId;
|
||||||
use lemmy_db_schema::{source::site::Site, traits::Crud};
|
use lemmy_db_schema::{source::site::Site, traits::Crud};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
pub(crate) async fn parse_lemmy_community(context: &Data<LemmyContext>) -> ApubCommunity {
|
pub(crate) async fn parse_lemmy_community(
|
||||||
|
context: &Data<LemmyContext>,
|
||||||
|
) -> LemmyResult<ApubCommunity> {
|
||||||
// use separate counter so this doesnt affect tests
|
// use separate counter so this doesnt affect tests
|
||||||
let context2 = context.reset_request_count();
|
let context2 = context.reset_request_count();
|
||||||
let mut json: Group = file_to_json_object("assets/lemmy/objects/group.json").unwrap();
|
let mut json: Group = file_to_json_object("assets/lemmy/objects/group.json")?;
|
||||||
// change these links so they dont fetch over the network
|
// change these links so they dont fetch over the network
|
||||||
json.attributed_to = None;
|
json.attributed_to = None;
|
||||||
json.outbox =
|
json.outbox = CollectionId::parse("https://enterprise.lemmy.ml/c/tenforward/not_outbox")?;
|
||||||
CollectionId::parse("https://enterprise.lemmy.ml/c/tenforward/not_outbox").unwrap();
|
json.followers = CollectionId::parse("https://enterprise.lemmy.ml/c/tenforward/not_followers")?;
|
||||||
json.followers =
|
|
||||||
CollectionId::parse("https://enterprise.lemmy.ml/c/tenforward/not_followers").unwrap();
|
|
||||||
|
|
||||||
let url = Url::parse("https://enterprise.lemmy.ml/c/tenforward").unwrap();
|
let url = Url::parse("https://enterprise.lemmy.ml/c/tenforward")?;
|
||||||
ApubCommunity::verify(&json, &url, &context2).await.unwrap();
|
ApubCommunity::verify(&json, &url, &context2).await?;
|
||||||
let community = ApubCommunity::from_json(json, &context2).await.unwrap();
|
let community = ApubCommunity::from_json(json, &context2).await?;
|
||||||
// this makes requests to the (intentionally broken) outbox and followers collections
|
// this makes requests to the (intentionally broken) outbox and followers collections
|
||||||
assert_eq!(context2.request_count(), 2);
|
assert_eq!(context2.request_count(), 2);
|
||||||
community
|
Ok(community)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_parse_lemmy_community() {
|
async fn test_parse_lemmy_community() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
let site = parse_lemmy_instance(&context).await;
|
let site = parse_lemmy_instance(&context).await?;
|
||||||
let community = parse_lemmy_community(&context).await;
|
let community = parse_lemmy_community(&context).await?;
|
||||||
|
|
||||||
assert_eq!(community.title, "Ten Forward");
|
assert_eq!(community.title, "Ten Forward");
|
||||||
assert!(!community.local);
|
assert!(!community.local);
|
||||||
assert_eq!(community.description.as_ref().unwrap().len(), 132);
|
assert_eq!(
|
||||||
|
community.description.as_ref().map(std::string::String::len),
|
||||||
|
Some(132)
|
||||||
|
);
|
||||||
|
|
||||||
Community::delete(&mut context.pool(), community.id)
|
Community::delete(&mut context.pool(), community.id).await?;
|
||||||
.await
|
Site::delete(&mut context.pool(), site.id).await?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
Site::delete(&mut context.pool(), site.id).await.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,32 +214,34 @@ pub(in crate::objects) async fn fetch_instance_actor_for_object<T: Into<Url> + C
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::protocol::tests::file_to_json_object;
|
use crate::protocol::tests::file_to_json_object;
|
||||||
use lemmy_db_schema::traits::Crud;
|
use lemmy_db_schema::traits::Crud;
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
pub(crate) async fn parse_lemmy_instance(context: &Data<LemmyContext>) -> ApubSite {
|
pub(crate) async fn parse_lemmy_instance(context: &Data<LemmyContext>) -> LemmyResult<ApubSite> {
|
||||||
let json: Instance = file_to_json_object("assets/lemmy/objects/instance.json").unwrap();
|
let json: Instance = file_to_json_object("assets/lemmy/objects/instance.json")?;
|
||||||
let id = Url::parse("https://enterprise.lemmy.ml/").unwrap();
|
let id = Url::parse("https://enterprise.lemmy.ml/")?;
|
||||||
ApubSite::verify(&json, &id, context).await.unwrap();
|
ApubSite::verify(&json, &id, context).await?;
|
||||||
let site = ApubSite::from_json(json, context).await.unwrap();
|
let site = ApubSite::from_json(json, context).await?;
|
||||||
assert_eq!(context.request_count(), 0);
|
assert_eq!(context.request_count(), 0);
|
||||||
site
|
Ok(site)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_parse_lemmy_instance() {
|
async fn test_parse_lemmy_instance() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
let site = parse_lemmy_instance(&context).await;
|
let site = parse_lemmy_instance(&context).await?;
|
||||||
|
|
||||||
assert_eq!(site.name, "Enterprise");
|
assert_eq!(site.name, "Enterprise");
|
||||||
assert_eq!(site.description.as_ref().unwrap().len(), 15);
|
assert_eq!(
|
||||||
|
site.description.as_ref().map(std::string::String::len),
|
||||||
|
Some(15)
|
||||||
|
);
|
||||||
|
|
||||||
Site::delete(&mut context.pool(), site.id).await.unwrap();
|
Site::delete(&mut context.pool(), site.id).await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,9 +219,6 @@ impl GetActorType for ApubPerson {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::instance::{tests::parse_lemmy_instance, ApubSite},
|
objects::instance::{tests::parse_lemmy_instance, ApubSite},
|
||||||
|
@ -229,60 +226,64 @@ pub(crate) mod tests {
|
||||||
};
|
};
|
||||||
use activitypub_federation::fetch::object_id::ObjectId;
|
use activitypub_federation::fetch::object_id::ObjectId;
|
||||||
use lemmy_db_schema::{source::site::Site, traits::Crud};
|
use lemmy_db_schema::{source::site::Site, traits::Crud};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
pub(crate) async fn parse_lemmy_person(context: &Data<LemmyContext>) -> (ApubPerson, ApubSite) {
|
pub(crate) async fn parse_lemmy_person(
|
||||||
let site = parse_lemmy_instance(context).await;
|
context: &Data<LemmyContext>,
|
||||||
let json = file_to_json_object("assets/lemmy/objects/person.json").unwrap();
|
) -> LemmyResult<(ApubPerson, ApubSite)> {
|
||||||
let url = Url::parse("https://enterprise.lemmy.ml/u/picard").unwrap();
|
let site = parse_lemmy_instance(context).await?;
|
||||||
ApubPerson::verify(&json, &url, context).await.unwrap();
|
let json = file_to_json_object("assets/lemmy/objects/person.json")?;
|
||||||
let person = ApubPerson::from_json(json, context).await.unwrap();
|
let url = Url::parse("https://enterprise.lemmy.ml/u/picard")?;
|
||||||
|
ApubPerson::verify(&json, &url, context).await?;
|
||||||
|
let person = ApubPerson::from_json(json, context).await?;
|
||||||
assert_eq!(context.request_count(), 0);
|
assert_eq!(context.request_count(), 0);
|
||||||
(person, site)
|
Ok((person, site))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_parse_lemmy_person() {
|
async fn test_parse_lemmy_person() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
let (person, site) = parse_lemmy_person(&context).await;
|
let (person, site) = parse_lemmy_person(&context).await?;
|
||||||
|
|
||||||
assert_eq!(person.display_name, Some("Jean-Luc Picard".to_string()));
|
assert_eq!(person.display_name, Some("Jean-Luc Picard".to_string()));
|
||||||
assert!(!person.local);
|
assert!(!person.local);
|
||||||
assert_eq!(person.bio.as_ref().unwrap().len(), 39);
|
assert_eq!(person.bio.as_ref().map(std::string::String::len), Some(39));
|
||||||
|
|
||||||
cleanup((person, site), &context).await;
|
cleanup((person, site), &context).await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_parse_pleroma_person() {
|
async fn test_parse_pleroma_person() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
|
|
||||||
// create and parse a fake pleroma instance actor, to avoid network request during test
|
// create and parse a fake pleroma instance actor, to avoid network request during test
|
||||||
let mut json: Instance = file_to_json_object("assets/lemmy/objects/instance.json").unwrap();
|
let mut json: Instance = file_to_json_object("assets/lemmy/objects/instance.json")?;
|
||||||
json.id = ObjectId::parse("https://queer.hacktivis.me/").unwrap();
|
json.id = ObjectId::parse("https://queer.hacktivis.me/")?;
|
||||||
let url = Url::parse("https://queer.hacktivis.me/users/lanodan").unwrap();
|
let url = Url::parse("https://queer.hacktivis.me/users/lanodan")?;
|
||||||
ApubSite::verify(&json, &url, &context).await.unwrap();
|
ApubSite::verify(&json, &url, &context).await?;
|
||||||
let site = ApubSite::from_json(json, &context).await.unwrap();
|
let site = ApubSite::from_json(json, &context).await?;
|
||||||
|
|
||||||
let json = file_to_json_object("assets/pleroma/objects/person.json").unwrap();
|
let json = file_to_json_object("assets/pleroma/objects/person.json")?;
|
||||||
ApubPerson::verify(&json, &url, &context).await.unwrap();
|
ApubPerson::verify(&json, &url, &context).await?;
|
||||||
let person = ApubPerson::from_json(json, &context).await.unwrap();
|
let person = ApubPerson::from_json(json, &context).await?;
|
||||||
|
|
||||||
assert_eq!(person.actor_id, url.into());
|
assert_eq!(person.actor_id, url.into());
|
||||||
assert_eq!(person.name, "lanodan");
|
assert_eq!(person.name, "lanodan");
|
||||||
assert!(!person.local);
|
assert!(!person.local);
|
||||||
assert_eq!(context.request_count(), 0);
|
assert_eq!(context.request_count(), 0);
|
||||||
assert_eq!(person.bio.as_ref().unwrap().len(), 873);
|
assert_eq!(person.bio.as_ref().map(std::string::String::len), Some(873));
|
||||||
|
|
||||||
cleanup((person, site), &context).await;
|
cleanup((person, site), &context).await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn cleanup(data: (ApubPerson, ApubSite), context: &LemmyContext) {
|
async fn cleanup(data: (ApubPerson, ApubSite), context: &LemmyContext) -> LemmyResult<()> {
|
||||||
DbPerson::delete(&mut context.pool(), data.0.id)
|
DbPerson::delete(&mut context.pool(), data.0.id).await?;
|
||||||
.await
|
Site::delete(&mut context.pool(), data.1.id).await?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
Site::delete(&mut context.pool(), data.1.id).await.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,9 +290,6 @@ impl Object for ApubPost {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{
|
objects::{
|
||||||
|
@ -304,44 +301,47 @@ mod tests {
|
||||||
protocol::tests::file_to_json_object,
|
protocol::tests::file_to_json_object,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::source::site::Site;
|
use lemmy_db_schema::source::site::Site;
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_parse_lemmy_post() {
|
async fn test_parse_lemmy_post() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
let (person, site) = parse_lemmy_person(&context).await;
|
let (person, site) = parse_lemmy_person(&context).await?;
|
||||||
let community = parse_lemmy_community(&context).await;
|
let community = parse_lemmy_community(&context).await?;
|
||||||
|
|
||||||
let json = file_to_json_object("assets/lemmy/objects/page.json").unwrap();
|
let json = file_to_json_object("assets/lemmy/objects/page.json")?;
|
||||||
let url = Url::parse("https://enterprise.lemmy.ml/post/55143").unwrap();
|
let url = Url::parse("https://enterprise.lemmy.ml/post/55143")?;
|
||||||
ApubPost::verify(&json, &url, &context).await.unwrap();
|
ApubPost::verify(&json, &url, &context).await?;
|
||||||
let post = ApubPost::from_json(json, &context).await.unwrap();
|
let post = ApubPost::from_json(json, &context).await?;
|
||||||
|
|
||||||
assert_eq!(post.ap_id, url.into());
|
assert_eq!(post.ap_id, url.into());
|
||||||
assert_eq!(post.name, "Post title");
|
assert_eq!(post.name, "Post title");
|
||||||
assert!(post.body.is_some());
|
assert!(post.body.is_some());
|
||||||
assert_eq!(post.body.as_ref().unwrap().len(), 45);
|
assert_eq!(post.body.as_ref().map(std::string::String::len), Some(45));
|
||||||
assert!(!post.locked);
|
assert!(!post.locked);
|
||||||
assert!(!post.featured_community);
|
assert!(!post.featured_community);
|
||||||
assert_eq!(context.request_count(), 0);
|
assert_eq!(context.request_count(), 0);
|
||||||
|
|
||||||
cleanup(&context, person, site, community, post).await;
|
cleanup(&context, person, site, community, post).await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_convert_mastodon_post_title() {
|
async fn test_convert_mastodon_post_title() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
let (person, site) = parse_lemmy_person(&context).await;
|
let (person, site) = parse_lemmy_person(&context).await?;
|
||||||
let community = parse_lemmy_community(&context).await;
|
let community = parse_lemmy_community(&context).await?;
|
||||||
|
|
||||||
let json = file_to_json_object("assets/mastodon/objects/page.json").unwrap();
|
let json = file_to_json_object("assets/mastodon/objects/page.json")?;
|
||||||
let post = ApubPost::from_json(json, &context).await.unwrap();
|
let post = ApubPost::from_json(json, &context).await?;
|
||||||
|
|
||||||
assert_eq!(post.name, "Variable never resetting at refresh");
|
assert_eq!(post.name, "Variable never resetting at refresh");
|
||||||
|
|
||||||
cleanup(&context, person, site, community, post).await;
|
cleanup(&context, person, site, community, post).await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn cleanup(
|
async fn cleanup(
|
||||||
|
@ -350,14 +350,11 @@ mod tests {
|
||||||
site: ApubSite,
|
site: ApubSite,
|
||||||
community: ApubCommunity,
|
community: ApubCommunity,
|
||||||
post: ApubPost,
|
post: ApubPost,
|
||||||
) {
|
) -> LemmyResult<()> {
|
||||||
Post::delete(&mut context.pool(), post.id).await.unwrap();
|
Post::delete(&mut context.pool(), post.id).await?;
|
||||||
Person::delete(&mut context.pool(), person.id)
|
Person::delete(&mut context.pool(), person.id).await?;
|
||||||
.await
|
Community::delete(&mut context.pool(), community.id).await?;
|
||||||
.unwrap();
|
Site::delete(&mut context.pool(), site.id).await?;
|
||||||
Community::delete(&mut context.pool(), community.id)
|
Ok(())
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
Site::delete(&mut context.pool(), site.id).await.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,9 +148,6 @@ impl Object for ApubPrivateMessage {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{
|
objects::{
|
||||||
|
@ -161,90 +158,75 @@ mod tests {
|
||||||
};
|
};
|
||||||
use assert_json_diff::assert_json_include;
|
use assert_json_diff::assert_json_include;
|
||||||
use lemmy_db_schema::source::site::Site;
|
use lemmy_db_schema::source::site::Site;
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
async fn prepare_comment_test(
|
async fn prepare_comment_test(
|
||||||
url: &Url,
|
url: &Url,
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
) -> (ApubPerson, ApubPerson, ApubSite) {
|
) -> LemmyResult<(ApubPerson, ApubPerson, ApubSite)> {
|
||||||
let context2 = context.reset_request_count();
|
let context2 = context.reset_request_count();
|
||||||
let lemmy_person = file_to_json_object("assets/lemmy/objects/person.json").unwrap();
|
let lemmy_person = file_to_json_object("assets/lemmy/objects/person.json")?;
|
||||||
let site = parse_lemmy_instance(&context2).await;
|
let site = parse_lemmy_instance(&context2).await?;
|
||||||
ApubPerson::verify(&lemmy_person, url, &context2)
|
ApubPerson::verify(&lemmy_person, url, &context2).await?;
|
||||||
.await
|
let person1 = ApubPerson::from_json(lemmy_person, &context2).await?;
|
||||||
.unwrap();
|
let pleroma_person = file_to_json_object("assets/pleroma/objects/person.json")?;
|
||||||
let person1 = ApubPerson::from_json(lemmy_person, &context2)
|
let pleroma_url = Url::parse("https://queer.hacktivis.me/users/lanodan")?;
|
||||||
.await
|
ApubPerson::verify(&pleroma_person, &pleroma_url, &context2).await?;
|
||||||
.unwrap();
|
let person2 = ApubPerson::from_json(pleroma_person, &context2).await?;
|
||||||
let pleroma_person = file_to_json_object("assets/pleroma/objects/person.json").unwrap();
|
Ok((person1, person2, site))
|
||||||
let pleroma_url = Url::parse("https://queer.hacktivis.me/users/lanodan").unwrap();
|
|
||||||
ApubPerson::verify(&pleroma_person, &pleroma_url, &context2)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let person2 = ApubPerson::from_json(pleroma_person, &context2)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
(person1, person2, site)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn cleanup(data: (ApubPerson, ApubPerson, ApubSite), context: &Data<LemmyContext>) {
|
async fn cleanup(
|
||||||
Person::delete(&mut context.pool(), data.0.id)
|
data: (ApubPerson, ApubPerson, ApubSite),
|
||||||
.await
|
context: &Data<LemmyContext>,
|
||||||
.unwrap();
|
) -> LemmyResult<()> {
|
||||||
Person::delete(&mut context.pool(), data.1.id)
|
Person::delete(&mut context.pool(), data.0.id).await?;
|
||||||
.await
|
Person::delete(&mut context.pool(), data.1.id).await?;
|
||||||
.unwrap();
|
Site::delete(&mut context.pool(), data.2.id).await?;
|
||||||
Site::delete(&mut context.pool(), data.2.id).await.unwrap();
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_parse_lemmy_pm() {
|
async fn test_parse_lemmy_pm() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
let url = Url::parse("https://enterprise.lemmy.ml/private_message/1621").unwrap();
|
let url = Url::parse("https://enterprise.lemmy.ml/private_message/1621")?;
|
||||||
let data = prepare_comment_test(&url, &context).await;
|
let data = prepare_comment_test(&url, &context).await?;
|
||||||
let json: ChatMessage = file_to_json_object("assets/lemmy/objects/chat_message.json").unwrap();
|
let json: ChatMessage = file_to_json_object("assets/lemmy/objects/chat_message.json")?;
|
||||||
ApubPrivateMessage::verify(&json, &url, &context)
|
ApubPrivateMessage::verify(&json, &url, &context).await?;
|
||||||
.await
|
let pm = ApubPrivateMessage::from_json(json.clone(), &context).await?;
|
||||||
.unwrap();
|
|
||||||
let pm = ApubPrivateMessage::from_json(json.clone(), &context)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(pm.ap_id.clone(), url.into());
|
assert_eq!(pm.ap_id.clone(), url.into());
|
||||||
assert_eq!(pm.content.len(), 20);
|
assert_eq!(pm.content.len(), 20);
|
||||||
assert_eq!(context.request_count(), 0);
|
assert_eq!(context.request_count(), 0);
|
||||||
|
|
||||||
let pm_id = pm.id;
|
let pm_id = pm.id;
|
||||||
let to_apub = pm.into_json(&context).await.unwrap();
|
let to_apub = pm.into_json(&context).await?;
|
||||||
assert_json_include!(actual: json, expected: to_apub);
|
assert_json_include!(actual: json, expected: to_apub);
|
||||||
|
|
||||||
PrivateMessage::delete(&mut context.pool(), pm_id)
|
PrivateMessage::delete(&mut context.pool(), pm_id).await?;
|
||||||
.await
|
cleanup(data, &context).await?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
cleanup(data, &context).await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_parse_pleroma_pm() {
|
async fn test_parse_pleroma_pm() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
let url = Url::parse("https://enterprise.lemmy.ml/private_message/1621").unwrap();
|
let url = Url::parse("https://enterprise.lemmy.ml/private_message/1621")?;
|
||||||
let data = prepare_comment_test(&url, &context).await;
|
let data = prepare_comment_test(&url, &context).await?;
|
||||||
let pleroma_url = Url::parse("https://queer.hacktivis.me/objects/2").unwrap();
|
let pleroma_url = Url::parse("https://queer.hacktivis.me/objects/2")?;
|
||||||
let json = file_to_json_object("assets/pleroma/objects/chat_message.json").unwrap();
|
let json = file_to_json_object("assets/pleroma/objects/chat_message.json")?;
|
||||||
ApubPrivateMessage::verify(&json, &pleroma_url, &context)
|
ApubPrivateMessage::verify(&json, &pleroma_url, &context).await?;
|
||||||
.await
|
let pm = ApubPrivateMessage::from_json(json, &context).await?;
|
||||||
.unwrap();
|
|
||||||
let pm = ApubPrivateMessage::from_json(json, &context).await.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(pm.ap_id, pleroma_url.into());
|
assert_eq!(pm.ap_id, pleroma_url.into());
|
||||||
assert_eq!(pm.content.len(), 3);
|
assert_eq!(pm.content.len(), 3);
|
||||||
assert_eq!(context.request_count(), 0);
|
assert_eq!(context.request_count(), 0);
|
||||||
|
|
||||||
PrivateMessage::delete(&mut context.pool(), pm.id)
|
PrivateMessage::delete(&mut context.pool(), pm.id).await?;
|
||||||
.await
|
cleanup(data, &context).await?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
cleanup(data, &context).await;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,16 @@ pub mod undo_block_user;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
|
activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
|
||||||
tests::test_parse_lemmy_item,
|
tests::test_parse_lemmy_item,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_lemmy_block() {
|
fn test_parse_lemmy_block() -> LemmyResult<()> {
|
||||||
test_parse_lemmy_item::<BlockUser>("assets/lemmy/activities/block/block_user.json").unwrap();
|
test_parse_lemmy_item::<BlockUser>("assets/lemmy/activities/block/block_user.json")?;
|
||||||
test_parse_lemmy_item::<UndoBlockUser>("assets/lemmy/activities/block/undo_block_user.json")
|
test_parse_lemmy_item::<UndoBlockUser>("assets/lemmy/activities/block/undo_block_user.json")?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,6 @@ pub mod update;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
activities::community::{
|
activities::community::{
|
||||||
announce::AnnounceActivity,
|
announce::AnnounceActivity,
|
||||||
|
@ -21,37 +18,32 @@ mod tests {
|
||||||
},
|
},
|
||||||
tests::test_parse_lemmy_item,
|
tests::test_parse_lemmy_item,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_lemmy_community_activities() {
|
fn test_parse_lemmy_community_activities() -> LemmyResult<()> {
|
||||||
test_parse_lemmy_item::<AnnounceActivity>(
|
test_parse_lemmy_item::<AnnounceActivity>(
|
||||||
"assets/lemmy/activities/community/announce_create_page.json",
|
"assets/lemmy/activities/community/announce_create_page.json",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
test_parse_lemmy_item::<CollectionAdd>("assets/lemmy/activities/community/add_mod.json")
|
test_parse_lemmy_item::<CollectionAdd>("assets/lemmy/activities/community/add_mod.json")?;
|
||||||
.unwrap();
|
test_parse_lemmy_item::<CollectionRemove>("assets/lemmy/activities/community/remove_mod.json")?;
|
||||||
test_parse_lemmy_item::<CollectionRemove>("assets/lemmy/activities/community/remove_mod.json")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
test_parse_lemmy_item::<CollectionAdd>(
|
test_parse_lemmy_item::<CollectionAdd>(
|
||||||
"assets/lemmy/activities/community/add_featured_post.json",
|
"assets/lemmy/activities/community/add_featured_post.json",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
test_parse_lemmy_item::<CollectionRemove>(
|
test_parse_lemmy_item::<CollectionRemove>(
|
||||||
"assets/lemmy/activities/community/remove_featured_post.json",
|
"assets/lemmy/activities/community/remove_featured_post.json",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
test_parse_lemmy_item::<LockPage>("assets/lemmy/activities/community/lock_page.json").unwrap();
|
test_parse_lemmy_item::<LockPage>("assets/lemmy/activities/community/lock_page.json")?;
|
||||||
test_parse_lemmy_item::<UndoLockPage>("assets/lemmy/activities/community/undo_lock_page.json")
|
test_parse_lemmy_item::<UndoLockPage>("assets/lemmy/activities/community/undo_lock_page.json")?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
test_parse_lemmy_item::<UpdateCommunity>(
|
test_parse_lemmy_item::<UpdateCommunity>(
|
||||||
"assets/lemmy/activities/community/update_community.json",
|
"assets/lemmy/activities/community/update_community.json",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
test_parse_lemmy_item::<Report>("assets/lemmy/activities/community/report_page.json").unwrap();
|
test_parse_lemmy_item::<Report>("assets/lemmy/activities/community/report_page.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,6 @@ pub mod page;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
activities::create_or_update::{
|
activities::create_or_update::{
|
||||||
chat_message::CreateOrUpdateChatMessage,
|
chat_message::CreateOrUpdateChatMessage,
|
||||||
|
@ -15,24 +12,22 @@ mod tests {
|
||||||
},
|
},
|
||||||
tests::test_parse_lemmy_item,
|
tests::test_parse_lemmy_item,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_lemmy_create_or_update() {
|
fn test_parse_lemmy_create_or_update() -> LemmyResult<()> {
|
||||||
test_parse_lemmy_item::<CreateOrUpdatePage>(
|
test_parse_lemmy_item::<CreateOrUpdatePage>(
|
||||||
"assets/lemmy/activities/create_or_update/create_page.json",
|
"assets/lemmy/activities/create_or_update/create_page.json",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
test_parse_lemmy_item::<CreateOrUpdatePage>(
|
test_parse_lemmy_item::<CreateOrUpdatePage>(
|
||||||
"assets/lemmy/activities/create_or_update/update_page.json",
|
"assets/lemmy/activities/create_or_update/update_page.json",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
test_parse_lemmy_item::<CreateOrUpdateNote>(
|
test_parse_lemmy_item::<CreateOrUpdateNote>(
|
||||||
"assets/lemmy/activities/create_or_update/create_note.json",
|
"assets/lemmy/activities/create_or_update/create_note.json",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
test_parse_lemmy_item::<CreateOrUpdateChatMessage>(
|
test_parse_lemmy_item::<CreateOrUpdateChatMessage>(
|
||||||
"assets/lemmy/activities/create_or_update/create_private_message.json",
|
"assets/lemmy/activities/create_or_update/create_private_message.json",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,9 @@ pub struct Delete {
|
||||||
/// If summary is present, this is a mod action (Remove in Lemmy terms). Otherwise, its a user
|
/// If summary is present, this is a mod action (Remove in Lemmy terms). Otherwise, its a user
|
||||||
/// deleting their own content.
|
/// deleting their own content.
|
||||||
pub(crate) summary: Option<String>,
|
pub(crate) summary: Option<String>,
|
||||||
|
/// Nonstandard field, only valid if object refers to a Person. If present, all content from the
|
||||||
|
/// user should be deleted along with the account
|
||||||
|
pub(crate) remove_data: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
@ -52,6 +55,7 @@ impl InCommunity for Delete {
|
||||||
post.community_id
|
post.community_id
|
||||||
}
|
}
|
||||||
DeletableObjects::Post(p) => p.community_id,
|
DeletableObjects::Post(p) => p.community_id,
|
||||||
|
DeletableObjects::Person(_) => return Err(anyhow!("Person is not part of community").into()),
|
||||||
DeletableObjects::PrivateMessage(_) => {
|
DeletableObjects::PrivateMessage(_) => {
|
||||||
return Err(anyhow!("Private message is not part of community").into())
|
return Err(anyhow!("Private message is not part of community").into())
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,31 +4,27 @@ pub mod undo_delete;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
activities::deletion::{delete::Delete, delete_user::DeleteUser, undo_delete::UndoDelete},
|
activities::deletion::{delete::Delete, delete_user::DeleteUser, undo_delete::UndoDelete},
|
||||||
tests::test_parse_lemmy_item,
|
tests::test_parse_lemmy_item,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_lemmy_deletion() {
|
fn test_parse_lemmy_deletion() -> LemmyResult<()> {
|
||||||
test_parse_lemmy_item::<Delete>("assets/lemmy/activities/deletion/remove_note.json").unwrap();
|
test_parse_lemmy_item::<Delete>("assets/lemmy/activities/deletion/remove_note.json")?;
|
||||||
test_parse_lemmy_item::<Delete>("assets/lemmy/activities/deletion/delete_page.json").unwrap();
|
test_parse_lemmy_item::<Delete>("assets/lemmy/activities/deletion/delete_page.json")?;
|
||||||
|
|
||||||
test_parse_lemmy_item::<UndoDelete>("assets/lemmy/activities/deletion/undo_remove_note.json")
|
test_parse_lemmy_item::<UndoDelete>("assets/lemmy/activities/deletion/undo_remove_note.json")?;
|
||||||
.unwrap();
|
test_parse_lemmy_item::<UndoDelete>("assets/lemmy/activities/deletion/undo_delete_page.json")?;
|
||||||
test_parse_lemmy_item::<UndoDelete>("assets/lemmy/activities/deletion/undo_delete_page.json")
|
test_parse_lemmy_item::<Delete>(
|
||||||
.unwrap();
|
"assets/lemmy/activities/deletion/delete_private_message.json",
|
||||||
test_parse_lemmy_item::<Delete>("assets/lemmy/activities/deletion/delete_private_message.json")
|
)?;
|
||||||
.unwrap();
|
|
||||||
test_parse_lemmy_item::<UndoDelete>(
|
test_parse_lemmy_item::<UndoDelete>(
|
||||||
"assets/lemmy/activities/deletion/undo_delete_private_message.json",
|
"assets/lemmy/activities/deletion/undo_delete_private_message.json",
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
test_parse_lemmy_item::<DeleteUser>("assets/lemmy/activities/deletion/delete_user.json")
|
test_parse_lemmy_item::<DeleteUser>("assets/lemmy/activities/deletion/delete_user.json")?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,19 +4,17 @@ pub mod undo_follow;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
activities::following::{accept::AcceptFollow, follow::Follow, undo_follow::UndoFollow},
|
activities::following::{accept::AcceptFollow, follow::Follow, undo_follow::UndoFollow},
|
||||||
tests::test_parse_lemmy_item,
|
tests::test_parse_lemmy_item,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_lemmy_accept_follow() {
|
fn test_parse_lemmy_accept_follow() -> LemmyResult<()> {
|
||||||
test_parse_lemmy_item::<Follow>("assets/lemmy/activities/following/follow.json").unwrap();
|
test_parse_lemmy_item::<Follow>("assets/lemmy/activities/following/follow.json")?;
|
||||||
test_parse_lemmy_item::<AcceptFollow>("assets/lemmy/activities/following/accept.json").unwrap();
|
test_parse_lemmy_item::<AcceptFollow>("assets/lemmy/activities/following/accept.json")?;
|
||||||
test_parse_lemmy_item::<UndoFollow>("assets/lemmy/activities/following/undo_follow.json")
|
test_parse_lemmy_item::<UndoFollow>("assets/lemmy/activities/following/undo_follow.json")?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,6 @@ pub enum CreateOrUpdateType {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
activities::{
|
activities::{
|
||||||
community::announce::AnnounceActivity,
|
community::announce::AnnounceActivity,
|
||||||
|
@ -29,58 +26,66 @@ mod tests {
|
||||||
},
|
},
|
||||||
tests::test_json,
|
tests::test_json,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_smithereen_activities() {
|
fn test_parse_smithereen_activities() -> LemmyResult<()> {
|
||||||
test_json::<CreateOrUpdateNote>("assets/smithereen/activities/create_note.json").unwrap();
|
test_json::<CreateOrUpdateNote>("assets/smithereen/activities/create_note.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_pleroma_activities() {
|
fn test_parse_pleroma_activities() -> LemmyResult<()> {
|
||||||
test_json::<CreateOrUpdateNote>("assets/pleroma/activities/create_note.json").unwrap();
|
test_json::<CreateOrUpdateNote>("assets/pleroma/activities/create_note.json")?;
|
||||||
test_json::<Delete>("assets/pleroma/activities/delete.json").unwrap();
|
test_json::<Delete>("assets/pleroma/activities/delete.json")?;
|
||||||
test_json::<Follow>("assets/pleroma/activities/follow.json").unwrap();
|
test_json::<Follow>("assets/pleroma/activities/follow.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_mastodon_activities() {
|
fn test_parse_mastodon_activities() -> LemmyResult<()> {
|
||||||
test_json::<CreateOrUpdateNote>("assets/mastodon/activities/create_note.json").unwrap();
|
test_json::<CreateOrUpdateNote>("assets/mastodon/activities/create_note.json")?;
|
||||||
test_json::<Delete>("assets/mastodon/activities/delete.json").unwrap();
|
test_json::<Delete>("assets/mastodon/activities/delete.json")?;
|
||||||
test_json::<Follow>("assets/mastodon/activities/follow.json").unwrap();
|
test_json::<Follow>("assets/mastodon/activities/follow.json")?;
|
||||||
test_json::<UndoFollow>("assets/mastodon/activities/undo_follow.json").unwrap();
|
test_json::<UndoFollow>("assets/mastodon/activities/undo_follow.json")?;
|
||||||
test_json::<Vote>("assets/mastodon/activities/like_page.json").unwrap();
|
test_json::<Vote>("assets/mastodon/activities/like_page.json")?;
|
||||||
test_json::<UndoVote>("assets/mastodon/activities/undo_like_page.json").unwrap();
|
test_json::<UndoVote>("assets/mastodon/activities/undo_like_page.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_lotide_activities() {
|
fn test_parse_lotide_activities() -> LemmyResult<()> {
|
||||||
test_json::<Follow>("assets/lotide/activities/follow.json").unwrap();
|
test_json::<Follow>("assets/lotide/activities/follow.json")?;
|
||||||
test_json::<CreateOrUpdatePage>("assets/lotide/activities/create_page.json").unwrap();
|
test_json::<CreateOrUpdatePage>("assets/lotide/activities/create_page.json")?;
|
||||||
test_json::<CreateOrUpdatePage>("assets/lotide/activities/create_page_image.json").unwrap();
|
test_json::<CreateOrUpdatePage>("assets/lotide/activities/create_page_image.json")?;
|
||||||
test_json::<CreateOrUpdateNote>("assets/lotide/activities/create_note_reply.json").unwrap();
|
test_json::<CreateOrUpdateNote>("assets/lotide/activities/create_note_reply.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_friendica_activities() {
|
fn test_parse_friendica_activities() -> LemmyResult<()> {
|
||||||
test_json::<CreateOrUpdatePage>("assets/friendica/activities/create_page_1.json").unwrap();
|
test_json::<CreateOrUpdatePage>("assets/friendica/activities/create_page_1.json")?;
|
||||||
test_json::<CreateOrUpdatePage>("assets/friendica/activities/create_page_2.json").unwrap();
|
test_json::<CreateOrUpdatePage>("assets/friendica/activities/create_page_2.json")?;
|
||||||
test_json::<CreateOrUpdateNote>("assets/friendica/activities/create_note.json").unwrap();
|
test_json::<CreateOrUpdateNote>("assets/friendica/activities/create_note.json")?;
|
||||||
test_json::<CreateOrUpdateNote>("assets/friendica/activities/update_note.json").unwrap();
|
test_json::<CreateOrUpdateNote>("assets/friendica/activities/update_note.json")?;
|
||||||
test_json::<Delete>("assets/friendica/activities/delete.json").unwrap();
|
test_json::<Delete>("assets/friendica/activities/delete.json")?;
|
||||||
test_json::<Vote>("assets/friendica/activities/like_page.json").unwrap();
|
test_json::<Vote>("assets/friendica/activities/like_page.json")?;
|
||||||
test_json::<Vote>("assets/friendica/activities/dislike_page.json").unwrap();
|
test_json::<Vote>("assets/friendica/activities/dislike_page.json")?;
|
||||||
test_json::<UndoVote>("assets/friendica/activities/undo_dislike_page.json").unwrap();
|
test_json::<UndoVote>("assets/friendica/activities/undo_dislike_page.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_gnusocial_activities() {
|
fn test_parse_gnusocial_activities() -> LemmyResult<()> {
|
||||||
test_json::<CreateOrUpdatePage>("assets/gnusocial/activities/create_page.json").unwrap();
|
test_json::<CreateOrUpdatePage>("assets/gnusocial/activities/create_page.json")?;
|
||||||
test_json::<CreateOrUpdateNote>("assets/gnusocial/activities/create_note.json").unwrap();
|
test_json::<CreateOrUpdateNote>("assets/gnusocial/activities/create_note.json")?;
|
||||||
test_json::<Vote>("assets/gnusocial/activities/like_note.json").unwrap();
|
test_json::<Vote>("assets/gnusocial/activities/like_note.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_peertube_activities() {
|
fn test_parse_peertube_activities() -> LemmyResult<()> {
|
||||||
test_json::<AnnounceActivity>("assets/peertube/activities/announce_video.json").unwrap();
|
test_json::<AnnounceActivity>("assets/peertube/activities/announce_video.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,22 +3,19 @@ pub mod vote;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
activities::voting::{undo_vote::UndoVote, vote::Vote},
|
activities::voting::{undo_vote::UndoVote, vote::Vote},
|
||||||
tests::test_parse_lemmy_item,
|
tests::test_parse_lemmy_item,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_lemmy_voting() {
|
fn test_parse_lemmy_voting() -> LemmyResult<()> {
|
||||||
test_parse_lemmy_item::<Vote>("assets/lemmy/activities/voting/like_note.json").unwrap();
|
test_parse_lemmy_item::<Vote>("assets/lemmy/activities/voting/like_note.json")?;
|
||||||
test_parse_lemmy_item::<Vote>("assets/lemmy/activities/voting/dislike_page.json").unwrap();
|
test_parse_lemmy_item::<Vote>("assets/lemmy/activities/voting/dislike_page.json")?;
|
||||||
|
|
||||||
test_parse_lemmy_item::<UndoVote>("assets/lemmy/activities/voting/undo_like_note.json")
|
test_parse_lemmy_item::<UndoVote>("assets/lemmy/activities/voting/undo_like_note.json")?;
|
||||||
.unwrap();
|
test_parse_lemmy_item::<UndoVote>("assets/lemmy/activities/voting/undo_dislike_page.json")?;
|
||||||
test_parse_lemmy_item::<UndoVote>("assets/lemmy/activities/voting/undo_dislike_page.json")
|
Ok(())
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,6 @@ pub(crate) mod group_outbox;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
collections::{
|
collections::{
|
||||||
empty_outbox::EmptyOutbox,
|
empty_outbox::EmptyOutbox,
|
||||||
|
@ -19,23 +16,23 @@ mod tests {
|
||||||
},
|
},
|
||||||
tests::{test_json, test_parse_lemmy_item},
|
tests::{test_json, test_parse_lemmy_item},
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_lemmy_collections() {
|
fn test_parse_lemmy_collections() -> LemmyResult<()> {
|
||||||
test_parse_lemmy_item::<GroupFollowers>("assets/lemmy/collections/group_followers.json")
|
test_parse_lemmy_item::<GroupFollowers>("assets/lemmy/collections/group_followers.json")?;
|
||||||
.unwrap();
|
|
||||||
let outbox =
|
let outbox =
|
||||||
test_parse_lemmy_item::<GroupOutbox>("assets/lemmy/collections/group_outbox.json").unwrap();
|
test_parse_lemmy_item::<GroupOutbox>("assets/lemmy/collections/group_outbox.json")?;
|
||||||
assert_eq!(outbox.ordered_items.len() as i32, outbox.total_items);
|
assert_eq!(outbox.ordered_items.len() as i32, outbox.total_items);
|
||||||
test_parse_lemmy_item::<GroupFeatured>("assets/lemmy/collections/group_featured_posts.json")
|
test_parse_lemmy_item::<GroupFeatured>("assets/lemmy/collections/group_featured_posts.json")?;
|
||||||
.unwrap();
|
test_parse_lemmy_item::<GroupModerators>("assets/lemmy/collections/group_moderators.json")?;
|
||||||
test_parse_lemmy_item::<GroupModerators>("assets/lemmy/collections/group_moderators.json")
|
test_parse_lemmy_item::<EmptyOutbox>("assets/lemmy/collections/person_outbox.json")?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
test_parse_lemmy_item::<EmptyOutbox>("assets/lemmy/collections/person_outbox.json").unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_mastodon_collections() {
|
fn test_parse_mastodon_collections() -> LemmyResult<()> {
|
||||||
test_json::<GroupFeatured>("assets/mastodon/collections/featured.json").unwrap();
|
test_json::<GroupFeatured>("assets/mastodon/collections/featured.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,9 +89,6 @@ pub trait InCommunity {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use activitypub_federation::protocol::context::WithContext;
|
use activitypub_federation::protocol::context::WithContext;
|
||||||
use assert_json_diff::assert_json_include;
|
use assert_json_diff::assert_json_include;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::LemmyError;
|
||||||
|
|
|
@ -95,9 +95,6 @@ impl LanguageTag {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
objects::{
|
objects::{
|
||||||
chat_message::ChatMessage,
|
chat_message::ChatMessage,
|
||||||
|
@ -110,77 +107,87 @@ mod tests {
|
||||||
},
|
},
|
||||||
tests::{test_json, test_parse_lemmy_item},
|
tests::{test_json, test_parse_lemmy_item},
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_objects_lemmy() {
|
fn test_parse_objects_lemmy() -> LemmyResult<()> {
|
||||||
test_parse_lemmy_item::<Instance>("assets/lemmy/objects/instance.json").unwrap();
|
test_parse_lemmy_item::<Instance>("assets/lemmy/objects/instance.json")?;
|
||||||
test_parse_lemmy_item::<Group>("assets/lemmy/objects/group.json").unwrap();
|
test_parse_lemmy_item::<Group>("assets/lemmy/objects/group.json")?;
|
||||||
test_parse_lemmy_item::<Person>("assets/lemmy/objects/person.json").unwrap();
|
test_parse_lemmy_item::<Person>("assets/lemmy/objects/person.json")?;
|
||||||
test_parse_lemmy_item::<Page>("assets/lemmy/objects/page.json").unwrap();
|
test_parse_lemmy_item::<Page>("assets/lemmy/objects/page.json")?;
|
||||||
test_parse_lemmy_item::<Note>("assets/lemmy/objects/note.json").unwrap();
|
test_parse_lemmy_item::<Note>("assets/lemmy/objects/note.json")?;
|
||||||
test_parse_lemmy_item::<ChatMessage>("assets/lemmy/objects/chat_message.json").unwrap();
|
test_parse_lemmy_item::<ChatMessage>("assets/lemmy/objects/chat_message.json")?;
|
||||||
test_parse_lemmy_item::<Tombstone>("assets/lemmy/objects/tombstone.json").unwrap();
|
test_parse_lemmy_item::<Tombstone>("assets/lemmy/objects/tombstone.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_objects_pleroma() {
|
fn test_parse_objects_pleroma() -> LemmyResult<()> {
|
||||||
test_json::<Person>("assets/pleroma/objects/person.json").unwrap();
|
test_json::<Person>("assets/pleroma/objects/person.json")?;
|
||||||
test_json::<Note>("assets/pleroma/objects/note.json").unwrap();
|
test_json::<Note>("assets/pleroma/objects/note.json")?;
|
||||||
test_json::<ChatMessage>("assets/pleroma/objects/chat_message.json").unwrap();
|
test_json::<ChatMessage>("assets/pleroma/objects/chat_message.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_objects_smithereen() {
|
fn test_parse_objects_smithereen() -> LemmyResult<()> {
|
||||||
test_json::<Person>("assets/smithereen/objects/person.json").unwrap();
|
test_json::<Person>("assets/smithereen/objects/person.json")?;
|
||||||
test_json::<Note>("assets/smithereen/objects/note.json").unwrap();
|
test_json::<Note>("assets/smithereen/objects/note.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_objects_mastodon() {
|
fn test_parse_objects_mastodon() -> LemmyResult<()> {
|
||||||
test_json::<Person>("assets/mastodon/objects/person.json").unwrap();
|
test_json::<Person>("assets/mastodon/objects/person.json")?;
|
||||||
test_json::<Note>("assets/mastodon/objects/note.json").unwrap();
|
test_json::<Note>("assets/mastodon/objects/note.json")?;
|
||||||
test_json::<Page>("assets/mastodon/objects/page.json").unwrap();
|
test_json::<Page>("assets/mastodon/objects/page.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_objects_lotide() {
|
fn test_parse_objects_lotide() -> LemmyResult<()> {
|
||||||
test_json::<Group>("assets/lotide/objects/group.json").unwrap();
|
test_json::<Group>("assets/lotide/objects/group.json")?;
|
||||||
test_json::<Person>("assets/lotide/objects/person.json").unwrap();
|
test_json::<Person>("assets/lotide/objects/person.json")?;
|
||||||
test_json::<Note>("assets/lotide/objects/note.json").unwrap();
|
test_json::<Note>("assets/lotide/objects/note.json")?;
|
||||||
test_json::<Page>("assets/lotide/objects/page.json").unwrap();
|
test_json::<Page>("assets/lotide/objects/page.json")?;
|
||||||
test_json::<Tombstone>("assets/lotide/objects/tombstone.json").unwrap();
|
test_json::<Tombstone>("assets/lotide/objects/tombstone.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_object_friendica() {
|
fn test_parse_object_friendica() -> LemmyResult<()> {
|
||||||
test_json::<Person>("assets/friendica/objects/person_1.json").unwrap();
|
test_json::<Person>("assets/friendica/objects/person_1.json")?;
|
||||||
test_json::<Person>("assets/friendica/objects/person_2.json").unwrap();
|
test_json::<Person>("assets/friendica/objects/person_2.json")?;
|
||||||
test_json::<Page>("assets/friendica/objects/page_1.json").unwrap();
|
test_json::<Page>("assets/friendica/objects/page_1.json")?;
|
||||||
test_json::<Page>("assets/friendica/objects/page_2.json").unwrap();
|
test_json::<Page>("assets/friendica/objects/page_2.json")?;
|
||||||
test_json::<Note>("assets/friendica/objects/note_1.json").unwrap();
|
test_json::<Note>("assets/friendica/objects/note_1.json")?;
|
||||||
test_json::<Note>("assets/friendica/objects/note_2.json").unwrap();
|
test_json::<Note>("assets/friendica/objects/note_2.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_object_gnusocial() {
|
fn test_parse_object_gnusocial() -> LemmyResult<()> {
|
||||||
test_json::<Person>("assets/gnusocial/objects/person.json").unwrap();
|
test_json::<Person>("assets/gnusocial/objects/person.json")?;
|
||||||
test_json::<Group>("assets/gnusocial/objects/group.json").unwrap();
|
test_json::<Group>("assets/gnusocial/objects/group.json")?;
|
||||||
test_json::<Page>("assets/gnusocial/objects/page.json").unwrap();
|
test_json::<Page>("assets/gnusocial/objects/page.json")?;
|
||||||
test_json::<Note>("assets/gnusocial/objects/note.json").unwrap();
|
test_json::<Note>("assets/gnusocial/objects/note.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_object_peertube() {
|
fn test_parse_object_peertube() -> LemmyResult<()> {
|
||||||
test_json::<Person>("assets/peertube/objects/person.json").unwrap();
|
test_json::<Person>("assets/peertube/objects/person.json")?;
|
||||||
test_json::<Group>("assets/peertube/objects/group.json").unwrap();
|
test_json::<Group>("assets/peertube/objects/group.json")?;
|
||||||
test_json::<Page>("assets/peertube/objects/video.json").unwrap();
|
test_json::<Page>("assets/peertube/objects/video.json")?;
|
||||||
test_json::<Note>("assets/peertube/objects/note.json").unwrap();
|
test_json::<Note>("assets/peertube/objects/note.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_object_mobilizon() {
|
fn test_parse_object_mobilizon() -> LemmyResult<()> {
|
||||||
test_json::<Group>("assets/mobilizon/objects/group.json").unwrap();
|
test_json::<Group>("assets/mobilizon/objects/group.json")?;
|
||||||
test_json::<Page>("assets/mobilizon/objects/event.json").unwrap();
|
test_json::<Page>("assets/mobilizon/objects/event.json")?;
|
||||||
test_json::<Person>("assets/mobilizon/objects/person.json").unwrap();
|
test_json::<Person>("assets/mobilizon/objects/person.json")?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,9 +252,6 @@ where
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
|
||||||
#![allow(clippy::indexing_slicing)]
|
|
||||||
|
|
||||||
use crate::protocol::{objects::page::Page, tests::test_parse_lemmy_item};
|
use crate::protocol::{objects::page::Page, tests::test_parse_lemmy_item};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -13,6 +13,9 @@ name = "lemmy_db_schema"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
full = [
|
full = [
|
||||||
"diesel",
|
"diesel",
|
||||||
|
|
|
@ -11,7 +11,7 @@ impl CommentAggregates {
|
||||||
pub async fn read(pool: &mut DbPool<'_>, comment_id: CommentId) -> Result<Self, Error> {
|
pub async fn read(pool: &mut DbPool<'_>, comment_id: CommentId) -> Result<Self, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
comment_aggregates::table
|
comment_aggregates::table
|
||||||
.filter(comment_aggregates::comment_id.eq(comment_id))
|
.find(comment_id)
|
||||||
.first::<Self>(conn)
|
.first::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,7 @@ impl CommentAggregates {
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
|
||||||
diesel::update(comment_aggregates::table)
|
diesel::update(comment_aggregates::table.find(comment_id))
|
||||||
.filter(comment_aggregates::comment_id.eq(comment_id))
|
|
||||||
.set(comment_aggregates::hot_rank.eq(hot_rank(
|
.set(comment_aggregates::hot_rank.eq(hot_rank(
|
||||||
comment_aggregates::score,
|
comment_aggregates::score,
|
||||||
comment_aggregates::published,
|
comment_aggregates::published,
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
aggregates::structs::CommunityAggregates,
|
aggregates::structs::CommunityAggregates,
|
||||||
newtypes::CommunityId,
|
newtypes::CommunityId,
|
||||||
schema::{
|
schema::{community_aggregates, community_aggregates::subscribers},
|
||||||
community_aggregates,
|
|
||||||
community_aggregates::{community_id, subscribers},
|
|
||||||
},
|
|
||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
use diesel::{result::Error, ExpressionMethods, QueryDsl};
|
use diesel::{result::Error, ExpressionMethods, QueryDsl};
|
||||||
|
@ -14,7 +11,7 @@ impl CommunityAggregates {
|
||||||
pub async fn read(pool: &mut DbPool<'_>, for_community_id: CommunityId) -> Result<Self, Error> {
|
pub async fn read(pool: &mut DbPool<'_>, for_community_id: CommunityId) -> Result<Self, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
community_aggregates::table
|
community_aggregates::table
|
||||||
.filter(community_id.eq(for_community_id))
|
.find(for_community_id)
|
||||||
.first::<Self>(conn)
|
.first::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -26,7 +23,7 @@ impl CommunityAggregates {
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
let new_subscribers: i64 = new_subscribers.into();
|
let new_subscribers: i64 = new_subscribers.into();
|
||||||
diesel::update(community_aggregates::table.filter(community_id.eq(for_community_id)))
|
diesel::update(community_aggregates::table.find(for_community_id))
|
||||||
.set(subscribers.eq(new_subscribers))
|
.set(subscribers.eq(new_subscribers))
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -4,14 +4,14 @@ use crate::{
|
||||||
schema::person_aggregates,
|
schema::person_aggregates,
|
||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
use diesel::{result::Error, ExpressionMethods, QueryDsl};
|
use diesel::{result::Error, QueryDsl};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
|
|
||||||
impl PersonAggregates {
|
impl PersonAggregates {
|
||||||
pub async fn read(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<Self, Error> {
|
pub async fn read(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<Self, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
person_aggregates::table
|
person_aggregates::table
|
||||||
.filter(person_aggregates::person_id.eq(person_id))
|
.find(person_id)
|
||||||
.first::<Self>(conn)
|
.first::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm},
|
aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm},
|
||||||
diesel::BoolExpressionMethods,
|
|
||||||
newtypes::{PersonId, PostId},
|
newtypes::{PersonId, PostId},
|
||||||
schema::person_post_aggregates::dsl::{person_id, person_post_aggregates, post_id},
|
schema::person_post_aggregates::dsl::{person_id, person_post_aggregates, post_id},
|
||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
use diesel::{insert_into, result::Error, ExpressionMethods, QueryDsl};
|
use diesel::{insert_into, result::Error, QueryDsl};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
|
|
||||||
impl PersonPostAggregates {
|
impl PersonPostAggregates {
|
||||||
|
@ -29,7 +28,7 @@ impl PersonPostAggregates {
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
person_post_aggregates
|
person_post_aggregates
|
||||||
.filter(post_id.eq(post_id_).and(person_id.eq(person_id_)))
|
.find((person_id_, post_id_))
|
||||||
.first::<Self>(conn)
|
.first::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ impl PostAggregates {
|
||||||
pub async fn read(pool: &mut DbPool<'_>, post_id: PostId) -> Result<Self, Error> {
|
pub async fn read(pool: &mut DbPool<'_>, post_id: PostId) -> Result<Self, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
post_aggregates::table
|
post_aggregates::table
|
||||||
.filter(post_aggregates::post_id.eq(post_id))
|
.find(post_id)
|
||||||
.first::<Self>(conn)
|
.first::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -33,8 +33,7 @@ impl PostAggregates {
|
||||||
.first::<i64>(conn)
|
.first::<i64>(conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
diesel::update(post_aggregates::table)
|
diesel::update(post_aggregates::table.find(post_id))
|
||||||
.filter(post_aggregates::post_id.eq(post_id))
|
|
||||||
.set((
|
.set((
|
||||||
post_aggregates::hot_rank.eq(hot_rank(post_aggregates::score, post_aggregates::published)),
|
post_aggregates::hot_rank.eq(hot_rank(post_aggregates::score, post_aggregates::published)),
|
||||||
post_aggregates::hot_rank_active.eq(hot_rank(
|
post_aggregates::hot_rank_active.eq(hot_rank(
|
||||||
|
|
|
@ -13,13 +13,17 @@ use serde::{Deserialize, Serialize};
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
use ts_rs::TS;
|
use ts_rs::TS;
|
||||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
|
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable, TS))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Queryable, Selectable, Associations, Identifiable, TS)
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = comment_aggregates))]
|
#[cfg_attr(feature = "full", diesel(table_name = comment_aggregates))]
|
||||||
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
|
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(comment_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// Aggregate data for a comment.
|
/// Aggregate data for a comment.
|
||||||
pub struct CommentAggregates {
|
pub struct CommentAggregates {
|
||||||
pub id: i32,
|
|
||||||
pub comment_id: CommentId,
|
pub comment_id: CommentId,
|
||||||
pub score: i64,
|
pub score: i64,
|
||||||
pub upvotes: i64,
|
pub upvotes: i64,
|
||||||
|
@ -34,16 +38,19 @@ pub struct CommentAggregates {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
|
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable, TS))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Queryable, Selectable, Associations, Identifiable, TS)
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = community_aggregates))]
|
#[cfg_attr(feature = "full", diesel(table_name = community_aggregates))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "full",
|
feature = "full",
|
||||||
diesel(belongs_to(crate::source::community::Community))
|
diesel(belongs_to(crate::source::community::Community))
|
||||||
)]
|
)]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(community_id)))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// Aggregate data for a community.
|
/// Aggregate data for a community.
|
||||||
pub struct CommunityAggregates {
|
pub struct CommunityAggregates {
|
||||||
pub id: i32,
|
|
||||||
pub community_id: CommunityId,
|
pub community_id: CommunityId,
|
||||||
pub subscribers: i64,
|
pub subscribers: i64,
|
||||||
pub posts: i64,
|
pub posts: i64,
|
||||||
|
@ -62,13 +69,17 @@ pub struct CommunityAggregates {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone, Default)]
|
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone, Default)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable, TS))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Queryable, Selectable, Associations, Identifiable, TS)
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = person_aggregates))]
|
#[cfg_attr(feature = "full", diesel(table_name = person_aggregates))]
|
||||||
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::person::Person)))]
|
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::person::Person)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(person_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// Aggregate data for a person.
|
/// Aggregate data for a person.
|
||||||
pub struct PersonAggregates {
|
pub struct PersonAggregates {
|
||||||
pub id: i32,
|
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
pub post_count: i64,
|
pub post_count: i64,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
|
@ -79,13 +90,17 @@ pub struct PersonAggregates {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
|
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable, TS))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Queryable, Selectable, Associations, Identifiable, TS)
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = post_aggregates))]
|
#[cfg_attr(feature = "full", diesel(table_name = post_aggregates))]
|
||||||
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::post::Post)))]
|
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::post::Post)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(post_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// Aggregate data for a post.
|
/// Aggregate data for a post.
|
||||||
pub struct PostAggregates {
|
pub struct PostAggregates {
|
||||||
pub id: i32,
|
|
||||||
pub post_id: PostId,
|
pub post_id: PostId,
|
||||||
pub comments: i64,
|
pub comments: i64,
|
||||||
pub score: i64,
|
pub score: i64,
|
||||||
|
@ -122,12 +137,16 @@ pub struct PostAggregates {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
|
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Queryable, Selectable, Associations, Identifiable)
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = person_post_aggregates))]
|
#[cfg_attr(feature = "full", diesel(table_name = person_post_aggregates))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(person_id, post_id)))]
|
||||||
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::person::Person)))]
|
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::person::Person)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
/// Aggregate data for a person's post.
|
/// Aggregate data for a person's post.
|
||||||
pub struct PersonPostAggregates {
|
pub struct PersonPostAggregates {
|
||||||
pub id: i32,
|
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
pub post_id: PostId,
|
pub post_id: PostId,
|
||||||
/// The number of comments they've read on that post.
|
/// The number of comments they've read on that post.
|
||||||
|
@ -148,13 +167,17 @@ pub struct PersonPostAggregatesForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
|
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable, TS))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Queryable, Selectable, Associations, Identifiable, TS)
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = site_aggregates))]
|
#[cfg_attr(feature = "full", diesel(table_name = site_aggregates))]
|
||||||
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::site::Site)))]
|
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::site::Site)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(site_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// Aggregate data for a site.
|
/// Aggregate data for a site.
|
||||||
pub struct SiteAggregates {
|
pub struct SiteAggregates {
|
||||||
pub id: i32,
|
|
||||||
pub site_id: SiteId,
|
pub site_id: SiteId,
|
||||||
pub users: i64,
|
pub users: i64,
|
||||||
pub posts: i64,
|
pub posts: i64,
|
||||||
|
|
|
@ -39,16 +39,15 @@ impl SentActivity {
|
||||||
|
|
||||||
impl ReceivedActivity {
|
impl ReceivedActivity {
|
||||||
pub async fn create(pool: &mut DbPool<'_>, ap_id_: &DbUrl) -> Result<(), Error> {
|
pub async fn create(pool: &mut DbPool<'_>, ap_id_: &DbUrl) -> Result<(), Error> {
|
||||||
use crate::schema::received_activity::dsl::{ap_id, id, received_activity};
|
use crate::schema::received_activity::dsl::{ap_id, received_activity};
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
let res = insert_into(received_activity)
|
let rows_affected = insert_into(received_activity)
|
||||||
.values(ap_id.eq(ap_id_))
|
.values(ap_id.eq(ap_id_))
|
||||||
.on_conflict_do_nothing()
|
.on_conflict_do_nothing()
|
||||||
.returning(id)
|
.execute(conn)
|
||||||
.get_result::<i64>(conn)
|
|
||||||
.await
|
.await
|
||||||
.optional()?;
|
.optional()?;
|
||||||
if res.is_some() {
|
if rows_affected == Some(1) {
|
||||||
// new activity inserted successfully
|
// new activity inserted successfully
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -119,7 +119,7 @@ impl SiteLanguage {
|
||||||
site::table
|
site::table
|
||||||
.inner_join(local_site::table)
|
.inner_join(local_site::table)
|
||||||
.inner_join(site_language::table)
|
.inner_join(site_language::table)
|
||||||
.order(site_language::id)
|
.order(site_language::language_id)
|
||||||
.select(site_language::language_id)
|
.select(site_language::language_id)
|
||||||
.load(conn)
|
.load(conn)
|
||||||
.await
|
.await
|
||||||
|
@ -191,14 +191,12 @@ impl CommunityLanguage {
|
||||||
for_language_id: Option<LanguageId>,
|
for_language_id: Option<LanguageId>,
|
||||||
for_community_id: CommunityId,
|
for_community_id: CommunityId,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
use crate::schema::community_language::dsl::{community_id, community_language, language_id};
|
use crate::schema::community_language::dsl::community_language;
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
|
||||||
if let Some(for_language_id) = for_language_id {
|
if let Some(for_language_id) = for_language_id {
|
||||||
let is_allowed = select(exists(
|
let is_allowed = select(exists(
|
||||||
community_language
|
community_language.find((for_community_id, for_language_id)),
|
||||||
.filter(language_id.eq(for_language_id))
|
|
||||||
.filter(community_id.eq(for_community_id)),
|
|
||||||
))
|
))
|
||||||
.get_result(conn)
|
.get_result(conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
schema::captcha_answer::dsl::{answer, captcha_answer, uuid},
|
schema::captcha_answer::dsl::{answer, captcha_answer},
|
||||||
source::captcha_answer::{CaptchaAnswer, CaptchaAnswerForm, CheckCaptchaAnswer},
|
source::captcha_answer::{CaptchaAnswer, CaptchaAnswerForm, CheckCaptchaAnswer},
|
||||||
utils::{functions::lower, get_conn, DbPool},
|
utils::{functions::lower, get_conn, DbPool},
|
||||||
};
|
};
|
||||||
|
@ -31,16 +31,15 @@ impl CaptchaAnswer {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
|
||||||
// fetch requested captcha
|
// fetch requested captcha
|
||||||
let captcha_exists = select(exists(
|
let captcha_exists =
|
||||||
captcha_answer
|
select(exists(captcha_answer.find(to_check.uuid).filter(
|
||||||
.filter((uuid).eq(to_check.uuid))
|
lower(answer).eq(to_check.answer.to_lowercase().clone()),
|
||||||
.filter(lower(answer).eq(to_check.answer.to_lowercase().clone())),
|
)))
|
||||||
))
|
|
||||||
.get_result::<bool>(conn)
|
.get_result::<bool>(conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// delete checked captcha
|
// delete checked captcha
|
||||||
delete(captcha_answer.filter(uuid.eq(to_check.uuid)))
|
delete(captcha_answer.find(to_check.uuid))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -192,16 +192,12 @@ impl Likeable for CommentLike {
|
||||||
}
|
}
|
||||||
async fn remove(
|
async fn remove(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
person_id_: PersonId,
|
person_id: PersonId,
|
||||||
comment_id_: CommentId,
|
comment_id: CommentId,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
use crate::schema::comment_like::dsl::{comment_id, comment_like, person_id};
|
use crate::schema::comment_like::dsl::comment_like;
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(
|
diesel::delete(comment_like.find((person_id, comment_id)))
|
||||||
comment_like
|
|
||||||
.filter(comment_id.eq(comment_id_))
|
|
||||||
.filter(person_id.eq(person_id_)),
|
|
||||||
)
|
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -228,12 +224,10 @@ impl Saveable for CommentSaved {
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
comment_saved_form: &CommentSavedForm,
|
comment_saved_form: &CommentSavedForm,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
use crate::schema::comment_saved::dsl::{comment_id, comment_saved, person_id};
|
use crate::schema::comment_saved::dsl::comment_saved;
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(
|
diesel::delete(
|
||||||
comment_saved
|
comment_saved.find((comment_saved_form.person_id, comment_saved_form.comment_id)),
|
||||||
.filter(comment_id.eq(comment_saved_form.comment_id))
|
|
||||||
.filter(person_id.eq(comment_saved_form.person_id)),
|
|
||||||
)
|
)
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await
|
.await
|
||||||
|
@ -349,7 +343,6 @@ mod tests {
|
||||||
let inserted_comment_like = CommentLike::like(pool, &comment_like_form).await.unwrap();
|
let inserted_comment_like = CommentLike::like(pool, &comment_like_form).await.unwrap();
|
||||||
|
|
||||||
let expected_comment_like = CommentLike {
|
let expected_comment_like = CommentLike {
|
||||||
id: inserted_comment_like.id,
|
|
||||||
comment_id: inserted_comment.id,
|
comment_id: inserted_comment.id,
|
||||||
post_id: inserted_post.id,
|
post_id: inserted_post.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_person.id,
|
||||||
|
@ -366,7 +359,6 @@ mod tests {
|
||||||
let inserted_comment_saved = CommentSaved::save(pool, &comment_saved_form).await.unwrap();
|
let inserted_comment_saved = CommentSaved::save(pool, &comment_saved_form).await.unwrap();
|
||||||
|
|
||||||
let expected_comment_saved = CommentSaved {
|
let expected_comment_saved = CommentSaved {
|
||||||
id: inserted_comment_saved.id,
|
|
||||||
comment_id: inserted_comment.id,
|
comment_id: inserted_comment.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_person.id,
|
||||||
published: inserted_comment_saved.published,
|
published: inserted_comment_saved.published,
|
||||||
|
|
|
@ -95,13 +95,12 @@ impl Joinable for CommunityModerator {
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
community_moderator_form: &CommunityModeratorForm,
|
community_moderator_form: &CommunityModeratorForm,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
use crate::schema::community_moderator::dsl::{community_id, community_moderator, person_id};
|
use crate::schema::community_moderator::dsl::community_moderator;
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(
|
diesel::delete(community_moderator.find((
|
||||||
community_moderator
|
community_moderator_form.person_id,
|
||||||
.filter(community_id.eq(community_moderator_form.community_id))
|
community_moderator_form.community_id,
|
||||||
.filter(person_id.eq(community_moderator_form.person_id)),
|
)))
|
||||||
)
|
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -199,13 +198,12 @@ impl Bannable for CommunityPersonBan {
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
community_person_ban_form: &CommunityPersonBanForm,
|
community_person_ban_form: &CommunityPersonBanForm,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
use crate::schema::community_person_ban::dsl::{community_id, community_person_ban, person_id};
|
use crate::schema::community_person_ban::dsl::community_person_ban;
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(
|
diesel::delete(community_person_ban.find((
|
||||||
community_person_ban
|
community_person_ban_form.person_id,
|
||||||
.filter(community_id.eq(community_person_ban_form.community_id))
|
community_person_ban_form.community_id,
|
||||||
.filter(person_id.eq(community_person_ban_form.person_id)),
|
)))
|
||||||
)
|
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -274,33 +272,20 @@ impl Followable for CommunityFollower {
|
||||||
}
|
}
|
||||||
async fn follow_accepted(
|
async fn follow_accepted(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
community_id_: CommunityId,
|
community_id: CommunityId,
|
||||||
person_id_: PersonId,
|
person_id: PersonId,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
use crate::schema::community_follower::dsl::{
|
use crate::schema::community_follower::dsl::{community_follower, pending};
|
||||||
community_follower,
|
|
||||||
community_id,
|
|
||||||
pending,
|
|
||||||
person_id,
|
|
||||||
};
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::update(
|
diesel::update(community_follower.find((person_id, community_id)))
|
||||||
community_follower
|
|
||||||
.filter(community_id.eq(community_id_))
|
|
||||||
.filter(person_id.eq(person_id_)),
|
|
||||||
)
|
|
||||||
.set(pending.eq(false))
|
.set(pending.eq(false))
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
async fn unfollow(pool: &mut DbPool<'_>, form: &CommunityFollowerForm) -> Result<usize, Error> {
|
async fn unfollow(pool: &mut DbPool<'_>, form: &CommunityFollowerForm) -> Result<usize, Error> {
|
||||||
use crate::schema::community_follower::dsl::{community_follower, community_id, person_id};
|
use crate::schema::community_follower::dsl::community_follower;
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(
|
diesel::delete(community_follower.find((form.person_id, form.community_id)))
|
||||||
community_follower
|
|
||||||
.filter(community_id.eq(&form.community_id))
|
|
||||||
.filter(person_id.eq(&form.person_id)),
|
|
||||||
)
|
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -448,7 +433,6 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let expected_community_follower = CommunityFollower {
|
let expected_community_follower = CommunityFollower {
|
||||||
id: inserted_community_follower.id,
|
|
||||||
community_id: inserted_community.id,
|
community_id: inserted_community.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_person.id,
|
||||||
pending: false,
|
pending: false,
|
||||||
|
@ -465,7 +449,6 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let expected_community_moderator = CommunityModerator {
|
let expected_community_moderator = CommunityModerator {
|
||||||
id: inserted_community_moderator.id,
|
|
||||||
community_id: inserted_community.id,
|
community_id: inserted_community.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_person.id,
|
||||||
published: inserted_community_moderator.published,
|
published: inserted_community_moderator.published,
|
||||||
|
@ -482,7 +465,6 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let expected_community_person_ban = CommunityPersonBan {
|
let expected_community_person_ban = CommunityPersonBan {
|
||||||
id: inserted_community_person_ban.id,
|
|
||||||
community_id: inserted_community.id,
|
community_id: inserted_community.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_person.id,
|
||||||
published: inserted_community_person_ban.published,
|
published: inserted_community_person_ban.published,
|
||||||
|
|
|
@ -1,12 +1,33 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
newtypes::{CommunityId, PersonId},
|
||||||
schema::community_block::dsl::{community_block, community_id, person_id},
|
schema::community_block::dsl::{community_block, community_id, person_id},
|
||||||
source::community_block::{CommunityBlock, CommunityBlockForm},
|
source::community_block::{CommunityBlock, CommunityBlockForm},
|
||||||
traits::Blockable,
|
traits::Blockable,
|
||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
|
use diesel::{
|
||||||
|
dsl::{exists, insert_into},
|
||||||
|
result::Error,
|
||||||
|
select,
|
||||||
|
QueryDsl,
|
||||||
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
|
|
||||||
|
impl CommunityBlock {
|
||||||
|
pub async fn read(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
for_person_id: PersonId,
|
||||||
|
for_community_id: CommunityId,
|
||||||
|
) -> Result<bool, Error> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
select(exists(
|
||||||
|
community_block.find((for_person_id, for_community_id)),
|
||||||
|
))
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Blockable for CommunityBlock {
|
impl Blockable for CommunityBlock {
|
||||||
type Form = CommunityBlockForm;
|
type Form = CommunityBlockForm;
|
||||||
|
@ -25,11 +46,10 @@ impl Blockable for CommunityBlock {
|
||||||
community_block_form: &Self::Form,
|
community_block_form: &Self::Form,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(
|
diesel::delete(community_block.find((
|
||||||
community_block
|
community_block_form.person_id,
|
||||||
.filter(person_id.eq(community_block_form.person_id))
|
community_block_form.community_id,
|
||||||
.filter(community_id.eq(community_block_form.community_id)),
|
)))
|
||||||
)
|
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
newtypes::{DbUrl, LocalImageId, LocalUserId},
|
newtypes::{DbUrl, LocalUserId},
|
||||||
schema::{
|
schema::{
|
||||||
local_image::dsl::{local_image, local_user_id, pictrs_alias},
|
local_image::dsl::{local_image, local_user_id, pictrs_alias},
|
||||||
remote_image::dsl::{link, remote_image},
|
remote_image::dsl::{link, remote_image},
|
||||||
|
@ -41,16 +41,6 @@ impl LocalImage {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete(
|
|
||||||
pool: &mut DbPool<'_>,
|
|
||||||
image_upload_id: LocalImageId,
|
|
||||||
) -> Result<usize, Error> {
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
|
||||||
diesel::delete(local_image.find(image_upload_id))
|
|
||||||
.execute(conn)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn delete_by_alias(pool: &mut DbPool<'_>, alias: &str) -> Result<usize, Error> {
|
pub async fn delete_by_alias(pool: &mut DbPool<'_>, alias: &str) -> Result<usize, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(local_image.filter(pictrs_alias.eq(alias)))
|
diesel::delete(local_image.filter(pictrs_alias.eq(alias)))
|
||||||
|
|
|
@ -115,7 +115,7 @@ impl Instance {
|
||||||
.left_join(federation_allowlist::table)
|
.left_join(federation_allowlist::table)
|
||||||
.select((
|
.select((
|
||||||
Self::as_select(),
|
Self::as_select(),
|
||||||
federation_allowlist::id.nullable().is_not_null(),
|
federation_allowlist::instance_id.nullable().is_not_null(),
|
||||||
is_dead_expr,
|
is_dead_expr,
|
||||||
))
|
))
|
||||||
.order_by(instance::id)
|
.order_by(instance::id)
|
||||||
|
@ -126,7 +126,7 @@ impl Instance {
|
||||||
.left_join(federation_blocklist::table)
|
.left_join(federation_blocklist::table)
|
||||||
.select((
|
.select((
|
||||||
Self::as_select(),
|
Self::as_select(),
|
||||||
federation_blocklist::id.nullable().is_null(),
|
federation_blocklist::instance_id.nullable().is_null(),
|
||||||
is_dead_expr,
|
is_dead_expr,
|
||||||
))
|
))
|
||||||
.order_by(instance::id)
|
.order_by(instance::id)
|
||||||
|
@ -150,8 +150,8 @@ impl Instance {
|
||||||
.select((
|
.select((
|
||||||
Self::as_select(),
|
Self::as_select(),
|
||||||
Option::<FederationQueueState>::as_select(),
|
Option::<FederationQueueState>::as_select(),
|
||||||
federation_blocklist::id.nullable().is_not_null(),
|
federation_blocklist::instance_id.nullable().is_not_null(),
|
||||||
federation_allowlist::id.nullable().is_not_null(),
|
federation_allowlist::instance_id.nullable().is_not_null(),
|
||||||
))
|
))
|
||||||
.get_results(conn)
|
.get_results(conn)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -1,12 +1,33 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
newtypes::{InstanceId, PersonId},
|
||||||
schema::instance_block::dsl::{instance_block, instance_id, person_id},
|
schema::instance_block::dsl::{instance_block, instance_id, person_id},
|
||||||
source::instance_block::{InstanceBlock, InstanceBlockForm},
|
source::instance_block::{InstanceBlock, InstanceBlockForm},
|
||||||
traits::Blockable,
|
traits::Blockable,
|
||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
|
use diesel::{
|
||||||
|
dsl::{exists, insert_into},
|
||||||
|
result::Error,
|
||||||
|
select,
|
||||||
|
QueryDsl,
|
||||||
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
|
|
||||||
|
impl InstanceBlock {
|
||||||
|
pub async fn read(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
for_person_id: PersonId,
|
||||||
|
for_instance_id: InstanceId,
|
||||||
|
) -> Result<bool, Error> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
select(exists(
|
||||||
|
instance_block.find((for_person_id, for_instance_id)),
|
||||||
|
))
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Blockable for InstanceBlock {
|
impl Blockable for InstanceBlock {
|
||||||
type Form = InstanceBlockForm;
|
type Form = InstanceBlockForm;
|
||||||
|
@ -25,11 +46,10 @@ impl Blockable for InstanceBlock {
|
||||||
instance_block_form: &Self::Form,
|
instance_block_form: &Self::Form,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(
|
diesel::delete(instance_block.find((
|
||||||
instance_block
|
instance_block_form.person_id,
|
||||||
.filter(person_id.eq(instance_block_form.person_id))
|
instance_block_form.instance_id,
|
||||||
.filter(instance_id.eq(instance_block_form.instance_id)),
|
)))
|
||||||
)
|
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
diesel::ExpressionMethods,
|
diesel::ExpressionMethods,
|
||||||
newtypes::LanguageId,
|
newtypes::LanguageId,
|
||||||
schema::language::dsl::{code, id, language},
|
schema::language::dsl::{code, language},
|
||||||
source::language::Language,
|
source::language::Language,
|
||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
|
@ -16,7 +16,7 @@ impl Language {
|
||||||
|
|
||||||
pub async fn read_from_id(pool: &mut DbPool<'_>, id_: LanguageId) -> Result<Language, Error> {
|
pub async fn read_from_id(pool: &mut DbPool<'_>, id_: LanguageId) -> Result<Language, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
language.filter(id.eq(id_)).first::<Self>(conn).await
|
language.find(id_).first::<Self>(conn).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to find the given language code and return its ID. If not found, returns none.
|
/// Attempts to find the given language code and return its ID. If not found, returns none.
|
||||||
|
|
|
@ -76,6 +76,8 @@ impl LocalUser {
|
||||||
community,
|
community,
|
||||||
community_block,
|
community_block,
|
||||||
community_follower,
|
community_follower,
|
||||||
|
instance,
|
||||||
|
instance_block,
|
||||||
person,
|
person,
|
||||||
person_block,
|
person_block,
|
||||||
post,
|
post,
|
||||||
|
@ -118,6 +120,13 @@ impl LocalUser {
|
||||||
.get_results(conn)
|
.get_results(conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let blocked_instances = instance_block::dsl::instance_block
|
||||||
|
.filter(instance_block::person_id.eq(person_id_))
|
||||||
|
.inner_join(instance::table)
|
||||||
|
.select(instance::domain)
|
||||||
|
.get_results(conn)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// TODO: use join for parallel queries?
|
// TODO: use join for parallel queries?
|
||||||
|
|
||||||
Ok(UserBackupLists {
|
Ok(UserBackupLists {
|
||||||
|
@ -126,6 +135,7 @@ impl LocalUser {
|
||||||
saved_comments,
|
saved_comments,
|
||||||
blocked_communities,
|
blocked_communities,
|
||||||
blocked_users,
|
blocked_users,
|
||||||
|
blocked_instances,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,6 +146,7 @@ pub struct UserBackupLists {
|
||||||
pub saved_comments: Vec<DbUrl>,
|
pub saved_comments: Vec<DbUrl>,
|
||||||
pub blocked_communities: Vec<DbUrl>,
|
pub blocked_communities: Vec<DbUrl>,
|
||||||
pub blocked_users: Vec<DbUrl>,
|
pub blocked_users: Vec<DbUrl>,
|
||||||
|
pub blocked_instances: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
diesel::{ExpressionMethods, QueryDsl},
|
diesel::{ExpressionMethods, QueryDsl},
|
||||||
newtypes::LocalUserId,
|
newtypes::LocalUserId,
|
||||||
schema::login_token::{dsl::login_token, token, user_id},
|
schema::login_token::{dsl::login_token, user_id},
|
||||||
source::login_token::{LoginToken, LoginTokenCreateForm},
|
source::login_token::{LoginToken, LoginTokenCreateForm},
|
||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
|
@ -25,9 +25,7 @@ impl LoginToken {
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
select(exists(
|
select(exists(
|
||||||
login_token
|
login_token.find(token_).filter(user_id.eq(user_id_)),
|
||||||
.filter(user_id.eq(user_id_))
|
|
||||||
.filter(token.eq(token_)),
|
|
||||||
))
|
))
|
||||||
.get_result(conn)
|
.get_result(conn)
|
||||||
.await
|
.await
|
||||||
|
@ -48,9 +46,7 @@ impl LoginToken {
|
||||||
/// Invalidate specific token on user logout.
|
/// Invalidate specific token on user logout.
|
||||||
pub async fn invalidate(pool: &mut DbPool<'_>, token_: &str) -> Result<usize, Error> {
|
pub async fn invalidate(pool: &mut DbPool<'_>, token_: &str) -> Result<usize, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
delete(login_token.filter(token.eq(token_)))
|
delete(login_token.find(token_)).execute(conn).await
|
||||||
.execute(conn)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invalidate all logins of given user on password reset/change, account deletion or site ban.
|
/// Invalidate all logins of given user on password reset/change, account deletion or site ban.
|
||||||
|
|
|
@ -155,13 +155,9 @@ impl Followable for PersonFollower {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
async fn unfollow(pool: &mut DbPool<'_>, form: &PersonFollowerForm) -> Result<usize, Error> {
|
async fn unfollow(pool: &mut DbPool<'_>, form: &PersonFollowerForm) -> Result<usize, Error> {
|
||||||
use crate::schema::person_follower::dsl::{follower_id, person_follower, person_id};
|
use crate::schema::person_follower::dsl::person_follower;
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(
|
diesel::delete(person_follower.find((form.follower_id, form.person_id)))
|
||||||
person_follower
|
|
||||||
.filter(follower_id.eq(&form.follower_id))
|
|
||||||
.filter(person_id.eq(&form.person_id)),
|
|
||||||
)
|
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,12 @@ use crate::{
|
||||||
traits::Blockable,
|
traits::Blockable,
|
||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl};
|
use diesel::{
|
||||||
|
dsl::{exists, insert_into},
|
||||||
|
result::Error,
|
||||||
|
select,
|
||||||
|
QueryDsl,
|
||||||
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
|
|
||||||
impl PersonBlock {
|
impl PersonBlock {
|
||||||
|
@ -13,12 +18,10 @@ impl PersonBlock {
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
for_person_id: PersonId,
|
for_person_id: PersonId,
|
||||||
for_recipient_id: PersonId,
|
for_recipient_id: PersonId,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<bool, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
person_block
|
select(exists(person_block.find((for_person_id, for_recipient_id))))
|
||||||
.filter(person_id.eq(for_person_id))
|
.get_result(conn)
|
||||||
.filter(target_id.eq(for_recipient_id))
|
|
||||||
.first::<Self>(conn)
|
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,11 +44,7 @@ impl Blockable for PersonBlock {
|
||||||
}
|
}
|
||||||
async fn unblock(pool: &mut DbPool<'_>, person_block_form: &Self::Form) -> Result<usize, Error> {
|
async fn unblock(pool: &mut DbPool<'_>, person_block_form: &Self::Form) -> Result<usize, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(
|
diesel::delete(person_block.find((person_block_form.person_id, person_block_form.target_id)))
|
||||||
person_block
|
|
||||||
.filter(person_id.eq(person_block_form.person_id))
|
|
||||||
.filter(target_id.eq(person_block_form.target_id)),
|
|
||||||
)
|
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,11 +266,7 @@ impl Likeable for PostLike {
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
use crate::schema::post_like::dsl;
|
use crate::schema::post_like::dsl;
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(
|
diesel::delete(dsl::post_like.find((person_id, post_id)))
|
||||||
dsl::post_like
|
|
||||||
.filter(dsl::post_id.eq(post_id))
|
|
||||||
.filter(dsl::person_id.eq(person_id)),
|
|
||||||
)
|
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -291,13 +287,9 @@ impl Saveable for PostSaved {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
async fn unsave(pool: &mut DbPool<'_>, post_saved_form: &PostSavedForm) -> Result<usize, Error> {
|
async fn unsave(pool: &mut DbPool<'_>, post_saved_form: &PostSavedForm) -> Result<usize, Error> {
|
||||||
use crate::schema::post_saved::dsl::{person_id, post_id, post_saved};
|
use crate::schema::post_saved::dsl::post_saved;
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(
|
diesel::delete(post_saved.find((post_saved_form.person_id, post_saved_form.post_id)))
|
||||||
post_saved
|
|
||||||
.filter(post_id.eq(post_saved_form.post_id))
|
|
||||||
.filter(person_id.eq(post_saved_form.person_id)),
|
|
||||||
)
|
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -445,7 +437,6 @@ mod tests {
|
||||||
let inserted_post_like = PostLike::like(pool, &post_like_form).await.unwrap();
|
let inserted_post_like = PostLike::like(pool, &post_like_form).await.unwrap();
|
||||||
|
|
||||||
let expected_post_like = PostLike {
|
let expected_post_like = PostLike {
|
||||||
id: inserted_post_like.id,
|
|
||||||
post_id: inserted_post.id,
|
post_id: inserted_post.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_person.id,
|
||||||
published: inserted_post_like.published,
|
published: inserted_post_like.published,
|
||||||
|
@ -461,7 +452,6 @@ mod tests {
|
||||||
let inserted_post_saved = PostSaved::save(pool, &post_saved_form).await.unwrap();
|
let inserted_post_saved = PostSaved::save(pool, &post_saved_form).await.unwrap();
|
||||||
|
|
||||||
let expected_post_saved = PostSaved {
|
let expected_post_saved = PostSaved {
|
||||||
id: inserted_post_saved.id,
|
|
||||||
post_id: inserted_post.id,
|
post_id: inserted_post.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_person.id,
|
||||||
published: inserted_post_saved.published,
|
published: inserted_post_saved.published,
|
||||||
|
|
|
@ -83,12 +83,6 @@ pub struct PersonMentionId(i32);
|
||||||
/// The person block id.
|
/// The person block id.
|
||||||
pub struct PersonBlockId(i32);
|
pub struct PersonBlockId(i32);
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
|
||||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// The community block id.
|
|
||||||
pub struct CommunityBlockId(i32);
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
@ -119,30 +113,12 @@ pub struct SiteId(i32);
|
||||||
/// The language id.
|
/// The language id.
|
||||||
pub struct LanguageId(pub i32);
|
pub struct LanguageId(pub i32);
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
|
||||||
#[cfg_attr(feature = "full", derive(DieselNewType))]
|
|
||||||
pub struct LocalUserLanguageId(pub i32);
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
|
||||||
#[cfg_attr(feature = "full", derive(DieselNewType))]
|
|
||||||
pub struct SiteLanguageId(pub i32);
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
|
||||||
#[cfg_attr(feature = "full", derive(DieselNewType))]
|
|
||||||
pub struct CommunityLanguageId(pub i32);
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// The comment reply id.
|
/// The comment reply id.
|
||||||
pub struct CommentReplyId(i32);
|
pub struct CommentReplyId(i32);
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
|
||||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
/// The Image Upload id.
|
|
||||||
pub struct LocalImageId(i32);
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
|
||||||
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
|
|
@ -65,8 +65,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
captcha_answer (id) {
|
captcha_answer (uuid) {
|
||||||
id -> Int4,
|
|
||||||
uuid -> Uuid,
|
uuid -> Uuid,
|
||||||
answer -> Text,
|
answer -> Text,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
@ -96,8 +95,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
comment_aggregates (id) {
|
comment_aggregates (comment_id) {
|
||||||
id -> Int4,
|
|
||||||
comment_id -> Int4,
|
comment_id -> Int4,
|
||||||
score -> Int8,
|
score -> Int8,
|
||||||
upvotes -> Int8,
|
upvotes -> Int8,
|
||||||
|
@ -110,8 +108,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
comment_like (id) {
|
comment_like (person_id, comment_id) {
|
||||||
id -> Int4,
|
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
comment_id -> Int4,
|
comment_id -> Int4,
|
||||||
post_id -> Int4,
|
post_id -> Int4,
|
||||||
|
@ -145,8 +142,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
comment_saved (id) {
|
comment_saved (person_id, comment_id) {
|
||||||
id -> Int4,
|
|
||||||
comment_id -> Int4,
|
comment_id -> Int4,
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
@ -191,8 +187,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
community_aggregates (id) {
|
community_aggregates (community_id) {
|
||||||
id -> Int4,
|
|
||||||
community_id -> Int4,
|
community_id -> Int4,
|
||||||
subscribers -> Int8,
|
subscribers -> Int8,
|
||||||
posts -> Int8,
|
posts -> Int8,
|
||||||
|
@ -207,8 +202,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
community_block (id) {
|
community_block (person_id, community_id) {
|
||||||
id -> Int4,
|
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
community_id -> Int4,
|
community_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
@ -216,8 +210,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
community_follower (id) {
|
community_follower (person_id, community_id) {
|
||||||
id -> Int4,
|
|
||||||
community_id -> Int4,
|
community_id -> Int4,
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
@ -226,16 +219,14 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
community_language (id) {
|
community_language (community_id, language_id) {
|
||||||
id -> Int4,
|
|
||||||
community_id -> Int4,
|
community_id -> Int4,
|
||||||
language_id -> Int4,
|
language_id -> Int4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
community_moderator (id) {
|
community_moderator (person_id, community_id) {
|
||||||
id -> Int4,
|
|
||||||
community_id -> Int4,
|
community_id -> Int4,
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
@ -243,8 +234,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
community_person_ban (id) {
|
community_person_ban (person_id, community_id) {
|
||||||
id -> Int4,
|
|
||||||
community_id -> Int4,
|
community_id -> Int4,
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
@ -267,8 +257,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
custom_emoji_keyword (id) {
|
custom_emoji_keyword (custom_emoji_id, keyword) {
|
||||||
id -> Int4,
|
|
||||||
custom_emoji_id -> Int4,
|
custom_emoji_id -> Int4,
|
||||||
#[max_length = 128]
|
#[max_length = 128]
|
||||||
keyword -> Varchar,
|
keyword -> Varchar,
|
||||||
|
@ -286,8 +275,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
federation_allowlist (id) {
|
federation_allowlist (instance_id) {
|
||||||
id -> Int4,
|
|
||||||
instance_id -> Int4,
|
instance_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
updated -> Nullable<Timestamptz>,
|
updated -> Nullable<Timestamptz>,
|
||||||
|
@ -295,8 +283,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
federation_blocklist (id) {
|
federation_blocklist (instance_id) {
|
||||||
id -> Int4,
|
|
||||||
instance_id -> Int4,
|
instance_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
updated -> Nullable<Timestamptz>,
|
updated -> Nullable<Timestamptz>,
|
||||||
|
@ -304,8 +291,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
federation_queue_state (id) {
|
federation_queue_state (instance_id) {
|
||||||
id -> Int4,
|
|
||||||
instance_id -> Int4,
|
instance_id -> Int4,
|
||||||
last_successful_id -> Nullable<Int8>,
|
last_successful_id -> Nullable<Int8>,
|
||||||
fail_count -> Int4,
|
fail_count -> Int4,
|
||||||
|
@ -314,16 +300,6 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
|
||||||
local_image (id) {
|
|
||||||
id -> Int4,
|
|
||||||
local_user_id -> Int4,
|
|
||||||
pictrs_alias -> Text,
|
|
||||||
pictrs_delete_token -> Text,
|
|
||||||
published -> Timestamptz,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
instance (id) {
|
instance (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
|
@ -339,8 +315,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
instance_block (id) {
|
instance_block (person_id, instance_id) {
|
||||||
id -> Int4,
|
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
instance_id -> Int4,
|
instance_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
@ -356,6 +331,15 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
local_image (pictrs_alias) {
|
||||||
|
local_user_id -> Int4,
|
||||||
|
pictrs_alias -> Text,
|
||||||
|
pictrs_delete_token -> Text,
|
||||||
|
published -> Timestamptz,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
use diesel::sql_types::*;
|
use diesel::sql_types::*;
|
||||||
use super::sql_types::ListingTypeEnum;
|
use super::sql_types::ListingTypeEnum;
|
||||||
|
@ -391,8 +375,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
local_site_rate_limit (id) {
|
local_site_rate_limit (local_site_id) {
|
||||||
id -> Int4,
|
|
||||||
local_site_id -> Int4,
|
local_site_id -> Int4,
|
||||||
message -> Int4,
|
message -> Int4,
|
||||||
message_per_second -> Int4,
|
message_per_second -> Int4,
|
||||||
|
@ -452,16 +435,14 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
local_user_language (id) {
|
local_user_language (local_user_id, language_id) {
|
||||||
id -> Int4,
|
|
||||||
local_user_id -> Int4,
|
local_user_id -> Int4,
|
||||||
language_id -> Int4,
|
language_id -> Int4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
login_token (id) {
|
login_token (token) {
|
||||||
id -> Int4,
|
|
||||||
token -> Text,
|
token -> Text,
|
||||||
user_id -> Int4,
|
user_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
@ -632,8 +613,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
person_aggregates (id) {
|
person_aggregates (person_id) {
|
||||||
id -> Int4,
|
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
post_count -> Int8,
|
post_count -> Int8,
|
||||||
post_score -> Int8,
|
post_score -> Int8,
|
||||||
|
@ -643,16 +623,14 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
person_ban (id) {
|
person_ban (person_id) {
|
||||||
id -> Int4,
|
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
person_block (id) {
|
person_block (person_id, target_id) {
|
||||||
id -> Int4,
|
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
target_id -> Int4,
|
target_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
@ -660,8 +638,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
person_follower (id) {
|
person_follower (follower_id, person_id) {
|
||||||
id -> Int4,
|
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
follower_id -> Int4,
|
follower_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
@ -680,8 +657,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
person_post_aggregates (id) {
|
person_post_aggregates (person_id, post_id) {
|
||||||
id -> Int4,
|
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
post_id -> Int4,
|
post_id -> Int4,
|
||||||
read_comments -> Int8,
|
read_comments -> Int8,
|
||||||
|
@ -720,8 +696,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
post_aggregates (id) {
|
post_aggregates (post_id) {
|
||||||
id -> Int4,
|
|
||||||
post_id -> Int4,
|
post_id -> Int4,
|
||||||
comments -> Int8,
|
comments -> Int8,
|
||||||
score -> Int8,
|
score -> Int8,
|
||||||
|
@ -743,8 +718,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
post_like (id) {
|
post_like (person_id, post_id) {
|
||||||
id -> Int4,
|
|
||||||
post_id -> Int4,
|
post_id -> Int4,
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
score -> Int2,
|
score -> Int2,
|
||||||
|
@ -753,8 +727,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
post_read (id) {
|
post_read (person_id, post_id) {
|
||||||
id -> Int4,
|
|
||||||
post_id -> Int4,
|
post_id -> Int4,
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
@ -779,8 +752,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
post_saved (id) {
|
post_saved (person_id, post_id) {
|
||||||
id -> Int4,
|
|
||||||
post_id -> Int4,
|
post_id -> Int4,
|
||||||
person_id -> Int4,
|
person_id -> Int4,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
@ -818,8 +790,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
received_activity (id) {
|
received_activity (ap_id) {
|
||||||
id -> Int8,
|
|
||||||
ap_id -> Text,
|
ap_id -> Text,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
}
|
}
|
||||||
|
@ -893,8 +864,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
site_aggregates (id) {
|
site_aggregates (site_id) {
|
||||||
id -> Int4,
|
|
||||||
site_id -> Int4,
|
site_id -> Int4,
|
||||||
users -> Int8,
|
users -> Int8,
|
||||||
posts -> Int8,
|
posts -> Int8,
|
||||||
|
@ -908,8 +878,7 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
site_language (id) {
|
site_language (site_id, language_id) {
|
||||||
id -> Int4,
|
|
||||||
site_id -> Int4,
|
site_id -> Int4,
|
||||||
language_id -> Int4,
|
language_id -> Int4,
|
||||||
}
|
}
|
||||||
|
@ -961,9 +930,9 @@ diesel::joinable!(email_verification -> local_user (local_user_id));
|
||||||
diesel::joinable!(federation_allowlist -> instance (instance_id));
|
diesel::joinable!(federation_allowlist -> instance (instance_id));
|
||||||
diesel::joinable!(federation_blocklist -> instance (instance_id));
|
diesel::joinable!(federation_blocklist -> instance (instance_id));
|
||||||
diesel::joinable!(federation_queue_state -> instance (instance_id));
|
diesel::joinable!(federation_queue_state -> instance (instance_id));
|
||||||
diesel::joinable!(local_image -> local_user (local_user_id));
|
|
||||||
diesel::joinable!(instance_block -> instance (instance_id));
|
diesel::joinable!(instance_block -> instance (instance_id));
|
||||||
diesel::joinable!(instance_block -> person (person_id));
|
diesel::joinable!(instance_block -> person (person_id));
|
||||||
|
diesel::joinable!(local_image -> local_user (local_user_id));
|
||||||
diesel::joinable!(local_site -> site (site_id));
|
diesel::joinable!(local_site -> site (site_id));
|
||||||
diesel::joinable!(local_site_rate_limit -> local_site (local_site_id));
|
diesel::joinable!(local_site_rate_limit -> local_site (local_site_id));
|
||||||
diesel::joinable!(local_user -> person (person_id));
|
diesel::joinable!(local_user -> person (person_id));
|
||||||
|
@ -1041,10 +1010,10 @@ diesel::allow_tables_to_appear_in_same_query!(
|
||||||
federation_allowlist,
|
federation_allowlist,
|
||||||
federation_blocklist,
|
federation_blocklist,
|
||||||
federation_queue_state,
|
federation_queue_state,
|
||||||
local_image,
|
|
||||||
instance,
|
instance,
|
||||||
instance_block,
|
instance_block,
|
||||||
language,
|
language,
|
||||||
|
local_image,
|
||||||
local_site,
|
local_site,
|
||||||
local_site_rate_limit,
|
local_site_rate_limit,
|
||||||
local_user,
|
local_user,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
newtypes::{ActivityId, CommunityId, DbUrl},
|
newtypes::{ActivityId, CommunityId, DbUrl},
|
||||||
schema::sent_activity,
|
schema::{received_activity, sent_activity},
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use diesel::{sql_types::Nullable, Queryable};
|
use diesel::{sql_types::Nullable, Queryable};
|
||||||
|
@ -51,8 +51,10 @@ impl ActivitySendTargets {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Queryable)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
#[diesel(table_name = sent_activity)]
|
#[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(table_name = sent_activity))]
|
||||||
pub struct SentActivity {
|
pub struct SentActivity {
|
||||||
pub id: ActivityId,
|
pub id: ActivityId,
|
||||||
pub ap_id: DbUrl,
|
pub ap_id: DbUrl,
|
||||||
|
@ -66,8 +68,8 @@ pub struct SentActivity {
|
||||||
pub actor_apub_id: Option<DbUrl>,
|
pub actor_apub_id: Option<DbUrl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Insertable)]
|
#[cfg_attr(feature = "full", derive(Insertable))]
|
||||||
#[diesel(table_name = sent_activity)]
|
#[cfg_attr(feature = "full", diesel(table_name = sent_activity))]
|
||||||
pub struct SentActivityForm {
|
pub struct SentActivityForm {
|
||||||
pub ap_id: DbUrl,
|
pub ap_id: DbUrl,
|
||||||
pub data: Value,
|
pub data: Value,
|
||||||
|
@ -87,10 +89,12 @@ pub enum ActorType {
|
||||||
Person,
|
Person,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Queryable)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
#[diesel(table_name = received_activity)]
|
#[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(ap_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(table_name = received_activity))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
pub struct ReceivedActivity {
|
pub struct ReceivedActivity {
|
||||||
pub id: i64,
|
|
||||||
pub ap_id: DbUrl,
|
pub ap_id: DbUrl,
|
||||||
pub published: DateTime<Utc>,
|
pub published: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,14 @@
|
||||||
use crate::newtypes::{
|
use crate::newtypes::{CommunityId, LanguageId, LocalUserId, SiteId};
|
||||||
CommunityId,
|
|
||||||
CommunityLanguageId,
|
|
||||||
LanguageId,
|
|
||||||
LocalUserId,
|
|
||||||
LocalUserLanguageId,
|
|
||||||
SiteId,
|
|
||||||
SiteLanguageId,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
use crate::schema::local_user_language;
|
use crate::schema::local_user_language;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
|
#[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = local_user_language))]
|
#[cfg_attr(feature = "full", diesel(table_name = local_user_language))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(local_user_id, language_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
pub struct LocalUserLanguage {
|
pub struct LocalUserLanguage {
|
||||||
#[serde(skip)]
|
|
||||||
pub id: LocalUserLanguageId,
|
|
||||||
pub local_user_id: LocalUserId,
|
pub local_user_id: LocalUserId,
|
||||||
pub language_id: LanguageId,
|
pub language_id: LanguageId,
|
||||||
}
|
}
|
||||||
|
@ -33,11 +25,11 @@ pub struct LocalUserLanguageForm {
|
||||||
use crate::schema::community_language;
|
use crate::schema::community_language;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
|
#[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = community_language))]
|
#[cfg_attr(feature = "full", diesel(table_name = community_language))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(community_id, language_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
pub struct CommunityLanguage {
|
pub struct CommunityLanguage {
|
||||||
#[serde(skip)]
|
|
||||||
pub id: CommunityLanguageId,
|
|
||||||
pub community_id: CommunityId,
|
pub community_id: CommunityId,
|
||||||
pub language_id: LanguageId,
|
pub language_id: LanguageId,
|
||||||
}
|
}
|
||||||
|
@ -54,11 +46,11 @@ pub struct CommunityLanguageForm {
|
||||||
use crate::schema::site_language;
|
use crate::schema::site_language;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
|
#[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = site_language))]
|
#[cfg_attr(feature = "full", diesel(table_name = site_language))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(site_id, language_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
pub struct SiteLanguage {
|
pub struct SiteLanguage {
|
||||||
#[serde(skip)]
|
|
||||||
pub id: SiteLanguageId,
|
|
||||||
pub site_id: SiteId,
|
pub site_id: SiteId,
|
||||||
pub language_id: LanguageId,
|
pub language_id: LanguageId,
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,10 @@ use uuid::Uuid;
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable))]
|
#[cfg_attr(feature = "full", derive(Queryable, Selectable))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = captcha_answer))]
|
#[cfg_attr(feature = "full", diesel(table_name = captcha_answer))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
pub struct CaptchaAnswer {
|
pub struct CaptchaAnswer {
|
||||||
pub id: i32,
|
|
||||||
pub uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
pub answer: String,
|
pub answer: String,
|
||||||
pub published: DateTime<Utc>,
|
pub published: DateTime<Utc>,
|
||||||
|
@ -18,8 +18,9 @@ pub struct CaptchaAnswer {
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable))]
|
#[cfg_attr(feature = "full", derive(Queryable, Selectable))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = captcha_answer))]
|
#[cfg_attr(feature = "full", diesel(table_name = captcha_answer))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
pub struct CheckCaptchaAnswer {
|
pub struct CheckCaptchaAnswer {
|
||||||
pub uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
pub answer: String,
|
pub answer: String,
|
||||||
|
|
|
@ -14,10 +14,14 @@ use typed_builder::TypedBuilder;
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable, TS))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Queryable, Selectable, Associations, Identifiable, TS)
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::post::Post)))]
|
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::post::Post)))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = comment))]
|
#[cfg_attr(feature = "full", diesel(table_name = comment))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
/// A comment.
|
/// A comment.
|
||||||
pub struct Comment {
|
pub struct Comment {
|
||||||
pub id: CommentId,
|
pub id: CommentId,
|
||||||
|
@ -83,11 +87,15 @@ pub struct CommentUpdateForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Identifiable, Queryable, Selectable, Associations)
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
|
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = comment_like))]
|
#[cfg_attr(feature = "full", diesel(table_name = comment_like))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(person_id, comment_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
pub struct CommentLike {
|
pub struct CommentLike {
|
||||||
pub id: i32,
|
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
pub comment_id: CommentId,
|
pub comment_id: CommentId,
|
||||||
pub post_id: PostId, // TODO this is redundant
|
pub post_id: PostId, // TODO this is redundant
|
||||||
|
@ -106,11 +114,15 @@ pub struct CommentLikeForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Identifiable, Queryable, Selectable, Associations)
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
|
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = comment_saved))]
|
#[cfg_attr(feature = "full", diesel(table_name = comment_saved))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(person_id, comment_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
pub struct CommentSaved {
|
pub struct CommentSaved {
|
||||||
pub id: i32,
|
|
||||||
pub comment_id: CommentId,
|
pub comment_id: CommentId,
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
pub published: DateTime<Utc>,
|
pub published: DateTime<Utc>,
|
||||||
|
|
|
@ -7,9 +7,13 @@ use serde::{Deserialize, Serialize};
|
||||||
use ts_rs::TS;
|
use ts_rs::TS;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable, TS))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Queryable, Selectable, Associations, Identifiable, TS)
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
|
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = comment_reply))]
|
#[cfg_attr(feature = "full", diesel(table_name = comment_reply))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// A comment reply.
|
/// A comment reply.
|
||||||
pub struct CommentReply {
|
pub struct CommentReply {
|
||||||
|
|
|
@ -9,9 +9,13 @@ use ts_rs::TS;
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, Clone)]
|
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable, TS))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Queryable, Selectable, Associations, Identifiable, TS)
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
|
#[cfg_attr(feature = "full", diesel(belongs_to(crate::source::comment::Comment)))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = comment_report))]
|
#[cfg_attr(feature = "full", diesel(table_name = comment_report))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// A comment report.
|
/// A comment report.
|
||||||
pub struct CommentReport {
|
pub struct CommentReport {
|
||||||
|
|
|
@ -13,8 +13,9 @@ use typed_builder::TypedBuilder;
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Identifiable, TS))]
|
#[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable, TS))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = community))]
|
#[cfg_attr(feature = "full", diesel(table_name = community))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// A community.
|
/// A community.
|
||||||
pub struct Community {
|
pub struct Community {
|
||||||
|
@ -128,14 +129,18 @@ pub struct CommunityUpdateForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Identifiable, Queryable, Selectable, Associations)
|
||||||
|
)]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "full",
|
feature = "full",
|
||||||
diesel(belongs_to(crate::source::community::Community))
|
diesel(belongs_to(crate::source::community::Community))
|
||||||
)]
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = community_moderator))]
|
#[cfg_attr(feature = "full", diesel(table_name = community_moderator))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(person_id, community_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
pub struct CommunityModerator {
|
pub struct CommunityModerator {
|
||||||
pub id: i32,
|
|
||||||
pub community_id: CommunityId,
|
pub community_id: CommunityId,
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
pub published: DateTime<Utc>,
|
pub published: DateTime<Utc>,
|
||||||
|
@ -150,14 +155,18 @@ pub struct CommunityModeratorForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Identifiable, Queryable, Selectable, Associations)
|
||||||
|
)]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "full",
|
feature = "full",
|
||||||
diesel(belongs_to(crate::source::community::Community))
|
diesel(belongs_to(crate::source::community::Community))
|
||||||
)]
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = community_person_ban))]
|
#[cfg_attr(feature = "full", diesel(table_name = community_person_ban))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(person_id, community_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
pub struct CommunityPersonBan {
|
pub struct CommunityPersonBan {
|
||||||
pub id: i32,
|
|
||||||
pub community_id: CommunityId,
|
pub community_id: CommunityId,
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
pub published: DateTime<Utc>,
|
pub published: DateTime<Utc>,
|
||||||
|
@ -174,14 +183,18 @@ pub struct CommunityPersonBanForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Identifiable, Queryable, Selectable, Associations)
|
||||||
|
)]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "full",
|
feature = "full",
|
||||||
diesel(belongs_to(crate::source::community::Community))
|
diesel(belongs_to(crate::source::community::Community))
|
||||||
)]
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = community_follower))]
|
#[cfg_attr(feature = "full", diesel(table_name = community_follower))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(person_id, community_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
pub struct CommunityFollower {
|
pub struct CommunityFollower {
|
||||||
pub id: i32,
|
|
||||||
pub community_id: CommunityId,
|
pub community_id: CommunityId,
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
pub published: DateTime<Utc>,
|
pub published: DateTime<Utc>,
|
||||||
|
|
|
@ -1,18 +1,22 @@
|
||||||
use crate::newtypes::{CommunityBlockId, CommunityId, PersonId};
|
use crate::newtypes::{CommunityId, PersonId};
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
use crate::schema::community_block;
|
use crate::schema::community_block;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
derive(Queryable, Selectable, Associations, Identifiable)
|
||||||
|
)]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "full",
|
feature = "full",
|
||||||
diesel(belongs_to(crate::source::community::Community))
|
diesel(belongs_to(crate::source::community::Community))
|
||||||
)]
|
)]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = community_block))]
|
#[cfg_attr(feature = "full", diesel(table_name = community_block))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(person_id, community_id)))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
pub struct CommunityBlock {
|
pub struct CommunityBlock {
|
||||||
pub id: CommunityBlockId,
|
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
pub community_id: CommunityId,
|
pub community_id: CommunityId,
|
||||||
pub published: DateTime<Utc>,
|
pub published: DateTime<Utc>,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue