diff --git a/app/__init__.py b/app/__init__.py index e9c6652..093a92d 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -53,11 +53,11 @@ def create_app(test_config=None): if request.endpoint == "static": filename = request.view_args.get("filename", "") if request.view_args else "" if filename.endswith(".css"): - response.headers["Cache-Control"] = "public, max-age=2592000, immutable" + response.headers["Cache-Control"] = "public, max-age=1800, immutable" else: - response.headers["Cache-Control"] = "public, max-age=2592000, immutable" + response.headers["Cache-Control"] = "public, max-age=1800, immutable" elif response.mimetype == "text/html": - response.headers["Cache-Control"] = "no-store, private, must-revalidate" + response.headers["Cache-Control"] = "private, no-store" return response @login_manager.user_loader diff --git a/app/config.py b/app/config.py index 40ea272..545f59f 100644 --- a/app/config.py +++ b/app/config.py @@ -35,7 +35,7 @@ class Config: SECRET_KEY = env("SECRET_KEY", "dev-secret") SQLALCHEMY_DATABASE_URI = env("DATABASE_URL", "sqlite:////app/instance/fueltrack.db") SQLALCHEMY_TRACK_MODIFICATIONS = False - API_TOKEN_MAX_AGE_SECONDS = env_int("API_TOKEN_MAX_AGE_SECONDS", 28800) + API_TOKEN_MAX_AGE_SECONDS = env_int("API_TOKEN_MAX_AGE_SECONDS", 928800) HTTP_TIMEOUT_SECONDS = env_float("HTTP_TIMEOUT_SECONDS", 30) ORLEN_TIMEOUT_SECONDS = env_float("ORLEN_TIMEOUT_SECONDS", 15) diff --git a/app/database.py b/app/database.py index b2b5301..fdba4b5 100644 --- a/app/database.py +++ b/app/database.py @@ -1,11 +1,8 @@ from __future__ import annotations - import fcntl from contextlib import contextmanager from pathlib import Path - from flask import Flask - from .database_init import initialize_database from .database_migrations import migrate_database diff --git a/app/database_init.py b/app/database_init.py index c507dfa..d017c19 100644 --- a/app/database_init.py +++ b/app/database_init.py @@ -1,7 +1,5 @@ from __future__ import annotations - from sqlalchemy import inspect - from .extensions import db from .models import AppSetting, CompanySettings, User diff --git a/app/database_migrations.py b/app/database_migrations.py index 30e3a5b..e1f32cd 100644 --- a/app/database_migrations.py +++ b/app/database_migrations.py @@ -1,10 +1,7 @@ from __future__ import annotations - from collections.abc import Callable from dataclasses import dataclass - from sqlalchemy import inspect, text - from .extensions import db diff --git a/app/services.py b/app/services.py index d40a6dd..4adfcbe 100644 --- a/app/services.py +++ b/app/services.py @@ -1,4 +1,3 @@ -"""Compatibility facade. New code lives in domain/ and integrations/.""" from .domain.costs import calculate_costs, money from .domain.invoices import invoice_period from .integrations.orlen import fetch_orlen_price, fetch_orlen_range, POLISH_REGIONS, PRODUCT_IDS diff --git a/app/static/js/ajax.js b/app/static/js/ajax.js index 5398b2e..563cfa6 100644 --- a/app/static/js/ajax.js +++ b/app/static/js/ajax.js @@ -1 +1 @@ -(()=>{const F=FuelTrack;F.replaceMain=async(url=location.href,{push=false}={})=>{const r=await fetch(url,{headers:{'X-Requested-With':'XMLHttpRequest'}});if(!r.ok)throw new Error('Nie udało się odświeżyć widoku.');const doc=new DOMParser().parseFromString(await r.text(),'text/html');const incoming=F.qs('main',doc),current=F.qs('main');if(!incoming||!current)return;current.replaceWith(incoming);document.documentElement.dataset.bsTheme=doc.documentElement.dataset.bsTheme||'light';const next=F.qs('#bootstrap-theme',doc),theme=F.qs('#bootstrap-theme');if(next&&theme)theme.href=next.href;if(push)history.pushState({},'',url);F.initPage();F.qsa('script:not([src])',doc).forEach(x=>{if(x.textContent.includes('FuelTrack.'))try{Function(x.textContent)()}catch(e){console.error(e)}})};F.submitAjax=async form=>{const b=F.qs('[type=submit]',form),old=b?.innerHTML;if(b){b.disabled=true;b.innerHTML='Zapisywanie…'}try{const r=await fetch(form.action||location.href,{method:(form.dataset.method||form.getAttribute('method')||'POST').toUpperCase(),body:new FormData(form),headers:{'X-Requested-With':'XMLHttpRequest','Accept':'application/json'}});const d=await r.json();if(!r.ok||!d.ok)throw new Error(d.error||d.message||'Operacja nie powiodła się.');F.notify(d.message||'Zapisano');bootstrap.Modal.getInstance(form.closest('.modal'))?.hide();await F.replaceMain((d.data||{}).redirect||location.href,{push:Boolean((d.data||{}).redirect)})}catch(e){F.notify(e.message,'danger')}finally{if(b){b.disabled=false;b.innerHTML=old}}};F.bindAjaxForms=()=>{F.qsa('form.ajax-form').forEach(f=>{if(f.dataset.bound)return;f.dataset.bound='1';f.addEventListener('submit',e=>{e.preventDefault();F.submitAjax(f)})});F.qsa('form.ajax-nav-form').forEach(f=>{if(f.dataset.bound)return;f.dataset.bound='1';f.addEventListener('submit',e=>{e.preventDefault();F.replaceMain(`${f.action||location.pathname}?${new URLSearchParams(new FormData(f))}`,{push:true}).catch(x=>F.notify(x.message,'danger'))})});F.qsa('a.ajax-nav-link').forEach(a=>{if(a.dataset.bound)return;a.dataset.bound='1';a.addEventListener('click',e=>{e.preventDefault();F.replaceMain(a.href,{push:true}).catch(x=>F.notify(x.message,'danger'))})})}})(); +(()=>{const F=FuelTrack;F.replaceMain=async(url=location.href,{push=false}={})=>{const r=await fetch(url,{headers:{'X-Requested-With':'XMLHttpRequest'}});if(!r.ok)throw new Error('Nie udało się odświeżyć widoku.');const doc=new DOMParser().parseFromString(await r.text(),'text/html');const incoming=F.qs('main',doc),current=F.qs('main');if(!incoming||!current)return;current.replaceWith(incoming);document.documentElement.dataset.bsTheme=doc.documentElement.dataset.bsTheme||'light';const next=F.qs('#bootstrap-theme',doc),theme=F.qs('#bootstrap-theme');if(next&&theme)theme.href=next.href;if(push)history.pushState({},'',url);F.initPage();F.qsa('script:not([src])',doc).forEach(x=>{if(x.textContent.includes('FuelTrack.'))try{Function(x.textContent)()}catch(e){console.error(e)}})};F.submitAjax=async form=>{const b=F.qs('[type=submit]',form),old=b?.innerHTML;if(b){b.disabled=true;b.innerHTML='Zapisywanie…'}try{const r=await fetch(form.action||location.href,{method:(form.dataset.method||form.getAttribute('method')||'POST').toUpperCase(),body:new FormData(form),headers:{'X-Requested-With':'XMLHttpRequest','Accept':'application/json'}});const d=await r.json();if(!r.ok||!d.ok)throw new Error(d.error||d.message||'Operacja nie powiodła się.');F.notify(d.message||'Zapisano');bootstrap.Modal.getInstance(form.closest('.modal'))?.hide();await F.replaceMain((d.data||{}).redirect||location.href,{push:Boolean((d.data||{}).redirect)})}catch(e){F.notify(e.message,'danger')}finally{if(b){b.disabled=false;b.innerHTML=old}}};F.bindAjaxForms=()=>{F.qsa('form.ajax-form').forEach(f=>{if(f.dataset.bound)return;f.dataset.bound='1';f.addEventListener('submit',e=>{e.preventDefault();F.submitAjax(f)})});F.qsa('form.ajax-nav-form').forEach(f=>{if(f.dataset.bound)return;f.dataset.bound='1';f.addEventListener('submit',e=>{e.preventDefault();(()=>{const url=new URL(f.getAttribute('action')||location.pathname,location.origin);url.search=new URLSearchParams(new FormData(f)).toString();return F.replaceMain(url.toString(),{push:true})})().catch(x=>F.notify(x.message,'danger'))})});F.qsa('a.ajax-nav-link').forEach(a=>{if(a.dataset.bound)return;a.dataset.bound='1';a.addEventListener('click',e=>{e.preventDefault();F.replaceMain(a.href,{push:true}).catch(x=>F.notify(x.message,'danger'))})})}})(); diff --git a/app/templates/orlen.html b/app/templates/orlen.html index 2571a8c..80fb6de 100644 --- a/app/templates/orlen.html +++ b/app/templates/orlen.html @@ -47,6 +47,6 @@
Cena za litr w złotych.
| Data | Paliwo | Cena netto zł/l | Region | Pobrano |
|---|---|---|---|---|
| {{r.effective_date}} | {{r.product_name}} | {{'%.4f'|format(r.price_per_liter|float)}} | {{r.region or '—'}} | {{r.fetched_at.strftime('%Y-%m-%d %H:%M')}} |
| Brak danych w bazie. | ||||
| Data | Paliwo | Cena netto zł/l | Region | Pobrano |
|---|---|---|---|---|
| {{r.effective_date}} | {{r.product_name}} | {{'%.4f'|format(r.price_per_liter|float)}} | {{r.region or '—'}} | {{r.fetched_at.strftime('%Y-%m-%d %H:%M')}} |
| Brak danych w bazie. | ||||