naive_now,
post_view::*,
site::*,
+ site_aggregates::SiteAggregates,
user_view::*,
views::site_view::SiteView,
Crud,
u
});
+ let counts = blocking(context.pool(), move |conn| SiteAggregates::read(conn)).await??;
+
Ok(GetSiteResponse {
site: site_view,
admins,
version: version::VERSION.to_string(),
my_user,
federated_instances: linked_instances(context.pool()).await?,
- // TODO
- number_of_users: 0,
- number_of_posts: 0,
- number_of_comments: 0,
- number_of_communities: 0,
+ counts,
})
}
}
let banned = blocking(context.pool(), move |conn| UserView::banned(conn)).await??;
+ let counts = blocking(context.pool(), move |conn| SiteAggregates::read(conn)).await??;
+
Ok(GetSiteResponse {
site: Some(site_view),
admins,
version: version::VERSION.to_string(),
my_user: Some(user),
federated_instances: linked_instances(context.pool()).await?,
- // TODO
- number_of_users: 0,
- number_of_posts: 0,
- number_of_comments: 0,
- number_of_communities: 0,
+ counts,
})
}
}
where
T: AsBase<Kind> + AsObject<Kind> + ActorAndObjectRefExt,
{
- let to_and_cc = get_activity_to_and_cc(activity)?;
+ let to_and_cc = get_activity_to_and_cc(activity);
if to_and_cc.len() != 1 {
return Err(anyhow!("Private message can only be addressed to one user").into());
}
Community::read_from_name(&conn, &path)
})
.await??;
- let to_and_cc = get_activity_to_and_cc(&activity)?;
+ let to_and_cc = get_activity_to_and_cc(&activity);
if !to_and_cc.contains(&&community.actor_id()?) {
return Err(anyhow!("Activity delivered to wrong community").into());
}
}
}
-pub(crate) fn get_activity_to_and_cc<T, Kind>(activity: &T) -> Result<Vec<Url>, LemmyError>
+pub(crate) fn get_activity_to_and_cc<T, Kind>(activity: &T) -> Vec<Url>
where
T: AsBase<Kind> + AsObject<Kind> + ActorAndObjectRefExt,
{
.collect();
to_and_cc.append(&mut cc);
}
- Ok(to_and_cc)
+ to_and_cc
}
pub(crate) fn is_addressed_to_public<T, Kind>(activity: &T) -> Result<(), LemmyError>
where
T: AsBase<Kind> + AsObject<Kind> + ActorAndObjectRefExt,
{
- let to_and_cc = get_activity_to_and_cc(activity)?;
+ let to_and_cc = get_activity_to_and_cc(activity);
if to_and_cc.contains(&public()) {
Ok(())
} else {
let activity_any_base = activity.clone().into_any_base()?;
let mut res: Option<HttpResponse> = None;
- let to_and_cc = get_activity_to_and_cc(&activity)?;
+ let to_and_cc = get_activity_to_and_cc(&activity);
// Handle community first, so in case the sender is banned by the community, it will error out.
// If we handled the user receive first, the activity would be inserted to the database before the
// community could check for bans.
User_::read_from_name(&conn, &username)
})
.await??;
- let to_and_cc = get_activity_to_and_cc(&activity)?;
+ let to_and_cc = get_activity_to_and_cc(&activity);
// TODO: we should also accept activities that are sent to community followers
if !to_and_cc.contains(&&user.actor_id()?) {
return Err(anyhow!("Activity delivered to wrong user").into());
context: &LemmyContext,
activity: &UserAcceptedActivities,
) -> Result<(), LemmyError> {
- let to_and_cc = get_activity_to_and_cc(activity)?;
+ let to_and_cc = get_activity_to_and_cc(activity);
// Check if it is addressed directly to any local user
if is_addressed_to_local_user(&to_and_cc, context.pool()).await? {
return Ok(());
pub mod private_message_view;
pub mod schema;
pub mod site;
-pub mod site_view;
+pub mod site_aggregates;
pub mod user;
pub mod user_mention;
pub mod user_mention_view;
}
}
+table! {
+ site_aggregates (id) {
+ id -> Int4,
+ users -> Int8,
+ posts -> Int8,
+ comments -> Int8,
+ communities -> Int8,
+ }
+}
+
table! {
user_ (id) {
id -> Int4,
post_saved,
private_message,
site,
+ site_aggregates,
user_,
user_ban,
user_fast,
--- /dev/null
+use crate::schema::site_aggregates;
+use diesel::{result::Error, *};
+use serde::Serialize;
+
+#[derive(Queryable, Associations, Identifiable, PartialEq, Debug, Serialize)]
+#[table_name = "site_aggregates"]
+pub struct SiteAggregates {
+ pub id: i32,
+ pub users: i64,
+ pub posts: i64,
+ pub comments: i64,
+ pub communities: i64,
+}
+
+impl SiteAggregates {
+ pub fn read(conn: &PgConnection) -> Result<Self, Error> {
+ site_aggregates::table.first::<Self>(conn)
+ }
+}
+++ /dev/null
-use diesel::{result::Error, *};
-use serde::Serialize;
-
-table! {
- site_view (id) {
- id -> Int4,
- name -> Varchar,
- description -> Nullable<Text>,
- creator_id -> Int4,
- published -> Timestamp,
- updated -> Nullable<Timestamp>,
- enable_downvotes -> Bool,
- open_registration -> Bool,
- enable_nsfw -> Bool,
- icon -> Nullable<Text>,
- banner -> Nullable<Text>,
- creator_name -> Varchar,
- creator_preferred_username -> Nullable<Varchar>,
- creator_avatar -> Nullable<Text>,
- number_of_users -> BigInt,
- number_of_posts -> BigInt,
- number_of_comments -> BigInt,
- number_of_communities -> BigInt,
- }
-}
-
-#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
-#[table_name = "site_view"]
-pub struct SiteView {
- pub id: i32,
- pub name: String,
- pub description: Option<String>,
- pub creator_id: i32,
- pub published: chrono::NaiveDateTime,
- pub updated: Option<chrono::NaiveDateTime>,
- pub enable_downvotes: bool,
- pub open_registration: bool,
- pub enable_nsfw: bool,
- pub icon: Option<String>,
- pub banner: Option<String>,
- pub creator_name: String,
- pub creator_preferred_username: Option<String>,
- pub creator_avatar: Option<String>,
- pub number_of_users: i64,
- pub number_of_posts: i64,
- pub number_of_comments: i64,
- pub number_of_communities: i64,
-}
-
-impl SiteView {
- pub fn read(conn: &PgConnection) -> Result<Self, Error> {
- use super::site_view::site_view::dsl::*;
- site_view.first::<Self>(conn)
- }
-}
pub mod site_view;
+pub mod user_view;
--- /dev/null
+use crate::{
+ schema::user_,
+ user::{UserSafe, User_},
+};
+use diesel::{result::Error, *};
+use serde::Serialize;
+
+#[derive(Debug, Serialize, Clone)]
+pub struct UserViewSafe {
+ pub user: UserSafe,
+ // TODO
+ // pub number_of_posts: i64,
+ // pub post_score: i64,
+ // pub number_of_comments: i64,
+ // pub comment_score: i64,
+}
+
+pub struct UserViewDangerous {
+ pub user: User_,
+ // TODO
+ // pub number_of_posts: i64,
+ // pub post_score: i64,
+ // pub number_of_comments: i64,
+ // pub comment_score: i64,
+}
+
+impl UserViewDangerous {
+ pub fn read(conn: &PgConnection, id: i32) -> Result<Self, Error> {
+ let user = user_::table.find(id).first::<User_>(conn)?;
+ Ok(Self { user })
+ }
+}
+
+impl UserViewSafe {
+ pub fn read(conn: &PgConnection, id: i32) -> Result<Self, Error> {
+ let user = user_::table.find(id).first::<User_>(conn)?.to_safe();
+ Ok(Self { user })
+ }
+
+ pub fn admins(conn: &PgConnection) -> Result<Vec<Self>, Error> {
+ let admins = user_::table
+ // TODO do joins here
+ .filter(user_::admin.eq(true))
+ .order_by(user_::published)
+ .load::<User_>(conn)?;
+
+ Ok(vec_to_user_view_safe(admins))
+ }
+
+ pub fn banned(conn: &PgConnection) -> Result<Vec<Self>, Error> {
+ let banned = user_::table
+ // TODO do joins here
+ .filter(user_::banned.eq(true))
+ .load::<User_>(conn)?;
+
+ Ok(vec_to_user_view_safe(banned))
+ }
+}
+
+fn vec_to_user_view_safe(users: Vec<User_>) -> Vec<UserViewSafe> {
+ users
+ .iter()
+ .map(|a| UserViewSafe { user: a.to_safe() })
+ .collect::<Vec<UserViewSafe>>()
+}
community_view::*,
moderator_views::*,
post_view::*,
+ site_aggregates::SiteAggregates,
user::*,
user_view::*,
views::site_view::SiteView,
#[derive(Serialize)]
pub struct GetSiteResponse {
pub site: Option<SiteView>, // Because the site might not be set up yet
- pub number_of_users: i64,
- pub number_of_posts: i64,
- pub number_of_comments: i64,
- pub number_of_communities: i64,
+ pub counts: SiteAggregates,
pub admins: Vec<UserView>,
pub banned: Vec<UserView>,
pub online: usize,
--- /dev/null
+-- Site aggregates
+drop table site_aggregates;
+drop trigger site_aggregates_insert_user on user_;
+drop trigger site_aggregates_delete_user on user_;
+drop trigger site_aggregates_insert_post on post;
+drop trigger site_aggregates_delete_post on post;
+drop trigger site_aggregates_insert_comment on comment;
+drop trigger site_aggregates_delete_comment on comment;
+drop trigger site_aggregates_insert_community on community;
+drop trigger site_aggregates_delete_community on community;
+drop function
+ site_aggregates_user_increment,
+ site_aggregates_user_decrement,
+ site_aggregates_post_increment,
+ site_aggregates_post_decrement,
+ site_aggregates_comment_increment,
+ site_aggregates_comment_decrement,
+ site_aggregates_community_increment,
+ site_aggregates_community_decrement;
--- /dev/null
+-- Add site aggregates
+create table site_aggregates (
+ id serial primary key,
+ users bigint not null,
+ posts bigint not null,
+ comments bigint not null,
+ communities bigint not null
+);
+
+insert into site_aggregates (users, posts, comments, communities)
+ select ( select coalesce(count(*), 0) from user_) as users,
+ ( select coalesce(count(*), 0) from post) as posts,
+ ( select coalesce(count(*), 0) from comment) as comments,
+ ( select coalesce(count(*), 0) from community) as communities;
+
+-- Add site aggregate triggers
+-- user
+create function site_aggregates_user_increment()
+returns trigger language plpgsql
+as $$
+begin
+ update site_aggregates
+ set users = users + 1;
+ return null;
+end $$;
+
+create trigger site_aggregates_insert_user
+after insert on user_
+execute procedure site_aggregates_user_increment();
+
+create function site_aggregates_user_decrement()
+returns trigger language plpgsql
+as $$
+begin
+ update site_aggregates
+ set users = users - 1;
+ return null;
+end $$;
+
+create trigger site_aggregates_delete_user
+after delete on user_
+execute procedure site_aggregates_user_decrement();
+
+-- post
+create function site_aggregates_post_increment()
+returns trigger language plpgsql
+as $$
+begin
+ update site_aggregates
+ set posts = posts + 1;
+ return null;
+end $$;
+
+create trigger site_aggregates_insert_post
+after insert on post
+execute procedure site_aggregates_post_increment();
+
+create function site_aggregates_post_decrement()
+returns trigger language plpgsql
+as $$
+begin
+ update site_aggregates
+ set posts = posts - 1;
+ return null;
+end $$;
+
+create trigger site_aggregates_delete_post
+after delete on post
+execute procedure site_aggregates_post_decrement();
+
+-- comment
+create function site_aggregates_comment_increment()
+returns trigger language plpgsql
+as $$
+begin
+ update site_aggregates
+ set comments = comments + 1;
+ return null;
+end $$;
+
+create trigger site_aggregates_insert_comment
+after insert on comment
+execute procedure site_aggregates_comment_increment();
+
+create function site_aggregates_comment_decrement()
+returns trigger language plpgsql
+as $$
+begin
+ update site_aggregates
+ set comments = comments - 1;
+ return null;
+end $$;
+
+create trigger site_aggregates_delete_comment
+after delete on comment
+execute procedure site_aggregates_comment_decrement();
+
+-- community
+create function site_aggregates_community_increment()
+returns trigger language plpgsql
+as $$
+begin
+ update site_aggregates
+ set communities = communities + 1;
+ return null;
+end $$;
+
+create trigger site_aggregates_insert_community
+after insert on community
+execute procedure site_aggregates_community_increment();
+
+create function site_aggregates_community_decrement()
+returns trigger language plpgsql
+as $$
+begin
+ update site_aggregates
+ set communities = communities - 1;
+ return null;
+end $$;
+
+create trigger site_aggregates_delete_community
+after delete on community
+execute procedure site_aggregates_community_decrement();
+
+++ /dev/null
--- This file should undo anything in `up.sql`
\ No newline at end of file
+++ /dev/null
--- Your SQL goes here
\ No newline at end of file