mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-30 05:11:03 +00:00
Adding post editing.
- Adding post editing. Fixes #23 - Making SQL versions of comment and post fetching. Fixes #21 - Starting to add forum categories. #17
This commit is contained in:
parent
c786464381
commit
e690d6c470
25 changed files with 764 additions and 414 deletions
|
@ -40,6 +40,7 @@ We have a twitter alternative (mastodon), a facebook alternative (friendica), so
|
||||||
- [Rust JWT](https://github.com/Keats/jsonwebtoken)
|
- [Rust JWT](https://github.com/Keats/jsonwebtoken)
|
||||||
- [Hierarchical tree building javascript](https://stackoverflow.com/a/40732240/1655478)
|
- [Hierarchical tree building javascript](https://stackoverflow.com/a/40732240/1655478)
|
||||||
- [Hot sorting discussion](https://meta.stackexchange.com/questions/11602/what-formula-should-be-used-to-determine-hot-questions) [2](https://medium.com/hacking-and-gonzo/how-reddit-ranking-algorithms-work-ef111e33d0d9)
|
- [Hot sorting discussion](https://meta.stackexchange.com/questions/11602/what-formula-should-be-used-to-determine-hot-questions) [2](https://medium.com/hacking-and-gonzo/how-reddit-ranking-algorithms-work-ef111e33d0d9)
|
||||||
|
- [Classification types.](https://www.reddit.com/r/ModeratorDuck/wiki/subreddit_classification)
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
- Endpoints
|
- Endpoints
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
drop table community_moderator;
|
drop table community_moderator;
|
||||||
drop table community_follower;
|
drop table community_follower;
|
||||||
drop table community;
|
drop table community;
|
||||||
|
drop table category;
|
||||||
|
|
|
@ -1,6 +1,44 @@
|
||||||
|
create table category (
|
||||||
|
id serial primary key,
|
||||||
|
name varchar(100) not null unique
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into category (name) values
|
||||||
|
('Discussion'),
|
||||||
|
('Humor/Memes'),
|
||||||
|
('Gaming'),
|
||||||
|
('Movies'),
|
||||||
|
('TV'),
|
||||||
|
('Music'),
|
||||||
|
('Literature'),
|
||||||
|
('Comics'),
|
||||||
|
('Photography'),
|
||||||
|
('Art'),
|
||||||
|
('Learning'),
|
||||||
|
('DIY'),
|
||||||
|
('Lifestyle'),
|
||||||
|
('News'),
|
||||||
|
('Politics'),
|
||||||
|
('Society'),
|
||||||
|
('Gender/Identity/Sexuality'),
|
||||||
|
('Race/Colonisation'),
|
||||||
|
('Religion'),
|
||||||
|
('Science/Technology'),
|
||||||
|
('Programming/Software'),
|
||||||
|
('Health/Sports/Fitness'),
|
||||||
|
('Porn'),
|
||||||
|
('Places'),
|
||||||
|
('Meta'),
|
||||||
|
('Other');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
create table community (
|
create table community (
|
||||||
id serial primary key,
|
id serial primary key,
|
||||||
name varchar(20) not null unique,
|
name varchar(20) not null unique,
|
||||||
|
title varchar(100) not null,
|
||||||
|
description text,
|
||||||
|
category_id int references category on update cascade on delete cascade not null,
|
||||||
creator_id int references user_ on update cascade on delete cascade not null,
|
creator_id int references user_ on update cascade on delete cascade not null,
|
||||||
published timestamp not null default now(),
|
published timestamp not null default now(),
|
||||||
updated timestamp
|
updated timestamp
|
||||||
|
@ -20,4 +58,4 @@ create table community_follower (
|
||||||
published timestamp not null default now()
|
published timestamp not null default now()
|
||||||
);
|
);
|
||||||
|
|
||||||
insert into community (name, creator_id) values ('main', 1);
|
insert into community (name, title, category_id, creator_id) values ('main', 'The default Community', 1, 1);
|
||||||
|
|
|
@ -13,30 +13,23 @@ create view post_view as
|
||||||
with all_post as
|
with all_post as
|
||||||
(
|
(
|
||||||
select
|
select
|
||||||
p.id as id,
|
p.*,
|
||||||
p.name as name,
|
|
||||||
p.url,
|
|
||||||
p.body,
|
|
||||||
p.creator_id,
|
|
||||||
(select name from user_ where p.creator_id = user_.id) creator_name,
|
(select name from user_ where p.creator_id = user_.id) creator_name,
|
||||||
p.community_id,
|
|
||||||
(select name from community where p.community_id = community.id) as community_name,
|
(select name from community where p.community_id = community.id) as community_name,
|
||||||
(select count(*) from comment where comment.post_id = p.id) as number_of_comments,
|
(select count(*) from comment where comment.post_id = p.id) as number_of_comments,
|
||||||
coalesce(sum(pl.score), 0) as score,
|
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 upvotes,
|
||||||
count (case when pl.score = -1 then 1 else null end) as downvotes,
|
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,
|
hot_rank(coalesce(sum(pl.score) , 0), p.published) as hot_rank
|
||||||
p.published,
|
|
||||||
p.updated
|
|
||||||
from post p
|
from post p
|
||||||
left join post_like pl on p.id = pl.post_id
|
left join post_like pl on p.id = pl.post_id
|
||||||
group by p.id
|
group by p.id
|
||||||
)
|
)
|
||||||
|
|
||||||
select
|
select
|
||||||
|
ap.*,
|
||||||
u.id as user_id,
|
u.id as user_id,
|
||||||
coalesce(pl.score, 0) as my_vote,
|
coalesce(pl.score, 0) as my_vote
|
||||||
ap.*
|
|
||||||
from user_ u
|
from user_ u
|
||||||
cross join all_post ap
|
cross join all_post ap
|
||||||
left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
|
left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
|
||||||
|
@ -44,9 +37,9 @@ left join post_like pl on u.id = pl.user_id and ap.id = pl.post_id
|
||||||
union all
|
union all
|
||||||
|
|
||||||
select
|
select
|
||||||
null as user_id,
|
ap.*,
|
||||||
null as my_vote,
|
null as user_id,
|
||||||
ap.*
|
null as my_vote
|
||||||
from all_post ap
|
from all_post ap
|
||||||
;
|
;
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
drop view community_view;
|
||||||
|
drop view community_moderator_view;
|
||||||
|
drop view community_follower_view;
|
|
@ -0,0 +1,16 @@
|
||||||
|
create view community_view as
|
||||||
|
select *,
|
||||||
|
(select name from user_ u where c.creator_id = u.id) as creator_name,
|
||||||
|
(select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers,
|
||||||
|
(select count(*) from post p where p.community_id = c.id) as number_of_posts
|
||||||
|
from community c;
|
||||||
|
|
||||||
|
create view community_moderator_view as
|
||||||
|
select *,
|
||||||
|
(select name from user_ u where cm.user_id = u.id) as user_name
|
||||||
|
from community_moderator cm;
|
||||||
|
|
||||||
|
create view community_follower_view as
|
||||||
|
select *,
|
||||||
|
(select name from user_ u where cf.user_id = u.id) as user_name
|
||||||
|
from community_follower cf;
|
|
@ -0,0 +1 @@
|
||||||
|
drop view comment_view;
|
|
@ -0,0 +1,30 @@
|
||||||
|
create view comment_view as
|
||||||
|
with all_comment as
|
||||||
|
(
|
||||||
|
select
|
||||||
|
c.*,
|
||||||
|
(select name from user_ where c.creator_id = user_.id) creator_name,
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
select
|
||||||
|
ac.*,
|
||||||
|
u.id as user_id,
|
||||||
|
coalesce(cl.score, 0) as my_vote
|
||||||
|
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
|
||||||
|
from all_comment ac
|
||||||
|
;
|
|
@ -117,97 +117,6 @@ impl CommentLike {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl Comment {
|
|
||||||
fn from_post(conn: &PgConnection, post_id_from: i32) -> Result<Vec<Self>, Error> {
|
|
||||||
use schema::comment::dsl::*;
|
|
||||||
comment
|
|
||||||
.filter(post_id.eq(post_id_from))
|
|
||||||
.order_by(published.desc())
|
|
||||||
.load::<Self>(conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct CommentView {
|
|
||||||
pub id: i32,
|
|
||||||
pub creator_id: i32,
|
|
||||||
pub content: String,
|
|
||||||
pub post_id: i32,
|
|
||||||
pub parent_id: Option<i32>,
|
|
||||||
pub published: chrono::NaiveDateTime,
|
|
||||||
pub updated: Option<chrono::NaiveDateTime>,
|
|
||||||
pub score: i32,
|
|
||||||
pub upvotes: i32,
|
|
||||||
pub downvotes: i32,
|
|
||||||
pub my_vote: Option<i16>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommentView {
|
|
||||||
pub fn from_comment(comment: &Comment, likes: &Vec<CommentLike>, user_id: Option<i32>) -> Self {
|
|
||||||
let mut upvotes: i32 = 0;
|
|
||||||
let mut downvotes: i32 = 0;
|
|
||||||
let mut my_vote: Option<i16> = Some(0);
|
|
||||||
|
|
||||||
for like in likes.iter() {
|
|
||||||
if like.score == 1 {
|
|
||||||
upvotes += 1;
|
|
||||||
} else if like.score == -1 {
|
|
||||||
downvotes += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(user) = user_id {
|
|
||||||
if like.user_id == user {
|
|
||||||
my_vote = Some(like.score);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
let score: i32 = upvotes - downvotes;
|
|
||||||
|
|
||||||
CommentView {
|
|
||||||
id: comment.id,
|
|
||||||
content: comment.content.to_owned(),
|
|
||||||
parent_id: comment.parent_id,
|
|
||||||
post_id: comment.post_id,
|
|
||||||
creator_id: comment.creator_id,
|
|
||||||
published: comment.published,
|
|
||||||
updated: comment.updated,
|
|
||||||
upvotes: upvotes,
|
|
||||||
score: score,
|
|
||||||
downvotes: downvotes,
|
|
||||||
my_vote: my_vote
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(conn: &PgConnection, comment_id: i32, user_id: Option<i32>) -> Self {
|
|
||||||
let comment = Comment::read(&conn, comment_id).unwrap();
|
|
||||||
let likes = CommentLike::read(&conn, comment_id).unwrap();
|
|
||||||
Self::from_comment(&comment, &likes, user_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_post(conn: &PgConnection, post_id: i32, user_id: Option<i32>) -> Vec<Self> {
|
|
||||||
let comments = Comment::from_post(&conn, post_id).unwrap();
|
|
||||||
let post_comment_likes = CommentLike::from_post(&conn, post_id).unwrap();
|
|
||||||
|
|
||||||
let mut views = Vec::new();
|
|
||||||
for comment in comments.iter() {
|
|
||||||
let comment_likes: Vec<CommentLike> = post_comment_likes
|
|
||||||
.iter()
|
|
||||||
.filter(|like| comment.id == like.comment_id)
|
|
||||||
.cloned()
|
|
||||||
.collect();
|
|
||||||
let comment_view = CommentView::from_comment(&comment, &comment_likes, user_id);
|
|
||||||
views.push(comment_view);
|
|
||||||
};
|
|
||||||
|
|
||||||
views
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use establish_connection;
|
use establish_connection;
|
||||||
|
@ -233,6 +142,9 @@ mod tests {
|
||||||
|
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "test community".to_string(),
|
name: "test community".to_string(),
|
||||||
|
title: "nada".to_owned(),
|
||||||
|
description: None,
|
||||||
|
category_id: 1,
|
||||||
creator_id: inserted_user.id,
|
creator_id: inserted_user.id,
|
||||||
updated: None
|
updated: None
|
||||||
};
|
};
|
||||||
|
|
195
server/src/actions/comment_view.rs
Normal file
195
server/src/actions/comment_view.rs
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
extern crate diesel;
|
||||||
|
use diesel::*;
|
||||||
|
use diesel::result::Error;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
// The faked schema since diesel doesn't do views
|
||||||
|
table! {
|
||||||
|
comment_view (id) {
|
||||||
|
id -> Int4,
|
||||||
|
creator_id -> Int4,
|
||||||
|
post_id -> Int4,
|
||||||
|
parent_id -> Nullable<Int4>,
|
||||||
|
content -> Text,
|
||||||
|
published -> Timestamp,
|
||||||
|
updated -> Nullable<Timestamp>,
|
||||||
|
creator_name -> Varchar,
|
||||||
|
score -> BigInt,
|
||||||
|
upvotes -> BigInt,
|
||||||
|
downvotes -> BigInt,
|
||||||
|
user_id -> Nullable<Int4>,
|
||||||
|
my_vote -> Nullable<Int4>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
|
||||||
|
#[table_name="comment_view"]
|
||||||
|
pub struct CommentView {
|
||||||
|
pub id: i32,
|
||||||
|
pub creator_id: i32,
|
||||||
|
pub post_id: i32,
|
||||||
|
pub parent_id: Option<i32>,
|
||||||
|
pub content: String,
|
||||||
|
pub published: chrono::NaiveDateTime,
|
||||||
|
pub updated: Option<chrono::NaiveDateTime>,
|
||||||
|
pub creator_name: String,
|
||||||
|
pub score: i64,
|
||||||
|
pub upvotes: i64,
|
||||||
|
pub downvotes: i64,
|
||||||
|
pub user_id: Option<i32>,
|
||||||
|
pub my_vote: Option<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommentView {
|
||||||
|
|
||||||
|
pub fn list(conn: &PgConnection, from_post_id: i32, from_user_id: Option<i32>) -> Result<Vec<Self>, Error> {
|
||||||
|
use actions::comment_view::comment_view::dsl::*;
|
||||||
|
use diesel::prelude::*;
|
||||||
|
|
||||||
|
let mut query = comment_view.into_boxed();
|
||||||
|
|
||||||
|
// The view lets you pass a null user_id, if you're not logged in
|
||||||
|
if let Some(from_user_id) = from_user_id {
|
||||||
|
query = query.filter(user_id.eq(from_user_id));
|
||||||
|
} else {
|
||||||
|
query = query.filter(user_id.is_null());
|
||||||
|
}
|
||||||
|
|
||||||
|
query = query.filter(post_id.eq(from_post_id)).order_by(published.desc());
|
||||||
|
|
||||||
|
query.load::<Self>(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(conn: &PgConnection, from_comment_id: i32, from_user_id: Option<i32>) -> Result<Self, Error> {
|
||||||
|
use actions::comment_view::comment_view::dsl::*;
|
||||||
|
use diesel::prelude::*;
|
||||||
|
|
||||||
|
let mut query = comment_view.into_boxed();
|
||||||
|
|
||||||
|
// The view lets you pass a null user_id, if you're not logged in
|
||||||
|
if let Some(from_user_id) = from_user_id {
|
||||||
|
query = query.filter(user_id.eq(from_user_id));
|
||||||
|
} else {
|
||||||
|
query = query.filter(user_id.is_null());
|
||||||
|
}
|
||||||
|
|
||||||
|
query = query.filter(id.eq(from_comment_id)).order_by(published.desc());
|
||||||
|
|
||||||
|
query.first::<Self>(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use establish_connection;
|
||||||
|
use super::*;
|
||||||
|
use actions::post::*;
|
||||||
|
use actions::community::*;
|
||||||
|
use actions::user::*;
|
||||||
|
use actions::comment::*;
|
||||||
|
use {Crud,Likeable};
|
||||||
|
#[test]
|
||||||
|
fn test_crud() {
|
||||||
|
let conn = establish_connection();
|
||||||
|
|
||||||
|
let new_user = UserForm {
|
||||||
|
name: "timmy".into(),
|
||||||
|
fedi_name: "rrf".into(),
|
||||||
|
preferred_username: None,
|
||||||
|
password_encrypted: "nope".into(),
|
||||||
|
email: None,
|
||||||
|
updated: None
|
||||||
|
};
|
||||||
|
|
||||||
|
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
||||||
|
|
||||||
|
let new_community = CommunityForm {
|
||||||
|
name: "test community 5".to_string(),
|
||||||
|
title: "nada".to_owned(),
|
||||||
|
description: None,
|
||||||
|
category_id: 1,
|
||||||
|
creator_id: inserted_user.id,
|
||||||
|
updated: None
|
||||||
|
};
|
||||||
|
|
||||||
|
let inserted_community = Community::create(&conn, &new_community).unwrap();
|
||||||
|
|
||||||
|
let new_post = PostForm {
|
||||||
|
name: "A test post 2".into(),
|
||||||
|
creator_id: inserted_user.id,
|
||||||
|
url: None,
|
||||||
|
body: None,
|
||||||
|
community_id: inserted_community.id,
|
||||||
|
updated: None
|
||||||
|
};
|
||||||
|
|
||||||
|
let inserted_post = Post::create(&conn, &new_post).unwrap();
|
||||||
|
|
||||||
|
let comment_form = CommentForm {
|
||||||
|
content: "A test comment 32".into(),
|
||||||
|
creator_id: inserted_user.id,
|
||||||
|
post_id: inserted_post.id,
|
||||||
|
parent_id: None,
|
||||||
|
updated: None
|
||||||
|
};
|
||||||
|
|
||||||
|
let inserted_comment = Comment::create(&conn, &comment_form).unwrap();
|
||||||
|
|
||||||
|
let comment_like_form = CommentLikeForm {
|
||||||
|
comment_id: inserted_comment.id,
|
||||||
|
post_id: inserted_post.id,
|
||||||
|
user_id: inserted_user.id,
|
||||||
|
score: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let _inserted_comment_like = CommentLike::like(&conn, &comment_like_form).unwrap();
|
||||||
|
|
||||||
|
let expected_comment_view_no_user = CommentView {
|
||||||
|
id: inserted_comment.id,
|
||||||
|
content: "A test comment 32".into(),
|
||||||
|
creator_id: inserted_user.id,
|
||||||
|
post_id: inserted_post.id,
|
||||||
|
parent_id: None,
|
||||||
|
published: inserted_comment.published,
|
||||||
|
updated: None,
|
||||||
|
creator_name: inserted_user.name.to_owned(),
|
||||||
|
score: 1,
|
||||||
|
downvotes: 0,
|
||||||
|
upvotes: 1,
|
||||||
|
user_id: None,
|
||||||
|
my_vote: None
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected_comment_view_with_user = CommentView {
|
||||||
|
id: inserted_comment.id,
|
||||||
|
content: "A test comment 32".into(),
|
||||||
|
creator_id: inserted_user.id,
|
||||||
|
post_id: inserted_post.id,
|
||||||
|
parent_id: None,
|
||||||
|
published: inserted_comment.published,
|
||||||
|
updated: None,
|
||||||
|
creator_name: inserted_user.name.to_owned(),
|
||||||
|
score: 1,
|
||||||
|
downvotes: 0,
|
||||||
|
upvotes: 1,
|
||||||
|
user_id: Some(inserted_user.id),
|
||||||
|
my_vote: Some(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
let read_comment_views_no_user = CommentView::list(&conn, inserted_post.id, None).unwrap();
|
||||||
|
let read_comment_views_with_user = CommentView::list(&conn, inserted_post.id, Some(inserted_user.id)).unwrap();
|
||||||
|
let like_removed = CommentLike::remove(&conn, &comment_like_form).unwrap();
|
||||||
|
let num_deleted = Comment::delete(&conn, inserted_comment.id).unwrap();
|
||||||
|
Post::delete(&conn, inserted_post.id).unwrap();
|
||||||
|
Community::delete(&conn, inserted_community.id).unwrap();
|
||||||
|
User_::delete(&conn, inserted_user.id).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(expected_comment_view_no_user, read_comment_views_no_user[0]);
|
||||||
|
assert_eq!(expected_comment_view_with_user, read_comment_views_with_user[0]);
|
||||||
|
assert_eq!(1, num_deleted);
|
||||||
|
assert_eq!(1, like_removed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,9 @@ use {Crud, Followable, Joinable};
|
||||||
pub struct Community {
|
pub struct Community {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub title: String,
|
||||||
|
pub description: Option<String>,
|
||||||
|
pub category_id: i32,
|
||||||
pub creator_id: i32,
|
pub creator_id: i32,
|
||||||
pub published: chrono::NaiveDateTime,
|
pub published: chrono::NaiveDateTime,
|
||||||
pub updated: Option<chrono::NaiveDateTime>
|
pub updated: Option<chrono::NaiveDateTime>
|
||||||
|
@ -19,6 +22,9 @@ pub struct Community {
|
||||||
#[table_name="community"]
|
#[table_name="community"]
|
||||||
pub struct CommunityForm {
|
pub struct CommunityForm {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
pub title: String,
|
||||||
|
pub description: Option<String>,
|
||||||
|
pub category_id: i32,
|
||||||
pub creator_id: i32,
|
pub creator_id: i32,
|
||||||
pub updated: Option<chrono::NaiveDateTime>
|
pub updated: Option<chrono::NaiveDateTime>
|
||||||
}
|
}
|
||||||
|
@ -149,8 +155,11 @@ mod tests {
|
||||||
|
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "TIL".into(),
|
name: "TIL".into(),
|
||||||
|
creator_id: inserted_user.id,
|
||||||
|
title: "nada".to_owned(),
|
||||||
|
description: None,
|
||||||
|
category_id: 1,
|
||||||
updated: None,
|
updated: None,
|
||||||
creator_id: inserted_user.id
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_community = Community::create(&conn, &new_community).unwrap();
|
let inserted_community = Community::create(&conn, &new_community).unwrap();
|
||||||
|
@ -159,6 +168,9 @@ mod tests {
|
||||||
id: inserted_community.id,
|
id: inserted_community.id,
|
||||||
creator_id: inserted_user.id,
|
creator_id: inserted_user.id,
|
||||||
name: "TIL".into(),
|
name: "TIL".into(),
|
||||||
|
title: "nada".to_owned(),
|
||||||
|
description: None,
|
||||||
|
category_id: 1,
|
||||||
published: inserted_community.published,
|
published: inserted_community.published,
|
||||||
updated: None
|
updated: None
|
||||||
};
|
};
|
||||||
|
@ -196,7 +208,6 @@ mod tests {
|
||||||
let updated_community = Community::update(&conn, inserted_community.id, &new_community).unwrap();
|
let updated_community = Community::update(&conn, inserted_community.id, &new_community).unwrap();
|
||||||
let ignored_community = CommunityFollower::ignore(&conn, &community_follower_form).unwrap();
|
let ignored_community = CommunityFollower::ignore(&conn, &community_follower_form).unwrap();
|
||||||
let left_community = CommunityModerator::leave(&conn, &community_user_form).unwrap();
|
let left_community = CommunityModerator::leave(&conn, &community_user_form).unwrap();
|
||||||
let loaded_count = Community::list_all(&conn).unwrap().len();
|
|
||||||
let num_deleted = Community::delete(&conn, inserted_community.id).unwrap();
|
let num_deleted = Community::delete(&conn, inserted_community.id).unwrap();
|
||||||
User_::delete(&conn, inserted_user.id).unwrap();
|
User_::delete(&conn, inserted_user.id).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -3,3 +3,4 @@ pub mod community;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
pub mod comment;
|
pub mod comment;
|
||||||
pub mod post_view;
|
pub mod post_view;
|
||||||
|
pub mod comment_view;
|
||||||
|
|
|
@ -122,6 +122,9 @@ mod tests {
|
||||||
|
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: "test community_2".to_string(),
|
name: "test community_2".to_string(),
|
||||||
|
title: "nada".to_owned(),
|
||||||
|
description: None,
|
||||||
|
category_id: 1,
|
||||||
creator_id: inserted_user.id,
|
creator_id: inserted_user.id,
|
||||||
updated: None
|
updated: None
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,47 +16,47 @@ pub enum ListingSortType {
|
||||||
// The faked schema since diesel doesn't do views
|
// The faked schema since diesel doesn't do views
|
||||||
table! {
|
table! {
|
||||||
post_view (id) {
|
post_view (id) {
|
||||||
user_id -> Nullable<Int4>,
|
|
||||||
my_vote -> Nullable<Int4>,
|
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
name -> Varchar,
|
name -> Varchar,
|
||||||
url -> Nullable<Text>,
|
url -> Nullable<Text>,
|
||||||
body -> Nullable<Text>,
|
body -> Nullable<Text>,
|
||||||
creator_id -> Int4,
|
creator_id -> Int4,
|
||||||
creator_name -> Varchar,
|
|
||||||
community_id -> Int4,
|
community_id -> Int4,
|
||||||
|
published -> Timestamp,
|
||||||
|
updated -> Nullable<Timestamp>,
|
||||||
|
creator_name -> Varchar,
|
||||||
community_name -> Varchar,
|
community_name -> Varchar,
|
||||||
number_of_comments -> BigInt,
|
number_of_comments -> BigInt,
|
||||||
score -> BigInt,
|
score -> BigInt,
|
||||||
upvotes -> BigInt,
|
upvotes -> BigInt,
|
||||||
downvotes -> BigInt,
|
downvotes -> BigInt,
|
||||||
hot_rank -> Int4,
|
hot_rank -> Int4,
|
||||||
published -> Timestamp,
|
user_id -> Nullable<Int4>,
|
||||||
updated -> Nullable<Timestamp>,
|
my_vote -> Nullable<Int4>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName)]
|
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
|
||||||
#[table_name="post_view"]
|
#[table_name="post_view"]
|
||||||
pub struct PostView {
|
pub struct PostView {
|
||||||
pub user_id: Option<i32>,
|
|
||||||
pub my_vote: Option<i32>,
|
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub url: Option<String>,
|
pub url: Option<String>,
|
||||||
pub body: Option<String>,
|
pub body: Option<String>,
|
||||||
pub creator_id: i32,
|
pub creator_id: i32,
|
||||||
pub creator_name: String,
|
|
||||||
pub community_id: i32,
|
pub community_id: i32,
|
||||||
|
pub published: chrono::NaiveDateTime,
|
||||||
|
pub updated: Option<chrono::NaiveDateTime>,
|
||||||
|
pub creator_name: String,
|
||||||
pub community_name: String,
|
pub community_name: String,
|
||||||
pub number_of_comments: i64,
|
pub number_of_comments: i64,
|
||||||
pub score: i64,
|
pub score: i64,
|
||||||
pub upvotes: i64,
|
pub upvotes: i64,
|
||||||
pub downvotes: i64,
|
pub downvotes: i64,
|
||||||
pub hot_rank: i32,
|
pub hot_rank: i32,
|
||||||
pub published: chrono::NaiveDateTime,
|
pub user_id: Option<i32>,
|
||||||
pub updated: Option<chrono::NaiveDateTime>
|
pub my_vote: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PostView {
|
impl PostView {
|
||||||
|
@ -103,7 +103,6 @@ impl PostView {
|
||||||
pub fn get(conn: &PgConnection, from_post_id: i32, from_user_id: Option<i32>) -> Result<Self, Error> {
|
pub fn get(conn: &PgConnection, from_post_id: i32, from_user_id: Option<i32>) -> Result<Self, Error> {
|
||||||
|
|
||||||
use actions::post_view::post_view::dsl::*;
|
use actions::post_view::post_view::dsl::*;
|
||||||
use diesel::dsl::*;
|
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
|
||||||
let mut query = post_view.into_boxed();
|
let mut query = post_view.into_boxed();
|
||||||
|
@ -113,45 +112,8 @@ impl PostView {
|
||||||
if let Some(from_user_id) = from_user_id {
|
if let Some(from_user_id) = from_user_id {
|
||||||
query = query.filter(user_id.eq(from_user_id));
|
query = query.filter(user_id.eq(from_user_id));
|
||||||
} else {
|
} else {
|
||||||
// This fills in nulls for the user_id and user vote
|
query = query.filter(user_id.is_null());
|
||||||
query = query
|
}
|
||||||
.select((
|
|
||||||
sql("null"),
|
|
||||||
sql("null"),
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
url,
|
|
||||||
body,
|
|
||||||
creator_id,
|
|
||||||
creator_name,
|
|
||||||
community_id,
|
|
||||||
community_name,
|
|
||||||
number_of_comments,
|
|
||||||
score,
|
|
||||||
upvotes,
|
|
||||||
downvotes,
|
|
||||||
hot_rank,
|
|
||||||
published,
|
|
||||||
updated
|
|
||||||
))
|
|
||||||
.group_by((
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
url,
|
|
||||||
body,
|
|
||||||
creator_id,
|
|
||||||
creator_name,
|
|
||||||
community_id,
|
|
||||||
community_name,
|
|
||||||
number_of_comments,
|
|
||||||
score,
|
|
||||||
upvotes,
|
|
||||||
downvotes,
|
|
||||||
hot_rank,
|
|
||||||
published,
|
|
||||||
updated
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
query.first::<Self>(conn)
|
query.first::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
@ -187,7 +149,10 @@ mod tests {
|
||||||
|
|
||||||
let new_community = CommunityForm {
|
let new_community = CommunityForm {
|
||||||
name: community_name.to_owned(),
|
name: community_name.to_owned(),
|
||||||
|
title: "nada".to_owned(),
|
||||||
|
description: None,
|
||||||
creator_id: inserted_user.id,
|
creator_id: inserted_user.id,
|
||||||
|
category_id: 1,
|
||||||
updated: None
|
updated: None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@ impl User_ {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::activitypub::{context, actor::Person};
|
|
||||||
use super::User_;
|
use super::User_;
|
||||||
use naive_now;
|
use naive_now;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
table! {
|
||||||
|
category (id) {
|
||||||
|
id -> Int4,
|
||||||
|
name -> Varchar,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
comment (id) {
|
comment (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
|
@ -25,6 +32,9 @@ table! {
|
||||||
community (id) {
|
community (id) {
|
||||||
id -> Int4,
|
id -> Int4,
|
||||||
name -> Varchar,
|
name -> Varchar,
|
||||||
|
title -> Varchar,
|
||||||
|
description -> Nullable<Text>,
|
||||||
|
category_id -> Int4,
|
||||||
creator_id -> Int4,
|
creator_id -> Int4,
|
||||||
published -> Timestamp,
|
published -> Timestamp,
|
||||||
updated -> Nullable<Timestamp>,
|
updated -> Nullable<Timestamp>,
|
||||||
|
@ -91,6 +101,7 @@ joinable!(comment -> user_ (creator_id));
|
||||||
joinable!(comment_like -> comment (comment_id));
|
joinable!(comment_like -> comment (comment_id));
|
||||||
joinable!(comment_like -> post (post_id));
|
joinable!(comment_like -> post (post_id));
|
||||||
joinable!(comment_like -> user_ (user_id));
|
joinable!(comment_like -> user_ (user_id));
|
||||||
|
joinable!(community -> category (category_id));
|
||||||
joinable!(community -> user_ (creator_id));
|
joinable!(community -> user_ (creator_id));
|
||||||
joinable!(community_follower -> community (community_id));
|
joinable!(community_follower -> community (community_id));
|
||||||
joinable!(community_follower -> user_ (user_id));
|
joinable!(community_follower -> user_ (user_id));
|
||||||
|
@ -102,6 +113,7 @@ joinable!(post_like -> post (post_id));
|
||||||
joinable!(post_like -> user_ (user_id));
|
joinable!(post_like -> user_ (user_id));
|
||||||
|
|
||||||
allow_tables_to_appear_in_same_query!(
|
allow_tables_to_appear_in_same_query!(
|
||||||
|
category,
|
||||||
comment,
|
comment,
|
||||||
comment_like,
|
comment_like,
|
||||||
community,
|
community,
|
||||||
|
|
|
@ -16,10 +16,11 @@ use actions::user::*;
|
||||||
use actions::post::*;
|
use actions::post::*;
|
||||||
use actions::comment::*;
|
use actions::comment::*;
|
||||||
use actions::post_view::*;
|
use actions::post_view::*;
|
||||||
|
use actions::comment_view::*;
|
||||||
|
|
||||||
#[derive(EnumString,ToString,Debug)]
|
#[derive(EnumString,ToString,Debug)]
|
||||||
pub enum UserOperation {
|
pub enum UserOperation {
|
||||||
Login, Register, CreateCommunity, CreatePost, ListCommunities, GetPost, GetCommunity, CreateComment, EditComment, CreateCommentLike, GetPosts, CreatePostLike
|
Login, Register, CreateCommunity, CreatePost, ListCommunities, GetPost, GetCommunity, CreateComment, EditComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, EditCommunity
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
@ -93,6 +94,9 @@ pub struct LoginResponse {
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct CreateCommunity {
|
pub struct CreateCommunity {
|
||||||
name: String,
|
name: String,
|
||||||
|
title: String,
|
||||||
|
description: Option<String>,
|
||||||
|
category_id: i32 ,
|
||||||
auth: String
|
auth: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,9 +125,9 @@ pub struct CreatePost {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct CreatePostResponse {
|
pub struct PostResponse {
|
||||||
op: String,
|
op: String,
|
||||||
post: Post
|
post: PostView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -175,13 +179,6 @@ pub struct CreateComment {
|
||||||
auth: String
|
auth: String
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct CreateCommentResponse {
|
|
||||||
op: String,
|
|
||||||
comment: CommentView
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct EditComment {
|
pub struct EditComment {
|
||||||
content: String,
|
content: String,
|
||||||
|
@ -192,7 +189,7 @@ pub struct EditComment {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct EditCommentResponse {
|
pub struct CommentResponse {
|
||||||
op: String,
|
op: String,
|
||||||
comment: CommentView
|
comment: CommentView
|
||||||
}
|
}
|
||||||
|
@ -205,12 +202,6 @@ pub struct CreateCommentLike {
|
||||||
auth: String
|
auth: String
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct CreateCommentLikeResponse {
|
|
||||||
op: String,
|
|
||||||
comment: CommentView
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct CreatePostLike {
|
pub struct CreatePostLike {
|
||||||
|
@ -225,6 +216,26 @@ pub struct CreatePostLikeResponse {
|
||||||
post: PostView
|
post: PostView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct EditPost {
|
||||||
|
edit_id: i32,
|
||||||
|
community_id: i32,
|
||||||
|
name: String,
|
||||||
|
url: Option<String>,
|
||||||
|
body: Option<String>,
|
||||||
|
auth: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct EditCommunity {
|
||||||
|
edit_id: i32,
|
||||||
|
title: String,
|
||||||
|
description: Option<String>,
|
||||||
|
category_id: i32,
|
||||||
|
auth: String
|
||||||
|
}
|
||||||
|
|
||||||
/// `ChatServer` manages chat rooms and responsible for coordinating chat
|
/// `ChatServer` manages chat rooms and responsible for coordinating chat
|
||||||
/// session. implementation is super primitive
|
/// session. implementation is super primitive
|
||||||
pub struct ChatServer {
|
pub struct ChatServer {
|
||||||
|
@ -260,15 +271,15 @@ impl ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send message only to self
|
// /// Send message only to self
|
||||||
fn send(&self, message: &str, id: &usize) {
|
// fn send(&self, message: &str, id: &usize) {
|
||||||
// println!("{:?}", self.sessions);
|
// // println!("{:?}", self.sessions);
|
||||||
if let Some(addr) = self.sessions.get(id) {
|
// if let Some(addr) = self.sessions.get(id) {
|
||||||
println!("msg: {}", message);
|
// println!("msg: {}", message);
|
||||||
// println!("{:?}", addr.connected());
|
// // println!("{:?}", addr.connected());
|
||||||
let _ = addr.do_send(WSMessage(message.to_owned()));
|
// let _ = addr.do_send(WSMessage(message.to_owned()));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make actor from `ChatServer`
|
/// Make actor from `ChatServer`
|
||||||
|
@ -309,12 +320,12 @@ impl Handler<Disconnect> for ChatServer {
|
||||||
fn handle(&mut self, msg: Disconnect, _: &mut Context<Self>) {
|
fn handle(&mut self, msg: Disconnect, _: &mut Context<Self>) {
|
||||||
println!("Someone disconnected");
|
println!("Someone disconnected");
|
||||||
|
|
||||||
let mut rooms: Vec<i32> = Vec::new();
|
// let mut rooms: Vec<i32> = Vec::new();
|
||||||
|
|
||||||
// remove address
|
// remove address
|
||||||
if self.sessions.remove(&msg.id).is_some() {
|
if self.sessions.remove(&msg.id).is_some() {
|
||||||
// remove session from all rooms
|
// remove session from all rooms
|
||||||
for (id, sessions) in &mut self.rooms {
|
for (_id, sessions) in &mut self.rooms {
|
||||||
if sessions.remove(&msg.id) {
|
if sessions.remove(&msg.id) {
|
||||||
// rooms.push(*id);
|
// rooms.push(*id);
|
||||||
}
|
}
|
||||||
|
@ -398,6 +409,10 @@ impl Handler<StandardMessage> for ChatServer {
|
||||||
let create_post_like: CreatePostLike = serde_json::from_str(&data.to_string()).unwrap();
|
let create_post_like: CreatePostLike = serde_json::from_str(&data.to_string()).unwrap();
|
||||||
create_post_like.perform(self, msg.id)
|
create_post_like.perform(self, msg.id)
|
||||||
},
|
},
|
||||||
|
UserOperation::EditPost => {
|
||||||
|
let edit_post: EditPost = serde_json::from_str(&data.to_string()).unwrap();
|
||||||
|
edit_post.perform(self, msg.id)
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let e = ErrorMessage {
|
let e = ErrorMessage {
|
||||||
op: "Unknown".to_string(),
|
op: "Unknown".to_string(),
|
||||||
|
@ -413,7 +428,7 @@ impl Handler<StandardMessage> for ChatServer {
|
||||||
|
|
||||||
|
|
||||||
pub trait Perform {
|
pub trait Perform {
|
||||||
fn perform(&self, chat: &mut ChatServer, addr: usize) -> String;
|
fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> String;
|
||||||
fn op_type(&self) -> UserOperation;
|
fn op_type(&self) -> UserOperation;
|
||||||
fn error(&self, error_msg: &str) -> String {
|
fn error(&self, error_msg: &str) -> String {
|
||||||
serde_json::to_string(
|
serde_json::to_string(
|
||||||
|
@ -430,14 +445,14 @@ impl Perform for Login {
|
||||||
fn op_type(&self) -> UserOperation {
|
fn op_type(&self) -> UserOperation {
|
||||||
UserOperation::Login
|
UserOperation::Login
|
||||||
}
|
}
|
||||||
fn perform(&self, chat: &mut ChatServer, addr: usize) -> String {
|
fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> String {
|
||||||
|
|
||||||
let conn = establish_connection();
|
let conn = establish_connection();
|
||||||
|
|
||||||
// Fetch that username / email
|
// Fetch that username / email
|
||||||
let user: User_ = match User_::find_by_email_or_username(&conn, &self.username_or_email) {
|
let user: User_ = match User_::find_by_email_or_username(&conn, &self.username_or_email) {
|
||||||
Ok(user) => user,
|
Ok(user) => user,
|
||||||
Err(e) => return self.error("Couldn't find that username or email")
|
Err(_e) => return self.error("Couldn't find that username or email")
|
||||||
};
|
};
|
||||||
|
|
||||||
// Verify the password
|
// Verify the password
|
||||||
|
@ -462,7 +477,7 @@ impl Perform for Register {
|
||||||
fn op_type(&self) -> UserOperation {
|
fn op_type(&self) -> UserOperation {
|
||||||
UserOperation::Register
|
UserOperation::Register
|
||||||
}
|
}
|
||||||
fn perform(&self, chat: &mut ChatServer, addr: usize) -> String {
|
fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> String {
|
||||||
|
|
||||||
let conn = establish_connection();
|
let conn = establish_connection();
|
||||||
|
|
||||||
|
@ -484,7 +499,7 @@ impl Perform for Register {
|
||||||
// Create the user
|
// Create the user
|
||||||
let inserted_user = match User_::create(&conn, &user_form) {
|
let inserted_user = match User_::create(&conn, &user_form) {
|
||||||
Ok(user) => user,
|
Ok(user) => user,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("User already exists.");
|
return self.error("User already exists.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -506,32 +521,33 @@ impl Perform for CreateCommunity {
|
||||||
UserOperation::CreateCommunity
|
UserOperation::CreateCommunity
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform(&self, chat: &mut ChatServer, addr: usize) -> String {
|
fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> String {
|
||||||
|
|
||||||
let conn = establish_connection();
|
let conn = establish_connection();
|
||||||
|
|
||||||
let claims = match Claims::decode(&self.auth) {
|
let claims = match Claims::decode(&self.auth) {
|
||||||
Ok(claims) => claims.claims,
|
Ok(claims) => claims.claims,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Not logged in.");
|
return self.error("Not logged in.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let user_id = claims.id;
|
let user_id = claims.id;
|
||||||
let username = claims.username;
|
|
||||||
let iss = claims.iss;
|
|
||||||
|
|
||||||
// When you create a community, make sure the user becomes a moderator and a follower
|
// When you create a community, make sure the user becomes a moderator and a follower
|
||||||
|
|
||||||
let community_form = CommunityForm {
|
let community_form = CommunityForm {
|
||||||
name: self.name.to_owned(),
|
name: self.name.to_owned(),
|
||||||
|
title: self.title.to_owned(),
|
||||||
|
description: self.description.to_owned(),
|
||||||
|
category_id: self.category_id,
|
||||||
creator_id: user_id,
|
creator_id: user_id,
|
||||||
updated: None
|
updated: None
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_community = match Community::create(&conn, &community_form) {
|
let inserted_community = match Community::create(&conn, &community_form) {
|
||||||
Ok(community) => community,
|
Ok(community) => community,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Community already exists.");
|
return self.error("Community already exists.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -541,9 +557,9 @@ impl Perform for CreateCommunity {
|
||||||
user_id: user_id
|
user_id: user_id
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) {
|
let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) {
|
||||||
Ok(user) => user,
|
Ok(user) => user,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Community moderator already exists.");
|
return self.error("Community moderator already exists.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -553,9 +569,9 @@ impl Perform for CreateCommunity {
|
||||||
user_id: user_id
|
user_id: user_id
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) {
|
let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) {
|
||||||
Ok(user) => user,
|
Ok(user) => user,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Community follower already exists.");
|
return self.error("Community follower already exists.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -575,7 +591,7 @@ impl Perform for ListCommunities {
|
||||||
UserOperation::ListCommunities
|
UserOperation::ListCommunities
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform(&self, chat: &mut ChatServer, addr: usize) -> String {
|
fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> String {
|
||||||
|
|
||||||
let conn = establish_connection();
|
let conn = establish_connection();
|
||||||
|
|
||||||
|
@ -597,20 +613,18 @@ impl Perform for CreatePost {
|
||||||
UserOperation::CreatePost
|
UserOperation::CreatePost
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform(&self, chat: &mut ChatServer, addr: usize) -> String {
|
fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> String {
|
||||||
|
|
||||||
let conn = establish_connection();
|
let conn = establish_connection();
|
||||||
|
|
||||||
let claims = match Claims::decode(&self.auth) {
|
let claims = match Claims::decode(&self.auth) {
|
||||||
Ok(claims) => claims.claims,
|
Ok(claims) => claims.claims,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Not logged in.");
|
return self.error("Not logged in.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let user_id = claims.id;
|
let user_id = claims.id;
|
||||||
let username = claims.username;
|
|
||||||
let iss = claims.iss;
|
|
||||||
|
|
||||||
let post_form = PostForm {
|
let post_form = PostForm {
|
||||||
name: self.name.to_owned(),
|
name: self.name.to_owned(),
|
||||||
|
@ -623,7 +637,7 @@ impl Perform for CreatePost {
|
||||||
|
|
||||||
let inserted_post = match Post::create(&conn, &post_form) {
|
let inserted_post = match Post::create(&conn, &post_form) {
|
||||||
Ok(post) => post,
|
Ok(post) => post,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Couldn't create Post");
|
return self.error("Couldn't create Post");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -636,17 +650,25 @@ impl Perform for CreatePost {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only add the like if the score isnt 0
|
// Only add the like if the score isnt 0
|
||||||
let inserted_like = match PostLike::like(&conn, &like_form) {
|
let _inserted_like = match PostLike::like(&conn, &like_form) {
|
||||||
Ok(like) => like,
|
Ok(like) => like,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Couldn't like post.");
|
return self.error("Couldn't like post.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Refetch the view
|
||||||
|
let post_view = match PostView::get(&conn, inserted_post.id, Some(user_id)) {
|
||||||
|
Ok(post) => post,
|
||||||
|
Err(_e) => {
|
||||||
|
return self.error("Couldn't find Post");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
serde_json::to_string(
|
serde_json::to_string(
|
||||||
&CreatePostResponse {
|
&PostResponse {
|
||||||
op: self.op_type().to_string(),
|
op: self.op_type().to_string(),
|
||||||
post: inserted_post
|
post: post_view
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -670,11 +692,9 @@ impl Perform for GetPost {
|
||||||
match Claims::decode(&auth) {
|
match Claims::decode(&auth) {
|
||||||
Ok(claims) => {
|
Ok(claims) => {
|
||||||
let user_id = claims.claims.id;
|
let user_id = claims.claims.id;
|
||||||
let username = claims.claims.username;
|
|
||||||
let iss = claims.claims.iss;
|
|
||||||
Some(user_id)
|
Some(user_id)
|
||||||
}
|
}
|
||||||
Err(e) => None
|
Err(_e) => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => None
|
None => None
|
||||||
|
@ -682,13 +702,13 @@ impl Perform for GetPost {
|
||||||
|
|
||||||
let post_view = match PostView::get(&conn, self.id, user_id) {
|
let post_view = match PostView::get(&conn, self.id, user_id) {
|
||||||
Ok(post) => post,
|
Ok(post) => post,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Couldn't find Post");
|
return self.error("Couldn't find Post");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// remove session from all rooms
|
// remove session from all rooms
|
||||||
for (n, sessions) in &mut chat.rooms {
|
for (_n, sessions) in &mut chat.rooms {
|
||||||
sessions.remove(&addr);
|
sessions.remove(&addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -698,10 +718,7 @@ impl Perform for GetPost {
|
||||||
|
|
||||||
chat.rooms.get_mut(&self.id).unwrap().insert(addr);
|
chat.rooms.get_mut(&self.id).unwrap().insert(addr);
|
||||||
|
|
||||||
let comments = CommentView::from_post(&conn, self.id, user_id);
|
let comments = CommentView::list(&conn, self.id, user_id).unwrap();
|
||||||
|
|
||||||
// println!("{:?}", chat.rooms.keys());
|
|
||||||
// println!("{:?}", chat.rooms.get(&5i32).unwrap());
|
|
||||||
|
|
||||||
// Return the jwt
|
// Return the jwt
|
||||||
serde_json::to_string(
|
serde_json::to_string(
|
||||||
|
@ -720,13 +737,13 @@ impl Perform for GetCommunity {
|
||||||
UserOperation::GetCommunity
|
UserOperation::GetCommunity
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform(&self, chat: &mut ChatServer, addr: usize) -> String {
|
fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> String {
|
||||||
|
|
||||||
let conn = establish_connection();
|
let conn = establish_connection();
|
||||||
|
|
||||||
let community = match Community::read(&conn, self.id) {
|
let community = match Community::read(&conn, self.id) {
|
||||||
Ok(community) => community,
|
Ok(community) => community,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Couldn't find Community");
|
return self.error("Couldn't find Community");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -753,15 +770,12 @@ impl Perform for CreateComment {
|
||||||
|
|
||||||
let claims = match Claims::decode(&self.auth) {
|
let claims = match Claims::decode(&self.auth) {
|
||||||
Ok(claims) => claims.claims,
|
Ok(claims) => claims.claims,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Not logged in.");
|
return self.error("Not logged in.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let user_id = claims.id;
|
let user_id = claims.id;
|
||||||
let username = claims.username;
|
|
||||||
let iss = claims.iss;
|
|
||||||
let fedi_user_id = format!("{}/{}", iss, username);
|
|
||||||
|
|
||||||
let comment_form = CommentForm {
|
let comment_form = CommentForm {
|
||||||
content: self.content.to_owned(),
|
content: self.content.to_owned(),
|
||||||
|
@ -773,7 +787,7 @@ impl Perform for CreateComment {
|
||||||
|
|
||||||
let inserted_comment = match Comment::create(&conn, &comment_form) {
|
let inserted_comment = match Comment::create(&conn, &comment_form) {
|
||||||
Ok(comment) => comment,
|
Ok(comment) => comment,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Couldn't create Comment");
|
return self.error("Couldn't create Comment");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -786,22 +800,21 @@ impl Perform for CreateComment {
|
||||||
score: 1
|
score: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_like = match CommentLike::like(&conn, &like_form) {
|
let _inserted_like = match CommentLike::like(&conn, &like_form) {
|
||||||
Ok(like) => like,
|
Ok(like) => like,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Couldn't like comment.");
|
return self.error("Couldn't like comment.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let likes: Vec<CommentLike> = vec![inserted_like];
|
let comment_view = CommentView::read(&conn, inserted_comment.id, Some(user_id)).unwrap();
|
||||||
|
|
||||||
let comment_view = CommentView::from_comment(&inserted_comment, &likes, Some(user_id));
|
|
||||||
|
|
||||||
let mut comment_sent = comment_view.clone();
|
let mut comment_sent = comment_view.clone();
|
||||||
comment_sent.my_vote = None;
|
comment_sent.my_vote = None;
|
||||||
|
comment_sent.user_id = None;
|
||||||
|
|
||||||
let comment_out = serde_json::to_string(
|
let comment_out = serde_json::to_string(
|
||||||
&CreateCommentResponse {
|
&CommentResponse {
|
||||||
op: self.op_type().to_string(),
|
op: self.op_type().to_string(),
|
||||||
comment: comment_view
|
comment: comment_view
|
||||||
}
|
}
|
||||||
|
@ -809,7 +822,7 @@ impl Perform for CreateComment {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let comment_sent_out = serde_json::to_string(
|
let comment_sent_out = serde_json::to_string(
|
||||||
&CreateCommentLikeResponse {
|
&CommentResponse {
|
||||||
op: self.op_type().to_string(),
|
op: self.op_type().to_string(),
|
||||||
comment: comment_sent
|
comment: comment_sent
|
||||||
}
|
}
|
||||||
|
@ -833,15 +846,12 @@ impl Perform for EditComment {
|
||||||
|
|
||||||
let claims = match Claims::decode(&self.auth) {
|
let claims = match Claims::decode(&self.auth) {
|
||||||
Ok(claims) => claims.claims,
|
Ok(claims) => claims.claims,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Not logged in.");
|
return self.error("Not logged in.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let user_id = claims.id;
|
let user_id = claims.id;
|
||||||
let username = claims.username;
|
|
||||||
let iss = claims.iss;
|
|
||||||
let fedi_user_id = format!("{}/{}", iss, username);
|
|
||||||
|
|
||||||
let comment_form = CommentForm {
|
let comment_form = CommentForm {
|
||||||
content: self.content.to_owned(),
|
content: self.content.to_owned(),
|
||||||
|
@ -851,27 +861,22 @@ impl Perform for EditComment {
|
||||||
updated: Some(naive_now())
|
updated: Some(naive_now())
|
||||||
};
|
};
|
||||||
|
|
||||||
let updated_comment = match Comment::update(&conn, self.edit_id, &comment_form) {
|
let _updated_comment = match Comment::update(&conn, self.edit_id, &comment_form) {
|
||||||
Ok(comment) => comment,
|
Ok(comment) => comment,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Couldn't update Comment");
|
return self.error("Couldn't update Comment");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let likes = match CommentLike::read(&conn, self.edit_id) {
|
|
||||||
Ok(likes) => likes,
|
|
||||||
Err(e) => {
|
|
||||||
return self.error("Couldn't get likes");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let comment_view = CommentView::from_comment(&updated_comment, &likes, Some(user_id));
|
let comment_view = CommentView::read(&conn, self.edit_id, Some(user_id)).unwrap();
|
||||||
|
|
||||||
let mut comment_sent = comment_view.clone();
|
let mut comment_sent = comment_view.clone();
|
||||||
comment_sent.my_vote = None;
|
comment_sent.my_vote = None;
|
||||||
|
comment_sent.user_id = None;
|
||||||
|
|
||||||
let comment_out = serde_json::to_string(
|
let comment_out = serde_json::to_string(
|
||||||
&CreateCommentResponse {
|
&CommentResponse {
|
||||||
op: self.op_type().to_string(),
|
op: self.op_type().to_string(),
|
||||||
comment: comment_view
|
comment: comment_view
|
||||||
}
|
}
|
||||||
|
@ -879,7 +884,7 @@ impl Perform for EditComment {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let comment_sent_out = serde_json::to_string(
|
let comment_sent_out = serde_json::to_string(
|
||||||
&CreateCommentLikeResponse {
|
&CommentResponse {
|
||||||
op: self.op_type().to_string(),
|
op: self.op_type().to_string(),
|
||||||
comment: comment_sent
|
comment: comment_sent
|
||||||
}
|
}
|
||||||
|
@ -903,15 +908,12 @@ impl Perform for CreateCommentLike {
|
||||||
|
|
||||||
let claims = match Claims::decode(&self.auth) {
|
let claims = match Claims::decode(&self.auth) {
|
||||||
Ok(claims) => claims.claims,
|
Ok(claims) => claims.claims,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Not logged in.");
|
return self.error("Not logged in.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let user_id = claims.id;
|
let user_id = claims.id;
|
||||||
let username = claims.username;
|
|
||||||
let iss = claims.iss;
|
|
||||||
let fedi_user_id = format!("{}/{}", iss, username);
|
|
||||||
|
|
||||||
let like_form = CommentLikeForm {
|
let like_form = CommentLikeForm {
|
||||||
comment_id: self.comment_id,
|
comment_id: self.comment_id,
|
||||||
|
@ -925,23 +927,23 @@ impl Perform for CreateCommentLike {
|
||||||
|
|
||||||
// Only add the like if the score isnt 0
|
// Only add the like if the score isnt 0
|
||||||
if &like_form.score != &0 {
|
if &like_form.score != &0 {
|
||||||
let inserted_like = match CommentLike::like(&conn, &like_form) {
|
let _inserted_like = match CommentLike::like(&conn, &like_form) {
|
||||||
Ok(like) => like,
|
Ok(like) => like,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Couldn't like comment.");
|
return self.error("Couldn't like comment.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have to refetch the comment to get the current state
|
// Have to refetch the comment to get the current state
|
||||||
// thread::sleep(time::Duration::from_secs(1));
|
let liked_comment = CommentView::read(&conn, self.comment_id, Some(user_id)).unwrap();
|
||||||
let liked_comment = CommentView::read(&conn, self.comment_id, Some(user_id));
|
|
||||||
|
|
||||||
let mut liked_comment_sent = liked_comment.clone();
|
let mut liked_comment_sent = liked_comment.clone();
|
||||||
liked_comment_sent.my_vote = None;
|
liked_comment_sent.my_vote = None;
|
||||||
|
liked_comment_sent.user_id = None;
|
||||||
|
|
||||||
let like_out = serde_json::to_string(
|
let like_out = serde_json::to_string(
|
||||||
&CreateCommentLikeResponse {
|
&CommentResponse {
|
||||||
op: self.op_type().to_string(),
|
op: self.op_type().to_string(),
|
||||||
comment: liked_comment
|
comment: liked_comment
|
||||||
}
|
}
|
||||||
|
@ -949,7 +951,7 @@ impl Perform for CreateCommentLike {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let like_sent_out = serde_json::to_string(
|
let like_sent_out = serde_json::to_string(
|
||||||
&CreateCommentLikeResponse {
|
&CommentResponse {
|
||||||
op: self.op_type().to_string(),
|
op: self.op_type().to_string(),
|
||||||
comment: liked_comment_sent
|
comment: liked_comment_sent
|
||||||
}
|
}
|
||||||
|
@ -968,7 +970,7 @@ impl Perform for GetPosts {
|
||||||
UserOperation::GetPosts
|
UserOperation::GetPosts
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform(&self, chat: &mut ChatServer, addr: usize) -> String {
|
fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> String {
|
||||||
|
|
||||||
let conn = establish_connection();
|
let conn = establish_connection();
|
||||||
|
|
||||||
|
@ -981,7 +983,7 @@ impl Perform for GetPosts {
|
||||||
let user_id = claims.claims.id;
|
let user_id = claims.claims.id;
|
||||||
Some(user_id)
|
Some(user_id)
|
||||||
}
|
}
|
||||||
Err(e) => None
|
Err(_e) => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => None
|
None => None
|
||||||
|
@ -992,8 +994,8 @@ impl Perform for GetPosts {
|
||||||
|
|
||||||
let posts = match PostView::list(&conn, type_, sort, self.community_id, user_id, self.limit) {
|
let posts = match PostView::list(&conn, type_, sort, self.community_id, user_id, self.limit) {
|
||||||
Ok(posts) => posts,
|
Ok(posts) => posts,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
eprintln!("{}", e);
|
eprintln!("{}", _e);
|
||||||
return self.error("Couldn't get posts");
|
return self.error("Couldn't get posts");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1015,13 +1017,13 @@ impl Perform for CreatePostLike {
|
||||||
UserOperation::CreatePostLike
|
UserOperation::CreatePostLike
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform(&self, chat: &mut ChatServer, addr: usize) -> String {
|
fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> String {
|
||||||
|
|
||||||
let conn = establish_connection();
|
let conn = establish_connection();
|
||||||
|
|
||||||
let claims = match Claims::decode(&self.auth) {
|
let claims = match Claims::decode(&self.auth) {
|
||||||
Ok(claims) => claims.claims,
|
Ok(claims) => claims.claims,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Not logged in.");
|
return self.error("Not logged in.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1039,9 +1041,9 @@ impl Perform for CreatePostLike {
|
||||||
|
|
||||||
// Only add the like if the score isnt 0
|
// Only add the like if the score isnt 0
|
||||||
if &like_form.score != &0 {
|
if &like_form.score != &0 {
|
||||||
let inserted_like = match PostLike::like(&conn, &like_form) {
|
let _inserted_like = match PostLike::like(&conn, &like_form) {
|
||||||
Ok(like) => like,
|
Ok(like) => like,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Couldn't like post.");
|
return self.error("Couldn't like post.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1049,7 +1051,7 @@ impl Perform for CreatePostLike {
|
||||||
|
|
||||||
let post_view = match PostView::get(&conn, self.post_id, Some(user_id)) {
|
let post_view = match PostView::get(&conn, self.post_id, Some(user_id)) {
|
||||||
Ok(post) => post,
|
Ok(post) => post,
|
||||||
Err(e) => {
|
Err(_e) => {
|
||||||
return self.error("Couldn't find Post");
|
return self.error("Couldn't find Post");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1068,6 +1070,66 @@ impl Perform for CreatePostLike {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Perform for EditPost {
|
||||||
|
fn op_type(&self) -> UserOperation {
|
||||||
|
UserOperation::EditPost
|
||||||
|
}
|
||||||
|
|
||||||
|
fn perform(&self, chat: &mut ChatServer, addr: usize) -> String {
|
||||||
|
|
||||||
|
let conn = establish_connection();
|
||||||
|
|
||||||
|
let claims = match Claims::decode(&self.auth) {
|
||||||
|
Ok(claims) => claims.claims,
|
||||||
|
Err(_e) => {
|
||||||
|
return self.error("Not logged in.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let user_id = claims.id;
|
||||||
|
|
||||||
|
let post_form = PostForm {
|
||||||
|
name: self.name.to_owned(),
|
||||||
|
url: self.url.to_owned(),
|
||||||
|
body: self.body.to_owned(),
|
||||||
|
creator_id: user_id,
|
||||||
|
community_id: self.community_id,
|
||||||
|
updated: Some(naive_now())
|
||||||
|
};
|
||||||
|
|
||||||
|
let _updated_post = match Post::update(&conn, self.edit_id, &post_form) {
|
||||||
|
Ok(post) => post,
|
||||||
|
Err(_e) => {
|
||||||
|
return self.error("Couldn't update Post");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let post_view = PostView::get(&conn, self.edit_id, Some(user_id)).unwrap();
|
||||||
|
|
||||||
|
let mut post_sent = post_view.clone();
|
||||||
|
post_sent.my_vote = None;
|
||||||
|
|
||||||
|
let post_out = serde_json::to_string(
|
||||||
|
&PostResponse {
|
||||||
|
op: self.op_type().to_string(),
|
||||||
|
post: post_view
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let post_sent_out = serde_json::to_string(
|
||||||
|
&PostResponse {
|
||||||
|
op: self.op_type().to_string(),
|
||||||
|
post: post_sent
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
chat.send_room_message(self.edit_id, &post_sent_out, addr);
|
||||||
|
|
||||||
|
post_out
|
||||||
|
}
|
||||||
|
}
|
||||||
// impl Handler<Login> for ChatServer {
|
// impl Handler<Login> for ChatServer {
|
||||||
|
|
||||||
// type Result = MessageResult<Login>;
|
// type Result = MessageResult<Login>;
|
||||||
|
@ -1078,7 +1140,7 @@ impl Perform for CreatePostLike {
|
||||||
// // Fetch that username / email
|
// // Fetch that username / email
|
||||||
// let user: User_ = match User_::find_by_email_or_username(&conn, &msg.username_or_email) {
|
// let user: User_ = match User_::find_by_email_or_username(&conn, &msg.username_or_email) {
|
||||||
// Ok(user) => user,
|
// Ok(user) => user,
|
||||||
// Err(e) => return MessageResult(
|
// Err(_e) => return MessageResult(
|
||||||
// Err(
|
// Err(
|
||||||
// ErrorMessage {
|
// ErrorMessage {
|
||||||
// op: UserOperation::Login.to_string(),
|
// op: UserOperation::Login.to_string(),
|
||||||
|
@ -1144,7 +1206,7 @@ impl Perform for CreatePostLike {
|
||||||
// // Create the user
|
// // Create the user
|
||||||
// let inserted_user = match User_::create(&conn, &user_form) {
|
// let inserted_user = match User_::create(&conn, &user_form) {
|
||||||
// Ok(user) => user,
|
// Ok(user) => user,
|
||||||
// Err(e) => return MessageResult(
|
// Err(_e) => return MessageResult(
|
||||||
// Err(
|
// Err(
|
||||||
// ErrorMessage {
|
// ErrorMessage {
|
||||||
// op: UserOperation::Register.to_string(),
|
// op: UserOperation::Register.to_string(),
|
||||||
|
@ -1184,7 +1246,7 @@ impl Perform for CreatePostLike {
|
||||||
|
|
||||||
// let community = match Community::create(&conn, &community_form) {
|
// let community = match Community::create(&conn, &community_form) {
|
||||||
// Ok(community) => community,
|
// Ok(community) => community,
|
||||||
// Err(e) => return MessageResult(
|
// Err(_e) => return MessageResult(
|
||||||
// Err(
|
// Err(
|
||||||
// ErrorMessage {
|
// ErrorMessage {
|
||||||
// op: UserOperation::CreateCommunity.to_string(),
|
// op: UserOperation::CreateCommunity.to_string(),
|
||||||
|
|
|
@ -1,47 +1,11 @@
|
||||||
import { Component, linkEvent } from 'inferno';
|
import { Component, linkEvent } from 'inferno';
|
||||||
import { Subscription } from "rxjs";
|
import { PostForm } from './post-form';
|
||||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
|
||||||
import { PostForm, Post, PostResponse, UserOperation, Community, ListCommunitiesResponse } from '../interfaces';
|
|
||||||
import { WebSocketService, UserService } from '../services';
|
|
||||||
import { msgOp } from '../utils';
|
|
||||||
import { MomentTime } from './moment-time';
|
|
||||||
|
|
||||||
interface State {
|
export class CreatePost extends Component<any, any> {
|
||||||
postForm: PostForm;
|
|
||||||
communities: Array<Community>;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export class CreatePost extends Component<any, State> {
|
|
||||||
|
|
||||||
private subscription: Subscription;
|
|
||||||
private emptyState: State = {
|
|
||||||
postForm: {
|
|
||||||
name: null,
|
|
||||||
auth: null,
|
|
||||||
community_id: null
|
|
||||||
},
|
|
||||||
communities: []
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
this.handlePostCreate = this.handlePostCreate.bind(this);
|
||||||
this.state = this.emptyState;
|
|
||||||
|
|
||||||
this.subscription = WebSocketService.Instance.subject
|
|
||||||
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
|
|
||||||
.subscribe(
|
|
||||||
(msg) => this.parseMessage(msg),
|
|
||||||
(err) => console.error(err),
|
|
||||||
() => console.log('complete')
|
|
||||||
);
|
|
||||||
|
|
||||||
WebSocketService.Instance.listCommunities();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.subscription.unsubscribe();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -49,92 +13,17 @@ export class CreatePost extends Component<any, State> {
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-lg-6 mb-4">
|
<div class="col-12 col-lg-6 mb-4">
|
||||||
{this.postForm()}
|
<h3>Create a Post</h3>
|
||||||
|
<PostForm onCreate={this.handlePostCreate}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
postForm() {
|
handlePostCreate(id: number) {
|
||||||
return (
|
this.props.history.push(`/post/${id}`);
|
||||||
<div>
|
|
||||||
<form onSubmit={linkEvent(this, this.handlePostSubmit)}>
|
|
||||||
<h3>Create a Post</h3>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-2 col-form-label">URL</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<input type="url" class="form-control" value={this.state.postForm.url} onInput={linkEvent(this, this.handlePostUrlChange)} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-2 col-form-label">Title</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<textarea value={this.state.postForm.name} onInput={linkEvent(this, this.handlePostNameChange)} class="form-control" required rows={3} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-2 col-form-label">Body</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<textarea value={this.state.postForm.body} onInput={linkEvent(this, this.handlePostBodyChange)} class="form-control" rows={6} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-2 col-form-label">Forum</label>
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<select class="form-control" value={this.state.postForm.community_id} onInput={linkEvent(this, this.handlePostCommunityChange)}>
|
|
||||||
{this.state.communities.map(community =>
|
|
||||||
<option value={community.id}>{community.name}</option>
|
|
||||||
)}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-sm-10">
|
|
||||||
<button type="submit" class="btn btn-secondary">Create Post</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePostSubmit(i: CreatePost, event) {
|
|
||||||
event.preventDefault();
|
|
||||||
WebSocketService.Instance.createPost(i.state.postForm);
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePostUrlChange(i: CreatePost, event) {
|
|
||||||
i.state.postForm.url = event.target.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePostNameChange(i: CreatePost, event) {
|
|
||||||
i.state.postForm.name = event.target.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePostBodyChange(i: CreatePost, event) {
|
|
||||||
i.state.postForm.body = event.target.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePostCommunityChange(i: CreatePost, event) {
|
|
||||||
i.state.postForm.community_id = Number(event.target.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
parseMessage(msg: any) {
|
|
||||||
console.log(msg);
|
|
||||||
let op: UserOperation = msgOp(msg);
|
|
||||||
if (msg.error) {
|
|
||||||
alert(msg.error);
|
|
||||||
return;
|
|
||||||
} else if (op == UserOperation.ListCommunities) {
|
|
||||||
let res: ListCommunitiesResponse = msg;
|
|
||||||
this.state.communities = res.communities;
|
|
||||||
this.state.postForm.community_id = res.communities[0].id; // TODO set it to the default community
|
|
||||||
this.setState(this.state);
|
|
||||||
} else if (op == UserOperation.CreatePost) {
|
|
||||||
let res: PostResponse = msg;
|
|
||||||
this.props.history.push(`/post/${res.post.id}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
162
ui/src/components/post-form.tsx
Normal file
162
ui/src/components/post-form.tsx
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
import { Component, linkEvent } from 'inferno';
|
||||||
|
import { Subscription } from "rxjs";
|
||||||
|
import { retryWhen, delay, take } from 'rxjs/operators';
|
||||||
|
import { PostForm as PostFormI, Post, PostResponse, UserOperation, Community, ListCommunitiesResponse } from '../interfaces';
|
||||||
|
import { WebSocketService, UserService } from '../services';
|
||||||
|
import { msgOp } from '../utils';
|
||||||
|
import { MomentTime } from './moment-time';
|
||||||
|
|
||||||
|
interface PostFormProps {
|
||||||
|
post?: Post; // If a post is given, that means this is an edit
|
||||||
|
onCancel?();
|
||||||
|
onCreate?(id: number);
|
||||||
|
onEdit?(post: Post);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PostFormState {
|
||||||
|
postForm: PostFormI;
|
||||||
|
communities: Array<Community>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
|
|
||||||
|
private subscription: Subscription;
|
||||||
|
private emptyState: PostFormState = {
|
||||||
|
postForm: {
|
||||||
|
name: null,
|
||||||
|
auth: null,
|
||||||
|
community_id: null
|
||||||
|
},
|
||||||
|
communities: []
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
|
||||||
|
this.state = this.emptyState;
|
||||||
|
|
||||||
|
if (this.props.post) {
|
||||||
|
this.state.postForm = {
|
||||||
|
body: this.props.post.body,
|
||||||
|
name: this.props.post.name,
|
||||||
|
community_id: this.props.post.community_id,
|
||||||
|
edit_id: this.props.post.id,
|
||||||
|
url: this.props.post.url,
|
||||||
|
auth: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.subscription = WebSocketService.Instance.subject
|
||||||
|
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
|
||||||
|
.subscribe(
|
||||||
|
(msg) => this.parseMessage(msg),
|
||||||
|
(err) => console.error(err),
|
||||||
|
() => console.log('complete')
|
||||||
|
);
|
||||||
|
|
||||||
|
WebSocketService.Instance.listCommunities();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<form onSubmit={linkEvent(this, this.handlePostSubmit)}>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-2 col-form-label">URL</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="url" class="form-control" value={this.state.postForm.url} onInput={linkEvent(this, this.handlePostUrlChange)} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-2 col-form-label">Title</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea value={this.state.postForm.name} onInput={linkEvent(this, this.handlePostNameChange)} class="form-control" required rows={3} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-2 col-form-label">Body</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea value={this.state.postForm.body} onInput={linkEvent(this, this.handlePostBodyChange)} class="form-control" rows={6} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-2 col-form-label">Forum</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select class="form-control" value={this.state.postForm.community_id} onInput={linkEvent(this, this.handlePostCommunityChange)}>
|
||||||
|
{this.state.communities.map(community =>
|
||||||
|
<option value={community.id}>{community.name}</option>
|
||||||
|
)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<button type="submit" class="btn btn-secondary">{this.props.post ? 'Edit' : 'Create'} Post</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePostSubmit(i: PostForm, event) {
|
||||||
|
event.preventDefault();
|
||||||
|
console.log(i.state.postForm);
|
||||||
|
if (i.props.post) {
|
||||||
|
WebSocketService.Instance.editPost(i.state.postForm);
|
||||||
|
} else {
|
||||||
|
WebSocketService.Instance.createPost(i.state.postForm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePostUrlChange(i: PostForm, event) {
|
||||||
|
i.state.postForm.url = event.target.value;
|
||||||
|
i.setState(i.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePostNameChange(i: PostForm, event) {
|
||||||
|
i.state.postForm.name = event.target.value;
|
||||||
|
i.setState(i.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePostBodyChange(i: PostForm, event) {
|
||||||
|
i.state.postForm.body = event.target.value;
|
||||||
|
i.setState(i.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePostCommunityChange(i: PostForm, event) {
|
||||||
|
i.state.postForm.community_id = Number(event.target.value);
|
||||||
|
i.setState(i.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
parseMessage(msg: any) {
|
||||||
|
console.log(msg);
|
||||||
|
let op: UserOperation = msgOp(msg);
|
||||||
|
if (msg.error) {
|
||||||
|
alert(msg.error);
|
||||||
|
return;
|
||||||
|
} else if (op == UserOperation.ListCommunities) {
|
||||||
|
let res: ListCommunitiesResponse = msg;
|
||||||
|
this.state.communities = res.communities;
|
||||||
|
if (this.props.post) {
|
||||||
|
this.state.postForm.community_id = this.props.post.community_id;
|
||||||
|
} else {
|
||||||
|
this.state.postForm.community_id = res.communities[0].id;
|
||||||
|
}
|
||||||
|
this.setState(this.state);
|
||||||
|
} else if (op == UserOperation.CreatePost) {
|
||||||
|
let res: PostResponse = msg;
|
||||||
|
this.props.onCreate(res.post.id);
|
||||||
|
} else if (op == UserOperation.EditPost) {
|
||||||
|
let res: PostResponse = msg;
|
||||||
|
this.props.onEdit(res.post);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,18 @@ import { Link } from 'inferno-router';
|
||||||
import { Subscription } from "rxjs";
|
import { Subscription } from "rxjs";
|
||||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
import { retryWhen, delay, take } from 'rxjs/operators';
|
||||||
import { WebSocketService, UserService } from '../services';
|
import { WebSocketService, UserService } from '../services';
|
||||||
import { Post, CreatePostLikeResponse, CreatePostLikeForm } from '../interfaces';
|
import { Post, CreatePostLikeResponse, CreatePostLikeForm, PostForm as PostFormI } from '../interfaces';
|
||||||
import { MomentTime } from './moment-time';
|
import { MomentTime } from './moment-time';
|
||||||
|
import { PostForm } from './post-form';
|
||||||
import { mdToHtml } from '../utils';
|
import { mdToHtml } from '../utils';
|
||||||
|
|
||||||
interface PostListingState {
|
interface PostListingState {
|
||||||
|
showEdit: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PostListingProps {
|
interface PostListingProps {
|
||||||
post: Post;
|
post: Post;
|
||||||
|
editable?: boolean;
|
||||||
showCommunity?: boolean;
|
showCommunity?: boolean;
|
||||||
showBody?: boolean;
|
showBody?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +22,7 @@ interface PostListingProps {
|
||||||
export class PostListing extends Component<PostListingProps, PostListingState> {
|
export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
|
|
||||||
private emptyState: PostListingState = {
|
private emptyState: PostListingState = {
|
||||||
|
showEdit: false
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
|
@ -27,9 +31,21 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
this.state = this.emptyState;
|
this.state = this.emptyState;
|
||||||
this.handlePostLike = this.handlePostLike.bind(this);
|
this.handlePostLike = this.handlePostLike.bind(this);
|
||||||
this.handlePostDisLike = this.handlePostDisLike.bind(this);
|
this.handlePostDisLike = this.handlePostDisLike.bind(this);
|
||||||
|
this.handleEditPost = this.handleEditPost.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{!this.state.showEdit
|
||||||
|
? this.listing()
|
||||||
|
: <PostForm post={this.props.post} onEdit={this.handleEditPost} />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
listing() {
|
||||||
let post = this.props.post;
|
let post = this.props.post;
|
||||||
return (
|
return (
|
||||||
<div class="listing">
|
<div class="listing">
|
||||||
|
@ -74,15 +90,25 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
<Link to={`/post/${post.id}`}>{post.number_of_comments} Comments</Link>
|
<Link to={`/post/${post.id}`}>{post.number_of_comments} Comments</Link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
{this.myPost &&
|
||||||
|
<ul class="list-inline mb-1 text-muted small font-weight-bold">
|
||||||
|
<li className="list-inline-item">
|
||||||
|
<span class="pointer" onClick={linkEvent(this, this.handleEditClick)}>edit</span>
|
||||||
|
</li>
|
||||||
|
<li className="list-inline-item">
|
||||||
|
<span class="pointer" onClick={linkEvent(this, this.handleDeleteClick)}>delete</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
{this.props.showBody && this.props.post.body && <div className="md-div" dangerouslySetInnerHTML={mdToHtml(post.body)} />}
|
{this.props.showBody && this.props.post.body && <div className="md-div" dangerouslySetInnerHTML={mdToHtml(post.body)} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// private get myPost(): boolean {
|
private get myPost(): boolean {
|
||||||
// return this.props.node.comment.attributed_to == UserService.Instance.fediUserId;
|
return this.props.editable && UserService.Instance.loggedIn && this.props.post.creator_id == UserService.Instance.user.id;
|
||||||
// }
|
}
|
||||||
|
|
||||||
handlePostLike(i: PostListing, event) {
|
handlePostLike(i: PostListing, event) {
|
||||||
|
|
||||||
|
@ -100,5 +126,27 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
};
|
};
|
||||||
WebSocketService.Instance.likePost(form);
|
WebSocketService.Instance.likePost(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleEditClick(i: PostListing, event) {
|
||||||
|
i.state.showEdit = true;
|
||||||
|
i.setState(i.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEditPost(post: Post) {
|
||||||
|
this.state.showEdit = false;
|
||||||
|
this.setState(this.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDeleteClick(i: PostListing, event) {
|
||||||
|
let deleteForm: PostFormI = {
|
||||||
|
body: '',
|
||||||
|
community_id: i.props.post.community_id,
|
||||||
|
name: "deleted",
|
||||||
|
url: '',
|
||||||
|
edit_id: i.props.post.id,
|
||||||
|
auth: null
|
||||||
|
};
|
||||||
|
WebSocketService.Instance.editPost(deleteForm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { Component, linkEvent } from 'inferno';
|
import { Component, linkEvent } from 'inferno';
|
||||||
|
import { Link } from 'inferno-router';
|
||||||
import { Subscription } from "rxjs";
|
import { Subscription } from "rxjs";
|
||||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
import { retryWhen, delay, take } from 'rxjs/operators';
|
||||||
import { UserOperation, Community, Post as PostI, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentLikeForm, CreateCommentLikeResponse, CommentSortType, CreatePostLikeResponse } from '../interfaces';
|
import { UserOperation, Community, Post as PostI, GetPostResponse, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentLikeForm, CreateCommentLikeResponse, CommentSortType, CreatePostLikeResponse } from '../interfaces';
|
||||||
import { WebSocketService, UserService } from '../services';
|
import { WebSocketService, UserService } from '../services';
|
||||||
import { msgOp, hotRank,mdToHtml } from '../utils';
|
import { msgOp, hotRank,mdToHtml } from '../utils';
|
||||||
import { MomentTime } from './moment-time';
|
import { MomentTime } from './moment-time';
|
||||||
|
@ -60,7 +61,7 @@ export class Post extends Component<any, State> {
|
||||||
{this.state.post &&
|
{this.state.post &&
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-sm-8 col-lg-7 mb-3">
|
<div class="col-12 col-sm-8 col-lg-7 mb-3">
|
||||||
<PostListing post={this.state.post} showBody showCommunity />
|
<PostListing post={this.state.post} showBody showCommunity editable />
|
||||||
<div className="mb-2" />
|
<div className="mb-2" />
|
||||||
<CommentForm postId={this.state.post.id} />
|
<CommentForm postId={this.state.post.id} />
|
||||||
{this.sortRadios()}
|
{this.sortRadios()}
|
||||||
|
@ -181,7 +182,7 @@ export class Post extends Component<any, State> {
|
||||||
alert(msg.error);
|
alert(msg.error);
|
||||||
return;
|
return;
|
||||||
} else if (op == UserOperation.GetPost) {
|
} else if (op == UserOperation.GetPost) {
|
||||||
let res: PostResponse = msg;
|
let res: GetPostResponse = msg;
|
||||||
this.state.post = res.post;
|
this.state.post = res.post;
|
||||||
this.state.comments = res.comments;
|
this.state.comments = res.comments;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
@ -212,6 +213,10 @@ export class Post extends Component<any, State> {
|
||||||
this.state.post.upvotes = res.post.upvotes;
|
this.state.post.upvotes = res.post.upvotes;
|
||||||
this.state.post.downvotes = res.post.downvotes;
|
this.state.post.downvotes = res.post.downvotes;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
} else if (op == UserOperation.EditPost) {
|
||||||
|
let res: PostResponse = msg;
|
||||||
|
this.state.post = res.post;
|
||||||
|
this.setState(this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -281,7 +286,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
<div className="details ml-4">
|
<div className="details ml-4">
|
||||||
<ul class="list-inline mb-0 text-muted small">
|
<ul class="list-inline mb-0 text-muted small">
|
||||||
<li className="list-inline-item">
|
<li className="list-inline-item">
|
||||||
<a href={node.comment.attributed_to}>{node.comment.attributed_to}</a>
|
<Link to={`/user/${node.comment.creator_id}`}>{node.comment.creator_name}</Link>
|
||||||
</li>
|
</li>
|
||||||
<li className="list-inline-item">
|
<li className="list-inline-item">
|
||||||
<span>(
|
<span>(
|
||||||
|
@ -327,7 +332,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private get myComment(): boolean {
|
private get myComment(): boolean {
|
||||||
return this.props.node.comment.attributed_to == UserService.Instance.fediUserId;
|
return UserService.Instance.loggedIn && this.props.node.comment.creator_id == UserService.Instance.user.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleReplyClick(i: CommentNode, event) {
|
handleReplyClick(i: CommentNode, event) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export enum UserOperation {
|
export enum UserOperation {
|
||||||
Login, Register, CreateCommunity, CreatePost, ListCommunities, GetPost, GetCommunity, CreateComment, EditComment, CreateCommentLike, GetPosts, CreatePostLike
|
Login, Register, CreateCommunity, CreatePost, ListCommunities, GetPost, GetCommunity, CreateComment, EditComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, EditCommunity
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
|
@ -56,19 +56,26 @@ export interface PostForm {
|
||||||
body?: string;
|
body?: string;
|
||||||
community_id: number;
|
community_id: number;
|
||||||
updated?: number;
|
updated?: number;
|
||||||
|
edit_id?: number;
|
||||||
auth: string;
|
auth: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GetPostResponse {
|
||||||
|
op: string;
|
||||||
|
post: Post;
|
||||||
|
comments: Array<Comment>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PostResponse {
|
export interface PostResponse {
|
||||||
op: string;
|
op: string;
|
||||||
post: Post;
|
post: Post;
|
||||||
comments: Array<Comment>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Comment {
|
export interface Comment {
|
||||||
id: number;
|
id: number;
|
||||||
content: string;
|
content: string;
|
||||||
creator_id: number;
|
creator_id: number;
|
||||||
|
creator_name: string;
|
||||||
post_id: number,
|
post_id: number,
|
||||||
parent_id?: number;
|
parent_id?: number;
|
||||||
published: string;
|
published: string;
|
||||||
|
@ -99,11 +106,6 @@ export interface CommentLikeForm {
|
||||||
auth?: string;
|
auth?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateCommentLikeResponse {
|
|
||||||
op: string;
|
|
||||||
comment: Comment;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GetPostsForm {
|
export interface GetPostsForm {
|
||||||
type_: string;
|
type_: string;
|
||||||
sort: string;
|
sort: string;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Subject } from 'rxjs';
|
||||||
|
|
||||||
export class UserService {
|
export class UserService {
|
||||||
private static _instance: UserService;
|
private static _instance: UserService;
|
||||||
private user: User;
|
public user: User;
|
||||||
public sub: Subject<User> = new Subject<User>();
|
public sub: Subject<User> = new Subject<User>();
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
|
@ -45,10 +45,6 @@ export class UserService {
|
||||||
console.log(this.user);
|
console.log(this.user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get fediUserId(): string {
|
|
||||||
return `${this.user.iss}/${this.user.username}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get Instance(){
|
public static get Instance(){
|
||||||
return this._instance || (this._instance = new this());
|
return this._instance || (this._instance = new this());
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,11 @@ export class WebSocketService {
|
||||||
this.subject.next(this.wsSendWrapper(UserOperation.CreatePostLike, form));
|
this.subject.next(this.wsSendWrapper(UserOperation.CreatePostLike, form));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public editPost(postForm: PostForm) {
|
||||||
|
this.setAuth(postForm);
|
||||||
|
this.subject.next(this.wsSendWrapper(UserOperation.EditPost, postForm));
|
||||||
|
}
|
||||||
|
|
||||||
private wsSendWrapper(op: UserOperation, data: any) {
|
private wsSendWrapper(op: UserOperation, data: any) {
|
||||||
let send = { op: UserOperation[op], data: data };
|
let send = { op: UserOperation[op], data: data };
|
||||||
console.log(send);
|
console.log(send);
|
||||||
|
|
Loading…
Reference in a new issue