zbiorki_app/app.py
Mateusz Gruszczyński 6bd6284f49 first commit
2025-03-07 22:35:43 +01:00

269 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, login_user, login_required, logout_user, current_user, UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
from markupsafe import Markup
import markdown as md
from flask import abort
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///baza.db'
app.config['SECRET_KEY'] = 'tajny_klucz'
# Konfiguracja rejestracji i admina
app.config['ALLOW_REGISTRATION'] = False
app.config['MAIN_ADMIN_USERNAME'] = 'admin'
app.config['MAIN_ADMIN_PASSWORD'] = 'admin'
db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
# MODELE
class User(UserMixin, db.Model):
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
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
class Zbiorka(db.Model):
id = db.Column(db.Integer, primary_key=True)
nazwa = db.Column(db.String(100), nullable=False)
opis = db.Column(db.Text, nullable=False)
numer_konta = db.Column(db.String(50), nullable=False)
numer_telefonu_blik = db.Column(db.String(50), nullable=False)
cel = db.Column(db.Float, nullable=False, default=0.0)
stan = db.Column(db.Float, default=0.0)
ukryta = db.Column(db.Boolean, default=False)
ukryj_kwote = db.Column(db.Boolean, default=False)
wplaty = db.relationship('Wplata', backref='zbiorka', lazy=True)
class Wplata(db.Model):
id = db.Column(db.Integer, primary_key=True)
zbiorka_id = db.Column(db.Integer, db.ForeignKey('zbiorka.id'), nullable=False)
kwota = db.Column(db.Float, nullable=False)
data = db.Column(db.DateTime, default=datetime.utcnow)
opis = db.Column(db.Text, nullable=True) # Opis wpłaty
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
# Dodaj filtr Markdown pozwala na zagnieżdżanie linków i obrazków w opisie
@app.template_filter('markdown')
def markdown_filter(text):
return Markup(md.markdown(text))
# TRASY PUBLICZNE
@app.route('/')
def index():
zbiorki = Zbiorka.query.filter_by(ukryta=False).all()
return render_template('index.html', zbiorki=zbiorki)
@app.errorhandler(404)
def page_not_found(e):
return redirect(url_for('index'))
@app.route('/zbiorka/<int:zbiorka_id>')
def zbiorka(zbiorka_id):
zb = Zbiorka.query.get_or_404(zbiorka_id)
# Jeżeli zbiórka jest ukryta i użytkownik nie jest administratorem, zwróć 404
if zb.ukryta and (not current_user.is_authenticated or not current_user.is_admin):
abort(404)
return render_template('zbiorka.html', zbiorka=zb)
# TRASY LOGOWANIA I REJESTRACJI
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username).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'))
else:
flash('Nieprawidłowe dane logowania', 'danger')
return render_template('login.html')
@app.route('/logout')
@login_required
def logout():
logout_user()
flash('Wylogowano', 'success')
return redirect(url_for('login'))
@app.route('/register', methods=['GET', 'POST'])
def register():
if not app.config.get('ALLOW_REGISTRATION', False):
flash('Rejestracja została wyłączona przez administratora', 'danger')
return redirect(url_for('login'))
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if User.query.filter_by(username=username).first():
flash('Użytkownik już istnieje', 'danger')
return redirect(url_for('register'))
new_user = User(username=username)
new_user.set_password(password)
db.session.add(new_user)
db.session.commit()
flash('Konto utworzone, możesz się zalogować', 'success')
return redirect(url_for('login'))
return render_template('register.html')
# PANEL ADMINISTRACYJNY
@app.route('/admin')
@login_required
def admin_dashboard():
# Tylko użytkownik z flagą is_admin ma dostęp do pełnych funkcji panelu
if not current_user.is_admin:
flash('Brak uprawnień do panelu administracyjnego', 'danger')
return redirect(url_for('index'))
zbiorki = Zbiorka.query.all()
return render_template('admin/dashboard.html', zbiorki=zbiorki)
@app.route('/admin/zbiorka/dodaj', methods=['GET', 'POST'])
@login_required
def dodaj_zbiorka():
if not current_user.is_admin:
flash('Brak uprawnień', 'danger')
return redirect(url_for('index'))
if request.method == 'POST':
nazwa = request.form['nazwa']
opis = request.form['opis']
numer_konta = request.form['numer_konta']
numer_telefonu_blik = request.form['numer_telefonu_blik']
cel = float(request.form['cel'])
# Jeśli checkbox jest zaznaczony, wartość będzie obecna w formularzu
ukryj_kwote = 'ukryj_kwote' in request.form
nowa_zbiorka = Zbiorka(
nazwa=nazwa,
opis=opis,
numer_konta=numer_konta,
numer_telefonu_blik=numer_telefonu_blik,
cel=cel,
ukryj_kwote=ukryj_kwote
)
db.session.add(nowa_zbiorka)
db.session.commit()
flash('Zbiórka została dodana', 'success')
return redirect(url_for('admin_dashboard'))
# Zwracamy szablon dla żądania GET
return render_template('admin/add_zbiorka.html')
@app.route('/admin/zbiorka/edytuj/<int:zbiorka_id>', methods=['GET', 'POST'])
@login_required
def edytuj_zbiorka(zbiorka_id):
if not current_user.is_admin:
flash('Brak uprawnień', 'danger')
return redirect(url_for('index'))
zb = Zbiorka.query.get_or_404(zbiorka_id)
if request.method == 'POST':
zb.nazwa = request.form['nazwa']
zb.opis = request.form['opis']
zb.numer_konta = request.form['numer_konta']
zb.numer_telefonu_blik = request.form['numer_telefonu_blik']
try:
zb.cel = float(request.form['cel'])
except ValueError:
flash('Podano nieprawidłową wartość dla celu zbiórki', 'danger')
return render_template('admin/edit_zbiorka.html', zbiorka=zb)
# Ustawienie opcji ukrywania kwot, jeśli checkbox jest zaznaczony
zb.ukryj_kwote = 'ukryj_kwote' in request.form
db.session.commit()
flash('Zbiórka została zaktualizowana', 'success')
return redirect(url_for('admin_dashboard'))
# Dla żądania GET zwracamy formularz edycji
return render_template('admin/edit_zbiorka.html', zbiorka=zb)
# TRASA DODAWANIA WPŁATY Z OPISEM
# TRASA DODAWANIA WPŁATY W PANELU ADMINA
@app.route('/admin/zbiorka/<int:zbiorka_id>/wplata/dodaj', methods=['GET', 'POST'])
@login_required
def admin_dodaj_wplate(zbiorka_id):
if not current_user.is_admin:
flash('Brak uprawnień', 'danger')
return redirect(url_for('index'))
zb = Zbiorka.query.get_or_404(zbiorka_id)
if request.method == 'POST':
kwota = float(request.form['kwota'])
opis = request.form.get('opis', '')
nowa_wplata = Wplata(zbiorka_id=zb.id, kwota=kwota, opis=opis)
zb.stan += kwota # Aktualizacja stanu zbiórki
db.session.add(nowa_wplata)
db.session.commit()
flash('Wpłata została dodana', 'success')
return redirect(url_for('admin_dashboard'))
return render_template('admin/add_wplata.html', zbiorka=zb)
@app.route('/admin/zbiorka/usun/<int:zbiorka_id>', methods=['POST'])
@login_required
def usun_zbiorka(zbiorka_id):
if not current_user.is_admin:
flash('Brak uprawnień', 'danger')
return redirect(url_for('index'))
zb = Zbiorka.query.get_or_404(zbiorka_id)
db.session.delete(zb)
db.session.commit()
flash('Zbiórka została usunięta', 'success')
return redirect(url_for('admin_dashboard'))
@app.route('/admin/zbiorka/edytuj_stan/<int:zbiorka_id>', methods=['GET', 'POST'])
@login_required
def edytuj_stan(zbiorka_id):
if not current_user.is_admin:
flash('Brak uprawnień', 'danger')
return redirect(url_for('index'))
zb = Zbiorka.query.get_or_404(zbiorka_id)
if request.method == 'POST':
try:
nowy_stan = float(request.form['stan'])
except ValueError:
flash('Nieprawidłowa wartość kwoty', 'danger')
return redirect(url_for('edytuj_stan', zbiorka_id=zbiorka_id))
zb.stan = nowy_stan
db.session.commit()
flash('Stan zbiórki został zaktualizowany', 'success')
return redirect(url_for('admin_dashboard'))
return render_template('admin/edytuj_stan.html', zbiorka=zb)
@app.route('/admin/zbiorka/toggle_visibility/<int:zbiorka_id>', methods=['POST'])
@login_required
def toggle_visibility(zbiorka_id):
if not current_user.is_admin:
flash('Brak uprawnień', 'danger')
return redirect(url_for('index'))
zb = Zbiorka.query.get_or_404(zbiorka_id)
zb.ukryta = not zb.ukryta
db.session.commit()
flash('Zbiórka została ' + ('ukryta' if zb.ukryta else 'przywrócona'), 'success')
return redirect(url_for('admin_dashboard'))
if __name__ == '__main__':
with app.app_context():
db.create_all()
# Tworzenie konta głównego admina, jeśli nie istnieje
if not User.query.filter_by(is_admin=True).first():
main_admin = User(username=app.config['MAIN_ADMIN_USERNAME'], is_admin=True)
main_admin.set_password(app.config['MAIN_ADMIN_PASSWORD'])
db.session.add(main_admin)
db.session.commit()
app.run(debug=True)