fixes and my notes function
This commit is contained in:
+42
@@ -22,6 +22,9 @@ pub struct User { pub id: i64, pub nickname: String, pub email: String, pub pass
|
||||
#[derive(Deserialize)] pub struct LoginRequest { email: String, password: String }
|
||||
#[derive(Deserialize)] pub struct ResetRequest { email: String }
|
||||
#[derive(Deserialize)] pub struct ResetConfirmRequest { token: String, password: String }
|
||||
#[derive(Deserialize)] pub struct ResourceActionRequest { kind: String, slug: String, #[serde(default)] password: Option<String> }
|
||||
#[derive(Serialize, FromRow)] pub struct ResourceItem { slug: String, title: String, protected: i64, updated_at: String }
|
||||
#[derive(Serialize)] pub struct ResourceList { workspaces: Vec<ResourceItem>, pads: Vec<ResourceItem> }
|
||||
#[derive(Serialize)] pub struct SessionResponse { token: String, nickname: String, email: String, expires_at: String }
|
||||
#[derive(Serialize)] pub struct IdentityResponse { nickname: String, registered: bool }
|
||||
|
||||
@@ -79,6 +82,45 @@ pub async fn me(State(state): State<SharedState>, headers: HeaderMap) -> Result<
|
||||
Ok(Json(SessionResponse { token: token.into(), nickname: user.nickname, email: user.email, expires_at }))
|
||||
}
|
||||
|
||||
pub async fn resources(State(state): State<SharedState>, headers: HeaderMap) -> Result<Json<ResourceList>, AuthError> {
|
||||
let user = require_user(&state, &headers).await?;
|
||||
let workspaces = sqlx::query_as::<_, ResourceItem>(queries::get(state.db.kind(), queries::USER_LIST_WORKSPACES)).bind(user.id).fetch_all(state.db.pool()).await.map_err(AuthError::database)?;
|
||||
let pads = sqlx::query_as::<_, ResourceItem>(queries::get(state.db.kind(), queries::USER_LIST_PADS)).bind(user.id).fetch_all(state.db.pool()).await.map_err(AuthError::database)?;
|
||||
Ok(Json(ResourceList { workspaces, pads }))
|
||||
}
|
||||
|
||||
pub async fn update_resource(State(state): State<SharedState>, headers: HeaderMap, Json(req): Json<ResourceActionRequest>) -> Result<Json<serde_json::Value>, AuthError> {
|
||||
let user = require_user(&state, &headers).await?;
|
||||
let hash = match req.password.as_deref().map(str::trim).filter(|v| !v.is_empty()) { Some(v) => { validate_password(v)?; Some(hash_password(v)?) }, None => None };
|
||||
ensure_owner(&state, user.id, &req.kind, &req.slug).await?;
|
||||
let query = match req.kind.as_str() { "workspace" => queries::USER_SET_WORKSPACE_PASSWORD, "pad" => queries::USER_SET_PAD_PASSWORD, _ => return Err(AuthError::bad_request("Unknown resource type.")) };
|
||||
sqlx::query(queries::get(state.db.kind(), query)).bind(hash).bind(req.slug.trim()).execute(state.db.pool()).await.map_err(AuthError::database)?;
|
||||
Ok(Json(serde_json::json!({"ok":true})))
|
||||
}
|
||||
|
||||
pub async fn delete_resource(State(state): State<SharedState>, headers: HeaderMap, Json(req): Json<ResourceActionRequest>) -> Result<Json<serde_json::Value>, AuthError> {
|
||||
let user = require_user(&state, &headers).await?;
|
||||
ensure_owner(&state, user.id, &req.kind, &req.slug).await?;
|
||||
let query = match req.kind.as_str() { "workspace" => queries::USER_DELETE_WORKSPACE, "pad" => queries::USER_DELETE_PAD, _ => return Err(AuthError::bad_request("Unknown resource type.")) };
|
||||
sqlx::query(queries::get(state.db.kind(), query)).bind(req.slug.trim()).execute(state.db.pool()).await.map_err(AuthError::database)?;
|
||||
Ok(Json(serde_json::json!({"ok":true})))
|
||||
}
|
||||
|
||||
pub async fn optional_user(state: &SharedState, headers: &HeaderMap) -> Result<Option<User>, AuthError> {
|
||||
match bearer(headers) { Some(token) => user_from_token(state, token).await, None => Ok(None) }
|
||||
}
|
||||
|
||||
async fn require_user(state: &SharedState, headers: &HeaderMap) -> Result<User, AuthError> {
|
||||
optional_user(state, headers).await?.ok_or_else(|| AuthError::unauthorized("Log in first."))
|
||||
}
|
||||
|
||||
async fn ensure_owner(state: &SharedState, user_id: i64, kind: &str, slug: &str) -> Result<(), AuthError> {
|
||||
let query = match kind { "workspace" => queries::USER_OWNS_WORKSPACE, "pad" => queries::USER_OWNS_PAD, _ => return Err(AuthError::bad_request("Unknown resource type.")) };
|
||||
let count: i64 = sqlx::query_scalar(queries::get(state.db.kind(), query)).bind(user_id).bind(slug.trim()).fetch_one(state.db.pool()).await.map_err(AuthError::database)?;
|
||||
if count == 0 { return Err(AuthError::forbidden("This item does not belong to your account.")); }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn logout(State(state): State<SharedState>, headers: HeaderMap) -> Result<Json<serde_json::Value>, AuthError> {
|
||||
if let Some(token) = bearer(&headers) {
|
||||
let result = sqlx::query(queries::get(state.db.kind(), queries::AUTH_DELETE_SESSION_BY_TOKEN)).bind(token).execute(state.db.pool()).await.map_err(AuthError::database)?;
|
||||
|
||||
Reference in New Issue
Block a user