mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-26 14:21:19 +00:00
Merge remote-tracking branch 'origin/main' into remove_success_responses
This commit is contained in:
commit
bb0a2a922e
121 changed files with 1282 additions and 543 deletions
|
@ -73,12 +73,12 @@ steps:
|
|||
when:
|
||||
- event: pull_request
|
||||
|
||||
cargo_machete:
|
||||
cargo_shear:
|
||||
image: *rust_nightly_image
|
||||
commands:
|
||||
- *install_binstall
|
||||
- cargo binstall -y cargo-machete
|
||||
- cargo machete
|
||||
- cargo binstall -y cargo-shear
|
||||
- cargo shear
|
||||
when:
|
||||
- event: pull_request
|
||||
|
||||
|
@ -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
|
||||
|
@ -215,7 +222,7 @@ steps:
|
|||
when: *slow_check_paths
|
||||
|
||||
run_federation_tests:
|
||||
image: node:20-bookworm-slim
|
||||
image: node:22-bookworm-slim
|
||||
environment:
|
||||
LEMMY_DATABASE_URL: postgres://lemmy:password@database:5432
|
||||
DO_WRITE_HOSTS_FILE: "1"
|
||||
|
|
19
Cargo.lock
generated
19
Cargo.lock
generated
|
@ -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"
|
||||
|
@ -2570,7 +2564,6 @@ dependencies = [
|
|||
"futures",
|
||||
"html2md",
|
||||
"html2text",
|
||||
"http 1.1.0",
|
||||
"itertools 0.13.0",
|
||||
"lemmy_api_common",
|
||||
"lemmy_db_schema",
|
||||
|
@ -2815,7 +2808,6 @@ dependencies = [
|
|||
"markdown-it-sup",
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"reqwest 0.12.8",
|
||||
"reqwest-middleware",
|
||||
"rosetta-build",
|
||||
"rosetta-i18n",
|
||||
|
@ -5257,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",
|
||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -24,11 +24,12 @@ doctest = false
|
|||
[lints]
|
||||
workspace = true
|
||||
|
||||
# See https://github.com/johnthagen/min-sized-rust for additional optimizations
|
||||
[profile.release]
|
||||
debug = 0
|
||||
lto = "thin"
|
||||
strip = true # Automatically strip symbols from the binary.
|
||||
opt-level = "z" # Optimize for size.
|
||||
lto = "fat"
|
||||
opt-level = 3 # Optimize for speed, not size.
|
||||
codegen-units = 1 # Reduce parallel code generation.
|
||||
|
||||
# This profile significantly speeds up build time. If debug info is needed you can comment the line
|
||||
# out temporarily, but make sure to leave this in the main branch.
|
||||
|
@ -141,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"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"repository": "https://github.com/LemmyNet/lemmy",
|
||||
"author": "Dessalines",
|
||||
"license": "AGPL-3.0",
|
||||
"packageManager": "pnpm@9.12.0",
|
||||
"packageManager": "pnpm@9.12.3",
|
||||
"scripts": {
|
||||
"lint": "tsc --noEmit && eslint --report-unused-disable-directives && prettier --check 'src/**/*.ts'",
|
||||
"fix": "prettier --write src && eslint --fix src",
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -860,7 +860,7 @@ test("Dont send a comment reply to a blocked community", async () => {
|
|||
|
||||
/// Fetching a deeply nested comment can lead to stack overflow as all parent comments are also
|
||||
/// fetched recursively. Ensure that it works properly.
|
||||
test("Fetch a deeply nested comment", async () => {
|
||||
test.skip("Fetch a deeply nested comment", async () => {
|
||||
let lastComment;
|
||||
for (let i = 0; i < 50; i++) {
|
||||
let commentRes = await createComment(
|
||||
|
|
|
@ -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://yahoo.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";
|
||||
|
|
|
@ -5,10 +5,7 @@ use lemmy_api_common::{
|
|||
request::fetch_link_metadata,
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::{
|
||||
error::{LemmyErrorExt, LemmyResult},
|
||||
LemmyErrorType,
|
||||
};
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
use url::Url;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
|
|
|
@ -31,7 +31,10 @@ use lemmy_db_schema::{
|
|||
RegistrationMode,
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType, CACHE_DURATION_API};
|
||||
use lemmy_utils::{
|
||||
error::{LemmyErrorType, LemmyResult},
|
||||
CACHE_DURATION_API,
|
||||
};
|
||||
use serial_test::serial;
|
||||
|
||||
async fn create_test_site(context: &Data<LemmyContext>) -> LemmyResult<(Instance, LocalUserView)> {
|
||||
|
|
|
@ -14,9 +14,9 @@ async fn generate_urlset(
|
|||
) -> LemmyResult<UrlSet> {
|
||||
let urls = posts
|
||||
.into_iter()
|
||||
.map_while(|post| {
|
||||
Url::builder(post.0.to_string())
|
||||
.last_modified(post.1.into())
|
||||
.map_while(|(url, date_time)| {
|
||||
Url::builder(url.to_string())
|
||||
.last_modified(date_time.into())
|
||||
.build()
|
||||
.ok()
|
||||
})
|
||||
|
|
|
@ -72,7 +72,7 @@ jsonwebtoken = { version = "9.3.0", optional = true }
|
|||
# necessary for wasmt compilation
|
||||
getrandom = { version = "0.2.15", features = ["js"] }
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
[package.metadata.cargo-shear]
|
||||
ignored = ["getrandom"]
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -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<CommentId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub language_id: Option<LanguageId>,
|
||||
}
|
||||
|
||||
|
@ -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<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub language_id: Option<LanguageId>,
|
||||
}
|
||||
|
||||
|
@ -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<String>,
|
||||
}
|
||||
|
||||
|
@ -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<ListingType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sort: Option<CommentSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub max_depth: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub community_id: Option<CommunityId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub community_name: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub post_id: Option<PostId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub parent_id: Option<CommentId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub saved_only: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub liked_only: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub disliked_only: Option<bool>,
|
||||
}
|
||||
|
||||
|
@ -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<CommentId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
/// Only shows the unresolved reports
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub unresolved_only: Option<bool>,
|
||||
/// 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<CommunityId>,
|
||||
}
|
||||
|
||||
|
@ -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<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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<CommunityId>,
|
||||
/// Example: star_trek , or star_trek@xyz.tld
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
|
@ -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<Site>,
|
||||
pub moderators: Vec<CommunityModeratorView>,
|
||||
pub discussion_languages: Vec<LanguageId>,
|
||||
|
@ -48,17 +52,27 @@ pub struct CreateCommunity {
|
|||
pub name: String,
|
||||
/// A longer title.
|
||||
pub title: String,
|
||||
/// A longer sidebar, or description of your community, in markdown.
|
||||
/// A sidebar for the community in markdown.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sidebar: Option<String>,
|
||||
/// A shorter, one line description of your community.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub description: Option<String>,
|
||||
/// An icon URL.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub icon: Option<String>,
|
||||
/// A banner URL.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub banner: Option<String>,
|
||||
/// Whether its an NSFW community.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub nsfw: Option<bool>,
|
||||
/// Whether to restrict posting only to moderators.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub posting_restricted_to_mods: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub discussion_languages: Option<Vec<LanguageId>>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub visibility: Option<CommunityVisibility>,
|
||||
}
|
||||
|
||||
|
@ -77,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<ListingType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sort: Option<CommunitySortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub show_nsfw: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
}
|
||||
|
||||
|
@ -103,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<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub reason: Option<String>,
|
||||
/// 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<i64>,
|
||||
}
|
||||
|
||||
|
@ -146,18 +168,29 @@ pub struct AddModToCommunityResponse {
|
|||
pub struct EditCommunity {
|
||||
pub community_id: CommunityId,
|
||||
/// A longer title.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub title: Option<String>,
|
||||
/// A longer sidebar, or description of your community, in markdown.
|
||||
/// A sidebar for the community in markdown.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sidebar: Option<String>,
|
||||
/// A shorter, one line description of your community.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub description: Option<String>,
|
||||
/// An icon URL.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub icon: Option<String>,
|
||||
/// A banner URL.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub banner: Option<String>,
|
||||
/// Whether its an NSFW community.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub nsfw: Option<bool>,
|
||||
/// Whether to restrict posting only to moderators.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub posting_restricted_to_mods: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub discussion_languages: Option<Vec<LanguageId>>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub visibility: Option<CommunityVisibility>,
|
||||
}
|
||||
|
||||
|
@ -169,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<String>,
|
||||
}
|
||||
|
||||
|
@ -190,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<String>,
|
||||
}
|
||||
|
||||
|
@ -236,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<ListingType>,
|
||||
}
|
||||
|
|
|
@ -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<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub category: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub ignore_page_limits: Option<bool>,
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ pub extern crate lemmy_db_views_actor;
|
|||
pub extern crate lemmy_db_views_moderator;
|
||||
pub extern crate lemmy_utils;
|
||||
|
||||
pub use lemmy_utils::LemmyErrorType;
|
||||
pub use lemmy_utils::error::LemmyErrorType;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{cmp::min, time::Duration};
|
||||
|
||||
|
|
|
@ -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<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub account_linking_enabled: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub enabled: Option<bool>,
|
||||
}
|
||||
|
||||
|
@ -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<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub authorization_endpoint: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub token_endpoint: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub userinfo_endpoint: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub id_claim: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub client_secret: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub scopes: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub auto_verify_email: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub account_linking_enabled: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub enabled: Option<bool>,
|
||||
}
|
||||
|
||||
|
@ -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<bool>,
|
||||
/// Username is mandatory at registration time
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub username: Option<String>,
|
||||
/// An answer is mandatory if require application is enabled on the server
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub answer: Option<String>,
|
||||
}
|
||||
|
|
|
@ -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<String>,
|
||||
}
|
||||
|
||||
|
@ -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<bool>,
|
||||
/// email is mandatory if email verification is enabled on the server
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub email: Option<SensitiveString>,
|
||||
/// The UUID of the captcha item.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub captcha_uuid: Option<String>,
|
||||
/// Your captcha answer.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub captcha_answer: Option<String>,
|
||||
/// A form field to trick signup bots. Should be None.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub honeypot: Option<String>,
|
||||
/// An answer is mandatory if require application is enabled on the server
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub answer: Option<String>,
|
||||
}
|
||||
|
||||
|
@ -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<CaptchaResponse>,
|
||||
}
|
||||
|
||||
|
@ -83,60 +91,89 @@ pub struct CaptchaResponse {
|
|||
/// Saves settings for your user.
|
||||
pub struct SaveUserSettings {
|
||||
/// Show nsfw posts.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub show_nsfw: Option<bool>,
|
||||
/// Blur nsfw posts.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub blur_nsfw: Option<bool>,
|
||||
/// Your user's theme.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub theme: Option<String>,
|
||||
/// The default post listing type, usually "local"
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_listing_type: Option<ListingType>,
|
||||
/// A post-view mode that changes how multiple post listings look.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub post_listing_mode: Option<PostListingMode>,
|
||||
/// The default post sort, usually "active"
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_post_sort_type: Option<PostSortType>,
|
||||
/// The default comment sort, usually "hot"
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_comment_sort_type: Option<CommentSortType>,
|
||||
/// The language of the lemmy interface
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub interface_language: Option<String>,
|
||||
/// A URL for your avatar.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub avatar: Option<String>,
|
||||
/// A URL for your banner.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub banner: Option<String>,
|
||||
/// 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<String>,
|
||||
/// Your email.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub email: Option<SensitiveString>,
|
||||
/// Your bio / info, in markdown.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub bio: Option<String>,
|
||||
/// Your matrix user id. Ex: @my_user:matrix.org
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub matrix_user_id: Option<String>,
|
||||
/// Whether to show or hide avatars.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub show_avatars: Option<bool>,
|
||||
/// Sends notifications to your email.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub send_notifications_to_email: Option<bool>,
|
||||
/// 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<bool>,
|
||||
/// Whether to show bot accounts.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub show_bot_accounts: Option<bool>,
|
||||
/// Whether to show read posts.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub show_read_posts: Option<bool>,
|
||||
/// A list of languages you are able to see discussion in.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub discussion_languages: Option<Vec<LanguageId>>,
|
||||
/// Open links in a new tab
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub open_links_in_new_tab: Option<bool>,
|
||||
/// Enable infinite scroll
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub infinite_scroll_enabled: Option<bool>,
|
||||
/// Whether to allow keyboard navigation (for browsing and interacting with posts and comments).
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub enable_keyboard_navigation: Option<bool>,
|
||||
/// 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<bool>,
|
||||
/// Whether to auto-collapse bot comments.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub collapse_bot_comments: Option<bool>,
|
||||
/// Some vote display mode settings
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub show_scores: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub show_upvotes: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub show_downvotes: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub show_upvote_percentage: Option<bool>,
|
||||
}
|
||||
|
||||
|
@ -158,6 +195,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<SensitiveString>,
|
||||
/// If registration applications are required, this will return true for a signup response.
|
||||
pub registration_created: bool,
|
||||
|
@ -173,13 +211,20 @@ pub struct LoginResponse {
|
|||
///
|
||||
/// Either person_id, or username are required.
|
||||
pub struct GetPersonDetails {
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub person_id: Option<PersonId>,
|
||||
/// Example: dessalines , or dessalines@xyz.tld
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub username: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sort: Option<PostSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub community_id: Option<CommunityId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub saved_only: Option<bool>,
|
||||
}
|
||||
|
||||
|
@ -190,6 +235,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<Site>,
|
||||
pub comments: Vec<CommentView>,
|
||||
pub posts: Vec<PostView>,
|
||||
|
@ -223,11 +269,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<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub reason: Option<String>,
|
||||
/// 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<i64>,
|
||||
}
|
||||
|
||||
|
@ -273,9 +322,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<CommentSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub unread_only: Option<bool>,
|
||||
}
|
||||
|
||||
|
@ -294,9 +347,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<CommentSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub unread_only: Option<bool>,
|
||||
}
|
||||
|
||||
|
@ -375,6 +432,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<CommunityId>,
|
||||
}
|
||||
|
||||
|
@ -384,9 +442,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<CommunityId>,
|
||||
pub comment_reports: i64,
|
||||
pub post_reports: i64,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub private_message_reports: Option<i64>,
|
||||
}
|
||||
|
||||
|
@ -436,7 +496,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<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String>,
|
||||
/// An optional body for the post in markdown.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub body: Option<String>,
|
||||
/// An optional alt_text, usable for image posts.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub alt_text: Option<String>,
|
||||
/// A honeypot to catch bots. Should be None.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub honeypot: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub nsfw: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub language_id: Option<LanguageId>,
|
||||
/// Instead of fetching a thumbnail, use a custom one.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub custom_thumbnail: Option<String>,
|
||||
/// Time when this post should be scheduled. Null means publish immediately.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub scheduled_publish_time: Option<i64>,
|
||||
}
|
||||
|
||||
|
@ -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<PostId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub comment_id: Option<CommentId>,
|
||||
}
|
||||
|
||||
|
@ -70,21 +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<ListingType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sort: Option<PostSortType>,
|
||||
/// DEPRECATED, use page_cursor
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub community_id: Option<CommunityId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub community_name: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub saved_only: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub liked_only: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub disliked_only: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub show_hidden: Option<bool>,
|
||||
/// 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<bool>,
|
||||
/// 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<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
/// If true, then only show posts with no comments
|
||||
pub no_comments_only: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page_cursor: Option<PaginationCursor>,
|
||||
}
|
||||
|
||||
|
@ -96,6 +123,7 @@ pub struct GetPosts {
|
|||
pub struct GetPostsResponse {
|
||||
pub posts: Vec<PostView>,
|
||||
/// the pagination cursor to use to fetch the next page
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub next_page: Option<PaginationCursor>,
|
||||
}
|
||||
|
||||
|
@ -116,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<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub url: Option<String>,
|
||||
/// An optional body for the post in markdown.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub body: Option<String>,
|
||||
/// An optional alt_text, usable for image posts.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub alt_text: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub nsfw: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub language_id: Option<LanguageId>,
|
||||
/// Instead of fetching a thumbnail, use a custom one.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub custom_thumbnail: Option<String>,
|
||||
/// Time when this post should be scheduled. Null means publish immediately.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub scheduled_publish_time: Option<i64>,
|
||||
}
|
||||
|
||||
|
@ -147,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<String>,
|
||||
}
|
||||
|
||||
|
@ -230,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<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
/// Only shows the unresolved reports
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub unresolved_only: Option<bool>,
|
||||
// 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<CommunityId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub post_id: Option<PostId>,
|
||||
}
|
||||
|
||||
|
@ -271,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<String>,
|
||||
}
|
||||
|
||||
|
@ -280,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<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub description: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub(crate) image: Option<DbUrl>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub embed_video_url: Option<DbUrl>,
|
||||
}
|
||||
|
||||
|
@ -293,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<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub creator_id: Option<PersonId>,
|
||||
}
|
||||
|
||||
|
@ -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<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
/// Only shows the unresolved reports
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub unresolved_only: Option<bool>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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<CommunityId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub community_name: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub creator_id: Option<PersonId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub type_: Option<SearchType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sort: Option<PostSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub listing_type: Option<ListingType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub title_only: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub post_url_only: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub saved_only: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub liked_only: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub disliked_only: Option<bool>,
|
||||
}
|
||||
|
||||
|
@ -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<CommentView>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub post: Option<PostView>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub community: Option<CommunityView>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub person: Option<PersonView>,
|
||||
}
|
||||
|
||||
|
@ -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<PersonId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub community_id: Option<CommunityId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub type_: Option<ModlogActionType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub other_person_id: Option<PersonId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub post_id: Option<PostId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub comment_id: Option<CommentId>,
|
||||
}
|
||||
|
||||
|
@ -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<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub description: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub icon: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub banner: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub enable_nsfw: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub community_creation_admin_only: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub require_email_verification: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub application_question: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub private_instance: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_theme: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_post_listing_type: Option<ListingType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_post_listing_mode: Option<PostListingMode>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_post_sort_type: Option<PostSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_comment_sort_type: Option<CommentSortType>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub legal_information: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub application_email_admins: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub hide_modlog_mod_names: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub discussion_languages: Option<Vec<LanguageId>>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub slur_filter_regex: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub actor_name_max_length: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_message: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_message_per_second: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_post: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_post_per_second: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_register: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_register_per_second: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_image: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_image_per_second: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_comment: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_comment_per_second: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_search: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_search_per_second: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub federation_enabled: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub federation_debug: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub captcha_enabled: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub captcha_difficulty: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub allowed_instances: Option<Vec<String>>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub blocked_instances: Option<Vec<String>>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub registration_mode: Option<RegistrationMode>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub oauth_registration: Option<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub content_warning: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub post_upvotes: Option<FederationMode>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub post_downvotes: Option<FederationMode>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub comment_upvotes: Option<FederationMode>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub comment_downvotes: Option<FederationMode>,
|
||||
}
|
||||
|
||||
|
@ -220,93 +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<String>,
|
||||
/// A sidebar for the site, in markdown.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sidebar: Option<String>,
|
||||
/// A shorter, one line description of your site.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub description: Option<String>,
|
||||
/// A url for your site's icon.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub icon: Option<String>,
|
||||
/// A url for your site's banner.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub banner: Option<String>,
|
||||
/// Whether to enable NSFW.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub enable_nsfw: Option<bool>,
|
||||
/// Limits community creation to admins only.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub community_creation_admin_only: Option<bool>,
|
||||
/// Whether to require email verification.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub require_email_verification: Option<bool>,
|
||||
/// Your application question form. This is in markdown, and can be many questions.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub application_question: Option<String>,
|
||||
/// Whether your instance is public, or private.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub private_instance: Option<bool>,
|
||||
/// The default theme. Usually "browser"
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_theme: Option<String>,
|
||||
/// The default post listing type, usually "local"
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_post_listing_type: Option<ListingType>,
|
||||
/// Default value for listing mode, usually "list"
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_post_listing_mode: Option<PostListingMode>,
|
||||
/// The default post sort, usually "active"
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_post_sort_type: Option<PostSortType>,
|
||||
/// The default comment sort, usually "hot"
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub default_comment_sort_type: Option<CommentSortType>,
|
||||
/// An optional page of legal information
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub legal_information: Option<String>,
|
||||
/// Whether to email admins when receiving a new application.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub application_email_admins: Option<bool>,
|
||||
/// Whether to hide moderator names from the modlog.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub hide_modlog_mod_names: Option<bool>,
|
||||
/// A list of allowed discussion languages.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub discussion_languages: Option<Vec<LanguageId>>,
|
||||
/// A regex string of items to filter.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub slur_filter_regex: Option<String>,
|
||||
/// The max length of actor names.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub actor_name_max_length: Option<i32>,
|
||||
/// The number of messages allowed in a given time frame.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_message: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_message_per_second: Option<i32>,
|
||||
/// The number of posts allowed in a given time frame.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_post: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_post_per_second: Option<i32>,
|
||||
/// The number of registrations allowed in a given time frame.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_register: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_register_per_second: Option<i32>,
|
||||
/// The number of image uploads allowed in a given time frame.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_image: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_image_per_second: Option<i32>,
|
||||
/// The number of comments allowed in a given time frame.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_comment: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_comment_per_second: Option<i32>,
|
||||
/// The number of searches allowed in a given time frame.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_search: Option<i32>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub rate_limit_search_per_second: Option<i32>,
|
||||
/// Whether to enable federation.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub federation_enabled: Option<bool>,
|
||||
/// Enables federation debugging.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub federation_debug: Option<bool>,
|
||||
/// Whether to enable captchas for signups.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub captcha_enabled: Option<bool>,
|
||||
/// The captcha difficulty. Can be easy, medium, or hard
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub captcha_difficulty: Option<String>,
|
||||
/// A list of allowed instances. If none are set, federation is open.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub allowed_instances: Option<Vec<String>>,
|
||||
/// A list of blocked instances.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub blocked_instances: Option<Vec<String>>,
|
||||
/// A list of blocked URLs
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub blocked_urls: Option<Vec<String>>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub registration_mode: Option<RegistrationMode>,
|
||||
/// Whether to email admins for new reports.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub reports_email_admins: Option<bool>,
|
||||
/// 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<String>,
|
||||
/// Whether or not external auth methods can auto-register users.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub oauth_registration: Option<bool>,
|
||||
/// What kind of post upvotes your site allows.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub post_upvotes: Option<FederationMode>,
|
||||
/// What kind of post downvotes your site allows.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub post_downvotes: Option<FederationMode>,
|
||||
/// What kind of comment upvotes your site allows.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub comment_upvotes: Option<FederationMode>,
|
||||
/// What kind of comment downvotes your site allows.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub comment_downvotes: Option<FederationMode>,
|
||||
}
|
||||
|
||||
|
@ -329,6 +448,7 @@ pub struct GetSiteResponse {
|
|||
pub site_view: SiteView,
|
||||
pub admins: Vec<PersonView>,
|
||||
pub version: String,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub my_user: Option<MyUserInfo>,
|
||||
pub all_languages: Vec<Language>,
|
||||
pub discussion_languages: Vec<LanguageId>,
|
||||
|
@ -337,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<Tagline>,
|
||||
/// A list of external auth methods your site supports.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub oauth_providers: Option<Vec<PublicOAuthProvider>>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub admin_oauth_providers: Option<Vec<OAuthProvider>>,
|
||||
pub blocked_urls: Vec<LocalSiteUrlBlocklist>,
|
||||
}
|
||||
|
@ -351,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<FederatedInstances>,
|
||||
}
|
||||
|
||||
|
@ -386,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<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
|
@ -410,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<ReadableFederationState>,
|
||||
}
|
||||
|
||||
|
@ -420,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<String>,
|
||||
}
|
||||
|
||||
|
@ -430,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<String>,
|
||||
}
|
||||
|
||||
|
@ -440,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<String>,
|
||||
}
|
||||
|
||||
|
@ -450,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<String>,
|
||||
}
|
||||
|
||||
|
@ -460,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<bool>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub page: Option<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
}
|
||||
|
||||
|
@ -490,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<String>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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<i64>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub limit: Option<i64>,
|
||||
}
|
||||
|
|
|
@ -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)?
|
||||
}
|
||||
|
@ -1110,7 +1112,7 @@ async fn proxy_image_link_internal(
|
|||
|
||||
/// Rewrite a link to go through `/api/v3/image_proxy` endpoint. This is only for remote urls and
|
||||
/// if image_proxy setting is enabled.
|
||||
pub(crate) async fn proxy_image_link(link: Url, context: &LemmyContext) -> LemmyResult<DbUrl> {
|
||||
pub async fn proxy_image_link(link: Url, context: &LemmyContext) -> LemmyResult<DbUrl> {
|
||||
proxy_image_link_internal(
|
||||
link,
|
||||
context.settings().pictrs_config()?.image_mode(),
|
||||
|
|
|
@ -34,5 +34,5 @@ serde_json = { workspace = true }
|
|||
serde = { workspace = true }
|
||||
serde_with = { workspace = true }
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
[package.metadata.cargo-shear]
|
||||
ignored = ["futures"]
|
||||
|
|
|
@ -36,7 +36,11 @@ use lemmy_utils::{
|
|||
error::{LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||
utils::{
|
||||
slurs::check_slurs,
|
||||
validation::{is_valid_actor_name, is_valid_body_field},
|
||||
validation::{
|
||||
is_valid_actor_name,
|
||||
is_valid_body_field,
|
||||
site_or_community_description_length_check,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -57,8 +61,18 @@ pub async fn create_community(
|
|||
let url_blocklist = get_url_blocklist(&context).await?;
|
||||
check_slurs(&data.name, &slur_regex)?;
|
||||
check_slurs(&data.title, &slur_regex)?;
|
||||
let description =
|
||||
process_markdown_opt(&data.description, &slur_regex, &url_blocklist, &context).await?;
|
||||
let sidebar = process_markdown_opt(&data.sidebar, &slur_regex, &url_blocklist, &context).await?;
|
||||
|
||||
// Ensure that the sidebar has fewer than the max num characters...
|
||||
if let Some(sidebar) = &sidebar {
|
||||
is_valid_body_field(sidebar, false)?;
|
||||
}
|
||||
|
||||
let description = data.description.clone();
|
||||
if let Some(desc) = &description {
|
||||
site_or_community_description_length_check(desc)?;
|
||||
check_slurs(desc, &slur_regex)?;
|
||||
}
|
||||
|
||||
let icon = diesel_url_create(data.icon.as_deref())?;
|
||||
let icon = proxy_image_link_api(icon, &context).await?;
|
||||
|
@ -68,10 +82,6 @@ pub async fn create_community(
|
|||
|
||||
is_valid_actor_name(&data.name, local_site.actor_name_max_length as usize)?;
|
||||
|
||||
if let Some(desc) = &data.description {
|
||||
is_valid_body_field(desc, false)?;
|
||||
}
|
||||
|
||||
// Double check for duplicate community actor_ids
|
||||
let community_actor_id = generate_local_apub_endpoint(
|
||||
EndpointType::Community,
|
||||
|
@ -88,6 +98,7 @@ pub async fn create_community(
|
|||
let keypair = generate_actor_keypair()?;
|
||||
|
||||
let community_form = CommunityInsertForm {
|
||||
sidebar,
|
||||
description,
|
||||
icon,
|
||||
banner,
|
||||
|
|
|
@ -41,16 +41,18 @@ pub async fn update_community(
|
|||
let url_blocklist = get_url_blocklist(&context).await?;
|
||||
check_slurs_opt(&data.title, &slur_regex)?;
|
||||
|
||||
let description = diesel_string_update(
|
||||
process_markdown_opt(&data.description, &slur_regex, &url_blocklist, &context)
|
||||
let sidebar = diesel_string_update(
|
||||
process_markdown_opt(&data.sidebar, &slur_regex, &url_blocklist, &context)
|
||||
.await?
|
||||
.as_deref(),
|
||||
);
|
||||
|
||||
if let Some(Some(desc)) = &description {
|
||||
is_valid_body_field(desc, false)?;
|
||||
if let Some(Some(sidebar)) = &sidebar {
|
||||
is_valid_body_field(sidebar, false)?;
|
||||
}
|
||||
|
||||
let description = diesel_string_update(data.description.as_deref());
|
||||
|
||||
let old_community = Community::read(&mut context.pool(), data.community_id).await?;
|
||||
|
||||
let icon = diesel_url_update(data.icon.as_deref())?;
|
||||
|
@ -84,6 +86,7 @@ pub async fn update_community(
|
|||
|
||||
let community_form = CommunityUpdateForm {
|
||||
title: data.title.clone(),
|
||||
sidebar,
|
||||
description,
|
||||
icon,
|
||||
banner,
|
||||
|
|
|
@ -2,7 +2,7 @@ use chrono::{DateTime, TimeZone, Utc};
|
|||
use lemmy_api_common::context::LemmyContext;
|
||||
use lemmy_db_schema::source::post::Post;
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
|
||||
pub mod create;
|
||||
pub mod delete;
|
||||
|
|
|
@ -29,13 +29,13 @@ use lemmy_db_views::structs::{LocalUserView, SiteView};
|
|||
use lemmy_utils::{
|
||||
error::{LemmyErrorType, LemmyResult},
|
||||
utils::{
|
||||
slurs::{check_slurs, check_slurs_opt},
|
||||
slurs::check_slurs,
|
||||
validation::{
|
||||
build_and_check_regex,
|
||||
check_site_visibility_valid,
|
||||
is_valid_body_field,
|
||||
site_description_length_check,
|
||||
site_name_length_check,
|
||||
site_or_community_description_length_check,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -167,8 +167,8 @@ fn validate_create_payload(local_site: &LocalSite, create_site: &CreateSite) ->
|
|||
check_slurs(&create_site.name, &slur_regex)?;
|
||||
|
||||
if let Some(desc) = &create_site.description {
|
||||
site_description_length_check(desc)?;
|
||||
check_slurs_opt(&create_site.description, &slur_regex)?;
|
||||
site_or_community_description_length_check(desc)?;
|
||||
check_slurs(desc, &slur_regex)?;
|
||||
}
|
||||
|
||||
site_default_post_listing_type_check(&create_site.default_post_listing_type)?;
|
||||
|
|
|
@ -40,8 +40,8 @@ use lemmy_utils::{
|
|||
check_site_visibility_valid,
|
||||
check_urls_are_valid,
|
||||
is_valid_body_field,
|
||||
site_description_length_check,
|
||||
site_name_length_check,
|
||||
site_or_community_description_length_check,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -219,7 +219,7 @@ fn validate_update_payload(local_site: &LocalSite, edit_site: &EditSite) -> Lemm
|
|||
}
|
||||
|
||||
if let Some(desc) = &edit_site.description {
|
||||
site_description_length_check(desc)?;
|
||||
site_or_community_description_length_check(desc)?;
|
||||
check_slurs_opt(&edit_site.description, &slur_regex)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ tokio = { workspace = true }
|
|||
tracing = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
url = { workspace = true }
|
||||
http = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
"type": "Group",
|
||||
"preferredUsername": "tenforward",
|
||||
"name": "Ten Forward",
|
||||
"summary": "<p>Lounge and recreation facility</p>\n<hr />\n<p>Welcome to the Enterprise!.</p>\n",
|
||||
"summary": "A description of ten forward.",
|
||||
"content": "<p>Lounge and recreation facility</p>\n<hr />\n<p>Welcome to the Enterprise!.</p>\n",
|
||||
"source": {
|
||||
"content": "Lounge and recreation facility\n\n---\n\nWelcome to the Enterprise!",
|
||||
"mediaType": "text/markdown"
|
||||
},
|
||||
"mediaType": "text/html",
|
||||
"sensitive": false,
|
||||
"icon": {
|
||||
"type": "Image",
|
||||
|
|
79
crates/apub/assets/mastodon/objects/note_2.json
Normal file
79
crates/apub/assets/mastodon/objects/note_2.json
Normal file
|
@ -0,0 +1,79 @@
|
|||
{
|
||||
"@context": [
|
||||
"https://www.w3.org/ns/activitystreams",
|
||||
{
|
||||
"ostatus": "http://ostatus.org#",
|
||||
"atomUri": "ostatus:atomUri",
|
||||
"inReplyToAtomUri": "ostatus:inReplyToAtomUri",
|
||||
"conversation": "ostatus:conversation",
|
||||
"sensitive": "as:sensitive",
|
||||
"toot": "http://joinmastodon.org/ns#",
|
||||
"votersCount": "toot:votersCount",
|
||||
"blurhash": "toot:blurhash",
|
||||
"focalPoint": {
|
||||
"@container": "@list",
|
||||
"@id": "toot:focalPoint"
|
||||
}
|
||||
}
|
||||
],
|
||||
"id": "https://floss.social/users/kde/statuses/113306831140126616",
|
||||
"type": "Note",
|
||||
"summary": null,
|
||||
"inReplyTo": "https://floss.social/users/kde/statuses/113306824627995724",
|
||||
"published": "2024-10-14T16:57:15Z",
|
||||
"url": "https://floss.social/@kde/113306831140126616",
|
||||
"attributedTo": "https://floss.social/users/kde",
|
||||
"to": ["https://www.w3.org/ns/activitystreams#Public"],
|
||||
"cc": [
|
||||
"https://floss.social/users/kde/followers",
|
||||
"https://lemmy.kde.social/c/kde",
|
||||
"https://lemmy.kde.social/c/kde/followers"
|
||||
],
|
||||
"sensitive": false,
|
||||
"atomUri": "https://floss.social/users/kde/statuses/113306831140126616",
|
||||
"inReplyToAtomUri": "https://floss.social/users/kde/statuses/113306824627995724",
|
||||
"conversation": "tag:floss.social,2024-10-14:objectId=71424279:objectType=Conversation",
|
||||
"content": "<p><span class=\"h-card\" translate=\"no\"><a href=\"https://lemmy.kde.social/c/kde\" class=\"u-url mention\">@<span>kde@lemmy.kde.social</span></a></span> </p><p>We also need funding 💶 to keep the gears turning! Please support us with a donation:</p><p><a href=\"https://kde.org/donate/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"\">kde.org/donate/</span><span class=\"invisible\"></span></a></p><p>[3/3]</p>",
|
||||
"contentMap": {
|
||||
"en": "<p><span class=\"h-card\" translate=\"no\"><a href=\"https://lemmy.kde.social/c/kde\" class=\"u-url mention\">@<span>kde@lemmy.kde.social</span></a></span> </p><p>We also need funding 💶 to keep the gears turning! Please support us with a donation:</p><p><a href=\"https://kde.org/donate/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" translate=\"no\"><span class=\"invisible\">https://</span><span class=\"\">kde.org/donate/</span><span class=\"invisible\"></span></a></p><p>[3/3]</p>"
|
||||
},
|
||||
"attachment": [
|
||||
{
|
||||
"type": "Document",
|
||||
"mediaType": "image/jpeg",
|
||||
"url": "https://cdn.masto.host/floss/media_attachments/files/113/306/826/682/985/891/original/c8d906a2f2ab2334.jpg",
|
||||
"name": "The KDE dragons Katie and Konqi stand on either side of a pot filling up with gold coins. Donate!",
|
||||
"blurhash": "USQv:h-W-qI-^,W;RPs=^-R%NZxbo#sDobSc",
|
||||
"focalPoint": [0.0, 0.0],
|
||||
"width": 1500,
|
||||
"height": 1095
|
||||
}
|
||||
],
|
||||
"tag": [
|
||||
{
|
||||
"type": "Mention",
|
||||
"href": "https://lemmy.kde.social/c/kde",
|
||||
"name": "@kde@lemmy.kde.social"
|
||||
}
|
||||
],
|
||||
"replies": {
|
||||
"id": "https://floss.social/users/kde/statuses/113306831140126616/replies",
|
||||
"type": "Collection",
|
||||
"first": {
|
||||
"type": "CollectionPage",
|
||||
"next": "https://floss.social/users/kde/statuses/113306831140126616/replies?only_other_accounts=true&page=true",
|
||||
"partOf": "https://floss.social/users/kde/statuses/113306831140126616/replies",
|
||||
"items": []
|
||||
}
|
||||
},
|
||||
"likes": {
|
||||
"id": "https://floss.social/users/kde/statuses/113306831140126616/likes",
|
||||
"type": "Collection",
|
||||
"totalItems": 39
|
||||
},
|
||||
"shares": {
|
||||
"id": "https://floss.social/users/kde/statuses/113306831140126616/shares",
|
||||
"type": "Collection",
|
||||
"totalItems": 24
|
||||
}
|
||||
}
|
|
@ -39,10 +39,7 @@ use lemmy_db_schema::{
|
|||
},
|
||||
traits::{Bannable, Crud, Followable},
|
||||
};
|
||||
use lemmy_utils::{
|
||||
error::{LemmyError, LemmyResult},
|
||||
LemmyErrorType,
|
||||
};
|
||||
use lemmy_utils::error::{FederationError, LemmyError, LemmyResult};
|
||||
use url::Url;
|
||||
|
||||
impl BlockUser {
|
||||
|
@ -135,7 +132,7 @@ impl ActivityHandler for BlockUser {
|
|||
.object
|
||||
.inner()
|
||||
.domain()
|
||||
.ok_or(LemmyErrorType::UrlWithoutDomain)?;
|
||||
.ok_or(FederationError::UrlWithoutDomain)?;
|
||||
if context.settings().hostname == domain {
|
||||
return Err(
|
||||
anyhow!("Site bans from remote instance can't affect user's home instance").into(),
|
||||
|
|
|
@ -26,7 +26,7 @@ use lemmy_db_schema::{
|
|||
source::{activity::ActivitySendTargets, community::CommunityFollower},
|
||||
CommunityVisibility,
|
||||
};
|
||||
use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult};
|
||||
use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorType, LemmyResult};
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
|
||||
|
@ -54,7 +54,7 @@ impl ActivityHandler for RawAnnouncableActivities {
|
|||
|
||||
// This is only for sending, not receiving so we reject it.
|
||||
if let AnnouncableActivities::Page(_) = activity {
|
||||
Err(LemmyErrorType::CannotReceivePage)?
|
||||
Err(FederationError::CannotReceivePage)?
|
||||
}
|
||||
|
||||
// Need to treat community as optional here because `Delete/PrivateMessage` gets routed through
|
||||
|
@ -165,7 +165,7 @@ impl ActivityHandler for AnnounceActivity {
|
|||
|
||||
// This is only for sending, not receiving so we reject it.
|
||||
if let AnnouncableActivities::Page(_) = object {
|
||||
Err(LemmyErrorType::CannotReceivePage)?
|
||||
Err(FederationError::CannotReceivePage)?
|
||||
}
|
||||
|
||||
let community = object.community(context).await?;
|
||||
|
|
|
@ -27,7 +27,7 @@ use lemmy_db_schema::{
|
|||
},
|
||||
traits::{Crud, Reportable},
|
||||
};
|
||||
use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult};
|
||||
use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorType, LemmyResult};
|
||||
use url::Url;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
|
@ -118,7 +118,7 @@ pub(in crate::activities) async fn receive_remove_action(
|
|||
match DeletableObjects::read_from_db(object, context).await? {
|
||||
DeletableObjects::Community(community) => {
|
||||
if community.local {
|
||||
Err(LemmyErrorType::OnlyLocalAdminCanRemoveCommunity)?
|
||||
Err(FederationError::OnlyLocalAdminCanRemoveCommunity)?
|
||||
}
|
||||
let form = ModRemoveCommunityForm {
|
||||
mod_person_id: actor.id,
|
||||
|
|
|
@ -25,7 +25,7 @@ use lemmy_db_schema::{
|
|||
},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult};
|
||||
use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorType, LemmyResult};
|
||||
use url::Url;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
|
@ -100,7 +100,7 @@ impl UndoDelete {
|
|||
match DeletableObjects::read_from_db(object, context).await? {
|
||||
DeletableObjects::Community(community) => {
|
||||
if community.local {
|
||||
Err(LemmyErrorType::OnlyLocalAdminCanRestoreCommunity)?
|
||||
Err(FederationError::OnlyLocalAdminCanRestoreCommunity)?
|
||||
}
|
||||
let form = ModRemoveCommunityForm {
|
||||
mod_person_id: actor.id,
|
||||
|
|
|
@ -42,7 +42,7 @@ use lemmy_db_schema::{
|
|||
traits::Crud,
|
||||
};
|
||||
use lemmy_db_views_actor::structs::{CommunityPersonBanView, CommunityView};
|
||||
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
use serde::Serialize;
|
||||
use tracing::info;
|
||||
use url::{ParseError, Url};
|
||||
|
@ -81,7 +81,7 @@ pub(crate) async fn verify_person_in_community(
|
|||
) -> LemmyResult<()> {
|
||||
let person = person_id.dereference(context).await?;
|
||||
if person.banned {
|
||||
Err(LemmyErrorType::PersonIsBannedFromSite(
|
||||
Err(FederationError::PersonIsBannedFromSite(
|
||||
person.actor_id.to_string(),
|
||||
))?
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ pub(crate) async fn verify_mod_action(
|
|||
|
||||
pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> LemmyResult<()> {
|
||||
if ![to, cc].iter().any(|set| set.contains(&public())) {
|
||||
Err(LemmyErrorType::ObjectIsNotPublic)?
|
||||
Err(FederationError::ObjectIsNotPublic)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ where
|
|||
{
|
||||
let b: ObjectId<ApubCommunity> = b.into();
|
||||
if a != &b {
|
||||
Err(LemmyErrorType::InvalidCommunity)?
|
||||
Err(FederationError::InvalidCommunity)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ where
|
|||
|
||||
pub(crate) fn check_community_deleted_or_removed(community: &Community) -> LemmyResult<()> {
|
||||
if community.deleted || community.removed {
|
||||
Err(LemmyErrorType::CannotCreatePostOrCommentInDeletedOrRemovedCommunity)?
|
||||
Err(FederationError::CannotCreatePostOrCommentInDeletedOrRemovedCommunity)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ use crate::{
|
|||
};
|
||||
use activitypub_federation::{config::Data, traits::ActivityHandler};
|
||||
use lemmy_api_common::context::LemmyContext;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ pub async fn list_posts(
|
|||
let show_hidden = data.show_hidden;
|
||||
let show_read = data.show_read;
|
||||
let show_nsfw = data.show_nsfw;
|
||||
let no_comments_only = data.no_comments_only;
|
||||
|
||||
let liked_only = data.liked_only;
|
||||
let disliked_only = data.disliked_only;
|
||||
|
@ -82,6 +83,7 @@ pub async fn list_posts(
|
|||
show_hidden,
|
||||
show_read,
|
||||
show_nsfw,
|
||||
no_comments_only,
|
||||
..Default::default()
|
||||
}
|
||||
.list(&local_site.site, &mut context.pool())
|
||||
|
|
|
@ -86,7 +86,7 @@ mod tests {
|
|||
traits::Crud,
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
use serial_test::serial;
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
@ -26,7 +26,7 @@ pub enum PostOrComment {
|
|||
#[serde(untagged)]
|
||||
pub enum PageOrNote {
|
||||
Page(Box<Page>),
|
||||
Note(Note),
|
||||
Note(Box<Note>),
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
|
@ -61,7 +61,7 @@ impl Object for PostOrComment {
|
|||
async fn into_json(self, data: &Data<Self::DataType>) -> LemmyResult<Self::Kind> {
|
||||
Ok(match self {
|
||||
PostOrComment::Post(p) => PageOrNote::Page(Box::new(p.into_json(data).await?)),
|
||||
PostOrComment::Comment(c) => PageOrNote::Note(c.into_json(data).await?),
|
||||
PostOrComment::Comment(c) => PageOrNote::Note(Box::new(c.into_json(data).await?)),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ impl Object for PostOrComment {
|
|||
async fn from_json(apub: PageOrNote, context: &Data<LemmyContext>) -> LemmyResult<Self> {
|
||||
Ok(match apub {
|
||||
PageOrNote::Page(p) => PostOrComment::Post(ApubPost::from_json(*p, context).await?),
|
||||
PageOrNote::Note(n) => PostOrComment::Comment(ApubComment::from_json(n, context).await?),
|
||||
PageOrNote::Note(n) => PostOrComment::Comment(ApubComment::from_json(*n, context).await?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use activitypub_federation::{
|
|||
use actix_web::{web, HttpResponse};
|
||||
use lemmy_api_common::context::LemmyContext;
|
||||
use lemmy_db_schema::{source::community::Community, traits::ApubActor};
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
|
|
|
@ -17,7 +17,7 @@ use lemmy_db_schema::{
|
|||
source::{activity::SentActivity, community::Community},
|
||||
CommunityVisibility,
|
||||
};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
use lemmy_utils::error::{FederationError, LemmyErrorType, LemmyResult};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{ops::Deref, time::Duration};
|
||||
use tokio::time::timeout;
|
||||
|
@ -45,7 +45,7 @@ pub async fn shared_inbox(
|
|||
// consider the activity broken and move on.
|
||||
timeout(INCOMING_ACTIVITY_TIMEOUT, receive_fut)
|
||||
.await
|
||||
.map_err(|_| LemmyErrorType::InboxTimeout)?
|
||||
.map_err(|_| FederationError::InboxTimeout)?
|
||||
}
|
||||
|
||||
/// Convert the data to json and turn it into an HTTP Response with the correct ActivityPub
|
||||
|
@ -106,7 +106,9 @@ pub(crate) async fn get_activity(
|
|||
info.id
|
||||
))?
|
||||
.into();
|
||||
let activity = SentActivity::read_from_apub_id(&mut context.pool(), &activity_id).await?;
|
||||
let activity = SentActivity::read_from_apub_id(&mut context.pool(), &activity_id)
|
||||
.await
|
||||
.map_err(|_| FederationError::CouldntFindActivity)?;
|
||||
|
||||
let sensitive = activity.sensitive;
|
||||
if sensitive {
|
||||
|
|
|
@ -7,7 +7,7 @@ use activitypub_federation::{config::Data, traits::Object};
|
|||
use actix_web::{web, HttpResponse};
|
||||
use lemmy_api_common::{context::LemmyContext, utils::generate_outbox_url};
|
||||
use lemmy_db_schema::{source::person::Person, traits::ApubActor};
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_db_schema::{
|
|||
utils::{ActualDbPool, DbPool},
|
||||
};
|
||||
use lemmy_utils::{
|
||||
error::{LemmyError, LemmyErrorType, LemmyResult},
|
||||
error::{FederationError, LemmyError, LemmyErrorType, LemmyResult},
|
||||
CACHE_DURATION_FEDERATION,
|
||||
};
|
||||
use moka::future::Cache;
|
||||
|
@ -51,17 +51,27 @@ impl UrlVerifier for VerifyUrlData {
|
|||
let local_site_data = local_site_data_cached(&mut (&self.0).into())
|
||||
.await
|
||||
.expect("read local site data");
|
||||
use FederationError::*;
|
||||
check_apub_id_valid(url, &local_site_data).map_err(|err| match err {
|
||||
LemmyError {
|
||||
error_type: LemmyErrorType::FederationDisabled,
|
||||
error_type:
|
||||
LemmyErrorType::FederationError {
|
||||
error: Some(FederationDisabled),
|
||||
},
|
||||
..
|
||||
} => ActivityPubError::Other("Federation disabled".into()),
|
||||
LemmyError {
|
||||
error_type: LemmyErrorType::DomainBlocked(domain),
|
||||
error_type:
|
||||
LemmyErrorType::FederationError {
|
||||
error: Some(DomainBlocked(domain)),
|
||||
},
|
||||
..
|
||||
} => ActivityPubError::Other(format!("Domain {domain:?} is blocked")),
|
||||
LemmyError {
|
||||
error_type: LemmyErrorType::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()),
|
||||
|
@ -81,7 +91,7 @@ impl UrlVerifier for VerifyUrlData {
|
|||
fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> LemmyResult<()> {
|
||||
let domain = apub_id
|
||||
.domain()
|
||||
.ok_or(LemmyErrorType::UrlWithoutDomain)?
|
||||
.ok_or(FederationError::UrlWithoutDomain)?
|
||||
.to_string();
|
||||
|
||||
if !local_site_data
|
||||
|
@ -90,7 +100,7 @@ fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> LemmyR
|
|||
.map(|l| l.federation_enabled)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
Err(LemmyErrorType::FederationDisabled)?
|
||||
Err(FederationError::FederationDisabled)?
|
||||
}
|
||||
|
||||
if local_site_data
|
||||
|
@ -98,7 +108,7 @@ fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> LemmyR
|
|||
.iter()
|
||||
.any(|i| domain.to_lowercase().eq(&i.domain.to_lowercase()))
|
||||
{
|
||||
Err(LemmyErrorType::DomainBlocked(domain.clone()))?
|
||||
Err(FederationError::DomainBlocked(domain.clone()))?
|
||||
}
|
||||
|
||||
// Only check this if there are instances in the allowlist
|
||||
|
@ -108,7 +118,7 @@ fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> LemmyR
|
|||
.iter()
|
||||
.any(|i| domain.to_lowercase().eq(&i.domain.to_lowercase()))
|
||||
{
|
||||
Err(LemmyErrorType::DomainNotInAllowList(domain))?
|
||||
Err(FederationError::DomainNotInAllowList(domain))?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -164,7 +174,7 @@ pub(crate) async fn check_apub_id_valid_with_strictness(
|
|||
) -> LemmyResult<()> {
|
||||
let domain = apub_id
|
||||
.domain()
|
||||
.ok_or(LemmyErrorType::UrlWithoutDomain)?
|
||||
.ok_or(FederationError::UrlWithoutDomain)?
|
||||
.to_string();
|
||||
let local_instance = context
|
||||
.settings()
|
||||
|
@ -194,10 +204,10 @@ pub(crate) async fn check_apub_id_valid_with_strictness(
|
|||
|
||||
let domain = apub_id
|
||||
.domain()
|
||||
.ok_or(LemmyErrorType::UrlWithoutDomain)?
|
||||
.ok_or(FederationError::UrlWithoutDomain)?
|
||||
.to_string();
|
||||
if !allowed_and_local.contains(&domain) {
|
||||
Err(LemmyErrorType::FederationDisabledByStrictAllowList)?
|
||||
Err(FederationError::FederationDisabledByStrictAllowList)?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -11,7 +11,10 @@ use lemmy_db_schema::{
|
|||
traits::Crud,
|
||||
utils::DbPool,
|
||||
};
|
||||
use lemmy_utils::{error::LemmyResult, utils::mention::scrape_text_for_mentions, LemmyErrorType};
|
||||
use lemmy_utils::{
|
||||
error::{FederationError, LemmyResult},
|
||||
utils::mention::scrape_text_for_mentions,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
|
@ -57,7 +60,7 @@ pub async fn collect_non_local_mentions(
|
|||
&parent_creator
|
||||
.id()
|
||||
.domain()
|
||||
.ok_or(LemmyErrorType::UrlWithoutDomain)?
|
||||
.ok_or(FederationError::UrlWithoutDomain)?
|
||||
)),
|
||||
kind: MentionType::Mention,
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
check_apub_id_valid_with_strictness,
|
||||
fetcher::markdown_links::markdown_rewrite_remote_links,
|
||||
mentions::collect_non_local_mentions,
|
||||
objects::{read_from_string_or_source, verify_is_remote_object},
|
||||
objects::{append_attachments_to_comment, read_from_string_or_source, verify_is_remote_object},
|
||||
protocol::{
|
||||
objects::{note::Note, LanguageTag},
|
||||
InCommunity,
|
||||
|
@ -33,7 +33,7 @@ use lemmy_db_schema::{
|
|||
utils::naive_now,
|
||||
};
|
||||
use lemmy_utils::{
|
||||
error::{LemmyError, LemmyErrorType, LemmyResult},
|
||||
error::{FederationError, LemmyError, LemmyResult},
|
||||
utils::markdown::markdown_to_html,
|
||||
};
|
||||
use std::ops::Deref;
|
||||
|
@ -124,6 +124,7 @@ impl Object for ApubComment {
|
|||
distinguished: Some(self.distinguished),
|
||||
language,
|
||||
audience: Some(community.actor_id.into()),
|
||||
attachment: vec![],
|
||||
};
|
||||
|
||||
Ok(note)
|
||||
|
@ -162,7 +163,7 @@ impl Object for ApubComment {
|
|||
.await
|
||||
.is_ok();
|
||||
if post.locked && !is_mod_or_admin {
|
||||
Err(LemmyErrorType::PostIsLocked)?
|
||||
Err(FederationError::PostIsLocked)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -181,6 +182,7 @@ impl Object for ApubComment {
|
|||
let local_site = LocalSite::read(&mut context.pool()).await.ok();
|
||||
let slur_regex = &local_site_opt_to_slur_regex(&local_site);
|
||||
let url_blocklist = get_url_blocklist(context).await?;
|
||||
let content = append_attachments_to_comment(content, ¬e.attachment, context).await?;
|
||||
let content = process_markdown(&content, slur_regex, &url_blocklist, context).await?;
|
||||
let content = markdown_rewrite_remote_links(content, context).await;
|
||||
let language_id = Some(
|
||||
|
@ -247,13 +249,13 @@ pub(crate) mod tests {
|
|||
}
|
||||
|
||||
async fn cleanup(
|
||||
data: (ApubPerson, ApubCommunity, ApubPost, ApubSite),
|
||||
(person, community, post, site): (ApubPerson, ApubCommunity, ApubPost, ApubSite),
|
||||
context: &LemmyContext,
|
||||
) -> LemmyResult<()> {
|
||||
Post::delete(&mut context.pool(), data.2.id).await?;
|
||||
Community::delete(&mut context.pool(), data.1.id).await?;
|
||||
Person::delete(&mut context.pool(), data.0.id).await?;
|
||||
Site::delete(&mut context.pool(), data.3.id).await?;
|
||||
Post::delete(&mut context.pool(), post.id).await?;
|
||||
Community::delete(&mut context.pool(), community.id).await?;
|
||||
Person::delete(&mut context.pool(), person.id).await?;
|
||||
Site::delete(&mut context.pool(), site.id).await?;
|
||||
LocalSite::delete(&mut context.pool()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ use crate::{
|
|||
use activitypub_federation::{
|
||||
config::Data,
|
||||
kinds::actor::GroupType,
|
||||
protocol::values::MediaTypeHtml,
|
||||
traits::{Actor, Object},
|
||||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
|
@ -107,8 +108,10 @@ impl Object for ApubCommunity {
|
|||
id: self.id().into(),
|
||||
preferred_username: self.name.clone(),
|
||||
name: Some(self.title.clone()),
|
||||
summary: self.description.as_ref().map(|b| markdown_to_html(b)),
|
||||
source: self.description.clone().map(Source::new),
|
||||
content: self.sidebar.as_ref().map(|d| markdown_to_html(d)),
|
||||
source: self.sidebar.clone().map(Source::new),
|
||||
summary: self.description.clone(),
|
||||
media_type: self.sidebar.as_ref().map(|_| MediaTypeHtml::Html),
|
||||
icon: self.icon.clone().map(ImageObject::new),
|
||||
image: self.banner.clone().map(ImageObject::new),
|
||||
sensitive: Some(self.nsfw),
|
||||
|
@ -144,10 +147,9 @@ impl Object for ApubCommunity {
|
|||
let local_site = LocalSite::read(&mut context.pool()).await.ok();
|
||||
let slur_regex = &local_site_opt_to_slur_regex(&local_site);
|
||||
let url_blocklist = get_url_blocklist(context).await?;
|
||||
let description = read_from_string_or_source_opt(&group.summary, &None, &group.source);
|
||||
let description =
|
||||
process_markdown_opt(&description, slur_regex, &url_blocklist, context).await?;
|
||||
let description = markdown_rewrite_remote_links_opt(description, context).await;
|
||||
let sidebar = read_from_string_or_source_opt(&group.content, &None, &group.source);
|
||||
let sidebar = process_markdown_opt(&sidebar, slur_regex, &url_blocklist, context).await?;
|
||||
let sidebar = markdown_rewrite_remote_links_opt(sidebar, context).await;
|
||||
let icon = proxy_image_link_opt_apub(group.icon.map(|i| i.url), context).await?;
|
||||
let banner = proxy_image_link_opt_apub(group.image.map(|i| i.url), context).await?;
|
||||
|
||||
|
@ -161,7 +163,8 @@ impl Object for ApubCommunity {
|
|||
last_refreshed_at: Some(naive_now()),
|
||||
icon,
|
||||
banner,
|
||||
description,
|
||||
sidebar,
|
||||
description: group.summary,
|
||||
followers_url: group.followers.clone().map(Into::into),
|
||||
inbox_url: Some(
|
||||
group
|
||||
|
@ -299,10 +302,16 @@ pub(crate) mod tests {
|
|||
|
||||
assert_eq!(community.title, "Ten Forward");
|
||||
assert!(!community.local);
|
||||
|
||||
// Test the sidebar and description
|
||||
assert_eq!(
|
||||
community.description.as_ref().map(std::string::String::len),
|
||||
community.sidebar.as_ref().map(std::string::String::len),
|
||||
Some(63)
|
||||
);
|
||||
assert_eq!(
|
||||
community.description,
|
||||
Some("A description of ten forward.".into())
|
||||
);
|
||||
|
||||
Community::delete(&mut context.pool(), community.id).await?;
|
||||
Site::delete(&mut context.pool(), site.id).await?;
|
||||
|
|
|
@ -42,12 +42,11 @@ use lemmy_db_schema::{
|
|||
utils::naive_now,
|
||||
};
|
||||
use lemmy_utils::{
|
||||
error::{LemmyError, LemmyResult},
|
||||
error::{FederationError, LemmyError, LemmyResult},
|
||||
utils::{
|
||||
markdown::markdown_to_html,
|
||||
slurs::{check_slurs, check_slurs_opt},
|
||||
},
|
||||
LemmyErrorType,
|
||||
};
|
||||
use std::ops::Deref;
|
||||
use tracing::debug;
|
||||
|
@ -89,7 +88,7 @@ impl Object for ApubSite {
|
|||
}
|
||||
|
||||
async fn delete(self, _data: &Data<Self::DataType>) -> LemmyResult<()> {
|
||||
Err(LemmyErrorType::CantDeleteSite.into())
|
||||
Err(FederationError::CantDeleteSite.into())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -144,7 +143,7 @@ impl Object for ApubSite {
|
|||
.id
|
||||
.inner()
|
||||
.domain()
|
||||
.ok_or(LemmyErrorType::UrlWithoutDomain)?;
|
||||
.ok_or(FederationError::UrlWithoutDomain)?;
|
||||
let instance = DbInstance::read_or_create(&mut context.pool(), domain.to_string()).await?;
|
||||
|
||||
let local_site = LocalSite::read(&mut context.pool()).await.ok();
|
||||
|
@ -220,7 +219,7 @@ pub(in crate::objects) async fn fetch_instance_actor_for_object<T: Into<Url> + C
|
|||
debug!("Failed to dereference site for {}: {}", &instance_id, e);
|
||||
let domain = instance_id
|
||||
.domain()
|
||||
.ok_or(LemmyErrorType::UrlWithoutDomain)?;
|
||||
.ok_or(FederationError::UrlWithoutDomain)?;
|
||||
Ok(
|
||||
DbInstance::read_or_create(&mut context.pool(), domain.to_string())
|
||||
.await?
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::protocol::Source;
|
||||
use crate::protocol::{objects::page::Attachment, Source};
|
||||
use activitypub_federation::{
|
||||
config::Data,
|
||||
fetch::object_id::ObjectId,
|
||||
|
@ -46,6 +46,23 @@ pub(crate) fn read_from_string_or_source_opt(
|
|||
.map(|content| read_from_string_or_source(content, media_type, source))
|
||||
}
|
||||
|
||||
pub(crate) async fn append_attachments_to_comment(
|
||||
content: String,
|
||||
attachments: &[Attachment],
|
||||
context: &Data<LemmyContext>,
|
||||
) -> LemmyResult<String> {
|
||||
let mut content = content;
|
||||
// Don't modify comments with no attachments
|
||||
if !attachments.is_empty() {
|
||||
content += "\n";
|
||||
for attachment in attachments {
|
||||
content = content + "\n" + &attachment.as_markdown(context).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
/// When for example a Post is made in a remote community, the community will send it back,
|
||||
/// wrapped in Announce. If we simply receive this like any other federated object, overwrite the
|
||||
/// existing, local Post. In particular, it will set the field local = false, so that the object
|
||||
|
|
|
@ -285,9 +285,12 @@ pub(crate) mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn cleanup(data: (ApubPerson, ApubSite), context: &LemmyContext) -> LemmyResult<()> {
|
||||
DbPerson::delete(&mut context.pool(), data.0.id).await?;
|
||||
Site::delete(&mut context.pool(), data.1.id).await?;
|
||||
async fn cleanup(
|
||||
(person, site): (ApubPerson, ApubSite),
|
||||
context: &LemmyContext,
|
||||
) -> LemmyResult<()> {
|
||||
DbPerson::delete(&mut context.pool(), person.id).await?;
|
||||
Site::delete(&mut context.pool(), site.id).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ use lemmy_db_schema::{
|
|||
utils::naive_now,
|
||||
};
|
||||
use lemmy_utils::{
|
||||
error::{LemmyError, LemmyErrorType, LemmyResult},
|
||||
error::{FederationError, LemmyError, LemmyErrorType, LemmyResult},
|
||||
utils::markdown::markdown_to_html,
|
||||
};
|
||||
use std::ops::Deref;
|
||||
|
@ -113,7 +113,7 @@ impl Object for ApubPrivateMessage {
|
|||
check_apub_id_valid_with_strictness(note.id.inner(), false, context).await?;
|
||||
let person = note.attributed_to.dereference(context).await?;
|
||||
if person.banned {
|
||||
Err(LemmyErrorType::PersonIsBannedFromSite(
|
||||
Err(FederationError::PersonIsBannedFromSite(
|
||||
person.actor_id.to_string(),
|
||||
))?
|
||||
} else {
|
||||
|
@ -186,12 +186,12 @@ mod tests {
|
|||
}
|
||||
|
||||
async fn cleanup(
|
||||
data: (ApubPerson, ApubPerson, ApubSite),
|
||||
(person1, person2, site): (ApubPerson, ApubPerson, ApubSite),
|
||||
context: &Data<LemmyContext>,
|
||||
) -> LemmyResult<()> {
|
||||
Person::delete(&mut context.pool(), data.0.id).await?;
|
||||
Person::delete(&mut context.pool(), data.1.id).await?;
|
||||
Site::delete(&mut context.pool(), data.2.id).await?;
|
||||
Person::delete(&mut context.pool(), person1.id).await?;
|
||||
Person::delete(&mut context.pool(), person2.id).await?;
|
||||
Site::delete(&mut context.pool(), site.id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
};
|
||||
use activitypub_federation::{config::Data, fetch::object_id::ObjectId};
|
||||
use lemmy_api_common::context::LemmyContext;
|
||||
use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult};
|
||||
use lemmy_utils::error::{FederationError, LemmyError, LemmyResult};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::Display;
|
||||
use url::Url;
|
||||
|
@ -35,7 +35,7 @@ impl TryFrom<i16> for VoteType {
|
|||
match value {
|
||||
1 => Ok(VoteType::Like),
|
||||
-1 => Ok(VoteType::Dislike),
|
||||
_ => Err(LemmyErrorType::InvalidVoteValue.into()),
|
||||
_ => Err(FederationError::InvalidVoteValue.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
community_outbox::ApubCommunityOutbox,
|
||||
},
|
||||
local_site_data_cached,
|
||||
objects::{community::ApubCommunity, read_from_string_or_source_opt},
|
||||
objects::community::ApubCommunity,
|
||||
protocol::{
|
||||
objects::{Endpoints, LanguageTag},
|
||||
ImageObject,
|
||||
|
@ -21,6 +21,7 @@ use activitypub_federation::{
|
|||
protocol::{
|
||||
helpers::deserialize_skip_error,
|
||||
public_key::PublicKey,
|
||||
values::MediaTypeHtml,
|
||||
verification::verify_domains_match,
|
||||
},
|
||||
};
|
||||
|
@ -50,9 +51,13 @@ pub struct Group {
|
|||
|
||||
/// title
|
||||
pub(crate) name: Option<String>,
|
||||
pub(crate) summary: Option<String>,
|
||||
// sidebar
|
||||
pub(crate) content: Option<String>,
|
||||
#[serde(deserialize_with = "deserialize_skip_error", default)]
|
||||
pub(crate) source: Option<Source>,
|
||||
pub(crate) media_type: Option<MediaTypeHtml>,
|
||||
// short instance description
|
||||
pub(crate) summary: Option<String>,
|
||||
#[serde(deserialize_with = "deserialize_skip_error", default)]
|
||||
pub(crate) icon: Option<ImageObject>,
|
||||
/// banner
|
||||
|
@ -86,8 +91,7 @@ impl Group {
|
|||
|
||||
check_slurs(&self.preferred_username, slur_regex)?;
|
||||
check_slurs_opt(&self.name, slur_regex)?;
|
||||
let description = read_from_string_or_source_opt(&self.summary, &None, &self.source);
|
||||
check_slurs_opt(&description, slur_regex)?;
|
||||
check_slurs_opt(&self.summary, slur_regex)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,9 +32,9 @@ pub struct Instance {
|
|||
pub(crate) content: Option<String>,
|
||||
#[serde(deserialize_with = "deserialize_skip_error", default)]
|
||||
pub(crate) source: Option<Source>,
|
||||
pub(crate) media_type: Option<MediaTypeHtml>,
|
||||
// short instance description
|
||||
pub(crate) summary: Option<String>,
|
||||
pub(crate) media_type: Option<MediaTypeHtml>,
|
||||
/// instance icon
|
||||
pub(crate) icon: Option<ImageObject>,
|
||||
/// instance banner
|
||||
|
|
|
@ -145,7 +145,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_parse_objects_mastodon() -> LemmyResult<()> {
|
||||
test_json::<Person>("assets/mastodon/objects/person.json")?;
|
||||
test_json::<Note>("assets/mastodon/objects/note.json")?;
|
||||
test_json::<Note>("assets/mastodon/objects/note_1.json")?;
|
||||
test_json::<Note>("assets/mastodon/objects/note_2.json")?;
|
||||
test_json::<Page>("assets/mastodon/objects/page.json")?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -3,7 +3,11 @@ use crate::{
|
|||
fetcher::post_or_comment::PostOrComment,
|
||||
mentions::MentionOrValue,
|
||||
objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson, post::ApubPost},
|
||||
protocol::{objects::LanguageTag, InCommunity, Source},
|
||||
protocol::{
|
||||
objects::{page::Attachment, LanguageTag},
|
||||
InCommunity,
|
||||
Source,
|
||||
},
|
||||
};
|
||||
use activitypub_federation::{
|
||||
config::Data,
|
||||
|
@ -20,7 +24,10 @@ use lemmy_db_schema::{
|
|||
source::{community::Community, post::Post},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType, MAX_COMMENT_DEPTH_LIMIT};
|
||||
use lemmy_utils::{
|
||||
error::{LemmyErrorType, LemmyResult},
|
||||
MAX_COMMENT_DEPTH_LIMIT,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::skip_serializing_none;
|
||||
use url::Url;
|
||||
|
@ -50,6 +57,8 @@ pub struct Note {
|
|||
pub(crate) distinguished: Option<bool>,
|
||||
pub(crate) language: Option<LanguageTag>,
|
||||
pub(crate) audience: Option<ObjectId<ApubCommunity>>,
|
||||
#[serde(default)]
|
||||
pub(crate) attachment: Vec<Attachment>,
|
||||
}
|
||||
|
||||
impl Note {
|
||||
|
|
|
@ -19,8 +19,8 @@ use activitypub_federation::{
|
|||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
use itertools::Itertools;
|
||||
use lemmy_api_common::context::LemmyContext;
|
||||
use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult};
|
||||
use lemmy_api_common::{context::LemmyContext, utils::proxy_image_link};
|
||||
use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorType, LemmyResult};
|
||||
use serde::{de::Error, Deserialize, Deserializer, Serialize};
|
||||
use serde_with::skip_serializing_none;
|
||||
use url::Url;
|
||||
|
@ -93,6 +93,7 @@ pub(crate) struct Document {
|
|||
#[serde(rename = "type")]
|
||||
kind: DocumentType,
|
||||
url: Url,
|
||||
media_type: Option<String>,
|
||||
/// Used for alt_text
|
||||
name: Option<String>,
|
||||
}
|
||||
|
@ -124,6 +125,24 @@ impl Attachment {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn as_markdown(&self, context: &Data<LemmyContext>) -> LemmyResult<String> {
|
||||
let (url, name, media_type) = match self {
|
||||
Attachment::Image(i) => (i.url.clone(), i.name.clone(), Some(String::from("image"))),
|
||||
Attachment::Document(d) => (d.url.clone(), d.name.clone(), d.media_type.clone()),
|
||||
Attachment::Link(l) => (l.href.clone(), None, l.media_type.clone()),
|
||||
};
|
||||
|
||||
let is_image =
|
||||
media_type.is_some_and(|media| media.starts_with("video") || media.starts_with("image"));
|
||||
|
||||
if is_image {
|
||||
let url = proxy_image_link(url, context).await?;
|
||||
Ok(format!("![{}]({url})", name.unwrap_or_default()))
|
||||
} else {
|
||||
Ok(format!("[{url}]({url})"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
|
@ -162,7 +181,7 @@ impl Page {
|
|||
.iter()
|
||||
.find(|a| a.kind == PersonOrGroupType::Person)
|
||||
.map(|a| ObjectId::<ApubPerson>::from(a.id.clone().into_inner()))
|
||||
.ok_or_else(|| LemmyErrorType::PageDoesNotSpecifyCreator.into()),
|
||||
.ok_or_else(|| FederationError::PageDoesNotSpecifyCreator.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,3 @@ derive-new.workspace = true
|
|||
[dev-dependencies]
|
||||
serial_test = { workspace = true }
|
||||
pretty_assertions = { workspace = true }
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
ignored = ["strum"]
|
||||
|
|
|
@ -13,7 +13,7 @@ use diesel::{
|
|||
QueryDsl,
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
|
||||
impl CaptchaAnswer {
|
||||
pub async fn insert(pool: &mut DbPool<'_>, captcha: &CaptchaAnswerForm) -> Result<Self, Error> {
|
||||
|
|
|
@ -508,6 +508,7 @@ mod tests {
|
|||
id: inserted_community.id,
|
||||
name: "TIL".into(),
|
||||
title: "nada".to_owned(),
|
||||
sidebar: None,
|
||||
description: None,
|
||||
nsfw: false,
|
||||
removed: false,
|
||||
|
|
|
@ -16,7 +16,7 @@ use diesel::{
|
|||
QueryDsl,
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
|
||||
impl CommunityBlock {
|
||||
pub async fn read(
|
||||
|
|
|
@ -16,7 +16,7 @@ use diesel::{
|
|||
QueryDsl,
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
|
||||
impl InstanceBlock {
|
||||
pub async fn read(
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
};
|
||||
use diesel::{delete, dsl::exists, insert_into, result::Error, select};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
|
||||
impl LoginToken {
|
||||
pub async fn create(pool: &mut DbPool<'_>, form: LoginTokenCreateForm) -> Result<Self, Error> {
|
||||
|
|
|
@ -21,7 +21,7 @@ use diesel::{
|
|||
QueryDsl,
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
|
||||
#[async_trait]
|
||||
impl Crud for Person {
|
||||
|
|
|
@ -17,7 +17,7 @@ use diesel::{
|
|||
QueryDsl,
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
|
||||
impl PersonBlock {
|
||||
pub async fn read(
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
};
|
||||
use diesel::{dsl::insert_into, result::Error, ExpressionMethods, OptionalExtension, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
use url::Url;
|
||||
|
||||
#[async_trait]
|
||||
|
|
|
@ -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<Url>);
|
||||
|
||||
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<ts_rs::Dependency> {
|
||||
Vec::new()
|
||||
}
|
||||
fn transparent() -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "full")]
|
||||
impl ToSql<Text, Pg> for DbUrl {
|
||||
fn to_sql(&self, out: &mut Output<Pg>) -> diesel::serialize::Result {
|
||||
|
|
|
@ -170,7 +170,7 @@ diesel::table! {
|
|||
name -> Varchar,
|
||||
#[max_length = 255]
|
||||
title -> Varchar,
|
||||
description -> Nullable<Text>,
|
||||
sidebar -> Nullable<Text>,
|
||||
removed -> Bool,
|
||||
published -> Timestamptz,
|
||||
updated -> Nullable<Timestamptz>,
|
||||
|
@ -196,6 +196,8 @@ diesel::table! {
|
|||
#[max_length = 255]
|
||||
featured_url -> Nullable<Varchar>,
|
||||
visibility -> CommunityVisibility,
|
||||
#[max_length = 150]
|
||||
description -> Nullable<Varchar>,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String> 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 {
|
||||
"string".to_string()
|
||||
}
|
||||
fn dependencies() -> Vec<ts_rs::Dependency> {
|
||||
Vec::new()
|
||||
}
|
||||
fn transparent() -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ pub struct Comment {
|
|||
/// Whether the comment has been removed.
|
||||
pub removed: bool,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
/// Whether the comment has been deleted by its creator.
|
||||
pub deleted: bool,
|
||||
|
|
|
@ -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<PersonId>,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -24,11 +24,13 @@ pub struct Community {
|
|||
pub name: String,
|
||||
/// A longer title, that can contain other characters, and doesn't have to be unique.
|
||||
pub title: String,
|
||||
/// A sidebar / markdown description.
|
||||
pub description: Option<String>,
|
||||
/// A sidebar for the community in markdown.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub sidebar: Option<String>,
|
||||
/// Whether the community is removed by a mod.
|
||||
pub removed: bool,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
/// 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<Utc>,
|
||||
/// A URL for an icon.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub icon: Option<DbUrl>,
|
||||
/// A URL for a banner.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub banner: Option<DbUrl>,
|
||||
#[cfg_attr(feature = "full", ts(skip))]
|
||||
#[serde(skip)]
|
||||
|
@ -66,6 +70,9 @@ pub struct Community {
|
|||
#[serde(skip)]
|
||||
pub featured_url: Option<DbUrl>,
|
||||
pub visibility: CommunityVisibility,
|
||||
/// A shorter, one-line description of the site.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, derive_new::new)]
|
||||
|
@ -77,7 +84,7 @@ pub struct CommunityInsertForm {
|
|||
pub title: String,
|
||||
pub public_key: String,
|
||||
#[new(default)]
|
||||
pub description: Option<String>,
|
||||
pub sidebar: Option<String>,
|
||||
#[new(default)]
|
||||
pub removed: Option<bool>,
|
||||
#[new(default)]
|
||||
|
@ -114,6 +121,8 @@ pub struct CommunityInsertForm {
|
|||
pub posting_restricted_to_mods: Option<bool>,
|
||||
#[new(default)]
|
||||
pub visibility: Option<CommunityVisibility>,
|
||||
#[new(default)]
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
|
@ -121,7 +130,7 @@ pub struct CommunityInsertForm {
|
|||
#[cfg_attr(feature = "full", diesel(table_name = community))]
|
||||
pub struct CommunityUpdateForm {
|
||||
pub title: Option<String>,
|
||||
pub description: Option<Option<String>>,
|
||||
pub sidebar: Option<Option<String>>,
|
||||
pub removed: Option<bool>,
|
||||
pub published: Option<DateTime<Utc>>,
|
||||
pub updated: Option<Option<DateTime<Utc>>>,
|
||||
|
@ -141,6 +150,7 @@ pub struct CommunityUpdateForm {
|
|||
pub hidden: Option<bool>,
|
||||
pub posting_restricted_to_mods: Option<bool>,
|
||||
pub visibility: Option<CommunityVisibility>,
|
||||
pub description: Option<Option<String>>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
|
|
|
@ -21,6 +21,7 @@ pub struct CustomEmoji {
|
|||
pub alt_text: String,
|
||||
pub category: String,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ActivityId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub last_successful_published_time: Option<DateTime<Utc>>,
|
||||
/// 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<DateTime<Utc>>,
|
||||
}
|
||||
|
|
|
@ -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<LocalUserId>,
|
||||
pub pictrs_alias: String,
|
||||
pub pictrs_delete_token: String,
|
||||
|
|
|
@ -19,8 +19,11 @@ pub struct Instance {
|
|||
pub id: InstanceId,
|
||||
pub domain: String,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub software: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub version: Option<String>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String>,
|
||||
/// 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<String>,
|
||||
/// 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<String>,
|
||||
/// 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<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
pub registration_mode: RegistrationMode,
|
||||
/// Whether to email admins on new reports.
|
||||
|
|
|
@ -34,6 +34,7 @@ pub struct LocalSiteRateLimit {
|
|||
pub search: i32,
|
||||
pub search_per_second: i32,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
pub import_user_settings: i32,
|
||||
pub import_user_settings_per_second: i32,
|
||||
|
|
|
@ -16,6 +16,7 @@ pub struct LocalSiteUrlBlocklist {
|
|||
pub id: i32,
|
||||
pub url: String,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ pub struct LocalUser {
|
|||
pub person_id: PersonId,
|
||||
#[serde(skip)]
|
||||
pub password_encrypted: Option<SensitiveString>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub email: Option<SensitiveString>,
|
||||
/// Whether to show NSFW content.
|
||||
pub show_nsfw: bool,
|
||||
|
|
|
@ -24,7 +24,9 @@ pub struct LoginToken {
|
|||
pub published: DateTime<Utc>,
|
||||
/// 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<String>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub user_agent: Option<String>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String>,
|
||||
pub removed: bool,
|
||||
pub when_: DateTime<Utc>,
|
||||
|
@ -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<String>,
|
||||
pub removed: bool,
|
||||
pub when_: DateTime<Utc>,
|
||||
|
@ -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<String>,
|
||||
pub removed: bool,
|
||||
pub when_: DateTime<Utc>,
|
||||
|
@ -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<String>,
|
||||
pub banned: bool,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub expires: Option<DateTime<Utc>>,
|
||||
pub when_: DateTime<Utc>,
|
||||
}
|
||||
|
@ -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<String>,
|
||||
pub banned: bool,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub expires: Option<DateTime<Utc>>,
|
||||
pub when_: DateTime<Utc>,
|
||||
}
|
||||
|
@ -211,6 +218,7 @@ pub struct ModHideCommunity {
|
|||
pub community_id: CommunityId,
|
||||
pub mod_person_id: PersonId,
|
||||
pub when_: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub reason: Option<String>,
|
||||
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<String>,
|
||||
pub when_: DateTime<Utc>,
|
||||
}
|
||||
|
@ -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<String>,
|
||||
pub when_: DateTime<Utc>,
|
||||
}
|
||||
|
@ -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<String>,
|
||||
pub when_: DateTime<Utc>,
|
||||
}
|
||||
|
@ -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<String>,
|
||||
pub when_: DateTime<Utc>,
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ pub struct OAuthAccount {
|
|||
pub oauth_provider_id: OAuthProviderId,
|
||||
pub oauth_user_id: String,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ pub struct OAuthProvider {
|
|||
/// switch to enable or disable an oauth provider
|
||||
pub enabled: bool,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String>,
|
||||
/// A URL for an avatar.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub avatar: Option<DbUrl>,
|
||||
/// Whether the person is banned.
|
||||
pub banned: bool,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
/// The federated actor_id.
|
||||
pub actor_id: DbUrl,
|
||||
/// An optional bio, in markdown.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub bio: Option<String>,
|
||||
/// 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<Utc>,
|
||||
/// A URL for a banner.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub banner: Option<DbUrl>,
|
||||
/// 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<String>,
|
||||
/// 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<DateTime<Utc>>,
|
||||
pub instance_id: InstanceId,
|
||||
}
|
||||
|
|
|
@ -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<DbUrl>,
|
||||
/// An optional post body, in markdown.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub body: Option<String>,
|
||||
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<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
/// 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<String>,
|
||||
/// A description for the link.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub embed_description: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||
/// A thumbnail picture url.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub thumbnail_url: Option<DbUrl>,
|
||||
#[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<DbUrl>,
|
||||
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<String>,
|
||||
/// An optional alt_text, usable for image posts.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub alt_text: Option<String>,
|
||||
/// Time at which the post will be published. None means publish immediately.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub scheduled_publish_time: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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<DbUrl>,
|
||||
/// The original post body.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub original_post_body: Option<String>,
|
||||
pub reason: String,
|
||||
pub resolved: bool,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub resolver_id: Option<PersonId>,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ pub struct PrivateMessage {
|
|||
pub deleted: bool,
|
||||
pub read: bool,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
pub ap_id: DbUrl,
|
||||
pub local: bool,
|
||||
|
|
|
@ -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<PersonId>,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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<PersonId>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub deny_reason: Option<String>,
|
||||
pub published: DateTime<Utc>,
|
||||
}
|
||||
|
|
|
@ -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<String>,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
/// An icon URL.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub icon: Option<DbUrl>,
|
||||
/// A banner url.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub banner: Option<DbUrl>,
|
||||
/// A shorter, one-line description of the site.
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub description: Option<String>,
|
||||
/// 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<String>,
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ pub struct Tagline {
|
|||
pub id: i32,
|
||||
pub content: String,
|
||||
pub published: DateTime<Utc>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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> = 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<AsyncPgConnection>;
|
||||
|
||||
/// 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<Option<DbUrl>> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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::<Vec<String>>()
|
||||
.join(" ");
|
||||
|
||||
url.set_query(Some(&format!("options={options_segments}")));
|
||||
url.into()
|
||||
}
|
||||
|
||||
fn establish_connection(config: &str) -> BoxFuture<ConnectionResult<AsyncPgConnection>> {
|
||||
let fut = async {
|
||||
/// Use a once_lock to create the postgres connection config, since this config never changes
|
||||
static POSTGRES_CONFIG_WITH_OPTIONS: OnceLock<String> = 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<ConnectionResult<AsyncPgConne
|
|||
AsyncPgConnection::establish(config).await?
|
||||
};
|
||||
|
||||
diesel::select((
|
||||
// Change geqo_threshold back to default value if it was changed, so it's higher than the
|
||||
// collapse limits
|
||||
functions::set_config("geqo_threshold", "12", false),
|
||||
// Change collapse limits from 8 to 11 so the query planner can find a better table join
|
||||
// order for more complicated queries
|
||||
functions::set_config("from_collapse_limit", "11", false),
|
||||
functions::set_config("join_collapse_limit", "11", false),
|
||||
// Set `lemmy.protocol_and_hostname` so triggers can use it
|
||||
functions::set_config(
|
||||
"lemmy.protocol_and_hostname",
|
||||
SETTINGS.get_protocol_and_hostname(),
|
||||
false,
|
||||
),
|
||||
))
|
||||
.execute(&mut conn)
|
||||
.await
|
||||
.map_err(ConnectionError::CouldntSetupConfiguration)?;
|
||||
Ok(conn)
|
||||
};
|
||||
fut.boxed()
|
||||
|
@ -498,7 +508,7 @@ static EMAIL_REGEX: LazyLock<Regex> = 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<T: diesel::sql_types::SqlType + diesel::sql_types::SingleValue>(x: diesel::sql_types::Nullable<T>, 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*";
|
||||
|
|
|
@ -391,6 +391,7 @@ mod tests {
|
|||
actor_id: inserted_community.actor_id.clone(),
|
||||
local: true,
|
||||
title: inserted_community.title,
|
||||
sidebar: None,
|
||||
description: None,
|
||||
updated: None,
|
||||
banner: None,
|
||||
|
|
|
@ -1092,6 +1092,7 @@ mod tests {
|
|||
actor_id: data.inserted_community.actor_id.clone(),
|
||||
local: true,
|
||||
title: "nada".to_owned(),
|
||||
sidebar: None,
|
||||
description: None,
|
||||
updated: None,
|
||||
banner: None,
|
||||
|
|
|
@ -76,16 +76,16 @@ impl CustomEmojiView {
|
|||
fn from_tuple_to_vec(items: Vec<CustomEmojiTuple>) -> Vec<Self> {
|
||||
let mut result = Vec::new();
|
||||
let mut hash: HashMap<CustomEmojiId, Vec<CustomEmojiKeyword>> = HashMap::new();
|
||||
for item in &items {
|
||||
let emoji_id: CustomEmojiId = item.0.id;
|
||||
for (emoji, keyword) in &items {
|
||||
let emoji_id: CustomEmojiId = emoji.id;
|
||||
if let std::collections::hash_map::Entry::Vacant(e) = hash.entry(emoji_id) {
|
||||
e.insert(Vec::new());
|
||||
result.push(CustomEmojiView {
|
||||
custom_emoji: item.0.clone(),
|
||||
custom_emoji: emoji.clone(),
|
||||
keywords: Vec::new(),
|
||||
})
|
||||
}
|
||||
if let Some(item_keyword) = &item.1 {
|
||||
if let Some(item_keyword) = &keyword {
|
||||
if let Some(keywords) = hash.get_mut(&emoji_id) {
|
||||
keywords.push(item_keyword.clone())
|
||||
}
|
||||
|
|
|
@ -401,6 +401,11 @@ fn queries<'a>() -> Queries<
|
|||
query = query.filter(person::bot_account.eq(false));
|
||||
};
|
||||
|
||||
// Filter to show only posts with no comments
|
||||
if options.no_comments_only.unwrap_or_default() {
|
||||
query = query.filter(post_aggregates::comments.eq(0));
|
||||
};
|
||||
|
||||
// If its saved only, then filter, and order by the saved time, not the comment creation time.
|
||||
if options.saved_only.unwrap_or_default() {
|
||||
query = query
|
||||
|
@ -617,6 +622,7 @@ pub struct PostQuery<'a> {
|
|||
pub show_hidden: Option<bool>,
|
||||
pub show_read: Option<bool>,
|
||||
pub show_nsfw: Option<bool>,
|
||||
pub no_comments_only: Option<bool>,
|
||||
}
|
||||
|
||||
impl<'a> PostQuery<'a> {
|
||||
|
@ -728,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,
|
||||
|
@ -768,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,
|
||||
|
@ -776,7 +783,7 @@ mod tests {
|
|||
use lemmy_utils::error::LemmyResult;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serial_test::serial;
|
||||
use std::time::Duration;
|
||||
use std::time::{Duration, Instant};
|
||||
use url::Url;
|
||||
|
||||
const POST_WITH_ANOTHER_TITLE: &str = "Another title";
|
||||
|
@ -1834,6 +1841,7 @@ mod tests {
|
|||
actor_id: inserted_community.actor_id.clone(),
|
||||
local: true,
|
||||
title: "nada".to_owned(),
|
||||
sidebar: None,
|
||||
description: None,
|
||||
updated: None,
|
||||
banner: None,
|
||||
|
@ -1987,4 +1995,90 @@ 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<()> {
|
||||
let pool = &build_db_pool().await?;
|
||||
let pool = &mut pool.into();
|
||||
let data = init_data(pool).await?;
|
||||
|
||||
// Create a comment for a post
|
||||
let comment_form = CommentInsertForm::new(
|
||||
data.local_user_view.person.id,
|
||||
data.inserted_post.id,
|
||||
"a comment".to_owned(),
|
||||
);
|
||||
Comment::create(pool, &comment_form, None).await?;
|
||||
|
||||
// Make sure it doesnt come back with the no_comments option
|
||||
let post_listings_no_comments = PostQuery {
|
||||
sort: Some(PostSortType::New),
|
||||
no_comments_only: Some(true),
|
||||
local_user: Some(&data.local_user_view.local_user),
|
||||
..Default::default()
|
||||
}
|
||||
.list(&data.site, pool)
|
||||
.await?;
|
||||
|
||||
assert_eq!(vec![POST_BY_BOT], names(&post_listings_no_comments));
|
||||
|
||||
cleanup(data, pool).await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use lemmy_db_schema::{
|
|||
schema::{local_site, local_site_rate_limit, site, site_aggregates},
|
||||
utils::{get_conn, DbPool},
|
||||
};
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
|
||||
impl SiteView {
|
||||
pub async fn read_local(pool: &mut DbPool<'_>) -> LemmyResult<Self> {
|
||||
|
|
|
@ -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<i16>,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub resolver: Option<Person>,
|
||||
}
|
||||
|
||||
|
@ -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<i16>,
|
||||
}
|
||||
|
||||
|
@ -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<i16>,
|
||||
pub unread_comments: i64,
|
||||
pub counts: PostAggregates,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub resolver: Option<Person>,
|
||||
}
|
||||
|
||||
|
@ -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<ImageDetails>,
|
||||
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<i16>,
|
||||
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<Person>,
|
||||
}
|
||||
|
||||
|
@ -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<Person>,
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue