[[package]]
name = "lemmy_api"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"actix",
"actix-rt",
[[package]]
name = "lemmy_api_common"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"actix-web",
"chrono",
[[package]]
name = "lemmy_api_crud"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"actix",
"actix-rt",
[[package]]
name = "lemmy_apub"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"activitystreams-kinds",
"actix",
[[package]]
name = "lemmy_apub_lib"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"activitystreams",
"actix-web",
[[package]]
name = "lemmy_apub_lib_derive"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"proc-macro2 1.0.32",
"quote 1.0.10",
[[package]]
name = "lemmy_db_schema"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"bcrypt",
"chrono",
[[package]]
name = "lemmy_db_views"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"diesel",
"lemmy_db_schema",
[[package]]
name = "lemmy_db_views_actor"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"diesel",
"lemmy_db_schema",
[[package]]
name = "lemmy_db_views_moderator"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"diesel",
"lemmy_db_schema",
[[package]]
name = "lemmy_routes"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"actix",
"actix-http",
[[package]]
name = "lemmy_server"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"activitystreams",
"actix",
[[package]]
name = "lemmy_utils"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"actix-rt",
"actix-web",
[[package]]
name = "lemmy_websocket"
-version = "0.14.1"
+version = "0.14.3"
dependencies = [
"actix",
"actix-web",
[package]
name = "lemmy_server"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
]
[dependencies]
-lemmy_api = { version = "=0.14.1", path = "./crates/api" }
-lemmy_api_crud = { version = "=0.14.1", path = "./crates/api_crud" }
-lemmy_apub = { version = "=0.14.1", path = "./crates/apub" }
-lemmy_apub_lib = { version = "=0.14.1", path = "./crates/apub_lib" }
-lemmy_utils = { version = "=0.14.1", path = "./crates/utils" }
-lemmy_db_schema = { version = "=0.14.1", path = "./crates/db_schema" }
-lemmy_db_views = { version = "=0.14.1", path = "./crates/db_views" }
-lemmy_db_views_moderator = { version = "=0.14.1", path = "./crates/db_views_moderator" }
-lemmy_db_views_actor = { version = "=0.14.1", path = "./crates/db_views_actor" }
-lemmy_api_common = { version = "=0.14.1", path = "crates/api_common" }
-lemmy_websocket = { version = "=0.14.1", path = "./crates/websocket" }
-lemmy_routes = { version = "=0.14.1", path = "./crates/routes" }
+lemmy_api = { version = "=0.14.3", path = "./crates/api" }
+lemmy_api_crud = { version = "=0.14.3", path = "./crates/api_crud" }
+lemmy_apub = { version = "=0.14.3", path = "./crates/apub" }
+lemmy_apub_lib = { version = "=0.14.3", path = "./crates/apub_lib" }
+lemmy_utils = { version = "=0.14.3", path = "./crates/utils" }
+lemmy_db_schema = { version = "=0.14.3", path = "./crates/db_schema" }
+lemmy_db_views = { version = "=0.14.3", path = "./crates/db_views" }
+lemmy_db_views_moderator = { version = "=0.14.3", path = "./crates/db_views_moderator" }
+lemmy_db_views_actor = { version = "=0.14.3", path = "./crates/db_views_actor" }
+lemmy_api_common = { version = "=0.14.3", path = "crates/api_common" }
+lemmy_websocket = { version = "=0.14.3", path = "./crates/websocket" }
+lemmy_routes = { version = "=0.14.3", path = "./crates/routes" }
diesel = "1.4.8"
diesel_migrations = "1.4.0"
chrono = { version = "0.4.19", features = ["serde"] }
[package]
name = "lemmy_api"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
doctest = false
[dependencies]
-lemmy_apub = { version = "=0.14.1", path = "../apub" }
-lemmy_apub_lib = { version = "=0.14.1", path = "../apub_lib" }
-lemmy_utils = { version = "=0.14.1", path = "../utils" }
-lemmy_db_schema = { version = "=0.14.1", path = "../db_schema" }
-lemmy_db_views = { version = "=0.14.1", path = "../db_views" }
-lemmy_db_views_moderator = { version = "=0.14.1", path = "../db_views_moderator" }
-lemmy_db_views_actor = { version = "=0.14.1", path = "../db_views_actor" }
-lemmy_api_common = { version = "=0.14.1", path = "../api_common" }
-lemmy_websocket = { version = "=0.14.1", path = "../websocket" }
+lemmy_apub = { version = "=0.14.3", path = "../apub" }
+lemmy_apub_lib = { version = "=0.14.3", path = "../apub_lib" }
+lemmy_utils = { version = "=0.14.3", path = "../utils" }
+lemmy_db_schema = { version = "=0.14.3", path = "../db_schema" }
+lemmy_db_views = { version = "=0.14.3", path = "../db_views" }
+lemmy_db_views_moderator = { version = "=0.14.3", path = "../db_views_moderator" }
+lemmy_db_views_actor = { version = "=0.14.3", path = "../db_views_actor" }
+lemmy_api_common = { version = "=0.14.3", path = "../api_common" }
+lemmy_websocket = { version = "=0.14.3", path = "../websocket" }
diesel = "1.4.8"
bcrypt = "0.10.1"
chrono = { version = "0.4.19", features = ["serde"] }
UserOperation::CreatePostLike => {
do_websocket_operation::<CreatePostLike>(context, id, op, data).await
}
+ UserOperation::MarkPostAsRead => {
+ do_websocket_operation::<MarkPostAsRead>(context, id, op, data).await
+ }
UserOperation::SavePost => do_websocket_operation::<SavePost>(context, id, op, data).await,
UserOperation::CreatePostReport => {
do_websocket_operation::<CreatePostReport>(context, id, op, data).await
get_local_user_view_from_jwt,
is_mod_or_admin,
mark_post_as_read,
+ mark_post_as_unread,
post::*,
};
use lemmy_apub::{
}
}
+#[async_trait::async_trait(?Send)]
+impl Perform for MarkPostAsRead {
+ type Response = PostResponse;
+
+ async fn perform(
+ &self,
+ context: &Data<LemmyContext>,
+ _websocket_id: Option<ConnectionId>,
+ ) -> Result<Self::Response, LemmyError> {
+ let data = self;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+
+ let post_id = data.post_id;
+ let person_id = local_user_view.person.id;
+
+ // Mark the post as read / unread
+ if data.read {
+ mark_post_as_read(person_id, post_id, context.pool()).await?;
+ } else {
+ mark_post_as_unread(person_id, post_id, context.pool()).await?;
+ }
+
+ // Fetch it
+ let post_view = blocking(context.pool(), move |conn| {
+ PostView::read(conn, post_id, Some(person_id))
+ })
+ .await??;
+
+ let res = Self::Response { post_view };
+
+ Ok(res)
+ }
+}
+
#[async_trait::async_trait(?Send)]
impl Perform for LockPost {
type Response = PostResponse;
[package]
name = "lemmy_api_common"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
doctest = false
[dependencies]
-lemmy_db_views = { version = "=0.14.1", path = "../db_views" }
-lemmy_db_views_moderator = { version = "=0.14.1", path = "../db_views_moderator" }
-lemmy_db_views_actor = { version = "=0.14.1", path = "../db_views_actor" }
-lemmy_db_schema = { version = "=0.14.1", path = "../db_schema" }
-lemmy_utils = { version = "=0.14.1", path = "../utils" }
+lemmy_db_views = { version = "=0.14.3", path = "../db_views" }
+lemmy_db_views_moderator = { version = "=0.14.3", path = "../db_views_moderator" }
+lemmy_db_views_actor = { version = "=0.14.3", path = "../db_views_actor" }
+lemmy_db_schema = { version = "=0.14.3", path = "../db_schema" }
+lemmy_utils = { version = "=0.14.3", path = "../utils" }
serde = { version = "1.0.130", features = ["derive"] }
diesel = "1.4.8"
actix-web = { version = "4.0.0-beta.9", default-features = false, features = ["cookies"] }
pub auth: String,
}
+#[derive(Serialize, Deserialize)]
+pub struct GetComment {
+ pub id: CommentId,
+ pub auth: Option<String>,
+}
+
#[derive(Serialize, Deserialize)]
pub struct EditComment {
pub content: String,
PostRead::mark_as_read(conn, &post_read_form)
})
.await?
- .map_err(|_| ApiError::err_plain("couldnt_mark_post_as_read").into())
+ .map_err(|e| ApiError::err("couldnt_mark_post_as_read", e).into())
+}
+
+pub async fn mark_post_as_unread(
+ person_id: PersonId,
+ post_id: PostId,
+ pool: &DbPool,
+) -> Result<usize, LemmyError> {
+ let post_read_form = PostReadForm { post_id, person_id };
+
+ blocking(pool, move |conn| {
+ PostRead::mark_as_unread(conn, &post_read_form)
+ })
+ .await?
+ .map_err(|e| ApiError::err("couldnt_mark_post_as_read", e).into())
}
pub async fn get_local_user_view_from_jwt(
pub auth: String,
}
+#[derive(Serialize, Deserialize)]
+pub struct MarkPostAsRead {
+ pub post_id: PostId,
+ pub read: bool,
+ pub auth: String,
+}
+
#[derive(Serialize, Deserialize)]
pub struct LockPost {
pub post_id: PostId,
[package]
name = "lemmy_api_crud"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
documentation = "https://join-lemmy.org/docs/en/index.html"
[dependencies]
-lemmy_apub = { version = "=0.14.1", path = "../apub" }
-lemmy_apub_lib = { version = "=0.14.1", path = "../apub_lib" }
-lemmy_utils = { version = "=0.14.1", path = "../utils" }
-lemmy_db_schema = { version = "=0.14.1", path = "../db_schema" }
-lemmy_db_views = { version = "=0.14.1", path = "../db_views" }
-lemmy_db_views_moderator = { version = "=0.14.1", path = "../db_views_moderator" }
-lemmy_db_views_actor = { version = "=0.14.1", path = "../db_views_actor" }
-lemmy_api_common = { version = "=0.14.1", path = "../api_common" }
-lemmy_websocket = { version = "=0.14.1", path = "../websocket" }
+lemmy_apub = { version = "=0.14.3", path = "../apub" }
+lemmy_apub_lib = { version = "=0.14.3", path = "../apub_lib" }
+lemmy_utils = { version = "=0.14.3", path = "../utils" }
+lemmy_db_schema = { version = "=0.14.3", path = "../db_schema" }
+lemmy_db_views = { version = "=0.14.3", path = "../db_views" }
+lemmy_db_views_moderator = { version = "=0.14.3", path = "../db_views_moderator" }
+lemmy_db_views_actor = { version = "=0.14.3", path = "../db_views_actor" }
+lemmy_api_common = { version = "=0.14.3", path = "../api_common" }
+lemmy_websocket = { version = "=0.14.3", path = "../websocket" }
diesel = "1.4.8"
bcrypt = "0.10.1"
chrono = { version = "0.4.19", features = ["serde"] }
ListingType,
SortType,
};
-use lemmy_db_views::comment_view::CommentQueryBuilder;
+use lemmy_db_views::comment_view::{CommentQueryBuilder, CommentView};
use lemmy_utils::{ApiError, ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
+#[async_trait::async_trait(?Send)]
+impl PerformCrud for GetComment {
+ type Response = CommentResponse;
+
+ async fn perform(
+ &self,
+ context: &Data<LemmyContext>,
+ _websocket_id: Option<ConnectionId>,
+ ) -> Result<Self::Response, LemmyError> {
+ let data = self;
+ let local_user_view =
+ get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?;
+
+ let person_id = local_user_view.map(|u| u.person.id);
+ let id = data.id;
+ let comment_view = blocking(context.pool(), move |conn| {
+ CommentView::read(conn, id, person_id)
+ })
+ .await?
+ .map_err(|e| ApiError::err("couldnt_find_comment", e))?;
+
+ Ok(Self::Response {
+ comment_view,
+ form_id: None,
+ recipient_ids: Vec::new(),
+ })
+ }
+}
+
#[async_trait::async_trait(?Send)]
impl PerformCrud for GetComments {
type Response = GetCommentsResponse;
UserOperationCrud::RemoveComment => {
do_websocket_operation::<RemoveComment>(context, id, op, data).await
}
+ UserOperationCrud::GetComment => {
+ do_websocket_operation::<GetComment>(context, id, op, data).await
+ }
UserOperationCrud::GetComments => {
do_websocket_operation::<GetComments>(context, id, op, data).await
}
[package]
name = "lemmy_apub"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
doctest = false
[dependencies]
-lemmy_utils = { version = "=0.14.1", path = "../utils" }
-lemmy_apub_lib = { version = "=0.14.1", path = "../apub_lib" }
-lemmy_db_schema = { version = "=0.14.1", path = "../db_schema" }
-lemmy_db_views = { version = "=0.14.1", path = "../db_views" }
-lemmy_db_views_actor = { version = "=0.14.1", path = "../db_views_actor" }
-lemmy_api_common = { version = "=0.14.1", path = "../api_common" }
-lemmy_websocket = { version = "=0.14.1", path = "../websocket" }
+lemmy_utils = { version = "=0.14.3", path = "../utils" }
+lemmy_apub_lib = { version = "=0.14.3", path = "../apub_lib" }
+lemmy_db_schema = { version = "=0.14.3", path = "../db_schema" }
+lemmy_db_views = { version = "=0.14.3", path = "../db_views" }
+lemmy_db_views_actor = { version = "=0.14.3", path = "../db_views_actor" }
+lemmy_api_common = { version = "=0.14.3", path = "../api_common" }
+lemmy_websocket = { version = "=0.14.3", path = "../websocket" }
diesel = "1.4.8"
activitystreams-kinds = "0.1.2"
bcrypt = "0.10.1"
[package]
name = "lemmy_apub_lib"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
documentation = "https://join-lemmy.org/docs/en/index.html"
[dependencies]
-lemmy_utils = { version = "=0.14.1", path = "../utils" }
-lemmy_apub_lib_derive = { version = "=0.14.1", path = "../apub_lib_derive" }
+lemmy_utils = { version = "=0.14.3", path = "../utils" }
+lemmy_apub_lib_derive = { version = "=0.14.3", path = "../apub_lib_derive" }
activitystreams = "0.7.0-alpha.11"
serde = { version = "1.0.130", features = ["derive"] }
async-trait = "0.1.51"
[package]
name = "lemmy_apub_lib_derive"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
[package]
name = "lemmy_db_schema"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
doctest = false
[dependencies]
-lemmy_utils = { version = "=0.14.1", path = "../utils" }
-lemmy_apub_lib = { version = "=0.14.1", path = "../apub_lib" }
+lemmy_utils = { version = "=0.14.3", path = "../utils" }
+lemmy_apub_lib = { version = "=0.14.3", path = "../apub_lib" }
diesel = { version = "1.4.8", features = ["postgres","chrono","r2d2","serde_json"] }
diesel_migrations = "1.4.0"
chrono = { version = "0.4.19", features = ["serde"] }
[package]
name = "lemmy_db_views"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
doctest = false
[dependencies]
-lemmy_db_schema = { version = "=0.14.1", path = "../db_schema" }
+lemmy_db_schema = { version = "=0.14.3", path = "../db_schema" }
diesel = { version = "1.4.8", features = ["postgres","chrono","r2d2","serde_json"] }
serde = { version = "1.0.130", features = ["derive"] }
tracing = "0.1.29"
let mut query = comment_report::table
.inner_join(comment::table)
.inner_join(post::table.on(comment::post_id.eq(post::id)))
- .inner_join(
- community_moderator::table.on(community_moderator::community_id.eq(post::community_id)),
- )
.filter(comment_report::resolved.eq(false))
.into_boxed();
- // If its not an admin, get only the ones you mod
- if !admin {
- query = query.filter(community_moderator::person_id.eq(my_person_id));
- }
-
if let Some(community_id) = community_id {
query = query.filter(post::community_id.eq(community_id))
}
- query.select(count(comment_report::id)).first::<i64>(conn)
+ // If its not an admin, get only the ones you mod
+ if !admin {
+ query
+ .inner_join(
+ community_moderator::table.on(
+ community_moderator::community_id
+ .eq(post::community_id)
+ .and(community_moderator::person_id.eq(my_person_id)),
+ ),
+ )
+ .select(count(comment_report::id))
+ .first::<i64>(conn)
+ } else {
+ query.select(count(comment_report::id)).first::<i64>(conn)
+ }
}
}
.inner_join(community::table.on(post::community_id.eq(community::id)))
.inner_join(person::table.on(comment_report::creator_id.eq(person::id)))
.inner_join(person_alias_1::table.on(comment::creator_id.eq(person_alias_1::id)))
- // Test this join
- .inner_join(
- community_moderator::table.on(community_moderator::community_id.eq(post::community_id)),
- )
.inner_join(
comment_aggregates::table.on(comment_report::comment_id.eq(comment_aggregates::comment_id)),
)
))
.into_boxed();
- // If its not an admin, get only the ones you mod
- if !self.admin {
- query = query.filter(community_moderator::person_id.eq(self.my_person_id));
- }
-
if let Some(community_id) = self.community_id {
query = query.filter(post::community_id.eq(community_id));
}
let (limit, offset) = limit_and_offset(self.page, self.limit);
- let res = query
- .order_by(comment_report::published.asc())
+ query = query
+ .order_by(comment_report::published.desc())
.limit(limit)
- .offset(offset)
- .load::<CommentReportViewTuple>(self.conn)?;
+ .offset(offset);
+
+ // If its not an admin, get only the ones you mod
+ let res = if !self.admin {
+ query
+ .inner_join(
+ community_moderator::table.on(
+ community_moderator::community_id
+ .eq(post::community_id)
+ .and(community_moderator::person_id.eq(self.my_person_id)),
+ ),
+ )
+ .load::<CommentReportViewTuple>(self.conn)?
+ } else {
+ query.load::<CommentReportViewTuple>(self.conn)?
+ };
Ok(CommentReportView::from_tuple_to_vec(res))
}
assert_eq!(
reports,
[
- expected_sara_report_view.to_owned(),
- expected_jessica_report_view.to_owned()
+ expected_jessica_report_view.to_owned(),
+ expected_sara_report_view.to_owned()
]
);
use diesel::dsl::*;
let mut query = post_report::table
.inner_join(post::table)
- // Test this join
- .inner_join(
- community_moderator::table.on(community_moderator::community_id.eq(post::community_id)),
- )
.filter(post_report::resolved.eq(false))
.into_boxed();
- // If its not an admin, get only the ones you mod
- if !admin {
- query = query.filter(community_moderator::person_id.eq(my_person_id));
- }
-
if let Some(community_id) = community_id {
query = query.filter(post::community_id.eq(community_id))
}
- query.select(count(post_report::id)).first::<i64>(conn)
+ // If its not an admin, get only the ones you mod
+ if !admin {
+ query
+ .inner_join(
+ community_moderator::table.on(
+ community_moderator::community_id
+ .eq(post::community_id)
+ .and(community_moderator::person_id.eq(my_person_id)),
+ ),
+ )
+ .select(count(post_report::id))
+ .first::<i64>(conn)
+ } else {
+ query.select(count(post_report::id)).first::<i64>(conn)
+ }
}
}
.inner_join(community::table.on(post::community_id.eq(community::id)))
.inner_join(person::table.on(post_report::creator_id.eq(person::id)))
.inner_join(person_alias_1::table.on(post::creator_id.eq(person_alias_1::id)))
- .inner_join(
- community_moderator::table.on(community_moderator::community_id.eq(post::community_id)),
- )
.left_join(
community_person_ban::table.on(
post::community_id
))
.into_boxed();
- // If its not an admin, get only the ones you mod
- if !self.admin {
- query = query.filter(community_moderator::person_id.eq(self.my_person_id));
- }
-
if let Some(community_id) = self.community_id {
query = query.filter(post::community_id.eq(community_id));
}
let (limit, offset) = limit_and_offset(self.page, self.limit);
- let res = query
- .order_by(post_report::published.asc())
+ query = query
+ .order_by(post_report::published.desc())
.limit(limit)
- .offset(offset)
- .load::<PostReportViewTuple>(self.conn)?;
+ .offset(offset);
+
+ // If its not an admin, get only the ones you mod
+ let res = if !self.admin {
+ query
+ .inner_join(
+ community_moderator::table.on(
+ community_moderator::community_id
+ .eq(post::community_id)
+ .and(community_moderator::person_id.eq(self.my_person_id)),
+ ),
+ )
+ .load::<PostReportViewTuple>(self.conn)?
+ } else {
+ query.load::<PostReportViewTuple>(self.conn)?
+ };
Ok(PostReportView::from_tuple_to_vec(res))
}
assert_eq!(
reports,
[
- expected_sara_report_view.to_owned(),
- expected_jessica_report_view.to_owned()
+ expected_jessica_report_view.to_owned(),
+ expected_sara_report_view.to_owned()
]
);
[package]
name = "lemmy_db_views_actor"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
doctest = false
[dependencies]
-lemmy_db_schema = { version = "=0.14.1", path = "../db_schema" }
+lemmy_db_schema = { version = "=0.14.3", path = "../db_schema" }
diesel = { version = "1.4.8", features = ["postgres","chrono","r2d2","serde_json"] }
serde = { version = "1.0.130", features = ["derive"] }
[package]
name = "lemmy_db_views_moderator"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
doctest = false
[dependencies]
-lemmy_db_schema = { version = "=0.14.1", path = "../db_schema" }
+lemmy_db_schema = { version = "=0.14.3", path = "../db_schema" }
diesel = { version = "1.4.8", features = ["postgres","chrono","r2d2","serde_json"] }
serde = { version = "1.0.130", features = ["derive"] }
[package]
name = "lemmy_routes"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
doctest = false
[dependencies]
-lemmy_utils = { version = "=0.14.1", path = "../utils" }
-lemmy_websocket = { version = "=0.14.1", path = "../websocket" }
-lemmy_db_views = { version = "=0.14.1", path = "../db_views" }
-lemmy_db_views_actor = { version = "=0.14.1", path = "../db_views_actor" }
-lemmy_db_schema = { version = "=0.14.1", path = "../db_schema" }
-lemmy_api_common = { version = "=0.14.1", path = "../api_common" }
-lemmy_apub = { version = "=0.14.1", path = "../apub" }
+lemmy_utils = { version = "=0.14.3", path = "../utils" }
+lemmy_websocket = { version = "=0.14.3", path = "../websocket" }
+lemmy_db_views = { version = "=0.14.3", path = "../db_views" }
+lemmy_db_views_actor = { version = "=0.14.3", path = "../db_views_actor" }
+lemmy_db_schema = { version = "=0.14.3", path = "../db_schema" }
+lemmy_api_common = { version = "=0.14.3", path = "../api_common" }
+lemmy_apub = { version = "=0.14.3", path = "../apub" }
diesel = "1.4.8"
actix = "0.12.0"
actix-web = { version = "4.0.0-beta.9", default-features = false, features = ["rustls"] }
[package]
name = "lemmy_utils"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
static VALID_ACTOR_NAME_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^[a-zA-Z0-9_]{3,}$").expect("compile regex"));
static VALID_POST_TITLE_REGEX: Lazy<Regex> =
- Lazy::new(|| Regex::new(r".*\S.*").expect("compile regex"));
+ Lazy::new(|| Regex::new(r".*\S{3,}.*").expect("compile regex"));
static VALID_MATRIX_ID_REGEX: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"^@[A-Za-z0-9._=-]+:[A-Za-z0-9.-]+\.[A-Za-z]{2,}$").expect("compile regex")
});
out.into_iter().unique().collect()
}
+fn has_newline(name: &str) -> bool {
+ name.contains('\n')
+}
+
pub fn is_valid_actor_name(name: &str, actor_name_max_length: usize) -> bool {
- name.chars().count() <= actor_name_max_length && VALID_ACTOR_NAME_REGEX.is_match(name)
+ name.chars().count() <= actor_name_max_length
+ && VALID_ACTOR_NAME_REGEX.is_match(name)
+ && !has_newline(name)
}
// Can't do a regex here, reverse lookarounds not supported
&& !name.starts_with('\u{200b}')
&& name.chars().count() >= 3
&& name.chars().count() <= actor_name_max_length
+ && !has_newline(name)
}
pub fn is_valid_matrix_id(matrix_id: &str) -> bool {
- VALID_MATRIX_ID_REGEX.is_match(matrix_id)
+ VALID_MATRIX_ID_REGEX.is_match(matrix_id) && !has_newline(matrix_id)
}
pub fn is_valid_post_title(title: &str) -> bool {
- VALID_POST_TITLE_REGEX.is_match(title)
+ VALID_POST_TITLE_REGEX.is_match(title) && !has_newline(title)
}
pub fn get_ip(conn_info: &ConnectionInfo) -> IpAddr {
#[cfg(test)]
mod tests {
- use crate::utils::clean_url_params;
+ use crate::utils::{clean_url_params, is_valid_post_title};
use url::Url;
#[test]
let cleaned = clean_url_params(url.clone());
assert_eq!(url.to_string(), cleaned.to_string());
}
+
+ #[test]
+ fn regex_checks() {
+ assert!(!is_valid_post_title("hi"));
+ assert!(is_valid_post_title("him"));
+ assert!(!is_valid_post_title("n\n\n\n\nanother"));
+ assert!(!is_valid_post_title("hello there!\n this is a test."));
+ assert!(is_valid_post_title("hello there! this is a test."));
+ }
}
[package]
name = "lemmy_websocket"
-version = "0.14.1"
+version = "0.14.3"
edition = "2018"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
doctest = false
[dependencies]
-lemmy_utils = { version = "=0.14.1", path = "../utils" }
-lemmy_api_common = { version = "=0.14.1", path = "../api_common" }
-lemmy_db_schema = { version = "=0.14.1", path = "../db_schema" }
-lemmy_db_views = { version = "=0.14.1", path = "../db_views" }
-lemmy_db_views_actor = { version = "=0.14.1", path = "../db_views_actor" }
+lemmy_utils = { version = "=0.14.3", path = "../utils" }
+lemmy_api_common = { version = "=0.14.3", path = "../api_common" }
+lemmy_db_schema = { version = "=0.14.3", path = "../db_schema" }
+lemmy_db_views = { version = "=0.14.3", path = "../db_views" }
+lemmy_db_views_actor = { version = "=0.14.3", path = "../db_views_actor" }
reqwest = { version = "0.11.4", features = ["json"] }
tracing = "0.1.29"
rand = "0.8.4"
} else {
let user_operation = UserOperation::from_str(op)?;
let fut = (message_handler)(context, msg.id, user_operation.clone(), data);
- rate_limiter.message().wrap(ip, fut).await
+ match user_operation {
+ UserOperation::GetCaptcha => rate_limiter.post().wrap(ip, fut).await,
+ _ => rate_limiter.message().wrap(ip, fut).await,
+ }
}
}
}
CreatePostLike,
LockPost,
StickyPost,
+ MarkPostAsRead,
SavePost,
CreatePostReport,
ResolvePostReport,
RemovePost,
// Comment
CreateComment,
+ GetComment,
GetComments,
EditComment,
DeleteComment,
- postgres
lemmy-ui:
- image: dessalines/lemmy-ui:0.14.1
+ image: dessalines/lemmy-ui:0.14.3
restart: always
environment:
- LEMMY_INTERNAL_HOST=lemmy:8536
- ./volumes/pictrs_alpha:/mnt
lemmy-alpha-ui:
- image: dessalines/lemmy-ui:0.14.1
+ image: dessalines/lemmy-ui:0.14.3
environment:
- LEMMY_INTERNAL_HOST=lemmy-alpha:8541
- LEMMY_EXTERNAL_HOST=localhost:8541
- ./volumes/postgres_alpha:/var/lib/postgresql/data
lemmy-beta-ui:
- image: dessalines/lemmy-ui:0.14.1
+ image: dessalines/lemmy-ui:0.14.3
environment:
- LEMMY_INTERNAL_HOST=lemmy-beta:8551
- LEMMY_EXTERNAL_HOST=localhost:8551
- ./volumes/postgres_beta:/var/lib/postgresql/data
lemmy-gamma-ui:
- image: dessalines/lemmy-ui:0.14.1
+ image: dessalines/lemmy-ui:0.14.3
environment:
- LEMMY_INTERNAL_HOST=lemmy-gamma:8561
- LEMMY_EXTERNAL_HOST=localhost:8561
# An instance with only an allowlist for beta
lemmy-delta-ui:
- image: dessalines/lemmy-ui:0.14.1
+ image: dessalines/lemmy-ui:0.14.3
environment:
- LEMMY_INTERNAL_HOST=lemmy-delta:8571
- LEMMY_EXTERNAL_HOST=localhost:8571
# An instance who has a blocklist, with lemmy-alpha blocked
lemmy-epsilon-ui:
- image: dessalines/lemmy-ui:0.14.1
+ image: dessalines/lemmy-ui:0.14.3
environment:
- LEMMY_INTERNAL_HOST=lemmy-epsilon:8581
- LEMMY_EXTERNAL_HOST=localhost:8581
restart: always
lemmy:
- image: dessalines/lemmy:0.14.1
+ image: dessalines/lemmy:0.14.3
ports:
- "127.0.0.1:8536:8536"
restart: always
- pictrs
lemmy-ui:
- image: dessalines/lemmy-ui:0.14.1
+ image: dessalines/lemmy-ui:0.14.3
ports:
- "127.0.0.1:1235:1234"
restart: always
alter table activity alter column ap_id set not null;
-- Delete dupes, keeping the first one
-delete
-from activity
-where id not in (
- select min(id)
+delete from activity a using (
+ select min(id) as id, ap_id
from activity
- group by ap_id
-);
+ group by ap_id having count(*) > 1
+) b
+where a.ap_id = b.ap_id
+and a.id <> b.id;
-- The index
create unique index idx_activity_ap_id on activity(ap_id);
--- /dev/null
+drop index idx_comment_report_published;
+drop index idx_post_report_published;
--- /dev/null
+create index idx_comment_report_published on comment_report (published desc);
+create index idx_post_report_published on post_report (published desc);
.route("", web::put().to(route_post_crud::<EditPost>))
.route("/delete", web::post().to(route_post_crud::<DeletePost>))
.route("/remove", web::post().to(route_post_crud::<RemovePost>))
+ .route(
+ "/mark_as_read",
+ web::post().to(route_post::<MarkPostAsRead>),
+ )
.route("/lock", web::post().to(route_post::<LockPost>))
.route("/sticky", web::post().to(route_post::<StickyPost>))
.route("/list", web::get().to(route_get_crud::<GetPosts>))
.service(
web::scope("/comment")
.wrap(rate_limit.message())
+ .route("", web::get().to(route_get_crud::<GetComment>))
.route("", web::put().to(route_post_crud::<EditComment>))
.route("/delete", web::post().to(route_post_crud::<DeleteComment>))
.route("/remove", web::post().to(route_post_crud::<RemoveComment>))
.wrap(rate_limit.register())
.route(web::post().to(route_post_crud::<Register>)),
)
+ .service(
+ // Handle captcha separately
+ web::resource("/user/get_captcha")
+ .wrap(rate_limit.post())
+ .route(web::get().to(route_get::<GetCaptcha>)),
+ )
// User actions
.service(
web::scope("/user")
.route("/block", web::post().to(route_post::<BlockPerson>))
// Account actions. I don't like that they're in /user maybe /accounts
.route("/login", web::post().to(route_post::<Login>))
- .route("/get_captcha", web::get().to(route_get::<GetCaptcha>))
.route(
"/delete_account",
web::post().to(route_post_crud::<DeleteAccount>),