This commit is contained in:
Ondrej Vlach 2023-12-03 15:46:05 +01:00
parent a5e0857285
commit 2b133a9f3f
Signed by: ovlach
GPG Key ID: 4FF1A23B4914DE70
13 changed files with 779 additions and 152 deletions

View File

@ -0,0 +1,31 @@
name: release
run-name: release
on:
push:
branches:
- master
jobs:
tests:
uses: ./.gitea/workflows/test.yaml # use the callable tests job to run tests
secrets: inherit
deploy:
name: deploy
runs-on: ubuntu-latest
needs: [tests] # require tests to pass before deploy runs
container:
image: ovlach/docker-gitea:v0.0.2-alpha
steps:
- uses: https://github.com/actions/checkout.git@v4
- name: Login to git.nanobyte.cz
uses: https://github.com/docker/login-action@v3
with:
username: ${{ secrets.DEPLOYMENT_PACKAGE }}
password: ${{ secrets.DEPLOYMENT_PACKAGE }}
registry: git.nanobyte.cz
- name: Get short hash from git repository
id: git
run: echo "::set-output name=short_hash::$(git rev-parse --short HEAD)"
- name: Build and push docker
run: |
docker build . -t git.nanobyte.cz/$GITHUB_REPOSITORY_OWNER/ovlach_backend:${{steps.git.outputs.short_hash}} --build-arg GITEA_TOKEN="Bearer ${{secrets.DEPLOYMENT_PACKAGE}}" && \
docker push git.nanobyte.cz/$GITHUB_REPOSITORY_OWNER/ovlach_backend:${{steps.git.outputs.short_hash}}

View File

@ -2,52 +2,66 @@ name: test
run-name: test run-name: test
on: on:
workflow_call: workflow_call:
secrets:
DEPLOYMENT_PACKAGE:
description: 'needed for checkout depenediencies'
required: true
push: push:
branches: branches:
- '*' - '*'
jobs: jobs:
clippy: clippy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container:
image: git.nanobyte.cz/nanobyte/nano-rust-builder:1.74.5f84654
steps: steps:
- uses: https://github.com/actions/checkout.git@v4 - uses: https://github.com/actions/checkout.git@v4
- name: Hash of Cargo.lock
id: get-hash
run: echo "::set-output name=hash::$(md5sum Cargo.lock | awk '{ print $1; }')"
- uses: https://gitea.com/wolfogre/cache/restore@v3 - uses: https://gitea.com/wolfogre/cache/restore@v3
id: cache id: cache
with: with:
key: "${{github.repository}}-cache-cargo-clippy-v4-${{ steps.get-hash.outputs.hash }}"
path: | path: |
.cache .cache
target target
key: ${{github.repository}}-cache-cargo-clippy-v4-${{ hashFiles('Cargo.lock') }}
restore-keys: ${{github.repository}}-cache-cargo-clippy-v4 restore-keys: ${{github.repository}}-cache-cargo-clippy-v4
- uses: nanobyte-public/rust-action@master - uses: nanobyte-public/rust-action@master
with: with:
args: CARGO_HOME=./.cache cargo clippy -- -Dwarnings args: CARGO_HOME=./.cache cargo-nan \"Bearer ${{secrets.DEPLOYMENT_PACKAGE}}\" cargo clippy -- -Dwarnings
- uses: https://gitea.com/wolfogre/cache/save@v3 - uses: https://gitea.com/wolfogre/cache/save@v3
if: steps.cache.outputs.cache-hit != 'true' if: steps.cache.outputs.cache-hit != 'true'
with: with:
path: | path: |
.cache .cache
target target
key: ${{github.repository}}-cache-cargo-clippy-v4-${{ hashFiles('Cargo.lock') }} key: "${{github.repository}}-cache-cargo-clippy-v4-${{ steps.get-hash.outputs.hash }}"
test: test:
container:
image: git.nanobyte.cz/nanobyte/nano-rust-builder:1.74.5f84654
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: https://github.com/actions/checkout.git@v4 - uses: https://github.com/actions/checkout.git@v4
- name: Hash of Cargo.lock
id: get-hash
run: echo "::set-output name=hash::$(md5sum Cargo.lock | awk '{ print $1; '})"
- uses: https://gitea.com/wolfogre/cache/restore@v3 - uses: https://gitea.com/wolfogre/cache/restore@v3
id: cache id: cache
with: with:
path: | path: |
.cache .cache
target target
key: ${{github.repository}}-cache-cargo-test-v4-${{ hashFiles('Cargo.lock') }} key: "${{github.repository}}-cache-test-clippy-v4-${{ steps.get-hash.outputs.hash }}"
restore-keys: ${{github.repository}}-cache-cargo-test-v4 restore-keys: ${{github.repository}}-cache-test-test-v4
- uses: nanobyte-public/rust-action@master - uses: nanobyte-public/rust-action@master
with: with:
args: | args: |
CARGO_HOME=./.cache cargo test CARGO_HOME=./.cache cargo-nan \"Bearer ${{secrets.DEPLOYMENT_PACKAGE}}\" cargo test
- uses: https://gitea.com/wolfogre/cache/save@v3 - uses: https://gitea.com/wolfogre/cache/save@v3
if: steps.cache.outputs.cache-hit != 'true' if: steps.cache.outputs.cache-hit != 'true'
with: with:
path: | path: |
.cache .cache
target target
key: ${{github.repository}}-cache-cargo-test-v4-${{ hashFiles('Cargo.lock') }} key: "${{github.repository}}-cache-test-clippy-v4-${{ steps.get-hash.outputs.hash }}"

524
Cargo.lock generated
View File

@ -41,6 +41,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "anyhow"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]] [[package]]
name = "async-stream" name = "async-stream"
version = "0.3.5" version = "0.3.5"
@ -60,7 +66,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -71,7 +77,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -95,6 +101,51 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "axum"
version = "0.6.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
dependencies = [
"async-trait",
"axum-core",
"bitflags 1.3.2",
"bytes",
"futures-util",
"http",
"http-body",
"hyper",
"itoa",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"rustversion",
"serde",
"sync_wrapper",
"tower",
"tower-layer",
"tower-service",
]
[[package]]
name = "axum-core"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c"
dependencies = [
"async-trait",
"bytes",
"futures-util",
"http",
"http-body",
"mime",
"rustversion",
"tower-layer",
"tower-service",
]
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.69" version = "0.3.69"
@ -362,7 +413,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"proc-macro2-diagnostics", "proc-macro2-diagnostics",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -383,7 +434,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -625,7 +676,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -681,6 +732,16 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "gethostname"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
dependencies = [
"libc",
"windows-targets",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.11" version = "0.2.11"
@ -740,13 +801,19 @@ dependencies = [
"futures-sink", "futures-sink",
"futures-util", "futures-util",
"http", "http",
"indexmap", "indexmap 2.1.0",
"slab", "slab",
"tokio", "tokio",
"tokio-util", "tokio-util",
"tracing", "tracing",
] ]
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.14.3" version = "0.14.3"
@ -832,6 +899,18 @@ dependencies = [
"want", "want",
] ]
[[package]]
name = "hyper-timeout"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1"
dependencies = [
"hyper",
"pin-project-lite",
"tokio",
"tokio-io-timeout",
]
[[package]] [[package]]
name = "hyper-tls" name = "hyper-tls"
version = "0.5.0" version = "0.5.0"
@ -894,6 +973,16 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.1.0" version = "2.1.0"
@ -901,7 +990,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown", "hashbrown 0.14.3",
"serde", "serde",
] ]
@ -967,6 +1056,15 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.9" version = "1.0.9"
@ -1066,6 +1164,12 @@ dependencies = [
"regex-automata 0.1.10", "regex-automata 0.1.10",
] ]
[[package]]
name = "matchit"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.6.4" version = "2.6.4"
@ -1128,18 +1232,46 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "nanobyte_opentelemetry"
version = "0.2.3"
source = "sparse+https://git.nanobyte.cz/api/packages/nanobyte/cargo/"
checksum = "053fac4ff7f3cab0a088383bc68774e402c07c92d19478bcbb51d1d49a5d42bf"
dependencies = [
"gethostname",
"opentelemetry",
"opentelemetry-appender-tracing",
"opentelemetry-otlp",
"opentelemetry-semantic-conventions",
"opentelemetry-stdout",
"opentelemetry_sdk",
"reqwest",
"rocket",
"tracing",
"tracing-appender",
"tracing-core",
"tracing-log",
"tracing-opentelemetry",
"tracing-subscriber",
"uuid",
"yansi 0.5.1",
]
[[package]] [[package]]
name = "nanobyte_tera" name = "nanobyte_tera"
version = "0.1.0" version = "0.2.0"
source = "git+https://glpat-Us_EdFTzQLv4shViQXi_:glpat-Us_EdFTzQLv4shViQXi_@gitlab.nanobyte.cz/tools/nanobyte_tera.git?branch=master#75c20a9806663ca04c6f8a7afff64d7b5906d113" source = "sparse+https://git.nanobyte.cz/api/packages/nanobyte/cargo/"
checksum = "6fa686074d8273526885446e3c7f4a6f35affab0dfcbba55c9b1aca6efae7c67"
dependencies = [ dependencies = [
"chrono", "chrono",
"fluent-bundle", "fluent-bundle",
"fluent-resmgr", "fluent-resmgr",
"log", "log",
"ovlach_data",
"rocket_dyn_templates", "rocket_dyn_templates",
"serde",
"serde_json",
"sha256", "sha256",
"tracing",
"unic-langid", "unic-langid",
] ]
@ -1256,7 +1388,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -1277,6 +1409,125 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "opentelemetry"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e32339a5dc40459130b3bd269e9892439f55b33e772d2a9d402a789baaf4e8a"
dependencies = [
"futures-core",
"futures-sink",
"indexmap 2.1.0",
"js-sys",
"once_cell",
"pin-project-lite",
"thiserror",
"urlencoding",
]
[[package]]
name = "opentelemetry-appender-tracing"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12c4bd073648dae8ac45cfc81588d74b3dc5f334119ac08567ddcbfe16f2d809"
dependencies = [
"once_cell",
"opentelemetry",
"opentelemetry_sdk",
"tracing",
"tracing-core",
"tracing-subscriber",
]
[[package]]
name = "opentelemetry-otlp"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f24cda83b20ed2433c68241f918d0f6fdec8b1d43b7a9590ab4420c5095ca930"
dependencies = [
"async-trait",
"futures-core",
"http",
"opentelemetry",
"opentelemetry-proto",
"opentelemetry-semantic-conventions",
"opentelemetry_sdk",
"prost",
"thiserror",
"tokio",
"tonic",
]
[[package]]
name = "opentelemetry-proto"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2e155ce5cc812ea3d1dffbd1539aed653de4bf4882d60e6e04dcf0901d674e1"
dependencies = [
"opentelemetry",
"opentelemetry_sdk",
"prost",
"tonic",
]
[[package]]
name = "opentelemetry-semantic-conventions"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5774f1ef1f982ef2a447f6ee04ec383981a3ab99c8e77a1a7b30182e65bbc84"
dependencies = [
"opentelemetry",
]
[[package]]
name = "opentelemetry-stdout"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c13b2df4cd59c176099ac82806725ba340c8fa7b1a7004c0912daad30470f63e"
dependencies = [
"async-trait",
"chrono",
"futures-util",
"opentelemetry",
"opentelemetry_sdk",
"ordered-float",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "opentelemetry_sdk"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "968ba3f2ca03e90e5187f5e4f46c791ef7f2c163ae87789c8ce5f5ca3b7b7de5"
dependencies = [
"async-trait",
"crossbeam-channel",
"futures-channel",
"futures-executor",
"futures-util",
"glob",
"once_cell",
"opentelemetry",
"ordered-float",
"percent-encoding",
"rand",
"serde_json",
"thiserror",
"tokio",
"tokio-stream",
]
[[package]]
name = "ordered-float"
version = "4.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "536900a8093134cf9ccf00a27deb3532421099e958d9dd431135d0c7543ca1e8"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "overload" name = "overload"
version = "0.1.1" version = "0.1.1"
@ -1285,8 +1536,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]] [[package]]
name = "ovlach_data" name = "ovlach_data"
version = "0.1.0" version = "0.1.2"
source = "git+https://glpat-Ju_qUN9Yh8qa5rEnd6T7:glpat-Ju_qUN9Yh8qa5rEnd6T7@gitlab.nanobyte.cz/ondrej/ov-site-api-data.git?branch=add_missing_fields#c13748b039d812d3bf1aaa93312699da7b921868" source = "sparse+https://git.nanobyte.cz/api/packages/ovlach/cargo/"
checksum = "98843b3cefbdbf054f13312e82493248501cdd8abb39379ca2546559358c1437"
dependencies = [ dependencies = [
"chrono", "chrono",
"rocket", "rocket",
@ -1302,6 +1554,7 @@ dependencies = [
"fluent-bundle", "fluent-bundle",
"fluent-resmgr", "fluent-resmgr",
"log", "log",
"nanobyte_opentelemetry",
"nanobyte_tera", "nanobyte_tera",
"ovlach_data", "ovlach_data",
"ovlach_tera", "ovlach_tera",
@ -1310,16 +1563,19 @@ dependencies = [
"rocket", "rocket",
"rocket_dyn_templates", "rocket_dyn_templates",
"serde", "serde",
"serde_json",
"serde_yaml", "serde_yaml",
"sha256", "sha256",
"tokio", "tokio",
"tracing",
"unic-langid", "unic-langid",
] ]
[[package]] [[package]]
name = "ovlach_tera" name = "ovlach_tera"
version = "0.1.0" version = "0.2.0"
source = "git+https://glpat-_yPuXbEzECyk3FaHudCN:glpat-_yPuXbEzECyk3FaHudCN@gitlab.nanobyte.cz/ondrej/ovlach_tera.git?branch=master#0ab1bbadd76c1336e00b2a38e572048003879ab6" source = "sparse+https://git.nanobyte.cz/api/packages/ovlach/cargo/"
checksum = "fd6d3a0c415f223c68db7bd0290405b247f488180e6b96810b3be4acd0b37764"
dependencies = [ dependencies = [
"rocket_dyn_templates", "rocket_dyn_templates",
"serde", "serde",
@ -1365,7 +1621,7 @@ checksum = "61a386cd715229d399604b50d1361683fe687066f42d56f54be995bc6868f71c"
dependencies = [ dependencies = [
"inlinable_string", "inlinable_string",
"pear_codegen", "pear_codegen",
"yansi", "yansi 1.0.0-rc.1",
] ]
[[package]] [[package]]
@ -1377,7 +1633,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"proc-macro2-diagnostics", "proc-macro2-diagnostics",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -1417,7 +1673,7 @@ dependencies = [
"pest_meta", "pest_meta",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -1471,7 +1727,7 @@ dependencies = [
"phf_shared", "phf_shared",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -1483,6 +1739,26 @@ dependencies = [
"siphasher", "siphasher",
] ]
[[package]]
name = "pin-project"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.13" version = "0.2.13"
@ -1530,9 +1806,32 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
"version_check", "version_check",
"yansi", "yansi 1.0.0-rc.1",
]
[[package]]
name = "prost"
version = "0.11.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd"
dependencies = [
"bytes",
"prost-derive",
]
[[package]]
name = "prost-derive"
version = "0.11.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
"syn 1.0.109",
] ]
[[package]] [[package]]
@ -1609,7 +1908,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -1708,7 +2007,7 @@ dependencies = [
"either", "either",
"figment", "figment",
"futures", "futures",
"indexmap", "indexmap 2.1.0",
"log", "log",
"memchr", "memchr",
"multer", "multer",
@ -1729,7 +2028,7 @@ dependencies = [
"tokio-util", "tokio-util",
"ubyte", "ubyte",
"version_check", "version_check",
"yansi", "yansi 1.0.0-rc.1",
] ]
[[package]] [[package]]
@ -1740,11 +2039,11 @@ checksum = "a2238066abf75f21be6cd7dc1a09d5414a671f4246e384e49fe3f8a4936bd04c"
dependencies = [ dependencies = [
"devise", "devise",
"glob", "glob",
"indexmap", "indexmap 2.1.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"rocket_http", "rocket_http",
"syn", "syn 2.0.39",
"unicode-xid", "unicode-xid",
"version_check", "version_check",
] ]
@ -1773,7 +2072,7 @@ dependencies = [
"futures", "futures",
"http", "http",
"hyper", "hyper",
"indexmap", "indexmap 2.1.0",
"log", "log",
"memchr", "memchr",
"pear", "pear",
@ -1911,7 +2210,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -1952,7 +2251,7 @@ version = "0.9.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c" checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c"
dependencies = [ dependencies = [
"indexmap", "indexmap 2.1.0",
"itoa", "itoa",
"ryu", "ryu",
"serde", "serde",
@ -2082,6 +2381,17 @@ dependencies = [
"loom", "loom",
] ]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.39" version = "2.0.39"
@ -2093,6 +2403,12 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "sync_wrapper"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]] [[package]]
name = "system-configuration" name = "system-configuration"
version = "0.5.1" version = "0.5.1"
@ -2166,7 +2482,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -2251,6 +2567,16 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "tokio-io-timeout"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf"
dependencies = [
"pin-project-lite",
"tokio",
]
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "2.2.0" version = "2.2.0"
@ -2259,7 +2585,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -2324,13 +2650,67 @@ version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
dependencies = [ dependencies = [
"indexmap", "indexmap 2.1.0",
"serde", "serde",
"serde_spanned", "serde_spanned",
"toml_datetime", "toml_datetime",
"winnow", "winnow",
] ]
[[package]]
name = "tonic"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a"
dependencies = [
"async-trait",
"axum",
"base64",
"bytes",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"hyper-timeout",
"percent-encoding",
"pin-project",
"prost",
"tokio",
"tokio-stream",
"tower",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
dependencies = [
"futures-core",
"futures-util",
"indexmap 1.9.3",
"pin-project",
"pin-project-lite",
"rand",
"slab",
"tokio",
"tokio-util",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-layer"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
[[package]] [[package]]
name = "tower-service" name = "tower-service"
version = "0.3.2" version = "0.3.2"
@ -2348,6 +2728,18 @@ dependencies = [
"tracing-core", "tracing-core",
] ]
[[package]]
name = "tracing-appender"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf"
dependencies = [
"crossbeam-channel",
"thiserror",
"time",
"tracing-subscriber",
]
[[package]] [[package]]
name = "tracing-attributes" name = "tracing-attributes"
version = "0.1.27" version = "0.1.27"
@ -2356,7 +2748,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -2380,6 +2772,34 @@ dependencies = [
"tracing-core", "tracing-core",
] ]
[[package]]
name = "tracing-opentelemetry"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c67ac25c5407e7b961fafc6f7e9aa5958fd297aada2d20fa2ae1737357e55596"
dependencies = [
"js-sys",
"once_cell",
"opentelemetry",
"opentelemetry_sdk",
"smallvec",
"tracing",
"tracing-core",
"tracing-log",
"tracing-subscriber",
"web-time",
]
[[package]]
name = "tracing-serde"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1"
dependencies = [
"serde",
"tracing-core",
]
[[package]] [[package]]
name = "tracing-subscriber" name = "tracing-subscriber"
version = "0.3.18" version = "0.3.18"
@ -2390,12 +2810,15 @@ dependencies = [
"nu-ansi-term", "nu-ansi-term",
"once_cell", "once_cell",
"regex", "regex",
"serde",
"serde_json",
"sharded-slab", "sharded-slab",
"smallvec", "smallvec",
"thread_local", "thread_local",
"tracing", "tracing",
"tracing-core", "tracing-core",
"tracing-log", "tracing-log",
"tracing-serde",
] ]
[[package]] [[package]]
@ -2556,6 +2979,21 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]]
name = "uuid"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560"
dependencies = [
"getrandom",
]
[[package]] [[package]]
name = "valuable" name = "valuable"
version = "0.1.0" version = "0.1.0"
@ -2620,7 +3058,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -2654,7 +3092,7 @@ checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.39",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -2675,6 +3113,16 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "web-time"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57099a701fb3a8043f993e8228dc24229c7b942e2b009a1b962e54489ba1d3bf"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@ -2809,6 +3257,12 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
[[package]] [[package]]
name = "yansi" name = "yansi"
version = "1.0.0-rc.1" version = "1.0.0-rc.1"

View File

@ -14,12 +14,17 @@ rocket = { version = "0.5.0", features = ["json"] }
rocket_dyn_templates = { version = "0.1.0", features = ["tera"]} rocket_dyn_templates = { version = "0.1.0", features = ["tera"]}
reqwest = { version = "0.11", features = ["json"] } reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
ovlach_data = { git = "https://glpat-Ju_qUN9Yh8qa5rEnd6T7:glpat-Ju_qUN9Yh8qa5rEnd6T7@gitlab.nanobyte.cz/ondrej/ov-site-api-data.git", branch = "add_missing_fields"} ovlach_data = { version = "0.1.2", registry = "gitea_ovlach"}
nanobyte_opentelemetry = { version = "0.2.3", registry = "gitea_nanobyte", features = ["rocket-reqwest"] }
chrono = "0.4.31" chrono = "0.4.31"
sha256 = "1.4.0" sha256 = "1.4.0"
fluent-bundle = "0.15.2" fluent-bundle = "0.15.2"
fluent-resmgr = "0.0.6" fluent-resmgr = "0.0.6"
unic-langid = "0.9.1" unic-langid = "0.9.1"
phf = { version = "0.11.2", features = ["macros"] } phf = { version = "0.11.2", features = ["macros"] }
nanobyte_tera = { git = "https://glpat-Us_EdFTzQLv4shViQXi_:glpat-Us_EdFTzQLv4shViQXi_@gitlab.nanobyte.cz/tools/nanobyte_tera.git", branch = "master" } nanobyte_tera = { version = "0.2.0", registry = "gitea_nanobyte" }
ovlach_tera = { git = "https://glpat-_yPuXbEzECyk3FaHudCN:glpat-_yPuXbEzECyk3FaHudCN@gitlab.nanobyte.cz/ondrej/ovlach_tera.git", branch = "master" } ovlach_tera = { version="0.2.0", registry="gitea_ovlach" }
tracing = "0.1.40"
[dev-dependencies]
serde_json = "1.0.108"

View File

@ -4,4 +4,5 @@ cv_backend_path = "http://localhost:8002"
[default] [default]
static_route = "http://localhost:8001" static_route = "http://localhost:8001"
cv_backend_path = "http://localhost:8002" cv_backend_path = "http://localhost:8002"
default_person_name = "ovlach"

View File

@ -4,6 +4,7 @@ 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;
use tools::tera::advanced_filter;
pub mod routes; pub mod routes;
pub mod services; pub mod services;
@ -21,13 +22,19 @@ pub struct CVBackendConfig {
cv_backend_path: String, cv_backend_path: String,
} }
#[derive(Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct DefaultPerson {
default_person_name: String,
}
pub fn rocket_builder() -> Rocket<Build> {
pub fn rocket_builder() -> Rocket<Build> {
let rocket = rocket::build(); let rocket = rocket::build();
//let figment = rocket.figment(); //let figment = rocket.figment();
// extract the entire config any `Deserialize` value // extract the entire config any `Deserialize` value
//let config: PresentationConfig = figment.extract().expect("config"); //let config: PresentationConfig = figment.extract().expect("config");
rocket.attach( rocket.attach(
Template::try_custom(|engines| { Template::try_custom(|engines| {
engines.tera.register_filter("static", static_filter); engines.tera.register_filter("static", static_filter);
@ -39,6 +46,7 @@ pub fn rocket_builder() -> Rocket<Build> {
engines.tera.register_filter("lang_entity", lang_entity); engines.tera.register_filter("lang_entity", lang_entity);
engines.tera.register_filter("format_date", get_year); // deprecated engines.tera.register_filter("format_date", get_year); // deprecated
engines.tera.register_filter("get_year", get_year); engines.tera.register_filter("get_year", get_year);
engines.tera.register_filter("advanced_filter", advanced_filter);
Ok(()) Ok(())
}) })
).attach( ).attach(
@ -46,9 +54,11 @@ pub fn rocket_builder() -> Rocket<Build> {
).attach( ).attach(
AdHoc::config::<CVBackendConfig>() AdHoc::config::<CVBackendConfig>()
).attach( ).attach(
tools::rocket::RequestTimer AdHoc::config::<DefaultPerson>()
).attach(
nanobyte_opentelemetry::rocket::TracingFairing::ignite()
).mount("/", routes![ ).mount("/", routes![
routes::root::index, routes::root::index,
routes::root::index_without_lang routes::root::index_without_lang
]) ])
} }

View File

@ -1,8 +1,14 @@
use nanobyte_opentelemetry::{install_panic_handler, default_filter_layer, LogLevel};
use ovlach_frontend::rocket_builder; use ovlach_frontend::rocket_builder;
use rocket::launch;
#[rocket::main]
#[launch] async fn main() {
fn rocket() -> _ { install_panic_handler();
rocket_builder() let _opentelemetry = nanobyte_opentelemetry::init_telemetry(
} env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
&std::env::var("OTLP_ENDPOINT").unwrap_or("".to_string()),
Some(default_filter_layer(LogLevel::DebugWithoutRs))
);
let _ = rocket_builder().launch().await;
}

View File

@ -1,35 +1,45 @@
use std::{thread::sleep, time::Duration};
use log::error; use log::error;
use ovlach_data::cv::cv::CV; use nanobyte_opentelemetry::rocket::{OtelReqwestClient, TracingSpan};
use rocket::{get, State, response::Redirect, http::Status}; use nanobyte_tera::l18n::LanguageDescription;
use ovlach_data::cv::data::CV;
use rocket::{get, State, response::Redirect, http::Status, futures::executor::enter};
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}; use crate::{PresentationConfig, services::cv::fetch_cv_data_from_backend, CVBackendConfig, tools::rocket::RequestLanguage, DefaultPerson};
#[derive(Serialize, Debug)] #[derive(Serialize, Debug)]
struct RootPage { struct RootPage {
static_host: String, static_host: String,
cv: CV, cv: CV,
download_cv_url: String, download_cv_url: String,
lang: String, lang: LanguageDescription,
} }
#[get("/<language>")] #[get("/<language>")]
pub async fn index(presentation_config: &State<PresentationConfig>, cv_config: &State<CVBackendConfig>, language: RequestLanguage) -> Result<Template, Status> { pub async fn index(presentation_config: &State<PresentationConfig>, cv_config: &State<CVBackendConfig>, language: RequestLanguage, client: OtelReqwestClient,
let context = match fetch_cv_data_from_backend(cv_config.cv_backend_path.clone()).await { default_person: &State<DefaultPerson>, span: TracingSpan) -> Result<Template, Status> {
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 {
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(), download_cv_url: "FIXME!".to_string(),
lang: language.language, lang: LanguageDescription::new(&language.language.as_str(), "ovlach_frontend"),
}, },
Err(e) => { Err(e) => {
error!("Can't fetch CV data from backend {:?}", e); error!("Can't fetch CV data from backend {:?}", e);
drop(span);
return Err(Status::InternalServerError) return Err(Status::InternalServerError)
} }
}; };
Ok(Template::render("default", &context)) let result = Ok(Template::render("default", &context));
drop(span);
result
} }

View File

@ -1,4 +1,6 @@
use ovlach_data::cv::cv::CV; use ovlach_data::cv::data::CV;
use reqwest::Client;
use tracing::{debug, instrument};
#[derive(Debug)] #[derive(Debug)]
@ -12,10 +14,14 @@ impl From<reqwest::Error> for FetchError {
} }
} }
pub async fn fetch_cv_data_from_backend(backend_host: String) -> Result<CV, FetchError> { #[instrument]
let resp = reqwest::get(format!("{}/{}", backend_host, "/api/cv/ovlach")) pub async fn fetch_cv_data_from_backend(backend_host: &String, person_name: &String, client: &Client) -> Result<CV, FetchError> {
let url = format!("{}/{}/{}", backend_host, "/api/v1/cv", person_name);
debug!("Fetching CV data from backend: {}", url);
let resp = client
.get(url).send()
.await? .await?
.json::<CV>() .json::<CV>()
.await?; .await?;
Ok(resp) Ok(resp)
} }

View File

@ -1,2 +1,3 @@
pub mod rocket; pub(crate) mod rocket;
pub mod lang; pub(crate) mod lang;
pub(crate) mod tera;

View File

@ -27,57 +27,3 @@ impl<'r> FromParam<'r> for RequestLanguage {
} }
} }
} }
/// Fairing for timing requests.
pub struct RequestTimer;
/// Value stored in request-local state.
#[derive(Copy, Clone)]
struct TimerStart(Option<SystemTime>);
#[rocket::async_trait]
impl Fairing for RequestTimer {
fn info(&self) -> Info {
Info {
name: "Request Timer",
kind: Kind::Request | Kind::Response
}
}
/// Stores the start time of the request in request-local state.
async fn on_request(&self, request: &mut Request<'_>, _: &mut Data<'_>) {
// Store a `TimerStart` instead of directly storing a `SystemTime`
// to ensure that this usage doesn't conflict with anything else
// that might store a `SystemTime` in request-local cache.
request.local_cache(|| TimerStart(Some(SystemTime::now())));
}
/// Adds a header to the response indicating how long the server took to
/// process the request.
async fn on_response<'r>(&self, req: &'r Request<'_>, res: &mut Response<'r>) {
let start_time = req.local_cache(|| TimerStart(None));
if let Some(Ok(duration)) = start_time.0.map(|st| st.elapsed()) {
let ms = duration.as_secs() * 1000 + duration.subsec_millis() as u64;
res.set_raw_header("X-Response-Time", format!("{} ms", ms));
info!("Response time: {} ms", ms);
}
}
}
/// Request guard used to retrieve the start time of a request.
#[derive(Copy, Clone)]
pub struct StartTime(pub SystemTime);
// Allows a route to access the time a request was initiated.
#[rocket::async_trait]
impl<'r> FromRequest<'r> for StartTime {
type Error = ();
async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, ()> {
match *request.local_cache(|| TimerStart(None)) {
TimerStart(Some(time)) => request::Outcome::Success(StartTime(time)),
TimerStart(None) => request::Outcome::Error((Status::InternalServerError, ())),
}
}
}

116
src/tools/tera.rs Normal file
View File

@ -0,0 +1,116 @@
use std::collections::HashMap;
use rocket_dyn_templates::tera::{try_get_value, Error, Value, to_value};
/// If the `value` is not passed, optionally discard all elements where the attribute is null. (include_null -> all, none, only)
pub fn advanced_filter(value: &Value, args: &HashMap<String, Value>) -> Result<Value, Error> {
let mut arr = try_get_value!("filter", "value", Vec<Value>, value);
if arr.is_empty() {
return Ok(arr.into());
}
let key = match args.get("attribute") {
Some(val) => try_get_value!("filter", "attribute", String, val),
None => return Err(Error::msg("The `filter` filter has to have an `attribute` argument")),
};
let null = match args.get("include_null") {
Some(val) => try_get_value!("filter", "attribute", String, val),
None => "none".to_string(),
};
let against_value = match args.get("value") {
Some(val) => Some(try_get_value!("filter", "value", String, val)),
None => None
};
if null == "only" && against_value.is_some() {
return Err(Error::msg("The `filter` filter cannot have both `include_null=only` and `value`"))
}
arr = arr
.into_iter()
.filter(|v| {
let tested_value = v.get(key.clone()).unwrap_or(&Value::Null);
if tested_value.is_null() {
return match null.as_str() {
"all" => true,
"none" => false,
"only" => true,
_ => false,
}
} else {
if null != "only" {
let val = tested_value.as_str();
match val {
Some(match_v) => {
match against_value.clone() {
Some(against_v) => match_v == against_v,
None => true,
}
}
None => true,
}
} else {
false
}
}
})
.collect::<Vec<_>>();
Ok(to_value(arr).unwrap())
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
use std::collections::HashMap;
fn call_advanced_filter(data: &Vec<TestClass>, include_null: &str, value: Option<&str>) -> Result<Value, Error> {
let mut args = HashMap::new();
args.insert("attribute".to_string(), json!("against_value"));
args.insert("include_null".to_string(), json!(include_null));
if let Some(val) = value {
args.insert("value".to_string(), json!(val));
}
advanced_filter(&json!(data), &args)
}
#[derive(serde::Serialize, serde::Deserialize, Debug)]
struct TestClass {
against_value: Option<String>,
}
impl TestClass {
pub fn new(against_value: Option<String>) -> Self {
TestClass { against_value }
}
}
fn generate_test_class(first_data: Option<String>, second_data: Option<String>) -> Vec<TestClass> {
vec![TestClass::new(first_data), TestClass::new(second_data)]
}
#[test]
fn test_advanced_filter() {
let data = vec![TestClass::new(Some("foo".to_string())), TestClass::new(None)];
let result = call_advanced_filter(&data, "all", None).unwrap();
assert_eq!(result, json!(generate_test_class(Some("foo".to_string()), None)));
let result = call_advanced_filter(&data, "none", None).unwrap();
assert_eq!(result, json!(vec![TestClass::new(Some("foo".to_string()))]));
let mut vec: Vec<TestClass> = Vec::new();
vec.push(TestClass::new(None));
let result = call_advanced_filter(&data, "only", None).unwrap();
assert_eq!(result, json!(vec![TestClass::new(None)]));
// Test filtering strings
let result = call_advanced_filter(&data, "all", Some("foo")).unwrap();
assert_eq!(result, json!(vec![TestClass::new(Some("foo".to_string())), TestClass::new(None)]));
let result = call_advanced_filter(&data, "none", Some("bar")).unwrap();
let vec: Vec<TestClass> = Vec::new();
assert_eq!(result, json!(vec));
let result = call_advanced_filter(&data, "only", Some("zz")).is_err();
assert_eq!(result, true);
}
}

View File

@ -20,29 +20,29 @@
<nav role="navigation"> <nav role="navigation">
<ul class="nav justify-content-center"> <ul class="nav justify-content-center">
{% block navlinks %} {% block navlinks %}
{% if cv.social.facebook %} {% if cv.person.social.facebook %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{{ cv.social.facebook }}" title="Facebook"><i class="fab fa-facebook"></i><span class="menu-title sr-only">Facebook</span></a> <a class="nav-link" href="{{ cv.person.social.facebook }}" title="Facebook"><i class="fab fa-facebook"></i><span class="menu-title sr-only">Facebook</span></a>
</li> </li>
{% endif %} {% endif %}
{% if cv.social.github %} {% if cv.person.social.github %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{{ cv.social.github }}" title="github"><i class="fab fa-github"></i><span class="menu-title sr-only">Github</span></a> <a class="nav-link" href="{{ cv.person.social.github }}" title="github"><i class="fab fa-github"></i><span class="menu-title sr-only">Github</span></a>
</li> </li>
{% endif %} {% endif %}
{% if cv.social.linkedin %} {% if cv.person.social.linkedin %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{{ cv.social.linkedin }}" title="github"><i class="fab fa-linkedin"></i><span class="menu-title sr-only">Linkedin</span></a> <a class="nav-link" href="{{ cv.person.social.linkedin }}" title="github"><i class="fab fa-linkedin"></i><span class="menu-title sr-only">Linkedin</span></a>
</li> </li>
{% endif %} {% endif %}
{% if cv.social.instagram %} {% if cv.person.social.instagram %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{{ cv.social.instagram }}" title="github"><i class="fab fa-instagram"></i><span class="menu-title sr-only">Instagram</span></a> <a class="nav-link" href="{{ cv.person.social.instagram }}" title="github"><i class="fab fa-instagram"></i><span class="menu-title sr-only">Instagram</span></a>
</li> </li>
{% endif %} {% endif %}
{% if cv.social.mastodon %} {% if cv.person.social.mastodon %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{{ cv.social.mastodon }}" title="github"><i class="fab fa-mastodon"></i><span class="menu-title sr-only">Mastodon</span></a> <a class="nav-link" href="{{ cv.person.social.mastodon }}" title="github"><i class="fab fa-mastodon"></i><span class="menu-title sr-only">Mastodon</span></a>
</li> </li>
{% endif %} {% endif %}
{% endblock navlinks %} {% endblock navlinks %}
@ -94,6 +94,23 @@
<div class="pb-2">{{ cv.person.address }} </div> <div class="pb-2">{{ cv.person.address }} </div>
</div> </div>
{% endif %} {% endif %}
<div class="col-sm-10">
{% if cv.person.social.facebook %}
<a class="nav-link" href="{{ cv.person.social.facebook }}" title="facebook"><i class="pe-2 fab fa-facebook"></i>&nbsp;{{ cv.person.social.github }}</a>
{% endif %}
{% if cv.person.social.github %}
<a class="nav-link" href="{{ cv.person.social.github }}" title="github"><i class="pe-2 fab fa-github"></i>&nbsp;{{ cv.person.social.github }}</a>
{% endif %}
{% if cv.person.social.linkedin %}
<a class="nav-link" href="{{ cv.person.social.linkedin }}" title="linkedin"><i class="pe-2 fab fa-linkedin"></i>&nbsp;{{ cv.person.social.linkedin }}</a>
{% endif %}
{% if cv.person.social.instagram %}
<a class="nav-link" href="{{ cv.person.social.instagram }}" title="instagram"><i class="pe-2 fab fa-instagram"></i>&nbsp;{{ cv.person.social.instagram }}</a>
{% endif %}
{% if cv.person.social.mastodon %}
<a class="nav-link" href="{{ cv.person.social.mastodon }}" title="mastodon"><i class="pe-2 fab fa-mastodon"></i>&nbsp;{{ cv.person.social.mastodon }}</a>
{% endif %}
</div>
</div> </div>
</div> </div>
</div> </div>
@ -104,14 +121,11 @@
<h2 class="h2 fw-light mb-4">{{ "professional-skills" | translate(lang=lang) }}</h2> <h2 class="h2 fw-light mb-4">{{ "professional-skills" | translate(lang=lang) }}</h2>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
{% set arr_cnt = cv.skills | length %} {% for skill in cv.skills | filter(attribute="techtype",value="Language") %}
{% set split_index = arr_cnt / 2 | round(method="ceil") %}
{% for skill in cv.skills | slice(start = 0, end = split_index) %}
{{ split_index}}
<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">
<div class="progress-bar bg-info" role="progressbar" data-aos="zoom-in-right" data-aos-delay="100" <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 %};" 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"> aria-valuenow="95" aria-valuemin="0" aria-valuemax="100">
{{ skill.skill}} {{ skill.skill}}
</div> </div>
@ -120,18 +134,31 @@
{% endfor %} {% endfor %}
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
{% for skill in cv.skills | slice(start = split_index) %} {% for skill in cv.skills | filter(attribute="techtype",value="Technology") | advanced_filter(attribute="skill", include_null="none") %}
{{ split_index}} <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"> <div class="progress-bar bg-info" role="progressbar" data-aos="zoom-in-right" data-aos-delay="100"
<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 %};"
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">
aria-valuenow="95" aria-valuemin="0" aria-valuemax="100"> {{ skill.skill}}
{{ skill.skill}} </div>
</div> </div>
</div> </div>
</div> {% endfor %}
{% endfor %} {% 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="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="Technology") | advanced_filter(attribute="skill", include_null="only") %}
<span class="fw-bolder">{{ skill.name }}</span>,<!-- TODO: fix last, -->
{% endfor %}
</div> </div>
</div> </div>
</div> </div>
@ -173,7 +200,7 @@
{% endif %} {% endif %}
</div> </div>
<div class="timeline-body px-4 pb-4"> <div class="timeline-body px-4 pb-4">
{% if education.description %} {% if education.description %}
<div class="text-muted text-small mb-3">{{ education.from | format_date(type="job") }} - {{ education.to | format_date(type="job") }}</div> <div class="text-muted text-small mb-3">{{ education.from | format_date(type="job") }} - {{ education.to | format_date(type="job") }}</div>
<div>{{ education.description | lang_entity(lang=lang) }}</div> <div>{{ education.description | lang_entity(lang=lang) }}</div>
@ -219,4 +246,4 @@
</div> </div>
</div></div> </div></div>
</div> </div>
{% endblock content %} {% endblock content %}