Merge remote-tracking branch 'refs/remotes/origin/new-design' into new-design
This commit is contained in:
commit
877dcae1a9
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,3 +12,4 @@ node_modules
|
|||||||
/assets/build.js
|
/assets/build.js
|
||||||
/assets/build.js.map
|
/assets/build.js.map
|
||||||
/assets/style.css
|
/assets/style.css
|
||||||
|
config
|
||||||
|
@ -885,6 +885,10 @@ select {
|
|||||||
width: 1.25rem;
|
width: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-64 {
|
||||||
|
width: 16rem;
|
||||||
|
}
|
||||||
|
|
||||||
.w-8 {
|
.w-8 {
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
}
|
}
|
||||||
@ -1113,6 +1117,11 @@ select {
|
|||||||
line-height: 1.25rem;
|
line-height: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-xl {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
line-height: 1.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.font-bold {
|
.font-bold {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,16 @@ pub fn mount(config: &mut ServiceConfig) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn translations(l10n: &mut oswilno_view::TranslationStorage) {
|
||||||
|
l10n
|
||||||
|
// Polish
|
||||||
|
.with_lang(oswilno_view::Lang::Pl)
|
||||||
|
.add("Location", "Miejsce")
|
||||||
|
.add("Spot", "Miejsce postojowe")
|
||||||
|
.add("Register parking space", "Zarejestruj miejsce postojowe")
|
||||||
|
.done();
|
||||||
|
}
|
||||||
|
|
||||||
#[autometrics]
|
#[autometrics]
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
async fn root() -> HttpResponse {
|
async fn root() -> HttpResponse {
|
||||||
@ -139,8 +149,8 @@ async fn load_locations(db: Arc<DatabaseConnection>) -> Vec<parking_space_locati
|
|||||||
v.sort_by(|l, r| {
|
v.sort_by(|l, r| {
|
||||||
l.name
|
l.name
|
||||||
.cmp(&r.name)
|
.cmp(&r.name)
|
||||||
.cmp(&l.number.cmp(&r.number))
|
.then(l.number.cmp(&r.number))
|
||||||
.cmp(&l.stage.cmp(&r.stage))
|
.then(l.stage.cmp(&r.stage))
|
||||||
});
|
});
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
@ -231,7 +241,10 @@ async fn create(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
unreachable!()
|
HttpResponse::SeeOther()
|
||||||
|
.append_header(("Location", "/parking-spaces/all"))
|
||||||
|
.append_header(("HX-Redirect", "/parking-spaces/all"))
|
||||||
|
.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn ensure_locations(db: Arc<sea_orm::DatabaseConnection>) {
|
async fn ensure_locations(db: Arc<sea_orm::DatabaseConnection>) {
|
||||||
|
@ -1,12 +1,23 @@
|
|||||||
<section id="main-view" class="min-h-screen flex items-center justify-center">
|
<section id="main-view" class="min-h-screen flex items-center justify-center">
|
||||||
<section class="max-w-md w-full p-6 bg-white rounded-lg shadow-lg">
|
<section class="max-w-md w-full p-6 bg-white rounded-lg shadow-lg">
|
||||||
|
<h2 class="text-xl text-gray-900 mb-2">{{ "Register parking space"|t(lang,t) }}</h2>
|
||||||
{% for error in errors.global() %}
|
{% for error in errors.global() %}
|
||||||
<oswilno-error>{{error|t(lang,t)}}</oswilno-error>
|
<oswilno-error>{{error|t(lang,t)}}</oswilno-error>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<form hx-post="/login" hx-target="#main-view">
|
<form hx-post="/parking-spaces/create" hx-target="main">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label for="location_id" class="block mb-2 text-sm text-gray-600">location_id</label>
|
<label
|
||||||
<select id="location_id" name="location_id" value="{{ form.location_id }}" class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-cyan-500">
|
for="location_id"
|
||||||
|
class="block mb-2 text-sm text-gray-600"
|
||||||
|
>
|
||||||
|
{{ "Location"|t(lang,t) }}
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
id="location_id"
|
||||||
|
name="location_id"
|
||||||
|
value="{{ form.location_id|skip_if(0) }}"
|
||||||
|
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-cyan-500"
|
||||||
|
>
|
||||||
{% for loc in locations %}
|
{% for loc in locations %}
|
||||||
<option value="{{loc.id}}">
|
<option value="{{loc.id}}">
|
||||||
{{ loc.name }}
|
{{ loc.name }}
|
||||||
@ -19,11 +30,26 @@
|
|||||||
<oswilno-error>{{error|t(lang,t)}}</oswilno-error>
|
<oswilno-error>{{error|t(lang,t)}}</oswilno-error>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label
|
||||||
|
for="spot"
|
||||||
|
class="block mb-2 text-sm text-gray-600"
|
||||||
|
>
|
||||||
|
{{ "Spot"|t(lang,t) }}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="spot"
|
||||||
|
name="spot"
|
||||||
|
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-cyan-500"
|
||||||
|
type="number"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<input
|
<input
|
||||||
type="submit"
|
type="submit"
|
||||||
value="{{"Submit"|t(lang,t)}}"
|
value="{{"Register parking space"|t(lang,t)}}"
|
||||||
class="w-32 bg-cyan-600 text-white py-2 rounded-lg mx-auto block focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-cyan-500 mb-2"
|
class="w-64 bg-cyan-600 text-white py-2 rounded-lg mx-auto block focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-cyan-500 mb-2"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -49,6 +49,8 @@ async fn main() -> std::io::Result<()> {
|
|||||||
let session_config = oswilno_session::SessionConfigurator::new(redis.clone());
|
let session_config = oswilno_session::SessionConfigurator::new(redis.clone());
|
||||||
session_config.translations(&mut l10n);
|
session_config.translations(&mut l10n);
|
||||||
|
|
||||||
|
oswilno_parking_space::translations(&mut l10n);
|
||||||
|
|
||||||
oswilno_parking_space::init(Arc::new(conn.clone())).await;
|
oswilno_parking_space::init(Arc::new(conn.clone())).await;
|
||||||
|
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use std::io::Read;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -99,12 +100,6 @@ impl SessionConfigurator {
|
|||||||
|
|
||||||
pub fn translations(&self, l10n: &mut oswilno_view::TranslationStorage) {
|
pub fn translations(&self, l10n: &mut oswilno_view::TranslationStorage) {
|
||||||
l10n
|
l10n
|
||||||
// English
|
|
||||||
.with_lang(oswilno_view::Lang::En)
|
|
||||||
.add("Sign in", "Sign in")
|
|
||||||
.add("Sign up", "Sign up")
|
|
||||||
.add("Bad credentials", "Bad credentials")
|
|
||||||
.done()
|
|
||||||
// Polish
|
// Polish
|
||||||
.with_lang(oswilno_view::Lang::Pl)
|
.with_lang(oswilno_view::Lang::Pl)
|
||||||
.add("Sign in", "Logowanie")
|
.add("Sign in", "Logowanie")
|
||||||
@ -127,7 +122,10 @@ impl SessionConfigurator {
|
|||||||
|
|
||||||
pub fn new(redis: redis_async_pool::RedisPool) -> Self {
|
pub fn new(redis: redis_async_pool::RedisPool) -> Self {
|
||||||
let jwt_ttl = JWTTtl(std::time::Duration::from_secs(31 * 60 * 60));
|
let jwt_ttl = JWTTtl(std::time::Duration::from_secs(31 * 60 * 60));
|
||||||
let jwt_signing_keys = JwtSigningKeys::generate().unwrap();
|
|
||||||
|
std::fs::create_dir_all("./config").ok();
|
||||||
|
|
||||||
|
let jwt_signing_keys = JwtSigningKeys::load_or_create();
|
||||||
let auth_middleware_factory = RedisMiddlewareFactory::<Claims>::new(
|
let auth_middleware_factory = RedisMiddlewareFactory::<Claims>::new(
|
||||||
Arc::new(jwt_signing_keys.encoding_key),
|
Arc::new(jwt_signing_keys.encoding_key),
|
||||||
Arc::new(jwt_signing_keys.decoding_key),
|
Arc::new(jwt_signing_keys.decoding_key),
|
||||||
@ -303,11 +301,13 @@ async fn login_inner(
|
|||||||
actix_web::cookie::Cookie::build(actix_jwt_session::DEFAULT_HEADER_NAME, &bearer_token)
|
actix_web::cookie::Cookie::build(actix_jwt_session::DEFAULT_HEADER_NAME, &bearer_token)
|
||||||
.http_only(true)
|
.http_only(true)
|
||||||
.finish();
|
.finish();
|
||||||
Ok(HttpResponse::Ok()
|
Ok(HttpResponse::SeeOther()
|
||||||
.append_header((
|
.append_header((
|
||||||
actix_jwt_session::DEFAULT_HEADER_NAME,
|
actix_jwt_session::DEFAULT_HEADER_NAME,
|
||||||
format!("Bearer {bearer_token}").as_str(),
|
format!("Bearer {bearer_token}").as_str(),
|
||||||
))
|
))
|
||||||
|
.append_header(("Location", "/"))
|
||||||
|
.append_header(("HX-Redirect", "/"))
|
||||||
.cookie(cookie)
|
.cookie(cookie)
|
||||||
.body(""))
|
.body(""))
|
||||||
}
|
}
|
||||||
@ -552,14 +552,42 @@ pub struct JwtSigningKeys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl JwtSigningKeys {
|
impl JwtSigningKeys {
|
||||||
|
fn load_or_create() -> Self {
|
||||||
|
match Self::load_from_files() {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Self::generate().unwrap(),
|
||||||
|
Err(e) => panic!("{:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn generate() -> Result<Self, Box<dyn std::error::Error>> {
|
fn generate() -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
let doc = Ed25519KeyPair::generate_pkcs8(&SystemRandom::new())?;
|
let doc = Ed25519KeyPair::generate_pkcs8(&SystemRandom::new())?;
|
||||||
let keypair = Ed25519KeyPair::from_pkcs8(doc.as_ref())?;
|
let keypair = Ed25519KeyPair::from_pkcs8(doc.as_ref())?;
|
||||||
let encoding_key = EncodingKey::from_ed_der(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());
|
let decoding_key = DecodingKey::from_ed_der(keypair.public_key().as_ref());
|
||||||
|
|
||||||
|
std::fs::write("./config/jwt-encoding.bin", doc.as_ref()).unwrap();
|
||||||
|
std::fs::write("./config/jwt-decoding.bin", keypair.public_key()).unwrap();
|
||||||
|
|
||||||
Ok(JwtSigningKeys {
|
Ok(JwtSigningKeys {
|
||||||
encoding_key,
|
encoding_key,
|
||||||
decoding_key,
|
decoding_key,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_from_files() -> std::io::Result<Self> {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let mut e = std::fs::File::open("./config/jwt-encoding.bin")?;
|
||||||
|
e.read_to_end(&mut buf).unwrap();
|
||||||
|
let encoding_key: EncodingKey = EncodingKey::from_ed_der(&buf);
|
||||||
|
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let mut e = std::fs::File::open("./config/jwt-decoding.bin")?;
|
||||||
|
e.read_to_end(&mut buf).unwrap();
|
||||||
|
let decoding_key = DecodingKey::from_ed_der(&buf);
|
||||||
|
Ok(Self {
|
||||||
|
encoding_key,
|
||||||
|
decoding_key,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,3 +11,11 @@ pub fn t<T: std::fmt::Display + std::fmt::Debug>(
|
|||||||
// tracing::debug!("translating {s:?} to lang {lang:?} with {t:?}");
|
// tracing::debug!("translating {s:?} to lang {lang:?} with {t:?}");
|
||||||
Ok(t.to_lang(*lang, &s.to_string()))
|
Ok(t.to_lang(*lang, &s.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn skip_if<T: std::fmt::Display + PartialEq + Copy>(n: &T, skip: T) -> Result<String> {
|
||||||
|
Ok(if n == &skip {
|
||||||
|
"".to_string()
|
||||||
|
} else {
|
||||||
|
n.to_string()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user