<commit_before>import sys
import base64
import json
import subprocess

try:
    import ssl
except ImportError:
    ssl = False

try:
    str_instances = (str, basestring)
except Exception:
    str_instances = (str, )

try:
    import urllib
    from urllib.request import Request, urlopen
    HTTPError = urllib.error.HTTPError
    URLError = urllib.error.URLError
except (AttributeError, ImportError, ValueError):
    import urllib2
    from urllib2 import Request, urlopen
    HTTPError = urllib2.HTTPError
    URLError = urllib2.URLError

try:
    from .. import editor
    from . import msg, shared as G, utils
except ImportError:
    import editor
    import msg
    import shared as G
    import utils

def get_basic_auth():
    basic_auth = ('%s:%s' % (G.API_KEY or G.USERNAME, G.SECRET)).encode('utf-8')
    basic_auth = base64.encodestring(basic_auth)
    return basic_auth.decode('ascii').replace('\n', '')

class APIResponse():
    def __init__(self, r):
        if isinstance(r, bytes):
            r = r.decode('utf-8')
        if isinstance(r, str_instances):
            lines = r.split('\n')
            self.code = int(lines[0])
            self.body = json.loads('\n'.join(lines[1:]))
        else:
            self.code = r.code
            self.body = json.loads(r.read())

def proxy_api_request(url, data=None):
    args = ['python', '-m', 'floo.proxy', '--url', url]
    if data:
        args += ["--data", json.dumps(data)]
    msg.debug('Running %s' % ' '.join(args))
    proc = subprocess.Popen(args, cwd=G.PLUGIN_PATH, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    (stdout, stderr) = proc.communicate()
    if stderr:
        raise IOError(stderr)

    if proc.poll() != 0:
        raise IOError(stdout)
    r = APIResponse(stdout)
    return r

def hit_url(url, data=None):
    if data:
        data = json.dumps(data).encode('utf-8')
    r = Request(url, data=data)
    r.add_header('Authorization', 'Basic %s' % get_basic_auth())
    r.add_header('Accept', 'application/json')
    r.add_header('Content-type', 'application/json')
    r.add_header('User-Agent', 'Floobits Plugin %s %s %s py-%s.%s' % (
        editor.name(),
        G.__PLUGIN_VERSION__,
        editor.platform(),
        sys.version_info[0],
        sys.version_info[1]
    ))
    return urlopen(r, timeout=5)

def api_request(url, data=None):
    if ssl is False:
        return proxy_api_request(url, data)
    try:
        r = hit_url(url, data)
    except HTTPError as e:
        r = e
    return APIResponse(r)

def create_workspace(post_data):
    url = 'https://%s/api/workspace/' % G.DEFAULT_HOST
    return api_request(url, post_data)

def get_workspace_by_url(url):
    result = utils.parse_url(url)
    api_url = 'https://%s/api/workspace/%s/%s/' % (result['host'], result['owner'], result['workspace'])
    return api_request(api_url)

def get_workspace(owner, workspace):
    api_url = 'https://%s/api/workspace/%s/%s/' % (G.DEFAULT_HOST, owner, workspace)
    return api_request(api_url)

def get_workspaces():
    api_url = 'https://%s/api/workspace/can/view/' % (G.DEFAULT_HOST)
    return api_request(api_url)

def get_orgs():
    api_url = 'https://%s/api/orgs/' % (G.DEFAULT_HOST)
    return api_request(api_url)

def get_orgs_can_admin():
    api_url = 'https://%s/api/orgs/can/admin/' % (G.DEFAULT_HOST)
    return api_request(api_url)

def send_error(data):
    try:
        api_url = 'https://%s/api/error/' % (G.DEFAULT_HOST)
        return api_request(api_url, data)
    except Exception as e:
        print(e)
<commit_msg>Apparently our API isn't authing against API keys right now? wtf?<commit_after>import sys
import base64
import json
import subprocess

try:
    import ssl
except ImportError:
    ssl = False

try:
    str_instances = (str, basestring)
except Exception:
    str_instances = (str, )

try:
    import urllib
    from urllib.request import Request, urlopen
    HTTPError = urllib.error.HTTPError
    URLError = urllib.error.URLError
except (AttributeError, ImportError, ValueError):
    import urllib2
    from urllib2 import Request, urlopen
    HTTPError = urllib2.HTTPError
    URLError = urllib2.URLError

try:
    from .. import editor
    from . import msg, shared as G, utils
except ImportError:
    import editor
    import msg
    import shared as G
    import utils

def get_basic_auth():
    basic_auth = ('%s:%s' % (G.USERNAME, G.SECRET)).encode('utf-8')
    basic_auth = base64.encodestring(basic_auth)
    return basic_auth.decode('ascii').replace('\n', '')

class APIResponse():
    def __init__(self, r):
        if isinstance(r, bytes):
            r = r.decode('utf-8')
        if isinstance(r, str_instances):
            lines = r.split('\n')
            self.code = int(lines[0])
            self.body = json.loads('\n'.join(lines[1:]))
        else:
            self.code = r.code
            self.body = json.loads(r.read())

def proxy_api_request(url, data=None):
    args = ['python', '-m', 'floo.proxy', '--url', url]
    if data:
        args += ["--data", json.dumps(data)]
    msg.debug('Running %s' % ' '.join(args))
    proc = subprocess.Popen(args, cwd=G.PLUGIN_PATH, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    (stdout, stderr) = proc.communicate()
    if stderr:
        raise IOError(stderr)

    if proc.poll() != 0:
        raise IOError(stdout)
    r = APIResponse(stdout)
    return r

def hit_url(url, data=None):
    if data:
        data = json.dumps(data).encode('utf-8')
    r = Request(url, data=data)
    r.add_header('Authorization', 'Basic %s' % get_basic_auth())
    r.add_header('Accept', 'application/json')
    r.add_header('Content-type', 'application/json')
    r.add_header('User-Agent', 'Floobits Plugin %s %s %s py-%s.%s' % (
        editor.name(),
        G.__PLUGIN_VERSION__,
        editor.platform(),
        sys.version_info[0],
        sys.version_info[1]
    ))
    return urlopen(r, timeout=5)

def api_request(url, data=None):
    if ssl is False:
        return proxy_api_request(url, data)
    try:
        r = hit_url(url, data)
    except HTTPError as e:
        r = e
    return APIResponse(r)

def create_workspace(post_data):
    url = 'https://%s/api/workspace/' % G.DEFAULT_HOST
    return api_request(url, post_data)

def get_workspace_by_url(url):
    result = utils.parse_url(url)
    api_url = 'https://%s/api/workspace/%s/%s/' % (result['host'], result['owner'], result['workspace'])
    return api_request(api_url)

def get_workspace(owner, workspace):
    api_url = 'https://%s/api/workspace/%s/%s/' % (G.DEFAULT_HOST, owner, workspace)
    return api_request(api_url)

def get_workspaces():
    api_url = 'https://%s/api/workspace/can/view/' % (G.DEFAULT_HOST)
    return api_request(api_url)

def get_orgs():
    api_url = 'https://%s/api/orgs/' % (G.DEFAULT_HOST)
    return api_request(api_url)

def get_orgs_can_admin():
    api_url = 'https://%s/api/orgs/can/admin/' % (G.DEFAULT_HOST)
    return api_request(api_url)

def send_error(data):
    try:
        api_url = 'https://%s/api/error/' % (G.DEFAULT_HOST)
        return api_request(api_url, data)
    except Exception as e:
        print(e)
<|endoftext|>


<commit_before>import os
import sys
import json

import datetime
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import subprocess

import requests
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['GET'])
def verify():
    # when the endpoint is registered as a webhook, it must echo back
    # the 'hub.challenge' value it receives in the query arguments
    if request.args.get("hub.mode") == "subscribe" and request.args.get("hub.challenge"):
        if not request.args.get("hub.verify_token") == os.environ["VERIFY_TOKEN"]:
            return "Verification token mismatch", 403
        return request.args["hub.challenge"], 200

    return "Hello world", 200

@app.route('/', methods=['POST'])
def webhook():

    # endpoint for processing incoming messaging events

    data = request.get_json()
    log(data)  # you may not want to log every incoming message in production, but it's good for testing

    if data["object"] == "page":

        for entry in data["entry"]:
            for messaging_event in entry["messaging"]:

                if messaging_event.get("message"):  # someone sent us a message

                    sender_id = messaging_event["sender"]["id"]        # the facebook ID of the person sending you the message
                    recipient_id = messaging_event["recipient"]["id"]  # the recipient's ID, which should be your page's facebook ID
                    message_text = messaging_event["message"]["text"]  # the message's text

                    message = construct_schedule()
                    send_message(sender_id, "roger that!")
                    send_message(sender_id, message)

                if messaging_event.get("delivery"):  # delivery confirmation
                    pass

                if messaging_event.get("optin"):  # optin confirmation
                    pass

                if messaging_event.get("postback"):  # user clicked/tapped "postback" button in earlier message

                    sender_id = messaging_event["sender"]["id"]        # the facebook ID of the person sending you the message
                    message_text = messaging_event["postback"]["payload"]
                    message_text = message_text.lower()

                    if (message_text == "get started"):
                        send_message(sender_id, "Further instructions coming...")

                    if (message_text == "menu payload"):
                        send_message(sender_id, "Working...")

                    if (message_text == "todays prayer times"):
                        subproces.call("./quickreply.sh")

    return "ok", 200

def construct_schedule():

    # get date details
    #day = datetime.datetime.day()
    #month = datetime.datetime.month()

    now = datetime.datetime.now()
    day = now.day
    month = now.month
    monthCode = ""

    if month == 6:
        monthCode = "Jun-17"
    elif month == 7:
        monthCode = "Jul-17"
    elif month == 8:
        monthCode = "Aug-17"
    else:
        monthCode = "Sep-17"

    # sort out cell range
    dayCell = str(day + 2)
    cellRange = 'B' + dayCell + ":" + "M" + dayCell

    # read from excel sheet which has times in it
    # authentication
    scope = ['https://spreadsheets.google.com/feeds']
    credentials = ServiceAccountCredentials.from_json_keyfile_name('London Prayer Times-dd7e33e594b6.json', scope)
    gc = gspread.authorize(credentials)

    # Open a worksheet from spreadsheet with one shot
    #wks = gc.open_by_url('https://drive.google.com/open?id=1atbX-oMa6qeS0VjScLUAzEaghCVyh8MkcJ9pk5r3sAk')
    wks = gc.open('elm-prayer-times')
    worksheet = wks.worksheet(monthCode)

    # Fetch a cell range
    values_list = worksheet.row_values(day + 2)
    times = values_list[1:13]

    # construct message
    intro = "Prayer Times for today are:" + "\n\n"

    fajr_begins = "Fajr Begins - " + times[0] + "\n"
    fajr_jamaah = "Fajr Jama'ah - " + times[1] + "\n"

    sunrise = "Sunrise - " + times[2] + "\n"

    zuhr_begins = "Zuhr Begins - " + times[3] + "\n"
    zuhr_jamaah = "Zuhr Jama'ah - " + times[4] + "\n"

    asr_mithl1 = "Asr Mithl 1 - " + times[5] + "\n"
    asr_mithl2 = "Asr Mithl 2 - " + times[6] + "\n"
    asr_jamaah = "Asr Jama'ah - " + times[7] + "\n"

    maghrib_begins = "Maghrib Begins - " + times[8] + "\n"
    maghrib_jamaah = "Maghrib Jama'ah - "  + times[9] + "\n"

    isha_begins = "Isha Begins - " + times[10] + "\n"
    isha_jamaah = "Isha Jama'ah - " + times[11]

    msg = intro + fajr_begins + fajr_jamaah + sunrise + zuhr_begins + zuhr_jamaah + asr_mithl1 + asr_mithl2 + asr_jamaah + maghrib_begins + maghrib_jamaah + isha_begins + isha_jamaah

    return(msg)

def send_message(recipient_id, message_text):

    log("sending message to {recipient}: {text}".format(recipient=recipient_id, text=message_text))

    params = {
        "access_token": os.environ["PAGE_ACCESS_TOKEN"]
    }
    headers = {
        "Content-Type": "application/json"
    }
    data = json.dumps({
        "recipient": {
            "id": recipient_id
        },
        "message": {
            "text": message_text
        }
    })
    r = requests.post("https://graph.facebook.com/v2.6/me/messages", params=params, headers=headers, data=data)
    if r.status_code != 200:
        log(r.status_code)
        log(r.text)

def log(message):  # simple wrapper for logging to stdout on heroku
    print str(message)
    sys.stdout.flush()

if __name__ == '__main__':
    app.run(debug=True)
<commit_msg>quick reply buttons<commit_after>import os
import sys
import json

import datetime
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import subprocess

import requests
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['GET'])
def verify():
    # when the endpoint is registered as a webhook, it must echo back
    # the 'hub.challenge' value it receives in the query arguments
    if request.args.get("hub.mode") == "subscribe" and request.args.get("hub.challenge"):
        if not request.args.get("hub.verify_token") == os.environ["VERIFY_TOKEN"]:
            return "Verification token mismatch", 403
        return request.args["hub.challenge"], 200

    return "Hello world", 200

@app.route('/', methods=['POST'])
def webhook():

    # endpoint for processing incoming messaging events

    data = request.get_json()
    log(data)  # you may not want to log every incoming message in production, but it's good for testing

    if data["object"] == "page":

        for entry in data["entry"]:
            for messaging_event in entry["messaging"]:

                if messaging_event.get("message"):  # someone sent us a message

                    sender_id = messaging_event["sender"]["id"]        # the facebook ID of the person sending you the message
                    recipient_id = messaging_event["recipient"]["id"]  # the recipient's ID, which should be your page's facebook ID
                    message_text = messaging_event["message"]["text"]  # the message's text

                    message = construct_schedule()
                    send_message(sender_id, "roger that!")
                    send_message(sender_id, message)

                if messaging_event.get("delivery"):  # delivery confirmation
                    pass

                if messaging_event.get("optin"):  # optin confirmation
                    pass

                if messaging_event.get("postback"):  # user clicked/tapped "postback" button in earlier message

                    sender_id = messaging_event["sender"]["id"]        # the facebook ID of the person sending you the message
                    message_text = messaging_event["postback"]["payload"]
                    message_text = message_text.lower()

                    if (message_text == "get started"):
                        send_message(sender_id, "Further instructions coming...")

                    if (message_text == "menu payload"):
                        subproces.call("./quickreply.sh")
                        #send_message(sender_id, "Working...")

                    if (message_text == "todays prayer times"):
                        #subproces.call("./quickreply.sh")
                        pass

    return "ok", 200

def construct_schedule():

    # get date details
    #day = datetime.datetime.day()
    #month = datetime.datetime.month()

    now = datetime.datetime.now()
    day = now.day
    month = now.month
    monthCode = ""

    if month == 6:
        monthCode = "Jun-17"
    elif month == 7:
        monthCode = "Jul-17"
    elif month == 8:
        monthCode = "Aug-17"
    else:
        monthCode = "Sep-17"

    # sort out cell range
    dayCell = str(day + 2)
    cellRange = 'B' + dayCell + ":" + "M" + dayCell

    # read from excel sheet which has times in it
    # authentication
    scope = ['https://spreadsheets.google.com/feeds']
    credentials = ServiceAccountCredentials.from_json_keyfile_name('London Prayer Times-dd7e33e594b6.json', scope)
    gc = gspread.authorize(credentials)

    # Open a worksheet from spreadsheet with one shot
    #wks = gc.open_by_url('https://drive.google.com/open?id=1atbX-oMa6qeS0VjScLUAzEaghCVyh8MkcJ9pk5r3sAk')
    wks = gc.open('elm-prayer-times')
    worksheet = wks.worksheet(monthCode)

    # Fetch a cell range
    values_list = worksheet.row_values(day + 2)
    times = values_list[1:13]

    # construct message
    intro = "Prayer Times for today are:" + "\n\n"

    fajr_begins = "Fajr Begins - " + times[0] + "\n"
    fajr_jamaah = "Fajr Jama'ah - " + times[1] + "\n"

    sunrise = "Sunrise - " + times[2] + "\n"

    zuhr_begins = "Zuhr Begins - " + times[3] + "\n"
    zuhr_jamaah = "Zuhr Jama'ah - " + times[4] + "\n"

    asr_mithl1 = "Asr Mithl 1 - " + times[5] + "\n"
    asr_mithl2 = "Asr Mithl 2 - " + times[6] + "\n"
    asr_jamaah = "Asr Jama'ah - " + times[7] + "\n"

    maghrib_begins = "Maghrib Begins - " + times[8] + "\n"
    maghrib_jamaah = "Maghrib Jama'ah - "  + times[9] + "\n"

    isha_begins = "Isha Begins - " + times[10] + "\n"
    isha_jamaah = "Isha Jama'ah - " + times[11]

    msg = intro + fajr_begins + fajr_jamaah + sunrise + zuhr_begins + zuhr_jamaah + asr_mithl1 + asr_mithl2 + asr_jamaah + maghrib_begins + maghrib_jamaah + isha_begins + isha_jamaah

    return(msg)

def send_message(recipient_id, message_text):

    log("sending message to {recipient}: {text}".format(recipient=recipient_id, text=message_text))

    params = {
        "access_token": os.environ["PAGE_ACCESS_TOKEN"]
    }
    headers = {
        "Content-Type": "application/json"
    }
    data = json.dumps({
        "recipient": {
            "id": recipient_id
        },
        "message": {
            "text": message_text
        }
    })
    r = requests.post("https://graph.facebook.com/v2.6/me/messages", params=params, headers=headers, data=data)
    if r.status_code != 200:
        log(r.status_code)
        log(r.text)

def log(message):  # simple wrapper for logging to stdout on heroku
    print str(message)
    sys.stdout.flush()

if __name__ == '__main__':
    app.run(debug=True)
<|endoftext|>


<commit_before>import pylibmc
import requests
from requests.auth import HTTPBasicAuth
from flask import Flask, request, render_template, jsonify

import config

app = Flask(__name__)
cache = pylibmc.Client(config.MEMCACHE['SERVERS'], binary=True,
                       behaviors=config.MEMCACHE['OPTIONS'])

@app.route("/")
def index():
    return render_template('index.html')

@app.route("/search")
def search():
    search_term = request.args.get('q')
    response = _search_for_term(search_term)
    return jsonify(response)

def _search_for_term(search_term):
    cache_key = 's-{}'.format(search_term)
    response = cache.get(cache_key)
    if not response:
        response = _make_request(search_term)
        cache.set(cache_key, response, 3600)
    return response

def _make_request(search_term):
    basic_auth = HTTPBasicAuth(config.GITHUB_TOKEN, 'x-oauth-basic')
    url = ('https://api.github.com/search/repositories?q="cookiecutter%20'
           'template"+{term}+in:description&sort=stars&order=desc')

    github_response = requests.get(url.format(term=search_term),
                                   auth=basic_auth)

    if github_response.status_code == 401:
        response = {
            'error': "We're over quota. Please come back after a few minutes :)"
        }
    elif github_response.status_code == 200:
        response = _transform_response(github_response)
    else:
        response = {
            'error': 'An unknown error ocurred: {}'.format(github_response.status_code)
        }

    return response

def _transform_response(github_response):
    response = []
    items = github_response.json().get('items', [])
    for item in items:
        response.append({
            'name': item['full_name'],
            'description': item['description'],
            'url': item['html_url'],
        })
    return {'results': response}

if __name__ == "__main__":
    app.debug = config.DEBUG
    app.run()
<commit_msg>Cache expire after 5 min<commit_after>import pylibmc
import requests
from requests.auth import HTTPBasicAuth
from flask import Flask, request, render_template, jsonify

import config

app = Flask(__name__)
cache = pylibmc.Client(config.MEMCACHE['SERVERS'], binary=True,
                       behaviors=config.MEMCACHE['OPTIONS'])

@app.route("/")
def index():
    return render_template('index.html')

@app.route("/search")
def search():
    search_term = request.args.get('q')
    response = _search_for_term(search_term)
    return jsonify(response)

def _search_for_term(search_term):
    cache_key = 's-{}'.format(search_term)
    response = cache.get(cache_key)
    if not response:
        response = _make_request(search_term)
        cache.set(cache_key, response, 300)
    return response

def _make_request(search_term):
    basic_auth = HTTPBasicAuth(config.GITHUB_TOKEN, 'x-oauth-basic')
    url = ('https://api.github.com/search/repositories?q="cookiecutter%20'
           'template"+{term}+in:description&sort=stars&order=desc')

    github_response = requests.get(url.format(term=search_term),
                                   auth=basic_auth)

    if github_response.status_code == 401:
        response = {
            'error': "We're over quota. Please come back after a few minutes :)"
        }
    elif github_response.status_code == 200:
        response = _transform_response(github_response)
    else:
        response = {
            'error': 'An unknown error ocurred: {}'.format(github_response.status_code)
        }

    return response

def _transform_response(github_response):
    response = []
    items = github_response.json().get('items', [])
    for item in items:
        response.append({
            'name': item['full_name'],
            'description': item['description'],
            'url': item['html_url'],
        })
    return {'results': response}

if __name__ == "__main__":
    app.debug = config.DEBUG
    app.run()
<|endoftext|>


<commit_before>import urllib
import os
import uuid
import requests
import stripe
import json
import flask
from flask import Flask, render_template, request, redirect, session, url_for, g
from flask.ext.sqlalchemy import SQLAlchemy
from flask_socketio import SocketIO
from flask_failsafe import failsafe
import calendar
import time
import jinja2
app = Flask(__name__)
app.jinja_loader = jinja2.FileSystemLoader(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates'))
socketio = SocketIO(app)
from threading import Thread
thread = None
from sqlalchemy.dialects.postgresql import JSONB, JSON
from sqlalchemy.sql.expression import cast, func
import psycopg2
import psycopg2.extras
import traceback
app.config.from_pyfile('_config.py')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
import re
import models
from sqlalchemy.sql import text

from flask_oauth import OAuth

oauth = OAuth()
from flask_cors import CORS, cross_origin

CORS(app)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})

stripe_keys = {
  'secret_key': app.config['STRIPE_SECRET_KEY'],
  'publishable_key': app.config['STRIPE_PUBLISHABLE_KEY']
}

stripe.api_key = stripe_keys['secret_key']

REDIRECT_URI = 'https://devapi.wayeasycorp.com/oauth/google'

def get_user(request):
    session_uuid = session.get('session_uuid') if session.get('session_uuid') else request.args.get('session_uuid')
    print session_uuid
    if not session_uuid:
        return None
    q = db.session.query(models.Session).filter(models.Session.secret_uuid == session_uuid)
    if q.first():
        if q.first().active:
            return db.session.query(models.User).filter(models.User.user_uuid == q.first().user_uuid).first()
        else:
            return None
    else:
        return None

@app.route('/api/is_logged_in', strict_slashes=False)
def is_logged_in():
    return flask.jsonify(is_logged_in=bool(get_user(request)))

@app.route('/api/set_session', strict_slashes=False)
def set_session():
    if session.get('oauth_id'):
        session['oauth_id'] = session['oauth_id'].strip()
    access_token = session.get('access_token')
    session_uuid = session.get('session_uuid')
    if access_token is None:
        return redirect(url_for('login'))

    access_token = access_token[0]
    from urllib2 import Request, urlopen, URLError

    headers = {'Authorization': 'OAuth '+access_token}
    req = Request('https://www.googleapis.com/oauth2/v1/userinfo',
                  None, headers)
    try:
        res = urlopen(req)
    except URLError, e:
        if e.code == 401:
            # Unauthorized - bad token
            session.pop('access_token', None)
            return redirect(url_for('login'))
        return res.read()
    oauth_data = json.loads(res.read())
    session['oauth_id'] = oauth_data['id']

    if not db.session.query(models.Oauth).filter(models.Oauth.oauth_id == session.get('oauth_id')).count():
        #Create the db user
        user_data = oauth_data
        user_data['created_at'] = calendar.timegm(time.gmtime())*1000
        new_user = models.User(
            data = user_data
        )
        db.session.add(new_user)
        db.session.commit()
        new_oauth = models.Oauth(
            user_uuid = new_user.user_uuid,
            provider = 'google',
            access_token = access_token,
            oauth_id = oauth_data['id'],
            data = oauth_data
        )
        db.session.add(new_oauth)
        db.session.commit()
    oauth_in_db = db.session.query(models.Oauth).filter(models.Oauth.oauth_id == session.get('oauth_id')).first()
    oauth_in_db.data = oauth_data
    oauth_in_db.access_token = access_token
    db.session.commit()
    user_in_db = db.session.query(models.User).filter(models.User.user_uuid == oauth_in_db.user_uuid).first()
    if  user_in_db.data:
        d = oauth_data
        user_in_db.data.update(d)
    else:
        d = oauth_data
        user_in_db.data = d
    db.session.commit()
    user_uuid = db.session.query(models.Oauth).filter(models.Oauth.oauth_id == session.get('oauth_id')).first().user_uuid
    q = db.session.query(models.Session).filter(models.Session.secret_uuid == session.get('session_uuid'))
    if session_uuid is None:
        new_session = models.Session(
            user_uuid = user_uuid,
            active = True
        )
        db.session.add(new_session)
        db.session.commit()
        session['session_uuid'] = new_session.secret_uuid
        session_in_db = q.first()
    else:
        session_in_db = q.first()
        session_in_db.user_uuid = user_uuid
        session_in_db.active = True
        db.session.commit()
        if session_in_db:
            if session_in_db.active == False:
                redirect(url_for('login'))
        else:
            redirect(url_for('login'))
    session['oauth_id'] = oauth_data['id']
    next = request.args.get('next', '/')
    if next.startswith('https://'):
        import urllib
        next = next + '?' + urllib.urlencode({'access_token': access_token, 'session_uuid': session_uuid})
    return redirect(next)

google = oauth.remote_app('google',
          base_url='https://www.google.com/accounts/',
          authorize_url='https://accounts.google.com/o/oauth2/auth',
          request_token_url=None,
          request_token_params={'prompt': 'select_account', 'scope': 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email',
                                'response_type': 'code', 'state': ''},
          access_token_url='https://accounts.google.com/o/oauth2/token',
          access_token_method='POST',
          access_token_params={'grant_type': 'authorization_code'},
          consumer_key=app.config['GOOGLE_CLIENT_ID'],
          consumer_secret=app.config['GOOGLE_CLIENT_SECRET'])

@app.route('/login', strict_slashes=False)
def login():
    next=request.args.get('next') or request.referrer or ''
    callback=url_for('authorized', _external=True, _scheme='https')
    google.request_token_params.update({'state': next})
    return google.authorize(callback=callback)

@app.route('/oauth/google', strict_slashes=False)
@google.authorized_handler
def authorized(resp):
    access_token = resp['access_token']
    session['access_token'] = access_token, ''
    next=request.args.get('state', '')
    print 'next', next
    print 'next', next, url_for('set_session', next=next)

    return redirect(url_for('set_session', next=next))

@google.tokengetter
def get_access_token():
    return session.get('access_token')

@app.route('/logout')
def logout():
    try:
        q = db.session.query(models.Session).filter(models.Session.secret_uuid == session.get('session_uuid'))
        session_in_db = q.first()
        session_in_db.active = False
        db.session.commit()
    except AttributeError:
        pass
    return redirect('/')

import signal
import time

class Timeout():
    """Timeout class using ALARM signal."""
    class Timeout(Exception):
        pass

    def __init__(self, sec):
        self.sec = sec

    def __enter__(self):
        signal.signal(signal.SIGALRM, self.raise_timeout)
        signal.alarm(self.sec)

    def __exit__(self, *args):
        signal.alarm(0)    # disable alarm

    def raise_timeout(self, *args):
        raise Timeout.Timeout()

@app.route('/api/query_public_data')
def query_public_data():
    try:
        conn = psycopg2.connect("dbname='megatransparency' user='public_data_query' host='localhost' password='%s' options='-c statement_timeout=3s'" % (app.config['PUBLIC_DATA_QUERY_PASSWORD']))
    except:
        return flask.jsonify(success=False, error="can't connect to database as public query user")
    try:
        cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
        sql = request.args.get('sql', request.form.get('sql'))
        if not sql:
            return flask.jsonify(success=False, error='sql query is missing')
        cur.execute(sql)
        data_to_return = [dict([(row[0], str(row[1])) for row in row]) for row in cur.fetchall()]
        columns = [{'name': row[0], 'type': row[1]} for row in cur.description]
        return flask.jsonify(success=True, data=data_to_return, sql=sql, columns=columns)
        cur.close()
        conn.close()
    except Exception, e:
        error = traceback.format_exc()
        if 'canceling statement due to statement timeout' in error:
            error = "query didn't finish within the required three seconds"
        return flask.jsonify(success=False, error=error)

@app.before_request
def log_page_view():
    if not ('update_page_view' in request.path or 'set_session' in request.path or 'oauth' in request.path or 'ico' in request.path or 'static' in request.path):

        session_uuid = session.get('session_uuid')
        if session_uuid: # validate the session uuid
            if not db.session.query(models.Session).filter(models.Session.secret_uuid == session.get('session_uuid')):
                session_uuid = None
        if not session_uuid:
            new_session = models.Session(
                active = False
            )
            db.session.add(new_session)
            db.session.commit()
            session['session_uuid'] = new_session.secret_uuid
        ip_address = request.headers.get('X-Forwarded-For', request.remote_addr)
        if ',' in ip_address:
            ip_address = ip_address.split(',')[0]
        data = {"ip_address": ip_address}
        session_data = db.session.query(models.Session).filter(models.Session.secret_uuid == session.get('session_uuid')).first()
        data['session_public_uuid'] = str(session_data.public_uuid)
        data['is_logged_in'] = session_data.active
        data['url'] = request.url
        if '?' in data['url']:
            data['url'] = data['url'][:request.url.index('?')]
        data['time_arrived'] = calendar.timegm(time.gmtime())*1000
        data['referrer'] = request.referrer
        if data['referrer'].startswith('https://megatransparency.com/'):
            if '?' in data['referrer']:
                data['referrer'] = data['referrer'][:request.url.index('?')]
        if data['referrer'].startswith('https://accounts.google.com/AccountChooser'):
            data['referrer'] = 'https://accounts.google.com/AccountChooser'
        data['post_data'] = dict(request.form)
        data['get_data'] = dict(request.args)
        if 'session_uuid' in data['get_data']:
            del data['get_data']['session_uuid']
        if 'session_uuid' in data['get_data']:
            del data['get_data']['access_token']
        print 'SESSION DATA', session_data.user_uuid
        if session_data.user_uuid:
            data['user_uuid'] = str(session_data.user_uuid)
            db.session.query(models.PageViews).filter(models.PageViews.data['session_public_uuid'].astext == str(session_data.public_uuid)).update({'data': cast(cast(models.PageViews.data, JSONB)
                           .concat(func.jsonb_build_object('user_uuid', str(session_data.user_uuid))), JSON)}, synchronize_session="fetch")
        user_agent = request.user_agent
        for key in ['platform', 'browser', 'version', 'language', 'string']:
            data['user_agent_'+key] = getattr(user_agent, key)
        new_page_view = models.PageViews(
            data = data
        )
        db.session.add(new_page_view)
        db.session.commit()
        print db.session.query(models.PageViews).filter(models.PageViews.uuid == new_page_view.uuid).first().data
        g.new_page_view_uuid = new_page_view.uuid

@app.errorhandler(404) # We always return index.html if route not found because we use Vue.JS routing
def page_not_found(e):
    return render_template('index.html', page_view_uuid=g.new_page_view_uuid)

@app.route('/api/update_page_view', strict_slashes=False, methods=['POST'])
def update_page_view():
    time_left = calendar.timegm(time.gmtime())*1000
    uuid = request.form['uuid']
    data = json.loads(request.form['data'])
    cleaned_data = {"time_left": time_left}
    for key in data:
        if key in ['mouse_locations', 'scrolls', 'screen_width', 'screen_height']:
            cleaned_data[key] = data[key]
    page_view_in_db = db.session.query(models.PageViews).filter(models.PageViews.uuid == uuid).first()
    print 'page view in db', page_view_in_db
    if page_view_in_db:
        # for whatever reason modifying page_view_in_db.data then doing db.session.commit() didn't update the page_view row
        page_view_in_db.data.update(cleaned_data)
        db.session.query(models.PageViews).filter(models.PageViews.uuid == uuid).update(dict(data=page_view_in_db.data))
        try:
            db.session.commit()
        except Exception, e:
            traceback.print_exc(file=sys.stdout)
            db.session.rollback()
            db.session.flush()
    return flask.jsonify(success=True)

@app.route('/api/server_time', strict_slashes=False)
def server_time():
    return flask.jsonify(datetime=calendar.timegm(time.gmtime())*1000)

@app.route('/charge', methods=['POST'], strict_slashes=False)
def charge():
    # Amount in cents
    amount = 500

    customer = stripe.Customer.create(
        email='customer@example.com',
        source=request.form['stripeToken']
    )

    charge = stripe.Charge.create(
        customer=customer.id,
        amount=amount,
        currency='usd',
        description='Flask Charge'
    )

    return render_template('charge.html', amount=amount)

@failsafe
def create_app():
    return app

import eventlet
eventlet.monkey_patch()
if __name__ == '__main__':
    socketio.run(create_app(), debug=True, port=app.config['PORT'])
<commit_msg>make all a string until can be more percise later<commit_after>import urllib
import os
import uuid
import requests
import stripe
import json
import flask
from flask import Flask, render_template, request, redirect, session, url_for, g
from flask.ext.sqlalchemy import SQLAlchemy
from flask_socketio import SocketIO
from flask_failsafe import failsafe
import calendar
import time
import jinja2
app = Flask(__name__)
app.jinja_loader = jinja2.FileSystemLoader(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates'))
socketio = SocketIO(app)
from threading import Thread
thread = None
from sqlalchemy.dialects.postgresql import JSONB, JSON
from sqlalchemy.sql.expression import cast, func
import psycopg2
import psycopg2.extras
import traceback
app.config.from_pyfile('_config.py')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
import re
import models
from sqlalchemy.sql import text

from flask_oauth import OAuth

oauth = OAuth()
from flask_cors import CORS, cross_origin

CORS(app)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})

stripe_keys = {
  'secret_key': app.config['STRIPE_SECRET_KEY'],
  'publishable_key': app.config['STRIPE_PUBLISHABLE_KEY']
}

stripe.api_key = stripe_keys['secret_key']

REDIRECT_URI = 'https://devapi.wayeasycorp.com/oauth/google'

def get_user(request):
    session_uuid = session.get('session_uuid') if session.get('session_uuid') else request.args.get('session_uuid')
    print session_uuid
    if not session_uuid:
        return None
    q = db.session.query(models.Session).filter(models.Session.secret_uuid == session_uuid)
    if q.first():
        if q.first().active:
            return db.session.query(models.User).filter(models.User.user_uuid == q.first().user_uuid).first()
        else:
            return None
    else:
        return None

@app.route('/api/is_logged_in', strict_slashes=False)
def is_logged_in():
    return flask.jsonify(is_logged_in=bool(get_user(request)))

@app.route('/api/set_session', strict_slashes=False)
def set_session():
    if session.get('oauth_id'):
        session['oauth_id'] = session['oauth_id'].strip()
    access_token = session.get('access_token')
    session_uuid = session.get('session_uuid')
    if access_token is None:
        return redirect(url_for('login'))

    access_token = access_token[0]
    from urllib2 import Request, urlopen, URLError

    headers = {'Authorization': 'OAuth '+access_token}
    req = Request('https://www.googleapis.com/oauth2/v1/userinfo',
                  None, headers)
    try:
        res = urlopen(req)
    except URLError, e:
        if e.code == 401:
            # Unauthorized - bad token
            session.pop('access_token', None)
            return redirect(url_for('login'))
        return res.read()
    oauth_data = json.loads(res.read())
    session['oauth_id'] = oauth_data['id']

    if not db.session.query(models.Oauth).filter(models.Oauth.oauth_id == session.get('oauth_id')).count():
        #Create the db user
        user_data = oauth_data
        user_data['created_at'] = calendar.timegm(time.gmtime())*1000
        new_user = models.User(
            data = user_data
        )
        db.session.add(new_user)
        db.session.commit()
        new_oauth = models.Oauth(
            user_uuid = new_user.user_uuid,
            provider = 'google',
            access_token = access_token,
            oauth_id = oauth_data['id'],
            data = oauth_data
        )
        db.session.add(new_oauth)
        db.session.commit()
    oauth_in_db = db.session.query(models.Oauth).filter(models.Oauth.oauth_id == session.get('oauth_id')).first()
    oauth_in_db.data = oauth_data
    oauth_in_db.access_token = access_token
    db.session.commit()
    user_in_db = db.session.query(models.User).filter(models.User.user_uuid == oauth_in_db.user_uuid).first()
    if  user_in_db.data:
        d = oauth_data
        user_in_db.data.update(d)
    else:
        d = oauth_data
        user_in_db.data = d
    db.session.commit()
    user_uuid = db.session.query(models.Oauth).filter(models.Oauth.oauth_id == session.get('oauth_id')).first().user_uuid
    q = db.session.query(models.Session).filter(models.Session.secret_uuid == session.get('session_uuid'))
    if session_uuid is None:
        new_session = models.Session(
            user_uuid = user_uuid,
            active = True
        )
        db.session.add(new_session)
        db.session.commit()
        session['session_uuid'] = new_session.secret_uuid
        session_in_db = q.first()
    else:
        session_in_db = q.first()
        session_in_db.user_uuid = user_uuid
        session_in_db.active = True
        db.session.commit()
        if session_in_db:
            if session_in_db.active == False:
                redirect(url_for('login'))
        else:
            redirect(url_for('login'))
    session['oauth_id'] = oauth_data['id']
    next = request.args.get('next', '/')
    if next.startswith('https://'):
        import urllib
        next = next + '?' + urllib.urlencode({'access_token': access_token, 'session_uuid': session_uuid})
    return redirect(next)

google = oauth.remote_app('google',
          base_url='https://www.google.com/accounts/',
          authorize_url='https://accounts.google.com/o/oauth2/auth',
          request_token_url=None,
          request_token_params={'prompt': 'select_account', 'scope': 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email',
                                'response_type': 'code', 'state': ''},
          access_token_url='https://accounts.google.com/o/oauth2/token',
          access_token_method='POST',
          access_token_params={'grant_type': 'authorization_code'},
          consumer_key=app.config['GOOGLE_CLIENT_ID'],
          consumer_secret=app.config['GOOGLE_CLIENT_SECRET'])

@app.route('/login', strict_slashes=False)
def login():
    next=request.args.get('next') or request.referrer or ''
    callback=url_for('authorized', _external=True, _scheme='https')
    google.request_token_params.update({'state': next})
    return google.authorize(callback=callback)

@app.route('/oauth/google', strict_slashes=False)
@google.authorized_handler
def authorized(resp):
    access_token = resp['access_token']
    session['access_token'] = access_token, ''
    next=request.args.get('state', '')
    print 'next', next
    print 'next', next, url_for('set_session', next=next)

    return redirect(url_for('set_session', next=next))

@google.tokengetter
def get_access_token():
    return session.get('access_token')

@app.route('/logout')
def logout():
    try:
        q = db.session.query(models.Session).filter(models.Session.secret_uuid == session.get('session_uuid'))
        session_in_db = q.first()
        session_in_db.active = False
        db.session.commit()
    except AttributeError:
        pass
    return redirect('/')

import signal
import time

class Timeout():
    """Timeout class using ALARM signal."""
    class Timeout(Exception):
        pass

    def __init__(self, sec):
        self.sec = sec

    def __enter__(self):
        signal.signal(signal.SIGALRM, self.raise_timeout)
        signal.alarm(self.sec)

    def __exit__(self, *args):
        signal.alarm(0)    # disable alarm

    def raise_timeout(self, *args):
        raise Timeout.Timeout()

@app.route('/api/query_public_data')
def query_public_data():
    try:
        conn = psycopg2.connect("dbname='megatransparency' user='public_data_query' host='localhost' password='%s' options='-c statement_timeout=3s'" % (app.config['PUBLIC_DATA_QUERY_PASSWORD']))
    except:
        return flask.jsonify(success=False, error="can't connect to database as public query user")
    try:
        cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
        sql = request.args.get('sql', request.form.get('sql'))
        if not sql:
            return flask.jsonify(success=False, error='sql query is missing')
        cur.execute(sql)
        data_to_return = [dict([(col[0], str(col[1])) for col in row]) for row in cur.fetchall()]
        columns = [{'name': row[0], 'type': row[1]} for row in cur.description]
        return flask.jsonify(success=True, data=data_to_return, sql=sql, columns=columns)
        cur.close()
        conn.close()
    except Exception, e:
        error = traceback.format_exc()
        if 'canceling statement due to statement timeout' in error:
            error = "query didn't finish within the required three seconds"
        return flask.jsonify(success=False, error=error)

@app.before_request
def log_page_view():
    if not ('update_page_view' in request.path or 'set_session' in request.path or 'oauth' in request.path or 'ico' in request.path or 'static' in request.path):

        session_uuid = session.get('session_uuid')
        if session_uuid: # validate the session uuid
            if not db.session.query(models.Session).filter(models.Session.secret_uuid == session.get('session_uuid')):
                session_uuid = None
        if not session_uuid:
            new_session = models.Session(
                active = False
            )
            db.session.add(new_session)
            db.session.commit()
            session['session_uuid'] = new_session.secret_uuid
        ip_address = request.headers.get('X-Forwarded-For', request.remote_addr)
        if ',' in ip_address:
            ip_address = ip_address.split(',')[0]
        data = {"ip_address": ip_address}
        session_data = db.session.query(models.Session).filter(models.Session.secret_uuid == session.get('session_uuid')).first()
        data['session_public_uuid'] = str(session_data.public_uuid)
        data['is_logged_in'] = session_data.active
        data['url'] = request.url
        if '?' in data['url']:
            data['url'] = data['url'][:request.url.index('?')]
        data['time_arrived'] = calendar.timegm(time.gmtime())*1000
        data['referrer'] = request.referrer
        if data['referrer'].startswith('https://megatransparency.com/'):
            if '?' in data['referrer']:
                data['referrer'] = data['referrer'][:request.url.index('?')]
        if data['referrer'].startswith('https://accounts.google.com/AccountChooser'):
            data['referrer'] = 'https://accounts.google.com/AccountChooser'
        data['post_data'] = dict(request.form)
        data['get_data'] = dict(request.args)
        if 'session_uuid' in data['get_data']:
            del data['get_data']['session_uuid']
        if 'session_uuid' in data['get_data']:
            del data['get_data']['access_token']
        print 'SESSION DATA', session_data.user_uuid
        if session_data.user_uuid:
            data['user_uuid'] = str(session_data.user_uuid)
            db.session.query(models.PageViews).filter(models.PageViews.data['session_public_uuid'].astext == str(session_data.public_uuid)).update({'data': cast(cast(models.PageViews.data, JSONB)
                           .concat(func.jsonb_build_object('user_uuid', str(session_data.user_uuid))), JSON)}, synchronize_session="fetch")
        user_agent = request.user_agent
        for key in ['platform', 'browser', 'version', 'language', 'string']:
            data['user_agent_'+key] = getattr(user_agent, key)
        new_page_view = models.PageViews(
            data = data
        )
        db.session.add(new_page_view)
        db.session.commit()
        print db.session.query(models.PageViews).filter(models.PageViews.uuid == new_page_view.uuid).first().data
        g.new_page_view_uuid = new_page_view.uuid

@app.errorhandler(404) # We always return index.html if route not found because we use Vue.JS routing
def page_not_found(e):
    return render_template('index.html', page_view_uuid=g.new_page_view_uuid)

@app.route('/api/update_page_view', strict_slashes=False, methods=['POST'])
def update_page_view():
    time_left = calendar.timegm(time.gmtime())*1000
    uuid = request.form['uuid']
    data = json.loads(request.form['data'])
    cleaned_data = {"time_left": time_left}
    for key in data:
        if key in ['mouse_locations', 'scrolls', 'screen_width', 'screen_height']:
            cleaned_data[key] = data[key]
    page_view_in_db = db.session.query(models.PageViews).filter(models.PageViews.uuid == uuid).first()
    print 'page view in db', page_view_in_db
    if page_view_in_db:
        # for whatever reason modifying page_view_in_db.data then doing db.session.commit() didn't update the page_view row
        page_view_in_db.data.update(cleaned_data)
        db.session.query(models.PageViews).filter(models.PageViews.uuid == uuid).update(dict(data=page_view_in_db.data))
        try:
            db.session.commit()
        except Exception, e:
            traceback.print_exc(file=sys.stdout)
            db.session.rollback()
            db.session.flush()
    return flask.jsonify(success=True)

@app.route('/api/server_time', strict_slashes=False)
def server_time():
    return flask.jsonify(datetime=calendar.timegm(time.gmtime())*1000)

@app.route('/charge', methods=['POST'], strict_slashes=False)
def charge():
    # Amount in cents
    amount = 500

    customer = stripe.Customer.create(
        email='customer@example.com',
        source=request.form['stripeToken']
    )

    charge = stripe.Charge.create(
        customer=customer.id,
        amount=amount,
        currency='usd',
        description='Flask Charge'
    )

    return render_template('charge.html', amount=amount)

@failsafe
def create_app():
    return app

import eventlet
eventlet.monkey_patch()
if __name__ == '__main__':
    socketio.run(create_app(), debug=True, port=app.config['PORT'])
<|endoftext|>


<commit_before>import chdb
from scripts.snippet_parser import CITATION_NEEDED_MARKER, REF_MARKER

import flask
import flask_sslify
from flask.ext.compress import Compress

import os
import contextlib
import collections
from datetime import datetime
import itertools

# the markup we're going to use for [citation-needed] and <ref> tags,
# pre-marked as safe for jinja.
SUPERSCRIPT_HTML = flask.Markup('[%s]')
CITATION_NEEDED_HTML = flask.Markup(SUPERSCRIPT_HTML % 'citation-needed')

@contextlib.contextmanager
def log_time(operation):
    before = datetime.now()
    yield
    after = datetime.now()
    ms = (after - before).microseconds / 1000.
    print '[citationhunt] %s took %.2f ms' % (operation, ms)

def get_db():
    db = getattr(flask.g, '_db', None)
    if db is None:
        db = flask.g._db = chdb.init_db()
    return db

Category = collections.namedtuple('Category', ['id', 'title'])
CATEGORY_ALL = Category('all', '')
def get_categories(include_default = True):
    categories = getattr(flask.g, '_categories', None)
    if categories is None:
        cursor = get_db().cursor()
        cursor.execute('''
            SELECT id, title FROM categories WHERE id != "unassigned"
            ORDER BY title;
        ''')
        categories = [CATEGORY_ALL] + [Category(*row) for row in cursor]
        flask.g._categories = categories
    return categories if include_default else categories[1:]

def get_category_by_id(catid, default = None):
    for c in get_categories():
        if catid == c.id:
            return c
    return default

def select_snippet_by_id(id):
    cursor = get_db().cursor()
    with log_time('select snippet by id'):
        cursor.execute('''
            SELECT snippets.snippet, snippets.section, articles.url,
            articles.title FROM snippets, articles WHERE snippets.id = %s AND
            snippets.article_id = articles.page_id;''', (id,))
        ret = cursor.fetchone()
    return ret

def select_random_id(cat = CATEGORY_ALL):
    cursor = get_db().cursor()

    ret = None
    if cat is not CATEGORY_ALL:
        with log_time('select with category'):
            cursor.execute('''
                SELECT snippets.id FROM snippets, articles_categories
                WHERE snippets.article_id = articles_categories.article_id AND
                articles_categories.category_id = %s ORDER BY RAND()
                LIMIT 1;''', (cat.id,))
            ret = cursor.fetchone()

    if ret is None:
        with log_time('select without category'):
            p = '1e-4' if not debug else '1e-2'
            cursor.execute('''
                SELECT id FROM snippets WHERE RAND() < ''' + p + '''LIMIT 1;''')
            ret = cursor.fetchone()

    assert ret and len(ret) == 1
    return ret[0]

def select_next_id(curr_id, cat = CATEGORY_ALL):
    cursor = get_db().cursor()

    if cat is not CATEGORY_ALL:
        with log_time('select next id'):
            cursor.execute('''
                SELECT next FROM snippets_links WHERE prev = %s
                AND cat_id = %s''', (curr_id, cat.id))
            ret = cursor.fetchone()
            if ret is None:
                # curr_id doesn't belong to the category
                return None
            assert ret and len(ret) == 1
            next_id = ret[0]
    else:
        next_id = curr_id
        for i in range(3): # super paranoid :)
            next_id = select_random_id(cat)
            if next_id != curr_id:
                break
    return next_id

app = flask.Flask(__name__)
Compress(app)
debug = 'DEBUG' in os.environ
if not debug:
    flask_sslify.SSLify(app, permanent = True)

@app.route('/')
def citation_hunt():
    id = flask.request.args.get('id')
    cat = flask.request.args.get('cat')

    if cat is not None:
        cat = get_category_by_id(cat)
        if cat is None:
            # invalid category, normalize to "all" and try again by id
            cat = CATEGORY_ALL
            return flask.redirect(
                flask.url_for('citation_hunt', id = id, cat = cat.id))
    else:
        cat = CATEGORY_ALL

    if id is not None:
        sinfo = select_snippet_by_id(id)
        if sinfo is None:
            # invalid id
            flask.abort(404)
        snippet, section, aurl, atitle = sinfo
        next_snippet_id = select_next_id(id, cat)
        if next_snippet_id is None:
            # the snippet doesn't belong to the category!
            assert cat is not CATEGORY_ALL
            return flask.redirect(
                flask.url_for('citation_hunt', id = id, cat = CATEGORY_ALL.id))
        return flask.render_template('index.html',
            snippet = snippet, section = section, article_url = aurl,
            article_title = atitle, current_category = cat,
            next_snippet_id = next_snippet_id,
            cn_marker = CITATION_NEEDED_MARKER, cn_html = CITATION_NEEDED_HTML,
            ref_marker = REF_MARKER, ref_html = SUPERSCRIPT_HTML)

    id = select_random_id(cat)
    return flask.redirect(
        flask.url_for('citation_hunt', id = id, cat = cat.id))

@app.route('/categories.html')
def categories_html():
    return flask.render_template('categories.html',
        categories = get_categories(include_default = False));

@app.after_request
def add_cache_header(response):
    if response.status_code == 200 and response.cache_control.max_age is None:
        response.cache_control.public = True
        response.cache_control.max_age = 3 * 24 * 60 * 60
    elif response.status_code == 302:
        response.cache_control.no_cache = True
        response.cache_control.no_store = True
    return response

@app.teardown_appcontext
def close_db(exception):
    db = getattr(flask.g, '_db', None)
    if db is not None:
        db.close()

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host = '0.0.0.0', port = port, debug = debug)
<commit_msg>s/citation-needed/citation needed/<commit_after>import chdb
from scripts.snippet_parser import CITATION_NEEDED_MARKER, REF_MARKER

import flask
import flask_sslify
from flask.ext.compress import Compress

import os
import contextlib
import collections
from datetime import datetime
import itertools

# the markup we're going to use for [citation needed] and <ref> tags,
# pre-marked as safe for jinja.
SUPERSCRIPT_HTML = flask.Markup('[%s]')
CITATION_NEEDED_HTML = flask.Markup(SUPERSCRIPT_HTML % 'citation needed')

@contextlib.contextmanager
def log_time(operation):
    before = datetime.now()
    yield
    after = datetime.now()
    ms = (after - before).microseconds / 1000.
    print '[citationhunt] %s took %.2f ms' % (operation, ms)

def get_db():
    db = getattr(flask.g, '_db', None)
    if db is None:
        db = flask.g._db = chdb.init_db()
    return db

Category = collections.namedtuple('Category', ['id', 'title'])
CATEGORY_ALL = Category('all', '')
def get_categories(include_default = True):
    categories = getattr(flask.g, '_categories', None)
    if categories is None:
        cursor = get_db().cursor()
        cursor.execute('''
            SELECT id, title FROM categories WHERE id != "unassigned"
            ORDER BY title;
        ''')
        categories = [CATEGORY_ALL] + [Category(*row) for row in cursor]
        flask.g._categories = categories
    return categories if include_default else categories[1:]

def get_category_by_id(catid, default = None):
    for c in get_categories():
        if catid == c.id:
            return c
    return default

def select_snippet_by_id(id):
    cursor = get_db().cursor()
    with log_time('select snippet by id'):
        cursor.execute('''
            SELECT snippets.snippet, snippets.section, articles.url,
            articles.title FROM snippets, articles WHERE snippets.id = %s AND
            snippets.article_id = articles.page_id;''', (id,))
        ret = cursor.fetchone()
    return ret

def select_random_id(cat = CATEGORY_ALL):
    cursor = get_db().cursor()

    ret = None
    if cat is not CATEGORY_ALL:
        with log_time('select with category'):
            cursor.execute('''
                SELECT snippets.id FROM snippets, articles_categories
                WHERE snippets.article_id = articles_categories.article_id AND
                articles_categories.category_id = %s ORDER BY RAND()
                LIMIT 1;''', (cat.id,))
            ret = cursor.fetchone()

    if ret is None:
        with log_time('select without category'):
            p = '1e-4' if not debug else '1e-2'
            cursor.execute('''
                SELECT id FROM snippets WHERE RAND() < ''' + p + '''LIMIT 1;''')
            ret = cursor.fetchone()

    assert ret and len(ret) == 1
    return ret[0]

def select_next_id(curr_id, cat = CATEGORY_ALL):
    cursor = get_db().cursor()

    if cat is not CATEGORY_ALL:
        with log_time('select next id'):
            cursor.execute('''
                SELECT next FROM snippets_links WHERE prev = %s
                AND cat_id = %s''', (curr_id, cat.id))
            ret = cursor.fetchone()
            if ret is None:
                # curr_id doesn't belong to the category
                return None
            assert ret and len(ret) == 1
            next_id = ret[0]
    else:
        next_id = curr_id
        for i in range(3): # super paranoid :)
            next_id = select_random_id(cat)
            if next_id != curr_id:
                break
    return next_id

app = flask.Flask(__name__)
Compress(app)
debug = 'DEBUG' in os.environ
if not debug:
    flask_sslify.SSLify(app, permanent = True)

@app.route('/')
def citation_hunt():
    id = flask.request.args.get('id')
    cat = flask.request.args.get('cat')

    if cat is not None:
        cat = get_category_by_id(cat)
        if cat is None:
            # invalid category, normalize to "all" and try again by id
            cat = CATEGORY_ALL
            return flask.redirect(
                flask.url_for('citation_hunt', id = id, cat = cat.id))
    else:
        cat = CATEGORY_ALL

    if id is not None:
        sinfo = select_snippet_by_id(id)
        if sinfo is None:
            # invalid id
            flask.abort(404)
        snippet, section, aurl, atitle = sinfo
        next_snippet_id = select_next_id(id, cat)
        if next_snippet_id is None:
            # the snippet doesn't belong to the category!
            assert cat is not CATEGORY_ALL
            return flask.redirect(
                flask.url_for('citation_hunt', id = id, cat = CATEGORY_ALL.id))
        return flask.render_template('index.html',
            snippet = snippet, section = section, article_url = aurl,
            article_title = atitle, current_category = cat,
            next_snippet_id = next_snippet_id,
            cn_marker = CITATION_NEEDED_MARKER, cn_html = CITATION_NEEDED_HTML,
            ref_marker = REF_MARKER, ref_html = SUPERSCRIPT_HTML)

    id = select_random_id(cat)
    return flask.redirect(
        flask.url_for('citation_hunt', id = id, cat = cat.id))

@app.route('/categories.html')
def categories_html():
    return flask.render_template('categories.html',
        categories = get_categories(include_default = False));

@app.after_request
def add_cache_header(response):
    if response.status_code == 200 and response.cache_control.max_age is None:
        response.cache_control.public = True
        response.cache_control.max_age = 3 * 24 * 60 * 60
    elif response.status_code == 302:
        response.cache_control.no_cache = True
        response.cache_control.no_store = True
    return response

@app.teardown_appcontext
def close_db(exception):
    db = getattr(flask.g, '_db', None)
    if db is not None:
        db.close()

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host = '0.0.0.0', port = port, debug = debug)
<|endoftext|>


<commit_before>
'''
Authors: Spencer Norris, Sabbir Rashid
File: app.py
Description: Implementation of server code for Wuu-Bernstein.

Note: you'll need to set the environment variable 'TWITTER_USER' to the
user of the local node.
'''

from datetime import datetime
from copy import copy
import requests
import pickle
import socket
import json
import time
import csv
import os

#========================== Class Structure ====================================#

class Tweet:
    def __init__(self, user, text, time):
        self.user = user
        self.text = text
        self.time = time

class BlockEvent:
    def __init__(self, user, target, time):
        self.user = user
        self.target = target
        self.time = time

class UnblockEvent:
    def __init__(self, user, target, time):
        self.user = user
        self.target = target
        self.time = time

#============ Globals, global population and local data read/write =============#

LOG = None
BLOCKED = None
USERS = None
ADDRESSES = None
TIME_MATRIX = None

def __BACKUP_LOG():
    global LOG
    L = list(LOG)
    pickle.dump(L, open('LOG.pickle', 'wb'))

def __READ_LOG_BACKUP():
    '''
    Read our pickled copy of the log between restarts.
    If the file doesn't exist, return empty log.
    '''
    if not os.path.isfile('LOG.pickle'):
        return set()
    else:
        L = pickle.load(open("LOG.pickle", 'rb'))
        return set(L)

def __UNHASH_DICT(L):
    '''
    Reads in the hashed versions of the TIME_MATRIX.
    '''
    matrix = {}

    #Create dummy matrix
    for user in USERS:
        matrix[user] = {}
        for other_user in USERS:
            matrix[user][other_user] = 0

    #Populate new matrix
    for elem in L:
        user = elem[0]
        other_user = elem[1]
        t = elem[2]
        matrix[user][other_user] = t
    return matrix

def __HASH_DICT(d):
    '''
    Writes out hashable versions of the TIME_MATRIX.
    '''
    L = []
    for user, v in d.items():
        for other_user, t in v.items():
            L.append((user,other_user,t))
    return L

def __READ_TIME_MATRIX():
    '''
    This matrix, implemented as a dict of dicts, defines what
    any given node knows about any other given node based on
    what their most recent known time stamp was.

    {
        'user_1': {
            'user_2': TIME
            ...
        }
        ...
    }

    If this matrix already exists as a pickled object, read
    it from the local disk. Otherwise, create a brand new
    time matrix.
    '''
    global USERS
    time = datetime.utcnow()
    if not os.path.isfile('TIME_MATRIX.pickle'):
        matrix = {}
        for user in USERS:
            matrix[user] = {}
            for other_user in USERS:
                matrix[user][other_user] = time
        return matrix
    else:
        L = pickle.load(open("TIME_MATRIX.pickle", 'rb'))
        return __UNHASH_DICT(L)

def __BACKUP_MATRIX():
    '''
    Dictionaries in Python are not hashable,
    thus we need a small workaround for storing
    the pickled object when backing up the time matrix.
    '''
    global TIME_MATRIX
    L = __HASH_DICT(TIME_MATRIX)
    pickle.dump(L, open('TIME_MATRIX.pickle', 'wb'))

def __GET_BLOCKED_USERS():
    '''
    Returns a dictionary of what what users are
    and aren't blocking other users.
    For example, if user_1 blocked user_2 at time 5,
    ex.
    {
        'user_1' : {
            'user_2' : BlockEvent('user_1', 'user_2', 5)
        }
        ...
    }

    meaning user_1 blocked user_2 at time 5. If user_1 unblocks user_2 at time 6,

    {
        'user_1' : {
            'user_2' : UnblockEvent('user_1', 'user_2', 6)
        }
        ...
    }
    '''
    global LOG
    global USERS

    #Create dictionary of users pointing to dictionary of other users
    #Pointing to the earliest possible state between users of the system
    blocked = {}
    if(USERS is not None) :
        for user in USERS:
            blocked[user] = {}
            for other_user in USERS:
                if not other_user == user:
                    blocked[user][other_user] = UnblockEvent(user, other_user, datetime.now())

    #Get all block and unblock events
    events = set(filter(
                lambda event:
                type(event) is BlockEvent or type(event) is UnblockEvent,
            LOG))

    #Set each user-user interaction to the most block or unblock
    for event in events:
        if event.time > blocked[event.user][event.target].time:
            blocked[event.user][event.target] = event

    return blocked

def __GET_ALL_USERS_ADDRESSES():
    '''
    Read in local two-column CSV file to get list of users and addresses.
    '''
    users = []
    addresses = []
    with open('users.csv', 'r') as f:
        reader = csv.reader(f)
        for row in reader:
            users.append(row[0])
            addresses.append(row[1])
    return users,addresses

def __GET_ALL_TWEETS():
    '''
    Returns list of all tweets currently in the log.
    '''
    global LOG
    return set(filter(lambda event: type(event) is Tweet, LOG))

def __GET_PRUNED_LOG(other_user):
    '''
    Prunes the log so it only sends events after the most recent
    timestamp this node has on record for other_user.
    '''

    def __has_rec(event):
        '''
        Determines whether it's possible other_user knows about the event.
        '''
        global TIME_MATRIX
        return TIME_MATRIX[event.user][other_user] >= event.time

    global LOG
    pruned_log = copy(LOG)
    for event in LOG:
        if not __has_rec(event):
            pruned_log.add(event)
    return pruned_log

#============================ Server API Implementation ============================#

#Populate globals on initialization
LOG = __READ_LOG_BACKUP()
USERS, ADDRESSES = __GET_ALL_USERS_ADDRESSES()
BLOCKED = __GET_BLOCKED_USERS()
TIME_MATRIX = __READ_TIME_MATRIX()
MY_USER = os.environ['TWITTER_USER']
MY_CLIENT_ADDRESS = os.environ['CLIENT_ADDR']
VALID_COMMANDS = ['view', 'tweet', 'block', 'unblock']

def tweet(text):

    def __send_message(log, target_user):
        '''
        Carries out a transaction with the receiving node in order to transmit
        the pickled, hashed version of the time matrix and the pickled, hashed
        version of the log.
        '''
        global TIME_MATRIX
        global ADDRESSES

        #Retrieve target address
        target_addr = ADDRESSES[USERS.index(other_user)]

        #Create hashable objects, pickle them
        hashable_time_matrix = __HASH_DICT(TIME_MATRIX)
        L = list(log)
        hashable_time_matrix = pickle.dumps(hashable_time_matrix)
        L = pickle.dumps(L)

        #TODO: send pickled objects to mailbox of target user w/ timestamp####################
        #@Sabbir
        pass

    #Update time matrix
    global TIME_MATRIX
    global MY_USER
    time = datetime.utcnow()
    TIME_MATRIX[MY_USER][MY_USER] = time

    #Create tweet event, add to pruned logs
    tweet = Tweet(MY_USER, text, time)

    #Send pruned log, time matrix to all non-blocked users
    global USERS
    global ADDRESSES
    global BLOCKED
    for other_user in USERS:
        if other_user == MY_USER:
            continue
        if not type(BLOCKED[MY_USER][other_user]) is BlockEvent:
            pruned_log = __GET_PRUNED_LOG(other_user)
            pruned_log.add(tweet)
            print(pruned_log)
            __send_message(pruned_log,other_user)

    #Backup log, backup matrix
    LOG.add(tweet)
    __BACKUP_LOG()
    __BACKUP_MATRIX()

def block(target):
    '''
    Add block event to local log for target user.
    '''
    global LOG
    global TIME_MATRIX
    global BLOCKED
    time = datetime.utcnow()

    #Find most recent block or unblock operation by our user on target and remove it
    LOG = {event for event in LOG
             if not (
                        (
                         (type(event) is BlockEvent) or
                         (type(event) is UnblockEvent)
                        ) and
                        event.user == MY_USER and event.target == target
                )
        }

    #Add this operation to log
    LOG.add(BlockEvent(MY_USER, target, time))

    #Update time matrix
    TIME_MATRIX[MY_USER][MY_USER] = time

    #Update block matrix
    BLOCKED[MY_USER][target] = BlockEvent(MY_USER, target, time)

    #Backup log, matrix
    __BACKUP_LOG()
    __BACKUP_MATRIX()

def unblock(target):
    global LOG
    global MY_USER
    time = datetime.utcnow()

    #Find most recent block or unblock operation by our user on target and remove it
    LOG = {
            event for event in LOG
            if not (
                        (
                         (type(event) is BlockEvent) or
                         (type(event) is UnblockEvent)
                        ) and
                        event.user == MY_USER and event.target == target
                )
        }

    #Add this operation to log
    LOG.add(UnblockEvent(MY_USER, target, time))

    #Update matrix
    TIME_MATRIX[MY_USER][MY_USER] = time

    #Update block matrix
    BLOCKED[MY_USER][target] = UnblockEvent(MY_USER, target, time)

    #Backup log, matrix
    __BACKUP_LOG()
    __BACKUP_MATRIX()

def view():
    '''
    Send ordered list of tweets as tuples to client.
    '''

    def __send_to_client(tweets):
        '''
        Passes the dumped tweets back to the client over TCP.
        '''
        #Needs to be implemented @Sabbir
        pass

    global USERS
    global BLOCKED
    global MY_CLIENT_ADDRESS

    #Pull in all tweets and sort
    tweets = [(tweet.user, tweet.text, tweet.time) for tweet in __GET_ALL_TWEETS()]
    tweets = sorted(tweets, key=lambda tweet: tweet[2], reverse=True)

    #filter out tweets this user isn't allowed to see
    for other_user in USERS:
        if other_user == MY_USER:
            continue
        block_unblock_event = BLOCKED[other_user][MY_USER]
        if type(block_unblock_event) is BlockEvent:
            tweets = list(filter(lambda tweet: not tweet[0] == other_user, tweets))

    #Send tweets back to client
    __send_to_client(tweets)
    print(tweets)

def receive_tweet(remote_user, other_log, other_time_matrix):
    '''
    Reads in log, time matrix from other node and updates each.
    '''
    global LOG
    global USERS
    global BLOCKED

    def __update_time_matrix(remote_user, other_time_matrix):
        '''
        Updates the time matrix according to Wuu-Bernstein.
        '''
        global TIME_MATRIX
        for user in USERS:
            TIME_MATRIX[MY_USER][user] = max(
                    TIME_MATRIX[MY_USER][user],
                    other_time_matrix[remote_user][user]
                )
        for user in USERS:
            for other_user in USERS:
                TIME_MATRIX[user][other_user] = max(
                    TIME_MATRIX[user][other_user],
                    other_time_matrix[user][other_user]
                )

    #Update local time matrix
    __update_time_matrix(remote_user, other_time_matrix)

    #Update block and unblock states
    block_unblock_events = list(filter(
                            lambda event:
                                type(event) is BlockEvent
                                or type(event) is UnblockEvent,
                            other_log))

    #If the block or unblock event is more recent than our most recent one...
    for event in block_unblock_events:
        if event.time > BLOCKED[event.user][event.target].time :

            #Remove our event from the log...
            LOG = {our_event for our_event in LOG
                     if not (
                                (
                                 (type(event) is BlockEvent) or
                                 (type(event) is UnblockEvent)
                                ) and
                                event.user == our_event.user and event.target == our_event.target
                        )
                }

            #Update our BLOCKED matrix...
            BLOCKED[event.user][event.target] = event

            #and insert the event into our log
            LOG.add(event)

    #Merge the other log with our log after removing block and unblock events
    other_log = set(filter(
                    lambda event: not (
                                    type(event) is BlockEvent
                                    or type(event) is UnblockEvent
                                ),
                other_log))
    LOG = LOG.union(other_log)
    print(LOG)

    #Backup
    __BACKUP_LOG()
    __BACKUP_MATRIX()

def get_message():
    '''
    Retrieves a message from the mailbox daemon.
    '''
    #@Sabbir
    def __decode_receive_tweet():
        '''
        Performs the transaction for receiving a log and time
        matrix from the mailbox.

        Requires two handshakes: one to receive the pickled log,
        the other to receive the pickled time matrix.
        '''
        other_user = None
        time_matrix = None
        log = None

        #Perform transaction to read in, unpickle and
        #unhash the time matrix and log

        #Close connection
        client.close()

        return [other_user, log, time_matrix]

    def __decode_strin_in():
        '''
        Carries out the client-side interaction for
        pulling in a string from the mailbox as part
        of the transaction for blocking, unblocking
        and tweeting.
        '''
        strin = None
        client.close()
        return strin

    # create an ipv4 (AF_INET) socket object using the tcp protocol (SOCK_STREAM)
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # connect the client
    # client.connect((target, port))
    client.connect(('0.0.0.0', 9999))

    # TODO: implement request msg from mailbox

    # receive the response data (4096 is recommended buffer size)
    token = client.recv(4096)
    token_to_cmd = {
        '0' : 'tweet',
        '1' : 'view',
        '2' : 'block',
        '3' : 'unblock',
        '4' : 'receive_tweet'
    }
    cmd = token_to_cmd[token]

    if cmd == 'block' or cmd == 'unblock' or cmd == 'tweet':
        return [cmd, __decode_string_in()]
    elif cmd == 'view':
        return ['view', None]
    elif cmd == 'receive_tweet':
        [cmd, __decode_receive_tweet()]

#=================MAIN LOOP==========================================#

# while(True):
#     cmd = get_message() #Retrieves message of form ('command', [Args])

#     #No messages right now
#     if cmd is None:
#         continue

#     #Catch invalid commands
#     if not cmd[0] in VALID_COMMANDS:
#         print("Invalid command!")
#         continue

#     #Handle commands
#     #NOTE: Can always assume commands come from client
#     if cmd[0] == 'block':
#         block(cmd[1]) # blocked user goes here
#     elif cmd[0] == 'unblock':
#         unblock(cmd[1]) # unblocked user goes here
#     elif cmd[0] == 'tweet':
#         tweet(cmd[1]) # tweet text goes here
#     elif cmd[0] == 'view':
#         view()
#     elif cmd[0] == 'receive_tweet':
#         receive_tweet(cmd[1][0], cmd[1][1], cmd[1][2]) #other user, other log and other time matrix
#     else:
#         print("No matching command!")
#         continue
<commit_msg>almost forgot to uncomment main loop<commit_after>
'''
Authors: Spencer Norris, Sabbir Rashid
File: app.py
Description: Implementation of server code for Wuu-Bernstein.

Note: you'll need to set the environment variable 'TWITTER_USER' to the
user of the local node.
'''

from datetime import datetime
from copy import copy
import requests
import pickle
import socket
import json
import time
import csv
import os

#========================== Class Structure ====================================#

class Tweet:
    def __init__(self, user, text, time):
        self.user = user
        self.text = text
        self.time = time

class BlockEvent:
    def __init__(self, user, target, time):
        self.user = user
        self.target = target
        self.time = time

class UnblockEvent:
    def __init__(self, user, target, time):
        self.user = user
        self.target = target
        self.time = time

#============ Globals, global population and local data read/write =============#

LOG = None
BLOCKED = None
USERS = None
ADDRESSES = None
TIME_MATRIX = None

def __BACKUP_LOG():
    global LOG
    L = list(LOG)
    pickle.dump(L, open('LOG.pickle', 'wb'))

def __READ_LOG_BACKUP():
    '''
    Read our pickled copy of the log between restarts.
    If the file doesn't exist, return empty log.
    '''
    if not os.path.isfile('LOG.pickle'):
        return set()
    else:
        L = pickle.load(open("LOG.pickle", 'rb'))
        return set(L)

def __UNHASH_DICT(L):
    '''
    Reads in the hashed versions of the TIME_MATRIX.
    '''
    matrix = {}

    #Create dummy matrix
    for user in USERS:
        matrix[user] = {}
        for other_user in USERS:
            matrix[user][other_user] = 0

    #Populate new matrix
    for elem in L:
        user = elem[0]
        other_user = elem[1]
        t = elem[2]
        matrix[user][other_user] = t
    return matrix

def __HASH_DICT(d):
    '''
    Writes out hashable versions of the TIME_MATRIX.
    '''
    L = []
    for user, v in d.items():
        for other_user, t in v.items():
            L.append((user,other_user,t))
    return L

def __READ_TIME_MATRIX():
    '''
    This matrix, implemented as a dict of dicts, defines what
    any given node knows about any other given node based on
    what their most recent known time stamp was.

    {
        'user_1': {
            'user_2': TIME
            ...
        }
        ...
    }

    If this matrix already exists as a pickled object, read
    it from the local disk. Otherwise, create a brand new
    time matrix.
    '''
    global USERS
    time = datetime.utcnow()
    if not os.path.isfile('TIME_MATRIX.pickle'):
        matrix = {}
        for user in USERS:
            matrix[user] = {}
            for other_user in USERS:
                matrix[user][other_user] = time
        return matrix
    else:
        L = pickle.load(open("TIME_MATRIX.pickle", 'rb'))
        return __UNHASH_DICT(L)

def __BACKUP_MATRIX():
    '''
    Dictionaries in Python are not hashable,
    thus we need a small workaround for storing
    the pickled object when backing up the time matrix.
    '''
    global TIME_MATRIX
    L = __HASH_DICT(TIME_MATRIX)
    pickle.dump(L, open('TIME_MATRIX.pickle', 'wb'))

def __GET_BLOCKED_USERS():
    '''
    Returns a dictionary of what what users are
    and aren't blocking other users.
    For example, if user_1 blocked user_2 at time 5,
    ex.
    {
        'user_1' : {
            'user_2' : BlockEvent('user_1', 'user_2', 5)
        }
        ...
    }

    meaning user_1 blocked user_2 at time 5. If user_1 unblocks user_2 at time 6,

    {
        'user_1' : {
            'user_2' : UnblockEvent('user_1', 'user_2', 6)
        }
        ...
    }
    '''
    global LOG
    global USERS

    #Create dictionary of users pointing to dictionary of other users
    #Pointing to the earliest possible state between users of the system
    blocked = {}
    if(USERS is not None) :
        for user in USERS:
            blocked[user] = {}
            for other_user in USERS:
                if not other_user == user:
                    blocked[user][other_user] = UnblockEvent(user, other_user, datetime.now())

    #Get all block and unblock events
    events = set(filter(
                lambda event:
                type(event) is BlockEvent or type(event) is UnblockEvent,
            LOG))

    #Set each user-user interaction to the most block or unblock
    for event in events:
        if event.time > blocked[event.user][event.target].time:
            blocked[event.user][event.target] = event

    return blocked

def __GET_ALL_USERS_ADDRESSES():
    '''
    Read in local two-column CSV file to get list of users and addresses.
    '''
    users = []
    addresses = []
    with open('users.csv', 'r') as f:
        reader = csv.reader(f)
        for row in reader:
            users.append(row[0])
            addresses.append(row[1])
    return users,addresses

def __GET_ALL_TWEETS():
    '''
    Returns list of all tweets currently in the log.
    '''
    global LOG
    return set(filter(lambda event: type(event) is Tweet, LOG))

def __GET_PRUNED_LOG(other_user):
    '''
    Prunes the log so it only sends events after the most recent
    timestamp this node has on record for other_user.
    '''

    def __has_rec(event):
        '''
        Determines whether it's possible other_user knows about the event.
        '''
        global TIME_MATRIX
        return TIME_MATRIX[event.user][other_user] >= event.time

    global LOG
    pruned_log = copy(LOG)
    for event in LOG:
        if not __has_rec(event):
            pruned_log.add(event)
    return pruned_log

#============================ Server API Implementation ============================#

#Populate globals on initialization
LOG = __READ_LOG_BACKUP()
USERS, ADDRESSES = __GET_ALL_USERS_ADDRESSES()
BLOCKED = __GET_BLOCKED_USERS()
TIME_MATRIX = __READ_TIME_MATRIX()
MY_USER = os.environ['TWITTER_USER']
MY_CLIENT_ADDRESS = os.environ['CLIENT_ADDR']
VALID_COMMANDS = ['view', 'tweet', 'block', 'unblock']

def tweet(text):

    def __send_message(log, target_user):
        '''
        Carries out a transaction with the receiving node in order to transmit
        the pickled, hashed version of the time matrix and the pickled, hashed
        version of the log.
        '''
        global TIME_MATRIX
        global ADDRESSES

        #Retrieve target address
        target_addr = ADDRESSES[USERS.index(other_user)]

        #Create hashable objects, pickle them
        hashable_time_matrix = __HASH_DICT(TIME_MATRIX)
        L = list(log)
        hashable_time_matrix = pickle.dumps(hashable_time_matrix)
        L = pickle.dumps(L)

        #TODO: send pickled objects to mailbox of target user w/ timestamp####################
        #@Sabbir
        pass

    #Update time matrix
    global TIME_MATRIX
    global MY_USER
    time = datetime.utcnow()
    TIME_MATRIX[MY_USER][MY_USER] = time

    #Create tweet event, add to pruned logs
    tweet = Tweet(MY_USER, text, time)

    #Send pruned log, time matrix to all non-blocked users
    global USERS
    global ADDRESSES
    global BLOCKED
    for other_user in USERS:
        if other_user == MY_USER:
            continue
        if not type(BLOCKED[MY_USER][other_user]) is BlockEvent:
            pruned_log = __GET_PRUNED_LOG(other_user)
            pruned_log.add(tweet)
            print(pruned_log)
            __send_message(pruned_log,other_user)

    #Backup log, backup matrix
    LOG.add(tweet)
    __BACKUP_LOG()
    __BACKUP_MATRIX()

def block(target):
    '''
    Add block event to local log for target user.
    '''
    global LOG
    global TIME_MATRIX
    global BLOCKED
    time = datetime.utcnow()

    #Find most recent block or unblock operation by our user on target and remove it
    LOG = {event for event in LOG
             if not (
                        (
                         (type(event) is BlockEvent) or
                         (type(event) is UnblockEvent)
                        ) and
                        event.user == MY_USER and event.target == target
                )
        }

    #Add this operation to log
    LOG.add(BlockEvent(MY_USER, target, time))

    #Update time matrix
    TIME_MATRIX[MY_USER][MY_USER] = time

    #Update block matrix
    BLOCKED[MY_USER][target] = BlockEvent(MY_USER, target, time)

    #Backup log, matrix
    __BACKUP_LOG()
    __BACKUP_MATRIX()

def unblock(target):
    global LOG
    global MY_USER
    time = datetime.utcnow()

    #Find most recent block or unblock operation by our user on target and remove it
    LOG = {
            event for event in LOG
            if not (
                        (
                         (type(event) is BlockEvent) or
                         (type(event) is UnblockEvent)
                        ) and
                        event.user == MY_USER and event.target == target
                )
        }

    #Add this operation to log
    LOG.add(UnblockEvent(MY_USER, target, time))

    #Update matrix
    TIME_MATRIX[MY_USER][MY_USER] = time

    #Update block matrix
    BLOCKED[MY_USER][target] = UnblockEvent(MY_USER, target, time)

    #Backup log, matrix
    __BACKUP_LOG()
    __BACKUP_MATRIX()

def view():
    '''
    Send ordered list of tweets as tuples to client.
    '''

    def __send_to_client(tweets):
        '''
        Passes the dumped tweets back to the client over TCP.
        '''
        #Needs to be implemented @Sabbir
        pass

    global USERS
    global BLOCKED
    global MY_CLIENT_ADDRESS

    #Pull in all tweets and sort
    tweets = [(tweet.user, tweet.text, tweet.time) for tweet in __GET_ALL_TWEETS()]
    tweets = sorted(tweets, key=lambda tweet: tweet[2], reverse=True)

    #filter out tweets this user isn't allowed to see
    for other_user in USERS:
        if other_user == MY_USER:
            continue
        block_unblock_event = BLOCKED[other_user][MY_USER]
        if type(block_unblock_event) is BlockEvent:
            tweets = list(filter(lambda tweet: not tweet[0] == other_user, tweets))

    #Send tweets back to client
    __send_to_client(tweets)
    print(tweets)

def receive_tweet(remote_user, other_log, other_time_matrix):
    '''
    Reads in log, time matrix from other node and updates each.
    '''
    global LOG
    global USERS
    global BLOCKED

    def __update_time_matrix(remote_user, other_time_matrix):
        '''
        Updates the time matrix according to Wuu-Bernstein.
        '''
        global TIME_MATRIX
        for user in USERS:
            TIME_MATRIX[MY_USER][user] = max(
                    TIME_MATRIX[MY_USER][user],
                    other_time_matrix[remote_user][user]
                )
        for user in USERS:
            for other_user in USERS:
                TIME_MATRIX[user][other_user] = max(
                    TIME_MATRIX[user][other_user],
                    other_time_matrix[user][other_user]
                )

    #Update local time matrix
    __update_time_matrix(remote_user, other_time_matrix)

    #Update block and unblock states
    block_unblock_events = list(filter(
                            lambda event:
                                type(event) is BlockEvent
                                or type(event) is UnblockEvent,
                            other_log))

    #If the block or unblock event is more recent than our most recent one...
    for event in block_unblock_events:
        if event.time > BLOCKED[event.user][event.target].time :

            #Remove our event from the log...
            LOG = {our_event for our_event in LOG
                     if not (
                                (
                                 (type(event) is BlockEvent) or
                                 (type(event) is UnblockEvent)
                                ) and
                                event.user == our_event.user and event.target == our_event.target
                        )
                }

            #Update our BLOCKED matrix...
            BLOCKED[event.user][event.target] = event

            #and insert the event into our log
            LOG.add(event)

    #Merge the other log with our log after removing block and unblock events
    other_log = set(filter(
                    lambda event: not (
                                    type(event) is BlockEvent
                                    or type(event) is UnblockEvent
                                ),
                other_log))
    LOG = LOG.union(other_log)
    print(LOG)

    #Backup
    __BACKUP_LOG()
    __BACKUP_MATRIX()

def get_message():
    '''
    Retrieves a message from the mailbox daemon.
    '''
    #@Sabbir
    def __decode_receive_tweet():
        '''
        Performs the transaction for receiving a log and time
        matrix from the mailbox.

        Requires two handshakes: one to receive the pickled log,
        the other to receive the pickled time matrix.
        '''
        other_user = None
        time_matrix = None
        log = None

        #Perform transaction to read in, unpickle and
        #unhash the time matrix and log

        #Close connection
        client.close()

        return [other_user, log, time_matrix]

    def __decode_strin_in():
        '''
        Carries out the client-side interaction for
        pulling in a string from the mailbox as part
        of the transaction for blocking, unblocking
        and tweeting.
        '''
        strin = None
        client.close()
        return strin

    # create an ipv4 (AF_INET) socket object using the tcp protocol (SOCK_STREAM)
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # connect the client
    # client.connect((target, port))
    client.connect(('0.0.0.0', 9999))

    # TODO: implement request msg from mailbox

    # receive the response data (4096 is recommended buffer size)
    token = client.recv(4096)
    token_to_cmd = {
        '0' : 'tweet',
        '1' : 'view',
        '2' : 'block',
        '3' : 'unblock',
        '4' : 'receive_tweet'
    }
    cmd = token_to_cmd[token]

    if cmd == 'block' or cmd == 'unblock' or cmd == 'tweet':
        return [cmd, __decode_string_in()]
    elif cmd == 'view':
        return ['view', None]
    elif cmd == 'receive_tweet':
        [cmd, __decode_receive_tweet()]

#=================MAIN LOOP==========================================#

while(True):
    cmd = get_message() #Retrieves message of form ('command', [Args])

    #No messages right now
    if cmd is None:
        continue

    #Catch invalid commands
    if not cmd[0] in VALID_COMMANDS:
        print("Invalid command!")
        continue

    #Handle commands
    #NOTE: Can always assume commands come from client
    if cmd[0] == 'block':
        block(cmd[1]) # blocked user goes here
    elif cmd[0] == 'unblock':
        unblock(cmd[1]) # unblocked user goes here
    elif cmd[0] == 'tweet':
        tweet(cmd[1]) # tweet text goes here
    elif cmd[0] == 'view':
        view()
    elif cmd[0] == 'receive_tweet':
        receive_tweet(cmd[1][0], cmd[1][1], cmd[1][2]) #other user, other log and other time matrix
    else:
        print("No matching command!")
        continue
<|endoftext|>


<commit_before>from flask import Flask, render_template, redirect, url_for, request
app = Flask(__name__)

@app.route('/')
def home():
	return "Hello World, new Flask App"

@app.route('/welcome')
def welcome():
	return render_template('welcome.html')

@app.route('/login', methods=['GET','POST'])
def login():
	error = None
	if request.method == 'POST':
		if request.form['username'] != 'admin' or request.form['password'] != 'admin':
			error = 'Invalid credentials. Please try again.'
		else:
			return redirect(url_for('home'))
	return render_template('login.html',error=error)

if __name__ == '__main__':
	app.run(debug=True)<commit_msg>Added login wraps and loggedin_required<commit_after>from flask import Flask, render_template, redirect, url_for, request, session, flash
from functools import wraps

app = Flask(__name__)

app.secret_key = "my precious"

def login_required(f):
	@wraps(f)
	def wrap(*args, **kwargs):
		if 'logged_in' in session:
			return f(*args, **kwargs)
		else:
			flash('You need to login first.')
			return redirect(url_for('login'))
	return wrap

@app.route('/')
@login_required
def home():
	return render_template('index.html')

@app.route('/welcome')
def welcome():
	return render_template('welcome.html')

@app.route('/login', methods=['GET','POST'])
def login():
	error = None
	if request.method == 'POST':
		if request.form['username'] != 'admin' or request.form['password'] != 'admin':
			error = 'Invalid credentials. Please try again.'
		else:
			session['logged_in'] = True
			flash('You were just logged in!')
			return redirect(url_for('home'))
	return render_template('login.html',error=error)

@app.route('/logout')
@login_required
def logout():
	session.pop('logged_in', None)
	flash('You were just logged out!')
	return redirect(url_for('welcome'))

if __name__ == '__main__':
	app.run(debug=True)<|endoftext|>