diff --git a/.woodpecker.yml b/.woodpecker.yml index 885796cac..8930c21fc 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -122,7 +122,6 @@ steps: environment: CARGO_HOME: .cargo_home commands: - - export LEMMY_CONFIG_LOCATION=./config/config.hjson - ./scripts/update_config_defaults.sh config/defaults_current.hjson - diff config/defaults.hjson config/defaults_current.hjson when: *slow_check_paths @@ -147,7 +146,6 @@ steps: CARGO_HOME: .cargo_home commands: # same as scripts/db_perf.sh but without creating a new database server - - export LEMMY_CONFIG_LOCATION=config/config.hjson - cargo run --package lemmy_db_perf -- --posts 10 --read-post-pages 1 when: *slow_check_paths @@ -176,11 +174,20 @@ steps: RUST_BACKTRACE: "1" CARGO_HOME: .cargo_home LEMMY_TEST_FAST_FEDERATION: "1" + LEMMY_CONFIG_LOCATION: ../../config/config.hjson commands: - - export LEMMY_CONFIG_LOCATION=../../config/config.hjson - cargo test --workspace --no-fail-fast when: *slow_check_paths + check_ts_bindings: + image: *rust_image + environment: + CARGO_HOME: .cargo_home + commands: + - ./scripts/ts_bindings_check.sh + when: + - event: pull_request + check_diesel_migration: # TODO: use willsquire/diesel-cli image when shared libraries become optional in lemmy_server image: *rust_image diff --git a/Cargo.lock b/Cargo.lock index 491b7cc94..edf237ab3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" - [[package]] name = "accept-language" version = "3.1.0" @@ -5255,22 +5249,23 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "ts-rs" -version = "7.1.1" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2cae1fc5d05d47aa24b64f9a4f7cba24cdc9187a2084dd97ac57bef5eccae6" +checksum = "3a2f31991cee3dce1ca4f929a8a04fdd11fd8801aac0f2030b0fa8a0a3fef6b9" dependencies = [ "chrono", + "lazy_static", "thiserror", "ts-rs-macros", + "url", ] [[package]] name = "ts-rs-macros" -version = "7.1.1" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f7f9b821696963053a89a7bd8b292dc34420aea8294d7b225274d488f3ec92" +checksum = "0ea0b99e8ec44abd6f94a18f28f7934437809dd062820797c52401298116f70e" dependencies = [ - "Inflector", "proc-macro2", "quote", "syn 2.0.77", diff --git a/Cargo.toml b/Cargo.toml index 99e6a53e2..0373c4e51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -142,10 +142,11 @@ itertools = "0.13.0" futures = "0.3.30" http = "1.1" rosetta-i18n = "0.1.3" -ts-rs = { version = "7.1.1", features = [ +ts-rs = { version = "10.0.0", features = [ "serde-compat", "chrono-impl", "no-serde-warnings", + "url-impl", ] } rustls = { version = "0.23.12", features = ["ring"] } futures-util = "0.3.30" diff --git a/api_tests/src/shared.ts b/api_tests/src/shared.ts index 017dad903..20cb171c5 100644 --- a/api_tests/src/shared.ts +++ b/api_tests/src/shared.ts @@ -83,7 +83,7 @@ export const fetchFunction = fetch; export const imageFetchLimit = 50; export const sampleImage = "https://i.pinimg.com/originals/df/5f/5b/df5f5b1b174a2b4b6026cc6c8f9395c1.jpg"; -export const sampleSite = "https://google.com"; +export const sampleSite = "https://w3.org"; export const alphaUrl = "http://127.0.0.1:8541"; export const betaUrl = "http://127.0.0.1:8551"; diff --git a/crates/api_common/src/comment.rs b/crates/api_common/src/comment.rs index 48800cf8d..e08365789 100644 --- a/crates/api_common/src/comment.rs +++ b/crates/api_common/src/comment.rs @@ -17,7 +17,9 @@ use ts_rs::TS; pub struct CreateComment { pub content: String, pub post_id: PostId, + #[cfg_attr(feature = "full", ts(optional))] pub parent_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub language_id: Option, } @@ -37,7 +39,9 @@ pub struct GetComment { /// Edit a comment. pub struct EditComment { pub comment_id: CommentId, + #[cfg_attr(feature = "full", ts(optional))] pub content: Option, + #[cfg_attr(feature = "full", ts(optional))] pub language_id: Option, } @@ -69,6 +73,7 @@ pub struct DeleteComment { pub struct RemoveComment { pub comment_id: CommentId, pub removed: bool, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, } @@ -107,17 +112,29 @@ pub struct CreateCommentLike { #[cfg_attr(feature = "full", ts(export))] /// Get a list of comments. pub struct GetComments { + #[cfg_attr(feature = "full", ts(optional))] pub type_: Option, + #[cfg_attr(feature = "full", ts(optional))] pub sort: Option, + #[cfg_attr(feature = "full", ts(optional))] pub max_depth: Option, + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, + #[cfg_attr(feature = "full", ts(optional))] pub community_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub community_name: Option, + #[cfg_attr(feature = "full", ts(optional))] pub post_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub parent_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub saved_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub liked_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub disliked_only: Option, } @@ -161,12 +178,17 @@ pub struct ResolveCommentReport { #[cfg_attr(feature = "full", ts(export))] /// List comment reports. pub struct ListCommentReports { + #[cfg_attr(feature = "full", ts(optional))] pub comment_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, /// Only shows the unresolved reports + #[cfg_attr(feature = "full", ts(optional))] pub unresolved_only: Option, /// if no community is given, it returns reports for all communities moderated by the auth user + #[cfg_attr(feature = "full", ts(optional))] pub community_id: Option, } @@ -185,7 +207,9 @@ pub struct ListCommentReportsResponse { /// List comment likes. Admins-only. pub struct ListCommentLikes { pub comment_id: CommentId, + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, } diff --git a/crates/api_common/src/community.rs b/crates/api_common/src/community.rs index 1def2111b..2fab2d05c 100644 --- a/crates/api_common/src/community.rs +++ b/crates/api_common/src/community.rs @@ -19,10 +19,13 @@ use ts_rs::TS; #[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)] #[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", ts(export))] +// TODO make this into a tagged enum /// Get a community. Must provide either an id, or a name. pub struct GetCommunity { + #[cfg_attr(feature = "full", ts(optional))] pub id: Option, /// Example: star_trek , or star_trek@xyz.tld + #[cfg_attr(feature = "full", ts(optional))] pub name: Option, } @@ -33,6 +36,7 @@ pub struct GetCommunity { /// The community response. pub struct GetCommunityResponse { pub community_view: CommunityView, + #[cfg_attr(feature = "full", ts(optional))] pub site: Option, pub moderators: Vec, pub discussion_languages: Vec, @@ -49,18 +53,26 @@ pub struct CreateCommunity { /// A longer title. pub title: String, /// A sidebar for the community in markdown. + #[cfg_attr(feature = "full", ts(optional))] pub sidebar: Option, /// A shorter, one line description of your community. + #[cfg_attr(feature = "full", ts(optional))] pub description: Option, /// An icon URL. + #[cfg_attr(feature = "full", ts(optional))] pub icon: Option, /// A banner URL. + #[cfg_attr(feature = "full", ts(optional))] pub banner: Option, /// Whether its an NSFW community. + #[cfg_attr(feature = "full", ts(optional))] pub nsfw: Option, /// Whether to restrict posting only to moderators. + #[cfg_attr(feature = "full", ts(optional))] pub posting_restricted_to_mods: Option, + #[cfg_attr(feature = "full", ts(optional))] pub discussion_languages: Option>, + #[cfg_attr(feature = "full", ts(optional))] pub visibility: Option, } @@ -79,10 +91,15 @@ pub struct CommunityResponse { #[cfg_attr(feature = "full", ts(export))] /// Fetches a list of communities. pub struct ListCommunities { + #[cfg_attr(feature = "full", ts(optional))] pub type_: Option, + #[cfg_attr(feature = "full", ts(optional))] pub sort: Option, + #[cfg_attr(feature = "full", ts(optional))] pub show_nsfw: Option, + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, } @@ -105,11 +122,14 @@ pub struct BanFromCommunity { pub ban: bool, /// Optionally remove or restore all their data. Useful for new troll accounts. /// If ban is true, then this means remove. If ban is false, it means restore. + #[cfg_attr(feature = "full", ts(optional))] pub remove_or_restore_data: Option, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, /// A time that the ban will expire, in unix epoch seconds. /// /// An i64 unix timestamp is used for a simpler API client implementation. + #[cfg_attr(feature = "full", ts(optional))] pub expires: Option, } @@ -148,20 +168,29 @@ pub struct AddModToCommunityResponse { pub struct EditCommunity { pub community_id: CommunityId, /// A longer title. + #[cfg_attr(feature = "full", ts(optional))] pub title: Option, /// A sidebar for the community in markdown. + #[cfg_attr(feature = "full", ts(optional))] pub sidebar: Option, /// A shorter, one line description of your community. + #[cfg_attr(feature = "full", ts(optional))] pub description: Option, /// An icon URL. + #[cfg_attr(feature = "full", ts(optional))] pub icon: Option, /// A banner URL. + #[cfg_attr(feature = "full", ts(optional))] pub banner: Option, /// Whether its an NSFW community. + #[cfg_attr(feature = "full", ts(optional))] pub nsfw: Option, /// Whether to restrict posting only to moderators. + #[cfg_attr(feature = "full", ts(optional))] pub posting_restricted_to_mods: Option, + #[cfg_attr(feature = "full", ts(optional))] pub discussion_languages: Option>, + #[cfg_attr(feature = "full", ts(optional))] pub visibility: Option, } @@ -173,6 +202,7 @@ pub struct EditCommunity { pub struct HideCommunity { pub community_id: CommunityId, pub hidden: bool, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, } @@ -194,6 +224,7 @@ pub struct DeleteCommunity { pub struct RemoveCommunity { pub community_id: CommunityId, pub removed: bool, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, } @@ -240,5 +271,6 @@ pub struct TransferCommunity { #[cfg_attr(feature = "full", ts(export))] /// Fetches a random community pub struct GetRandomCommunity { + #[cfg_attr(feature = "full", ts(optional))] pub type_: Option, } diff --git a/crates/api_common/src/custom_emoji.rs b/crates/api_common/src/custom_emoji.rs index 3804b71af..76bc9c9e2 100644 --- a/crates/api_common/src/custom_emoji.rs +++ b/crates/api_common/src/custom_emoji.rs @@ -62,8 +62,12 @@ pub struct ListCustomEmojisResponse { #[cfg_attr(feature = "full", ts(export))] /// Fetches a list of custom emojis. pub struct ListCustomEmojis { + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, + #[cfg_attr(feature = "full", ts(optional))] pub category: Option, + #[cfg_attr(feature = "full", ts(optional))] pub ignore_page_limits: Option, } diff --git a/crates/api_common/src/oauth_provider.rs b/crates/api_common/src/oauth_provider.rs index 14847edf1..36fef3b18 100644 --- a/crates/api_common/src/oauth_provider.rs +++ b/crates/api_common/src/oauth_provider.rs @@ -20,8 +20,11 @@ pub struct CreateOAuthProvider { pub client_id: String, pub client_secret: String, pub scopes: String, + #[cfg_attr(feature = "full", ts(optional))] pub auto_verify_email: Option, + #[cfg_attr(feature = "full", ts(optional))] pub account_linking_enabled: Option, + #[cfg_attr(feature = "full", ts(optional))] pub enabled: Option, } @@ -32,15 +35,25 @@ pub struct CreateOAuthProvider { /// Edit an external auth method. pub struct EditOAuthProvider { pub id: OAuthProviderId, + #[cfg_attr(feature = "full", ts(optional))] pub display_name: Option, + #[cfg_attr(feature = "full", ts(optional))] pub authorization_endpoint: Option, + #[cfg_attr(feature = "full", ts(optional))] pub token_endpoint: Option, + #[cfg_attr(feature = "full", ts(optional))] pub userinfo_endpoint: Option, + #[cfg_attr(feature = "full", ts(optional))] pub id_claim: Option, + #[cfg_attr(feature = "full", ts(optional))] pub client_secret: Option, + #[cfg_attr(feature = "full", ts(optional))] pub scopes: Option, + #[cfg_attr(feature = "full", ts(optional))] pub auto_verify_email: Option, + #[cfg_attr(feature = "full", ts(optional))] pub account_linking_enabled: Option, + #[cfg_attr(feature = "full", ts(optional))] pub enabled: Option, } @@ -59,13 +72,14 @@ pub struct DeleteOAuthProvider { /// Logging in with an OAuth 2.0 authorization pub struct AuthenticateWithOauth { pub code: String, - #[cfg_attr(feature = "full", ts(type = "string"))] pub oauth_provider_id: OAuthProviderId, - #[cfg_attr(feature = "full", ts(type = "string"))] pub redirect_uri: Url, + #[cfg_attr(feature = "full", ts(optional))] pub show_nsfw: Option, /// Username is mandatory at registration time + #[cfg_attr(feature = "full", ts(optional))] pub username: Option, /// An answer is mandatory if require application is enabled on the server + #[cfg_attr(feature = "full", ts(optional))] pub answer: Option, } diff --git a/crates/api_common/src/person.rs b/crates/api_common/src/person.rs index 08d952070..31ba03222 100644 --- a/crates/api_common/src/person.rs +++ b/crates/api_common/src/person.rs @@ -28,6 +28,7 @@ pub struct Login { pub username_or_email: SensitiveString, pub password: SensitiveString, /// May be required, if totp is enabled for their account. + #[cfg_attr(feature = "full", ts(optional))] pub totp_2fa_token: Option, } @@ -40,16 +41,22 @@ pub struct Register { pub username: String, pub password: SensitiveString, pub password_verify: SensitiveString, + #[cfg_attr(feature = "full", ts(optional))] pub show_nsfw: Option, /// email is mandatory if email verification is enabled on the server + #[cfg_attr(feature = "full", ts(optional))] pub email: Option, /// The UUID of the captcha item. + #[cfg_attr(feature = "full", ts(optional))] pub captcha_uuid: Option, /// Your captcha answer. + #[cfg_attr(feature = "full", ts(optional))] pub captcha_answer: Option, /// A form field to trick signup bots. Should be None. + #[cfg_attr(feature = "full", ts(optional))] pub honeypot: Option, /// An answer is mandatory if require application is enabled on the server + #[cfg_attr(feature = "full", ts(optional))] pub answer: Option, } @@ -60,6 +67,7 @@ pub struct Register { /// A wrapper for the captcha response. pub struct GetCaptchaResponse { /// Will be None if captchas are disabled. + #[cfg_attr(feature = "full", ts(optional))] pub ok: Option, } @@ -83,62 +91,91 @@ pub struct CaptchaResponse { /// Saves settings for your user. pub struct SaveUserSettings { /// Show nsfw posts. + #[cfg_attr(feature = "full", ts(optional))] pub show_nsfw: Option, /// Blur nsfw posts. + #[cfg_attr(feature = "full", ts(optional))] pub blur_nsfw: Option, /// Your user's theme. + #[cfg_attr(feature = "full", ts(optional))] pub theme: Option, /// The default post listing type, usually "local" + #[cfg_attr(feature = "full", ts(optional))] pub default_listing_type: Option, /// A post-view mode that changes how multiple post listings look. + #[cfg_attr(feature = "full", ts(optional))] pub post_listing_mode: Option, /// The default post sort, usually "active" + #[cfg_attr(feature = "full", ts(optional))] pub default_post_sort_type: Option, /// The default comment sort, usually "hot" + #[cfg_attr(feature = "full", ts(optional))] pub default_comment_sort_type: Option, /// The language of the lemmy interface + #[cfg_attr(feature = "full", ts(optional))] pub interface_language: Option, /// A URL for your avatar. + #[cfg_attr(feature = "full", ts(optional))] pub avatar: Option, /// A URL for your banner. + #[cfg_attr(feature = "full", ts(optional))] pub banner: Option, /// Your display name, which can contain strange characters, and does not need to be unique. + #[cfg_attr(feature = "full", ts(optional))] pub display_name: Option, /// Your email. + #[cfg_attr(feature = "full", ts(optional))] pub email: Option, /// Your bio / info, in markdown. + #[cfg_attr(feature = "full", ts(optional))] pub bio: Option, /// Your matrix user id. Ex: @my_user:matrix.org + #[cfg_attr(feature = "full", ts(optional))] pub matrix_user_id: Option, /// Whether to show or hide avatars. + #[cfg_attr(feature = "full", ts(optional))] pub show_avatars: Option, /// Sends notifications to your email. + #[cfg_attr(feature = "full", ts(optional))] pub send_notifications_to_email: Option, /// Whether this account is a bot account. Users can hide these accounts easily if they wish. + #[cfg_attr(feature = "full", ts(optional))] pub bot_account: Option, /// Whether to show bot accounts. + #[cfg_attr(feature = "full", ts(optional))] pub show_bot_accounts: Option, /// Whether to show read posts. + #[cfg_attr(feature = "full", ts(optional))] pub show_read_posts: Option, /// A list of languages you are able to see discussion in. + #[cfg_attr(feature = "full", ts(optional))] pub discussion_languages: Option>, /// Open links in a new tab + #[cfg_attr(feature = "full", ts(optional))] pub open_links_in_new_tab: Option, /// Enable infinite scroll + #[cfg_attr(feature = "full", ts(optional))] pub infinite_scroll_enabled: Option, /// Whether to allow keyboard navigation (for browsing and interacting with posts and comments). + #[cfg_attr(feature = "full", ts(optional))] pub enable_keyboard_navigation: Option, /// Whether user avatars or inline images in the UI that are gifs should be allowed to play or /// should be paused + #[cfg_attr(feature = "full", ts(optional))] pub enable_animated_images: Option, /// Whether a user can send / receive private messages pub enable_private_messages: Option, /// Whether to auto-collapse bot comments. + #[cfg_attr(feature = "full", ts(optional))] pub collapse_bot_comments: Option, /// Some vote display mode settings + #[cfg_attr(feature = "full", ts(optional))] pub show_scores: Option, + #[cfg_attr(feature = "full", ts(optional))] pub show_upvotes: Option, + #[cfg_attr(feature = "full", ts(optional))] pub show_downvotes: Option, + #[cfg_attr(feature = "full", ts(optional))] pub show_upvote_percentage: Option, } @@ -160,6 +197,7 @@ pub struct ChangePassword { pub struct LoginResponse { /// This is None in response to `Register` if email verification is enabled, or the server /// requires registration applications. + #[cfg_attr(feature = "full", ts(optional))] pub jwt: Option, /// If registration applications are required, this will return true for a signup response. pub registration_created: bool, @@ -175,13 +213,20 @@ pub struct LoginResponse { /// /// Either person_id, or username are required. pub struct GetPersonDetails { + #[cfg_attr(feature = "full", ts(optional))] pub person_id: Option, /// Example: dessalines , or dessalines@xyz.tld + #[cfg_attr(feature = "full", ts(optional))] pub username: Option, + #[cfg_attr(feature = "full", ts(optional))] pub sort: Option, + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, + #[cfg_attr(feature = "full", ts(optional))] pub community_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub saved_only: Option, } @@ -192,6 +237,7 @@ pub struct GetPersonDetails { /// A person's details response. pub struct GetPersonDetailsResponse { pub person_view: PersonView, + #[cfg_attr(feature = "full", ts(optional))] pub site: Option, pub comments: Vec, pub posts: Vec, @@ -225,11 +271,14 @@ pub struct BanPerson { pub ban: bool, /// Optionally remove or restore all their data. Useful for new troll accounts. /// If ban is true, then this means remove. If ban is false, it means restore. + #[cfg_attr(feature = "full", ts(optional))] pub remove_or_restore_data: Option, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, /// A time that the ban will expire, in unix epoch seconds. /// /// An i64 unix timestamp is used for a simpler API client implementation. + #[cfg_attr(feature = "full", ts(optional))] pub expires: Option, } @@ -275,9 +324,13 @@ pub struct BlockPersonResponse { #[cfg_attr(feature = "full", ts(export))] /// Get comment replies. pub struct GetReplies { + #[cfg_attr(feature = "full", ts(optional))] pub sort: Option, + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, + #[cfg_attr(feature = "full", ts(optional))] pub unread_only: Option, } @@ -296,9 +349,13 @@ pub struct GetRepliesResponse { #[cfg_attr(feature = "full", ts(export))] /// Get mentions for your user. pub struct GetPersonMentions { + #[cfg_attr(feature = "full", ts(optional))] pub sort: Option, + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, + #[cfg_attr(feature = "full", ts(optional))] pub unread_only: Option, } @@ -377,6 +434,7 @@ pub struct PasswordChangeAfterReset { #[cfg_attr(feature = "full", ts(export))] /// Get a count of the number of reports. pub struct GetReportCount { + #[cfg_attr(feature = "full", ts(optional))] pub community_id: Option, } @@ -386,9 +444,11 @@ pub struct GetReportCount { #[cfg_attr(feature = "full", ts(export))] /// A response for the number of reports. pub struct GetReportCountResponse { + #[cfg_attr(feature = "full", ts(optional))] pub community_id: Option, pub comment_reports: i64, pub post_reports: i64, + #[cfg_attr(feature = "full", ts(optional))] pub private_message_reports: Option, } @@ -438,7 +498,9 @@ pub struct UpdateTotpResponse { #[cfg_attr(feature = "full", ts(export))] /// Get your user's image / media uploads. pub struct ListMedia { + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, } diff --git a/crates/api_common/src/post.rs b/crates/api_common/src/post.rs index 22d5e1431..ca4f53e9d 100644 --- a/crates/api_common/src/post.rs +++ b/crates/api_common/src/post.rs @@ -19,18 +19,26 @@ use ts_rs::TS; pub struct CreatePost { pub name: String, pub community_id: CommunityId, + #[cfg_attr(feature = "full", ts(optional))] pub url: Option, /// An optional body for the post in markdown. + #[cfg_attr(feature = "full", ts(optional))] pub body: Option, /// An optional alt_text, usable for image posts. + #[cfg_attr(feature = "full", ts(optional))] pub alt_text: Option, /// A honeypot to catch bots. Should be None. + #[cfg_attr(feature = "full", ts(optional))] pub honeypot: Option, + #[cfg_attr(feature = "full", ts(optional))] pub nsfw: Option, + #[cfg_attr(feature = "full", ts(optional))] pub language_id: Option, /// Instead of fetching a thumbnail, use a custom one. + #[cfg_attr(feature = "full", ts(optional))] pub custom_thumbnail: Option, /// Time when this post should be scheduled. Null means publish immediately. + #[cfg_attr(feature = "full", ts(optional))] pub scheduled_publish_time: Option, } @@ -45,9 +53,12 @@ pub struct PostResponse { #[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", ts(export))] +// TODO this should be made into a tagged enum /// Get a post. Needs either the post id, or comment_id. pub struct GetPost { + #[cfg_attr(feature = "full", ts(optional))] pub id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub comment_id: Option, } @@ -70,23 +81,37 @@ pub struct GetPostResponse { #[cfg_attr(feature = "full", ts(export))] /// Get a list of posts. pub struct GetPosts { + #[cfg_attr(feature = "full", ts(optional))] pub type_: Option, + #[cfg_attr(feature = "full", ts(optional))] pub sort: Option, /// DEPRECATED, use page_cursor + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, + #[cfg_attr(feature = "full", ts(optional))] pub community_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub community_name: Option, + #[cfg_attr(feature = "full", ts(optional))] pub saved_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub liked_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub disliked_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub show_hidden: Option, /// If true, then show the read posts (even if your user setting is to hide them) + #[cfg_attr(feature = "full", ts(optional))] pub show_read: Option, /// If true, then show the nsfw posts (even if your user setting is to hide them) + #[cfg_attr(feature = "full", ts(optional))] pub show_nsfw: Option, + #[cfg_attr(feature = "full", ts(optional))] /// If true, then only show posts with no comments pub no_comments_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub page_cursor: Option, } @@ -98,6 +123,7 @@ pub struct GetPosts { pub struct GetPostsResponse { pub posts: Vec, /// the pagination cursor to use to fetch the next page + #[cfg_attr(feature = "full", ts(optional))] pub next_page: Option, } @@ -118,17 +144,25 @@ pub struct CreatePostLike { /// Edit a post. pub struct EditPost { pub post_id: PostId, + #[cfg_attr(feature = "full", ts(optional))] pub name: Option, + #[cfg_attr(feature = "full", ts(optional))] pub url: Option, /// An optional body for the post in markdown. + #[cfg_attr(feature = "full", ts(optional))] pub body: Option, /// An optional alt_text, usable for image posts. + #[cfg_attr(feature = "full", ts(optional))] pub alt_text: Option, + #[cfg_attr(feature = "full", ts(optional))] pub nsfw: Option, + #[cfg_attr(feature = "full", ts(optional))] pub language_id: Option, /// Instead of fetching a thumbnail, use a custom one. + #[cfg_attr(feature = "full", ts(optional))] pub custom_thumbnail: Option, /// Time when this post should be scheduled. Null means publish immediately. + #[cfg_attr(feature = "full", ts(optional))] pub scheduled_publish_time: Option, } @@ -149,6 +183,7 @@ pub struct DeletePost { pub struct RemovePost { pub post_id: PostId, pub removed: bool, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, } @@ -232,12 +267,18 @@ pub struct ResolvePostReport { #[cfg_attr(feature = "full", ts(export))] /// List post reports. pub struct ListPostReports { + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, /// Only shows the unresolved reports + #[cfg_attr(feature = "full", ts(optional))] pub unresolved_only: Option, + // TODO make into tagged enum at some point /// if no community is given, it returns reports for all communities moderated by the auth user + #[cfg_attr(feature = "full", ts(optional))] pub community_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub post_id: Option, } @@ -273,6 +314,7 @@ pub struct GetSiteMetadataResponse { pub struct LinkMetadata { #[serde(flatten)] pub opengraph_data: OpenGraphData, + #[cfg_attr(feature = "full", ts(optional))] pub content_type: Option, } @@ -282,9 +324,13 @@ pub struct LinkMetadata { #[cfg_attr(feature = "full", ts(export))] /// Site metadata, from its opengraph tags. pub struct OpenGraphData { + #[cfg_attr(feature = "full", ts(optional))] pub title: Option, + #[cfg_attr(feature = "full", ts(optional))] pub description: Option, + #[cfg_attr(feature = "full", ts(optional))] pub(crate) image: Option, + #[cfg_attr(feature = "full", ts(optional))] pub embed_video_url: Option, } @@ -295,7 +341,9 @@ pub struct OpenGraphData { /// List post likes. Admins-only. pub struct ListPostLikes { pub post_id: PostId, + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, } diff --git a/crates/api_common/src/private_message.rs b/crates/api_common/src/private_message.rs index 429d68643..666fe3865 100644 --- a/crates/api_common/src/private_message.rs +++ b/crates/api_common/src/private_message.rs @@ -47,9 +47,13 @@ pub struct MarkPrivateMessageAsRead { #[cfg_attr(feature = "full", ts(export))] /// Get your private messages. pub struct GetPrivateMessages { + #[cfg_attr(feature = "full", ts(optional))] pub unread_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, + #[cfg_attr(feature = "full", ts(optional))] pub creator_id: Option, } @@ -102,9 +106,12 @@ pub struct ResolvePrivateMessageReport { /// List private message reports. // TODO , perhaps GetReports should be a tagged enum list too. pub struct ListPrivateMessageReports { + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, /// Only shows the unresolved reports + #[cfg_attr(feature = "full", ts(optional))] pub unresolved_only: Option, } diff --git a/crates/api_common/src/site.rs b/crates/api_common/src/site.rs index 8fc091e9d..40a5cc42d 100644 --- a/crates/api_common/src/site.rs +++ b/crates/api_common/src/site.rs @@ -71,18 +71,31 @@ use ts_rs::TS; /// Searches the site, given a query string, and some optional filters. pub struct Search { pub q: String, + #[cfg_attr(feature = "full", ts(optional))] pub community_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub community_name: Option, + #[cfg_attr(feature = "full", ts(optional))] pub creator_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub type_: Option, + #[cfg_attr(feature = "full", ts(optional))] pub sort: Option, + #[cfg_attr(feature = "full", ts(optional))] pub listing_type: Option, + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, + #[cfg_attr(feature = "full", ts(optional))] pub title_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub post_url_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub saved_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub liked_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub disliked_only: Option, } @@ -115,9 +128,13 @@ pub struct ResolveObject { // TODO Change this to an enum /// The response of an apub object fetch. pub struct ResolveObjectResponse { + #[cfg_attr(feature = "full", ts(optional))] pub comment: Option, + #[cfg_attr(feature = "full", ts(optional))] pub post: Option, + #[cfg_attr(feature = "full", ts(optional))] pub community: Option, + #[cfg_attr(feature = "full", ts(optional))] pub person: Option, } @@ -127,13 +144,21 @@ pub struct ResolveObjectResponse { #[cfg_attr(feature = "full", ts(export))] /// Fetches the modlog. pub struct GetModlog { + #[cfg_attr(feature = "full", ts(optional))] pub mod_person_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub community_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, + #[cfg_attr(feature = "full", ts(optional))] pub type_: Option, + #[cfg_attr(feature = "full", ts(optional))] pub other_person_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub post_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub comment_id: Option, } @@ -167,50 +192,95 @@ pub struct GetModlogResponse { /// Creates a site. Should be done after first running lemmy. pub struct CreateSite { pub name: String, + #[cfg_attr(feature = "full", ts(optional))] pub sidebar: Option, + #[cfg_attr(feature = "full", ts(optional))] pub description: Option, + #[cfg_attr(feature = "full", ts(optional))] pub icon: Option, + #[cfg_attr(feature = "full", ts(optional))] pub banner: Option, + #[cfg_attr(feature = "full", ts(optional))] pub enable_nsfw: Option, + #[cfg_attr(feature = "full", ts(optional))] pub community_creation_admin_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub require_email_verification: Option, + #[cfg_attr(feature = "full", ts(optional))] pub application_question: Option, + #[cfg_attr(feature = "full", ts(optional))] pub private_instance: Option, + #[cfg_attr(feature = "full", ts(optional))] pub default_theme: Option, + #[cfg_attr(feature = "full", ts(optional))] pub default_post_listing_type: Option, + #[cfg_attr(feature = "full", ts(optional))] pub default_post_listing_mode: Option, + #[cfg_attr(feature = "full", ts(optional))] pub default_post_sort_type: Option, + #[cfg_attr(feature = "full", ts(optional))] pub default_comment_sort_type: Option, + #[cfg_attr(feature = "full", ts(optional))] pub legal_information: Option, + #[cfg_attr(feature = "full", ts(optional))] pub application_email_admins: Option, + #[cfg_attr(feature = "full", ts(optional))] pub hide_modlog_mod_names: Option, + #[cfg_attr(feature = "full", ts(optional))] pub discussion_languages: Option>, + #[cfg_attr(feature = "full", ts(optional))] pub slur_filter_regex: Option, + #[cfg_attr(feature = "full", ts(optional))] pub actor_name_max_length: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_message: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_message_per_second: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_post: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_post_per_second: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_register: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_register_per_second: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_image: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_image_per_second: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_comment: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_comment_per_second: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_search: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_search_per_second: Option, + #[cfg_attr(feature = "full", ts(optional))] pub federation_enabled: Option, + #[cfg_attr(feature = "full", ts(optional))] pub federation_debug: Option, + #[cfg_attr(feature = "full", ts(optional))] pub captcha_enabled: Option, + #[cfg_attr(feature = "full", ts(optional))] pub captcha_difficulty: Option, + #[cfg_attr(feature = "full", ts(optional))] pub allowed_instances: Option>, + #[cfg_attr(feature = "full", ts(optional))] pub blocked_instances: Option>, + #[cfg_attr(feature = "full", ts(optional))] pub registration_mode: Option, + #[cfg_attr(feature = "full", ts(optional))] pub oauth_registration: Option, + #[cfg_attr(feature = "full", ts(optional))] pub content_warning: Option, + #[cfg_attr(feature = "full", ts(optional))] pub post_upvotes: Option, + #[cfg_attr(feature = "full", ts(optional))] pub post_downvotes: Option, + #[cfg_attr(feature = "full", ts(optional))] pub comment_upvotes: Option, + #[cfg_attr(feature = "full", ts(optional))] pub comment_downvotes: Option, } @@ -220,94 +290,142 @@ pub struct CreateSite { #[cfg_attr(feature = "full", ts(export))] /// Edits a site. pub struct EditSite { + #[cfg_attr(feature = "full", ts(optional))] pub name: Option, /// A sidebar for the site, in markdown. + #[cfg_attr(feature = "full", ts(optional))] pub sidebar: Option, /// A shorter, one line description of your site. + #[cfg_attr(feature = "full", ts(optional))] pub description: Option, /// A url for your site's icon. + #[cfg_attr(feature = "full", ts(optional))] pub icon: Option, /// A url for your site's banner. + #[cfg_attr(feature = "full", ts(optional))] pub banner: Option, /// Whether to enable NSFW. + #[cfg_attr(feature = "full", ts(optional))] pub enable_nsfw: Option, /// Limits community creation to admins only. + #[cfg_attr(feature = "full", ts(optional))] pub community_creation_admin_only: Option, /// Whether to require email verification. + #[cfg_attr(feature = "full", ts(optional))] pub require_email_verification: Option, /// Your application question form. This is in markdown, and can be many questions. + #[cfg_attr(feature = "full", ts(optional))] pub application_question: Option, /// Whether your instance is public, or private. + #[cfg_attr(feature = "full", ts(optional))] pub private_instance: Option, /// The default theme. Usually "browser" + #[cfg_attr(feature = "full", ts(optional))] pub default_theme: Option, /// The default post listing type, usually "local" + #[cfg_attr(feature = "full", ts(optional))] pub default_post_listing_type: Option, /// Default value for listing mode, usually "list" + #[cfg_attr(feature = "full", ts(optional))] pub default_post_listing_mode: Option, /// The default post sort, usually "active" + #[cfg_attr(feature = "full", ts(optional))] pub default_post_sort_type: Option, /// The default comment sort, usually "hot" + #[cfg_attr(feature = "full", ts(optional))] pub default_comment_sort_type: Option, /// An optional page of legal information + #[cfg_attr(feature = "full", ts(optional))] pub legal_information: Option, /// Whether to email admins when receiving a new application. + #[cfg_attr(feature = "full", ts(optional))] pub application_email_admins: Option, /// Whether to hide moderator names from the modlog. + #[cfg_attr(feature = "full", ts(optional))] pub hide_modlog_mod_names: Option, /// A list of allowed discussion languages. + #[cfg_attr(feature = "full", ts(optional))] pub discussion_languages: Option>, /// A regex string of items to filter. + #[cfg_attr(feature = "full", ts(optional))] pub slur_filter_regex: Option, /// The max length of actor names. + #[cfg_attr(feature = "full", ts(optional))] pub actor_name_max_length: Option, /// The number of messages allowed in a given time frame. + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_message: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_message_per_second: Option, /// The number of posts allowed in a given time frame. + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_post: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_post_per_second: Option, /// The number of registrations allowed in a given time frame. + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_register: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_register_per_second: Option, /// The number of image uploads allowed in a given time frame. + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_image: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_image_per_second: Option, /// The number of comments allowed in a given time frame. + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_comment: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_comment_per_second: Option, /// The number of searches allowed in a given time frame. + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_search: Option, + #[cfg_attr(feature = "full", ts(optional))] pub rate_limit_search_per_second: Option, /// Whether to enable federation. + #[cfg_attr(feature = "full", ts(optional))] pub federation_enabled: Option, /// Enables federation debugging. + #[cfg_attr(feature = "full", ts(optional))] pub federation_debug: Option, /// Whether to enable captchas for signups. + #[cfg_attr(feature = "full", ts(optional))] pub captcha_enabled: Option, /// The captcha difficulty. Can be easy, medium, or hard + #[cfg_attr(feature = "full", ts(optional))] pub captcha_difficulty: Option, /// A list of allowed instances. If none are set, federation is open. + #[cfg_attr(feature = "full", ts(optional))] pub allowed_instances: Option>, /// A list of blocked instances. + #[cfg_attr(feature = "full", ts(optional))] pub blocked_instances: Option>, /// A list of blocked URLs + #[cfg_attr(feature = "full", ts(optional))] pub blocked_urls: Option>, + #[cfg_attr(feature = "full", ts(optional))] pub registration_mode: Option, /// Whether to email admins for new reports. + #[cfg_attr(feature = "full", ts(optional))] pub reports_email_admins: Option, /// If present, nsfw content is visible by default. Should be displayed by frontends/clients /// when the site is first opened by a user. + #[cfg_attr(feature = "full", ts(optional))] pub content_warning: Option, /// Whether or not external auth methods can auto-register users. + #[cfg_attr(feature = "full", ts(optional))] pub oauth_registration: Option, /// What kind of post upvotes your site allows. + #[cfg_attr(feature = "full", ts(optional))] pub post_upvotes: Option, /// What kind of post downvotes your site allows. + #[cfg_attr(feature = "full", ts(optional))] pub post_downvotes: Option, /// What kind of comment upvotes your site allows. + #[cfg_attr(feature = "full", ts(optional))] pub comment_upvotes: Option, /// What kind of comment downvotes your site allows. + #[cfg_attr(feature = "full", ts(optional))] pub comment_downvotes: Option, } @@ -330,6 +448,7 @@ pub struct GetSiteResponse { pub site_view: SiteView, pub admins: Vec, pub version: String, + #[cfg_attr(feature = "full", ts(optional))] pub my_user: Option, pub all_languages: Vec, pub discussion_languages: Vec, @@ -338,9 +457,12 @@ pub struct GetSiteResponse { /// deprecated, use /api/v3/custom_emoji/list pub custom_emojis: Vec<()>, /// If the site has any taglines, a random one is included here for displaying + #[cfg_attr(feature = "full", ts(optional))] pub tagline: Option, /// A list of external auth methods your site supports. + #[cfg_attr(feature = "full", ts(optional))] pub oauth_providers: Option>, + #[cfg_attr(feature = "full", ts(optional))] pub admin_oauth_providers: Option>, pub blocked_urls: Vec, } @@ -352,6 +474,7 @@ pub struct GetSiteResponse { /// A response of federated instances. pub struct GetFederatedInstancesResponse { /// Optional, because federation may be disabled. + #[cfg_attr(feature = "full", ts(optional))] pub federated_instances: Option, } @@ -387,6 +510,7 @@ pub struct ReadableFederationState { #[serde(flatten)] internal_state: FederationQueueState, /// timestamp of the next retry attempt (null if fail count is 0) + #[cfg_attr(feature = "full", ts(optional))] next_retry: Option>, } @@ -411,6 +535,7 @@ pub struct InstanceWithFederationState { pub instance: Instance, /// if federation to this instance is or was active, show state of outgoing federation to this /// instance + #[cfg_attr(feature = "full", ts(optional))] pub federation_state: Option, } @@ -421,6 +546,7 @@ pub struct InstanceWithFederationState { /// Purges a person from the database. This will delete all content attached to that person. pub struct PurgePerson { pub person_id: PersonId, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, } @@ -431,6 +557,7 @@ pub struct PurgePerson { /// Purges a community from the database. This will delete all content attached to that community. pub struct PurgeCommunity { pub community_id: CommunityId, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, } @@ -441,6 +568,7 @@ pub struct PurgeCommunity { /// Purges a post from the database. This will delete all content attached to that post. pub struct PurgePost { pub post_id: PostId, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, } @@ -451,6 +579,7 @@ pub struct PurgePost { /// Purges a comment from the database. This will delete all content attached to that comment. pub struct PurgeComment { pub comment_id: CommentId, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, } @@ -461,8 +590,11 @@ pub struct PurgeComment { /// Fetches a list of registration applications. pub struct ListRegistrationApplications { /// Only shows the unread applications (IE those without an admin actor) + #[cfg_attr(feature = "full", ts(optional))] pub unread_only: Option, + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, } @@ -491,6 +623,7 @@ pub struct GetRegistrationApplication { pub struct ApproveRegistrationApplication { pub id: RegistrationApplicationId, pub approve: bool, + #[cfg_attr(feature = "full", ts(optional))] pub deny_reason: Option, } diff --git a/crates/api_common/src/tagline.rs b/crates/api_common/src/tagline.rs index 3090a2678..528d37947 100644 --- a/crates/api_common/src/tagline.rs +++ b/crates/api_common/src/tagline.rs @@ -50,6 +50,8 @@ pub struct ListTaglinesResponse { #[cfg_attr(feature = "full", ts(export))] /// Fetches a list of taglines. pub struct ListTaglines { + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, } diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index ee9f7d153..7b5659334 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -216,7 +216,9 @@ pub async fn check_registration_application( let local_user_id = local_user_view.local_user.id; let registration = RegistrationApplication::find_by_local_user_id(pool, local_user_id).await?; if registration.admin_id.is_some() { - Err(LemmyErrorType::RegistrationDenied(registration.deny_reason))? + Err(LemmyErrorType::RegistrationDenied { + reason: registration.deny_reason, + })? } else { Err(LemmyErrorType::RegistrationApplicationIsPending)? } diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index a04aec655..e11475d6c 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -54,15 +54,24 @@ impl UrlVerifier for VerifyUrlData { use FederationError::*; check_apub_id_valid(url, &local_site_data).map_err(|err| match err { LemmyError { - error_type: LemmyErrorType::FederationError(Some(FederationDisabled)), + error_type: + LemmyErrorType::FederationError { + error: Some(FederationDisabled), + }, .. } => ActivityPubError::Other("Federation disabled".into()), LemmyError { - error_type: LemmyErrorType::FederationError(Some(DomainBlocked(domain))), + error_type: + LemmyErrorType::FederationError { + error: Some(DomainBlocked(domain)), + }, .. } => ActivityPubError::Other(format!("Domain {domain:?} is blocked")), LemmyError { - error_type: LemmyErrorType::FederationError(Some(DomainNotInAllowList(domain))), + error_type: + LemmyErrorType::FederationError { + error: Some(DomainNotInAllowList(domain)), + }, .. } => ActivityPubError::Other(format!("Domain {domain:?} is not in allowlist")), _ => ActivityPubError::Other("Failed validating apub id".into()), diff --git a/crates/db_schema/src/newtypes.rs b/crates/db_schema/src/newtypes.rs index fe1febef5..c28be8222 100644 --- a/crates/db_schema/src/newtypes.rs +++ b/crates/db_schema/src/newtypes.rs @@ -174,8 +174,9 @@ pub struct LtreeDef(pub String); #[repr(transparent)] #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug, Hash)] -#[cfg_attr(feature = "full", derive(AsExpression, FromSqlRow))] +#[cfg_attr(feature = "full", derive(AsExpression, FromSqlRow, TS))] #[cfg_attr(feature = "full", diesel(sql_type = diesel::sql_types::Text))] +#[cfg_attr(feature = "full", ts(export))] pub struct DbUrl(pub(crate) Box); impl DbUrl { @@ -248,19 +249,6 @@ impl Deref for DbUrl { } } -#[cfg(feature = "full")] -impl TS for DbUrl { - fn name() -> String { - "string".to_string() - } - fn dependencies() -> Vec { - Vec::new() - } - fn transparent() -> bool { - true - } -} - #[cfg(feature = "full")] impl ToSql for DbUrl { fn to_sql(&self, out: &mut Output) -> diesel::serialize::Result { diff --git a/crates/db_schema/src/sensitive.rs b/crates/db_schema/src/sensitive.rs index 340679e2f..5d1d449fb 100644 --- a/crates/db_schema/src/sensitive.rs +++ b/crates/db_schema/src/sensitive.rs @@ -4,8 +4,9 @@ use std::{fmt::Debug, ops::Deref}; use ts_rs::TS; #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, Default)] -#[cfg_attr(feature = "full", derive(DieselNewType))] +#[cfg_attr(feature = "full", derive(DieselNewType, TS))] #[serde(transparent)] +#[cfg_attr(feature = "full", ts(export))] pub struct SensitiveString(String); impl SensitiveString { @@ -39,19 +40,3 @@ impl From for SensitiveString { SensitiveString(t) } } - -#[cfg(feature = "full")] -impl TS for SensitiveString { - fn name() -> String { - "string".to_string() - } - fn name_with_type_args(_args: Vec) -> String { - "string".to_string() - } - fn dependencies() -> Vec { - Vec::new() - } - fn transparent() -> bool { - true - } -} diff --git a/crates/db_schema/src/source/comment.rs b/crates/db_schema/src/source/comment.rs index 1e5f043f1..7e65638ed 100644 --- a/crates/db_schema/src/source/comment.rs +++ b/crates/db_schema/src/source/comment.rs @@ -30,6 +30,7 @@ pub struct Comment { /// Whether the comment has been removed. pub removed: bool, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, /// Whether the comment has been deleted by its creator. pub deleted: bool, diff --git a/crates/db_schema/src/source/comment_report.rs b/crates/db_schema/src/source/comment_report.rs index 73dadc945..a19b6925a 100644 --- a/crates/db_schema/src/source/comment_report.rs +++ b/crates/db_schema/src/source/comment_report.rs @@ -25,8 +25,10 @@ pub struct CommentReport { pub original_comment_text: String, pub reason: String, pub resolved: bool, + #[cfg_attr(feature = "full", ts(optional))] pub resolver_id: Option, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, } diff --git a/crates/db_schema/src/source/community.rs b/crates/db_schema/src/source/community.rs index 2eb6c143c..870a132f2 100644 --- a/crates/db_schema/src/source/community.rs +++ b/crates/db_schema/src/source/community.rs @@ -25,10 +25,12 @@ pub struct Community { /// A longer title, that can contain other characters, and doesn't have to be unique. pub title: String, /// A sidebar for the community in markdown. + #[cfg_attr(feature = "full", ts(optional))] pub sidebar: Option, /// Whether the community is removed by a mod. pub removed: bool, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, /// Whether the community has been deleted by its creator. pub deleted: bool, @@ -45,8 +47,10 @@ pub struct Community { #[serde(skip)] pub last_refreshed_at: DateTime, /// A URL for an icon. + #[cfg_attr(feature = "full", ts(optional))] pub icon: Option, /// A URL for a banner. + #[cfg_attr(feature = "full", ts(optional))] pub banner: Option, #[cfg_attr(feature = "full", ts(skip))] #[serde(skip)] @@ -67,6 +71,7 @@ pub struct Community { pub featured_url: Option, pub visibility: CommunityVisibility, /// A shorter, one-line description of the site. + #[cfg_attr(feature = "full", ts(optional))] pub description: Option, } diff --git a/crates/db_schema/src/source/custom_emoji.rs b/crates/db_schema/src/source/custom_emoji.rs index f5a92ea46..bb95cb7c8 100644 --- a/crates/db_schema/src/source/custom_emoji.rs +++ b/crates/db_schema/src/source/custom_emoji.rs @@ -21,6 +21,7 @@ pub struct CustomEmoji { pub alt_text: String, pub category: String, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, } diff --git a/crates/db_schema/src/source/federation_queue_state.rs b/crates/db_schema/src/source/federation_queue_state.rs index 134dfe452..27e464d1f 100644 --- a/crates/db_schema/src/source/federation_queue_state.rs +++ b/crates/db_schema/src/source/federation_queue_state.rs @@ -19,10 +19,13 @@ use ts_rs::TS; pub struct FederationQueueState { pub instance_id: InstanceId, /// the last successfully sent activity id + #[cfg_attr(feature = "full", ts(optional))] pub last_successful_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub last_successful_published_time: Option>, /// how many failed attempts have been made to send the next activity pub fail_count: i32, /// timestamp of the last retry attempt (when the last failing activity was resent) + #[cfg_attr(feature = "full", ts(optional))] pub last_retry: Option>, } diff --git a/crates/db_schema/src/source/images.rs b/crates/db_schema/src/source/images.rs index 22f5e6eb4..acd339d8e 100644 --- a/crates/db_schema/src/source/images.rs +++ b/crates/db_schema/src/source/images.rs @@ -23,6 +23,7 @@ use ts_rs::TS; #[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))] #[cfg_attr(feature = "full", diesel(primary_key(pictrs_alias)))] pub struct LocalImage { + #[cfg_attr(feature = "full", ts(optional))] pub local_user_id: Option, pub pictrs_alias: String, pub pictrs_delete_token: String, diff --git a/crates/db_schema/src/source/instance.rs b/crates/db_schema/src/source/instance.rs index 8c27a2cb6..f622751cc 100644 --- a/crates/db_schema/src/source/instance.rs +++ b/crates/db_schema/src/source/instance.rs @@ -19,8 +19,11 @@ pub struct Instance { pub id: InstanceId, pub domain: String, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, + #[cfg_attr(feature = "full", ts(optional))] pub software: Option, + #[cfg_attr(feature = "full", ts(optional))] pub version: Option, } diff --git a/crates/db_schema/src/source/local_site.rs b/crates/db_schema/src/source/local_site.rs index 5fa57fe3b..b5bcebc58 100644 --- a/crates/db_schema/src/source/local_site.rs +++ b/crates/db_schema/src/source/local_site.rs @@ -33,6 +33,7 @@ pub struct LocalSite { /// Whether emails are required. pub require_email_verification: bool, /// An optional registration application questionnaire in markdown. + #[cfg_attr(feature = "full", ts(optional))] pub application_question: Option, /// Whether the instance is private or public. pub private_instance: bool, @@ -40,12 +41,14 @@ pub struct LocalSite { pub default_theme: String, pub default_post_listing_type: ListingType, /// An optional legal disclaimer page. + #[cfg_attr(feature = "full", ts(optional))] pub legal_information: Option, /// Whether to hide mod names on the modlog. pub hide_modlog_mod_names: bool, /// Whether new applications email admins. pub application_email_admins: bool, /// An optional regex to filter words. + #[cfg_attr(feature = "full", ts(optional))] pub slur_filter_regex: Option, /// The max actor name length. pub actor_name_max_length: i32, @@ -56,6 +59,7 @@ pub struct LocalSite { /// The captcha difficulty. pub captcha_difficulty: String, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, pub registration_mode: RegistrationMode, /// Whether to email admins on new reports. diff --git a/crates/db_schema/src/source/local_site_rate_limit.rs b/crates/db_schema/src/source/local_site_rate_limit.rs index f7f25f5c1..af424a248 100644 --- a/crates/db_schema/src/source/local_site_rate_limit.rs +++ b/crates/db_schema/src/source/local_site_rate_limit.rs @@ -34,6 +34,7 @@ pub struct LocalSiteRateLimit { pub search: i32, pub search_per_second: i32, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, pub import_user_settings: i32, pub import_user_settings_per_second: i32, diff --git a/crates/db_schema/src/source/local_site_url_blocklist.rs b/crates/db_schema/src/source/local_site_url_blocklist.rs index 4ac0893ec..d6127a78a 100644 --- a/crates/db_schema/src/source/local_site_url_blocklist.rs +++ b/crates/db_schema/src/source/local_site_url_blocklist.rs @@ -16,6 +16,7 @@ pub struct LocalSiteUrlBlocklist { pub id: i32, pub url: String, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, } diff --git a/crates/db_schema/src/source/local_user.rs b/crates/db_schema/src/source/local_user.rs index 6837a5d0c..fd15253cc 100644 --- a/crates/db_schema/src/source/local_user.rs +++ b/crates/db_schema/src/source/local_user.rs @@ -27,6 +27,7 @@ pub struct LocalUser { pub person_id: PersonId, #[serde(skip)] pub password_encrypted: Option, + #[cfg_attr(feature = "full", ts(optional))] pub email: Option, /// Whether to show NSFW content. pub show_nsfw: bool, diff --git a/crates/db_schema/src/source/login_token.rs b/crates/db_schema/src/source/login_token.rs index 38aac33ef..20d81afb0 100644 --- a/crates/db_schema/src/source/login_token.rs +++ b/crates/db_schema/src/source/login_token.rs @@ -24,7 +24,9 @@ pub struct LoginToken { pub published: DateTime, /// IP address where login was made from, allows invalidating logins by IP address. /// Could be stored in truncated format, or store derived information for better privacy. + #[cfg_attr(feature = "full", ts(optional))] pub ip: Option, + #[cfg_attr(feature = "full", ts(optional))] pub user_agent: Option, } diff --git a/crates/db_schema/src/source/moderator.rs b/crates/db_schema/src/source/moderator.rs index c1f58ebc8..b4fdcc676 100644 --- a/crates/db_schema/src/source/moderator.rs +++ b/crates/db_schema/src/source/moderator.rs @@ -34,6 +34,7 @@ pub struct ModRemovePost { pub id: i32, pub mod_person_id: PersonId, pub post_id: PostId, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, pub removed: bool, pub when_: DateTime, @@ -105,6 +106,7 @@ pub struct ModRemoveComment { pub id: i32, pub mod_person_id: PersonId, pub comment_id: CommentId, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, pub removed: bool, pub when_: DateTime, @@ -130,6 +132,7 @@ pub struct ModRemoveCommunity { pub id: i32, pub mod_person_id: PersonId, pub community_id: CommunityId, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, pub removed: bool, pub when_: DateTime, @@ -156,8 +159,10 @@ pub struct ModBanFromCommunity { pub mod_person_id: PersonId, pub other_person_id: PersonId, pub community_id: CommunityId, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, pub banned: bool, + #[cfg_attr(feature = "full", ts(optional))] pub expires: Option>, pub when_: DateTime, } @@ -184,8 +189,10 @@ pub struct ModBan { pub id: i32, pub mod_person_id: PersonId, pub other_person_id: PersonId, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, pub banned: bool, + #[cfg_attr(feature = "full", ts(optional))] pub expires: Option>, pub when_: DateTime, } @@ -211,6 +218,7 @@ pub struct ModHideCommunity { pub community_id: CommunityId, pub mod_person_id: PersonId, pub when_: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, pub hidden: bool, } @@ -303,6 +311,7 @@ pub struct ModAddForm { pub struct AdminPurgePerson { pub id: i32, pub admin_person_id: PersonId, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, pub when_: DateTime, } @@ -324,6 +333,7 @@ pub struct AdminPurgePersonForm { pub struct AdminPurgeCommunity { pub id: i32, pub admin_person_id: PersonId, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, pub when_: DateTime, } @@ -346,6 +356,7 @@ pub struct AdminPurgePost { pub id: i32, pub admin_person_id: PersonId, pub community_id: CommunityId, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, pub when_: DateTime, } @@ -369,6 +380,7 @@ pub struct AdminPurgeComment { pub id: i32, pub admin_person_id: PersonId, pub post_id: PostId, + #[cfg_attr(feature = "full", ts(optional))] pub reason: Option, pub when_: DateTime, } diff --git a/crates/db_schema/src/source/oauth_account.rs b/crates/db_schema/src/source/oauth_account.rs index 83b578e22..b7d190c35 100644 --- a/crates/db_schema/src/source/oauth_account.rs +++ b/crates/db_schema/src/source/oauth_account.rs @@ -19,6 +19,7 @@ pub struct OAuthAccount { pub oauth_provider_id: OAuthProviderId, pub oauth_user_id: String, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, } diff --git a/crates/db_schema/src/source/oauth_provider.rs b/crates/db_schema/src/source/oauth_provider.rs index 75b989805..a70405a5e 100644 --- a/crates/db_schema/src/source/oauth_provider.rs +++ b/crates/db_schema/src/source/oauth_provider.rs @@ -60,6 +60,7 @@ pub struct OAuthProvider { /// switch to enable or disable an oauth provider pub enabled: bool, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, } diff --git a/crates/db_schema/src/source/person.rs b/crates/db_schema/src/source/person.rs index c3aeeb4d7..d8b0a5b1a 100644 --- a/crates/db_schema/src/source/person.rs +++ b/crates/db_schema/src/source/person.rs @@ -22,16 +22,20 @@ pub struct Person { pub id: PersonId, pub name: String, /// A shorter display name. + #[cfg_attr(feature = "full", ts(optional))] pub display_name: Option, /// A URL for an avatar. + #[cfg_attr(feature = "full", ts(optional))] pub avatar: Option, /// Whether the person is banned. pub banned: bool, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, /// The federated actor_id. pub actor_id: DbUrl, /// An optional bio, in markdown. + #[cfg_attr(feature = "full", ts(optional))] pub bio: Option, /// Whether the person is local to our site. pub local: bool, @@ -42,6 +46,7 @@ pub struct Person { #[serde(skip)] pub last_refreshed_at: DateTime, /// A URL for a banner. + #[cfg_attr(feature = "full", ts(optional))] pub banner: Option, /// Whether the person is deleted. pub deleted: bool, @@ -49,10 +54,12 @@ pub struct Person { #[serde(skip, default = "placeholder_apub_url")] pub inbox_url: DbUrl, /// A matrix id, usually given an @person:matrix.org + #[cfg_attr(feature = "full", ts(optional))] pub matrix_user_id: Option, /// Whether the person is a bot account. pub bot_account: bool, /// When their ban, if it exists, expires, if at all. + #[cfg_attr(feature = "full", ts(optional))] pub ban_expires: Option>, pub instance_id: InstanceId, } diff --git a/crates/db_schema/src/source/post.rs b/crates/db_schema/src/source/post.rs index 3819bd773..3417f87b5 100644 --- a/crates/db_schema/src/source/post.rs +++ b/crates/db_schema/src/source/post.rs @@ -17,10 +17,11 @@ use ts_rs::TS; pub struct Post { pub id: PostId, pub name: String, - #[cfg_attr(feature = "full", ts(type = "string"))] /// An optional link / url for the post. + #[cfg_attr(feature = "full", ts(optional))] pub url: Option, /// An optional post body, in markdown. + #[cfg_attr(feature = "full", ts(optional))] pub body: Option, pub creator_id: PersonId, pub community_id: CommunityId, @@ -29,35 +30,40 @@ pub struct Post { /// Whether the post is locked. pub locked: bool, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, /// Whether the post is deleted. pub deleted: bool, /// Whether the post is NSFW. pub nsfw: bool, /// A title for the link. + #[cfg_attr(feature = "full", ts(optional))] pub embed_title: Option, /// A description for the link. + #[cfg_attr(feature = "full", ts(optional))] pub embed_description: Option, - #[cfg_attr(feature = "full", ts(type = "string"))] /// A thumbnail picture url. + #[cfg_attr(feature = "full", ts(optional))] pub thumbnail_url: Option, - #[cfg_attr(feature = "full", ts(type = "string"))] /// The federated activity id / ap_id. pub ap_id: DbUrl, /// Whether the post is local. pub local: bool, - #[cfg_attr(feature = "full", ts(type = "string"))] /// A video url for the link. + #[cfg_attr(feature = "full", ts(optional))] pub embed_video_url: Option, pub language_id: LanguageId, /// Whether the post is featured to its community. pub featured_community: bool, /// Whether the post is featured to its site. pub featured_local: bool, + #[cfg_attr(feature = "full", ts(optional))] pub url_content_type: Option, /// An optional alt_text, usable for image posts. + #[cfg_attr(feature = "full", ts(optional))] pub alt_text: Option, /// Time at which the post will be published. None means publish immediately. + #[cfg_attr(feature = "full", ts(optional))] pub scheduled_publish_time: Option>, } diff --git a/crates/db_schema/src/source/post_report.rs b/crates/db_schema/src/source/post_report.rs index 9aee9ed97..610e495ae 100644 --- a/crates/db_schema/src/source/post_report.rs +++ b/crates/db_schema/src/source/post_report.rs @@ -25,13 +25,17 @@ pub struct PostReport { /// The original post title. pub original_post_name: String, /// The original post url. + #[cfg_attr(feature = "full", ts(optional))] pub original_post_url: Option, /// The original post body. + #[cfg_attr(feature = "full", ts(optional))] pub original_post_body: Option, pub reason: String, pub resolved: bool, + #[cfg_attr(feature = "full", ts(optional))] pub resolver_id: Option, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, } diff --git a/crates/db_schema/src/source/private_message.rs b/crates/db_schema/src/source/private_message.rs index 8afaa14f1..f15373907 100644 --- a/crates/db_schema/src/source/private_message.rs +++ b/crates/db_schema/src/source/private_message.rs @@ -29,6 +29,7 @@ pub struct PrivateMessage { pub deleted: bool, pub read: bool, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, pub ap_id: DbUrl, pub local: bool, diff --git a/crates/db_schema/src/source/private_message_report.rs b/crates/db_schema/src/source/private_message_report.rs index 7b4c8c637..570f55584 100644 --- a/crates/db_schema/src/source/private_message_report.rs +++ b/crates/db_schema/src/source/private_message_report.rs @@ -29,8 +29,10 @@ pub struct PrivateMessageReport { pub original_pm_text: String, pub reason: String, pub resolved: bool, + #[cfg_attr(feature = "full", ts(optional))] pub resolver_id: Option, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, } diff --git a/crates/db_schema/src/source/registration_application.rs b/crates/db_schema/src/source/registration_application.rs index 2ac973f34..f01c042d9 100644 --- a/crates/db_schema/src/source/registration_application.rs +++ b/crates/db_schema/src/source/registration_application.rs @@ -18,7 +18,9 @@ pub struct RegistrationApplication { pub id: RegistrationApplicationId, pub local_user_id: LocalUserId, pub answer: String, + #[cfg_attr(feature = "full", ts(optional))] pub admin_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub deny_reason: Option, pub published: DateTime, } diff --git a/crates/db_schema/src/source/site.rs b/crates/db_schema/src/source/site.rs index 0ec4043e4..0fe33de01 100644 --- a/crates/db_schema/src/source/site.rs +++ b/crates/db_schema/src/source/site.rs @@ -21,14 +21,19 @@ pub struct Site { pub id: SiteId, pub name: String, /// A sidebar for the site in markdown. + #[cfg_attr(feature = "full", ts(optional))] pub sidebar: Option, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, /// An icon URL. + #[cfg_attr(feature = "full", ts(optional))] pub icon: Option, /// A banner url. + #[cfg_attr(feature = "full", ts(optional))] pub banner: Option, /// A shorter, one-line description of the site. + #[cfg_attr(feature = "full", ts(optional))] pub description: Option, /// The federated actor_id. pub actor_id: DbUrl, @@ -43,6 +48,7 @@ pub struct Site { pub instance_id: InstanceId, /// If present, nsfw content is visible by default. Should be displayed by frontends/clients /// when the site is first opened by a user. + #[cfg_attr(feature = "full", ts(optional))] pub content_warning: Option, } diff --git a/crates/db_schema/src/source/tagline.rs b/crates/db_schema/src/source/tagline.rs index 05f7e0520..80c045a0a 100644 --- a/crates/db_schema/src/source/tagline.rs +++ b/crates/db_schema/src/source/tagline.rs @@ -17,6 +17,7 @@ pub struct Tagline { pub id: i32, pub content: String, pub published: DateTime, + #[cfg_attr(feature = "full", ts(optional))] pub updated: Option>, } diff --git a/crates/db_schema/src/utils.rs b/crates/db_schema/src/utils.rs index 1e56563bc..6c5b792eb 100644 --- a/crates/db_schema/src/utils.rs +++ b/crates/db_schema/src/utils.rs @@ -22,7 +22,6 @@ use diesel_async::{ ManagerConfig, }, AsyncConnection, - RunQueryDsl, }; use futures_util::{future::BoxFuture, Future, FutureExt}; use i_love_jesus::CursorKey; @@ -47,7 +46,7 @@ use rustls::{ }; use std::{ ops::{Deref, DerefMut}, - sync::{Arc, LazyLock}, + sync::{Arc, LazyLock, OnceLock}, time::Duration, }; use tracing::error; @@ -59,6 +58,8 @@ pub const SITEMAP_LIMIT: i64 = 50000; pub const SITEMAP_DAYS: Option = TimeDelta::try_days(31); pub const RANK_DEFAULT: f64 = 0.0001; +/// Some connection options to speed up queries +const CONNECTION_OPTIONS: [&str; 1] = ["geqo_threshold=12"]; pub type ActualDbPool = Pool; /// References a pool or connection. Functions must take `&mut DbPool<'_>` to allow implicit @@ -345,10 +346,37 @@ pub fn diesel_url_create(opt: Option<&str>) -> LemmyResult> { } } +/// Sets a few additional config options necessary for starting lemmy +fn build_config_options_uri_segment(config: &str) -> String { + let mut url = Url::parse(config).expect("Couldn't parse postgres connection URI"); + + // Set `lemmy.protocol_and_hostname` so triggers can use it + let lemmy_protocol_and_hostname_option = + "lemmy.protocol_and_hostname=".to_owned() + &SETTINGS.get_protocol_and_hostname(); + let mut options = CONNECTION_OPTIONS.to_vec(); + options.push(&lemmy_protocol_and_hostname_option); + + // Create the connection uri portion + let options_segments = options + .iter() + .map(|o| "-c ".to_owned() + o) + .collect::>() + .join(" "); + + url.set_query(Some(&format!("options={options_segments}"))); + url.into() +} + fn establish_connection(config: &str) -> BoxFuture> { let fut = async { + /// Use a once_lock to create the postgres connection config, since this config never changes + static POSTGRES_CONFIG_WITH_OPTIONS: OnceLock = OnceLock::new(); + + let config = + POSTGRES_CONFIG_WITH_OPTIONS.get_or_init(|| build_config_options_uri_segment(config)); + // We only support TLS with sslmode=require currently - let mut conn = if config.contains("sslmode=require") { + let conn = if config.contains("sslmode=require") { let rustls_config = DangerousClientConfigBuilder { cfg: ClientConfig::builder(), } @@ -369,24 +397,6 @@ fn establish_connection(config: &str) -> BoxFuture = LazyLock::new(|| { }); pub mod functions { - use diesel::sql_types::{BigInt, Bool, Text, Timestamptz}; + use diesel::sql_types::{BigInt, Text, Timestamptz}; sql_function! { #[sql_name = "r.hot_rank"] @@ -521,8 +531,6 @@ pub mod functions { // really this function is variadic, this just adds the two-argument version sql_function!(fn coalesce(x: diesel::sql_types::Nullable, y: T) -> T); - - sql_function!(fn set_config(setting_name: Text, new_value: Text, is_local: Bool) -> Text); } pub const DELETED_REPLACEMENT_TEXT: &str = "*Permanently Deleted*"; diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index 13520f1cf..dc00b0438 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -734,6 +734,7 @@ mod tests { structs::LocalUserView, }; use chrono::Utc; + use diesel_async::SimpleAsyncConnection; use lemmy_db_schema::{ aggregates::structs::PostAggregates, impls::actor_language::UNDETERMINED_ID, @@ -774,7 +775,7 @@ mod tests { site::Site, }, traits::{Bannable, Blockable, Crud, Followable, Joinable, Likeable, Saveable}, - utils::{build_db_pool, build_db_pool_for_tests, DbPool, RANK_DEFAULT}, + utils::{build_db_pool, build_db_pool_for_tests, get_conn, DbPool, RANK_DEFAULT}, CommunityVisibility, PostSortType, SubscribedType, @@ -782,7 +783,10 @@ mod tests { use lemmy_utils::error::LemmyResult; use pretty_assertions::assert_eq; use serial_test::serial; - use std::{collections::HashSet, time::Duration}; + use std::{ + collections::HashSet, + time::{Duration, Instant}, + }; use url::Url; const POST_WITH_ANOTHER_TITLE: &str = "Another title"; @@ -1995,6 +1999,62 @@ mod tests { cleanup(data, pool).await } + #[tokio::test] + #[serial] + async fn speed_check() -> LemmyResult<()> { + let pool = &build_db_pool().await?; + let pool = &mut pool.into(); + let data = init_data(pool).await?; + + // Make sure the post_view query is less than this time + let duration_max = Duration::from_millis(40); + + // Create some dummy posts + let num_posts = 1000; + for x in 1..num_posts { + let name = format!("post_{x}"); + let url = Some(Url::parse(&format!("https://google.com/{name}"))?.into()); + + let post_form = PostInsertForm { + url, + ..PostInsertForm::new( + name, + data.local_user_view.person.id, + data.inserted_community.id, + ) + }; + Post::create(pool, &post_form).await?; + } + + // 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"); + let conn = &mut get_conn(pool).await?; + conn.batch_execute("ANALYZE;").await?; + + // Time how fast the query took + let now = Instant::now(); + PostQuery { + sort: Some(PostSortType::Active), + local_user: Some(&data.local_user_view.local_user), + ..Default::default() + } + .list(&data.site, pool) + .await?; + + let elapsed = now.elapsed(); + println!("Elapsed: {:.0?}", elapsed); + + assert!( + elapsed.lt(&duration_max), + "Query took {:.0?}, longer than the max of {:.0?}", + elapsed, + duration_max + ); + + cleanup(data, pool).await + } + #[tokio::test] #[serial] async fn post_listings_no_comments_only() -> LemmyResult<()> { diff --git a/crates/db_views/src/structs.rs b/crates/db_views/src/structs.rs index 3c219d63f..4586fbcac 100644 --- a/crates/db_views/src/structs.rs +++ b/crates/db_views/src/structs.rs @@ -48,7 +48,9 @@ pub struct CommentReportView { pub creator_blocked: bool, pub subscribed: SubscribedType, pub saved: bool, + #[cfg_attr(feature = "full", ts(optional))] pub my_vote: Option, + #[cfg_attr(feature = "full", ts(optional))] pub resolver: Option, } @@ -71,6 +73,7 @@ pub struct CommentView { pub subscribed: SubscribedType, pub saved: bool, pub creator_blocked: bool, + #[cfg_attr(feature = "full", ts(optional))] pub my_vote: Option, } @@ -106,9 +109,11 @@ pub struct PostReportView { pub read: bool, pub hidden: bool, pub creator_blocked: bool, + #[cfg_attr(feature = "full", ts(optional))] pub my_vote: Option, pub unread_comments: i64, pub counts: PostAggregates, + #[cfg_attr(feature = "full", ts(optional))] pub resolver: Option, } @@ -131,6 +136,7 @@ pub struct PostView { pub post: Post, pub creator: Person, pub community: Community, + #[cfg_attr(feature = "full", ts(optional))] pub image_details: Option, pub creator_banned_from_community: bool, pub banned_from_community: bool, @@ -142,6 +148,7 @@ pub struct PostView { pub read: bool, pub hidden: bool, pub creator_blocked: bool, + #[cfg_attr(feature = "full", ts(optional))] pub my_vote: Option, pub unread_comments: i64, } @@ -168,6 +175,7 @@ pub struct PrivateMessageReportView { pub private_message: PrivateMessage, pub private_message_creator: Person, pub creator: Person, + #[cfg_attr(feature = "full", ts(optional))] pub resolver: Option, } @@ -181,6 +189,7 @@ pub struct RegistrationApplicationView { pub registration_application: RegistrationApplication, pub creator_local_user: LocalUser, pub creator: Person, + #[cfg_attr(feature = "full", ts(optional))] pub admin: Option, } diff --git a/crates/db_views_actor/src/structs.rs b/crates/db_views_actor/src/structs.rs index ecf9ba11d..db5cb1899 100644 --- a/crates/db_views_actor/src/structs.rs +++ b/crates/db_views_actor/src/structs.rs @@ -109,6 +109,7 @@ pub struct PersonMentionView { pub subscribed: SubscribedType, pub saved: bool, pub creator_blocked: bool, + #[cfg_attr(feature = "full", ts(optional))] pub my_vote: Option, } @@ -133,6 +134,7 @@ pub struct CommentReplyView { pub subscribed: SubscribedType, pub saved: bool, pub creator_blocked: bool, + #[cfg_attr(feature = "full", ts(optional))] pub my_vote: Option, } diff --git a/crates/db_views_moderator/src/structs.rs b/crates/db_views_moderator/src/structs.rs index 10ad78942..27ee82522 100644 --- a/crates/db_views_moderator/src/structs.rs +++ b/crates/db_views_moderator/src/structs.rs @@ -39,6 +39,7 @@ use ts_rs::TS; /// When someone is added as a community moderator. pub struct ModAddCommunityView { pub mod_add_community: ModAddCommunity, + #[cfg_attr(feature = "full", ts(optional))] pub moderator: Option, pub community: Community, pub modded_person: Person, @@ -52,6 +53,7 @@ pub struct ModAddCommunityView { /// When someone is added as a site moderator. pub struct ModAddView { pub mod_add: ModAdd, + #[cfg_attr(feature = "full", ts(optional))] pub moderator: Option, pub modded_person: Person, } @@ -64,6 +66,7 @@ pub struct ModAddView { /// When someone is banned from a community. pub struct ModBanFromCommunityView { pub mod_ban_from_community: ModBanFromCommunity, + #[cfg_attr(feature = "full", ts(optional))] pub moderator: Option, pub community: Community, pub banned_person: Person, @@ -77,6 +80,7 @@ pub struct ModBanFromCommunityView { /// When someone is banned from the site. pub struct ModBanView { pub mod_ban: ModBan, + #[cfg_attr(feature = "full", ts(optional))] pub moderator: Option, pub banned_person: Person, } @@ -89,6 +93,7 @@ pub struct ModBanView { /// When a community is hidden from public view. pub struct ModHideCommunityView { pub mod_hide_community: ModHideCommunity, + #[cfg_attr(feature = "full", ts(optional))] pub admin: Option, pub community: Community, } @@ -101,6 +106,7 @@ pub struct ModHideCommunityView { /// When a moderator locks a post (prevents new comments being made). pub struct ModLockPostView { pub mod_lock_post: ModLockPost, + #[cfg_attr(feature = "full", ts(optional))] pub moderator: Option, pub post: Post, pub community: Community, @@ -114,6 +120,7 @@ pub struct ModLockPostView { /// When a moderator removes a comment. pub struct ModRemoveCommentView { pub mod_remove_comment: ModRemoveComment, + #[cfg_attr(feature = "full", ts(optional))] pub moderator: Option, pub comment: Comment, pub commenter: Person, @@ -129,6 +136,7 @@ pub struct ModRemoveCommentView { /// When a moderator removes a community. pub struct ModRemoveCommunityView { pub mod_remove_community: ModRemoveCommunity, + #[cfg_attr(feature = "full", ts(optional))] pub moderator: Option, pub community: Community, } @@ -141,6 +149,7 @@ pub struct ModRemoveCommunityView { /// When a moderator removes a post. pub struct ModRemovePostView { pub mod_remove_post: ModRemovePost, + #[cfg_attr(feature = "full", ts(optional))] pub moderator: Option, pub post: Post, pub community: Community, @@ -154,6 +163,7 @@ pub struct ModRemovePostView { /// When a moderator features a post on a community (pins it to the top). pub struct ModFeaturePostView { pub mod_feature_post: ModFeaturePost, + #[cfg_attr(feature = "full", ts(optional))] pub moderator: Option, pub post: Post, pub community: Community, @@ -167,6 +177,7 @@ pub struct ModFeaturePostView { /// When a moderator transfers a community to a new owner. pub struct ModTransferCommunityView { pub mod_transfer_community: ModTransferCommunity, + #[cfg_attr(feature = "full", ts(optional))] pub moderator: Option, pub community: Community, pub modded_person: Person, @@ -180,6 +191,7 @@ pub struct ModTransferCommunityView { /// When an admin purges a comment. pub struct AdminPurgeCommentView { pub admin_purge_comment: AdminPurgeComment, + #[cfg_attr(feature = "full", ts(optional))] pub admin: Option, pub post: Post, } @@ -192,6 +204,7 @@ pub struct AdminPurgeCommentView { /// When an admin purges a community. pub struct AdminPurgeCommunityView { pub admin_purge_community: AdminPurgeCommunity, + #[cfg_attr(feature = "full", ts(optional))] pub admin: Option, } @@ -203,6 +216,7 @@ pub struct AdminPurgeCommunityView { /// When an admin purges a person. pub struct AdminPurgePersonView { pub admin_purge_person: AdminPurgePerson, + #[cfg_attr(feature = "full", ts(optional))] pub admin: Option, } @@ -214,6 +228,7 @@ pub struct AdminPurgePersonView { /// When an admin purges a post. pub struct AdminPurgePostView { pub admin_purge_post: AdminPurgePost, + #[cfg_attr(feature = "full", ts(optional))] pub admin: Option, pub community: Community, } @@ -225,12 +240,19 @@ pub struct AdminPurgePostView { #[cfg_attr(feature = "full", ts(export))] /// Querying / filtering the modlog. pub struct ModlogListParams { + #[cfg_attr(feature = "full", ts(optional))] pub community_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub mod_person_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub other_person_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub post_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub comment_id: Option, + #[cfg_attr(feature = "full", ts(optional))] pub page: Option, + #[cfg_attr(feature = "full", ts(optional))] pub limit: Option, pub hide_modlog_names: bool, } diff --git a/crates/utils/src/error.rs b/crates/utils/src/error.rs index c95af03e2..75cecc41f 100644 --- a/crates/utils/src/error.rs +++ b/crates/utils/src/error.rs @@ -119,7 +119,10 @@ pub enum LemmyErrorType { InvalidUrl, EmailSendFailed, Slurs, - RegistrationDenied(Option), + RegistrationDenied { + #[cfg_attr(feature = "full", ts(optional))] + reason: Option, + }, SiteNameRequired, SiteNameLengthOverflow, PermissiveRegex, @@ -147,7 +150,10 @@ pub enum LemmyErrorType { CommunityHasNoFollowers, PostScheduleTimeMustBeInFuture, TooManyScheduledPosts, - FederationError(Option), + FederationError { + #[cfg_attr(feature = "full", ts(optional))] + error: Option, + }, } /// Federation related errors, these dont need to be translated. @@ -262,7 +268,7 @@ cfg_if! { fn from(error_type: FederationError) -> Self { let inner = anyhow::anyhow!("{}", error_type); LemmyError { - error_type: LemmyErrorType::FederationError(Some(error_type)), + error_type: LemmyErrorType::FederationError { error: Some(error_type) }, inner, context: Backtrace::capture(), } diff --git a/scripts/start_dev_db.sh b/scripts/start_dev_db.sh index 5965316ba..1cbe9e16a 100644 --- a/scripts/start_dev_db.sh +++ b/scripts/start_dev_db.sh @@ -2,8 +2,12 @@ export PGDATA="$PWD/dev_pgdata" export PGHOST=$PWD + +# Necessary to encode the dev db path into proper URL params +export ENCODED_HOST=$(printf $PWD | jq -sRr @uri) + export PGUSER=postgres -export DATABASE_URL="postgresql://lemmy:password@/lemmy?host=$PWD" +export DATABASE_URL="postgresql://lemmy:password@$ENCODED_HOST/lemmy" export LEMMY_DATABASE_URL=$DATABASE_URL export PGDATABASE=lemmy diff --git a/scripts/ts_bindings_check.sh b/scripts/ts_bindings_check.sh new file mode 100755 index 000000000..a925081c8 --- /dev/null +++ b/scripts/ts_bindings_check.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -e + +# This check is only used for CI. + +CWD="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" + +cd "$CWD/../" + +# Export the ts-rs bindings +cargo test --workspace export_bindings + +# Make sure no rows are returned +! grep -nr --include=\*.ts ' | null' ./crates/