Add task for adding data file from FS. Improve home page
This commit is contained in:
File diff suppressed because one or more lines are too long
BIN
assets/static/images/optimized.jpg
Normal file
BIN
assets/static/images/optimized.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 585 KiB |
@@ -1,6 +1,5 @@
|
|||||||
{% import "website/macros/chip.html" as chip %} {% extends "website/base.html"
|
{% import "website/macros/chip.html" as chip %} {% extends "website/base.html"
|
||||||
%} {% block content %}
|
%} {% block content %}
|
||||||
<span class="m-8">🌟</span>
|
|
||||||
<div
|
<div
|
||||||
class="flex flex-col items-center justify-center gap-2 p-4 bg-white rounded-lg"
|
class="flex flex-col items-center justify-center gap-2 p-4 bg-white rounded-lg"
|
||||||
>
|
>
|
||||||
@@ -34,11 +33,9 @@
|
|||||||
<div
|
<div
|
||||||
class="flex flex-wrap items-center justify-center gap-4 m-4 md:m-0 md:w-1/2"
|
class="flex flex-wrap items-center justify-center gap-4 m-4 md:m-0 md:w-1/2"
|
||||||
>
|
>
|
||||||
{{ chip::chip(text="Computer Science 💾")}}
|
{{ chip::chip(text="Computer Science 💾")}} {{ chip::chip(text="Sci-Fi
|
||||||
{{ chip::chip(text="Sci-Fi Books📚")}}
|
Books📚")}} {{ chip::chip(text="Astronomy 🔭")}} {{ chip::chip(text="Sports
|
||||||
{{ chip::chip(text="Astronomy 🔭")}}
|
🏅") }} {{ chip::chip(text="History 🏰")}}
|
||||||
{{ chip::chip(text="Sports 🏅") }}
|
|
||||||
{{ chip::chip(text="History 🏰")}}
|
|
||||||
</div>
|
</div>
|
||||||
<h1 class="mt-6 text-3xl font-bold">FAQ ❓</h1>
|
<h1 class="mt-6 text-3xl font-bold">FAQ ❓</h1>
|
||||||
<div class="flex flex-col gap-2 m-4">
|
<div class="flex flex-col gap-2 m-4">
|
||||||
|
@@ -1,8 +1,7 @@
|
|||||||
<nav
|
<nav
|
||||||
class="fixed z-20 flex flex-col items-center justify-center w-full p-4 bg-gray-900 shadow-2xl md:flex-row"
|
class="fixed z-20 flex flex-col items-center justify-center w-full p-4 bg-transparent md:flex-row"
|
||||||
id="navbar"
|
id="navbar"
|
||||||
>
|
>
|
||||||
<a href="/" class="text-2xl"> Gabriel Kaszewski </a>
|
|
||||||
<span class="flex-1"></span>
|
<span class="flex-1"></span>
|
||||||
<div class="flex gap-4">
|
<div class="flex gap-4">
|
||||||
<a href="/" class="text-lg"> Home </a>
|
<a href="/" class="text-lg"> Home </a>
|
||||||
|
@@ -1,5 +1,126 @@
|
|||||||
{% import "website/macros/chip.html" as chip %} {% extends "website/base.html"
|
{% import "website/macros/chip.html" as chip %} {% extends "website/base.html"
|
||||||
%} {% block content %}
|
%} {% block content %}
|
||||||
|
<div class="w-full">
|
||||||
|
<div class="relative inline-block w-full min-w-full">
|
||||||
|
<img
|
||||||
|
src="/static/images/optimized.jpg"
|
||||||
|
alt="Background"
|
||||||
|
class="object-cover w-full max-h-full pointer-events-none"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="absolute inset-0 flex flex-col items-center justify-center w-full gap-4 md:items-start md:justify-start md:p-16 lg:p-20"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<h1
|
||||||
|
class="mb-4 text-2xl font-bold tracking-tight text-white md:text-4xl lg:text-6xl md:mb-0"
|
||||||
|
>
|
||||||
|
Gabriel Kaszewski
|
||||||
|
</h1>
|
||||||
|
<h2
|
||||||
|
class="mt-8 text-lg font-light tracking-tight text-white md:text-xl lg:text-2xl md:mt-0"
|
||||||
|
>
|
||||||
|
Full-Stack Developer
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="items-center hidden gap-2 md:flex">
|
||||||
|
<a href="/api/data/cv.pdf" title="My CV">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path d="M14 2v4a2 2 0 0 0 2 2h4" />
|
||||||
|
<path d="M15 18a3 3 0 1 0-6 0" />
|
||||||
|
<path
|
||||||
|
d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z"
|
||||||
|
/>
|
||||||
|
<circle cx="12" cy="13" r="2" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/GKaszewski" title="GitHub">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4"
|
||||||
|
/>
|
||||||
|
<path d="M9 18c-4.51 2-5-2-7-2" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a href="mailto: gabrielkaszewski@gmail.com" title="My email">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<circle cx="12" cy="12" r="4" />
|
||||||
|
<path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://www.linkedin.com/in/gabriel-kaszewski-5344b3183"
|
||||||
|
title="LinkedIn"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"
|
||||||
|
/>
|
||||||
|
<rect width="4" height="12" x="2" y="9" />
|
||||||
|
<circle cx="4" cy="4" r="2" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="absolute bottom-0 p-2 text-sm">
|
||||||
|
<span class="flex gap-1">
|
||||||
|
Photo by
|
||||||
|
<a
|
||||||
|
class="underline"
|
||||||
|
href="https://unsplash.com/@federize?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash"
|
||||||
|
>
|
||||||
|
Federico Beccari
|
||||||
|
</a>
|
||||||
|
on
|
||||||
|
<a
|
||||||
|
class="underline"
|
||||||
|
href="https://unsplash.com/photos/red-moon-eGJg5iRGlg8?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash"
|
||||||
|
>
|
||||||
|
Unsplash
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="w-full mt-8"></div>
|
<div class="w-full mt-8"></div>
|
||||||
<h3 class="mt-4 mb-2 text-5xl font-bold tracking-tight">Who am I? 🤔</h3>
|
<h3 class="mt-4 mb-2 text-5xl font-bold tracking-tight">Who am I? 🤔</h3>
|
||||||
<section
|
<section
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
use core::task;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@@ -72,6 +73,7 @@ impl Hooks for App {
|
|||||||
tasks.register(tasks::create_user::CreateUserData);
|
tasks.register(tasks::create_user::CreateUserData);
|
||||||
tasks.register(tasks::create_job::CreateJobData);
|
tasks.register(tasks::create_job::CreateJobData);
|
||||||
tasks.register(tasks::create_skill::CreateSkillData);
|
tasks.register(tasks::create_skill::CreateSkillData);
|
||||||
|
tasks.register(tasks::add_data_file::AddDataFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn truncate(db: &DatabaseConnection) -> Result<()> {
|
async fn truncate(db: &DatabaseConnection) -> Result<()> {
|
||||||
|
@@ -33,7 +33,7 @@ pub async fn upload_data(
|
|||||||
Err(_) => return unauthorized("Unauthorized"),
|
Err(_) => return unauthorized("Unauthorized"),
|
||||||
}
|
}
|
||||||
|
|
||||||
services::data::add(&auth, &ctx, payload).await?;
|
services::data::add(&auth, &ctx, payload, true).await?;
|
||||||
format::html("<h1>File uploaded successfully</h1>")
|
format::html("<h1>File uploaded successfully</h1>")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,9 +5,13 @@ use crate::models::users::users;
|
|||||||
use axum::extract::Multipart;
|
use axum::extract::Multipart;
|
||||||
use axum_extra::headers::Range;
|
use axum_extra::headers::Range;
|
||||||
use axum_extra::TypedHeader;
|
use axum_extra::TypedHeader;
|
||||||
|
|
||||||
|
use bytes::Bytes;
|
||||||
use loco_rs::prelude::*;
|
use loco_rs::prelude::*;
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
|
|
||||||
|
use std::fs::{self};
|
||||||
|
|
||||||
use axum_range::KnownSize;
|
use axum_range::KnownSize;
|
||||||
use axum_range::Ranged;
|
use axum_range::Ranged;
|
||||||
|
|
||||||
@@ -51,7 +55,49 @@ pub async fn serve_data_file(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn add(auth: &auth::JWT, ctx: &AppContext, mut payload: Multipart) -> ModelResult<Model> {
|
pub async fn add_data_file_from_path(
|
||||||
|
ctx: &AppContext,
|
||||||
|
file_path: &str,
|
||||||
|
file_name: &str,
|
||||||
|
protected: bool,
|
||||||
|
uuid_name: bool,
|
||||||
|
) -> ModelResult<Model> {
|
||||||
|
let ext = String::from(file_name.split('.').last().unwrap_or("txt"));
|
||||||
|
let file_name = if uuid_name {
|
||||||
|
let temp_file_name = uuid::Uuid::new_v4().to_string();
|
||||||
|
format!("{}.{}", temp_file_name, ext)
|
||||||
|
} else {
|
||||||
|
file_name.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let path = PathBuf::from(file_path);
|
||||||
|
let content = fs::read(&path).map_err(|_| ModelError::Any("Failed to read file".into()))?;
|
||||||
|
let content = Bytes::from(content);
|
||||||
|
|
||||||
|
let mut item = ActiveModel {
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
item.protected = Set(protected);
|
||||||
|
item.file_name = Set(file_name.to_string());
|
||||||
|
item.file_url = Set(format!("uploads/{}", file_name));
|
||||||
|
|
||||||
|
let item = item.insert(&ctx.db).await?;
|
||||||
|
|
||||||
|
match ctx.storage.as_ref().upload(&path.as_path(), &content).await {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(_) => return Err(ModelError::Any("Failed to save file to storage".into())),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn add(
|
||||||
|
auth: &auth::JWT,
|
||||||
|
ctx: &AppContext,
|
||||||
|
mut payload: Multipart,
|
||||||
|
uuid_name: bool,
|
||||||
|
) -> ModelResult<Model> {
|
||||||
let _current_user = users::Model::find_by_pid(&ctx.db, &auth.claims.pid).await?;
|
let _current_user = users::Model::find_by_pid(&ctx.db, &auth.claims.pid).await?;
|
||||||
|
|
||||||
let mut protected = None;
|
let mut protected = None;
|
||||||
@@ -83,7 +129,13 @@ pub async fn add(auth: &auth::JWT, ctx: &AppContext, mut payload: Multipart) ->
|
|||||||
.ok_or_else(|| ModelError::Any("Failed to get file name".into()))?;
|
.ok_or_else(|| ModelError::Any("Failed to get file name".into()))?;
|
||||||
let ext = String::from(og_file_name.split('.').last().unwrap_or("txt"));
|
let ext = String::from(og_file_name.split('.').last().unwrap_or("txt"));
|
||||||
|
|
||||||
let temp_file_name = uuid::Uuid::new_v4().to_string();
|
let temp_file_name = if uuid_name {
|
||||||
|
let temp_file_name = uuid::Uuid::new_v4().to_string();
|
||||||
|
format!("{}.{}", temp_file_name, ext)
|
||||||
|
} else {
|
||||||
|
og_file_name.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
let temp_file_name = format!("{}.{}", temp_file_name, ext);
|
let temp_file_name = format!("{}.{}", temp_file_name, ext);
|
||||||
|
|
||||||
file_name = Some(temp_file_name.clone());
|
file_name = Some(temp_file_name.clone());
|
||||||
|
38
src/tasks/add_data_file.rs
Normal file
38
src/tasks/add_data_file.rs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
use loco_rs::prelude::*;
|
||||||
|
|
||||||
|
use crate::services;
|
||||||
|
|
||||||
|
pub struct AddDataFile;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Task for AddDataFile {
|
||||||
|
fn task(&self) -> TaskInfo {
|
||||||
|
TaskInfo {
|
||||||
|
name: "add_data_file".to_string(),
|
||||||
|
detail: "Task for adding a new data file".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run(&self, app_context: &AppContext, vars: &task::Vars) -> Result<()> {
|
||||||
|
let file_path = vars.cli_arg("file_path")?;
|
||||||
|
let file_name = vars.cli_arg("file_name")?;
|
||||||
|
let protected = vars.cli_arg("protected")?;
|
||||||
|
let uuid_name = vars.cli_arg("uuid_name")?;
|
||||||
|
|
||||||
|
let protected = protected.parse::<bool>().unwrap_or(false);
|
||||||
|
let uuid_name = uuid_name.parse::<bool>().unwrap_or(false);
|
||||||
|
|
||||||
|
services::data::add_data_file_from_path(
|
||||||
|
&app_context,
|
||||||
|
file_path,
|
||||||
|
file_name,
|
||||||
|
protected,
|
||||||
|
uuid_name,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
tracing::info!("Data file added successfully");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@@ -1,3 +1,4 @@
|
|||||||
|
pub mod add_data_file;
|
||||||
pub mod create_job;
|
pub mod create_job;
|
||||||
pub mod create_skill;
|
pub mod create_skill;
|
||||||
pub mod create_user;
|
pub mod create_user;
|
||||||
|
Reference in New Issue
Block a user