Skip to content

Commit

Permalink
make bitbucket configurable via api v2
Browse files Browse the repository at this point in the history
  • Loading branch information
John Tordoff committed Nov 29, 2023
1 parent 3141057 commit d413391
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 4 deletions.
47 changes: 46 additions & 1 deletion addons/bitbucket/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
from framework.auth import Auth
from osf.models.external import ExternalProvider
from osf.models.files import File, Folder, BaseFileNode
from rest_framework import exceptions as drf_exceptions
from website import settings
from website.util import web_url_for
from website.util import web_url_for, api_v2_url

hook_domain = bitbucket_settings.HOOK_DOMAIN or settings.DOMAIN

Expand Down Expand Up @@ -454,3 +455,47 @@ def before_make_public(self, node):

def after_delete(self, user):
self.deauthorize(Auth(user=user), log=True)

def get_folders(self, path, folder_id):
return [{
'id': repo['full_name'],
'path': '/',
'addon': 'bitbucket',
'kind': 'folder',
'name': repo['full_name'],
'urls': {
'folders': api_v2_url(f'nodes/{self.owner._id}/addons/bitbucket/folders/'),
}
} for repo in BitbucketClient(access_token=self.external_account.oauth_key).repos()]

def set_folder(self, folder_id, auth):
connection = BitbucketClient(access_token=self.external_account.oauth_key)
try:
username, repo = folder_id.split('/')
except ValueError:
raise drf_exceptions.PermissionDenied(f'The credentials provided are incorrect.')

if not connection.repo(username, repo):
raise drf_exceptions.PermissionDenied(f'The credentials provided are incorrect.')

user_settings = auth.user.get_or_add_addon('bitbucket')
user_settings.save()
self.user_settings = user_settings
self.save()

if folder_id != self.repo:
self.repo = repo
self.user = username
self.owner.add_log(
action='bitbucket_repo_linked',
params={
'project': self.owner.parent_id,
'node': self.owner._id,
'bitbucket': {
'user': self.external_account.display_name,
'repo': folder_id
}
},
auth=auth
)
self.save()
4 changes: 2 additions & 2 deletions api/base/settings/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,8 @@
VARNISH_SERVERS = osf_settings.VARNISH_SERVERS
ESI_MEDIA_TYPES = osf_settings.ESI_MEDIA_TYPES

ADDONS_FOLDER_CONFIGURABLE = ['box', 'dropbox', 's3', 'googledrive', 'figshare', 'owncloud', 'onedrive']
ADDONS_OAUTH = ADDONS_FOLDER_CONFIGURABLE + ['dataverse', 'github', 'bitbucket', 'gitlab', 'mendeley', 'zotero', 'forward', 'boa']
ADDONS_FOLDER_CONFIGURABLE = ['box', 'dropbox', 's3', 'googledrive', 'figshare', 'owncloud', 'onedrive', 'bitbucket']
ADDONS_OAUTH = ADDONS_FOLDER_CONFIGURABLE + ['dataverse', 'github', 'gitlab', 'mendeley', 'zotero', 'forward', 'boa']

BYPASS_THROTTLE_TOKEN = 'test-token'

Expand Down
59 changes: 59 additions & 0 deletions api_tests/addons_tests/bitbucket/test_bitbucket_configure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import mock
import pytest
from framework.auth.core import Auth
from api.base.settings.defaults import API_BASE
from osf_tests.factories import ProjectFactory, AuthUserFactory, ExternalAccountFactory
from addons.bitbucket.tests.factories import BitbucketUserSettingsFactory


@pytest.mark.django_db
class TestBitbucketConfig:

@pytest.fixture()
def user(self):
return AuthUserFactory()

@pytest.fixture()
def node(self, user):
return ProjectFactory(creator=user)

@pytest.fixture()
def enabled_addon(self, node, user):
addon = node.get_or_add_addon('bitbucket', auth=Auth(user))
addon.user_settings = BitbucketUserSettingsFactory(owner=user)
addon.save()
return addon

@pytest.fixture()
def node_with_authorized_addon(self, user, node, enabled_addon):
external_account = ExternalAccountFactory(provider='bitbucket')
enabled_addon.external_account = external_account
user_settings = enabled_addon.user_settings
user_settings.oauth_grants[node._id] = {enabled_addon.external_account._id: []}
user_settings.save()
user.external_accounts.add(external_account)
user.save()
enabled_addon.save()
return node

def setup_bitbucket_mock(self, mock_client):
mock_return = lambda attributes: type('MockObject', (mock.Mock,), attributes)
mock_client.return_value = mock_return({
'repos': lambda *args, **kwargs: [
{
'full_name': 'bitbucket-user-name/test-folder'
}
],
'repo': mock_return({})
})

@mock.patch('addons.bitbucket.models.BitbucketClient')
def test_addon_folders_PATCH(self, mock_bitbucket, app, node_with_authorized_addon, user):
self.setup_bitbucket_mock(mock_bitbucket)

payload = {'data': {'attributes': {'folder_id': 'bitbucket-user-name/test-folder'}}}

resp = app.patch_json_api(f'/{API_BASE}nodes/{node_with_authorized_addon._id}/addons/bitbucket/', payload, auth=user.auth)
assert resp.status_code == 200
assert resp.json['data']['attributes']['folder_id'] == 'test-folder'
assert resp.json['data']['attributes']['folder_path'] == 'test-folder'
41 changes: 40 additions & 1 deletion api_tests/nodes/views/test_node_addons.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,11 +680,15 @@ class TestNodeWikiAddon(NodeUnmanageableAddonTestSuiteMixin, ApiAddonTestCase):

# OAUTH

class TestNodeBitbucketAddon(NodeOAuthAddonTestSuiteMixin, ApiAddonTestCase):
class TestNodeBitbucketAddon(NodeConfigurableAddonTestSuiteMixin, ApiAddonTestCase):
short_name = 'bitbucket'
AccountFactory = BitbucketAccountFactory
NodeSettingsFactory = BitbucketNodeSettingsFactory

@property
def _mock_folder_info(self):
return {'folder_id': 'jasonkelece/0987654321'}

def _settings_kwargs(self, node, user_settings):
return {
'user_settings': self.user_settings,
Expand All @@ -693,6 +697,41 @@ def _settings_kwargs(self, node, user_settings):
'owner': self.node
}

@mock.patch('addons.bitbucket.models.BitbucketClient')
def test_folder_list_GET_expected_behavior(self, mock_client):
mock_return = lambda attributes: type('MockObject', (mock.Mock,), attributes)
mock_client.return_value = mock_return({
'repos': lambda *args, **kwargs: [
{
'full_name': 'bitbucket-user-name/test-folder'
}
],
'repo': mock_return({})
})
super(TestNodeBitbucketAddon, self).test_folder_list_GET_expected_behavior()

@mock.patch('addons.bitbucket.models.BitbucketClient')
def test_settings_detail_PUT_all_sets_settings(self, mock_client):
mock_return = lambda attributes: type('MockObject', (mock.Mock,), attributes)
mock_client.return_value = mock_return({
'repos': lambda *args, **kwargs: [
{
'full_name': 'bitbucket-user-name/test-folder'
}
],
'repo': mock_return({})
})
super(TestNodeBitbucketAddon, self).test_settings_detail_PUT_all_sets_settings()

@property
def _mock_folder_result(self):
return {
'name': 'bitbucket-user-name/test-folder',
'path': '/',
'id': 'bitbucket-user-name/test-folder',
}



class TestNodeDataverseAddon(NodeOAuthAddonTestSuiteMixin, ApiAddonTestCase):
short_name = 'dataverse'
Expand Down

0 comments on commit d413391

Please sign in to comment.