import urllib import requests import functools import oauth2 as oauth from flask import Flask, request, abort, jsonify, render_template, make_response, json app = Flask('socialist') app.config.from_pyfile('socialist.cfg') consumer_secret = app.config['CONSUMER_SECRET'] consumer_key = app.config['CONSUMER_KEY'] oauth_token = app.config['OAUTH_TOKEN'] oauth_token_secret = app.config['OAUTH_TOKEN_SECRET'] auth_url = app.config['AUTH_URL'] cap_url = app.config['CAP_URL'] api_allowed = app.config['API_AUTHORIZED'] twitter_role = app.config['TWITTER_ROLE'] def api_access(f): @functools.wraps(f) def func(*a, **kw): dn = request.environ.get('PEER_DN') if dn not in api_allowed: return abort(403) return f(*a, **kw) return func def get_login(): return request.login def plain_error(text='Unauthorized', code=401): return make_response(text, code, { 'Content-Type': 'text/plain' }) def json_error(errors=[{'message': 'Unauthorized', 'code':401}], status_code=401): res = jsonify(errors = errors) res.status_code = status_code return res def require_role(role, login_source = get_login, error_func = plain_error): def decorator(f): @functools.wraps(f) def func(*a, **kw): res = requests.get('/'.join((cap_url, role, get_login())), verify = False) # T_T if res.status_code == 200: return f(*a, **kw) else: return error_func() return func return decorator def irc_dereference(from_parameter = 'nick', to_attribute = 'login', error_func = plain_error): def decorator(f): @functools.wraps(f) def func(*a, **kw): res = requests.post(auth_url + '/irc', verify = False, # T_T data = { 'nick': request.form[from_parameter] }) if res.status_code == 200: request.login = res.text return f(*a, **kw) else: return error_func() return func return decorator def oauth_req(url, http_method = 'GET', data = {}, headers = None): # za https://dev.twitter.com/docs/auth/oauth/single-user-with-examples#python from urllib import urlencode consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret) token = oauth.Token(key=oauth_token, secret=oauth_token_secret) client = oauth.Client(consumer, token) return client.request( url, method = http_method, body = urlencode(data), headers = headers) def post_update(entry, format_str, title_shortener, max_title_length): title = title_shortener(get_text(entry, 'title'), max_title_length) try: author = get_text(get_first_child(entry, 'author'), 'name') except IndexError: author = 'Somebody' url = get_first_child(entry, 'link').attributes['href'].value text = format_str % dict(title=title, author=author, url=url) logger.info('posting update (text: "%s")' % text) oauth_req('https://api.twitter.com/1/statuses/update.json', 'POST', { 'status': text }) @app.route('/') def motd(): return render_template('motd.html') @app.route('/socialist/tweet', methods=['GET']) def test_form(): return render_template('tweet_form.html') def irc_authorize(role, role_error): def decorator(f): mkerr = lambda ermsg: [{'messages': ermsg, 'code': 401}] return api_access( irc_dereference(error_func = lambda: json_error(mkerr('Unknown nick')))( require_role(role, error_func = lambda: json_error(mkerr(role_error)))( f))) return decorator @app.route('/socialist/tweet', methods=['POST']) @irc_authorize(twitter_role, 'Unauthorized to tweet') def irc_tweet(): tw_res = oauth_req('https://api.twitter.com/1.1/statuses/update.json', 'POST', { 'status': request.form['text'] }) print tw_res return make_response(tw_res[1], tw_res[0].status, { 'Content-Type': 'application/json'}) @app.route('/socialist/detweet/', methods=['POST']) @irc_authorize(twitter_role, 'Unauthorized to remove tweets') def irc_detweet(tid): tw_res = oauth_req('https://api.twitter.com/1.1/statuses/destroy/%s.json' % tid, 'POST') return make_response(tw_res[1], tw_res[0].status, { 'Content-Type': 'application/json'}) @app.route('/socialist/test', methods=['POST']) @irc_authorize(twitter_role, "test error") def irc_test(): return json_error() app.debug = True if __name__ == '__main__': app.run('0.0.0.0', port=8083, debug=True)