diff options
author | 2018-06-23 02:10:47 -0400 | |
---|---|---|
committer | 2018-06-23 02:10:47 -0400 | |
commit | bb60c29b8c51c26fba4e9678cb2d743e5dfc2e62 (patch) | |
tree | dde45d3b5c39d0a7ad0743da1dc9a8fe33362bd7 /pysite | |
parent | Add button to jam index in team list (diff) |
GitLab team repo storage, edit form, etc.
Diffstat (limited to 'pysite')
-rw-r--r-- | pysite/constants.py | 2 | ||||
-rw-r--r-- | pysite/tables.py | 3 | ||||
-rw-r--r-- | pysite/views/main/jams/jam_team_list.py | 2 | ||||
-rw-r--r-- | pysite/views/main/jams/team_edit_repo.py | 118 |
4 files changed, 123 insertions, 2 deletions
diff --git a/pysite/constants.py b/pysite/constants.py index 016ab9c5..fa5dbab2 100644 --- a/pysite/constants.py +++ b/pysite/constants.py @@ -53,6 +53,8 @@ DISCORD_OAUTH_SECRET = environ.get('DISCORD_OAUTH_SECRET', '') DISCORD_OAUTH_SCOPE = 'identify' OAUTH_DATABASE = "oauth_data" +GITLAB_ACCESS_TOKEN = environ.get("GITLAB_ACCESS_TOKEN", '') + PREFERRED_URL_SCHEME = environ.get("PREFERRED_URL_SCHEME", "http") ERROR_DESCRIPTIONS = { diff --git a/pysite/tables.py b/pysite/tables.py index cf38a698..191b52bd 100644 --- a/pysite/tables.py +++ b/pysite/tables.py @@ -93,7 +93,8 @@ TABLES = { keys=sorted([ "id", # uuid "name", # str - "members" # list[str] + "members", # list[str] + "repo" # str ]) ), diff --git a/pysite/views/main/jams/jam_team_list.py b/pysite/views/main/jams/jam_team_list.py index 474c8f77..8165f235 100644 --- a/pysite/views/main/jams/jam_team_list.py +++ b/pysite/views/main/jams/jam_team_list.py @@ -9,7 +9,7 @@ from pysite.mixins import DBMixin, OAuthMixin log = logging.getLogger(__name__) -class JamsUserTeamListView(RouteView, DBMixin, OAuthMixin): +class JamsTeamListView(RouteView, DBMixin, OAuthMixin): path = "/jams/teams/<int:jam_id>" name = "jams.jam_team_list" diff --git a/pysite/views/main/jams/team_edit_repo.py b/pysite/views/main/jams/team_edit_repo.py new file mode 100644 index 00000000..1b41335c --- /dev/null +++ b/pysite/views/main/jams/team_edit_repo.py @@ -0,0 +1,118 @@ +import logging +import re +from urllib.parse import quote + +import requests +from flask import jsonify, request +from rethinkdb import ReqlNonExistenceError +from urllib3.util import parse_url +from werkzeug.exceptions import NotFound, Unauthorized, BadRequest + +from pysite.base_route import RouteView +from pysite.constants import GITLAB_ACCESS_TOKEN +from pysite.decorators import csrf +from pysite.mixins import DBMixin, OAuthMixin + +log = logging.getLogger(__name__) + + +class JamsTeamEditRepo(RouteView, DBMixin, OAuthMixin): + path = "/jams/teams/<string:team_id>/edit_repo" + name = "jams.team.edit_repo" + + table_name = "code_jam_teams" + jams_table = "code_jams" + + gitlab_projects_api_endpoint = "https://gitlab.com/api/v4/projects/{0}" + + @csrf + def post(self, team_id): + if not self.user_data: + return self.redirect_login() + + try: + query = self.db.query(self.table_name).get(team_id).merge( + lambda team: { + "jam": + self.db.query("code_jams").filter( + lambda jam: jam["teams"].contains(team["id"]) + ).coerce_to("array")[0] + } + ) + + team = self.db.run(query) + except ReqlNonExistenceError: + log.exception("Failed RethinkDB query") + raise NotFound() + + if not self.user_data["user_id"] in team["members"]: + raise Unauthorized() + + repo_url = request.form.get("repo_url").strip() + + # check if repo is a valid GitLab repo URI + url = parse_url(repo_url) + + if url.host != "gitlab.com" or url.path is None: + raise BadRequest() + + project_path = url.path.strip("/") + if len(project_path.split("/")) < 2: + raise BadRequest() + + word_regex = re.compile("^[\-\w]+$") + for segment in project_path.split("/"): + if not word_regex.fullmatch(segment): + raise BadRequest() + + project_path_encoded = quote(project_path, safe='') + if not self.validate_project(team, project_path_encoded): + return + + team_obj = self.db.get(self.table_name, team_id) + team_obj["repo"] = project_path + self.db.insert(self.table_name, team_obj, conflict="update") + + return jsonify( + { + "project_path": project_path + } + ) + + def validate_project(self, team, project_path): + # check on GitLab if the project exists, and is a fork + query_response = self.request_project(project_path) + + if query_response.status_code != 200: + raise BadRequest() + + project_data = query_response.json() + if "forked_from_project" not in project_data: + raise BadRequest() + + # check if it's a fork for the right repo + forked_from_project = project_data["forked_from_project"] + + jam_repo = team["jam"]["repo"] + if not jam_repo or jam_repo == "": + return True + + jam_repo_path = quote(parse_url(jam_repo).path.strip("/"), safe='') + jam_repo_response = self.request_project(jam_repo_path) + + if jam_repo_response.status_code != 200: + return True + + jam_repo_data = jam_repo_response.json() + if jam_repo_data["id"] != forked_from_project["id"]: + raise BadRequest() + + return True + + def request_project(self, project_path): + return requests.get( + self.gitlab_projects_api_endpoint.format(project_path), + params={ + "private_token": GITLAB_ACCESS_TOKEN + } + ) |