+
+ {% if (user and user.id == post.owner) or can_manage_posts %} {% if user and
+ user.id == post.owner %}
+
+ {% endif %}
diff --git a/crates/app/src/routes/pages/communities.rs b/crates/app/src/routes/pages/communities.rs
index 1b4c83d..3ce74a9 100644
--- a/crates/app/src/routes/pages/communities.rs
+++ b/crates/app/src/routes/pages/communities.rs
@@ -834,6 +834,120 @@ pub async fn reposts_request(
))
}
+/// `/post/{id}/likes`
+pub async fn likes_request(
+ jar: CookieJar,
+ Path(id): Path,
+ Query(props): Query,
+ Extension(data): Extension,
+) -> impl IntoResponse {
+ let data = data.read().await;
+ let user = get_user_from_token!(jar, data.0);
+
+ let post = match data.0.get_post_by_id(id).await {
+ Ok(p) => p,
+ Err(e) => return Err(Html(render_error(e, &jar, &data, &user).await)),
+ };
+
+ let community = match data.0.get_community_by_id(post.community).await {
+ Ok(c) => c,
+ Err(e) => return Err(Html(render_error(e, &jar, &data, &user).await)),
+ };
+
+ let ignore_users = if let Some(ref ua) = user {
+ data.0.get_userblocks_receivers(ua.id).await
+ } else {
+ Vec::new()
+ };
+
+ // ...
+ let owner = match data.0.get_user_by_id(post.owner).await {
+ Ok(ua) => ua,
+ Err(e) => return Err(Html(render_error(e, &jar, &data, &user).await)),
+ };
+
+ check_user_blocked_or_private!(user, owner, data, jar);
+
+ // check repost
+ let reposting = data.0.get_post_reposting(&post, &ignore_users).await;
+
+ // check question
+ let question = match data.0.get_post_question(&post, &ignore_users).await {
+ Ok(q) => q,
+ Err(e) => return Err(Html(render_error(e, &jar, &data, &user).await)),
+ };
+
+ // check permissions
+ let (can_read, _) = check_permissions!(community, jar, data, user);
+
+ if !can_read {
+ return Err(Html(
+ render_error(Error::NotAllowed, &jar, &data, &user).await,
+ ));
+ }
+
+ // ...
+ let ignore_users = if let Some(ref ua) = user {
+ data.0.get_userblocks_receivers(ua.id).await
+ } else {
+ Vec::new()
+ };
+
+ let list = match data.0.get_reactions_by_asset(post.id, 12, props.page).await {
+ Ok(p) => match data.0.fill_reactions(&p, ignore_users).await {
+ Ok(p) => p,
+ Err(e) => return Err(Html(render_error(e, &jar, &data, &user).await)),
+ },
+ Err(e) => return Err(Html(render_error(e, &jar, &data, &user).await)),
+ };
+
+ // init context
+ let lang = get_lang!(jar, data.0);
+ let mut context = initial_context(&data.0.0, lang, &user).await;
+
+ let (
+ is_owner,
+ is_joined,
+ is_pending,
+ can_post,
+ can_manage_posts,
+ can_manage_community,
+ can_manage_roles,
+ can_manage_questions,
+ ) = community_context_bools!(data, user, community);
+
+ context.insert("post", &post);
+ context.insert("question", &question);
+ context.insert("reposting", &reposting);
+ context.insert("list", &list);
+ context.insert("page", &props.page);
+ context.insert(
+ "owner",
+ &data
+ .0
+ .get_user_by_id(post.owner)
+ .await
+ .unwrap_or(User::deleted()),
+ );
+
+ community_context(
+ &mut context,
+ &community,
+ is_owner,
+ is_joined,
+ is_pending,
+ can_post,
+ can_read,
+ can_manage_posts,
+ can_manage_community,
+ can_manage_roles,
+ can_manage_questions,
+ );
+
+ // return
+ Ok(Html(data.1.render("post/likes.html", &context).unwrap()))
+}
+
/// `/community/{title}/members`
pub async fn members_request(
jar: CookieJar,
diff --git a/crates/app/src/routes/pages/mod.rs b/crates/app/src/routes/pages/mod.rs
index 4ace446..0e8b501 100644
--- a/crates/app/src/routes/pages/mod.rs
+++ b/crates/app/src/routes/pages/mod.rs
@@ -89,6 +89,7 @@ pub fn routes() -> Router {
)
.route("/post/{id}", get(communities::post_request))
.route("/post/{id}/reposts", get(communities::reposts_request))
+ .route("/post/{id}/likes", get(communities::likes_request))
.route("/question/{id}", get(communities::question_request))
// chats
.route("/chats", get(chats::redirect_request))
diff --git a/crates/core/src/database/drivers/sql/create_requests.sql b/crates/core/src/database/drivers/sql/create_requests.sql
index d134c0b..ef5d83e 100644
--- a/crates/core/src/database/drivers/sql/create_requests.sql
+++ b/crates/core/src/database/drivers/sql/create_requests.sql
@@ -3,5 +3,6 @@ CREATE TABLE IF NOT EXISTS requests (
created BIGINT NOT NULL,
owner BIGINT NOT NULL,
action_type TEXT NOT NULL,
- linked_asset BIGINT NOT NULL
+ linked_asset BIGINT NOT NULL,
+ PRIMARY KEY (id, owner, linked_asset)
)
diff --git a/crates/core/src/database/reactions.rs b/crates/core/src/database/reactions.rs
index 5ac9bd5..99fbcca 100644
--- a/crates/core/src/database/reactions.rs
+++ b/crates/core/src/database/reactions.rs
@@ -6,7 +6,7 @@ use crate::model::{
permissions::FinePermission,
reactions::{AssetType, Reaction},
};
-use crate::{auto_method, execute, get, query_row, params};
+use crate::{auto_method, execute, get, params, query_row, query_rows};
#[cfg(feature = "sqlite")]
use rusqlite::Row;
@@ -32,6 +32,51 @@ impl DataManager {
auto_method!(get_reaction_by_id()@get_reaction_from_row -> "SELECT * FROM reactions WHERE id = $1" --name="reaction" --returns=Reaction --cache-key-tmpl="atto.reaction:{}");
+ /// Get all owner profiles from a reactions list.
+ pub async fn fill_reactions(
+ &self,
+ reactions: &Vec,
+ ignore_users: Vec,
+ ) -> Result> {
+ let mut out = Vec::new();
+
+ for reaction in reactions {
+ if ignore_users.contains(&reaction.owner) {
+ continue;
+ }
+
+ out.push(self.get_user_by_id(reaction.owner.to_owned()).await?);
+ }
+
+ Ok(out)
+ }
+
+ /// Get a reaction by `owner` and `asset`.
+ pub async fn get_reactions_by_asset(
+ &self,
+ asset: usize,
+ batch: usize,
+ page: usize,
+ ) -> Result> {
+ let conn = match self.connect().await {
+ Ok(c) => c,
+ Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
+ };
+
+ let res = query_rows!(
+ &conn,
+ "SELECT * FROM reactions WHERE asset = $1 ORDER BY created DESC LIMIT $2 OFFSET $3",
+ &[&(asset as i64), &(batch as i64), &((page * batch) as i64)],
+ |x| { Self::get_reaction_from_row(x) }
+ );
+
+ if res.is_err() {
+ return Err(Error::GeneralNotFound("reaction".to_string()));
+ }
+
+ Ok(res.unwrap())
+ }
+
/// Get a reaction by `owner` and `asset`.
pub async fn get_reaction_by_owner_asset(
&self,
diff --git a/sql_changes/requests_pkeys.sql b/sql_changes/requests_pkeys.sql
new file mode 100644
index 0000000..65d7313
--- /dev/null
+++ b/sql_changes/requests_pkeys.sql
@@ -0,0 +1 @@
+ALTER TABLE requests ADD CONSTRAINT requests_pkey PRIMARY KEY (id, owner, linked_asset);