From d4e85ea44f4b96721a77b24d9c9fd9a943169db0 Mon Sep 17 00:00:00 2001 From: nocci Date: Tue, 29 Apr 2025 12:51:23 +0200 Subject: [PATCH 1/6] update readme due release on codeberg --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b9d38c5..5055fbe 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,16 @@ It's even possible to gift your keys via a unique website. Just edit the game to ## 🚀 Get Started! 🚀 -### 1. **Clone the Repository** +## 1. **Clone the Repository (Option 1 or Option 2)** + +### Option 1: Clone the main repository + +```bash +git clone https://codeberg.org/nocci/GameKeyManager +cd steam-gift-manager +``` + +### Option 2: Clone from alternative repository (if option 1 fails) ```bash git clone https://git.nocci.it/nocci/GameKeyManager From 653d04e76aa60cdbecfb6b45dd65c427fb94b6d6 Mon Sep 17 00:00:00 2001 From: nocci Date: Tue, 29 Apr 2025 14:13:27 +0200 Subject: [PATCH 2/6] docker compose missing in setup.sh --- setup.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.sh b/setup.sh index 7a24685..f6def89 100644 --- a/setup.sh +++ b/setup.sh @@ -52,6 +52,7 @@ else elif command -v apt-get &>/dev/null; then sudo apt-get update sudo apt-get install -y docker-compose-plugin + sudo apt-get install -y docker-compose elif command -v dnf &>/dev/null; then sudo dnf install -y docker-compose elif command -v yum &>/dev/null; then From 277bd5a2836d302222014ded1d003b9d47096106 Mon Sep 17 00:00:00 2001 From: nocci Date: Tue, 29 Apr 2025 14:27:55 +0200 Subject: [PATCH 3/6] switch webserver to gunicorn --- setup.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/setup.sh b/setup.sh index f6def89..b2c2083 100644 --- a/setup.sh +++ b/setup.sh @@ -108,6 +108,7 @@ matrix-client reportlab requests pillow +gunicorn EOL # 3. .env-Datei im übergeordneten Verzeichnis erstellen @@ -878,9 +879,7 @@ RUN groupadd -g \$GID appuser && \ chown -R appuser:appuser /app USER appuser - -EXPOSE 5000 -CMD ["python", "app.py"] +CMD ["gunicorn", "-b", "0.0.0.0:5000", "app:app"] DOCKER_END # 6. docker-compose.yml From 2ea3a8059c90cdfb571baf0e14f40cbb6913b940 Mon Sep 17 00:00:00 2001 From: nocci Date: Tue, 29 Apr 2025 14:32:45 +0200 Subject: [PATCH 4/6] typo in Dockerfile --- setup.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.sh b/setup.sh index b2c2083..a56f879 100644 --- a/setup.sh +++ b/setup.sh @@ -879,6 +879,9 @@ RUN groupadd -g \$GID appuser && \ chown -R appuser:appuser /app USER appuser + +EXPOSE 5000 + CMD ["gunicorn", "-b", "0.0.0.0:5000", "app:app"] DOCKER_END From c886d5f28e76f9bc696a1797435fb6adcd3c3b57 Mon Sep 17 00:00:00 2001 From: nocci Date: Tue, 29 Apr 2025 14:46:55 +0200 Subject: [PATCH 5/6] translations of setup.sh --- setup.sh | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/setup.sh b/setup.sh index a56f879..0793758 100644 --- a/setup.sh +++ b/setup.sh @@ -75,12 +75,12 @@ else fi -# Konfiguration +# Configuration PROJECT_DIR="steam-gift-manager" TRANSLATIONS_DIR="../translations" DATA_DIR="../data" -# 1. Projektordner & Übersetzungsordner erstellen +# 1. Create project folder & translations folder mkdir -p "$PROJECT_DIR"/{templates,static} mkdir -p "$TRANSLATIONS_DIR"/de/LC_MESSAGES mkdir -p "$TRANSLATIONS_DIR"/en/LC_MESSAGES @@ -111,7 +111,7 @@ pillow gunicorn EOL -# 3. .env-Datei im übergeordneten Verzeichnis erstellen +# 3. Create .env file in parent directory cd .. SECRET_KEY=$(python3 -c 'import secrets; print(secrets.token_hex(24))') REDEEM_SECRET=$(python3 -c 'import secrets; print(secrets.token_hex(16))') @@ -154,10 +154,10 @@ MATRIX_ACCESS_TOKEN="" MATRIX_ROOM_ID="" EOL -# Zurück ins Projektverzeichnis +# Back to project directory cd $PROJECT_DIR -# 4. app.py (vollständige korrigierte Version) +# 4. app.py (the main app) cat <<'PYTHON_END' > app.py import os import logging @@ -220,7 +220,7 @@ load_dotenv(override=True) # Lade Umgebungsvariablen aus .env mit override load_dotenv(override=True) -# Konfiguration +# App-Configuration app.config.update( SECRET_KEY=os.getenv('SECRET_KEY'), SQLALCHEMY_DATABASE_URI=('sqlite:////app/data/games.db'), @@ -235,7 +235,7 @@ app.config.update( interval_hours = int(os.getenv('CHECK_EXPIRING_KEYS_INTERVAL_HOURS', 12)) -# Initialisierung +# Initialisation db = SQLAlchemy(app, metadata=metadata) migrate = Migrate(app, db) login_manager = LoginManager(app) @@ -259,7 +259,7 @@ def inject_template_vars(): theme='dark' if request.cookies.get('dark_mode') == 'true' else 'light' ) -# Datenbankmodelle +# DB Models class User(db.Model, UserMixin): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) @@ -590,7 +590,7 @@ def export_pdf(): game.redeem_date.strftime('%d.%m.%y') if game.redeem_date else '' ]) - # Tabelle formatieren + # Table format table = Table(data, colWidths=col_widths, repeatRows=1) table.setStyle(TableStyle([ ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'), @@ -814,7 +814,7 @@ def check_expiring_keys(): send_notification(user, game) -# Optional: Cleanup-Funktion für regelmäßiges Löschen abgelaufener Tokens +# Optional: cleaning up old tokens def cleanup_expired_tokens(): now = datetime.utcnow() expired = RedeemToken.query.filter(RedeemToken.expires < now).all() @@ -823,13 +823,13 @@ def cleanup_expired_tokens(): db.session.commit() -# Scheduler initialisieren und starten +# Scheduler start scheduler = BackgroundScheduler() scheduler.add_job(func=check_expiring_keys, trigger="interval", hours=interval_hours) scheduler.add_job(func=cleanup_expired_tokens, trigger="interval", hours=1) scheduler.start() -# Shutdown des Schedulers bei Beendigung der App +# Shutdown of the Schedulers when stopping the app atexit.register(lambda: scheduler.shutdown()) if __name__ == '__main__': @@ -839,7 +839,7 @@ if __name__ == '__main__': PYTHON_END -# Babel Konfiguration erstellen +# Create Babel configuration cat < babel.cfg [python: **.py] [jinja2: **/templates/**.html] @@ -903,11 +903,11 @@ services: restart: unless-stopped COMPOSE_END -# 7. Verzeichnisse und Berechtigungen +# 7. Directories and permissions mkdir -p ../data ../translations chmod -R a+rwX ../data ../translations -# 8. Übersetzungs- und Upgrade-Scripte +# 8. Translation and upgrade scripts cat <<'SCRIPT_END' > ../translate.sh #!/bin/bash set -e @@ -919,10 +919,10 @@ declare -A locales=( ["en"]="en" ) -# POT-Datei erstellen +# create POT-file docker-compose exec steam-manager pybabel extract -F babel.cfg -o translations/messages.pot . -# Für jede Sprache prüfen und ggf. initialisieren +# Check for each language and initialize if necessary for lang in "${!locales[@]}"; do if [ ! -f "translations/${locales[$lang]}/LC_MESSAGES/messages.po" ]; then docker-compose exec steam-manager pybabel init \ @@ -932,11 +932,11 @@ for lang in "${!locales[@]}"; do fi done -# Übersetzungen aktualisieren und kompilieren +# Update and compile translations docker-compose exec steam-manager pybabel update -i translations/messages.pot -d translations docker-compose exec steam-manager pybabel compile -d translations -echo "✅ Übersetzungen aktualisiert!" +echo "✅ Translations updated!" SCRIPT_END chmod +x ../translate.sh @@ -944,25 +944,25 @@ cat <<'SCRIPT_END' > ../upgrade.sh #!/bin/bash set -e -# Setze das Arbeitsverzeichnis auf das Projektverzeichnis +# Set the working directory to the project directory cd "$(dirname "$0")/steam-gift-manager" # Setze FLASK_APP, falls nötig export FLASK_APP=app.py -# Initialisiere migrations, falls noch nicht vorhanden +# Initialize migrations, if not yet available if [ ! -d migrations ]; then echo "Starting Flask-Migrate..." docker-compose exec steam-manager flask db init fi -# Erzeuge Migration (nur wenn sich Modelle geändert haben) +# Create migration (only if models have changed) docker-compose exec steam-manager flask db migrate -m "Automatic Migration" -# Wende Migration an +# Apply migration docker-compose exec steam-manager flask db upgrade -echo "✅ Database-Migration abgeschlossen!" +echo "✅ Database migration completed!" SCRIPT_END chmod +x ../upgrade.sh @@ -1482,7 +1482,7 @@ function updateCountdown() { updateProgressBar(percent); } -// Initialisierung +// run countdown updateCountdown(); const timer = setInterval(updateCountdown, 1000); @@ -1558,7 +1558,7 @@ body { color: #ff6b6b; } -/* Progressbar-Animationen */ +/* Progressbar-Animations */ #expiry-bar { transition: width 1s linear, background-color 0.5s ease; } From d3eb37ebff3c6d9805884b0594c911f2ef9c16db Mon Sep 17 00:00:00 2001 From: nocci Date: Tue, 29 Apr 2025 15:19:59 +0200 Subject: [PATCH 6/6] more translations fixed --- .env | 34 +++++ setup.sh | 22 ++-- steam-gift-manager/Dockerfile | 3 +- steam-gift-manager/app.py | 14 +- steam-gift-manager/requirements.txt | 1 + steam-gift-manager/static/style.css | 2 +- steam-gift-manager/templates/login.html | 2 +- steam-gift-manager/templates/redeem.html | 2 +- translate.sh | 8 +- translations/de/LC_MESSAGES/messages.mo | Bin 445 -> 445 bytes translations/de/LC_MESSAGES/messages.po | 159 +++++++++++------------ translations/en/LC_MESSAGES/messages.mo | Bin 445 -> 445 bytes translations/en/LC_MESSAGES/messages.po | 35 ++--- translations/messages.pot | 33 ++--- upgrade.sh | 10 +- 15 files changed, 170 insertions(+), 155 deletions(-) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 0000000..e8985d5 --- /dev/null +++ b/.env @@ -0,0 +1,34 @@ +# Flask-Configuration - Key are generated through setup.sh +SECRET_KEY="" +REDEEM_SECRET="" +WTF_CSRF_SECRET_KEY="" + +# locales +BABEL_DEFAULT_LOCALE="en" +BABEL_SUPPORTED_LOCALES="de,en" +BABEL_TRANSLATION_DIRECTORIES="translations" + +# Timezone +TZ=Europe/Berlin + +# Security +SESSION_COOKIE_SECURE="False" +CSRF_ENABLED="True" +# Account registration +REGISTRATION_ENABLED="True" + +# checking interval if keys have to be redeemed before a specific date +CHECK_EXPIRING_KEYS_INTERVAL_HOURS=6 + +# Pushover +PUSHOVER_APP_TOKEN="" +PUSHOVER_USER_KEY="" + +# Gotify +GOTIFY_URL="" +GOTIFY_TOKEN="" + +# Matrix +MATRIX_HOMESERVER="" +MATRIX_ACCESS_TOKEN="" +MATRIX_ROOM_ID="" diff --git a/setup.sh b/setup.sh index 0793758..362cdb9 100644 --- a/setup.sh +++ b/setup.sh @@ -351,7 +351,7 @@ def login(): @app.route('/register', methods=['GET', 'POST']) def register(): if not app.config['REGISTRATION_ENABLED']: - flash(_('Registrierungen sind deaktiviert'), 'danger') + flash(_('No new registrations. They are deactivated!'), 'danger') return redirect(url_for('login')) if request.method == 'POST': @@ -385,16 +385,16 @@ def change_password(): confirm_password = request.form['confirm_password'] if not check_password_hash(current_user.password, current_password): - flash(_('Aktuelles Passwort ist falsch'), 'danger') + flash(_('Current passwort is wrong'), 'danger') return redirect(url_for('change_password')) if new_password != confirm_password: - flash(_('Neue Passwörter stimmen nicht überein'), 'danger') + flash(_('New Passwords are not matching'), 'danger') return redirect(url_for('change_password')) current_user.password = generate_password_hash(new_password) db.session.commit() - flash(_('Passwort erfolgreich geändert'), 'success') + flash(_('Password changed successfully'), 'success') return redirect(url_for('index')) return render_template('change_password.html') @@ -652,15 +652,15 @@ def import_games(): db.session.commit() - flash(_('%(new)d neue Spiele importiert, %(dup)d Duplikate übersprungen', new=new_games, dup=duplicates), 'success') + flash(_('%(new)d new games imported, %(dup)d skipped duplicates', new=new_games, dup=duplicates), 'success') except Exception as e: db.session.rollback() - flash(_('Importfehler: %(error)s', error=str(e)), 'danger') + flash(_('Import error: %(error)s', error=str(e)), 'danger') return redirect(url_for('index')) - flash(_('Bitte eine gültige CSV-Datei hochladen.'), 'danger') + flash(_('Please upload a valid CSV file.'), 'danger') return render_template('import.html') @@ -1015,7 +1015,7 @@ cat < templates/base.html {% if current_user.is_authenticated %}