import json import os import tempfile import zipfile import django from django import forms from django.conf import settings from django.contrib import admin, messages from django.contrib.auth import get_permission_codename from django.core.exceptions import PermissionDenied from django.core.files.storage import default_storage from django.http import HttpResponseRedirect from django.template.response import TemplateResponse from django.urls import path, reverse from django.utils.translation import gettext_lazy as _ from .. import models from .forms import ImportForm class ImportMixin(admin.ModelAdmin): """ Import mixin. This is intended to be mixed with django.contrib.admin.ModelAdmin https://docs.djangoproject.com/en/2.1/ref/contrib/admin/#modeladmin-objects """ #: template for change_list view change_list_template = 'admin/import_export/change_list_import.html' #: template for import view import_template_name = 'admin/import_export/import.html' def get_model_info(self): app_label = self.model._meta.app_label return (self.model._meta.app_label, self.model._meta.model_name) def has_import_permission(self, request): """ Returns whether a request has import permission. """ IMPORT_PERMISSION_CODE = getattr(settings, 'IMPORT_EXPORT_IMPORT_PERMISSION_CODE', None) if IMPORT_PERMISSION_CODE is None: return True opts = self.opts codename = get_permission_codename(IMPORT_PERMISSION_CODE, opts) return request.user.has_perm("%s.%s" % (opts.app_label, codename)) def get_urls(self): urls = super().get_urls() info = self.get_model_info() my_urls = [ path('import/', self.admin_site.admin_view(self.import_action), name='%s_%s_import' % info), ] return my_urls + urls def get_import_context_data(self, **kwargs): return self.get_context_data(**kwargs) def get_context_data(self, **kwargs): return {} def get_form_kwargs(self, form, *args, **kwargs): """ Prepare/returns kwargs for the import form. To distinguish between import and confirm import forms, the following approach may be used: if isinstance(form, ImportForm): # your code here for the import form kwargs # e.g. update.kwargs({...}) elif isinstance(form, ConfirmImportForm): # your code here for the confirm import form kwargs # e.g. update.kwargs({...}) ... """ return kwargs def import_action(self, request, *args, **kwargs): """ Perform a dry_run of the import to make sure the import will not result in errors. If there where no error, save the user uploaded file to a local temp file that will be used by 'process_import' for the actual import. """ if not self.has_import_permission(request): raise PermissionDenied context = self.get_import_context_data() form_type = ImportForm form_kwargs = self.get_form_kwargs(form_type, *args, **kwargs) form = form_type(request.POST or None, request.FILES or None, **form_kwargs) if request.POST and form.is_valid(): import_file_tema = form.cleaned_data['tema'] if zipfile.is_zipfile(import_file_tema): with zipfile.ZipFile(import_file_tema, 'r') as zip_ref: with tempfile.TemporaryDirectory() as tempdir: zip_ref.extractall(tempdir) lst = os.listdir(tempdir) allowed_extensions=[".gif", ".jpg", ".jpeg", ".png", ".svg"] try: tema_json = [s for s in os.listdir(f'{tempdir}/{lst[0]}') if '.json' in s][0] logo = [s for s in os.listdir(f'{tempdir}/{lst[0]}/logo') if any(ele in s for ele in allowed_extensions)][0] favicon = [s for s in os.listdir(f'{tempdir}/{lst[0]}/favicon') if any(ele in s for ele in allowed_extensions)][0] with open(f'{tempdir}/{lst[0]}/{tema_json}', 'r') as temporary_file: result = json.loads(temporary_file.read()) with open(f'{tempdir}/{lst[0]}/logo/{logo}', 'rb') as temporary_file: default_storage.save(f"admin-interface/logo/{temporary_file.name.split('/')[-1]}", temporary_file) with open(f'{tempdir}/{lst[0]}/favicon/{favicon}', 'rb') as temporary_file: default_storage.save(f"admin-interface/favicon/{temporary_file.name.split('/')[-1]}", temporary_file) skip_result = False except FileNotFoundError as e: messages.error(request, 'Struttura del file .zip errata.') skip_result = True if not skip_result: try: new_theme = models.Theme( **result[0]['fields'] ) new_theme.save() messages.success(request, _('Import finished')) except: messages.error(request, 'Struttura del file .json errata.') else: messages.error(request, 'È richiesto un file .zip') url = reverse('admin:%s_%s_changelist' % self.get_model_info(), current_app=self.admin_site.name) return HttpResponseRedirect(url) else: context.update(self.admin_site.each_context(request)) context['title'] = _("Import") context['form'] = form context['opts'] = self.model._meta request.current_app = self.admin_site.name return TemplateResponse(request, [self.import_template_name], context) def changelist_view(self, request, extra_context=None): if extra_context is None: extra_context = {} extra_context['has_import_permission'] = self.has_import_permission(request) return super().changelist_view(request, extra_context)