bitque/actors/database-actor/src/users.rs

232 lines
6.2 KiB
Rust
Raw Normal View History

use {
2020-12-24 16:24:47 +01:00
crate::{
db_create, db_create_with_conn, 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_with_conn! {
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<ProjectId>,
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::<i64>(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<String>
}
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};
2020-12-24 16:24:47 +01:00
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::<Project>(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);
}
}