Skip to content
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
2 changes: 1 addition & 1 deletion openedx/core/djangoapps/appsembler/sites/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def get_serializer_class(self):
return super(SiteConfigurationViewSet, self).get_serializer_class()

def perform_destroy(self, instance):
delete_site(instance)
delete_site(instance.site)


class FileUploadView(views.APIView):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from django.core.management.base import BaseCommand, CommandError
from django.contrib.sites.models import Site

from openedx.core.djangoapps.appsembler.sites.utils import delete_site


class Command(BaseCommand):
"""
Remove a Tahoe website from LMS records.

Must be used `remove_site` on AMC to avoid any errors there.
"""

def add_arguments(self, parser):
parser.add_argument(
'domain',
help='The domain of the organization to be deleted.',
type=str,
)

def handle(self, *args, **options):
organization_domain = options['domain']
self.stdout.write(self.style.WARNING('Same command must be ran on the connected AMC instance'))

self.stdout.write('Removing "%s" in progress...' % organization_domain)
organization = self._get_site(organization_domain)

delete_site(organization)
self.stdout.write(self.style.SUCCESS('Successfully removed site "%s"' % organization_domain))

def _get_site(self, domain):
"""
Locates the site to be deleted and return its instance.

:param domain: The domain of the site to be returned.
:return: Returns the site object that has the given domain.
"""
try:
return Site.objects.get(domain=domain)
except Site.DoesNotExist:
raise CommandError('Cannot find "%s" in Sites!' % domain)
46 changes: 46 additions & 0 deletions openedx/core/djangoapps/appsembler/sites/tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from django.core.management import call_command

from openedx.core.djangoapps.appsembler.sites.management.commands.create_devstack_site import Command
from openedx.core.djangoapps.site_configuration.models import SiteConfiguration
from openedx.core.djangoapps.theming.models import SiteTheme
from organizations.models import Organization
from provider.constants import CONFIDENTIAL
from provider.oauth2.models import AccessToken, RefreshToken, Client
Expand Down Expand Up @@ -68,3 +70,47 @@ def test_create_devstack_site(self):
assert fake_token == '80bfa968ffad007c79bfc603f3670c99', 'Ensure hash is identical to AMC'
assert AccessToken.objects.get(user=user).token == fake_token, 'Access token is needed'
assert RefreshToken.objects.get(user=user).token == fake_token, 'Refresh token is needed'


@override_settings(
DEBUG=True,
DEFAULT_SITE_THEME='edx-theme-codebase',
FEATURES={
'AMC_APP_URL': 'http://localhost:13000',
"DISABLE_COURSE_CREATION": False,
"ENABLE_CREATOR_GROUP": True,
},
COMPREHENSIVE_THEME_DIRS=[settings.REPO_ROOT / 'common/test/appsembler'],
)
class RemoveSiteCommandTestCase(TestCase):
"""
Test ./manage.py lms remove_site mysite
"""
def setUp(self):
assert settings.ENABLE_COMPREHENSIVE_THEMING
Client.objects.create(url=settings.FEATURES['AMC_APP_URL'], client_type=CONFIDENTIAL)

self.to_be_deleted = 'delete'
self.shall_remain = 'keep'

# This command should be tested above
call_command('create_devstack_site', self.to_be_deleted)
call_command('create_devstack_site', self.shall_remain)

def test_create_devstack_site(self):
"""
Test that `create_devstack_site` and creates the required objects.
"""
call_command('remove_site', '{}.localhost:18000'.format(self.to_be_deleted))

# Ensure objects are removed correctly.
deleted_domain = '{}.localhost:18000'.format(self.to_be_deleted)
remained_domain = '{}.localhost:18000'.format(self.shall_remain)

assert not Site.objects.filter(domain=deleted_domain).exists()
site = Site.objects.get(domain=remained_domain)

assert SiteConfiguration.objects.count() == 1
assert SiteConfiguration.objects.get(site=site)

assert SiteTheme.objects.filter(site=site).count() == site.themes.count()
1 change: 1 addition & 0 deletions openedx/core/djangoapps/appsembler/sites/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.conf import settings
from django.conf.urls import url, include
from rest_framework.routers import DefaultRouter

from openedx.core.djangoapps.appsembler.sites.api import (
CustomDomainView,
DomainAvailabilityView,
Expand Down
6 changes: 3 additions & 3 deletions openedx/core/djangoapps/appsembler/sites/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,10 +306,10 @@ def bootstrap_site(site, org_data=None, user_email=None):
return organization, site, user


def delete_site(site_id):
site = Site.objects.get(id=site_id)
def delete_site(site):
site.configuration.delete()
site.themes.delete()
site.themes.all().delete()

site.delete()


Expand Down