backup added

This commit is contained in:
Joshua Perry 2024-06-10 22:05:03 +01:00
parent cda66aa56b
commit dc86209ddb
7 changed files with 177 additions and 71 deletions

12
Cargo.lock generated
View File

@ -370,6 +370,7 @@ dependencies = [
"serde",
"serde_json",
"tokio",
"tokio-stream",
"vrd 0.0.7",
]
@ -1702,6 +1703,17 @@ dependencies = [
"tokio",
]
[[package]]
name = "tokio-stream"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-util"
version = "0.7.11"

View File

@ -15,4 +15,5 @@ pyo3 = { version = "0.21.2", features = ["auto-initialize"]}
serde = "1.0.203"
serde_json = "1.0.117"
tokio = "1.38.0"
tokio-stream = "0.1.15"
vrd = "0.0.7"

View File

@ -4,10 +4,11 @@ use anyhow::Result;
use axum::{
body::Body, response::{IntoResponse, Response}, routing::{get, post}, Json, Router
};
use serde::{Deserialize, Serialize};
use crate::ApiResult;
use db::{get_users, User};
use db::{get_database, get_users, LogEntry, Mole, User};
use http::{header::HeaderMap, StatusCode};
use mongodb::bson::{doc, oid::ObjectId};
use mongodb::bson::{doc, oid::ObjectId, to_document, Document};
use serde_json::json;
pub fn router() -> Router {
@ -39,6 +40,11 @@ pub async fn auth(api: &str) -> Result<Option<User>> {
}
#[derive(Serialize, Deserialize)]
struct BackupData {
moles: Vec<Mole>,
logs: Vec<LogEntry>,
}
async fn get_sign_in(Json(body): Json<User>) -> ApiResult {
let db = get_users().await?;
@ -79,8 +85,8 @@ async fn post_sign_in(Json(body): Json<User>) -> ApiResult {
}
};
match db.find_one(query.clone(), None).await? {
Some(_user) => {
match db.count_documents(query.clone(), None).await? {
count if count != 0 => {
db.update_one(query, update, None).await?;
Ok(Response::builder()
@ -89,7 +95,7 @@ async fn post_sign_in(Json(body): Json<User>) -> ApiResult {
"_api_key": api.to_string()
})).into_response().into_body())?)
},
None => {
_ => {
Ok(Response::builder()
.status(StatusCode::UNAUTHORIZED)
.body(Body::from("Username or password is incorrect"))?)
@ -110,13 +116,13 @@ async fn post_sign_up(Json(body): Json<User>) -> ApiResult {
}
};
match db.find_one(query, None).await? {
Some(_user) => {
match db.count_documents(query, None).await? {
count if count != 0 => {
Ok(Response::builder()
.status(StatusCode::NOT_ACCEPTABLE)
.body(Body::from("Username is already taken"))?)
},
None => {
_ => {
db.insert_one(body, None).await?;
Ok(Response::builder()
@ -154,6 +160,51 @@ async fn post_sign_out(headers: HeaderMap) -> ApiResult {
},
}
}
pub async fn post_backup() {} //TODO: Backup
async fn get_restore() {
//TODO: Restore
//find all moles that match user_id
//find all logs that match mole_ids
//Return as Json
pub async fn get_restore() {} //TODO: restore
}
async fn post_backup(headers: HeaderMap, Json(user_data): Json<BackupData>) -> ApiResult {
let api = headers["api_key"].to_str()?;
match auth(api).await? {
Some(_user) => {
let _ = backup_docs_if_new(user_data.moles, "moles").await;
let _ = backup_docs_if_new(user_data.logs, "logs").await;
Ok(Response::builder()
.status(StatusCode::CREATED)
.body(Body::from("Account backup successful"))?)
},
None => Ok(Response::builder()
.status(StatusCode::UNAUTHORIZED)
.body(Body::from("API Key is incorrect"))?),
}
}
async fn backup_docs_if_new<T: serde::Serialize>(docs: Vec<T>, collection: &'static str) -> Result<()> {
let _ = docs.iter()
.map(|doc| to_document(doc).unwrap())
.map(|doc| {
tokio::spawn(async move {
let _ = insert_if_new(doc, collection).await;
})
});
Ok(())
}
async fn insert_if_new(doc: Document, collection: &str) -> Result<()> {
let db = get_database().await?.collection(collection);
match db.count_documents(doc.clone(), None).await? {
0 => Some(db.insert_one(doc, None)),
_ => None,
};
Ok(())
}

View File

@ -1,4 +1,7 @@
pub mod locations;
use anyhow::Result;
use locations::Location;
use serde::{Deserialize, Serialize};
use mongodb::{
bson::{doc, oid::ObjectId, DateTime},
@ -24,55 +27,13 @@ pub async fn get_users() -> Result<Collection<User>> {
#[derive(Serialize, Deserialize)]
pub struct Mole {
#[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
id: Option<ObjectId>,
pub id: Option<ObjectId>,
#[serde(rename="_user_id")]
user_id: ObjectId,
pub user_id: ObjectId,
#[serde(rename="_image_path", skip_serializing_if = "Option::is_none")]
image_path: Option<String>,
location: Location,
pub image_path: Option<String>,
pub location: Location,
}
impl Mole {
pub fn new(user_id: ObjectId, location: Location) -> Self {
let id = None;
let image_path = None;
Self {
id,
user_id,
image_path,
location,
}
}
pub fn with_image(user_id: ObjectId, location: Location, image_path: String) -> Self {
let id = None;
let image_path = Some(image_path);
Self {
id,
user_id,
image_path,
location
}
}
}
#[derive(Serialize, Deserialize)]
pub enum Location {
FrontLocation(FrontLocation),
LeftSideLocation(LeftSideLocation),
RightSideLocation(RightSideLocation),
BackLocation(BackLocation),
}
#[derive(Serialize, Deserialize)]
pub enum FrontLocation {} //TODO: Add front locations
#[derive(Serialize, Deserialize)]
pub enum LeftSideLocation {} //TODO: Add left side locations
#[derive(Serialize, Deserialize)]
pub enum RightSideLocation {} //TODO: Add right side locations
#[derive(Serialize, Deserialize)]
pub enum BackLocation {} //TODO: Add back locations
#[derive(Serialize, Deserialize)]
pub struct LogEntry {
@ -84,19 +45,6 @@ pub struct LogEntry {
#[serde(rename = "_mole_id")]
pub mole_id: ObjectId
}
impl LogEntry {
pub fn new(contents: String, mole_id: ObjectId) -> Self {
let id = None;
let date_created: DateTime = chrono::Utc::now().into();
Self {
id,
date_created,
contents,
mole_id,
}
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct User {

View File

@ -0,0 +1,94 @@
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub enum Location {
FrontLocation(FrontLocation),
LeftSideLocation(SideLocation),
RightSideLocation(SideLocation),
BackLocation(BackLocation),
}
#[derive(Serialize, Deserialize)]
pub enum FrontLocation {
Forehead,
Nose,
LeftEye,
RightEye,
Lips,
Chin,
Neck,
LeftCollar,
RightCollar,
LeftBreast,
RightBreast,
Stomach,
Genitals,
LeftShoulder,
RightShoulder,
LeftUpperArm,
RightUpperArm,
LeftInnerElbow,
RightInnerElbow,
LeftLowerArm,
RightLowerArm,
LeftWrist,
RightWrist,
LeftPalm,
RightPalm,
LeftThigh,
RightThigh,
LeftKnee,
RightKnee,
LeftShin,
RightShin,
LeftAnkle,
RightAnkle,
LeftFoot,
RightFoot,
}
#[derive(Serialize, Deserialize)]
pub enum SideLocation {
Head,
Ear,
Cheek,
Neck,
Shoulder,
UpperArm,
Elbow,
LowerArm,
Wrist,
Hand,
UpperTorso,
LowerTorso,
Hip,
UpperLeg,
Knee,
LowerLeg,
Ankle,
Foot,
}
#[derive(Serialize, Deserialize)]
pub enum BackLocation {
Head,
Neck,
LeftShoulder,
RightShoulder,
UpperBack,
LowerBack,
LeftButtock,
RightButtock,
LeftHamstring,
RightHamstring,
LeftKneePit,
RightKneePit,
LeftCalf,
RightCalf,
LeftAnkle,
RightAnkle,
LeftHeel,
RightHeel,
}

View File

@ -14,7 +14,7 @@ pub async fn run() -> Result<()> {
let app = router();
let port = std::env::var("API_PORT")?;
let listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{port}")).await.unwrap();
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{port}")).await.unwrap();
axum::serve(listener, app).await.unwrap();

View File

@ -28,4 +28,4 @@ def predict(model_bytes, image_bytes):
model = process_model_bytes(model_bytes)
result = model.predict(image)
return result[0], result[1]
return result[0][0], result[0][1]