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
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ __pycache__/
local_settings.py
db.sqlite3
db.sqlite3-journal
media

# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
# in your Git repository. Update and uncomment the following line accordingly.
Expand Down
2 changes: 2 additions & 0 deletions aigle/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,5 @@
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

MEDIA_ROOT = os.path.join(BASE_DIR, "media")
46 changes: 46 additions & 0 deletions core/utils/odt_processor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import zipfile
import tempfile
from pathlib import Path
from typing import Dict, Any


class ODTTemplateProcessor:
def __init__(self, template_path: str):
self.template_path = template_path

def replace_placeholders(
self, replacements: Dict[str, Any], output_path: str
) -> None:
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)

with zipfile.ZipFile(self.template_path, "r") as zip_ref:
zip_ref.extractall(temp_path)

content_file = temp_path / "content.xml"
if content_file.exists():
self._process_xml_file(content_file, replacements)

styles_file = temp_path / "styles.xml"
if styles_file.exists():
self._process_xml_file(styles_file, replacements)

self._create_odt_file(temp_path, output_path)

def _process_xml_file(self, xml_file: Path, replacements: Dict[str, Any]) -> None:
with open(xml_file, "r", encoding="utf-8") as f:
content = f.read()

for placeholder, value in replacements.items():
content = content.replace("{{" + placeholder + "}}", str(value))
content = content.replace(placeholder, str(value))

with open(xml_file, "w", encoding="utf-8") as f:
f.write(content)

def _create_odt_file(self, source_dir: Path, output_path: str) -> None:
with zipfile.ZipFile(output_path, "w", zipfile.ZIP_DEFLATED) as zip_file:
for file_path in source_dir.rglob("*"):
if file_path.is_file():
relative_path = file_path.relative_to(source_dir)
zip_file.write(file_path, relative_path)
30 changes: 28 additions & 2 deletions core/views/detection/detection_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
DetectionPrescriptionStatus,
DetectionValidationStatus,
)
from core.models.geo_custom_zone import GeoCustomZone, GeoCustomZoneStatus
from core.models.geo_custom_zone_category import GeoCustomZoneCategory
from core.models.tile_set import TileSet, TileSetStatus, TileSetType
from core.models.user import UserRole
from core.permissions.tile_set import TileSetPermission
from core.permissions.user import UserPermission
from core.repository.base import NumberRepoFilter, RepoFilterLookup
Expand Down Expand Up @@ -275,6 +278,29 @@ def filter_queryset(self, queryset):
"detection_object__parcel__geometry",
"detection_object__commune__geometry",
)

# TODO: move this in permission file and apply this to geo
if self.request.user.user_role == UserRole.SUPER_ADMIN:
geo_custom_zones_prefetch = Prefetch("detection_object__geo_custom_zones")
geo_custom_zones_category_prefetch = Prefetch(
"detection_object__geo_custom_zones__geo_custom_zone_category"
)
else:
geo_custom_zones_prefetch = Prefetch(
"detection_object__geo_custom_zones",
queryset=GeoCustomZone.objects.filter(
geo_custom_zone_status=GeoCustomZoneStatus.ACTIVE,
user_groups_custom_geo_zones__user_user_groups__user=self.request.user.id,
),
)
geo_custom_zones_category_prefetch = Prefetch(
"detection_object__geo_custom_zones__geo_custom_zone_category",
queryset=GeoCustomZoneCategory.objects.filter(
geo_custom_zones__geo_custom_zone_status=GeoCustomZoneStatus.ACTIVE,
geo_custom_zones__user_groups_custom_geo_zones__user_user_groups__user=self.request.user.id,
),
)

queryset = queryset.prefetch_related(
"detection_object",
"detection_object__object_type",
Expand All @@ -293,8 +319,8 @@ def filter_queryset(self, queryset):
.order_by(*DEFAULT_VALUES["order_bys"])
.distinct(),
),
"detection_object__geo_custom_zones",
"detection_object__geo_custom_zones__geo_custom_zone_category",
geo_custom_zones_prefetch,
geo_custom_zones_category_prefetch,
"detection_data",
"tile_set",
).select_related("detection_data")
Expand Down
2 changes: 2 additions & 0 deletions core/views/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from . import get_custom_geometry
from . import get_annotation_grid
from . import contact_us
from . import generate_prior_letter

URL_PREFIX = "utils/"

Expand All @@ -18,5 +19,6 @@
get_custom_geometry,
get_annotation_grid,
contact_us,
generate_prior_letter,
]
]
56 changes: 56 additions & 0 deletions core/views/utils/generate_prior_letter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import os
import tempfile
from django.conf import settings
from django.http import HttpResponse, JsonResponse

from rest_framework import serializers


from common.constants.models import DEFAULT_MAX_LENGTH
from rest_framework.status import HTTP_500_INTERNAL_SERVER_ERROR

from core.utils.odt_processor import ODTTemplateProcessor


class EndpointSerializer(serializers.Serializer):
firstName = serializers.CharField(max_length=DEFAULT_MAX_LENGTH)
lastName = serializers.CharField(max_length=DEFAULT_MAX_LENGTH)
collectivity = serializers.CharField(max_length=DEFAULT_MAX_LENGTH)
job = serializers.CharField(max_length=DEFAULT_MAX_LENGTH)
phone = serializers.CharField(max_length=DEFAULT_MAX_LENGTH)
email = serializers.EmailField()


TEMPLATE_PATH = os.path.join(settings.MEDIA_ROOT, "templates", "test.odt")


def endpoint(request):
try:
filename = "test.odt"

with tempfile.NamedTemporaryFile(suffix=".odt", delete=False) as temp_file:
temp_output_path = temp_file.name

try:
processor = ODTTemplateProcessor(TEMPLATE_PATH)
processor.replace_placeholders(
{"template_value": "hello la team"}, temp_output_path
)

with open(temp_output_path, "rb") as f:
response = HttpResponse(
f.read(), content_type="application/vnd.oasis.opendocument.text"
)
response["Content-Disposition"] = f'attachment; filename="{filename}"'
return response
finally:
os.unlink(temp_output_path)

except Exception as e:
return JsonResponse(
{"error": "Failed to generate document", "details": str(e)},
status=HTTP_500_INTERNAL_SERVER_ERROR,
)


URL = "generate-prior-letter/"
Binary file added media/templates/test.odt
Binary file not shown.