Skip to content

Commit

Permalink
Merge pull request #213 from avored/209-move-element-data-type-to-be-…
Browse files Browse the repository at this point in the history
…inside-the-component-table

209 move element data type to be inside the component table
  • Loading branch information
indpurvesh authored Aug 14, 2024
2 parents 0a6a35e + c716cb6 commit c8ea994
Show file tree
Hide file tree
Showing 16 changed files with 497 additions and 235 deletions.
548 changes: 358 additions & 190 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ tower-http = { version = "0.5.2", features = ["fs", "cors"] }
dotenvy = "0.15.7"
axum-extra = { version = "0.9.3", features = ["cookie", "cookie-signed"] }
futures = "0.3.30"
tower = "0.4.13"
argon2 = "0.5.3"
rand = "0.8.5"
urlencoding = "2.1.3"
Expand All @@ -26,8 +25,12 @@ chrono = { version = "0.4.38", features = [] }
email_address = "0.2.4"
rust-i18n = "3.0.1"
lettre = { version = "0.11.7", features = ["tokio1-native-tls"] }
handlebars = "5.1.2"
handlebars = "6.0.0"
utoipa = "4.2.3"
juniper = "0.16.1"
juniper_axum = { version = "0.1.0", features = ["subscriptions"] }
tokio-stream = "0.1.15"

[dev-dependencies]
mockall = "0.13.0"
tower = { version = "0.5.0", features = ["util"] }
7 changes: 5 additions & 2 deletions react-admin/src/pages/component/ComponentCreatePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const ComponentCreatePage = (() => {
const [t] = useTranslation("global");

const addElementOnClick = () => {
append({ name: "", identifier: "", element_type: AvoRedFieldTypesEnum.TEXT });
append({ name: "", identifier: "", element_type: AvoRedFieldTypesEnum.TEXT, element_data_type: 'TEXT' });
};

const deleteElementOnClick = (elementIndex: number) => {
Expand All @@ -44,6 +44,9 @@ export const ComponentCreatePage = (() => {
) => {
setValue(`elements.${fieldIndex}.element_type`, fieldTypeValue);
setValue(`elements.${fieldIndex}.element_data`, [{ label: "", value: "" }]);
// Ideally value of this data type can be based on element
// e.g: Number Input field will have INT(It should match rust backend type) data type
setValue(`elements.${fieldIndex}.element_data_type`, 'TEXT');
trigger(`elements.${fieldIndex}`);
};

Expand Down Expand Up @@ -228,7 +231,7 @@ export const ComponentCreatePage = (() => {
/>
</div>

<div className="w-1/2 ml-3 w-full">
<div className="w-1/2 ml-3">
<label
htmlFor="hs-inline-leading-pricing-select-label"
className="text-sm text-gray-600"
Expand Down
5 changes: 4 additions & 1 deletion react-admin/src/pages/component/ComponentEditPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const ComponentEditPage = (() => {
})

const addFieldOnClick = (() => {
append({name: '', identifier: '', element_type: AvoRedFieldTypesEnum.TEXT})
append({name: '', identifier: '', element_type: AvoRedFieldTypesEnum.TEXT, element_data_type: "TEXT"})
})

const deleteElementOnClick = ((elementIndex: number) => {
Expand Down Expand Up @@ -107,6 +107,9 @@ export const ComponentEditPage = (() => {
) => {
setValue(`elements.${elementIndex}.element_type`, fieldTypeValue)
setValue(`elements.${elementIndex}.element_data`, [{label: '', value: ''}])
// Ideally value of this data type can be based on element
// e.g: Number Input field will have INT(It should match rust backend type) data type
setValue(`elements.${elementIndex}.element_data_type`, 'TEXT');
await trigger(`elements.${elementIndex}`)
})

Expand Down
1 change: 1 addition & 0 deletions react-admin/src/types/component/ICreatableComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type CreatableElementType = {
name: string;
identifier: string;
element_type: string;
element_data_type: string;
element_data?: Array<CreatableElementDataType>
}

Expand Down
1 change: 1 addition & 0 deletions react-admin/src/types/component/IEditableComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type EditableComponentElementType = {
name: string;
identifier: string;
element_type: string;
element_data_type: string;
element_data?: Array<EditableComponentElementDataType>
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct CreatableElementRequest {
pub name: String,
pub identifier: String,
pub element_type: String,
pub element_data_type: String,
pub element_data: Option<Vec<CreatableComponentElementDataRequest>>
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub struct UpdatableElementRequest {
pub name: String,
pub identifier: String,
pub element_type: String,
pub element_data_type: String,
pub element_data: Option<Vec<UpdatableComponentElementDataRequest>>
}

Expand Down
1 change: 1 addition & 0 deletions src/api/handlers/component/store_component_api_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub async fn store_component_api_handler(
name: payload_element.name,
identifier: payload_element.identifier,
element_type: payload_element.element_type,
element_data_type: payload_element.element_data_type,
element_data: Some(creatable_element_data)

};
Expand Down
1 change: 1 addition & 0 deletions src/api/handlers/component/update_component_api_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub async fn update_component_api_handler(
name: payload_element.name,
identifier: payload_element.identifier,
element_type: payload_element.element_type,
element_data_type: payload_element.element_data_type,
element_data: Some(updatable_element_data)
};
updatable_elements.push(updatable_component_element_model);
Expand Down
65 changes: 45 additions & 20 deletions src/api/handlers/component_all_api_handler.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,77 @@
use std::sync::Arc;
use axum::extract::State;
use axum::Json;
use crate::responses::ApiResponse;
use crate::avored_state::AvoRedState;
use crate::error::Result;
use crate::models::component_model::ComponentModel;

pub async fn component_all_api_handler(
state: State<Arc<AvoRedState>>
) -> Result<Json<Vec<ComponentModel>>> {
) -> Result<Json<ApiResponse<Vec<ComponentModel>>>> {
println!("->> {:<12} - component_all_api_handler", "HANDLER");

Ok(Json(state.component_service.all(&state.db).await?))
let all_components = state.component_service.all(&state.db).await?;
let response = ApiResponse {
status: true,
data: all_components
};
Ok(Json(response))
}

#[cfg(test)]
mod tests {
use axum::body::Body;
use axum::http::StatusCode;
use serde_json::{json, Value};
use tower::ServiceExt;
use crate::api::handlers::setup::post_setup_avored_handler::SetupViewModel;
use crate::api::rest_api_routes::tests::{get_axum_app, send_post_request};
use crate::error::Result;
use crate::api::rest_api_routes::tests::{get_auth_token, get_axum_app, send_get_request};
use crate::responses::ApiResponse;
use crate::error::{Result, Error};
use crate::models::component_model::ComponentModel;
use crate::repositories::into_iter_objects;

#[tokio::test]
async fn test_component_all_api_handler() -> Result<()>
{
let app = get_axum_app().await.unwrap();
let body = Body::from(
r#"{
"email": "[email protected]",
"password": "admin123"
let (app, state) = get_axum_app().await.unwrap();
let token = get_auth_token(state.clone())?;

}"#,
);
let sql = "
CREATE components:content_id_1 CONTENT {
name: 'unittest name 1',
identifier: 'unittest identifier 1',
element_type: 'TEXT',
element_type: '[]',
created_at: time::now(),
updated_at: time::now(),
}
";

//@todo check for component-all-api with success response
let response = app.oneshot(send_post_request("/api/setup", body)).await.unwrap();
let (ds, ses) = &state.db;

assert_eq!(response.status(), StatusCode::OK);
let dummy_res = SetupViewModel {
status: true
let query_responses = ds.execute(sql, ses, None).await?;
let result_object_option = into_iter_objects(query_responses)?.next();
let result_object = match result_object_option {
Some(object) => object,
None => Err(Error::Generic("no record found".to_string())),
};
let component_model: ComponentModel = result_object?.try_into()?;

let mut all_components: Vec<ComponentModel> = vec![];
all_components.push(component_model);

let dummy_res = ApiResponse {
status: true,
data: all_components
};

let response = app.oneshot(send_get_request("/api/component-all", token)).await.unwrap();

assert_eq!(response.status(), StatusCode::OK);
let res_b = response.into_body();
let body = axum::body::to_bytes(res_b, usize::MAX).await.unwrap();
let body: Value = serde_json::from_slice(&body).unwrap();
assert_eq!(body, json!(&dummy_res));

println!("Component_ALL: {:?}", json!(&dummy_res));
Ok(())
}
}
7 changes: 2 additions & 5 deletions src/api/handlers/health_check_api_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ pub struct ResponseData {
data: String
}




#[cfg(test)]
mod tests {
use axum::http::StatusCode;
Expand All @@ -33,9 +30,9 @@ mod tests {
#[tokio::test]
async fn test_health_check_api_handler() -> Result<()>
{
let app = get_axum_app().await.unwrap();
let (app, _state) = get_axum_app().await.unwrap();

let response = app.oneshot(send_get_request("/api/health-check")).await.unwrap();
let response = app.oneshot(send_get_request("/api/health-check", String::from(""))).await.unwrap();

let dummy_res = ResponseData {
status: true,
Expand Down
62 changes: 55 additions & 7 deletions src/api/rest_api_routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,18 +213,28 @@ pub fn rest_api_routes(state: Arc<AvoRedState>) -> Router {
// }
// }


#[cfg(test)]
pub mod tests {
use std::env;
use std::sync::Arc;
use axum::{body::Body, http::Request, Router};
use crate::api::rest_api_routes::rest_api_routes;
use axum::body::Body;
use axum::http::{self, header, Request};
use axum::Router;
use jsonwebtoken::{encode, EncodingKey, Header};
use crate::avored_state::AvoRedState;
use crate::error::Result;
use crate::models::admin_user_model::AdminUserModel;
use crate::models::token_claim_model::TokenClaims;

use super::rest_api_routes;

pub fn send_get_request(uri: &str, token: String) -> Request<Body> {

pub fn send_get_request(uri: &str) -> Request<Body> {
Request::builder()
.uri(uri)
.header(header::AUTHORIZATION, format!("Bearer {token}"))
.header(header::CONTENT_TYPE, "application/json")
.method("GET")
.body(Body::empty())
.unwrap()
Expand All @@ -233,21 +243,59 @@ pub mod tests {
pub fn send_post_request(uri: &str, body: Body) -> Request<Body> {
Request::builder()
.uri(uri)
.header("content-type", "application/json")
.header(http::header::CONTENT_TYPE, "application/json")
.method("POST")
.body(body).unwrap()
.body(body)
.unwrap()
}

pub fn get_auth_token(state: Arc<AvoRedState>) -> Result<String> {
let now = chrono::Utc::now();
let iat = now.timestamp() as usize;
let exp = (now + chrono::Duration::minutes(60)).timestamp() as usize;
let admin_user_model = AdminUserModel::default();

let claims: TokenClaims = TokenClaims {
sub: admin_user_model.clone().id,
name: admin_user_model.clone().full_name,
email:admin_user_model.clone().email,
admin_user_model: admin_user_model.clone(),
exp,
iat,
};
Ok(encode(
&Header::default(),
&claims,
&EncodingKey::from_secret(state.config.jwt_secret_key.as_ref()),
).unwrap())
}

pub async fn get_axum_app() -> Result<Router>
pub async fn get_axum_app() -> Result<(Router, Arc<AvoRedState>)>
{
env::set_var("AVORED_DATABASE_NAMESPACE", "public_test");
env::set_var("AVORED_DATABASE_NAME", "avored_cms_test");
env::set_var("AVORED_DATABASE_FOLDER_NAME", "memory");


env::set_var("AVORED_PASSWORD_SALT", "UnitTestUnitTestUnitTestUnitTestUnitTestUnitTestUnitTestUnitTest");

env::set_var("AVORED_JWT_SECRET", "UnitTestUnitTestUnitTestUnitTestUnitTestUnitTestUnitTestUnitTest");
env::set_var("AVORED_JWT_EXPIRED_IN", "60");
env::set_var("AVORED_JWT_MAXAGE", "60");

env::set_var("AVORED_REACT_FRONTEND_APP_URL", "http://localhost:5173");
env::set_var("AVORED_REACT_ADMIN_APP_URL", "http://localhost:3000");
env::set_var("AVORED_BACK_END_APP_URL", "http://localhost:8080");

env::set_var("SMTP_HOST", "http://smtp.url");
env::set_var("SMTP_USERNAME", "smtp_username");
env::set_var("SMTP_PASSWORD", "smtp_password");
env::set_var("SMTP_PORT", "587");

let state = Arc::new(AvoRedState::new().await?);

let app = rest_api_routes(state.clone());

Ok(app)
Ok((app, state))
}
}
5 changes: 5 additions & 0 deletions src/models/component_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub struct ComponentElementModel {
pub name: String,
pub identifier: String,
pub element_type: String,
pub element_data_type: String,
pub element_data: Option<Vec<ComponentElementDataModel>>
}

Expand Down Expand Up @@ -80,6 +81,7 @@ impl TryFrom<Object> for ComponentElementModel {
let name = val.get("name").get_string()?;
let identifier = val.get("identifier").get_string()?;
let element_type = val.get("element_type").get_string()?;
let element_data_type = val.get("element_data_type").get_string()?;
let element_data = match val.get("element_data") {
Some(val) => {

Expand Down Expand Up @@ -109,6 +111,7 @@ impl TryFrom<Object> for ComponentElementModel {
name,
identifier,
element_type,
element_data_type,
element_data :Some(element_data)
})
}
Expand Down Expand Up @@ -162,6 +165,7 @@ pub struct CreatableComponentElementModel {
pub name: String,
pub identifier: String,
pub element_type: String,
pub element_data_type: String,
pub element_data: Option<Vec<ComponentElementDataModel>>,
}

Expand All @@ -187,6 +191,7 @@ pub struct UpdatableComponentElementModel {
pub name: String,
pub identifier: String,
pub element_type: String,
pub element_data_type: String,
pub element_data: Option<Vec<ComponentElementDataModel>>,
}

Expand Down
Loading

0 comments on commit c8ea994

Please sign in to comment.