applications: unlink app in services on deletion (#74659)
gitea/hobo/pipeline/head This commit looks good
Details
gitea/hobo/pipeline/head This commit looks good
Details
This commit is contained in:
parent
3bb0a0c3ca
commit
a1e8c69eef
|
@ -71,6 +71,10 @@ class DeploymentError(ApplicationError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnlinkError(ApplicationError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Application(models.Model):
|
class Application(models.Model):
|
||||||
SUPPORTED_MODULES = ('wcs',)
|
SUPPORTED_MODULES = ('wcs',)
|
||||||
|
|
||||||
|
@ -180,6 +184,24 @@ class Application(models.Model):
|
||||||
elements[(element.type, element.slug)] = (element, relation)
|
elements[(element.type, element.slug)] = (element, relation)
|
||||||
return elements
|
return elements
|
||||||
|
|
||||||
|
def unlink(self):
|
||||||
|
for service_id, services in getattr(settings, 'KNOWN_SERVICES', {}).items():
|
||||||
|
if service_id not in Application.SUPPORTED_MODULES:
|
||||||
|
continue
|
||||||
|
service_objects = {x.get_base_url_path(): x for x in get_installed_services(types=[service_id])}
|
||||||
|
for service in services.values():
|
||||||
|
if service['url'] not in service_objects:
|
||||||
|
continue
|
||||||
|
if service_objects[service['url']].secondary:
|
||||||
|
continue
|
||||||
|
url = urllib.parse.urljoin(service['url'], 'api/export-import/unlink/')
|
||||||
|
response = requests.post(url, data={'application': self.slug})
|
||||||
|
if not response.ok:
|
||||||
|
raise UnlinkError(
|
||||||
|
_('Failed to unlink application in module %s (%s)')
|
||||||
|
% (service_id, response.status_code)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Element(models.Model):
|
class Element(models.Model):
|
||||||
type = models.CharField(max_length=100, verbose_name=_('Type'))
|
type = models.CharField(max_length=100, verbose_name=_('Type'))
|
||||||
|
|
|
@ -19,6 +19,7 @@ import io
|
||||||
import json
|
import json
|
||||||
import tarfile
|
import tarfile
|
||||||
|
|
||||||
|
from django.contrib import messages
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
from django.db.models import Prefetch
|
from django.db.models import Prefetch
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
|
@ -31,7 +32,16 @@ from django.views.generic import DetailView, FormView, ListView, TemplateView
|
||||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
from django.views.generic.edit import CreateView, DeleteView, UpdateView
|
||||||
|
|
||||||
from .forms import GenerateForm, InstallForm, MetadataForm
|
from .forms import GenerateForm, InstallForm, MetadataForm
|
||||||
from .models import STATUS_CHOICES, Application, AsyncJob, Element, Relation, Version, get_object_types
|
from .models import (
|
||||||
|
STATUS_CHOICES,
|
||||||
|
Application,
|
||||||
|
AsyncJob,
|
||||||
|
Element,
|
||||||
|
Relation,
|
||||||
|
UnlinkError,
|
||||||
|
Version,
|
||||||
|
get_object_types,
|
||||||
|
)
|
||||||
from .utils import Requests
|
from .utils import Requests
|
||||||
|
|
||||||
requests = Requests()
|
requests = Requests()
|
||||||
|
@ -383,6 +393,19 @@ class AppDeleteView(DeleteView):
|
||||||
model = Application
|
model = Application
|
||||||
template_name = 'hobo/applications/app_confirm_delete.html'
|
template_name = 'hobo/applications/app_confirm_delete.html'
|
||||||
|
|
||||||
|
def delete(self, request, *args, **kwargs):
|
||||||
|
self.object = self.get_object()
|
||||||
|
success_url = self.get_success_url()
|
||||||
|
try:
|
||||||
|
self.object.unlink()
|
||||||
|
except UnlinkError as e:
|
||||||
|
messages.error(self.request, str(e))
|
||||||
|
return HttpResponseRedirect(
|
||||||
|
reverse('application-manifest', kwargs={'app_slug': self.kwargs['slug']})
|
||||||
|
)
|
||||||
|
self.object.delete()
|
||||||
|
return HttpResponseRedirect(success_url)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse('applications-home')
|
return reverse('applications-home')
|
||||||
|
|
||||||
|
|
|
@ -754,9 +754,8 @@ def test_delete_application(app, admin_user, settings):
|
||||||
|
|
||||||
with HTTMock(mocked_http):
|
with HTTMock(mocked_http):
|
||||||
resp = app.get('/applications/manifest/app_to_delete/')
|
resp = app.get('/applications/manifest/app_to_delete/')
|
||||||
resp = resp.click(re.compile('^Delete$'))
|
resp = resp.click(re.compile('^Delete$'))
|
||||||
|
resp = resp.forms[0].submit()
|
||||||
resp = resp.forms[0].submit()
|
|
||||||
resp = resp.follow()
|
resp = resp.follow()
|
||||||
|
|
||||||
assert '/applications/' in resp
|
assert '/applications/' in resp
|
||||||
|
@ -765,6 +764,20 @@ def test_delete_application(app, admin_user, settings):
|
||||||
assert Application.objects.count() == 1
|
assert Application.objects.count() == 1
|
||||||
assert Application.objects.first().name == 'OtherApp'
|
assert Application.objects.first().name == 'OtherApp'
|
||||||
|
|
||||||
|
def response_content(url, request):
|
||||||
|
if url.path == '/api/export-import/unlink/':
|
||||||
|
return {'status_code': 500}
|
||||||
|
return mocked_http(url, request)
|
||||||
|
|
||||||
|
with HTTMock(response_content):
|
||||||
|
resp = app.get('/applications/manifest/other_app/')
|
||||||
|
resp = resp.click(re.compile('^Delete$'))
|
||||||
|
resp = resp.forms[0].submit()
|
||||||
|
resp = resp.follow()
|
||||||
|
assert 'Failed to unlink application in module wcs (500)' in resp
|
||||||
|
assert Application.objects.count() == 1
|
||||||
|
assert Application.objects.first().name == 'OtherApp'
|
||||||
|
|
||||||
|
|
||||||
def test_404_unknown_app(app, admin_user, settings):
|
def test_404_unknown_app(app, admin_user, settings):
|
||||||
login(app)
|
login(app)
|
||||||
|
|
Loading…
Reference in New Issue