spolszczenie wszystkiego i poprawki
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,4 +4,5 @@ instance/
|
|||||||
venv/
|
venv/
|
||||||
.env
|
.env
|
||||||
version.txt
|
version.txt
|
||||||
deploy/varnish/default.vcl
|
deploy/varnish/default.vcl
|
||||||
|
*.tar.gz
|
76
alters.txt
76
alters.txt
@@ -1,68 +1,18 @@
|
|||||||
-- WŁĄCZ/wyłącz FK zależnie od etapu migracji
|
|
||||||
PRAGMA foreign_keys = OFF;
|
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
-- 1) Nowa tabela z właściwym FK (ON DELETE CASCADE)
|
-- UŻYTKOWNIK
|
||||||
CREATE TABLE wplata_new (
|
ALTER TABLE user RENAME TO uzytkownik;
|
||||||
id INTEGER PRIMARY KEY,
|
ALTER TABLE uzytkownik RENAME COLUMN username TO uzytkownik;
|
||||||
zbiorka_id INTEGER NOT NULL,
|
ALTER TABLE uzytkownik RENAME COLUMN password_hash TO haslo_hash;
|
||||||
kwota REAL NOT NULL,
|
ALTER TABLE uzytkownik RENAME COLUMN is_admin TO czy_admin;
|
||||||
data DATETIME,
|
|
||||||
opis TEXT,
|
|
||||||
FOREIGN KEY(zbiorka_id) REFERENCES zbiorka(id) ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
-- 2) (opcjonalnie) upewnij się, że nie ma „sierotek”
|
-- USTAWIENIA GLOBALNE
|
||||||
-- SELECT w.* FROM wplata w LEFT JOIN zbiorka z ON z.id = w.zbiorka_id WHERE z.id IS NULL;
|
ALTER TABLE global_settings RENAME TO ustawienia_globalne;
|
||||||
|
ALTER TABLE ustawienia_globalne RENAME COLUMN allowed_login_hosts TO dozwolone_hosty_logowania;
|
||||||
-- 3) Kopiowanie danych
|
ALTER TABLE ustawienia_globalne RENAME COLUMN site_title TO tytul_strony;
|
||||||
INSERT INTO wplata_new (id, zbiorka_id, kwota, data, opis)
|
ALTER TABLE ustawienia_globalne RENAME COLUMN show_logo_in_navbar TO pokaz_logo_w_navbar;
|
||||||
SELECT id, zbiorka_id, kwota, data, opis
|
ALTER TABLE ustawienia_globalne RENAME COLUMN navbar_brand_mode TO typ_navbar;
|
||||||
FROM wplata;
|
ALTER TABLE ustawienia_globalne RENAME COLUMN footer_brand_mode TO typ_stopka;
|
||||||
|
ALTER TABLE ustawienia_globalne RENAME COLUMN footer_text TO stopka_text;
|
||||||
-- 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);
|
|
||||||
|
|
||||||
COMMIT;
|
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');
|
|
246
app.py
246
app.py
@@ -65,18 +65,18 @@ APP_VERSION = f"{deploy_date}+{commit}"
|
|||||||
app.config["APP_VERSION"] = APP_VERSION
|
app.config["APP_VERSION"] = APP_VERSION
|
||||||
|
|
||||||
# MODELE
|
# MODELE
|
||||||
class User(UserMixin, db.Model):
|
class Uzytkownik(UserMixin, db.Model):
|
||||||
|
__tablename__ = "uzytkownik"
|
||||||
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
username = db.Column(db.String(80), unique=True, nullable=False)
|
uzytkownik = db.Column(db.String(80), unique=True, nullable=False)
|
||||||
password_hash = db.Column(db.String(128), nullable=False)
|
haslo_hash = db.Column(db.String(128), nullable=False)
|
||||||
is_admin = db.Column(db.Boolean, default=False) # Flaga głównego administratora
|
czy_admin = db.Column(db.Boolean, default=False)
|
||||||
|
|
||||||
def set_password(self, password):
|
def set_password(self, password):
|
||||||
self.password_hash = generate_password_hash(password)
|
self.haslo_hash = generate_password_hash(password)
|
||||||
|
|
||||||
def check_password(self, 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):
|
class Zbiorka(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
@@ -89,6 +89,9 @@ class Zbiorka(db.Model):
|
|||||||
ukryta = db.Column(db.Boolean, default=False)
|
ukryta = db.Column(db.Boolean, default=False)
|
||||||
ukryj_kwote = db.Column(db.Boolean, default=False)
|
ukryj_kwote = db.Column(db.Boolean, default=False)
|
||||||
zrealizowana = 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(
|
wplaty = db.relationship(
|
||||||
"Wplata",
|
"Wplata",
|
||||||
@@ -139,10 +142,8 @@ class Wplata(db.Model):
|
|||||||
kwota = db.Column(Numeric(12, 2), nullable=False)
|
kwota = db.Column(Numeric(12, 2), nullable=False)
|
||||||
data = db.Column(db.DateTime, default=datetime.utcnow)
|
data = db.Column(db.DateTime, default=datetime.utcnow)
|
||||||
opis = db.Column(db.Text, nullable=True)
|
opis = db.Column(db.Text, nullable=True)
|
||||||
|
|
||||||
zbiorka = db.relationship("Zbiorka", back_populates="wplaty")
|
zbiorka = db.relationship("Zbiorka", back_populates="wplaty")
|
||||||
|
|
||||||
|
|
||||||
class Wydatek(db.Model):
|
class Wydatek(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
zbiorka_id = db.Column(
|
zbiorka_id = db.Column(
|
||||||
@@ -155,22 +156,24 @@ class Wydatek(db.Model):
|
|||||||
opis = db.Column(db.Text, nullable=True)
|
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)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
numer_konta = db.Column(db.String(50), nullable=False)
|
numer_konta = db.Column(db.String(50), nullable=False)
|
||||||
numer_telefonu_blik = 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)
|
logo_url = db.Column(db.String(255), nullable=True)
|
||||||
site_title = db.Column(db.String(120), nullable=True)
|
tytul_strony = db.Column(db.String(120), nullable=True)
|
||||||
show_logo_in_navbar = db.Column(db.Boolean, default=False)
|
pokaz_logo_w_navbar = db.Column(db.Boolean, default=False)
|
||||||
navbar_brand_mode = db.Column(db.String(10), default="text")
|
typ_navbar = db.Column(db.String(10), default="text")
|
||||||
footer_brand_mode = db.Column(db.String(10), default="text")
|
typ_stopka = db.Column(db.String(10), default="text")
|
||||||
footer_text = db.Column(db.String(200), nullable=True)
|
stopka_text = db.Column(db.String(200), nullable=True)
|
||||||
|
|
||||||
|
|
||||||
@login_manager.user_loader
|
@login_manager.user_loader
|
||||||
def load_user(user_id):
|
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")
|
@event.listens_for(Engine, "connect")
|
||||||
@@ -249,11 +252,9 @@ def markdown_filter(text):
|
|||||||
|
|
||||||
@app.context_processor
|
@app.context_processor
|
||||||
def inject_globals():
|
def inject_globals():
|
||||||
settings = GlobalSettings.query.first()
|
settings = UstawieniaGlobalne.query.first()
|
||||||
allowed_hosts_str = (
|
allowed_hosts_str = (
|
||||||
settings.allowed_login_hosts
|
settings.dozwolone_hosty_logowania if settings and settings.dozwolone_hosty_logowania else ""
|
||||||
if settings and settings.allowed_login_hosts
|
|
||||||
else ""
|
|
||||||
)
|
)
|
||||||
client_ip = get_real_ip()
|
client_ip = get_real_ip()
|
||||||
return {
|
return {
|
||||||
@@ -290,7 +291,7 @@ def zbiorka(zbiorka_id):
|
|||||||
zb = db.session.get(Zbiorka, zbiorka_id)
|
zb = db.session.get(Zbiorka, zbiorka_id)
|
||||||
if zb is None:
|
if zb is None:
|
||||||
abort(404)
|
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)
|
abort(404)
|
||||||
|
|
||||||
# scalona oś czasu: wpłaty + wydatki
|
# scalona oś czasu: wpłaty + wydatki
|
||||||
@@ -311,34 +312,22 @@ def zbiorka(zbiorka_id):
|
|||||||
|
|
||||||
@app.route("/zaloguj", methods=["GET", "POST"])
|
@app.route("/zaloguj", methods=["GET", "POST"])
|
||||||
def zaloguj():
|
def zaloguj():
|
||||||
# Pobierz ustawienia globalne, w tym dozwolone hosty
|
settings = UstawieniaGlobalne.query.first()
|
||||||
settings = GlobalSettings.query.first()
|
allowed_hosts_str = settings.dozwolone_hosty_logowania or "" if settings else ""
|
||||||
allowed_hosts_str = ""
|
|
||||||
if settings and settings.allowed_login_hosts:
|
|
||||||
allowed_hosts_str = settings.allowed_login_hosts
|
|
||||||
|
|
||||||
# Sprawdzenie, czy adres IP klienta jest dozwolony
|
|
||||||
client_ip = get_real_ip()
|
client_ip = get_real_ip()
|
||||||
if not is_allowed_ip(client_ip, allowed_hosts_str):
|
if not is_allowed_ip(client_ip, allowed_hosts_str):
|
||||||
flash(
|
flash("Dostęp do tego systemu jest zablokowany dla Twojego adresu IP", "danger")
|
||||||
"Dostęp do tego systemu jest zablokowany dla Twojego adresu IP",
|
|
||||||
"danger",
|
|
||||||
)
|
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
username = request.form["username"]
|
login = request.form["uzytkownik"]
|
||||||
password = request.form["password"]
|
password = request.form["haslo"]
|
||||||
user = User.query.filter_by(username=username).first()
|
user = Uzytkownik.query.filter_by(uzytkownik=login).first()
|
||||||
if user and user.check_password(password):
|
if user and user.check_password(password):
|
||||||
login_user(user)
|
login_user(user)
|
||||||
flash("Zalogowano pomyślnie", "success")
|
flash("Zalogowano pomyślnie", "success")
|
||||||
next_page = request.args.get("next")
|
next_page = request.args.get("next")
|
||||||
return (
|
return redirect(next_page) if next_page else redirect(url_for("admin_dashboard"))
|
||||||
redirect(next_page)
|
|
||||||
if next_page
|
|
||||||
else redirect(url_for("admin_dashboard"))
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
flash("Nieprawidłowe dane logowania", "danger")
|
flash("Nieprawidłowe dane logowania", "danger")
|
||||||
return render_template("login.html")
|
return render_template("login.html")
|
||||||
@@ -358,12 +347,12 @@ def zarejestruj():
|
|||||||
flash("Rejestracja została wyłączona przez administratora", "danger")
|
flash("Rejestracja została wyłączona przez administratora", "danger")
|
||||||
return redirect(url_for("zaloguj"))
|
return redirect(url_for("zaloguj"))
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
username = request.form["username"]
|
login = request.form["uzytkownik"]
|
||||||
password = request.form["password"]
|
password = request.form["haslo"]
|
||||||
if User.query.filter_by(username=username).first():
|
if Uzytkownik.query.filter_by(uzytkownik=login).first():
|
||||||
flash("Użytkownik już istnieje", "danger")
|
flash("Użytkownik już istnieje", "danger")
|
||||||
return redirect(url_for("register"))
|
return redirect(url_for("register"))
|
||||||
new_user = User(username=username)
|
new_user = Uzytkownik(uzytkownik=login)
|
||||||
new_user.set_password(password)
|
new_user.set_password(password)
|
||||||
db.session.add(new_user)
|
db.session.add(new_user)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@@ -376,7 +365,7 @@ def zarejestruj():
|
|||||||
@app.route("/admin")
|
@app.route("/admin")
|
||||||
@login_required
|
@login_required
|
||||||
def admin_dashboard():
|
def admin_dashboard():
|
||||||
if not current_user.is_admin:
|
if not current_user.czy_admin:
|
||||||
flash("Brak uprawnień do panelu administracyjnego", "danger")
|
flash("Brak uprawnień do panelu administracyjnego", "danger")
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
active_zbiorki = Zbiorka.query.filter_by(zrealizowana=False).all()
|
active_zbiorki = Zbiorka.query.filter_by(zrealizowana=False).all()
|
||||||
@@ -392,30 +381,32 @@ def admin_dashboard():
|
|||||||
@app.route("/admin/zbiorka/edytuj/<int:zbiorka_id>", methods=["GET", "POST"])
|
@app.route("/admin/zbiorka/edytuj/<int:zbiorka_id>", methods=["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def formularz_zbiorek(zbiorka_id=None):
|
def formularz_zbiorek(zbiorka_id=None):
|
||||||
if not current_user.is_admin:
|
if not current_user.czy_admin:
|
||||||
flash("Brak uprawnień", "danger")
|
flash("Brak uprawnień", "danger")
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
# Tryb: dodawanie vs edycja
|
|
||||||
is_edit = zbiorka_id is not None
|
is_edit = zbiorka_id is not None
|
||||||
|
|
||||||
# Obiekt zbiórki ładujemy TYLKO przy edycji
|
|
||||||
zb = None
|
zb = None
|
||||||
if is_edit:
|
if is_edit:
|
||||||
zb = db.session.get(Zbiorka, zbiorka_id)
|
zb = db.session.get(Zbiorka, zbiorka_id)
|
||||||
if zb is None:
|
if zb is None:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
global_settings = GlobalSettings.query.first()
|
global_settings = UstawieniaGlobalne.query.first()
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
# Pola wspólne
|
# Pola wspólne
|
||||||
nazwa = request.form.get("nazwa", "").strip()
|
nazwa = request.form.get("nazwa", "").strip()
|
||||||
opis = request.form.get("opis", "").strip()
|
opis = request.form.get("opis", "").strip()
|
||||||
|
|
||||||
numer_konta = request.form.get("numer_konta", "").strip()
|
numer_konta = request.form.get("numer_konta", "").strip()
|
||||||
numer_telefonu_blik = request.form.get("numer_telefonu_blik", "").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
|
# Cel — Decimal, > 0
|
||||||
try:
|
try:
|
||||||
cel_str = request.form.get("cel", "").replace(",", ".").strip()
|
cel_str = request.form.get("cel", "").replace(",", ".").strip()
|
||||||
@@ -424,23 +415,38 @@ def formularz_zbiorek(zbiorka_id=None):
|
|||||||
raise InvalidOperation
|
raise InvalidOperation
|
||||||
except (InvalidOperation, ValueError):
|
except (InvalidOperation, ValueError):
|
||||||
flash("Podano nieprawidłową wartość dla celu zbiórki", "danger")
|
flash("Podano nieprawidłową wartość dla celu zbiórki", "danger")
|
||||||
# Utwórz tymczasowy obiekt do ponownego renderu formularza
|
|
||||||
temp_zb = (zb or Zbiorka(
|
# Przy błędzie celu odtwórz stan formularza (również przełączniki)
|
||||||
nazwa=nazwa,
|
if is_edit and zb:
|
||||||
opis=opis,
|
zb.nazwa = nazwa
|
||||||
numer_konta=numer_konta,
|
zb.opis = opis
|
||||||
numer_telefonu_blik=numer_telefonu_blik,
|
zb.numer_konta = numer_konta
|
||||||
cel=None,
|
zb.numer_telefonu_blik = numer_telefonu_blik
|
||||||
ukryj_kwote=("ukryj_kwote" in request.form),
|
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(
|
return render_template(
|
||||||
"admin/formularz_zbiorek.html",
|
"admin/formularz_zbiorek.html",
|
||||||
zbiorka=temp_zb,
|
zbiorka=temp_zb,
|
||||||
global_settings=global_settings,
|
global_settings=global_settings,
|
||||||
)
|
)
|
||||||
|
|
||||||
ukryj_kwote = "ukryj_kwote" in request.form
|
# Lista produktów
|
||||||
|
|
||||||
names = request.form.getlist("item_nazwa[]")
|
names = request.form.getlist("item_nazwa[]")
|
||||||
links = request.form.getlist("item_link[]")
|
links = request.form.getlist("item_link[]")
|
||||||
prices = request.form.getlist("item_cena[]")
|
prices = request.form.getlist("item_cena[]")
|
||||||
@@ -464,11 +470,14 @@ def formularz_zbiorek(zbiorka_id=None):
|
|||||||
zb.opis = opis
|
zb.opis = opis
|
||||||
zb.numer_konta = numer_konta
|
zb.numer_konta = numer_konta
|
||||||
zb.numer_telefonu_blik = numer_telefonu_blik
|
zb.numer_telefonu_blik = numer_telefonu_blik
|
||||||
zb.cel = cel # pozostaje Decimal
|
zb.cel = cel
|
||||||
zb.ukryj_kwote = ukryj_kwote
|
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()
|
zb.przedmioty.clear()
|
||||||
for i, raw_name in enumerate(names):
|
for i, raw_name in enumerate(names):
|
||||||
name = (raw_name or "").strip()
|
name = (raw_name or "").strip()
|
||||||
@@ -496,11 +505,14 @@ def formularz_zbiorek(zbiorka_id=None):
|
|||||||
opis=opis,
|
opis=opis,
|
||||||
numer_konta=numer_konta,
|
numer_konta=numer_konta,
|
||||||
numer_telefonu_blik=numer_telefonu_blik,
|
numer_telefonu_blik=numer_telefonu_blik,
|
||||||
cel=cel, # Decimal
|
cel=cel,
|
||||||
ukryj_kwote=ukryj_kwote,
|
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.add(nowa)
|
||||||
db.session.commit() # potrzebne ID
|
db.session.commit() # potrzebne ID
|
||||||
|
|
||||||
# Dodaj produkty do nowej zbiórki
|
# Dodaj produkty do nowej zbiórki
|
||||||
for i, raw_name in enumerate(names):
|
for i, raw_name in enumerate(names):
|
||||||
@@ -526,14 +538,16 @@ def formularz_zbiorek(zbiorka_id=None):
|
|||||||
|
|
||||||
# GET
|
# GET
|
||||||
return render_template(
|
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/<int:zbiorka_id>/wplata/dodaj", methods=["GET", "POST"])
|
@app.route("/admin/zbiorka/<int:zbiorka_id>/wplata/dodaj", methods=["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def dodaj_wplate(zbiorka_id):
|
def dodaj_wplate(zbiorka_id):
|
||||||
if not current_user.is_admin:
|
if not current_user.czy_admin:
|
||||||
flash("Brak uprawnień", "danger")
|
flash("Brak uprawnień", "danger")
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
@@ -565,7 +579,7 @@ def dodaj_wplate(zbiorka_id):
|
|||||||
@app.route("/admin/zbiorka/usun/<int:zbiorka_id>", methods=["POST"])
|
@app.route("/admin/zbiorka/usun/<int:zbiorka_id>", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def usun_zbiorka(zbiorka_id):
|
def usun_zbiorka(zbiorka_id):
|
||||||
if not current_user.is_admin:
|
if not current_user.czy_admin:
|
||||||
flash("Brak uprawnień", "danger")
|
flash("Brak uprawnień", "danger")
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
zb = db.session.get(Zbiorka, zbiorka_id)
|
zb = db.session.get(Zbiorka, zbiorka_id)
|
||||||
@@ -580,7 +594,7 @@ def usun_zbiorka(zbiorka_id):
|
|||||||
@app.route("/admin/zbiorka/edytuj_stan/<int:zbiorka_id>", methods=["GET", "POST"])
|
@app.route("/admin/zbiorka/edytuj_stan/<int:zbiorka_id>", methods=["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def edytuj_stan(zbiorka_id):
|
def edytuj_stan(zbiorka_id):
|
||||||
if not current_user.is_admin:
|
if not current_user.czy_admin:
|
||||||
flash("Brak uprawnień", "danger")
|
flash("Brak uprawnień", "danger")
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
zb = db.session.get(Zbiorka, zbiorka_id)
|
zb = db.session.get(Zbiorka, zbiorka_id)
|
||||||
@@ -602,7 +616,7 @@ def edytuj_stan(zbiorka_id):
|
|||||||
@app.route("/admin/zbiorka/zmien_widzialnosc/<int:zbiorka_id>", methods=["POST"])
|
@app.route("/admin/zbiorka/zmien_widzialnosc/<int:zbiorka_id>", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def zmien_widzialnosc(zbiorka_id):
|
def zmien_widzialnosc(zbiorka_id):
|
||||||
if not current_user.is_admin:
|
if not current_user.czy_admin:
|
||||||
flash("Brak uprawnień", "danger")
|
flash("Brak uprawnień", "danger")
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
zb = db.session.get(Zbiorka, zbiorka_id)
|
zb = db.session.get(Zbiorka, zbiorka_id)
|
||||||
@@ -615,15 +629,17 @@ def zmien_widzialnosc(zbiorka_id):
|
|||||||
|
|
||||||
|
|
||||||
def create_admin_account():
|
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:
|
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"])
|
main_admin.set_password(app.config["MAIN_ADMIN_PASSWORD"])
|
||||||
db.session.add(main_admin)
|
db.session.add(main_admin)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.after_request
|
@app.after_request
|
||||||
def apply_headers(response):
|
def apply_headers(response):
|
||||||
if request.path.startswith("/static/"):
|
if request.path.startswith("/static/"):
|
||||||
@@ -638,9 +654,9 @@ def apply_headers(response):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
path_norm = request.path.lstrip("/")
|
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"):
|
if (response.mimetype or "").startswith("text/html"):
|
||||||
response.headers["Cache-Control"] = "no-store, no-cache"
|
response.headers["Cache-Control"] = "no-store, no-cache"
|
||||||
response.headers.pop("ETag", None)
|
response.headers.pop("ETag", None)
|
||||||
@@ -667,7 +683,7 @@ def apply_headers(response):
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
app.config.get("BLOCK_BOTS", False)
|
app.config.get("BLOCK_BOTS", False)
|
||||||
and not is_admin
|
and not czy_admin
|
||||||
and not request.path.startswith("/static/")
|
and not request.path.startswith("/static/")
|
||||||
):
|
):
|
||||||
cc_override = app.config.get("CACHE_CONTROL_HEADER")
|
cc_override = app.config.get("CACHE_CONTROL_HEADER")
|
||||||
@@ -683,60 +699,58 @@ def apply_headers(response):
|
|||||||
@app.route("/admin/ustawienia", methods=["GET", "POST"])
|
@app.route("/admin/ustawienia", methods=["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def admin_ustawienia():
|
def admin_ustawienia():
|
||||||
if not current_user.is_admin:
|
if not current_user.czy_admin:
|
||||||
flash("Brak uprawnień do panelu administracyjnego", "danger")
|
flash("Brak uprawnień do panelu administracyjnego", "danger")
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
client_ip = get_real_ip()
|
client_ip = get_real_ip()
|
||||||
settings = GlobalSettings.query.first()
|
settings = UstawieniaGlobalne.query.first()
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
numer_konta = request.form.get("numer_konta")
|
numer_konta = request.form.get("numer_konta")
|
||||||
numer_telefonu_blik = request.form.get("numer_telefonu_blik")
|
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")
|
logo_url = request.form.get("logo_url")
|
||||||
site_title = request.form.get("site_title")
|
tytul_strony = request.form.get("tytul_strony")
|
||||||
navbar_brand_mode = request.form.get("navbar_brand_mode", "text")
|
typ_navbar = request.form.get("typ_navbar", "text")
|
||||||
footer_brand_mode = request.form.get("footer_brand_mode", "text")
|
typ_stopka = request.form.get("typ_stopka", "text")
|
||||||
footer_text = request.form.get("footer_text") or None
|
stopka_text = request.form.get("stopka_text") or None
|
||||||
show_logo_in_navbar = navbar_brand_mode == "logo"
|
pokaz_logo_w_navbar = (typ_navbar == "logo")
|
||||||
|
|
||||||
if settings is None:
|
if settings is None:
|
||||||
settings = GlobalSettings(
|
settings = UstawieniaGlobalne(
|
||||||
numer_konta=numer_konta,
|
numer_konta=numer_konta,
|
||||||
numer_telefonu_blik=numer_telefonu_blik,
|
numer_telefonu_blik=numer_telefonu_blik,
|
||||||
allowed_login_hosts=allowed_login_hosts,
|
dozwolone_hosty_logowania=dozwolone_hosty_logowania,
|
||||||
logo_url=logo_url,
|
logo_url=logo_url,
|
||||||
site_title=site_title,
|
tytul_strony=tytul_strony,
|
||||||
show_logo_in_navbar=show_logo_in_navbar,
|
pokaz_logo_w_navbar=pokaz_logo_w_navbar,
|
||||||
navbar_brand_mode=navbar_brand_mode,
|
typ_navbar=typ_navbar,
|
||||||
footer_brand_mode=footer_brand_mode,
|
typ_stopka=typ_stopka,
|
||||||
footer_text=footer_text,
|
stopka_text=stopka_text,
|
||||||
)
|
)
|
||||||
db.session.add(settings)
|
db.session.add(settings)
|
||||||
else:
|
else:
|
||||||
settings.numer_konta = numer_konta
|
settings.numer_konta = numer_konta
|
||||||
settings.numer_telefonu_blik = numer_telefonu_blik
|
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.logo_url = logo_url
|
||||||
settings.site_title = site_title
|
settings.tytul_strony = tytul_strony
|
||||||
settings.show_logo_in_navbar = show_logo_in_navbar
|
settings.pokaz_logo_w_navbar = pokaz_logo_w_navbar
|
||||||
settings.navbar_brand_mode = navbar_brand_mode
|
settings.typ_navbar = typ_navbar
|
||||||
settings.footer_brand_mode = footer_brand_mode
|
settings.typ_stopka = typ_stopka
|
||||||
settings.footer_text = footer_text
|
settings.stopka_text = stopka_text
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash("Ustawienia globalne zostały zaktualizowane", "success")
|
flash("Ustawienia globalne zostały zaktualizowane", "success")
|
||||||
return redirect(url_for("admin_dashboard"))
|
return redirect(url_for("admin_dashboard"))
|
||||||
|
|
||||||
return render_template(
|
return render_template("admin/ustawienia.html", settings=settings, client_ip=client_ip)
|
||||||
"admin/ustawienia.html", settings=settings, client_ip=client_ip
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/admin/zbiorka/<int:zbiorka_id>/wydatek/dodaj", methods=["GET", "POST"])
|
@app.route("/admin/zbiorka/<int:zbiorka_id>/wydatek/dodaj", methods=["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def dodaj_wydatek(zbiorka_id):
|
def dodaj_wydatek(zbiorka_id):
|
||||||
if not current_user.is_admin:
|
if not current_user.czy_admin:
|
||||||
flash("Brak uprawnień", "danger")
|
flash("Brak uprawnień", "danger")
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
@@ -778,7 +792,7 @@ def dodaj_wydatek(zbiorka_id):
|
|||||||
)
|
)
|
||||||
@login_required
|
@login_required
|
||||||
def oznacz_zbiorka(zbiorka_id):
|
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")
|
flash("Brak uprawnień do wykonania tej operacji", "danger")
|
||||||
return redirect(url_for("index"))
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
@@ -810,7 +824,7 @@ def robots():
|
|||||||
@app.route("/admin/zbiorka/<int:zbiorka_id>/transakcje")
|
@app.route("/admin/zbiorka/<int:zbiorka_id>/transakcje")
|
||||||
@login_required
|
@login_required
|
||||||
def transakcje_zbiorki(zbiorka_id):
|
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"))
|
flash("Brak uprawnień", "danger"); return redirect(url_for("index"))
|
||||||
zb = db.session.get(Zbiorka, zbiorka_id)
|
zb = db.session.get(Zbiorka, zbiorka_id)
|
||||||
if zb is None:
|
if zb is None:
|
||||||
@@ -826,7 +840,7 @@ def transakcje_zbiorki(zbiorka_id):
|
|||||||
@app.route("/admin/wplata/<int:wplata_id>/zapisz", methods=["POST"])
|
@app.route("/admin/wplata/<int:wplata_id>/zapisz", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def zapisz_wplate(wplata_id):
|
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"))
|
flash("Brak uprawnień", "danger"); return redirect(url_for("index"))
|
||||||
w = db.session.get(Wplata, wplata_id)
|
w = db.session.get(Wplata, wplata_id)
|
||||||
if w is None:
|
if w is None:
|
||||||
@@ -852,7 +866,7 @@ def zapisz_wplate(wplata_id):
|
|||||||
@app.route("/admin/wplata/<int:wplata_id>/usun", methods=["POST"])
|
@app.route("/admin/wplata/<int:wplata_id>/usun", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def usun_wplate(wplata_id):
|
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"))
|
flash("Brak uprawnień", "danger"); return redirect(url_for("index"))
|
||||||
w = db.session.get(Wplata, wplata_id)
|
w = db.session.get(Wplata, wplata_id)
|
||||||
if w is None:
|
if w is None:
|
||||||
@@ -868,7 +882,7 @@ def usun_wplate(wplata_id):
|
|||||||
@app.route("/admin/wydatek/<int:wydatek_id>/zapisz", methods=["POST"])
|
@app.route("/admin/wydatek/<int:wydatek_id>/zapisz", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def zapisz_wydatek(wydatek_id):
|
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"))
|
flash("Brak uprawnień", "danger"); return redirect(url_for("index"))
|
||||||
x = db.session.get(Wydatek, wydatek_id)
|
x = db.session.get(Wydatek, wydatek_id)
|
||||||
if x is None:
|
if x is None:
|
||||||
@@ -895,7 +909,7 @@ def zapisz_wydatek(wydatek_id):
|
|||||||
@app.route("/admin/wydatek/<int:wydatek_id>/usun", methods=["POST"])
|
@app.route("/admin/wydatek/<int:wydatek_id>/usun", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def usun_wydatek(wydatek_id):
|
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"))
|
flash("Brak uprawnień", "danger"); return redirect(url_for("index"))
|
||||||
x = db.session.get(Wydatek, wydatek_id)
|
x = db.session.get(Wydatek, wydatek_id)
|
||||||
if x is None:
|
if x is None:
|
||||||
@@ -926,14 +940,12 @@ def healthcheck():
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
db.create_all()
|
db.create_all()
|
||||||
# Tworzenie konta głównego admina, jeśli nie istnieje
|
stmt = select(Uzytkownik).filter_by(czy_admin=True)
|
||||||
stmt = select(User).filter_by(is_admin=True)
|
|
||||||
admin = db.session.execute(stmt).scalars().first()
|
admin = db.session.execute(stmt).scalars().first()
|
||||||
|
|
||||||
if not admin:
|
if not admin:
|
||||||
main_admin = User(
|
main_admin = Uzytkownik(
|
||||||
username=app.config["MAIN_ADMIN_USERNAME"],
|
uzytkownik=app.config["MAIN_ADMIN_USERNAME"],
|
||||||
is_admin=True
|
czy_admin=True
|
||||||
)
|
)
|
||||||
main_admin.set_password(app.config["MAIN_ADMIN_PASSWORD"])
|
main_admin.set_password(app.config["MAIN_ADMIN_PASSWORD"])
|
||||||
db.session.add(main_admin)
|
db.session.add(main_admin)
|
||||||
|
@@ -1,19 +1,20 @@
|
|||||||
(function () {
|
// static/js/ustawienia.js
|
||||||
// IBAN: tylko cyfry, auto-grupowanie co 4 (po prefiksie PL)
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
// Formatowanie IBAN (PL)
|
||||||
const iban = document.getElementById('numer_konta');
|
const iban = document.getElementById('numer_konta');
|
||||||
if (iban) {
|
if (iban) {
|
||||||
iban.addEventListener('input', () => {
|
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();
|
const chunked = digits.replace(/(.{4})/g, '$1 ').trim();
|
||||||
iban.value = chunked;
|
iban.value = chunked;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Telefon BLIK: tylko cyfry, format 3-3-3
|
// Telefon BLIK 3-3-3
|
||||||
const tel = document.getElementById('numer_telefonu_blik');
|
const tel = document.getElementById('numer_telefonu_blik');
|
||||||
if (tel) {
|
if (tel) {
|
||||||
tel.addEventListener('input', () => {
|
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 = [];
|
const parts = [];
|
||||||
if (digits.length > 0) parts.push(digits.substring(0, 3));
|
if (digits.length > 0) parts.push(digits.substring(0, 3));
|
||||||
if (digits.length > 3) parts.push(digits.substring(3, 6));
|
if (digits.length > 3) parts.push(digits.substring(3, 6));
|
||||||
@@ -22,24 +23,23 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Biała lista IP/hostów — helpery
|
// Biała lista IP/hostów
|
||||||
const ta = document.getElementById('allowed_login_hosts');
|
const ta = document.getElementById('dozwolone_hosty_logowania');
|
||||||
const count = document.getElementById('hostsCount');
|
const count = document.getElementById('hostsCount');
|
||||||
const addBtn = document.getElementById('btn-add-host');
|
const addBtn = document.getElementById('btn-add-host');
|
||||||
const addMyBtn = document.getElementById('btn-add-my-ip');
|
const addMyBtn = document.getElementById('btn-add-my-ip');
|
||||||
const input = document.getElementById('host_input');
|
const input = document.getElementById('host_input');
|
||||||
|
const dedupeBtn = document.getElementById('btn-dedupe');
|
||||||
|
|
||||||
function parseList(text) {
|
const parseList = (text) =>
|
||||||
// akceptuj przecinki, średniki i nowe linie; trimuj; usuń puste
|
text
|
||||||
return text
|
.split(/[\r\n,;]+/) // \r?\n, przecinek, średnik
|
||||||
.split(/[\\n,;]+/)
|
|
||||||
.map(s => s.trim())
|
.map(s => s.trim())
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
}
|
|
||||||
function formatList(arr) {
|
const formatList = (arr) => arr.join('\n');
|
||||||
return arr.join('\\n');
|
|
||||||
}
|
const dedupe = (arr) => {
|
||||||
function dedupe(arr) {
|
|
||||||
const seen = new Set();
|
const seen = new Set();
|
||||||
const out = [];
|
const out = [];
|
||||||
for (const v of arr) {
|
for (const v of arr) {
|
||||||
@@ -47,22 +47,23 @@
|
|||||||
if (!seen.has(k)) { seen.add(k); out.push(v); }
|
if (!seen.has(k)) { seen.add(k); out.push(v); }
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
};
|
||||||
function updateCount() {
|
|
||||||
|
const updateCount = () => {
|
||||||
if (!ta || !count) return;
|
if (!ta || !count) return;
|
||||||
count.textContent = parseList(ta.value).length.toString();
|
count.textContent = String(parseList(ta.value).length);
|
||||||
}
|
};
|
||||||
function addEntry(val) {
|
|
||||||
|
const addEntry = (val) => {
|
||||||
if (!ta || !val) return;
|
if (!ta || !val) return;
|
||||||
const list = dedupe([...parseList(ta.value), val]);
|
const list = dedupe([...parseList(ta.value), val]);
|
||||||
ta.value = formatList(list);
|
ta.value = formatList(list);
|
||||||
updateCount();
|
updateCount();
|
||||||
}
|
};
|
||||||
|
|
||||||
if (ta) {
|
if (ta) {
|
||||||
ta.addEventListener('input', updateCount);
|
ta.addEventListener('input', updateCount);
|
||||||
// inicjalny przelicznik
|
updateCount(); // inicjalne przeliczenie
|
||||||
updateCount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addBtn && input) {
|
if (addBtn && input) {
|
||||||
@@ -82,11 +83,10 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const dedupeBtn = document.getElementById('btn-dedupe');
|
|
||||||
if (dedupeBtn && ta) {
|
if (dedupeBtn && ta) {
|
||||||
dedupeBtn.addEventListener('click', () => {
|
dedupeBtn.addEventListener('click', () => {
|
||||||
ta.value = formatList(dedupe(parseList(ta.value)));
|
ta.value = formatList(dedupe(parseList(ta.value)));
|
||||||
updateCount();
|
updateCount();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})();
|
});
|
||||||
|
@@ -9,11 +9,11 @@
|
|||||||
}, false);
|
}, false);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const pw = document.getElementById('password');
|
const pw = document.getElementById("haslo");
|
||||||
const toggle = document.getElementById('togglePw');
|
const toggle = document.getElementById('togglePw');
|
||||||
toggle.addEventListener('click', () => {
|
toggle.addEventListener('click', () => {
|
||||||
const isText = pw.type === 'text';
|
const isText = pw.type === 'text';
|
||||||
pw.type = isText ? 'password' : 'text';
|
pw.type = isText ? "haslo" : 'text';
|
||||||
toggle.textContent = isText ? 'Pokaż' : 'Ukryj';
|
toggle.textContent = isText ? 'Pokaż' : 'Ukryj';
|
||||||
toggle.setAttribute('aria-pressed', (!isText).toString());
|
toggle.setAttribute('aria-pressed', (!isText).toString());
|
||||||
pw.focus();
|
pw.focus();
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
const pw1 = document.getElementById('password');
|
const pw1 = document.getElementById("haslo");
|
||||||
const pw2 = document.getElementById('password2');
|
const pw2 = document.getElementById('password2');
|
||||||
if (pw1.value !== pw2.value) {
|
if (pw1.value !== pw2.value) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -19,11 +19,11 @@
|
|||||||
}, false);
|
}, false);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const pw = document.getElementById('password');
|
const pw = document.getElementById("haslo");
|
||||||
const toggle = document.getElementById('togglePw');
|
const toggle = document.getElementById('togglePw');
|
||||||
toggle.addEventListener('click', () => {
|
toggle.addEventListener('click', () => {
|
||||||
const isText = pw.type === 'text';
|
const isText = pw.type === 'text';
|
||||||
pw.type = isText ? 'password' : 'text';
|
pw.type = isText ? "haslo" : 'text';
|
||||||
toggle.textContent = isText ? 'Pokaż' : 'Ukryj';
|
toggle.textContent = isText ? 'Pokaż' : 'Ukryj';
|
||||||
pw.focus();
|
pw.focus();
|
||||||
});
|
});
|
||||||
|
@@ -269,8 +269,45 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row g-3 mt-2">
|
||||||
|
<div class="col-12 col-md-4">
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" type="checkbox" id="pokaz_postep_finanse"
|
||||||
|
name="pokaz_postep_finanse" {% if is_edit and zbiorka.pokaz_postep_finanse or not
|
||||||
|
is_edit %}checked{% endif %}>
|
||||||
|
<label class="form-check-label" for="pokaz_postep_finanse">Pokaż postęp: Finanse</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-4">
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" type="checkbox" id="pokaz_postep_pozycje"
|
||||||
|
name="pokaz_postep_pozycje" {% if is_edit and zbiorka.pokaz_postep_pozycje or not
|
||||||
|
is_edit %}checked{% endif %}>
|
||||||
|
<label class="form-check-label" for="pokaz_postep_pozycje">Pokaż postęp: Zakupy
|
||||||
|
(liczba)</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-4">
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" type="checkbox" id="pokaz_postep_kwotowo"
|
||||||
|
name="pokaz_postep_kwotowo" {% if is_edit and zbiorka.pokaz_postep_kwotowo or not
|
||||||
|
is_edit %}checked{% endif %}>
|
||||||
|
<label class="form-check-label" for="pokaz_postep_kwotowo">Pokaż postęp: Zakupy
|
||||||
|
(kwotowo)</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- CTA -->
|
<!-- CTA -->
|
||||||
<div class="d-flex flex-wrap gap-2">
|
<div class="d-flex flex-wrap gap-2">
|
||||||
<button type="submit" class="btn btn-success">
|
<button type="submit" class="btn btn-success">
|
||||||
|
@@ -6,14 +6,24 @@
|
|||||||
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
<h3 class="mb-0">Transakcje: {{ zbiorka.nazwa }}</h3>
|
<h3 class="mb-0">Transakcje: {{ zbiorka.nazwa }}</h3>
|
||||||
<div class="btn-group">
|
<div class="btn-group" role="group" aria-label="Akcje zbiórki">
|
||||||
<a class="btn btn-sm btn-outline-light border" href="{{ url_for('dodaj_wplate', zbiorka_id=zbiorka.id) }}">+
|
<a class="btn btn-sm btn-outline-light border" href="{{ url_for('dodaj_wplate', zbiorka_id=zbiorka.id) }}">
|
||||||
Wpłata</a>
|
<i class="fas fa-plus-circle"></i> Dodaj wpłatę
|
||||||
<a class="btn btn-sm btn-outline-light border"
|
</a>
|
||||||
href="{{ url_for('dodaj_wydatek', zbiorka_id=zbiorka.id) }}">+ Wydatek</a>
|
|
||||||
<a class="btn btn-sm btn-outline-light border"
|
<a class="btn btn-sm btn-outline-light border" href="{{ url_for('dodaj_wydatek', zbiorka_id=zbiorka.id) }}">
|
||||||
href="{{ url_for('zbiorka', zbiorka_id=zbiorka.id) }}">Szczegóły zbiórki</a>
|
Dodaj wydatek
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="btn btn-sm btn-outline-light border" href="{{ url_for('edytuj_stan', zbiorka_id=zbiorka.id) }}">
|
||||||
|
Edytuj stan
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="btn btn-sm btn-outline-light border" href="{{ url_for('zbiorka', zbiorka_id=zbiorka.id) }}">
|
||||||
|
Otwórz ↗
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card shadow-sm">
|
<div class="card shadow-sm">
|
||||||
|
@@ -40,42 +40,60 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- SEKCJA: Dostępy / biała lista IP -->
|
||||||
<!-- SEKCJA: Dostępy / biała lista IP -->
|
<!-- SEKCJA: Dostępy / biała lista IP -->
|
||||||
<div class="card shadow-sm mb-4">
|
<div class="card shadow-sm mb-4">
|
||||||
<div class="card-header bg-secondary text-white d-flex align-items-center justify-content-between gap-2">
|
<div class="card-header bg-secondary text-white d-flex align-items-center justify-content-between gap-2">
|
||||||
<h3 class="card-title mb-0">Dostęp — dozwolone adresy IP / hosty</h3>
|
<h3 class="card-title mb-0">Dostęp — dozwolone adresy IP / hosty</h3>
|
||||||
<small class="opacity-75">Zależnie od konfiguracji, logowanie może wymagać dopasowania do białej listy</small>
|
<small class="opacity-75">Zależnie od konfiguracji logowanie może wymagać dopasowania do białej listy</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
<!-- Wiersz z inputem i przyciskiem dodawania -->
|
||||||
<div class="row g-3 align-items-end">
|
<div class="row g-3 align-items-end">
|
||||||
<div class="col-12 col-md-6">
|
<div class="col-12 col-lg-8">
|
||||||
<label for="host_input" class="form-label">Dodaj pojedynczy IP/host</label>
|
<label for="host_input" class="form-label">Dodaj IP/host</label>
|
||||||
<input type="text" class="form-control" id="host_input" placeholder="np. 203.0.113.42 lub corp.example.com"
|
<div class="input-group">
|
||||||
aria-describedby="hostAddHelp">
|
<input type="text" class="form-control" id="host_input"
|
||||||
<div id="hostAddHelp" class="form-text">Po wpisaniu kliknij „Dodaj do listy”. Duplikaty są pomijane.</div>
|
placeholder="np. 203.0.113.42 lub corp.example.com" aria-describedby="hostAddHelp">
|
||||||
|
<button type="button" class="btn btn-outline-primary" id="btn-add-host">
|
||||||
|
<i class="fas fa-plus-circle"></i> Dodaj
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="hostAddHelp" class="form-text">Po wpisaniu kliknij „Dodaj”. Duplikaty są pomijane.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 d-flex gap-2">
|
|
||||||
<button type="button" class="btn btn-outline-light border" id="btn-add-host">Dodaj do listy</button>
|
<div class="col-12 col-lg-4">
|
||||||
<button type="button" class="btn btn-light text-dark" id="btn-add-my-ip" data-my-ip="{{ client_ip }}">Dodaj
|
<div class="d-flex flex-wrap gap-2 justify-content-lg-end">
|
||||||
moje IP ({{ client_ip }})</button>
|
<button type="button" class="btn btn-light text-dark" id="btn-add-my-ip" data-my-ip="{{ client_ip }}">
|
||||||
<button type="button" class="btn btn-outline-light border" id="btn-dedupe">Usuń duplikaty</button>
|
<i class="fas fa-location-arrow"></i> Dodaj moje IP ({{ client_ip }})
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-secondary" id="btn-dedupe">
|
||||||
|
<i class="fas fa-broom"></i> Usuń duplikaty
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-3">
|
<div class="mt-3">
|
||||||
<label for="allowed_login_hosts" class="form-label">Dozwolone hosty logowania (jeden na linię lub rozdzielone
|
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||||
przecinkami)</label>
|
<label for="dozwolone_hosty_logowania" class="form-label mb-0">
|
||||||
<textarea class="form-control" id="allowed_login_hosts" name="allowed_login_hosts" rows="6"
|
Dozwolone hosty logowania (jeden na linię lub rozdzielone przecinkami)
|
||||||
placeholder="Adresy IP lub nazwy domen — każdy w osobnej linii lub rozdzielony przecinkiem">{{ settings.allowed_login_hosts if settings and settings.allowed_login_hosts else '' }}</textarea>
|
</label>
|
||||||
<div class="d-flex justify-content-between mt-1">
|
<span class="badge text-bg-secondary">Pozycji: <span id="hostsCount">0</span></span>
|
||||||
<small class="text-muted">Akceptowane separatory: przecinek (`,`), średnik (`;`) i nowa linia.</small>
|
|
||||||
<small class="text-muted">Pozycji na liście: <span id="hostsCount">0</span></small>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<textarea class="form-control" id="dozwolone_hosty_logowania" name="dozwolone_hosty_logowania" rows="6"
|
||||||
|
placeholder="Adresy IP lub nazwy domen — każdy w osobnej linii lub rozdzielony przecinkiem">{{ settings.dozwolone_hosty_logowania if settings and settings.dozwolone_hosty_logowania else '' }}</textarea>
|
||||||
|
|
||||||
|
<small class="text-muted d-block mt-1">
|
||||||
|
Akceptowane separatory: przecinek (`,`), średnik (`;`) i nowa linia.
|
||||||
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- SEKCJA: Branding -->
|
<!-- SEKCJA: Branding -->
|
||||||
<div class="card shadow-sm mb-4">
|
<div class="card shadow-sm mb-4">
|
||||||
<div class="card-header bg-secondary text-white d-flex align-items-center justify-content-between gap-2">
|
<div class="card-header bg-secondary text-white d-flex align-items-center justify-content-between gap-2">
|
||||||
@@ -99,9 +117,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<label for="site_title" class="form-label">Tytuł serwisu</label>
|
<label for="tytul_strony" class="form-label">Tytuł serwisu</label>
|
||||||
<input type="text" class="form-control" id="site_title" name="site_title"
|
<input type="text" class="form-control" id="tytul_strony" name="tytul_strony"
|
||||||
value="{{ settings.site_title if settings else '' }}" placeholder="Np. Zbiórki unitraklub.pl">
|
value="{{ settings.tytul_strony if settings else '' }}" placeholder="Np. Zbiórki unitraklub.pl">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -112,15 +130,15 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h6 class="mb-2">Menu (navbar)</h6>
|
<h6 class="mb-2">Menu (navbar)</h6>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="radio" name="navbar_brand_mode" id="navbar_mode_logo" value="logo"
|
<input class="form-check-input" type="radio" name="typ_navbar" id="navbar_mode_logo" value="logo" {% if
|
||||||
{% if settings and settings.navbar_brand_mode=='logo' or (settings and settings.show_logo_in_navbar)
|
settings and settings.typ_navbar=='logo' or (settings and settings.pokaz_logo_w_navbar) %}checked{%
|
||||||
%}checked{% endif %}>
|
endif %}>
|
||||||
<label class="form-check-label" for="navbar_mode_logo">Pokaż logo</label>
|
<label class="form-check-label" for="navbar_mode_logo">Pokaż logo</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="radio" name="navbar_brand_mode" id="navbar_mode_text" value="text"
|
<input class="form-check-input" type="radio" name="typ_navbar" id="navbar_mode_text" value="text" {% if
|
||||||
{% if not settings or (settings and settings.navbar_brand_mode !='logo' and not
|
not settings or (settings and settings.typ_navbar !='logo' and not settings.pokaz_logo_w_navbar)
|
||||||
settings.show_logo_in_navbar) %}checked{% endif %}>
|
%}checked{% endif %}>
|
||||||
<label class="form-check-label" for="navbar_mode_text">Pokaż tekst</label>
|
<label class="form-check-label" for="navbar_mode_text">Pokaż tekst</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-text mt-1">Jeśli wybierzesz logo, użyjemy adresu z pola "Tytuł serwisu".</div>
|
<div class="form-text mt-1">Jeśli wybierzesz logo, użyjemy adresu z pola "Tytuł serwisu".</div>
|
||||||
@@ -130,19 +148,19 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h6 class="mb-2">Stopka</h6>
|
<h6 class="mb-2">Stopka</h6>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="radio" name="footer_brand_mode" id="footer_mode_logo" value="logo"
|
<input class="form-check-input" type="radio" name="typ_stopka" id="footer_mode_logo" value="logo" {% if
|
||||||
{% if settings and settings.footer_brand_mode=='logo' %}checked{% endif %}>
|
settings and settings.typ_stopka=='logo' %}checked{% endif %}>
|
||||||
<label class="form-check-label" for="footer_mode_logo">Logo</label>
|
<label class="form-check-label" for="footer_mode_logo">Logo</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="radio" name="footer_brand_mode" id="footer_mode_text" value="text"
|
<input class="form-check-input" type="radio" name="typ_stopka" id="footer_mode_text" value="text" {% if
|
||||||
{% if not settings or (settings and settings.footer_brand_mode !='logo' ) %}checked{% endif %}>
|
not settings or (settings and settings.typ_stopka !='logo' ) %}checked{% endif %}>
|
||||||
<label class="form-check-label" for="footer_mode_text">Tekst</label>
|
<label class="form-check-label" for="footer_mode_text">Tekst</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="footer_text" class="form-label mt-2">Tekst w stopce (gdy wybrano „Tekst”)</label>
|
<label for="stopka_text" class="form-label mt-2">Tekst w stopce (gdy wybrano „Tekst”)</label>
|
||||||
<input type="text" class="form-control" id="footer_text" name="footer_text"
|
<input type="text" class="form-control" id="stopka_text" name="stopka_text"
|
||||||
value="{{ settings.footer_text if settings and settings.footer_text else '' }}"
|
value="{{ settings.stopka_text if settings and settings.stopka_text else '' }}"
|
||||||
placeholder="Np. © {{ now().year if now else '2025' }} Zbiórki">
|
placeholder="Np. © {{ now().year if now else '2025' }} Zbiórki">
|
||||||
<div class="form-text">Pozostaw pusty, by użyć domyślnego.</div>
|
<div class="form-text">Pozostaw pusty, by użyć domyślnego.</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -14,13 +14,13 @@
|
|||||||
<nav class="navbar navbar-expand-lg">
|
<nav class="navbar navbar-expand-lg">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand d-flex align-items-center gap-2" href="{{ url_for('index') }}">
|
<a class="navbar-brand d-flex align-items-center gap-2" href="{{ url_for('index') }}">
|
||||||
{% set nav_mode = (global_settings.navbar_brand_mode if global_settings and
|
{% set nav_mode = (global_settings.typ_navbar if global_settings and
|
||||||
global_settings.navbar_brand_mode else ('logo' if global_settings and
|
global_settings.typ_navbar else ('logo' if global_settings and
|
||||||
global_settings.show_logo_in_navbar else 'text')) %}
|
global_settings.pokaz_logo_w_navbar else 'text')) %}
|
||||||
{% if nav_mode == 'logo' and global_settings and global_settings.logo_url %}
|
{% if nav_mode == 'logo' and global_settings and global_settings.logo_url %}
|
||||||
<img src="{{ global_settings.logo_url }}" alt="Logo" style="max-height:40px; vertical-align:middle;">
|
<img src="{{ global_settings.logo_url }}" alt="Logo" style="max-height:40px; vertical-align:middle;">
|
||||||
{% else %}
|
{% else %}
|
||||||
<span>{{ global_settings.site_title if global_settings and global_settings.site_title else "Zbiórki"
|
<span>{{ global_settings.tytul_strony if global_settings and global_settings.tytul_strony else "Zbiórki"
|
||||||
}}</span>
|
}}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
@@ -72,12 +72,12 @@
|
|||||||
|
|
||||||
<!-- stopka -->
|
<!-- stopka -->
|
||||||
<footer class="mt-auto text-center py-3 border-top" style="background: var(--surface-0);">
|
<footer class="mt-auto text-center py-3 border-top" style="background: var(--surface-0);">
|
||||||
{% set footer_mode = global_settings.footer_brand_mode if global_settings and global_settings.footer_brand_mode
|
{% set footer_mode = global_settings.typ_stopka if global_settings and global_settings.typ_stopka
|
||||||
else 'text' %}
|
else 'text' %}
|
||||||
{% if footer_mode == 'logo' and global_settings and global_settings.logo_url %}
|
{% if footer_mode == 'logo' and global_settings and global_settings.logo_url %}
|
||||||
<img src="{{ global_settings.logo_url }}" alt="Logo" style="max-height:28px;">
|
<img src="{{ global_settings.logo_url }}" alt="Logo" style="max-height:28px;">
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ global_settings.footer_text if global_settings and global_settings.footer_text else "© " ~ (now().year if now
|
{{ global_settings.stopka_text if global_settings and global_settings.stopka_text else "© " ~ (now().year if now
|
||||||
else '2025') ~ " linuxiarz.pl" }}
|
else '2025') ~ " linuxiarz.pl" }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="small text-muted">v{{ APP_VERSION }}</div>
|
<div class="small text-muted">v{{ APP_VERSION }}</div>
|
||||||
|
@@ -105,7 +105,7 @@ zbiórki{% endif %}{% endblock %}
|
|||||||
{% else %}
|
{% else %}
|
||||||
<h5 class="mb-2">Brak aktywnych zbiórek</h5>
|
<h5 class="mb-2">Brak aktywnych zbiórek</h5>
|
||||||
<p class="text-muted mb-4">Wygląda na to, że teraz nic nie zbieramy.</p>
|
<p class="text-muted mb-4">Wygląda na to, że teraz nic nie zbieramy.</p>
|
||||||
{% if current_user.is_authenticated and current_user.is_admin %}
|
{% if current_user.is_authenticated and current_user.czy_admin %}
|
||||||
<a href="{{ url_for('admin_dashboard') }}" class="btn btn-primary">Utwórz nową zbiórkę</a>
|
<a href="{{ url_for('admin_dashboard') }}" class="btn btn-primary">Utwórz nową zbiórkę</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ url_for('zbiorki_zrealizowane') }}" class="btn btn-primary">Zobacz zrealizowane</a>
|
<a href="{{ url_for('zbiorki_zrealizowane') }}" class="btn btn-primary">Zobacz zrealizowane</a>
|
||||||
|
@@ -18,21 +18,21 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="username" class="form-label">Nazwa użytkownika</label>
|
<label for="uzytkownik" class="form-label">Nazwa użytkownika</label>
|
||||||
<input type="text" class="form-control" id="username" name="username"
|
<input type="text" class="form-control" id="uzytkownik" name="uzytkownik"
|
||||||
autocomplete="username" autocapitalize="none" spellcheck="false" required autofocus>
|
autocomplete="username" autocapitalize="none" spellcheck="false" required autofocus>
|
||||||
<div class="invalid-feedback">Podaj nazwę użytkownika.</div>
|
<div class="invalid-feedback">Podaj nazwę użytkownika.</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<label for="password" class="form-label d-flex justify-content-between align-items-center">
|
<label for="haslo" class="form-label d-flex justify-content-between align-items-center">
|
||||||
<span>Hasło</span>
|
<span>Hasło</span>
|
||||||
<small id="capsWarning" class="text-muted" style="display:none;">CAPS LOCK
|
<small id="capsWarning" class="text-muted" style="display:none;">CAPS LOCK
|
||||||
włączony</small>
|
włączony</small>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="password" class="form-control" id="password" name="password"
|
<input type="password" class="form-control" id="haslo" name="haslo"
|
||||||
autocomplete="current-password" required minlength="5">
|
autocomplete="current-password" required minlength="5">
|
||||||
<button type="button" class="btn btn-secondary rounded-end" id="togglePw"
|
<button type="button" class="btn btn-secondary rounded-end" id="togglePw"
|
||||||
aria-label="Pokaż/ukryj hasło">Pokaż</button>
|
aria-label="Pokaż/ukryj hasło">Pokaż</button>
|
||||||
|
@@ -14,20 +14,20 @@
|
|||||||
<form method="post" class="needs-validation" novalidate>
|
<form method="post" class="needs-validation" novalidate>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="username" class="form-label">Nazwa użytkownika</label>
|
<label for="uzytkownik" class="form-label">Nazwa użytkownika</label>
|
||||||
<input type="text" class="form-control" id="username" name="username"
|
<input type="text" class="form-control" id="uzytkownik" name="uzytkownik"
|
||||||
autocomplete="username" autocapitalize="none" spellcheck="false" required autofocus>
|
autocomplete="username" autocapitalize="none" spellcheck="false" required autofocus>
|
||||||
<div class="invalid-feedback">Podaj nazwę użytkownika.</div>
|
<div class="invalid-feedback">Podaj nazwę użytkownika.</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="password" class="form-label d-flex justify-content-between align-items-center">
|
<label for="haslo" class="form-label d-flex justify-content-between align-items-center">
|
||||||
<span>Hasło</span>
|
<span>Hasło</span>
|
||||||
<small id="capsWarning" class="text-muted" style="display:none;">CAPS LOCK
|
<small id="capsWarning" class="text-muted" style="display:none;">CAPS LOCK
|
||||||
włączony</small>
|
włączony</small>
|
||||||
</label>
|
</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="password" class="form-control" id="password" name="password"
|
<input type="password" class="form-control" id="haslo" name="haslo"
|
||||||
autocomplete="new-password" required minlength="6">
|
autocomplete="new-password" required minlength="6">
|
||||||
<button type="button" class="btn btn-secondary" id="togglePw"
|
<button type="button" class="btn btn-secondary" id="togglePw"
|
||||||
aria-label="Pokaż/ukryj hasło">Pokaż</button>
|
aria-label="Pokaż/ukryj hasło">Pokaż</button>
|
||||||
|
@@ -103,23 +103,28 @@
|
|||||||
<h5 class="mb-0">Postęp</h5>
|
<h5 class="mb-0">Postęp</h5>
|
||||||
|
|
||||||
<div class="d-flex flex-wrap align-items-center gap-2">
|
<div class="d-flex flex-wrap align-items-center gap-2">
|
||||||
{% if has_cel and not zbiorka.ukryj_kwote %}
|
{% if has_cel and not zbiorka.ukryj_kwote and zbiorka.pokaz_postep_finanse %}
|
||||||
<span class="badge bg-dark border" style="border-color: var(--border);">
|
<span class="badge bg-dark border" style="border-color: var(--border);">
|
||||||
Finanse: {{ zbiorka.stan|round(2) }} / {{ zbiorka.cel|round(2) }} PLN
|
Finanse: {{ zbiorka.stan|round(2) }} / {{ zbiorka.cel|round(2) }} PLN
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if has_items %}
|
|
||||||
|
{% if has_items and zbiorka.pokaz_postep_pozycje %}
|
||||||
<span class="badge bg-secondary">Pozycje: {{ kupione_cnt }}/{{ total_cnt }}</span>
|
<span class="badge bg-secondary">Pozycje: {{ kupione_cnt }}/{{ total_cnt }}</span>
|
||||||
{% if not zbiorka.ukryj_kwote and (suma_all or 0) > 0 %}
|
|
||||||
<span class="badge bg-secondary">Zakupy (kwotowo):
|
|
||||||
{{ (suma_kupione or 0)|round(2) }} / {{ (suma_all or 0)|round(2) }} PLN
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if has_items and not zbiorka.ukryj_kwote and (suma_all or 0) > 0 and zbiorka.pokaz_postep_kwotowo %}
|
||||||
|
<span class="badge bg-secondary">
|
||||||
|
Zakupy (kwotowo): {{ (suma_kupione or 0)|round(2) }} / {{ (suma_all or 0)|round(2) }} PLN
|
||||||
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="hr-bw">
|
<hr class="hr-bw">
|
||||||
<!-- Pasek: Finanse (zawsze) -->
|
|
||||||
|
{# Pasek: Finanse #}
|
||||||
|
{% if zbiorka.pokaz_postep_finanse %}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<small class="text-muted">Finanse</small>
|
<small class="text-muted">Finanse</small>
|
||||||
<div class="progress" role="progressbar" aria-valuenow="{{ progress_clamped|round(2) }}" aria-valuemin="0"
|
<div class="progress" role="progressbar" aria-valuenow="{{ progress_clamped|round(2) }}" aria-valuemin="0"
|
||||||
@@ -130,9 +135,10 @@
|
|||||||
{% if zbiorka.ukryj_kwote %}—{% else %}{{ progress|round(1) }}%{% endif %}
|
{% if zbiorka.ukryj_kwote %}—{% else %}{{ progress|round(1) }}%{% endif %}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if has_items %}
|
{# Pasek: Zakupy sztukami #}
|
||||||
<!-- Pasek: Zakupy sztukami -->
|
{% if has_items and zbiorka.pokaz_postep_pozycje %}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<small class="text-muted">Zakupy (liczba pozycji)</small>
|
<small class="text-muted">Zakupy (liczba pozycji)</small>
|
||||||
<div class="progress" role="progressbar" aria-valuenow="{{ items_pct|round(2) }}" aria-valuemin="0"
|
<div class="progress" role="progressbar" aria-valuenow="{{ items_pct|round(2) }}" aria-valuemin="0"
|
||||||
@@ -141,9 +147,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<small class="text-muted">{{ items_pct|round(1) }}%</small>
|
<small class="text-muted">{{ items_pct|round(1) }}%</small>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if not zbiorka.ukryj_kwote and (suma_all or 0) > 0 %}
|
{# Pasek: Zakupy kwotowo #}
|
||||||
<!-- Pasek: Zakupy kwotowo -->
|
{% if has_items and not zbiorka.ukryj_kwote and (suma_all or 0) > 0 and zbiorka.pokaz_postep_kwotowo %}
|
||||||
<div>
|
<div>
|
||||||
<small class="text-muted">Zakupy (kwotowo)</small>
|
<small class="text-muted">Zakupy (kwotowo)</small>
|
||||||
<div class="progress" role="progressbar" aria-valuenow="{{ suma_pct|round(2) }}" aria-valuemin="0"
|
<div class="progress" role="progressbar" aria-valuenow="{{ suma_pct|round(2) }}" aria-valuemin="0"
|
||||||
@@ -153,7 +160,6 @@
|
|||||||
<small class="text-muted">{{ suma_pct|round(1) }}%</small>
|
<small class="text-muted">{{ suma_pct|round(1) }}%</small>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -238,7 +244,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
{% if current_user.is_authenticated and current_user.is_admin %}
|
{% if current_user.is_authenticated and current_user.czy_admin %}
|
||||||
<hr>
|
<hr>
|
||||||
<div class="d-grid gap-2 mt-2">
|
<div class="d-grid gap-2 mt-2">
|
||||||
<a href="{{ url_for('dodaj_wplate', zbiorka_id=zbiorka.id) }}" class="btn btn-outline-light btn-sm">Dodaj
|
<a href="{{ url_for('dodaj_wplate', zbiorka_id=zbiorka.id) }}" class="btn btn-outline-light btn-sm">Dodaj
|
||||||
@@ -264,7 +270,7 @@
|
|||||||
{% if aktywnosci and aktywnosci|length > 0 %}
|
{% if aktywnosci and aktywnosci|length > 0 %}
|
||||||
<small class="text-muted">Łącznie pozycji: {{ aktywnosci|length }}</small>
|
<small class="text-muted">Łącznie pozycji: {{ aktywnosci|length }}</small>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if current_user.is_authenticated and current_user.is_admin %}
|
{% if current_user.is_authenticated and current_user.czy_admin %}
|
||||||
<a href="{{ url_for('transakcje_zbiorki', zbiorka_id=zbiorka.id) }}"
|
<a href="{{ url_for('transakcje_zbiorki', zbiorka_id=zbiorka.id) }}"
|
||||||
class="btn btn-sm btn-outline-light border">
|
class="btn btn-sm btn-outline-light border">
|
||||||
Zarządzaj
|
Zarządzaj
|
||||||
|
Reference in New Issue
Block a user