You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
3.2 KiB
Rust

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::crypto::PrivKey;
use crate::util::password::ClearPassword;
use crate::util::validate::{ResultBuilder, Validate};
#[derive(Deserialize)]
struct SignupData {
username: String,
email: String,
password: ClearPassword,
agreement: bool,
locale: String,
reason: Option<String>,
}
#[post("")]
async fn signup(data: web::Form<SignupData>, state: AppState) -> Result<HttpResponse> {
let data: Sane<SignupData> = Insane::from(data.into_inner()).try_into()?;
let data = data.inner();
let private_key = PrivKey::new()?;
let public_key = private_key.derive_pubkey().await?;
let account = state
.repo
.accounts
.create(Insane::from(NewAccount {
iri: None,
name: data.username,
domain: "localhost".into(),
display_name: None,
public_key: Some(public_key),
}))
.await?;
let user_result = state
.repo
.users
.create(Insane::from(NewUser {
account_id: account.id,
email: data.email,
password: data.password.hash(),
locale: data.locale,
reason: data.reason,
private_key,
}))
.await;
if user_result.is_err() {
state.repo.accounts.delete(account).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<HttpResponse> {
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<AccountId>,
state: AppState,
) -> Result<HttpResponse> {
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<AccountId>, state: AppState) -> Result<HttpResponse> {
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);
}