From 4bebbb27e45741dd89894bdaadeccc01bb11dadc Mon Sep 17 00:00:00 2001 From: nocci Date: Tue, 22 Apr 2025 13:45:13 +0200 Subject: [PATCH] ready for version 0.2 --- setup.sh | 1 - steam-gift-manager/Dockerfile | 3 - steam-gift-manager/app.py | 72 ++++++++++++++---- steam-gift-manager/templates/base.html | 2 + steam-gift-manager/templates/import.html | 14 ++++ steam-translations/de/LC_MESSAGES/messages.mo | Bin 445 -> 445 bytes steam-translations/en/LC_MESSAGES/messages.mo | Bin 445 -> 445 bytes steam-translations/en/LC_MESSAGES/messages.po | 52 ++++++++++--- steam-translations/messages.pot | 50 +++++++++--- 9 files changed, 157 insertions(+), 37 deletions(-) create mode 100644 steam-gift-manager/templates/import.html diff --git a/setup.sh b/setup.sh index 773442d..37c72f3 100644 --- a/setup.sh +++ b/setup.sh @@ -317,7 +317,6 @@ DOCKER_END # 6. docker-compose.yml cat < docker-compose.yml -version: '3.8' services: steam-manager: diff --git a/steam-gift-manager/Dockerfile b/steam-gift-manager/Dockerfile index 5f82566..56ab9f1 100644 --- a/steam-gift-manager/Dockerfile +++ b/steam-gift-manager/Dockerfile @@ -1,9 +1,7 @@ FROM python:3.10-slim -# Shell explizit setzen SHELL ["/bin/bash", "-c"] -# Datenbankordner erstellen und Berechtigungen setzen RUN mkdir -p /app/data && chmod -R a+rwX /app/data WORKDIR /app @@ -14,7 +12,6 @@ COPY . . ARG UID=1000 ARG GID=1000 - RUN groupadd -g $GID appuser && useradd -u $UID -g $GID -m appuser && chown -R appuser:appuser /app USER appuser diff --git a/steam-gift-manager/app.py b/steam-gift-manager/app.py index af6bdc8..c94340a 100644 --- a/steam-gift-manager/app.py +++ b/steam-gift-manager/app.py @@ -1,10 +1,12 @@ -from flask import Flask, render_template, request, redirect, url_for, flash, make_response, session, abort +from flask import Flask, render_template, request, redirect, url_for, flash, make_response, session, abort, send_file from flask_sqlalchemy import SQLAlchemy from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user from flask_babel import Babel, _ from werkzeug.security import generate_password_hash, check_password_hash from datetime import datetime import os +import io +import csv app = Flask(__name__) app.config['SECRET_KEY'] = os.urandom(24) @@ -14,7 +16,6 @@ app.config['BABEL_DEFAULT_LOCALE'] = 'de' app.config['BABEL_SUPPORTED_LOCALES'] = ['de', 'en'] app.config['BABEL_TRANSLATION_DIRECTORIES'] = 'translations' - db = SQLAlchemy(app) login_manager = LoginManager(app) login_manager.login_view = 'login' @@ -138,7 +139,7 @@ def add_game(): recipient=request.form.get('recipient', ''), notes=request.form.get('notes', ''), url=url, - steam_appid=steam_appid, # <- jetzt wird sie gesetzt! + steam_appid=steam_appid, redeem_date=datetime.strptime(request.form['redeem_date'], '%Y-%m-%d') if request.form['redeem_date'] else None, user_id=current_user.id ) @@ -151,45 +152,37 @@ def add_game(): flash(_('Error: ') + str(e), 'danger') return render_template('add_game.html') - @app.route('/edit/', methods=['GET', 'POST']) @login_required def edit_game(game_id): - game = db.session.get(Game, game_id) # SQLAlchemy 2.x-kompatibel + game = db.session.get(Game, game_id) if not game or game.owner != current_user: return _("Not allowed!"), 403 - + if request.method == 'POST': try: - # Steam AppID aus Formular oder URL extrahieren url = request.form.get('url', '') steam_appid = request.form.get('steam_appid', '').strip() if not steam_appid: steam_appid = extract_steam_appid(url) - - # Aktualisiere alle Felder game.name = request.form['name'] game.steam_key = request.form['steam_key'] game.status = request.form['status'] game.recipient = request.form.get('recipient', '') game.notes = request.form.get('notes', '') game.url = url - game.steam_appid = steam_appid # <- FEHLTE HIER + game.steam_appid = steam_appid game.redeem_date = datetime.strptime(request.form['redeem_date'], '%Y-%m-%d') if request.form['redeem_date'] else None - db.session.commit() flash(_('Changes saved!'), 'success') return redirect(url_for('index')) - except Exception as e: db.session.rollback() flash(_('Error: ') + str(e), 'danger') - return render_template('edit_game.html', game=game, redeem_date=game.redeem_date.strftime('%Y-%m-%d') if game.redeem_date else '') - @app.route('/delete/', methods=['POST']) @login_required def delete_game(game_id): @@ -205,6 +198,57 @@ def delete_game(game_id): flash(_('Error deleting: ') + str(e), 'danger') return redirect(url_for('index')) +# --- Import/Export Funktionen --- + +@app.route('/export', methods=['GET']) +@login_required +def export_games(): + games = Game.query.filter_by(user_id=current_user.id).all() + output = io.StringIO() + writer = csv.writer(output) + writer.writerow(['Name', 'Steam Key', 'Status', 'Recipient', 'Notes', 'URL', 'Created', 'Redeem by', 'Steam AppID']) + for game in games: + writer.writerow([ + game.name, game.steam_key, game.status, game.recipient, game.notes, + game.url, game.created_at.strftime('%Y-%m-%d %H:%M:%S') if game.created_at else '', + game.redeem_date.strftime('%Y-%m-%d') if game.redeem_date else '', + game.steam_appid + ]) + output.seek(0) + return send_file( + io.BytesIO(output.getvalue().encode('utf-8')), + mimetype='text/csv', + as_attachment=True, + download_name='games_export.csv' + ) + +@app.route('/import', methods=['GET', 'POST']) +@login_required +def import_games(): + if request.method == 'POST': + file = request.files.get('file') + if file and file.filename.endswith('.csv'): + stream = io.StringIO(file.stream.read().decode("UTF8"), newline=None) + reader = csv.DictReader(stream) + for row in reader: + new_game = Game( + name=row['Name'], + steam_key=row['Steam Key'], + status=row['Status'], + recipient=row.get('Recipient', ''), + notes=row.get('Notes', ''), + url=row.get('URL', ''), + created_at=datetime.strptime(row['Created'], '%Y-%m-%d %H:%M:%S') if row.get('Created') else datetime.utcnow(), + redeem_date=datetime.strptime(row['Redeem by'], '%Y-%m-%d') if row.get('Redeem by') else None, + steam_appid=row.get('Steam AppID', ''), + user_id=current_user.id + ) + db.session.add(new_game) + db.session.commit() + flash(_('Import erfolgreich!'), 'success') + return redirect(url_for('index')) + flash(_('Bitte eine gültige CSV-Datei hochladen.'), 'danger') + return render_template('import.html') if __name__ == '__main__': with app.app_context(): diff --git a/steam-gift-manager/templates/base.html b/steam-gift-manager/templates/base.html index b5751b3..032731e 100644 --- a/steam-gift-manager/templates/base.html +++ b/steam-gift-manager/templates/base.html @@ -45,6 +45,8 @@ {% if current_user.is_authenticated %} + ⬇️ {{ _('Export') }} + ⬆️ {{ _('Import') }} {{ _('Logout') }} {% endif %} diff --git a/steam-gift-manager/templates/import.html b/steam-gift-manager/templates/import.html new file mode 100644 index 0000000..05ff360 --- /dev/null +++ b/steam-gift-manager/templates/import.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} +{% block content %} +
+

{{ _('Import Games') }}

+
+
+ + +
+ + {{ _('Abbrechen') }} +
+
+{% endblock %} diff --git a/steam-translations/de/LC_MESSAGES/messages.mo b/steam-translations/de/LC_MESSAGES/messages.mo index 838123496487609ebb88c3e2f6ae8a55ee1f7494..13beeed6514e16d6a16a2f7d065c6ece27738fa2 100644 GIT binary patch delta 28 ccmdnXyq9^xM0O(uLqjVgqlq&V;miYn0eTJy>;M1& delta 28 ccmdnXyq9^xM0P_3LqjVglZi7F;miYn0eTe(?f?J) diff --git a/steam-translations/en/LC_MESSAGES/messages.mo b/steam-translations/en/LC_MESSAGES/messages.mo index ab9f395ad55133122c975d7917c4039816cfa834..36b14ed4061e6973006c96034fca74bcc82aed15 100644 GIT binary patch delta 28 ccmdnXyq9^xM0O(uLqjVgqlq&V;miYn0eTJy>;M1& delta 28 ccmdnXyq9^xM0P_3LqjVglZi7F;miYn0eTe(?f?J) diff --git a/steam-translations/en/LC_MESSAGES/messages.po b/steam-translations/en/LC_MESSAGES/messages.po index 7eacdbd..bb47948 100644 --- a/steam-translations/en/LC_MESSAGES/messages.po +++ b/steam-translations/en/LC_MESSAGES/messages.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2025-04-21 11:24+0000\n" -"PO-Revision-Date: 2025-04-21 11:24+0000\n" +"POT-Creation-Date: 2025-04-22 11:22+0000\n" +"PO-Revision-Date: 2025-04-22 11:22+0000\n" "Last-Translator: FULL NAME \n" "Language: en\n" "Language-Team: en \n" @@ -18,38 +18,46 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.17.0\n" -#: app.py:93 +#: app.py:94 msgid "Invalid credentials" msgstr "" -#: app.py:102 +#: app.py:103 msgid "Username already exists" msgstr "" -#: app.py:147 +#: app.py:148 msgid "Game added successfully!" msgstr "" -#: app.py:151 app.py:186 +#: app.py:152 app.py:181 msgid "Error: " msgstr "" -#: app.py:160 app.py:198 +#: app.py:160 app.py:191 msgid "Not allowed!" msgstr "" -#: app.py:181 +#: app.py:177 msgid "Changes saved!" msgstr "" -#: app.py:202 +#: app.py:195 msgid "Game deleted!" msgstr "" -#: app.py:205 +#: app.py:198 msgid "Error deleting: " msgstr "" +#: app.py:248 +msgid "Import erfolgreich!" +msgstr "" + +#: app.py:250 +msgid "Bitte eine gültige CSV-Datei hochladen." +msgstr "" + #: templates/add_game.html:4 templates/index.html:6 msgid "Add New Game" msgstr "" @@ -120,6 +128,14 @@ msgid "Dark Mode" msgstr "" #: templates/base.html:48 +msgid "Export" +msgstr "" + +#: templates/base.html:49 +msgid "Import" +msgstr "" + +#: templates/base.html:50 msgid "Logout" msgstr "" @@ -131,6 +147,22 @@ msgstr "" msgid "Steam AppID (optional)" msgstr "" +#: templates/import.html:4 +msgid "Import Games" +msgstr "" + +#: templates/import.html:7 +msgid "CSV-Datei auswählen" +msgstr "" + +#: templates/import.html:10 +msgid "Importieren" +msgstr "" + +#: templates/import.html:11 +msgid "Abbrechen" +msgstr "" + #: templates/index.html:4 msgid "My Games" msgstr "" diff --git a/steam-translations/messages.pot b/steam-translations/messages.pot index 8f32f79..585ef16 100644 --- a/steam-translations/messages.pot +++ b/steam-translations/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2025-04-21 11:24+0000\n" +"POT-Creation-Date: 2025-04-22 11:22+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,38 +17,46 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.17.0\n" -#: app.py:93 +#: app.py:94 msgid "Invalid credentials" msgstr "" -#: app.py:102 +#: app.py:103 msgid "Username already exists" msgstr "" -#: app.py:147 +#: app.py:148 msgid "Game added successfully!" msgstr "" -#: app.py:151 app.py:186 +#: app.py:152 app.py:181 msgid "Error: " msgstr "" -#: app.py:160 app.py:198 +#: app.py:160 app.py:191 msgid "Not allowed!" msgstr "" -#: app.py:181 +#: app.py:177 msgid "Changes saved!" msgstr "" -#: app.py:202 +#: app.py:195 msgid "Game deleted!" msgstr "" -#: app.py:205 +#: app.py:198 msgid "Error deleting: " msgstr "" +#: app.py:248 +msgid "Import erfolgreich!" +msgstr "" + +#: app.py:250 +msgid "Bitte eine gültige CSV-Datei hochladen." +msgstr "" + #: templates/add_game.html:4 templates/index.html:6 msgid "Add New Game" msgstr "" @@ -119,6 +127,14 @@ msgid "Dark Mode" msgstr "" #: templates/base.html:48 +msgid "Export" +msgstr "" + +#: templates/base.html:49 +msgid "Import" +msgstr "" + +#: templates/base.html:50 msgid "Logout" msgstr "" @@ -130,6 +146,22 @@ msgstr "" msgid "Steam AppID (optional)" msgstr "" +#: templates/import.html:4 +msgid "Import Games" +msgstr "" + +#: templates/import.html:7 +msgid "CSV-Datei auswählen" +msgstr "" + +#: templates/import.html:10 +msgid "Importieren" +msgstr "" + +#: templates/import.html:11 +msgid "Abbrechen" +msgstr "" + #: templates/index.html:4 msgid "My Games" msgstr ""