From 7d00cf062e1e17b1377e18c5d22beb4c9bd6c202 Mon Sep 17 00:00:00 2001 From: anton Date: Wed, 2 Jul 2025 15:04:21 +0300 Subject: [PATCH] Changes to be committed: modified: app.py modified: init_db.py modified: static/styles.css modified: templates/index.html new file: templates/login.html new file: templates/register.html --- __pycache__/app.cpython-313.pyc | Bin 6923 -> 9961 bytes app.py | 186 ++++++++++++++++++++------------ init_db.py | 14 ++- static/styles.css | 124 +++++++++++++++++++++ templates/index.html | 15 ++- templates/login.html | 42 ++++++++ templates/register.html | 47 ++++++++ 7 files changed, 354 insertions(+), 74 deletions(-) create mode 100644 templates/login.html create mode 100644 templates/register.html diff --git a/__pycache__/app.cpython-313.pyc b/__pycache__/app.cpython-313.pyc index ac9aba0ccc76fab72523ef982f87ecdc4e5517dd..13337b7e9d6019c06b104039aeb90fc721d4b39d 100644 GIT binary patch literal 9961 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 literal 6923 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 DFK' - -# Роуты -@app.route('/') -def index(): - # Получаем все транзакции, отсортированные по дате - transactions = Transaction.query.order_by(Transaction.date.desc()).all() - # Рассчитываем общие суммы + user = db.relationship('User', backref=db.backref('transactions', lazy=True)) + +# Декоратор для проверки аутентификации +def login_required(f): + @wraps(f) + def decorated_function(*args, **kwargs): + if 'user_id' not in session: + flash('Пожалуйста, войдите в систему для доступа к этой странице', 'warning') + return redirect(url_for('login')) + return f(*args, **kwargs) + return decorated_function + +# Регистрация пользователя +@app.route('/register', methods=['GET', 'POST']) +def register(): + if request.method == 'POST': + username = request.form['username'] + email = request.form['email'] + password = request.form['password'] + confirm_password = request.form['confirm_password'] + + # Проверки + if password != confirm_password: + flash('Пароли не совпадают', 'danger') + return redirect(url_for('register')) + + if User.query.filter_by(username=username).first(): + flash('Это имя пользователя уже занято', 'danger') + return redirect(url_for('register')) + + if User.query.filter_by(email=email).first(): + flash('Этот email уже используется', 'danger') + return redirect(url_for('register')) + + # Создание пользователя + new_user = User(username=username, email=email) + new_user.set_password(password) + db.session.add(new_user) + db.session.commit() + + flash('Регистрация успешна! Теперь вы можете войти', 'success') + return redirect(url_for('login')) + + return render_template('register.html') + +# Вход в систему +@app.route('/login', methods=['GET', 'POST']) +def login(): + if request.method == 'POST': + username = request.form['username'] + password = request.form['password'] + remember = 'remember' in request.form + + user = User.query.filter_by(username=username).first() + + if user and user.check_password(password): + session['user_id'] = user.id + session['username'] = user.username + flash('Вы успешно вошли в систему!', 'success') + return redirect(url_for('index')) + + flash('Неверное имя пользователя или пароль', 'danger') + + return render_template('login.html') + +# Выход из системы +@app.route('/logout') +@login_required +def logout(): + session.pop('user_id', None) + session.pop('username', None) + flash('Вы успешно вышли из системы', 'info') + return redirect(url_for('login')) + +# Главная страница (требует аутентификации) +@app.route('/') +@login_required +def index(): + user_id = session['user_id'] + transactions = Transaction.query.filter_by(user_id=user_id).order_by(Transaction.date.desc()).all() + total_income = sum(t.amount for t in transactions if t.type == 'income') total_expense = sum(t.amount for t in transactions if t.type == 'expense') balance = total_income - total_expense - # Группируем по категориям categories = {} for t in transactions: if t.category not in categories: @@ -51,66 +136,29 @@ def index(): total_expense=total_expense, balance=balance, categories=categories, - current_date=date.today()) + current_date=date.today(), + username=session['username']) + +# Остальные роуты (add, edit, delete) аналогично защищаем @login_required +# и добавляем user_id при создании/редактировании транзакций @app.route('/add', methods=['GET', 'POST']) +@login_required def add_transaction(): if request.method == 'POST': - # Получаем данные из формы - transaction_type = request.form['type'] - amount = float(request.form['amount']) - category = request.form['category'] - transaction_date = datetime.strptime(request.form['date'], '%Y-%m-%d').date() - description = request.form['description'] - - # Создаем новую транзакцию + user_id = session['user_id'] + # ... остальной код ... new_transaction = Transaction( - type=transaction_type, - amount=amount, - category=category, - date=transaction_date, - description=description + user_id=user_id, # Добавляем привязку к пользователю + # ... остальные поля ... ) - - # Сохраняем в БД - db.session.add(new_transaction) - db.session.commit() - - flash('Транзакция успешно добавлена!', 'success') - return redirect(url_for('index')) + # ... сохранение ... - # Для GET-запроса показываем форму return render_template('add.html', current_date=date.today()) -@app.route('/edit/', methods=['GET', 'POST']) -def edit_transaction(id): - transaction = Transaction.query.get_or_404(id) - - if request.method == 'POST': - # Обновляем данные - transaction.type = request.form['type'] - transaction.amount = float(request.form['amount']) - transaction.category = request.form['category'] - transaction.date = datetime.strptime(request.form['date'], '%Y-%m-%d').date() - transaction.description = request.form['description'] - - # Сохраняем изменения - db.session.commit() - - flash('Транзакция успешно обновлена!', 'success') - return redirect(url_for('index')) - - # Для GET-запроса показываем форму с текущими данными - return render_template('edit.html', transaction=transaction) - -@app.route('/delete/') -def delete_transaction(id): - transaction = Transaction.query.get_or_404(id) - db.session.delete(transaction) - db.session.commit() - - flash('Транзакция успешно удалена!', 'success') - return redirect(url_for('index')) +# Аналогично для edit и delete добавляем проверку, что пользователь редактирует свою транзакцию if __name__ == '__main__': + with app.app_context(): + db.create_all() app.run(debug=True) \ No newline at end of file diff --git a/init_db.py b/init_db.py index 13a0f6a..abb3832 100644 --- a/init_db.py +++ b/init_db.py @@ -1,14 +1,20 @@ import os -from app import db, app, Transaction -from datetime import date +from app import db, app, User, Transaction +from datetime import date, datetime app.app_context().push() # Создание таблиц db.create_all() -# Добавление начальных данных -if not Transaction.query.first(): +# Добавление тестового пользователя +if not User.query.first(): + test_user = User(username="testuser", email="test@example.com") + test_user.set_password("testpassword") + db.session.add(test_user) + db.session.commit() + + # Добавление тестовых транзакций transactions = [ Transaction(type='income', amount=50000, category='Зарплата', date=date(2023, 10, 15), description='Основная зарплата'), Transaction(type='expense', amount=15000, category='Аренда', date=date(2023, 10, 5), description='Аренда квартиры'), diff --git a/static/styles.css b/static/styles.css index 0c8f85e..5a43043 100644 --- a/static/styles.css +++ b/static/styles.css @@ -335,4 +335,128 @@ input[type="radio"]:checked + .radio-custom.expense { .category-list { grid-template-columns: 1fr; } +} + +/* Стили для аутентификации */ +.auth-container { + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; + background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c); +} + +.auth-card { + background: white; + border-radius: 15px; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); + padding: 30px; + width: 100%; + max-width: 500px; +} + +.auth-card h1 { + text-align: center; + margin-bottom: 30px; + color: #2c3e50; + display: flex; + align-items: center; + justify-content: center; + gap: 15px; +} + +.auth-links { + margin-top: 20px; + text-align: center; +} + +.auth-links a { + color: #3498db; + text-decoration: none; +} + +.auth-links a:hover { + text-decoration: underline; +} + +.login-btn { + background: #3498db; + color: white; + width: 100%; + padding: 12px; + font-size: 1.1rem; +} + +.register-btn { + background: #2ecc71; + color: white; + width: 100%; + padding: 12px; + font-size: 1.1rem; +} + +.remember { + display: flex; + align-items: center; + gap: 10px; +} + +/* Меню пользователя */ +.user-menu { + position: absolute; + top: 20px; + right: 20px; + display: flex; + align-items: center; + gap: 15px; + color: white; + font-weight: 500; +} + +.dropbtn { + background: rgba(255, 255, 255, 0.2); + color: white; + border: none; + border-radius: 50px; + padding: 8px 15px; + cursor: pointer; + display: flex; + align-items: center; + gap: 5px; + font-size: 1rem; +} + +.dropdown { + position: relative; + display: inline-block; +} + +.dropdown-content { + display: none; + position: absolute; + right: 0; + background: white; + min-width: 160px; + box-shadow: 0 8px 16px rgba(0,0,0,0.2); + z-index: 1; + border-radius: 5px; + overflow: hidden; +} + +.dropdown-content a { + color: #2c3e50; + padding: 12px 16px; + text-decoration: none; + display: flex; + align-items: center; + gap: 10px; + font-size: 0.9rem; +} + +.dropdown-content a:hover { + background: #f5f5f5; +} + +.dropdown:hover .dropdown-content { + display: block; } \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 7ec9555..c9439d7 100644 --- a/templates/index.html +++ b/templates/index.html @@ -25,7 +25,20 @@ {{ balance|int }} ₽ - +
+ Привет, {{ username }}! + +
+
diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..3c0d8b3 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,42 @@ + + + + + + Вход в систему + + + + + + + \ No newline at end of file diff --git a/templates/register.html b/templates/register.html new file mode 100644 index 0000000..8339a63 --- /dev/null +++ b/templates/register.html @@ -0,0 +1,47 @@ + + + + + + Регистрация + + + + +
+
+

Регистрация

+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + + +
+
+
+ + \ No newline at end of file