diff --git a/settings/common.py b/settings/common.py index a0156181..5bc1605c 100644 --- a/settings/common.py +++ b/settings/common.py @@ -561,19 +561,30 @@ MAX_PENDING_MEMBERSHIPS = 30 # Max number of unconfirmed memberships in a projec from .sr import * -GITHUB_API_CLIENT_ID = "" -GITHUB_API_CLIENT_SECRET = "" - -TRELLO_API_KEY = "" -TRELLO_SECRET_KEY = "" - -ASANA_APP_CALLBACK_URL = "" -ASANA_APP_ID = "" -ASANA_APP_SECRET = "" - -JIRA_CONSUMER_KEY = "" -JIRA_CERT = "" -JIRA_PUB_CERT = "" +IMPORTERS = { + "github": { + "active": False, + "client_id": "", + "client_secret": "", + }, + "trello": { + "active": False, + "api_key": "", + "secret_key": "", + }, + "jira": { + "active": False, + "consumer_key": "", + "cert": "", + "pub_cert": "", + }, + "asana": { + "active": False, + "callback_url": "", + "app_id": "", + "app_secret": "", + } +} # NOTE: DON'T INSERT MORE SETTINGS AFTER THIS LINE TEST_RUNNER="django.test.runner.DiscoverRunner" diff --git a/settings/testing.py b/settings/testing.py index 12532b9b..ffabbe12 100644 --- a/settings/testing.py +++ b/settings/testing.py @@ -38,3 +38,9 @@ REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"] = { "register-success": None, "user-detail": None, } + + +IMPORTERS['github']['active'] = True +IMPORTERS['jira']['active'] = True +IMPORTERS['asana']['active'] = True +IMPORTERS['trello']['active'] = True diff --git a/taiga/importers/asana/api.py b/taiga/importers/asana/api.py index d92dda55..b13914bf 100644 --- a/taiga/importers/asana/api.py +++ b/taiga/importers/asana/api.py @@ -114,7 +114,11 @@ class AsanaImporterViewSet(viewsets.ViewSet): def auth_url(self, request, *args, **kwargs): self.check_permissions(request, "auth_url", None) - url = AsanaImporter.get_auth_url(settings.ASANA_APP_ID, settings.ASANA_APP_SECRET, settings.ASANA_APP_CALLBACK_URL) + url = AsanaImporter.get_auth_url( + settings.IMPORTERS.get('asana', {}).get('app_id', None), + settings.IMPORTERS.get('asana', {}).get('app_secret', None), + settings.IMPORTERS.get('asana', {}).get('callback_url', None) + ) return response.Ok({"url": url}) @@ -127,7 +131,12 @@ class AsanaImporterViewSet(viewsets.ViewSet): raise exc.BadRequest(_("Code param needed")) try: - asana_token = AsanaImporter.get_access_token(code, settings.ASANA_APP_ID, settings.ASANA_APP_SECRET, settings.ASANA_APP_CALLBACK_URL) + asana_token = AsanaImporter.get_access_token( + code, + settings.IMPORTERS.get('asana', {}).get('app_id', None), + settings.IMPORTERS.get('asana', {}).get('app_secret', None), + settings.IMPORTERS.get('asana', {}).get('callback_url', None) + ) except exceptions.InvalidRequest: raise exc.BadRequest(_('Invalid Asana API request')) except exceptions.FailedRequest: diff --git a/taiga/importers/github/api.py b/taiga/importers/github/api.py index 675d7a90..0c7af495 100644 --- a/taiga/importers/github/api.py +++ b/taiga/importers/github/api.py @@ -110,7 +110,10 @@ class GithubImporterViewSet(viewsets.ViewSet): def auth_url(self, request, *args, **kwargs): self.check_permissions(request, "auth_url", None) callback_uri = request.QUERY_PARAMS.get('uri') - url = GithubImporter.get_auth_url(settings.GITHUB_API_CLIENT_ID, callback_uri) + url = GithubImporter.get_auth_url( + settings.IMPORTERS.get('github', {}).get('client_id', None), + callback_uri + ) return response.Ok({"url": url}) @list_route(methods=["POST"]) @@ -122,7 +125,11 @@ class GithubImporterViewSet(viewsets.ViewSet): raise exc.BadRequest(_("Code param needed")) try: - token = GithubImporter.get_access_token(settings.GITHUB_API_CLIENT_ID, settings.GITHUB_API_CLIENT_SECRET, code) + token = GithubImporter.get_access_token( + settings.IMPORTERS.get('github', {}).get('client_id', None), + settings.IMPORTERS.get('github', {}).get('client_secret', None), + code + ) return response.Ok({ "token": token }) diff --git a/taiga/importers/jira/api.py b/taiga/importers/jira/api.py index 5e0d1de8..c704a2fd 100644 --- a/taiga/importers/jira/api.py +++ b/taiga/importers/jira/api.py @@ -40,8 +40,8 @@ class JiraImporterViewSet(viewsets.ViewSet): token = { "access_token": token_data[0], "access_token_secret": token_data[1], - "key_cert": settings.JIRA_CERT, - "consumer_key": settings.JIRA_CONSUMER_KEY + "key_cert": settings.IMPORTERS.get('jira', {}).get('cert', None), + "consumer_key": settings.IMPORTERS.get('jira', {}).get('consumer_key', None) } return token @@ -180,8 +180,8 @@ class JiraImporterViewSet(viewsets.ViewSet): (oauth_token, oauth_secret, url) = JiraNormalImporter.get_auth_url( jira_url, - settings.JIRA_CONSUMER_KEY, - settings.JIRA_CERT, + settings.IMPORTERS.get('jira', {}).get('consumer_key', None), + settings.IMPORTERS.get('jira', {}).get('cert', None), True ) @@ -215,8 +215,8 @@ class JiraImporterViewSet(viewsets.ViewSet): jira_token = JiraNormalImporter.get_access_token( server_url, - settings.JIRA_CONSUMER_KEY, - settings.JIRA_CERT, + settings.IMPORTERS.get('jira', {}).get('consumer_key', None), + settings.IMPORTERS.get('jira', {}).get('cert', None), oauth_token, oauth_secret, True diff --git a/taiga/importers/management/commands/import_from_asana.py b/taiga/importers/management/commands/import_from_asana.py index d7d7dd21..9d954422 100644 --- a/taiga/importers/management/commands/import_from_asana.py +++ b/taiga/importers/management/commands/import_from_asana.py @@ -52,10 +52,19 @@ class Command(BaseCommand): if options.get('token', None): token = json.loads(options.get('token')) else: - url = AsanaImporter.get_auth_url(settings.ASANA_APP_ID, settings.ASANA_APP_SECRET, settings.ASANA_APP_CALLBACK_URL) + url = AsanaImporter.get_auth_url( + settings.IMPORTERS.get('asana', {}).get('app_id', None), + settings.IMPORTERS.get('asana', {}).get('app_secret', None), + settings.IMPORTERS.get('asana', {}).get('callback_url', None) + ) print("Go to here and come with your code (in the redirected url): {}".format(url)) code = input("Code: ") - access_data = AsanaImporter.get_access_token(code, settings.ASANA_APP_ID, settings.ASANA_APP_SECRET, settings.ASANA_APP_CALLBACK_URL) + access_data = AsanaImporter.get_access_token( + code, + settings.IMPORTERS.get('asana', {}).get('app_id', None), + settings.IMPORTERS.get('asana', {}).get('app_secret', None), + settings.IMPORTERS.get('asana', {}).get('callback_url', None) + ) token = access_data importer = AsanaImporter(admin, token) diff --git a/taiga/importers/management/commands/import_from_github.py b/taiga/importers/management/commands/import_from_github.py index 9c93a527..e2ad7b96 100644 --- a/taiga/importers/management/commands/import_from_github.py +++ b/taiga/importers/management/commands/import_from_github.py @@ -51,10 +51,16 @@ class Command(BaseCommand): if options.get('token', None): token = options.get('token') else: - url = GithubImporter.get_auth_url(settings.GITHUB_API_CLIENT_ID) + url = GithubImporter.get_auth_url( + settings.IMPORTERS.get('github', {}).get('client_id', None) + ) print("Go to here and come with your code (in the redirected url): {}".format(url)) code = input("Code: ") - access_data = GithubImporter.get_access_token(settings.GITHUB_API_CLIENT_ID, settings.GITHUB_API_CLIENT_SECRET, code) + access_data = GithubImporter.get_access_token( + settings.IMPORTERS.get('github', {}).get('client_id', None) + settings.IMPORTERS.get('github', {}).get('client_secret', None) + code + ) token = access_data importer = GithubImporter(admin, token) diff --git a/taiga/importers/management/commands/import_from_jira.py b/taiga/importers/management/commands/import_from_jira.py index 972e6ba6..30c723d6 100644 --- a/taiga/importers/management/commands/import_from_jira.py +++ b/taiga/importers/management/commands/import_from_jira.py @@ -62,10 +62,22 @@ class Command(BaseCommand): elif options.get('token', None): token = json.loads(options.get('token')) else: - (rtoken, rtoken_secret, url) = JiraNormalImporter.get_auth_url(server, settings.JIRA_CONSUMER_KEY, settings.JIRA_CERT, True) + (rtoken, rtoken_secret, url) = JiraNormalImporter.get_auth_url( + server, + settings.IMPORTERS.get('jira', {}).get('consumer_key', None), + settings.IMPORTERS.get('jira', {}).get('cert', None), + True + ) print(url) code = input("Go to the url and get back the code") - token = JiraNormalImporter.get_access_token(server, settings.JIRA_CONSUMER_KEY, settings.JIRA_CERT, rtoken, rtoken_secret, True) + token = JiraNormalImporter.get_access_token( + server, + settings.IMPORTERS.get('jira', {}).get('consumer_key', None), + settings.IMPORTERS.get('jira', {}).get('cert', None), + rtoken, + rtoken_secret, + True + ) print("Auth token: {}".format(json.dumps(token))) diff --git a/taiga/importers/trello/importer.py b/taiga/importers/trello/importer.py index e41063b8..c36e3086 100644 --- a/taiga/importers/trello/importer.py +++ b/taiga/importers/trello/importer.py @@ -92,8 +92,8 @@ class TrelloImporter: self._user = user self._cached_orgs = {} self._client = TrelloClient( - api_key=settings.TRELLO_API_KEY, - api_secret=settings.TRELLO_SECRET_KEY, + api_key=settings.IMPORTERS.get('trello', {}).get('api_key', None), + api_secret=settings.IMPORTERS.get('trello', {}).get('secret_key', None), token=token, ) @@ -492,8 +492,8 @@ class TrelloImporter: return_url = resolve_front_url("new-project-import", "trello") expiration = "1day" scope = "read,write,account" - trello_key = settings.TRELLO_API_KEY - trello_secret = settings.TRELLO_SECRET_KEY + trello_key = settings.IMPORTERS.get('trello', {}).get('api_key', None) + trello_secret = settings.IMPORTERS.get('trello', {}).get('secret_key', None) name = "Taiga" session = OAuth1Session(client_key=trello_key, client_secret=trello_secret) @@ -515,8 +515,8 @@ class TrelloImporter: @classmethod def get_access_token(cls, oauth_token, oauth_token_secret, oauth_verifier): - api_key = settings.TRELLO_API_KEY - api_secret = settings.TRELLO_SECRET_KEY + api_key = settings.IMPORTERS.get('trello', {}).get('api_key', None) + api_secret = settings.IMPORTERS.get('trello', {}).get('secret_key', None) access_token_url = 'https://trello.com/1/OAuthGetAccessToken' session = OAuth1Session(client_key=api_key, client_secret=api_secret, resource_owner_key=oauth_token, resource_owner_secret=oauth_token_secret, diff --git a/taiga/routers.py b/taiga/routers.py index 382ede82..013e7453 100644 --- a/taiga/routers.py +++ b/taiga/routers.py @@ -17,6 +17,7 @@ # along with this program. If not, see . from taiga.base import routers +from django.conf import settings router = routers.DefaultRouter(trailing_slash=False) @@ -284,15 +285,21 @@ router.register(r"applications", Application, base_name="applications") router.register(r"application-tokens", ApplicationToken, base_name="application-tokens") # Third party importers -from taiga.importers.trello.api import TrelloImporterViewSet -from taiga.importers.jira.api import JiraImporterViewSet -from taiga.importers.github.api import GithubImporterViewSet -from taiga.importers.asana.api import AsanaImporterViewSet +if settings.IMPORTERS.get('trello', {}).get('active', False): + from taiga.importers.trello.api import TrelloImporterViewSet + router.register(r"importers/trello", TrelloImporterViewSet, base_name="importers-trello") -router.register(r"importers/trello", TrelloImporterViewSet, base_name="importers-trello") -router.register(r"importers/jira", JiraImporterViewSet, base_name="importers-jira") -router.register(r"importers/github", GithubImporterViewSet, base_name="importers-github") -router.register(r"importers/asana", AsanaImporterViewSet, base_name="importers-asana") +if settings.IMPORTERS.get('jira', {}).get('active', False): + from taiga.importers.jira.api import JiraImporterViewSet + router.register(r"importers/jira", JiraImporterViewSet, base_name="importers-jira") + +if settings.IMPORTERS.get('github', {}).get('active', False): + from taiga.importers.github.api import GithubImporterViewSet + router.register(r"importers/github", GithubImporterViewSet, base_name="importers-github") + +if settings.IMPORTERS.get('asana', {}).get('active', False): + from taiga.importers.asana.api import AsanaImporterViewSet + router.register(r"importers/asana", AsanaImporterViewSet, base_name="importers-asana") # Stats diff --git a/tests/integration/test_importers_asana_api.py b/tests/integration/test_importers_asana_api.py index aab4d143..d44a7232 100644 --- a/tests/integration/test_importers_asana_api.py +++ b/tests/integration/test_importers_asana_api.py @@ -35,16 +35,20 @@ pytestmark = pytest.mark.django_db def test_auth_url(client, settings): user = f.UserFactory.create() client.login(user) - settings.ASANA_APP_CALLBACK_URL = "http://testserver/url" - settings.ASANA_APP_ID = "test-id" - settings.ASANA_APP_SECRET = "test-secret" + settings.IMPORTERS['asana']['callback_url'] = "http://testserver/url" + settings.IMPORTERS['asana']['app_id'] = "test-id" + settings.IMPORTERS['asana']['app_secret'] = "test-secret" url = reverse("importers-asana-auth-url") with mock.patch('taiga.importers.asana.api.AsanaImporter') as AsanaImporterMock: AsanaImporterMock.get_auth_url.return_value = "https://auth_url" response = client.get(url, content_type="application/json") - assert AsanaImporterMock.get_auth_url.calledWith(settings.ASANA_APP_ID, settings.ASANA_APP_SECRET, settings.ASANA_APP_CALLBACK_URL) + assert AsanaImporterMock.get_auth_url.calledWith( + settings.IMPORTERS['asana']['app_id'], + settings.IMPORTERS['asana']['app_secret'], + settings.IMPORTERS['asana']['callback_url'] + ) assert response.status_code == 200 assert 'url' in response.data @@ -60,7 +64,11 @@ def test_authorize(client, settings): with mock.patch('taiga.importers.asana.api.AsanaImporter') as AsanaImporterMock: AsanaImporterMock.get_access_token.return_value = "token" response = client.post(authorize_url, content_type="application/json", data=json.dumps({"code": "code"})) - assert AsanaImporterMock.get_access_token.calledWith(settings.ASANA_APP_ID, settings.ASANA_APP_SECRET, "code") + assert AsanaImporterMock.get_access_token.calledWith( + settings.IMPORTERS['asana']['app_id'], + settings.IMPORTERS['asana']['app_secret'], + "code" + ) assert response.status_code == 200 assert 'token' in response.data @@ -90,7 +98,11 @@ def test_authorize_with_bad_verify(client, settings): with mock.patch('taiga.importers.asana.api.AsanaImporter') as AsanaImporterMock: AsanaImporterMock.get_access_token.side_effect = exceptions.InvalidRequest() response = client.post(authorize_url, content_type="application/json", data=json.dumps({"code": "bad"})) - assert AsanaImporterMock.get_access_token.calledWith(settings.ASANA_APP_ID, settings.ASANA_APP_SECRET, "bad") + assert AsanaImporterMock.get_access_token.calledWith( + settings.IMPORTERS['asana']['app_id'], + settings.IMPORTERS['asana']['app_secret'], + "bad" + ) assert response.status_code == 400 assert 'token' not in response.data diff --git a/tests/integration/test_importers_github_api.py b/tests/integration/test_importers_github_api.py index bda1c928..4d30b8ff 100644 --- a/tests/integration/test_importers_github_api.py +++ b/tests/integration/test_importers_github_api.py @@ -53,7 +53,11 @@ def test_authorize(client, settings): with mock.patch('taiga.importers.github.api.GithubImporter') as GithubImporterMock: GithubImporterMock.get_access_token.return_value = "token" response = client.post(authorize_url, content_type="application/json", data=json.dumps({"code": "code"})) - assert GithubImporterMock.get_access_token.calledWith(settings.GITHUB_API_CLIENT_ID, settings.GITHUB_API_CLIENT_SECRET, "code") + assert GithubImporterMock.get_access_token.calledWith( + settings.IMPORTERS['github']['client_id'], + settings.IMPORTERS['github']['client_secret'], + "code" + ) assert response.status_code == 200 assert 'token' in response.data @@ -82,7 +86,11 @@ def test_authorize_with_bad_verify(client, settings): with mock.patch('taiga.importers.github.api.GithubImporter') as GithubImporterMock: GithubImporterMock.get_access_token.side_effect = exceptions.InvalidAuthResult() response = client.post(authorize_url, content_type="application/json", data=json.dumps({"code": "bad"})) - assert GithubImporterMock.get_access_token.calledWith(settings.GITHUB_API_CLIENT_ID, settings.GITHUB_API_CLIENT_SECRET, "bad") + assert GithubImporterMock.get_access_token.calledWith( + settings.IMPORTERS['github']['client_id'], + settings.IMPORTERS['github']['client_secret'], + "bad" + ) assert response.status_code == 400 assert 'token' not in response.data