Explorar o código

Create the signal route no device access yet

Lee Morgan hai 2 meses
pai
achega
c58b9a5157

+ 1 - 0
src/controllers/device/mod.rs

@@ -1,2 +1,3 @@
 pub mod create;
 pub mod delete;
+pub mod signal;

+ 45 - 0
src/controllers/device/signal.rs

@@ -0,0 +1,45 @@
+use actix_web::{HttpResponse, HttpRequest, web, post};
+use serde::Deserialize;
+use sqlx::PgPool;
+use uuid::Uuid;
+use serde_json::json;
+use crate::{
+    auth::user_auth,
+    app_error::AppError,
+    models::device::{Device, DeviceType}
+};
+
+#[derive(Deserialize)]
+struct Body {
+    signal: String
+}
+
+#[derive(Deserialize)]
+struct Params {
+    home_id: String,
+    device_id: String
+}
+
+#[post("/home/{home_id}/device/{device_id}/signal")]
+pub async fn route(
+    db: web::Data<PgPool>,
+    body: web::Json<Body>,
+    params: web::Path<Params>,
+    req: HttpRequest
+) -> Result<HttpResponse, AppError> {
+    let user = user_auth(&db, &req).await?;
+    let home_id = Uuid::parse_str(&params.home_id)?;
+    let device_id = Uuid::parse_str(&params.device_id)?;
+    let device = Device::find_one(&db, user.id, home_id, device_id).await?;
+    validate_signal(&device.device_type, &body.signal)?;
+    Ok(HttpResponse::Ok().json(json!({"success": true})))
+}
+
+fn validate_signal(device_type: &DeviceType, signal: &String) -> Result<(), AppError> {
+    match device_type {
+        DeviceType::OnOffSwitch => match signal.as_str() {
+            "on" | "off" => Ok(()),
+            _ => Err(AppError::invalid_input("Invalid signal for 'on_off_switch'"))
+        }
+    }
+}

+ 33 - 7
src/models/device.rs

@@ -3,18 +3,18 @@ use serde::Serialize;
 use sqlx::{PgPool, postgres::PgQueryResult};
 use crate::app_error::AppError;
 
-#[derive(Serialize)]
+#[derive(Serialize, sqlx::FromRow)]
 pub struct Device {
-    id: Uuid,
-    home_id: Uuid,
-    name: String,
-    description: Option<String>,
-    device_type: DeviceType
+    pub id: Uuid,
+    pub home_id: Uuid,
+    pub name: String,
+    pub description: Option<String>,
+    pub device_type: DeviceType
 }
 
 #[derive(Serialize, sqlx::Type)]
 #[sqlx(type_name = "device_type", rename_all = "snake_case")]
-enum DeviceType {
+pub enum DeviceType {
     OnOffSwitch
 }
 
@@ -100,4 +100,30 @@ impl Device {
 
         Ok(())
     }
+
+    pub async fn find_one(
+        db: &PgPool,
+        user_id: Uuid,
+        home_id: Uuid,
+        device_id: Uuid,
+    ) -> Result<Device, AppError> {
+        let device = sqlx::query_as::<_, Device>(
+            "SELECT devices.*
+            FROM devices
+            JOIN users_homes ON users_homes.home_id = devices.home_id
+            WHERE devices.id = $1
+                AND devices.home_id = $2
+                AND users_homes.user_id = $3"
+        )
+            .bind(device_id)
+            .bind(home_id)
+            .bind(user_id)
+            .fetch_optional(db)
+            .await?;
+
+        match device {
+            Some(d) => Ok(d),
+            None => Err(AppError::forbidden("Unauthorized access to device"))
+        }
+    }
 }

+ 3 - 1
src/routes/device.rs

@@ -1,10 +1,12 @@
 use actix_web::web;
 use crate::controllers::device::{
     create,
-    delete
+    delete,
+    signal
 };
 
 pub fn config(cfg: &mut web::ServiceConfig) {
     cfg.service(create::route);
     cfg.service(delete::route);
+    cfg.service(signal::route);
 }