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
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);
|
|
}
|