]> git.lizzy.rs Git - cheatdb.git/blobdiff - app/blueprints/github/__init__.py
Add links to GitHub oauth connection settings
[cheatdb.git] / app / blueprints / github / __init__.py
index e3ce8d7aa3a6c5c089695fd909f5a41379c28102..7477238e94418d1f47b6bdf126bc0d26bae091af 100644 (file)
@@ -18,13 +18,13 @@ from flask import Blueprint
 
 bp = Blueprint("github", __name__)
 
-from flask import redirect, url_for, request, flash, abort, render_template, jsonify
+from flask import redirect, url_for, request, flash, abort, render_template, jsonify, current_app
 from flask_user import current_user, login_required
 from sqlalchemy import func
 from flask_github import GitHub
 from app import github, csrf
 from app.models import db, User, APIToken, Package, Permission
-from app.utils import loginUser, randomString
+from app.utils import loginUser, randomString, abs_url_for
 from app.blueprints.api.support import error, handleCreateRelease
 import hmac, requests, json
 
@@ -33,7 +33,13 @@ from wtforms import SelectField, SubmitField
 
 @bp.route("/github/start/")
 def start():
-       return github.authorize("", redirect_uri=url_for("github.callback"))
+       return github.authorize("", redirect_uri=abs_url_for("github.callback"))
+
+@bp.route("/github/view/")
+def view_permissions():
+       url = "https://github.com/settings/connections/applications/" + \
+                       current_app.config["GITHUB_CLIENT_ID"]
+       return redirect(url)
 
 @bp.route("/github/callback/")
 @github.authorized_handler
@@ -123,12 +129,15 @@ def webhook():
 
        event = request.headers.get("X-GitHub-Event")
        if event == "push":
-               title = json["head_commit"]["message"].partition("\n")[0]
                ref = json["after"]
+               title = json["head_commit"]["message"].partition("\n")[0]
+       elif event == "create" and json["ref_type"] == "tag":
+               ref = json["ref"]
+               title = ref
        elif event == "ping":
                return jsonify({ "success": True, "message": "Ping successful" })
        else:
-               return error(400, "Unsupported event. Only 'push' and 'ping' are supported.")
+               return error(400, "Unsupported event. Only 'push', `create:tag`, and 'ping' are supported.")
 
        #
        # Perform release
@@ -138,7 +147,7 @@ def webhook():
 
 
 class SetupWebhookForm(FlaskForm):
-       event   = SelectField("Event Type", choices=[('push', 'Push'), ('tag', 'New tag')])
+       event   = SelectField("Event Type", choices=[('create', 'New tag or GitHub release'), ('push', 'Push')])
        submit  = SubmitField("Save")
 
 
@@ -177,53 +186,85 @@ def setup_webhook():
 
        if current_user.github_access_token is None:
                return github.authorize("write:repo_hook", \
-                       redirect_uri=url_for("github.callback_webhook", pid=pid, _external=True))
+                       redirect_uri=abs_url_for("github.callback_webhook", pid=pid))
 
        form = SetupWebhookForm(formdata=request.form)
        if request.method == "POST" and form.validate():
                token = APIToken()
-               token.name = "Github Webhook for " + package.title
+               token.name = "GitHub Webhook for " + package.title
                token.owner = current_user
                token.access_token = randomString(32)
                token.package = package
 
                event = form.event.data
-               if event != "push" and event != "tag":
+               if event != "push" and event != "create":
                        abort(500)
 
-               # Create webhook
-               url = "https://api.github.com/repos/{}/{}/hooks".format(gh_user, gh_repo)
-               data = {
-                       "name": "web",
-                       "active": True,
-                       "events": [event],
-                       "config": {
-                               "url": url_for("github.webhook", _external=True),
-                               "content_type": "json",
-                               "secret": token.access_token
-                       },
-               }
-
-               headers = {
-                       "Authorization": "token " + current_user.github_access_token
-               }
-
-               r = requests.post(url, headers=headers, data=json.dumps(data))
-               if r.status_code == 201:
-                       db.session.add(token)
-                       db.session.commit()
-
+               if handleMakeWebhook(gh_user, gh_repo, package, \
+                               current_user.github_access_token, event, token):
+                       flash("Successfully created webhook", "success")
                        return redirect(package.getDetailsURL())
-               elif r.status_code == 401 or r.status_code == 403:
-                       current_user.github_access_token = None
-                       db.session.commit()
-
-                       return github.authorize("write:repo_hook", \
-                               redirect_uri=url_for("github.callback_webhook", pid=pid, _external=True))
                else:
-                       flash("Failed to create webhook, received response from Github " +
-                               str(r.status_code) + ": " +
-                               str(r.json().get("message")), "danger")
+                       return redirect(url_for("github.setup_webhook", pid=package.id))
 
        return render_template("github/setup_webhook.html", \
                form=form, package=package)
+
+
+def handleMakeWebhook(gh_user, gh_repo, package, oauth, event, token):
+       url = "https://api.github.com/repos/{}/{}/hooks".format(gh_user, gh_repo)
+       headers = {
+               "Authorization": "token " + oauth
+       }
+       data = {
+               "name": "web",
+               "active": True,
+               "events": [event],
+               "config": {
+                       "url": abs_url_for("github.webhook"),
+                       "content_type": "json",
+                       "secret": token.access_token
+               },
+       }
+
+       # First check that the webhook doesn't already exist
+       r = requests.get(url, headers=headers)
+
+       if r.status_code == 401 or r.status_code == 403:
+               current_user.github_access_token = None
+               db.session.commit()
+               return False
+
+       if r.status_code != 200:
+               flash("Failed to create webhook, received response from Github " +
+                       str(r.status_code) + ": " +
+                       str(r.json().get("message")), "danger")
+               return False
+
+       for hook in r.json():
+               if hook.get("config") and hook["config"].get("url") and \
+                               hook["config"]["url"] == data["config"]["url"]:
+                       flash("Failed to create webhook, as it already exists", "danger")
+                       return False
+
+
+       # Create it
+       r = requests.post(url, headers=headers, data=json.dumps(data))
+
+       if r.status_code == 201:
+               db.session.add(token)
+               db.session.commit()
+
+               return True
+
+       elif r.status_code == 401 or r.status_code == 403:
+               current_user.github_access_token = None
+               db.session.commit()
+
+               return False
+
+       else:
+               flash("Failed to create webhook, received response from Github " +
+                       str(r.status_code) + ": " +
+                       str(r.json().get("message")), "danger")
+               return False