diff --git a/.gitignore b/.gitignore index bfe5ef4..f825246 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ instance/ venv/ .env version.txt -deploy/varnish/default.vcl \ No newline at end of file +deploy/varnish/default.vcl +*.tar.gz \ No newline at end of file diff --git a/alters.txt b/alters.txt index dc048b5..891edd7 100644 --- a/alters.txt +++ b/alters.txt @@ -1,68 +1,18 @@ --- WŁĄCZ/wyłącz FK zależnie od etapu migracji -PRAGMA foreign_keys = OFF; - BEGIN TRANSACTION; --- 1) Nowa tabela z właściwym FK (ON DELETE CASCADE) -CREATE TABLE wplata_new ( - id INTEGER PRIMARY KEY, - zbiorka_id INTEGER NOT NULL, - kwota REAL NOT NULL, - data DATETIME, - opis TEXT, - FOREIGN KEY(zbiorka_id) REFERENCES zbiorka(id) ON DELETE CASCADE -); +-- UŻYTKOWNIK +ALTER TABLE user RENAME TO uzytkownik; +ALTER TABLE uzytkownik RENAME COLUMN username TO uzytkownik; +ALTER TABLE uzytkownik RENAME COLUMN password_hash TO haslo_hash; +ALTER TABLE uzytkownik RENAME COLUMN is_admin TO czy_admin; --- 2) (opcjonalnie) upewnij się, że nie ma „sierotek” --- SELECT w.* FROM wplata w LEFT JOIN zbiorka z ON z.id = w.zbiorka_id WHERE z.id IS NULL; - --- 3) Kopiowanie danych -INSERT INTO wplata_new (id, zbiorka_id, kwota, data, opis) -SELECT id, zbiorka_id, kwota, data, opis -FROM wplata; - --- 4) Usunięcie starej tabeli -DROP TABLE wplata; - --- 5) Zmiana nazwy nowej tabeli na właściwą -ALTER TABLE wplata_new RENAME TO wplata; - --- 6) Odtwórz indeksy/trigger-y jeśli jakieś były (przykład indeksu po FK) --- CREATE INDEX idx_wplata_zbiorka_id ON wplata(zbiorka_id); +-- USTAWIENIA GLOBALNE +ALTER TABLE global_settings RENAME TO ustawienia_globalne; +ALTER TABLE ustawienia_globalne RENAME COLUMN allowed_login_hosts TO dozwolone_hosty_logowania; +ALTER TABLE ustawienia_globalne RENAME COLUMN site_title TO tytul_strony; +ALTER TABLE ustawienia_globalne RENAME COLUMN show_logo_in_navbar TO pokaz_logo_w_navbar; +ALTER TABLE ustawienia_globalne RENAME COLUMN navbar_brand_mode TO typ_navbar; +ALTER TABLE ustawienia_globalne RENAME COLUMN footer_brand_mode TO typ_stopka; +ALTER TABLE ustawienia_globalne RENAME COLUMN footer_text TO stopka_text; COMMIT; - -PRAGMA foreign_keys = ON; - - -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - -PRAGMA foreign_keys=OFF; -BEGIN TRANSACTION; - -ALTER TABLE global_settings ADD COLUMN logo_url TEXT DEFAULT ''; -ALTER TABLE global_settings ADD COLUMN site_title TEXT DEFAULT ''; -ALTER TABLE global_settings ADD COLUMN show_logo_in_navbar BOOLEAN DEFAULT 0; - - - -COMMIT; -PRAGMA foreign_keys=ON; - -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - --- 1) Dodajemy nowe kolumny (SQLite pozwala tylko na ADD COLUMN) -ALTER TABLE global_settings ADD COLUMN navbar_brand_mode TEXT DEFAULT 'text'; -ALTER TABLE global_settings ADD COLUMN footer_brand_mode TEXT DEFAULT 'text'; -ALTER TABLE global_settings ADD COLUMN footer_text TEXT; - --- 2) Backfill: zgodność wsteczna z show_logo_in_navbar -UPDATE global_settings -SET navbar_brand_mode = 'logo' -WHERE COALESCE(show_logo_in_navbar, 0) = 1; - --- 3) Upewnij się, że wartości są ustawione (na wypadek NULL-i) -UPDATE global_settings -SET navbar_brand_mode = COALESCE(navbar_brand_mode, 'text'), - footer_brand_mode = COALESCE(footer_brand_mode, 'text'); \ No newline at end of file diff --git a/app.py b/app.py index 0bc9249..1b3150d 100644 --- a/app.py +++ b/app.py @@ -65,18 +65,18 @@ APP_VERSION = f"{deploy_date}+{commit}" app.config["APP_VERSION"] = APP_VERSION # MODELE -class User(UserMixin, db.Model): +class Uzytkownik(UserMixin, db.Model): + __tablename__ = "uzytkownik" + id = db.Column(db.Integer, primary_key=True) - username = db.Column(db.String(80), unique=True, nullable=False) - password_hash = db.Column(db.String(128), nullable=False) - is_admin = db.Column(db.Boolean, default=False) # Flaga głównego administratora + uzytkownik = db.Column(db.String(80), unique=True, nullable=False) + haslo_hash = db.Column(db.String(128), nullable=False) + czy_admin = db.Column(db.Boolean, default=False) def set_password(self, password): - self.password_hash = generate_password_hash(password) - + self.haslo_hash = generate_password_hash(password) def check_password(self, password): - return check_password_hash(self.password_hash, password) - + return check_password_hash(self.haslo_hash, password) class Zbiorka(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -89,6 +89,9 @@ class Zbiorka(db.Model): ukryta = db.Column(db.Boolean, default=False) ukryj_kwote = db.Column(db.Boolean, default=False) zrealizowana = db.Column(db.Boolean, default=False) + pokaz_postep_finanse = db.Column(db.Boolean, default=True, nullable=False) + pokaz_postep_pozycje = db.Column(db.Boolean, default=True, nullable=False) + pokaz_postep_kwotowo = db.Column(db.Boolean, default=True, nullable=False) wplaty = db.relationship( "Wplata", @@ -139,10 +142,8 @@ class Wplata(db.Model): kwota = db.Column(Numeric(12, 2), nullable=False) data = db.Column(db.DateTime, default=datetime.utcnow) opis = db.Column(db.Text, nullable=True) - zbiorka = db.relationship("Zbiorka", back_populates="wplaty") - class Wydatek(db.Model): id = db.Column(db.Integer, primary_key=True) zbiorka_id = db.Column( @@ -155,22 +156,24 @@ class Wydatek(db.Model): opis = db.Column(db.Text, nullable=True) -class GlobalSettings(db.Model): +class UstawieniaGlobalne(db.Model): + __tablename__ = "ustawienia_globalne" + id = db.Column(db.Integer, primary_key=True) numer_konta = db.Column(db.String(50), nullable=False) numer_telefonu_blik = db.Column(db.String(50), nullable=False) - allowed_login_hosts = db.Column(db.Text, nullable=True) + dozwolone_hosty_logowania = db.Column(db.Text, nullable=True) logo_url = db.Column(db.String(255), nullable=True) - site_title = db.Column(db.String(120), nullable=True) - show_logo_in_navbar = db.Column(db.Boolean, default=False) - navbar_brand_mode = db.Column(db.String(10), default="text") - footer_brand_mode = db.Column(db.String(10), default="text") - footer_text = db.Column(db.String(200), nullable=True) + tytul_strony = db.Column(db.String(120), nullable=True) + pokaz_logo_w_navbar = db.Column(db.Boolean, default=False) + typ_navbar = db.Column(db.String(10), default="text") + typ_stopka = db.Column(db.String(10), default="text") + stopka_text = db.Column(db.String(200), nullable=True) @login_manager.user_loader def load_user(user_id): - return db.session.get(User, int(user_id)) + return db.session.get(Uzytkownik, int(user_id)) @event.listens_for(Engine, "connect") @@ -249,11 +252,9 @@ def markdown_filter(text): @app.context_processor def inject_globals(): - settings = GlobalSettings.query.first() + settings = UstawieniaGlobalne.query.first() allowed_hosts_str = ( - settings.allowed_login_hosts - if settings and settings.allowed_login_hosts - else "" + settings.dozwolone_hosty_logowania if settings and settings.dozwolone_hosty_logowania else "" ) client_ip = get_real_ip() return { @@ -290,7 +291,7 @@ def zbiorka(zbiorka_id): zb = db.session.get(Zbiorka, zbiorka_id) if zb is None: abort(404) - if zb.ukryta and (not current_user.is_authenticated or not current_user.is_admin): + if zb.ukryta and (not current_user.is_authenticated or not current_user.czy_admin): abort(404) # scalona oś czasu: wpłaty + wydatki @@ -311,34 +312,22 @@ def zbiorka(zbiorka_id): @app.route("/zaloguj", methods=["GET", "POST"]) def zaloguj(): - # Pobierz ustawienia globalne, w tym dozwolone hosty - settings = GlobalSettings.query.first() - allowed_hosts_str = "" - if settings and settings.allowed_login_hosts: - allowed_hosts_str = settings.allowed_login_hosts - - # Sprawdzenie, czy adres IP klienta jest dozwolony + settings = UstawieniaGlobalne.query.first() + allowed_hosts_str = settings.dozwolone_hosty_logowania or "" if settings else "" client_ip = get_real_ip() if not is_allowed_ip(client_ip, allowed_hosts_str): - flash( - "Dostęp do tego systemu jest zablokowany dla Twojego adresu IP", - "danger", - ) + flash("Dostęp do tego systemu jest zablokowany dla Twojego adresu IP", "danger") return redirect(url_for("index")) if request.method == "POST": - username = request.form["username"] - password = request.form["password"] - user = User.query.filter_by(username=username).first() + login = request.form["uzytkownik"] + password = request.form["haslo"] + user = Uzytkownik.query.filter_by(uzytkownik=login).first() if user and user.check_password(password): login_user(user) flash("Zalogowano pomyślnie", "success") next_page = request.args.get("next") - return ( - redirect(next_page) - if next_page - else redirect(url_for("admin_dashboard")) - ) + return redirect(next_page) if next_page else redirect(url_for("admin_dashboard")) else: flash("Nieprawidłowe dane logowania", "danger") return render_template("login.html") @@ -358,12 +347,12 @@ def zarejestruj(): flash("Rejestracja została wyłączona przez administratora", "danger") return redirect(url_for("zaloguj")) if request.method == "POST": - username = request.form["username"] - password = request.form["password"] - if User.query.filter_by(username=username).first(): + login = request.form["uzytkownik"] + password = request.form["haslo"] + if Uzytkownik.query.filter_by(uzytkownik=login).first(): flash("Użytkownik już istnieje", "danger") return redirect(url_for("register")) - new_user = User(username=username) + new_user = Uzytkownik(uzytkownik=login) new_user.set_password(password) db.session.add(new_user) db.session.commit() @@ -376,7 +365,7 @@ def zarejestruj(): @app.route("/admin") @login_required def admin_dashboard(): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień do panelu administracyjnego", "danger") return redirect(url_for("index")) active_zbiorki = Zbiorka.query.filter_by(zrealizowana=False).all() @@ -392,30 +381,32 @@ def admin_dashboard(): @app.route("/admin/zbiorka/edytuj/", methods=["GET", "POST"]) @login_required def formularz_zbiorek(zbiorka_id=None): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień", "danger") return redirect(url_for("index")) - # Tryb: dodawanie vs edycja is_edit = zbiorka_id is not None - - # Obiekt zbiórki ładujemy TYLKO przy edycji zb = None if is_edit: zb = db.session.get(Zbiorka, zbiorka_id) if zb is None: abort(404) - global_settings = GlobalSettings.query.first() + global_settings = UstawieniaGlobalne.query.first() if request.method == "POST": # Pola wspólne nazwa = request.form.get("nazwa", "").strip() opis = request.form.get("opis", "").strip() - numer_konta = request.form.get("numer_konta", "").strip() numer_telefonu_blik = request.form.get("numer_telefonu_blik", "").strip() + # Widoczność kwot i poszczególnych pasków postępu + ukryj_kwote = "ukryj_kwote" in request.form + pokaz_postep_finanse = "pokaz_postep_finanse" in request.form + pokaz_postep_pozycje = "pokaz_postep_pozycje" in request.form + pokaz_postep_kwotowo = "pokaz_postep_kwotowo" in request.form + # Cel — Decimal, > 0 try: cel_str = request.form.get("cel", "").replace(",", ".").strip() @@ -424,23 +415,38 @@ def formularz_zbiorek(zbiorka_id=None): raise InvalidOperation except (InvalidOperation, ValueError): flash("Podano nieprawidłową wartość dla celu zbiórki", "danger") - # Utwórz tymczasowy obiekt do ponownego renderu formularza - temp_zb = (zb or Zbiorka( - nazwa=nazwa, - opis=opis, - numer_konta=numer_konta, - numer_telefonu_blik=numer_telefonu_blik, - cel=None, - ukryj_kwote=("ukryj_kwote" in request.form), - )) + + # Przy błędzie celu odtwórz stan formularza (również przełączniki) + if is_edit and zb: + zb.nazwa = nazwa + zb.opis = opis + zb.numer_konta = numer_konta + zb.numer_telefonu_blik = numer_telefonu_blik + zb.ukryj_kwote = ukryj_kwote + zb.pokaz_postep_finanse = pokaz_postep_finanse + zb.pokaz_postep_pozycje = pokaz_postep_pozycje + zb.pokaz_postep_kwotowo = pokaz_postep_kwotowo + temp_zb = zb + else: + temp_zb = Zbiorka( + nazwa=nazwa, + opis=opis, + numer_konta=numer_konta, + numer_telefonu_blik=numer_telefonu_blik, + cel=None, + ukryj_kwote=ukryj_kwote, + pokaz_postep_finanse=pokaz_postep_finanse, + pokaz_postep_pozycje=pokaz_postep_pozycje, + pokaz_postep_kwotowo=pokaz_postep_kwotowo, + ) + return render_template( "admin/formularz_zbiorek.html", zbiorka=temp_zb, global_settings=global_settings, ) - ukryj_kwote = "ukryj_kwote" in request.form - + # Lista produktów names = request.form.getlist("item_nazwa[]") links = request.form.getlist("item_link[]") prices = request.form.getlist("item_cena[]") @@ -464,11 +470,14 @@ def formularz_zbiorek(zbiorka_id=None): zb.opis = opis zb.numer_konta = numer_konta zb.numer_telefonu_blik = numer_telefonu_blik - zb.cel = cel # pozostaje Decimal + zb.cel = cel zb.ukryj_kwote = ukryj_kwote - db.session.commit() # zapisz bazowe pola + zb.pokaz_postep_finanse = pokaz_postep_finanse + zb.pokaz_postep_pozycje = pokaz_postep_pozycje + zb.pokaz_postep_kwotowo = pokaz_postep_kwotowo + db.session.commit() # zapisz bazowe pola - # Nadpisz listę produktów (czyść i dodaj od nowa dla prostoty) + # Nadpisz listę produktów zb.przedmioty.clear() for i, raw_name in enumerate(names): name = (raw_name or "").strip() @@ -496,11 +505,14 @@ def formularz_zbiorek(zbiorka_id=None): opis=opis, numer_konta=numer_konta, numer_telefonu_blik=numer_telefonu_blik, - cel=cel, # Decimal + cel=cel, ukryj_kwote=ukryj_kwote, + pokaz_postep_finanse=pokaz_postep_finanse, + pokaz_postep_pozycje=pokaz_postep_pozycje, + pokaz_postep_kwotowo=pokaz_postep_kwotowo, ) db.session.add(nowa) - db.session.commit() # potrzebne ID + db.session.commit() # potrzebne ID # Dodaj produkty do nowej zbiórki for i, raw_name in enumerate(names): @@ -526,14 +538,16 @@ def formularz_zbiorek(zbiorka_id=None): # GET return render_template( - "admin/formularz_zbiorek.html", zbiorka=zb, global_settings=global_settings + "admin/formularz_zbiorek.html", + zbiorka=zb, + global_settings=global_settings ) @app.route("/admin/zbiorka//wplata/dodaj", methods=["GET", "POST"]) @login_required def dodaj_wplate(zbiorka_id): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień", "danger") return redirect(url_for("index")) @@ -565,7 +579,7 @@ def dodaj_wplate(zbiorka_id): @app.route("/admin/zbiorka/usun/", methods=["POST"]) @login_required def usun_zbiorka(zbiorka_id): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień", "danger") return redirect(url_for("index")) zb = db.session.get(Zbiorka, zbiorka_id) @@ -580,7 +594,7 @@ def usun_zbiorka(zbiorka_id): @app.route("/admin/zbiorka/edytuj_stan/", methods=["GET", "POST"]) @login_required def edytuj_stan(zbiorka_id): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień", "danger") return redirect(url_for("index")) zb = db.session.get(Zbiorka, zbiorka_id) @@ -602,7 +616,7 @@ def edytuj_stan(zbiorka_id): @app.route("/admin/zbiorka/zmien_widzialnosc/", methods=["POST"]) @login_required def zmien_widzialnosc(zbiorka_id): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień", "danger") return redirect(url_for("index")) zb = db.session.get(Zbiorka, zbiorka_id) @@ -615,15 +629,17 @@ def zmien_widzialnosc(zbiorka_id): def create_admin_account(): - admin = User.query.filter_by(is_admin=True).first() + admin = Uzytkownik.query.filter_by(czy_admin=True).first() if not admin: - main_admin = User(username=app.config["MAIN_ADMIN_USERNAME"], is_admin=True) + main_admin = Uzytkownik( + uzytkownik=app.config["MAIN_ADMIN_USERNAME"], + czy_admin=True + ) main_admin.set_password(app.config["MAIN_ADMIN_PASSWORD"]) db.session.add(main_admin) db.session.commit() - @app.after_request def apply_headers(response): if request.path.startswith("/static/"): @@ -638,9 +654,9 @@ def apply_headers(response): return response path_norm = request.path.lstrip("/") - is_admin = path_norm.startswith("admin/") or path_norm == "admin" + czy_admin = path_norm.startswith("admin/") or path_norm == "admin" - if is_admin: + if czy_admin: if (response.mimetype or "").startswith("text/html"): response.headers["Cache-Control"] = "no-store, no-cache" response.headers.pop("ETag", None) @@ -667,7 +683,7 @@ def apply_headers(response): if ( app.config.get("BLOCK_BOTS", False) - and not is_admin + and not czy_admin and not request.path.startswith("/static/") ): cc_override = app.config.get("CACHE_CONTROL_HEADER") @@ -683,60 +699,58 @@ def apply_headers(response): @app.route("/admin/ustawienia", methods=["GET", "POST"]) @login_required def admin_ustawienia(): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień do panelu administracyjnego", "danger") return redirect(url_for("index")) client_ip = get_real_ip() - settings = GlobalSettings.query.first() + settings = UstawieniaGlobalne.query.first() if request.method == "POST": numer_konta = request.form.get("numer_konta") numer_telefonu_blik = request.form.get("numer_telefonu_blik") - allowed_login_hosts = request.form.get("allowed_login_hosts") + dozwolone_hosty_logowania = request.form.get("dozwolone_hosty_logowania") logo_url = request.form.get("logo_url") - site_title = request.form.get("site_title") - navbar_brand_mode = request.form.get("navbar_brand_mode", "text") - footer_brand_mode = request.form.get("footer_brand_mode", "text") - footer_text = request.form.get("footer_text") or None - show_logo_in_navbar = navbar_brand_mode == "logo" + tytul_strony = request.form.get("tytul_strony") + typ_navbar = request.form.get("typ_navbar", "text") + typ_stopka = request.form.get("typ_stopka", "text") + stopka_text = request.form.get("stopka_text") or None + pokaz_logo_w_navbar = (typ_navbar == "logo") if settings is None: - settings = GlobalSettings( + settings = UstawieniaGlobalne( numer_konta=numer_konta, numer_telefonu_blik=numer_telefonu_blik, - allowed_login_hosts=allowed_login_hosts, + dozwolone_hosty_logowania=dozwolone_hosty_logowania, logo_url=logo_url, - site_title=site_title, - show_logo_in_navbar=show_logo_in_navbar, - navbar_brand_mode=navbar_brand_mode, - footer_brand_mode=footer_brand_mode, - footer_text=footer_text, + tytul_strony=tytul_strony, + pokaz_logo_w_navbar=pokaz_logo_w_navbar, + typ_navbar=typ_navbar, + typ_stopka=typ_stopka, + stopka_text=stopka_text, ) db.session.add(settings) else: settings.numer_konta = numer_konta settings.numer_telefonu_blik = numer_telefonu_blik - settings.allowed_login_hosts = allowed_login_hosts + settings.dozwolone_hosty_logowania = dozwolone_hosty_logowania settings.logo_url = logo_url - settings.site_title = site_title - settings.show_logo_in_navbar = show_logo_in_navbar - settings.navbar_brand_mode = navbar_brand_mode - settings.footer_brand_mode = footer_brand_mode - settings.footer_text = footer_text + settings.tytul_strony = tytul_strony + settings.pokaz_logo_w_navbar = pokaz_logo_w_navbar + settings.typ_navbar = typ_navbar + settings.typ_stopka = typ_stopka + settings.stopka_text = stopka_text db.session.commit() flash("Ustawienia globalne zostały zaktualizowane", "success") return redirect(url_for("admin_dashboard")) - return render_template( - "admin/ustawienia.html", settings=settings, client_ip=client_ip - ) + return render_template("admin/ustawienia.html", settings=settings, client_ip=client_ip) @app.route("/admin/zbiorka//wydatek/dodaj", methods=["GET", "POST"]) @login_required def dodaj_wydatek(zbiorka_id): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień", "danger") return redirect(url_for("index")) @@ -778,7 +792,7 @@ def dodaj_wydatek(zbiorka_id): ) @login_required def oznacz_zbiorka(zbiorka_id): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień do wykonania tej operacji", "danger") return redirect(url_for("index")) @@ -810,7 +824,7 @@ def robots(): @app.route("/admin/zbiorka//transakcje") @login_required def transakcje_zbiorki(zbiorka_id): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień", "danger"); return redirect(url_for("index")) zb = db.session.get(Zbiorka, zbiorka_id) if zb is None: @@ -826,7 +840,7 @@ def transakcje_zbiorki(zbiorka_id): @app.route("/admin/wplata//zapisz", methods=["POST"]) @login_required def zapisz_wplate(wplata_id): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień", "danger"); return redirect(url_for("index")) w = db.session.get(Wplata, wplata_id) if w is None: @@ -852,7 +866,7 @@ def zapisz_wplate(wplata_id): @app.route("/admin/wplata//usun", methods=["POST"]) @login_required def usun_wplate(wplata_id): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień", "danger"); return redirect(url_for("index")) w = db.session.get(Wplata, wplata_id) if w is None: @@ -868,7 +882,7 @@ def usun_wplate(wplata_id): @app.route("/admin/wydatek//zapisz", methods=["POST"]) @login_required def zapisz_wydatek(wydatek_id): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień", "danger"); return redirect(url_for("index")) x = db.session.get(Wydatek, wydatek_id) if x is None: @@ -895,7 +909,7 @@ def zapisz_wydatek(wydatek_id): @app.route("/admin/wydatek//usun", methods=["POST"]) @login_required def usun_wydatek(wydatek_id): - if not current_user.is_admin: + if not current_user.czy_admin: flash("Brak uprawnień", "danger"); return redirect(url_for("index")) x = db.session.get(Wydatek, wydatek_id) if x is None: @@ -926,14 +940,12 @@ def healthcheck(): if __name__ == "__main__": with app.app_context(): db.create_all() - # Tworzenie konta głównego admina, jeśli nie istnieje - stmt = select(User).filter_by(is_admin=True) + stmt = select(Uzytkownik).filter_by(czy_admin=True) admin = db.session.execute(stmt).scalars().first() - if not admin: - main_admin = User( - username=app.config["MAIN_ADMIN_USERNAME"], - is_admin=True + main_admin = Uzytkownik( + uzytkownik=app.config["MAIN_ADMIN_USERNAME"], + czy_admin=True ) main_admin.set_password(app.config["MAIN_ADMIN_PASSWORD"]) db.session.add(main_admin) diff --git a/static/js/ustawienia.js b/static/js/ustawienia.js index cd98bc1..ff2c824 100644 --- a/static/js/ustawienia.js +++ b/static/js/ustawienia.js @@ -1,19 +1,20 @@ -(function () { - // IBAN: tylko cyfry, auto-grupowanie co 4 (po prefiksie PL) +// static/js/ustawienia.js +document.addEventListener('DOMContentLoaded', () => { + // Formatowanie IBAN (PL) const iban = document.getElementById('numer_konta'); if (iban) { iban.addEventListener('input', () => { - const digits = iban.value.replace(/\\D/g, '').slice(0, 26); // 26 cyfr po "PL" + const digits = iban.value.replace(/\D/g, '').slice(0, 26); const chunked = digits.replace(/(.{4})/g, '$1 ').trim(); iban.value = chunked; }); } - // Telefon BLIK: tylko cyfry, format 3-3-3 + // Telefon BLIK 3-3-3 const tel = document.getElementById('numer_telefonu_blik'); if (tel) { tel.addEventListener('input', () => { - const digits = tel.value.replace(/\\D/g, '').slice(0, 9); + const digits = tel.value.replace(/\D/g, '').slice(0, 9); const parts = []; if (digits.length > 0) parts.push(digits.substring(0, 3)); if (digits.length > 3) parts.push(digits.substring(3, 6)); @@ -22,24 +23,23 @@ }); } - // Biała lista IP/hostów — helpery - const ta = document.getElementById('allowed_login_hosts'); + // Biała lista IP/hostów + const ta = document.getElementById('dozwolone_hosty_logowania'); const count = document.getElementById('hostsCount'); const addBtn = document.getElementById('btn-add-host'); const addMyBtn = document.getElementById('btn-add-my-ip'); const input = document.getElementById('host_input'); + const dedupeBtn = document.getElementById('btn-dedupe'); - function parseList(text) { - // akceptuj przecinki, średniki i nowe linie; trimuj; usuń puste - return text - .split(/[\\n,;]+/) + const parseList = (text) => + text + .split(/[\r\n,;]+/) // \r?\n, przecinek, średnik .map(s => s.trim()) .filter(Boolean); - } - function formatList(arr) { - return arr.join('\\n'); - } - function dedupe(arr) { + + const formatList = (arr) => arr.join('\n'); + + const dedupe = (arr) => { const seen = new Set(); const out = []; for (const v of arr) { @@ -47,22 +47,23 @@ if (!seen.has(k)) { seen.add(k); out.push(v); } } return out; - } - function updateCount() { + }; + + const updateCount = () => { if (!ta || !count) return; - count.textContent = parseList(ta.value).length.toString(); - } - function addEntry(val) { + count.textContent = String(parseList(ta.value).length); + }; + + const addEntry = (val) => { if (!ta || !val) return; const list = dedupe([...parseList(ta.value), val]); ta.value = formatList(list); updateCount(); - } + }; if (ta) { ta.addEventListener('input', updateCount); - // inicjalny przelicznik - updateCount(); + updateCount(); // inicjalne przeliczenie } if (addBtn && input) { @@ -82,11 +83,10 @@ }); } - const dedupeBtn = document.getElementById('btn-dedupe'); if (dedupeBtn && ta) { dedupeBtn.addEventListener('click', () => { ta.value = formatList(dedupe(parseList(ta.value))); updateCount(); }); } -})(); \ No newline at end of file +}); diff --git a/static/js/walidacja_logowanie.js b/static/js/walidacja_logowanie.js index c7736eb..1b54212 100644 --- a/static/js/walidacja_logowanie.js +++ b/static/js/walidacja_logowanie.js @@ -9,11 +9,11 @@ }, false); })(); -const pw = document.getElementById('password'); +const pw = document.getElementById("haslo"); const toggle = document.getElementById('togglePw'); toggle.addEventListener('click', () => { const isText = pw.type === 'text'; - pw.type = isText ? 'password' : 'text'; + pw.type = isText ? "haslo" : 'text'; toggle.textContent = isText ? 'Pokaż' : 'Ukryj'; toggle.setAttribute('aria-pressed', (!isText).toString()); pw.focus(); diff --git a/static/js/walidacja_rejestracja.js b/static/js/walidacja_rejestracja.js index 389da00..d132b70 100644 --- a/static/js/walidacja_rejestracja.js +++ b/static/js/walidacja_rejestracja.js @@ -5,7 +5,7 @@ e.preventDefault(); e.stopPropagation(); } - const pw1 = document.getElementById('password'); + const pw1 = document.getElementById("haslo"); const pw2 = document.getElementById('password2'); if (pw1.value !== pw2.value) { e.preventDefault(); @@ -19,11 +19,11 @@ }, false); })(); -const pw = document.getElementById('password'); +const pw = document.getElementById("haslo"); const toggle = document.getElementById('togglePw'); toggle.addEventListener('click', () => { const isText = pw.type === 'text'; - pw.type = isText ? 'password' : 'text'; + pw.type = isText ? "haslo" : 'text'; toggle.textContent = isText ? 'Pokaż' : 'Ukryj'; pw.focus(); }); diff --git a/templates/admin/formularz_zbiorek.html b/templates/admin/formularz_zbiorek.html index de9b477..f9cadc5 100644 --- a/templates/admin/formularz_zbiorek.html +++ b/templates/admin/formularz_zbiorek.html @@ -269,8 +269,45 @@ + + + +
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+ + + + + +
+
+
Po wpisaniu kliknij „Dodaj”. Duplikaty są pomijane.
-
- - - + +
+
+ + +
- - -
- Akceptowane separatory: przecinek (`,`), średnik (`;`) i nowa linia. - Pozycji na liście: 0 +
+ + Pozycji: 0
+ + + + + Akceptowane separatory: przecinek (`,`), średnik (`;`) i nowa linia. +
+
@@ -99,9 +117,9 @@
- - + +
@@ -112,15 +130,15 @@
Menu (navbar)
- +
- +
Jeśli wybierzesz logo, użyjemy adresu z pola "Tytuł serwisu".
@@ -130,19 +148,19 @@
Stopka
- +
- +
- - Tekst w stopce (gdy wybrano „Tekst”) +
Pozostaw pusty, by użyć domyślnego.
diff --git a/templates/base.html b/templates/base.html index 86c0233..faf5d88 100644 --- a/templates/base.html +++ b/templates/base.html @@ -14,13 +14,13 @@