estelam ticket, varizha , others

This commit is contained in:
javad committed 2026-10-13 15:48:24 +03:30
1 parent 35a1ec1794
commit 6b546aad76
71 files changed
+2865 -191

No files matched your search

+2 -1
View File
@@ -54,4 +54,5 @@ class AttachmentPolicyAdmin(admin.ModelAdmin):
form = AttachmentPolicyAdminForm
admin.site.register(Attachment)
from apps.tickets.response_admin import RelatedResponseContentAdmin
admin.site.register(Attachment, RelatedResponseContentAdmin)
+13
View File
@@ -19,3 +19,16 @@ def signed_media_redirect(relative_path, *, download=False, lifetime=300):
if download:
query["download"] = "1"
return HttpResponseRedirect(f"{uri}?{urlencode(query)}")
def attachment_response(attachment, *, download=False):
"""Deliver authorized bytes; confidential responses never use bearer URLs."""
import mimetypes
from django.http import FileResponse
if settings.USE_NGINX_MEDIA and not attachment.relative_path.startswith("dispatch-responses/"):
return signed_media_redirect(attachment.relative_path, download=download)
content_type = attachment.mime_type or mimetypes.guess_type(attachment.original_name)[0] or "application/octet-stream"
response = FileResponse(attachment.file.open("rb"), content_type=content_type,
as_attachment=download, filename=attachment.original_name)
response["X-Content-Type-Options"] = "nosniff"
return response
+4
View File
@@ -5,6 +5,10 @@ from django.db import models
from apps.core.models import PublicIdModel
def attachment_path(instance,filename):
ext=Path(filename).suffix.lower(); t=instance.message.ticket; m=instance.message
from apps.tickets.dispatch_responses import response_control
control = response_control(t.group_dispatch) if t.group_dispatch_id else None
if m.author_id == t.customer_id and control and control.mode == "SEALED":
return f"dispatch-responses/{t.public_id}/{m.public_id}/{uuid.uuid4().hex}{ext}"
return f"tickets/{t.created_at:%Y/%m}/{t.public_id}/{m.public_id}/{uuid.uuid4().hex}{ext}"
class AttachmentPolicy(models.Model):
attachment_type=models.CharField(max_length=20,unique=True); is_enabled=models.BooleanField(default=True); max_file_size=models.PositiveBigIntegerField(); max_files_per_message=models.PositiveSmallIntegerField(default=10); allowed_extensions=models.JSONField(default=list); allowed_mime_types=models.JSONField(default=list); sort_order=models.PositiveIntegerField(default=0); updated_at=models.DateTimeField(auto_now=True)
+9 -16
View File
@@ -1,30 +1,23 @@
import mimetypes
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.http import FileResponse
from django.shortcuts import get_object_or_404
from apps.tickets.policies import TicketPolicy
from apps.accounts.magic_access import get_ticket_magic_access
from .delivery import signed_media_redirect
from .delivery import attachment_response
from .models import Attachment
from django.views.decorators.cache import never_cache
def _authorized_attachment(request,public_id):
attachment=get_object_or_404(Attachment.objects.select_related("message__ticket"),public_id=public_id); ticket=attachment.message.ticket
magic_link = None if request.user.is_authenticated else get_ticket_magic_access(request,ticket)
if not TicketPolicy.can_view(request.user,ticket) and not magic_link: raise PermissionDenied
from apps.tickets.dispatch_responses import can_read_response
actor = ticket.customer if magic_link else request.user
if not can_read_response(actor, attachment.message): raise PermissionDenied
if attachment.message.is_internal and (magic_link or getattr(request.user,"account_type",None)=="CUSTOMER"): raise PermissionDenied
if attachment.message.deleted_at and not request.user.has_perm("messaging.view_deleted_message_content"): raise PermissionDenied
return attachment
@never_cache
def view(request,public_id):
attachment=_authorized_attachment(request,public_id)
if settings.USE_NGINX_MEDIA:
return signed_media_redirect(attachment.relative_path)
content_type=attachment.mime_type or mimetypes.guess_type(attachment.original_name)[0] or "application/octet-stream"
response=FileResponse(attachment.file.open("rb"),content_type=content_type)
response["Content-Disposition"]=f'inline; filename="{attachment.original_name}"'
response["X-Content-Type-Options"]="nosniff"
return response
return attachment_response(_authorized_attachment(request, public_id))
@never_cache
def download(request,public_id):
attachment=_authorized_attachment(request,public_id)
if settings.USE_NGINX_MEDIA:
return signed_media_redirect(attachment.relative_path, download=True)
return FileResponse(attachment.file.open("rb"),as_attachment=True,filename=attachment.original_name)
return attachment_response(_authorized_attachment(request, public_id), download=True)