diff options
Diffstat (limited to 'pysite/views')
| -rw-r--r-- | pysite/views/main/jams/jam_team_list.py | 2 | ||||
| -rw-r--r-- | pysite/views/main/jams/team_edit_repo.py | 118 | 
2 files changed, 119 insertions, 1 deletions
| 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 +            } +        ) | 
