Merge remote-tracking branch 'refs/remotes/origin/new-design' into new-design

This commit is contained in:
eraden 2023-08-23 22:53:01 +02:00
commit 877dcae1a9
7 changed files with 103 additions and 16 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ node_modules
/assets/build.js
/assets/build.js.map
/assets/style.css
config

View File

@ -885,6 +885,10 @@ select {
width: 1.25rem;
}
.w-64 {
width: 16rem;
}
.w-8 {
width: 2rem;
}
@ -1113,6 +1117,11 @@ select {
line-height: 1.25rem;
}
.text-xl {
font-size: 1.25rem;
line-height: 1.75rem;
}
.font-bold {
font-weight: 700;
}

View File

@ -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]
#[get("/")]
async fn root() -> HttpResponse {
@ -139,8 +149,8 @@ async fn load_locations(db: Arc<DatabaseConnection>) -> Vec<parking_space_locati
v.sort_by(|l, r| {
l.name
.cmp(&r.name)
.cmp(&l.number.cmp(&r.number))
.cmp(&l.stage.cmp(&r.stage))
.then(l.number.cmp(&r.number))
.then(l.stage.cmp(&r.stage))
});
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>) {

View File

@ -1,12 +1,23 @@
<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">
<h2 class="text-xl text-gray-900 mb-2">{{ "Register parking space"|t(lang,t) }}</h2>
{% for error in errors.global() %}
<oswilno-error>{{error|t(lang,t)}}</oswilno-error>
{% endfor %}
<form hx-post="/login" hx-target="#main-view">
<form hx-post="/parking-spaces/create" hx-target="main">
<div class="mb-4">
<label for="location_id" class="block mb-2 text-sm text-gray-600">location_id</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">
<label
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 %}
<option value="{{loc.id}}">
{{ loc.name }}
@ -19,11 +30,26 @@
<oswilno-error>{{error|t(lang,t)}}</oswilno-error>
{% endfor %}
</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">
<input
type="submit"
value="{{"Submit"|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"
value="{{"Register parking space"|t(lang,t)}}"
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>
</form>

View File

@ -49,6 +49,8 @@ async fn main() -> std::io::Result<()> {
let session_config = oswilno_session::SessionConfigurator::new(redis.clone());
session_config.translations(&mut l10n);
oswilno_parking_space::translations(&mut l10n);
oswilno_parking_space::init(Arc::new(conn.clone())).await;
HttpServer::new(move || {

View File

@ -1,3 +1,4 @@
use std::io::Read;
use std::ops::Add;
use std::sync::Arc;
@ -99,12 +100,6 @@ impl SessionConfigurator {
pub fn translations(&self, l10n: &mut oswilno_view::TranslationStorage) {
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
.with_lang(oswilno_view::Lang::Pl)
.add("Sign in", "Logowanie")
@ -127,7 +122,10 @@ impl SessionConfigurator {
pub fn new(redis: redis_async_pool::RedisPool) -> Self {
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(
Arc::new(jwt_signing_keys.encoding_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)
.http_only(true)
.finish();
Ok(HttpResponse::Ok()
Ok(HttpResponse::SeeOther()
.append_header((
actix_jwt_session::DEFAULT_HEADER_NAME,
format!("Bearer {bearer_token}").as_str(),
))
.append_header(("Location", "/"))
.append_header(("HX-Redirect", "/"))
.cookie(cookie)
.body(""))
}
@ -552,14 +552,42 @@ pub struct 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>> {
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());
std::fs::write("./config/jwt-encoding.bin", doc.as_ref()).unwrap();
std::fs::write("./config/jwt-decoding.bin", keypair.public_key()).unwrap();
Ok(JwtSigningKeys {
encoding_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,
})
}
}

View File

@ -11,3 +11,11 @@ pub fn t<T: std::fmt::Display + std::fmt::Debug>(
// tracing::debug!("translating {s:?} to lang {lang:?} with {t:?}");
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()
})
}