Merge branch 'main' into patch-1

SleeplessOne1917 3 weeks ago committed by GitHub
commit a066ad3909
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -143,16 +143,6 @@ steps:
- diff tmp.schema crates/db_schema/src/schema.rs
when: *slow_check_paths
check_diesel_migration_revertable:
image: willsquire/diesel-cli
environment:
CARGO_HOME: .cargo_home
DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
commands:
- diesel migration run
- diesel migration redo
when: *slow_check_paths
check_db_perf_tool:
image: *rust_image
environment:
@ -194,6 +184,44 @@ steps:
- cargo test --workspace --no-fail-fast
when: *slow_check_paths
check_diesel_migration:
# TODO: use willsquire/diesel-cli image when shared libraries become optional in lemmy_server
image: *rust_image
environment:
LEMMY_DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
RUST_BACKTRACE: "1"
CARGO_HOME: .cargo_home
DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
PGUSER: lemmy
PGPASSWORD: password
PGHOST: database
PGDATABASE: lemmy
commands:
- cargo install diesel_cli
- export PATH="$CARGO_HOME/bin:$PATH"
# Run all migrations
- diesel migration run
# Dump schema to before.sqldump (PostgreSQL apt repo is used to prevent pg_dump version mismatch error)
- apt update && apt install -y lsb-release
- sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
- wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
- apt update && apt install -y postgresql-client-16
- psql -c "DROP SCHEMA IF EXISTS r CASCADE;"
- pg_dump --no-owner --no-privileges --no-table-access-method --schema-only --no-sync -f before.sqldump
# Make sure that the newest migration is revertable without the `r` schema
- diesel migration redo
# Run schema setup twice, which fails on the 2nd time if `DROP SCHEMA IF EXISTS r CASCADE` drops the wrong things
- alias lemmy_schema_setup="target/lemmy_server --disable-scheduled-tasks --disable-http-server --disable-activity-sending"
- lemmy_schema_setup
- lemmy_schema_setup
# Make sure that the newest migration is revertable with the `r` schema
- diesel migration redo
# Check for changes in the schema, which would be caused by an incorrect migration
- psql -c "DROP SCHEMA IF EXISTS r CASCADE;"
- pg_dump --no-owner --no-privileges --no-table-access-method --schema-only --no-sync -f after.sqldump
- diff before.sqldump after.sqldump
when: *slow_check_paths
run_federation_tests:
image: node:20-bookworm-slim
environment:

490
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -1,5 +1,5 @@
[workspace.package]
version = "0.19.4-beta.3"
version = "0.19.4-beta.4"
edition = "2021"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
@ -88,24 +88,24 @@ unused_self = "deny"
unwrap_used = "deny"
[workspace.dependencies]
lemmy_api = { version = "=0.19.4-beta.3", path = "./crates/api" }
lemmy_api_crud = { version = "=0.19.4-beta.3", path = "./crates/api_crud" }
lemmy_apub = { version = "=0.19.4-beta.3", path = "./crates/apub" }
lemmy_utils = { version = "=0.19.4-beta.3", path = "./crates/utils", default-features = false }
lemmy_db_schema = { version = "=0.19.4-beta.3", path = "./crates/db_schema" }
lemmy_api_common = { version = "=0.19.4-beta.3", path = "./crates/api_common" }
lemmy_routes = { version = "=0.19.4-beta.3", path = "./crates/routes" }
lemmy_db_views = { version = "=0.19.4-beta.3", path = "./crates/db_views" }
lemmy_db_views_actor = { version = "=0.19.4-beta.3", path = "./crates/db_views_actor" }
lemmy_db_views_moderator = { version = "=0.19.4-beta.3", path = "./crates/db_views_moderator" }
lemmy_federate = { version = "=0.19.4-beta.3", path = "./crates/federate" }
lemmy_api = { version = "=0.19.4-beta.4", path = "./crates/api" }
lemmy_api_crud = { version = "=0.19.4-beta.4", path = "./crates/api_crud" }
lemmy_apub = { version = "=0.19.4-beta.4", path = "./crates/apub" }
lemmy_utils = { version = "=0.19.4-beta.4", path = "./crates/utils", default-features = false }
lemmy_db_schema = { version = "=0.19.4-beta.4", path = "./crates/db_schema" }
lemmy_api_common = { version = "=0.19.4-beta.4", path = "./crates/api_common" }
lemmy_routes = { version = "=0.19.4-beta.4", path = "./crates/routes" }
lemmy_db_views = { version = "=0.19.4-beta.4", path = "./crates/db_views" }
lemmy_db_views_actor = { version = "=0.19.4-beta.4", path = "./crates/db_views_actor" }
lemmy_db_views_moderator = { version = "=0.19.4-beta.4", path = "./crates/db_views_moderator" }
lemmy_federate = { version = "=0.19.4-beta.4", path = "./crates/federate" }
activitypub_federation = { version = "0.5.4", default-features = false, features = [
"actix-web",
] }
diesel = "2.1.4"
diesel = "2.1.6"
diesel_migrations = "2.1.0"
diesel-async = "0.4.1"
serde = { version = "1.0.197", features = ["derive"] }
serde = { version = "1.0.198", features = ["derive"] }
serde_with = "3.7.0"
actix-web = { version = "4.5.1", default-features = false, features = [
"macros",
@ -121,28 +121,28 @@ tracing-error = "0.2.0"
tracing-log = "0.2.0"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
url = { version = "2.5.0", features = ["serde"] }
reqwest = { version = "0.11.26", features = ["json", "blocking", "gzip"] }
reqwest-middleware = "0.2.4"
reqwest-tracing = "0.4.7"
reqwest = { version = "0.11.27", features = ["json", "blocking", "gzip"] }
reqwest-middleware = "0.2.5"
reqwest-tracing = "0.4.8"
clokwerk = "0.4.0"
doku = { version = "0.21.1", features = ["url-2"] }
bcrypt = "0.15.0"
chrono = { version = "0.4.35", features = ["serde"], default-features = false }
serde_json = { version = "1.0.114", features = ["preserve_order"] }
base64 = "0.21.7"
uuid = { version = "1.7.0", features = ["serde", "v4"] }
async-trait = "0.1.77"
bcrypt = "0.15.1"
chrono = { version = "0.4.38", features = ["serde"], default-features = false }
serde_json = { version = "1.0.116", features = ["preserve_order"] }
base64 = "0.22.0"
uuid = { version = "1.8.0", features = ["serde", "v4"] }
async-trait = "0.1.80"
captcha = "0.0.9"
anyhow = { version = "1.0.81", features = [
anyhow = { version = "1.0.82", features = [
"backtrace",
] } # backtrace is on by default on nightly, but not stable rust
diesel_ltree = "0.3.1"
typed-builder = "0.18.1"
typed-builder = "0.18.2"
serial_test = "2.0.0"
tokio = { version = "1.36.0", features = ["full"] }
regex = "1.10.3"
tokio = { version = "1.37.0", features = ["full"] }
regex = "1.10.4"
once_cell = "1.19.0"
diesel-derive-newtype = "2.1.0"
diesel-derive-newtype = "2.1.2"
diesel-derive-enum = { version = "2.1.0", features = ["postgres"] }
strum = "0.25.0"
strum_macros = "0.25.3"
@ -157,15 +157,15 @@ ts-rs = { version = "7.1.1", features = [
"chrono-impl",
"no-serde-warnings",
] }
rustls = { version = "0.21.10", features = ["dangerous_configuration"] }
rustls = { version = "0.21.11", features = ["dangerous_configuration"] }
futures-util = "0.3.30"
tokio-postgres = "0.7.10"
tokio-postgres-rustls = "0.10.0"
urlencoding = "2.1.3"
enum-map = "2.7"
moka = { version = "0.12.5", features = ["future"] }
moka = { version = "0.12.7", features = ["future"] }
i-love-jesus = { version = "0.1.0" }
clap = { version = "4.5.2", features = ["derive"] }
clap = { version = "4.5.4", features = ["derive"] }
pretty_assertions = "1.4.0"
[dependencies]
@ -196,7 +196,7 @@ tracing-opentelemetry = { workspace = true, optional = true }
opentelemetry = { workspace = true, optional = true }
console-subscriber = { version = "0.1.10", optional = true }
opentelemetry-otlp = { version = "0.12.0", optional = true }
pict-rs = { version = "0.5.9", optional = true }
pict-rs = { version = "0.5.13", optional = true }
tokio.workspace = true
actix-cors = "0.6.5"
futures-util = { workspace = true }

@ -6,6 +6,7 @@
"repository": "https://github.com/LemmyNet/lemmy",
"author": "Dessalines",
"license": "AGPL-3.0",
"packageManager": "pnpm@9.0.4",
"scripts": {
"lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src && prettier --check 'src/**/*.ts'",
"fix": "prettier --write src && eslint --fix src",
@ -27,7 +28,7 @@
"eslint": "^8.57.0",
"eslint-plugin-prettier": "^5.1.3",
"jest": "^29.5.0",
"lemmy-js-client": "0.19.4-alpha.16",
"lemmy-js-client": "0.19.4-alpha.18",
"prettier": "^3.2.5",
"ts-jest": "^29.1.0",
"typescript": "^5.4.4"

File diff suppressed because it is too large Load Diff

@ -242,7 +242,7 @@ test("Admin actions in remote community are not federated to origin", async () =
);
expect(banRes.banned).toBe(true);
// ban doesnt federate to community's origin instance alpha
// ban doesn't federate to community's origin instance alpha
let alphaPost = (await resolvePost(alpha, gammaPost.post)).post;
expect(alphaPost?.creator_banned_from_community).toBe(false);
@ -452,7 +452,7 @@ test("Dont receive community activities after unsubscribe", async () => {
);
expect(communityRes1.community_view.counts.subscribers).toBe(2);
// temporarily block alpha, so that it doesnt know about unfollow
// temporarily block alpha, so that it doesn't know about unfollow
let editSiteForm: EditSite = {};
editSiteForm.allowed_instances = ["lemmy-epsilon"];
await beta.editSite(editSiteForm);
@ -513,7 +513,7 @@ test("Fetch community, includes posts", async () => {
expect(post_listing.posts[0].post.ap_id).toBe(postRes.post_view.post.ap_id);
});
test("Content in local-only community doesnt federate", async () => {
test("Content in local-only community doesn't federate", async () => {
// create a community and set it local-only
let communityRes = (await createCommunity(alpha)).community_view.community;
let form: EditCommunity = {

@ -27,9 +27,10 @@ import {
setupLogins,
waitForPost,
unfollows,
editPostThumbnail,
getPost,
waitUntil,
randomString,
createPostWithThumbnail,
} from "./shared";
const downloadFileSync = require("download-file-sync");
@ -41,7 +42,7 @@ test("Upload image and delete it", async () => {
// Before running this test, you need to delete all previous images in the DB
await deleteAllImages(alpha);
// Upload test image. We use a simple string buffer as pictrs doesnt require an actual image
// Upload test image. We use a simple string buffer as pictrs doesn't require an actual image
// in testing mode.
const upload_form: UploadImage = {
image: Buffer.from("test"),
@ -71,9 +72,14 @@ test("Upload image and delete it", async () => {
// The deleteUrl is a combination of the endpoint, delete token, and alias
let firstImage = listMediaRes.images[0];
let deleteUrl = `${alphaUrl}/pictrs/image/delete/${firstImage.pictrs_delete_token}/${firstImage.pictrs_alias}`;
let deleteUrl = `${alphaUrl}/pictrs/image/delete/${firstImage.local_image.pictrs_delete_token}/${firstImage.local_image.pictrs_alias}`;
expect(deleteUrl).toBe(upload.delete_url);
// Make sure the uploader is correct
expect(firstImage.person.actor_id).toBe(
`http://lemmy-alpha:8541/u/lemmy_alpha`,
);
// delete image
const delete_form: DeleteImage = {
token: upload.files![0].delete_token,
@ -230,7 +236,7 @@ test("No image proxying if setting is disabled", async () => {
);
expect(post.post_view.post).toBeDefined();
// remote image doesnt get proxied after upload
// remote image doesn't get proxied after upload
expect(
post.post_view.post.url?.startsWith("http://127.0.0.1:8551/pictrs/image/"),
).toBeTruthy();
@ -243,7 +249,7 @@ test("No image proxying if setting is disabled", async () => {
);
expect(betaPost.post).toBeDefined();
// remote image doesnt get proxied after federation
// remote image doesn't get proxied after federation
expect(
betaPost.post.url?.startsWith("http://127.0.0.1:8551/pictrs/image/"),
).toBeTruthy();
@ -264,10 +270,11 @@ test("Make regular post, and give it a custom thumbnail", async () => {
// Use wikipedia since it has an opengraph image
const wikipediaUrl = "https://wikipedia.org/";
let post = await createPost(
let post = await createPostWithThumbnail(
alphaImage,
community.community_view.community.id,
wikipediaUrl,
upload1.url!,
);
// Wait for the metadata to get fetched, since this is backgrounded now
@ -276,21 +283,11 @@ test("Make regular post, and give it a custom thumbnail", async () => {
p => p.post_view.post.thumbnail_url != undefined,
);
expect(post.post_view.post.url).toBe(wikipediaUrl);
expect(post.post_view.post.thumbnail_url).toBeDefined();
// Edit the thumbnail
await editPostThumbnail(alphaImage, post.post_view.post, upload1.url!);
post = await waitUntil(
() => getPost(alphaImage, post.post_view.post.id),
p => p.post_view.post.thumbnail_url == upload1.url,
);
// Make sure the thumbnail got edited.
// Make sure it uses custom thumbnail
expect(post.post_view.post.thumbnail_url).toBe(upload1.url);
});
test("Create an image post, and make sure a custom thumbnail doesnt overwrite it", async () => {
test("Create an image post, and make sure a custom thumbnail doesn't overwrite it", async () => {
const uploadForm1: UploadImage = {
image: Buffer.from("test1"),
};
@ -303,23 +300,17 @@ test("Create an image post, and make sure a custom thumbnail doesnt overwrite it
const community = await createCommunity(alphaImage);
let post = await createPost(
let post = await createPostWithThumbnail(
alphaImage,
community.community_view.community.id,
upload1.url,
upload1.url!,
upload2.url!,
);
expect(post.post_view.post.url).toBe(upload1.url);
// Edit the post
await editPostThumbnail(alphaImage, post.post_view.post, upload2.url!);
// Wait for the metadata to get fetched
post = await waitUntil(
() => getPost(alphaImage, post.post_view.post.id),
p => p.post_view.post.thumbnail_url == upload1.url,
p => p.post_view.post.thumbnail_url != undefined,
);
// Make sure the new custom thumbnail is ignored, and doesn't overwrite the image post
expect(post.post_view.post.url).toBe(upload1.url);
expect(post.post_view.post.thumbnail_url).toBe(upload1.url);
// Make sure the custom thumbnail is ignored
expect(post.post_view.post.thumbnail_url == upload2.url).toBe(false);
});

@ -203,6 +203,7 @@ export async function createPost(
// use example.com for consistent title and embed description
name: string = randomString(5),
alt_text = randomString(10),
custom_thumbnail: string | undefined = undefined,
): Promise<PostResponse> {
let form: CreatePost = {
name,
@ -210,6 +211,7 @@ export async function createPost(
body,
alt_text,
community_id,
custom_thumbnail,
};
return api.createPost(form);
}
@ -226,16 +228,19 @@ export async function editPost(
return api.editPost(form);
}
export async function editPostThumbnail(
export async function createPostWithThumbnail(
api: LemmyHttp,
post: Post,
customThumbnail: string,
community_id: number,
url: string,
custom_thumbnail: string,
): Promise<PostResponse> {
let form: EditPost = {
post_id: post.id,
custom_thumbnail: customThumbnail,
let form: CreatePost = {
name: randomString(10),
url,
community_id,
custom_thumbnail,
};
return api.editPost(form);
return api.createPost(form);
}
export async function deletePost(
@ -887,8 +892,8 @@ export async function deleteAllImages(api: LemmyHttp) {
for (const image of imagesRes.images) {
const form: DeleteImage = {
token: image.pictrs_delete_token,
filename: image.pictrs_alias,
token: image.local_image.pictrs_delete_token,
filename: image.local_image.pictrs_alias,
};
await api.deleteImage(form);
}

@ -49,7 +49,7 @@
cache_external_link_previews: true
# Specifies how to handle remote images, so that users don't have to connect directly to remote servers.
image_mode:
# Leave images unchanged, don't generate any local thumbnails for post urls. Instead the the
# Leave images unchanged, don't generate any local thumbnails for post urls. Instead the
# Opengraph image is directly returned as thumbnail
"None"

@ -17,7 +17,9 @@ pub async fn distinguish_comment(
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<CommentResponse>> {
let orig_comment = CommentView::read(&mut context.pool(), data.comment_id, None).await?;
let orig_comment = CommentView::read(&mut context.pool(), data.comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
check_community_user_action(
&local_user_view.person,
@ -54,7 +56,8 @@ pub async fn distinguish_comment(
data.comment_id,
Some(local_user_view.person.id),
)
.await?;
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
Ok(Json(CommentResponse {
comment_view,

@ -35,7 +35,9 @@ pub async fn like_comment(
check_bot_account(&local_user_view.person)?;
let comment_id = data.comment_id;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
check_community_user_action(
&local_user_view.person,
@ -46,9 +48,10 @@ pub async fn like_comment(
// Add parent poster or commenter to recipients
let comment_reply = CommentReply::read_by_comment(&mut context.pool(), comment_id).await;
if let Ok(reply) = comment_reply {
if let Ok(Some(reply)) = comment_reply {
let recipient_id = reply.recipient_id;
if let Ok(local_recipient) = LocalUserView::read_person(&mut context.pool(), recipient_id).await
if let Ok(Some(local_recipient)) =
LocalUserView::read_person(&mut context.pool(), recipient_id).await
{
recipient_ids.push(local_recipient.local_user.id);
}

@ -5,7 +5,7 @@ use lemmy_api_common::{
utils::is_mod_or_admin,
};
use lemmy_db_views::structs::{CommentView, LocalUserView, VoteView};
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
/// Lists likes for a comment
#[tracing::instrument(skip(context))]
@ -19,7 +19,9 @@ pub async fn list_comment_likes(
data.comment_id,
Some(local_user_view.person.id),
)
.await?;
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
is_mod_or_admin(
&mut context.pool(),
&local_user_view.person,

@ -33,7 +33,9 @@ pub async fn save_comment(
let comment_id = data.comment_id;
let person_id = local_user_view.person.id;
let comment_view = CommentView::read(&mut context.pool(), comment_id, Some(person_id)).await?;
let comment_view = CommentView::read(&mut context.pool(), comment_id, Some(person_id))
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
Ok(Json(CommentResponse {
comment_view,

@ -35,7 +35,9 @@ pub async fn create_comment_report(
let person_id = local_user_view.person.id;
let comment_id = data.comment_id;
let comment_view = CommentView::read(&mut context.pool(), comment_id, None).await?;
let comment_view = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
check_community_user_action(
&local_user_view.person,
@ -58,8 +60,9 @@ pub async fn create_comment_report(
.await
.with_lemmy_type(LemmyErrorType::CouldntCreateReport)?;
let comment_report_view =
CommentReportView::read(&mut context.pool(), report.id, person_id).await?;
let comment_report_view = CommentReportView::read(&mut context.pool(), report.id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommentReport)?;
// Email the admins
if local_site.reports_email_admins {

@ -17,7 +17,9 @@ pub async fn resolve_comment_report(
) -> LemmyResult<Json<CommentReportResponse>> {
let report_id = data.report_id;
let person_id = local_user_view.person.id;
let report = CommentReportView::read(&mut context.pool(), report_id, person_id).await?;
let report = CommentReportView::read(&mut context.pool(), report_id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommentReport)?;
let person_id = local_user_view.person.id;
check_community_mod_action(
@ -39,8 +41,9 @@ pub async fn resolve_comment_report(
}
let report_id = data.report_id;
let comment_report_view =
CommentReportView::read(&mut context.pool(), report_id, person_id).await?;
let comment_report_view = CommentReportView::read(&mut context.pool(), report_id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommentReport)?;
Ok(Json(CommentReportResponse {
comment_report_view,

@ -33,7 +33,9 @@ pub async fn add_mod_to_community(
&mut context.pool(),
)
.await?;
let community = Community::read(&mut context.pool(), community_id).await?;
let community = Community::read(&mut context.pool(), community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
if local_user_view.local_user.admin && !community.local {
Err(LemmyErrorType::NotAModerator)?
}

@ -89,7 +89,9 @@ pub async fn ban_from_community(
ModBanFromCommunity::create(&mut context.pool(), &form).await?;
let person_view = PersonView::read(&mut context.pool(), data.person_id).await?;
let person_view = PersonView::read(&mut context.pool(), data.person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
ActivityChannel::submit_activity(
SendActivityData::BanFromCommunity {

@ -51,7 +51,9 @@ pub async fn block_community(
}
let community_view =
CommunityView::read(&mut context.pool(), community_id, Some(person_id), false).await?;
CommunityView::read(&mut context.pool(), community_id, Some(person_id), false)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
ActivityChannel::submit_activity(
SendActivityData::FollowCommunity(

@ -23,7 +23,9 @@ pub async fn follow_community(
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<CommunityResponse>> {
let community = Community::read(&mut context.pool(), data.community_id).await?;
let community = Community::read(&mut context.pool(), data.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
let mut community_follower_form = CommunityFollowerForm {
community_id: community.id,
person_id: local_user_view.person.id,
@ -62,7 +64,10 @@ pub async fn follow_community(
let community_id = data.community_id;
let person_id = local_user_view.person.id;
let community_view =
CommunityView::read(&mut context.pool(), community_id, Some(person_id), false).await?;
CommunityView::read(&mut context.pool(), community_id, Some(person_id), false)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
let discussion_languages = CommunityLanguage::read(&mut context.pool(), community_id).await?;
Ok(Json(CommunityResponse {

@ -79,8 +79,8 @@ pub async fn transfer_community(
let person_id = local_user_view.person.id;
let community_view =
CommunityView::read(&mut context.pool(), community_id, Some(person_id), false)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
let community_id = data.community_id;
let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id)

@ -252,7 +252,9 @@ pub async fn local_user_view_from_jwt(
let local_user_id = Claims::validate(jwt, context)
.await
.with_lemmy_type(LemmyErrorType::NotLoggedIn)?;
let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id).await?;
let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id)
.await?
.ok_or(LemmyErrorType::CouldntFindLocalUser)?;
check_user_valid(&local_user_view.person)?;
Ok(local_user_view)

@ -26,8 +26,8 @@ pub async fn add_admin(
// Make sure that the person_id added is local
let added_local_user = LocalUserView::read_person(&mut context.pool(), data.person_id)
.await
.with_lemmy_type(LemmyErrorType::ObjectNotLocal)?;
.await?
.ok_or(LemmyErrorType::ObjectNotLocal)?;
let added_admin = LocalUser::update(
&mut context.pool(),

@ -49,7 +49,7 @@ pub async fn ban_from_site(
// if its a local user, invalidate logins
let local_user = LocalUserView::read_person(&mut context.pool(), person.id).await;
if let Ok(local_user) = local_user {
if let Ok(Some(local_user)) = local_user {
LoginToken::invalidate_all(&mut context.pool(), local_user.local_user.id).await?;
}
@ -70,7 +70,9 @@ pub async fn ban_from_site(
ModBan::create(&mut context.pool(), &form).await?;
let person_view = PersonView::read(&mut context.pool(), person.id).await?;
let person_view = PersonView::read(&mut context.pool(), person.id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
ban_nonlocal_user_from_local_communities(
&local_user_view,

@ -30,8 +30,12 @@ pub async fn block_person(
target_id,
};
let target_user = LocalUserView::read_person(&mut context.pool(), target_id).await;
if target_user.map(|t| t.local_user.admin) == Ok(true) {
let target_user = LocalUserView::read_person(&mut context.pool(), target_id)
.await
.ok()
.flatten();
if target_user.is_some_and(|t| t.local_user.admin) {
Err(LemmyErrorType::CantBlockAdmin)?
}
@ -45,7 +49,9 @@ pub async fn block_person(
.with_lemmy_type(LemmyErrorType::PersonBlockAlreadyExists)?;
}
let person_view = PersonView::read(&mut context.pool(), target_id).await?;
let person_view = PersonView::read(&mut context.pool(), target_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
Ok(Json(BlockPersonResponse {
person_view,
blocked: data.block,

@ -20,8 +20,9 @@ pub async fn change_password_after_reset(
// Fetch the user_id from the token
let token = data.token.clone();
let local_user_id = PasswordResetRequest::read_from_token(&mut context.pool(), &token)
.await
.map(|p| p.local_user_id)?;
.await?
.ok_or(LemmyErrorType::TokenNotFound)?
.local_user_id;
password_length_check(&data.password)?;

@ -17,7 +17,9 @@ pub async fn generate_totp_secret(
local_user_view: LocalUserView,
context: Data<LemmyContext>,
) -> LemmyResult<Json<GenerateTotpSecretResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
if local_user_view.local_user.totp_2fa_enabled {
return Err(LemmyErrorType::TotpAlreadyEnabled)?;

@ -3,8 +3,7 @@ use lemmy_api_common::{
context::LemmyContext,
person::{ListMedia, ListMediaResponse},
};
use lemmy_db_schema::source::images::LocalImage;
use lemmy_db_views::structs::LocalUserView;
use lemmy_db_views::structs::{LocalImageView, LocalUserView};
use lemmy_utils::error::LemmyResult;
#[tracing::instrument(skip(context))]
@ -15,7 +14,7 @@ pub async fn list_media(
) -> LemmyResult<Json<ListMediaResponse>> {
let page = data.page;
let limit = data.limit;
let images = LocalImage::get_all_paged_by_local_user_id(
let images = LocalImageView::get_all_paged_by_local_user_id(
&mut context.pool(),
local_user_view.local_user.id,
page,

@ -16,7 +16,7 @@ use lemmy_db_schema::{
RegistrationMode,
};
use lemmy_db_views::structs::{LocalUserView, SiteView};
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
#[tracing::instrument(skip(context))]
pub async fn login(
@ -24,14 +24,16 @@ pub async fn login(
req: HttpRequest,
context: Data<LemmyContext>,
) -> LemmyResult<Json<LoginResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
// Fetch that username / email
let username_or_email = data.username_or_email.clone();
let local_user_view =
LocalUserView::find_by_email_or_name(&mut context.pool(), &username_or_email)
.await
.with_lemmy_type(LemmyErrorType::IncorrectLogin)?;
.await?
.ok_or(LemmyErrorType::IncorrectLogin)?;
// Verify the password
let valid: bool = verify(
@ -79,7 +81,9 @@ async fn check_registration_application(
// Fetch the registration application. If no admin id is present its still pending. Otherwise it
// was processed (either accepted or denied).
let local_user_id = local_user_view.local_user.id;
let registration = RegistrationApplication::find_by_local_user_id(pool, local_user_id).await?;
let registration = RegistrationApplication::find_by_local_user_id(pool, local_user_id)
.await?
.ok_or(LemmyErrorType::CouldntFindRegistrationApplication)?;
if registration.admin_id.is_some() {
Err(LemmyErrorType::RegistrationDenied(registration.deny_reason))?
} else {

@ -18,7 +18,9 @@ pub async fn mark_person_mention_as_read(
local_user_view: LocalUserView,
) -> LemmyResult<Json<PersonMentionResponse>> {
let person_mention_id = data.person_mention_id;
let read_person_mention = PersonMention::read(&mut context.pool(), person_mention_id).await?;
let read_person_mention = PersonMention::read(&mut context.pool(), person_mention_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPersonMention)?;
if local_user_view.person.id != read_person_mention.recipient_id {
Err(LemmyErrorType::CouldntUpdateComment)?
@ -37,7 +39,9 @@ pub async fn mark_person_mention_as_read(
let person_mention_id = read_person_mention.id;
let person_id = local_user_view.person.id;
let person_mention_view =
PersonMentionView::read(&mut context.pool(), person_mention_id, Some(person_id)).await?;
PersonMentionView::read(&mut context.pool(), person_mention_id, Some(person_id))
.await?
.ok_or(LemmyErrorType::CouldntFindPersonMention)?;
Ok(Json(PersonMentionResponse {
person_mention_view,

@ -18,7 +18,9 @@ pub async fn mark_reply_as_read(
local_user_view: LocalUserView,
) -> LemmyResult<Json<CommentReplyResponse>> {
let comment_reply_id = data.comment_reply_id;
let read_comment_reply = CommentReply::read(&mut context.pool(), comment_reply_id).await?;
let read_comment_reply = CommentReply::read(&mut context.pool(), comment_reply_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommentReply)?;
if local_user_view.person.id != read_comment_reply.recipient_id {
Err(LemmyErrorType::CouldntUpdateComment)?
@ -38,7 +40,9 @@ pub async fn mark_reply_as_read(
let comment_reply_id = read_comment_reply.id;
let person_id = local_user_view.person.id;
let comment_reply_view =
CommentReplyView::read(&mut context.pool(), comment_reply_id, Some(person_id)).await?;
CommentReplyView::read(&mut context.pool(), comment_reply_id, Some(person_id))
.await?
.ok_or(LemmyErrorType::CouldntFindCommentReply)?;
Ok(Json(CommentReplyResponse { comment_reply_view }))
}

@ -8,7 +8,7 @@ use lemmy_api_common::{
};
use lemmy_db_schema::source::password_reset_request::PasswordResetRequest;
use lemmy_db_views::structs::{LocalUserView, SiteView};
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
#[tracing::instrument(skip(context))]
pub async fn reset_password(
@ -18,8 +18,8 @@ pub async fn reset_password(
// Fetch that email
let email = data.email.to_lowercase();
let local_user_view = LocalUserView::find_by_email(&mut context.pool(), &email)
.await
.with_lemmy_type(LemmyErrorType::IncorrectLogin)?;
.await?
.ok_or(LemmyErrorType::IncorrectLogin)?;
// Check for too many attempts (to limit potential abuse)
let recent_resets_count = PasswordResetRequest::get_recent_password_resets_count(
@ -30,7 +30,9 @@ pub async fn reset_password(
if recent_resets_count >= 3 {
Err(LemmyErrorType::PasswordResetLimitReached)?
}
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
check_email_verified(&local_user_view, &site_view)?;
// Email the pure token to the user.

@ -35,7 +35,9 @@ pub async fn save_user_settings(
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<SuccessResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let slur_regex = local_site_to_slur_regex(&site_view.local_site);
let url_blocklist = get_url_blocklist(&context).await?;

@ -15,17 +15,19 @@ use lemmy_db_schema::{
RegistrationMode,
};
use lemmy_db_views::structs::SiteView;
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
pub async fn verify_email(
data: Json<VerifyEmail>,
context: Data<LemmyContext>,
) -> LemmyResult<Json<SuccessResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let token = data.token.clone();
let verification = EmailVerification::read_for_token(&mut context.pool(), &token)
.await
.with_lemmy_type(LemmyErrorType::TokenNotFound)?;
.await?
.ok_or(LemmyErrorType::TokenNotFound)?;
let form = LocalUserUpdateForm {
// necessary in case this is a new signup
@ -44,7 +46,10 @@ pub async fn verify_email(
if site_view.local_site.registration_mode == RegistrationMode::RequireApplication
&& site_view.local_site.application_email_admins
{
let person = Person::read(&mut context.pool(), local_user.person_id).await?;
let person = Person::read(&mut context.pool(), local_user.person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
send_new_applicant_email_to_admins(&person.name, &mut context.pool(), context.settings())
.await?;
}

@ -16,7 +16,7 @@ use lemmy_db_schema::{
PostFeatureType,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn feature_post(
@ -25,7 +25,9 @@ pub async fn feature_post(
local_user_view: LocalUserView,
) -> LemmyResult<Json<PostResponse>> {
let post_id = data.post_id;
let orig_post = Post::read(&mut context.pool(), post_id).await?;
let orig_post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
check_community_mod_action(
&local_user_view.person,

@ -11,7 +11,7 @@ pub async fn get_link_metadata(
data: Query<GetSiteMetadata>,
context: Data<LemmyContext>,
) -> LemmyResult<Json<GetSiteMetadataResponse>> {
let metadata = fetch_link_metadata(&data.url, false, &context).await?;
let metadata = fetch_link_metadata(&data.url, &context).await?;
Ok(Json(GetSiteMetadataResponse { metadata }))
}

@ -38,7 +38,9 @@ pub async fn like_post(
// Check for a community ban
let post_id = data.post_id;
let post = Post::read(&mut context.pool(), post_id).await?;
let post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
check_community_user_action(
&local_user_view.person,
@ -69,11 +71,15 @@ pub async fn like_post(
// Mark the post as read
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
let community = Community::read(&mut context.pool(), post.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
ActivityChannel::submit_activity(
SendActivityData::LikePostOrComment {
object_id: post.ap_id,
actor: local_user_view.person.clone(),
community: Community::read(&mut context.pool(), post.community_id).await?,
community,
score: data.score,
},
&context,

@ -6,7 +6,7 @@ use lemmy_api_common::{
};
use lemmy_db_schema::{source::post::Post, traits::Crud};
use lemmy_db_views::structs::{LocalUserView, VoteView};
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
/// Lists likes for a post
#[tracing::instrument(skip(context))]
@ -15,7 +15,9 @@ pub async fn list_post_likes(
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<ListPostLikesResponse>> {
let post = Post::read(&mut context.pool(), data.post_id).await?;
let post = Post::read(&mut context.pool(), data.post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
is_mod_or_admin(
&mut context.pool(),
&local_user_view.person,

@ -15,7 +15,7 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn lock_post(
@ -24,7 +24,9 @@ pub async fn lock_post(
local_user_view: LocalUserView,
) -> LemmyResult<Json<PostResponse>> {
let post_id = data.post_id;
let orig_post = Post::read(&mut context.pool(), post_id).await?;
let orig_post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
check_community_mod_action(
&local_user_view.person,

@ -34,7 +34,9 @@ pub async fn save_post(
let post_id = data.post_id;
let person_id = local_user_view.person.id;
let post_view = PostView::read(&mut context.pool(), post_id, Some(person_id), false).await?;
let post_view = PostView::read(&mut context.pool(), post_id, Some(person_id), false)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
// Mark the post as read
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;

@ -35,7 +35,9 @@ pub async fn create_post_report(
let person_id = local_user_view.person.id;
let post_id = data.post_id;
let post_view = PostView::read(&mut context.pool(), post_id, None, false).await?;
let post_view = PostView::read(&mut context.pool(), post_id, None, false)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
check_community_user_action(
&local_user_view.person,
@ -59,7 +61,9 @@ pub async fn create_post_report(
.await
.with_lemmy_type(LemmyErrorType::CouldntCreateReport)?;
let post_report_view = PostReportView::read(&mut context.pool(), report.id, person_id).await?;
let post_report_view = PostReportView::read(&mut context.pool(), report.id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPostReport)?;
// Email the admins
if local_site.reports_email_admins {

@ -17,7 +17,9 @@ pub async fn resolve_post_report(
) -> LemmyResult<Json<PostReportResponse>> {
let report_id = data.report_id;
let person_id = local_user_view.person.id;
let report = PostReportView::read(&mut context.pool(), report_id, person_id).await?;
let report = PostReportView::read(&mut context.pool(), report_id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPostReport)?;
let person_id = local_user_view.person.id;
check_community_mod_action(
@ -38,7 +40,9 @@ pub async fn resolve_post_report(
.with_lemmy_type(LemmyErrorType::CouldntResolveReport)?;
}
let post_report_view = PostReportView::read(&mut context.pool(), report_id, person_id).await?;
let post_report_view = PostReportView::read(&mut context.pool(), report_id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPostReport)?;
Ok(Json(PostReportResponse { post_report_view }))
}

@ -18,7 +18,9 @@ pub async fn mark_pm_as_read(
) -> LemmyResult<Json<PrivateMessageResponse>> {
// Checking permissions
let private_message_id = data.private_message_id;
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?;
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
if local_user_view.person.id != orig_private_message.recipient_id {
Err(LemmyErrorType::CouldntUpdatePrivateMessage)?
}
@ -37,7 +39,9 @@ pub async fn mark_pm_as_read(
.await
.with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?;
let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?;
let view = PrivateMessageView::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
Ok(Json(PrivateMessageResponse {
private_message_view: view,
}))

@ -29,7 +29,9 @@ pub async fn create_pm_report(
let person_id = local_user_view.person.id;
let private_message_id = data.private_message_id;
let private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?;
let private_message = PrivateMessage::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
// Make sure that only the recipient of the private message can create a report
if person_id != private_message.recipient_id {
@ -47,8 +49,9 @@ pub async fn create_pm_report(
.await
.with_lemmy_type(LemmyErrorType::CouldntCreateReport)?;
let private_message_report_view =
PrivateMessageReportView::read(&mut context.pool(), report.id).await?;
let private_message_report_view = PrivateMessageReportView::read(&mut context.pool(), report.id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessageReport)?;
// Email the admins
if local_site.reports_email_admins {

@ -28,8 +28,9 @@ pub async fn resolve_pm_report(
.with_lemmy_type(LemmyErrorType::CouldntResolveReport)?;
}
let private_message_report_view =
PrivateMessageReportView::read(&mut context.pool(), report_id).await?;
let private_message_report_view = PrivateMessageReportView::read(&mut context.pool(), report_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessageReport)?;
Ok(Json(PrivateMessageReportResponse {
private_message_report_view,

@ -5,13 +5,15 @@ use lemmy_api_common::{
utils::build_federated_instances,
};
use lemmy_db_views::structs::SiteView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn get_federated_instances(
context: Data<LemmyContext>,
) -> LemmyResult<Json<GetFederatedInstancesResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let federated_instances =
build_federated_instances(&site_view.local_site, &mut context.pool()).await?;

@ -55,7 +55,9 @@ pub async fn leave_admin(
ModAdd::create(&mut context.pool(), &form).await?;
// Reread site and admins
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let admins = PersonView::admins(&mut context.pool()).await?;
let all_languages = Language::read_all(&mut context.pool()).await?;

@ -4,8 +4,7 @@ use lemmy_api_common::{
person::{ListMedia, ListMediaResponse},
utils::is_admin,
};
use lemmy_db_schema::source::images::LocalImage;
use lemmy_db_views::structs::LocalUserView;
use lemmy_db_views::structs::{LocalImageView, LocalUserView};
use lemmy_utils::error::LemmyResult;
#[tracing::instrument(skip(context))]
@ -19,6 +18,6 @@ pub async fn list_all_media(
let page = data.page;
let limit = data.limit;
let images = LocalImage::get_all(&mut context.pool(), page, limit).await?;
let images = LocalImageView::get_all(&mut context.pool(), page, limit).await?;
Ok(Json(ListMediaResponse { images }))
}

@ -15,7 +15,7 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views::structs::{CommentView, LocalUserView};
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn purge_comment(
@ -29,7 +29,9 @@ pub async fn purge_comment(
let comment_id = data.comment_id;
// Read the comment to get the post_id and community
let comment_view = CommentView::read(&mut context.pool(), comment_id, None).await?;
let comment_view = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
let post_id = comment_view.comment.post_id;

@ -16,7 +16,7 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn purge_community(
@ -28,7 +28,9 @@ pub async fn purge_community(
is_admin(&local_user_view)?;
// Read the community to get its images
let community = Community::read(&mut context.pool(), data.community_id).await?;
let community = Community::read(&mut context.pool(), data.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
if let Some(banner) = &community.banner {
purge_image_from_pictrs(banner, &context).await.ok();

@ -16,7 +16,7 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn purge_person(
@ -27,7 +27,9 @@ pub async fn purge_person(
// Only let admin purge an item
is_admin(&local_user_view)?;
let person = Person::read(&mut context.pool(), data.person_id).await?;
let person = Person::read(&mut context.pool(), data.person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
ban_nonlocal_user_from_local_communities(
&local_user_view,
&person,

@ -16,7 +16,7 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn purge_post(
@ -28,7 +28,9 @@ pub async fn purge_post(
is_admin(&local_user_view)?;
// Read the post to get the community_id
let post = Post::read(&mut context.pool(), data.post_id).await?;
let post = Post::read(&mut context.pool(), data.post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
// Purge image
if let Some(url) = &post.url {

@ -13,7 +13,7 @@ use lemmy_db_schema::{
utils::diesel_option_overwrite,
};
use lemmy_db_views::structs::{LocalUserView, RegistrationApplicationView};
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
pub async fn approve_registration_application(
data: Json<ApproveRegistrationApplication>,
@ -45,8 +45,9 @@ pub async fn approve_registration_application(
LocalUser::update(&mut context.pool(), approved_user_id, &local_user_form).await?;
if data.approve {
let approved_local_user_view =
LocalUserView::read(&mut context.pool(), approved_user_id).await?;
let approved_local_user_view = LocalUserView::read(&mut context.pool(), approved_user_id)
.await?
.ok_or(LemmyErrorType::CouldntFindLocalUser)?;
if approved_local_user_view.local_user.email.is_some() {
send_application_approved_email(&approved_local_user_view, context.settings()).await?;
@ -54,8 +55,9 @@ pub async fn approve_registration_application(
}
// Read the view
let registration_application =
RegistrationApplicationView::read(&mut context.pool(), app_id).await?;
let registration_application = RegistrationApplicationView::read(&mut context.pool(), app_id)
.await?
.ok_or(LemmyErrorType::CouldntFindRegistrationApplication)?;
Ok(Json(RegistrationApplicationResponse {
registration_application,

@ -72,7 +72,7 @@ webpage = { version = "1.6", default-features = false, features = [
encoding = { version = "0.2.33", optional = true }
jsonwebtoken = { version = "8.3.0", optional = true }
# necessary for wasmt compilation
getrandom = { version = "0.2.12", features = ["js"] }
getrandom = { version = "0.2.14", features = ["js"] }
[package.metadata.cargo-machete]
ignored = ["getrandom"]

@ -27,6 +27,7 @@ use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{
error::LemmyResult,
utils::{markdown::markdown_to_html, mention::MentionData},
LemmyErrorType,
};
pub async fn build_comment_response(
@ -36,7 +37,9 @@ pub async fn build_comment_response(
recipient_ids: Vec<LocalUserId>,
) -> LemmyResult<CommentResponse> {
let person_id = local_user_view.map(|l| l.person.id);
let comment_view = CommentView::read(&mut context.pool(), comment_id, person_id).await?;
let comment_view = CommentView::read(&mut context.pool(), comment_id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
Ok(CommentResponse {
comment_view,
recipient_ids,
@ -58,7 +61,8 @@ pub async fn build_community_response(
Some(person_id),
is_mod_or_admin,
)
.await?;
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
let discussion_languages = CommunityLanguage::read(&mut context.pool(), community_id).await?;
Ok(Json(CommunityResponse {
@ -82,7 +86,8 @@ pub async fn build_post_response(
Some(person.id),
is_mod_or_admin,
)
.await?;
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
Ok(Json(PostResponse { post_view }))
}
@ -99,7 +104,9 @@ pub async fn send_local_notifs(
let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname());
// Read the comment view to get extra info
let comment_view = CommentView::read(&mut context.pool(), comment_id, None).await?;
let comment_view = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
let comment = comment_view.comment;
let post = comment_view.post;
let community = comment_view.community;
@ -111,7 +118,7 @@ pub async fn send_local_notifs(
{
let mention_name = mention.name.clone();
let user_view = LocalUserView::read_from_name(&mut context.pool(), &mention_name).await;
if let Ok(mention_user_view) = user_view {
if let Ok(Some(mention_user_view)) = user_view {
// TODO
// At some point, make it so you can't tag the parent creator either
// Potential duplication of notifications, one for reply and the other for mention, is handled below by checking recipient ids
@ -146,7 +153,9 @@ pub async fn send_local_notifs(
// Send comment_reply to the parent commenter / poster
if let Some(parent_comment_id) = comment.parent_comment_id() {
let parent_comment = Comment::read(&mut context.pool(), parent_comment_id).await?;
let parent_comment = Comment::read(&mut context.pool(), parent_comment_id)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
// Get the parent commenter local_user
let parent_creator_id = parent_comment.creator_id;
@ -165,7 +174,7 @@ pub async fn send_local_notifs(
// Don't send a notif to yourself
if parent_comment.creator_id != person.id && !check_blocks {
let user_view = LocalUserView::read_person(&mut context.pool(), parent_creator_id).await;
if let Ok(parent_user_view) = user_view {
if let Ok(Some(parent_user_view)) = user_view {
// Don't duplicate notif if already mentioned by checking recipient ids
if !recipient_ids.contains(&parent_user_view.local_user.id) {
recipient_ids.push(parent_user_view.local_user.id);
@ -212,7 +221,7 @@ pub async fn send_local_notifs(
if post.creator_id != person.id && !check_blocks {
let creator_id = post.creator_id;
let parent_user = LocalUserView::read_person(&mut context.pool(), creator_id).await;
if let Ok(parent_user_view) = parent_user {
if let Ok(Some(parent_user_view)) = parent_user {
if !recipient_ids.contains(&parent_user_view.local_user.id) {
recipient_ids.push(parent_user_view.local_user.id);

@ -99,7 +99,7 @@ mod tests {
async fn test_should_not_validate_user_token_after_password_change() {
let pool_ = build_db_pool_for_tests().await;
let pool = &mut (&pool_).into();
let secret = Secret::init(pool).await.unwrap();
let secret = Secret::init(pool).await.unwrap().unwrap();
let context = LemmyContext::create(
pool_.clone(),
ClientBuilder::new(Client::default()).build(),

@ -1,13 +1,13 @@
use crate::sensitive::Sensitive;
use lemmy_db_schema::{
newtypes::{CommentReplyId, CommunityId, LanguageId, PersonId, PersonMentionId},
source::{images::LocalImage, site::Site},
source::site::Site,
CommentSortType,
ListingType,
PostListingMode,
SortType,
};
use lemmy_db_views::structs::{CommentView, PostView};
use lemmy_db_views::structs::{CommentView, LocalImageView, PostView};
use lemmy_db_views_actor::structs::{
CommentReplyView,
CommunityModeratorView,
@ -437,5 +437,5 @@ pub struct ListMedia {
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ListMediaResponse {
pub images: Vec<LocalImage>,
pub images: Vec<LocalImageView>,
}

@ -270,8 +270,6 @@ pub struct LinkMetadata {
#[serde(flatten)]
pub opengraph_data: OpenGraphData,
pub content_type: Option<String>,
#[serde(skip)]
pub thumbnail: Option<DbUrl>,
}
#[skip_serializing_none]

@ -42,11 +42,7 @@ pub fn client_builder(settings: &Settings) -> ClientBuilder {
/// Fetches metadata for the given link and optionally generates thumbnail.
#[tracing::instrument(skip_all)]
pub async fn fetch_link_metadata(
url: &Url,
generate_thumbnail: bool,
context: &LemmyContext,
) -> LemmyResult<LinkMetadata> {
pub async fn fetch_link_metadata(url: &Url, context: &LemmyContext) -> LemmyResult<LinkMetadata> {
info!("Fetching site metadata for url: {}", url);
let response = context.client().get(url.as_str()).send().await?;
@ -63,71 +59,61 @@ pub async fn fetch_link_metadata(
let opengraph_data = extract_opengraph_data(&html_bytes, url)
.map_err(|e| info!("{e}"))
.unwrap_or_default();
let thumbnail =
extract_thumbnail_from_opengraph_data(url, &opengraph_data, generate_thumbnail, context).await;
Ok(LinkMetadata {
opengraph_data,
content_type: content_type.map(|c| c.to_string()),
thumbnail,
})
}
#[tracing::instrument(skip_all)]
pub async fn fetch_link_metadata_opt(
url: Option<&Url>,
generate_thumbnail: bool,
context: &LemmyContext,
) -> LinkMetadata {
match &url {
Some(url) => fetch_link_metadata(url, generate_thumbnail, context)
.await
.unwrap_or_default(),
_ => Default::default(),
}
}
/// Generate post thumbnail in background task, because some sites can be very slow to respond.
///
/// Takes a callback to generate a send activity task, so that post can be federated with metadata.
///
/// TODO: `federated_thumbnail` param can be removed once we federate full metadata and can
/// write it to db directly, without calling this function.
/// https://github.com/LemmyNet/lemmy/issues/4598
pub fn generate_post_link_metadata(
post: Post,
custom_thumbnail: Option<Url>,
federated_thumbnail: Option<Url>,
send_activity: impl FnOnce(Post) -> Option<SendActivityData> + Send + 'static,
local_site: Option<LocalSite>,
context: Data<LemmyContext>,
) {
spawn_try_task(async move {
// Decide if the thumbnail should be generated
let allow_sensitive = local_site_opt_to_sensitive(&local_site);
let page_is_sensitive = post.nsfw;
let allow_generate_thumbnail = allow_sensitive || !page_is_sensitive;
let do_generate_thumbnail =
allow_generate_thumbnail && custom_thumbnail.is_none() && post.thumbnail_url.is_none();
// Generate local thumbnail only if no thumbnail was federated and 'sensitive' attributes allow it.
let metadata = fetch_link_metadata_opt(
post.url.as_ref().map(DbUrl::inner),
do_generate_thumbnail,
&context,
)
.await;
// If its an image post, it needs to overwrite the thumbnail, and take precedence
let image_url = if metadata
let metadata = match &post.url {
Some(url) => fetch_link_metadata(url, &context).await.unwrap_or_default(),
_ => Default::default(),
};
let is_image_post = metadata
.content_type
.as_ref()
.is_some_and(|content_type| content_type.starts_with("image"))
{
post.url.map(Into::into)
} else {
None
};
.is_some_and(|content_type| content_type.starts_with("image"));
// Decide if we are allowed to generate local thumbnail
let allow_sensitive = local_site_opt_to_sensitive(&local_site);
let allow_generate_thumbnail = allow_sensitive || !post.nsfw;
// Build the thumbnail url based on either the post image url, custom thumbnail, metadata fetch, or existing thumbnail.
let thumbnail_url = image_url
.or(custom_thumbnail)
.or(metadata.thumbnail.map(Into::into))
.or(post.thumbnail_url.map(Into::into));
// Use custom thumbnail if available and its not an image post
let thumbnail_url = if !is_image_post && custom_thumbnail.is_some() {
custom_thumbnail
}
// Use federated thumbnail if available
else if federated_thumbnail.is_some() {
federated_thumbnail
}
// Generate local thumbnail if allowed
else if allow_generate_thumbnail {
match post.url.or(metadata.opengraph_data.image) {
Some(url) => generate_pictrs_thumbnail(&url, &context).await.ok(),
None => None,
}
}
// Otherwise use opengraph preview image directly
else {
metadata.opengraph_data.image.map(Into::into)
};
// Proxy the image fetch if necessary
let proxied_thumbnail_url = proxy_image_link_opt_apub(thumbnail_url, &context).await?;
@ -213,28 +199,6 @@ fn extract_opengraph_data(html_bytes: &[u8], url: &Url) -> LemmyResult<OpenGraph
})
}
#[tracing::instrument(skip_all)]
pub async fn extract_thumbnail_from_opengraph_data(
url: &Url,
opengraph_data: &OpenGraphData,
generate_thumbnail: bool,
context: &LemmyContext,
) -> Option<DbUrl> {
if generate_thumbnail {
let image_url = opengraph_data
.image
.as_ref()
.map(DbUrl::inner)
.unwrap_or(url);
generate_pictrs_thumbnail(image_url, context)
.await
.ok()
.map(Into::into)
} else {
opengraph_data.image.clone()
}
}
#[derive(Deserialize, Debug)]
struct PictrsResponse {
files: Vec<PictrsFile>,
@ -414,9 +378,7 @@ mod tests {
async fn test_link_metadata() {
let context = LemmyContext::init_test_context().await;
let sample_url = Url::parse("https://gitlab.com/IzzyOnDroid/repo/-/wikis/FAQ").unwrap();
let sample_res = fetch_link_metadata(&sample_url, false, &context)
.await
.unwrap();
let sample_res = fetch_link_metadata(&sample_url, &context).await.unwrap();
assert_eq!(
Some("FAQ · Wiki · IzzyOnDroid / repo · GitLab".to_string()),
sample_res.opengraph_data.title
@ -438,17 +400,8 @@ mod tests {
Some(mime::TEXT_HTML_UTF_8.to_string()),
sample_res.content_type
);
assert!(sample_res.thumbnail.is_some());
}
// #[test]
// fn test_pictshare() {
// let res = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpg");
// assert!(res.is_ok());
// let res_other = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpgaoeu");
// assert!(res_other.is_err());
// }
#[test]
fn test_resolve_image_url() {
// url that lists the opengraph fields

@ -12,7 +12,7 @@ use lemmy_db_schema::{
community::{Community, CommunityModerator, CommunityUpdateForm},
community_block::CommunityBlock,
email_verification::{EmailVerification, EmailVerificationForm},
images::{LocalImage, RemoteImage},
images::RemoteImage,
instance::Instance,
instance_block::InstanceBlock,
local_site::LocalSite,
@ -27,7 +27,10 @@ use lemmy_db_schema::{
traits::Crud,
utils::DbPool,
};
use lemmy_db_views::{comment_view::CommentQuery, structs::LocalUserView};
use lemmy_db_views::{
comment_view::CommentQuery,
structs::{LocalImageView, LocalUserView},
};
use lemmy_db_views_actor::structs::{
CommunityModeratorView,
CommunityPersonBanView,
@ -139,8 +142,8 @@ pub fn is_top_mod(
#[tracing::instrument(skip_all)]
pub async fn get_post(post_id: PostId, pool: &mut DbPool<'_>) -> LemmyResult<Post> {
Post::read(pool, post_id)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindPost)
.await?
.ok_or(LemmyErrorType::CouldntFindPost.into())
}
#[tracing::instrument(skip_all)]
@ -188,8 +191,8 @@ async fn check_community_deleted_removed(
pool: &mut DbPool<'_>,
) -> LemmyResult<()> {
let community = Community::read(pool, community_id)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
if community.deleted || community.removed {
Err(LemmyErrorType::Deleted)?
}
@ -660,15 +663,20 @@ pub async fn purge_image_posts_for_person(
/// Delete a local_user's images
async fn delete_local_user_images(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> {
if let Ok(local_user) = LocalUserView::read_person(&mut context.pool(), person_id).await {
if let Ok(Some(local_user)) = LocalUserView::read_person(&mut context.pool(), person_id).await {
let pictrs_uploads =
LocalImage::get_all_by_local_user_id(&mut context.pool(), local_user.local_user.id).await?;
LocalImageView::get_all_by_local_user_id(&mut context.pool(), local_user.local_user.id)
.await?;
// Delete their images
for upload in pictrs_uploads {
delete_image_from_pictrs(&upload.pictrs_alias, &upload.pictrs_delete_token, context)
.await
.ok();
delete_image_from_pictrs(
&upload.local_image.pictrs_alias,
&upload.local_image.pictrs_delete_token,
context,
)
.await
.ok();
}
}
Ok(())
@ -700,7 +708,9 @@ pub async fn remove_user_data(
) -> LemmyResult<()> {
let pool = &mut context.pool();
// Purge user images
let person = Person::read(pool, banned_person_id).await?;
let person = Person::read(pool, banned_person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
if let Some(avatar) = person.avatar {
purge_image_from_pictrs(&avatar, context).await.ok();
}
@ -813,7 +823,9 @@ pub async fn remove_user_data_in_community(
pub async fn purge_user_account(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> {
let pool = &mut context.pool();
let person = Person::read(pool, person_id).await?;
let person = Person::read(pool, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
// Delete their local images, if they're a local user
delete_local_user_images(person_id, context).await.ok();

@ -70,7 +70,8 @@ pub async fn create_comment(
Comment::read(&mut context.pool(), parent_id).await.ok()
} else {
None
};
}
.flatten();
// If there's a parent_id, check to make sure that comment is in that post
// Strange issue where sometimes the post ID of the parent comment is incorrect
@ -172,7 +173,7 @@ pub async fn create_comment(
let parent_id = parent.id;
let comment_reply =
CommentReply::read_by_comment_and_person(&mut context.pool(), parent_id, person_id).await;
if let Ok(reply) = comment_reply {
if let Ok(Some(reply)) = comment_reply {
CommentReply::update(
&mut context.pool(),
reply.id,
@ -185,7 +186,7 @@ pub async fn create_comment(
// If the parent has PersonMentions mark them as read too
let person_mention =
PersonMention::read_by_comment_and_person(&mut context.pool(), parent_id, person_id).await;
if let Ok(mention) = person_mention {
if let Ok(Some(mention)) = person_mention {
PersonMention::update(
&mut context.pool(),
mention.id,

@ -21,7 +21,9 @@ pub async fn delete_comment(
local_user_view: LocalUserView,
) -> LemmyResult<Json<CommentResponse>> {
let comment_id = data.comment_id;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
// Dont delete it if its already been deleted.
if orig_comment.comment.deleted == data.deleted {

@ -25,7 +25,9 @@ pub async fn remove_comment(
local_user_view: LocalUserView,
) -> LemmyResult<Json<CommentResponse>> {
let comment_id = data.comment_id;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
check_community_mod_action(
&local_user_view.person,

@ -36,7 +36,9 @@ pub async fn update_comment(
let local_site = LocalSite::read(&mut context.pool()).await?;
let comment_id = data.comment_id;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
check_community_user_action(
&local_user_view.person,

@ -46,7 +46,9 @@ pub async fn create_community(
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<CommunityResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let local_site = site_view.local_site;
if local_site.community_creation_admin_only && is_admin(&local_user_view).is_err() {

@ -6,7 +6,7 @@ use lemmy_api_common::{
};
use lemmy_db_views::structs::{LocalUserView, SiteView};
use lemmy_db_views_actor::community_view::CommunityQuery;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn list_communities(
@ -14,7 +14,9 @@ pub async fn list_communities(
context: Data<LemmyContext>,
local_user_view: Option<LocalUserView>,
) -> LemmyResult<Json<ListCommunitiesResponse>> {
let local_site = SiteView::read_local(&mut context.pool()).await?;
let local_site = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let is_admin = local_user_view
.as_ref()
.map(|luv| is_admin(luv).is_ok())

@ -43,7 +43,9 @@ pub async fn update_community(
let description =
process_markdown_opt(&data.description, &slur_regex, &url_blocklist, &context).await?;
is_valid_body_field(&data.description, false)?;
let old_community = Community::read(&mut context.pool(), data.community_id).await?;
let old_community = Community::read(&mut context.pool(), data.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
replace_image(&data.icon, &old_community.icon, &context).await?;
replace_image(&data.banner, &old_community.banner, &context).await?;

@ -85,7 +85,9 @@ pub async fn create_post(
.await?;
let community_id = data.community_id;
let community = Community::read(&mut context.pool(), community_id).await?;
let community = Community::read(&mut context.pool(), community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
if community.posting_restricted_to_mods {
let community_id = data.community_id;
let is_mod = CommunityModeratorView::is_community_moderator(
@ -157,6 +159,7 @@ pub async fn create_post(
generate_post_link_metadata(
updated_post.clone(),
custom_thumbnail,
None,
|post| Some(SendActivityData::CreatePost(post)),
Some(local_site),
context.reset_request_count(),

@ -21,7 +21,9 @@ pub async fn delete_post(
local_user_view: LocalUserView,
) -> LemmyResult<Json<PostResponse>> {
let post_id = data.post_id;
let orig_post = Post::read(&mut context.pool(), post_id).await?;
let orig_post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
// Dont delete it if its already been deleted.
if orig_post.deleted == data.deleted {

@ -22,7 +22,9 @@ pub async fn get_post(
context: Data<LemmyContext>,
local_user_view: Option<LocalUserView>,
) -> LemmyResult<Json<GetPostResponse>> {
let local_site = SiteView::read_local(&mut context.pool()).await?;
let local_site = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
check_private_instance(&local_user_view, &local_site.local_site)?;
@ -33,15 +35,19 @@ pub async fn get_post(
id
} else if let Some(comment_id) = data.comment_id {
Comment::read(&mut context.pool(), comment_id)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindPost)?
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?
.post_id
} else {
Err(LemmyErrorType::CouldntFindPost)?
};
// Check to see if the person is a mod or admin, to show deleted / removed
let community_id = Post::read(&mut context.pool(), post_id).await?.community_id;
let community_id = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?
.community_id;
let is_mod_or_admin = is_mod_or_admin_opt(
&mut context.pool(),
local_user_view.as_ref(),
@ -51,8 +57,8 @@ pub async fn get_post(
.is_ok();
let post_view = PostView::read(&mut context.pool(), post_id, person_id, is_mod_or_admin)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindPost)?;
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
// Mark the post as read
let post_id = post_view.post.id;
@ -67,8 +73,8 @@ pub async fn get_post(
person_id,
is_mod_or_admin,
)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
// Insert into PersonPostAggregates
// to update the read_comments count

@ -16,7 +16,7 @@ use lemmy_db_schema::{
traits::{Crud, Reportable},
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn remove_post(
@ -25,7 +25,9 @@ pub async fn remove_post(
local_user_view: LocalUserView,
) -> LemmyResult<Json<PostResponse>> {
let post_id = data.post_id;
let orig_post = Post::read(&mut context.pool(), post_id).await?;
let orig_post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
check_community_mod_action(
&local_user_view.person,

@ -70,7 +70,9 @@ pub async fn update_post(
check_url_scheme(&custom_thumbnail)?;
let post_id = data.post_id;
let orig_post = Post::read(&mut context.pool(), post_id).await?;
let orig_post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
check_community_user_action(
&local_user_view.person,
@ -116,6 +118,7 @@ pub async fn update_post(
generate_post_link_metadata(
updated_post.clone(),
custom_thumbnail,
None,
|post| Some(SendActivityData::UpdatePost(post)),
Some(local_site),
context.reset_request_count(),

@ -76,12 +76,16 @@ pub async fn create_private_message(
.await
.with_lemmy_type(LemmyErrorType::CouldntCreatePrivateMessage)?;
let view = PrivateMessageView::read(&mut context.pool(), inserted_private_message.id).await?;
let view = PrivateMessageView::read(&mut context.pool(), inserted_private_message.id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
// Send email to the local recipient, if one exists
if view.recipient.local {
let recipient_id = data.recipient_id;
let local_recipient = LocalUserView::read_person(&mut context.pool(), recipient_id).await?;
let local_recipient = LocalUserView::read_person(&mut context.pool(), recipient_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
let lang = get_interface_language(&local_recipient);
let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname());
let sender_name = &local_user_view.person.name;

@ -20,7 +20,9 @@ pub async fn delete_private_message(
) -> LemmyResult<Json<PrivateMessageResponse>> {
// Checking permissions
let private_message_id = data.private_message_id;
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?;
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
if local_user_view.person.id != orig_private_message.creator_id {
Err(LemmyErrorType::EditPrivateMessageNotAllowed)?
}
@ -45,7 +47,9 @@ pub async fn delete_private_message(
)
.await?;
let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?;
let view = PrivateMessageView::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
Ok(Json(PrivateMessageResponse {
private_message_view: view,
}))

@ -30,7 +30,9 @@ pub async fn update_private_message(
// Checking permissions
let private_message_id = data.private_message_id;
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?;
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
if local_user_view.person.id != orig_private_message.creator_id {
Err(LemmyErrorType::EditPrivateMessageNotAllowed)?
}
@ -54,7 +56,9 @@ pub async fn update_private_message(
.await
.with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?;
let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?;
let view = PrivateMessageView::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
ActivityChannel::submit_activity(
SendActivityData::UpdatePrivateMessage(view.clone()),

@ -129,7 +129,9 @@ pub async fn create_site(
LocalSiteRateLimit::update(&mut context.pool(), &local_site_rate_limit_form).await?;
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let new_taglines = data.taglines.clone();
let taglines = Tagline::replace(&mut context.pool(), local_site.id, new_taglines).await?;

@ -41,7 +41,9 @@ pub async fn get_site(
// This data is independent from the user account so we can cache it across requests
let mut site_response = CACHE
.try_get_with::<_, LemmyError>((), async {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let admins = PersonView::admins(&mut context.pool()).await?;
let all_languages = Language::read_all(&mut context.pool()).await?;
let discussion_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?;

@ -52,7 +52,9 @@ pub async fn update_site(
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<SiteResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let local_site = site_view.local_site;
let site = site_view.site;
@ -181,7 +183,9 @@ pub async fn update_site(
let new_taglines = data.taglines.clone();
let taglines = Tagline::replace(&mut context.pool(), local_site.id, new_taglines).await?;
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let rate_limit_config =
local_site_rate_limit_to_rate_limit_config(&site_view.local_site_rate_limit);

@ -45,7 +45,9 @@ pub async fn register(
req: HttpRequest,
context: Data<LemmyContext>,
) -> LemmyResult<Json<LoginResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let local_site = site_view.local_site;
let require_registration_application =
local_site.registration_mode == RegistrationMode::RequireApplication;

@ -23,7 +23,10 @@ use lemmy_db_schema::{
utils::DbPool,
};
use lemmy_db_views::structs::SiteView;
use lemmy_utils::error::{LemmyError, LemmyResult};
use lemmy_utils::{
error::{LemmyError, LemmyResult},
LemmyErrorType,
};
use serde::Deserialize;
use url::Url;
@ -134,7 +137,13 @@ pub(crate) async fn send_ban_from_site(
expires: Option<i64>,
context: Data<LemmyContext>,
) -> LemmyResult<()> {
let site = SiteOrCommunity::Site(SiteView::read_local(&mut context.pool()).await?.site.into());
let site = SiteOrCommunity::Site(
SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?
.site
.into(),
);
let expires = check_expire_time(expires)?;
// if the action affects a local user, federate to other instances
@ -174,6 +183,7 @@ pub(crate) async fn send_ban_from_community(
) -> LemmyResult<()> {
let community: ApubCommunity = Community::read(&mut context.pool(), community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
let expires = check_expire_time(data.expires)?;

@ -36,7 +36,10 @@ use lemmy_db_schema::{
},
traits::{Crud, Joinable},
};
use lemmy_utils::error::{LemmyError, LemmyResult};
use lemmy_utils::{
error::{LemmyError, LemmyResult},
LemmyErrorType,
};
use url::Url;
impl CollectionAdd {
@ -126,7 +129,9 @@ impl ActivityHandler for CollectionAdd {
async fn receive(self, context: &Data<Self::DataType>) -> LemmyResult<()> {
insert_received_activity(&self.id, context).await?;
let (community, collection_type) =
Community::get_by_collection_url(&mut context.pool(), &self.target.into()).await?;
Community::get_by_collection_url(&mut context.pool(), &self.target.into())
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
match collection_type {
CollectionType::Moderators => {
let new_mod = ObjectId::<ApubPerson>::from(self.object)
@ -183,9 +188,11 @@ pub(crate) async fn send_add_mod_to_community(
let actor: ApubPerson = actor.into();
let community: ApubCommunity = Community::read(&mut context.pool(), community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
let updated_mod: ApubPerson = Person::read(&mut context.pool(), updated_mod_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?
.into();
if added {
CollectionAdd::send_add_mod(&community, &updated_mod, &actor, &context).await
@ -204,6 +211,7 @@ pub(crate) async fn send_feature_post(
let post: ApubPost = post.into();
let community = Community::read(&mut context.pool(), post.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
if featured {
CollectionAdd::send_add_featured_post(&community, &post, &actor, &context).await

@ -31,7 +31,10 @@ use lemmy_db_schema::{
},
traits::{Crud, Joinable},
};
use lemmy_utils::error::{LemmyError, LemmyResult};
use lemmy_utils::{
error::{LemmyError, LemmyResult},
LemmyErrorType,
};
use url::Url;
impl CollectionRemove {
@ -121,7 +124,9 @@ impl ActivityHandler for CollectionRemove {
async fn receive(self, context: &Data<Self::DataType>) -> LemmyResult<()> {
insert_received_activity(&self.id, context).await?;
let (community, collection_type) =
Community::get_by_collection_url(&mut context.pool(), &self.target.into()).await?;
Community::get_by_collection_url(&mut context.pool(), &self.target.into())
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
match collection_type {
CollectionType::Moderators => {
let remove_mod = ObjectId::<ApubPerson>::from(self.object)

@ -31,7 +31,10 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_utils::error::{LemmyError, LemmyResult};
use lemmy_utils::{
error::{LemmyError, LemmyResult},
LemmyErrorType,
};
use url::Url;
#[async_trait::async_trait]
@ -109,6 +112,7 @@ pub(crate) async fn send_lock_post(
) -> LemmyResult<()> {
let community: ApubCommunity = Community::read(&mut context.pool(), post.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
let id = generate_activity_id(
LockType::Lock,

@ -29,7 +29,10 @@ use lemmy_db_schema::{
},
traits::{Crud, Reportable},
};
use lemmy_utils::error::{LemmyError, LemmyResult};
use lemmy_utils::{
error::{LemmyError, LemmyResult},
LemmyErrorType,
};
use url::Url;
impl Report {
@ -67,7 +70,9 @@ impl Report {
PostOrComment::Post(p) => p.creator_id,
PostOrComment::Comment(c) => c.creator_id,
};
let object_creator = Person::read(&mut context.pool(), object_creator_id).await?;
let object_creator = Person::read(&mut context.pool(), object_creator_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
let object_creator_site: Option<ApubSite> =
Site::read_from_instance_id(&mut context.pool(), object_creator.instance_id)
.await?

@ -42,6 +42,7 @@ use lemmy_db_schema::{
use lemmy_utils::{
error::{LemmyError, LemmyResult},
utils::mention::scrape_text_for_mentions,
LemmyErrorType,
};
use url::Url;
@ -55,11 +56,17 @@ impl CreateOrUpdateNote {
) -> LemmyResult<()> {
// TODO: might be helpful to add a comment method to retrieve community directly
let post_id = comment.post_id;
let post = Post::read(&mut context.pool(), post_id).await?;
let post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
let community_id = post.community_id;
let person: ApubPerson = Person::read(&mut context.pool(), person_id).await?.into();
let person: ApubPerson = Person::read(&mut context.pool(), person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?
.into();
let community: ApubCommunity = Community::read(&mut context.pool(), community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
let id = generate_activity_id(

@ -68,9 +68,13 @@ impl CreateOrUpdatePage {
) -> LemmyResult<()> {
let post = ApubPost(post);
let community_id = post.community_id;
let person: ApubPerson = Person::read(&mut context.pool(), person_id).await?.into();
let person: ApubPerson = Person::read(&mut context.pool(), person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?
.into();
let community: ApubCommunity = Community::read(&mut context.pool(), community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
let create_or_update =

@ -39,7 +39,7 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
use std::ops::Deref;
use url::Url;
@ -87,6 +87,7 @@ pub(crate) async fn send_apub_delete_private_message(
let recipient_id = pm.recipient_id;
let recipient: ApubPerson = Person::read(&mut context.pool(), recipient_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?
.into();
let deletable = DeletableObjects::PrivateMessage(pm.into());

@ -245,7 +245,9 @@ pub async fn match_outgoing_activities(
CreateOrUpdatePage::send(post, creator_id, CreateOrUpdateType::Update, context).await
}
DeletePost(post, person, data) => {
let community = Community::read(&mut context.pool(), post.community_id).await?;
let community = Community::read(&mut context.pool(), post.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
send_apub_delete_in_community(
person,
community,
@ -262,7 +264,9 @@ pub async fn match_outgoing_activities(
reason,
removed,
} => {
let community = Community::read(&mut context.pool(), post.community_id).await?;
let community = Community::read(&mut context.pool(), post.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
send_apub_delete_in_community(
moderator,
community,

@ -44,7 +44,7 @@ pub(crate) async fn send_like_activity(
let activity = AnnouncableActivities::Vote(vote);
send_activity_in_community(activity, &actor, &community, empty, false, &context).await
} else {
// Lemmy API doesnt distinguish between Undo/Like and Undo/Dislike, so we hardcode it here.
// Lemmy API doesn't distinguish between Undo/Like and Undo/Dislike, so we hardcode it here.
let vote = Vote::new(object_id, &actor, &community, VoteType::Like, &context)?;
let undo_vote = UndoVote::new(vote, &actor, &community, &context)?;
let activity = AnnouncableActivities::UndoVote(undo_vote);

@ -58,7 +58,12 @@ pub async fn list_comments(
// If a parent_id is given, fetch the comment to get the path
let parent_path = if let Some(parent_id) = parent_id {
Some(Comment::read(&mut context.pool(), parent_id).await?.path)
Some(
Comment::read(&mut context.pool(), parent_id)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?
.path,
)
} else {
None
};

@ -23,7 +23,9 @@ pub async fn list_posts(
context: Data<LemmyContext>,
local_user_view: Option<LocalUserView>,
) -> LemmyResult<Json<GetPostsResponse>> {
let local_site = SiteView::read_local(&mut context.pool()).await?;
let local_site = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
check_private_instance(&local_user_view, &local_site.local_site)?;

@ -56,8 +56,8 @@ pub async fn get_community(
person_id,
is_mod_or_admin,
)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id)
.await

@ -26,7 +26,9 @@ pub async fn read_person(
Err(LemmyErrorType::NoIdGiven)?
}
let local_site = SiteView::read_local(&mut context.pool()).await?;
let local_site = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
check_private_instance(&local_user_view, &local_site.local_site)?;
@ -46,7 +48,9 @@ pub async fn read_person(
// You don't need to return settings for the user, since this comes back with GetSite
// `my_user`
let person_view = PersonView::read(&mut context.pool(), person_details_id).await?;
let person_view = PersonView::read(&mut context.pool(), person_details_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
let sort = data.sort;
let page = data.page;

@ -53,20 +53,36 @@ async fn convert_response(
match object {
Post(p) => {
removed_or_deleted = p.deleted || p.removed;
res.post = Some(PostView::read(pool, p.id, user_id, false).await?)
res.post = Some(
PostView::read(pool, p.id, user_id, false)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?,
)
}
Comment(c) => {
removed_or_deleted = c.deleted || c.removed;
res.comment = Some(CommentView::read(pool, c.id, user_id).await?)
res.comment = Some(
CommentView::read(pool, c.id, user_id)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?,
)
}
PersonOrCommunity(p) => match *p {
UserOrCommunity::User(u) => {
removed_or_deleted = u.deleted;
res.person = Some(PersonView::read(pool, u.id).await?)
res.person = Some(
PersonView::read(pool, u.id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?,
)
}
UserOrCommunity::Community(c) => {
removed_or_deleted = c.deleted || c.removed;
res.community = Some(CommunityView::read(pool, c.id, user_id, false).await?)
res.community = Some(
CommunityView::read(pool, c.id, user_id, false)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?,
)
}
},
};

@ -13,7 +13,7 @@ use lemmy_db_views::{
structs::{LocalUserView, SiteView},
};
use lemmy_db_views_actor::{community_view::CommunityQuery, person_view::PersonQuery};
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn search(
@ -21,7 +21,9 @@ pub async fn search(
context: Data<LemmyContext>,
local_user_view: Option<LocalUserView>,
) -> LemmyResult<Json<SearchResponse>> {
let local_site = SiteView::read_local(&mut context.pool()).await?;
let local_site = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
check_private_instance(&local_user_view, &local_site.local_site)?;

@ -363,7 +363,11 @@ mod tests {
.build();
let local_user = LocalUser::create(&mut context.pool(), &user_form, vec![]).await?;
Ok(LocalUserView::read(&mut context.pool(), local_user.id).await?)
Ok(
LocalUserView::read(&mut context.pool(), local_user.id)
.await?
.ok_or(LemmyErrorType::CouldntFindLocalUser)?,
)
}
#[tokio::test]
@ -396,8 +400,9 @@ mod tests {
// wait for background task to finish
sleep(Duration::from_millis(1000)).await;
let import_user_updated =
LocalUserView::read(&mut context.pool(), import_user.local_user.id).await?;
let import_user_updated = LocalUserView::read(&mut context.pool(), import_user.local_user.id)
.await?
.ok_or(LemmyErrorType::CouldntFindLocalUser)?;
assert_eq!(
export_user.person.display_name,

@ -23,7 +23,10 @@ use lemmy_db_schema::{
traits::Crud,
utils::FETCH_LIMIT_MAX,
};
use lemmy_utils::error::{LemmyError, LemmyResult};
use lemmy_utils::{
error::{LemmyError, LemmyResult},
LemmyErrorType,
};
use url::Url;
#[derive(Clone, Debug)]
@ -47,6 +50,7 @@ impl Collection for ApubCommunityOutbox {
for post in post_list {
let person = Person::read(&mut data.pool(), post.creator_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?
.into();
let create =
CreateOrUpdatePage::new(post, &person, owner, CreateOrUpdateType::Create, data).await?;

@ -42,9 +42,12 @@ where
.splitn(2, '@')
.collect_tuple()
.expect("invalid query");
let actor = DbActor::read_from_name_and_domain(&mut context.pool(), name, domain).await;
if actor.is_ok() {
Ok(actor?.into())
let actor = DbActor::read_from_name_and_domain(&mut context.pool(), name, domain)
.await
.ok()
.flatten();
if let Some(actor) = actor {
Ok(actor.into())
} else if local_user_view.is_some() {
// Fetch the actor from its home instance using webfinger
let actor: ActorType = webfinger_resolve_actor(&identifier.to_lowercase(), context).await?;
@ -59,6 +62,7 @@ where
Ok(
DbActor::read_from_name(&mut context.pool(), &identifier, include_deleted)
.await?
.ok_or(NotFound)?
.into(),
)
}

@ -12,7 +12,10 @@ use lemmy_db_schema::{
source::{community::Community, post::Post},
traits::Crud,
};
use lemmy_utils::error::{LemmyError, LemmyResult};
use lemmy_utils::{
error::{LemmyError, LemmyResult},
LemmyErrorType,
};
use serde::Deserialize;
use url::Url;
@ -91,9 +94,15 @@ impl InCommunity for PostOrComment {
PostOrComment::Comment(c) => {
Post::read(&mut context.pool(), c.post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?
.community_id
}
};
Ok(Community::read(&mut context.pool(), cid).await?.into())
Ok(
Community::read(&mut context.pool(), cid)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into(),
)
}
}

@ -15,7 +15,7 @@ use lemmy_db_schema::{
source::{comment::Comment, community::Community, post::Post},
traits::Crud,
};
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
use serde::Deserialize;
#[derive(Deserialize)]
@ -31,9 +31,16 @@ pub(crate) async fn get_apub_comment(
) -> LemmyResult<HttpResponse> {
let id = CommentId(info.comment_id.parse::<i32>()?);
// Can't use CommentView here because it excludes deleted/removed/local-only items
let comment: ApubComment = Comment::read(&mut context.pool(), id).await?.into();
let post = Post::read(&mut context.pool(), comment.post_id).await?;
let community = Community::read(&mut context.pool(), post.community_id).await?;
let comment: ApubComment = Comment::read(&mut context.pool(), id)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?
.into();
let post = Post::read(&mut context.pool(), comment.post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
let community = Community::read(&mut context.pool(), post.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
check_community_public(&community)?;
if !comment.local {

@ -18,7 +18,7 @@ use activitypub_federation::{
use actix_web::{web, web::Bytes, HttpRequest, HttpResponse};
use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{source::community::Community, traits::ApubActor};
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
use serde::Deserialize;
#[derive(Deserialize, Clone)]
@ -35,6 +35,7 @@ pub(crate) async fn get_apub_community_http(
let community: ApubCommunity =
Community::read_from_name(&mut context.pool(), &info.community_name, true)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
if community.deleted || community.removed {
@ -64,8 +65,9 @@ pub(crate) async fn get_apub_community_followers(
info: web::Path<CommunityQuery>,
context: Data<LemmyContext>,
) -> LemmyResult<HttpResponse> {
let community =
Community::read_from_name(&mut context.pool(), &info.community_name, false).await?;
let community = Community::read_from_name(&mut context.pool(), &info.community_name, false)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
check_community_public(&community)?;
let followers = ApubCommunityFollower::read_local(&community.into(), &context).await?;
create_apub_response(&followers)
@ -80,6 +82,7 @@ pub(crate) async fn get_apub_community_outbox(
let community: ApubCommunity =
Community::read_from_name(&mut context.pool(), &info.community_name, false)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
check_community_public(&community)?;
let outbox = ApubCommunityOutbox::read_local(&community, &context).await?;
@ -94,6 +97,7 @@ pub(crate) async fn get_apub_community_moderators(
let community: ApubCommunity =
Community::read_from_name(&mut context.pool(), &info.community_name, false)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
check_community_public(&community)?;
let moderators = ApubCommunityModerators::read_local(&community, &context).await?;
@ -108,6 +112,7 @@ pub(crate) async fn get_apub_community_featured(
let community: ApubCommunity =
Community::read_from_name(&mut context.pool(), &info.community_name, false)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
check_community_public(&community)?;
let featured = ApubCommunityFeatured::read_local(&community, &context).await?;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save