diff options
author | Dessalines <tyhou13@gmx.com> | 2019-03-22 18:42:57 -0700 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2019-03-22 18:42:57 -0700 |
commit | e570c70701e1c66dad12bef76821f6d94c717a02 (patch) | |
tree | 070d5ba322226acd5fe0d0a7757cb936462ab2ff | |
parent | 816aa0b15f3766e340d8722f03e8b3a7633ab6fb (diff) |
Adding login and Register
- Login and Register mostly working.
- Starting to work on creating communities.
26 files changed, 825 insertions, 300 deletions
@@ -35,6 +35,8 @@ We have a twitter alternative (mastodon), a facebook alternative (friendica), so - [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) - https://github.com/sparksuite/simplemde-markdown-editor - [Sticky Sidebar](https://stackoverflow.com/questions/38382043/how-to-use-css-position-sticky-to-keep-a-sidebar-visible-with-bootstrap-4/49111934) +- [RXJS websocket](https://stackoverflow.com/questions/44060315/reconnecting-a-websocket-in-angular-and-rxjs/44067972#44067972) +- [Rust JWT](https://github.com/Keats/jsonwebtoken) ## TODOs - Endpoints diff --git a/server/Cargo.lock b/server/Cargo.lock index b4557d00..21594ccf 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -704,6 +704,20 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "jsonwebtoken" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1309,7 +1323,9 @@ dependencies = [ "dotenv 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonwebtoken 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "strum 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1977,6 +1993,7 @@ dependencies = [ "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum ipconfig 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "08f7eadeaf4b52700de180d147c4805f199854600b36faa963d91114827b2ffc" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" +"checksum jsonwebtoken 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8d438ea707d465c230305963b67f8357a1d56fcfad9434797d7cb1c46c2e41df" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" diff --git a/server/Cargo.toml b/server/Cargo.toml index 3c875e90..ebd7b568 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -18,3 +18,5 @@ env_logger = "*" rand = "0.6.5" strum = "0.14.0" strum_macros = "0.14.0" +jsonwebtoken = "*" +regex = "1" diff --git a/server/migrations/2019-02-26-002946_create_user/up.sql b/server/migrations/2019-02-26-002946_create_user/up.sql index 577ff136..d4edb370 100644 --- a/server/migrations/2019-02-26-002946_create_user/up.sql +++ b/server/migrations/2019-02-26-002946_create_user/up.sql @@ -1,9 +1,9 @@ create table user_ ( id serial primary key, - name varchar(20) not null, + name varchar(20) not null unique, preferred_username varchar(20), password_encrypted text not null, - email text, + email text unique, icon bytea, published timestamp not null default now(), updated timestamp diff --git a/server/migrations/2019-02-27-170003_create_community/up.sql b/server/migrations/2019-02-27-170003_create_community/up.sql index 30deec5b..1ee2e51d 100644 --- a/server/migrations/2019-02-27-170003_create_community/up.sql +++ b/server/migrations/2019-02-27-170003_create_community/up.sql @@ -1,6 +1,6 @@ create table community ( id serial primary key, - name varchar(20) not null, + name varchar(20) not null unique, published timestamp not null default now(), updated timestamp ); diff --git a/server/src/actions/comment.rs b/server/src/actions/comment.rs index d23382c6..98d5322c 100644 --- a/server/src/actions/comment.rs +++ b/server/src/actions/comment.rs @@ -23,14 +23,14 @@ pub struct Comment { pub updated: Option<chrono::NaiveDateTime> } -#[derive(Insertable, AsChangeset, Clone, Copy)] +#[derive(Insertable, AsChangeset, Clone)] #[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> +pub struct CommentForm { + pub content: String, + pub attributed_to: String, + pub post_id: i32, + pub parent_id: Option<i32>, + pub updated: Option<chrono::NaiveDateTime> } #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] @@ -44,59 +44,55 @@ pub struct CommentLike { pub published: chrono::NaiveDateTime, } -#[derive(Insertable, AsChangeset, Clone, Copy)] +#[derive(Insertable, AsChangeset, Clone)] #[table_name="comment_like"] -pub struct CommentLikeForm<'a> { - pub comment_id: &'a i32, - pub fedi_user_id: &'a str, - pub score: &'a i16 +pub struct CommentLikeForm { + pub comment_id: i32, + pub fedi_user_id: String, + pub score: i16 } -impl<'a> Crud<CommentForm<'a>> for Comment { - fn read(conn: &PgConnection, comment_id: i32) -> Comment { +impl Crud<CommentForm> for Comment { + fn read(conn: &PgConnection, comment_id: i32) -> Result<Self, Error> { use schema::comment::dsl::*; comment.find(comment_id) - .first::<Comment>(conn) - .expect("Error in query") + .first::<Self>(conn) } - fn delete(conn: &PgConnection, comment_id: i32) -> usize { + fn delete(conn: &PgConnection, comment_id: i32) -> Result<usize, Error> { 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> { + fn create(conn: &PgConnection, comment_form: &CommentForm) -> Result<Self, Error> { use schema::comment::dsl::*; insert_into(comment) .values(comment_form) - .get_result::<Comment>(conn) + .get_result::<Self>(conn) } - fn update(conn: &PgConnection, comment_id: i32, comment_form: CommentForm) -> Comment { + fn update(conn: &PgConnection, comment_id: i32, comment_form: &CommentForm) -> Result<Self, Error> { use schema::comment::dsl::*; diesel::update(comment.find(comment_id)) .set(comment_form) - .get_result::<Comment>(conn) - .expect(&format!("Unable to find {}", comment_id)) + .get_result::<Self>(conn) } } -impl<'a> Likeable <CommentLikeForm<'a>> for CommentLike { - fn like(conn: &PgConnection, comment_like_form: CommentLikeForm) -> Result<CommentLike, Error> { +impl Likeable <CommentLikeForm> for CommentLike { + fn like(conn: &PgConnection, comment_like_form: &CommentLikeForm) -> Result<Self, Error> { use schema::comment_like::dsl::*; insert_into(comment_like) .values(comment_like_form) - .get_result::<CommentLike>(conn) + .get_result::<Self>(conn) } - fn remove(conn: &PgConnection, comment_like_form: CommentLikeForm) -> usize { + fn remove(conn: &PgConnection, comment_like_form: &CommentLikeForm) -> Result<usize, Error> { 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))) + .filter(fedi_user_id.eq(&comment_like_form.fedi_user_id))) .execute(conn) - .expect("Error deleting.") } } @@ -117,17 +113,17 @@ mod tests { updated: None }; - let inserted_post = Post::create(&conn, new_post).unwrap(); + 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, + post_id: inserted_post.id, parent_id: None, updated: None }; - let inserted_comment = Comment::create(&conn, comment_form).unwrap(); + let inserted_comment = Comment::create(&conn, &comment_form).unwrap(); let expected_comment = Comment { id: inserted_comment.id, @@ -142,20 +138,20 @@ mod tests { 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), + 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 inserted_child_comment = Comment::create(&conn, &child_comment_form).unwrap(); let comment_like_form = CommentLikeForm { - comment_id: &inserted_comment.id, + comment_id: inserted_comment.id, fedi_user_id: "test".into(), - score: &1 + score: 1 }; - let inserted_comment_like = CommentLike::like(&conn, comment_like_form).unwrap(); + let inserted_comment_like = CommentLike::like(&conn, &comment_like_form).unwrap(); let expected_comment_like = CommentLike { id: inserted_comment_like.id, @@ -165,12 +161,12 @@ mod tests { 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); + let read_comment = Comment::read(&conn, inserted_comment.id).unwrap(); + let updated_comment = Comment::update(&conn, inserted_comment.id, &comment_form).unwrap(); + let like_removed = CommentLike::remove(&conn, &comment_like_form).unwrap(); + let num_deleted = Comment::delete(&conn, inserted_comment.id).unwrap(); + Comment::delete(&conn, inserted_child_comment.id).unwrap(); + Post::delete(&conn, inserted_post.id).unwrap(); assert_eq!(expected_comment, read_comment); assert_eq!(expected_comment, inserted_comment); diff --git a/server/src/actions/community.rs b/server/src/actions/community.rs index 03490369..44d7b749 100644 --- a/server/src/actions/community.rs +++ b/server/src/actions/community.rs @@ -2,9 +2,10 @@ extern crate diesel; use schema::{community, community_user, community_follower}; use diesel::*; use diesel::result::Error; +use serde::{Deserialize, Serialize}; use {Crud, Followable, Joinable}; -#[derive(Queryable, Identifiable, PartialEq, Debug)] +#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] #[table_name="community"] pub struct Community { pub id: i32, @@ -13,11 +14,11 @@ pub struct Community { pub updated: Option<chrono::NaiveDateTime> } -#[derive(Insertable, AsChangeset, Clone, Copy)] +#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)] #[table_name="community"] -pub struct CommunityForm<'a> { - pub name: &'a str, - pub updated: Option<&'a chrono::NaiveDateTime> +pub struct CommunityForm { + pub name: String, + pub updated: Option<chrono::NaiveDateTime> } #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] @@ -30,11 +31,11 @@ pub struct CommunityUser { pub published: chrono::NaiveDateTime, } -#[derive(Insertable, AsChangeset, Clone, Copy)] +#[derive(Insertable, AsChangeset, Clone)] #[table_name="community_user"] -pub struct CommunityUserForm<'a> { - pub community_id: &'a i32, - pub fedi_user_id: &'a str, +pub struct CommunityUserForm { + pub community_id: i32, + pub fedi_user_id: String, } #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] @@ -47,76 +48,72 @@ pub struct CommunityFollower { pub published: chrono::NaiveDateTime, } -#[derive(Insertable, AsChangeset, Clone, Copy)] +#[derive(Insertable, AsChangeset, Clone)] #[table_name="community_follower"] -pub struct CommunityFollowerForm<'a> { - pub community_id: &'a i32, - pub fedi_user_id: &'a str, +pub struct CommunityFollowerForm { + pub community_id: i32, + pub fedi_user_id: String, } -impl<'a> Crud<CommunityForm<'a>> for Community { - fn read(conn: &PgConnection, community_id: i32) -> Community { +impl Crud<CommunityForm> for Community { + fn read(conn: &PgConnection, community_id: i32) -> Result<Self, Error> { use schema::community::dsl::*; community.find(community_id) - .first::<Community>(conn) - .expect("Error in query") + .first::<Self>(conn) } - fn delete(conn: &PgConnection, community_id: i32) -> usize { + fn delete(conn: &PgConnection, community_id: i32) -> Result<usize, Error> { use schema::community::dsl::*; diesel::delete(community.find(community_id)) .execute(conn) - .expect("Error deleting.") } - fn create(conn: &PgConnection, new_community: CommunityForm) -> Result<Community, Error> { + fn create(conn: &PgConnection, new_community: &CommunityForm) -> Result<Self, Error> { use schema::community::dsl::*; insert_into(community) .values(new_community) - .get_result::<Community>(conn) + .get_result::<Self>(conn) } - fn update(conn: &PgConnection, community_id: i32, new_community: CommunityForm) -> Community { + fn update(conn: &PgConnection, community_id: i32, new_community: &CommunityForm) -> Result<Self, Error> { use schema::community::dsl::*; diesel::update(community.find(community_id)) .set(new_community) - .get_result::<Community>(conn) - .expect(&format!("Unable to find {}", community_id)) + .get_result::<Self>(conn) } } -impl<'a> Followable<CommunityFollowerForm<'a>> for CommunityFollower { - fn follow(conn: &PgConnection, community_follower_form: CommunityFollowerForm) -> Result<CommunityFollower, Error> { +impl Followable<CommunityFollowerForm> for CommunityFollower { + fn follow(conn: &PgConnection, community_follower_form: &CommunityFollowerForm) -> Result<Self, Error> { use schema::community_follower::dsl::*; insert_into(community_follower) .values(community_follower_form) - .get_result::<CommunityFollower>(conn) + .get_result::<Self>(conn) } - fn ignore(conn: &PgConnection, community_follower_form: CommunityFollowerForm) -> usize { + fn ignore(conn: &PgConnection, community_follower_form: &CommunityFollowerForm) -> Result<usize, Error> { use schema::community_follower::dsl::*; diesel::delete(community_follower - .filter(community_id.eq(community_follower_form.community_id)) - .filter(fedi_user_id.eq(community_follower_form.fedi_user_id))) + .filter(community_id.eq(&community_follower_form.community_id)) + .filter(fedi_user_id.eq(&community_follower_form.fedi_user_id))) .execute(conn) - .expect("Error deleting.") } } -impl<'a> Joinable<CommunityUserForm<'a>> for CommunityUser { - fn join(conn: &PgConnection, community_user_form: CommunityUserForm) -> Result<CommunityUser, Error> { +impl Joinable<CommunityUserForm> for CommunityUser { + fn join(conn: &PgConnection, community_user_form: &CommunityUserForm) -> Result<Self, Error> { use schema::community_user::dsl::*; insert_into(community_user) .values(community_user_form) - .get_result::<CommunityUser>(conn) + .get_result::<Self>(conn) } - fn leave(conn: &PgConnection, community_user_form: CommunityUserForm) -> usize { + + fn leave(conn: &PgConnection, community_user_form: &CommunityUserForm) -> Result<usize, Error> { use schema::community_user::dsl::*; diesel::delete(community_user .filter(community_id.eq(community_user_form.community_id)) - .filter(fedi_user_id.eq(community_user_form.fedi_user_id))) + .filter(fedi_user_id.eq(&community_user_form.fedi_user_id))) .execute(conn) - .expect("Error deleting.") } } @@ -135,7 +132,7 @@ mod tests { updated: None }; - let inserted_community = Community::create(&conn, new_community).unwrap(); + let inserted_community = Community::create(&conn, &new_community).unwrap(); let expected_community = Community { id: inserted_community.id, @@ -145,21 +142,21 @@ mod tests { }; let new_user = UserForm { - name: "thom".into(), + name: "terry".into(), preferred_username: None, password_encrypted: "nope".into(), email: None, updated: None }; - let inserted_user = User_::create(&conn, new_user).unwrap(); + let inserted_user = User_::create(&conn, &new_user).unwrap(); let community_follower_form = CommunityFollowerForm { - community_id: &inserted_community.id, + community_id: inserted_community.id, fedi_user_id: "test".into() }; - let inserted_community_follower = CommunityFollower::follow(&conn, community_follower_form).unwrap(); + let inserted_community_follower = CommunityFollower::follow(&conn, &community_follower_form).unwrap(); let expected_community_follower = CommunityFollower { id: inserted_community_follower.id, @@ -169,11 +166,11 @@ mod tests { }; let community_user_form = CommunityUserForm { - community_id: &inserted_community.id, + community_id: inserted_community.id, fedi_user_id: "test".into() }; - let inserted_community_user = CommunityUser::join(&conn, community_user_form).unwrap(); + let inserted_community_user = CommunityUser::join(&conn, &community_user_form).unwrap(); let expected_community_user = CommunityUser { id: inserted_community_user.id, @@ -182,12 +179,12 @@ mod tests { published: inserted_community_user.published }; - let read_community = Community::read(&conn, inserted_community.id); - let updated_community = Community::update(&conn, inserted_community.id, new_community); - let ignored_community = CommunityFollower::ignore(&conn, community_follower_form); - let left_community = CommunityUser::leave(&conn, community_user_form); - let num_deleted = Community::delete(&conn, inserted_community.id); - User_::delete(&conn, inserted_user.id); + let read_community = Community::read(&conn, inserted_community.id).unwrap(); + let updated_community = Community::update(&conn, inserted_community.id, &new_community).unwrap(); + let ignored_community = CommunityFollower::ignore(&conn, &community_follower_form).unwrap(); + let left_community = CommunityUser::leave(&conn, &community_user_form).unwrap(); + let num_deleted = Community::delete(&conn, inserted_community.id).unwrap(); + User_::delete(&conn, inserted_user.id).unwrap(); assert_eq!(expected_community, read_community); assert_eq!(expected_community, inserted_community); diff --git a/server/src/actions/post.rs b/server/src/actions/post.rs index dd80f582..889fcf03 100644 --- a/server/src/actions/post.rs +++ b/server/src/actions/post.rs @@ -15,13 +15,13 @@ pub struct Post { pub updated: Option<chrono::NaiveDateTime> } -#[derive(Insertable, AsChangeset, Clone, Copy)] +#[derive(Insertable, AsChangeset, Clone)] #[table_name="post"] -pub struct PostForm<'a> { - pub name: &'a str, - pub url: &'a str, - pub attributed_to: &'a str, - pub updated: Option<&'a chrono::NaiveDateTime> +pub struct PostForm { + pub name: String, + pub url: String, + pub attributed_to: String, + pub updated: Option<chrono::NaiveDateTime> } #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] @@ -35,59 +35,55 @@ pub struct PostLike { pub published: chrono::NaiveDateTime, } -#[derive(Insertable, AsChangeset, Clone, Copy)] +#[derive(Insertable, AsChangeset, Clone)] #[table_name="post_like"] -pub struct PostLikeForm<'a> { - pub post_id: &'a i32, - pub fedi_user_id: &'a str, - pub score: &'a i16 +pub struct PostLikeForm { + pub post_id: i32, + pub fedi_user_id: String, + pub score: i16 } -impl<'a> Crud<PostForm<'a>> for Post { - fn read(conn: &PgConnection, post_id: i32) -> Post { +impl Crud<PostForm> for Post { + fn read(conn: &PgConnection, post_id: i32) -> Result<Self, Error> { use schema::post::dsl::*; post.find(post_id) - .first::<Post>(conn) - .expect("Error in query") + .first::<Self>(conn) } - fn delete(conn: &PgConnection, post_id: i32) -> usize { + fn delete(conn: &PgConnection, post_id: i32) -> Result<usize, Error> { use schema::post::dsl::*; diesel::delete(post.find(post_id)) .execute(conn) - .expect("Error deleting.") } - fn create(conn: &PgConnection, new_post: PostForm) -> Result<Post, Error> { + fn create(conn: &PgConnection, new_post: &PostForm) -> Result<Self, Error> { use schema::post::dsl::*; insert_into(post) .values(new_post) - .get_result::<Post>(conn) + .get_result::<Self>(conn) } - fn update(conn: &PgConnection, post_id: i32, new_post: PostForm) -> Post { + fn update(conn: &PgConnection, post_id: i32, new_post: &PostForm) -> Result<Self, Error> { use schema::post::dsl::*; diesel::update(post.find(post_id)) .set(new_post) - .get_result::<Post>(conn) - .expect(&format!("Unable to find {}", post_id)) + .get_result::<Self>(conn) } } -impl<'a> Likeable <PostLikeForm<'a>> for PostLike { - fn like(conn: &PgConnection, post_like_form: PostLikeForm) -> Result<PostLike, Error> { +impl Likeable <PostLikeForm> for PostLike { + fn like(conn: &PgConnection, post_like_form: &PostLikeForm) -> Result<Self, Error> { use schema::post_like::dsl::*; insert_into(post_like) .values(post_like_form) - .get_result::<PostLike>(conn) + .get_result::<Self>(conn) } - fn remove(conn: &PgConnection, post_like_form: PostLikeForm) -> usize { + fn remove(conn: &PgConnection, post_like_form: &PostLikeForm) -> Result<usize, Error> { use schema::post_like::dsl::*; diesel::delete(post_like .filter(post_id.eq(post_like_form.post_id)) - .filter(fedi_user_id.eq(post_like_form.fedi_user_id))) + .filter(fedi_user_id.eq(&post_like_form.fedi_user_id))) .execute(conn) - .expect("Error deleting.") } } @@ -107,7 +103,7 @@ mod tests { updated: None }; - let inserted_post = Post::create(&conn, new_post).unwrap(); + let inserted_post = Post::create(&conn, &new_post).unwrap(); let expected_post = Post { id: inserted_post.id, @@ -119,12 +115,12 @@ mod tests { }; let post_like_form = PostLikeForm { - post_id: &inserted_post.id, + post_id: inserted_post.id, fedi_user_id: "test".into(), - score: &1 + score: 1 }; - let inserted_post_like = PostLike::like(&conn, post_like_form).unwrap(); + let inserted_post_like = PostLike::like(&conn, &post_like_form).unwrap(); let expected_post_like = PostLike { id: inserted_post_like.id, @@ -134,10 +130,10 @@ mod tests { score: 1 }; - let read_post = Post::read(&conn, inserted_post.id); - let updated_post = Post::update(&conn, inserted_post.id, new_post); - let like_removed = PostLike::remove(&conn, post_like_form); - let num_deleted = Post::delete(&conn, inserted_post.id); + let read_post = Post::read(&conn, inserted_post.id).unwrap(); + let updated_post = Post::update(&conn, inserted_post.id, &new_post).unwrap(); + let like_removed = PostLike::remove(&conn, &post_like_form).unwrap(); + let num_deleted = Post::delete(&conn, inserted_post.id).unwrap(); assert_eq!(expected_post, read_post); assert_eq!(expected_post, inserted_post); diff --git a/server/src/actions/user.rs b/server/src/actions/user.rs index 8556525f..6016580d 100644 --- a/server/src/actions/user.rs +++ b/server/src/actions/user.rs @@ -1,9 +1,11 @@ -extern crate diesel; use schema::user_; use diesel::*; use diesel::result::Error; use schema::user_::dsl::*; -use Crud; +use serde::{Serialize, Deserialize}; +use {Crud,is_email_regex}; +use jsonwebtoken::{encode, decode, Header, Validation}; +use bcrypt::{DEFAULT_COST, hash}; #[derive(Queryable, Identifiable, PartialEq, Debug)] #[table_name="user_"] @@ -18,43 +20,75 @@ pub struct User_ { pub updated: Option<chrono::NaiveDateTime> } -#[derive(Insertable, AsChangeset, Clone, Copy)] +#[derive(Insertable, AsChangeset, Clone)] #[table_name="user_"] -pub struct UserForm<'a> { - pub name: &'a str, - pub preferred_username: Option<&'a str>, - pub password_encrypted: &'a str, - pub email: Option<&'a str>, - pub updated: Option<&'a chrono::NaiveDateTime> +pub struct UserForm { + pub name: String, + pub preferred_username: Option<String>, + pub password_encrypted: String, + pub email: Option<String>, + pub updated: Option<chrono::NaiveDateTime> } -impl<'a> Crud<UserForm<'a>> for User_ { - fn read(conn: &PgConnection, user_id: i32) -> User_ { +impl Crud<UserForm> for User_ { + fn read(conn: &PgConnection, user_id: i32) -> Result<Self, Error> { user_.find(user_id) - .first::<User_>(conn) - .expect("Error in query") + .first::<Self>(conn) } - fn delete(conn: &PgConnection, user_id: i32) -> usize { + fn delete(conn: &PgConnection, user_id: i32) -> Result<usize, Error> { diesel::delete(user_.find(user_id)) .execute(conn) - .expect("Error deleting.") } - fn create(conn: &PgConnection, form: UserForm) -> Result<User_, Error> { + fn create(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> { let mut edited_user = form.clone(); - // Add the rust crypt - edited_user.password_encrypted = "here"; - // edited_user.password_encrypted; - insert_into(user_) - .values(edited_user) - .get_result::<User_>(conn) + let password_hash = hash(&form.password_encrypted, DEFAULT_COST) + .expect("Couldn't hash password"); + edited_user.password_encrypted = password_hash; + insert_into(user_) + .values(edited_user) + .get_result::<Self>(conn) } - fn update(conn: &PgConnection, user_id: i32, form: UserForm) -> User_ { + fn update(conn: &PgConnection, user_id: i32, form: &UserForm) -> Result<Self, Error> { let mut edited_user = form.clone(); - edited_user.password_encrypted = "here"; + let password_hash = hash(&form.password_encrypted, DEFAULT_COST) + .expect("Couldn't hash password"); + edited_user.password_encrypted = password_hash; diesel::update(user_.find(user_id)) .set(edited_user) - .get_result::<User_>(conn) - .expect(&format!("Unable to find user {}", user_id)) + .get_result::<Self>(conn) + } +} + +#[derive(Debug, Serialize, Deserialize)] +struct Claims { + id: i32, + username: String +} + +type Jwt = String; +impl User_ { + pub fn jwt(&self) -> Jwt { + let my_claims = Claims { + id: self.id, + username: self.name.to_owned() + }; + encode(&Header::default(), &my_claims, "secret".as_ref()).unwrap() + } + + pub fn find_by_email_or_username(conn: &PgConnection, username_or_email: &str) -> Result<Self, Error> { + if is_email_regex(username_or_email) { + user_.filter(email.eq(username_or_email)) + .first::<User_>(conn) + } else { + user_.filter(name.eq(username_or_email)) + .first::<User_>(conn) + } + } + + pub fn find_by_jwt(conn: &PgConnection, jwt: &str) -> Result<Self, Error> { + let token = decode::<Claims>(&jwt, "secret".as_ref(), &Validation::default()) + .expect("Couldn't decode jwt"); + Self::read(&conn, token.claims.id) } } @@ -75,26 +109,26 @@ mod tests { updated: None }; - let inserted_user = User_::create(&conn, new_user).unwrap(); + let inserted_user = User_::create(&conn, &new_user).unwrap(); let expected_user = User_ { id: inserted_user.id, name: "thom".into(), preferred_username: None, - password_encrypted: "here".into(), + password_encrypted: "$2y$12$YXpNpYsdfjmed.QlYLvw4OfTCgyKUnKHc/V8Dgcf9YcVKHPaYXYYy".into(), email: None, icon: None, published: inserted_user.published, updated: None }; - let read_user = User_::read(&conn, inserted_user.id); - let updated_user = User_::update(&conn, inserted_user.id, new_user); - let num_de |