diff --git a/readthedocs/oauth/services/gitlab.py b/readthedocs/oauth/services/gitlab.py index 672784ae461..2d853fac566 100644 --- a/readthedocs/oauth/services/gitlab.py +++ b/readthedocs/oauth/services/gitlab.py @@ -41,6 +41,10 @@ class GitLabService(Service): re.escape(urlparse(adapter.provider_base_url).netloc), ) + PERMISSION_NO_ACCESS = 0 + PERMISSION_MAINTAINER = 40 + PERMISSION_OWNER = 50 + def _get_repo_id(self, project): # The ID or URL-encoded path of the project # https://docs.gitlab.com/ce/api/README.html#namespaced-path-encoding @@ -132,13 +136,20 @@ def sync_organizations(self): return remote_organizations, remote_repositories - def is_owned_by(self, owner_id): - return self.account.extra_data['id'] == owner_id - def create_repository(self, fields, privacy=None, organization=None): """ Update or create a repository from GitLab API response. + ``admin`` field is computed using the ``permissions`` fields from the + repository response. The permission from GitLab is given by an integer: + * 0: No access + * (... others ...) + * 40: Maintainer + * 50: Owner + + https://docs.gitlab.com/ee/api/access_requests.html + https://gitlab.com/help/user/permissions + :param fields: dictionary of response data from API :param privacy: privacy level to support :param organization: remote organization to associate with @@ -179,9 +190,17 @@ def create_repository(self, fields, privacy=None, organization=None): else: repo.clone_url = fields['http_url_to_repo'] - repo.admin = not repo_is_public - if not repo.admin and 'owner' in fields: - repo.admin = self.is_owned_by(fields['owner']['id']) + project_access_level = group_access_level = self.PERMISSION_NO_ACCESS + project_access = fields.get('permissions', {}).get('project_access', {}) + if project_access: + project_access_level = project_access.get('access_level', self.PERMISSION_NO_ACCESS) + group_access = fields.get('permissions', {}).get('group_access', {}) + if group_access: + group_access_level = group_access.get('access_level', self.PERMISSION_NO_ACCESS) + repo.admin = any([ + project_access_level in (self.PERMISSION_MAINTAINER, self.PERMISSION_OWNER), + group_access_level in (self.PERMISSION_MAINTAINER, self.PERMISSION_OWNER), + ]) repo.vcs = 'git' repo.account = self.account diff --git a/readthedocs/rtd_tests/tests/test_oauth.py b/readthedocs/rtd_tests/tests/test_oauth.py index 24b197ee168..13c002cbbbf 100644 --- a/readthedocs/rtd_tests/tests/test_oauth.py +++ b/readthedocs/rtd_tests/tests/test_oauth.py @@ -951,12 +951,10 @@ def get_private_repo_data(self): return data def test_make_project_pass(self): - with mock.patch('readthedocs.oauth.services.gitlab.GitLabService.is_owned_by') as m: # yapf: disable - m.return_value = True - repo = self.service.create_repository( - self.repo_response_data, organization=self.org, - privacy=self.privacy, - ) + repo = self.service.create_repository( + self.repo_response_data, organization=self.org, + privacy=self.privacy, + ) self.assertIsInstance(repo, RemoteRepository) self.assertEqual(repo.name, 'testrepo') self.assertEqual(repo.full_name, 'testorga / testrepo') @@ -1009,9 +1007,7 @@ def test_make_private_project(self): """ data = self.repo_response_data.copy() data['visibility'] = 'public' - with mock.patch('readthedocs.oauth.services.gitlab.GitLabService.is_owned_by') as m: # yapf: disable - m.return_value = True - repo = self.service.create_repository(data, organization=self.org) + repo = self.service.create_repository(data, organization=self.org) self.assertIsNotNone(repo) @mock.patch('readthedocs.oauth.services.gitlab.log')