first commit

This commit is contained in:
Thies Mueller
2025-02-23 15:38:59 +01:00
commit 929b282aca
3 changed files with 159 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
config.ini
device_tokens.db
instance/*
*.p8
+149
View File
@@ -0,0 +1,149 @@
import asyncio
import aiohttp
import configparser
from apns2.client import APNsClient
from apns2.payload import Payload
from apns2.credentials import TokenCredentials
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
config = configparser.ConfigParser()
config.read('config.ini')
REGISTER_AUTH = config.get('AUTH', 'REGISTER_AUTH', fallback=None)
MANAGE_AUTH = config.get('AUTH', 'MANAGE_AUTH', fallback=None)
SQLALCHEMY_DATABASE_URI = config.get('DATABASE', 'SQLALCHEMY_DATABASE_URI', fallback='sqlite:///device_tokens.db')
auth_key_path = config.get('APNS', 'auth_key_path', fallback='./APNSAuthKey.p8')
auth_key_id = config.get('APNS', 'auth_key_id', fallback=None)
team_id = config.get('APNS', 'team_id', fallback=None)
topic = config.get('APNS', 'topic', fallback=None)
results_api = config.get('API', 'resultsapi', fallback='https://sat-api.tservic.es/api/v1/results')
if not all([REGISTER_AUTH, MANAGE_AUTH, auth_key_id, team_id, topic, results_api]):
raise ValueError("Fehlende Pflichtfelder in der Konfiguration!")
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = SQLALCHEMY_DATABASE_URI
db = SQLAlchemy(app)
def authenticate(request, required_token):
auth_header = request.headers.get("Authorization")
return auth_header == f"Bearer {required_token}"
class DeviceToken(db.Model):
id = db.Column(db.Integer, primary_key=True)
device_token = db.Column(db.String(256), nullable=False, unique=True)
class NotificationLog(db.Model):
id = db.Column(db.Integer, primary_key=True)
result_uuid = db.Column(db.String(256), nullable=False, unique=True)
sent_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
def create_apns_client():
token_credentials = TokenCredentials(
auth_key_path=auth_key_path,
auth_key_id=auth_key_id,
team_id=team_id
)
return APNsClient(credentials=token_credentials, use_sandbox=False)
def send_notification(device_token, title, subtitle, text):
try:
apns_client = create_apns_client()
payload = Payload(alert=title, sound="default", badge=1, custom={"subtitle": subtitle, "text": text})
apns_client.send_notification(device_token, payload, topic)
except Exception as e:
print(f"Fehler beim Senden der Benachrichtigung: {e}")
async def fetch_results_and_send_notifications():
try:
async with aiohttp.ClientSession() as session:
async with session.get(results_api) as response:
if response.status != 200:
raise Exception(f"API Fehler: {response.status}")
results = await response.json()
results = results.get('ergebnisse', {})
if not results:
raise ValueError("Keine Ergebnisse gefunden.")
device_tokens = DeviceToken.query.all()
for result in results.values():
winner_bahn = result[result['winner']]
title = f"{result['title']} Ergebnis: {winner_bahn['boot']} gewinnt mit {winner_bahn['zeit']}"
subtitle = f"{winner_bahn['boot']} gewinnt mit {winner_bahn['zeit']}"
text = "Klicke hier, um die Ergebnisse anzusehen"
if NotificationLog.query.filter_by(result_uuid=result['uuid']).first():
continue
for token in device_tokens:
send_notification(token.device_token, title, subtitle, text)
new_log = NotificationLog(result_uuid=result['uuid'])
db.session.add(new_log)
db.session.commit()
except Exception as e:
print(f"Fehler beim Abrufen und Senden von Benachrichtigungen: {e}")
@app.route("/api/getresults", methods=["POST"])
def get_results():
if not authenticate(request, MANAGE_AUTH):
return jsonify({"error": "Unauthorized"}), 401
try:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(fetch_results_and_send_notifications())
return jsonify({"message": "Benachrichtigungen gesendet"}), 200
except Exception as e:
return jsonify({'error': 'Interner Serverfehler', 'details': str(e)}), 500
@app.route("/api/registerDeviceToken", methods=["POST"])
def register_device_token():
if not authenticate(request, REGISTER_AUTH):
return jsonify({"error": "Unauthorized"}), 401
try:
data = request.get_json()
if 'device_token' not in data:
return jsonify({'error': 'device_token fehlt'}), 400
new_device_token = DeviceToken(device_token=data['device_token'])
db.session.add(new_device_token)
db.session.commit()
return jsonify({'message': 'Device Token erfolgreich registriert'}), 200
except Exception as e:
return jsonify({'error': 'Interner Serverfehler', 'details': str(e)}), 500
@app.route("/showdevicetokens", methods=["GET"])
def show_device_tokens():
tokens = DeviceToken.query.all()
return {"device_tokens": [token.device_token for token in tokens]}
@app.route("/shownotificationlog", methods=["GET"])
def show_notification_log():
logs = NotificationLog.query.all()
log_data = [{
'result_uuid': log.result_uuid,
'sent_at': log.sent_at.strftime('%Y-%m-%d %H:%M:%S')
} for log in logs]
return jsonify({'notification_logs': log_data}), 200
@app.route("/api/deleteAllDeviceTokens", methods=["POST"])
def delete_all_device_tokens():
if not authenticate(request, MANAGE_AUTH):
return jsonify({"error": "Unauthorized"}), 401
try:
db.session.query(DeviceToken).delete()
db.session.commit()
return jsonify({'message': 'Alle Device Tokens wurden gelöscht'}), 200
except Exception as e:
return jsonify({'error': 'Interner Serverfehler', 'details': str(e)}), 500
if __name__ == "__main__":
with app.app_context():
db.create_all()
app.run(host='0.0.0.0', port=3000)
+6
View File
@@ -0,0 +1,6 @@
flask
flask_sqlalchemy
asyncio
aiohttp
apns2
configparser