use actix_web::{get, post, web, HttpResponse}; use serde::Deserialize; use crate::core::*; use crate::ent; use crate::middle::AuthData; use crate::model::{AccountId, NewAccount, NewUser}; use crate::state::AppState; use crate::util::keys::generate_keypair; use crate::util::password::{self, ClearPassword}; use crate::util::validate::{ResultBuilder, Validate}; #[derive(Deserialize)] struct SignupData { username: String, email: String, password: ClearPassword, agreement: bool, locale: String, reason: Option, } #[post("")] async fn signup(data: web::Form, state: AppState) -> Result { let data: Sane = Insane::from(data.into_inner()).try_into()?; let data = data.inner(); let (pubkey, privkey) = generate_keypair()?; let account = state .repo .accounts .create(Insane::from(NewAccount { iri: None, name: data.username, domain: "localhost".into(), display_name: None, public_key: Some(pubkey), })) .await?; state .repo .users .create(Insane::from(NewUser { account_id: account.id, email: data.email, password: password::hash(&data.password), locale: data.locale, reason: data.reason, private_key: privkey, })) .await?; Ok(HttpResponse::Ok().finish()) } impl Validate for SignupData { fn validate(&self, builder: ResultBuilder) -> ResultBuilder { builder .check( &self.agreement, "agreement", "You must accept the Terms of Service", |v| *v, ) .field_auto(&self.password, "password") } } #[get("/verify_credentials")] async fn verify_credentials(auth: AuthData, state: AppState) -> Result { let account = auth.require()?; let response = ent::CredentialAccount::from_model(&state, account).await?; Ok(HttpResponse::Ok().json(response)) } #[get("/{id}")] async fn get_by_id( auth: AuthData, path: web::Path, state: AppState, ) -> Result { let id = path.into_inner(); if let Some(auth) = auth.maybe() { if auth.id == id { let response = ent::CredentialAccount::from_model(&state, auth).await?; return Ok(HttpResponse::Ok().json(response)); } } let account = state.repo.accounts.by_id(id).await?; let response = ent::Account::from_model(&state, &account).await?; Ok(HttpResponse::Ok().json(response)) } #[get("/{id}/statuses")] async fn get_notes(path: web::Path, state: AppState) -> Result { let id = path.into_inner(); let account = state.repo.accounts.by_id(id).await?; let notes = state.repo.notes.by_account(account, utc_now()).await?; Ok(HttpResponse::Ok().json(notes)) } pub fn configure(cfg: &mut web::ServiceConfig) { cfg.service(verify_credentials) .service(get_by_id) .service(get_notes) .service(signup); }