Implement heir endpoints
This commit is contained in:
parent
fae3d0ebaa
commit
c6e3fa3eee
5 changed files with 140 additions and 16 deletions
|
@ -1,7 +1,11 @@
|
||||||
use diesel::{SqliteConnection, r2d2::{ConnectionManager, PooledConnection}, RunQueryDsl, QueryDsl, SelectableHelper, ExpressionMethods, OptionalExtension};
|
use diesel::{SqliteConnection, r2d2::{ConnectionManager, PooledConnection}, RunQueryDsl, QueryDsl, SelectableHelper, ExpressionMethods, OptionalExtension};
|
||||||
use crate::database::models::User;
|
use crate::database::models::User;
|
||||||
|
|
||||||
pub fn user(user_id: &str, conn: &mut PooledConnection<ConnectionManager<SqliteConnection>>) -> diesel::result::QueryResult<User> {
|
use super::models::Heir;
|
||||||
|
|
||||||
|
type Connection<'a> = &'a mut PooledConnection<ConnectionManager<SqliteConnection>>;
|
||||||
|
|
||||||
|
pub fn user(user_id: &str, conn: Connection) -> diesel::result::QueryResult<User> {
|
||||||
use crate::database::schema::users::dsl::users;
|
use crate::database::schema::users::dsl::users;
|
||||||
users
|
users
|
||||||
.find(user_id)
|
.find(user_id)
|
||||||
|
@ -9,7 +13,7 @@ pub fn user(user_id: &str, conn: &mut PooledConnection<ConnectionManager<SqliteC
|
||||||
.first(conn)
|
.first(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn user_by_email(email: &str, conn: &mut PooledConnection<ConnectionManager<SqliteConnection>>) -> diesel::result::QueryResult<Option<User>> {
|
pub fn user_by_email(email: &str, conn: Connection) -> diesel::result::QueryResult<Option<User>> {
|
||||||
use crate::database::schema::users::dsl as users;
|
use crate::database::schema::users::dsl as users;
|
||||||
users::users
|
users::users
|
||||||
.filter(users::email.eq(email))
|
.filter(users::email.eq(email))
|
||||||
|
@ -18,3 +22,11 @@ pub fn user_by_email(email: &str, conn: &mut PooledConnection<ConnectionManager<
|
||||||
.first(conn)
|
.first(conn)
|
||||||
.optional()
|
.optional()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn list_heirs(user_id: &str, conn: Connection) -> diesel::result::QueryResult<Vec<Heir>> {
|
||||||
|
use crate::database::schema::heirs::dsl as heirs;
|
||||||
|
heirs::heirs
|
||||||
|
.filter(heirs::user_id.eq(user_id))
|
||||||
|
.select(Heir::as_select())
|
||||||
|
.load(conn)
|
||||||
|
}
|
|
@ -62,11 +62,11 @@ pub struct Entry {
|
||||||
#[diesel(table_name = schema::heirs)]
|
#[diesel(table_name = schema::heirs)]
|
||||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||||
pub struct Heir {
|
pub struct Heir {
|
||||||
id: String,
|
pub id: String,
|
||||||
user_id: String,
|
pub user_id: String,
|
||||||
created_at: NaiveDateTime,
|
pub created_at: NaiveDateTime,
|
||||||
name: String,
|
pub name: String,
|
||||||
email: Option<String>,
|
pub email: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Queryable, Selectable, Serialize, Deserialize)]
|
#[derive(Queryable, Selectable, Serialize, Deserialize)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use argon2::{password_hash::{rand_core::OsRng, SaltString}, Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
|
use argon2::{password_hash::{rand_core::OsRng, SaltString}, Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
|
||||||
use axum::{extract::State, http::StatusCode, routing::{get, post}, Json, Router};
|
use axum::{extract::State, http::StatusCode, routing::{get, post, put, delete}, Json, Router};
|
||||||
use chrono::{Utc, NaiveDateTime};
|
use chrono::{Utc, NaiveDateTime};
|
||||||
use diesel::{RunQueryDsl, ExpressionMethods};
|
use diesel::{QueryDsl, RunQueryDsl, ExpressionMethods};
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
@ -13,6 +13,9 @@ pub fn auth_router() -> Router<AppState> {
|
||||||
.route("/auth/register", post(register))
|
.route("/auth/register", post(register))
|
||||||
.route("/auth/login", post(login))
|
.route("/auth/login", post(login))
|
||||||
.route("/auth/genkey", get(genkey))
|
.route("/auth/genkey", get(genkey))
|
||||||
|
.route("/auth/heirs", get(list_heirs))
|
||||||
|
.route("/auth/heirs", put(insert_heir))
|
||||||
|
.route("/auth/heirs", delete(delete_heir))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
|
@ -46,7 +49,7 @@ async fn genkey(State(state): State<AppState>, ExtractJwtUser(user): ExtractJwtU
|
||||||
let session_key = Uuid::new_v4().to_string();
|
let session_key = Uuid::new_v4().to_string();
|
||||||
let result = diesel::insert_into(session_keys)
|
let result = diesel::insert_into(session_keys)
|
||||||
.values((
|
.values((
|
||||||
user_id.eq(user.uid),
|
user_id.eq(&user.uid),
|
||||||
key.eq(&session_key),
|
key.eq(&session_key),
|
||||||
))
|
))
|
||||||
.execute(&mut conn);
|
.execute(&mut conn);
|
||||||
|
@ -56,7 +59,7 @@ async fn genkey(State(state): State<AppState>, ExtractJwtUser(user): ExtractJwtU
|
||||||
session_key,
|
session_key,
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
error!("failed to insert into session_keys");
|
error!("failed to insert into session_keys {}, error: {:?}", user.uid, result.err());
|
||||||
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -199,3 +202,109 @@ async fn register(State(state): State<AppState>, Json(req): Json<RegisterRequest
|
||||||
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct HttpHeir {
|
||||||
|
id: String,
|
||||||
|
contact_method: String,
|
||||||
|
name: String,
|
||||||
|
value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<crate::database::models::Heir> for HttpHeir {
|
||||||
|
fn from(value: crate::database::models::Heir) -> Self {
|
||||||
|
Self {
|
||||||
|
id: value.id,
|
||||||
|
// Only e-mail is implemented right now
|
||||||
|
contact_method: "email".into(),
|
||||||
|
name: value.name,
|
||||||
|
value: value.email.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn list_heirs(State(state): State<AppState>, ExtractJwtUser(user): ExtractJwtUser) -> Result<Json<Vec<HttpHeir>>, StatusCode> {
|
||||||
|
if let Ok(mut conn) = state.pool.get() {
|
||||||
|
let result = actions::list_heirs(&user.uid, &mut conn);
|
||||||
|
if let Ok(heirs) = result {
|
||||||
|
Ok(Json(heirs.into_iter().map(HttpHeir::from).collect()))
|
||||||
|
} else {
|
||||||
|
error!("failed to obtain heirs: {}, error: {:?}", user.uid, result.err());
|
||||||
|
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("failed to obtain pooled connection");
|
||||||
|
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct InsertHeirRequest {
|
||||||
|
contact_method: String,
|
||||||
|
name: String,
|
||||||
|
value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn insert_heir(State(state): State<AppState>, ExtractJwtUser(user): ExtractJwtUser, Json(req): Json<InsertHeirRequest>) -> Result<Json<Vec<HttpHeir>>, StatusCode> {
|
||||||
|
use crate::database::schema::heirs::dsl::*;
|
||||||
|
if let Ok(mut conn) = state.pool.get() {
|
||||||
|
let heir_id = Uuid::new_v4().to_string();
|
||||||
|
let result = diesel::insert_into(heirs)
|
||||||
|
.values((
|
||||||
|
id.eq(heir_id),
|
||||||
|
created_at.eq(Utc::now().naive_utc()),
|
||||||
|
user_id.eq(&user.uid),
|
||||||
|
name.eq(req.name),
|
||||||
|
// Only e-mail is implemented right now
|
||||||
|
email.eq(req.value),
|
||||||
|
))
|
||||||
|
.execute(&mut conn);
|
||||||
|
|
||||||
|
if result.is_err() {
|
||||||
|
error!("failed to insert into heirs: {}, error: {:?}", user.uid, result.err());
|
||||||
|
return Err(StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = actions::list_heirs(&user.uid, &mut conn);
|
||||||
|
if let Ok(heirs_list) = result {
|
||||||
|
Ok(Json(heirs_list.into_iter().map(HttpHeir::from).collect()))
|
||||||
|
} else {
|
||||||
|
error!("failed to obtain heirs: {}, error: {:?}", user.uid, result.err());
|
||||||
|
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("failed to obtain pooled connection");
|
||||||
|
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct DeleteHeirRequest {
|
||||||
|
id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn delete_heir(State(state): State<AppState>, ExtractJwtUser(user): ExtractJwtUser, Json(req): Json<DeleteHeirRequest>) -> Result<Json<Vec<HttpHeir>>, StatusCode> {
|
||||||
|
use crate::database::schema::heirs::dsl::*;
|
||||||
|
if let Ok(mut conn) = state.pool.get() {
|
||||||
|
let result = diesel::delete(heirs.filter(id.eq(&req.id))).execute(&mut conn);
|
||||||
|
if result.is_err() {
|
||||||
|
error!("failed to delete from heirs: {}, heir_id: {}, error: {:?}", user.uid, req.id, result.err());
|
||||||
|
return Err(StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = actions::list_heirs(&user.uid, &mut conn);
|
||||||
|
if let Ok(heirs_list) = result {
|
||||||
|
Ok(Json(heirs_list.into_iter().map(HttpHeir::from).collect()))
|
||||||
|
} else {
|
||||||
|
error!("failed to obtain heirs: {}, error: {:?}", user.uid, result.err());
|
||||||
|
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("failed to obtain pooled connection");
|
||||||
|
Err(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
}
|
|
@ -102,7 +102,7 @@ export default function register(app: AppInterface, auth: AuthInterface, databas
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await database.removeHeir(request.body);
|
await database.removeHeir(request.body.id);
|
||||||
|
|
||||||
return (await database.listHeirs(payload.uid))
|
return (await database.listHeirs(payload.uid))
|
||||||
.map((v) => (v["contactMethod"] = "email"))
|
.map((v) => (v["contactMethod"] = "email"))
|
||||||
|
@ -111,9 +111,9 @@ export default function register(app: AppInterface, auth: AuthInterface, databas
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
headers: { $ref: "schema://identity/authorization" },
|
headers: { $ref: "schema://identity/authorization" },
|
||||||
body: {
|
body: Type.Object({
|
||||||
type: "string",
|
id: Type.String(),
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,10 @@ export async function removeHeir(credentials: Credentials, heirID: string): Prom
|
||||||
return await asJson(
|
return await asJson(
|
||||||
sendRequest('/auth/heirs', credentials, {
|
sendRequest('/auth/heirs', credentials, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
body: heirID
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ id: heirID })
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue