Data view
This commit is contained in:
@@ -74,6 +74,8 @@ impl Hooks for App {
|
||||
tasks.register(tasks::create_job::CreateJobData);
|
||||
tasks.register(tasks::create_skill::CreateSkillData);
|
||||
tasks.register(tasks::add_data_file::AddDataFile);
|
||||
tasks.register(tasks::delete_data::DeleteData);
|
||||
tasks.register(tasks::clear_data::ClearData);
|
||||
}
|
||||
|
||||
async fn truncate(db: &DatabaseConnection) -> Result<()> {
|
||||
|
@@ -54,6 +54,19 @@ pub async fn render_project_detail_from_name(
|
||||
views::website::project_detail_from_name(v, &ctx, name).await
|
||||
}
|
||||
|
||||
pub async fn render_data(
|
||||
auth: auth::JWT,
|
||||
ViewEngine(v): ViewEngine<TeraView>,
|
||||
State(ctx): State<AppContext>,
|
||||
) -> Result<impl IntoResponse> {
|
||||
match users::Model::find_by_pid(&ctx.db, &auth.claims.pid).await {
|
||||
Ok(_) => {}
|
||||
Err(_) => return unauthorized("Unauthorized"),
|
||||
}
|
||||
|
||||
views::data::list(v, &ctx).await
|
||||
}
|
||||
|
||||
pub fn routes() -> Routes {
|
||||
Routes::new()
|
||||
.add("/", get(render_index))
|
||||
@@ -62,5 +75,6 @@ pub fn routes() -> Routes {
|
||||
.add("/projects", get(render_projects))
|
||||
.add("/projects/:id", get(render_project_detail))
|
||||
.add("/projects/project/:name", get(render_project_detail_from_name))
|
||||
.add("/data", get(render_data))
|
||||
.add("/about", get(render_about))
|
||||
}
|
||||
|
@@ -30,6 +30,18 @@ pub struct ProjectDto {
|
||||
pub thumbnails: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CreateProject {
|
||||
pub name: String,
|
||||
pub short_description: String,
|
||||
pub description: Option<String>,
|
||||
pub category: Category,
|
||||
pub github_url: Option<String>,
|
||||
pub download_url: Option<String>,
|
||||
pub visit_url: Option<String>,
|
||||
pub technologies: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn get_category_from_string(category: &str) -> Category {
|
||||
match category {
|
||||
"Web" => Category::Web,
|
||||
@@ -44,4 +56,14 @@ pub fn get_category_from_string(category: &str) -> Category {
|
||||
"api" => Category::Api,
|
||||
_ => Category::Desktop,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_string_from_category(category: &Category) -> String {
|
||||
match category {
|
||||
Category::Web => "Web".to_string(),
|
||||
Category::Mobile => "Mobile".to_string(),
|
||||
Category::Desktop => "Desktop".to_string(),
|
||||
Category::Game => "Game".to_string(),
|
||||
Category::Api => "Api".to_string(),
|
||||
}
|
||||
}
|
@@ -15,6 +15,11 @@ use std::fs::{self};
|
||||
use axum_range::KnownSize;
|
||||
use axum_range::Ranged;
|
||||
|
||||
pub async fn get_all_data(ctx: &AppContext) -> ModelResult<Vec<Model>> {
|
||||
let data = Entity::find().all(&ctx.db).await?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub async fn get_data_by_file_name(file_name: &str, ctx: &AppContext) -> ModelResult<Model> {
|
||||
let data = Entity::find()
|
||||
.filter(data::Column::FileName.eq(file_name))
|
||||
@@ -183,3 +188,41 @@ pub async fn add(
|
||||
}
|
||||
Ok(item)
|
||||
}
|
||||
|
||||
pub async fn clear_all_data(ctx: &AppContext) -> ModelResult<()> {
|
||||
let data = get_all_data(&ctx).await?;
|
||||
for item in data {
|
||||
let path = PathBuf::from(&item.file_url);
|
||||
tracing::info!("Deleting file: {:?}", path);
|
||||
match ctx.storage.as_ref().delete(&path).await {
|
||||
Ok(_) => {}
|
||||
Err(_) => return Err(ModelError::Any("Failed to delete file from storage".into())),
|
||||
}
|
||||
|
||||
item.delete(&ctx.db).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_data_by_file_name(file_name: &str, ctx: &AppContext) -> ModelResult<()> {
|
||||
let data = get_data_by_file_name(&file_name, &ctx).await?;
|
||||
|
||||
let path = PathBuf::from(&data.file_url);
|
||||
match ctx.storage.as_ref().delete(&path).await {
|
||||
Ok(_) => {}
|
||||
Err(_) => return Err(ModelError::Any("Failed to delete file from storage".into())),
|
||||
}
|
||||
|
||||
data.delete(&ctx.db).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_multiple_data_by_file_names(
|
||||
file_names: Vec<String>,
|
||||
ctx: &AppContext,
|
||||
) -> ModelResult<()> {
|
||||
for file_name in file_names {
|
||||
delete_data_by_file_name(&file_name, &ctx).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
@@ -4,9 +4,9 @@ use crate::{
|
||||
models::{
|
||||
_entities::{
|
||||
project_thumbnails,
|
||||
projects::{self, Entity, Model},
|
||||
projects::{self, ActiveModel, Entity, Model},
|
||||
},
|
||||
projects::{get_category_from_string, ProjectDto},
|
||||
projects::{get_category_from_string, get_string_from_category, Category, CreateProject, ProjectDto},
|
||||
},
|
||||
shared::get_technologies_from_string::get_technologies_from_string,
|
||||
};
|
||||
@@ -139,3 +139,25 @@ pub async fn get_project_dto_by_name(ctx: &AppContext, name: &str) -> Result<Pro
|
||||
|
||||
Ok(project_dto)
|
||||
}
|
||||
|
||||
pub async fn add_project(
|
||||
ctx: &AppContext,
|
||||
data: CreateProject,
|
||||
) -> ModelResult<Model> {
|
||||
let mut item = ActiveModel {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
item.name = Set(data.name);
|
||||
item.short_description = Set(data.short_description);
|
||||
item.description = Set(data.description);
|
||||
item.category = Set(get_string_from_category(&data.category));
|
||||
item.github_url = Set(data.github_url);
|
||||
item.download_url = Set(data.download_url);
|
||||
item.visit_url = Set(data.visit_url);
|
||||
item.technology = Set(data.technologies.join(","));
|
||||
|
||||
let item = item.insert(&ctx.db).await?;
|
||||
|
||||
Ok(item)
|
||||
}
|
||||
|
@@ -5,3 +5,7 @@ pub fn get_technologies_from_string(technologies: &str) -> Vec<String> {
|
||||
.filter(|s| !s.trim().is_empty())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn convert_technologies_to_string(technologies: Vec<String>) -> String {
|
||||
technologies.join(", ")
|
||||
}
|
23
src/tasks/clear_data.rs
Normal file
23
src/tasks/clear_data.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use loco_rs::prelude::*;
|
||||
|
||||
use crate::services;
|
||||
|
||||
pub struct ClearData;
|
||||
|
||||
#[async_trait]
|
||||
impl Task for ClearData {
|
||||
fn task(&self) -> TaskInfo {
|
||||
TaskInfo {
|
||||
name: "clear_data".to_string(),
|
||||
detail: "Task for clearing all data".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(&self, app_context: &AppContext, _vars: &task::Vars) -> Result<()> {
|
||||
services::data::clear_all_data(&app_context).await?;
|
||||
|
||||
tracing::info!("All data cleared successfully");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
24
src/tasks/delete_data.rs
Normal file
24
src/tasks/delete_data.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use loco_rs::prelude::*;
|
||||
|
||||
use crate::services;
|
||||
|
||||
pub struct DeleteData;
|
||||
|
||||
#[async_trait]
|
||||
impl Task for DeleteData {
|
||||
fn task(&self) -> TaskInfo {
|
||||
TaskInfo {
|
||||
name: "delete_data".to_string(),
|
||||
detail: "Task for deleting all data".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(&self, app_context: &AppContext, vars: &task::Vars) -> Result<()> {
|
||||
let file_name = vars.cli_arg("name")?;
|
||||
|
||||
services::data::delete_data_by_file_name(&file_name, &app_context).await?;
|
||||
|
||||
tracing::info!("Data file {} deleted successfully", file_name);
|
||||
Ok(())
|
||||
}
|
||||
}
|
@@ -3,3 +3,5 @@ pub mod create_job;
|
||||
pub mod create_skill;
|
||||
pub mod create_user;
|
||||
pub mod seed;
|
||||
pub mod clear_data;
|
||||
pub mod delete_data;
|
@@ -1,5 +1,12 @@
|
||||
use loco_rs::prelude::*;
|
||||
|
||||
use crate::services;
|
||||
|
||||
pub async fn upload(v: impl ViewRenderer) -> Result<impl IntoResponse> {
|
||||
format::render().view(&v, "website/data-upload.html", data!({}))
|
||||
}
|
||||
|
||||
pub async fn list(v: impl ViewRenderer, ctx: &AppContext) -> Result<impl IntoResponse> {
|
||||
let data = services::data::get_all_data(&ctx).await?;
|
||||
format::render().view(&v, "website/data.html", data!({ "data": data }))
|
||||
}
|
Reference in New Issue
Block a user