You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
4.0 KiB

  1. use diesel::prelude::*;
  2. use crate::models::{self, Pagination, UserId, Username};
  3. use crate::{errors, models::Password};
  4. use bcrypt::{hash, verify, DEFAULT_COST};
  5. use validators::prelude::*;
  6. pub fn find_user_by_uid(
  7. uid: &UserId,
  8. conn: &impl diesel::Connection<Backend = diesel::sqlite::Sqlite>,
  9. ) -> Result<Option<models::User>, errors::DomainError> {
  10. use crate::schema::users::dsl::*;
  11. let maybe_user = users
  12. .select(users::all_columns())
  13. .find(uid)
  14. .first::<models::User>(conn)
  15. .optional();
  16. Ok(maybe_user?)
  17. }
  18. pub fn _find_user_by_name(
  19. user_name: Username,
  20. conn: &impl diesel::Connection<Backend = diesel::sqlite::Sqlite>,
  21. ) -> Result<Option<models::User>, errors::DomainError> {
  22. use crate::schema::users::dsl::*;
  23. let maybe_user = query::_get_user_by_name()
  24. .filter(name.eq(user_name))
  25. .first::<models::User>(conn)
  26. .optional();
  27. Ok(maybe_user?)
  28. }
  29. // def findAll(userId: Long, limit: Int, offset: Int) = db.run {
  30. // for {
  31. // comments <- query.filter(_.creatorId === userId)
  32. // .sortBy(_.createdAt)
  33. // .drop(offset).take(limit)
  34. // .result
  35. // numberOfComments <- query.filter(_.creatorId === userId).length.result
  36. // } yield PaginatedResult(
  37. // totalCount = numberOfComments,
  38. // entities = comments.toList,
  39. // hasNextPage = numberOfComments - (offset + limit) > 0
  40. // )
  41. // }
  42. pub fn get_all_users(
  43. pagination: &Pagination,
  44. conn: &impl diesel::Connection<Backend = diesel::sqlite::Sqlite>,
  45. ) -> Result<Vec<models::User>, errors::DomainError> {
  46. Ok(query::_paginate_result(&pagination).load::<models::User>(conn)?)
  47. }
  48. pub fn search_users(
  49. query: &str,
  50. pagination: &Pagination,
  51. conn: &impl diesel::Connection<Backend = diesel::sqlite::Sqlite>,
  52. ) -> Result<Vec<models::User>, errors::DomainError> {
  53. use crate::schema::users::dsl::*;
  54. Ok(query::_paginate_result(&pagination)
  55. .filter(name.like(format!("%{}%", query)))
  56. .load::<models::User>(conn)?)
  57. }
  58. pub fn insert_new_user(
  59. nu: models::NewUser,
  60. conn: &impl diesel::Connection<Backend = diesel::sqlite::Sqlite>,
  61. hash_cost: Option<u32>,
  62. ) -> Result<models::User, errors::DomainError> {
  63. use crate::schema::users::dsl::*;
  64. let nu = {
  65. let mut nu2 = nu;
  66. let hash =
  67. hash(&nu2.password.as_str(), hash_cost.unwrap_or(DEFAULT_COST))?;
  68. nu2.password = Password::parse_string(hash).map_err(|err| {
  69. errors::DomainError::new_field_validation_error(err.to_string())
  70. })?;
  71. nu2
  72. };
  73. diesel::insert_into(users).values(&nu).execute(conn)?;
  74. let user = query::_get_user_by_name()
  75. .filter(name.eq(nu.name.as_str()))
  76. .first::<models::User>(conn)?;
  77. Ok(user)
  78. }
  79. //TODO: Add newtype here
  80. pub fn verify_password(
  81. user_name: &str,
  82. given_password: &str,
  83. conn: &impl diesel::Connection<Backend = diesel::sqlite::Sqlite>,
  84. ) -> Result<bool, errors::DomainError> {
  85. use crate::schema::users::dsl::*;
  86. let password_hash = users
  87. .select(password)
  88. .filter(name.eq(user_name))
  89. .first::<String>(conn)?;
  90. Ok(verify(given_password, password_hash.as_str())?)
  91. }
  92. mod query {
  93. use super::*;
  94. use diesel::sql_types::Integer;
  95. use diesel::sql_types::Text;
  96. use diesel::sql_types::Timestamp;
  97. use diesel::sqlite::Sqlite;
  98. /// <'a, B, T> where a = lifetime, B = Backend, T = SQL data types
  99. type Query<'a, B, T> = crate::schema::users::BoxedQuery<'a, B, T>;
  100. pub fn _get_user_by_name(
  101. ) -> Query<'static, Sqlite, (Integer, Text, Text, Timestamp)> {
  102. use crate::schema::users::dsl::*;
  103. users.into_boxed()
  104. }
  105. pub fn _paginate_result(
  106. pagination: &Pagination,
  107. ) -> Query<'static, Sqlite, (Integer, Text, Text, Timestamp)> {
  108. use crate::schema::users::dsl::*;
  109. users
  110. .order_by(created_at)
  111. .offset(pagination.calc_offset().as_uint().into())
  112. .limit(pagination.limit.as_uint().into())
  113. .into_boxed()
  114. }
  115. }