diff --git a/Mapapi/migrations/0006_discussionmessage.py b/Mapapi/migrations/0006_discussionmessage.py new file mode 100644 index 00000000..481b0afc --- /dev/null +++ b/Mapapi/migrations/0006_discussionmessage.py @@ -0,0 +1,26 @@ +# Generated by Django 4.2.7 on 2025-02-27 17:27 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('Mapapi', '0005_user_is_verified_user_otp_user_otp_expiration_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='DiscussionMessage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('message', models.TextField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('collaboration', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Mapapi.collaboration')), + ('incident', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Mapapi.incident')), + ('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/Mapapi/migrations/0007_auto_20250303_0923.py b/Mapapi/migrations/0007_auto_20250303_0923.py new file mode 100644 index 00000000..032181f1 --- /dev/null +++ b/Mapapi/migrations/0007_auto_20250303_0923.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.7 on 2025-03-03 09:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('Mapapi', '0006_discussionmessage'), + ] + + operations = [ + migrations.AddField( + model_name='Collaboration', + name='motivation', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='Collaboration', + name='other_option', + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name='Collaboration', + name='status', + field=models.CharField(max_length=20, default='pending'), + ), + ] diff --git a/Mapapi/migrations/0008_discussionmessage_recipient.py b/Mapapi/migrations/0008_discussionmessage_recipient.py new file mode 100644 index 00000000..6428beec --- /dev/null +++ b/Mapapi/migrations/0008_discussionmessage_recipient.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2025-03-03 11:21 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('Mapapi', '0007_auto_20250303_0923'), + ] + + operations = [ + migrations.AddField( + model_name='discussionmessage', + name='recipient', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='received_messages', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/Mapapi/migrations/0009_alter_collaboration_unique_together.py b/Mapapi/migrations/0009_alter_collaboration_unique_together.py new file mode 100644 index 00000000..2409d48b --- /dev/null +++ b/Mapapi/migrations/0009_alter_collaboration_unique_together.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.7 on 2025-03-03 11:43 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('Mapapi', '0008_discussionmessage_recipient'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='collaboration', + unique_together={('incident', 'user')}, + ), + ] diff --git a/Mapapi/models.py b/Mapapi/models.py index 26727694..591619a0 100644 --- a/Mapapi/models.py +++ b/Mapapi/models.py @@ -390,6 +390,8 @@ class Collaboration(models.Model): other_option = models.CharField(max_length=255, blank=True, null=True) status = models.CharField(max_length=20, default='pending') + class Meta: + unique_together = (("incident", "user"),) def __str__(self): return f"Collaboration on {self.incident} by {self.user}" @@ -446,3 +448,14 @@ class UserAction(models.Model): def __str__(self): return self.action + +class DiscussionMessage(models.Model): + incident = models.ForeignKey('Incident', on_delete=models.CASCADE) + collaboration = models.ForeignKey(Collaboration, on_delete=models.CASCADE) + sender = models.ForeignKey(User, on_delete=models.CASCADE) + message = models.TextField() + created_at = models.DateTimeField(auto_now_add=True) + recipient = models.ForeignKey(User, on_delete=models.CASCADE, related_name="received_messages", null=True, blank=True) + + def __str__(self): + return f"Message de {self.sender} le {self.created_at}" diff --git a/Mapapi/serializer.py b/Mapapi/serializer.py index 0c86335e..d4a0c811 100644 --- a/Mapapi/serializer.py +++ b/Mapapi/serializer.py @@ -275,3 +275,13 @@ class Meta: model = UserAction fields = '__all__' + +class DiscussionMessageSerializer(serializers.ModelSerializer): + sender = UserSerializer(read_only=True) + recipient = UserSerializer(read_only=True) + class Meta: + model = DiscussionMessage + fields = ['id', 'incident', 'collaboration', 'sender', 'message', 'created_at','recipient'] + read_only_fields = ('sender', 'incident', 'collaboration','recipient') + + diff --git a/Mapapi/urls.py b/Mapapi/urls.py index f70514f2..5484b513 100644 --- a/Mapapi/urls.py +++ b/Mapapi/urls.py @@ -102,6 +102,8 @@ path('collaborations/accept/', AcceptCollaborationView.as_view(), name='accept-collaboration'), path('collaboration/', CollaborationView.as_view(), name="collaboration"), path('collaboration///', HandleCollaborationRequestView.as_view(), name="handle_collaboration_request"), + path('discussion//', DiscussionMessageView.as_view(), name='discussion'), + # Search Incident path('Search/', IncidentSearchView.as_view(), name="search"), path('prediction/', PredictionView.as_view(), name="predicton"), diff --git a/Mapapi/views.py b/Mapapi/views.py index a7c7b3e8..1ef395af 100644 --- a/Mapapi/views.py +++ b/Mapapi/views.py @@ -1967,10 +1967,16 @@ def send_sms(phone_number, otp_code): class CollaborationView(generics.CreateAPIView, generics.ListAPIView): - permission_classes = () + permission_classes = [IsAuthenticated] queryset = Collaboration.objects.all() serializer_class = CollaborationSerializer + def get_queryset(self): + user = self.request.user + return Collaboration.objects.filter( + Q(user=user) | Q(incident__taken_by=user) + ) + def post(self, request, *args, **kwargs): try: serializer = CollaborationSerializer(data=request.data) @@ -2402,3 +2408,49 @@ def post(self, request): return Response({"message": "OTP invalide ou expiré"}, status=status.HTTP_400_BAD_REQUEST) except User.DoesNotExist: return Response({"message": "Utilisateur non trouvé"}, status=status.HTTP_404_NOT_FOUND) + + +class DiscussionMessageView(generics.ListCreateAPIView): + serializer_class = DiscussionMessageSerializer + permission_classes = [IsAuthenticated] + + def get_queryset(self): + incident_id = self.kwargs.get('incident_id') + user = self.request.user + try: + collaboration = Collaboration.objects.get( + Q(user=user) | Q(incident__taken_by=user), + incident__id=incident_id, + status='accepted' + ) + except Collaboration.DoesNotExist: + raise NotFound("Aucune discussion trouvée pour cet incident.") + + if collaboration.incident.etat == "resolved": + raise NotFound("La discussion est terminée car l'incident est résolu.") + + return DiscussionMessage.objects.filter( + incident__id=incident_id + ).filter( + Q(sender=user) | Q(recipient=user) + ) + + def perform_create(self, serializer): + incident_id = self.kwargs.get('incident_id') + try: + collaboration = Collaboration.objects.get(incident__id=incident_id, user=self.request.user, status='accepted') + recipient = collaboration.incident.taken_by + except Collaboration.DoesNotExist: + collaboration = Collaboration.objects.get(incident__id=incident_id, status='accepted') + recipient = collaboration.user + + if collaboration.incident.etat == "resolved": + raise ValidationError("Cet incident est résolu, la discussion est terminée.") + + serializer.save( + sender=self.request.user, + incident=collaboration.incident, + collaboration=collaboration, + recipient=recipient + ) +