Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

trial workflow fixes #838

Merged
merged 6 commits into from
Mar 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ def with_organization_context(site_color, configs=None):
yield org


def create_org_user(organization, **kwargs):
def create_org_user(organization, is_amc_admin=False, **kwargs):
"""
Create one user and save it to the database.
"""
user = UserFactory.create(**kwargs)
UserOrganizationMapping.objects.create(user=user, organization=organization)
UserOrganizationMapping.objects.create(user=user, organization=organization, is_amc_admin=is_amc_admin)
return user


Expand Down
13 changes: 6 additions & 7 deletions openedx/core/djangoapps/appsembler/sites/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
from django.conf.urls import url
from django.conf import settings
from django.template.response import TemplateResponse
from django.utils.html import format_html
from hijack_admin.admin import HijackUserAdminMixin
from ratelimitbackend import admin
from student.admin import UserAdmin

from openedx.core.djangolib.markup import HTML, Text
from openedx.core.djangoapps.appsembler.sites.models import AlternativeDomain
from organizations.models import UserOrganizationMapping

Expand All @@ -24,7 +24,7 @@
class TahoeUserAdmin(UserAdmin, HijackUserAdminMixin):
list_display = UserAdmin.list_display + (
'hijack_field',
'make_amc_admin_action',
'amc_actions',
)

def get_urls(self):
Expand All @@ -36,12 +36,11 @@ def get_urls(self):
),
] + super(UserAdmin, self).get_urls()

def make_amc_admin_action(self, obj):
return HTML('<a class="button" href="{href}">AMC Admin Form</a> ').format(
href=Text(reverse('admin:make-amc-admin', args=[obj.id])),
def amc_actions(self, obj):
return format_html(
'<a class="button" href="{href}">AMC Admin Form</a> ',
href=reverse('admin:make-amc-admin', args=[obj.id])
)
make_amc_admin_action.short_description = 'AMC Actions'
make_amc_admin_action.allow_tags = True

def process_make_amc_admin(self, request, user_id, *args, **kwargs):
user = self.get_object(request, user_id)
Expand Down
8 changes: 4 additions & 4 deletions openedx/core/djangoapps/appsembler/sites/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from rest_framework.views import APIView
from openedx.core.lib.api.permissions import ApiKeyHeaderPermission
from openedx.core.lib.api.authentication import (
OAuth2AuthenticationAllowInactiveUser,
BearerAuthenticationAllowInactiveUser,
)
from openedx.core.djangoapps.appsembler.sites.models import AlternativeDomain
from openedx.core.djangoapps.appsembler.sites.permissions import AMCAdminPermission
Expand All @@ -40,14 +40,14 @@
class SiteViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Site.objects.all()
serializer_class = SiteSerializer
authentication_classes = (OAuth2AuthenticationAllowInactiveUser,)
authentication_classes = (BearerAuthenticationAllowInactiveUser,)
permission_classes = (IsAuthenticated, AMCAdminPermission)

def get_queryset(self):
queryset = Site.objects.exclude(id=settings.SITE_ID)
user = self.request.user
if not user.is_superuser:
queryset = queryset.filter(organizations=user.organizations.all())
queryset = queryset.filter(organizations__in=user.organizations.all())
return queryset


Expand All @@ -56,7 +56,7 @@ class SiteConfigurationViewSet(viewsets.ModelViewSet):
serializer_class = SiteConfigurationSerializer
list_serializer_class = SiteConfigurationListSerializer
create_serializer_class = SiteSerializer
authentication_classes = (OAuth2AuthenticationAllowInactiveUser,)
authentication_classes = (BearerAuthenticationAllowInactiveUser,)
permission_classes = (IsAuthenticated, AMCAdminPermission)

def get_serializer_class(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@ def congrats(self, **kwargs):
))

def handle(self, *args, **options):
# TODO: Uncomment after fixing the AMC trial site
# if not settings.DEBUG:
# raise CommandError('This only works on devstack.')
if not settings.DEBUG:
raise CommandError('This only works on devstack.')

name = options['name'][0].lower()
try:
Expand Down Expand Up @@ -90,7 +89,7 @@ def handle(self, *args, **options):
'domain': site_name,
'name': site_name,
},
'user_email': user.email,
'username': user.username,
'organization': {
'name': name,
'short_name': name,
Expand Down
2 changes: 1 addition & 1 deletion openedx/core/djangoapps/appsembler/sites/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class Meta:

def create(self, validated_data):
site = super(SiteSerializer, self).create(validated_data)
organization, site, user = bootstrap_site(site)
_organization, site, _user = bootstrap_site(site)
return site

def custom_domain_status(self, obj):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
UserStandingFactory,
)

from organizations.models import Organization, OrganizationCourse
from organizations.models import Organization, OrganizationCourse, UserOrganizationMapping

from oauth2_provider.models import AccessToken, RefreshToken, Application

Expand Down Expand Up @@ -97,6 +97,7 @@ def test_create_devstack_site(self):
user = get_user_model().objects.get()
assert user.check_password(self.name)
assert user.profile.name == self.name
assert UserOrganizationMapping.objects.get(organization__name=self.name, user=user)

assert CourseCreatorRole().has_user(user), 'User should be a course creator'

Expand Down
43 changes: 39 additions & 4 deletions openedx/core/djangoapps/appsembler/sites/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
from mock import patch

from django.urls import reverse
from openedx.core.djangoapps.appsembler.sites.utils import make_amc_admin
from rest_framework import status
from rest_framework.test import APITestCase
from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser

from openedx.core.djangolib.testing.utils import skip_unless_lms
from openedx.core.djangoapps.appsembler.multi_tenant_emails.tests.test_utils import (
Expand Down Expand Up @@ -47,7 +49,7 @@ def test_find_username(self):
create_org_user(red_org, email=email, username=username)

response = self.get_username(email, red_org.name)
assert response.status_code == status.HTTP_200_OK, response.content
assert response.status_code == status.HTTP_200_OK, response.content.decode('utf-8')
assert response.json()['username'] == username

def test_organization_separation(self):
Expand All @@ -64,11 +66,11 @@ def test_organization_separation(self):
pass

response = self.get_username(email, blue_org.name)
assert response.status_code == status.HTTP_404_NOT_FOUND, response.content # Should keep sites separated
assert response.status_code == status.HTTP_404_NOT_FOUND, response.content.decode('utf-8') # Should keep sites separated

blue_user = create_org_user(blue_org, email=email)
response = self.get_username(email, blue_org.name)
assert response.status_code == status.HTTP_200_OK, response.content
assert response.status_code == status.HTTP_200_OK, response.content.decode('utf-8')
assert response.json()['username'] == blue_user.username

def test_not_found(self):
Expand All @@ -79,4 +81,37 @@ def test_not_found(self):
pass

response = self.get_username('[email protected]', red_org.name)
assert response.status_code == status.HTTP_404_NOT_FOUND, response.content
assert response.status_code == status.HTTP_404_NOT_FOUND, response.content.decode('utf-8')


@skip_unless_lms
@patch(
'openedx.core.djangoapps.appsembler.sites.api.SiteViewSet.authentication_classes',
[SessionAuthenticationAllowInactiveUser]
)
class TestSiteViewSet(APITestCase):
"""
Tests for the SiteViewSet AMC API.
"""
def setUp(self):
super(TestSiteViewSet, self).setUp()
self.url = reverse('site-list')
self.color = 'red'
with with_organization_context(site_color=self.color) as red_org:
self.red_org = red_org
self.admin = create_org_user(
organization=red_org,
is_amc_admin=True,
email='[email protected]',
username=self.color,
password=self.color
)

def test_list_sites(self):
with with_organization_context(site_color=self.color):
assert self.client.login(username=self.admin.username, password=self.color)
response = self.client.get(
self.url,
)
content = response.content.decode('utf-8')
assert response.status_code == status.HTTP_200_OK, content
6 changes: 3 additions & 3 deletions openedx/core/djangoapps/appsembler/tpa_admin/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from openedx.core.djangoapps.appsembler.sites.permissions import AMCAdminPermission

from openedx.core.lib.api.authentication import (
OAuth2AuthenticationAllowInactiveUser,
BearerAuthenticationAllowInactiveUser,
)
from third_party_auth.models import SAMLConfiguration, SAMLProviderConfig
from openedx.core.djangoapps.appsembler.tpa_admin.serializers import (
Expand All @@ -25,7 +25,7 @@ class SAMLConfigurationViewSet(viewsets.ModelViewSet):
model = SAMLConfiguration
queryset = SAMLConfiguration.objects.current_set().order_by('id')
serializer_class = SAMLConfigurationSerializer
authentication_classes = (OAuth2AuthenticationAllowInactiveUser,)
authentication_classes = (BearerAuthenticationAllowInactiveUser,)
permission_classes = (IsAuthenticated, AMCAdminPermission)
filterset_class = SAMLConfigurationFilter

Expand All @@ -50,7 +50,7 @@ def get_queryset(self):
class SAMLProviderConfigViewSet(viewsets.ModelViewSet):
queryset = SAMLProviderConfig.objects.current_set().order_by('id')
serializer_class = SAMLProviderConfigSerializer
authentication_classes = (OAuth2AuthenticationAllowInactiveUser,)
authentication_classes = (BearerAuthenticationAllowInactiveUser,)
permission_classes = (IsAuthenticated, AMCAdminPermission)
filterset_class = SAMLProviderConfigFilter

Expand Down