Skip to content

Commit

Permalink
Adding posts and comments.
Browse files Browse the repository at this point in the history
  • Loading branch information
dessalines committed Mar 6, 2019
1 parent 58de24c commit 064d7f8
Show file tree
Hide file tree
Showing 14 changed files with 401 additions and 113 deletions.
13 changes: 7 additions & 6 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"inbox": "https://rust-reddit-fediverse/api/v1/user/sally_smith/inbox",
"outbox": "https://rust-reddit-fediverse/api/v1/user/sally_smith/outbox",
"liked": "https://rust-reddit-fediverse/api/v1/user/sally_smith/liked",
// TODO disliked?
"following": "https://rust-reddit-fediverse/api/v1/user/sally_smith/following",
"name": "sally_smith",
"preferredUsername": "Sally",
Expand All @@ -62,7 +63,7 @@
"width": 32,
"height": 32
},
"startTime": "2014-12-31T23:00:00-08:00",
"published": "2014-12-31T23:00:00-08:00",
"summary"?: "This is sally's profile."
}
```
Expand All @@ -78,7 +79,7 @@
"http://joe.example.org",
],
"followers": "https://rust-reddit-fediverse/api/v1/community/today_i_learned/followers",
"startTime": "2014-12-31T23:00:00-08:00",
"published": "2014-12-31T23:00:00-08:00",
"summary"?: "The group's tagline",
"attachment: [{}] // TBD, these would be where strong types for custom styles, and images would work.
}
Expand All @@ -95,7 +96,7 @@
"name": "The title of a post, maybe a link to imgur",
"url": "https://news.blah.com"
"attributedTo": "http://joe.example.org", // The poster
"startTime": "2014-12-31T23:00:00-08:00",
"published": "2014-12-31T23:00:00-08:00",
}
```

Expand All @@ -116,11 +117,11 @@
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Note",
"id": "https://rust-reddit-fediverse/api/v1/comment/1",
"name": "A note",
"content": "Looks like it is going to rain today. Bring an umbrella <a href='http://sally.example.org'>@sally</a>!"
"mediaType": "text/markdown",
"content": "Looks like it is going to rain today. Bring an umbrella *if necessary*!"
"attributedTo": john_id,
"inReplyTo": "comment or post id",
"startTime": "2014-12-31T23:00:00-08:00",
"published": "2014-12-31T23:00:00-08:00",
"updated"?: "2014-12-12T12:12:12Z"
"replies" // TODO, not sure if these objects should embed all replies in them or not.
"to": [sally_id, group_id]
Expand Down
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ We have a twitter alternative (mastodon), a facebook alternative (friendica), so

[ActivityPub API.md](API.md)


## Goals
- Come up with a name / codename.
- Must have communities.
Expand All @@ -21,7 +20,9 @@ We have a twitter alternative (mastodon), a facebook alternative (friendica), so
- Backend: Actix, Diesel.
- Frontend: inferno, typescript and bootstrap for now.
- Should it allow bots?
- Should the comments / votes be static, or feel like a chat, like [flowchat?](https://flow-chat.com).
- Should the comments / votes be static, or feel like a chat, like [flowchat?](https://flow-chat.com).
- Two pane model - Right pane is live comments, left pane is live tree view.
- On mobile, allow you to switch between them. Default?

## Resources / Potential Libraries
- Use the [activitypub crate.](https://docs.rs/activitypub/0.1.4/activitypub/)
Expand All @@ -31,3 +32,9 @@ We have a twitter alternative (mastodon), a facebook alternative (friendica), so
- [Diesel to Postgres data types](https://kotiri.com/2018/01/31/postgresql-diesel-rust-types.html)
- [helpful diesel examples](http://siciarz.net/24-days-rust-diesel/)
- [Mastodan public key server example](https://blog.joinmastodon.org/2018/06/how-to-implement-a-basic-activitypub-server/)
- [Recursive query for adjacency list for nested comments](https://stackoverflow.com/questions/192220/what-is-the-most-efficient-elegant-way-to-parse-a-flat-table-into-a-tree/192462#192462)

## TODOs
- Endpoints
- DB
- Followers / following
1 change: 1 addition & 0 deletions server/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target
.env
.idea
1 change: 0 additions & 1 deletion server/migrations/2019-03-03-163336_create_post/down.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
drop table post_like;
drop table post_dislike;
drop table post;
10 changes: 2 additions & 8 deletions server/migrations/2019-03-03-163336_create_post/up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,9 @@ create table post (

create table post_like (
id serial primary key,
post_id int references post on update cascade on delete cascade not null,
fedi_user_id text not null,
post_id int references post on update cascade on delete cascade,
published timestamp not null default now()
);

create table post_dislike (
id serial primary key,
fedi_user_id text not null,
post_id int references post on update cascade on delete cascade,
score smallint not null, -- -1, or 1 for dislike, like, no row for no opinion
published timestamp not null default now()
);

2 changes: 2 additions & 0 deletions server/migrations/2019-03-05-233828_create_comment/down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
drop table comment_like;
drop table comment;
17 changes: 17 additions & 0 deletions server/migrations/2019-03-05-233828_create_comment/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
create table comment (
id serial primary key,
content text not null,
attributed_to text not null,
post_id int references post on update cascade on delete cascade not null,
parent_id int references comment on update cascade on delete cascade,
published timestamp not null default now(),
updated timestamp
);

create table comment_like (
id serial primary key,
comment_id int references comment on update cascade on delete cascade not null,
fedi_user_id text not null,
score smallint not null, -- -1, or 1 for dislike, like, no row for no opinion
published timestamp not null default now()
);
177 changes: 177 additions & 0 deletions server/src/actions/comment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
extern crate diesel;
use schema::{comment, comment_like};
use diesel::*;
use diesel::result::Error;
use {Crud, Likeable};

#[derive(Queryable, Identifiable, PartialEq, Debug)]
#[table_name="comment"]
pub struct Comment {
pub id: i32,
pub content: String,
pub attributed_to: String,
pub post_id: i32,
pub parent_id: Option<i32>,
pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime>
}

#[derive(Insertable, AsChangeset, Clone, Copy)]
#[table_name="comment"]
pub struct CommentForm<'a> {
pub content: &'a str,
pub attributed_to: &'a str,
pub post_id: &'a i32,
pub parent_id: Option<&'a i32>,
pub updated: Option<&'a chrono::NaiveDateTime>
}

#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
#[belongs_to(Comment)]
#[table_name = "comment_like"]
pub struct CommentLike {
pub id: i32,
pub comment_id: i32,
pub fedi_user_id: String,
pub score: i16,
pub published: chrono::NaiveDateTime,
}

#[derive(Insertable, AsChangeset, Clone, Copy)]
#[table_name="comment_like"]
pub struct CommentLikeForm<'a> {
pub comment_id: &'a i32,
pub fedi_user_id: &'a str,
pub score: &'a i16
}

impl<'a> Crud<CommentForm<'a>> for Comment {
fn read(conn: &PgConnection, comment_id: i32) -> Comment {
use schema::comment::dsl::*;
comment.find(comment_id)
.first::<Comment>(conn)
.expect("Error in query")
}

fn delete(conn: &PgConnection, comment_id: i32) -> usize {
use schema::comment::dsl::*;
diesel::delete(comment.find(comment_id))
.execute(conn)
.expect("Error deleting.")
}

fn create(conn: &PgConnection, comment_form: CommentForm) -> Result<Comment, Error> {
use schema::comment::dsl::*;
insert_into(comment)
.values(comment_form)
.get_result::<Comment>(conn)
}

fn update(conn: &PgConnection, comment_id: i32, comment_form: CommentForm) -> Comment {
use schema::comment::dsl::*;
diesel::update(comment.find(comment_id))
.set(comment_form)
.get_result::<Comment>(conn)
.expect(&format!("Unable to find {}", comment_id))
}
}

impl<'a> Likeable <CommentLikeForm<'a>> for CommentLike {
fn like(conn: &PgConnection, comment_like_form: CommentLikeForm) -> Result<CommentLike, Error> {
use schema::comment_like::dsl::*;
insert_into(comment_like)
.values(comment_like_form)
.get_result::<CommentLike>(conn)
}
fn remove(conn: &PgConnection, comment_like_form: CommentLikeForm) -> usize {
use schema::comment_like::dsl::*;
diesel::delete(comment_like
.filter(comment_id.eq(comment_like_form.comment_id))
.filter(fedi_user_id.eq(comment_like_form.fedi_user_id)))
.execute(conn)
.expect("Error deleting.")
}
}

#[cfg(test)]
mod tests {
use establish_connection;
use super::*;
use actions::post::*;
use Crud;
#[test]
fn test_crud() {
let conn = establish_connection();

let new_post = PostForm {
name: "A test post".into(),
url: "https://test.com".into(),
attributed_to: "test_user.com".into(),
updated: None
};

let inserted_post = Post::create(&conn, new_post).unwrap();

let comment_form = CommentForm {
content: "A test comment".into(),
attributed_to: "test_user.com".into(),
post_id: &inserted_post.id,
parent_id: None,
updated: None
};

let inserted_comment = Comment::create(&conn, comment_form).unwrap();

let expected_comment = Comment {
id: inserted_comment.id,
content: "A test comment".into(),
attributed_to: "test_user.com".into(),
post_id: inserted_post.id,
parent_id: None,
published: inserted_comment.published,
updated: None
};

let child_comment_form = CommentForm {
content: "A child comment".into(),
attributed_to: "test_user.com".into(),
post_id: &inserted_post.id,
parent_id: Some(&inserted_comment.id),
updated: None
};

let inserted_child_comment = Comment::create(&conn, child_comment_form).unwrap();

let comment_like_form = CommentLikeForm {
comment_id: &inserted_comment.id,
fedi_user_id: "test".into(),
score: &1
};

let inserted_comment_like = CommentLike::like(&conn, comment_like_form).unwrap();

let expected_comment_like = CommentLike {
id: inserted_comment_like.id,
comment_id: inserted_comment.id,
fedi_user_id: "test".into(),
published: inserted_comment_like.published,
score: 1
};

let read_comment = Comment::read(&conn, inserted_comment.id);
let updated_comment = Comment::update(&conn, inserted_comment.id, comment_form);
let like_removed = CommentLike::remove(&conn, comment_like_form);
let num_deleted = Comment::delete(&conn, inserted_comment.id);
Comment::delete(&conn, inserted_child_comment.id);
Post::delete(&conn, inserted_post.id);

assert_eq!(expected_comment, read_comment);
assert_eq!(expected_comment, inserted_comment);
assert_eq!(expected_comment, updated_comment);
assert_eq!(expected_comment_like, inserted_comment_like);
assert_eq!(expected_comment.id, inserted_child_comment.parent_id.unwrap());
assert_eq!(1, like_removed);
assert_eq!(1, num_deleted);

}
}
1 change: 1 addition & 0 deletions server/src/actions/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod user;
pub mod community;
pub mod post;
pub mod comment;
Loading

0 comments on commit 064d7f8

Please sign in to comment.