Adding SiteAggregates.

This commit is contained in:
Dessalines 2020-12-02 22:39:31 -05:00
parent ca7224c086
commit 7731479607
17 changed files with 257 additions and 80 deletions

View file

@ -19,6 +19,7 @@ use lemmy_db::{
naive_now, naive_now,
post_view::*, post_view::*,
site::*, site::*,
site_aggregates::SiteAggregates,
user_view::*, user_view::*,
views::site_view::SiteView, views::site_view::SiteView,
Crud, Crud,
@ -310,6 +311,8 @@ impl Perform for GetSite {
u u
}); });
let counts = blocking(context.pool(), move |conn| SiteAggregates::read(conn)).await??;
Ok(GetSiteResponse { Ok(GetSiteResponse {
site: site_view, site: site_view,
admins, admins,
@ -318,11 +321,7 @@ impl Perform for GetSite {
version: version::VERSION.to_string(), version: version::VERSION.to_string(),
my_user, my_user,
federated_instances: linked_instances(context.pool()).await?, federated_instances: linked_instances(context.pool()).await?,
// TODO counts,
number_of_users: 0,
number_of_posts: 0,
number_of_comments: 0,
number_of_communities: 0,
}) })
} }
} }
@ -546,6 +545,8 @@ impl Perform for TransferSite {
let banned = blocking(context.pool(), move |conn| UserView::banned(conn)).await??; let banned = blocking(context.pool(), move |conn| UserView::banned(conn)).await??;
let counts = blocking(context.pool(), move |conn| SiteAggregates::read(conn)).await??;
Ok(GetSiteResponse { Ok(GetSiteResponse {
site: Some(site_view), site: Some(site_view),
admins, admins,
@ -554,11 +555,7 @@ impl Perform for TransferSite {
version: version::VERSION.to_string(), version: version::VERSION.to_string(),
my_user: Some(user), my_user: Some(user),
federated_instances: linked_instances(context.pool()).await?, federated_instances: linked_instances(context.pool()).await?,
// TODO counts,
number_of_users: 0,
number_of_posts: 0,
number_of_comments: 0,
number_of_communities: 0,
}) })
} }
} }

View file

@ -194,7 +194,7 @@ async fn check_private_message_activity_valid<T, Kind>(
where where
T: AsBase<Kind> + AsObject<Kind> + ActorAndObjectRefExt, 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 { if to_and_cc.len() != 1 {
return Err(anyhow!("Private message can only be addressed to one user").into()); return Err(anyhow!("Private message can only be addressed to one user").into());
} }

View file

@ -81,7 +81,7 @@ pub async fn community_inbox(
Community::read_from_name(&conn, &path) Community::read_from_name(&conn, &path)
}) })
.await??; .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()?) { if !to_and_cc.contains(&&community.actor_id()?) {
return Err(anyhow!("Activity delivered to wrong community").into()); return Err(anyhow!("Activity delivered to wrong community").into());
} }

View file

@ -50,7 +50,7 @@ pub(crate) async fn is_activity_already_known(
} }
} }
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 where
T: AsBase<Kind> + AsObject<Kind> + ActorAndObjectRefExt, T: AsBase<Kind> + AsObject<Kind> + ActorAndObjectRefExt,
{ {
@ -75,14 +75,14 @@ where
.collect(); .collect();
to_and_cc.append(&mut cc); 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> pub(crate) fn is_addressed_to_public<T, Kind>(activity: &T) -> Result<(), LemmyError>
where where
T: AsBase<Kind> + AsObject<Kind> + ActorAndObjectRefExt, 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()) { if to_and_cc.contains(&public()) {
Ok(()) Ok(())
} else { } else {

View file

@ -66,7 +66,7 @@ pub async fn shared_inbox(
let activity_any_base = activity.clone().into_any_base()?; let activity_any_base = activity.clone().into_any_base()?;
let mut res: Option<HttpResponse> = None; 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. // 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 // If we handled the user receive first, the activity would be inserted to the database before the
// community could check for bans. // community could check for bans.

View file

@ -101,7 +101,7 @@ pub async fn user_inbox(
User_::read_from_name(&conn, &username) User_::read_from_name(&conn, &username)
}) })
.await??; .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 // TODO: we should also accept activities that are sent to community followers
if !to_and_cc.contains(&&user.actor_id()?) { if !to_and_cc.contains(&&user.actor_id()?) {
return Err(anyhow!("Activity delivered to wrong user").into()); return Err(anyhow!("Activity delivered to wrong user").into());
@ -172,7 +172,7 @@ async fn is_for_user_inbox(
context: &LemmyContext, context: &LemmyContext,
activity: &UserAcceptedActivities, activity: &UserAcceptedActivities,
) -> Result<(), LemmyError> { ) -> 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 // Check if it is addressed directly to any local user
if is_addressed_to_local_user(&to_and_cc, context.pool()).await? { if is_addressed_to_local_user(&to_and_cc, context.pool()).await? {
return Ok(()); return Ok(());

View file

@ -28,7 +28,7 @@ pub mod private_message;
pub mod private_message_view; pub mod private_message_view;
pub mod schema; pub mod schema;
pub mod site; pub mod site;
pub mod site_view; pub mod site_aggregates;
pub mod user; pub mod user;
pub mod user_mention; pub mod user_mention;
pub mod user_mention_view; pub mod user_mention_view;

View file

@ -440,6 +440,16 @@ table! {
} }
} }
table! {
site_aggregates (id) {
id -> Int4,
users -> Int8,
posts -> Int8,
comments -> Int8,
communities -> Int8,
}
}
table! { table! {
user_ (id) { user_ (id) {
id -> Int4, id -> Int4,
@ -587,6 +597,7 @@ allow_tables_to_appear_in_same_query!(
post_saved, post_saved,
private_message, private_message,
site, site,
site_aggregates,
user_, user_,
user_ban, user_ban,
user_fast, user_fast,

View file

@ -0,0 +1,19 @@
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)
}
}

View file

@ -1,55 +0,0 @@
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)
}
}

View file

@ -1 +1,2 @@
pub mod site_view; pub mod site_view;
pub mod user_view;

View file

@ -0,0 +1,65 @@
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>>()
}

View file

@ -4,6 +4,7 @@ use lemmy_db::{
community_view::*, community_view::*,
moderator_views::*, moderator_views::*,
post_view::*, post_view::*,
site_aggregates::SiteAggregates,
user::*, user::*,
user_view::*, user_view::*,
views::site_view::SiteView, views::site_view::SiteView,
@ -98,10 +99,7 @@ pub struct SiteResponse {
#[derive(Serialize)] #[derive(Serialize)]
pub struct GetSiteResponse { pub struct GetSiteResponse {
pub site: Option<SiteView>, // Because the site might not be set up yet pub site: Option<SiteView>, // Because the site might not be set up yet
pub number_of_users: i64, pub counts: SiteAggregates,
pub number_of_posts: i64,
pub number_of_comments: i64,
pub number_of_communities: i64,
pub admins: Vec<UserView>, pub admins: Vec<UserView>,
pub banned: Vec<UserView>, pub banned: Vec<UserView>,
pub online: usize, pub online: usize,

View file

@ -0,0 +1,19 @@
-- 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;

View file

@ -0,0 +1,124 @@
-- 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();

View file

@ -1 +0,0 @@
-- This file should undo anything in `up.sql`

View file

@ -1 +0,0 @@
-- Your SQL goes here