use super::{EmailOtpPlugin, EmailOtpType};
use crate::authentication_helpers::{JsonField, JsonFieldKind};
use crate::endpoint::{definition, validate_fields};
use alibi_core::endpoint::{
EndpointCall, EndpointDefinition, EndpointInput, EndpointResponse, ServerEndpoint,
};
use alibi_core::utils::json::JsValue;
use alibi_core::{AuthContext, AuthResult, AuthSchema, HttpMethod};
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct EmailOtpRead {
pub otp: Option<String>,
}
const FIELDS: &[JsonField] = &[
JsonField::string("email", true),
JsonField {
name: "type",
kind: JsonFieldKind::OneOf(&[
"email-verification",
"sign-in",
"forget-password",
"change-email",
]),
required: true,
},
];
pub(super) fn definitions() -> Vec<EndpointDefinition> {
vec![
definition(
"createVerificationOTP",
"createEmailVerificationOTP",
None,
HttpMethod::Post,
),
definition(
"getVerificationOTP",
"getEmailVerificationOTP",
None,
HttpMethod::Get,
),
]
}
pub(super) fn validate(call: &EndpointCall) -> AuthResult<EndpointInput> {
if call.operation_id() == "createEmailVerificationOTP" {
Ok(EndpointInput {
body: Some(validate_fields(call.body(), "body", FIELDS)?),
query: call.query().cloned(),
})
} else {
Ok(EndpointInput {
body: call.body().cloned(),
query: Some(validate_fields(call.query(), "query", FIELDS)?),
})
}
}
impl EmailOtpPlugin {
#[must_use]
pub fn create_verification_otp_endpoint(
email: impl Into<String>,
otp_type: EmailOtpType,
) -> ServerEndpoint<String> {
ServerEndpoint::new("email-otp", "createVerificationOTP")
.with_body_value(input(email.into(), otp_type))
}
#[must_use]
pub fn get_verification_otp_endpoint(
email: impl Into<String>,
otp_type: EmailOtpType,
) -> ServerEndpoint<EmailOtpRead> {
ServerEndpoint::new("email-otp", "getVerificationOTP")
.with_query_value(input(email.into(), otp_type))
}
pub(super) async fn call_endpoint(
&self,
call: &EndpointCall,
ctx: &AuthContext<impl AuthSchema>,
) -> AuthResult<EndpointResponse> {
let (email, otp_type) = if call.operation_id() == "createEmailVerificationOTP" {
let body: super::types::SendRequest = call.body_as()?;
(body.email, body.otp_type)
} else {
let query: super::types::SendRequest = call.query_as()?;
(query.email, query.otp_type)
};
if call.operation_id() == "createEmailVerificationOTP" {
EndpointResponse::json(&self.create_verification_otp(ctx, &email, otp_type).await?)
} else {
EndpointResponse::json(
&serde_json::json!({"otp": self.get_verification_otp(ctx, &email, otp_type).await?}),
)
}
}
}
fn input(email: String, otp_type: EmailOtpType) -> JsValue {
JsValue::Object(
[
("email".into(), JsValue::String(email)),
("type".into(), JsValue::String(otp_type.as_str().into())),
]
.into_iter()
.collect(),
)
}