Compare commits

...

3 Commits

5 changed files with 57 additions and 12 deletions

8
API/integration-tests.sh Normal file → Executable file
View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
RESPONSE=`curl -sSLX POST http://localhost:5287/api/Users -d '{"Email":"hej@example.com","Username":"Gamer","Password":"Gamer123!"}' -H 'Content-Type: application/json' -H 'Accept: */*' -w '\n%{http_code}' --output -` RESPONSE=`curl -sSLX POST http://localhost:5287/api/Users -d '{"Email":"hej@example.com","Username":"Gamer","Password":"Gamer123!"}' -H 'Content-Type: application/json' -H 'Accept: */*' -w '\n%{http_code}'`
HTTP_STATUS=`echo -n "$RESPONSE" | tail -n 1` HTTP_STATUS=`echo -n "$RESPONSE" | tail -n 1`
USER_ID=`echo "$RESPONSE" | head -n -1` USER_ID=`echo "$RESPONSE" | head -n -1`
@ -14,7 +14,7 @@ fi
echo -e " User ID: $USER_ID\n" echo -e " User ID: $USER_ID\n"
RESPONSE=`curl -sSLX POST http://localhost:5287/api/Users/login -d '{"Email":"hej@example.com","Password":"Gamer123!"}' -H 'Content-Type: application/json' -H 'Accept: */*' -w '\n%{http_code}' --output -` RESPONSE=`curl -sSLX POST http://localhost:5287/api/Users/login -d '{"Email":"hej@example.com","Password":"Gamer123!"}' -H 'Content-Type: application/json' -H 'Accept: */*' -w '\n%{http_code}'`
HTTP_STATUS=`echo -n "$RESPONSE" | tail -n 1` HTTP_STATUS=`echo -n "$RESPONSE" | tail -n 1`
TOKEN=`echo "$RESPONSE" | head -n -1` TOKEN=`echo "$RESPONSE" | head -n -1`
@ -28,7 +28,7 @@ fi
echo -e " Received token: $TOKEN\n" echo -e " Received token: $TOKEN\n"
RESPONSE=`curl -sSL http://localhost:5287/api/Users/$USER_ID -w '\n%{http_code}' -H 'Accept: */*' --output -` RESPONSE=`curl -sSL http://localhost:5287/api/Users/$USER_ID -w '\n%{http_code}' -H 'Accept: */*'`
HTTP_STATUS=`echo -n "$RESPONSE" | tail -n 1` HTTP_STATUS=`echo -n "$RESPONSE" | tail -n 1`
USER_DATA=`echo "$RESPONSE" | head -n -1` USER_DATA=`echo "$RESPONSE" | head -n -1`
@ -42,7 +42,7 @@ fi
echo -e " User data: $USER_DATA\n" echo -e " User data: $USER_DATA\n"
RESPONSE=`curl -sSLX DELETE http://localhost:5287/api/Users/$USER_ID --location-trusted -w '%{http_code}' -H "Authorization: Bearer $TOKEN" -H 'Accept: */*' --output -` RESPONSE=`curl -sSLX DELETE http://localhost:5287/api/Users/$USER_ID --location-trusted -w '%{http_code}' -H "Authorization: Bearer $TOKEN" -H 'Accept: */*'`
HTTP_STATUS=`echo -n "$RESPONSE" | tail -n 1` HTTP_STATUS=`echo -n "$RESPONSE" | tail -n 1`
echo "DELETE /api/Users/$USER_ID - $HTTP_STATUS" echo "DELETE /api/Users/$USER_ID - $HTTP_STATUS"

View File

@ -1135,6 +1135,7 @@ dependencies = [
"hmac", "hmac",
"refinery", "refinery",
"rusqlite", "rusqlite",
"serde",
"serde_json", "serde_json",
"sha2", "sha2",
] ]

View File

@ -7,6 +7,7 @@ edition = "2021"
base64 = "0.22.1" base64 = "0.22.1"
sha2 = "0.10.8" sha2 = "0.10.8"
hmac = "0.12.1" hmac = "0.12.1"
serde = "1.0.207"
serde_json = "1.0.124" serde_json = "1.0.124"
actix-web = "4" actix-web = "4"
actix-utils = "3.0.1" actix-utils = "3.0.1"

View File

@ -1,8 +1,10 @@
mod auth; mod auth;
mod models;
use actix_web::{get, Responder, HttpResponse, HttpServer, App, web}; use actix_web::{get, Responder, HttpResponse, HttpServer, App, web};
use std::sync::{Mutex, Arc}; use std::sync::{Mutex, MutexGuard, Arc};
use crate::auth::AuthorizedUser; use auth::AuthorizedUser;
use models::Favorite;
mod embedded { mod embedded {
use refinery::embed_migrations; use refinery::embed_migrations;
@ -29,6 +31,26 @@ async fn authorized(auth: AuthorizedUser) -> impl Responder {
HttpResponse::Ok().body(format!("Authorized as {} ({})", auth.username, auth.user_id)) HttpResponse::Ok().body(format!("Authorized as {} ({})", auth.username, auth.user_id))
} }
#[get("/favorites")]
async fn favorites(auth: AuthorizedUser, data: web::Data<AppData>) -> impl Responder {
let db = data.database.lock().unwrap();
match get_favorites(db, auth.user_id) {
Some(favorites) => HttpResponse::Ok().json(favorites),
None => HttpResponse::InternalServerError().finish(),
}
}
fn get_favorites(db: MutexGuard<'_, rusqlite::Connection>, user_id: String) -> Option<Vec<Favorite>> {
Some(
db.prepare("SELECT * FROM favorites WHERE user_id = :user_id").ok()?
.query_map(&[(":user_id", &user_id)], |row| Favorite::from_row(row))
.ok()?
.map(|fav| fav.unwrap())
.collect()
)
}
#[actix_web::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
let _ = dotenvy::dotenv(); let _ = dotenvy::dotenv();
@ -49,18 +71,16 @@ async fn main() -> std::io::Result<()> {
println!("Starting web server at port {}", port); println!("Starting web server at port {}", port);
HttpServer::new(|| { let conn = Arc::new(Mutex::new(rusqlite::Connection::open(database_path).unwrap()));
let database_path = std::env::var("RUST_BACKEND_DB")
.unwrap_or("database.sqlite3".to_string());
let conn = Arc::new(Mutex::new(rusqlite::Connection::open(database_path).unwrap()));
HttpServer::new(move || {
App::new() App::new()
.app_data(web::Data::new(AppData { .app_data(web::Data::new(AppData {
database: conn, database: conn.clone(),
})) }))
.service(healthcheck) .service(healthcheck)
.service(authorized) .service(authorized)
.service(favorites)
}) })
.bind(("0.0.0.0", port))? .bind(("0.0.0.0", port))?
.run() .run()

View File

@ -0,0 +1,23 @@
use std::string::String;
use serde::Serialize;
use rusqlite::{Row, Error};
#[derive(Serialize)]
pub struct Favorite {
pub id: usize,
pub user_id: String,
pub lat: f64,
pub lng: f64,
}
impl Favorite {
pub fn from_row(row: &Row) -> Result<Self, Error> {
Ok(Favorite {
id: row.get("id")?,
user_id: row.get("user_id")?,
lat: row.get("lat")?,
lng: row.get("lng")?,
})
}
}