use { crate::{ db_create, db_find, db_load, db_update, projects::CreateProject, q, user_projects::CreateUserProject, DbPooledConn, }, diesel::prelude::*, jirs_data::{EmailString, IssueId, ProjectId, User, UserId, UserRole, UsernameString}, }; db_find! { FindUser, msg => users => users.find(msg.user_id), User, user_id => UserId } db_find! { LookupUser, msg => users => users .distinct_on(id) .filter(email.eq(msg.email.as_str())) .filter(name.eq(msg.name.as_str())), User, name => UsernameString, email => EmailString } db_load! { LoadProjectUsers, msg => users => { use crate::schema::user_projects::dsl::{project_id, user_id, user_projects}; use crate::schema::users::all_columns; users .distinct_on(id) .inner_join(user_projects.on(user_id.eq(id))) .filter(project_id.eq(msg.project_id)) .select(all_columns) }, User, project_id => ProjectId } db_load! { LoadIssueAssignees, msg => users => { use crate::schema::issue_assignees::dsl::{issue_assignees, issue_id, user_id}; users .distinct_on(id) .inner_join(issue_assignees.on(user_id.eq(id))) .filter(issue_id.eq(msg.issue_id)) .select(users::all_columns()) }, User, issue_id => IssueId } db_create! { CreateUser, msg => users => diesel::insert_into(users) .values((name.eq(msg.name.as_str()), email.eq(msg.email.as_str()))), User, name => UsernameString, email => EmailString } db_create! { Register, msg => conn => users => { if count_matching_users(msg.name.as_str(), msg.email.as_str(), conn) > 0 { return Err(crate::DatabaseError::User(crate::UserError::InvalidPair(msg.name, msg.email))); } let current_project_id: ProjectId = match msg.project_id { Some(current_project_id) => current_project_id, _ => { CreateProject { name: "initial".to_string(), url: None, description: None, category: None, time_tracking: None, } .execute(conn)? .id } }; let user: User = CreateUser { name: msg.name, email: msg.email, } .execute(conn)?; CreateUserProject { user_id: user.id, project_id: current_project_id, is_current: true, is_default: true, role: msg.role, } .execute(conn)?; users.find(user.id) }, User, name => UsernameString, email => EmailString, project_id => Option, role => UserRole } db_load! { LoadInvitedUsers, msg => users => { use crate::schema::invitations::dsl::{email as i_email, invitations, invited_by_id}; users .inner_join(invitations.on(i_email.eq(email))) .filter(invited_by_id.eq(msg.user_id)) .select(users::all_columns()) }, User, user_id => UserId } fn count_matching_users(name: &str, email: &str, conn: &DbPooledConn) -> i64 { use crate::schema::users::dsl; q!(dsl::users .filter(dsl::email.eq(email).and(dsl::name.ne(name))) .or_filter(dsl::email.ne(email).and(dsl::name.eq(name))) .or_filter(dsl::email.eq(email).and(dsl::name.eq(name))) .count()) .get_result::(conn) .unwrap_or(1) } db_update! { UpdateAvatarUrl, msg => users => diesel::update(users.find(msg.user_id)) .set(avatar_url.eq(msg.avatar_url)), User, user_id => UserId, avatar_url => Option } db_update! { ProfileUpdate, msg => users => diesel::update(users.find(msg.user_id)) .set((email.eq(msg.email), name.eq(msg.name))), User, user_id => UserId, name => String, email => String } #[cfg(test)] mod tests { use diesel::connection::TransactionManager; use jirs_data::{Project, ProjectCategory}; use crate::build_pool; use super::*; #[test] fn check_collision() { use crate::schema::projects::dsl::projects; use crate::schema::user_projects::dsl::user_projects; use crate::schema::users::dsl::users; let pool = build_pool(); let conn = &pool.get().unwrap(); let tm = conn.transaction_manager(); tm.begin_transaction(conn).unwrap(); diesel::delete(user_projects).execute(conn).unwrap(); diesel::delete(users).execute(conn).unwrap(); diesel::delete(projects).execute(conn).unwrap(); let project: Project = { use crate::schema::projects::dsl::*; diesel::insert_into(projects) .values(( name.eq("baz".to_string()), url.eq("/uz".to_string()), description.eq("None".to_string()), category.eq(ProjectCategory::Software), )) .get_result::(conn) .unwrap() }; let user: User = { use crate::schema::users::dsl::*; diesel::insert_into(users) .values(( name.eq("Foo".to_string()), email.eq("foo@example.com".to_string()), )) .get_result(conn) .unwrap() }; { use crate::schema::user_projects::dsl::*; diesel::insert_into(user_projects) .values(( user_id.eq(user.id), project_id.eq(project.id), is_current.eq(true), is_default.eq(true), )) .execute(conn) .unwrap(); } let res1 = count_matching_users("Foo", "bar@example.com", conn); let res2 = count_matching_users("Bar", "foo@example.com", conn); let res3 = count_matching_users("Foo", "foo@example.com", conn); tm.rollback_transaction(conn).unwrap(); assert_eq!(res1, 1); assert_eq!(res2, 1); assert_eq!(res3, 1); } }