mirror of https://github.com/LemmyNet/lemmy.git
Merge branch 'main' into markdown-link-rule
commit
dc17cb13e9
|
@ -1510,6 +1510,12 @@ dependencies = [
|
||||||
"syn 2.0.40",
|
"syn 2.0.40",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diff"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
|
@ -2540,6 +2546,7 @@ dependencies = [
|
||||||
"lemmy_db_views_actor",
|
"lemmy_db_views_actor",
|
||||||
"lemmy_db_views_moderator",
|
"lemmy_db_views_moderator",
|
||||||
"lemmy_utils",
|
"lemmy_utils",
|
||||||
|
"pretty_assertions",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
"sitemap-rs",
|
"sitemap-rs",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -2570,6 +2577,7 @@ dependencies = [
|
||||||
"lemmy_utils",
|
"lemmy_utils",
|
||||||
"mime",
|
"mime",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"pretty_assertions",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"reqwest-middleware",
|
"reqwest-middleware",
|
||||||
|
@ -2634,6 +2642,7 @@ dependencies = [
|
||||||
"lemmy_utils",
|
"lemmy_utils",
|
||||||
"moka",
|
"moka",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"pretty_assertions",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -2665,6 +2674,7 @@ dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"lemmy_utils",
|
"lemmy_utils",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"pretty_assertions",
|
||||||
"regex",
|
"regex",
|
||||||
"rustls 0.21.10",
|
"rustls 0.21.10",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -2694,6 +2704,7 @@ dependencies = [
|
||||||
"diesel_ltree",
|
"diesel_ltree",
|
||||||
"lemmy_db_schema",
|
"lemmy_db_schema",
|
||||||
"lemmy_utils",
|
"lemmy_utils",
|
||||||
|
"pretty_assertions",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
|
@ -2710,6 +2721,7 @@ dependencies = [
|
||||||
"diesel",
|
"diesel",
|
||||||
"diesel-async",
|
"diesel-async",
|
||||||
"lemmy_db_schema",
|
"lemmy_db_schema",
|
||||||
|
"pretty_assertions",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
|
@ -2805,6 +2817,7 @@ dependencies = [
|
||||||
"opentelemetry 0.19.0",
|
"opentelemetry 0.19.0",
|
||||||
"opentelemetry-otlp 0.12.0",
|
"opentelemetry-otlp 0.12.0",
|
||||||
"pict-rs",
|
"pict-rs",
|
||||||
|
"pretty_assertions",
|
||||||
"prometheus",
|
"prometheus",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"reqwest-middleware",
|
"reqwest-middleware",
|
||||||
|
@ -2839,6 +2852,7 @@ dependencies = [
|
||||||
"markdown-it",
|
"markdown-it",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"openssl",
|
"openssl",
|
||||||
|
"pretty_assertions",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"reqwest-middleware",
|
"reqwest-middleware",
|
||||||
|
@ -3946,6 +3960,16 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_assertions"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66"
|
||||||
|
dependencies = [
|
||||||
|
"diff",
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.70"
|
version = "1.0.70"
|
||||||
|
@ -6447,6 +6471,12 @@ dependencies = [
|
||||||
"linked-hash-map",
|
"linked-hash-map",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.30"
|
version = "0.7.30"
|
||||||
|
|
|
@ -156,6 +156,7 @@ tokio-postgres-rustls = "0.10.0"
|
||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
enum-map = "2.7"
|
enum-map = "2.7"
|
||||||
moka = { version = "0.12.1", features = ["future"] }
|
moka = { version = "0.12.1", features = ["future"] }
|
||||||
|
pretty_assertions = "1.4.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_api = { workspace = true }
|
lemmy_api = { workspace = true }
|
||||||
|
@ -194,3 +195,6 @@ prometheus = { version = "0.13.3", features = ["process"] }
|
||||||
serial_test = { workspace = true }
|
serial_test = { workspace = true }
|
||||||
clap = { version = "4.4.11", features = ["derive"] }
|
clap = { version = "4.4.11", features = ["derive"] }
|
||||||
actix-web-prom = "0.7.0"
|
actix-web-prom = "0.7.0"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
pretty_assertions = { workspace = true }
|
||||||
|
|
|
@ -112,18 +112,19 @@ test("Delete user", async () => {
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Requests with invalid auth should be treated as unauthenticated", async () => {
|
test("Requests with invalid auth should throw error", async () => {
|
||||||
let invalid_auth = new LemmyHttp(alphaUrl, {
|
let invalid_auth = new LemmyHttp(alphaUrl, {
|
||||||
headers: { Authorization: "Bearer foobar" },
|
headers: { Authorization: "Bearer foobar" },
|
||||||
fetchFunction,
|
fetchFunction,
|
||||||
});
|
});
|
||||||
let site = await getSite(invalid_auth);
|
await expect(getSite(invalid_auth)).rejects.toStrictEqual(
|
||||||
expect(site.my_user).toBeUndefined();
|
Error("incorrect_login"),
|
||||||
expect(site.site_view).toBeDefined();
|
);
|
||||||
|
|
||||||
let form: GetPosts = {};
|
let form: GetPosts = {};
|
||||||
let posts = invalid_auth.getPosts(form);
|
await expect(invalid_auth.getPosts(form)).rejects.toStrictEqual(
|
||||||
expect((await posts).posts).toBeDefined();
|
Error("incorrect_login"),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Create user with Arabic name", async () => {
|
test("Create user with Arabic name", async () => {
|
||||||
|
|
|
@ -42,3 +42,4 @@ actix-web-httpauth = "0.8.1"
|
||||||
serial_test = { workspace = true }
|
serial_test = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
elementtree = "1.2.3"
|
elementtree = "1.2.3"
|
||||||
|
pretty_assertions = { workspace = true }
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
use actix_web::web::{Data, Json, Query};
|
||||||
|
use lemmy_api_common::{
|
||||||
|
comment::{ListCommentLikes, ListCommentLikesResponse},
|
||||||
|
context::LemmyContext,
|
||||||
|
utils::is_admin,
|
||||||
|
};
|
||||||
|
use lemmy_db_views::structs::{LocalUserView, VoteView};
|
||||||
|
use lemmy_utils::error::LemmyError;
|
||||||
|
|
||||||
|
/// Lists likes for a comment
|
||||||
|
#[tracing::instrument(skip(context))]
|
||||||
|
pub async fn list_comment_likes(
|
||||||
|
data: Query<ListCommentLikes>,
|
||||||
|
context: Data<LemmyContext>,
|
||||||
|
local_user_view: LocalUserView,
|
||||||
|
) -> Result<Json<ListCommentLikesResponse>, LemmyError> {
|
||||||
|
// Make sure user is an admin
|
||||||
|
is_admin(&local_user_view)?;
|
||||||
|
|
||||||
|
let comment_likes =
|
||||||
|
VoteView::list_for_comment(&mut context.pool(), data.comment_id, data.page, data.limit).await?;
|
||||||
|
|
||||||
|
Ok(Json(ListCommentLikesResponse { comment_likes }))
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod distinguish;
|
pub mod distinguish;
|
||||||
pub mod like;
|
pub mod like;
|
||||||
|
pub mod list_comment_likes;
|
||||||
pub mod save;
|
pub mod save;
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub async fn resolve_comment_report(
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
report.community.id,
|
report.community.id,
|
||||||
false,
|
true,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
@ -2,15 +2,11 @@ use actix_web::{http::header::Header, HttpRequest};
|
||||||
use actix_web_httpauth::headers::authorization::{Authorization, Bearer};
|
use actix_web_httpauth::headers::authorization::{Authorization, Bearer};
|
||||||
use base64::{engine::general_purpose::STANDARD_NO_PAD as base64, Engine};
|
use base64::{engine::general_purpose::STANDARD_NO_PAD as base64, Engine};
|
||||||
use captcha::Captcha;
|
use captcha::Captcha;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::utils::{local_site_to_slur_regex, AUTH_COOKIE_NAME};
|
||||||
claims::Claims,
|
|
||||||
context::LemmyContext,
|
|
||||||
utils::{check_user_valid, local_site_to_slur_regex, AUTH_COOKIE_NAME},
|
|
||||||
};
|
|
||||||
use lemmy_db_schema::source::local_site::LocalSite;
|
use lemmy_db_schema::source::local_site::LocalSite;
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::{LemmyError, LemmyErrorExt, LemmyErrorExt2, LemmyErrorType, LemmyResult},
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||||
utils::slurs::check_slurs,
|
utils::slurs::check_slurs,
|
||||||
};
|
};
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
@ -141,20 +137,6 @@ pub(crate) fn build_totp_2fa(
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntGenerateTotp)
|
.with_lemmy_type(LemmyErrorType::CouldntGenerateTotp)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
|
||||||
pub async fn local_user_view_from_jwt(
|
|
||||||
jwt: &str,
|
|
||||||
context: &LemmyContext,
|
|
||||||
) -> Result<LocalUserView, LemmyError> {
|
|
||||||
let local_user_id = Claims::validate(jwt, context)
|
|
||||||
.await
|
|
||||||
.with_lemmy_type(LemmyErrorType::NotLoggedIn)?;
|
|
||||||
let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id).await?;
|
|
||||||
check_user_valid(&local_user_view.person)?;
|
|
||||||
|
|
||||||
Ok(local_user_view)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#![allow(clippy::unwrap_used)]
|
#![allow(clippy::unwrap_used)]
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::{local_user_view_from_jwt, read_auth_token};
|
use crate::read_auth_token;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
web::{Data, Json},
|
web::{Data, Json},
|
||||||
HttpRequest,
|
HttpRequest,
|
||||||
};
|
};
|
||||||
use lemmy_api_common::{context::LemmyContext, SuccessResponse};
|
use lemmy_api_common::{claims::Claims, context::LemmyContext, SuccessResponse};
|
||||||
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt2, LemmyErrorType};
|
||||||
|
|
||||||
/// Returns an error message if the auth token is invalid for any reason. Necessary because other
|
/// Returns an error message if the auth token is invalid for any reason. Necessary because other
|
||||||
/// endpoints silently treat any call with invalid auth as unauthenticated.
|
/// endpoints silently treat any call with invalid auth as unauthenticated.
|
||||||
|
@ -15,7 +15,9 @@ pub async fn validate_auth(
|
||||||
) -> Result<Json<SuccessResponse>, LemmyError> {
|
) -> Result<Json<SuccessResponse>, LemmyError> {
|
||||||
let jwt = read_auth_token(&req)?;
|
let jwt = read_auth_token(&req)?;
|
||||||
if let Some(jwt) = jwt {
|
if let Some(jwt) = jwt {
|
||||||
local_user_view_from_jwt(&jwt, &context).await?;
|
Claims::validate(&jwt, &context)
|
||||||
|
.await
|
||||||
|
.with_lemmy_type(LemmyErrorType::NotLoggedIn)?;
|
||||||
} else {
|
} else {
|
||||||
Err(LemmyErrorType::NotLoggedIn)?;
|
Err(LemmyErrorType::NotLoggedIn)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
use actix_web::web::{Data, Json, Query};
|
||||||
|
use lemmy_api_common::{
|
||||||
|
context::LemmyContext,
|
||||||
|
post::{ListPostLikes, ListPostLikesResponse},
|
||||||
|
utils::is_admin,
|
||||||
|
};
|
||||||
|
use lemmy_db_views::structs::{LocalUserView, VoteView};
|
||||||
|
use lemmy_utils::error::LemmyError;
|
||||||
|
|
||||||
|
/// Lists likes for a post
|
||||||
|
#[tracing::instrument(skip(context))]
|
||||||
|
pub async fn list_post_likes(
|
||||||
|
data: Query<ListPostLikes>,
|
||||||
|
context: Data<LemmyContext>,
|
||||||
|
local_user_view: LocalUserView,
|
||||||
|
) -> Result<Json<ListPostLikesResponse>, LemmyError> {
|
||||||
|
// Make sure user is an admin
|
||||||
|
is_admin(&local_user_view)?;
|
||||||
|
|
||||||
|
let post_likes =
|
||||||
|
VoteView::list_for_post(&mut context.pool(), data.post_id, data.page, data.limit).await?;
|
||||||
|
|
||||||
|
Ok(Json(ListPostLikesResponse { post_likes }))
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
pub mod feature;
|
pub mod feature;
|
||||||
pub mod get_link_metadata;
|
pub mod get_link_metadata;
|
||||||
pub mod like;
|
pub mod like;
|
||||||
|
pub mod list_post_likes;
|
||||||
pub mod lock;
|
pub mod lock;
|
||||||
pub mod mark_read;
|
pub mod mark_read;
|
||||||
pub mod save;
|
pub mod save;
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub async fn resolve_post_report(
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
report.community.id,
|
report.community.id,
|
||||||
false,
|
true,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
|
@ -49,6 +49,7 @@ pub(crate) mod tests {
|
||||||
use chrono::{DateTime, NaiveDate, Utc};
|
use chrono::{DateTime, NaiveDate, Utc};
|
||||||
use elementtree::Element;
|
use elementtree::Element;
|
||||||
use lemmy_db_schema::newtypes::DbUrl;
|
use lemmy_db_schema::newtypes::DbUrl;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -82,3 +82,4 @@ ignored = ["getrandom"]
|
||||||
serial_test = { workspace = true }
|
serial_test = { workspace = true }
|
||||||
reqwest-middleware = { workspace = true }
|
reqwest-middleware = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
pretty_assertions = { workspace = true }
|
||||||
|
|
|
@ -6,7 +6,7 @@ use lemmy_db_schema::{
|
||||||
newtypes::LocalUserId,
|
newtypes::LocalUserId,
|
||||||
source::login_token::{LoginToken, LoginTokenCreateForm},
|
source::login_token::{LoginToken, LoginTokenCreateForm},
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
@ -25,8 +25,7 @@ impl Claims {
|
||||||
validation.required_spec_claims.remove("exp");
|
validation.required_spec_claims.remove("exp");
|
||||||
let jwt_secret = &context.secret().jwt_secret;
|
let jwt_secret = &context.secret().jwt_secret;
|
||||||
let key = DecodingKey::from_secret(jwt_secret.as_ref());
|
let key = DecodingKey::from_secret(jwt_secret.as_ref());
|
||||||
let claims =
|
let claims = decode::<Claims>(jwt, &key, &validation)?;
|
||||||
decode::<Claims>(jwt, &key, &validation).with_lemmy_type(LemmyErrorType::NotLoggedIn)?;
|
|
||||||
let user_id = LocalUserId(claims.claims.sub.parse()?);
|
let user_id = LocalUserId(claims.claims.sub.parse()?);
|
||||||
let is_valid = LoginToken::validate(&mut context.pool(), user_id, jwt).await?;
|
let is_valid = LoginToken::validate(&mut context.pool(), user_id, jwt).await?;
|
||||||
if !is_valid {
|
if !is_valid {
|
||||||
|
@ -89,6 +88,7 @@ mod tests {
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
use lemmy_utils::rate_limit::RateLimitCell;
|
use lemmy_utils::rate_limit::RateLimitCell;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use reqwest_middleware::ClientBuilder;
|
use reqwest_middleware::ClientBuilder;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
|
@ -3,7 +3,7 @@ use lemmy_db_schema::{
|
||||||
CommentSortType,
|
CommentSortType,
|
||||||
ListingType,
|
ListingType,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{CommentReportView, CommentView};
|
use lemmy_db_views::structs::{CommentReportView, CommentView, VoteView};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::skip_serializing_none;
|
use serde_with::skip_serializing_none;
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
|
@ -176,3 +176,22 @@ pub struct ListCommentReports {
|
||||||
pub struct ListCommentReportsResponse {
|
pub struct ListCommentReportsResponse {
|
||||||
pub comment_reports: Vec<CommentReportView>,
|
pub comment_reports: Vec<CommentReportView>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
||||||
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
/// List comment likes. Admins-only.
|
||||||
|
pub struct ListCommentLikes {
|
||||||
|
pub comment_id: CommentId,
|
||||||
|
pub page: Option<i64>,
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
/// The comment likes response
|
||||||
|
pub struct ListCommentLikesResponse {
|
||||||
|
pub comment_likes: Vec<VoteView>,
|
||||||
|
}
|
||||||
|
|
|
@ -43,5 +43,5 @@ impl Default for SuccessResponse {
|
||||||
|
|
||||||
/// how long to sleep based on how many retries have already happened
|
/// how long to sleep based on how many retries have already happened
|
||||||
pub fn federate_retry_sleep_duration(retry_count: i32) -> Duration {
|
pub fn federate_retry_sleep_duration(retry_count: i32) -> Duration {
|
||||||
Duration::from_secs_f64(10.0 * 2.0_f64.powf(f64::from(retry_count)))
|
Duration::from_secs_f64(2.0_f64.powf(f64::from(retry_count)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use lemmy_db_schema::{
|
||||||
PostFeatureType,
|
PostFeatureType,
|
||||||
SortType,
|
SortType,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{PaginationCursor, PostReportView, PostView};
|
use lemmy_db_views::structs::{PaginationCursor, PostReportView, PostView, VoteView};
|
||||||
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
|
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::skip_serializing_none;
|
use serde_with::skip_serializing_none;
|
||||||
|
@ -255,3 +255,22 @@ pub struct LinkMetadata {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub thumbnail: Option<DbUrl>,
|
pub thumbnail: Option<DbUrl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
|
||||||
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
/// List post likes. Admins-only.
|
||||||
|
pub struct ListPostLikes {
|
||||||
|
pub post_id: PostId,
|
||||||
|
pub page: Option<i64>,
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
/// The post likes response
|
||||||
|
pub struct ListPostLikesResponse {
|
||||||
|
pub post_likes: Vec<VoteView>,
|
||||||
|
}
|
||||||
|
|
|
@ -300,6 +300,7 @@ mod tests {
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
request::{extract_opengraph_data, fetch_link_metadata},
|
request::{extract_opengraph_data, fetch_link_metadata},
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
|
|
@ -934,6 +934,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::utils::{honeypot_check, limit_expire_time, password_length_check};
|
use crate::utils::{honeypot_check, limit_expire_time, password_length_check};
|
||||||
use chrono::{Days, Utc};
|
use chrono::{Days, Utc};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -51,3 +51,4 @@ enum_delegate = "0.2.0"
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test = { workspace = true }
|
serial_test = { workspace = true }
|
||||||
assert-json-diff = "2.0.2"
|
assert-json-diff = "2.0.2"
|
||||||
|
pretty_assertions = { workspace = true }
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::{generate_activity_id, send_lemmy_activity, verify_person_in_community},
|
activities::{generate_activity_id, send_lemmy_activity, verify_person_in_community},
|
||||||
insert_received_activity,
|
insert_received_activity,
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, instance::ApubSite, person::ApubPerson},
|
||||||
protocol::{activities::community::report::Report, InCommunity},
|
protocol::{activities::community::report::Report, InCommunity},
|
||||||
PostOrComment,
|
PostOrComment,
|
||||||
};
|
};
|
||||||
|
@ -19,8 +19,9 @@ use lemmy_db_schema::{
|
||||||
community::Community,
|
community::Community,
|
||||||
person::Person,
|
person::Person,
|
||||||
post_report::{PostReport, PostReportForm},
|
post_report::{PostReport, PostReportForm},
|
||||||
|
site::Site,
|
||||||
},
|
},
|
||||||
traits::Reportable,
|
traits::{Crud, Reportable},
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::LemmyError;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -44,18 +45,31 @@ impl Report {
|
||||||
let report = Report {
|
let report = Report {
|
||||||
actor: actor.id().into(),
|
actor: actor.id().into(),
|
||||||
to: [community.id().into()],
|
to: [community.id().into()],
|
||||||
object: object_id,
|
object: object_id.clone(),
|
||||||
summary: reason,
|
summary: reason,
|
||||||
kind,
|
kind,
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
audience: Some(community.id().into()),
|
audience: Some(community.id().into()),
|
||||||
};
|
};
|
||||||
let inbox = if community.local {
|
|
||||||
ActivitySendTargets::empty()
|
// send report to the community where object was posted
|
||||||
} else {
|
let mut inboxes = ActivitySendTargets::to_inbox(community.shared_inbox_or_inbox());
|
||||||
ActivitySendTargets::to_inbox(community.shared_inbox_or_inbox())
|
|
||||||
|
// also send report to user's home instance if possible
|
||||||
|
let object_creator_id = match object_id.dereference_local(&context).await? {
|
||||||
|
PostOrComment::Post(p) => p.creator_id,
|
||||||
|
PostOrComment::Comment(c) => c.creator_id,
|
||||||
};
|
};
|
||||||
send_lemmy_activity(&context, report, &actor, inbox, false).await
|
let object_creator = Person::read(&mut context.pool(), object_creator_id).await?;
|
||||||
|
let object_creator_site: Option<ApubSite> =
|
||||||
|
Site::read_from_instance_id(&mut context.pool(), object_creator.instance_id)
|
||||||
|
.await?
|
||||||
|
.map(Into::into);
|
||||||
|
if let Some(inbox) = object_creator_site.map(|s| s.shared_inbox_or_inbox()) {
|
||||||
|
inboxes.add_inbox(inbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
send_lemmy_activity(&context, report, &actor, inboxes, false).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -313,6 +313,7 @@ mod tests {
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
use lemmy_db_views_actor::structs::CommunityFollowerView;
|
use lemmy_db_views_actor::structs::CommunityFollowerView;
|
||||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
|
@ -119,6 +119,7 @@ mod tests {
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyResult;
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -200,6 +200,7 @@ pub(crate) mod tests {
|
||||||
use html2md::parse_html;
|
use html2md::parse_html;
|
||||||
use lemmy_db_schema::source::site::Site;
|
use lemmy_db_schema::source::site::Site;
|
||||||
use lemmy_utils::error::LemmyResult;
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
async fn prepare_comment_test(
|
async fn prepare_comment_test(
|
||||||
|
|
|
@ -264,6 +264,7 @@ pub(crate) mod tests {
|
||||||
use activitypub_federation::fetch::collection_id::CollectionId;
|
use activitypub_federation::fetch::collection_id::CollectionId;
|
||||||
use lemmy_db_schema::{source::site::Site, traits::Crud};
|
use lemmy_db_schema::{source::site::Site, traits::Crud};
|
||||||
use lemmy_utils::error::LemmyResult;
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
pub(crate) async fn parse_lemmy_community(
|
pub(crate) async fn parse_lemmy_community(
|
||||||
|
|
|
@ -218,6 +218,7 @@ pub(crate) mod tests {
|
||||||
use crate::protocol::tests::file_to_json_object;
|
use crate::protocol::tests::file_to_json_object;
|
||||||
use lemmy_db_schema::traits::Crud;
|
use lemmy_db_schema::traits::Crud;
|
||||||
use lemmy_utils::error::LemmyResult;
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
pub(crate) async fn parse_lemmy_instance(context: &Data<LemmyContext>) -> LemmyResult<ApubSite> {
|
pub(crate) async fn parse_lemmy_instance(context: &Data<LemmyContext>) -> LemmyResult<ApubSite> {
|
||||||
|
|
|
@ -227,6 +227,7 @@ pub(crate) mod tests {
|
||||||
use activitypub_federation::fetch::object_id::ObjectId;
|
use activitypub_federation::fetch::object_id::ObjectId;
|
||||||
use lemmy_db_schema::{source::site::Site, traits::Crud};
|
use lemmy_db_schema::{source::site::Site, traits::Crud};
|
||||||
use lemmy_utils::error::LemmyResult;
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
pub(crate) async fn parse_lemmy_person(
|
pub(crate) async fn parse_lemmy_person(
|
||||||
|
|
|
@ -303,6 +303,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::source::site::Site;
|
use lemmy_db_schema::source::site::Site;
|
||||||
use lemmy_utils::error::LemmyResult;
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -159,6 +159,7 @@ mod tests {
|
||||||
use assert_json_diff::assert_json_include;
|
use assert_json_diff::assert_json_include;
|
||||||
use lemmy_db_schema::source::site::Site;
|
use lemmy_db_schema::source::site::Site;
|
||||||
use lemmy_utils::error::LemmyResult;
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
async fn prepare_comment_test(
|
async fn prepare_comment_test(
|
||||||
|
|
|
@ -17,6 +17,7 @@ mod tests {
|
||||||
tests::{test_json, test_parse_lemmy_item},
|
tests::{test_json, test_parse_lemmy_item},
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyResult;
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_lemmy_collections() -> LemmyResult<()> {
|
fn test_parse_lemmy_collections() -> LemmyResult<()> {
|
||||||
|
|
|
@ -79,6 +79,7 @@ typed-builder = "0.15.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test = { workspace = true }
|
serial_test = { workspace = true }
|
||||||
|
pretty_assertions = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.cargo-machete]
|
[package.metadata.cargo-machete]
|
||||||
ignored = ["strum"]
|
ignored = ["strum"]
|
||||||
|
|
|
@ -49,6 +49,7 @@ mod tests {
|
||||||
traits::{Crud, Likeable},
|
traits::{Crud, Likeable},
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -47,6 +47,7 @@ mod tests {
|
||||||
traits::{Crud, Followable},
|
traits::{Crud, Followable},
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -34,6 +34,7 @@ mod tests {
|
||||||
traits::{Crud, Likeable},
|
traits::{Crud, Likeable},
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -68,6 +68,7 @@ mod tests {
|
||||||
traits::{Crud, Likeable},
|
traits::{Crud, Likeable},
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -31,6 +31,7 @@ mod tests {
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::{build_db_pool_for_tests, DbPool},
|
utils::{build_db_pool_for_tests, DbPool},
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
async fn prepare_site_with_community(
|
async fn prepare_site_with_community(
|
||||||
|
|
|
@ -67,6 +67,7 @@ mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{source::activity::ActorType, utils::build_db_pool_for_tests};
|
use crate::{source::activity::ActorType, utils::build_db_pool_for_tests};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
|
@ -412,6 +412,7 @@ mod tests {
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
async fn test_langs1(pool: &mut DbPool<'_>) -> Vec<LanguageId> {
|
async fn test_langs1(pool: &mut DbPool<'_>) -> Vec<LanguageId> {
|
||||||
|
|
|
@ -263,6 +263,7 @@ mod tests {
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
use diesel_ltree::Ltree;
|
use diesel_ltree::Ltree;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -89,6 +89,7 @@ mod tests {
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -366,6 +366,7 @@ mod tests {
|
||||||
traits::{Bannable, Crud, Followable, Joinable},
|
traits::{Bannable, Crud, Followable, Joinable},
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -56,6 +56,7 @@ mod tests {
|
||||||
source::{federation_allowlist::FederationAllowList, instance::Instance},
|
source::{federation_allowlist::FederationAllowList, instance::Instance},
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -46,6 +46,7 @@ mod tests {
|
||||||
#![allow(clippy::indexing_slicing)]
|
#![allow(clippy::indexing_slicing)]
|
||||||
|
|
||||||
use crate::{source::language::Language, utils::build_db_pool_for_tests};
|
use crate::{source::language::Language, utils::build_db_pool_for_tests};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -500,6 +500,7 @@ mod tests {
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -95,6 +95,7 @@ mod tests {
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -191,6 +191,7 @@ mod tests {
|
||||||
traits::{Crud, Followable},
|
traits::{Crud, Followable},
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -90,6 +90,7 @@ mod tests {
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -366,6 +366,7 @@ mod tests {
|
||||||
traits::{Crud, Likeable, Saveable},
|
traits::{Crud, Likeable, Saveable},
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,7 @@ mod tests {
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
async fn init(pool: &mut DbPool<'_>) -> (Person, PostReport) {
|
async fn init(pool: &mut DbPool<'_>) -> (Person, PostReport) {
|
||||||
|
|
|
@ -87,6 +87,7 @@ mod tests {
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -439,6 +439,7 @@ mod tests {
|
||||||
|
|
||||||
use super::{fuzzy_search, *};
|
use super::{fuzzy_search, *};
|
||||||
use crate::utils::is_email_regex;
|
use crate::utils::is_email_regex;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fuzzy_search() {
|
fn test_fuzzy_search() {
|
||||||
|
|
|
@ -42,3 +42,4 @@ actix-web = { workspace = true, optional = true }
|
||||||
serial_test = { workspace = true }
|
serial_test = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
|
pretty_assertions = { workspace = true }
|
||||||
|
|
|
@ -234,6 +234,7 @@ mod tests {
|
||||||
traits::{Crud, Joinable, Reportable},
|
traits::{Crud, Joinable, Reportable},
|
||||||
utils::{build_db_pool_for_tests, RANK_DEFAULT},
|
utils::{build_db_pool_for_tests, RANK_DEFAULT},
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -416,6 +416,7 @@ mod tests {
|
||||||
utils::{build_db_pool_for_tests, RANK_DEFAULT},
|
utils::{build_db_pool_for_tests, RANK_DEFAULT},
|
||||||
SubscribedType,
|
SubscribedType,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
|
|
|
@ -22,3 +22,5 @@ pub mod registration_application_view;
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
pub mod site_view;
|
pub mod site_view;
|
||||||
pub mod structs;
|
pub mod structs;
|
||||||
|
#[cfg(feature = "full")]
|
||||||
|
pub mod vote_view;
|
||||||
|
|
|
@ -208,6 +208,7 @@ mod tests {
|
||||||
traits::{Crud, Joinable, Reportable},
|
traits::{Crud, Joinable, Reportable},
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -749,6 +749,7 @@ mod tests {
|
||||||
SortType,
|
SortType,
|
||||||
SubscribedType,
|
SubscribedType,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::{assert_eq, assert_ne};
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
use std::{collections::HashSet, time::Duration};
|
use std::{collections::HashSet, time::Duration};
|
||||||
|
|
||||||
|
|
|
@ -121,6 +121,7 @@ mod tests {
|
||||||
traits::{Crud, Reportable},
|
traits::{Crud, Reportable},
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -168,6 +168,7 @@ mod tests {
|
||||||
traits::{Blockable, Crud},
|
traits::{Blockable, Crud},
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -149,6 +149,7 @@ mod tests {
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -184,3 +184,14 @@ pub struct CustomEmojiView {
|
||||||
pub custom_emoji: CustomEmoji,
|
pub custom_emoji: CustomEmoji,
|
||||||
pub keywords: Vec<CustomEmojiKeyword>,
|
pub keywords: Vec<CustomEmojiKeyword>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
|
||||||
|
#[cfg_attr(feature = "full", derive(TS, Queryable))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
/// A vote view for checking a post or comments votes.
|
||||||
|
pub struct VoteView {
|
||||||
|
pub creator: Person,
|
||||||
|
pub score: i16,
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,196 @@
|
||||||
|
use crate::structs::VoteView;
|
||||||
|
use diesel::{result::Error, ExpressionMethods, QueryDsl};
|
||||||
|
use diesel_async::RunQueryDsl;
|
||||||
|
use lemmy_db_schema::{
|
||||||
|
newtypes::{CommentId, PostId},
|
||||||
|
schema::{comment_like, person, post_like},
|
||||||
|
utils::{get_conn, limit_and_offset, DbPool},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl VoteView {
|
||||||
|
pub async fn list_for_post(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
post_id: PostId,
|
||||||
|
page: Option<i64>,
|
||||||
|
limit: Option<i64>,
|
||||||
|
) -> Result<Vec<Self>, Error> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
let (limit, offset) = limit_and_offset(page, limit)?;
|
||||||
|
|
||||||
|
post_like::table
|
||||||
|
.inner_join(person::table)
|
||||||
|
.filter(post_like::post_id.eq(post_id))
|
||||||
|
.select((person::all_columns, post_like::score))
|
||||||
|
.order_by(post_like::score)
|
||||||
|
.limit(limit)
|
||||||
|
.offset(offset)
|
||||||
|
.load::<Self>(conn)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn list_for_comment(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
comment_id: CommentId,
|
||||||
|
page: Option<i64>,
|
||||||
|
limit: Option<i64>,
|
||||||
|
) -> Result<Vec<Self>, Error> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
let (limit, offset) = limit_and_offset(page, limit)?;
|
||||||
|
|
||||||
|
comment_like::table
|
||||||
|
.inner_join(person::table)
|
||||||
|
.filter(comment_like::comment_id.eq(comment_id))
|
||||||
|
.select((person::all_columns, comment_like::score))
|
||||||
|
.order_by(comment_like::score)
|
||||||
|
.limit(limit)
|
||||||
|
.offset(offset)
|
||||||
|
.load::<Self>(conn)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#![allow(clippy::unwrap_used)]
|
||||||
|
#![allow(clippy::indexing_slicing)]
|
||||||
|
|
||||||
|
use crate::structs::VoteView;
|
||||||
|
use lemmy_db_schema::{
|
||||||
|
source::{
|
||||||
|
comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm},
|
||||||
|
community::{Community, CommunityInsertForm},
|
||||||
|
instance::Instance,
|
||||||
|
person::{Person, PersonInsertForm},
|
||||||
|
post::{Post, PostInsertForm, PostLike, PostLikeForm},
|
||||||
|
},
|
||||||
|
traits::{Crud, Likeable},
|
||||||
|
utils::build_db_pool_for_tests,
|
||||||
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use serial_test::serial;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
|
async fn post_and_comment_vote_views() {
|
||||||
|
let pool = &build_db_pool_for_tests().await;
|
||||||
|
let pool = &mut pool.into();
|
||||||
|
|
||||||
|
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let new_person = PersonInsertForm::builder()
|
||||||
|
.name("timmy_vv".into())
|
||||||
|
.public_key("pubkey".to_string())
|
||||||
|
.instance_id(inserted_instance.id)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let inserted_timmy = Person::create(pool, &new_person).await.unwrap();
|
||||||
|
|
||||||
|
let new_person_2 = PersonInsertForm::builder()
|
||||||
|
.name("sara_vv".into())
|
||||||
|
.public_key("pubkey".to_string())
|
||||||
|
.instance_id(inserted_instance.id)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let inserted_sara = Person::create(pool, &new_person_2).await.unwrap();
|
||||||
|
|
||||||
|
let new_community = CommunityInsertForm::builder()
|
||||||
|
.name("test community vv".to_string())
|
||||||
|
.title("nada".to_owned())
|
||||||
|
.public_key("pubkey".to_string())
|
||||||
|
.instance_id(inserted_instance.id)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let inserted_community = Community::create(pool, &new_community).await.unwrap();
|
||||||
|
|
||||||
|
let new_post = PostInsertForm::builder()
|
||||||
|
.name("A test post vv".into())
|
||||||
|
.creator_id(inserted_timmy.id)
|
||||||
|
.community_id(inserted_community.id)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let inserted_post = Post::create(pool, &new_post).await.unwrap();
|
||||||
|
|
||||||
|
let comment_form = CommentInsertForm::builder()
|
||||||
|
.content("A test comment vv".into())
|
||||||
|
.creator_id(inserted_timmy.id)
|
||||||
|
.post_id(inserted_post.id)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let inserted_comment = Comment::create(pool, &comment_form, None).await.unwrap();
|
||||||
|
|
||||||
|
// Timmy upvotes his own post
|
||||||
|
let timmy_post_vote_form = PostLikeForm {
|
||||||
|
post_id: inserted_post.id,
|
||||||
|
person_id: inserted_timmy.id,
|
||||||
|
score: 1,
|
||||||
|
};
|
||||||
|
PostLike::like(pool, &timmy_post_vote_form).await.unwrap();
|
||||||
|
|
||||||
|
// Sara downvotes timmy's post
|
||||||
|
let sara_post_vote_form = PostLikeForm {
|
||||||
|
post_id: inserted_post.id,
|
||||||
|
person_id: inserted_sara.id,
|
||||||
|
score: -1,
|
||||||
|
};
|
||||||
|
PostLike::like(pool, &sara_post_vote_form).await.unwrap();
|
||||||
|
|
||||||
|
let expected_post_vote_views = [
|
||||||
|
VoteView {
|
||||||
|
creator: inserted_sara.clone(),
|
||||||
|
score: -1,
|
||||||
|
},
|
||||||
|
VoteView {
|
||||||
|
creator: inserted_timmy.clone(),
|
||||||
|
score: 1,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let read_post_vote_views = VoteView::list_for_post(pool, inserted_post.id, None, None)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(read_post_vote_views, expected_post_vote_views);
|
||||||
|
|
||||||
|
// Timothy votes down his own comment
|
||||||
|
let timmy_comment_vote_form = CommentLikeForm {
|
||||||
|
post_id: inserted_post.id,
|
||||||
|
comment_id: inserted_comment.id,
|
||||||
|
person_id: inserted_timmy.id,
|
||||||
|
score: -1,
|
||||||
|
};
|
||||||
|
CommentLike::like(pool, &timmy_comment_vote_form)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Sara upvotes timmy's comment
|
||||||
|
let sara_comment_vote_form = CommentLikeForm {
|
||||||
|
post_id: inserted_post.id,
|
||||||
|
comment_id: inserted_comment.id,
|
||||||
|
person_id: inserted_sara.id,
|
||||||
|
score: 1,
|
||||||
|
};
|
||||||
|
CommentLike::like(pool, &sara_comment_vote_form)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let expected_comment_vote_views = [
|
||||||
|
VoteView {
|
||||||
|
creator: inserted_timmy.clone(),
|
||||||
|
score: -1,
|
||||||
|
},
|
||||||
|
VoteView {
|
||||||
|
creator: inserted_sara.clone(),
|
||||||
|
score: 1,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let read_comment_vote_views = VoteView::list_for_comment(pool, inserted_comment.id, None, None)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(read_comment_vote_views, expected_comment_vote_views);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
Instance::delete(pool, inserted_instance.id).await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ strum_macros = { workspace = true }
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test = { workspace = true }
|
serial_test = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
pretty_assertions = { workspace = true }
|
||||||
|
|
||||||
[package.metadata.cargo-machete]
|
[package.metadata.cargo-machete]
|
||||||
ignored = ["strum"]
|
ignored = ["strum"]
|
||||||
|
|
|
@ -167,6 +167,7 @@ mod tests {
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
|
|
|
@ -23,6 +23,7 @@ static INSTANCES_RECHECK_DELAY: Duration = Duration::from_secs(5);
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
static INSTANCES_RECHECK_DELAY: Duration = Duration::from_secs(60);
|
static INSTANCES_RECHECK_DELAY: Duration = Duration::from_secs(60);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Opts {
|
pub struct Opts {
|
||||||
/// how many processes you are starting in total
|
/// how many processes you are starting in total
|
||||||
pub process_count: i32,
|
pub process_count: i32,
|
||||||
|
@ -36,7 +37,7 @@ async fn start_stop_federation_workers(
|
||||||
federation_config: FederationConfig<LemmyContext>,
|
federation_config: FederationConfig<LemmyContext>,
|
||||||
cancel: CancellationToken,
|
cancel: CancellationToken,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let mut workers = HashMap::<InstanceId, CancellableTask<_>>::new();
|
let mut workers = HashMap::<InstanceId, CancellableTask>::new();
|
||||||
|
|
||||||
let (stats_sender, stats_receiver) = unbounded_channel();
|
let (stats_sender, stats_receiver) = unbounded_channel();
|
||||||
let exit_print = tokio::spawn(receive_print_stats(pool.clone(), stats_receiver));
|
let exit_print = tokio::spawn(receive_print_stats(pool.clone(), stats_receiver));
|
||||||
|
@ -66,40 +67,30 @@ async fn start_stop_federation_workers(
|
||||||
let should_federate = allowed && !is_dead;
|
let should_federate = allowed && !is_dead;
|
||||||
if should_federate {
|
if should_federate {
|
||||||
if workers.contains_key(&instance.id) {
|
if workers.contains_key(&instance.id) {
|
||||||
if workers
|
// worker already running
|
||||||
.get(&instance.id)
|
continue;
|
||||||
.map(util::CancellableTask::has_ended)
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
// task must have errored out, remove and recreated it
|
|
||||||
let worker = workers
|
|
||||||
.remove(&instance.id)
|
|
||||||
.expect("just checked contains_key");
|
|
||||||
tracing::error!(
|
|
||||||
"worker for {} has stopped, recreating: {:?}",
|
|
||||||
instance.domain,
|
|
||||||
worker.cancel().await
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// create new worker
|
// create new worker
|
||||||
|
let config = federation_config.clone();
|
||||||
let stats_sender = stats_sender.clone();
|
let stats_sender = stats_sender.clone();
|
||||||
let context = federation_config.to_request_data();
|
|
||||||
let pool = pool.clone();
|
let pool = pool.clone();
|
||||||
workers.insert(
|
workers.insert(
|
||||||
instance.id,
|
instance.id,
|
||||||
CancellableTask::spawn(WORKER_EXIT_TIMEOUT, |stop| async move {
|
CancellableTask::spawn(WORKER_EXIT_TIMEOUT, move |stop| {
|
||||||
InstanceWorker::init_and_loop(
|
let instance = instance.clone();
|
||||||
instance,
|
let req_data = config.clone().to_request_data();
|
||||||
context,
|
let stats_sender = stats_sender.clone();
|
||||||
&mut DbPool::Pool(&pool),
|
let pool = pool.clone();
|
||||||
stop,
|
async move {
|
||||||
stats_sender,
|
InstanceWorker::init_and_loop(
|
||||||
)
|
instance,
|
||||||
.await?;
|
req_data,
|
||||||
Ok(())
|
&mut DbPool::Pool(&pool),
|
||||||
|
stop,
|
||||||
|
stats_sender,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} else if !should_federate {
|
} else if !should_federate {
|
||||||
|
@ -135,9 +126,12 @@ pub fn start_stop_federation_workers_cancellable(
|
||||||
opts: Opts,
|
opts: Opts,
|
||||||
pool: ActualDbPool,
|
pool: ActualDbPool,
|
||||||
config: FederationConfig<LemmyContext>,
|
config: FederationConfig<LemmyContext>,
|
||||||
) -> CancellableTask<()> {
|
) -> CancellableTask {
|
||||||
CancellableTask::spawn(WORKER_EXIT_TIMEOUT, move |c| {
|
CancellableTask::spawn(WORKER_EXIT_TIMEOUT, move |stop| {
|
||||||
start_stop_federation_workers(opts, pool, config, c)
|
let opts = opts.clone();
|
||||||
|
let pool = pool.clone();
|
||||||
|
let config = config.clone();
|
||||||
|
async move { start_stop_federation_workers(opts, pool, config, stop).await }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,7 @@ use moka::future::Cache;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::{
|
use std::{fmt::Debug, future::Future, pin::Pin, sync::Arc, time::Duration};
|
||||||
future::Future,
|
|
||||||
pin::Pin,
|
|
||||||
sync::{Arc, RwLock},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
use tokio::{task::JoinHandle, time::sleep};
|
use tokio::{task::JoinHandle, time::sleep};
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
|
@ -49,41 +44,41 @@ pub(crate) static WORK_FINISHED_RECHECK_DELAY: Lazy<Duration> = Lazy::new(|| {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
pub struct CancellableTask<R: Send + 'static> {
|
/// A task that will be run in an infinite loop, unless it is cancelled.
|
||||||
f: Pin<Box<dyn Future<Output = Result<R, anyhow::Error>> + Send + 'static>>,
|
/// If the task exits without being cancelled, an error will be logged and the task will be restarted.
|
||||||
ended: Arc<RwLock<bool>>,
|
pub struct CancellableTask {
|
||||||
|
f: Pin<Box<dyn Future<Output = Result<(), anyhow::Error>> + Send + 'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Send + 'static> CancellableTask<R> {
|
impl CancellableTask {
|
||||||
/// spawn a task but with graceful shutdown
|
/// spawn a task but with graceful shutdown
|
||||||
pub fn spawn<F>(
|
pub fn spawn<F, R: Debug>(
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
task: impl FnOnce(CancellationToken) -> F,
|
task: impl Fn(CancellationToken) -> F + Send + 'static,
|
||||||
) -> CancellableTask<R>
|
) -> CancellableTask
|
||||||
where
|
where
|
||||||
F: Future<Output = Result<R>> + Send + 'static,
|
F: Future<Output = R> + Send + 'static,
|
||||||
{
|
{
|
||||||
let stop = CancellationToken::new();
|
let stop = CancellationToken::new();
|
||||||
let task = task(stop.clone());
|
let stop2 = stop.clone();
|
||||||
let ended = Arc::new(RwLock::new(false));
|
let task: JoinHandle<()> = tokio::spawn(async move {
|
||||||
let ended_write = ended.clone();
|
loop {
|
||||||
let task: JoinHandle<Result<R>> = tokio::spawn(async move {
|
let res = task(stop2.clone()).await;
|
||||||
match task.await {
|
if stop2.is_cancelled() {
|
||||||
Ok(o) => Ok(o),
|
return;
|
||||||
Err(e) => {
|
} else {
|
||||||
*ended_write.write().expect("poisoned") = true;
|
tracing::warn!("task exited, restarting: {res:?}");
|
||||||
Err(e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let abort = task.abort_handle();
|
let abort = task.abort_handle();
|
||||||
CancellableTask {
|
CancellableTask {
|
||||||
ended,
|
|
||||||
f: Box::pin(async move {
|
f: Box::pin(async move {
|
||||||
stop.cancel();
|
stop.cancel();
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
r = task => {
|
r = task => {
|
||||||
Ok(r.context("could not join")??)
|
r.context("could not join")?;
|
||||||
|
Ok(())
|
||||||
},
|
},
|
||||||
_ = sleep(timeout) => {
|
_ = sleep(timeout) => {
|
||||||
abort.abort();
|
abort.abort();
|
||||||
|
@ -96,12 +91,9 @@ impl<R: Send + 'static> CancellableTask<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// cancel the cancel signal, wait for timeout for the task to stop gracefully, otherwise abort it
|
/// cancel the cancel signal, wait for timeout for the task to stop gracefully, otherwise abort it
|
||||||
pub async fn cancel(self) -> Result<R, anyhow::Error> {
|
pub async fn cancel(self) -> Result<(), anyhow::Error> {
|
||||||
self.f.await
|
self.f.await
|
||||||
}
|
}
|
||||||
pub fn has_ended(&self) -> bool {
|
|
||||||
*self.ended.read().expect("poisoned")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// assuming apub priv key and ids are immutable, then we don't need to have TTL
|
/// assuming apub priv key and ids are immutable, then we don't need to have TTL
|
||||||
|
|
|
@ -206,6 +206,7 @@ impl InstanceWorker {
|
||||||
.await
|
.await
|
||||||
.context("failed figuring out inbox urls")?;
|
.context("failed figuring out inbox urls")?;
|
||||||
if inbox_urls.is_empty() {
|
if inbox_urls.is_empty() {
|
||||||
|
tracing::debug!("{}: {:?} no inboxes", self.instance.domain, activity.id);
|
||||||
self.state.last_successful_id = Some(activity.id);
|
self.state.last_successful_id = Some(activity.id);
|
||||||
self.state.last_successful_published_time = Some(activity.published);
|
self.state.last_successful_published_time = Some(activity.published);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use lemmy_api_common::{claims::Claims, context::LemmyContext, utils::check_user_valid};
|
use lemmy_api_common::{claims::Claims, context::LemmyContext, utils::check_user_valid};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt2, LemmyErrorType};
|
||||||
|
|
||||||
pub mod feeds;
|
pub mod feeds;
|
||||||
pub mod images;
|
pub mod images;
|
||||||
|
@ -12,7 +12,9 @@ async fn local_user_view_from_jwt(
|
||||||
jwt: &str,
|
jwt: &str,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
) -> Result<LocalUserView, LemmyError> {
|
) -> Result<LocalUserView, LemmyError> {
|
||||||
let local_user_id = Claims::validate(jwt, context).await?;
|
let local_user_id = Claims::validate(jwt, context)
|
||||||
|
.await
|
||||||
|
.with_lemmy_type(LemmyErrorType::NotLoggedIn)?;
|
||||||
let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id).await?;
|
let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id).await?;
|
||||||
check_user_valid(&local_user_view.person)?;
|
check_user_valid(&local_user_view.person)?;
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ enum-map = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
reqwest = { workspace = true }
|
reqwest = { workspace = true }
|
||||||
|
pretty_assertions = { workspace = true }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
rosetta-build = { version = "0.1.3", default-features = false }
|
rosetta-build = { version = "0.1.3", default-features = false }
|
||||||
|
|
|
@ -279,6 +279,7 @@ mod tests {
|
||||||
#![allow(clippy::indexing_slicing)]
|
#![allow(clippy::indexing_slicing)]
|
||||||
use super::*;
|
use super::*;
|
||||||
use actix_web::{body::MessageBody, ResponseError};
|
use actix_web::{body::MessageBody, ResponseError};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
|
|
@ -310,6 +310,7 @@ mod tests {
|
||||||
#![allow(clippy::indexing_slicing)]
|
#![allow(clippy::indexing_slicing)]
|
||||||
|
|
||||||
use super::{ActionType, BucketConfig, InstantSecs, RateLimitState, RateLimitedGroup};
|
use super::{ActionType, BucketConfig, InstantSecs, RateLimitState, RateLimitedGroup};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_split_ipv6() {
|
fn test_split_ipv6() {
|
||||||
|
|
|
@ -46,6 +46,7 @@ mod tests {
|
||||||
Responder,
|
Responder,
|
||||||
};
|
};
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn test_non_error_responses_are_not_modified() {
|
async fn test_non_error_responses_are_not_modified() {
|
||||||
|
|
|
@ -104,6 +104,7 @@ mod tests {
|
||||||
#![allow(clippy::indexing_slicing)]
|
#![allow(clippy::indexing_slicing)]
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_basic_markdown() {
|
fn test_basic_markdown() {
|
||||||
|
|
|
@ -140,6 +140,7 @@ mod tests {
|
||||||
|
|
||||||
use crate::utils::markdown::spoiler_rule::add;
|
use crate::utils::markdown::spoiler_rule::add;
|
||||||
use markdown_it::MarkdownIt;
|
use markdown_it::MarkdownIt;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_spoiler_markdown() {
|
fn test_spoiler_markdown() {
|
||||||
|
|
|
@ -39,6 +39,7 @@ mod test {
|
||||||
#![allow(clippy::indexing_slicing)]
|
#![allow(clippy::indexing_slicing)]
|
||||||
|
|
||||||
use crate::utils::mention::scrape_text_for_mentions;
|
use crate::utils::mention::scrape_text_for_mentions;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mentions_regex() {
|
fn test_mentions_regex() {
|
||||||
|
|
|
@ -69,6 +69,7 @@ mod test {
|
||||||
#![allow(clippy::indexing_slicing)]
|
#![allow(clippy::indexing_slicing)]
|
||||||
|
|
||||||
use crate::utils::slurs::{remove_slurs, slur_check, slurs_vec_to_str};
|
use crate::utils::slurs::{remove_slurs, slur_check, slurs_vec_to_str};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use regex::RegexBuilder;
|
use regex::RegexBuilder;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -6,7 +6,7 @@ use url::Url;
|
||||||
|
|
||||||
// From here: https://github.com/vector-im/element-android/blob/develop/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt#L35
|
// From here: https://github.com/vector-im/element-android/blob/develop/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt#L35
|
||||||
static VALID_MATRIX_ID_REGEX: Lazy<Regex> = Lazy::new(|| {
|
static VALID_MATRIX_ID_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||||
Regex::new(r"^@[A-Za-z0-9\\x21-\\x39\\x3B-\\x7F]+:[A-Za-z0-9.-]+(:[0-9]{2,5})?$")
|
Regex::new(r"^@[A-Za-z0-9\x21-\x39\x3B-\x7F]+:[A-Za-z0-9.-]+(:[0-9]{2,5})?$")
|
||||||
.expect("compile regex")
|
.expect("compile regex")
|
||||||
});
|
});
|
||||||
// taken from https://en.wikipedia.org/wiki/UTM_parameters
|
// taken from https://en.wikipedia.org/wiki/UTM_parameters
|
||||||
|
@ -310,6 +310,7 @@ mod tests {
|
||||||
SITE_NAME_MAX_LENGTH,
|
SITE_NAME_MAX_LENGTH,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -386,6 +387,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_valid_matrix_id() {
|
fn test_valid_matrix_id() {
|
||||||
assert!(is_valid_matrix_id("@dess:matrix.org").is_ok());
|
assert!(is_valid_matrix_id("@dess:matrix.org").is_ok());
|
||||||
|
assert!(is_valid_matrix_id("@dess_:matrix.org").is_ok());
|
||||||
assert!(is_valid_matrix_id("@dess:matrix.org:443").is_ok());
|
assert!(is_valid_matrix_id("@dess:matrix.org:443").is_ok());
|
||||||
assert!(is_valid_matrix_id("dess:matrix.org").is_err());
|
assert!(is_valid_matrix_id("dess:matrix.org").is_err());
|
||||||
assert!(is_valid_matrix_id(" @dess:matrix.org").is_err());
|
assert!(is_valid_matrix_id(" @dess:matrix.org").is_err());
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE site
|
||||||
|
ADD CONSTRAINT site_name_key UNIQUE (name);
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE site
|
||||||
|
DROP CONSTRAINT site_name_key;
|
||||||
|
|
|
@ -45,9 +45,9 @@
|
||||||
|
|
||||||
## Sobre El Proyecto
|
## Sobre El Proyecto
|
||||||
|
|
||||||
| Escritorio | Móvil |
|
| Escritorio | Móvil |
|
||||||
| ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
| --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||||
| ![desktop](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/main_img.webp) | ![mobile](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/mobile_pic.webp) |
|
| ![desktop](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/main_screen_2.webp) | ![mobile](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/mobile_pic.webp) |
|
||||||
|
|
||||||
[Lemmy](https://github.com/LemmyNet/lemmy) es similar a sitios como [Menéame](https://www.meneame.net/), [Reddit](https://reddit.com), [Lobste.rs](https://lobste.rs), [Raddle](https://raddle.me), o [Hacker News](https://news.ycombinator.com/): te subscribes a los foros que te interesan, publicas enlaces y debates, luego votas y comentas en ellos. Entre bastidores, es muy diferente; cualquiera puede gestionar fácilmente un servidor, y todos estos servidores son federados (piensa en el correo electrónico), y conectados al mismo universo, llamado [Fediverso](https://es.wikipedia.org/wiki/Fediverso).
|
[Lemmy](https://github.com/LemmyNet/lemmy) es similar a sitios como [Menéame](https://www.meneame.net/), [Reddit](https://reddit.com), [Lobste.rs](https://lobste.rs), [Raddle](https://raddle.me), o [Hacker News](https://news.ycombinator.com/): te subscribes a los foros que te interesan, publicas enlaces y debates, luego votas y comentas en ellos. Entre bastidores, es muy diferente; cualquiera puede gestionar fácilmente un servidor, y todos estos servidores son federados (piensa en el correo electrónico), y conectados al mismo universo, llamado [Fediverso](https://es.wikipedia.org/wiki/Fediverso).
|
||||||
|
|
||||||
|
|
|
@ -47,9 +47,9 @@
|
||||||
|
|
||||||
## プロジェクトについて
|
## プロジェクトについて
|
||||||
|
|
||||||
| デスクトップ | モバイル |
|
| デスクトップ | モバイル |
|
||||||
| ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
| --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||||
| ![desktop](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/main_img.webp) | ![mobile](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/mobile_pic.webp) |
|
| ![desktop](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/main_screen_2.webp) | ![mobile](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/mobile_pic.webp) |
|
||||||
|
|
||||||
[Lemmy](https://github.com/LemmyNet/lemmy) は、[Reddit](https://reddit.com)、[Lobste.rs](https://lobste.rs)、[Hacker News](https://news.ycombinator.com/) といったサイトに似ています。興味のあるフォーラムを購読してリンクや議論を掲載し、投票したり、コメントしたりしています。誰でも簡単にサーバーを運営することができ、これらのサーバーはすべて連合しており(電子メールを考えてください)、[Fediverse](https://en.wikipedia.org/wiki/Fediverse) と呼ばれる同じ宇宙に接続されています。
|
[Lemmy](https://github.com/LemmyNet/lemmy) は、[Reddit](https://reddit.com)、[Lobste.rs](https://lobste.rs)、[Hacker News](https://news.ycombinator.com/) といったサイトに似ています。興味のあるフォーラムを購読してリンクや議論を掲載し、投票したり、コメントしたりしています。誰でも簡単にサーバーを運営することができ、これらのサーバーはすべて連合しており(電子メールを考えてください)、[Fediverse](https://en.wikipedia.org/wiki/Fediverse) と呼ばれる同じ宇宙に接続されています。
|
||||||
|
|
||||||
|
|
|
@ -45,9 +45,9 @@
|
||||||
|
|
||||||
## О проекте
|
## О проекте
|
||||||
|
|
||||||
| Десктоп | Мобильный |
|
| Десктоп | Мобильный |
|
||||||
| ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
| --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||||
| ![desktop](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/main_img.webp) | ![mobile](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/mobile_pic.webp) |
|
| ![desktop](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/main_screen_2.webp) | ![mobile](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/mobile_pic.webp) |
|
||||||
|
|
||||||
[Lemmy](https://github.com/LemmyNet/lemmy) это аналог таких сайтов как [Reddit](https://reddit.com), [Lobste.rs](https://lobste.rs), или [Hacker News](https://news.ycombinator.com/): вы подписываетесь на форумы, которые вас интересуют , размещаете ссылки и дискутируете, затем голосуете и комментируете их. Однако за кулисами всё совсем по-другому; любой может легко запустить сервер, и все эти серверы объединены (например электронная почта) и подключены к одной вселенной, именуемой [Федиверс](https://ru.wikipedia.org/wiki/Fediverse).
|
[Lemmy](https://github.com/LemmyNet/lemmy) это аналог таких сайтов как [Reddit](https://reddit.com), [Lobste.rs](https://lobste.rs), или [Hacker News](https://news.ycombinator.com/): вы подписываетесь на форумы, которые вас интересуют , размещаете ссылки и дискутируете, затем голосуете и комментируете их. Однако за кулисами всё совсем по-другому; любой может легко запустить сервер, и все эти серверы объединены (например электронная почта) и подключены к одной вселенной, именуемой [Федиверс](https://ru.wikipedia.org/wiki/Fediverse).
|
||||||
|
|
||||||
|
|
|
@ -47,9 +47,9 @@
|
||||||
|
|
||||||
## 关于项目
|
## 关于项目
|
||||||
|
|
||||||
| 桌面应用 | 移动应用 |
|
| 桌面应用 | 移动应用 |
|
||||||
| ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
| --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||||
| ![desktop](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/main_img.webp) | ![mobile](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/mobile_pic.webp) |
|
| ![desktop](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/main_screen_2.webp) | ![mobile](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/mobile_pic.webp) |
|
||||||
|
|
||||||
[Lemmy](https://github.com/LemmyNet/lemmy) 与 [Reddit](https://reddit.com)、[Lobste.rs](https://lobste.rs) 或 [Hacker News](https://news.ycombinator.com/) 等网站类似:你可以订阅你感兴趣的论坛,发布链接和讨论,然后进行投票或评论。但在幕后,Lemmy 和他们不同——任何人都可以很容易地运行一个服务器,所有服务器都是联邦式的(想想电子邮件),并连接到 [联邦宇宙](https://zh.wikipedia.org/wiki/%E8%81%94%E9%82%A6%E5%AE%87%E5%AE%99)。
|
[Lemmy](https://github.com/LemmyNet/lemmy) 与 [Reddit](https://reddit.com)、[Lobste.rs](https://lobste.rs) 或 [Hacker News](https://news.ycombinator.com/) 等网站类似:你可以订阅你感兴趣的论坛,发布链接和讨论,然后进行投票或评论。但在幕后,Lemmy 和他们不同——任何人都可以很容易地运行一个服务器,所有服务器都是联邦式的(想想电子邮件),并连接到 [联邦宇宙](https://zh.wikipedia.org/wiki/%E8%81%94%E9%82%A6%E5%AE%87%E5%AE%99)。
|
||||||
|
|
||||||
|
|
|
@ -48,9 +48,9 @@
|
||||||
|
|
||||||
## 關於專案
|
## 關於專案
|
||||||
|
|
||||||
| 桌面設備 | 行動裝置 |
|
| 桌面設備 | 行動裝置 |
|
||||||
| ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
| --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||||
| ![desktop](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/main_img.webp) | ![mobile](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/mobile_pic.webp) |
|
| ![desktop](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/main_screen_2.webp) | ![mobile](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/mobile_pic.webp) |
|
||||||
|
|
||||||
[Lemmy](https://github.com/LemmyNet/lemmy) 與 [Reddit](https://reddit.com)、[Lobste.rs](https://lobste.rs) 或 [Hacker News](https://news.ycombinator.com/) 等網站類似:你可以訂閱你感興趣的論壇,釋出連結和討論,然後進行投票或評論。但在幕後,Lemmy 和他們不同——任何人都可以很容易地架設一個伺服器,所有伺服器都是聯邦式的(想想電子郵件),並與 [聯邦宇宙](https://zh.wikipedia.org/wiki/%E8%81%94%E9%82%A6%E5%AE%87%E5%AE%99) 互聯。
|
[Lemmy](https://github.com/LemmyNet/lemmy) 與 [Reddit](https://reddit.com)、[Lobste.rs](https://lobste.rs) 或 [Hacker News](https://news.ycombinator.com/) 等網站類似:你可以訂閱你感興趣的論壇,釋出連結和討論,然後進行投票或評論。但在幕後,Lemmy 和他們不同——任何人都可以很容易地架設一個伺服器,所有伺服器都是聯邦式的(想想電子郵件),並與 [聯邦宇宙](https://zh.wikipedia.org/wiki/%E8%81%94%E9%82%A6%E5%AE%87%E5%AE%99) 互聯。
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
use actix_web::{guard, web};
|
use actix_web::{guard, web};
|
||||||
use lemmy_api::{
|
use lemmy_api::{
|
||||||
comment::{distinguish::distinguish_comment, like::like_comment, save::save_comment},
|
comment::{
|
||||||
|
distinguish::distinguish_comment,
|
||||||
|
like::like_comment,
|
||||||
|
list_comment_likes::list_comment_likes,
|
||||||
|
save::save_comment,
|
||||||
|
},
|
||||||
comment_report::{
|
comment_report::{
|
||||||
create::create_comment_report,
|
create::create_comment_report,
|
||||||
list::list_comment_reports,
|
list::list_comment_reports,
|
||||||
|
@ -45,6 +50,7 @@ use lemmy_api::{
|
||||||
feature::feature_post,
|
feature::feature_post,
|
||||||
get_link_metadata::get_link_metadata,
|
get_link_metadata::get_link_metadata,
|
||||||
like::like_post,
|
like::like_post,
|
||||||
|
list_post_likes::list_post_likes,
|
||||||
lock::lock_post,
|
lock::lock_post,
|
||||||
mark_read::mark_post_as_read,
|
mark_read::mark_post_as_read,
|
||||||
save::save_post,
|
save::save_post,
|
||||||
|
@ -204,6 +210,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
|
||||||
.route("/feature", web::post().to(feature_post))
|
.route("/feature", web::post().to(feature_post))
|
||||||
.route("/list", web::get().to(list_posts))
|
.route("/list", web::get().to(list_posts))
|
||||||
.route("/like", web::post().to(like_post))
|
.route("/like", web::post().to(like_post))
|
||||||
|
.route("/like/list", web::get().to(list_post_likes))
|
||||||
.route("/save", web::put().to(save_post))
|
.route("/save", web::put().to(save_post))
|
||||||
.route("/report", web::post().to(create_post_report))
|
.route("/report", web::post().to(create_post_report))
|
||||||
.route("/report/resolve", web::put().to(resolve_post_report))
|
.route("/report/resolve", web::put().to(resolve_post_report))
|
||||||
|
@ -228,6 +235,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) {
|
||||||
.route("/mark_as_read", web::post().to(mark_reply_as_read))
|
.route("/mark_as_read", web::post().to(mark_reply_as_read))
|
||||||
.route("/distinguish", web::post().to(distinguish_comment))
|
.route("/distinguish", web::post().to(distinguish_comment))
|
||||||
.route("/like", web::post().to(like_comment))
|
.route("/like", web::post().to(like_comment))
|
||||||
|
.route("/like/list", web::get().to(list_comment_likes))
|
||||||
.route("/save", web::put().to(save_comment))
|
.route("/save", web::put().to(save_comment))
|
||||||
.route("/list", web::get().to(list_comments))
|
.route("/list", web::get().to(list_comments))
|
||||||
.route("/report", web::post().to(create_comment_report))
|
.route("/report", web::post().to(create_comment_report))
|
||||||
|
|
|
@ -516,6 +516,7 @@ mod tests {
|
||||||
#![allow(clippy::indexing_slicing)]
|
#![allow(clippy::indexing_slicing)]
|
||||||
|
|
||||||
use lemmy_routes::nodeinfo::NodeInfo;
|
use lemmy_routes::nodeinfo::NodeInfo;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -7,8 +7,14 @@ use actix_web::{
|
||||||
};
|
};
|
||||||
use core::future::Ready;
|
use core::future::Ready;
|
||||||
use futures_util::future::LocalBoxFuture;
|
use futures_util::future::LocalBoxFuture;
|
||||||
use lemmy_api::{local_user_view_from_jwt, read_auth_token};
|
use lemmy_api::read_auth_token;
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::{
|
||||||
|
claims::Claims,
|
||||||
|
context::LemmyContext,
|
||||||
|
lemmy_db_views::structs::LocalUserView,
|
||||||
|
utils::check_user_valid,
|
||||||
|
};
|
||||||
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt2, LemmyErrorType};
|
||||||
use reqwest::header::HeaderValue;
|
use reqwest::header::HeaderValue;
|
||||||
use std::{future::ready, rc::Rc};
|
use std::{future::ready, rc::Rc};
|
||||||
|
|
||||||
|
@ -67,14 +73,14 @@ where
|
||||||
let jwt = read_auth_token(req.request())?;
|
let jwt = read_auth_token(req.request())?;
|
||||||
|
|
||||||
if let Some(jwt) = &jwt {
|
if let Some(jwt) = &jwt {
|
||||||
// Ignore any invalid auth so the site can still be used
|
let local_user_id = Claims::validate(jwt, &context)
|
||||||
// TODO: this means it will be impossible to get any error message for invalid jwt. Need
|
.await
|
||||||
// to add a separate endpoint for that.
|
.with_lemmy_type(LemmyErrorType::IncorrectLogin)?;
|
||||||
// https://github.com/LemmyNet/lemmy/issues/3702
|
let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id)
|
||||||
let local_user_view = local_user_view_from_jwt(jwt, &context).await.ok();
|
.await
|
||||||
if let Some(local_user_view) = local_user_view {
|
.map_err(LemmyError::from)?;
|
||||||
req.extensions_mut().insert(local_user_view);
|
check_user_valid(&local_user_view.person)?;
|
||||||
}
|
req.extensions_mut().insert(local_user_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut res = svc.call(req).await?;
|
let mut res = svc.call(req).await?;
|
||||||
|
@ -113,6 +119,7 @@ mod tests {
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
use lemmy_utils::rate_limit::RateLimitCell;
|
use lemmy_utils::rate_limit::RateLimitCell;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use reqwest_middleware::ClientBuilder;
|
use reqwest_middleware::ClientBuilder;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
Loading…
Reference in New Issue