import os import datetime import base64 import random import string from dateutil import parser as dt_parser from toolz import compose from toolz.curried import map, filter from atomicwrites import atomic_write SURPRISE_TITLE = os.environ.get("SURPRISE_TITLE", "Surprise") print("SURPRISE_TITLE =", SURPRISE_TITLE) SURPRISE_STORE_FILE = os.environ.get("SURPRISE_STORE_FILE", "surprise.txt") print("SURPRISE_STORE_FILE =", SURPRISE_STORE_FILE) SURPRISE_SECRET = os.environ.get("SURPRISE_SECRET") print("SURPRISE_SECRET =", SURPRISE_SECRET) assert bool(SURPRISE_SECRET) SURPRISE_ASSET_DIR = os.environ.get("SURPRISE_ASSET_DIR", "../surprise-assets/gender-reveal") print("SURPRISE_ASSET_DIR =", SURPRISE_ASSET_DIR) assert os.path.isdir(SURPRISE_ASSET_DIR) SURPRISE_REVEAL_DATETIME = dt_parser.parse( os.environ.get( "SURPRISE_REVEAL_DATETIME", (datetime.datetime.now() + datetime.timedelta(minutes=1)).isoformat() ) ) print("SURPRISE_REVEAL_DATETIME =", SURPRISE_REVEAL_DATETIME) def _get_surprise_assets(): IMG_TYPES = ( '.png', '.jpeg', '.jpg', '.svg', '.apng', '.gif', '.webp', '.avif' ) _, _, files = next(os.walk(SURPRISE_ASSET_DIR)) surprise_assets = compose( dict, map(lambda xy: (xy[0], os.path.join('/assets', ''.join(xy)))), filter(lambda xy: xy[1] in IMG_TYPES), map(lambda s: os.path.splitext(s)), map(lambda s: s.lower().strip()) )(files) if '_null' not in surprise_assets: surprise_assets['_null'] = os.path.join('/static', '_null.svg') if '_secret' not in surprise_assets: surprise_assets['_secret'] = os.path.join('/static', '_secret.svg') return surprise_assets SURPRISE_ASSETS = _get_surprise_assets() assert len(SURPRISE_ASSETS) >= 4 print("SURPRISE_ASSETS =", SURPRISE_ASSETS) from flask import ( Flask, jsonify, send_from_directory, render_template, request, url_for, redirect, flash ) app = Flask(__name__) app.config['SECRET_KEY'] = ''.join(random.choice(string.ascii_lowercase) for i in range(20)) @app.route('/') def index(): return render_template('index.html', title=SURPRISE_TITLE) @app.route('/assets/') def assets(path): return send_from_directory(SURPRISE_ASSET_DIR, path) @app.route('/get-surprise.json') def get_surprise_json(): diff = (SURPRISE_REVEAL_DATETIME - datetime.datetime.now()).total_seconds() if os.path.isfile(SURPRISE_STORE_FILE): if diff < 0: with open(SURPRISE_STORE_FILE) as f: surprise = f.read() else: surprise = '_secret' else: surprise = '_null' return jsonify({ 'diff_seconds': diff, 'surprise': surprise, 'asset': SURPRISE_ASSETS[surprise] }) @app.route('/set-surprise') def set_surprise(): enum = [v for v in SURPRISE_ASSETS.keys() if v not in ('_null', '_secret')] return render_template('set_surprise.html', title=SURPRISE_TITLE, enum=enum) @app.route('/post-surprise', methods=['POST']) def post_surprise(): if request.form.get('password') != SURPRISE_SECRET: flash("Password is wrong") return redirect(url_for('set_surprise')) value = request.form.get('surprise') if value not in SURPRISE_ASSETS.keys(): flash("Invalid value '%s'" % value) return redirect(url_for('set_surprise')) with atomic_write(SURPRISE_STORE_FILE, overwrite=True) as f: f.write(value) flash("Value was successfully set to '%s'" % value) return redirect(url_for('index'))