Source code for labelord.web

# This is skeleton for labelord module
# MI-PYT, task 1 (requests+click)
# File: labelord.py
# TODO: create requirements.txt and install

import flask
import getpass
import requests
import click
import configparser
import json
import sys
import os
import hmac
import hashlib

from labelord.setupfile import setup

[docs]class LabelordWeb(flask.Flask): """ Flask web interface class """ def __init__(self, *args, **kwargs): """ Constructor :param: ``self`` Context :param: ``*args`` Arguments :param: ``**kwargs`` Arguments :return: ``None`` """ super().__init__(*args, **kwargs) # You can do something here, but you don't have to... # Adding more args before *args is also possible # You need to pass import_name to super as first arg or # via keyword (e.g. import_name=__name__) # Be careful not to override something Flask-specific # @see http://flask.pocoo.org/docs/0.12/api/ # @see https://github.com/pallets/flask
[docs] def inject_session(self, session): """ Session setting. :param: ``self`` Context :param: ``session`` Session for comunication with GitHub :return: ``None`` """ # TODO: inject session for communication with GitHub # The tests will call this method to pass the testing session. # Always use session from this call (it will be called before # any HTTP request). If this method is not called, create new # session. self.session = session
[docs] def reload_config(self): """ Config setting. Open config file and set congiguration (token, webhook secret, ...), set a self context. :param: ``self`` Context :return: ``None`` """ # TODO: check envvar LABELORD_CONFIG and reload the config # Because there are problems with reimporting the app with # different configuration, this method will be called in # order to reload configuration file. Check if everything # is correctly set-up conffile = configparser.ConfigParser() conffile.optionxform = str if 'LABELORD_CONFIG' in os.environ: config = os.environ['LABELORD_CONFIG'] conffile.read(config) else: if os.path.isfile('./config.cfg') == True: conffile.read('./config.cfg') config = './config.cfg' if os.path.isfile('./config.cfg') == False and 'github' not in conffile: print('No GitHub token has been provided', file=sys.stderr) sys.exit(3) if 'github' in conffile and 'token' not in conffile['github']: print('No GitHub token has been provided', file=sys.stderr) sys.exit(3) else: self.token = conffile['github']['token'] self.session = setup(self.session, self.token) if 'github' in conffile and 'webhook_secret' not in conffile['github']: print('No webhook secret has been provided', file=sys.stderr) sys.exit(8) else: self.secret = conffile['github']['webhook_secret'] self.repos = [] if not 'repos' in conffile: print('No repositories specification has been found', file=sys.stderr) sys.exit(7) for repo in conffile['repos']: if conffile.getboolean('repos', repo): self.repos.append(repo) self.labels = {} if 'labels' in conffile: for label in conffile['labels']: self.labels[label] = conffile['labels'][label] self.ename = '' self.dname = ''
# TODO: instantiate LabelordWeb app # Be careful with configs, this is module-wide variable, # you want to be able to run CLI app as it was in task 1. from flask import Flask, current_app, render_template, request, Response, json app = LabelordWeb(__name__) # TODO: implement web app # hint: you can use flask.current_app (inside app context) @app.template_filter('link') @app.route('/', methods=['GET'])
[docs]def get(): """ GET requests Handle GET requests - print repositories and link to repositories. :return: ``render template`` Rendering page """ if not current_app.session: session = requests.Session() current_app.inject_session(session) if not current_app.repos: current_app.reload_config() return render_template('get.html', repos=current_app.repos)
@app.route('/', methods=['POST'])
[docs]def post(): """ POST requests Handle POST requests - chech if request from GitHub, if do make command according to POST request and send response. :return: ``response`` """ if not current_app.session: session = requests.Session() current_app.inject_session(session) if not current_app.repos: current_app.reload_config() data = json.loads(request.data) datas = {'hello': 'world', 'number': 3} js = json.dumps(datas) if request.headers['Content-Type'] != 'application/json': resp = Response(js, status=200, mimetype='application/json') return resp signature = 'sha1=' + hmac.new(bytes(current_app.secret, encoding="UTF-8"), request.data, hashlib.sha1).hexdigest() if not 'X-Hub-Signature' in request.headers or signature != request.headers['X-Hub-Signature']: resp = Response(js, status=401, mimetype='application/json') return resp if request.headers['X-GitHub-Event'] != 'ping' and request.headers['X-GitHub-Event'] != 'label': resp = Response(js, status=200, mimetype='application/json') return resp if request.headers['X-GitHub-Event'] == 'ping': resp = Response(js, status=200, mimetype='application/json') return resp else: if data['action'] == 'created': if data['repository']['full_name'] not in current_app.repos: resp = Response(js, status=400, mimetype='application/json') return resp for repo in current_app.repos: if repo != data['repository']['full_name']: colors = json.dumps({"name": data['label']['name'], "color": data['label']['color']}) list = current_app.session.post('https://api.github.com/repos/' + repo + '/labels', data=colors) elif data['action'] == 'deleted': if data['repository']['full_name'] not in current_app.repos: resp = Response(js, status=400, mimetype='application/json') return resp for repo in current_app.repos: if repo != data['repository']['full_name'] and current_app.dname != data['label']['name']: list = current_app.session.delete('https://api.github.com/repos/' + repo + '/labels/' + data['label']['name']) # TODO current_app.dname = data['label']['name'] elif data['action'] == 'edited': if data['repository']['full_name'] not in current_app.repos: resp = Response(js, status=400, mimetype='application/json') return resp for repo in current_app.repos: if 'name' not in data['changes'] or 'from' not in data['changes']['name']: colorname = data['label']['name'] else: colorname = data['changes']['name']['from'] if repo != data['repository']['full_name'] and current_app.ename != data['label']['name']: colors = json.dumps({"name": data['label']['name'], "color": data['label']['color']}) list = current_app.session.patch('https://api.github.com/repos/' + repo + '/labels/' + colorname, data=colors) # TODO current_app.ename = data['label']['name'] resp = Response(js, status=200, content_type='application/json', mimetype='application/json') resp.headers['Link'] = 'https://api.github.com/' return resp