Skip to content

Commit

Permalink
store and update collection basic
Browse files Browse the repository at this point in the history
  • Loading branch information
indpurvesh committed Dec 28, 2024
1 parent e876c57 commit eeaba8d
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 50 deletions.
2 changes: 2 additions & 0 deletions src/api/handlers/collection/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
pub mod collection_table_api_handler;
pub mod store_collection_api_handler;
pub mod update_collection_api_handler;
pub mod request;
2 changes: 2 additions & 0 deletions src/api/handlers/collection/request/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
pub mod collection_table_request;
pub mod store_collection_request;
pub mod update_collection_request;
35 changes: 35 additions & 0 deletions src/api/handlers/collection/request/store_collection_request.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use rust_i18n::t;
use serde::Deserialize;
use crate::models::validation_error::{ErrorMessage, Validate};

#[derive(Deserialize, Debug, Clone, Default)]
pub struct StoreCollectionRequest {
pub name: String,
pub identifier: String,
}

impl StoreCollectionRequest {
pub fn validate(&self) -> crate::error::Result<Vec<ErrorMessage>> {
let mut errors: Vec<ErrorMessage> = vec![];

if !self.name.required()? {
let error_message = ErrorMessage {
key: String::from("name"),
message: t!("validation_required", attribute = t!("name")).to_string(),
};

errors.push(error_message);
}

if !self.identifier.required()? {
let error_message = ErrorMessage {
key: String::from("identifier"),
message: format!("Identifier is a required field {}", t!("identifier")),
};

errors.push(error_message);
}

Ok(errors)
}
}
26 changes: 26 additions & 0 deletions src/api/handlers/collection/request/update_collection_request.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use rust_i18n::t;
use serde::Deserialize;

use crate::models::validation_error::{ErrorMessage, Validate};

#[derive(Deserialize, Debug, Clone, Default)]
pub struct UpdateCollectionRequest {
pub name: String,
}

impl UpdateCollectionRequest {
pub fn validate(&self) -> crate::error::Result<Vec<ErrorMessage>> {
let mut errors: Vec<ErrorMessage> = vec![];

if !self.name.required()? {
let error_message = ErrorMessage {
key: String::from("name"),
message: t!("validation_required", attribute = t!("name")).to_string(),
};

errors.push(error_message);
}

Ok(errors)
}
}
54 changes: 54 additions & 0 deletions src/api/handlers/collection/store_collection_api_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use std::sync::Arc;
use axum::{Extension, Json};
use axum::extract::State;
use crate::api::handlers::collection::request::store_collection_request::StoreCollectionRequest;
use crate::avored_state::AvoRedState;
use crate::error::{Error, Result};
use crate::models::collection_model::{CollectionModel, CreatableCollection};
use crate::models::token_claim_model::LoggedInUser;
use crate::models::validation_error::ErrorResponse;
use crate::responses::ApiResponse;

pub async fn store_collection_api_handler (
state: State<Arc<AvoRedState>>,
Extension(logged_in_user): Extension<LoggedInUser>,
Json(payload): Json<StoreCollectionRequest>,
) -> Result<Json<ApiResponse<CollectionModel>>> {
println!("->> {:<12} - store_collection_api_handler", "HANDLER");

let has_permission_bool = state
.admin_user_service
.has_permission(logged_in_user.clone(), String::from("collection_create"))
.await?;
if !has_permission_bool {
return Err(Error::Forbidden);
}

let error_messages = payload.validate()?;

if !error_messages.is_empty() {
let error_response = ErrorResponse {
status: false,
errors: error_messages,
};

return Err(Error::BadRequest(error_response));
}

let creatable_model = CreatableCollection {
name: payload.name,
identifier: payload.identifier,
logged_in_username: logged_in_user.email,
};

let created_model = state
.collection_service
.create_collection(&state.db, creatable_model)
.await?;
let response = ApiResponse {
status: true,
data: created_model,
};

Ok(Json(response))
}
55 changes: 55 additions & 0 deletions src/api/handlers/collection/update_collection_api_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use std::sync::Arc;
use axum::{Extension, Json};
use axum::extract::{Path, State};
use crate::api::handlers::collection::request::update_collection_request::UpdateCollectionRequest;
use crate::avored_state::AvoRedState;
use crate::error::{Error, Result};
use crate::models::collection_model::{CollectionModel, UpdatableCollection};
use crate::models::token_claim_model::LoggedInUser;
use crate::models::validation_error::ErrorResponse;
use crate::responses::ApiResponse;

pub async fn update_collection_api_handler (
state: State<Arc<AvoRedState>>,
Path(collection_id): Path<String>,
Extension(logged_in_user): Extension<LoggedInUser>,
Json(payload): Json<UpdateCollectionRequest>,
) -> Result<Json<ApiResponse<CollectionModel>>> {
println!("->> {:<12} - update_collection_api_handler", "HANDLER");

let has_permission_bool = state
.admin_user_service
.has_permission(logged_in_user.clone(), String::from("collection_update"))
.await?;
if !has_permission_bool {
return Err(Error::Forbidden);
}

let error_messages = payload.validate()?;

if !error_messages.is_empty() {
let error_response = ErrorResponse {
status: false,
errors: error_messages,
};

return Err(Error::BadRequest(error_response));
}

let creatable_model = UpdatableCollection {
name: payload.name,
id: collection_id,
logged_in_username: logged_in_user.email,
};

let updated_model = state
.collection_service
.update_collection(&state.db, creatable_model)
.await?;
let response = ApiResponse {
status: true,
data: updated_model,
};

Ok(Json(response))
}
4 changes: 4 additions & 0 deletions src/api/rest_api_routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ use axum::{middleware, routing::get, Extension, Router};
use juniper::{EmptyMutation, EmptySubscription};
use std::sync::Arc;
use tower_http::cors::CorsLayer;
use crate::api::handlers::collection::store_collection_api_handler::store_collection_api_handler;
use crate::api::handlers::collection::update_collection_api_handler::update_collection_api_handler;

pub fn rest_api_routes(state: Arc<AvoRedState>) -> Router {
Router::new()
Expand Down Expand Up @@ -145,6 +147,8 @@ fn admin_api_routes(state: Arc<AvoRedState>) -> Router {
get(fetch_admin_user_api_handler),
)
.route("/api/collection", get(collection_table_api_handler))
.route("/api/collection", post(store_collection_api_handler))
.route("/api/collection/:collection_id", put(update_collection_api_handler))
.route("/api/model", get(model_table_api_handler))
.route("/api/model", post(store_model_api_handler))
.route("/api/model/:model_id", put(update_model_api_handler))
Expand Down
16 changes: 16 additions & 0 deletions src/models/collection_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@ pub struct CollectionPagination {
pub pagination: Pagination,
}

#[derive(Serialize, Debug, Deserialize, Clone)]
pub struct CreatableCollection {
pub name: String,
pub identifier: String,
pub logged_in_username: String,
}


#[derive(Serialize, Debug, Deserialize, Clone)]
pub struct UpdatableCollection {
pub id: String,
pub name: String,
pub logged_in_username: String,
}


impl TryFrom<Object> for CollectionModel {
type Error = Error;
fn try_from(val: Object) -> crate::error::Result<CollectionModel> {
Expand Down
103 changes: 72 additions & 31 deletions src/repositories/collection_repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ use std::collections::BTreeMap;

use super::into_iter_objects;
use crate::error::{Error, Result};
use crate::models::collection_model::CollectionModel;
use crate::models::collection_model::{CollectionModel, CreatableCollection, UpdatableCollection};
use crate::models::ModelCount;
use crate::PER_PAGE;
use surrealdb::dbs::Session;
use surrealdb::kvs::Datastore;
use surrealdb::sql::{Datetime, Value};

#[derive(Clone)]
pub struct CollectionRepository {}
Expand Down Expand Up @@ -151,34 +152,74 @@ impl CollectionRepository {
// model_count
// }

// pub async fn update_model(
// &self,
// datastore: &Datastore,
// database_session: &Session,
// updatable_model: UpdatableCollectionCollection,
// ) -> Result<CollectionCollection> {
// let sql = "
// UPDATE type::thing($table, $id) MERGE {
// name: $name,
// updated_by: $logged_in_user_name,
// updated_at: time::now()
// };";
//
// let vars = BTreeMap::from([
// ("name".into(), updatable_model.name.into()),
// ("logged_in_user_name".into(), updatable_model.logged_in_username.into()),
// ("id".into(), updatable_model.id.into()),
// ("table".into(), "models".into()),
// ]);
// let responses = datastore.execute(sql, database_session, Some(vars)).await?;
//
// let result_object_option = into_iter_objects(responses)?.next();
// let result_object = match result_object_option {
// Some(object) => object,
// None => Err(Error::Generic("no record found".to_string())),
// };
// let model_model: Result<CollectionCollection> = result_object?.try_into();
//
// model_model
// }
pub async fn update_collection(
&self,
datastore: &Datastore,
database_session: &Session,
updatable_model: UpdatableCollection,
) -> Result<CollectionModel> {
let sql = "
UPDATE type::thing($table, $id) MERGE {
name: $name,
updated_by: $logged_in_user_name,
updated_at: time::now()
};";

let vars = BTreeMap::from([
("name".into(), updatable_model.name.into()),
(
"logged_in_user_name".into(),
updatable_model.logged_in_username.into(),
),
("id".into(), updatable_model.id.into()),
("table".into(), "collections".into()),
]);
let responses = datastore.execute(sql, database_session, Some(vars)).await?;

let result_object_option = into_iter_objects(responses)?.next();
let result_object = match result_object_option {
Some(object) => object,
None => Err(Error::Generic("no record found".to_string())),
};
let model_model: Result<CollectionModel> = result_object?.try_into();

model_model
}

pub async fn create_collection(
&self,
datastore: &Datastore,
database_session: &Session,
creatable_model: CreatableCollection,
) -> Result<CollectionModel> {
let sql = "CREATE collections CONTENT $data";

let data: BTreeMap<String, Value> = [
("name".into(), creatable_model.name.into()),
("identifier".into(), creatable_model.identifier.into()),
(
"created_by".into(),
creatable_model.logged_in_username.clone().into(),
),
(
"updated_by".into(),
creatable_model.logged_in_username.into(),
),
("created_at".into(), Datetime::default().into()),
("updated_at".into(), Datetime::default().into()),
]
.into();
let vars: BTreeMap<String, Value> = [("data".into(), data.into())].into();

let responses = datastore.execute(sql, database_session, Some(vars)).await?;

let result_object_option = into_iter_objects(responses)?.next();
let result_object = match result_object_option {
Some(object) => object,
None => Err(Error::Generic("no record found".to_string())),
};
let created_model: Result<CollectionModel> = result_object?.try_into();

created_model
}
}
Loading

0 comments on commit eeaba8d

Please sign in to comment.