o
    PXhor                     @   sj  d Z ddlmZmZmZmZmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlZddlZddlmZmZ ddlmZ ddlmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z' ddl(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z. ddl/m0Z0m1Z1 e Z2e3e4Z5eeeddd Z6eeeddd Z7eeeddd Z8eeeddd Z9eeeddd Z:eee ddd Z;eee!ddd  Z<eee"dd!d" Z=eee#dd#d$ Z>eee$dd%d& Z?eeej@jAdd'd( ZBeee&dd)d* ZCed+d, ZDed-d. ZEed/d0 ZFd1d2 ZGd9d3d4ZHeeedd5d6 ZIed7d8 ZJdS ):a  Creative Management Signal Handlers

Django signal handlers for creative asset management.
Handles automated tasks, logging, notifications, and data integrity.

Signal Categories:
- Model Signals: pre_save, post_save, pre_delete, post_delete
- File Signals: File upload, deletion, and processing
- Approval Signals: Approval workflow automation
- Performance Signals: Performance data updates
- Compliance Signals: Compliance checking automation
- Notification Signals: Email and system notifications
- Cache Signals: Cache invalidation and updates
- Audit Signals: Activity logging and tracking

Handlers:
- creative_pre_save: Pre-save processing
- creative_post_save: Post-save automation
- creative_post_delete: Cleanup after deletion
- file_upload_handler: Handle file uploads
- approval_status_changed: Handle approval changes
- performance_updated: Handle performance updates
- compliance_checked: Handle compliance results
- version_created: Handle version creation
- asset_uploaded: Handle asset uploads

Integrations:
- Celery for async tasks
- Email notifications
- Cache management
- File storage cleanup
- Audit logging
- Performance tracking
    )pre_save	post_save
pre_deletepost_deletem2m_changed)receiver)cache)timezone)get_user_model)	send_mail)render_to_string)settings)transactionN)datetime	timedelta)shared_task   )
CreativeCreativeVersionCreativeAssetCreativeApprovalCreativePerformanceCreativeComplianceCreativeTemplateCreativeTagCreativeVariantCreativeFormat)process_creative_filecheck_compliancegenerate_thumbnailsextract_metadatasend_approval_notificationupdate_performance_metrics)get_file_metadatavalidate_creative_file)senderc              
   K   sD  zt  |_|js|jrtj|jj}tj|d |_|jr]|j	r]tj|jjd 
 }g dg dg dddgg dd	}|j	|v r]|||j	 vr]td
|j	 d| d|j  |jdu red|_|jdu rt|jrqd|_nd|_td|j d|j d W dS  ty } ztdt|  W Y d}~dS d}~ww )z
    Handle creative pre-save operations.
    
    Args:
        sender: Model class
        instance: Creative instance
        **kwargs: Additional arguments
    r   r   ).jpg.jpeg.png.gif.webp)z.mp4z.movz.aviz.webm)z.mp3z.wavz.aacz.ogg.htmlz.htm)r&   r'   r(   r)   r*   r+   )imageZvideoZaudioZhtmlZbannerzCreative type 'z ' doesn't match file extension 'z' for creative: N   Z
processingZdraftzCreative pre-save: z
 (Status: )zError in creative pre-save: )r	   nowZ
updated_atnameprimary_fileospathbasenamesplitextZcreative_typelowerloggerwarningprioritypkcreative_statusinfo	Exceptionerrorstr)r%   instancekwargsfilenameZfile_extZtype_extensionsexc rD   apps/creatives/signals.pycreative_pre_saveC   s>   




""rF   c              
      s  z|r?t d j d j d  jr.tjj d j jpdd j	d t
 fdd	  j	r> j	jr>t
 fd
d	 nLt d j d j d  jdrw jrw j d }tjj | j jphdd jd t
 fdd	  jdr jdkrt
 fdd	 d j  jrd j ndddg}td|D ]}t| qW dS  ty } zt dt|  W Y d}~dS d}~ww )z
    Handle creative post-save operations.
    
    Args:
        sender: Model class
        instance: Creative instance
        created: Whether instance was created
        **kwargs: Additional arguments
    zNew creative created:  (ID: r.   r   r   zInitial version)creativeversion_numberfile	file_sizeZchanges
created_byc                         t  jS Nr   delayr:   rD   r@   rD   rE   <lambda>       z$creative_post_save.<locals>.<lambda>c                      rM   rN   )send_creation_notificationrP   r:   rD   rQ   rD   rE   rR      rS   zCreative updated: r1   zFile updatedc                      rM   rN   rO   rD   rQ   rD   rE   rR      rS   r;   approvedc                      s   t  jdS )NrU   )send_status_notificationrP   r:   rD   rQ   rD   rE   rR          	creative_creative_list_Ncreative_statsdashboard_statszError in creative post-save: )r7   r<   r0   r:   r1   r   objectsZcreaterK   rL   r   	on_commitemailZtrackerZhas_changedversionscountZ
updated_byr;   campaign_idfilterr   deleter=   r>   r?   )r%   r@   createdrA   rI   
cache_keyskeyrC   rD   rQ   rE   creative_post_savez   sh   






"rg   c              
   K   s   zNt d|j d|j d g }|jr||jj |jr%||jj |j	 D ]}|j
r6||j
j q*|j	 D ]}|j
rH||j
j q<||_W dS  tyk } zt dt|  W Y d}~dS d}~ww )z
    Handle creative pre-delete operations.
    
    Args:
        sender: Model class
        instance: Creative instance
        **kwargs: Additional arguments
    zCreative being deleted: rG   r.   zError in creative pre-delete: N)r7   r<   r0   r:   r1   appendr3   Z	thumbnailr_   allrJ   Zassets_files_to_deleter=   r>   r?   )r%   r@   rA   files_to_deleteversionZassetrC   rD   rD   rE   creative_pre_delete   s(   
"rm   c                 K   s  zkt d|j  t|dg }|D ]6}ztj|r(t| t d|  W q tyH } zt 	d| dt
|  W Y d}~qd}~ww d|j |jrWd|j ndd	d
g}td|D ]}t| qaW dS  ty } zt dt
|  W Y d}~dS d}~ww )z
    Handle creative post-delete cleanup.
    
    Args:
        sender: Model class
        instance: Creative instance
        **kwargs: Additional arguments
    zCreative deleted: rj   zDeleted file: zCould not delete file : NrX   rY   rZ   r[   zError in creative post-delete: )r7   r<   r0   getattrr2   r3   existsremover=   r8   r?   r:   ra   rb   r   rc   r>   )r%   r@   rA   rk   Z	file_pathrC   re   rf   rD   rD   rE   creative_post_delete   s2   

&
"rr   c              
      s   z>|r9t d jj d j   j jj kr* jr* j j_ jjdgd  j	r<t
 fdd W dS W dS W dS  ty[ } zt dt|  W Y d}~dS d}~ww )	z
    Handle creative version creation.
    
    Args:
        sender: Model class
        instance: CreativeVersion instance
        created: Whether instance was created
        **kwargs: Additional arguments
    zNew version created: z vrK   Zupdate_fieldsc                         t  jjS rN   )r    rP   rH   r:   rD   rQ   rD   rE   rR   5  rW   z!version_created.<locals>.<lambda>zError in version creation: N)r7   r<   rH   r0   rI   r_   r`   rK   saverJ   r   r]   r=   r>   r?   r%   r@   rd   rA   rC   rD   rQ   rE   version_created  s&   


"rw   c              
      s   z<|r4 j r7td j d jj   j r# j j _ jdgd  jdkr:t	
 fdd W d	S W d	S W d	S W d	S  tyY } ztdt|  W Y d	}~d	S d	}~ww )
z
    Handle creative asset upload.
    
    Args:
        sender: Model class
        instance: CreativeAsset instance
        created: Whether instance was created
        **kwargs: Additional arguments
    zNew asset uploaded:  for creative rK   rs   r,   c                      rt   rN   )r   rP   rH   r:   rD   rQ   rD   rE   rR   V  rW   z asset_uploaded.<locals>.<lambda>zError in asset upload: N)rJ   r7   r<   r0   rH   sizerK   ru   Z
asset_typer   r]   r=   r>   r?   rv   rD   rQ   rE   asset_uploaded=  s$   




"rz   c              
      s   zP|rKt d jj d j   jdkr.d j_ jjdgd t fdd W dS  jdkrNd j_ jjdgd t fd	d W dS W dS W dS  t	ym } zt 
d
t|  W Y d}~dS d}~ww )z
    Handle approval status changes.
    
    Args:
        sender: Model class
        instance: CreativeApproval instance
        created: Whether instance was created
        **kwargs: Additional arguments
    zApproval created:  - rU   r;   rs   c                         t  jj j jj jS rN   r!   rP   rH   r:   approval_statusZreviewerZcommentsrD   rQ   rD   rE   rR   v      z)approval_status_changed.<locals>.<lambda>Zrejectedc                      r|   rN   r}   rD   rQ   rD   rE   rR     r   z!Error in approval status change: N)r7   r<   rH   r0   r~   r;   ru   r   r]   r=   r>   r?   rv   rD   rQ   rE   approval_status_changed^  s.   



	

"r   c              
   K   s   zQt d|jj d|j  |j}|jjtdtdtdd}|d p)d|_	|d	 p0d|_
|d
 p7d|_|jg dd td|j  td W dS  tyn } zt dt|  W Y d}~dS d}~ww )z
    Handle performance data updates.
    
    Args:
        sender: Model class
        instance: CreativePerformance instance
        created: Whether instance was created
        **kwargs: Additional arguments
    zPerformance updated: r{   impressionsclicksconversions)total_impressionstotal_clickstotal_conversionsr   r   r   r   )r   r   r   rs   creative_performance_performance_statszError in performance update: N)r7   r<   rH   r0   dateperformance_data	aggregatemodelsSumr   r   r   ru   r   rc   r:   r=   r>   r?   )r%   r@   rd   rA   rH   r   rC   rD   rD   rE   performance_updated  s(   "r   c              
      s   z7t d jj d j   j} jdk|_ j|_|jddgd  jdkr5t	 fdd	 W dS W dS  t
yT } zt d
t|  W Y d}~dS d}~ww )z
    Handle compliance check results.
    
    Args:
        sender: Model class
        instance: CreativeCompliance instance
        created: Whether instance was created
        **kwargs: Additional arguments
    zCompliance checked: r{   Z	compliantis_compliantcompliance_scorers   Znon_compliantc                      rM   rN   )send_compliance_notificationrP   r:   rD   rQ   rD   rE   rR     rS   z$compliance_checked.<locals>.<lambda>zError in compliance check: N)r7   r<   rH   r0   Zcompliance_statusr   r   ru   r   r]   r=   r>   r?   )r%   r@   rd   rA   rH   rC   rD   rQ   rE   compliance_checked  s"   


"r   c              
   K   s   z&|rt d|j  n	t d|j  td td|j  W dS  tyC } zt dt|  W Y d}~dS d}~ww )z
    Handle template updates.
    
    Args:
        sender: Model class
        instance: CreativeTemplate instance
        created: Whether instance was created
        **kwargs: Additional arguments
    zNew template created: zTemplate updated: Ztemplate_listZ	template_zError in template update: N	r7   r<   r0   r   rc   r:   r=   r>   r?   rv   rD   rD   rE   template_updated  s   
"r   c              
   K   s   z'|dv r%t d| d|j d|  td|j  td W dS W dS  tyD } zt dt|  W Y d}~dS d}~ww )	z
    Handle creative tag changes.
    
    Args:
        sender: Through model class
        instance: Creative instance
        action: M2M action (post_add, post_remove, etc.)
        pk_set: Set of tag PKs
        **kwargs: Additional arguments
    )Zpost_addZpost_removezTags z for creative: z	 - Tags: creative_tags_	tag_statszError in tag change: Nr   )r%   r@   actionZpk_setrA   rC   rD   rD   rE   creative_tags_changed  s   	"r   c              
   K   s   z:|r5t d|j d|jj  |jjjtddd pd}|dkr8t 	d|jj d	| d
 W dS W dS W dS  t
yW } zt dt|  W Y d}~dS d}~ww )z
    Handle creative variant creation.
    
    Args:
        sender: Model class
        instance: CreativeVariant instance
        created: Whether instance was created
        **kwargs: Additional arguments
    zNew variant created: rx   Ztraffic_allocation)totalr   r   d   z-Traffic allocation exceeds 100% for creative rn   %zError in variant creation: N)r7   r<   Zvariant_namerH   r0   Zvariantsr   r   r   r8   r=   r>   r?   )r%   r@   rd   rA   Ztotal_allocationrC   rD   rD   rE   variant_created  s,   

"r   c              
   C   s   zDt jj| d}|jr?|jjrBd|j }||jd}td|}td|}t|||tj	|jjgdd t
d|j  W dS W dS W dS  t jyW   t
d	|   Y dS  tys } zt
d
t|  W Y d}~dS d}~ww )zd
    Send creative creation notification.
    
    Args:
        creative_id (int): Creative ID
    idzCreative Created: )rH   userz+creatives/emails/creation_notification.htmlz*creatives/emails/creation_notification.txtTsubjectmessagehtml_messageZ
from_emailZrecipient_listZfail_silentlyz)Creation notification sent for creative: Creative not found: z%Error sending creation notification: Nr   r\   getrL   r^   r0   r   r   r   DEFAULT_FROM_EMAILr7   r<   DoesNotExistr>   r=   r?   )creative_idrH   r   contextr   plain_messagerC   rD   rD   rE   rT   -  s2   

	"rT   c              
   C   s   zEt jj| d}|jr@|jjrCd|j }|||jd}td|}td|}t|||tj	|jjgdd t
d|j  W dS W dS W dS  t jyX   t
d	|   Y dS  tyt } zt
d
t|  W Y d}~dS d}~ww )z
    Send creative status change notification.
    
    Args:
        creative_id (int): Creative ID
        status (str): New status
    r   zCreative Status Changed: )rH   statusr   z)creatives/emails/status_notification.htmlz(creatives/emails/status_notification.txtTr   z'Status notification sent for creative: r   z#Error sending status notification: Nr   )r   r   rH   r   r   r   r   rC   rD   rD   rE   rV   T  s4   	

	"rV   c              
   C   s   zHt jj| d}|j}|jrC|jjrFd|j }|||jd}td|}td|}t|||t	j
|jjgdd td|j  W dS W dS W dS  t jy[   td	|   Y dS  tyw } ztd
t|  W Y d}~dS d}~ww )zi
    Send compliance notification.
    
    Args:
        compliance_id (int): CreativeCompliance ID
    r   zCompliance Issue: )rH   
compliancer   z-creatives/emails/compliance_notification.htmlz,creatives/emails/compliance_notification.txtTr   z+Compliance notification sent for creative: zCompliance record not found: z'Error sending compliance notification: N)r   r\   r   rH   rL   r^   r0   r   r   r   r   r7   r<   r   r>   r=   r?   )Zcompliance_idr   rH   r   r   r   r   rC   rD   rD   rE   r   }  s6   

	"r   c                 C   sN   d|  d|  d|  dddddg}|D ]}t | qtd	|   d
S )zl
    Invalidate all caches related to a creative.
    
    Args:
        creative_id (int): Creative ID
    rX   r   r   Zcreative_listrZ   r[   r   r   z!Caches invalidated for creative: N)r   rc   r7   r<   )r   re   rf   rD   rD   rE   invalidate_creative_caches  s   r   c              
   C   s   z.t   | j| j||r|jnd|r|jnd|pi d}td| d| j d|  W dS  tyK } zt	dt
|  W Y d}~dS d}~ww )z
    Log creative activity for audit purposes.
    
    Args:
        creative (Creative): Creative instance
        action (str): Action performed
        user (User): User who performed action
        details (dict): Additional details
    N)Z	timestampr   Zcreative_namer   Zuser_idZ
user_emaildetailszCreative activity: r{   z by z!Error logging creative activity: )r	   r/   Z	isoformatr:   r0   r^   r7   r<   r=   r>   r?   )rH   r   r   r   Z	log_entryrC   rD   rD   rE   log_creative_activity  s   

$
"r   c              
      s  zm|sbj dkrej rjj  d ndjr jj d nd dk r>tdj ddd tfdd	  d
k rhjdkrktdj d dd t fdd	 W dS W dS W dS W dS W dS  ty } zt	dt
|  W Y d}~dS d}~ww )z
    Monitor creative performance and trigger alerts.
    
    Args:
        sender: Model class
        instance: Creative instance
        created: Whether instance was created
        **kwargs: Additional arguments
    r   r   g      ?zLow CTR alert: z - CTR: z.2fr   c                         t jd S )NZlow_ctrsend_performance_alertrP   r:   rD   )ctrr@   rD   rE   rR         z.monitor_creative_performance.<locals>.<lambda>g      ?zLow conversion rate alert: z	 - Rate: c                      r   )NZlow_conversionr   rD   )conversion_rater@   rD   rE   rR     r   z'Error monitoring creative performance: N)r   r   r   r7   r8   r0   r   r]   r=   r>   r?   rv   rD   )r   r   r@   rE   monitor_creative_performance  s0   

"r   c           
   
   C   s  z]t jj| d}g }|jr|jjr||jj |jr,|jjr,|jjjr,||jjj |r[d|j }|||d}t	d|}t	d|}t
|||tj|dd td|j  W dS W dS  t jyp   td	|   Y dS  ty }	 ztd
t|	  W Y d}	~	dS d}	~	ww )z
    Send performance alert notification.
    
    Args:
        creative_id (int): Creative ID
        alert_type (str): Type of alert
        metric_value (float): Metric value that triggered alert
    r   zPerformance Alert: )rH   
alert_typemetric_valuez'creatives/emails/performance_alert.htmlz&creatives/emails/performance_alert.txtTr   z%Performance alert sent for creative: r   z!Error sending performance alert: N)r   r\   r   rL   r^   rh   ZcampaignZmanagerr0   r   r   r   r   r7   r<   r   r>   r=   r?   )
r   r   r   rH   Z
recipientsr   r   r   r   rC   rD   rD   rE   r   
  s>   


	"r   )NN)K__doc__Zdjango.db.models.signalsr   r   r   r   r   Zdjango.dispatchr   Zdjango.core.cacher   Zdjango.utilsr	   Zdjango.contrib.authr
   Zdjango.core.mailr   Zdjango.template.loaderr   Zdjango.confr   Z	django.dbr   Zloggingr2   r   r   Zceleryr   r   r   r   r   r   r   r   r   r   r   r   Ztasksr   r   r   r    r!   r"   Zutilsr#   r$   ZUserZ	getLogger__name__r7   rF   rg   rm   rr   rw   rz   r   r   r   r   ZtagsZthroughr   r   rT   rV   r   r   r   r   r   rD   rD   rD   rE   <module>   sn    #0 



6

Q

&

'

!

 

2

%

 




&
(
)

 
)