]> git.atlas4tour.it Git - pia_atlas.git/commitdiff
generazione qrcode
authorValeria Vitti <valeria.vitti@dyrecta.com>
Tue, 15 Oct 2024 15:18:44 +0000 (17:18 +0200)
committerValeria Vitti <valeria.vitti@dyrecta.com>
Tue, 15 Oct 2024 15:18:44 +0000 (17:18 +0200)
modifiche poi e percorso su icone e immagini

15 files changed:
api/urls.py
api/views.py
media/icon/default.png [deleted file]
requirements.txt
sistema/datatables.py
sistema/forms.py
sistema/models.py
sistema/templates/add_mod_percorso.html
sistema/templates/add_mod_poi.html
sistema/templates/base.html
sistema/templates/modal_add_icona_percorso.html [new file with mode: 0644]
sistema/templates/percorsi_cliente_home.html
sistema/templates/percorsi_list.html
sistema/urls.py
sistema/views.py

index 28a75d7f853839dc35669b1a9c9908861758ecdd..09f4b954db733dd9ec09c22df0d4f73a2601447b 100644 (file)
@@ -2,7 +2,8 @@ from django.contrib import admin
 from django.urls import path, include
 from django.contrib.auth import views as auth_views
 
-from api.views import Login_v2, RegistrationAPI, ListaPercorsiAPI, DetailPercorsoAPI, DetailPoiAPI, SendFeedbackAPI
+from api.views import Login_v2, RegistrationAPI, ListaPercorsiAPI, DetailPercorsoAPI, DetailPoiAPI, SendFeedbackAPI, \
+    ShowQRCode
 
 urlpatterns = [
     path('api-login/', Login_v2.as_view(), name='api_login'),
@@ -12,4 +13,7 @@ urlpatterns = [
     path('detail_poi/', DetailPoiAPI.as_view(), name='detail_poi'),
 
     path('send_feedback/', SendFeedbackAPI.as_view(), name='send_feedback'),
+
+    path('show_qr_code/', ShowQRCode.as_view(), name='show_qr_code'),
+
 ]
index 4fdf28c6cf7e43a3dcf8c0dd4715a8f86dbf74b2..03bc0e2f762300686b4403dcd93e7a79656fe9b8 100644 (file)
@@ -1,7 +1,9 @@
+import os.path
+
 from django.contrib.auth.models import User
 from django.http import JsonResponse
 from django.shortcuts import render
-from django.utils.translation import ugettext as _
+from django.utils.translation import gettext as _
 from rest_framework import status
 from django.contrib.auth import authenticate
 from rest_framework import serializers
@@ -189,7 +191,6 @@ class DetailPoiAPI(APIView):
 
             if filter:
                 poi_serialize = PoiSerializer(filter, many=True)
-
                 multimedia = Multimedia.objects.filter(poi=filter.first(), is_active=True)
                 multimedia_list = MultimediaSerializer(multimedia, many=True)
 
@@ -245,3 +246,26 @@ class SendFeedbackAPI(APIView):
         else:
             return Response(
                 {'errors': 'Assicurati che le informazioni relative all\'utente, percorso e valutazione siano state inviate', 'error': True, 'data': '', 'messages': ['KO']})
+
+
+class ShowQRCode(APIView):
+    def get(self, request):
+        id = request.query_params['id_criptato']
+
+        errors = []
+        error = False
+        data = []
+        if id:
+            multimedia = Multimedia.objects.get(chiave_qr_code=str(id))
+            multimedia_list = MultimediaSerializer(multimedia)
+
+            data.append({
+                'multimedia': multimedia_list.data,
+            })
+
+            return Response({'errors': errors, 'error': error, 'data': data, 'messages': ['OK']})
+
+        else:
+            return Response({'errors': 'Multimedia non presente', 'error': True, 'data': '', 'messages': ['']})
+
+
diff --git a/media/icon/default.png b/media/icon/default.png
deleted file mode 100644 (file)
index d826176..0000000
Binary files a/media/icon/default.png and /dev/null differ
index a298f856ef1a1988da37ecaf7eb35003be3902c1..a28aaac79f8690a265596f0bfaa13fb49381f994 100644 (file)
Binary files a/requirements.txt and b/requirements.txt differ
index a484b8610ece667fc2e3fafabc305afbac29b765..3716636c79401169a01295a822101473794a10fd 100644 (file)
@@ -42,8 +42,8 @@ class LocalitaDatatables(BaseDatatableView):
 
 class MultimediaDatatables(BaseDatatableView):
     model = Multimedia
-    columns = ['id', 'tipologia', 'nome', 'descrizione', 'media', 'del']
-    order_columns = ['id', 'tipologia', 'nome', 'descrizione', 'media', 'del']
+    columns = ['id', 'tipologia', 'nome', 'descrizione', 'media', 'qr_code', 'del']
+    order_columns = ['id', 'tipologia', 'nome', 'descrizione', 'media', 'qr_code', 'del']
 
     def get_initial_queryset(self):
         poi = self.request.GET.get('pk')
@@ -62,6 +62,11 @@ class MultimediaDatatables(BaseDatatableView):
             return escape('{0}'.format(row.descrizione))
         if column == 'media':
             return f'<a href="{MEDIA_URL}{row.media}" target="_blank" title="vedi" class="btn btn-sm btn-secondary"><i class="far fa-eye"></i> visualizza </a>'
+        if column == 'qr_code':
+            if row.qr_code:
+                return f'<a href="{MEDIA_URL}{row.qr_code}" target="_blank" title="vedi" class="btn btn-sm btn-secondary"><i class="fas fa-qrcode"></i></a>'
+            else:
+                return '<button class="btn btn-sm btn-secondary" onclick="crea_qr_code(%s)"><i class="fas fa-qrcode"></i></button>' % row.pk
         if column == 'del':
             return '<button class="btn btn-sm btn-danger" onclick="DeleteMultimedia(%s)"><i class="fas fa-trash"></i></button>' % row.pk
         else:
@@ -104,8 +109,8 @@ class TipoMultimediaDatatables(BaseDatatableView):
 
 class PercorsoDatatables(BaseDatatableView):
     model = Percorso
-    columns = ['id', 'nome', 'descrizione', 'testo', 'mod', 'del']
-    order_columns = ['id', 'nome', 'descrizione', 'testo', 'mod', 'del']
+    columns = ['id', 'icona', 'nome', 'descrizione', 'testo', 'add', 'mod', 'del']
+    order_columns = ['id', 'icona', 'nome', 'descrizione', 'testo', 'add','mod', 'del']
 
     def get_initial_queryset(self):
         return self.model.objects.filter(is_active=True)
@@ -113,6 +118,8 @@ class PercorsoDatatables(BaseDatatableView):
     def render_column(self, row, column):
         if column == 'id':
             return escape('{0}'.format(row.pk))
+        if column == 'icona':
+            return f'<img src="{MEDIA_URL}{row.icona}" class="text-center user-img mr-2" alt="" height="50px">'
         if column == 'nome':
             return escape('{0}'.format(row.nome))
         if column == 'descrizione':
@@ -122,7 +129,9 @@ class PercorsoDatatables(BaseDatatableView):
         if column == 'mod':
             return '<a class="btn btn-sm btn-secondary" href="/mod_percorso/%s/" ><i class="fas fa-edit"></i></a>' % row.pk
         if column == 'del':
-            return '<a class="btn btn-sm btn-danger" href="DeletePercorso(%s)" ><i class="fas fa-trash"></i></a>' % row.pk
+            return '<button class="btn btn-sm btn-danger" onclick="DeletePercorso(%s)" ><i class="fas fa-trash"></i></a>' % row.pk
+        if column == 'add':
+            return '<button class="btn btn-sm btn-secondary" onclick="showModalIcona(%s)"><i class="fas fa-image"></i></button>' % row.pk
         else:
             return super(PercorsoDatatables, self).render_column(row, column)
 
index 73f369b472eec9de04eb36fb1c1c70a138f51901..4fd8433e2a59e5b05671f6dbaaaa9a7829002788 100644 (file)
@@ -58,14 +58,17 @@ class PoiForm(forms.ModelForm):
 
     class Meta:
         model = PointOfInterest
-        exclude = ('is_active',)
+        exclude = ('is_active','url')
 
     def __init__(self, *args, **kwargs):
         super(PoiForm, self).__init__(*args, **kwargs)
         self.fields['icona'].required = False
+        self.fields['descrizione'].required = False
 
         for f in self.fields:
-            if self.fields[f].widget.input_type != 'checkbox':
+            if self.fields[f].label == 'Descrizione':
+                self.fields[f].max_length = 3000
+            elif self.fields[f].widget.input_type != 'checkbox':
                 self.fields[f].widget.attrs.update({'class': ' form-control'})
 
 
@@ -80,12 +83,26 @@ class PoiForm(forms.ModelForm):
 
 
 class PercorsoForm(forms.ModelForm):
+    # icona = forms.FileField(label='Icona', widget=forms.FileInput(
+    #     attrs={'class': 'form-control', 'form': 'percorso_form'}), )
     class Meta:
         model = Percorso
-        exclude = ('is_active',)
+        exclude = ('is_active','url','icona')
 
     def __init__(self, *args, **kwargs):
         super(PercorsoForm, self).__init__(*args, **kwargs)
+        for f in self.fields:
+            if self.fields[f].label == 'Testo':
+                self.fields[f].max_length = 3000
+            self.fields[f].widget.attrs.update({'class': 'form-control'})
+
+class IconaPercorsoForm(forms.ModelForm):
+    class Meta:
+        model = Percorso
+        exclude = ('testo','nome','descrizione','prezzo','is_active','url',)
+
+    def __init__(self, *args, **kwargs):
+        super(IconaPercorsoForm, self).__init__(*args, **kwargs)
         for f in self.fields:
             self.fields[f].widget.attrs.update({'class': 'form-control'})
 
@@ -125,7 +142,7 @@ class MultimediaForm(forms.ModelForm):
 
     class Meta:
         model = Multimedia
-        exclude = ('poi', 'is_active',)
+        exclude = ('poi', 'is_active', 'chiave_qr_code', 'qr_code')
 
     def __init__(self, *args, **kwargs):
         super(MultimediaForm, self).__init__(*args, **kwargs)
index d4cee6ba159b4e582c6ebcf628b3b002c4ed35fc..e2e4e6307e6fb7f611926912e40971bbd595862a 100644 (file)
@@ -32,6 +32,8 @@ class PointOfInterest(models.Model):
     lat = models.FloatField()
     long = models.FloatField()
     icona = models.FileField(upload_to='icon/', null=True)
+    url = models.URLField(null=True)
+    descrizione = models.TextField()
     is_danger = models.BooleanField(default=False)
     is_active = models.BooleanField(default=True)
 
@@ -39,7 +41,9 @@ class PointOfInterest(models.Model):
 class Percorso(models.Model):
     nome = models.CharField(max_length=255, null=False)
     descrizione = models.CharField(max_length=255, null=False)
-    testo = models.TextField(max_length=255, null=False)
+    testo = models.TextField()
+    icona = models.FileField(upload_to='icon_percorso/', null=True)
+    url = models.URLField(null=True)
     prezzo = models.FloatField()
     is_active = models.BooleanField(default=True)
 
@@ -91,6 +95,8 @@ class Multimedia(models.Model):
     nome = models.CharField(max_length=255, null=False)
     descrizione = models.CharField(max_length=255, null=False)
     testo = models.TextField(max_length=255, null=False)
+    qr_code = models.FileField(upload_to='poi_media_qr_code/', null=True)
+    chiave_qr_code = models.CharField(max_length=255, null=True)
     is_active = models.BooleanField(default=True)
 
 
@@ -105,7 +111,7 @@ class Feedback(models.Model):
 class PercorsoSerializer(serializers.ModelSerializer):
     class Meta:
         model = Percorso
-        fields = ('id', 'nome', 'descrizione', 'testo')
+        fields = ('id', 'nome', 'descrizione', 'testo', 'icona', 'url')
 
 
 class FeedbackSerializer(serializers.ModelSerializer):
@@ -117,7 +123,7 @@ class FeedbackSerializer(serializers.ModelSerializer):
 class PoiSerializer(serializers.ModelSerializer):
     class Meta:
         model = PointOfInterest
-        fields = ('id', 'nome', 'lat', 'long', 'icona','is_danger')
+        fields = ('id', 'nome', 'lat', 'long', 'icona','is_danger', 'url', 'descrizione')
 
 
 class MultimediaSerializer(serializers.ModelSerializer):
@@ -127,4 +133,4 @@ class MultimediaSerializer(serializers.ModelSerializer):
     )
     class Meta:
         model = Multimedia
-        fields = ('id', 'nome', 'tipologia', 'media', 'nome', 'descrizione', 'testo')
\ No newline at end of file
+        fields = ('id', 'nome', 'tipologia', 'media', 'nome', 'descrizione', 'testo', 'qr_code')
\ No newline at end of file
index bbfef72ebafa7dd0c6d2e50d14b1c48f40b4bf58..89f0aff7edc0d74b522c889341034eeae38a1a71 100644 (file)
     </script>
 
 
-{% endblock %}
\ No newline at end of file
+{% endblock %}
index 75d991962f4a157ceda90e20c392bcf43305b315..2920493544bbb426e47a003d6023d44a6903abb2 100644 (file)
@@ -69,6 +69,7 @@
                                         <th>Nome</th>
                                         <th>Descrizione</th>
                                         <th>Media</th>
+                                        <th>QRcode</th>
                                         <th></th>
                                     </tr>
                                     </thead>
                         url: "//cdn.datatables.net/plug-ins/1.10.20/i18n/Italian.json"
                     },
                     columnDefs: [
-                        {"targets": 5, "orderable": false, "width": "5%"},
+                        {"targets": 5, "orderable": false, "width": "8%"},
+                        {"targets": 6, "orderable": false, "width": "5%"},
                     ],
                     "order": []
                 });
             {% endif %}
         });
 
+        function crea_qr_code(pk) {
+            $.ajax({
+                type: "POST",
+                data: {
+                    'pk': pk,
+                },
+                headers: {'X-CSRFToken': '{{ csrf_token }}'},
+                url: '{% url 'sistema:crea_qr_code' %}',
+                success: function(data) {
+                    location.reload();
+                    var url = window.location.origin;
+                    window.open(url+'/'+data.qr_code, '_blank');
+                },
+                error: function(data) {
+                    Swal.fire("Attenzione!", data.response , "error")
+                },
+            });
+        }
+
         function DeleteMultimedia(pk) {
             Swal.fire({
                 title: "Sei sicuro?",
index 95650d9db8f4c93a5465eda8c3932e4a15667f18..fce08522f61f666ee1c933124ba6995c4dea10ed 100644 (file)
                 {% endblock %}
 
             </section>
-
             <footer class="footer" id="footer">
                     <div class="copyright text-center">
                         <span>Copyright © <b>Dyrecta</b> - 2022</span>
 
     <!-- VARI MODAL CHE VENGONO RICHIAMATI ALL'INTERNO DEL GESTIONALE -->
 
+    {% include 'modal_add_icona_percorso.html' %}
 
     <!-- General JS Scripts -->
     <script src="{% static 'assets/js/app.min.js' %}"></script>
diff --git a/sistema/templates/modal_add_icona_percorso.html b/sistema/templates/modal_add_icona_percorso.html
new file mode 100644 (file)
index 0000000..24f32e4
--- /dev/null
@@ -0,0 +1,26 @@
+<div class="modal fade" id="modal-add-icona-percorso-dialog" tabindex="-1" aria-labelledby="exampleModalLabel"
+     aria-hidden="true">
+    <div class="modal-dialog">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title" id="exampleModalLabel">Aggiungi icona percorso</h5>
+                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+            </div>
+            <div class="modal-body mt-3">
+                <form method="post" action="{% url 'sistema:add_icona_percorso' %}"
+                      enctype="multipart/form-data" id="icona_percorso_form">
+                    {% csrf_token %}
+                    <input type="hidden" id="pk_percorso_modal" form="icona_percorso_form" name="pk_percorso_icona">
+                    {{ form }}
+
+            </div>
+            <div class="modal-footer bg-whitesmoke">
+                <button class="btn btn-dark" type="button" onclick="javascript:this.form.submit();">
+                    <i class="fas fa-save mr-1" aria-hidden="true"></i> Salva
+                </button>
+            </div>
+            </form>
+        </div>
+    </div>
+</div>
+
index ca950e0b3b37f2c50f30d3eac79fe9a0d7ca5c18..843e11dd8d26d1bbc5ac4f6352c44f9d85bfc35c 100644 (file)
                 <div class="row">
                     {% for percorso in list_percorsi %}
                         <div class="card" style="width: 18rem;">
-                            <img class="card-img-top" src="{% static 'assets/img/logo.png' %}">
+                            {% if percorso.icona %}
+                                <img class="card-img-top" src="/media/{{ percorso.icona }}">
+                            {% else %}
+                                <img class="card-img-top" src="{% static 'assets/img/logo.png' %}">
+                            {% endif %}
                             <div class="card-body">
                                 <h5 class="card-title">{{ percorso.nome}}</h5>
                                 <p class="card-text">{{ percorso.descrizione }}</p>
index 3a3377a8406e4988c9955084f338c9167e7d6cdd..d1b5c575efcefa9b59469d17a57329aec8969c11 100644 (file)
                                 <thead>
                                 <tr>
                                     <th>#</th>
+                                    <th>Icona</th>
                                     <th>Nome</th>
                                     <th>Descrizione</th>
                                     <th>Testo</th>
                                     <th></th>
                                     <th></th>
+                                    <th></th>
                                 </tr>
                                 </thead>
                                 <tbody>
                     url: "//cdn.datatables.net/plug-ins/1.10.20/i18n/Italian.json"
                 },
                 columnDefs: [
-                        {"targets": 4, "orderable": false, "width": "5%"},
-                        {"targets": 5, "orderable": false, "width": "5%"},
+                        {"targets": 5, "orderable": false, "width": "4%"},
+                        {"targets": 6, "orderable": false, "width": "4%"},
+                        {"targets": 7, "orderable": false, "width": "4%"},
                 ],
                 "order": []
             });
         });
 
+        function showModalIcona(pk){
+            $("#modal-add-icona-percorso-dialog").modal('show');
+            $("#pk_percorso_modal").val(pk);
+        }
+
         function DeletePercorso(pk){
             Swal.fire({
                 title: "Sei sicuro?",
index fd37ad9c37b652096d0dbd5c2b894c485ae8b670..53730adda229cd9ba5e766cc66080e4074119761 100644 (file)
@@ -3,7 +3,8 @@ from django.urls import path
 from sistema.datatables import LocalitaDatatables, MultimediaDatatables, TipoMultimediaDatatables, PercorsoDatatables, \
     PoiDatatables, FeedbackDatatables, GestisceLocalitaDatatables
 from sistema.views import Home, LocalitaListView, MultimediaListView, PuntiInteresseListView, \
-    TipologiaMultimediaListView, PercorsiListView, LocalitaView, TipoMultimediaView, PoiView, PercorsoView, FeedbackView, PercorsoInfo
+    TipologiaMultimediaListView, PercorsiListView, LocalitaView, TipoMultimediaView, PoiView, PercorsoView, \
+    FeedbackView, PercorsoInfo, QRCodeView
 
 urlpatterns = [
     path('', Home.as_view(), name='home'),
@@ -41,7 +42,10 @@ urlpatterns = [
     path('percorso/', PercorsoView.as_view(), name='percorso'),
     path('mod_percorso/<int:pk>/', PercorsoView.as_view(), name='mod_percorso'),
     path('percorso_info/<int:pk>/', PercorsoInfo.as_view(), name='percorso_info'),
+    path('add_icona_percorso/', PercorsoView.add_icona, name='add_icona_percorso'),
+
 
     ## FEEDBACK ##
     path('feedback/', FeedbackView.as_view(), name='feedback'),
+    path('crea_qr_code/', QRCodeView.crea_qr, name='crea_qr_code'),
 ]
index 06d9af3ec7ae4f1ef101a86ebe4d86f73ca19b8b..ab8d9e9b89f468973f2e653c30e8f89e3cfd1b8c 100644 (file)
@@ -1,7 +1,12 @@
+import hashlib
 import json
+from io import BytesIO
 
+import qrcode
+from cryptography.fernet import Fernet
 from django.contrib import messages
 from django.contrib.auth.mixins import LoginRequiredMixin
+from django.core.files.base import ContentFile
 from django.http import JsonResponse
 from django.shortcuts import render, redirect
 from django.urls import reverse
@@ -9,7 +14,7 @@ from django.views import View
 from django.views.generic import TemplateView
 from rest_framework import status
 
-from sistema.forms import LocalitaForm, TipoMultimediaForm, PoiForm, PercorsoForm, MultimediaForm
+from sistema.forms import LocalitaForm, TipoMultimediaForm, PoiForm, PercorsoForm, MultimediaForm, IconaPercorsoForm
 from sistema.models import Localita, TipologiaMultimedia, PointOfInterest, Percorso, Tappa, TappaSerializer, Multimedia, \
     Feedback, FeedbackSerializer
 from socoin_atlas import settings
@@ -49,7 +54,8 @@ class PercorsiListView(View):
             list_percorsi = Percorso.objects.filter(is_active=True)
             return render(request, 'percorsi_cliente_home.html', {'list_percorsi': list_percorsi})
         else:
-            return render(request, 'percorsi_list.html', {})
+            form = IconaPercorsoForm()
+            return render(request, 'percorsi_list.html', {'form': form})
 
 
 class Home(CustomLoginRequiredMixin, View):  # CustomLoginRequiredMixin
@@ -197,11 +203,16 @@ class PoiView(View):#PermissionRequiredMixin
         if form.is_valid():
             form_save = form.save(commit=False)
             form_save.is_danger = is_danger
+
             if files:
                 for f in files:
                     form_save.icona = f
+                    form_save.save()
+                    form_save.url = 'http://atlas.dyrecta.com/' + str(form_save.icona)
             else:
                 form_save.icona = os.path.join(MEDIA_ROOT, 'icon/default.png')
+                form_save.save()
+                form_save.url = 'http://atlas.dyrecta.com/' + str(form_save.icona)
             form_save.save()
 
             messages.add_message(request, messages.INFO, 'Nuova punto di interesse inserito con successo.')
@@ -235,9 +246,12 @@ class PoiView(View):#PermissionRequiredMixin
             if files:
                 for f in files:
                     form_save.icona = f
+                    form_save.save()
+                    form_save.url = 'http://atlas.dyrecta.com/' + str(form_save.icona)
             else:
                 if not icona:
                     form_save.icona = os.path.join(MEDIA_ROOT, 'icon/default.png')
+                    form_save.url = 'http://atlas.dyrecta.com/' + str(form_save.icona)
             form_save.save()
 
             messages.add_message(request, messages.INFO, 'Punto di interesse aggiornata con successo.')
@@ -291,6 +305,18 @@ class PoiView(View):#PermissionRequiredMixin
 
 class PercorsoView(View):#PermissionRequiredMixin
     #permission_required = [settings.TOUR_OPERATOR_GROUPS, settings.ADMIN_GROUPS]
+    def add_icona(self):
+        percorso = Percorso.objects.get(pk=int(self.POST.get('pk_percorso_icona')))
+        form = IconaPercorsoForm(self.POST, self.FILES, instance=percorso)
+        if form.is_valid():
+            form_save = form.save(commit=False)
+            if os.path.isfile(os.path.join(os.path.join(MEDIA_ROOT, "icon_percorso/"), str(form_save.icona))):
+                os.remove(os.path.join(os.path.join(MEDIA_ROOT, "icon_percorso/"), str(form_save.icona)))
+            form_save.url = 'http://atlas.dyrecta.com/media/icon_percorso/' + str(form_save.icona)
+            form_save.save()
+
+        return redirect('sistema:percorsi_list')
+
 
     def del_poi(self, request):
         percorso = Percorso.objects.get(pk=int(request.GET.get('pk')))
@@ -300,12 +326,13 @@ class PercorsoView(View):#PermissionRequiredMixin
     def add_percorso(self, request):
         form = PercorsoForm(data=json.loads(request.POST.get('percorso_form')))
         if form.is_valid():
-            form.save()
-
+            form_save = form.save(commit=False)
+            form_save.save()
             partenza = request.POST.get('partenza')
             arrivo = request.POST.get('arrivo')
             tappe = request.POST.getlist('tappe[]')
 
+
             if partenza and arrivo and tappe:
                 Tappa.insert_tappe_percorso(partenza, arrivo, tappe, form)
                 return JsonResponse({'response': 'Percorso inserito con successo'}, status=status.HTTP_200_OK)
@@ -323,7 +350,8 @@ class PercorsoView(View):#PermissionRequiredMixin
     def mod_percorso(self, request):
         form = PercorsoForm(data=json.loads(request.POST.get('percorso_form')), instance=Percorso.objects.get(pk=int(self.request.POST.get('pk_percorso_form'))))
         if form.is_valid():
-            form.save()
+            form_save = form.save(commit=False)
+            form_save.save()
 
             tappe = Tappa.objects.filter(percorso_id=int(self.request.POST.get('pk_percorso_form')))
             tappe.delete()
@@ -384,4 +412,40 @@ class FeedbackView(View):#PermissionRequiredMixin
     def get(self, request, *args, **kwargs):
         if request.GET.get('method') == 'del':
             self.del_feedback(request)
-            return JsonResponse({'response': 'Feedback eliminato con successo'}, status=status.HTTP_200_OK)
\ No newline at end of file
+            return JsonResponse({'response': 'Feedback eliminato con successo'}, status=status.HTTP_200_OK)
+
+
+
+class QRCodeView(View):
+    def crea_qr(self):
+        try:
+            id = str(self.POST.get('pk'))
+            id_criptato = hashlib.sha256(id.encode()).hexdigest()
+            base_url = 'http://atlas.dyrecta.com/api/show_qr_code/?id_criptato='
+            url_completo = f"{base_url}{id_criptato}"
+            qr = qrcode.QRCode(
+                version=1,
+                error_correction=qrcode.constants.ERROR_CORRECT_L,
+                box_size=10,
+                border=4,
+            )
+            qr.add_data(url_completo)
+            qr.make(fit=True)
+            img_bytes = BytesIO()
+            img = qr.make_image(fill_color="black", back_color="white")
+            img.save(img_bytes, format='PNG')
+            filename = 'qr_code_'+id_criptato[:10]+'.png'
+            img_bytes.seek(0)
+
+            multimedia = Multimedia.objects.get(pk = id)
+            multimedia.chiave_qr_code = id_criptato
+            multimedia.save()
+            if os.path.isfile(os.path.join(os.path.join(MEDIA_ROOT, "poi_media_qr_code/"), filename)):
+                os.remove(os.path.join(os.path.join(MEDIA_ROOT, "poi_media_qr_code/"), filename))
+            multimedia.qr_code.save(filename, ContentFile(img_bytes.getvalue()), save=True)
+            if os.path.isfile(filename):
+                os.remove(filename)
+            return JsonResponse({'response': 'OK', 'qr_code': 'media/' + str(multimedia.qr_code)}, status=status.HTTP_200_OK)
+        except Exception as e:
+            return JsonResponse({'response': str(e)},
+                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)
\ No newline at end of file