generated from nathanwoodburn/python-webserver-template
feat: Add bulk uploading
All checks were successful
Build Docker / BuildImage (push) Successful in 1m44s
All checks were successful
Build Docker / BuildImage (push) Successful in 1m44s
This commit is contained in:
@@ -263,6 +263,12 @@ def startTGBot(mainThread: bool = False):
|
||||
"Telegram bot token or name not set. Notifications via Telegram will not work.")
|
||||
return
|
||||
|
||||
# Check if DEV=true
|
||||
if os.getenv('DEV', 'false').lower() == 'true':
|
||||
print("Development mode is enabled. Skipping Telegram bot start.")
|
||||
return
|
||||
|
||||
|
||||
if TG_bot_running:
|
||||
print("Telegram bot is already running.")
|
||||
return
|
||||
|
||||
84
server.py
84
server.py
@@ -135,6 +135,89 @@ def logout():
|
||||
return response
|
||||
|
||||
|
||||
@app.route("/bulk_upload", methods=["POST"])
|
||||
def bulk_upload_notifications():
|
||||
"""
|
||||
Bulk upload notifications from a CSV file.
|
||||
"""
|
||||
token = request.cookies.get("token")
|
||||
if not token:
|
||||
return redirect(f"https://login.hns.au/auth?return={request.host_url}login")
|
||||
|
||||
user_data = requests.get(f"https://login.hns.au/auth/user?token={token}")
|
||||
if user_data.status_code != 200:
|
||||
return redirect(f"https://login.hns.au/auth?return={request.host_url}login")
|
||||
user_data = user_data.json()
|
||||
|
||||
username = user_data.get("username", None)
|
||||
if not username:
|
||||
return jsonify({"error": "Invalid user data"}), 400
|
||||
|
||||
# Check if the request contains a file
|
||||
if 'file' not in request.files:
|
||||
return jsonify({"error": "No file part in the request"}), 400
|
||||
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return jsonify({"error": "No selected file"}), 400
|
||||
|
||||
# Read the CSV file
|
||||
try:
|
||||
content = file.read().decode('utf-8')
|
||||
lines = content.splitlines()
|
||||
for line in lines:
|
||||
parts = line.split(',')
|
||||
if len(parts) < 3:
|
||||
continue # Skip invalid lines
|
||||
|
||||
domain = parts[0].strip()
|
||||
blocks = parts[1].strip()
|
||||
notification_type = parts[2].strip().lower() # Normalize to lowercase
|
||||
|
||||
# Find the notification type
|
||||
notificationType = None
|
||||
for notification in NOTIFICATION_TYPES:
|
||||
if notification['type'] == notification_type:
|
||||
notificationType = notification
|
||||
break
|
||||
else:
|
||||
return jsonify({"error": f"Invalid notification type: {notification_type}"}), 400
|
||||
continue # Skip invalid notification types
|
||||
|
||||
|
||||
# Create the notification data
|
||||
notification_data = {
|
||||
'domain': domain,
|
||||
'blocks': blocks,
|
||||
'type': notification_type,
|
||||
'user_name': username,
|
||||
'id': os.urandom(16).hex() # Generate a random ID for the notification
|
||||
}
|
||||
|
||||
arg = 3
|
||||
# Add additional fields based on the notification type
|
||||
for field in notificationType['fields']:
|
||||
if field['name'] not in notification_data and field.get('required', False):
|
||||
# Try to read the field from the line
|
||||
if len(parts) > arg:
|
||||
field_value = parts[arg].strip()
|
||||
if field_value:
|
||||
notification_data[field['name']] = field_value
|
||||
else:
|
||||
return jsonify({"error": f"Missing required field: {field['name']}"}), 400
|
||||
else:
|
||||
# Auto fill default values for username
|
||||
if field['type'] == 'username':
|
||||
notification_data[field['name']] = username
|
||||
else:
|
||||
return jsonify({"error": f"Missing required field: {field['name']}"}), 400
|
||||
print(notification_data)
|
||||
domains.add_notification(domain, notification_data)
|
||||
|
||||
return redirect(f"{request.host_url}account")
|
||||
except Exception as e:
|
||||
return jsonify({"error": f"Failed to process file: {str(e)}"}), 500
|
||||
|
||||
@app.route("/notification/<notificationtype>", methods=["POST"])
|
||||
def addNotification(notificationtype: str):
|
||||
"""
|
||||
@@ -252,7 +335,6 @@ def catch_all(path: str):
|
||||
|
||||
return render_template("404.html"), 404
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region API routes
|
||||
|
||||
@@ -126,6 +126,28 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="add-alerts-section">
|
||||
<h2>Bulk Upload Domains</h2>
|
||||
<p class="section-description">Upload a CSV file with your Handshake domains to set up multiple alerts at once.</p>
|
||||
<div class="bulk-upload-card">
|
||||
<form method="POST" action="/bulk_upload" enctype="multipart/form-data" class="bulk-upload-form">
|
||||
<div class="form-group">
|
||||
<label for="bulk-file">CSV File:</label>
|
||||
<input type="file" id="bulk-file" name="file" accept=".csv" required>
|
||||
<small class="form-note">Upload a CSV file with one domain per line.</small>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="button primary">Upload CSV</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="bulk-upload-info">
|
||||
<p>Format: Each line should contain a domain name, followed by the type of notification (e.g., "exampledomain, email") & notification parameters</p>
|
||||
<p>Example: <code>exampledomain, email</code></p>
|
||||
<p>Supported types: email, discord, slack, webhook</p>
|
||||
<p>Download example CSV: <a href="/assets/csv/example.csv" class="button secondary" download>Download Example CSV</a></p>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
.alerts-section, .add-alerts-section {
|
||||
margin-bottom: 60px;
|
||||
max-width: 1000px;
|
||||
margin: 16px auto;
|
||||
}
|
||||
|
||||
.alerts-section h2, .add-alerts-section h2 {
|
||||
|
||||
3
templates/assets/csv/example.csv
Normal file
3
templates/assets/csv/example.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
woodburn,1008,email,example@woodburn.au
|
||||
woodburn1,1008,discord_webhook,https://discord.com/api/webhooks/123456789012345678/abcdefghijklmnopqrstuvwxyz
|
||||
woodburn2,1008,telegram
|
||||
|
Reference in New Issue
Block a user