150 lines
3.9 KiB
Python
150 lines
3.9 KiB
Python
import os
|
|
import json
|
|
import time
|
|
import requests
|
|
import math
|
|
from datetime import datetime, timezone, timedelta
|
|
from flask import Flask, request, jsonify
|
|
from flask_cors import CORS
|
|
|
|
app = Flask(__name__)
|
|
|
|
# configure daily limit and data directory.
|
|
DAILY_LIMIT = 50
|
|
DATA_DIR = 'guestbook'
|
|
|
|
#get current UTC time and convert it to BMT
|
|
now_utc = datetime.now(timezone.utc)
|
|
bmt = now_utc + timedelta(hours=1)
|
|
|
|
currentDate = bmt.strftime('%Y-%m-%d')
|
|
submissionCountDay = 0
|
|
|
|
|
|
frontend_url = os.environ.get("FRONTEND_URL","*")
|
|
|
|
topic = os.environ.get("NTFY_TOPIC")
|
|
|
|
CORS(app, resources={r"/*": {"origins": frontend_url}})
|
|
|
|
if not os.path.exists(DATA_DIR):
|
|
os.makedirs(DATA_DIR)
|
|
|
|
@app.route('/comments', methods=['GET'])
|
|
def getComments():
|
|
comments = []
|
|
try:
|
|
files = sorted([f for f in os.listdir(DATA_DIR) if f.endswith('.json')], reverse=True)
|
|
|
|
for filename in files:
|
|
filepath = os.path.join(DATA_DIR, filename)
|
|
with open(filepath, 'r', encoding='utf-8') as f:
|
|
try:
|
|
data = json.load(f)
|
|
comments.append(data)
|
|
except json.JSONDecodeError:
|
|
continue
|
|
return jsonify(comments)
|
|
except Exception as e:
|
|
return jsonify({"error": str(e)}), 500
|
|
|
|
@app.route('/comments', methods=['POST'])
|
|
def addComment():
|
|
global currentDate, submissionCountDay
|
|
|
|
# Check date
|
|
today_str = datetime.now().strftime('%Y-%m-%d')
|
|
if today_str != currentDate:
|
|
currentDate = today_str
|
|
submissionCountDay = 0
|
|
|
|
# Check limit
|
|
if submissionCountDay >= DAILY_LIMIT:
|
|
return jsonify({"error": "Guestbook full for the day, try tomorrow!"}), 403
|
|
|
|
data = request.json
|
|
name = data.get('name', '').strip()
|
|
message = data.get('message', '').strip()
|
|
website = data.get('website', '').strip()
|
|
|
|
if not name or not message:
|
|
return jsonify({"error": "Missing fields"}), 400
|
|
|
|
#URL cleanup
|
|
if website:
|
|
# If forgot http://, add it for them
|
|
if not website.startswith(('http://', 'https://')):
|
|
website = 'https://' + website
|
|
|
|
date_str=time.strftime("%d-%m-%Y")
|
|
itime_beats=itime()
|
|
|
|
entry = {
|
|
'name': name,
|
|
'message': message,
|
|
'website': website,
|
|
'date': f"{date_str} @{itime_beats:03d}"
|
|
}
|
|
|
|
now = datetime.now()
|
|
readable_time = now.strftime('%Y-%m-%d_%H-%M-%S')
|
|
|
|
|
|
|
|
filename = f"{readable_time}.json"
|
|
filepath = os.path.join(DATA_DIR, filename)
|
|
|
|
try:
|
|
with open(filepath, 'x', encoding='utf-8') as f:
|
|
json.dump(entry, f)
|
|
except FileExistsError:
|
|
filename = f"{readable_time}_2.json"
|
|
filepath = os.path.join(DATA_DIR, filename)
|
|
with open(filepath, 'x', encoding='utf-8') as f:
|
|
json.dump(entry, f)
|
|
|
|
|
|
send_ntfy_notification(name, message)
|
|
|
|
|
|
submissionCountDay += 1
|
|
|
|
return jsonify({"status": "success"})
|
|
|
|
#helper functions:
|
|
|
|
# Source - https://stackoverflow.com/a/51722192
|
|
# Posted by kernel
|
|
# Retrieved 2026-01-29, License - CC BY-SA 4.0
|
|
#thanks @kernel!
|
|
def itime():
|
|
"""Calculate and return Swatch Internet Time
|
|
|
|
:returns: No. of beats (Swatch Internet Time)
|
|
:rtype: float
|
|
"""
|
|
midnight = bmt.replace(hour=0, minute=0, second=0, microsecond=0)
|
|
seconds_passed = (bmt - midnight).total_seconds()
|
|
beats = int(math.floor(seconds_passed / 86.4))
|
|
|
|
# if beats > 1000:
|
|
# beats -= 1000
|
|
# elif beats < 0:
|
|
# beats += 1000
|
|
|
|
return beats
|
|
|
|
|
|
def send_ntfy_notification(name, message):
|
|
if not topic:
|
|
return
|
|
try:
|
|
requests.post(f"https://ntfy.sh/{topic}",
|
|
data=f"{name} wrote: {message}",
|
|
headers={
|
|
"Title": "Someone Signed Your Guestbook!"
|
|
})
|
|
except Exception as e:
|
|
print(f"Notification failed: {e}")
|
|
if __name__ == '__main__':
|
|
app.run(host='0.0.0.0', port=5001) |