Merge remote-tracking branch 'origin/main' into custom_thumbnails

custom_thumbnails
Dessalines 2024-02-12 11:41:21 -05:00
commit 4d1df6f573
21 changed files with 182 additions and 102 deletions

View File

@ -257,7 +257,7 @@ steps:
services:
database:
image: postgres:15.2-alpine
image: postgres:16-alpine
environment:
POSTGRES_USER: lemmy
POSTGRES_PASSWORD: password

7
Cargo.lock generated
View File

@ -8,6 +8,12 @@ version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
[[package]]
name = "accept-language"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f27d075294830fcab6f66e320dab524bc6d048f4a151698e153205559113772"
[[package]]
name = "activitypub_federation"
version = "0.5.1-beta.1"
@ -2608,6 +2614,7 @@ dependencies = [
name = "lemmy_api_crud"
version = "0.19.3"
dependencies = [
"accept-language",
"activitypub_federation",
"actix-web",
"anyhow",

View File

@ -107,7 +107,6 @@ Each Lemmy server can set its own moderation policy; appointing site-wide admins
- NSFW post / community support.
- High performance.
- Server is written in rust.
- Front end is `~80kB` gzipped.
- Supports arm64 / Raspberry Pi.
## Installation

View File

@ -9,7 +9,7 @@ use lemmy_db_schema::{
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
pub struct Claims {
/// local_user_id, standard claim by RFC 7519.
pub sub: String,

View File

@ -10,7 +10,7 @@ use serde_with::skip_serializing_none;
use ts_rs::TS;
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Create a comment.
@ -22,7 +22,7 @@ pub struct CreateComment {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Fetch an individual comment.
@ -31,7 +31,7 @@ pub struct GetComment {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Edit a comment.
@ -42,7 +42,7 @@ pub struct EditComment {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Distinguish a comment (IE speak as moderator).
@ -52,7 +52,7 @@ pub struct DistinguishComment {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Delete your own comment.
@ -62,7 +62,7 @@ pub struct DeleteComment {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Remove a comment (only doable by mods).
@ -72,7 +72,7 @@ pub struct RemoveComment {
pub reason: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Save / bookmark a comment.
@ -91,7 +91,7 @@ pub struct CommentResponse {
pub recipient_ids: Vec<LocalUserId>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Like a comment.
@ -102,7 +102,7 @@ pub struct CreateCommentLike {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Get a list of comments.
@ -146,7 +146,7 @@ pub struct CommentReportResponse {
pub comment_report_view: CommentReportView,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Resolve a comment report (only doable by mods).
@ -156,7 +156,7 @@ pub struct ResolveCommentReport {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// List comment reports.
@ -178,7 +178,7 @@ pub struct ListCommentReportsResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// List comment likes. Admins-only.

View File

@ -12,7 +12,7 @@ use serde_with::skip_serializing_none;
use ts_rs::TS;
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Get a community. Must provide either an id, or a name.
@ -37,7 +37,7 @@ pub struct GetCommunityResponse {
#[skip_serializing_none]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
/// Create a community.
pub struct CreateCommunity {
/// The unique name.
@ -68,7 +68,7 @@ pub struct CommunityResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Fetches a list of communities.
@ -89,7 +89,7 @@ pub struct ListCommunitiesResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Ban a user from a community.
@ -114,7 +114,7 @@ pub struct BanFromCommunityResponse {
pub banned: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Add a moderator to a community.
@ -133,7 +133,7 @@ pub struct AddModToCommunityResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Edit a community.
@ -156,7 +156,7 @@ pub struct EditCommunity {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Hide a community from the main view.
@ -167,7 +167,7 @@ pub struct HideCommunity {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Delete your own community.
@ -177,7 +177,7 @@ pub struct DeleteCommunity {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Remove a community (only doable by moderators).
@ -187,7 +187,7 @@ pub struct RemoveCommunity {
pub reason: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Follow / subscribe to a community.
@ -196,7 +196,7 @@ pub struct FollowCommunity {
pub follow: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Block a community.
@ -215,7 +215,7 @@ pub struct BlockCommunityResponse {
pub blocked: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Transfer a community to a new owner.

View File

@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
use ts_rs::TS;
use url::Url;
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Create a custom emoji.
@ -18,7 +18,7 @@ pub struct CreateCustomEmoji {
pub keywords: Vec<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Edit a custom emoji.
@ -31,7 +31,7 @@ pub struct EditCustomEmoji {
pub keywords: Vec<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Delete a custom emoji.

View File

@ -20,7 +20,7 @@ use serde_with::skip_serializing_none;
use ts_rs::TS;
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Logging into lemmy.
@ -32,7 +32,7 @@ pub struct Login {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Register / Sign up to lemmy.
@ -77,7 +77,7 @@ pub struct CaptchaResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Saves settings for your user.
@ -131,7 +131,7 @@ pub struct SaveUserSettings {
pub collapse_bot_comments: Option<bool>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Changes your account password.
@ -156,7 +156,7 @@ pub struct LoginResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Gets a person's details.
@ -186,7 +186,7 @@ pub struct GetPersonDetailsResponse {
pub moderates: Vec<CommunityModeratorView>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Adds an admin to a site.
@ -204,7 +204,7 @@ pub struct AddAdminResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Ban a person from the site.
@ -238,7 +238,7 @@ pub struct BanPersonResponse {
pub banned: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Block a person.
@ -257,7 +257,7 @@ pub struct BlockPersonResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Get comment replies.
@ -278,7 +278,7 @@ pub struct GetRepliesResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Get mentions for your user.
@ -297,7 +297,7 @@ pub struct GetPersonMentionsResponse {
pub mentions: Vec<PersonMentionView>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Mark a person mention as read.
@ -314,7 +314,7 @@ pub struct PersonMentionResponse {
pub person_mention_view: PersonMentionView,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Mark a comment reply as read.
@ -331,7 +331,7 @@ pub struct CommentReplyResponse {
pub comment_reply_view: CommentReplyView,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Delete your account.
@ -340,7 +340,7 @@ pub struct DeleteAccount {
pub delete_content: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Reset your password via email.
@ -348,7 +348,7 @@ pub struct PasswordReset {
pub email: Sensitive<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Change your password after receiving a reset request.
@ -359,7 +359,7 @@ pub struct PasswordChangeAfterReset {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Get a count of the number of reports.
@ -389,7 +389,7 @@ pub struct GetUnreadCountResponse {
pub private_messages: i64,
}
#[derive(Serialize, Deserialize, Clone, Default, Debug)]
#[derive(Serialize, Deserialize, Clone, Default, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Verify your email.
@ -404,7 +404,7 @@ pub struct GenerateTotpSecretResponse {
pub totp_secret_url: Sensitive<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct UpdateTotp {

View File

@ -13,7 +13,7 @@ use ts_rs::TS;
use url::Url;
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Create a post.
@ -41,7 +41,7 @@ pub struct PostResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Get a post. Needs either the post id, or comment_id.
@ -64,7 +64,7 @@ pub struct GetPostResponse {
}
#[skip_serializing_none]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Get a list of posts.
@ -93,7 +93,7 @@ pub struct GetPostsResponse {
pub next_page: Option<PaginationCursor>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Like a post.
@ -104,7 +104,7 @@ pub struct CreatePostLike {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Edit a post.
@ -122,7 +122,7 @@ pub struct EditPost {
pub custom_thumbnail: Option<Url>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Delete a post.
@ -132,7 +132,7 @@ pub struct DeletePost {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Remove a post (only doable by mods).
@ -143,7 +143,7 @@ pub struct RemovePost {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Mark a post as read.
@ -154,7 +154,7 @@ pub struct MarkPostAsRead {
pub read: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Lock a post (prevent new comments).
@ -163,7 +163,7 @@ pub struct LockPost {
pub locked: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Feature a post (stickies / pins to the top).
@ -173,7 +173,7 @@ pub struct FeaturePost {
pub feature_type: PostFeatureType,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Save / bookmark a post.
@ -199,7 +199,7 @@ pub struct PostReportResponse {
pub post_report_view: PostReportView,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Resolve a post report (mods only).
@ -209,7 +209,7 @@ pub struct ResolvePostReport {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// List post reports.
@ -230,7 +230,7 @@ pub struct ListPostReportsResponse {
pub post_reports: Vec<PostReportView>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Get metadata for a given site.
@ -248,7 +248,7 @@ pub struct GetSiteMetadataResponse {
}
#[skip_serializing_none]
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Default)]
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Default, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Site metadata, from its opengraph tags.
@ -261,7 +261,7 @@ pub struct LinkMetadata {
}
#[skip_serializing_none]
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Default)]
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Default, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Site metadata, from its opengraph tags.
@ -273,7 +273,7 @@ pub struct OpenGraphData {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// List post likes. Admins-only.

View File

@ -5,7 +5,7 @@ use serde_with::skip_serializing_none;
#[cfg(feature = "full")]
use ts_rs::TS;
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Create a private message.
@ -14,7 +14,7 @@ pub struct CreatePrivateMessage {
pub recipient_id: PersonId,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Edit a private message.
@ -23,7 +23,7 @@ pub struct EditPrivateMessage {
pub content: String,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Delete a private message.
@ -32,7 +32,7 @@ pub struct DeletePrivateMessage {
pub deleted: bool,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Mark a private message as read.
@ -42,7 +42,7 @@ pub struct MarkPrivateMessageAsRead {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Get your private messages.
@ -69,7 +69,7 @@ pub struct PrivateMessageResponse {
pub private_message_view: PrivateMessageView,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Create a report for a private message.
@ -86,7 +86,7 @@ pub struct PrivateMessageReportResponse {
pub private_message_report_view: PrivateMessageReportView,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Resolve a private message report.
@ -96,7 +96,7 @@ pub struct ResolvePrivateMessageReport {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// List private message reports.

View File

@ -54,7 +54,7 @@ use serde_with::skip_serializing_none;
use ts_rs::TS;
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Searches the site, given a query string, and some optional filters.
@ -83,7 +83,7 @@ pub struct SearchResponse {
pub users: Vec<PersonView>,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Does an apub fetch for an object.
@ -106,7 +106,7 @@ pub struct ResolveObjectResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Fetches the modlog.
@ -143,7 +143,7 @@ pub struct GetModlogResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Creates a site. Should be done after first running lemmy.
@ -190,7 +190,7 @@ pub struct CreateSite {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Edits a site.
@ -363,7 +363,7 @@ pub struct InstanceWithFederationState {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Purges a person from the database. This will delete all content attached to that person.
@ -373,7 +373,7 @@ pub struct PurgePerson {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Purges a community from the database. This will delete all content attached to that community.
@ -383,7 +383,7 @@ pub struct PurgeCommunity {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Purges a post from the database. This will delete all content attached to that post.
@ -393,7 +393,7 @@ pub struct PurgePost {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Purges a comment from the database. This will delete all content attached to that comment.
@ -403,7 +403,7 @@ pub struct PurgeComment {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Fetches a list of registration applications.
@ -423,7 +423,7 @@ pub struct ListRegistrationApplicationsResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Approves a registration application.
@ -449,7 +449,7 @@ pub struct GetUnreadRegistrationApplicationCountResponse {
pub registration_applications: i64,
}
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Block an instance as user

View File

@ -29,6 +29,7 @@ moka.workspace = true
once_cell.workspace = true
anyhow.workspace = true
webmention = "0.5.0"
accept-language = "3.1.0"
[package.metadata.cargo-machete]
ignored = ["futures"]

View File

@ -52,7 +52,7 @@ pub async fn delete_post(
.await?;
ActivityChannel::submit_activity(
SendActivityData::DeletePost(post, local_user_view.person.clone(), data.0.clone()),
SendActivityData::DeletePost(post, local_user_view.person.clone(), data.0),
&context,
)
.await?;

View File

@ -126,6 +126,14 @@ pub async fn register(
// Also fixes a bug which allows users to log in when registrations are changed to closed.
let accepted_application = Some(!require_registration_application);
// Get the user's preferred language using the Accept-Language header
let language_tag = req.headers().get("Accept-Language").and_then(|hdr| {
accept_language::parse(hdr.to_str().unwrap_or_default())
.first()
// Remove the optional region code
.map(|lang_str| lang_str.split('-').next().unwrap_or_default().to_string())
});
// Create the local user
let local_user_form = LocalUserInsertForm::builder()
.person_id(inserted_person.id)
@ -134,6 +142,7 @@ pub async fn register(
.show_nsfw(Some(data.show_nsfw))
.accepted_application(accepted_application)
.default_listing_type(Some(local_site.default_post_listing_type))
.interface_language(language_tag)
// If its the initial site setup, they are an admin
.admin(Some(!local_site.site_setup))
.build();

View File

@ -130,6 +130,10 @@ async fn try_main() -> LemmyResult<()> {
// Make sure the println above shows the correct amount
assert_eq!(num_inserted_posts, num_posts as usize);
// Manually trigger and wait for a statistics update to ensure consistent and high amount of accuracy in the statistics used for query planning
println!("🧮 updating database statistics");
conn.batch_execute("ANALYZE;").await?;
// Enable auto_explain
conn
.batch_execute(

View File

@ -49,7 +49,7 @@ use strum_macros::{Display, EnumString};
use ts_rs::TS;
#[derive(
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default,
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash,
)]
#[cfg_attr(feature = "full", derive(DbEnum, TS))]
#[cfg_attr(
@ -83,7 +83,7 @@ pub enum SortType {
Scaled,
}
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy)]
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// The comment sort types. See here for descriptions: https://join-lemmy.org/docs/en/users/03-votes-and-ranking.html
@ -96,7 +96,7 @@ pub enum CommentSortType {
}
#[derive(
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default,
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash,
)]
#[cfg_attr(feature = "full", derive(DbEnum, TS))]
#[cfg_attr(
@ -119,7 +119,7 @@ pub enum ListingType {
}
#[derive(
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default,
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash,
)]
#[cfg_attr(feature = "full", derive(DbEnum, TS))]
#[cfg_attr(
@ -139,7 +139,7 @@ pub enum RegistrationMode {
Open,
}
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(DbEnum, TS))]
#[cfg_attr(
feature = "full",
@ -157,7 +157,7 @@ pub enum PostListingMode {
SmallCard,
}
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy)]
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// The type of content returned from a search.
@ -170,7 +170,7 @@ pub enum SearchType {
Url,
}
#[derive(EnumString, Display, Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy)]
#[derive(EnumString, Display, Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// A type / status for a community subscribe.
@ -180,7 +180,7 @@ pub enum SubscribedType {
Pending,
}
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// A list of possible types for the various modlog actions.
@ -204,7 +204,7 @@ pub enum ModlogActionType {
}
#[derive(
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq,
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash,
)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
@ -218,7 +218,7 @@ pub enum PostFeatureType {
}
#[derive(
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default,
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash,
)]
#[cfg_attr(feature = "full", derive(DbEnum, TS))]
#[cfg_attr(

View File

@ -25,10 +25,11 @@ use diesel::{
use diesel_async::{
pg::AsyncPgConnection,
pooled_connection::{
deadpool::{Object as PooledConnection, Pool},
deadpool::{Hook, HookError, Object as PooledConnection, Pool},
AsyncDieselConnectionManager,
ManagerConfig,
},
SimpleAsyncConnection,
};
use diesel_migrations::EmbeddedMigrations;
use futures_util::{future::BoxFuture, Future, FutureExt};
@ -46,7 +47,7 @@ use rustls::{
use std::{
ops::{Deref, DerefMut},
sync::Arc,
time::SystemTime,
time::{Duration, SystemTime},
};
use tracing::{error, info};
use url::Url;
@ -335,7 +336,14 @@ fn establish_connection(config: &str) -> BoxFuture<ConnectionResult<AsyncPgConne
error!("Database connection failed: {e}");
}
});
AsyncPgConnection::try_from(client).await
let mut conn = AsyncPgConnection::try_from(client).await?;
// * Change geqo_threshold back to default value if it was changed, so it's higher than the collapse limits
// * Change collapse limits from 8 to 11 so the query planner can find a better table join order for more complicated queries
conn
.batch_execute("SET geqo_threshold=12;SET from_collapse_limit=11;SET join_collapse_limit=11;")
.await
.map_err(ConnectionError::CouldntSetupConfiguration)?;
Ok(conn)
};
fut.boxed()
}
@ -389,6 +397,16 @@ pub async fn build_db_pool() -> Result<ActualDbPool, LemmyError> {
let pool = Pool::builder(manager)
.max_size(SETTINGS.database.pool_size)
.runtime(Runtime::Tokio1)
// Limit connection age to prevent use of prepared statements that have query plans based on very old statistics
.pre_recycle(Hook::sync_fn(|_conn, metrics| {
// Preventing the first recycle can cause an infinite loop when trying to get a new connection from the pool
let conn_was_used = metrics.recycled.is_some();
if metrics.age() > Duration::from_secs(3 * 24 * 60 * 60) && conn_was_used {
Err(HookError::Continue(None))
} else {
Ok(())
}
}))
.build()?;
run_migrations(&db_url)?;

View File

@ -98,7 +98,7 @@ pub struct PostReportView {
/// currently this is just a wrapper around post id, but should be seen as opaque from the client's perspective
/// stringified since we might want to use arbitrary info later, with a P prepended to prevent ossification
/// (api users love to make assumptions (e.g. parse stuff that looks like numbers as numbers) about apis that aren't part of the spec
#[derive(Serialize, Deserialize, Debug, Clone)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(ts_rs::TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct PaginationCursor(pub String);

View File

@ -99,7 +99,7 @@ services:
logging: *default-logging
postgres:
image: postgres:15-alpine
image: postgres:16-alpine
# this needs to match the database host in lemmy.hson
# Tune your settings via
# https://pgtune.leopard.in.ua/#/

View File

@ -20,7 +20,7 @@ x-lemmy-default: &lemmy-default
restart: always
x-postgres-default: &postgres-default
image: postgres:15-alpine
image: postgres:16-alpine
environment:
- POSTGRES_USER=lemmy
- POSTGRES_PASSWORD=password

View File

@ -0,0 +1,42 @@
#!/bin/sh
set -e
echo "Do not stop in the middle of this upgrade, wait until you see the message: Upgrade complete."
echo "Stopping lemmy and all services..."
sudo docker-compose stop
echo "Make sure postgres is started..."
sudo docker-compose up -d postgres
echo "Waiting..."
sleep 20s
echo "Exporting the Database to 15_16.dump.sql ..."
sudo docker-compose exec -T postgres pg_dumpall -c -U lemmy > 15_16_dump.sql
echo "Done."
echo "Stopping postgres..."
sudo docker-compose stop postgres
echo "Waiting..."
sleep 20s
echo "Removing the old postgres folder"
sudo rm -rf volumes/postgres
echo "Updating docker-compose to use postgres version 16."
sed -i "s/image: postgres:.*/image: postgres:16-alpine/" ./docker-compose.yml
echo "Starting up new postgres..."
sudo docker-compose up -d postgres
echo "Waiting..."
sleep 20s
echo "Importing the database...."
cat 15_16_dump.sql | sudo docker-compose exec -T postgres psql -U lemmy
echo "Done."
echo "Starting up lemmy..."
sudo docker-compose up -d
echo "A copy of your old database is at 15_16.dump.sql . You can delete this file if the upgrade went smoothly."
echo "Upgrade complete."