o
    $hi                     @   s  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mZ d dlmZ d dl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mZ G dd dejZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZ G dd deZ!G dd deZ"G d d! d!eZ#G d"d# d#eZ$G d$d% d%eZ%G d&d' d'eZ&G d(d) d)eZ'G d*d+ d+eZ(G d,d- d-eZ)G d.d/ d/eZ*G d0d1 d1eZ+e Z,G d2d3 d3eZ-G d4d5 d5ejZ.G d6d7 d7eZ/G d8d9 d9eZ0dS ):    )models)reverse)gettext_lazy)ValidationError)RichTextFieldN)slugify)now)transaction)get_user_model)timezone   )translate_to_englishc                       s   e Zd ZdZejdejddZej	dddZ
ej	dddZejdedddd	Zejded
ddZG dd dZ fddZ fddZdd Z fddZdddZ  ZS )	BaseModela  
    Abstract base model that contains common fields used across multiple models.
    
    Fields:
        guid: Unique identifier for the record
        created_at: Timestamp when the record was created
        ldm: Last date modified timestamp
        user: User ID who created/modified the record
        rskey: Record status key
        slug: URL-friendly version of the title (for models with titles)
    TF)uniquedefaulteditableauto_now_addr   )auto_nowr   r   zUser ID)r   	help_textr   blankzRecord Status Key)r   r   r   c                   @      e Zd ZdZdS )zBaseModel.MetaTN__name__
__module____qualname__abstract r   r   </var/www/html/mimamsha/mimansha/apps/mimansha_main/models.pyMeta'       r   c                       t    dS z%Validate the model data before savingNsupercleanself	__class__r   r   r%   *      zBaseModel.cleanc                    s   t  j|i | dS z(Override delete to handle image deletionN)r$   deleter'   argskwargsr(   r   r   r,   .   s   zBaseModel.deletec                 O   s   d| _ |   dS )zM
        Soft record blocking - sets rskey to 1 and saves the record
        r   N)rskeysaver-   r   r   r   srb3   s   zBaseModel.srbc              
      s<   z|    t j|i | W dS  ty } z d}~ww )zJ
        Override save method to perform validation before saving
        N)
full_cleanr$   r1   r   )r'   r.   r/   er(   r   r   r1   :   s   zBaseModel.saveNc                 C   sH   t | ts	td|du rd| _| S t |tr |dkr || _| S td)a  
        Helper function to assign a user ID to a model instance that inherits from BaseModel.
        If no user_id is provided, defaults to 0.
        
        Args:
            instance: An instance of a model that inherits from BaseModel
            user_id: (Optional) The user ID to assign to the instance
            
        Returns:
            The instance with the user field updated (not saved)
            
        Raises:
            ValueError: If the instance is not a subclass of BaseModel or if user_id is invalid
        z(Instance must be a subclass of BaseModelNr   z.user_id must be a non-negative integer or None)
isinstancer   
ValueErroruserint)instanceuser_idr   r   r   assign_user_to_modelD   s   
zBaseModel.assign_user_to_modelN)r   r   r   __doc__r   	UUIDFielduuiduuid4guidDateTimeField
created_atldmIntegerField_r7   r0   r   r%   r,   r2   r1   r;   __classcell__r   r   r(   r   r      s    
r   c                       s   e Zd ZejdddeddZejdddeddZejddded	dZ	ejddded
dZ
G dd dZ fddZ fddZ fddZ  ZS )BaseWithSeoTzmeta_images/
meta_image)nullr   	upload_tor      
meta_title
max_lengthrJ   r   r   i  meta_descriptionmeta_keywordsc                   @   r   )zBaseWithSeo.MetaTNr   r   r   r   r   r   g   r    r   c                    r!   r"   r#   r&   r(   r   r   r%   k   r*   zBaseWithSeo.cleanc                    sz   | j r2z#| jjj| j d}|jr%|j| jkr%tj|jjr%t|jj W n | jj	y1   Y nw t
 j|i | d S )Npk)rS   r)   objectsgetrI   ospathisfileremoveDoesNotExistr$   r1   r'   r.   r/   old_instancer(   r   r   r1   o   s   zBaseWithSeo.savec                    :   | j rtj| j jrt| j j t j|i | dS r+   )rI   rV   rW   rX   rY   r$   r,   r-   r(   r   r   r,   z      zBaseWithSeo.delete)r   r   r   r   
ImageFieldrF   rI   	CharFieldrM   rP   rQ   r   r%   r1   r,   rG   r   r   r(   r   rH   `   s    rH   c                       sb   e Zd ZdZejdddeddZejdddeddZ	G d	d
 d
Z
dd Z fddZ  ZS )SluggedBaseModelz
    Abstract base model that extends BaseModel and adds slug functionality
    for models that need a URL-friendly version of their title.
    rL   FtitlerN   T!URL-friendly version of the titlerO   r   r   r   c                   @   r   )zSluggedBaseModel.MetaTNr   r   r   r   r   r      r    r   c                 C   s   | j s<t| j}|| _ d}| j}|jj| j dj| jd r>| d| | _ |d7 }|jj| j dj| jd sdS dS dS )z
        Generate a slug from the title if slug is empty.
        If the slug already exists, append a counter to make it unique.
        r   slugrR   -N)	rf   r   rb   r)   rT   filterexcluderS   exists)r'   	base_slugcountermodel_classr   r   r   generate_slug   s   
"	zSluggedBaseModel.generate_slugc                    s   |    t j|i | dS )zE
        Override save method to generate slug before saving
        N)rn   r$   r1   r-   r(   r   r   r1      s   zSluggedBaseModel.save)r   r   r   r=   r   r`   rF   rb   	SlugFieldrf   r   rn   r1   rG   r   r   r(   r   ra      s    ra   c                       s   e Zd ZdZG dd dejZejejej	dZ
ejdddeddZejdd	ded
dZejdddeddZejdddeddZejdddeddZejdddeddZdd Z fddZ fddZ  ZS )AuthorzB
    Model representing blog authors with verification status
    c                   @   s0   e Zd ZdedfZdedfZdedfZdS )zAuthor.AuthorStatusr   User Submitted   
Unverified   VerifiedN)r   r   r   rF   USER_SUBMITTED
UNVERIFIEDVERIFIEDr   r   r   r   AuthorStatus   s    ry   choicesr   rL   FnamerN   zauthor_images/image)rJ   rK   r   r   description
affilationTphonerJ   r   r   r   emailc                 C      | j S r<   r|   r&   r   r   r   __str__      zAuthor.__str__c                    t   z#| j jj| jd}|jr"|j| jkr"tj|jjr"t|jj W n | j j	y.   Y nw t
 j|i | dS z8Override save to handle old image deletion when updatingrR   Nr)   rT   rU   rS   r}   rV   rW   rX   rY   rZ   r$   r1   r[   r(   r   r   r1      s   zAuthor.savec                    r]   r+   r}   rV   rW   rX   rY   r$   r,   r-   r(   r   r   r,      r^   zAuthor.delete)r   r   r   r=   r   IntegerChoicesry   rE   r{   rw   statusr`   rF   r|   r_   r}   r~   r   r   
EmailFieldr   r   r1   r,   rG   r   r   r(   r   rp      s    rp   c                   @      e Zd ZdZdd ZdS )BlogCategoryzF
    Model representing blog categories with auto-generated slugs
    c                 C   r   r<   rb   r&   r   r   r   r      r   zBlogCategory.__str__Nr   r   r   r=   r   r   r   r   r   r      s    r   c                   @   r   )Topicsz`
    Model representing individual topics within topic categories with auto-generated slugs
    c                 C   r   r<   r   r&   r   r   r   r      r   zTopics.__str__Nr   r   r   r   r   r      s    r   c                       s   e Zd ZdZG dd dejZejejej	dZ
ejddddZe Zejdejd	d	d
dZejdd
dZejdejd	d	d
dZejddZejdd	deddZejd	d	dZejddd	dZdd Z fddZdd Z fddZ   Z!S )BlogzP
    Main blog post model with content, categorization, and status tracking
    c                   @   <   e Zd ZdedfZdedfZdedfZdedfZd	S )
zBlog.Statusr   zPublish Nowrr   z
Save Draftrt   rq      ArchivedN)r   r   r   rF   	PUBLISHEDDRAFTrv   ARCHIVEDr   r   r   r   Status   
    r   rz   rL   FrO   rJ   r   r   Tblogs)	on_deleterJ   r   related_namerp   )r   r   r   rc   rd   rJ   r   related_topics)r   r   c                 C   r   r<   r   r&   r   r   r   r     r   zBlog.__str__c                    s@   | j rtjjddj| jd }|dkrtdt 	  dS )z Validate blog data before savingT)feature_thisrR   r   z*Only four blogs can be featured at a time.N)
r   r   rT   rh   ri   rS   countr   r$   r%   r'   featured_countr(   r   r   r%     s
   z
Blog.cleanc                 C   sl   t | j}t|}|}d}tjj|dj| jd r4| d| }|d7 }tjj|dj| jd s|S )z2Generate a unique slug from the (translated) titler   re   rR   rg   )	r   rb   r   r   rT   rh   ri   rS   rj   )r'   title_for_slugrk   rf   rl   r   r   r   rn     s   
zBlog.generate_slugc                    s^   | j rtjj| j djddd }|r|| jkr|  | _n|  | _t	 j
|i | dS )z/Override save to update slug when title changesrR   rb   T)flatN)rS   r   rT   rh   values_listfirstrb   rn   rf   r$   r1   )r'   r.   r/   	old_titler(   r   r   r1     s   

z	Blog.save)"r   r   r   r=   r   r   r   rE   r{   r   r   r`   rb   r   content
ForeignKeySET_NULLcategoryManyToManyFieldauthorstopicBooleanFieldr   ro   rF   rf   rB   published_timer   r   r%   rn   r1   rG   r   r   r(   r   r      s"    r   c                   @   s2   e Zd ZdZejddZejdddZdd Z	d	S )
Pollz)
    Model for polls with a question
    rL   rO   TFr   c                 C   r   r<   )questionr&   r   r   r   r   .  r   zPoll.__str__N)
r   r   r   r=   r   r`   r   rB   rC   r   r   r   r   r   r   '  s
    r   c                   @   sN   e Zd ZdZejedejdZej	ddZ
ejddZedd	 Zd
d ZdS )Optionz3
    Model for poll options with vote tracking
    options)r   r   rL   r   r   r   c                 C   s6   | j jtdd pd}|dkr| j| d S dS )z1Calculate the percentage of votes for this optionvotes
votes__sumr   d   )pollr   	aggregater   Sumr   )r'   total_votesr   r   r   
percentage:  s   zOption.percentagec                 C   r   r<   )option_textr&   r   r   r   r   @  r   zOption.__str__N)r   r   r   r=   r   r   r   CASCADEr   r`   r   rE   r   propertyr   r   r   r   r   r   r   2  s    
r   c                   @   sJ   e Zd ZdZejeejdZe	 Z
ejddZG dd dZdd Zd	S )
Votez2
    Model to track individual votes on polls
    )r   Tr   c                   @   r   )z	Vote.Meta)r   
ip_addressN)r   r   r   unique_togetherr   r   r   r   r   L  r    r   c                 C   s   | j  d| jj S )Nz
 voted on )r   r   r   r&   r   r   r   r   O     zVote.__str__N)r   r   r   r=   r   r   r   r   r   GenericIPAddressFieldr   rB   voted_atr   r   r   r   r   r   r   D  s    r   c                   @   s<   e Zd ZdZejddZejddZej	ddZ
dd Zd	S )

Subscriberz*
    Model for newsletter subscribers
    r   r   Tr   r   c                 C      | j  d| j dS N ())r|   r   r&   r   r   r   r   [  r   zSubscriber.__str__N)r   r   r   r=   r   r`   r|   r   r   r   	is_activer   r   r   r   r   r   S  s    r   c                       s   e Zd ZdZejddZejddZejddZ	ej
dddZej
dddZej
dddZejddddZd	d
 Z fddZ fddZ  ZS )
TeamMemberz8
    Model for team members with social media links
    r   r   zteam_images/)rK   Tr   rJ   )r   rJ   r   c                 C   r   r<   r   r&   r   r   r   r   k  r   zTeamMember.__str__c                    r   r   r   r[   r(   r   r   r1   n  s   zTeamMember.savec                    r]   r+   r   r-   r(   r   r   r,   {  r^   zTeamMember.delete)r   r   r   r=   r   r`   r|   roler_   r}   URLFieldfacebook_link
insta_linktwitter_linkr   r   r   r1   r,   rG   r   r   r(   r   r   _  s    r   c                   @   sp   e Zd ZdZejdddeddZejdddeddZ	ejdddeddZ
ejd	dded
dZdd ZdS )Contactz,
    Model for contact form submissions
    rL   Fr|   rN   mailr   r     messagec                 C   r   r<   r   r&   r   r   r   r     r   zContact.__str__N)r   r   r   r=   r   r`   rF   r|   r   r   r   r   r   r   r   r   r   r     s    r   c                   @   s\   e Zd ZdZejeejddZe	 Z
ejdddZejdddZG dd	 d	Zd
d ZdS )BlogViewz/
    Track individual page views for blogs
    viewsr   r   rL   T)rO   r   r   c                   @   s,   e Zd ZejddgdejddgdgZdS )zBlogView.MetablogrC   )fieldsr   
session_idN)r   r   r   r   Indexindexesr   r   r   r   r     s    r   c                 C      | j j d| j S N - )r   rb   r   r&   r   r   r   r     r   zBlogView.__str__N)r   r   r   r=   r   r   r   r   r   r   r   r`   
user_agentr   r   r   r   r   r   r   r     s    r   c                   @   sp   e Zd ZdZejeejddZe	 Z
ejddZejddZejddZejddZG dd dZd	d
 ZdS )BlogAnalyticsz.
    Aggregated daily analytics for blogs
    	analyticsr   r   r           c                   @      e Zd ZdZdgZdS )zBlogAnalytics.Meta)r   date-dateNr   r   r   r   orderingr   r   r   r   r         
r   c                 C   r   r   )r   rb   r   r&   r   r   r   r     s   zBlogAnalytics.__str__N)r   r   r   r=   r   r   r   r   r   	DateFieldr   rE   r   unique_visitorsavg_reading_time
FloatFieldengagement_scorer   r   r   r   r   r   r     s    r   c                   @   sd   e Zd ZdZejeejddZe	 Z
ejddZejddZejddZG dd dZd	d
 ZdS )AuthorAnalyticsz*
    Aggregated analytics for authors
    r   r   r   r   r   c                   @   r   )zAuthorAnalytics.Meta)authorr   r   Nr   r   r   r   r   r     r   r   c                 C   r   r   )r   r|   r   r&   r   r   r   r     r   zAuthorAnalytics.__str__N)r   r   r   r=   r   r   rp   r   r   r   r   rE   total_viewstotal_blogsr   engagement_rater   r   r   r   r   r   r     s    r   c                   @   sl   e Zd ZdZe ZejdddddZej	ddZ
ejdddd	Zejd
ddd	ZG dd dZdd ZdS )PageViewz&
    Tracks individual page views
    r   T )rO   r   rJ   r   r   r   -   )rO   r   rJ   (   c                   @   s   e Zd ZdgZg dZdS )zPageView.Metar   )r   	page_namer   session_keyN)r   r   r   r   r   r   r   r   r   r     s    r   c                 C   s   | j  d| j d| j dS )Nr   z views)r  r   r   r&   r   r   r   r        zPageView.__str__N)r   r   r   r=   r   r   r   r`   r  rE   r   r   r  r   r   r   r   r   r   r     s    r   c                   @   sJ   e Zd ZdZejddZejddZejddZ	G dd dZ
dd	 Zd
S )SiteAnalyticsz2
    Overall site analytics (aggregated data)
    Tr   r   r   c                   @   s   e Zd ZdgZdS )zSiteAnalytics.Metar   Nr   r   r   r   r   r   r   r   r     s    
r   c                 C   s   d| j  S )NzSite Analytics - )r   r&   r   r   r   r     s   zSiteAnalytics.__str__N)r   r   r   r=   r   r   r   rE   r   r   r   r   r   r   r   r   r    s    r  c                   @   s   e Zd ZdZg dZg dZejddZej	ddZ
e Zejded	d
Zejdedd
ZejeejdeddZejdddZej	ddddZG dd dZdd Zedd Zedd ZdS )Taskz#
    Tasks for admin dashboard
    ))highHigh)mediumMedium)lowLow)pendingPendingin_progresszIn Progress	completed	Completed)	cancelled	CancelledrL   r   T)r      r	  rO   r{   r   r  zAssigned To User ID)r   rJ   r   r   i  r   c                   @   s   e Zd ZddgZdS )z	Task.Metadue_datez	-priorityNr  r   r   r   r   r   	  s    r   c                 C   s   | j  d|   S r   )rb   get_status_displayr&   r   r   r   r     r   zTask.__str__c                 C   s   | j t  k o| jdkS )z0Check if task is past due date and not completedr  )r  r   r   r   r&   r   r   r   
is_overdue  s   zTask.is_overduec                 C   s   dddd}| | jdS )z'Return CSS classes for priority stylingzbg-red-50 text-red-700zbg-yellow-50 text-yellow-700zbg-green-50 text-green-700)r  r	  r  zbg-gray-50 text-gray-700)rU   priority)r'   classesr   r   r   priority_class  s
   zTask.priority_classN)r   r   r   r=   PRIORITY_CHOICESSTATUS_CHOICESr   r`   rb   	TextFieldr~   r   r  r  r   r   Userr   rF   assigned_torB   completed_atresponse_from_teamr   r   r   r  r  r   r   r   r   r    s$    
r  c                   @   s   e Zd Zg dZejddZe Zej	ddZ
ej	ddZej	ddZej	ddZejdddZejded	d
ZejeejddZejddZejdddZejddZG dd dZdd Zdd Zdd Zdd Zdd Zdd Zd"ddZ d d! Z!dS )#NewsletterTask)r  r  r  )failedFailed   r   r   r   Tr   r  r  r  )r   rJ   r   r   Fc                   @   s   e Zd ZdgZdZdZdS )zNewsletterTask.Metaz-created_atzNewsletter TaskzNewsletter TasksN)r   r   r   r   verbose_nameverbose_name_pluralr   r   r   r   r   5  s    r   c                 C   s   d| j  d|   dS )NzNewsletter: r   r   )subjectr  r&   r   r   r   r   :  s   zNewsletterTask.__str__c                 C   s"   | j dkrdS t| j| j  d S )Nr   r   )total_subscribersr8   sent_subscribersr&   r   r   r   get_progress_percentage=  s   
z&NewsletterTask.get_progress_percentagec                 C   s6   | j sg S zt| j W S  tjy   | j g Y S w r<   )errorsjsonloadsJSONDecodeErrorr&   r   r   r   get_errors_listB  s   zNewsletterTask.get_errors_listc                 C   s2   |   }|| t|dd  | _|   d S )Ni)r4  appendr1  dumpsr0  r1   )r'   error_messager0  r   r   r   	add_errorJ  s   
zNewsletterTask.add_errorc                 C   "   d| _ d| _t | _|   d S )Nr  Tr   is_completedr   r   r$  r1   r&   r   r   r   mark_completedP     
zNewsletterTask.mark_completedc                 C   r9  )Nr'  Tr:  r&   r   r   r   mark_failedV  r=  zNewsletterTask.mark_failedNc                 C   sP   |d ur|| _ |d ur|| _| j | j | _| jdkr"| jdkr"d| _|   d S )Nr   r  r  )successful_sendsfailed_sendsr.  r   r1   )r'   successful_countfailed_countr   r   r   update_progress\  s   zNewsletterTask.update_progressc                 C   sR   | j | j| j| j| j|  |  | jd| j	r| j	dnd | 
 d d d
S )Nz%Y-%m-%d %H:%Mr  )
r,  totalsent
successfulr'  progressr   rC   r$  r0  )r,  r-  r.  r?  r@  r/  r  rC   strftimer$  r4  r&   r   r   r   get_summaryi  s   
zNewsletterTask.get_summary)NN)"r   r   r   r   r   r`   r,  r!  r   PositiveIntegerFieldr-  r.  r?  r@  r0  r   r   r"  r   
created_byrB   rC   r$  r   r;  r   r   r/  r4  r8  r<  r>  rC  rI  r   r   r   r   r&    s.    
r&  c                       s   e Zd ZdZG dd dejZejdeddZ	ejdded	d
Z
ejddeddZejddeddZejdddeddZejejejdZejedddZejdddeddZdd Z fddZdd Z fddZ fd d!Z  ZS )"Issuea  
    Issue model to organize multiple blogs together as a collection
    
    Fields:
        name: Name of the issue
        issue_number: Unique number for the issue
        description: Optional description of the issue
        publication_date: Date when the issue was/will be published
        cover_image: Cover image for the issue
        is_published: Flag to indicate if the issue is published
        blogs: Many-to-many relationship with Blog model via IssueItem
        slug: URL-friendly version of the name
    c                   @   r   )
zIssue.Statusr   	Publishedrr   Draftrt   	Scheduledr   r   N)r   r   r   rF   r   r   	SCHEDULEDr   r   r   r   r   r     r   r   rL   zName of the issue)rO   r   2   Tz5Unique number for the issue (e.g., "Vol. 1, Issue 2"))rO   r   r   z!Optional description of the issuer   rJ   r   z)Date when the issue was/will be publishedzissues/covers/zCover image for the issue)rK   r   rJ   r   rz   	IssueItemissues)throughr   Fz URL-friendly version of the namerd   c                 C   r   r   )r|   issue_numberr&   r   r   r   r     r   zIssue.__str__c                    r!   )z!Validate issue data before savingNr#   r&   r(   r   r   r%     r*   zIssue.cleanc                 C   sp   t | j d| j }|}d}tjj|dj| jd r6| d| }|d7 }tjj|dj| jd s|S )z5Generate a unique slug from the name and issue numberrg   r   re   rR   )	r   r|   rV  rL  rT   rh   ri   rS   rj   )r'   rk   rf   rl   r   r   r   rn     s   zIssue.generate_slugc                    sr   | j r| jr)d}| jrtjj| jd }|r#|j| jks#|j| jkr(|  | _ n|  | _ t	 j
|i | dS )z>Override save to update slug when name or issue_number changesNrR   )rf   rS   rL  rT   rh   r   r|   rV  rn   r$   r1   )r'   r.   r/   	old_issuer(   r   r   r1     s   

z
Issue.savec                    r]   r+   )cover_imagerV   rW   rX   rY   r$   r,   r-   r(   r   r   r,     r^   zIssue.delete) r   r   r   r=   r   r   r   r`   rF   r|   rV  r!  r~   r   publication_dater_   rX  rE   r{   r   r   r   r   r   ro   rf   r   r%   rn   r1   r,   rG   r   r   r(   r   rL  x  s     rL  c                       s   e Zd ZdZejeejddZeje	ejddZ
ejdeddZejdeddZejd	d	ed
dZG dd dZdd Z fddZ fddZ  ZS )rS  ax  
    Through model for the many-to-many relationship between Issue and Blog
    
    Fields:
        issue: ForeignKey to Issue model
        blog: ForeignKey to Blog model
        order: Integer to determine the order of blogs in the issue
        featured: Flag to indicate if the blog is featured in the issue
        notes: Optional notes about the blog in this issue
    issue_itemsr   r   zOrder of the blog in the issue)r   r   Fz6Flag to indicate if the blog is featured in this issueTz+Optional notes about the blog in this issuerR  c                   @   s*   e Zd ZdgZddgZedZedZdS )zIssueItem.Metaorderissuer   z
Issue ItemzIssue ItemsN)r   r   r   r   r   rF   r*  r+  r   r   r   r   r     s
    r   c                 C   s   | j  d| j d| j dS )Nr   z	 (Order: r   )r\  r   r[  r&   r   r   r   r     r  zIssueItem.__str__c                    s   | j rd|dg v r7t   tjj| j| jdj	| j r | j nd dj
d d W d    n1 s2w   Y  t j|i | d S )Nr[  update_fields)r\  r[  rR   )r[  )rS   rU   r	   atomicrS  rT   rh   r\  r[  ri   updater$   r1   r-   r(   r   r   r1     s   
zIssueItem.savec                    sD   | j rtjj| jddj| jd }|dkrtdt	 
  dS )z&Validate issue item data before savingT)r\  featuredrR      z6Only five blogs can be featured in an issue at a time.N)r`  rS  rT   rh   r\  ri   rS   r   r   r$   r%   r   r(   r   r   r%     s   zIssueItem.clean)r   r   r   r=   r   r   rL  r   r\  r   r   rJ  rF   r[  r   r`  r!  notesr   r   r1   r%   rG   r   r   r(   r   rS    s    
rS  )1	django.dbr   django.urlsr   django.utils.translationr   rF   django.core.exceptionsr   ckeditor.fieldsr   r?   django.utils.textr   django.utils.timezoner   rV   r	   django.contrib.authr
   django.utilsr   r1  utilsr   Modelr   rH   ra   rp   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r"  r  r&  rL  rS  r   r   r   r   <module>   sL    L"%+	D$0YH