summaryrefslogtreecommitdiff
path: root/src/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/api')
-rw-r--r--src/api/liveops.rs2
-rw-r--r--src/api/mod.rs2
-rw-r--r--src/api/users.rs62
3 files changed, 65 insertions, 1 deletions
diff --git a/src/api/liveops.rs b/src/api/liveops.rs
index ff44107..2dda41d 100644
--- a/src/api/liveops.rs
+++ b/src/api/liveops.rs
@@ -7,5 +7,5 @@ async fn ping() -> HttpResponse {
}
pub fn service() -> Scope {
- web::scope("liveops/").service(ping)
+ web::scope("liveops").service(ping)
}
diff --git a/src/api/mod.rs b/src/api/mod.rs
index f934d0e..7becfbd 100644
--- a/src/api/mod.rs
+++ b/src/api/mod.rs
@@ -1,3 +1,5 @@
mod liveops;
+mod users;
pub use liveops::service as liveops;
+pub use users::service as users;
diff --git a/src/api/users.rs b/src/api/users.rs
new file mode 100644
index 0000000..5e409fd
--- /dev/null
+++ b/src/api/users.rs
@@ -0,0 +1,62 @@
+use actix_web::http::{header, StatusCode};
+use actix_web::{post, web, HttpResponse, ResponseError, Scope};
+use raise::yeet;
+use serde::Deserialize;
+use sqlx::MySqlPool;
+use thiserror::Error;
+
+use crate::models::User;
+use crate::services::crypto::PasswordHash;
+use crate::services::db::{new_user, username_is_used};
+use crate::services::id::new_user_id;
+
+#[derive(Clone, Deserialize)]
+struct CreateUser {
+ username: Box<str>,
+ password: Box<str>,
+}
+
+#[derive(Debug, Clone, Hash, Error)]
+#[error("An account with the given username already exists.")]
+struct CreateUserError {
+ username: Box<str>,
+}
+
+impl ResponseError for CreateUserError {
+ fn status_code(&self) -> StatusCode {
+ StatusCode::CONFLICT
+ }
+}
+
+#[post("")]
+async fn create_user(
+ body: web::Json<CreateUser>,
+ conn: web::Data<MySqlPool>,
+) -> Result<HttpResponse, CreateUserError> {
+ let conn = conn.get_ref();
+
+ let user_id = new_user_id(conn).await.unwrap();
+ let username = body.username.clone();
+ let password = PasswordHash::new(&body.password).unwrap();
+
+ if username_is_used(conn, &body.username).await.unwrap() {
+ yeet!(CreateUserError { username });
+ }
+
+ let user = User {
+ user_id,
+ username,
+ password,
+ };
+
+ new_user(conn, user).await.unwrap();
+
+ let response = HttpResponse::Created()
+ .insert_header((header::LOCATION, format!("users/{user_id}")))
+ .finish();
+ Ok(response)
+}
+
+pub fn service() -> Scope {
+ web::scope("users").service(create_user)
+}