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 Dec 1, 2023
1 parent 3d3bfdc commit 5333c65
Show file tree
Hide file tree
Showing 5 changed files with 143 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
Empty file.
73 changes: 73 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,73 @@
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

_mock = lambda attributes: type('MockObject', (mock.Mock,), attributes)


def mock_bitbucket_client():
return _mock({
'repos': lambda *args, **kwargs: [
{
'full_name': 'bitbucket-user-name/test-folder'
}
],
'repo': _mock({})
})


@pytest.mark.django_db
class TestBitbucketConfig:
"""
This class tests features added for our POSE grant which will enable us to access of Bitbucket Addon entirely via
osf.io's v2 REST API. This requires giving the user the ability to configure the base folder for their bitbucket
storage via the API.
"""

@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

@mock.patch('addons.bitbucket.models.BitbucketClient', return_value=mock_bitbucket_client())
def test_addon_folders_PATCH(self, mock_bitbucket, app, node_with_authorized_addon, user):
resp = app.patch_json_api(
f'/{API_BASE}nodes/{node_with_authorized_addon._id}/addons/bitbucket/',
{
'data': {
'attributes': {
'folder_id': 'bitbucket-user-name/test-folder'
}
}
},
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'
23 changes: 22 additions & 1 deletion api_tests/nodes/views/test_node_addons.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from api.base.settings.defaults import API_BASE
from osf_tests.factories import AuthUserFactory
from tests.base import ApiAddonTestCase
from api_tests.addons_tests.bitbucket.test_bitbucket_configure import mock_bitbucket_client

from addons.mendeley.tests.factories import (
MendeleyAccountFactory, MendeleyNodeSettingsFactory
Expand Down Expand Up @@ -680,11 +681,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 +698,22 @@ def _settings_kwargs(self, node, user_settings):
'owner': self.node
}

def test_folder_list_GET_expected_behavior(self):
with mock.patch('addons.bitbucket.models.BitbucketClient', return_value=mock_bitbucket_client()):
super(TestNodeBitbucketAddon, self).test_folder_list_GET_expected_behavior()

def test_settings_detail_PUT_all_sets_settings(self):
with mock.patch('addons.bitbucket.models.BitbucketClient', return_value=mock_bitbucket_client()):
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 5333c65

Please sign in to comment.