o
    &äfg×c  ã                   @   s¤   d dl Z d dlZd dl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mZ G dd„ dejƒZG d	d
„ d
ejƒZG dd„ dejƒZG dd„ dƒZdS )é    N)Úurlparse)Úmodels)Úslugify)Úreverse)ÚContentFilec                       s‚   e Zd ZejddZejdddZe ¡ Z	ej
ddZe ¡ Zdd„ Z‡ fdd	„Zd
d„ Zdd„ Zdd„ Zdd„ Zdd„ Z‡  ZS )ÚPostéÿ   ©Ú
max_lengthT)ÚuniqueÚblank©Údefaultc                 C   s   t d| jgdS )NZpost_detail)Úargs)r   Úslug©Úself© r   ú6/Users/rosstaylor/Documents/rossjtaylor/blog/models.pyÚget_absolute_url   s   zPost.get_absolute_urlc                    s`   | j s	t| jƒ| _ | j ¡ | _tƒ j|i |¤Ž | j ¡  	¡  | j
 ¡  	¡  |  ¡  |  ¡  d S ©N)r   r   ÚtitleÚbodyÚstripÚsuperÚsaveÚsectionsÚallÚdeleteZpostreference_setÚparse_referencesÚparse_body_into_sections)r   r   Úkwargs©Ú	__class__r   r   r      s   z	Post.savec                 C   s˜   t  d¡}| | j¡D ]>}| d¡ ¡ }| d¡ ¡ }| d¡r'| d¡ ¡ nd }|s5t|ƒ}d|j› }tj	j
| |d ¡ sItj	j| |||d qd S )Nz$\[([^]]+)\]\((\S+)(?:\s"([^"]+)")?\)é   é   é   zReference from )ÚpostÚurl)r'   r(   Úinline_textÚreference_title)ÚreÚcompileÚfinditerr   Úgroupr   r   ÚnetlocÚPostReferenceÚobjectsÚfilterÚexistsÚcreate)r   ÚpatternÚmatchr)   r(   Z	ref_titleÚparsedr   r   r   r   %   s"   
ü€ózPost.parse_referencesc           4   	   C   s¦  | j }d}t ||tj¡}g }g }d}|D ];}| ¡ | ¡ }}	||kr/| d|||… f¡ | d¡}
| d¡ ¡ }| d|
|f¡ | dt	|ƒd f¡ |	}q|t	|ƒk rb| d||d … f¡ d}g }|D ]·}|d dkr|d }d}t ||tj¡D ]€}| ¡ | ¡ }}	||kr™| d|||… f¡ | d¡ ¡ }| 
d	¡}|rø|d  ¡ }d
|v rë|dd … }d|v rÙ| d¡}d	 |d |… ¡ ¡ }d	 ||d d … ¡ ¡ }n	d	 |¡ ¡ }d}| d||f¡ n| dd	 |¡ ¡ f¡ n| d¡ |	}q|t	|ƒk r| d||d … f¡ qh|d dkr| |¡ qhd}g }|D ]¡}|d }|dkrí|d  ¡ }|s=q&| 
d	¡}g }|D ]}| ¡ }|sV| d¡ qFt ||¡} | rÍ|rxd	 |¡ ¡ }!|!rv|  |!¡}"| |"¡ g }|  d¡}#d }$d }%d|#v s‹d|#v rÁ|# d¡ 
¡ }&|&d }'|&dd … D ]}(|( d¡r­t|( 
d¡d ƒ}$qœd|v r¿| 
d¡d d d… }%|'}#| dd|#|$|%f¡ qF| |¡ qF|rëd	 |¡ ¡ }!|!rë|  |!¡}"| |"¡ q&|dkrÿ|d })| d|)f¡ q&|dkr|d }|d }| d||f¡ q&|dkrÇ|d }*||* \}+},}| 
d	¡}dd„ |D ƒ}|r9|d nd}-|-rDt ||-¡nd } d }#d }$d }%| rž|  d¡}#d|#v s^d|#v r”|# d¡ 
¡ }&|&d }'|&dd … D ]}(|( d¡r€t|( 
d¡d ƒ}$qod|v r’| 
d¡d d d… }%|'}#d	 |dd … ¡}.nd	 |¡}.|. ¡ rº|  |. ¡ ¡}"d	 dd„ |"D ƒ¡}/nd}/| d|,|/|#|$|%f¡ q&d}0|D ]}|d }|dkr	t	|ƒdkrö|d dkrö|d }1| jjd|0|1d d n|d }2| jjd|0|2d |0d7 }0qÍ|dkr%|d })| jjd|0d|)› dd |0d7 }0qÍ|dkrB|d }|d }| jjd|0||d }3|0d7 }0qÍ|dkry|d }#|d }$|d! }%| jjd|0dd}3|$rb|$|3_|#|3_ |%rk|%|3_|3jg d"¢d# |0d7 }0qÍ|dkrÏ|d },|d }/|d }#|d! }$t	|ƒd$kr™|d$ nd }%| jjd|0|,d%kr§d%nd&|#r³d'|#› d	|/› n|/d(}3|$r½|$|3_|%rÃ|%|3_|3jg d"¢d# |0d7 }0qÍd S ))Nz":::image_text_(left|right)(.*?):::r   Útextr$   r%   Ú
image_textZimage_text_placeholderz```(.*?)```Ú
Úexecutedz---Ú Úexecuted_codeÚcode)r>   r<   z!\[(.*?)\]\((.*?)\)zwidth=zdesc=ú"ú=éÿÿÿÿÚimagec                 S   s   g | ]
}|  ¡ r|  ¡ ‘qS r   )r   )Ú.0Úlr   r   r   Ú
<listcomp>¿   s    z1Post.parse_body_into_sections.<locals>.<listcomp>c                 S   s,   g | ]}|d  dkrt |ƒdk r|d ‘qS )r   r8   r&   r$   )Úlen)rC   Úsecr   r   r   rE   Ù   s   , r&   Úheading)Úsection_typeÚorderrH   r   )rI   rJ   r   z<pre><code>z</code></pre>)rI   rJ   r   Úcode_outputé   )r   Úimage_widthÚimage_description)Úupdate_fieldsé   ÚleftÚrightúIMAGE:)rI   rJ   Úimage_positionr   )r   r+   r-   ÚDOTALLÚstartÚendÚappendr.   r   rF   ÚsplitÚindexÚjoinr6   Úsplit_text_into_subsectionsÚextendÚ
startswithÚintr   r4   rM   rN   r   )4r   ÚcontentZimage_text_patternZimage_text_blocksZtmp_contentÚplaceholdersZlast_endr6   rV   rW   Z
block_sideZ
block_textZcode_fence_patternZfinal_sectionsÚitemÚsegmentÚposZ
code_matchZcode_block_contentÚ
code_linesÚ
first_lineZ	sep_indexÚ	code_partÚoutput_partZimage_patternZ	new_finalÚsectionÚstypeÚsegÚlinesZtext_lines_accÚlineZ	img_matchZbig_text_blockZsub_secsÚ	image_urlÚwidthZ
image_descÚpartsZmain_urlÚpZcode_contentrZ   Zit_typeÚsideZ
image_lineZ	text_partZcombined_bodyrJ   Úheading_textr   Úsr   r   r   r    A   s–  



€
€






€


€




€


€

üý

ý
ü
ý
ü€²zPost.parse_body_into_sectionsc                 C   ó˜   |  d¡}g }d}|D ]4}| ¡  d¡r1| ¡ dd …  ¡ }|s'| d¡ d}| d|› d¡ q|r:| d	¡ d}| |¡ q|rG| d	¡ d |¡S ©
Nr:   Fz- r%   zV<ul class="list-disc text-gray-700 leading-relaxed list-inside text-xl p-2 pb-4 pt-4">Tz<li>z</li>z</ul>©rY   r   r^   rX   r[   ©r   r8   rl   Zfinal_linesZin_listrm   r`   r   r   r   Úhandle_bullets3  s"   




zPost.handle_bulletsc                 C   ó,   t jdd|t jd}t jdd|t jd}|S ©Nz\*\*(.*?)\*\*z<strong>\1</strong>)Úflagsz	\*(.*?)\*z<em>\1</em>©r+   ÚsubrU   ©r   r8   r   r   r   Úhandle_inline_formattingG  ó   zPost.handle_inline_formattingc                 C   sê   |   |¡}|  |¡}t d| ¡ ¡}g }t d¡}|D ]W}| d¡}g }|D ]7}| ¡ }|s/q&| |¡}	|	rX|rJd |¡ ¡ }
|
rH| d|
f¡ g }|	 	d¡}| d|df¡ q&| |¡ q&|rrd |¡ ¡ }
|
rp| d|
f¡ g }q|S )aQ  
        Splits a large text block into subsections:
        - Handles bullets and inline formatting
        - Separates by blank lines into paragraphs
        - Detects headings at start of lines (#, ##, etc.)
        Returns a list of tuples like:
        ('text', 'paragraph text')
        ('text', 'heading text', 'heading')
        z\n\s*\nz^(#{1,6})\s+(.*)r:   r8   r%   rH   )
ry   r€   r+   rY   r   r,   r6   r[   rX   r.   )r   Z
text_blockÚ
paragraphsZsubsectionsZheading_patternÚparaZp_linesZtemp_para_linesrm   Zheading_matchZsubsection_textrs   r   r   r   r\   N  s:   





€z Post.split_text_into_subsections)Ú__name__Ú
__module__Ú__qualname__r   Ú	CharFieldr   Ú	SlugFieldr   Ú	DateFieldÚdateÚBooleanFieldZ	is_publicÚ	TextFieldr   r   r   r   r    ry   r€   r\   Ú__classcell__r   r   r"   r   r      s     sr   c                       sì   e Zd Zg d¢ZejeejddZej	dedZ
ejddZej	dd	d	d
Zejd	d	dZejdd	d	dZej	dddgd	d	dZejd	d	dZejd	d	dZejd	d	dZG dd„ dƒZdd„ Z‡ fdd„Zdd„ Zdd„ Zdd„ Z‡  ZS )ÚPostSection))r8   ÚText)r>   ZCode)rB   ÚImage)r9   zImage + Textr   )Ú	on_deleteÚrelated_nameé   )r
   Úchoicesr$   r   r   T)r
   r   Únull)r   r•   zpost_images/)Ú	upload_tor   r•   rP   )rQ   ÚLeft)rR   ÚRight)r
   r”   r   r•   c                   @   s   e Zd ZdgZdS )zPostSection.MetarJ   N)r„   r…   r†   Úorderingr   r   r   r   ÚMeta“  s    
rš   c                 C   s   | j j› d| j› d| j› S )Nz - z
 section #)r'   r   rI   rJ   r   r   r   r   Ú__str__–  s   zPostSection.__str__c                    sT   |  dd¡}tƒ j|i |¤Ž | jdv r"|s$| js&| jr(|  ¡  d S d S d S d S d S )NÚdownloading_imageF)rB   r9   )Úpopr   r   rI   rB   r   Údownload_and_replace_images)r   r   r!   Zis_downloadingr"   r   r   r   ™  s
   ÿzPostSection.savec           
      C   sò   | j sd S | j  ¡ }d|v r*| d¡d  d¡d }d}d | j  d¡dd … ¡}nd}d}t d¡}| | jj ¡D ]#}| d¡}| d	¡}| d
¡}| ¡ | ¡ kr]|r[|  	|¡| _
 nq:|sbd S |  |¡}	|	rw|| _|| _ | jdd d S d S )NrS   r$   r:   r   r9   rB   r<   z$!\[(.*?)\]\((\S+)(?:\s+"([^"]+)")?\)r%   r&   T)rœ   )r   r   rY   r[   r+   r,   r-   r'   r.   Úextract_width_from_titlerM   Údownload_imagerI   r   )
r   rn   rI   r   r5   r6   Zalt_textr(   r   Zlocal_file_namer   r   r   rž   ¥  s6   




ü
úz'PostSection.download_and_replace_imagesc                 C   s*   t  d¡}| |¡}|rt| d¡ƒS d S )Nzwidth=(\d+)r$   )r+   r,   Úsearchr_   r.   )r   Z	title_strZwidth_patternZwmatchr   r   r   rŸ   Ø  s
   

z$PostSection.extract_width_from_titlec                 C   st   zt j|dd}| ¡  W n t jy   Y d S w t|ƒ}tj |j¡}|s(d}t|j	ƒ}| j
j||dd | j
jS )Né
   )Útimeoutz	image.jpgF)r   )ÚrequestsÚgetZraise_for_statusZRequestExceptionr   ÚosÚpathÚbasenamer   r`   rB   r   Úname)r   r(   ÚresponseÚ
parsed_urlÚfilenameZimage_contentr   r   r   r    á  s   ÿ
zPostSection.download_image)r„   r…   r†   ZSECTION_TYPESr   Ú
ForeignKeyr   ÚCASCADEr'   r‡   rI   ÚPositiveIntegerFieldrJ   rH   rŒ   r   Ú
ImageFieldrB   rT   ÚIntegerFieldrM   rK   rN   rš   r›   r   rž   rŸ   r    r   r   r   r"   r   rŽ   |  s,    ý3	rŽ   c                   @   sD   e Zd ZejeejdZe ¡ Z	ej
ddZej
ddZdd„ ZdS )r0   )r‘   r   r	   iô  c                 C   s   | j › d| j› dS )Nz (ú))r*   r(   r   r   r   r   r›   ü  s   zPostReference.__str__N)r„   r…   r†   r   r­   r   r®   r'   ÚURLFieldr(   r‡   r)   r*   r›   r   r   r   r   r0   ö  s    r0   c                   @   s<   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd	d
„ Zdd„ ZdS )ÚPostBodyParserc                 C   s
   || _ d S r   )r8   r   r   r   r   Ú__init__  s   
zPostBodyParser.__init__c                 C   s$   g }| j  d¡}| |  |¡¡ |S )Nr:   )r8   rY   r]   Úparse_blocks)r   r   rl   r   r   r   Úparse  s   zPostBodyParser.parsec                 C   sÆ  g }d}g }|t |ƒk rÔ|| }| ¡  d¡rÅ| ¡  d¡ ¡ }| ¡ }|r*|d nd}d|v }	g }
|d7 }|t |ƒk r_||  ¡  d¡s_|
 || ¡ |d7 }|t |ƒk r_||  ¡  d¡rE|d7 }|	r¦d|
v r}|
 d¡}|
d|… }|
|d d… }n|
}g }d |¡}d |¡}|rœ|  d |¡¡}| |¡ g }| d	||d
œ¡ n(d |
¡}|r¼|  d |¡¡}| |¡ g }| d|dœ¡ n	| |¡ |d7 }|t |ƒk s|rá| |  d |¡¡¡ |S )ay  
        Parse the entire body into logical sections.
        We'll have:
        - Executed code blocks: ```python executed ...``` until ```
          with `---` line to separate code and output
        - Regular code blocks: ```python``` until ```
        - Bullet lists: lines starting with '- '
        - Bold/Italics inline: transform after building text sections
        r   z```r<   r;   r$   z---Nr:   r=   )Útyper   rK   r>   ©r¸   r   )	rF   r   r^   ÚlstriprY   rX   rZ   r[   Úcreate_text_section)r   rl   r   ÚiZcurrent_textrm   Z	lang_linerp   Úlangr;   re   Úidxrg   rh   Zcode_strZ
output_strZtext_sectionr   r   r   r¶     sd   
þ




ý


þ
Ã@zPostBodyParser.parse_blocksc                 C   s   |   |¡}|  |¡}d|dœS )Nr8   r¹   )ry   r€   r   r   r   r   r»   c  s   


z"PostBodyParser.create_text_sectionc                 C   ru   rv   rw   rx   r   r   r   ry   j  s"   




zPostBodyParser.handle_bulletsc                 C   rz   r{   r}   r   r   r   r   r€   €  r   z'PostBodyParser.handle_inline_formattingN)	r„   r…   r†   rµ   r·   r¶   r»   ry   r€   r   r   r   r   r´      s    Rr´   )r¦   Úuuidr+   r¤   Úurllib.parser   Ú	django.dbr   Údjango.utils.textr   Údjango.urlsr   Údjango.core.files.baser   ÚModelr   rŽ   r0   r´   r   r   r   r   Ú<module>   s     pz
