Add session

This commit is contained in:
Adrian Woźniak 2023-08-01 16:29:03 +02:00 committed by eraden
parent e48e8ffc9b
commit da4e57d7ce
22 changed files with 912 additions and 49 deletions

7
.gitignore vendored
View File

@ -2,13 +2,12 @@
node_modules
uploads
client/dist
client/dist/app.js.map
client/dist/app.js
client/dist/admin.js.map
client/dist/admin.js
web/tmp
web/build
**/*.wasm
tmp
web/node_modules
web/dist
node_modules
assets/build.js
assets/build.js.map

193
Cargo.lock generated
View File

@ -40,7 +40,7 @@ dependencies = [
"actix-admin-macros",
"actix-files",
"actix-multipart",
"actix-session",
"actix-session 0.7.2",
"actix-web",
"async-trait",
"chrono",
@ -159,6 +159,23 @@ dependencies = [
"zstd",
]
[[package]]
name = "actix-jwt-authc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5e2d7e61895ae7e33b8ee818d99e1fe1edd3bf0be5fa04331b66f31dc6e9fe"
dependencies = [
"actix-session 0.6.2",
"actix-web",
"derive_more",
"futures-util",
"jsonwebtoken",
"serde",
"time 0.3.24",
"tokio",
"tracing",
]
[[package]]
name = "actix-macros"
version = "0.2.4"
@ -166,7 +183,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
dependencies = [
"quote",
"syn 2.0.27",
"syn 2.0.28",
]
[[package]]
@ -260,6 +277,24 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "actix-session"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c9138a66462f1e65da829f9c0de81b44a96dfe193a4f19bfea32ee2be312368"
dependencies = [
"actix-service",
"actix-utils",
"actix-web",
"anyhow",
"async-trait",
"derive_more",
"serde",
"serde_json",
"time 0.3.24",
"tracing",
]
[[package]]
name = "actix-session"
version = "0.7.2"
@ -324,7 +359,7 @@ dependencies = [
"serde_urlencoded",
"smallvec",
"socket2",
"time 0.3.23",
"time 0.3.24",
"url",
]
@ -512,6 +547,16 @@ dependencies = [
"serde",
]
[[package]]
name = "askama_actix"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4b0dd17cfe203b00ba3853a89fba459ecf24c759b738b244133330607c78e55"
dependencies = [
"actix-web",
"askama",
]
[[package]]
name = "askama_derive"
version = "0.12.1"
@ -525,7 +570,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde",
"syn 2.0.27",
"syn 2.0.28",
]
[[package]]
@ -660,7 +705,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.27",
"syn 2.0.28",
]
[[package]]
@ -677,7 +722,7 @@ checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.27",
"syn 2.0.28",
]
[[package]]
@ -1097,7 +1142,7 @@ dependencies = [
"rand",
"sha2",
"subtle",
"time 0.3.23",
"time 0.3.24",
"version_check",
]
@ -1209,6 +1254,28 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "dashmap"
version = "5.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d"
dependencies = [
"cfg-if",
"hashbrown 0.14.0",
"lock_api",
"once_cell",
"parking_lot_core 0.9.8",
]
[[package]]
name = "deranged"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8810e7e2cf385b1e9b50d68264908ec367ba642c96d02edfe61c39e88e2a3c01"
dependencies = [
"serde",
]
[[package]]
name = "derive_more"
version = "0.99.17"
@ -1411,6 +1478,7 @@ dependencies = [
"futures-core",
"futures-task",
"futures-util",
"num_cpus",
]
[[package]]
@ -1453,7 +1521,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.27",
"syn 2.0.28",
]
[[package]]
@ -1854,6 +1922,20 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "jsonwebtoken"
version = "8.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378"
dependencies = [
"base64 0.21.2",
"pem",
"ring",
"serde",
"serde_json",
"simple_asn1",
]
[[package]]
name = "kv-log-macro"
version = "1.0.7"
@ -2121,6 +2203,7 @@ dependencies = [
"oswilno-admin",
"oswilno-config",
"oswilno-parking-space",
"oswilno-session",
"ron 0.8.0",
"sea-orm",
"serde",
@ -2129,6 +2212,7 @@ dependencies = [
"toml 0.7.6",
"tracing",
"tracing-subscriber",
"web-assets",
]
[[package]]
@ -2180,6 +2264,7 @@ dependencies = [
"actix",
"actix-web",
"askama",
"askama_actix",
"oswilno-contract",
"sea-orm",
"serde",
@ -2187,6 +2272,22 @@ dependencies = [
"tokio",
]
[[package]]
name = "oswilno-session"
version = "0.1.0"
dependencies = [
"actix-jwt-authc",
"actix-web",
"dashmap",
"futures",
"jsonwebtoken",
"rand",
"serde",
"time 0.3.24",
"tokio",
"uuid",
]
[[package]]
name = "ouroboros"
version = "0.15.6"
@ -2291,6 +2392,15 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "pem"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8"
dependencies = [
"base64 0.13.1",
]
[[package]]
name = "percent-encoding"
version = "2.3.0"
@ -2327,7 +2437,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.27",
"syn 2.0.28",
]
[[package]]
@ -2826,7 +2936,7 @@ dependencies = [
"serde_json",
"sqlx",
"thiserror",
"time 0.3.23",
"time 0.3.24",
"tracing",
"url",
"uuid",
@ -2889,7 +2999,7 @@ dependencies = [
"rust_decimal",
"sea-query-derive",
"serde_json",
"time 0.3.23",
"time 0.3.24",
"uuid",
]
@ -2905,7 +3015,7 @@ dependencies = [
"sea-query",
"serde_json",
"sqlx",
"time 0.3.23",
"time 0.3.24",
"uuid",
]
@ -2981,22 +3091,22 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
[[package]]
name = "serde"
version = "1.0.177"
version = "1.0.180"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63ba2516aa6bf82e0b19ca8b50019d52df58455d3cf9bdaf6315225fdd0c560a"
checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.177"
version = "1.0.180"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "401797fe7833d72109fedec6bfcbe67c0eed9b99772f26eb8afd261f0abc6fd3"
checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.27",
"syn 2.0.28",
]
[[package]]
@ -3092,6 +3202,18 @@ version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf"
[[package]]
name = "simple_asn1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085"
dependencies = [
"num-bigint",
"num-traits",
"thiserror",
"time 0.3.24",
]
[[package]]
name = "siphasher"
version = "0.3.10"
@ -3209,7 +3331,7 @@ dependencies = [
"sqlx-rt",
"stringprep",
"thiserror",
"time 0.3.23",
"time 0.3.24",
"tokio-stream",
"url",
"uuid",
@ -3282,9 +3404,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.27"
version = "2.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0"
checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
dependencies = [
"proc-macro2",
"quote",
@ -3356,7 +3478,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.27",
"syn 2.0.28",
]
[[package]]
@ -3381,10 +3503,11 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.23"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446"
checksum = "b79eabcd964882a646b3584543ccabeae7869e9ac32a46f6f22b7a5bd405308b"
dependencies = [
"deranged",
"itoa",
"serde",
"time-core",
@ -3399,9 +3522,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
[[package]]
name = "time-macros"
version = "0.2.10"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4"
checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd"
dependencies = [
"time-core",
]
@ -3449,7 +3572,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.27",
"syn 2.0.28",
]
[[package]]
@ -3552,7 +3675,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.27",
"syn 2.0.28",
]
[[package]]
@ -3836,7 +3959,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.27",
"syn 2.0.28",
"wasm-bindgen-shared",
]
@ -3870,7 +3993,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.27",
"syn 2.0.28",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -3881,6 +4004,18 @@ version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "web-assets"
version = "0.1.0"
dependencies = [
"actix",
"actix-web",
"askama",
"serde",
"serde_json",
"tokio",
]
[[package]]
name = "web-sys"
version = "0.3.64"

View File

@ -2,6 +2,8 @@
members = [
'./crates/oswilno-server',
'./crates/oswilno-contract',
'./crates/web-assets',
'./crates/oswilno-parking-space',
'./crates/migration',
'./crates/oswilno-actix-admin',
]

View File

@ -13,3 +13,4 @@ oswilno-contract = { path = "../oswilno-contract" }
sea-orm = { version = "0.11.1", features = ["runtime-actix-rustls", "sqlx", "sqlx-postgres", "debug-print"] }
serde = { version = "1.0.176", features = ["derive"] }
serde_json = "1.0.104"
askama_actix = "0.14.0"

View File

@ -1,17 +1,101 @@
use actix_web::get;
use actix_web::web::{scope, Data, ServiceConfig};
use actix_web::{get, HttpResponse};
use askama_actix::Template;
use oswilno_contract::accounts;
use oswilno_contract::parking_space_rents;
use oswilno_contract::parking_spaces;
use sea_orm::prelude::*;
use std::collections::HashMap;
use std::sync::Arc;
pub fn mount(config: &mut ServiceConfig) {
config.service(scope("/parking_spaces").service(all_parking_spaces));
config.service(
scope("/parking_spaces")
.service(all_parking_spaces)
.service(all_parial_parking_spaces),
);
}
#[derive(Template)]
#[template(path = "../templates/parking-spaces/all.html")]
struct AllParkingSpace {
parking_space_rents: Vec<parking_space_rents::Model>,
parking_space_by_id: HashMap<i32, parking_spaces::Model>,
account_by_id: HashMap<i32, accounts::Model>,
}
#[derive(Template)]
#[template(path = "../templates/parking-spaces/all-partial.html")]
struct AllPartialParkingSpace {
parking_space_rents: Vec<parking_space_rents::Model>,
parking_space_by_id: HashMap<i32, parking_spaces::Model>,
account_by_id: HashMap<i32, accounts::Model>,
}
#[get("/all")]
async fn all_parking_spaces(db: Data<sea_orm::DatabaseConnection>) -> HttpResponse {
use oswilno_contract::parking_spaces;
use sea_orm::prelude::*;
async fn all_parking_spaces(db: Data<sea_orm::DatabaseConnection>) -> AllParkingSpace {
let db = db.into_inner();
let spaces = parking_spaces::Entity::find().all(&*db).await.unwrap();
HttpResponse::Ok().json(spaces)
load_parking_spaces(db).await
}
#[get("/all-partial")]
async fn all_parial_parking_spaces(
db: Data<sea_orm::DatabaseConnection>,
) -> AllPartialParkingSpace {
let db = db.into_inner();
let AllParkingSpace {
parking_space_rents,
parking_space_by_id,
account_by_id,
} = load_parking_spaces(db).await;
AllPartialParkingSpace {
parking_space_rents,
parking_space_by_id,
account_by_id,
}
}
async fn load_parking_spaces(db: Arc<DatabaseConnection>) -> AllParkingSpace {
let rents = parking_space_rents::Entity::find().all(&*db).await.unwrap();
let (parking_space_by_id, account_ids) = {
let ids = rents
.iter()
.map(|r| r.parking_space_id)
.collect::<Vec<i32>>();
let v = parking_spaces::Entity::find()
.filter(parking_spaces::Column::Id.is_in(ids))
.all(&*db)
.await
.unwrap();
let len = v.len();
v.into_iter().fold(
(HashMap::with_capacity(len), Vec::with_capacity(len)),
|(mut by_id, mut ids), space| {
ids.push(space.account_id);
by_id.insert(space.id, space);
(by_id, ids)
},
)
};
let account_by_id = {
let accounts = accounts::Entity::find()
.filter(accounts::Column::Id.is_in(account_ids))
.all(&*db)
.await
.unwrap();
let len = accounts.len();
accounts
.into_iter()
.fold(HashMap::with_capacity(len), |mut agg, account| {
agg.insert(account.id, account);
agg
})
};
AllParkingSpace {
account_by_id,
parking_space_rents: rents,
parking_space_by_id,
}
}

View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<title>OS Wilno</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="/assets/build.js" type="module"></script>
{% block head %}
{% endblock %}
</head>
<body>
<base url="/" />
<main>
{% block body %}
{% endblock %}
</main>
</body>
</html>

View File

@ -8,8 +8,9 @@
<div>{{ account.login }}</div>
</oswilno-account>
</oswilno-parking-space>
<div id="parking-space-rent-{{ parking_space_rent.id }}-price" class="price">
</div>
<oswilno-price id="parking-space-rent-{{ parking_space_rent.id }}-price" multiplier="100" currency="PLN" price="{{ parking_space_rent.price }}">
{{ parking_space_rent.price }}
</oswilno-price>
</oswilno-parking-space-rent>
{% endif %}
{% endif %}

View File

@ -0,0 +1,4 @@
{% extends "../base.html" %}
{% block body %}
{% include "./all-partial.html" %}
{% endblock %}

View File

@ -17,6 +17,8 @@ oswilno-parking-space = { path = "../oswilno-parking-space" }
sea-orm = { version = "0.11.3", features = ["postgres-array", "runtime-actix-rustls", "sqlx-postgres"] }
=======
oswilno-admin = { path = "../oswilno-admin" }
oswilno-session = { path = "../oswilno-session" }
web-assets = { path = "../web-assets" }
sea-orm = { version = "0.11", features = ["postgres-array", "runtime-actix-rustls", "sqlx-postgres"] }
>>>>>>> b3a5655 (Compile issues - bad versions)
serde = { version = "1.0.175", features = ["derive"] }

View File

@ -1,13 +1,9 @@
use std::time::Duration;
use actix_web::web::Data;
use actix_web::{middleware, web, App, HttpServer, Responder};
use actix_web::{middleware, App, HttpServer};
use sea_orm::ConnectOptions;
async fn index() -> impl Responder {
"Hello world!"
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
{
@ -37,9 +33,9 @@ async fn main() -> std::io::Result<()> {
App::new()
.wrap(middleware::Logger::default())
.app_data(Data::new(conn.clone()))
.service(web::scope("/app").route("/index.html", web::get().to(index)))
.configure(oswilno_parking_space::mount)
.configure(oswilno_admin::mount)
.configure(web_assets::configure)
})
.bind(("0.0.0.0", 8080))?
.run()

View File

@ -0,0 +1,18 @@
[package]
name = "oswilno-session"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
actix-jwt-authc = { version = "0.2.0", features = ["tracing", "session"] }
actix-web = "4.3.1"
dashmap = "5.5.0"
futures = { version = "0.3.28", features = ["thread-pool"] }
jsonwebtoken = "8.3.0"
rand = "0.8.5"
serde = { version = "1.0.180", features = ["derive"] }
time = "0.3.24"
tokio = { version = "1.29.1", features = ["full"] }
uuid = { version = "1.4.1", features = ["v4"] }

View File

@ -0,0 +1,92 @@
use std::collections::HashSet;
use std::ops::Add;
use std::sync::Arc;
use std::time::Duration;
use actix_jwt_authc::*;
use actix_http::StatusCode;
use actix_web::web::Data;
use actix_web::dev::{Service, ServiceResponse};
use actix_web::{get, test, App, HttpResponse};
use dashmap::DashSet;
use futures::channel::{mpsc, mpsc::{channel, Sender}};
use futures::SinkExt;
use futures::stream::Stream;
use jsonwebtoken::*;
use ring::rand::SystemRandom;
use ring::signature::{Ed25519KeyPair, KeyPair};
use serde::{Deserialize, Serialize};
use time::ext::*;
use time::OffsetDateTime;
use uuid::Uuid;
use tokio::sync::Mutex;
struct JwtSigningKeys {
encoding_key: EncodingKey,
decoding_key: DecodingKey,
}
impl JwtSigningKeys {
fn generate() -> Result<Self, Box<dyn std::error::Error>> {
let doc = Ed25519KeyPair::generate_pkcs8(&SystemRandom::new())?;
let keypair = Ed25519KeyPair::from_pkcs8(doc.as_ref())?;
let encoding_key = EncodingKey::from_ed_der(doc.as_ref());
let decoding_key = DecodingKey::from_ed_der(keypair.public_key().as_ref());
Ok(JwtSigningKeys {
encoding_key,
decoding_key,
})
}
}
const JWT_SIGNING_ALGO: Algorithm = Algorithm::EdDSA;
pub fn configure(config: &mut ServiceConfig) {
let jwt_signing_keys = JwtSigningKeys::generate()?;
let validator = Validation::new(JWT_SIGNING_ALGO);
let auth_middleware_settings = AuthenticateMiddlewareSettings {
jwt_decoding_key: jwt_signing_keys.decoding_key,
jwt_authorization_header_prefixes: Some(vec!["Bearer".to_string()]),
jwt_validator: validator,
jwt_session_key: jwt_signing_keys.encoding_key
};
}
#[get("/login")]
async fn login(
jwt_encoding_key: Data<EncodingKey>,
jwt_ttl: Data<JWTTtl>
) -> Result<HttpResponse, Error> {
let sub = format!("{}", Uuid::new_v4().as_u128());
let iat = OffsetDateTime::now_utc().unix_timestamp() as usize;
let expires_at = OffsetDateTime::now_utc().add(jwt_ttl.0);
let exp = expires_at.unix_timestamp() as usize;
let jwt_claims = Claims { iat, exp, sub };
let jwt_token = encode(
&Header::new(JWT_SIGNING_ALGO),
&jwt_claims,
&jwt_encoding_key,
)
.map_err(|_| Error::InternalError)?;
let login_response = LoginResponse {
bearer_token: jwt_token,
claims: jwt_claims,
};
Ok(HttpResponse::Ok().json(login_response))
}
#[get("/session")]
async fn session_info(authenticated: Authenticated<Claims>) -> Result<HttpResponse, Error> {
Ok(HttpResponse::Ok().json(authenticated))
}
#[get("/logout")]
async fn logout(
invalidated_jwts: Data<InvalidatedJWTStore>,
authenticated: Authenticated<Claims>
) -> Result<HttpResponse, Error> {
invalidated_jwts.add_to_invalidated(authenticated).await;
Ok(HttpResponse::Ok().json(EmptyResponse {}))
}

View File

@ -0,0 +1,12 @@
[package]
name = "web-assets"
version = "0.1.0"
edition = "2021"
[dependencies]
actix = "0.13.0"
actix-web = "4.3.1"
askama = { version = "0.12.0", features = ["serde", "with-actix-web", "comrak", "mime"] }
tokio = { version = "1.29.1", features = ["full"] }
serde = { version = "1.0.176", features = ["derive"] }
serde_json = "1.0.104"

View File

@ -0,0 +1 @@
import './elements/oswilno-price.js';

View File

@ -0,0 +1,2 @@
(()=>{customElements.define(class extends HTMLElement{constructor(){let o=this.createShadowRoot({open:!0})}connectedCallback(){let o=this.shadowRoot,t=parseInt(this.getAttribute("price"));isNaN(t)&&(t=0);let i=parseInt(this.getAttribute("multiplier")),s=t,e=0;isNaN(i)||(s=Math.floor(t/i),e=t%i),o.innerHTML=`<style>:host{display:block;}</style><div>${s}.${e>=10?e:e+"0"}</div>`}},"oswilno-price");})();
//# sourceMappingURL=build.js.map

View File

@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["elements/oswilno-price.js"],
"sourcesContent": ["customElements.define(class extends HTMLElement {\n\tconstructor() {\n\t\tconst shadow = this.createShadowRoot({ open: true });\n\t}\n\tconnectedCallback() {\n\t\tlet shadow = this.shadowRoot;\n\t\tlet price = parseInt(this.getAttribute('price'));\n\t\tif (isNaN(price)) price = 0;\n\t\tconst multiplier = parseInt(this.getAttribute('multiplier'));\n\t\tlet major = price;\n\t\tlet minor = 0;\n\t\tif (!isNaN(multiplier)) {\n\t\t\tmajor = Math.floor(price / multiplier);\n\t\t\tminor = price % multiplier;\n\t\t}\n\t\tshadow.innerHTML = `<style>:host{display:block;}</style><div>${major}.${minor >= 10 ? minor : minor + '0'}</div>`;\n\t}\n}, 'oswilno-price');\n"],
"mappings": "MAAA,eAAe,OAAO,cAAc,WAAY,CAC/C,aAAc,CACb,IAAMA,EAAS,KAAK,iBAAiB,CAAE,KAAM,EAAK,CAAC,CACpD,CACA,mBAAoB,CACnB,IAAIA,EAAS,KAAK,WACdC,EAAQ,SAAS,KAAK,aAAa,OAAO,CAAC,EAC3C,MAAMA,CAAK,IAAGA,EAAQ,GAC1B,IAAMC,EAAa,SAAS,KAAK,aAAa,YAAY,CAAC,EACvDC,EAAQF,EACRG,EAAQ,EACP,MAAMF,CAAU,IACpBC,EAAQ,KAAK,MAAMF,EAAQC,CAAU,EACrCE,EAAQH,EAAQC,GAEjBF,EAAO,UAAY,4CAA4CG,CAAK,IAAIC,GAAS,GAAKA,EAAQA,EAAQ,GAAG,QAC1G,CACD,EAAG,eAAe",
"names": ["shadow", "price", "multiplier", "major", "minor"]
}

View File

@ -0,0 +1,20 @@
customElements.define('oswilno-price', class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
let shadow = this.shadowRoot;
let price = parseInt(this.getAttribute('price'));
if (isNaN(price)) price = 0;
const multiplier = parseInt(this.getAttribute('multiplier'));
let major = price;
let minor = 0;
if (!isNaN(multiplier)) {
major = Math.floor(price / multiplier);
minor = price % multiplier;
}
const currency = this.getAttribute('currency') || 'PLN';
shadow.innerHTML = `<style>:host{display:block;}</style><div>${major}.${minor >= 10 ? minor : minor + '0'} ${ currency }</div>`;
}
});

View File

@ -0,0 +1,10 @@
fn main() {
// use std::process::Stdio;
// let child = std::process::Command::new("./build.sh")
// .env("RUST_BACKTRACE", "1")
// .env("RUST_LOG", "debug")
// .stdout(Stdio::piped())
// .spawn()
// .expect("Failed to create child process for building JS");
// child.wait_with_output().expect("Failed to run child process for building JS");
}

13
crates/web-assets/build.sh Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env zsh
echo 'Start building JS'
ROOT=$(git rev-parse --show-toplevel)
WEB_ASSETS_ROOT=${ROOT}/crates/web-assets
cd ${ROOT}
mkdir assets
cd ${WEB_ASSETS_ROOT}
npm install esbuild
${WEB_ASSETS_ROOT}/node_modules/.bin/esbuild --bundle ${WEB_ASSETS_ROOT}/assets/app.js --outfile=${ROOT}/assets/build.js --minify --sourcemap

378
crates/web-assets/package-lock.json generated Normal file
View File

@ -0,0 +1,378 @@
{
"name": "web-assets",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"esbuild": "^0.18.17"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.17.tgz",
"integrity": "sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.17.tgz",
"integrity": "sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.17.tgz",
"integrity": "sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.17.tgz",
"integrity": "sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.17.tgz",
"integrity": "sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.17.tgz",
"integrity": "sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.17.tgz",
"integrity": "sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.17.tgz",
"integrity": "sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.17.tgz",
"integrity": "sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.17.tgz",
"integrity": "sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.17.tgz",
"integrity": "sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==",
"cpu": [
"loong64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.17.tgz",
"integrity": "sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==",
"cpu": [
"mips64el"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.17.tgz",
"integrity": "sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==",
"cpu": [
"ppc64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.17.tgz",
"integrity": "sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==",
"cpu": [
"riscv64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.17.tgz",
"integrity": "sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==",
"cpu": [
"s390x"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.17.tgz",
"integrity": "sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.17.tgz",
"integrity": "sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.17.tgz",
"integrity": "sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.17.tgz",
"integrity": "sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.17.tgz",
"integrity": "sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.17.tgz",
"integrity": "sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.17.tgz",
"integrity": "sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.17.tgz",
"integrity": "sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==",
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/android-arm": "0.18.17",
"@esbuild/android-arm64": "0.18.17",
"@esbuild/android-x64": "0.18.17",
"@esbuild/darwin-arm64": "0.18.17",
"@esbuild/darwin-x64": "0.18.17",
"@esbuild/freebsd-arm64": "0.18.17",
"@esbuild/freebsd-x64": "0.18.17",
"@esbuild/linux-arm": "0.18.17",
"@esbuild/linux-arm64": "0.18.17",
"@esbuild/linux-ia32": "0.18.17",
"@esbuild/linux-loong64": "0.18.17",
"@esbuild/linux-mips64el": "0.18.17",
"@esbuild/linux-ppc64": "0.18.17",
"@esbuild/linux-riscv64": "0.18.17",
"@esbuild/linux-s390x": "0.18.17",
"@esbuild/linux-x64": "0.18.17",
"@esbuild/netbsd-x64": "0.18.17",
"@esbuild/openbsd-x64": "0.18.17",
"@esbuild/sunos-x64": "0.18.17",
"@esbuild/win32-arm64": "0.18.17",
"@esbuild/win32-ia32": "0.18.17",
"@esbuild/win32-x64": "0.18.17"
}
}
}
}

View File

@ -0,0 +1,5 @@
{
"dependencies": {
"esbuild": "^0.18.17"
}
}

View File

@ -0,0 +1,63 @@
use std::{borrow::Cow, sync::Once};
use actix_web::{get, web::ServiceConfig, HttpResponse};
pub fn configure(config: &mut ServiceConfig) {
config.service(serve_build_js).service(serve_build_js_map);
}
macro_rules! static_resource {
($serve: ident, $name: ident, $path: expr, $once: ident, $content: ident) => {
static $once: Once = Once::new();
static mut $content: String = String::new();
fn $name() -> Cow<'static, str> {
if cfg!(debug_assertions) {
build();
std::fs::read_to_string(concat!(".", $path)).unwrap().into()
} else {
$once.call_once(|| {
build();
unsafe {
$content = std::fs::read_to_string(concat!(".", $path)).unwrap();
}
});
unsafe { $content.as_str().into() }
}
}
#[get($path)]
async fn $serve() -> HttpResponse {
HttpResponse::Ok()
.append_header(("Content-Type", "application/javascript"))
.body($name())
}
};
}
static_resource!(
serve_build_js_map,
build_js_map,
"/assets/build.js.map",
BUILD_JS_MAP_GUARD,
BUILD_JS_MAP
);
static_resource!(
serve_build_js,
build_js,
"/assets/build.js",
BUILD_JS_GUARD,
BUILD_JS
);
fn build() {
use std::process::Stdio;
let child = std::process::Command::new("./crates/web-assets/build.sh")
.env("RUST_BACKTRACE", "1")
.env("RUST_LOG", "debug")
.stdout(Stdio::piped())
.spawn()
.expect("Failed to create child process for building JS");
child
.wait_with_output()
.expect("Failed to run child process for building JS");
}