device.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. use uuid::Uuid;
  2. use serde::Serialize;
  3. use sqlx::{PgPool, postgres::PgQueryResult};
  4. use crate::app_error::AppError;
  5. #[derive(Serialize, sqlx::FromRow)]
  6. pub struct Device {
  7. pub id: Uuid,
  8. pub home_id: Uuid,
  9. pub name: String,
  10. pub description: Option<String>,
  11. pub device_type: DeviceType
  12. }
  13. #[derive(Serialize, sqlx::Type)]
  14. #[sqlx(type_name = "device_type", rename_all = "snake_case")]
  15. pub enum DeviceType {
  16. OnOffSwitch
  17. }
  18. impl Device {
  19. pub fn new(
  20. home_id: Uuid,
  21. name: String,
  22. description: Option<String>,
  23. device_type: String
  24. ) -> Result<Self, AppError> {
  25. Ok(Self {
  26. id: Uuid::now_v7(),
  27. home_id: home_id,
  28. name: name,
  29. description: description,
  30. device_type: match device_type.as_str() {
  31. "on_off_switch" => DeviceType::OnOffSwitch,
  32. _ => {return Err(AppError::invalid_input("Invalid device type"))}
  33. }
  34. })
  35. }
  36. pub async fn insert(
  37. &self,
  38. db: &PgPool,
  39. user_id: Uuid,
  40. home_id: Uuid
  41. ) -> Result<(), AppError> {
  42. let result: PgQueryResult = sqlx::query!(
  43. "INSERT INTO devices (id, home_id, name, description, device_type)
  44. SELECT $1, $2, $3, $4, $5
  45. WHERE EXISTS (
  46. SELECT 1
  47. FROM users_homes
  48. WHERE user_id = $6
  49. AND home_id = $2
  50. AND is_admin = true
  51. )",
  52. self.id,
  53. home_id,
  54. self.name,
  55. self.description,
  56. &self.device_type as &DeviceType,
  57. user_id
  58. )
  59. .execute(db)
  60. .await?;
  61. if result.rows_affected() == 0 {
  62. return Err(AppError::forbidden("Unauthorized access to home"));
  63. }
  64. Ok(())
  65. }
  66. pub async fn delete(
  67. db: &PgPool,
  68. user_id: Uuid,
  69. home_id: Uuid,
  70. device_id: Uuid
  71. ) -> Result<(), AppError> {
  72. let result = sqlx::query!(
  73. "DELETE FROM devices
  74. WHERE id = $1
  75. AND home_id = $2
  76. AND EXISTS (
  77. SELECT 1
  78. FROM users_homes
  79. WHERE user_id = $3
  80. AND home_id = $2
  81. AND is_admin = true
  82. );",
  83. device_id,
  84. home_id,
  85. user_id
  86. )
  87. .execute(db)
  88. .await?;
  89. if result.rows_affected() == 0 {
  90. return Err(AppError::forbidden("Unauthorized access to device"));
  91. }
  92. Ok(())
  93. }
  94. pub async fn find_one(
  95. db: &PgPool,
  96. user_id: Uuid,
  97. home_id: Uuid,
  98. device_id: Uuid,
  99. ) -> Result<Device, AppError> {
  100. let device = sqlx::query_as::<_, Device>(
  101. "SELECT devices.*
  102. FROM devices
  103. JOIN users_homes ON users_homes.home_id = devices.home_id
  104. WHERE devices.id = $1
  105. AND devices.home_id = $2
  106. AND users_homes.user_id = $3"
  107. )
  108. .bind(device_id)
  109. .bind(home_id)
  110. .bind(user_id)
  111. .fetch_optional(db)
  112. .await?;
  113. match device {
  114. Some(d) => Ok(d),
  115. None => Err(AppError::forbidden("Unauthorized access to device"))
  116. }
  117. }
  118. }