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.

108 lines
3.1 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::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<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 (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<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);
}