use once_cell::sync::Lazy; use regex::Regex; use revolt_database::{Database, User}; use revolt_models::v0; use revolt_quark::authifier::models::Session; use revolt_result::{create_error, Result}; use rocket::{serde::json::Json, State}; use serde::{Deserialize, Serialize}; use validator::Validate; /// Regex for valid usernames /// /// Block zero width space /// Block lookalike characters pub static RE_USERNAME: Lazy = Lazy::new(|| Regex::new(r"^(\p{L}|[\d_.-])+$").unwrap()); /// # New User Data #[derive(Validate, Serialize, Deserialize, JsonSchema)] pub struct DataOnboard { /// New username which will be used to identify the user on the platform #[validate(length(min = 2, max = 32), regex = "RE_USERNAME")] username: String, } /// # Complete Onboarding /// /// This sets a new username, completes onboarding and allows a user to start using Revolt. #[openapi(tag = "Onboarding")] #[post("/complete", data = "")] pub async fn req( db: &State, session: Session, user: Option, data: Json, ) -> Result> { if user.is_some() { return Err(create_error!(AlreadyOnboarded)); } let data = data.into_inner(); data.validate().map_err(|error| { create_error!(FailedValidation { error: error.to_string() }) })?; Ok(Json( User::create(db, data.username, session.user_id, None) .await? .into_self() .await, )) }