diff --git a/arkindex/dataimport/urls.py b/arkindex/dataimport/urls.py index d3ef6be5cb7c94ef719f1263ad0a3577129b7779..ed4abd173ade2d40a71c24e082199e34f3a5c2f1 100644 --- a/arkindex/dataimport/urls.py +++ b/arkindex/dataimport/urls.py @@ -1,18 +1,12 @@ from django.conf.urls import url -from arkindex.dataimport.views import ( - DataImportsList, DataImportStatus, DataImportFailures, DataFileList, - RepositoryList, RepositoryCreate, -) -from arkindex.users.views import CredentialsList, OAuthCallback - +from arkindex.project.views import FrontendView urlpatterns = [ - url(r'^$', DataImportsList.as_view(), name='imports'), - url(r'^(?P<pk>[\w\-]+)/status/?$', DataImportStatus.as_view(), name='import-status'), - url(r'^(?P<pk>[\w\-]+)/failures/?$', DataImportFailures.as_view(), name='import-failures'), - url(r'^files/?$', DataFileList.as_view(), name='files'), - url(r'^repos/?$', RepositoryList.as_view(), name='repositories'), - url(r'^repos/new/?$', RepositoryCreate.as_view(), name='repositories-create'), - url(r'^credentials/?$', CredentialsList.as_view(), name='credentials'), - url(r'^oauth/(?P<provider>\w+)/callback/?$', OAuthCallback.as_view(), name='oauth-callback'), + url(r'^$', FrontendView.as_view(), name='imports'), + url(r'^(?P<pk>[\w\-]+)/status/?$', FrontendView.as_view(), name='import-status'), + url(r'^(?P<pk>[\w\-]+)/failures/?$', FrontendView.as_view(), name='import-failures'), + url(r'^files/?$', FrontendView.as_view(), name='files'), + url(r'^repos/?$', FrontendView.as_view(), name='repositories'), + url(r'^repos/new/?$', FrontendView.as_view(), name='repositories-create'), + url(r'^credentials/?$', FrontendView.as_view(), name='credentials'), ] diff --git a/arkindex/dataimport/views.py b/arkindex/dataimport/views.py deleted file mode 100644 index 2bbca71a40391a89c3920ca04760f4a2074bc927..0000000000000000000000000000000000000000 --- a/arkindex/dataimport/views.py +++ /dev/null @@ -1,62 +0,0 @@ -from django.views.generic import TemplateView, DetailView -from django.contrib.auth.mixins import LoginRequiredMixin -from arkindex.documents.models import Corpus -from arkindex.dataimport.models import DataImport, DataImportState - - -class DataImportsList(LoginRequiredMixin, TemplateView): - """ - List data imports using Vue JS + API - """ - template_name = 'dataimport/list.html' - - -class DataImportStatus(LoginRequiredMixin, DetailView): - """ - View a data import workflow's status - """ - template_name = 'dataimport/status.html' - context_object_name = 'dataimport' - - def get_queryset(self): - return DataImport.objects.filter( - corpus__in=Corpus.objects.readable(self.request.user), - ).exclude( - state__in=[DataImportState.Created, DataImportState.Configured], - ) - - -class DataImportFailures(LoginRequiredMixin, DetailView): - """ - View a data import workflow's failures - """ - template_name = 'dataimport/failures.html' - context_object_name = 'dataimport' - - def get_queryset(self): - return DataImport.objects.filter( - corpus__in=Corpus.objects.readable(self.request.user), - ).exclude( - state__in=[DataImportState.Created, DataImportState.Configured], - ) - - -class DataFileList(LoginRequiredMixin, TemplateView): - """ - View and manage uploaded files - """ - template_name = 'dataimport/files.html' - - -class RepositoryList(LoginRequiredMixin, TemplateView): - """ - Manage repositories - """ - template_name = 'dataimport/repositories.html' - - -class RepositoryCreate(LoginRequiredMixin, TemplateView): - """ - Create a new repository - """ - template_name = 'dataimport/repository.new.html' diff --git a/arkindex/project/api_v1.py b/arkindex/project/api_v1.py index cb3dbc8cdac9b0e0c6bb789c479c7a629127ba56..65afc19b5c8089397d6da2b290da7f1110dd798f 100644 --- a/arkindex/project/api_v1.py +++ b/arkindex/project/api_v1.py @@ -18,7 +18,7 @@ from arkindex.dataimport.api import ( GitRepositoryImportHook, AvailableRepositoriesList, ElementHistory, ) from arkindex.users.api import ( - ProvidersList, CredentialsList, CredentialsRetrieve, OAuthSignIn, OAuthRetry, + ProvidersList, CredentialsList, CredentialsRetrieve, OAuthSignIn, OAuthRetry, OAuthCallback, UserRetrieve, UserCreate, UserEmailLogin, UserEmailVerification ) @@ -105,6 +105,7 @@ api = [ # Manage OAuth integrations url(r'^oauth/providers/$', ProvidersList.as_view(), name='providers-list'), url(r'^oauth/providers/(?P<provider>[\w\-]+)/signin/$', OAuthSignIn.as_view(), name='oauth-signin'), + url(r'^oauth/providers/(?P<provider>[\w\-]+)/callback/$', OAuthCallback.as_view(), name='oauth-callback'), url(r'^oauth/credentials/$', CredentialsList.as_view(), name='credentials-list'), url(r'^oauth/credentials/(?P<pk>[\w\-]+)/$', CredentialsRetrieve.as_view(), name='credentials-retrieve'), url(r'^oauth/credentials/(?P<pk>[\w\-]+)/retry/$', OAuthRetry.as_view(), name='oauth-retry'), diff --git a/arkindex/templates/dataimport/credentials.html b/arkindex/templates/dataimport/credentials.html deleted file mode 100644 index f8060b8b55bfc6e4e8d9413df334d9e8249de917..0000000000000000000000000000000000000000 --- a/arkindex/templates/dataimport/credentials.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} - -{% block content %} -<div id="app"> - <OAuth-List /> -</div> -{% endblock %} diff --git a/arkindex/templates/dataimport/failures.html b/arkindex/templates/dataimport/failures.html deleted file mode 100644 index d14b8d8e9dfcf472367a91a213e1a4262b3f92e3..0000000000000000000000000000000000000000 --- a/arkindex/templates/dataimport/failures.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} - -{% block content %} -<div id="app"> - <Import-Failures id="{{ dataimport.id }}" /> -</div> -{% endblock %} diff --git a/arkindex/templates/dataimport/files.html b/arkindex/templates/dataimport/files.html deleted file mode 100644 index 69fc93a9532fb63176217fe19e54c226fc8c846b..0000000000000000000000000000000000000000 --- a/arkindex/templates/dataimport/files.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} - -{% block content %} -<div id="app"> - <Files-List /> -</div> -{% endblock %} diff --git a/arkindex/templates/dataimport/list.html b/arkindex/templates/dataimport/list.html deleted file mode 100644 index 1af69ce04b5aa990d2a70d539a4918874cd61354..0000000000000000000000000000000000000000 --- a/arkindex/templates/dataimport/list.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} - -{% block content %} -<div id="app"> - <Imports-List /> -</div> -{% endblock %} diff --git a/arkindex/templates/dataimport/repositories.html b/arkindex/templates/dataimport/repositories.html deleted file mode 100644 index d0f5107af8e14f05a5d45f80a6b9b0f777e12e22..0000000000000000000000000000000000000000 --- a/arkindex/templates/dataimport/repositories.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} - -{% block content %} -<div id="app"> - <Repos-List /> -</div> -{% endblock %} diff --git a/arkindex/templates/dataimport/repository.new.html b/arkindex/templates/dataimport/repository.new.html deleted file mode 100644 index d7a054cb0252852bfa56c53d0b05ac996b2463a7..0000000000000000000000000000000000000000 --- a/arkindex/templates/dataimport/repository.new.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} - -{% block content %} -<div id="app"> - <Repos-Create /> -</div> -{% endblock %} diff --git a/arkindex/templates/dataimport/status.html b/arkindex/templates/dataimport/status.html deleted file mode 100644 index 681dfec717bdc98cc69be01a32d20945106e8c8c..0000000000000000000000000000000000000000 --- a/arkindex/templates/dataimport/status.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} - -{% block content %} -<div id="app"> - <Import-Status id="{{ dataimport.id }}" /> -</div> -{% endblock %} diff --git a/arkindex/users/api.py b/arkindex/users/api.py index 19b2594f41b6054c1fea9c195e838cf1cf111df6..ec0e6e874188dd6b9221843e3aede3fee62f5b4e 100644 --- a/arkindex/users/api.py +++ b/arkindex/users/api.py @@ -2,6 +2,7 @@ from django.urls import reverse from django.core.mail import send_mail from django.contrib.auth import login, logout from django.contrib.auth.tokens import default_token_generator +from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import Group from django.views.generic import RedirectView from django.template.loader import render_to_string @@ -198,3 +199,26 @@ class OAuthRetry(RetrieveAPIView): return Response({ 'url': creds.provider_class(request=self.request, credentials=creds).get_authorize_uri(), }) + + +class OAuthCallback(LoginRequiredMixin, RedirectView): + """ + Callback for OAuth responses + """ + + pattern_name = 'credentials' + + def get(self, request, *args, **kwargs): + assert 'provider' in kwargs + provider_class = get_provider(kwargs['provider']) + if not provider_class: + raise ValueError('Unknown provider') + provider = provider_class(self.request) + try: + provider.handle_callback() + except Exception: + if not provider.credentials: + raise + provider.credentials.status = OAuthStatus.Error + provider.credentials.save() + return super().get(request) diff --git a/arkindex/users/providers.py b/arkindex/users/providers.py index a629ab0208a0ed8cf0e20dff6c19275445ef35f5..d4d8ed461a20e15b938169aae52422b613c41b9b 100644 --- a/arkindex/users/providers.py +++ b/arkindex/users/providers.py @@ -79,7 +79,7 @@ class GitLabOAuthProvider(OAuthProvider): if not self.request: return return self.request.build_absolute_uri( - reverse('oauth-callback', kwargs={'provider': self.slug}), + reverse('api:oauth-callback', kwargs={'provider': self.slug}), ) def get_authorize_uri(self): diff --git a/arkindex/users/tests/test_gitlab_oauth.py b/arkindex/users/tests/test_gitlab_oauth.py index c21bccdf040d7a5dbd7a6c662e59ca29c83355b2..975625e86ac8b1843dc640de8f5582de8013a0a9 100644 --- a/arkindex/users/tests/test_gitlab_oauth.py +++ b/arkindex/users/tests/test_gitlab_oauth.py @@ -34,7 +34,7 @@ class TestGitLabOAuthProvider(FixtureTestCase): GitLabOAuthProvider(request=request_mock).get_callback_uri() self.assertEqual(request_mock.build_absolute_uri.call_count, 1) args, kwargs = request_mock.build_absolute_uri.call_args - self.assertTupleEqual(args, (reverse('oauth-callback', kwargs={'provider': 'gitlab'}), )) + self.assertTupleEqual(args, (reverse('api:oauth-callback', kwargs={'provider': 'gitlab'}), )) self.assertDictEqual(kwargs, {}) def test_authorize_uri(self): diff --git a/arkindex/users/tests/test_providers.py b/arkindex/users/tests/test_providers.py index c6e380689806fbb3906f50973ae4bcf8e68328a2..a395de36245d8a0553c24393e1f08c4e2e70a622 100644 --- a/arkindex/users/tests/test_providers.py +++ b/arkindex/users/tests/test_providers.py @@ -1,15 +1,40 @@ +from django.urls import reverse +from arkindex.project.tests import FixtureTestCase from arkindex.users import providers +from arkindex.users.models import OAuthStatus from arkindex.users.providers import get_provider -from django.test import TestCase +from unittest.mock import MagicMock -class TestProviders(TestCase): +class TestProviders(FixtureTestCase): - def test_get_provider(self): + @classmethod + def setUpTestData(cls): + super().setUpTestData() + cls.creds = cls.user.credentials.get() + cls.provider_mock = MagicMock() + cls.provider_mock.slug = 'provider-slug' + cls.provider_mock().credentials = cls.creds + # Raise anything to test callback error handling + cls.provider_mock().handle_callback.side_effect = ValueError + + def setUp(self): + self.old_providers = providers.oauth_providers + providers.oauth_providers = [self.provider_mock] - class SomeProvider(object): - slug = 'provider-slug' + def tearDown(self): + providers.oauth_providers = self.old_providers - providers.oauth_providers = [SomeProvider] - self.assertEqual(get_provider('provider-slug'), SomeProvider) + def test_get_provider(self): + self.assertEqual(get_provider('provider-slug'), self.provider_mock) self.assertIsNone(get_provider('doesnotexist')) + + def test_oauth_callback_error(self): + self.client.force_login(self.user) + self.creds.status = OAuthStatus.Created + self.creds.save() + response = self.client.get( + reverse('api:oauth-callback', kwargs={'provider': 'provider-slug'}), + ) + self.assertRedirects(response, reverse('credentials')) + self.assertEqual(self.creds.status, OAuthStatus.Error) diff --git a/arkindex/users/views.py b/arkindex/users/views.py deleted file mode 100644 index 83450bceba487af61afb4403a9e89f252ad8cc33..0000000000000000000000000000000000000000 --- a/arkindex/users/views.py +++ /dev/null @@ -1,34 +0,0 @@ -from django.views.generic import RedirectView, TemplateView -from django.contrib.auth.mixins import LoginRequiredMixin -from arkindex.users.models import OAuthStatus -from arkindex.users.providers import get_provider - - -class OAuthCallback(LoginRequiredMixin, RedirectView): - """ - Callback for OAuth responses - """ - - pattern_name = 'credentials' - - def get(self, request, *args, **kwargs): - assert 'provider' in kwargs - provider_class = get_provider(kwargs['provider']) - if not provider_class: - raise ValueError('Unknown provider') - provider = provider_class(self.request) - try: - provider.handle_callback() - except Exception: - if not provider.credentials: - raise - provider.credentials.status = OAuthStatus.Error - provider.credentials.save() - return super().get(request) - - -class CredentialsList(LoginRequiredMixin, TemplateView): - """ - View and manage OAuth providers - """ - template_name = 'dataimport/credentials.html'