Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Mapapi/migrations/0010_organisationtag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.7 on 2025-05-09 17:03

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('Mapapi', '0009_alter_collaboration_unique_together'),
]

operations = [
migrations.CreateModel(
name='OrganisationTag',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('incident_type', models.CharField(max_length=255)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='incident_preferences', to=settings.AUTH_USER_MODEL)),
],
),
]
6 changes: 5 additions & 1 deletion Mapapi/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def generate_otp(self):
self.save()

def send_verification_email(self):
verification_link = f"com.uwaish.MapActionApp://verify-email/{self.verification_token}"
verification_link = f"https://api.map-action.com/MapApi/web_verify-email/{self.verification_token}"
context = {"verification_link": verification_link}
subject = "Vérification de votre compte"
template_name = "emails/verification_email.html"
Expand Down Expand Up @@ -459,3 +459,7 @@ class DiscussionMessage(models.Model):

def __str__(self):
return f"Message de {self.sender} le {self.created_at}"

class OrganisationTag(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='incident_preferences')
incident_type = models.CharField(max_length=255)
52 changes: 41 additions & 11 deletions Mapapi/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,53 @@ def create(self, validated_data):
return user


class UserRegisterSerializer(serializers.ModelSerializer):
# class UserRegisterSerializer(serializers.ModelSerializer):
# class Meta:
# model = User
# fields = '__all__'
# depth = 1

# def create(self, validated_data):
# user = User(
# email=validated_data['email'],
# first_name=validated_data['first_name'],
# last_name=validated_data['last_name'],
# phone=validated_data['phone'],
# is_active=True,
# address=validated_data['address']
# )
# user.set_password(validated_data['password'])
# user.save()
# return user


class UserSerializer(ModelSerializer):
incident_preferences = serializers.ListField(
child=serializers.CharField(),
write_only=True,
required=False
)

class Meta:
model = User
fields = '__all__'
depth = 1
exclude = ('user_permissions', 'is_superuser', 'is_active', 'is_staff')

def create(self, validated_data):
user = User(
email=validated_data['email'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name'],
phone=validated_data['phone'],
is_active=True,
address=validated_data['address']
)
zones = validated_data.pop('zones', None)
incident_preferences = validated_data.pop('incident_preferences', [])

user = self.Meta.model(**validated_data)
user.set_password(validated_data['password'])
user.save()

if zones:
user.zones.set(zones)


if user.user_type == "elu" and incident_preferences:
for incident_type in incident_preferences:
OrganisationTag.objects.create(user=user, incident_type=incident_type)

return user


Expand Down
38 changes: 36 additions & 2 deletions Mapapi/signals.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Collaboration, Notification
from .models import Collaboration, Notification, User
from .Send_mails import send_email
import logging

Expand Down Expand Up @@ -46,4 +46,38 @@ def notify_organisation_on_collaboration(sender, instance, created, **kwargs):
logger.error(f"Erreur lors de l'envoi de l'email: {str(e)}")
else:
logger.error(f"Email non valide ou manquant pour l'utilisateur {user}. Collaboration annulée.")
instance.delete()
instance.delete()


def notify_organisations_on_prediction(sender, instance, created, **kwargs):
if not created:
return

incident_type = instance.incident_type

# Organisations intéressées par ce type d'incident
matching_orgs = User.objects.filter(
user_type="elu",
incident_preferences__incident_type=incident_type
).distinct()

for org in matching_orgs:
try:
context = {
'incident_type': incident_type,
'prediction_id': instance.id,
'incident_id': instance.incident_id,
'organisation': org.elu
}

send_email.delay(
subject=f"[MAP ACTION] Nouveau rapport : {incident_type}",
template_name='emails/incident_notification.html',
context=context,
to_email=org.email
)

logger.info(f"Email envoyé à {org.email} pour un nouvel incident de type {incident_type}.")

except Exception as e:
logger.error(f"Erreur lors de l'envoi d'une notification à {org.email} : {str(e)}")
47 changes: 39 additions & 8 deletions Mapapi/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from .serializer import *
from django.middleware.csrf import get_token
from django.http import JsonResponse
from django.http import JsonResponse, HttpResponse
from rest_framework.pagination import PageNumberPagination
from rest_framework import status
from rest_framework.permissions import AllowAny, IsAuthenticated
Expand All @@ -22,6 +22,7 @@
from django.conf import settings
from django.db import IntegrityError
from backend.settings import *
from django.views import View
import json
import datetime
# import requests
Expand All @@ -44,6 +45,13 @@
import logging
from django.utils import timezone
from datetime import timedelta
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
import random
import string

def get_random(length=6):
return ''.join(random.choices(string.digits, k=length))

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -370,10 +378,10 @@ def post(self, request, format=None):
longitude = serializer.data.get("longitude")
latitude = serializer.data.get("lattitude")
print("Longitude:", longitude)
incident_instance = Incident.objects.get(longitude=longitude)
incident_id = incident_instance.id
# incident_instance = Incident.objects.get(longitude=longitude)
# incident_id = incident_instance.id

print(incident_id)
# print(incident_id)



Expand Down Expand Up @@ -1589,17 +1597,16 @@ def get(self, request, id, format=None, **kwargs):
"data": listData
}, status=status.HTTP_200_OK)


@method_decorator(csrf_exempt, name='dispatch')
class PasswordResetView(generics.CreateAPIView):
""" use postman to test give 4 fields new_password new_password_confirm email code post methode"""
permission_classes = (

)
queryset = User.objects.all()
serializer_class = ResetPasswordSerializer

def post(self, request, *args, **kwargs):

print("✅ post() de PasswordResetView appelée")
if 'code' not in request.data or request.data['code'] is None:
return Response({
"status": "failure",
Expand Down Expand Up @@ -1685,7 +1692,9 @@ def post(self, request, *args, **kwargs):
user=user_,
code=code_
)
subject, from_email, to = '[MAP ACTION] - Votre code de reinitialisation', settings.EMAIL_HOST_USER, user_.email
subject = '[MAP ACTION] - Votre code de réinitialisation'
from_email = 'Map Action <{}>'.format(settings.EMAIL_HOST_USER)
to = user_.email
html_content = render_to_string('mail_pwd.html', {'code': code_}) # render with dynamic value#
text_content = strip_tags(html_content) # Strip the html tag. So people can see the pure text at least.
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
Expand Down Expand Up @@ -2452,3 +2461,25 @@ def perform_create(self, serializer):
recipient=recipient
)

class RedirectToAppView(View):
def get(self, request, token):
deep_link_url = f"com.uwaish.MapActionApp://verify-email/{token}"
html = f"""
<!DOCTYPE html>
<html>
<head>
<title>Redirection...</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript">
window.location = "{deep_link_url}";
setTimeout(function() {{
window.location = "https://map-action.com/"; // fallback si l'app n'est pas installée
}}, 3000);
</script>
</head>
<body>
<p>Redirection vers l'application en cours...</p>
</body>
</html>
"""
return HttpResponse(html)
68 changes: 68 additions & 0 deletions template/emails/incident_notification.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Nouveau Rapport d'Incident</title>
<style>
body {
font-family: 'Arial', sans-serif;
background-color: #f4f4f4;
padding: 20px;
color: #333;
}

.container {
background-color: #ffffff;
max-width: 600px;
margin: 0 auto;
padding: 30px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}

h2 {
color: #1976D2;
}

.btn {
display: inline-block;
margin-top: 20px;
padding: 12px 20px;
background-color: #1976D2;
color: #ffffff;
text-decoration: none;
border-radius: 5px;
}

.footer {
margin-top: 30px;
font-size: 12px;
text-align: center;
color: #999;
}

.highlight {
font-weight: bold;
color: #444;
}
</style>
</head>
<body>
<div class="container">
<h2>🔔 Nouveau rapport d'incident signalé</h2>

<p>Bonjour, {{ organisation }}</p>

<p>Un nouvel incident de type <span class="highlight">{{ incident_type }}</span> a été reporté sur la plateforme <strong>MAP ACTION</strong>.</p>

<p>👉 Nous vous recommandons de consulter la plateforme pour voir plus de détails et prendre les mesures nécessaires.</p>

<a href="https://app.map-action.com/auth/signin" class="btn">Consulter l'incident</a>

<div class="footer">
Cet email vous a été envoyé automatiquement par la plateforme MAP ACTION.<br>
Merci de ne pas répondre directement à ce message.
</div>
</div>
</body>
</html>