use async_trait::async_trait; use log::{debug, warn}; use rear::depot::prelude::*; use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityTrait, ModelTrait, Set}; use serde_json::Value; use crate::models::UserRepository; #[async_trait] impl DepotRepository for UserRepository { type Key = i64; fn key_from_string(&self, s: String) -> Option { if let Ok(i) = s.parse::() { Some(i) } else { None } } async fn info(&self, _: &RepositoryContext) -> RepositoryInfo { RepoInfo { name: "User", lookup_key: "id", display_list: &["id", "username"], fields: &[ "username", "password", "first_name", "last_name", "email", "is_staff", "is_active", "is_superuser", ], // fields_readonly: &["last_login", "date_joined"] } .build() .set_widget( "password", Widget::widget("/admin/widgets/password_change.jinja").as_password(), ) .set_widget("is_staff", Widget::checkbox()) .set_widget("is_active", Widget::checkbox()) .set_widget("is_superuser", Widget::checkbox()) } async fn get(&self, model: &RepositoryContext, id: &Self::Key) -> RepositoryResult { let id: i32 = *id as i32; // use try_into() instead. let get_user = entity::User::find_by_id(id).one(&self.connection).await; if let Ok(get_user) = get_user { if let Some(user) = get_user { let id = user.id.to_string(); match serde_json::to_value(&user) { Ok(item) => { return Ok(RepositoryResponse::ItemOnly(model.build_item(&*id, item))); } Err(_) => { return Err(RepositoryError::UnknownError( "JSON Error creating value".to_owned(), )) } } } } Ok(RepositoryResponse::NoItem) } async fn list(&self, model: &RepositoryContext) -> RepositoryList { let results = if let Ok(results) = entity::User::find().all(&self.connection).await { results } else { return RepositoryList::Empty; }; let repository_items: Vec = results .into_iter() .filter_map(|item| match serde_json::to_value(&item) { Ok(fields) => { let id = item.id.to_string(); Some(model.build_item(&*id, fields)) } Err(_) => None, }) .collect(); RepositoryList::List { values: repository_items, } } async fn create(&mut self, model: &RepositoryContext, data: Value) -> RepositoryResult { if let Value::Object(data) = data { let username = data.get("username").unwrap().as_str().unwrap(); let password = data.get("password").unwrap().as_str().unwrap(); let mut user = UserRepository::new_user(username, password); let keys = [ "first_name", "last_name", "email", "is_staff", "is_active", "is_superuser", ]; for key in &keys { if let Some(value) = data.get(*key) { match *key { "first_name" => user.first_name = Set(value.as_str().map(|s| s.to_owned())), "last_name" => user.last_name = Set(value.as_str().map(|s| s.to_owned())), "email" => user.email = Set(value.as_str().map(|s| s.to_owned())), "is_staff" => user.is_staff = Set(value.as_bool().unwrap_or(false)), "is_active" => user.is_active = Set(value.as_bool().unwrap_or(true)), "is_superuser" => user.is_superuser = Set(value.as_bool().unwrap_or(false)), _ => (), } } } if let Ok(user) = user.insert(&self.connection).await { let id = user.id.to_string(); let item = model.build_item(&*id, serde_json::to_value(&user).unwrap()); return Ok(RepositoryResponse::ItemOnly(item)); } } Ok(RepositoryResponse::NoItem) } async fn update( &mut self, model: &RepositoryContext, id: &Self::Key, data: Value, ) -> RepositoryResult { let id: i32 = *id as i32; let user: Option = entity::User::find_by_id(id) .one(&self.connection) .await .map_err(|e| RepositoryError::DatabaseError(Box::new(e)))?; let mut user: entity::user::ActiveModel = user.ok_or(RepositoryError::ItemNotFound)?.into(); // should we really allow username change? if let Some(value) = data.get("username") { if let Some(value) = value.as_str() { user.username = Set(value.to_owned()); } } let keys = [ "first_name", "last_name", "email", "is_staff", "is_active", "is_superuser", ]; for key in &keys { if let Some(value) = data.get(*key) { match *key { "first_name" => user.first_name = Set(value.as_str().map(|s| s.to_owned())), "last_name" => user.last_name = Set(value.as_str().map(|s| s.to_owned())), "email" => user.email = Set(value.as_str().map(|s| s.to_owned())), "is_staff" => user.is_staff = Set(value.as_bool().unwrap_or(false)), "is_active" => user.is_active = Set(value.as_bool().unwrap_or(true)), "is_superuser" => user.is_superuser = Set(value.as_bool().unwrap_or(false)), _ => (), } } } // update match user.update(&self.connection).await { Ok(user) => { let id = user.id.to_string(); return Ok(RepositoryResponse::ItemOnly( model.build_item(&*id, serde_json::to_value(&user).unwrap()), )); } Err(err) => { warn!("Error updating user"); return Err(RepositoryError::DatabaseError(Box::new(err))); } } } async fn replace( &mut self, model: &RepositoryContext, id: &Self::Key, data: Value, ) -> RepositoryResult { self.update(model, id, data).await } async fn delete(&mut self, _: &RepositoryContext, id: &Self::Key) -> Option { let id: i32 = *id as i32; let user: Option = entity::User::find_by_id(id) .one(&self.connection) .await .unwrap(); if let Some(user) = user { let delete_result = user.delete(&self.connection).await.unwrap(); // .ok_or(RepositoryError::DatabaseError(Box::new(err)))?; debug!("deleted rows: {}", delete_result.rows_affected); } None } } pub fn register(registry: &mut DepotRegistry, db: DatabaseConnection) -> UserRepository { let section_key = registry.register_section("Auth"); let repo = UserRepository::new(db); let model_config = DepotModelConfig { section_key: section_key, name: "User".to_owned(), }; let model_result = registry.register_model(model_config, repo.clone()); match model_result { Err(err) => panic!("{}", err), _ => repo, } }