summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorFelix <me@nutomic.com>2020-02-29 00:47:37 +0100
committerFelix <me@nutomic.com>2020-02-29 00:47:37 +0100
commitf9443dfbd3d542676385f37f68b60b0a61b48b2e (patch)
treed66f6e26a8a3a607f7a05a0539ae26f8168178ba /server
parentd932acad165f21f0cc7c952805596a60fc068627 (diff)
parent72c5bdbf9e788243df4b2ec1249495e4d7f4092c (diff)
Merge branch 'master' into federation
Diffstat (limited to 'server')
-rw-r--r--server/config/defaults.hjson2
-rwxr-xr-xserver/db-init.sh43
-rw-r--r--server/migrations/2020-02-06-165953_change_post_title_length/down.sql132
-rw-r--r--server/migrations/2020-02-06-165953_change_post_title_length/up.sql133
-rw-r--r--server/migrations/2020-02-07-210055_add_comment_subscribed/down.sql206
-rw-r--r--server/migrations/2020-02-07-210055_add_comment_subscribed/up.sql220
-rw-r--r--server/migrations/2020-02-08-145624_add_post_newest_activity_time/down.sql88
-rw-r--r--server/migrations/2020-02-08-145624_add_post_newest_activity_time/up.sql106
-rw-r--r--server/src/api/comment.rs53
-rw-r--r--server/src/api/post.rs20
-rw-r--r--server/src/db/comment_view.rs61
-rw-r--r--server/src/db/community_view.rs4
-rw-r--r--server/src/db/post_view.rs55
-rw-r--r--server/src/db/user_mention_view.rs12
-rw-r--r--server/src/db/user_view.rs5
-rw-r--r--server/src/routes/index.rs7
-rw-r--r--server/src/version.rs2
-rw-r--r--server/src/websocket/mod.rs1
-rw-r--r--server/src/websocket/server.rs169
19 files changed, 1231 insertions, 88 deletions
diff --git a/server/config/defaults.hjson b/server/config/defaults.hjson
index 6f4daaae..7eda46ec 100644
--- a/server/config/defaults.hjson
+++ b/server/config/defaults.hjson
@@ -32,7 +32,7 @@
# rate limits for various user actions, by user ip
rate_limit: {
# maximum number of messages created in interval
- message: 30
+ message: 180
# interval length for message limit
message_per_second: 60
# maximum number of posts created in interval
diff --git a/server/db-init.sh b/server/db-init.sh
new file mode 100755
index 00000000..c9150e9d
--- /dev/null
+++ b/server/db-init.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+username=lemmy
+dbname=lemmy
+port=5432
+
+password=""
+password_confirm=""
+password_valid=0
+
+while [ "$password_valid" == 0 ]
+do
+ read -p "Enter database password: " -s password
+ echo
+
+ read -p "Verify database password: " -s password_confirm
+ echo
+ echo
+
+ # Start the loop from the top if either check fails
+ if [ -z "$password" ]
+ then
+ echo "Error: Password cannot be empty." 1>&2
+ echo
+ continue
+ fi
+ if [ "$password" != "$password_confirm" ]
+ then
+ echo "Error: Passwords don't match." 1>&2
+ echo
+ continue
+ fi
+
+ # Set the password_valid variable to break out of the loop
+ password_valid=1
+done
+
+
+psql -c "CREATE USER $username WITH PASSWORD '$password' SUPERUSER;" -U postgres
+psql -c 'CREATE DATABASE $dbname WITH OWNER $username;' -U postgres
+export LEMMY_DATABASE_URL=postgres://$username:$password@localhost:$port/$dbname
+
+echo $LEMMY_DATABASE_URL
diff --git a/server/migrations/2020-02-06-165953_change_post_title_length/down.sql b/server/migrations/2020-02-06-165953_change_post_title_length/down.sql
new file mode 100644
index 00000000..2bc765f8
--- /dev/null
+++ b/server/migrations/2020-02-06-165953_change_post_title_length/down.sql
@@ -0,0 +1,132 @@
+-- Drop the dependent views
+drop view post_view;
+drop view post_mview;
+drop materialized view post_aggregates_mview;
+drop view post_aggregates_view;
+drop view mod_remove_post_view;
+drop view mod_sticky_post_view;
+drop view mod_lock_post_view;
+drop view mod_remove_comment_view;
+
+alter table post alter column name type varchar(100);
+
+-- regen post view
+create view post_aggregates_view as
+select
+p.*,
+(select u.banned from user_ u where p.creator_id = u.id) as banned,
+(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community,
+(select name from user_ where p.creator_id = user_.id) as creator_name,
+(select avatar from user_ where p.creator_id = user_.id) as creator_avatar,
+(select name from community where p.community_id = community.id) as community_name,
+(select removed from community c where p.community_id = c.id) as community_removed,
+(select deleted from community c where p.community_id = c.id) as community_deleted,
+(select nsfw from community c where p.community_id = c.id) as community_nsfw,
+(select count(*) from comment where comment.post_id = p.id) as number_of_comments,
+coalesce(sum(pl.score), 0) as score,
+count (case when pl.score = 1 then 1 else null end) as upvotes,
+count (case when pl.score = -1 then 1 else null end) as downvotes,
+hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank
+from post p
+left join post_like pl on p.id = pl.post_id
+group by p.id;
+
+create materialized view post_aggregates_mview as select * from post_aggregates_view;
+
+create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id);
+
+create view post_view as
+with all_post as (
+ select
+ pa.*
+ from post_aggregates_view pa
+)
+select
+ap.*,
+u.id as user_id,
+coalesce(pl.score, 0) as my_vote,
+(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed,
+(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read,
+(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved
+from user_ u
+cross join all_post ap
+left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
+
+union all
+
+select
+ap.*,
+null as user_id,
+null as my_vote,
+null as subscribed,
+null as read,
+null as saved
+from all_post ap
+;
+
+create view post_mview as
+with all_post as (
+ select
+ pa.*
+ from post_aggregates_mview pa
+)
+select
+ap.*,
+u.id as user_id,
+coalesce(pl.score, 0) as my_vote,
+(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed,
+(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read,
+(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved
+from user_ u
+cross join all_post ap
+left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
+
+union all
+
+select
+ap.*,
+null as user_id,
+null as my_vote,
+null as subscribed,
+null as read,
+null as saved
+from all_post ap
+;
+
+-- The mod views
+
+create view mod_remove_post_view as
+select mrp.*,
+(select name from user_ u where mrp.mod_user_id = u.id) as mod_user_name,
+(select name from post p where mrp.post_id = p.id) as post_name,
+(select c.id from post p, community c where mrp.post_id = p.id and p.community_id = c.id) as community_id,
+(select c.name from post p, community c where mrp.post_id = p.id and p.community_id = c.id) as community_name
+from mod_remove_post mrp;
+
+create view mod_lock_post_view as
+select mlp.*,
+(select name from user_ u where mlp.mod_user_id = u.id) as mod_user_name,
+(select name from post p where mlp.post_id = p.id) as post_name,
+(select c.id from post p, community c where mlp.post_id = p.id and p.community_id = c.id) as community_id,
+(select c.name from post p, community c where mlp.post_id = p.id and p.community_id = c.id) as community_name
+from mod_lock_post mlp;
+
+create view mod_remove_comment_view as
+select mrc.*,
+(select name from user_ u where mrc.mod_user_id = u.id) as mod_user_name,
+(select c.id from comment c where mrc.comment_id = c.id) as comment_user_id,
+(select name from user_ u, comment c where mrc.comment_id = c.id and u.id = c.creator_id) as comment_user_name,
+(select content from comment c where mrc.comment_id = c.id) as comment_content,
+(select p.id from post p, comment c where mrc.comment_id = c.id and c.post_id = p.id) as post_id,
+(select p.name from post p, comment c where mrc.comment_id = c.id and c.post_id = p.id) as post_name,
+(select co.id from comment c, post p, community co where mrc.comment_id = c.id and c.post_id = p.id and p.community_id = co.id) as community_id,
+(select co.name from comment c, post p, community co where mrc.comment_id = c.id and c.post_id = p.id and p.community_id = co.id) as community_name
+from mod_remove_comment mrc;
+
+create view mod_sticky_post_view as
+select msp.*,
+(select name from user_ u where msp.mod_user_id = u.id) as mod_user_name,
+(select name from post p where msp.post_id = p.id) as post_name,
+(select c.id from post p, community c where msp.post_id = p.id and p.community_id = c.id) as community_id,
+(select c.name from post p, community c where msp.post_id = p.id and p.community_id = c.id) as community_name
+from mod_sticky_post msp;
diff --git a/server/migrations/2020-02-06-165953_change_post_title_length/up.sql b/server/migrations/2020-02-06-165953_change_post_title_length/up.sql
new file mode 100644
index 00000000..006a7d04
--- /dev/null
+++ b/server/migrations/2020-02-06-165953_change_post_title_length/up.sql
@@ -0,0 +1,133 @@
+-- Drop the dependent views
+drop view post_view;
+drop view post_mview;
+drop materialized view post_aggregates_mview;
+drop view post_aggregates_view;
+drop view mod_remove_post_view;
+drop view mod_sticky_post_view;
+drop view mod_lock_post_view;
+drop view mod_remove_comment_view;
+
+-- Add the extra post limit
+alter table post alter column name type varchar(200);
+
+-- regen post view
+create view post_aggregates_view as
+select
+p.*,
+(select u.banned from user_ u where p.creator_id = u.id) as banned,
+(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community,
+(select name from user_ where p.creator_id = user_.id) as creator_name,
+(select avatar from user_ where p.creator_id = user_.id) as creator_avatar,
+(select name from community where p.community_id = community.id) as community_name,
+(select removed from community c where p.community_id = c.id) as community_removed,
+(select deleted from community c where p.community_id = c.id) as community_deleted,
+(select nsfw from community c where p.community_id = c.id) as community_nsfw,
+(select count(*) from comment where comment.post_id = p.id) as number_of_comments,
+coalesce(sum(pl.score), 0) as score,
+count (case when pl.score = 1 then 1 else null end) as upvotes,
+count (case when pl.score = -1 then 1 else null end) as downvotes,
+hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank
+from post p
+left join post_like pl on p.id = pl.post_id
+group by p.id;
+
+create materialized view post_aggregates_mview as select * from post_aggregates_view;
+
+create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id);
+
+create view post_view as
+with all_post as (
+ select
+ pa.*
+ from post_aggregates_view pa
+)
+select
+ap.*,
+u.id as user_id,
+coalesce(pl.score, 0) as my_vote,
+(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed,
+(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read,
+(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved
+from user_ u
+cross join all_post ap
+left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
+
+union all
+
+select
+ap.*,
+null as user_id,
+null as my_vote,
+null as subscribed,
+null as read,
+null as saved
+from all_post ap
+;
+
+create view post_mview as
+with all_post as (
+ select
+ pa.*
+ from post_aggregates_mview pa
+)
+select
+ap.*,
+u.id as user_id,
+coalesce(pl.score, 0) as my_vote,
+(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed,
+(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read,
+(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved
+from user_ u
+cross join all_post ap
+left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
+
+union all
+
+select
+ap.*,
+null as user_id,
+null as my_vote,
+null as subscribed,
+null as read,
+null as saved
+from all_post ap
+;
+
+-- The mod views
+
+create view mod_remove_post_view as
+select mrp.*,
+(select name from user_ u where mrp.mod_user_id = u.id) as mod_user_name,
+(select name from post p where mrp.post_id = p.id) as post_name,
+(select c.id from post p, community c where mrp.post_id = p.id and p.community_id = c.id) as community_id,
+(select c.name from post p, community c where mrp.post_id = p.id and p.community_id = c.id) as community_name
+from mod_remove_post mrp;
+
+create view mod_lock_post_view as
+select mlp.*,
+(select name from user_ u where mlp.mod_user_id = u.id) as mod_user_name,
+(select name from post p where mlp.post_id = p.id) as post_name,
+(select c.id from post p, community c where mlp.post_id = p.id and p.community_id = c.id) as community_id,
+(select c.name from post p, community c where mlp.post_id = p.id and p.community_id = c.id) as community_name
+from mod_lock_post mlp;
+
+create view mod_remove_comment_view as
+select mrc.*,
+(select name from user_ u where mrc.mod_user_id = u.id) as mod_user_name,
+(select c.id from comment c where mrc.comment_id = c.id) as comment_user_id,
+(select name from user_ u, comment c where mrc.comment_id = c.id and u.id = c.creator_id) as comment_user_name,
+(select content from comment c where mrc.comment_id = c.id) as comment_content,
+(select p.id from post p, comment c where mrc.comment_id = c.id and c.post_id = p.id) as post_id,
+(select p.name from post p, comment c where mrc.comment_id = c.id and c.post_id = p.id) as post_name,
+(select co.id from comment c, post p, community co where mrc.comment_id = c.id and c.post_id = p.id and p.community_id = co.id) as community_id,
+(select co.name from comment c, post p, community co where mrc.comment_id = c.id and c.post_id = p.id and p.community_id = co.id) as community_name
+from mod_remove_comment mrc;
+
+create view mod_sticky_post_view as
+select msp.*,
+(select name from user_ u where msp.mod_user_id = u.id) as mod_user_name,
+(select name from post p where msp.post_id = p.id) as post_name,
+(select c.id from post p, community c where msp.post_id = p.id and p.community_id = c.id) as community_id,
+(select c.name from post p, community c where msp.post_id = p.id and p.community_id = c.id) as community_name
+from mod_sticky_post msp;
diff --git a/server/migrations/2020-02-07-210055_add_comment_subscribed/down.sql b/server/migrations/2020-02-07-210055_add_comment_subscribed/down.sql
new file mode 100644
index 00000000..b6120d15
--- /dev/null
+++ b/server/migrations/2020-02-07-210055_add_comment_subscribed/down.sql
@@ -0,0 +1,206 @@
+
+drop view reply_view;
+drop view user_mention_view;
+drop view user_mention_mview;
+drop view comment_view;
+drop view comment_mview;
+drop materialized view comment_aggregates_mview;
+drop view comment_aggregates_view;
+
+-- reply and comment view
+create view comment_aggregates_view as
+select
+c.*,
+(select community_id from post p where p.id = c.post_id),
+(select u.banned from user_ u where c.creator_id = u.id) as banned,
+(select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community,
+(select name from user_ where c.creator_id = user_.id) as creator_name,
+(select avatar from user_ where c.creator_id = user_.id) as creator_avatar,
+coalesce(sum(cl.score), 0) as score,
+count (case when cl.score = 1 then 1 else null end) as upvotes,
+count (case when cl.score = -1 then 1 else null end) as downvotes
+from comment c
+left join comment_like cl on c.id = cl.comment_id
+group by c.id;
+
+create materialized view comment_aggregates_mview as select * from comment_aggregates_view;
+
+create unique index idx_comment_aggregates_mview_id on comment_aggregates_mview (id);
+
+create view comment_view as
+with all_comment as
+(
+ select
+ ca.*
+ from comment_aggregates_view ca
+)
+
+select
+ac.*,
+u.id as user_id,
+coalesce(cl.score, 0) as my_vote,
+(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved
+from user_ u
+cross join all_comment ac
+left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id
+
+union all
+
+select
+ ac.*,
+ null as user_id,
+ null as my_vote,
+ null as saved
+from all_comment ac
+;
+
+create view comment_mview as
+with all_comment as
+(
+ select
+ ca.*
+ from comment_aggregates_mview ca
+)
+
+select
+ac.*,
+u.id as user_id,
+coalesce(cl.score, 0) as my_vote,
+(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved
+from user_ u
+cross join all_comment ac
+left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id
+
+union all
+
+select
+ ac.*,
+ null as user_id,
+ null as my_vote,
+ null as saved
+from all_comment ac
+;
+
+
+-- Do the reply_view referencing the comment_mview
+create view reply_view as
+with closereply as (
+ select
+ c2.id,
+ c2.creator_id as sender_id,
+ c.creator_id as recipient_id
+ from comment c
+ inner join comment c2 on c.id = c2.parent_id
+ where c2.creator_id != c.creator_id
+ -- Do union where post is null
+ union
+ select
+ c.id,
+ c.creator_id as sender_id,
+ p.creator_id as recipient_id
+ from comment c, post p
+ where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id
+)
+select cv.*,
+closereply.recipient_id
+from comment_mview cv, closereply
+where closereply.id = cv.id
+;
+
+-- user mention
+create view user_mention_view as
+select
+ c.id,
+ um.id as user_mention_id,
+ c.creator_id,
+ c.post_id,
+ c.parent_id,
+ c.content,
+ c.removed,
+ um.read,
+ c.published,
+ c.updated,
+ c.deleted,
+ c.community_id,
+ c.banned,
+ c.banned_from_community,
+ c.creator_name,
+ c.creator_avatar,
+ c.score,
+ c.upvotes,
+ c.downvotes,
+ c.user_id,
+ c.my_vote,
+ c.saved,
+ um.recipient_id
+from user_mention um, comment_view c
+where um.comment_id = c.id;
+
+
+create view user_mention_mview as
+with all_comment as
+(
+ select
+ ca.*
+ from comment_aggregates_mview ca
+)
+
+select
+ ac.id,
+ um.id as user_mention_id,
+ ac.creator_id,
+ ac.post_id,
+ ac.parent_id,
+ ac.content,
+ ac.removed,
+ um.read,
+ ac.published,
+ ac.updated,
+ ac.deleted,
+ ac.community_id,
+ ac.banned,
+ ac.banned_from_community,
+ ac.creator_name,
+ ac.creator_avatar,
+ ac.score,
+ ac.upvotes,
+ ac.downvotes,
+ u.id as user_id,
+ coalesce(cl.score, 0) as my_vote,
+ (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved,
+ um.recipient_id
+from user_ u
+cross join all_comment ac
+left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id
+left join user_mention um on um.comment_id = ac.id
+
+union all
+
+select
+ ac.id,
+ um.id as user_mention_id,
+ ac.creator_id,
+ ac.post_id,
+ ac.parent_id,
+ ac.content,
+ ac.removed,
+ um.read,
+ ac.published,
+ ac.updated,
+ ac.deleted,
+ ac.community_id,
+ ac.banned,
+ ac.banned_from_community,
+ ac.creator_name,
+ ac.creator_avatar,
+ ac.score,
+ ac.upvotes,
+ ac.downvotes,
+ null as user_id,
+ null as my_vote,
+ null as saved,
+ um.recipient_id
+from all_comment ac
+left join user_mention um on um.comment_id = ac.id
+;
+
diff --git a/server/migrations/2020-02-07-210055_add_comment_subscribed/up.sql b/server/migrations/2020-02-07-210055_add_comment_subscribed/up.sql
new file mode 100644
index 00000000..8836a571
--- /dev/null
+++ b/server/migrations/2020-02-07-210055_add_comment_subscribed/up.sql
@@ -0,0 +1,220 @@
+
+-- Adding community name, hot_rank, to comment_view, user_mention_view, and subscribed to comment_view
+
+-- Rebuild the comment view
+drop view reply_view;
+drop view user_mention_view;
+drop view user_mention_mview;
+drop view comment_view;
+drop view comment_mview;
+drop materialized view comment_aggregates_mview;
+drop view comment_aggregates_view;
+
+-- reply and comment view
+create view comment_aggregates_view as
+select
+c.*,
+(select community_id from post p where p.id = c.post_id),
+(select co.name from post p, community co where p.id = c.post_id and p.community_id = co.id) as community_name,
+(select u.banned from user_ u where c.creator_id = u.id) as banned,
+(select cb.id::bool from community_user_ban cb, post p where c.creator_id = cb.user_id and p.id = c.post_id and p.community_id = cb.community_id) as banned_from_community,
+(select name from user_ where c.creator_id = user_.id) as creator_name,
+(select avatar from user_ where c.creator_id = user_.id) as creator_avatar,
+coalesce(sum(cl.score), 0) as score,
+count (case when cl.score = 1 then 1 else null end) as upvotes,
+count (case when cl.score = -1 then 1 else null end) as downvotes,
+hot_rank(coalesce(sum(cl.score) , 0), c.published) as hot_rank
+from comment c
+left join comment_like cl on c.id = cl.comment_id
+group by c.id;
+
+create materialized view comment_aggregates_mview as select * from comment_aggregates_view;
+
+create unique index idx_comment_aggregates_mview_id on comment_aggregates_mview (id);
+
+create view comment_view as
+with all_comment as
+(
+ select
+ ca.*
+ from comment_aggregates_view ca
+)
+
+select
+ac.*,
+u.id as user_id,
+coalesce(cl.score, 0) as my_vote,
+(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed,
+(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved
+from user_ u
+cross join all_comment ac
+left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id
+
+union all
+
+select
+ ac.*,
+ null as user_id,
+ null as my_vote,
+ null as subscribed,
+ null as saved
+from all_comment ac
+;
+
+create view comment_mview as
+with all_comment as
+(
+ select
+ ca.*
+ from comment_aggregates_mview ca
+)
+
+select
+ac.*,
+u.id as user_id,
+coalesce(cl.score, 0) as my_vote,
+(select cf.id::boolean from community_follower cf where u.id = cf.user_id and ac.community_id = cf.community_id) as subscribed,
+(select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved
+from user_ u
+cross join all_comment ac
+left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id
+
+union all
+
+select
+ ac.*,
+ null as user_id,
+ null as my_vote,
+ null as subscribed,
+ null as saved
+from all_comment ac
+;
+
+-- Do the reply_view referencing the comment_mview
+create view reply_view as
+with closereply as (
+ select
+ c2.id,
+ c2.creator_id as sender_id,
+ c.creator_id as recipient_id
+ from comment c
+ inner join comment c2 on c.id = c2.parent_id
+ where c2.creator_id != c.creator_id
+ -- Do union where post is null
+ union
+ select
+ c.id,
+ c.creator_id as sender_id,
+ p.creator_id as recipient_id
+ from comment c, post p
+ where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id
+)
+select cv.*,
+closereply.recipient_id
+from comment_mview cv, closereply
+where closereply.id = cv.id
+;
+
+-- user mention
+create view user_mention_view as
+select
+ c.id,
+ um.id as user_mention_id,
+ c.creator_id,
+ c.post_id,
+ c.parent_id,
+ c.content,
+ c.removed,
+ um.read,
+ c.published,
+ c.updated,
+ c.deleted,
+ c.community_id,
+ c.community_name,
+ c.banned,
+ c.banned_from_community,
+ c.creator_name,
+ c.creator_avatar,
+ c.score,
+ c.upvotes,
+ c.downvotes,
+ c.hot_rank,
+ c.user_id,
+ c.my_vote,
+ c.saved,
+ um.recipient_id
+from user_mention um, comment_view c
+where um.comment_id = c.id;
+
+
+create view user_mention_mview as
+with all_comment as
+(
+ select
+ ca.*
+ from comment_aggregates_mview ca
+)
+
+select
+ ac.id,
+ um.id as user_mention_id,
+ ac.creator_id,
+ ac.post_id,
+ ac.parent_id,
+ ac.content,
+ ac.removed,
+ um.read,
+ ac.published,
+ ac.updated,
+ ac.deleted,
+ ac.community_id,
+ ac.community_name,
+ ac.banned,
+ ac.banned_from_community,
+ ac.creator_name,
+ ac.creator_avatar,
+ ac.score,
+ ac.upvotes,
+ ac.downvotes,
+ ac.hot_rank,
+ u.id as user_id,
+ coalesce(cl.score, 0) as my_vote,
+ (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved,
+ um.recipient_id
+from user_ u
+cross join all_comment ac
+left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id
+left join user_mention um on um.comment_id = ac.id
+
+union all
+
+select
+ ac.id,
+ um.id as user_mention_id,
+ ac.creator_id,
+ ac.post_id,
+ ac.parent_id,
+ ac.content,
+ ac.removed,
+ um.read,
+ ac.published,
+ ac.updated,
+ ac.deleted,
+ ac.community_id,
+ ac.community_name,
+ ac.banned,
+ ac.banned_from_community,
+ ac.creator_name,
+ ac.creator_avatar,
+ ac.score,
+ ac.upvotes,
+ ac.downvotes,
+ ac.hot_rank,
+ null as user_id,
+ null as my_vote,
+ null as saved,
+ um.recipient_id
+from all_comment ac
+left join user_mention um on um.comment_id = ac.id
+;
+
diff --git a/server/migrations/2020-02-08-145624_add_post_newest_activity_time/down.sql b/server/migrations/2020-02-08-145624_add_post_newest_activity_time/down.sql
new file mode 100644
index 00000000..8b912fa3
--- /dev/null
+++ b/server/migrations/2020-02-08-145624_add_post_newest_activity_time/down.sql
@@ -0,0 +1,88 @@
+drop view post_view;
+drop view post_mview;
+drop materialized view post_aggregates_mview;
+drop view post_aggregates_view;
+
+-- regen post view
+create view post_aggregates_view as
+select
+p.*,
+(select u.banned from user_ u where p.creator_id = u.id) as banned,
+(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community,
+(select name from user_ where p.creator_id = user_.id) as creator_name,
+(select avatar from user_ where p.creator_id = user_.id) as creator_avatar,
+(select name from community where p.community_id = community.id) as community_name,
+(select removed from community c where p.community_id = c.id) as community_removed,
+(select deleted from community c where p.community_id = c.id) as community_deleted,
+(select nsfw from community c where p.community_id = c.id) as community_nsfw,
+(select count(*) from comment where comment.post_id = p.id) as number_of_comments,
+coalesce(sum(pl.score), 0) as score,
+count (case when pl.score = 1 then 1 else null end) as upvotes,
+count (case when pl.score = -1 then 1 else null end) as downvotes,
+hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank
+from post p
+left join post_like pl on p.id = pl.post_id
+group by p.id;
+
+create materialized view post_aggregates_mview as select * from post_aggregates_view;
+
+create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id);
+
+create view post_view as
+with all_post as (
+ select
+ pa.*
+ from post_aggregates_view pa
+)
+select
+ap.*,
+u.id as user_id,
+coalesce(pl.score, 0) as my_vote,
+(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed,
+(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read,
+(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved
+from user_ u
+cross join all_post ap
+left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
+
+union all
+
+select
+ap.*,
+null as user_id,
+null as my_vote,
+null as subscribed,
+null as read,
+null as saved
+from all_post ap
+;
+
+create view post_mview as
+with all_post as (
+ select
+ pa.*
+ from post_aggregates_mview pa
+)
+select
+ap.*,
+u.id as user_id,
+coalesce(pl.score, 0) as my_vote,
+(select cf.id::bool from community_follower cf where u.id = cf.user_id and cf.community_id = ap.community_id) as subscribed,
+(select pr.id::bool from post_read pr where u.id = pr.user_id and pr.post_id = ap.id) as read,
+(select ps.id::bool from post_saved ps where u.id = ps.user_id and ps.post_id = ap.id) as saved
+from user_ u
+cross join all_post ap
+left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
+
+union all
+
+select
+ap.*,
+null as user_id,
+null as my_vote,
+null as subscribed,
+null as read,
+null as saved
+from all_post ap
+;
+
diff --git a/server/migrations/2020-02-08-145624_add_post_newest_activity_time/up.sql b/server/migrations/2020-02-08-145624_add_post_newest_activity_time/up.sql
new file mode 100644
index 00000000..e1541277
--- /dev/null
+++ b/server/migrations/2020-02-08-145624_add_post_newest_activity_time/up.sql
@@ -0,0 +1,106 @@
+-- Adds a newest_activity_time for the post_views, in order to sort by newest comment
+drop view post_view;
+drop view post_mview;
+drop materialized view post_aggregates_mview;
+drop view post_aggregates_view;
+
+-- regen post view
+create view post_aggregates_view as
+select
+p.*,
+(select u.banned from user_ u where p.creator_id = u.id) as banned,
+(select cb.id::bool from community_user_ban cb where p.creator_id = cb.user_id and p.community_id = cb.community_id) as banned_from_community,
+(select name from user_ where p.creator_id = user_.id) as creator_name,
+(select avatar from user_ where p.creator_id = user_.id) as creator_avatar,
+(select name from community where p.community_id = community.id) as community_name,
+(select removed from community c where p.community_id = c.id) as community_removed,
+(select deleted from community c where p.community_id = c.id) as community_deleted,
+(select nsfw from community c where p.community_id = c.id) as community_nsfw,
+(select count(*) from comment where comment.post_id = p.id) as number_of_comments,
+coalesce(sum(pl.score), 0) as score,
+count (case when pl.score = 1 then 1 else null end) as upvotes,
+count (case when pl.score = -1 then 1 else null end) as downvotes,
+hot_rank(coalesce(sum(pl.score) , 0),
+ (
+ case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps
+ else greatest(c.recent_comment_time, p.published)
+ end
+ )
+) as hot_rank,
+(
+ case when (p.published < ('now'::timestamp - '1 month'::interval)) then p.published -- Prevents necro-bumps
+ else greatest(c.recent_comment_time, p.published)
+ end
+) as newest_activity_time
+from post p
+left join post_like pl on p.id = pl.post_id
+left join (
+ select post_id,
+ max(published) as recent_comment_time
+ from comment
+ group by 1
+) c on p.id = c.post_id
+group by p.id, c.recent_comment_time;
+
+create materialized view post_aggregates_mview as select * from post_aggregates_view;
+
+create unique index idx_post_aggregates_mview_id on post_aggregates_mview (id);
+
+create view post_view as
+with all_post as (
+ select
+ pa.*
+ from post_aggregates_view pa
+)
+select
+ap.*,
+u.id as user_id,
+coalesce(pl.score, 0) as my_vote,
+(selec