# -*- coding: utf-8 -*- import feedparser import requests import string import random import json from flask import Flask, render_template, request, flash, session, abort, jsonify, redirect from flask_session import Session from flask_session_captcha import FlaskSessionCaptcha from time import mktime, strftime from datetime import datetime app = Flask('main') app.config.from_pyfile('main.cfg') Session(app) captcha = FlaskSessionCaptcha(app) def pull_feed_entries(): all_entries = [] for tag, url in app.config['FEEDS']: entries = feedparser.parse(url).entries for e in entries: e.tag = tag dt = datetime.fromtimestamp(mktime(e.published_parsed)) e.updated_display = dt.strftime(app.config['DATE_FORMAT']) all_entries.extend(entries) all_entries.sort(key=lambda e: e.published_parsed, reverse=True) return all_entries[:app.config['MAX_ENTRIES']] def mailman_subscribe(email, mailing_list): password = "".join(random.choice(string.letters) for _ in range(8)) post = {"email": email, "fullname": "", "pw": password, "pw-conf": password, "email-button": "Zapisz", "digest": 0} headers = {"X-Forwarded-For": request.remote_addr} r = requests.post("https://lists.hackerspace.pl/subscribe/" + mailing_list, post, headers=headers) if r.status_code != 200: return False return True def parse_subscribe_requests(): if not captcha.validate(): flash(u"Nie rozwiązano poprawnie CAPTCHA.", "error") return if "email" in request.form: email = request.form["email"].strip() if len(email) > 0: if "@" in email: lists = [] if "mail-waw" in request.form: lists.append("waw") if "mail-proj" in request.form: lists.append("waw-proj") if "mail-offtopic" in request.form: lists.append("waw-ot") subscribed = [] failed = [] for maillist in lists: if mailman_subscribe(email, maillist): subscribed.append(maillist) else: failed.append(maillist) if len(subscribed) == 1: flash(u"Pomyślnie zasubskrybowano na listę %s@lists.hackerspace.pl.\ W celu aktywacji subskrypcji odwiedź odnośnik wysłany mailem na adres %s." % (subscribed[0], email)) elif len(subscribed) > 1: flash(u"Pomyślnie zasubskrybowano na listy %s. \ W celu aktywacji subskrypcji odwiedź odnośniki wysłane mailem na adres %s." % \ (", ".join(l + "@lists.hackerspace.pl" for l in subscribed), email)) if len(failed) > 0: flash(u"Wystąpił problem z zapisaniem na następujące listy: %s. Ups! Napisz na bofh@hackerspace.pl, spróbujemy to naprawić." % ", ".join(failed), "error") else: flash(u"Podano nieprawidłowy adres email.", "error") else: flash(u"Nie podano adresu email.", "error") @app.route('/', methods=["GET", "POST"]) def main(): if request.method == "POST": parse_subscribe_requests() return render_template('main.html', entries=pull_feed_entries()) @app.route('/about', methods=["GET", "POST"]) def about(): if request.method == "POST": parse_subscribe_requests() return render_template('about.html', entries=pull_feed_entries()) @app.route('/about_en', methods=["GET", "POST"]) def about_en(): if request.method == "POST": parse_subscribe_requests() return render_template('about_en.html', entries=pull_feed_entries()) @app.route('/card', methods=['GET', 'POST']) def card(): # redirect to homepage for now - will maybe be an API endpoint for the new # membership card in the future return redirect('https://hackerspace.pl/') @app.route('/spaceapi') def spaceapi(): space_open = None people_now_present = {'value': 0} open_day = False try: at_response = requests.get(app.config['AT_API_URL'], headers={ 'User-Agent': 'HSWAWSpaceAPI/1.0 +https://hackerspace.pl/spaceapi' }) at_object = json.loads(at_response.content) space_open = len(at_object['users']) > 0 people_now_present['value'] = len(at_object['users']) if len(at_object['users']) > 0: people_now_present['names'] = list(user['login'] for user in at_object['users']) open_day = space_open and int(strftime("%w")) == app.config['OPEN_DAY_WEEKDAY'] \ and int(strftime("%H")) >= app.config['OPEN_DAY_BEGIN_HOUR'] except: import traceback traceback.print_exc() result = { "api": "0.13", "space": "Warsaw Hackerspace", "logo": "https://static.hackerspace.pl/img/syrenka-black.png", "url": "https://hackerspace.pl", "location": { "lat": 52.24160, "lon": 20.98485, "address": "ul. Wolność 2A, 01-018 Warszawa, Poland", }, "state": { "open": space_open, "message": ("open for public" if open_day else "members only") + (", %d multicellular bodies present" % people_now_present['value'] if people_now_present['value'] else ""), # @TODO: customized *space* logo "icon": { "open": "https://static.hackerspace.pl/img/status-open-small.png", "closed": "https://static.hackerspace.pl/img/status-closed-small.png", } }, "contact": { "irc": "irc://chat.freenode.net/#hackerspace-pl", "twitter": "@hackerspacepl", "facebook": "hackerspacepl", "ml": "waw@lists.hackerspace.pl", }, "issue_report_channels": [ "ml" ], "projects": [ "https://wiki.hackerspace.pl/projects", ], "feeds": { "blog": {"type": "atom", "url": "https://blog.hackerspace.pl/feed/atom/"}, "calendar": {"type": "ical", "url": "https://www.google.com/calendar/ical/hackerspacewaw%40gmail.com/public/basic.ics"}, "wiki": {"type": "rss", "url": "https://wiki.hackerspace.pl/feed.php"}, }, "sensors": { "people_now_present": [people_now_present] }, } # SpaceAPI version <0.13 compliance result['open'] = result['state']['open'] result['icon'] = result['state']['icon'] result['status'] = result['state']['message'] result['address'] = result['location']['address'] result['lat'] = result['location']['lat'] result['lon'] = result['location']['lon'] return jsonify(result) @app.before_request def csrf_protect(): if request.method == "POST": token = session.pop('_csrf_token', None) if not token or token != request.form.get('_csrf_token'): abort(403) generate_csrf_token() def generate_csrf_token(): if '_csrf_token' not in session: session['_csrf_token'] = "".join(random.choice(string.letters) for _ in range(32)) return session['_csrf_token'] app.jinja_env.globals['csrf_token'] = generate_csrf_token if __name__ == '__main__': app.run('0.0.0.0', 8080, debug=True)