wip
This commit is contained in:
parent
2b133a9f3f
commit
32a9ed081e
@ -1,8 +1,11 @@
|
|||||||
[debug]
|
[debug]
|
||||||
static_route = "http://localhost:8001"
|
static_route = "http://localhost:8001"
|
||||||
cv_backend_path = "http://localhost:8002"
|
cv_backend_path = "http://localhost:8002"
|
||||||
|
contact_path = "http://localhost:8004"
|
||||||
|
|
||||||
[default]
|
[default]
|
||||||
static_route = "http://localhost:8001"
|
static_route = "http://localhost:8001"
|
||||||
cv_backend_path = "http://localhost:8002"
|
cv_backend_path = "http://localhost:8002"
|
||||||
|
contact_service = "http://localhost:8004"
|
||||||
|
pdf_service = "http://localhost:8003"
|
||||||
default_person_name = "ovlach"
|
default_person_name = "ovlach"
|
||||||
|
11
src/lib.rs
11
src/lib.rs
@ -3,7 +3,7 @@ use nanobyte_tera::{hosts::static_filter, l18n::translate_filter, date::{calcula
|
|||||||
use ovlach_tera::entity::lang_entity;
|
use ovlach_tera::entity::lang_entity;
|
||||||
use rocket::{*, fairing::AdHoc};
|
use rocket::{*, fairing::AdHoc};
|
||||||
use rocket_dyn_templates::Template;
|
use rocket_dyn_templates::Template;
|
||||||
use ::serde::Deserialize;
|
use ::serde::{Deserialize, Serialize};
|
||||||
use tools::tera::advanced_filter;
|
use tools::tera::advanced_filter;
|
||||||
|
|
||||||
pub mod routes;
|
pub mod routes;
|
||||||
@ -22,6 +22,13 @@ pub struct CVBackendConfig {
|
|||||||
cv_backend_path: String,
|
cv_backend_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(crate = "rocket::serde")]
|
||||||
|
pub struct FrontendSVCConfig {
|
||||||
|
pub contact_service: String,
|
||||||
|
pub pdf_service: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(crate = "rocket::serde")]
|
#[serde(crate = "rocket::serde")]
|
||||||
pub struct DefaultPerson {
|
pub struct DefaultPerson {
|
||||||
@ -55,6 +62,8 @@ pub fn rocket_builder() -> Rocket<Build> {
|
|||||||
AdHoc::config::<CVBackendConfig>()
|
AdHoc::config::<CVBackendConfig>()
|
||||||
).attach(
|
).attach(
|
||||||
AdHoc::config::<DefaultPerson>()
|
AdHoc::config::<DefaultPerson>()
|
||||||
|
).attach(
|
||||||
|
AdHoc::config::<FrontendSVCConfig>()
|
||||||
).attach(
|
).attach(
|
||||||
nanobyte_opentelemetry::rocket::TracingFairing::ignite()
|
nanobyte_opentelemetry::rocket::TracingFairing::ignite()
|
||||||
).mount("/", routes![
|
).mount("/", routes![
|
||||||
|
@ -8,27 +8,29 @@ use rocket::{get, State, response::Redirect, http::Status, futures::executor::en
|
|||||||
use rocket_dyn_templates::Template;
|
use rocket_dyn_templates::Template;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::{PresentationConfig, services::cv::fetch_cv_data_from_backend, CVBackendConfig, tools::rocket::RequestLanguage, DefaultPerson};
|
use crate::{PresentationConfig, services::cv::fetch_cv_data_from_backend, CVBackendConfig, tools::rocket::RequestLanguage, DefaultPerson, FrontendSVCConfig};
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
struct RootPage {
|
struct RootPage {
|
||||||
static_host: String,
|
static_host: String,
|
||||||
cv: CV,
|
cv: CV,
|
||||||
download_cv_url: String,
|
|
||||||
lang: LanguageDescription,
|
lang: LanguageDescription,
|
||||||
|
contact_svc: String,
|
||||||
|
pdf_download_url: String
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/<language>")]
|
#[get("/<language>")]
|
||||||
pub async fn index(presentation_config: &State<PresentationConfig>, cv_config: &State<CVBackendConfig>, language: RequestLanguage, client: OtelReqwestClient,
|
pub async fn index(presentation_config: &State<PresentationConfig>, cv_config: &State<CVBackendConfig>, language: RequestLanguage, client: OtelReqwestClient,
|
||||||
default_person: &State<DefaultPerson>, span: TracingSpan) -> Result<Template, Status> {
|
default_person: &State<DefaultPerson>, frontend_svc: &State<FrontendSVCConfig>, span: TracingSpan) -> Result<Template, Status> {
|
||||||
let span = span.0.enter();
|
let span = span.0.enter();
|
||||||
|
|
||||||
let context = match fetch_cv_data_from_backend(&cv_config.cv_backend_path, &default_person.default_person_name, &client.0).await {
|
let context = match fetch_cv_data_from_backend(&cv_config.cv_backend_path, &default_person.default_person_name, &client.0).await {
|
||||||
Ok(cv) => RootPage {
|
Ok(cv) => RootPage {
|
||||||
static_host: presentation_config.static_route.clone(),
|
static_host: presentation_config.static_route.clone(),
|
||||||
cv,
|
cv,
|
||||||
download_cv_url: "FIXME!".to_string(),
|
|
||||||
lang: LanguageDescription::new(&language.language.as_str(), "ovlach_frontend"),
|
lang: LanguageDescription::new(&language.language.as_str(), "ovlach_frontend"),
|
||||||
|
contact_svc: frontend_svc.inner().contact_service.clone(),
|
||||||
|
pdf_download_url: format!("{}/cv/{}/output.pdf", frontend_svc.inner().pdf_service.clone(), default_person.default_person_name)
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Can't fetch CV data from backend {:?}", e);
|
error!("Can't fetch CV data from backend {:?}", e);
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-print-none">
|
<div class="d-print-none">
|
||||||
<a class="btn btn-outline-light btn-lg shadow-sm mt-1 me-3" href="{{ download_cv_url }}" data-aos="fade-right" data-aos-delay="700">{{ "download-cv" | translate(lang=lang) }}</a>
|
<a class="btn btn-outline-light btn-lg shadow-sm mt-1 me-3" href="{{ pdf_download_url }}" data-aos="fade-right" data-aos-delay="700">{{ "download-cv" | translate(lang=lang) }}</a>
|
||||||
<a class="btn btn-info btn-lg shadow-sm mt-1" href="#contact" data-aos="fade-left" data-aos-delay="700"> {{ "hire-me" | translate(lang=lang) }} </a></div>
|
<a class="btn btn-info btn-lg shadow-sm mt-1" href="#contact" data-aos="fade-left" data-aos-delay="700"> {{ "hire-me" | translate(lang=lang) }} </a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -132,6 +132,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% for skill in cv.skills | filter(attribute="techtype",value="Language") | advanced_filter(attribute="skill", include_null="only") %}
|
||||||
|
<span class="fw-bolder">{{ skill.name }}</span>{% if not loop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
{% for skill in cv.skills | filter(attribute="techtype",value="Technology") | advanced_filter(attribute="skill", include_null="none") %}
|
{% for skill in cv.skills | filter(attribute="techtype",value="Technology") | advanced_filter(attribute="skill", include_null="none") %}
|
||||||
@ -145,6 +148,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% for skill in cv.skills | filter(attribute="techtype",value="Technology") | advanced_filter(attribute="skill", include_null="only") %}
|
||||||
|
<span class="fw-bolder">{{ skill.name }}</span>{% if not loop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h2 class="h2 fw-light mb-4">{{ "frameworks-and-databases" | translate(lang=lang) }}</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
{% for skill in cv.skills | filter(attribute="techtype",value="Framework") | advanced_filter(attribute="skill", include_null="none") %}
|
{% for skill in cv.skills | filter(attribute="techtype",value="Framework") | advanced_filter(attribute="skill", include_null="none") %}
|
||||||
<div class="mb-3"><span class="fw-bolder">{{ skill.name }}</span>
|
<div class="mb-3"><span class="fw-bolder">{{ skill.name }}</span>
|
||||||
<div class="progress my-2 rounded" style="height: 20px">
|
<div class="progress my-2 rounded" style="height: 20px">
|
||||||
@ -156,11 +167,40 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for skill in cv.skills | filter(attribute="techtype",value="Technology") | advanced_filter(attribute="skill", include_null="only") %}
|
{% for skill in cv.skills | filter(attribute="techtype",value="Framework") | advanced_filter(attribute="skill", include_null="only") %}
|
||||||
<span class="fw-bolder">{{ skill.name }}</span>,<!-- TODO: fix last, -->
|
<span class="fw-bolder">{{ skill.name }}</span>{% if not loop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{% for skill in cv.skills | filter(attribute="techtype",value="Database") | advanced_filter(attribute="skill", include_null="none") %}
|
||||||
|
<div class="mb-3"><span class="fw-bolder">{{ skill.name }}</span>
|
||||||
|
<div class="progress my-2 rounded" style="height: 20px">
|
||||||
|
<div class="progress-bar bg-info" role="progressbar" data-aos="zoom-in-right" data-aos-delay="100"
|
||||||
|
data-aos-anchor=".skills-section" style="width: {% if skill.skill == "Master" %}100%{% endif %}{% if skill.skill == "Expert" %}75%{% endif %}{% if skill.skill == "Intermediate" %}50%{% endif %}{% if skill.skill == "Beginer" %}25%{% endif %};"
|
||||||
|
aria-valuenow="95" aria-valuemin="0" aria-valuemax="100">
|
||||||
|
{{ skill.skill}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% for skill in cv.skills | filter(attribute="techtype",value="Database") | advanced_filter(attribute="skill", include_null="only") %}
|
||||||
|
<span class="fw-bolder">{{ skill.name }}</span>{% if not loop.last %},{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="fw-bolder">{{"tools" | translate(lang=lang)}}:</span> {% for skill in cv.skills | filter(attribute="techtype",value="Tool") | advanced_filter(attribute="skill", include_null="all") %}
|
||||||
|
{{ skill.name }}{% if skill.skill %} - {{skill.skill}}{% endif %},<!-- TODO: fix-me (empty "," if operating system empty) %-->
|
||||||
|
{% endfor %}
|
||||||
|
<span class="fw-bolder">{{"operating-systems" | translate(lang=lang)}}:</span> {% for skill in cv.skills | filter(attribute="techtype",value="OperatingSystem") | advanced_filter(attribute="skill", include_null="all") %}
|
||||||
|
{{ skill.name }}</span>{% if skill.skill %} - {{skill.skill}}{% endif %}{% if not loop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<span class="fw-bolder">{{"languages" | translate(lang=lang)}}:</span>
|
||||||
|
{% for language in cv.languages %}
|
||||||
|
{{language.lang}} - {{language.level|translate(lang=lang)}}
|
||||||
|
{% if not loop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -168,13 +208,45 @@
|
|||||||
<div class="work-experience-section">
|
<div class="work-experience-section">
|
||||||
<h2 class="h2 fw-light mb-4">{{ "work-experience" | translate(lang=lang) }}</h2>
|
<h2 class="h2 fw-light mb-4">{{ "work-experience" | translate(lang=lang) }}</h2>
|
||||||
<div class="timeline">
|
<div class="timeline">
|
||||||
{% for job in cv.jobs %}
|
{% for job in cv.jobs | filter(attribute="jobtype", value="Contract") %}
|
||||||
|
<div class="timeline-card timeline-card-info" data-aos="fade-in" data-aos-delay="{{ loop.index * 10 }}">
|
||||||
|
<div class="timeline-head px-4 pt-3">
|
||||||
|
<div class="h5">{{ job.title }} <span class="text-muted h6">at {{ job.company }}</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="timeline-body px-4 pb-4">
|
||||||
|
{% if job.languages and job.technologies %}
|
||||||
|
{{ job.languages | concat(with=job.technologies) }}
|
||||||
|
{% elif job.languages %}
|
||||||
|
{{job.languages}}
|
||||||
|
{% elif job.technologies %}
|
||||||
|
{{job.technologies}}
|
||||||
|
{% endif %}
|
||||||
|
{% if job.from | format_date(type="job") != job.to | format_date(type="job") %}
|
||||||
|
<div class="text-muted text-small mb-3">{{ job.from | format_date(type="job") }} - {{ job.to | format_date(type="job") }}</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="text-muted text-small mb-3">{{ job.from | format_date(type="job") }}</div>
|
||||||
|
{% endif %}
|
||||||
|
<div>{{ job.description | lang_entity(lang=lang) }} </div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<h2 class="h2 fw-light mb-4">{{ "work-freelance" | translate(lang=lang) }}</h2>
|
||||||
|
<div class="timeline">
|
||||||
|
{% for job in cv.jobs | filter(attribute="jobtype", value="Freelance") %}
|
||||||
<div class="timeline-card timeline-card-info" data-aos="fade-in" data-aos-delay="{{ loop.index * 100 }}">
|
<div class="timeline-card timeline-card-info" data-aos="fade-in" data-aos-delay="{{ loop.index * 100 }}">
|
||||||
<div class="timeline-head px-4 pt-3">
|
<div class="timeline-head px-4 pt-3">
|
||||||
<div class="h5">{{ job.title }} <span class="text-muted h6">at {{ job.company }}</span></div>
|
<div class="h5">{{ job.title }} <span class="text-muted h6">at {{ job.company }}</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="timeline-body px-4 pb-4">
|
<div class="timeline-body px-4 pb-4">
|
||||||
{% if job.from | format_date(type="job") != job.from | format_date(type="job") %}
|
{% if job.languages and job.technologies %}
|
||||||
|
{{ job.languages | concat(with=job.technologies) }}
|
||||||
|
{% elif job.languages %}
|
||||||
|
{{job.languages}}
|
||||||
|
{% elif job.technologies %}
|
||||||
|
{{job.technologies}}
|
||||||
|
{% endif %}
|
||||||
|
{% if job.from | format_date(type="job") != job.to | format_date(type="job") %}
|
||||||
<div class="text-muted text-small mb-3">{{ job.from | format_date(type="job") }} - {{ job.to | format_date(type="job") }}</div>
|
<div class="text-muted text-small mb-3">{{ job.from | format_date(type="job") }} - {{ job.to | format_date(type="job") }}</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="text-muted text-small mb-3">{{ job.from | format_date(type="job") }}</div>
|
<div class="text-muted text-small mb-3">{{ job.from | format_date(type="job") }}</div>
|
||||||
@ -219,7 +291,7 @@
|
|||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col-md-5" data-aos="fade-left" data-aos-delay="200">
|
<div class="col-md-5" data-aos="fade-left" data-aos-delay="200">
|
||||||
<div class="d-print-none">
|
<div class="d-print-none">
|
||||||
<form action="https://formspree.io/your@email.com" method="POST">
|
<form action="{{ contact_svc }}" method="POST">
|
||||||
<div class="form-outline mb-4">
|
<div class="form-outline mb-4">
|
||||||
<input type="text" id="name" class="form-control" required/>
|
<input type="text" id="name" class="form-control" required/>
|
||||||
<label class="form-label" for="name">Name</label>
|
<label class="form-label" for="name">Name</label>
|
||||||
|
Loading…
Reference in New Issue
Block a user