diff --git a/migrations/2023-08-23-142552_channels/up.sql b/migrations/2023-08-23-142552_channels/up.sql index f9c344c..3b68dd3 100644 --- a/migrations/2023-08-23-142552_channels/up.sql +++ b/migrations/2023-08-23-142552_channels/up.sql @@ -3,6 +3,6 @@ CREATE TABLE channels ( id BIGINT NOT NULL AUTO_INCREMENT, user BIGINT NOT NULL, name VARCHAR(255) NOT NULL, - Bio text, + bio text, PRIMARY KEY(id) ) diff --git a/migrations/2023-08-27-161051_subscription/down.sql b/migrations/2023-08-27-161051_subscription/down.sql new file mode 100644 index 0000000..3acec15 --- /dev/null +++ b/migrations/2023-08-27-161051_subscription/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +DROP TABLE subscription; diff --git a/migrations/2023-08-27-161051_subscription/up.sql b/migrations/2023-08-27-161051_subscription/up.sql new file mode 100644 index 0000000..007d49d --- /dev/null +++ b/migrations/2023-08-27-161051_subscription/up.sql @@ -0,0 +1,8 @@ +-- Your SQL goes here +CREATE TABLE subscription ( + subscription_id BIGINT AUTO_INCREMENT NOT NULL , + user_id BIGINT NOT NULL, + channel_id BIGINT NOT NULL, + PRIMARY KEY(subscription_id), + CONSTRAINT UC_Sub UNIQUE(user_id,channel_id) +); diff --git a/src/lib.rs b/src/lib.rs index 479c73e..f498564 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,9 +19,10 @@ use crypto::digest::Digest; use crypto::sha2::Sha256; use rand::{thread_rng, Rng}; -pub enum UserCreationStatus { +pub enum CreationStatus { Success, - UserExists, + ElementExists, + Unauthorized, QueryError(Error), DatabaseError(DatabaseErrorKind), } @@ -30,7 +31,7 @@ pub enum UserSelectionStatus { Success(T), UserDoesntExist, QueryError(Error), - DatabaseError(DatabaseErrorKind) + DatabaseError(DatabaseErrorKind), } pub fn create_connection() -> MysqlConnection { @@ -40,23 +41,27 @@ pub fn create_connection() -> MysqlConnection { MysqlConnection::establish(&database_url).unwrap() } -pub fn get_id_from_email(user_email: String, connection: &mut MysqlConnection) -> UserSelectionStatus { +pub fn get_id_from_email( + user_email: String, + connection: &mut MysqlConnection, +) -> UserSelectionStatus { use schema::users::dsl::*; - + let users_matching_email = match users .filter(email.eq(user_email)) .limit(1) .select(User::as_select()) - .load(connection) { + .load(connection) + { Ok(v) => v, - Err(_e) => vec![] + Err(e) => return UserSelectionStatus::QueryError(e), }; let user = match users_matching_email.get(0) { Some(v) => v, - None => return UserSelectionStatus::UserDoesntExist + None => return UserSelectionStatus::UserDoesntExist, }; - + UserSelectionStatus::Success(user.id) } @@ -65,21 +70,26 @@ pub fn check_password( password: String, connection: &mut MysqlConnection, ) -> UserSelectionStatus { - use self::schema::users::dsl::*; let users_matching = match users .filter(id.eq(user_id)) .limit(1) .select(User::as_select()) - .load(connection) { + .load(connection) + { Ok(v) => v, - Err(_e) => vec![] + Err(error) => match error { + Error::DatabaseError(error_kind, _) => { + return UserSelectionStatus::DatabaseError(error_kind) + } + _ => return UserSelectionStatus::QueryError(error), + }, }; let user = match users_matching.get(0) { Some(v) => v, - None => return UserSelectionStatus::UserDoesntExist + None => return UserSelectionStatus::UserDoesntExist, }; let mut hasher = Sha256::new(); @@ -90,12 +100,48 @@ pub fn check_password( UserSelectionStatus::Success(user.pass == hashed) } +pub fn subscribe( + user_id: i64, + channel_id: i64, + password: String, + connection: &mut MysqlConnection, +) -> CreationStatus { + match check_password(user_id, password, connection) { + UserSelectionStatus::Success(b) => match b { + true => (), + false => return CreationStatus::Unauthorized, + }, + UserSelectionStatus::UserDoesntExist => return CreationStatus::Unauthorized, + UserSelectionStatus::QueryError(e) => return CreationStatus::QueryError(e), + UserSelectionStatus::DatabaseError(e) => return CreationStatus::DatabaseError(e), + }; + + let new_subscription = model::NewSubscription { + user_id, + channel_id, + }; + + match diesel::insert_into(schema::subscription::dsl::subscription) + .values(&new_subscription) + .execute(connection) + { + Ok(_) => CreationStatus::Success, + Err(e) => match e { + Error::DatabaseError(database_error_kind, _) => match database_error_kind { + DatabaseErrorKind::UniqueViolation => CreationStatus::ElementExists, + _ => CreationStatus::DatabaseError(database_error_kind), + }, + _ => CreationStatus::QueryError(e), + }, + } +} + pub fn add_user( username: String, email: String, password: String, connection: &mut MysqlConnection, -) -> UserCreationStatus { +) -> CreationStatus { use schema::users::dsl::users; let joined = OffsetDateTime::now_utc().date(); @@ -130,13 +176,13 @@ pub fn add_user( .values(&new_user) .execute(connection) { - Ok(_) => UserCreationStatus::Success, + Ok(_) => CreationStatus::Success, Err(e) => match e { Error::DatabaseError(database_error_kind, _) => match database_error_kind { - DatabaseErrorKind::UniqueViolation => UserCreationStatus::UserExists, - _ => UserCreationStatus::DatabaseError(database_error_kind), + DatabaseErrorKind::UniqueViolation => CreationStatus::ElementExists, + _ => CreationStatus::DatabaseError(database_error_kind), }, - _ => UserCreationStatus::QueryError(e), + _ => CreationStatus::QueryError(e), }, } } diff --git a/src/model.rs b/src/model.rs index da8738e..9125ee2 100644 --- a/src/model.rs +++ b/src/model.rs @@ -14,6 +14,7 @@ pub struct User { #[derive(Insertable)] #[diesel(table_name = crate::schema::users)] +#[diesel(check_for_backend(diesel::mysql::Mysql))] pub struct NewUser { pub username: String, pub email: String, @@ -21,3 +22,39 @@ pub struct NewUser { pub pass: String, pub joined: Date, } + +#[derive(Queryable, Selectable)] +#[diesel(table_name = crate::schema::channels)] +#[diesel(check_for_backend(diesel::mysql::Mysql))] +pub struct Channel { + pub id: i64, + pub user: i64, + pub name: String, + pub bio: Option, +} + +#[derive(Insertable)] +#[diesel(table_name = crate::schema::channels)] +#[diesel(check_for_backend(diesel::mysql::Mysql))] +pub struct NewChannel { + pub user: i64, + pub name: String, + pub bio: Option, +} + +#[derive(Queryable, Selectable)] +#[diesel(table_name = crate::schema::subscription)] +#[diesel(check_for_backend(diesel::mysql::Mysql))] +pub struct Subscription { + pub subscription_id: i64, + pub user_id: i64, + pub channel_id: i64, +} + +#[derive(Insertable)] +#[diesel(table_name = crate::schema::subscription)] +#[diesel(check_for_backend(diesel::mysql::Mysql))] +pub struct NewSubscription { + pub user_id: i64, + pub channel_id: i64, +} diff --git a/src/schema.rs b/src/schema.rs index c0442b0..70bc4b0 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -6,7 +6,15 @@ diesel::table! { user -> Bigint, #[max_length = 255] name -> Varchar, - Bio -> Nullable, + bio -> Nullable, + } +} + +diesel::table! { + subscription (subscription_id) { + subscription_id -> Bigint, + user_id -> Bigint, + channel_id -> Bigint, } } @@ -25,4 +33,4 @@ diesel::table! { } } -diesel::allow_tables_to_appear_in_same_query!(channels, users,); +diesel::allow_tables_to_appear_in_same_query!(channels, subscription, users,);