def add_hook(self, save=True): if self.user_settings: connect = GitLabClient(external_account=self.external_account) secret = utils.make_hook_secret() hook = connect.add_hook( self.user, self.repo, 'web', { 'url': urlparse.urljoin( hook_domain, os.path.join(self.owner.api_url, 'gitlab', 'hook/')), 'content_type': gitlab_settings.HOOK_CONTENT_TYPE, 'secret': secret, }, events=gitlab_settings.HOOK_EVENTS, ) if hook: self.hook_id = hook.id self.hook_secret = secret if save: self.save()
def add_hook(self, save=True): if self.user_settings: connect = GitLabClient(external_account=self.external_account) secret = utils.make_hook_secret() hook = connect.add_hook( self.user, self.repo, 'web', { 'url': urlparse.urljoin( hook_domain, os.path.join( self.owner.api_url, 'gitlab', 'hook/' ) ), 'content_type': gitlab_settings.HOOK_CONTENT_TYPE, 'secret': secret, }, events=gitlab_settings.HOOK_EVENTS, ) if hook: self.hook_id = hook.id self.hook_secret = secret if save: self.save()
def gitlab_hgrid_data(node_settings, auth, **kwargs): # Quit if no repo linked if not node_settings.complete: return connection = GitLabClient(external_account=node_settings.external_account) # Initialize repo here in the event that it is set in the privacy check # below. This potentially saves an API call in _check_permissions, below. repo = None # Quit if privacy mismatch and not contributor node = node_settings.owner if node.is_public or node.is_contributor(auth.user): try: repo = connection.repo(node_settings.repo_id) except NotFoundError: logger.error('Could not access GitLab repo') return None try: branch, sha, branches = get_refs(node_settings, branch=kwargs.get('branch'), sha=kwargs.get('sha'), connection=connection) except (NotFoundError, GitLabError): logger.error('GitLab repo not found') return if branch is not None: ref = ref_to_params(branch, sha) can_edit = check_permissions(node_settings, auth, connection, branch, sha, repo=repo) else: ref = '' can_edit = False permissions = { 'edit': can_edit, 'view': True, 'private': node_settings.is_private } urls = { 'upload': node_settings.owner.api_url + 'gitlab/file/' + ref, 'fetch': node_settings.owner.api_url + 'gitlab/hgrid/' + ref, 'branch': node_settings.owner.api_url + 'gitlab/hgrid/root/' + ref, 'zip': 'https://{0}/{1}/repository/archive.zip?branch={2}'.format(node_settings.external_account.oauth_secret, repo.path_with_namespace, ref), 'repo': 'https://{0}/{1}/tree/{2}'.format(node_settings.external_account.oauth_secret, repo.path_with_namespace, ref) } branch_names = [each.name for each in branches] if not branch_names: branch_names = [branch] # if repo un-init-ed then still add default branch to list of branches return [rubeus.build_addon_root( node_settings, repo.path_with_namespace, urls=urls, permissions=permissions, branches=branch_names, private_key=kwargs.get('view_only', None), default_branch=repo.default_branch, )]
def gitlab_hgrid_data(node_settings, auth, **kwargs): # Quit if no repo linked if not node_settings.complete: return connection = GitLabClient(external_account=node_settings.external_account) # Initialize repo here in the event that it is set in the privacy check # below. This potentially saves an API call in _check_permissions, below. repo = None # Quit if privacy mismatch and not contributor node = node_settings.owner if node.is_public or node.is_contributor(auth.user): try: repo = connection.repo(node_settings.repo_id) except NotFoundError: logger.error('Could not access GitLab repo') return None try: branch, sha, branches = get_refs(node_settings, branch=kwargs.get('branch'), sha=kwargs.get('sha'), connection=connection) except (NotFoundError, GitLabError): logger.error('GitLab repo not found') return if branch is not None: ref = ref_to_params(branch, sha) can_edit = check_permissions(node_settings, auth, connection, branch, sha, repo=repo) else: ref = '' can_edit = False permissions = { 'edit': can_edit, 'view': True, 'private': node_settings.is_private } urls = { 'upload': node_settings.owner.api_url + 'gitlab/file/' + ref, 'fetch': node_settings.owner.api_url + 'gitlab/hgrid/' + ref, 'branch': node_settings.owner.api_url + 'gitlab/hgrid/root/' + ref, 'zip': 'https://{0}/{1}/repository/archive.zip?branch={2}'.format(node_settings.external_account.oauth_secret, repo['path_with_namespace'], ref), 'repo': 'https://{0}/{1}/tree/{2}'.format(node_settings.external_account.oauth_secret, repo['path_with_namespace'], ref) } branch_names = [each['name'] for each in branches] if not branch_names: branch_names = [branch] # if repo un-init-ed then still add default branch to list of branches return [rubeus.build_addon_root( node_settings, repo['path_with_namespace'], urls=urls, permissions=permissions, branches=branch_names, private_key=kwargs.get('view_only', None), default_branch=repo['default_branch'], )]
def before_page_load(self, node, user): """ :param Node node: :param User user: :return str: Alert message """ messages = [] # Quit if not contributor if not node.is_contributor(user): return messages # Quit if not configured if self.user is None or self.repo is None: return messages # Quit if no user authorization if self.user_settings is None: return messages connect = GitLabClient(external_account=self.external_account) try: repo = connect.repo(self.repo_id) except (ApiError, GitLabError): return except gitlab.exceptions.GitlabError as exc: if exc.response_code == 403 and 'must accept the Terms of Service' in exc.error_message: return [('Your gitlab account does not have proper authentication. Ensure you have agreed to Gitlab\'s ' 'current Terms of Service by disabling and re-enabling your account.')] else: raise exc # GitLab has visibility types: public, private, internal. node_permissions = 'public' if node.is_public else 'private' if repo.visibility != node_permissions: message = ( 'Warning: This OSF {category} is {node_perm}, but the GitLab ' 'repo {user} / {repo} has {repo_perm} visibility.'.format( category=markupsafe.escape(node.project_or_component), node_perm=markupsafe.escape(node_permissions), repo_perm=markupsafe.escape(repo.visibility), user=markupsafe.escape(self.user), repo=markupsafe.escape(self.repo), ) ) if repo.visibility == 'private': message += ( ' Users can view the contents of this private GitLab ' 'repository through this public project.' ) else: message += ( ' The files in this GitLab repo can be viewed on GitLab ' '<u><a href="{url}">here</a></u>.' ).format(url=repo.http_url_to_repo) messages.append(message) return messages
def to_json(self, user): ret = super(NodeSettings, self).to_json(user) user_settings = user.get_addon('gitlab') ret.update({ 'user_has_auth': user_settings and user_settings.has_auth, 'is_registration': self.owner.is_registration, }) if self.user_settings and self.user_settings.has_auth: valid_credentials = False owner = self.user_settings.owner connection = GitLabClient(external_account=self.external_account) valid_credentials = True try: repos = connection.repos() except GitLabError: valid_credentials = False if owner == user: ret.update({'repos': repos}) ret.update({ 'node_has_auth': True, 'gitlab_user': self.user or '', 'gitlab_repo': self.repo or '', 'gitlab_repo_id': self.repo_id if self.repo_id is not None else '0', 'gitlab_repo_full_name': '{0} / {1}'.format(self.user, self.repo) if (self.user and self.repo) else '', 'auth_osf_name': owner.fullname, 'auth_osf_url': owner.url, 'auth_osf_id': owner._id, 'gitlab_host': self.external_account.display_name, 'gitlab_user_name': self.external_account.display_name, 'gitlab_user_url': self.external_account.profile_url, 'is_owner': owner == user, 'valid_credentials': valid_credentials, 'addons_url': web_url_for('user_addons'), 'files_url': self.owner.web_url_for('collect_file_trees') }) return ret
def before_page_load(self, node, user): """ :param Node node: :param User user: :return str: Alert message """ messages = [] # Quit if not contributor if not node.is_contributor(user): return messages # Quit if not configured if self.user is None or self.repo is None: return messages # Quit if no user authorization if self.user_settings is None: return messages connect = GitLabClient(external_account=self.external_account) try: repo = connect.repo(self.repo_id) except (ApiError, GitLabError): return except gitlab.exceptions.GitlabError as exc: if exc.response_code == 403 and 'must accept the Terms of Service' in exc.error_message: return [( 'Your gitlab account does not have proper authentication. Ensure you have agreed to Gitlab\'s ' 'current Terms of Service by disabling and re-enabling your account.' )] else: raise exc # GitLab has visibility types: public, private, internal. node_permissions = 'public' if node.is_public else 'private' if repo.visibility != node_permissions: message = ( 'Warning: This OSF {category} is {node_perm}, but the GitLab ' 'repo {user} / {repo} has {repo_perm} visibility.'.format( category=markupsafe.escape(node.project_or_component), node_perm=markupsafe.escape(node_permissions), repo_perm=markupsafe.escape(repo.visibility), user=markupsafe.escape(self.user), repo=markupsafe.escape(self.repo), )) if repo.visibility == 'private': message += ( ' Users can view the contents of this private GitLab ' 'repository through this public project.') else: message += ( ' The files in this GitLab repo can be viewed on GitLab ' '<u><a href="{url}">here</a></u>.').format( url=repo.http_url_to_repo) messages.append(message) return messages
def before_page_load(self, node, user): """ :param Node node: :param User user: :return str: Alert message """ messages = [] # Quit if not contributor if not node.is_contributor(user): return messages # Quit if not configured if self.user is None or self.repo is None: return messages # Quit if no user authorization if self.user_settings is None: return messages connect = GitLabClient(external_account=self.external_account) try: repo = connect.repo(self.repo_id) except (ApiError, GitLabError): return # GitLab has visibility types: public, private, internal. node_permissions = 'public' if node.is_public else 'private' if repo.visibility != node_permissions: message = ( 'Warning: This OSF {category} is {node_perm}, but the GitLab ' 'repo {user} / {repo} has {repo_perm} visibility.'.format( category=markupsafe.escape(node.project_or_component), node_perm=markupsafe.escape(node_permissions), repo_perm=markupsafe.escape(repo.visibility), user=markupsafe.escape(self.user), repo=markupsafe.escape(self.repo), ) ) if repo.visibility == 'private': message += ( ' Users can view the contents of this private GitLab ' 'repository through this public project.' ) else: message += ( ' The files in this GitLab repo can be viewed on GitLab ' '<u><a href="{url}">here</a></u>.' ).format(url=repo.http_url_to_repo) messages.append(message) return messages
def gitlab_download_starball(node_addon, **kwargs): ref = request.args.get('branch', 'master') connection = GitLabClient(external_account=node_addon.external_account) headers, data = connection.starball(node_addon.user, node_addon.repo, node_addon.repo_id, ref) resp = make_response(data) for key, value in headers.iteritems(): resp.headers[key] = value return resp
def gitlab_download_starball(node_addon, **kwargs): ref = request.args.get('branch', 'master') connection = GitLabClient(external_account=node_addon.external_account) headers, data = connection.starball( node_addon.user, node_addon.repo, node_addon.repo_id, ref ) resp = make_response(data) for key, value in headers.iteritems(): resp.headers[key] = value return resp
def get_refs(addon, branch=None, sha=None, connection=None): """Get the appropriate branch name and sha given the addon settings object, and optionally the branch and sha from the request arguments. :param str branch: Branch name. If None, return the default branch from the repo settings. :param str sha: The SHA. :param GitLab connection: GitLab API object. If None, one will be created from the addon's user settings. """ connection = connection or GitLabClient( external_account=addon.external_account) if sha and not branch: raise HTTPError(http.BAD_REQUEST) # Get default branch if not provided if not branch: repo = connection.repo(addon.repo_id) if repo is None: return None, None, None branch = repo['default_branch'] # Get data from GitLab API if not registered branches = connection.branches(addon.repo_id) # Use registered SHA if provided for each in branches: if branch == each['name']: sha = each['commit']['id'] break return branch, sha, branches
def delete_hook(self, save=True): """ :return bool: Hook was deleted """ if self.user_settings and self.hook_id: connection = GitLabClient(external_account=self.external_account) try: response = connection.delete_hook(self.user, self.repo, self.hook_id) except (GitLabError, NotFoundError): return False if response: self.hook_id = None if save: self.save() return True return False
def credentials_are_valid(self, user_settings, client): if user_settings: client = client or GitLabClient( external_account=user_settings.external_accounts.first()) try: client.user() except (GitLabError, IndexError): return False return True
def gitlab_add_user_account(auth, **kwargs): """Verifies new external account credentials and adds to user's list""" host = request.json.get('host').rstrip('/') access_token = request.json.get('access_token') client = GitLabClient(access_token=access_token, host=host) try: user_info = client.user() except: # TODO: does gitlab even throw errors? raise if user_info.get('message') == '401 Unauthorized': raise HTTPError(http.UNAUTHORIZED) try: account = ExternalAccount( provider='gitlab', provider_name='GitLab', display_name=user_info['username'], oauth_key=access_token, oauth_secret=host, # Hijacked to allow multiple hosts provider_id=user_info['web_url'], # unique for host/username ) account.save() except ValidationError: # ... or get the old one account = ExternalAccount.objects.get( provider='gitlab', provider_id=user_info['web_url'] ) if account.oauth_key != access_token: account.oauth_key = access_token account.save() user = auth.user if not user.external_accounts.filter(id=account.id).exists(): user.external_accounts.add(account) user.get_or_add_addon('gitlab', auth=auth) user.save() return {}
def gitlab_add_user_account(auth, **kwargs): """Verifies new external account credentials and adds to user's list""" host = request.json.get('host').rstrip('/') access_token = request.json.get('access_token') client = GitLabClient(access_token=access_token, host=host) try: user_info = client.user() except: # TODO: does gitlab even throw errors? raise if user_info.get('message') == '401 Unauthorized': raise HTTPError(http.UNAUTHORIZED) try: account = ExternalAccount( provider='gitlab', provider_name='GitLab', display_name=user_info['username'], oauth_key=access_token, oauth_secret=host, # Hijacked to allow multiple hosts provider_id=user_info['web_url'], # unique for host/username ) account.save() except ValidationError: # ... or get the old one account = ExternalAccount.objects.get(provider='gitlab', provider_id=user_info['web_url']) if account.oauth_key != access_token: account.oauth_key = access_token account.save() user = auth.user if not user.external_accounts.filter(id=account.id).exists(): user.external_accounts.add(account) user.get_or_add_addon('gitlab', auth=auth) user.save() return {}
def gitlab_add_user_account(auth, **kwargs): """Verifies new external account credentials and adds to user's list""" host = request.json.get('host').rstrip('/') access_token = request.json.get('access_token') client = GitLabClient(access_token=access_token, host=host) user = client.user() try: account = ExternalAccount( provider='gitlab', provider_name='GitLab', display_name=user.username, oauth_key=access_token, oauth_secret=host, # Hijacked to allow multiple hosts provider_id=user.web_url, # unique for host/username ) account.save() except ValidationError: # ... or get the old one account = ExternalAccount.objects.get( provider='gitlab', provider_id=user.web_url ) if account.oauth_key != access_token: account.oauth_key = access_token account.save() user = auth.user if not user.external_accounts.filter(id=account.id).exists(): user.external_accounts.add(account) user.get_or_add_addon('gitlab', auth=auth) user.save() return {}
def gitlab_add_user_account(auth, **kwargs): """Verifies new external account credentials and adds to user's list""" host = request.json.get('host').rstrip('/') access_token = request.json.get('access_token') client = GitLabClient(access_token=access_token, host=host) user = client.user() try: account = ExternalAccount( provider='gitlab', provider_name='GitLab', display_name=user.username, oauth_key=access_token, oauth_secret=host, # Hijacked to allow multiple hosts provider_id=user.web_url, # unique for host/username ) account.save() except ValidationError: # ... or get the old one account = ExternalAccount.objects.get(provider='gitlab', provider_id=user.web_url) if account.oauth_key != access_token: account.oauth_key = access_token account.save() user = auth.user if not user.external_accounts.filter(id=account.id).exists(): user.external_accounts.add(account) user.get_or_add_addon('gitlab', auth=auth) user.save() return {}
class TestGitLabSerializer(StorageAddonSerializerTestSuiteMixin, OsfTestCase): addon_short_name = 'gitlab' Serializer = GitLabSerializer ExternalAccountFactory = GitLabAccountFactory client = GitLabClient() def set_provider_id(self, pid): self.node_settings.repo = pid ## Overrides ## def setUp(self): super(TestGitLabSerializer, self).setUp() self.mock_api_user = mock.patch('addons.gitlab.api.GitLabClient.user') self.mock_api_user.return_value = mock.Mock() self.mock_api_user.start() def tearDown(self): self.mock_api_user.stop() super(TestGitLabSerializer, self).tearDown() def test_serialize_acccount(self): ea = self.ExternalAccountFactory() expected = { 'id': ea._id, 'provider_id': ea.provider_id, 'provider_name': ea.provider_name, 'provider_short_name': ea.provider, 'display_name': ea.display_name, 'profile_url': ea.profile_url, 'nodes': [], 'host': ea.oauth_secret, 'host_url': ea.oauth_secret, } assert self.ser.serialize_account(ea) == expected
def is_private(self): connection = GitLabClient(external_account=self.external_account) return connection.repo(self.repo_id).visibility == 'private'
def gitlab_set_config(auth, **kwargs): node_settings = kwargs.get('node_addon', None) node = kwargs.get('node', None) user_settings = kwargs.get('user_addon', None) try: if not node: node = node_settings.owner if not user_settings: user_settings = node_settings.user_settings except AttributeError: raise HTTPError(http.BAD_REQUEST) # Parse request gitlab_user_name = request.json.get('gitlab_user', '') gitlab_repo_name = request.json.get('gitlab_repo', '') gitlab_repo_id = request.json.get('gitlab_repo_id', '') if not gitlab_user_name or not gitlab_repo_name or not gitlab_repo_id: raise HTTPError(http.BAD_REQUEST) # Verify that repo exists and that user can access connection = GitLabClient(external_account=node_settings.external_account) repo = connection.repo(gitlab_repo_id) if repo is None: if user_settings: message = ('Cannot access repo. Either the repo does not exist ' 'or your account does not have permission to view it.') else: message = ('Cannot access repo.') return {'message': message}, http.BAD_REQUEST changed = (gitlab_user_name != node_settings.user or gitlab_repo_name != node_settings.repo or gitlab_repo_id != node_settings.repo_id) # Update hooks if changed: # Delete existing hook, if any node_settings.delete_hook() # Update node settings node_settings.user = gitlab_user_name node_settings.repo = gitlab_repo_name node_settings.repo_id = gitlab_repo_id # Log repo select node.add_log( action='gitlab_repo_linked', params={ 'project': node.parent_id, 'node': node._id, 'gitlab': { 'user': gitlab_user_name, 'repo': gitlab_repo_name, 'repo_id': gitlab_repo_id, } }, auth=auth, ) # Add new hook if node_settings.user and node_settings.repo: node_settings.add_hook(save=False) node_settings.save() return {}
def gitlab_set_config(auth, **kwargs): node_settings = kwargs.get('node_addon', None) node = kwargs.get('node', None) user_settings = kwargs.get('user_addon', None) try: if not node: node = node_settings.owner if not user_settings: user_settings = node_settings.user_settings except AttributeError: raise HTTPError(http_status.HTTP_400_BAD_REQUEST) # Parse request gitlab_user_name = request.json.get('gitlab_user', '') gitlab_repo_name = request.json.get('gitlab_repo', '') gitlab_repo_id = request.json.get('gitlab_repo_id', '') if not gitlab_user_name or not gitlab_repo_name or not gitlab_repo_id: raise HTTPError(http_status.HTTP_400_BAD_REQUEST) # Verify that repo exists and that user can access connection = GitLabClient(external_account=node_settings.external_account) try: repo = connection.repo(gitlab_repo_id) except gitlab.exceptions.GitlabError as exc: if exc.response_code == 403 and 'must accept the Terms of Service' in exc.error_message: return { 'message': 'Your gitlab account does not have proper authentication. Ensure you have agreed to Gitlab\'s ' 'current Terms of Service by disabling and re-enabling your account.' }, http_status.HTTP_400_BAD_REQUEST if repo is None: if user_settings: message = ('Cannot access repo. Either the repo does not exist ' 'or your account does not have permission to view it.') else: message = ('Cannot access repo.') return {'message': message}, http_status.HTTP_400_BAD_REQUEST changed = (gitlab_user_name != node_settings.user or gitlab_repo_name != node_settings.repo or gitlab_repo_id != node_settings.repo_id) # Update hooks if changed: # Delete existing hook, if any node_settings.delete_hook() # Update node settings node_settings.user = gitlab_user_name node_settings.repo = gitlab_repo_name node_settings.repo_id = gitlab_repo_id # Log repo select node.add_log( action='gitlab_repo_linked', params={ 'project': node.parent_id, 'node': node._id, 'gitlab': { 'user': gitlab_user_name, 'repo': gitlab_repo_name, 'repo_id': gitlab_repo_id, } }, auth=auth, ) # Add new hook if node_settings.user and node_settings.repo: node_settings.add_hook(save=False) node_settings.save() return {}
def is_private(self): connection = GitLabClient(external_account=self.external_account) return not connection.repo(repo_id=self.repo_id)['public']
def gitlab_set_config(auth, **kwargs): node_settings = kwargs.get('node_addon', None) node = kwargs.get('node', None) user_settings = kwargs.get('user_addon', None) try: if not node: node = node_settings.owner if not user_settings: user_settings = node_settings.user_settings except AttributeError: raise HTTPError(http.BAD_REQUEST) # Parse request gitlab_user_name = request.json.get('gitlab_user', '') gitlab_repo_name = request.json.get('gitlab_repo', '') gitlab_repo_id = request.json.get('gitlab_repo_id', '') if not gitlab_user_name or not gitlab_repo_name or not gitlab_repo_id: raise HTTPError(http.BAD_REQUEST) # Verify that repo exists and that user can access connection = GitLabClient(external_account=node_settings.external_account) repo = connection.repo(gitlab_repo_id) if repo is None: if user_settings: message = ( 'Cannot access repo. Either the repo does not exist ' 'or your account does not have permission to view it.' ) else: message = ( 'Cannot access repo.' ) return {'message': message}, http.BAD_REQUEST changed = ( gitlab_user_name != node_settings.user or gitlab_repo_name != node_settings.repo or gitlab_repo_id != node_settings.repo_id ) # Update hooks if changed: # Delete existing hook, if any node_settings.delete_hook() # Update node settings node_settings.user = gitlab_user_name node_settings.repo = gitlab_repo_name node_settings.repo_id = gitlab_repo_id # Log repo select node.add_log( action='gitlab_repo_linked', params={ 'project': node.parent_id, 'node': node._id, 'gitlab': { 'user': gitlab_user_name, 'repo': gitlab_repo_name, 'repo_id': gitlab_repo_id, } }, auth=auth, ) # Add new hook if node_settings.user and node_settings.repo: node_settings.add_hook(save=False) node_settings.save() return {}