applification: ajustements (#88593) #233

Merged
lguerin merged 3 commits from wip/88593-applification-misc into main 2024-04-04 15:49:06 +02:00
2 changed files with 66 additions and 38 deletions

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import io
import json
import tarfile
@ -29,7 +28,7 @@ from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from chrono.agendas.models import Agenda, Category, EventsType, Resource, UnavailabilityCalendar
from chrono.api.utils import APIError
from chrono.api.utils import APIErrorBadRequest
from chrono.apps.export_import.models import Application, ApplicationElement
from chrono.manager.utils import import_site
@ -237,14 +236,14 @@ def component_redirect(request, component_type, slug):
class BundleCheck(GenericAPIView):
permission_classes = (permissions.IsAdminUser,)
def put(self, request, *args, **kwargs):
tar_io = io.BytesIO(request.read())
def post(self, request, *args, **kwargs):
bundle = request.FILES['bundle']
try:
with tarfile.open(fileobj=tar_io) as tar:
with tarfile.open(fileobj=bundle) as tar:
try:
manifest = json.loads(tar.extractfile('manifest.json').read().decode())
except KeyError:
raise APIError(_('Invalid tar file, missing manifest'))
raise APIErrorBadRequest(_('Invalid tar file, missing manifest'))
application_slug = manifest.get('slug')
application_version = manifest.get('version_number')
if not application_slug or not application_version:
@ -334,7 +333,7 @@ class BundleCheck(GenericAPIView):
}
)
except tarfile.TarError:
raise APIError(_('Invalid tar file'))
raise APIErrorBadRequest(_('Invalid tar file'))
return Response(
{
@ -355,15 +354,15 @@ class BundleImport(GenericAPIView):
permission_classes = (permissions.IsAdminUser,)
install = True
def put(self, request, *args, **kwargs):
tar_io = io.BytesIO(request.read())
def post(self, request, *args, **kwargs):
bundle = request.FILES['bundle']
components = {}
try:
with tarfile.open(fileobj=tar_io) as tar:
with tarfile.open(fileobj=bundle) as tar:
try:
manifest = json.loads(tar.extractfile('manifest.json').read().decode())
except KeyError:
raise APIError(_('Invalid tar file, missing manifest'))
raise APIErrorBadRequest(_('Invalid tar file, missing manifest'))
self.application = Application.update_or_create_from_manifest(
manifest,
tar,
@ -382,7 +381,7 @@ class BundleImport(GenericAPIView):
tar.extractfile('%s/%s' % (element['type'], element['slug'])).read().decode()
)
except KeyError:
raise APIError(
raise APIErrorBadRequest(
_(
'Invalid tar file, missing component %s/%s'
% (element['type'], element['slug'])
@ -390,7 +389,7 @@ class BundleImport(GenericAPIView):
)
components[component_type].append(json.loads(component_content).get('data'))
except tarfile.TarError:
raise APIError(_('Invalid tar file'))
raise APIErrorBadRequest(_('Invalid tar file'))
# init cache of application elements, from manifest
self.application_elements = set()

View File

@ -375,8 +375,7 @@ def test_unknown_compoment_type_dependencies(app, admin_user):
app.get('/api/export-import/unknown/foo/dependencies/', status=404)
def test_redirect(app, user):
app.authorization = ('Basic', ('john', 'doe'))
def test_redirect(app):
agenda = Agenda.objects.create(label='Rdv', slug='rdv', kind='meetings')
category = Category.objects.create(slug='cat', label='Category')
resource = Resource.objects.create(slug='foo', label='Foo')
@ -541,7 +540,7 @@ def test_bundle_import(app, admin_user):
EventsType.objects.all().delete()
UnavailabilityCalendar.objects.all().delete()
resp = app.put('/api/export-import/bundle-import/', bundles[0])
resp = app.post('/api/export-import/bundle-import/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
assert Agenda.objects.all().count() == 4
assert resp.json['err'] == 0
assert Application.objects.count() == 1
@ -576,7 +575,7 @@ def test_bundle_import(app, admin_user):
)
# check update
resp = app.put('/api/export-import/bundle-import/', bundles[1])
resp = app.post('/api/export-import/bundle-import/', upload_files=[('bundle', 'bundle.tar', bundles[1])])
assert Agenda.objects.all().count() == 4
assert resp.json['err'] == 0
assert Application.objects.count() == 1
@ -599,7 +598,9 @@ def test_bundle_import(app, admin_user):
assert last_snapshot.application_version == '42.1'
# bad file format
resp = app.put('/api/export-import/bundle-import/', b'garbage')
resp = app.post(
'/api/export-import/bundle-import/', upload_files=[('bundle', 'bundle.tar', b'garbage')], status=400
)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file'
@ -610,7 +611,11 @@ def test_bundle_import(app, admin_user):
tarinfo = tarfile.TarInfo('foo.json')
tarinfo.size = len(foo_fd.getvalue())
tar.addfile(tarinfo, fileobj=foo_fd)
resp = app.put('/api/export-import/bundle-import/', tar_io.getvalue())
resp = app.post(
'/api/export-import/bundle-import/',
upload_files=[('bundle', 'bundle.tar', tar_io.getvalue())],
status=400,
)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file, missing manifest'
@ -626,7 +631,11 @@ def test_bundle_import(app, admin_user):
tarinfo = tarfile.TarInfo('manifest.json')
tarinfo.size = len(manifest_fd.getvalue())
tar.addfile(tarinfo, fileobj=manifest_fd)
resp = app.put('/api/export-import/bundle-import/', tar_io.getvalue())
resp = app.post(
'/api/export-import/bundle-import/',
upload_files=[('bundle', 'bundle.tar', tar_io.getvalue())],
status=400,
)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file, missing component agendas/foo'
@ -635,7 +644,7 @@ def test_bundle_declare(app, admin_user):
app.authorization = ('Basic', ('admin', 'admin'))
bundle = create_bundle(app, admin_user, visible=False)
resp = app.put('/api/export-import/bundle-declare/', bundle)
resp = app.post('/api/export-import/bundle-declare/', upload_files=[('bundle', 'bundle.tar', bundle)])
assert Agenda.objects.all().count() == 4
assert resp.json['err'] == 0
assert Application.objects.count() == 1
@ -662,14 +671,16 @@ def test_bundle_declare(app, admin_user):
# and remove agendas to have unknown references in manifest
Agenda.objects.all().delete()
resp = app.put('/api/export-import/bundle-declare/', bundle)
resp = app.post('/api/export-import/bundle-declare/', upload_files=[('bundle', 'bundle.tar', bundle)])
assert Application.objects.count() == 1
application = Application.objects.latest('pk')
assert application.visible is True
assert ApplicationElement.objects.count() == 4 # category, events_type, unavailability_calendar, resource
# bad file format
resp = app.put('/api/export-import/bundle-declare/', b'garbage')
resp = app.post(
'/api/export-import/bundle-declare/', upload_files=[('bundle', 'bundle.tar', b'garbage')], status=400
)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file'
@ -680,7 +691,11 @@ def test_bundle_declare(app, admin_user):
tarinfo = tarfile.TarInfo('foo.json')
tarinfo.size = len(foo_fd.getvalue())
tar.addfile(tarinfo, fileobj=foo_fd)
resp = app.put('/api/export-import/bundle-declare/', tar_io.getvalue())
resp = app.post(
'/api/export-import/bundle-declare/',
upload_files=[('bundle', 'bundle.tar', tar_io.getvalue())],
status=400,
)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file, missing manifest'
@ -696,7 +711,11 @@ def test_bundle_declare(app, admin_user):
tarinfo = tarfile.TarInfo('manifest.json')
tarinfo.size = len(manifest_fd.getvalue())
tar.addfile(tarinfo, fileobj=manifest_fd)
resp = app.put('/api/export-import/bundle-declare/', tar_io.getvalue())
resp = app.post(
'/api/export-import/bundle-declare/',
upload_files=[('bundle', 'bundle.tar', tar_io.getvalue())],
status=400,
)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file, missing component agendas/foo'
@ -779,13 +798,17 @@ def test_bundle_check(app, admin_user):
incomplete_bundles.append(tar_io.getvalue())
# incorrect bundles, missing information
resp = app.put('/api/export-import/bundle-check/', incomplete_bundles[0])
resp = app.post(
'/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', incomplete_bundles[0])]
)
assert resp.json == {'data': {}}
resp = app.put('/api/export-import/bundle-check/', incomplete_bundles[1])
resp = app.post(
'/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', incomplete_bundles[1])]
)
assert resp.json == {'data': {}}
# not yet imported
resp = app.put('/api/export-import/bundle-check/', bundles[0])
resp = app.post('/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
assert resp.json == {
'data': {
'differences': [],
@ -805,13 +828,13 @@ def test_bundle_check(app, admin_user):
}
# import bundle
resp = app.put('/api/export-import/bundle-import/', bundles[0])
resp = app.post('/api/export-import/bundle-import/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
assert Application.objects.count() == 1
assert ApplicationElement.objects.count() == 8
# remove application links
Application.objects.all().delete()
resp = app.put('/api/export-import/bundle-check/', bundles[0])
resp = app.post('/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
assert resp.json == {
'data': {
'differences': [],
@ -871,12 +894,12 @@ def test_bundle_check(app, admin_user):
}
# import bundle again, recreate links
resp = app.put('/api/export-import/bundle-import/', bundles[0])
resp = app.post('/api/export-import/bundle-import/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
assert Application.objects.count() == 1
assert ApplicationElement.objects.count() == 8
# no changes since last import
resp = app.put('/api/export-import/bundle-check/', bundles[0])
resp = app.post('/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
assert resp.json == {
'data': {
'differences': [],
@ -901,7 +924,7 @@ def test_bundle_check(app, admin_user):
)
# and check
resp = app.put('/api/export-import/bundle-check/', bundles[0])
resp = app.post('/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', bundles[0])])
assert resp.json == {
'data': {
'differences': [
@ -993,10 +1016,10 @@ def test_bundle_check(app, admin_user):
}
# update bundle
resp = app.put('/api/export-import/bundle-import/', bundles[1])
resp = app.post('/api/export-import/bundle-import/', upload_files=[('bundle', 'bundle.tar', bundles[1])])
# and check
resp = app.put('/api/export-import/bundle-check/', bundles[1])
resp = app.post('/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', bundles[1])])
assert resp.json == {
'data': {
'differences': [],
@ -1008,7 +1031,7 @@ def test_bundle_check(app, admin_user):
# snapshots without application info
AgendaSnapshot.objects.update(application_slug=None, application_version=None)
resp = app.put('/api/export-import/bundle-check/', bundles[1])
resp = app.post('/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', bundles[1])])
assert resp.json == {
'data': {
'differences': [],
@ -1024,7 +1047,9 @@ def test_bundle_check(app, admin_user):
}
# bad file format
resp = app.put('/api/export-import/bundle-check/', b'garbage')
resp = app.post(
'/api/export-import/bundle-check/', upload_files=[('bundle', 'bundle.tar', b'garbage')], status=400
)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file'
@ -1035,6 +1060,10 @@ def test_bundle_check(app, admin_user):
tarinfo = tarfile.TarInfo('foo.json')
tarinfo.size = len(foo_fd.getvalue())
tar.addfile(tarinfo, fileobj=foo_fd)
resp = app.put('/api/export-import/bundle-check/', tar_io.getvalue())
resp = app.post(
'/api/export-import/bundle-check/',
upload_files=[('bundle', 'bundle.tar', tar_io.getvalue())],
status=400,
)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file, missing manifest'