Merge remote-tracking branch 'origin/main' into persistent-queue

This commit is contained in:
phiresky 2023-08-31 15:00:32 +00:00
commit 6e445ac581
107 changed files with 707 additions and 1204 deletions

View File

@ -239,7 +239,7 @@ steps:
settings: settings:
repo: dessalines/lemmy repo: dessalines/lemmy
dockerfile: docker/Dockerfile dockerfile: docker/Dockerfile
platforms: linux/amd64 platforms: linux/amd64,linux/arm64
build_args: build_args:
- RUST_RELEASE_MODE=release - RUST_RELEASE_MODE=release
auto_tag: true auto_tag: true
@ -252,7 +252,7 @@ steps:
settings: settings:
repo: dessalines/lemmy repo: dessalines/lemmy
dockerfile: docker/Dockerfile dockerfile: docker/Dockerfile
platforms: linux/amd64 platforms: linux/amd64,linux/arm64
build_args: build_args:
- RUST_RELEASE_MODE=release - RUST_RELEASE_MODE=release
tag: dev tag: dev

View File

@ -19,7 +19,7 @@
"eslint": "^8.40.0", "eslint": "^8.40.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"jest": "^29.5.0", "jest": "^29.5.0",
"lemmy-js-client": "0.19.0-rc.2", "lemmy-js-client": "0.19.0-rc.3",
"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"

View File

@ -21,6 +21,8 @@ import {
registerUser, registerUser,
API, API,
getPosts, getPosts,
getComments,
createComment,
getCommunityByName, getCommunityByName,
} from "./shared"; } from "./shared";
@ -245,12 +247,17 @@ test("moderator view", async () => {
client: alpha.client, client: alpha.client,
}; };
expect(otherUser.auth).not.toBe(""); expect(otherUser.auth).not.toBe("");
let otherCommunity = (await createCommunity(otherUser)).community_view; let otherCommunity = (await createCommunity(otherUser)).community_view;
expect(otherCommunity.community.name).toBeDefined(); expect(otherCommunity.community.name).toBeDefined();
let otherPost = (await createPost(otherUser, otherCommunity.community.id)) let otherPost = (await createPost(otherUser, otherCommunity.community.id))
.post_view; .post_view;
expect(otherPost.post.id).toBeDefined(); expect(otherPost.post.id).toBeDefined();
let otherComment = (await createComment(otherUser, otherPost.post.id))
.comment_view;
expect(otherComment.comment.id).toBeDefined();
// create a community and post on alpha // create a community and post on alpha
let alphaCommunity = (await createCommunity(alpha)).community_view; let alphaCommunity = (await createCommunity(alpha)).community_view;
expect(alphaCommunity.community.name).toBeDefined(); expect(alphaCommunity.community.name).toBeDefined();
@ -258,27 +265,56 @@ test("moderator view", async () => {
.post_view; .post_view;
expect(alphaPost.post.id).toBeDefined(); expect(alphaPost.post.id).toBeDefined();
let alphaComment = (await createComment(otherUser, alphaPost.post.id))
.comment_view;
expect(alphaComment.comment.id).toBeDefined();
// other user also posts on alpha's community // other user also posts on alpha's community
let otherAlphaPost = ( let otherAlphaPost = (
await createPost(otherUser, alphaCommunity.community.id) await createPost(otherUser, alphaCommunity.community.id)
).post_view; ).post_view;
expect(otherAlphaPost.post.id).toBeDefined(); expect(otherAlphaPost.post.id).toBeDefined();
// alpha lists posts on home page, should contain all posts that were made let otherAlphaComment = (
let posts = (await getPosts(alpha)).posts; await createComment(otherUser, otherAlphaPost.post.id)
).comment_view;
expect(otherAlphaComment.comment.id).toBeDefined();
// alpha lists posts and comments on home page, should contain all posts that were made
let posts = (await getPosts(alpha, "All")).posts;
expect(posts).toBeDefined(); expect(posts).toBeDefined();
let postIds = posts.map(post => post.post.id); let postIds = posts.map(post => post.post.id);
let comments = (await getComments(alpha, undefined, "All")).comments;
expect(comments).toBeDefined();
let commentIds = comments.map(comment => comment.comment.id);
expect(postIds).toContain(otherPost.post.id); expect(postIds).toContain(otherPost.post.id);
expect(commentIds).toContain(otherComment.comment.id);
expect(postIds).toContain(alphaPost.post.id); expect(postIds).toContain(alphaPost.post.id);
expect(commentIds).toContain(alphaComment.comment.id);
expect(postIds).toContain(otherAlphaPost.post.id); expect(postIds).toContain(otherAlphaPost.post.id);
expect(commentIds).toContain(otherAlphaComment.comment.id);
// in moderator view, alpha should not see otherPost, wich was posted on a community alpha doesn't moderate // in moderator view, alpha should not see otherPost, wich was posted on a community alpha doesn't moderate
posts = (await getPosts(alpha, true)).posts; posts = (await getPosts(alpha, "ModeratorView")).posts;
expect(posts).toBeDefined(); expect(posts).toBeDefined();
postIds = posts.map(post => post.post.id); postIds = posts.map(post => post.post.id);
comments = (await getComments(alpha, undefined, "ModeratorView")).comments;
expect(comments).toBeDefined();
commentIds = comments.map(comment => comment.comment.id);
expect(postIds).not.toContain(otherPost.post.id); expect(postIds).not.toContain(otherPost.post.id);
expect(commentIds).not.toContain(otherComment.comment.id);
expect(postIds).toContain(alphaPost.post.id); expect(postIds).toContain(alphaPost.post.id);
expect(commentIds).toContain(alphaComment.comment.id);
expect(postIds).toContain(otherAlphaPost.post.id); expect(postIds).toContain(otherAlphaPost.post.id);
expect(commentIds).toContain(otherAlphaComment.comment.id);
}); });
test("Get community for different casing on domain", async () => { test("Get community for different casing on domain", async () => {

View File

@ -4,7 +4,6 @@ import {
GetUnreadCount, GetUnreadCount,
GetUnreadCountResponse, GetUnreadCountResponse,
LemmyHttp, LemmyHttp,
LocalUser,
} 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";
@ -69,6 +68,7 @@ import { GetPostsResponse } from "lemmy-js-client/dist/types/GetPostsResponse";
import { GetPosts } from "lemmy-js-client/dist/types/GetPosts"; import { GetPosts } from "lemmy-js-client/dist/types/GetPosts";
import { GetPersonDetailsResponse } from "lemmy-js-client/dist/types/GetPersonDetailsResponse"; import { GetPersonDetailsResponse } from "lemmy-js-client/dist/types/GetPersonDetailsResponse";
import { GetPersonDetails } from "lemmy-js-client/dist/types/GetPersonDetails"; import { GetPersonDetails } from "lemmy-js-client/dist/types/GetPersonDetails";
import { ListingType } from "lemmy-js-client/dist/types/ListingType";
export interface API { export interface API {
client: LemmyHttp; client: LemmyHttp;
@ -201,7 +201,9 @@ export async function setupLogins() {
try { try {
await createCommunity(alpha, "main"); await createCommunity(alpha, "main");
await createCommunity(beta, "main"); await createCommunity(beta, "main");
} catch (_) {} } catch (_) {
console.log("Communities already exist");
}
} }
export async function createPost( export async function createPost(
@ -321,11 +323,12 @@ export async function getPost(
export async function getComments( export async function getComments(
api: API, api: API,
post_id: number, post_id?: number,
listingType: ListingType = "All",
): Promise<GetCommentsResponse> { ): Promise<GetCommentsResponse> {
let form: GetComments = { let form: GetComments = {
post_id: post_id, post_id: post_id,
type_: "All", type_: listingType,
sort: "New", sort: "New",
auth: api.auth, auth: api.auth,
}; };
@ -798,11 +801,11 @@ export async function listCommentReports(
export function getPosts( export function getPosts(
api: API, api: API,
moderator_view = false, listingType?: ListingType,
): Promise<GetPostsResponse> { ): Promise<GetPostsResponse> {
let form: GetPosts = { let form: GetPosts = {
moderator_view,
auth: api.auth, auth: api.auth,
type_: listingType,
}; };
return api.client.getPosts(form); return api.client.getPosts(form);
} }

View File

@ -6,7 +6,7 @@
"noImplicitAny": true, "noImplicitAny": true,
"lib": ["es2017", "es7", "es6", "dom"], "lib": ["es2017", "es7", "es6", "dom"],
"outDir": "./dist", "outDir": "./dist",
"target": "ES5", "target": "ES2015",
"strictNullChecks": true, "strictNullChecks": true,
"moduleResolution": "Node" "moduleResolution": "Node"
}, },

View File

@ -2174,10 +2174,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.2: lemmy-js-client@0.19.0-rc.3:
version "0.19.0-rc.2" version "0.19.0-rc.3"
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.19.0-rc.2.tgz#c3cb511b27f92538909a2b91a0f8527b1abad958" resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.19.0-rc.3.tgz#1efbfd5ce492319227a41cb020fc1cf9b2e7c075"
integrity sha512-FXuf8s7bpBVkHL/OGWDb/0aGIrJ7uv3d4Xt1h6zmNDhw6MmmuD8RXgCHiS2jqhxjAEp96Dpl1NFXbpmKpix7tQ== integrity sha512-RmibQ3+YTvqsQ89II2I29pfPmVAWiSObGAU9Nc/AGYfyvaCya7f5+TirKwHdKA2eWDWLOTnD4rm6WgcgAwvhWw==
dependencies: dependencies:
cross-fetch "^3.1.5" cross-fetch "^3.1.5"
form-data "^4.0.0" form-data "^4.0.0"

View File

@ -43,6 +43,8 @@
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"
# Cache remote images
cache_remote_images: true
} }
# Email sending configuration. All options except login/password are mandatory # Email sending configuration. All options except login/password are mandatory
email: { email: {

View File

@ -29,7 +29,7 @@ pub async fn add_mod_to_community(
is_mod_or_admin(&mut context.pool(), local_user_view.person.id, community_id).await?; is_mod_or_admin(&mut context.pool(), local_user_view.person.id, community_id).await?;
let community = Community::read(&mut context.pool(), community_id).await?; let community = Community::read(&mut context.pool(), community_id).await?;
if local_user_view.local_user.admin && !community.local { if local_user_view.local_user.admin && !community.local {
return Err(LemmyErrorType::NotAModerator)?; Err(LemmyErrorType::NotAModerator)?
} }
// Update in local database // Update in local database

View File

@ -42,7 +42,7 @@ impl Perform for TransferCommunity {
if !(is_top_mod(&local_user_view, &community_mods).is_ok() if !(is_top_mod(&local_user_view, &community_mods).is_ok()
|| is_admin(&local_user_view).is_ok()) || is_admin(&local_user_view).is_ok())
{ {
return Err(LemmyErrorType::NotAnAdmin)?; Err(LemmyErrorType::NotAnAdmin)?
} }
// You have to re-do the community_moderator table, reordering it. // You have to re-do the community_moderator table, reordering it.

View File

@ -41,16 +41,13 @@ pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> Result<String, LemmyEr
if let Some(samples16) = samples.as_sixteen() { if let Some(samples16) = samples.as_sixteen() {
concat_samples.extend(samples16); concat_samples.extend(samples16);
} else { } else {
Err(LemmyErrorType::CouldntCreateAudioCaptcha)?; Err(LemmyErrorType::CouldntCreateAudioCaptcha)?
} }
} }
// Encode the concatenated result as a wav file // Encode the concatenated result as a wav file
let mut output_buffer = Cursor::new(vec![]); let mut output_buffer = Cursor::new(vec![]);
let header = match any_header { if let Some(header) = any_header {
Some(header) => header,
None => return Err(LemmyErrorType::CouldntCreateAudioCaptcha)?,
};
wav::write( wav::write(
header, header,
&wav::BitDepth::Sixteen(concat_samples), &wav::BitDepth::Sixteen(concat_samples),
@ -59,6 +56,9 @@ pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> Result<String, LemmyEr
.with_lemmy_type(LemmyErrorType::CouldntCreateAudioCaptcha)?; .with_lemmy_type(LemmyErrorType::CouldntCreateAudioCaptcha)?;
Ok(base64.encode(output_buffer.into_inner())) Ok(base64.encode(output_buffer.into_inner()))
} else {
Err(LemmyErrorType::CouldntCreateAudioCaptcha)?
}
} }
/// Check size of report /// Check size of report
@ -67,13 +67,13 @@ pub(crate) fn check_report_reason(reason: &str, local_site: &LocalSite) -> Resul
check_slurs(reason, slur_regex)?; check_slurs(reason, slur_regex)?;
if reason.is_empty() { if reason.is_empty() {
Err(LemmyErrorType::ReportReasonRequired)?; Err(LemmyErrorType::ReportReasonRequired)?
} } else if reason.chars().count() > 1000 {
if reason.chars().count() > 1000 { Err(LemmyErrorType::ReportTooLong)?
Err(LemmyErrorType::ReportTooLong)?; } else {
}
Ok(()) Ok(())
} }
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -27,7 +27,7 @@ impl Perform for BlockPerson {
// Don't let a person block themselves // Don't let a person block themselves
if target_id == person_id { if target_id == person_id {
return Err(LemmyErrorType::CantBlockYourself)?; Err(LemmyErrorType::CantBlockYourself)?
} }
let person_block_form = PersonBlockForm { let person_block_form = PersonBlockForm {
@ -37,7 +37,7 @@ impl Perform for BlockPerson {
let target_user = LocalUserView::read_person(&mut context.pool(), target_id).await; let target_user = LocalUserView::read_person(&mut context.pool(), target_id).await;
if target_user.map(|t| t.local_user.admin) == Ok(true) { if target_user.map(|t| t.local_user.admin) == Ok(true) {
return Err(LemmyErrorType::CantBlockAdmin)?; Err(LemmyErrorType::CantBlockAdmin)?
} }
if data.block { if data.block {

View File

@ -25,7 +25,7 @@ impl Perform for ChangePassword {
// Make sure passwords match // Make sure passwords match
if data.new_password != data.new_password_verify { if data.new_password != data.new_password_verify {
return Err(LemmyErrorType::PasswordsDoNotMatch)?; Err(LemmyErrorType::PasswordsDoNotMatch)?
} }
// Check the old password // Check the old password
@ -35,7 +35,7 @@ impl Perform for ChangePassword {
) )
.unwrap_or(false); .unwrap_or(false);
if !valid { if !valid {
return Err(LemmyErrorType::IncorrectLogin)?; Err(LemmyErrorType::IncorrectLogin)?
} }
let local_user_id = local_user_view.local_user.id; let local_user_id = local_user_view.local_user.id;

View File

@ -29,7 +29,7 @@ impl Perform for PasswordChangeAfterReset {
// Make sure passwords match // Make sure passwords match
if data.password != data.password_verify { if data.password != data.password_verify {
return Err(LemmyErrorType::PasswordsDoNotMatch)?; Err(LemmyErrorType::PasswordsDoNotMatch)?
} }
// Update the user with the new password // Update the user with the new password

View File

@ -37,7 +37,7 @@ impl Perform for Login {
) )
.unwrap_or(false); .unwrap_or(false);
if !valid { if !valid {
return Err(LemmyErrorType::IncorrectLogin)?; Err(LemmyErrorType::IncorrectLogin)?
} }
check_user_valid( check_user_valid(
local_user_view.person.banned, local_user_view.person.banned,
@ -51,7 +51,7 @@ impl Perform for Login {
&& site_view.local_site.require_email_verification && site_view.local_site.require_email_verification
&& !local_user_view.local_user.email_verified && !local_user_view.local_user.email_verified
{ {
return Err(LemmyErrorType::EmailNotVerified)?; Err(LemmyErrorType::EmailNotVerified)?
} }
check_registration_application(&local_user_view, &site_view.local_site, &mut context.pool()) check_registration_application(&local_user_view, &site_view.local_site, &mut context.pool())

View File

@ -28,7 +28,7 @@ impl Perform for MarkPersonMentionAsRead {
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?;
if local_user_view.person.id != read_person_mention.recipient_id { if local_user_view.person.id != read_person_mention.recipient_id {
return Err(LemmyErrorType::CouldntUpdateComment)?; Err(LemmyErrorType::CouldntUpdateComment)?
} }
let person_mention_id = read_person_mention.id; let person_mention_id = read_person_mention.id;

View File

@ -22,7 +22,7 @@ pub async fn mark_reply_as_read(
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?;
if local_user_view.person.id != read_comment_reply.recipient_id { if local_user_view.person.id != read_comment_reply.recipient_id {
return Err(LemmyErrorType::CouldntUpdateComment)?; Err(LemmyErrorType::CouldntUpdateComment)?
} }
let comment_reply_id = read_comment_reply.id; let comment_reply_id = read_comment_reply.id;

View File

@ -33,7 +33,7 @@ impl Perform for PasswordReset {
) )
.await?; .await?;
if recent_resets_count >= 3 { if recent_resets_count >= 3 {
return Err(LemmyErrorType::PasswordResetLimitReached)?; Err(LemmyErrorType::PasswordResetLimitReached)?
} }
// Email the pure token to the user. // Email the pure token to the user.

View File

@ -65,7 +65,7 @@ impl Perform for SaveUserSettings {
// When the site requires email, make sure email is not Some(None). IE, an overwrite to a None value // When the site requires email, make sure email is not Some(None). IE, an overwrite to a None value
if let Some(email) = &email { if let Some(email) = &email {
if email.is_none() && site_view.local_site.require_email_verification { if email.is_none() && site_view.local_site.require_email_verification {
return Err(LemmyErrorType::EmailRequired)?; Err(LemmyErrorType::EmailRequired)?
} }
} }

View File

@ -29,7 +29,7 @@ impl Perform for MarkPrivateMessageAsRead {
let orig_private_message = let orig_private_message =
PrivateMessage::read(&mut context.pool(), private_message_id).await?; PrivateMessage::read(&mut context.pool(), private_message_id).await?;
if local_user_view.person.id != orig_private_message.recipient_id { if local_user_view.person.id != orig_private_message.recipient_id {
return Err(LemmyErrorType::CouldntUpdatePrivateMessage)?; Err(LemmyErrorType::CouldntUpdatePrivateMessage)?
} }
// Doing the update // Doing the update

View File

@ -36,7 +36,7 @@ impl Perform for LeaveAdmin {
// Make sure there isn't just one admin (so if one leaves, there will still be one left) // Make sure there isn't just one admin (so if one leaves, there will still be one left)
let admins = PersonView::admins(&mut context.pool()).await?; let admins = PersonView::admins(&mut context.pool()).await?;
if admins.len() == 1 { if admins.len() == 1 {
return Err(LemmyErrorType::CannotLeaveAdmin)?; Err(LemmyErrorType::CannotLeaveAdmin)?
} }
LocalUser::update( LocalUser::update(

View File

@ -77,7 +77,6 @@ pub struct GetPosts {
pub saved_only: Option<bool>, pub saved_only: Option<bool>,
pub liked_only: Option<bool>, pub liked_only: Option<bool>,
pub disliked_only: Option<bool>, pub disliked_only: Option<bool>,
pub moderator_view: Option<bool>,
pub auth: Option<Sensitive<String>>, pub auth: Option<Sensitive<String>>,
} }

View File

@ -44,7 +44,7 @@ fn html_to_site_metadata(html_bytes: &[u8], url: &Url) -> Result<SiteMetadata, L
.to_lowercase(); .to_lowercase();
if !first_line.starts_with("<!doctype html>") { if !first_line.starts_with("<!doctype html>") {
Err(LemmyErrorType::SiteMetadataPageIsNotDoctypeHtml)?; Err(LemmyErrorType::SiteMetadataPageIsNotDoctypeHtml)?
} }
let mut page = HTML::from_string(html.to_string(), None)?; let mut page = HTML::from_string(html.to_string(), None)?;
@ -123,6 +123,8 @@ pub(crate) async fn fetch_pictrs(
let pictrs_config = settings.pictrs_config()?; let pictrs_config = settings.pictrs_config()?;
is_image_content_type(client, image_url).await?; is_image_content_type(client, image_url).await?;
if pictrs_config.cache_remote_images {
// fetch remote non-pictrs images for persistent thumbnail link
let fetch_url = format!( let fetch_url = format!(
"{}image/download?url={}", "{}image/download?url={}",
pictrs_config.url, pictrs_config.url,
@ -142,6 +144,9 @@ pub(crate) async fn fetch_pictrs(
} else { } else {
Err(LemmyErrorType::PictrsResponseError(response.msg))? Err(LemmyErrorType::PictrsResponseError(response.msg))?
} }
} else {
Err(LemmyErrorType::PictrsCachingDisabled)?
}
} }
/// Purges an image from pictrs /// Purges an image from pictrs
@ -185,7 +190,7 @@ pub async fn purge_image_from_pictrs(
} }
/// Both are options, since the URL might be either an html page, or an image /// Both are options, since the URL might be either an html page, or an image
/// Returns the SiteMetadata, and a Pictrs URL, if there is a picture associated /// Returns the SiteMetadata, and an image URL, if there is a picture associated
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub async fn fetch_site_data( pub async fn fetch_site_data(
client: &ClientWithMiddleware, client: &ClientWithMiddleware,
@ -200,50 +205,46 @@ pub async fn fetch_site_data(
// Warning, this may ignore SSL errors // Warning, this may ignore SSL errors
let metadata_option = fetch_site_metadata(client, url).await.ok(); let metadata_option = fetch_site_metadata(client, url).await.ok();
if !include_image { if !include_image {
return (metadata_option, None); (metadata_option, None)
} else {
let thumbnail_url =
fetch_pictrs_url_from_site_metadata(client, &metadata_option, settings, url)
.await
.ok();
(metadata_option, thumbnail_url)
} }
let missing_pictrs_file =
|r: PictrsResponse| r.files.first().expect("missing pictrs file").file.clone();
// Fetch pictrs thumbnail
let pictrs_hash = match &metadata_option {
Some(metadata_res) => match &metadata_res.image {
// Metadata, with image
// Try to generate a small thumbnail if there's a full sized one from post-links
Some(metadata_image) => fetch_pictrs(client, settings, metadata_image)
.await
.map(missing_pictrs_file),
// Metadata, but no image
None => fetch_pictrs(client, settings, url)
.await
.map(missing_pictrs_file),
},
// No metadata, try to fetch the URL as an image
None => fetch_pictrs(client, settings, url)
.await
.map(missing_pictrs_file),
};
// The full urls are necessary for federation
let pictrs_thumbnail = pictrs_hash
.map(|p| {
Url::parse(&format!(
"{}/pictrs/image/{}",
settings.get_protocol_and_hostname(),
p
))
.ok()
})
.ok()
.flatten();
(metadata_option, pictrs_thumbnail.map(Into::into))
} }
None => (None, None), None => (None, None),
} }
} }
async fn fetch_pictrs_url_from_site_metadata(
client: &ClientWithMiddleware,
metadata_option: &Option<SiteMetadata>,
settings: &Settings,
url: &Url,
) -> Result<DbUrl, LemmyError> {
let pictrs_res = match metadata_option {
Some(metadata_res) => match &metadata_res.image {
// Metadata, with image
// Try to generate a small thumbnail if there's a full sized one from post-links
Some(metadata_image) => fetch_pictrs(client, settings, metadata_image).await,
// Metadata, but no image
None => fetch_pictrs(client, settings, url).await,
},
// No metadata, try to fetch the URL as an image
None => fetch_pictrs(client, settings, url).await,
}?;
Url::parse(&format!(
"{}/pictrs/image/{}",
settings.get_protocol_and_hostname(),
pictrs_res.files.first().expect("missing pictrs file").file
))
.map(Into::into)
.map_err(Into::into)
}
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
async fn is_image_content_type(client: &ClientWithMiddleware, url: &Url) -> Result<(), LemmyError> { async fn is_image_content_type(client: &ClientWithMiddleware, url: &Url) -> Result<(), LemmyError> {
let response = client.get(url.as_str()).send().await?; let response = client.get(url.as_str()).send().await?;

View File

@ -54,10 +54,11 @@ pub async fn is_mod_or_admin(
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
let is_mod_or_admin = CommunityView::is_mod_or_admin(pool, person_id, community_id).await?; let is_mod_or_admin = CommunityView::is_mod_or_admin(pool, person_id, community_id).await?;
if !is_mod_or_admin { if !is_mod_or_admin {
return Err(LemmyErrorType::NotAModOrAdmin)?; Err(LemmyErrorType::NotAModOrAdmin)?
} } else {
Ok(()) Ok(())
} }
}
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub async fn is_mod_or_admin_opt( pub async fn is_mod_or_admin_opt(
@ -78,10 +79,11 @@ pub async fn is_mod_or_admin_opt(
pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> { pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> {
if !local_user_view.local_user.admin { if !local_user_view.local_user.admin {
return Err(LemmyErrorType::NotAnAdmin)?; Err(LemmyErrorType::NotAnAdmin)?
} } else {
Ok(()) Ok(())
} }
}
pub fn is_top_mod( pub fn is_top_mod(
local_user_view: &LocalUserView, local_user_view: &LocalUserView,
@ -93,10 +95,11 @@ pub fn is_top_mod(
.map(|cm| cm.moderator.id) .map(|cm| cm.moderator.id)
.unwrap_or(PersonId(0)) .unwrap_or(PersonId(0))
{ {
Err(LemmyErrorType::NotTopMod)?; Err(LemmyErrorType::NotTopMod)?
} } else {
Ok(()) Ok(())
} }
}
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub async fn get_post(post_id: PostId, pool: &mut DbPool<'_>) -> Result<Post, LemmyError> { pub async fn get_post(post_id: PostId, pool: &mut DbPool<'_>) -> Result<Post, LemmyError> {
@ -190,16 +193,15 @@ pub fn check_user_valid(
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
// Check for a site ban // Check for a site ban
if is_banned(banned, ban_expires) { if is_banned(banned, ban_expires) {
Err(LemmyErrorType::SiteBan)?; Err(LemmyErrorType::SiteBan)?
} }
// check for account deletion // check for account deletion
if deleted { else if deleted {
Err(LemmyErrorType::Deleted)?; Err(LemmyErrorType::Deleted)?
} } else {
Ok(()) Ok(())
} }
}
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub async fn check_community_ban( pub async fn check_community_ban(
@ -259,10 +261,11 @@ pub async fn check_person_block(
#[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 {
Err(LemmyErrorType::DownvotesAreDisabled)?; Err(LemmyErrorType::DownvotesAreDisabled)?
} } else {
Ok(()) Ok(())
} }
}
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub fn check_private_instance( pub fn check_private_instance(
@ -270,10 +273,11 @@ pub fn check_private_instance(
local_site: &LocalSite, local_site: &LocalSite,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
if local_user_view.is_none() && local_site.private_instance { if local_user_view.is_none() && local_site.private_instance {
Err(LemmyErrorType::InstanceIsPrivate)?; Err(LemmyErrorType::InstanceIsPrivate)?
} } else {
Ok(()) Ok(())
} }
}
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
pub async fn build_federated_instances( pub async fn build_federated_instances(
@ -517,11 +521,11 @@ pub async fn check_registration_application(
if let Some(deny_reason) = registration.deny_reason { if let Some(deny_reason) = registration.deny_reason {
let lang = get_interface_language(local_user_view); let lang = get_interface_language(local_user_view);
let registration_denied_message = format!("{}: {}", lang.registration_denied(), deny_reason); let registration_denied_message = format!("{}: {}", lang.registration_denied(), deny_reason);
return Err(LemmyErrorType::RegistrationDenied( Err(LemmyErrorType::RegistrationDenied(
registration_denied_message, registration_denied_message,
))?; ))?
} else { } else {
return Err(LemmyErrorType::RegistrationApplicationIsPending)?; Err(LemmyErrorType::RegistrationApplicationIsPending)?
} }
} }
Ok(()) Ok(())
@ -531,10 +535,11 @@ pub fn check_private_instance_and_federation_enabled(
local_site: &LocalSite, local_site: &LocalSite,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
if local_site.private_instance && local_site.federation_enabled { if local_site.private_instance && local_site.federation_enabled {
Err(LemmyErrorType::CantEnablePrivateInstanceAndFederationTogether)?; Err(LemmyErrorType::CantEnablePrivateInstanceAndFederationTogether)?
} } else {
Ok(()) Ok(())
} }
}
pub async fn purge_image_posts_for_person( pub async fn purge_image_posts_for_person(
banned_person_id: PersonId, banned_person_id: PersonId,

View File

@ -65,7 +65,7 @@ pub async fn create_comment(
// Check if post is locked, no new comments // Check if post is locked, no new comments
if post.locked { if post.locked {
return Err(LemmyErrorType::Locked)?; Err(LemmyErrorType::Locked)?
} }
// Fetch the parent, if it exists // Fetch the parent, if it exists
@ -79,7 +79,7 @@ pub async fn create_comment(
// Strange issue where sometimes the post ID of the parent comment is incorrect // Strange issue where sometimes the post ID of the parent comment is incorrect
if let Some(parent) = parent_opt.as_ref() { if let Some(parent) = parent_opt.as_ref() {
if parent.post_id != post_id { if parent.post_id != post_id {
return Err(LemmyErrorType::CouldntCreateComment)?; Err(LemmyErrorType::CouldntCreateComment)?
} }
check_comment_depth(parent)?; check_comment_depth(parent)?;
} }

View File

@ -29,7 +29,7 @@ pub async fn delete_comment(
// Dont delete it if its already been deleted. // Dont delete it if its already been deleted.
if orig_comment.comment.deleted == data.deleted { if orig_comment.comment.deleted == data.deleted {
return Err(LemmyErrorType::CouldntUpdateComment)?; Err(LemmyErrorType::CouldntUpdateComment)?
} }
check_community_ban( check_community_ban(
@ -41,7 +41,7 @@ pub async fn delete_comment(
// Verify that only the creator can delete // Verify that only the creator can delete
if local_user_view.person.id != orig_comment.creator.id { if local_user_view.person.id != orig_comment.creator.id {
return Err(LemmyErrorType::NoCommentEditAllowed)?; Err(LemmyErrorType::NoCommentEditAllowed)?
} }
// Do the delete // Do the delete

View File

@ -51,7 +51,7 @@ pub async fn update_comment(
// Verify that only the creator can edit // Verify that only the creator can edit
if local_user_view.person.id != orig_comment.creator.id { if local_user_view.person.id != orig_comment.creator.id {
return Err(LemmyErrorType::NoCommentEditAllowed)?; Err(LemmyErrorType::NoCommentEditAllowed)?
} }
let language_id = data.language_id; let language_id = data.language_id;

View File

@ -51,7 +51,7 @@ pub async fn create_community(
let local_site = site_view.local_site; let local_site = site_view.local_site;
if local_site.community_creation_admin_only && is_admin(&local_user_view).is_err() { if local_site.community_creation_admin_only && is_admin(&local_user_view).is_err() {
return Err(LemmyErrorType::OnlyAdminsCanCreateCommunities)?; Err(LemmyErrorType::OnlyAdminsCanCreateCommunities)?
} }
// Check to make sure the icon and banners are urls // Check to make sure the icon and banners are urls
@ -79,7 +79,7 @@ pub async fn create_community(
let community_dupe = let community_dupe =
Community::read_from_apub_id(&mut context.pool(), &community_actor_id).await?; Community::read_from_apub_id(&mut context.pool(), &community_actor_id).await?;
if community_dupe.is_some() { if community_dupe.is_some() {
return Err(LemmyErrorType::CommunityAlreadyExists)?; Err(LemmyErrorType::CommunityAlreadyExists)?
} }
// When you create a community, make sure the user becomes a moderator and a follower // When you create a community, make sure the user becomes a moderator and a follower
@ -135,7 +135,7 @@ pub async fn create_community(
// https://stackoverflow.com/a/64227550 // https://stackoverflow.com/a/64227550
let is_subset = languages.iter().all(|item| site_languages.contains(item)); let is_subset = languages.iter().all(|item| site_languages.contains(item));
if !is_subset { if !is_subset {
return Err(LemmyErrorType::LanguageNotAllowed)?; Err(LemmyErrorType::LanguageNotAllowed)?
} }
CommunityLanguage::update(&mut context.pool(), languages, community_id).await?; CommunityLanguage::update(&mut context.pool(), languages, community_id).await?;
} }

View File

@ -50,7 +50,7 @@ pub async fn update_community(
.await .await
.map(|v| v.into_iter().map(|m| m.moderator.id).collect())?; .map(|v| v.into_iter().map(|m| m.moderator.id).collect())?;
if !mods.contains(&local_user_view.person.id) { if !mods.contains(&local_user_view.person.id) {
return Err(LemmyErrorType::NotAModerator)?; Err(LemmyErrorType::NotAModerator)?
} }
let community_id = data.community_id; let community_id = data.community_id;
@ -60,7 +60,7 @@ pub async fn update_community(
// https://stackoverflow.com/a/64227550 // https://stackoverflow.com/a/64227550
let is_subset = languages.iter().all(|item| site_languages.contains(item)); let is_subset = languages.iter().all(|item| site_languages.contains(item));
if !is_subset { if !is_subset {
return Err(LemmyErrorType::LanguageNotAllowed)?; Err(LemmyErrorType::LanguageNotAllowed)?
} }
CommunityLanguage::update(&mut context.pool(), languages, community_id).await?; CommunityLanguage::update(&mut context.pool(), languages, community_id).await?;
} }

View File

@ -82,7 +82,7 @@ pub async fn create_post(
) )
.await?; .await?;
if !is_mod { if !is_mod {
return Err(LemmyErrorType::OnlyModsCanPostInCommunity)?; Err(LemmyErrorType::OnlyModsCanPostInCommunity)?
} }
} }

View File

@ -25,7 +25,7 @@ pub async fn delete_post(
// Dont delete it if its already been deleted. // Dont delete it if its already been deleted.
if orig_post.deleted == data.deleted { if orig_post.deleted == data.deleted {
return Err(LemmyErrorType::CouldntUpdatePost)?; Err(LemmyErrorType::CouldntUpdatePost)?
} }
check_community_ban( check_community_ban(
@ -38,7 +38,7 @@ pub async fn delete_post(
// Verify that only the creator can delete // Verify that only the creator can delete
if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) {
return Err(LemmyErrorType::NoPostEditAllowed)?; Err(LemmyErrorType::NoPostEditAllowed)?
} }
// Update the post // Update the post

View File

@ -68,7 +68,7 @@ pub async fn update_post(
// Verify that only the creator can edit // Verify that only the creator can edit
if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) {
return Err(LemmyErrorType::NoPostEditAllowed)?; Err(LemmyErrorType::NoPostEditAllowed)?
} }
// Fetch post links and Pictrs cached image // Fetch post links and Pictrs cached image

View File

@ -24,7 +24,7 @@ pub async fn delete_private_message(
let private_message_id = data.private_message_id; 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?;
if local_user_view.person.id != orig_private_message.creator_id { if local_user_view.person.id != orig_private_message.creator_id {
return Err(LemmyErrorType::EditPrivateMessageNotAllowed)?; Err(LemmyErrorType::EditPrivateMessageNotAllowed)?
} }
// Doing the update // Doing the update

View File

@ -32,7 +32,7 @@ pub async fn update_private_message(
let private_message_id = data.private_message_id; 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?;
if local_user_view.person.id != orig_private_message.creator_id { if local_user_view.person.id != orig_private_message.creator_id {
return Err(LemmyErrorType::EditPrivateMessageNotAllowed)?; Err(LemmyErrorType::EditPrivateMessageNotAllowed)?
} }
// Doing the update // Doing the update

View File

@ -147,7 +147,7 @@ pub async fn create_site(
fn validate_create_payload(local_site: &LocalSite, create_site: &CreateSite) -> LemmyResult<()> { fn validate_create_payload(local_site: &LocalSite, create_site: &CreateSite) -> LemmyResult<()> {
// Make sure the site hasn't already been set up... // Make sure the site hasn't already been set up...
if local_site.site_setup { if local_site.site_setup {
Err(LemmyErrorType::SiteAlreadyExists)?; Err(LemmyErrorType::SiteAlreadyExists)?
}; };
// Check that the slur regex compiles, and returns the regex if valid... // Check that the slur regex compiles, and returns the regex if valid...

View File

@ -48,23 +48,23 @@ pub async fn register(
local_site.registration_mode == RegistrationMode::RequireApplication; local_site.registration_mode == RegistrationMode::RequireApplication;
if local_site.registration_mode == RegistrationMode::Closed { if local_site.registration_mode == RegistrationMode::Closed {
return Err(LemmyErrorType::RegistrationClosed)?; Err(LemmyErrorType::RegistrationClosed)?
} }
password_length_check(&data.password)?; password_length_check(&data.password)?;
honeypot_check(&data.honeypot)?; honeypot_check(&data.honeypot)?;
if local_site.require_email_verification && data.email.is_none() { if local_site.require_email_verification && data.email.is_none() {
return Err(LemmyErrorType::EmailRequired)?; Err(LemmyErrorType::EmailRequired)?
} }
if local_site.site_setup && require_registration_application && data.answer.is_none() { if local_site.site_setup && require_registration_application && data.answer.is_none() {
return Err(LemmyErrorType::RegistrationApplicationAnswerRequired)?; Err(LemmyErrorType::RegistrationApplicationAnswerRequired)?
} }
// Make sure passwords match // Make sure passwords match
if data.password != data.password_verify { if data.password != data.password_verify {
return Err(LemmyErrorType::PasswordsDoNotMatch)?; Err(LemmyErrorType::PasswordsDoNotMatch)?
} }
if local_site.site_setup && local_site.captcha_enabled { if local_site.site_setup && local_site.captcha_enabled {
@ -79,10 +79,10 @@ pub async fn register(
) )
.await?; .await?;
if !check { if !check {
return Err(LemmyErrorType::CaptchaIncorrect)?; Err(LemmyErrorType::CaptchaIncorrect)?
} }
} else { } else {
return Err(LemmyErrorType::CaptchaIncorrect)?; Err(LemmyErrorType::CaptchaIncorrect)?
} }
} }
@ -101,7 +101,7 @@ pub async fn register(
if let Some(email) = &data.email { if let Some(email) = &data.email {
if LocalUser::is_email_taken(&mut context.pool(), email).await? { if LocalUser::is_email_taken(&mut context.pool(), email).await? {
return Err(LemmyErrorType::EmailAlreadyExists)?; Err(LemmyErrorType::EmailAlreadyExists)?
} }
} }

View File

@ -24,7 +24,7 @@ pub async fn delete_account(
) )
.unwrap_or(false); .unwrap_or(false);
if !valid { if !valid {
return Err(LemmyErrorType::IncorrectLogin)?; Err(LemmyErrorType::IncorrectLogin)?
} }
if data.delete_content { if data.delete_content {

View File

@ -49,7 +49,7 @@ impl ActivityHandler for RawAnnouncableActivities {
let activity: AnnouncableActivities = self.clone().try_into()?; let activity: AnnouncableActivities = self.clone().try_into()?;
// This is only for sending, not receiving so we reject it. // This is only for sending, not receiving so we reject it.
if let AnnouncableActivities::Page(_) = activity { if let AnnouncableActivities::Page(_) = activity {
return Err(LemmyErrorType::CannotReceivePage)?; Err(LemmyErrorType::CannotReceivePage)?
} }
// verify and receive activity // verify and receive activity
@ -147,7 +147,7 @@ impl ActivityHandler for AnnounceActivity {
let object: AnnouncableActivities = self.object.object(context).await?.try_into()?; let object: AnnouncableActivities = self.object.object(context).await?.try_into()?;
// This is only for sending, not receiving so we reject it. // This is only for sending, not receiving so we reject it.
if let AnnouncableActivities::Page(_) = object { if let AnnouncableActivities::Page(_) = object {
return Err(LemmyErrorType::CannotReceivePage)?; Err(LemmyErrorType::CannotReceivePage)?
} }
// verify here in order to avoid fetching the object twice over http // verify here in order to avoid fetching the object twice over http

View File

@ -121,7 +121,7 @@ impl ActivityHandler for CreateOrUpdatePage {
// because then we will definitely receive all create and update activities separately. // because then we will definitely receive all create and update activities separately.
let is_locked = self.object.comments_enabled == Some(false); let is_locked = self.object.comments_enabled == Some(false);
if community.local && is_locked { if community.local && is_locked {
return Err(LemmyErrorType::NewPostCannotBeLocked)?; Err(LemmyErrorType::NewPostCannotBeLocked)?
} }
} }
CreateOrUpdateType::Update => { CreateOrUpdateType::Update => {

View File

@ -112,7 +112,7 @@ pub(in crate::activities) async fn receive_remove_action(
match DeletableObjects::read_from_db(object, context).await? { match DeletableObjects::read_from_db(object, context).await? {
DeletableObjects::Community(community) => { DeletableObjects::Community(community) => {
if community.local { if community.local {
return Err(LemmyErrorType::OnlyLocalAdminCanRemoveCommunity)?; Err(LemmyErrorType::OnlyLocalAdminCanRemoveCommunity)?
} }
let form = ModRemoveCommunityForm { let form = ModRemoveCommunityForm {
mod_person_id: actor.id, mod_person_id: actor.id,

View File

@ -100,7 +100,7 @@ impl UndoDelete {
match DeletableObjects::read_from_db(object, context).await? { match DeletableObjects::read_from_db(object, context).await? {
DeletableObjects::Community(community) => { DeletableObjects::Community(community) => {
if community.local { if community.local {
return Err(LemmyErrorType::OnlyLocalAdminCanRestoreCommunity)?; Err(LemmyErrorType::OnlyLocalAdminCanRestoreCommunity)?
} }
let form = ModRemoveCommunityForm { let form = ModRemoveCommunityForm {
mod_person_id: actor.id, mod_person_id: actor.id,

View File

@ -77,11 +77,12 @@ async fn verify_person(
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
let person = person_id.dereference(context).await?; let person = person_id.dereference(context).await?;
if person.banned { if person.banned {
return Err(anyhow!("Person {} is banned", person_id)) Err(anyhow!("Person {} is banned", person_id))
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment); .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)
} } else {
Ok(()) Ok(())
} }
}
/// Fetches the person and community to verify their type, then checks if person is banned from site /// Fetches the person and community to verify their type, then checks if person is banned from site
/// or community. /// or community.
@ -93,9 +94,9 @@ pub(crate) async fn verify_person_in_community(
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
let person = person_id.dereference(context).await?; let person = person_id.dereference(context).await?;
if person.banned { if person.banned {
return Err(LemmyErrorType::PersonIsBannedFromSite( Err(LemmyErrorType::PersonIsBannedFromSite(
person.actor_id.to_string(), person.actor_id.to_string(),
))?; ))?
} }
let person_id = person.id; let person_id = person.id;
let community_id = community.id; let community_id = community.id;
@ -103,11 +104,11 @@ pub(crate) async fn verify_person_in_community(
.await .await
.is_ok(); .is_ok();
if is_banned { if is_banned {
return Err(LemmyErrorType::PersonIsBannedFromCommunity)?; Err(LemmyErrorType::PersonIsBannedFromCommunity)?
} } else {
Ok(()) Ok(())
} }
}
/// Verify that mod action in community was performed by a moderator. /// Verify that mod action in community was performed by a moderator.
/// ///
@ -141,10 +142,11 @@ pub(crate) async fn verify_mod_action(
pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> Result<(), LemmyError> { pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> Result<(), LemmyError> {
if ![to, cc].iter().any(|set| set.contains(&public())) { if ![to, cc].iter().any(|set| set.contains(&public())) {
Err(LemmyErrorType::ObjectIsNotPublic)?; Err(LemmyErrorType::ObjectIsNotPublic)?
} } else {
Ok(()) Ok(())
} }
}
pub(crate) fn verify_community_matches<T>( pub(crate) fn verify_community_matches<T>(
a: &ObjectId<ApubCommunity>, a: &ObjectId<ApubCommunity>,
@ -155,10 +157,11 @@ where
{ {
let b: ObjectId<ApubCommunity> = b.into(); let b: ObjectId<ApubCommunity> = b.into();
if a != &b { if a != &b {
Err(LemmyErrorType::InvalidCommunity)?; Err(LemmyErrorType::InvalidCommunity)?
} } else {
Ok(()) Ok(())
} }
}
pub(crate) fn check_community_deleted_or_removed(community: &Community) -> Result<(), LemmyError> { pub(crate) fn check_community_deleted_or_removed(community: &Community) -> Result<(), LemmyError> {
if community.deleted || community.removed { if community.deleted || community.removed {

View File

@ -64,10 +64,11 @@ impl ActivityHandler for Vote {
.map(|l| l.enable_downvotes) .map(|l| l.enable_downvotes)
.unwrap_or(true); .unwrap_or(true);
if self.kind == VoteType::Dislike && !enable_downvotes { if self.kind == VoteType::Dislike && !enable_downvotes {
return Err(anyhow!("Downvotes disabled").into()); Err(anyhow!("Downvotes disabled").into())
} } else {
Ok(()) Ok(())
} }
}
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> { async fn receive(self, context: &Data<LemmyContext>) -> Result<(), LemmyError> {

View File

@ -43,8 +43,6 @@ pub async fn list_posts(
return Err(LemmyError::from(LemmyErrorType::ContradictingFilters)); return Err(LemmyError::from(LemmyErrorType::ContradictingFilters));
} }
let moderator_view = data.moderator_view.unwrap_or_default();
let listing_type = Some(listing_type_with_default( let listing_type = Some(listing_type_with_default(
data.type_, data.type_,
&local_site, &local_site,
@ -59,7 +57,6 @@ pub async fn list_posts(
saved_only, saved_only,
liked_only, liked_only,
disliked_only, disliked_only,
moderator_view,
page, page,
limit, limit,
..Default::default() ..Default::default()

View File

@ -26,7 +26,7 @@ pub async fn get_community(
let local_site = LocalSite::read(&mut context.pool()).await?; let local_site = LocalSite::read(&mut context.pool()).await?;
if data.name.is_none() && data.id.is_none() { if data.name.is_none() && data.id.is_none() {
return Err(LemmyErrorType::NoIdGiven)?; Err(LemmyErrorType::NoIdGiven)?
} }
check_private_instance(&local_user_view, &local_site)?; check_private_instance(&local_user_view, &local_site)?;

View File

@ -22,7 +22,7 @@ pub async fn read_person(
) -> Result<Json<GetPersonDetailsResponse>, LemmyError> { ) -> Result<Json<GetPersonDetailsResponse>, LemmyError> {
// Check to make sure a person name or an id is given // Check to make sure a person name or an id is given
if data.username.is_none() && data.person_id.is_none() { if data.username.is_none() && data.person_id.is_none() {
return Err(LemmyErrorType::NoIdGiven)?; Err(LemmyErrorType::NoIdGiven)?
} }
local_user_view_from_jwt_opt_new(&mut local_user_view, data.auth.as_ref(), &context).await; local_user_view_from_jwt_opt_new(&mut local_user_view, data.auth.as_ref(), &context).await;
@ -39,7 +39,7 @@ pub async fn read_person(
.with_lemmy_type(LemmyErrorType::CouldntFindPerson)? .with_lemmy_type(LemmyErrorType::CouldntFindPerson)?
.id .id
} else { } else {
return Err(LemmyErrorType::CouldntFindPerson)?; Err(LemmyErrorType::CouldntFindPerson)?
} }
} }
}; };

View File

@ -72,7 +72,8 @@ async fn convert_response(
}; };
// if the object was deleted from database, dont return it // if the object was deleted from database, dont return it
if removed_or_deleted { if removed_or_deleted {
return Err(NotFound {}.into()); Err(NotFound {}.into())
} } else {
Ok(Json(res)) Ok(Json(res))
} }
}

View File

@ -23,10 +23,8 @@ pub(crate) async fn get_apub_comment(
let id = CommentId(info.comment_id.parse::<i32>()?); let id = CommentId(info.comment_id.parse::<i32>()?);
let comment: ApubComment = Comment::read(&mut context.pool(), id).await?.into(); let comment: ApubComment = Comment::read(&mut context.pool(), id).await?.into();
if !comment.local { if !comment.local {
return Err(err_object_not_local()); Err(err_object_not_local())
} } else if !comment.deleted && !comment.removed {
if !comment.deleted && !comment.removed {
create_apub_response(&comment.into_json(&context).await?) create_apub_response(&comment.into_json(&context).await?)
} else { } else {
create_apub_tombstone_response(comment.ap_id.clone()) create_apub_tombstone_response(comment.ap_id.clone())

View File

@ -81,7 +81,7 @@ pub(crate) async fn get_apub_community_outbox(
.await? .await?
.into(); .into();
if community.deleted || community.removed { if community.deleted || community.removed {
return Err(LemmyErrorType::Deleted)?; Err(LemmyErrorType::Deleted)?
} }
let outbox = ApubCommunityOutbox::read_local(&community, &context).await?; let outbox = ApubCommunityOutbox::read_local(&community, &context).await?;
create_apub_response(&outbox) create_apub_response(&outbox)
@ -97,7 +97,7 @@ pub(crate) async fn get_apub_community_moderators(
.await? .await?
.into(); .into();
if community.deleted || community.removed { if community.deleted || community.removed {
return Err(LemmyErrorType::Deleted)?; Err(LemmyErrorType::Deleted)?
} }
let moderators = ApubCommunityModerators::read_local(&community, &context).await?; let moderators = ApubCommunityModerators::read_local(&community, &context).await?;
create_apub_response(&moderators) create_apub_response(&moderators)
@ -113,7 +113,7 @@ pub(crate) async fn get_apub_community_featured(
.await? .await?
.into(); .into();
if community.deleted || community.removed { if community.deleted || community.removed {
return Err(LemmyErrorType::Deleted)?; Err(LemmyErrorType::Deleted)?
} }
let featured = ApubCommunityFeatured::read_local(&community, &context).await?; let featured = ApubCommunityFeatured::read_local(&community, &context).await?;
create_apub_response(&featured) create_apub_response(&featured)

View File

@ -23,10 +23,8 @@ pub(crate) async fn get_apub_post(
let id = PostId(info.post_id.parse::<i32>()?); let id = PostId(info.post_id.parse::<i32>()?);
let post: ApubPost = Post::read(&mut context.pool(), id).await?.into(); let post: ApubPost = Post::read(&mut context.pool(), id).await?.into();
if !post.local { if !post.local {
return Err(err_object_not_local()); Err(err_object_not_local())
} } else if !post.deleted && !post.removed {
if !post.deleted && !post.removed {
create_apub_response(&post.into_json(&context).await?) create_apub_response(&post.into_json(&context).await?)
} else { } else {
create_apub_tombstone_response(post.ap_id.clone()) create_apub_tombstone_response(post.ap_id.clone())

View File

@ -79,7 +79,7 @@ fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> Result
.map(|l| l.federation_enabled) .map(|l| l.federation_enabled)
.unwrap_or(true) .unwrap_or(true)
{ {
Err(LemmyErrorType::FederationDisabled)?; Err(LemmyErrorType::FederationDisabled)?
} }
if local_site_data if local_site_data
@ -87,7 +87,7 @@ fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> Result
.iter() .iter()
.any(|i| domain.to_lowercase().eq(&i.domain.to_lowercase())) .any(|i| domain.to_lowercase().eq(&i.domain.to_lowercase()))
{ {
Err(LemmyErrorType::DomainBlocked(domain.clone()))?; Err(LemmyErrorType::DomainBlocked(domain.clone()))?
} }
// Only check this if there are instances in the allowlist // Only check this if there are instances in the allowlist
@ -97,7 +97,7 @@ fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> Result
.iter() .iter()
.any(|i| domain.to_lowercase().eq(&i.domain.to_lowercase())) .any(|i| domain.to_lowercase().eq(&i.domain.to_lowercase()))
{ {
Err(LemmyErrorType::DomainNotInAllowList(domain))?; Err(LemmyErrorType::DomainNotInAllowList(domain))?
} }
Ok(()) Ok(())
@ -176,7 +176,7 @@ pub(crate) async fn check_apub_id_valid_with_strictness(
let domain = apub_id.domain().expect("apud id has domain").to_string(); let domain = apub_id.domain().expect("apud id has domain").to_string();
if !allowed_and_local.contains(&domain) { if !allowed_and_local.contains(&domain) {
return Err(LemmyErrorType::FederationDisabledByStrictAllowList)?; Err(LemmyErrorType::FederationDisabledByStrictAllowList)?
} }
} }
Ok(()) Ok(())

View File

@ -143,10 +143,11 @@ impl Object for ApubComment {
verify_person_in_community(&note.attributed_to, &community, context).await?; verify_person_in_community(&note.attributed_to, &community, context).await?;
let (post, _) = note.get_parents(context).await?; let (post, _) = note.get_parents(context).await?;
if post.locked { if post.locked {
return Err(LemmyErrorType::PostIsLocked)?; Err(LemmyErrorType::PostIsLocked)?
} } else {
Ok(()) Ok(())
} }
}
/// Converts a `Note` to `Comment`. /// Converts a `Note` to `Comment`.
/// ///

View File

@ -107,12 +107,13 @@ impl Object for ApubPrivateMessage {
check_apub_id_valid_with_strictness(note.id.inner(), false, context).await?; check_apub_id_valid_with_strictness(note.id.inner(), false, context).await?;
let person = note.attributed_to.dereference(context).await?; let person = note.attributed_to.dereference(context).await?;
if person.banned { if person.banned {
return Err(LemmyErrorType::PersonIsBannedFromSite( Err(LemmyErrorType::PersonIsBannedFromSite(
person.actor_id.to_string(), person.actor_id.to_string(),
))?; ))?
} } else {
Ok(()) Ok(())
} }
}
#[tracing::instrument(skip_all)] #[tracing::instrument(skip_all)]
async fn from_json( async fn from_json(

View File

@ -208,7 +208,7 @@ impl InCommunity for Page {
break c; break c;
} }
} else { } else {
return Err(LemmyErrorType::NoCommunityFoundInCc)?; Err(LemmyErrorType::NoCommunityFoundInCc)?
} }
} }
} }

View File

@ -2,17 +2,6 @@ diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs
index 255c6422..f2ccf5e2 100644 index 255c6422..f2ccf5e2 100644
--- a/crates/db_schema/src/schema.rs --- a/crates/db_schema/src/schema.rs
+++ b/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs
@@ -9,10 +9,6 @@ pub mod sql_types {
#[diesel(postgres_type(name = "listing_type_enum"))]
pub struct ListingTypeEnum;
- #[derive(diesel::sql_types::SqlType)]
- #[diesel(postgres_type(name = "ltree"))]
- pub struct Ltree;
-
#[derive(diesel::sql_types::SqlType)]
#[diesel(postgres_type(name = "registration_mode_enum"))]
pub struct RegistrationModeEnum;
@@ -76,13 +76,13 @@ diesel::table! { @@ -76,13 +76,13 @@ diesel::table! {
published -> Timestamptz, published -> Timestamptz,
} }

View File

@ -44,7 +44,9 @@ use strum_macros::{Display, EnumString};
#[cfg(feature = "full")] #[cfg(feature = "full")]
use ts_rs::TS; use ts_rs::TS;
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] #[derive(
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default,
)]
#[cfg_attr(feature = "full", derive(DbEnum, TS))] #[cfg_attr(feature = "full", derive(DbEnum, TS))]
#[cfg_attr( #[cfg_attr(
feature = "full", feature = "full",
@ -54,6 +56,7 @@ use ts_rs::TS;
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// The post sort types. See here for descriptions: https://join-lemmy.org/docs/en/users/03-votes-and-ranking.html /// The post sort types. See here for descriptions: https://join-lemmy.org/docs/en/users/03-votes-and-ranking.html
pub enum SortType { pub enum SortType {
#[default]
Active, Active,
Hot, Hot,
New, New,
@ -99,7 +102,9 @@ pub enum PersonSortType {
PostCount, PostCount,
} }
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] #[derive(
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default,
)]
#[cfg_attr(feature = "full", derive(DbEnum, TS))] #[cfg_attr(feature = "full", derive(DbEnum, TS))]
#[cfg_attr( #[cfg_attr(
feature = "full", feature = "full",
@ -112,9 +117,12 @@ pub enum ListingType {
/// Content from your own site, as well as all connected / federated sites. /// Content from your own site, as well as all connected / federated sites.
All, All,
/// Content from your site only. /// Content from your site only.
#[default]
Local, Local,
/// Content only from communities you've subscribed to. /// Content only from communities you've subscribed to.
Subscribed, Subscribed,
/// Content that you can moderate (because you are a moderator of the community it is posted to)
ModeratorView,
} }
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] #[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
@ -135,6 +143,24 @@ pub enum RegistrationMode {
Open, Open,
} }
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "full", derive(DbEnum, TS))]
#[cfg_attr(
feature = "full",
ExistingTypePath = "crate::schema::sql_types::PostListingModeEnum"
)]
#[cfg_attr(feature = "full", DbValueStyle = "verbatim")]
#[cfg_attr(feature = "full", ts(export))]
/// A post-view mode that changes how multiple post listings look.
pub enum PostListingMode {
/// A compact, list-type view.
List,
/// A larger card-type view.
Card,
/// A smaller card-type view, usually with images as thumbnails
SmallCard,
}
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy)] #[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]

View File

@ -9,6 +9,14 @@ pub mod sql_types {
#[diesel(postgres_type(name = "listing_type_enum"))] #[diesel(postgres_type(name = "listing_type_enum"))]
pub struct ListingTypeEnum; pub struct ListingTypeEnum;
#[derive(diesel::sql_types::SqlType)]
#[diesel(postgres_type(name = "ltree"))]
pub struct Ltree;
#[derive(diesel::sql_types::SqlType)]
#[diesel(postgres_type(name = "post_listing_mode_enum"))]
pub struct PostListingModeEnum;
#[derive(diesel::sql_types::SqlType)] #[derive(diesel::sql_types::SqlType)]
#[diesel(postgres_type(name = "registration_mode_enum"))] #[diesel(postgres_type(name = "registration_mode_enum"))]
pub struct RegistrationModeEnum; pub struct RegistrationModeEnum;
@ -387,6 +395,7 @@ diesel::table! {
use diesel::sql_types::*; use diesel::sql_types::*;
use super::sql_types::SortTypeEnum; use super::sql_types::SortTypeEnum;
use super::sql_types::ListingTypeEnum; use super::sql_types::ListingTypeEnum;
use super::sql_types::PostListingModeEnum;
local_user (id) { local_user (id) {
id -> Int4, id -> Int4,
@ -415,6 +424,7 @@ diesel::table! {
auto_expand -> Bool, auto_expand -> Bool,
infinite_scroll_enabled -> Bool, infinite_scroll_enabled -> Bool,
admin -> Bool, admin -> Bool,
post_listing_mode -> PostListingModeEnum,
} }
} }

View File

@ -3,6 +3,7 @@ use crate::schema::local_user;
use crate::{ use crate::{
newtypes::{LocalUserId, PersonId}, newtypes::{LocalUserId, PersonId},
ListingType, ListingType,
PostListingMode,
SortType, SortType,
}; };
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
@ -60,6 +61,7 @@ pub struct LocalUser {
pub infinite_scroll_enabled: bool, pub infinite_scroll_enabled: bool,
/// Whether the person is an admin. /// Whether the person is an admin.
pub admin: bool, pub admin: bool,
pub post_listing_mode: PostListingMode,
} }
#[derive(Clone, TypedBuilder)] #[derive(Clone, TypedBuilder)]
@ -92,6 +94,7 @@ pub struct LocalUserInsertForm {
pub auto_expand: Option<bool>, pub auto_expand: Option<bool>,
pub infinite_scroll_enabled: Option<bool>, pub infinite_scroll_enabled: Option<bool>,
pub admin: Option<bool>, pub admin: Option<bool>,
pub post_listing_mode: Option<PostListingMode>,
} }
#[derive(Clone, Default)] #[derive(Clone, Default)]
@ -120,4 +123,5 @@ pub struct LocalUserUpdateForm {
pub auto_expand: Option<bool>, pub auto_expand: Option<bool>,
pub infinite_scroll_enabled: Option<bool>, pub infinite_scroll_enabled: Option<bool>,
pub admin: Option<bool>, pub admin: Option<bool>,
pub post_listing_mode: Option<PostListingMode>,
} }

View File

@ -182,13 +182,6 @@ pub trait Reportable {
Self: Sized; Self: Sized;
} }
pub trait JoinView {
type JoinTuple;
fn from_tuple(tuple: Self::JoinTuple) -> Self
where
Self: Sized;
}
#[async_trait] #[async_trait]
pub trait ApubActor { pub trait ApubActor {
async fn read_from_apub_id( async fn read_from_apub_id(

View File

@ -2,7 +2,6 @@ use crate::{
diesel::Connection, diesel::Connection,
diesel_migrations::MigrationHarness, diesel_migrations::MigrationHarness,
newtypes::DbUrl, newtypes::DbUrl,
traits::JoinView,
CommentSortType, CommentSortType,
PersonSortType, PersonSortType,
SortType, SortType,
@ -433,33 +432,13 @@ pub fn now() -> AsExprOf<diesel::dsl::now, diesel::sql_types::Timestamptz> {
pub type ResultFuture<'a, T> = BoxFuture<'a, Result<T, DieselError>>; pub type ResultFuture<'a, T> = BoxFuture<'a, Result<T, DieselError>>;
pub trait ReadFn<'a, T: JoinView, Args>: pub trait ReadFn<'a, T, Args>: Fn(DbConn<'a>, Args) -> ResultFuture<'a, T> {}
Fn(DbConn<'a>, Args) -> ResultFuture<'a, <T as JoinView>::JoinTuple>
{
}
impl< impl<'a, T, Args, F: Fn(DbConn<'a>, Args) -> ResultFuture<'a, T>> ReadFn<'a, T, Args> for F {}
'a,
T: JoinView,
Args,
F: Fn(DbConn<'a>, Args) -> ResultFuture<'a, <T as JoinView>::JoinTuple>,
> ReadFn<'a, T, Args> for F
{
}
pub trait ListFn<'a, T: JoinView, Args>: pub trait ListFn<'a, T, Args>: Fn(DbConn<'a>, Args) -> ResultFuture<'a, Vec<T>> {}
Fn(DbConn<'a>, Args) -> ResultFuture<'a, Vec<<T as JoinView>::JoinTuple>>
{
}
impl< impl<'a, T, Args, F: Fn(DbConn<'a>, Args) -> ResultFuture<'a, Vec<T>>> ListFn<'a, T, Args> for F {}
'a,
T: JoinView,
Args,
F: Fn(DbConn<'a>, Args) -> ResultFuture<'a, Vec<<T as JoinView>::JoinTuple>>,
> ListFn<'a, T, Args> for F
{
}
/// Allows read and list functions to capture a shared closure that has an inferred return type, which is useful for join logic /// Allows read and list functions to capture a shared closure that has an inferred return type, which is useful for join logic
pub struct Queries<RF, LF> { pub struct Queries<RF, LF> {
@ -474,11 +453,8 @@ impl Queries<(), ()> {
list_fn: LF2, list_fn: LF2,
) -> Queries<impl ReadFn<'a, RT, RA>, impl ListFn<'a, LT, LA>> ) -> Queries<impl ReadFn<'a, RT, RA>, impl ListFn<'a, LT, LA>>
where where
RFut: Future<Output = Result<<RT as JoinView>::JoinTuple, DieselError>> + Sized + Send + 'a, RFut: Future<Output = Result<RT, DieselError>> + Sized + Send + 'a,
LFut: LFut: Future<Output = Result<Vec<LT>, DieselError>> + Sized + Send + 'a,
Future<Output = Result<Vec<<LT as JoinView>::JoinTuple>, DieselError>> + Sized + Send + 'a,
RT: JoinView,
LT: JoinView,
RF2: Fn(DbConn<'a>, RA) -> RFut, RF2: Fn(DbConn<'a>, RA) -> RFut,
LF2: Fn(DbConn<'a>, LA) -> LFut, LF2: Fn(DbConn<'a>, LA) -> LFut,
{ {
@ -496,12 +472,10 @@ impl<RF, LF> Queries<RF, LF> {
args: Args, args: Args,
) -> Result<T, DieselError> ) -> Result<T, DieselError>
where where
T: JoinView,
RF: ReadFn<'a, T, Args>, RF: ReadFn<'a, T, Args>,
{ {
let conn = get_conn(pool).await?; let conn = get_conn(pool).await?;
let res = (self.read_fn)(conn, args).await?; (self.read_fn)(conn, args).await
Ok(T::from_tuple(res))
} }
pub async fn list<'a, T, Args>( pub async fn list<'a, T, Args>(
@ -510,12 +484,10 @@ impl<RF, LF> Queries<RF, LF> {
args: Args, args: Args,
) -> Result<Vec<T>, DieselError> ) -> Result<Vec<T>, DieselError>
where where
T: JoinView,
LF: ListFn<'a, T, Args>, LF: ListFn<'a, T, Args>,
{ {
let conn = get_conn(pool).await?; let conn = get_conn(pool).await?;
let res = (self.list_fn)(conn, args).await?; (self.list_fn)(conn, args).await
Ok(res.into_iter().map(T::from_tuple).collect())
} }
} }

View File

@ -11,7 +11,6 @@ use diesel::{
}; };
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::CommentAggregates,
aliases, aliases,
newtypes::{CommentReportId, CommunityId, PersonId}, newtypes::{CommentReportId, CommunityId, PersonId},
schema::{ schema::{
@ -25,14 +24,6 @@ use lemmy_db_schema::{
person, person,
post, post,
}, },
source::{
comment::Comment,
comment_report::CommentReport,
community::Community,
person::Person,
post::Post,
},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
}; };
@ -89,7 +80,7 @@ fn queries<'a>() -> Queries<
), ),
) )
.select(selection) .select(selection)
.first::<<CommentReportView as JoinView>::JoinTuple>(&mut conn) .first::<CommentReportView>(&mut conn)
.await .await
}; };
@ -135,12 +126,10 @@ fn queries<'a>() -> Queries<
.and(community_moderator::person_id.eq(user.person.id)), .and(community_moderator::person_id.eq(user.person.id)),
), ),
) )
.load::<<CommentReportView as JoinView>::JoinTuple>(&mut conn) .load::<CommentReportView>(&mut conn)
.await .await
} else { } else {
query query.load::<CommentReportView>(&mut conn).await
.load::<<CommentReportView as JoinView>::JoinTuple>(&mut conn)
.await
} }
}; };
@ -220,36 +209,6 @@ impl CommentReportQuery {
} }
} }
impl JoinView for CommentReportView {
type JoinTuple = (
CommentReport,
Comment,
Post,
Community,
Person,
Person,
CommentAggregates,
bool,
Option<i16>,
Option<Person>,
);
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
comment_report: a.0,
comment: a.1,
post: a.2,
community: a.3,
creator: a.4,
comment_creator: a.5,
counts: a.6,
creator_banned_from_community: a.7,
my_vote: a.8,
resolver: a.9,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(clippy::unwrap_used)] #![allow(clippy::unwrap_used)]

View File

@ -12,7 +12,6 @@ use diesel::{
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use diesel_ltree::{nlevel, subpath, Ltree, LtreeExtensions}; use diesel_ltree::{nlevel, subpath, Ltree, LtreeExtensions};
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::CommentAggregates,
newtypes::{CommentId, CommunityId, LocalUserId, PersonId, PostId}, newtypes::{CommentId, CommunityId, LocalUserId, PersonId, PostId},
schema::{ schema::{
comment, comment,
@ -22,38 +21,19 @@ use lemmy_db_schema::{
community, community,
community_block, community_block,
community_follower, community_follower,
community_moderator,
community_person_ban, community_person_ban,
local_user_language, local_user_language,
person, person,
person_block, person_block,
post, post,
}, },
source::{ source::community::CommunityFollower,
comment::Comment,
community::{Community, CommunityFollower},
person::Person,
post::Post,
},
traits::JoinView,
utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
CommentSortType, CommentSortType,
ListingType, ListingType,
SubscribedType,
}; };
type CommentViewTuple = (
Comment,
Person,
Post,
Community,
CommentAggregates,
bool,
SubscribedType,
bool,
bool,
Option<i16>,
);
fn queries<'a>() -> Queries< fn queries<'a>() -> Queries<
impl ReadFn<'a, CommentView, (CommentId, Option<PersonId>)>, impl ReadFn<'a, CommentView, (CommentId, Option<PersonId>)>,
impl ListFn<'a, CommentView, CommentQuery<'a>>, impl ListFn<'a, CommentView, CommentQuery<'a>>,
@ -101,6 +81,14 @@ fn queries<'a>() -> Queries<
.and(comment_like::person_id.eq(person_id_join)), .and(comment_like::person_id.eq(person_id_join)),
), ),
) )
.left_join(
community_moderator::table.on(
post::id
.eq(comment::post_id)
.and(post::community_id.eq(community_moderator::community_id))
.and(community_moderator::person_id.eq(person_id_join)),
),
)
}; };
let selection = ( let selection = (
@ -120,7 +108,7 @@ fn queries<'a>() -> Queries<
(comment_id, my_person_id): (CommentId, Option<PersonId>)| async move { (comment_id, my_person_id): (CommentId, Option<PersonId>)| async move {
all_joins(comment::table.find(comment_id).into_boxed(), my_person_id) all_joins(comment::table.find(comment_id).into_boxed(), my_person_id)
.select(selection) .select(selection)
.first::<CommentViewTuple>(&mut conn) .first::<CommentView>(&mut conn)
.await .await
}; };
@ -186,6 +174,9 @@ fn queries<'a>() -> Queries<
.or(community_follower::person_id.eq(person_id_join)), .or(community_follower::person_id.eq(person_id_join)),
) )
} }
ListingType::ModeratorView => {
query = query.filter(community_moderator::person_id.is_not_null());
}
} }
} }
@ -222,7 +213,9 @@ fn queries<'a>() -> Queries<
query = query.filter(person::bot_account.eq(false)); query = query.filter(person::bot_account.eq(false));
}; };
if options.local_user.is_some() { if options.local_user.is_some()
&& options.listing_type.unwrap_or_default() != ListingType::ModeratorView
{
// Filter out the rows with missing languages // Filter out the rows with missing languages
query = query.filter(local_user_language::language_id.is_not_null()); query = query.filter(local_user_language::language_id.is_not_null());
@ -282,7 +275,7 @@ fn queries<'a>() -> Queries<
query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.load::<CommentViewTuple>(&mut conn) .load::<CommentView>(&mut conn)
.await .await
}; };
@ -330,40 +323,13 @@ impl<'a> CommentQuery<'a> {
} }
} }
impl JoinView for CommentView {
type JoinTuple = CommentViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
comment: a.0,
creator: a.1,
post: a.2,
community: a.3,
counts: a.4,
creator_banned_from_community: a.5,
subscribed: a.6,
saved: a.7,
creator_blocked: a.8,
my_vote: a.9,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(clippy::unwrap_used)] #![allow(clippy::unwrap_used)]
#![allow(clippy::indexing_slicing)] #![allow(clippy::indexing_slicing)]
use crate::{ use crate::{
comment_view::{ comment_view::{CommentQuery, CommentSortType, CommentView, DbPool},
Comment,
CommentQuery,
CommentSortType,
CommentView,
Community,
DbPool,
Person,
Post,
},
structs::LocalUserView, structs::LocalUserView,
}; };
use lemmy_db_schema::{ use lemmy_db_schema::{
@ -372,14 +338,14 @@ mod tests {
newtypes::LanguageId, newtypes::LanguageId,
source::{ source::{
actor_language::LocalUserLanguage, actor_language::LocalUserLanguage,
comment::{CommentInsertForm, CommentLike, CommentLikeForm}, comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm},
community::CommunityInsertForm, community::{Community, CommunityInsertForm},
instance::Instance, instance::Instance,
language::Language, language::Language,
local_user::{LocalUser, LocalUserInsertForm}, local_user::{LocalUser, LocalUserInsertForm},
person::PersonInsertForm, person::{Person, PersonInsertForm},
person_block::{PersonBlock, PersonBlockForm}, person_block::{PersonBlock, PersonBlockForm},
post::PostInsertForm, post::{Post, PostInsertForm},
}, },
traits::{Blockable, Crud, Likeable}, traits::{Blockable, Crud, Likeable},
utils::build_db_pool_for_tests, utils::build_db_pool_for_tests,

View File

@ -3,18 +3,13 @@ use actix_web::{dev::Payload, FromRequest, HttpMessage, HttpRequest};
use diesel::{result::Error, BoolExpressionMethods, ExpressionMethods, JoinOnDsl, QueryDsl}; use diesel::{result::Error, BoolExpressionMethods, ExpressionMethods, JoinOnDsl, QueryDsl};
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::PersonAggregates,
newtypes::{LocalUserId, PersonId}, newtypes::{LocalUserId, PersonId},
schema::{local_user, person, person_aggregates}, schema::{local_user, person, person_aggregates},
source::{local_user::LocalUser, person::Person},
traits::JoinView,
utils::{functions::lower, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{functions::lower, DbConn, DbPool, ListFn, Queries, ReadFn},
}; };
use lemmy_utils::error::{LemmyError, LemmyErrorType}; use lemmy_utils::error::{LemmyError, LemmyErrorType};
use std::future::{ready, Ready}; use std::future::{ready, Ready};
type LocalUserViewTuple = (LocalUser, Person, PersonAggregates);
enum ReadBy<'a> { enum ReadBy<'a> {
Id(LocalUserId), Id(LocalUserId),
Person(PersonId), Person(PersonId),
@ -56,7 +51,7 @@ fn queries<'a>(
query query
.inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id))) .inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id)))
.select(selection) .select(selection)
.first::<LocalUserViewTuple>(&mut conn) .first::<LocalUserView>(&mut conn)
.await .await
}; };
@ -69,7 +64,7 @@ fn queries<'a>(
.inner_join(person::table) .inner_join(person::table)
.inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id))) .inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id)))
.select(selection) .select(selection)
.load::<LocalUserViewTuple>(&mut conn) .load::<LocalUserView>(&mut conn)
.await .await
} }
} }
@ -109,17 +104,6 @@ impl LocalUserView {
} }
} }
impl JoinView for LocalUserView {
type JoinTuple = LocalUserViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
local_user: a.0,
person: a.1,
counts: a.2,
}
}
}
impl FromRequest for LocalUserView { impl FromRequest for LocalUserView {
type Error = LemmyError; type Error = LemmyError;
type Future = Ready<Result<Self, Self::Error>>; type Future = Ready<Result<Self, Self::Error>>;

View File

@ -10,7 +10,6 @@ use diesel::{
}; };
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::PostAggregates,
aliases, aliases,
newtypes::{CommunityId, PersonId, PostReportId}, newtypes::{CommunityId, PersonId, PostReportId},
schema::{ schema::{
@ -23,23 +22,9 @@ use lemmy_db_schema::{
post_like, post_like,
post_report, post_report,
}, },
source::{community::Community, person::Person, post::Post, post_report::PostReport},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
}; };
type PostReportViewTuple = (
PostReport,
Post,
Community,
Person,
Person,
bool,
Option<i16>,
PostAggregates,
Option<Person>,
);
fn queries<'a>() -> Queries< fn queries<'a>() -> Queries<
impl ReadFn<'a, PostReportView, (PostReportId, PersonId)>, impl ReadFn<'a, PostReportView, (PostReportId, PersonId)>,
impl ListFn<'a, PostReportView, (PostReportQuery, &'a LocalUserView)>, impl ListFn<'a, PostReportView, (PostReportQuery, &'a LocalUserView)>,
@ -87,7 +72,7 @@ fn queries<'a>() -> Queries<
post_report::table.find(report_id).into_boxed(), post_report::table.find(report_id).into_boxed(),
my_person_id, my_person_id,
) )
.first::<PostReportViewTuple>(&mut conn) .first::<PostReportView>(&mut conn)
.await .await
}; };
@ -119,10 +104,10 @@ fn queries<'a>() -> Queries<
.and(community_moderator::person_id.eq(user.person.id)), .and(community_moderator::person_id.eq(user.person.id)),
), ),
) )
.load::<PostReportViewTuple>(&mut conn) .load::<PostReportView>(&mut conn)
.await .await
} else { } else {
query.load::<PostReportViewTuple>(&mut conn).await query.load::<PostReportView>(&mut conn).await
} }
}; };
@ -199,23 +184,6 @@ impl PostReportQuery {
} }
} }
impl JoinView for PostReportView {
type JoinTuple = PostReportViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
post_report: a.0,
post: a.1,
community: a.2,
creator: a.3,
post_creator: a.4,
creator_banned_from_community: a.5,
my_vote: a.6,
counts: a.7,
resolver: a.8,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(clippy::unwrap_used)] #![allow(clippy::unwrap_used)]

View File

@ -16,7 +16,6 @@ use diesel::{
}; };
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::PostAggregates,
newtypes::{CommunityId, LocalUserId, PersonId, PostId}, newtypes::{CommunityId, LocalUserId, PersonId, PostId},
schema::{ schema::{
community, community,
@ -34,33 +33,13 @@ use lemmy_db_schema::{
post_read, post_read,
post_saved, post_saved,
}, },
source::{ source::community::CommunityFollower,
community::{Community, CommunityFollower},
person::Person,
post::Post,
},
traits::JoinView,
utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
ListingType, ListingType,
SortType, SortType,
SubscribedType,
}; };
use tracing::debug; use tracing::debug;
type PostViewTuple = (
Post,
Person,
Community,
bool,
PostAggregates,
SubscribedType,
bool,
bool,
bool,
Option<i16>,
i64,
);
sql_function!(fn coalesce(x: sql_types::Nullable<sql_types::BigInt>, y: sql_types::BigInt) -> sql_types::BigInt); sql_function!(fn coalesce(x: sql_types::Nullable<sql_types::BigInt>, y: sql_types::BigInt) -> sql_types::BigInt);
fn queries<'a>() -> Queries< fn queries<'a>() -> Queries<
@ -182,7 +161,7 @@ fn queries<'a>() -> Queries<
); );
} }
query.first::<PostViewTuple>(&mut conn).await query.first::<PostView>(&mut conn).await
}; };
let list = move |mut conn: DbConn<'a>, options: PostQuery<'a>| async move { let list = move |mut conn: DbConn<'a>, options: PostQuery<'a>| async move {
@ -258,6 +237,9 @@ fn queries<'a>() -> Queries<
.or(community_follower::person_id.eq(person_id_join)), .or(community_follower::person_id.eq(person_id_join)),
) )
} }
ListingType::ModeratorView => {
query = query.filter(community_moderator::person_id.is_not_null());
}
} }
} }
@ -295,10 +277,6 @@ fn queries<'a>() -> Queries<
if options.saved_only { if options.saved_only {
query = query.filter(post_saved::id.is_not_null()); query = query.filter(post_saved::id.is_not_null());
} }
if options.moderator_view {
query = query.filter(community_moderator::person_id.is_not_null());
}
// Only hide the read posts, if the saved_only is false. Otherwise ppl with the hide_read // Only hide the read posts, if the saved_only is false. Otherwise ppl with the hide_read
// setting wont be able to see saved posts. // setting wont be able to see saved posts.
else if !options else if !options
@ -318,16 +296,17 @@ fn queries<'a>() -> Queries<
query = query.filter(post_like::score.eq(-1)); query = query.filter(post_like::score.eq(-1));
} }
if options.local_user.is_some() { // Dont filter blocks or missing languages for moderator view type
if options.local_user.is_some()
&& options.listing_type.unwrap_or_default() != ListingType::ModeratorView
{
// Filter out the rows with missing languages // Filter out the rows with missing languages
query = query.filter(local_user_language::language_id.is_not_null()); query = query.filter(local_user_language::language_id.is_not_null());
// Don't show blocked communities or persons // Don't show blocked communities or persons
query = query.filter(community_block::person_id.is_null()); query = query.filter(community_block::person_id.is_null());
if !options.moderator_view {
query = query.filter(person_block::person_id.is_null()); query = query.filter(person_block::person_id.is_null());
} }
}
let now = diesel::dsl::now.into_sql::<Timestamptz>(); let now = diesel::dsl::now.into_sql::<Timestamptz>();
query = match options.sort.unwrap_or(SortType::Hot) { query = match options.sort.unwrap_or(SortType::Hot) {
@ -395,7 +374,7 @@ fn queries<'a>() -> Queries<
debug!("Post View Query: {:?}", debug_query::<Pg, _>(&query)); debug!("Post View Query: {:?}", debug_query::<Pg, _>(&query));
query.load::<PostViewTuple>(&mut conn).await query.load::<PostView>(&mut conn).await
}; };
Queries::new(read, list) Queries::new(read, list)
@ -446,25 +425,6 @@ impl<'a> PostQuery<'a> {
} }
} }
impl JoinView for PostView {
type JoinTuple = PostViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
post: a.0,
creator: a.1,
community: a.2,
creator_banned_from_community: a.3,
counts: a.4,
subscribed: a.5,
saved: a.6,
read: a.7,
creator_blocked: a.8,
my_vote: a.9,
unread_comments: a.10,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(clippy::unwrap_used)] #![allow(clippy::unwrap_used)]

View File

@ -12,23 +12,9 @@ use lemmy_db_schema::{
aliases, aliases,
newtypes::PrivateMessageReportId, newtypes::PrivateMessageReportId,
schema::{person, private_message, private_message_report}, schema::{person, private_message, private_message_report},
source::{
person::Person,
private_message::PrivateMessage,
private_message_report::PrivateMessageReport,
},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
}; };
type PrivateMessageReportViewTuple = (
PrivateMessageReport,
PrivateMessage,
Person,
Person,
Option<Person>,
);
fn queries<'a>() -> Queries< fn queries<'a>() -> Queries<
impl ReadFn<'a, PrivateMessageReportView, PrivateMessageReportId>, impl ReadFn<'a, PrivateMessageReportView, PrivateMessageReportId>,
impl ListFn<'a, PrivateMessageReportView, PrivateMessageReportQuery>, impl ListFn<'a, PrivateMessageReportView, PrivateMessageReportQuery>,
@ -56,7 +42,7 @@ fn queries<'a>() -> Queries<
let read = move |mut conn: DbConn<'a>, report_id: PrivateMessageReportId| async move { let read = move |mut conn: DbConn<'a>, report_id: PrivateMessageReportId| async move {
all_joins(private_message_report::table.find(report_id).into_boxed()) all_joins(private_message_report::table.find(report_id).into_boxed())
.first::<PrivateMessageReportViewTuple>(&mut conn) .first::<PrivateMessageReportView>(&mut conn)
.await .await
}; };
@ -73,7 +59,7 @@ fn queries<'a>() -> Queries<
.order_by(private_message::published.desc()) .order_by(private_message::published.desc())
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.load::<PrivateMessageReportViewTuple>(&mut conn) .load::<PrivateMessageReportView>(&mut conn)
.await .await
}; };
@ -119,19 +105,6 @@ impl PrivateMessageReportQuery {
} }
} }
impl JoinView for PrivateMessageReportView {
type JoinTuple = PrivateMessageReportViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
private_message_report: a.0,
private_message: a.1,
private_message_creator: a.2,
creator: a.3,
resolver: a.4,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(clippy::unwrap_used)] #![allow(clippy::unwrap_used)]

View File

@ -13,14 +13,10 @@ use lemmy_db_schema::{
aliases, aliases,
newtypes::{PersonId, PrivateMessageId}, newtypes::{PersonId, PrivateMessageId},
schema::{person, private_message}, schema::{person, private_message},
source::{person::Person, private_message::PrivateMessage},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
}; };
use tracing::debug; use tracing::debug;
type PrivateMessageViewTuple = (PrivateMessage, Person, Person);
fn queries<'a>() -> Queries< fn queries<'a>() -> Queries<
impl ReadFn<'a, PrivateMessageView, PrivateMessageId>, impl ReadFn<'a, PrivateMessageView, PrivateMessageId>,
impl ListFn<'a, PrivateMessageView, (PrivateMessageQuery, PersonId)>, impl ListFn<'a, PrivateMessageView, (PrivateMessageQuery, PersonId)>,
@ -43,7 +39,7 @@ fn queries<'a>() -> Queries<
all_joins(private_message::table.find(private_message_id).into_boxed()) all_joins(private_message::table.find(private_message_id).into_boxed())
.order_by(private_message::published.desc()) .order_by(private_message::published.desc())
.select(selection) .select(selection)
.first::<PrivateMessageViewTuple>(&mut conn) .first::<PrivateMessageView>(&mut conn)
.await .await
}; };
@ -88,7 +84,7 @@ fn queries<'a>() -> Queries<
debug_query::<Pg, _>(&query) debug_query::<Pg, _>(&query)
); );
query.load::<PrivateMessageViewTuple>(&mut conn).await query.load::<PrivateMessageView>(&mut conn).await
}; };
Queries::new(read, list) Queries::new(read, list)
@ -137,17 +133,6 @@ impl PrivateMessageQuery {
} }
} }
impl JoinView for PrivateMessageView {
type JoinTuple = PrivateMessageViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
private_message: a.0,
creator: a.1,
recipient: a.2,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(clippy::unwrap_used)] #![allow(clippy::unwrap_used)]

View File

@ -12,18 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
aliases, aliases,
schema::{local_user, person, registration_application}, schema::{local_user, person, registration_application},
source::{
local_user::LocalUser,
person::Person,
registration_application::RegistrationApplication,
},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
}; };
type RegistrationApplicationViewTuple =
(RegistrationApplication, LocalUser, Person, Option<Person>);
fn queries<'a>() -> Queries< fn queries<'a>() -> Queries<
impl ReadFn<'a, RegistrationApplicationView, i32>, impl ReadFn<'a, RegistrationApplicationView, i32>,
impl ListFn<'a, RegistrationApplicationView, RegistrationApplicationQuery>, impl ListFn<'a, RegistrationApplicationView, RegistrationApplicationQuery>,
@ -51,7 +42,7 @@ fn queries<'a>() -> Queries<
.find(registration_application_id) .find(registration_application_id)
.into_boxed(), .into_boxed(),
) )
.first::<RegistrationApplicationViewTuple>(&mut conn) .first::<RegistrationApplicationView>(&mut conn)
.await .await
}; };
@ -73,9 +64,7 @@ fn queries<'a>() -> Queries<
.offset(offset) .offset(offset)
.order_by(registration_application::published.desc()); .order_by(registration_application::published.desc());
query query.load::<RegistrationApplicationView>(&mut conn).await
.load::<RegistrationApplicationViewTuple>(&mut conn)
.await
}; };
Queries::new(read, list) Queries::new(read, list)
@ -135,18 +124,6 @@ impl RegistrationApplicationQuery {
} }
} }
impl JoinView for RegistrationApplicationView {
type JoinTuple = RegistrationApplicationViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
registration_application: a.0,
creator_local_user: a.1,
creator: a.2,
admin: a.3,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(clippy::unwrap_used)] #![allow(clippy::unwrap_used)]
@ -290,6 +267,7 @@ mod tests {
open_links_in_new_tab: inserted_sara_local_user.open_links_in_new_tab, open_links_in_new_tab: inserted_sara_local_user.open_links_in_new_tab,
infinite_scroll_enabled: inserted_sara_local_user.infinite_scroll_enabled, infinite_scroll_enabled: inserted_sara_local_user.infinite_scroll_enabled,
admin: false, admin: false,
post_listing_mode: inserted_sara_local_user.post_listing_mode,
}, },
creator: Person { creator: Person {
id: inserted_sara_person.id, id: inserted_sara_person.id,

View File

@ -2,16 +2,14 @@ use crate::structs::SiteView;
use diesel::{result::Error, ExpressionMethods, JoinOnDsl, QueryDsl}; use diesel::{result::Error, ExpressionMethods, JoinOnDsl, QueryDsl};
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::SiteAggregates,
schema::{local_site, local_site_rate_limit, site, site_aggregates}, schema::{local_site, local_site_rate_limit, site, site_aggregates},
source::{local_site::LocalSite, local_site_rate_limit::LocalSiteRateLimit, site::Site},
utils::{get_conn, DbPool}, utils::{get_conn, DbPool},
}; };
impl SiteView { impl SiteView {
pub async fn read_local(pool: &mut DbPool<'_>) -> Result<Self, Error> { pub async fn read_local(pool: &mut DbPool<'_>) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
let (mut site, local_site, local_site_rate_limit, counts) = site::table let mut res = site::table
.inner_join(local_site::table) .inner_join(local_site::table)
.inner_join( .inner_join(
local_site_rate_limit::table.on(local_site::id.eq(local_site_rate_limit::local_site_id)), local_site_rate_limit::table.on(local_site::id.eq(local_site_rate_limit::local_site_id)),
@ -23,15 +21,10 @@ impl SiteView {
local_site_rate_limit::all_columns, local_site_rate_limit::all_columns,
site_aggregates::all_columns, site_aggregates::all_columns,
)) ))
.first::<(Site, LocalSite, LocalSiteRateLimit, SiteAggregates)>(conn) .first::<SiteView>(conn)
.await?; .await?;
site.private_key = None; res.site.private_key = None;
Ok(SiteView { Ok(res)
site,
local_site,
local_site_rate_limit,
counts,
})
} }
} }

View File

@ -1,3 +1,5 @@
#[cfg(feature = "full")]
use diesel::Queryable;
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::{CommentAggregates, PersonAggregates, PostAggregates, SiteAggregates}, aggregates::structs::{CommentAggregates, PersonAggregates, PostAggregates, SiteAggregates},
source::{ source::{
@ -26,7 +28,7 @@ use ts_rs::TS;
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A comment report view. /// A comment report view.
pub struct CommentReportView { pub struct CommentReportView {
@ -44,7 +46,7 @@ pub struct CommentReportView {
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A comment view. /// A comment view.
pub struct CommentView { pub struct CommentView {
@ -61,7 +63,7 @@ pub struct CommentView {
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A local user view. /// A local user view.
pub struct LocalUserView { pub struct LocalUserView {
@ -72,7 +74,7 @@ pub struct LocalUserView {
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A post report view. /// A post report view.
pub struct PostReportView { pub struct PostReportView {
@ -89,7 +91,7 @@ pub struct PostReportView {
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A post view. /// A post view.
pub struct PostView { pub struct PostView {
@ -107,7 +109,7 @@ pub struct PostView {
} }
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A private message view. /// A private message view.
pub struct PrivateMessageView { pub struct PrivateMessageView {
@ -118,7 +120,7 @@ pub struct PrivateMessageView {
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A private message report view. /// A private message report view.
pub struct PrivateMessageReportView { pub struct PrivateMessageReportView {
@ -131,7 +133,7 @@ pub struct PrivateMessageReportView {
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A registration application view. /// A registration application view.
pub struct RegistrationApplicationView { pub struct RegistrationApplicationView {
@ -142,7 +144,7 @@ pub struct RegistrationApplicationView {
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A site view. /// A site view.
pub struct SiteView { pub struct SiteView {

View File

@ -10,7 +10,6 @@ use diesel::{
}; };
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::CommentAggregates,
aliases, aliases,
newtypes::{CommentReplyId, PersonId}, newtypes::{CommentReplyId, PersonId},
schema::{ schema::{
@ -26,34 +25,11 @@ use lemmy_db_schema::{
person_block, person_block,
post, post,
}, },
source::{ source::community::CommunityFollower,
comment::Comment,
comment_reply::CommentReply,
community::{Community, CommunityFollower},
person::Person,
post::Post,
},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
CommentSortType, CommentSortType,
SubscribedType,
}; };
type CommentReplyViewTuple = (
CommentReply,
Comment,
Person,
Post,
Community,
Person,
CommentAggregates,
bool,
SubscribedType,
bool,
bool,
Option<i16>,
);
fn queries<'a>() -> Queries< fn queries<'a>() -> Queries<
impl ReadFn<'a, CommentReplyView, (CommentReplyId, Option<PersonId>)>, impl ReadFn<'a, CommentReplyView, (CommentReplyId, Option<PersonId>)>,
impl ListFn<'a, CommentReplyView, CommentReplyQuery>, impl ListFn<'a, CommentReplyView, CommentReplyQuery>,
@ -127,7 +103,7 @@ fn queries<'a>() -> Queries<
comment_reply::table.find(comment_reply_id).into_boxed(), comment_reply::table.find(comment_reply_id).into_boxed(),
my_person_id, my_person_id,
) )
.first::<CommentReplyViewTuple>(&mut conn) .first::<CommentReplyView>(&mut conn)
.await .await
}; };
@ -161,7 +137,7 @@ fn queries<'a>() -> Queries<
query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.load::<CommentReplyViewTuple>(&mut conn) .load::<CommentReplyView>(&mut conn)
.await .await
}; };
@ -214,23 +190,3 @@ impl CommentReplyQuery {
queries().list(pool, self).await queries().list(pool, self).await
} }
} }
impl JoinView for CommentReplyView {
type JoinTuple = CommentReplyViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
comment_reply: a.0,
comment: a.1,
creator: a.2,
post: a.3,
community: a.4,
recipient: a.5,
counts: a.6,
creator_banned_from_community: a.7,
subscribed: a.8,
saved: a.9,
creator_blocked: a.10,
my_vote: a.11,
}
}
}

View File

@ -4,17 +4,13 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{community, community_block, person}, schema::{community, community_block, person},
source::{community::Community, person::Person},
traits::JoinView,
utils::{get_conn, DbPool}, utils::{get_conn, DbPool},
}; };
type CommunityBlockViewTuple = (Person, Community);
impl CommunityBlockView { impl CommunityBlockView {
pub async fn for_person(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<Vec<Self>, Error> { pub async fn for_person(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
let res = community_block::table community_block::table
.inner_join(person::table) .inner_join(person::table)
.inner_join(community::table) .inner_join(community::table)
.select((person::all_columns, community::all_columns)) .select((person::all_columns, community::all_columns))
@ -22,19 +18,7 @@ impl CommunityBlockView {
.filter(community::deleted.eq(false)) .filter(community::deleted.eq(false))
.filter(community::removed.eq(false)) .filter(community::removed.eq(false))
.order_by(community_block::published) .order_by(community_block::published)
.load::<CommunityBlockViewTuple>(conn) .load::<CommunityBlockView>(conn)
.await?; .await
Ok(res.into_iter().map(Self::from_tuple).collect())
}
}
impl JoinView for CommunityBlockView {
type JoinTuple = CommunityBlockViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
person: a.0,
community: a.1,
}
} }
} }

View File

@ -10,13 +10,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::{CommunityId, DbUrl, InstanceId, PersonId}, newtypes::{CommunityId, DbUrl, InstanceId, PersonId},
schema::{community, community_follower, person}, schema::{community, community_follower, person},
source::{community::Community, person::Person},
traits::JoinView,
utils::{functions::coalesce, get_conn, DbPool}, utils::{functions::coalesce, get_conn, DbPool},
}; };
type CommunityFollowerViewTuple = (Community, Person);
impl CommunityFollowerView { impl CommunityFollowerView {
/// return a list of local community ids and remote inboxes that at least one user of the given instance has followed /// return a list of local community ids and remote inboxes that at least one user of the given instance has followed
pub async fn get_instance_followed_community_inboxes( pub async fn get_instance_followed_community_inboxes(
@ -73,7 +69,7 @@ impl CommunityFollowerView {
pub async fn for_person(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<Vec<Self>, Error> { pub async fn for_person(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
let res = community_follower::table community_follower::table
.inner_join(community::table) .inner_join(community::table)
.inner_join(person::table) .inner_join(person::table)
.select((community::all_columns, person::all_columns)) .select((community::all_columns, person::all_columns))
@ -81,19 +77,7 @@ impl CommunityFollowerView {
.filter(community::deleted.eq(false)) .filter(community::deleted.eq(false))
.filter(community::removed.eq(false)) .filter(community::removed.eq(false))
.order_by(community::title) .order_by(community::title)
.load::<CommunityFollowerViewTuple>(conn) .load::<CommunityFollowerView>(conn)
.await?; .await
Ok(res.into_iter().map(Self::from_tuple).collect())
}
}
impl JoinView for CommunityFollowerView {
type JoinTuple = CommunityFollowerViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
community: a.0,
follower: a.1,
}
} }
} }

View File

@ -4,13 +4,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::{CommunityId, PersonId}, newtypes::{CommunityId, PersonId},
schema::{community, community_moderator, person}, schema::{community, community_moderator, person},
source::{community::Community, person::Person},
traits::JoinView,
utils::{get_conn, DbPool}, utils::{get_conn, DbPool},
}; };
type CommunityModeratorViewTuple = (Community, Person);
impl CommunityModeratorView { impl CommunityModeratorView {
pub async fn is_community_moderator( pub async fn is_community_moderator(
pool: &mut DbPool<'_>, pool: &mut DbPool<'_>,
@ -36,38 +32,34 @@ impl CommunityModeratorView {
community_id: CommunityId, community_id: CommunityId,
) -> Result<Vec<Self>, Error> { ) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
let res = community_moderator::table community_moderator::table
.inner_join(community::table) .inner_join(community::table)
.inner_join(person::table) .inner_join(person::table)
.filter(community_moderator::community_id.eq(community_id)) .filter(community_moderator::community_id.eq(community_id))
.select((community::all_columns, person::all_columns)) .select((community::all_columns, person::all_columns))
.order_by(community_moderator::published) .order_by(community_moderator::published)
.load::<CommunityModeratorViewTuple>(conn) .load::<CommunityModeratorView>(conn)
.await?; .await
Ok(res.into_iter().map(Self::from_tuple).collect())
} }
pub async fn for_person(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<Vec<Self>, Error> { pub async fn for_person(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
let res = community_moderator::table community_moderator::table
.inner_join(community::table) .inner_join(community::table)
.inner_join(person::table) .inner_join(person::table)
.filter(community_moderator::person_id.eq(person_id)) .filter(community_moderator::person_id.eq(person_id))
.filter(community::deleted.eq(false)) .filter(community::deleted.eq(false))
.filter(community::removed.eq(false)) .filter(community::removed.eq(false))
.select((community::all_columns, person::all_columns)) .select((community::all_columns, person::all_columns))
.load::<CommunityModeratorViewTuple>(conn) .load::<CommunityModeratorView>(conn)
.await?; .await
Ok(res.into_iter().map(Self::from_tuple).collect())
} }
/// Finds all communities first mods / creators /// Finds all communities first mods / creators
/// Ideally this should be a group by, but diesel doesn't support it yet /// Ideally this should be a group by, but diesel doesn't support it yet
pub async fn get_community_first_mods(pool: &mut DbPool<'_>) -> Result<Vec<Self>, Error> { pub async fn get_community_first_mods(pool: &mut DbPool<'_>) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
let res = community_moderator::table community_moderator::table
.inner_join(community::table) .inner_join(community::table)
.inner_join(person::table) .inner_join(person::table)
.select((community::all_columns, person::all_columns)) .select((community::all_columns, person::all_columns))
@ -78,19 +70,7 @@ impl CommunityModeratorView {
community_moderator::community_id, community_moderator::community_id,
community_moderator::person_id, community_moderator::person_id,
)) ))
.load::<CommunityModeratorViewTuple>(conn) .load::<CommunityModeratorView>(conn)
.await?; .await
Ok(res.into_iter().map(Self::from_tuple).collect())
}
}
impl JoinView for CommunityModeratorView {
type JoinTuple = CommunityModeratorViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
community: a.0,
moderator: a.1,
}
} }
} }

View File

@ -4,7 +4,6 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::{CommunityId, PersonId}, newtypes::{CommunityId, PersonId},
schema::{community, community_person_ban, person}, schema::{community, community_person_ban, person},
source::{community::Community, person::Person},
utils::{get_conn, DbPool}, utils::{get_conn, DbPool},
}; };
@ -15,16 +14,14 @@ impl CommunityPersonBanView {
from_community_id: CommunityId, from_community_id: CommunityId,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
let (community, person) = community_person_ban::table community_person_ban::table
.inner_join(community::table) .inner_join(community::table)
.inner_join(person::table) .inner_join(person::table)
.select((community::all_columns, person::all_columns)) .select((community::all_columns, person::all_columns))
.filter(community_person_ban::community_id.eq(from_community_id)) .filter(community_person_ban::community_id.eq(from_community_id))
.filter(community_person_ban::person_id.eq(from_person_id)) .filter(community_person_ban::person_id.eq(from_person_id))
.order_by(community_person_ban::published) .order_by(community_person_ban::published)
.first::<(Community, Person)>(conn) .first::<CommunityPersonBanView>(conn)
.await?; .await
Ok(CommunityPersonBanView { community, person })
} }
} }

View File

@ -11,22 +11,14 @@ use diesel::{
}; };
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::CommunityAggregates,
newtypes::{CommunityId, PersonId}, newtypes::{CommunityId, PersonId},
schema::{community, community_aggregates, community_block, community_follower, local_user}, schema::{community, community_aggregates, community_block, community_follower, local_user},
source::{ source::{community::CommunityFollower, local_user::LocalUser},
community::{Community, CommunityFollower},
local_user::LocalUser,
},
traits::JoinView,
utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
ListingType, ListingType,
SortType, SortType,
SubscribedType,
}; };
type CommunityViewTuple = (Community, CommunityAggregates, SubscribedType, bool);
fn queries<'a>() -> Queries< fn queries<'a>() -> Queries<
impl ReadFn<'a, CommunityView, (CommunityId, Option<PersonId>, bool)>, impl ReadFn<'a, CommunityView, (CommunityId, Option<PersonId>, bool)>,
impl ListFn<'a, CommunityView, CommunityQuery<'a>>, impl ListFn<'a, CommunityView, CommunityQuery<'a>>,
@ -55,9 +47,9 @@ fn queries<'a>() -> Queries<
let selection = ( let selection = (
community::all_columns, community::all_columns,
community_aggregates::all_columns,
CommunityFollower::select_subscribed_type(), CommunityFollower::select_subscribed_type(),
community_block::id.nullable().is_not_null(), community_block::id.nullable().is_not_null(),
community_aggregates::all_columns,
); );
let not_removed_or_deleted = community::removed let not_removed_or_deleted = community::removed
@ -81,7 +73,7 @@ fn queries<'a>() -> Queries<
query = query.filter(not_removed_or_deleted); query = query.filter(not_removed_or_deleted);
} }
query.first::<CommunityViewTuple>(&mut conn).await query.first::<CommunityView>(&mut conn).await
}; };
let list = move |mut conn: DbConn<'a>, options: CommunityQuery<'a>| async move { let list = move |mut conn: DbConn<'a>, options: CommunityQuery<'a>| async move {
@ -154,7 +146,7 @@ fn queries<'a>() -> Queries<
query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.load::<CommunityViewTuple>(&mut conn) .load::<CommunityView>(&mut conn)
.await .await
}; };
@ -205,15 +197,3 @@ impl<'a> CommunityQuery<'a> {
queries().list(pool, self).await queries().list(pool, self).await
} }
} }
impl JoinView for CommunityView {
type JoinTuple = CommunityViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
community: a.0,
counts: a.1,
subscribed: a.2,
blocked: a.3,
}
}
}

View File

@ -4,19 +4,15 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{person, person_block}, schema::{person, person_block},
source::person::Person,
traits::JoinView,
utils::{get_conn, DbPool}, utils::{get_conn, DbPool},
}; };
type PersonBlockViewTuple = (Person, Person);
impl PersonBlockView { impl PersonBlockView {
pub async fn for_person(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<Vec<Self>, Error> { pub async fn for_person(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
let target_person_alias = diesel::alias!(person as person1); let target_person_alias = diesel::alias!(person as person1);
let res = person_block::table person_block::table
.inner_join(person::table.on(person_block::person_id.eq(person::id))) .inner_join(person::table.on(person_block::person_id.eq(person::id)))
.inner_join( .inner_join(
target_person_alias.on(person_block::target_id.eq(target_person_alias.field(person::id))), target_person_alias.on(person_block::target_id.eq(target_person_alias.field(person::id))),
@ -28,19 +24,7 @@ impl PersonBlockView {
.filter(person_block::person_id.eq(person_id)) .filter(person_block::person_id.eq(person_id))
.filter(target_person_alias.field(person::deleted).eq(false)) .filter(target_person_alias.field(person::deleted).eq(false))
.order_by(person_block::published) .order_by(person_block::published)
.load::<PersonBlockViewTuple>(conn) .load::<PersonBlockView>(conn)
.await?; .await
Ok(res.into_iter().map(Self::from_tuple).collect())
}
}
impl JoinView for PersonBlockView {
type JoinTuple = PersonBlockViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
person: a.0,
target: a.1,
}
} }
} }

View File

@ -11,7 +11,6 @@ use diesel::{
}; };
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::CommentAggregates,
aliases, aliases,
newtypes::{PersonId, PersonMentionId}, newtypes::{PersonId, PersonMentionId},
schema::{ schema::{
@ -27,34 +26,11 @@ use lemmy_db_schema::{
person_mention, person_mention,
post, post,
}, },
source::{ source::community::CommunityFollower,
comment::Comment,
community::{Community, CommunityFollower},
person::Person,
person_mention::PersonMention,
post::Post,
},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
CommentSortType, CommentSortType,
SubscribedType,
}; };
type PersonMentionViewTuple = (
PersonMention,
Comment,
Person,
Post,
Community,
Person,
CommentAggregates,
bool,
SubscribedType,
bool,
bool,
Option<i16>,
);
fn queries<'a>() -> Queries< fn queries<'a>() -> Queries<
impl ReadFn<'a, PersonMentionView, (PersonMentionId, Option<PersonId>)>, impl ReadFn<'a, PersonMentionView, (PersonMentionId, Option<PersonId>)>,
impl ListFn<'a, PersonMentionView, PersonMentionQuery>, impl ListFn<'a, PersonMentionView, PersonMentionQuery>,
@ -130,7 +106,7 @@ fn queries<'a>() -> Queries<
), ),
) )
.select(selection) .select(selection)
.first::<PersonMentionViewTuple>(&mut conn) .first::<PersonMentionView>(&mut conn)
.await .await
}; };
@ -177,7 +153,7 @@ fn queries<'a>() -> Queries<
query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.load::<PersonMentionViewTuple>(&mut conn) .load::<PersonMentionView>(&mut conn)
.await .await
}; };
@ -231,23 +207,3 @@ impl PersonMentionQuery {
queries().list(pool, self).await queries().list(pool, self).await
} }
} }
impl JoinView for PersonMentionView {
type JoinTuple = PersonMentionViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
person_mention: a.0,
comment: a.1,
creator: a.2,
post: a.3,
community: a.4,
recipient: a.5,
counts: a.6,
creator_banned_from_community: a.7,
subscribed: a.8,
saved: a.9,
creator_blocked: a.10,
my_vote: a.11,
}
}
}

View File

@ -10,18 +10,13 @@ use diesel::{
}; };
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::PersonAggregates,
newtypes::PersonId, newtypes::PersonId,
schema, schema,
schema::{local_user, person, person_aggregates}, schema::{local_user, person, person_aggregates},
source::person::Person,
traits::JoinView,
utils::{fuzzy_search, get_conn, limit_and_offset, now, DbConn, DbPool, ListFn, Queries, ReadFn}, utils::{fuzzy_search, get_conn, limit_and_offset, now, DbConn, DbPool, ListFn, Queries, ReadFn},
PersonSortType, PersonSortType,
}; };
type PersonViewTuple = (Person, PersonAggregates);
enum ListMode { enum ListMode {
Admins, Admins,
Banned, Banned,
@ -39,7 +34,7 @@ fn queries<'a>(
let read = move |mut conn: DbConn<'a>, person_id: PersonId| async move { let read = move |mut conn: DbConn<'a>, person_id: PersonId| async move {
all_joins(person::table.find(person_id).into_boxed()) all_joins(person::table.find(person_id).into_boxed())
.first::<PersonViewTuple>(&mut conn) .first::<PersonView>(&mut conn)
.await .await
}; };
@ -84,7 +79,7 @@ fn queries<'a>(
query = query.limit(limit).offset(offset); query = query.limit(limit).offset(offset);
} }
} }
query.load::<PersonViewTuple>(&mut conn).await query.load::<PersonView>(&mut conn).await
}; };
Queries::new(read, list) Queries::new(read, list)
@ -132,13 +127,3 @@ impl PersonQuery {
queries().list(pool, ListMode::Query(self)).await queries().list(pool, ListMode::Query(self)).await
} }
} }
impl JoinView for PersonView {
type JoinTuple = PersonViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
person: a.0,
counts: a.1,
}
}
}

View File

@ -1,3 +1,5 @@
#[cfg(feature = "full")]
use diesel::Queryable;
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::{CommentAggregates, CommunityAggregates, PersonAggregates}, aggregates::structs::{CommentAggregates, CommunityAggregates, PersonAggregates},
source::{ source::{
@ -16,7 +18,7 @@ use serde_with::skip_serializing_none;
use ts_rs::TS; use ts_rs::TS;
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A community block. /// A community block.
pub struct CommunityBlockView { pub struct CommunityBlockView {
@ -25,7 +27,7 @@ pub struct CommunityBlockView {
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A community follower. /// A community follower.
pub struct CommunityFollowerView { pub struct CommunityFollowerView {
@ -34,7 +36,7 @@ pub struct CommunityFollowerView {
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A community moderator. /// A community moderator.
pub struct CommunityModeratorView { pub struct CommunityModeratorView {
@ -43,6 +45,7 @@ pub struct CommunityModeratorView {
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(Queryable))]
/// A community person ban. /// A community person ban.
pub struct CommunityPersonBanView { pub struct CommunityPersonBanView {
pub community: Community, pub community: Community,
@ -50,7 +53,7 @@ pub struct CommunityPersonBanView {
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A community view. /// A community view.
pub struct CommunityView { pub struct CommunityView {
@ -61,7 +64,7 @@ pub struct CommunityView {
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A person block. /// A person block.
pub struct PersonBlockView { pub struct PersonBlockView {
@ -71,7 +74,7 @@ pub struct PersonBlockView {
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A person mention view. /// A person mention view.
pub struct PersonMentionView { pub struct PersonMentionView {
@ -91,7 +94,7 @@ pub struct PersonMentionView {
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A comment reply view. /// A comment reply view.
pub struct CommentReplyView { pub struct CommentReplyView {
@ -110,7 +113,7 @@ pub struct CommentReplyView {
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// A person view. /// A person view.
pub struct PersonView { pub struct PersonView {

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{admin_purge_comment, person, post}, schema::{admin_purge_comment, person, post},
source::{moderator::AdminPurgeComment, person::Person, post::Post},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type AdminPurgeCommentViewTuple = (AdminPurgeComment, Option<Person>, Post);
impl AdminPurgeCommentView { impl AdminPurgeCommentView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -46,25 +42,11 @@ impl AdminPurgeCommentView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(admin_purge_comment::when_.desc()) .order_by(admin_purge_comment::when_.desc())
.load::<AdminPurgeCommentViewTuple>(conn) .load::<AdminPurgeCommentView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for AdminPurgeCommentView {
type JoinTuple = AdminPurgeCommentViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
admin_purge_comment: a.0,
admin: a.1,
post: a.2,
}
} }
} }

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{admin_purge_community, person}, schema::{admin_purge_community, person},
source::{moderator::AdminPurgeCommunity, person::Person},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type AdminPurgeCommunityViewTuple = (AdminPurgeCommunity, Option<Person>);
impl AdminPurgeCommunityView { impl AdminPurgeCommunityView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -44,24 +40,11 @@ impl AdminPurgeCommunityView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(admin_purge_community::when_.desc()) .order_by(admin_purge_community::when_.desc())
.load::<AdminPurgeCommunityViewTuple>(conn) .load::<AdminPurgeCommunityView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for AdminPurgeCommunityView {
type JoinTuple = AdminPurgeCommunityViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
admin_purge_community: a.0,
admin: a.1,
}
} }
} }

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{admin_purge_person, person}, schema::{admin_purge_person, person},
source::{moderator::AdminPurgePerson, person::Person},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type AdminPurgePersonViewTuple = (AdminPurgePerson, Option<Person>);
impl AdminPurgePersonView { impl AdminPurgePersonView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -44,24 +40,11 @@ impl AdminPurgePersonView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(admin_purge_person::when_.desc()) .order_by(admin_purge_person::when_.desc())
.load::<AdminPurgePersonViewTuple>(conn) .load::<AdminPurgePersonView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for AdminPurgePersonView {
type JoinTuple = AdminPurgePersonViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
admin_purge_person: a.0,
admin: a.1,
}
} }
} }

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{admin_purge_post, community, person}, schema::{admin_purge_post, community, person},
source::{community::Community, moderator::AdminPurgePost, person::Person},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type AdminPurgePostViewTuple = (AdminPurgePost, Option<Person>, Community);
impl AdminPurgePostView { impl AdminPurgePostView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -46,25 +42,11 @@ impl AdminPurgePostView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(admin_purge_post::when_.desc()) .order_by(admin_purge_post::when_.desc())
.load::<AdminPurgePostViewTuple>(conn) .load::<AdminPurgePostView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for AdminPurgePostView {
type JoinTuple = AdminPurgePostViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
admin_purge_post: a.0,
admin: a.1,
community: a.2,
}
} }
} }

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{community, mod_add_community, person}, schema::{community, mod_add_community, person},
source::{community::Community, moderator::ModAddCommunity, person::Person},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type ModAddCommunityViewTuple = (ModAddCommunity, Option<Person>, Community, Person);
impl ModAddCommunityView { impl ModAddCommunityView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -58,26 +54,11 @@ impl ModAddCommunityView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(mod_add_community::when_.desc()) .order_by(mod_add_community::when_.desc())
.load::<ModAddCommunityViewTuple>(conn) .load::<ModAddCommunityView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for ModAddCommunityView {
type JoinTuple = ModAddCommunityViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
mod_add_community: a.0,
moderator: a.1,
community: a.2,
modded_person: a.3,
}
} }
} }

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{mod_add, person}, schema::{mod_add, person},
source::{moderator::ModAdd, person::Person},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type ModAddViewTuple = (ModAdd, Option<Person>, Person);
impl ModAddView { impl ModAddView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -50,25 +46,11 @@ impl ModAddView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(mod_add::when_.desc()) .order_by(mod_add::when_.desc())
.load::<ModAddViewTuple>(conn) .load::<ModAddView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for ModAddView {
type JoinTuple = ModAddViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
mod_add: a.0,
moderator: a.1,
modded_person: a.2,
}
} }
} }

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{community, mod_ban_from_community, person}, schema::{community, mod_ban_from_community, person},
source::{community::Community, moderator::ModBanFromCommunity, person::Person},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type ModBanFromCommunityViewTuple = (ModBanFromCommunity, Option<Person>, Community, Person);
impl ModBanFromCommunityView { impl ModBanFromCommunityView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -60,26 +56,11 @@ impl ModBanFromCommunityView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(mod_ban_from_community::when_.desc()) .order_by(mod_ban_from_community::when_.desc())
.load::<ModBanFromCommunityViewTuple>(conn) .load::<ModBanFromCommunityView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for ModBanFromCommunityView {
type JoinTuple = ModBanFromCommunityViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
mod_ban_from_community: a.0,
moderator: a.1,
community: a.2,
banned_person: a.3,
}
} }
} }

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{mod_ban, person}, schema::{mod_ban, person},
source::{moderator::ModBan, person::Person},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type ModBanViewTuple = (ModBan, Option<Person>, Person);
impl ModBanView { impl ModBanView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -50,25 +46,11 @@ impl ModBanView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(mod_ban::when_.desc()) .order_by(mod_ban::when_.desc())
.load::<ModBanViewTuple>(conn) .load::<ModBanView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for ModBanView {
type JoinTuple = ModBanViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
mod_ban: a.0,
moderator: a.1,
banned_person: a.2,
}
} }
} }

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{community, mod_feature_post, person, post}, schema::{community, mod_feature_post, person, post},
source::{community::Community, moderator::ModFeaturePost, person::Person, post::Post},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type ModFeaturePostViewTuple = (ModFeaturePost, Option<Person>, Post, Community);
impl ModFeaturePostView { impl ModFeaturePostView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -57,26 +53,11 @@ impl ModFeaturePostView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(mod_feature_post::when_.desc()) .order_by(mod_feature_post::when_.desc())
.load::<ModFeaturePostViewTuple>(conn) .load::<ModFeaturePostView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for ModFeaturePostView {
type JoinTuple = ModFeaturePostViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
mod_feature_post: a.0,
moderator: a.1,
post: a.2,
community: a.3,
}
} }
} }

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{community, mod_hide_community, person}, schema::{community, mod_hide_community, person},
source::{community::Community, moderator::ModHideCommunity, person::Person},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type ModHideCommunityViewTuple = (ModHideCommunity, Option<Person>, Community);
impl ModHideCommunityView { impl ModHideCommunityView {
// Pass in mod_id as admin_id because only admins can do this action // Pass in mod_id as admin_id because only admins can do this action
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
@ -51,25 +47,11 @@ impl ModHideCommunityView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(mod_hide_community::when_.desc()) .order_by(mod_hide_community::when_.desc())
.load::<ModHideCommunityViewTuple>(conn) .load::<ModHideCommunityView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for ModHideCommunityView {
type JoinTuple = ModHideCommunityViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
mod_hide_community: a.0,
admin: a.1,
community: a.2,
}
} }
} }

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{community, mod_lock_post, person, post}, schema::{community, mod_lock_post, person, post},
source::{community::Community, moderator::ModLockPost, person::Person, post::Post},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type ModLockPostViewTuple = (ModLockPost, Option<Person>, Post, Community);
impl ModLockPostView { impl ModLockPostView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -58,26 +54,11 @@ impl ModLockPostView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(mod_lock_post::when_.desc()) .order_by(mod_lock_post::when_.desc())
.load::<ModLockPostViewTuple>(conn) .load::<ModLockPostView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for ModLockPostView {
type JoinTuple = ModLockPostViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
mod_lock_post: a.0,
moderator: a.1,
post: a.2,
community: a.3,
}
} }
} }

View File

@ -12,26 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{comment, community, mod_remove_comment, person, post}, schema::{comment, community, mod_remove_comment, person, post},
source::{
comment::Comment,
community::Community,
moderator::ModRemoveComment,
person::Person,
post::Post,
},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type ModRemoveCommentViewTuple = (
ModRemoveComment,
Option<Person>,
Comment,
Person,
Post,
Community,
);
impl ModRemoveCommentView { impl ModRemoveCommentView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -73,28 +56,11 @@ impl ModRemoveCommentView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(mod_remove_comment::when_.desc()) .order_by(mod_remove_comment::when_.desc())
.load::<ModRemoveCommentViewTuple>(conn) .load::<ModRemoveCommentView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for ModRemoveCommentView {
type JoinTuple = ModRemoveCommentViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
mod_remove_comment: a.0,
moderator: a.1,
comment: a.2,
commenter: a.3,
post: a.4,
community: a.5,
}
} }
} }

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{community, mod_remove_community, person}, schema::{community, mod_remove_community, person},
source::{community::Community, moderator::ModRemoveCommunity, person::Person},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type ModRemoveCommunityTuple = (ModRemoveCommunity, Option<Person>, Community);
impl ModRemoveCommunityView { impl ModRemoveCommunityView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -45,25 +41,11 @@ impl ModRemoveCommunityView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(mod_remove_community::when_.desc()) .order_by(mod_remove_community::when_.desc())
.load::<ModRemoveCommunityTuple>(conn) .load::<ModRemoveCommunityView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for ModRemoveCommunityView {
type JoinTuple = ModRemoveCommunityTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
mod_remove_community: a.0,
moderator: a.1,
community: a.2,
}
} }
} }

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{community, mod_remove_post, person, post}, schema::{community, mod_remove_post, person, post},
source::{community::Community, moderator::ModRemovePost, person::Person, post::Post},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type ModRemovePostViewTuple = (ModRemovePost, Option<Person>, Post, Community);
impl ModRemovePostView { impl ModRemovePostView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -58,26 +54,11 @@ impl ModRemovePostView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(mod_remove_post::when_.desc()) .order_by(mod_remove_post::when_.desc())
.load::<ModRemovePostViewTuple>(conn) .load::<ModRemovePostView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for ModRemovePostView {
type JoinTuple = ModRemovePostViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
mod_remove_post: a.0,
moderator: a.1,
post: a.2,
community: a.3,
}
} }
} }

View File

@ -12,13 +12,9 @@ use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::PersonId, newtypes::PersonId,
schema::{community, mod_transfer_community, person}, schema::{community, mod_transfer_community, person},
source::{community::Community, moderator::ModTransferCommunity, person::Person},
traits::JoinView,
utils::{get_conn, limit_and_offset, DbPool}, utils::{get_conn, limit_and_offset, DbPool},
}; };
type ModTransferCommunityViewTuple = (ModTransferCommunity, Option<Person>, Community, Person);
impl ModTransferCommunityView { impl ModTransferCommunityView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> { pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
@ -60,26 +56,11 @@ impl ModTransferCommunityView {
let (limit, offset) = limit_and_offset(params.page, params.limit)?; let (limit, offset) = limit_and_offset(params.page, params.limit)?;
let res = query query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
.order_by(mod_transfer_community::when_.desc()) .order_by(mod_transfer_community::when_.desc())
.load::<ModTransferCommunityViewTuple>(conn) .load::<ModTransferCommunityView>(conn)
.await?; .await
let results = res.into_iter().map(Self::from_tuple).collect();
Ok(results)
}
}
impl JoinView for ModTransferCommunityView {
type JoinTuple = ModTransferCommunityViewTuple;
fn from_tuple(a: Self::JoinTuple) -> Self {
Self {
mod_transfer_community: a.0,
moderator: a.1,
community: a.2,
modded_person: a.3,
}
} }
} }

View File

@ -1,3 +1,5 @@
#[cfg(feature = "full")]
use diesel::Queryable;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::{CommunityId, PersonId}, newtypes::{CommunityId, PersonId},
source::{ source::{
@ -31,7 +33,7 @@ use ts_rs::TS;
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When someone is added as a community moderator. /// When someone is added as a community moderator.
pub struct ModAddCommunityView { pub struct ModAddCommunityView {
@ -43,7 +45,7 @@ pub struct ModAddCommunityView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When someone is added as a site moderator. /// When someone is added as a site moderator.
pub struct ModAddView { pub struct ModAddView {
@ -54,7 +56,7 @@ pub struct ModAddView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When someone is banned from a community. /// When someone is banned from a community.
pub struct ModBanFromCommunityView { pub struct ModBanFromCommunityView {
@ -66,7 +68,7 @@ pub struct ModBanFromCommunityView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When someone is banned from the site. /// When someone is banned from the site.
pub struct ModBanView { pub struct ModBanView {
@ -77,7 +79,7 @@ pub struct ModBanView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When a community is hidden from public view. /// When a community is hidden from public view.
pub struct ModHideCommunityView { pub struct ModHideCommunityView {
@ -88,7 +90,7 @@ pub struct ModHideCommunityView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When a moderator locks a post (prevents new comments being made). /// When a moderator locks a post (prevents new comments being made).
pub struct ModLockPostView { pub struct ModLockPostView {
@ -100,7 +102,7 @@ pub struct ModLockPostView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When a moderator removes a comment. /// When a moderator removes a comment.
pub struct ModRemoveCommentView { pub struct ModRemoveCommentView {
@ -114,7 +116,7 @@ pub struct ModRemoveCommentView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When a moderator removes a community. /// When a moderator removes a community.
pub struct ModRemoveCommunityView { pub struct ModRemoveCommunityView {
@ -125,7 +127,7 @@ pub struct ModRemoveCommunityView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When a moderator removes a post. /// When a moderator removes a post.
pub struct ModRemovePostView { pub struct ModRemovePostView {
@ -137,7 +139,7 @@ pub struct ModRemovePostView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When a moderator features a post on a community (pins it to the top). /// When a moderator features a post on a community (pins it to the top).
pub struct ModFeaturePostView { pub struct ModFeaturePostView {
@ -149,7 +151,7 @@ pub struct ModFeaturePostView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When a moderator transfers a community to a new owner. /// When a moderator transfers a community to a new owner.
pub struct ModTransferCommunityView { pub struct ModTransferCommunityView {
@ -161,7 +163,7 @@ pub struct ModTransferCommunityView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When an admin purges a comment. /// When an admin purges a comment.
pub struct AdminPurgeCommentView { pub struct AdminPurgeCommentView {
@ -172,7 +174,7 @@ pub struct AdminPurgeCommentView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When an admin purges a community. /// When an admin purges a community.
pub struct AdminPurgeCommunityView { pub struct AdminPurgeCommunityView {
@ -182,7 +184,7 @@ pub struct AdminPurgeCommunityView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When an admin purges a person. /// When an admin purges a person.
pub struct AdminPurgePersonView { pub struct AdminPurgePersonView {
@ -192,7 +194,7 @@ pub struct AdminPurgePersonView {
#[skip_serializing_none] #[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, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When an admin purges a post. /// When an admin purges a post.
pub struct AdminPurgePostView { pub struct AdminPurgePostView {
@ -203,7 +205,7 @@ pub struct AdminPurgePostView {
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Copy)] #[derive(Debug, Serialize, Deserialize, Clone, Copy)]
#[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// Querying / filtering the modlog. /// Querying / filtering the modlog.
pub struct ModlogListParams { pub struct ModlogListParams {

View File

@ -92,9 +92,9 @@ async fn upload(
context: web::Data<LemmyContext>, context: web::Data<LemmyContext>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
// TODO: check rate limit here // TODO: check rate limit here
let jwt = req let jwt = req.cookie("jwt").ok_or(error::ErrorUnauthorized(
.cookie("jwt") "No auth header for picture upload",
.expect("No auth header for picture upload"); ))?;
if Claims::decode(jwt.value(), &context.secret().jwt_secret).is_err() { if Claims::decode(jwt.value(), &context.secret().jwt_secret).is_err() {
return Ok(HttpResponse::Unauthorized().finish()); return Ok(HttpResponse::Unauthorized().finish());
@ -133,9 +133,9 @@ async fn full_res(
.await .await
.map_err(error::ErrorBadRequest)?; .map_err(error::ErrorBadRequest)?;
if local_site.private_instance { if local_site.private_instance {
let jwt = req let jwt = req.cookie("jwt").ok_or(error::ErrorUnauthorized(
.cookie("jwt") "No auth header for picture access",
.expect("No auth header for picture access"); ))?;
if local_user_view_from_jwt(jwt.value(), &context) if local_user_view_from_jwt(jwt.value(), &context)
.await .await
.is_err() .is_err()

View File

@ -50,8 +50,8 @@ async fn get_webfinger_response(
// Mastodon seems to prioritize the last webfinger item in case of duplicates. Put // Mastodon seems to prioritize the last webfinger item in case of duplicates. Put
// community last so that it gets prioritized. For Lemmy the order doesnt matter. // community last so that it gets prioritized. For Lemmy the order doesnt matter.
let links = vec![ let links = vec![
webfinger_link_for_actor(user_id, "Person"), webfinger_link_for_actor(user_id, "Person", &context),
webfinger_link_for_actor(community_id, "Group"), webfinger_link_for_actor(community_id, "Group", &context),
] ]
.into_iter() .into_iter()
.flatten() .flatten()
@ -66,29 +66,45 @@ async fn get_webfinger_response(
Ok(HttpResponse::Ok().json(json)) Ok(HttpResponse::Ok().json(json))
} }
fn webfinger_link_for_actor(url: Option<Url>, kind: &str) -> Vec<WebfingerLink> { fn webfinger_link_for_actor(
url: Option<Url>,
kind: &str,
context: &LemmyContext,
) -> Vec<WebfingerLink> {
if let Some(url) = url { if let Some(url) = url {
let mut properties = HashMap::new(); let type_key = "https://www.w3.org/ns/activitystreams#type"
properties.insert(
"https://www.w3.org/ns/activitystreams#type"
.parse() .parse()
.expect("parse url"), .expect("parse url");
kind.to_string(),
); let mut vec = vec![
vec![
WebfingerLink { WebfingerLink {
rel: Some("http://webfinger.net/rel/profile-page".to_string()), rel: Some("http://webfinger.net/rel/profile-page".into()),
kind: Some("text/html".to_string()), kind: Some("text/html".into()),
href: Some(url.clone()), href: Some(url.clone()),
..Default::default() ..Default::default()
}, },
WebfingerLink { WebfingerLink {
rel: Some("self".to_string()), rel: Some("self".into()),
kind: Some("application/activity+json".to_string()), kind: Some("application/activity+json".into()),
href: Some(url), href: Some(url),
properties, properties: HashMap::from([(type_key, kind.into())]),
..Default::default()
}, },
] ];
// insert remote follow link
if kind == "Person" {
let template = format!(
"{}/activitypub/externalInteraction?uri={{uri}}",
context.settings().get_protocol_and_hostname()
);
vec.push(WebfingerLink {
rel: Some("http://ostatus.org/schema/1.0/subscribe".into()),
template: Some(template),
..Default::default()
});
}
vec
} else { } else {
vec![] vec![]
} }

View File

@ -87,6 +87,7 @@ pub enum LemmyErrorType {
SiteMetadataPageIsNotDoctypeHtml, SiteMetadataPageIsNotDoctypeHtml,
PictrsResponseError(String), PictrsResponseError(String),
PictrsPurgeResponseError(String), PictrsPurgeResponseError(String),
PictrsCachingDisabled,
ImageUrlMissingPathSegments, ImageUrlMissingPathSegments,
ImageUrlMissingLastPathSegment, ImageUrlMissingLastPathSegment,
PictrsApiKeyNotProvided, PictrsApiKeyNotProvided,

View File

@ -38,11 +38,11 @@ impl Settings {
let config = from_str::<Settings>(&Self::read_config_file()?)?; let config = from_str::<Settings>(&Self::read_config_file()?)?;
if config.hostname == "unset" { if config.hostname == "unset" {
return Err(anyhow!("Hostname variable is not set!").into()); Err(anyhow!("Hostname variable is not set!").into())
} } else {
Ok(config) Ok(config)
} }
}
pub fn get_database_url(&self) -> String { pub fn get_database_url(&self) -> String {
match &self.database.connection { match &self.database.connection {

View File

@ -62,6 +62,10 @@ pub struct PictrsConfig {
/// Set a custom pictrs API key. ( Required for deleting images ) /// Set a custom pictrs API key. ( Required for deleting images )
#[default(None)] #[default(None)]
pub api_key: Option<String>, pub api_key: Option<String>,
/// Cache remote images
#[default(true)]
pub cache_remote_images: bool,
} }
#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)] #[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]

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