Ë
    ŠDj>8  ã                   óÔ   — d Z ddlZddlmZ ddlmZ ddl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mZ ddlmZ ddlmZ  ej4                  e«      Z G d„ d«      Zy)zGWeekly blog automation: plan, background generation, scheduled publish.é    N)Údate)Útimezone)ÚBlogArticleÚBlogSettings)Ú#enqueue_process_and_publish_article)Úrefresh_external_blog_inventory)Úgenerate_article_content)Úgenerate_weekly_topics)ÚBlogImageService)Úrandom_publish_datesÚweek_bounds)ÚShopifyBlogService)Úrefresh_trending_topicsc                   óÂ   — e Zd Zedd„«       Zedd„«       Zed„ «       Zedede	fd„«       Z
edd„«       Zedd	„«       Zed
„ «       Zed„ «       Zedd„«       Zedd„«       Zy)ÚBlogAutomationServiceNc                 óš   — t        | «      \  }}t        j                  j                  t        j                  ||¬«      j                  «       S )N)ÚstatusÚposted_at__date__gteÚposted_at__date__lte)r   r   ÚobjectsÚfilterÚSTATUS_PUBLISHEDÚcount©Ú	referenceÚstartÚends      úG/var/www/html/shopify_to_digistore/blogs/services/automation_service.pyÚ_published_this_week_countz0BlogAutomationService._published_this_week_count   sF   € ä  Ó+‰
ˆˆsÜ×"Ñ"×)Ñ)Ü×/Ñ/Ø!&Ø!$ð *ó 
÷ ‰%‹'ð		ó    c                 ó¸   — t        | «      \  }}t        j                  j                  ||¬«      j	                  t        j
                  ¬«      j                  «       S )N)Úscheduled_date__gteÚscheduled_date__lte)r   )r   r   r   r   ÚexcludeÚSTATUS_FAILEDr   r   s      r   Ú_scheduled_this_week_countz0BlogAutomationService._scheduled_this_week_count   sO   € ä  Ó+‰
ˆˆsä×Ñ×&Ñ&Ø$)Ø$'ð 'ó ÷ ‰WœK×5Ñ5ˆWÓ6ß‰U‹Wð	
r    c                 ó`   — | j                   xs dj                  «        xs | j                  d u S )NÚ )ÚcontentÚstripÚ
word_count)Úarticles    r   Ú_needs_generationz'BlogAutomationService._needs_generation+   s-   € à—O‘OÒ) r×0Ñ0Ó2Ð2ÒP°g×6HÑ6HÈDÐ6PÐPr    Úsettings_objÚreturnc                 óô  — ddg dœ}|j                   xs dj                  «       r	 t        |«      }t        |«      |d<   n/d	|_        |j                  d
dg¬«       |d   j                  d«       |j                  «        t        |«       |j                  «        t        |j                  xs g «      |d<   |S # t        $ r6}t
        j                  d«       |d   j                  d|› �«       Y d}~Œƒd}~ww xY w)z=Track A + B: research live blogs and refresh trending topics.r   )Úexternal_countÚtrending_countÚwarningsr(   r1   zexternal blog research failedr3   zblog research: Nzblog_list_url not setÚexternal_blog_inventory_errorÚ
updated_at©Úupdate_fieldsz1blog_list_url not set; skipped live blog researchr2   )Úblog_list_urlr*   r   ÚlenÚ	ExceptionÚloggerÚ	exceptionÚappendr4   ÚsaveÚrefresh_from_dbr   Útrending_topics)Úclsr.   ÚprepÚinvÚexcs        r   Ú_prepare_planning_dataz,BlogAutomationService._prepare_planning_data/   s  € ð #$°qÀbÑIˆà×&Ñ&Ò,¨"×3Ñ3Ô5ðAÜ5°lÓC�Ü),¨S«�Ð%Ò&ð
 :QˆLÔ6Ø×ÑØ>ÀÐMð ô ð �Ñ×#Ñ#Ð$WÔXà×$Ñ$Ô&Ü Ô-Ø×$Ñ$Ô&Ü!$ \×%AÑ%AÒ%GÀRÓ!HˆÐÑØˆøô ò AÜ× Ñ Ð!@ÔAØ�ZÑ ×'Ñ'¨/¸#¸Ð(?×@Ñ@ûðAús   ¦B8 Â8	C7Ã,C2Ã2C7c                 ó(  — t        j                  «       }| j                  |«      }|j                  «        |xs t	        j
                  «       }|j                  «       d   }t        ||«      }|rt        |||d¬«      }	d|	|dœS t        |||¬«      }
|
S )uT   
        A â†’ B â†’ C: research live blogs, refresh trends, plan articles.
        é   T)Úcalendar_weekÚscheduled_datesÚdry_run)rJ   Úpreview_topicsrB   ©rH   rI   )	r   ÚloadrE   r?   r   ÚtodayÚisocalendarr   r
   )rA   r   r   rJ   r.   rB   rN   ÚcwÚpublish_datesÚpreviewÚarticless              r   Úplan_weekly_postsz'BlogAutomationService.plan_weekly_postsH   s§   € ô
 $×(Ñ(Ó*ˆØ×)Ñ)¨,Ó7ˆØ×$Ñ$Ô&àÒ)œTŸZ™Z›\ˆØ×ÑÓ  Ñ#ˆÜ,¨U°EÓ:ˆáÜ,ØØ Ø -Øô	ˆGð  Ø")Øñð ô *ØØØ)ô
ˆð
 ˆr    c                 ó   — t        j                  «       }|j                  xs dj                  «       st	        d«      ‚|j
                  xs dj                  «       st	        d«      ‚| j                  |«      }|j                  «        |xs t        j                  «       }|j                  «       d   }t        d||g¬«      }|st	        d«      ‚|d   }d|j                  |j                  |d	œ}		 |r3t        |j                  «      }
d|	d
<   |
|	d<   d|j                  › d�|	d<   nX| j                  |j                  «       |j                  «        |j                   |	d<   |j"                  |	d<   |j$                  |	d<   t'        j(                  «       |_        d|_        d|_        |j1                  g d¢¬«       |	S # t2        $ rJ}t'        j(                  «       |_        d|_        t5        |«      |_        |j1                  g d¢¬«       ‚ d}~ww xY w)z”
        Full pipeline: research blog URL, refresh trending topics, plan one article,
        then generate content and publish to Shopify.
        r(   ú)shopify_blog_id required in Blog settingsú%description required in Blog settingsrG   rL   zPlanning produced no articler   T)ÚokÚ
article_idÚtitlerB   Ú
backgroundÚ
worker_pidzlogs/blog_article_z.logÚlog_pathÚshopify_article_idÚshopify_article_urlr   Úsuccess©Úlast_run_atÚlast_run_statusÚlast_run_errorr6   ÚfailedN)r   rM   Úshopify_blog_idr*   Ú
ValueErrorÚdescriptionrE   r?   r   rN   rO   r
   ÚpkrZ   r   Úprocess_and_publish_articler^   r_   r   r   Únowrb   rc   rd   r>   r:   Ústr)rA   r   r[   r.   rB   rN   rP   rS   r,   ÚresultÚpidrD   s               r   Úgenerate_and_publish_articlez2BlogAutomationService.generate_and_publish_articlei   sø  € ô $×(Ñ(Ó*ˆà×,Ñ,Ò2°×9Ñ9Ô;ÜÐHÓIÐIØ×(Ñ(Ò.¨B×5Ñ5Ô7ÜÐDÓEÐEà×)Ñ)¨,Ó7ˆØ×$Ñ$Ô&àÒ)œTŸZ™Z›\ˆØ×ÑÓ  Ñ#ˆÜ)ØØØ"˜Gô
ˆñ
 ÜÐ;Ó<Ð<à˜1‘+ˆàØ!Ÿ*™*Ø—]‘]Øñ	
ˆð	ÙÜ9¸'¿*¹*ÓE�Ø'+��|Ñ$Ø'*��|Ñ$Ø'9¸'¿*¹*¸ÀTÐ%J��zÒ"à×/Ñ/°·
±
Ô;Ø×'Ñ'Ô)Ø/6×/IÑ/I�Ð+Ñ,Ø07×0KÑ0K�Ð,Ñ-Ø#*§>¡>��xÑ ä'/§|¡|£~ˆLÔ$Ø+4ˆLÔ(Ø*,ˆLÔ'Ø×ÑÚRð ô ð ˆMøÜò 	Ü'/§|¡|£~ˆLÔ$Ø+3ˆLÔ(Ü*-¨c«(ˆLÔ'Ø×ÑÚRð ô ð ûð	ús   Ã0C	F: Æ:	HÇAHÈHc                 ó„  — t        j                  «       }t        j                  j	                  |¬«      }|j
                  t        j                  k(  r|S t        |«       |j                  rt        j                  |«       |j                  «        t        j                  |_        d|_        |j                  g d¢¬«       |S )uD   Generate content + images and mark ready (blocking â€” for workers).©ri   r(   )r   Úgeneration_errorr5   r6   )r   rM   r   r   Úgetr   r   r	   Úinclude_imagesr   Úgenerate_for_articler?   ÚSTATUS_READYrr   r>   )rA   rY   r.   r,   s       r   Úprocess_articlez%BlogAutomationService.process_article¨   s–   € ô $×(Ñ(Ó*ˆÜ×%Ñ%×)Ñ)¨ZÐ)Ó8ˆØ�>‰>œ[×9Ñ9Ò9ØˆNä  Ô,Ø×&Ò&Ü×1Ñ1°*Ô=à×ÑÔ!Ü$×1Ñ1ˆŒØ#%ˆÔ Ø�‰Ò#OˆÔPØˆr    c                 óÐ   — | j                  |«      }|j                  t        j                  k(  r|S t	        j
                  |d¬«       t        j                  j                  |¬«      S )zAGenerate content/images and publish to Shopify (blocking worker).T©Ú	publishedrq   )rw   r   r   r   r   Úpublish_articler   rs   )rA   rY   r,   s      r   rj   z1BlogAutomationService.process_and_publish_articleº   sU   € ð ×%Ñ% jÓ1ˆØ�>‰>œ[×9Ñ9Ò9ØˆNÜ×*Ñ*¨:ÀÕFÜ×"Ñ"×&Ñ&¨*Ð&Ó5Ð5r    c                 ó
  — |xs t        j                  «       }t        t        j                  j                  |t        j                  t        j                  t        j                  f¬«      j                  dd«      «      }dg dg g dœ}|D �]À  }|j                  t        j                  k(  rN	 t        j                  |j                  d¬«       |dxx   d	z  cc<   |d
   j                  |j                  «       Œo|j                  t        j&                  k(  rŒ�| j)                  |«      s„|j*                  rx	 t        j                  |_
        |j-                  ddg¬«       t        j                  |j                  d¬«       |dxx   d	z  cc<   |d
   j                  |j                  «       �Œ"|rI	 | j/                  |j                  «       |dxx   d	z  cc<   |d
   j                  |j                  «       �Œmt1        |j                  «      }|d   j                  |j                  «       |j3                  dg «      j                  |«       �ŒÃ |d   dk(  |d<   |S # t        $ rb}t         j#                  d|j                  «       |dxx   d	z  cc<   |d   j                  |j                  t%        |«      dœ«       Y d}~�ŒÉd}~ww xY w# t        $ rB}|dxx   d	z  cc<   |d   j                  |j                  t%        |«      dœ«       Y d}~�Œed}~ww xY w# t        $ rb}t         j#                  d|j                  «       |dxx   d	z  cc<   |d   j                  |j                  t%        |«      dœ«       Y d}~�Œód}~ww xY w)z«
        On each article's scheduled_date: generate + publish (background by default).
        Already-ready posts are published immediately without regenerating.
        )r#   Ú
status__inÚscheduled_dateÚidr   )rz   Úenqueuedre   ÚerrorsÚarticle_idsTry   rz   rG   r‚   zpublish ready failed article=%sre   r�   ©rY   ÚerrorNr   r5   r6   z!process+publish failed article=%sr€   Úworker_pidsrX   )r   rN   Úlistr   r   r   ÚSTATUS_PLANNEDrv   r%   Úorder_byr   r   r{   r   r=   r:   r;   r<   rl   ÚSTATUS_GENERATINGr-   r)   r>   rj   r   Ú
setdefault)	rA   r   ÚsyncrN   ÚdueÚresultsr,   rD   rn   s	            r   Úpublish_due_articlesz*BlogAutomationService.publish_due_articlesÃ   s  € ð Ò)œTŸZ™Z›\ˆÜÜ×Ñ×&Ñ&Ø$)ä×.Ñ.Ü×,Ñ,Ü×-Ñ-ðð 'ó ÷ ‰hÐ'¨Ó.ó	
ˆð ØØØØñ
ˆô ˆGØ�~‰~¤×!9Ñ!9Ò9ð	Ü&×6Ñ6°w·z±zÈTÕRØ˜KÓ(¨AÑ-Ó(Ø˜MÑ*×1Ñ1°'·*±*Ô=ð à�~‰~¤×!>Ñ!>Ò>Øà×(Ñ(¨Ô1°g·o²oð
Ü%0×%=Ñ%=�G”NØ—L‘L°¸,Ð/G�LÔHÜ&×6Ñ6°w·z±zÈTÕRØ˜KÓ(¨AÑ-Ó(Ø˜MÑ*×1Ñ1°'·*±*Ô=ñ áðØ×3Ñ3°G·J±JÔ?Ø˜KÓ(¨AÑ-Ó(Ø˜MÑ*×1Ñ1°'·*±*Ö=ô :¸'¿*¹*ÓE�Ø˜
Ñ#×*Ñ*¨7¯:©:Ô6Ø×"Ñ" =°"Ó5×<Ñ<¸SÖAð_ ðb   Ñ)¨QÑ.ˆ�‰ØˆøôY !ò Ü×$Ñ$Ð%FÈÏ
É
ÔSØ˜HÓ%¨Ñ*Ó%Ø˜HÑ%×,Ñ,Ø'.§z¡z¼CÀ»HÑE÷ò ûðûô$ !ò Ø˜HÓ%¨Ñ*Ó%Ø˜HÑ%×,Ñ,Ø'.§z¡z¼CÀ»HÑE÷ò ûðûô !ò Ü×$Ñ$Ø;¸W¿Z¹Zôð ˜HÓ%¨Ñ*Ó%Ø˜HÑ%×,Ñ,Ø'.§z¡z¼CÀ»HÑE÷ò ûðúsM   Â,AIÄ5A5K	Æ/ALÉ	KÉ$AKËKË		LË7LÌLÌ	NÌ AM=Í=Nc                 ó  — t        j                  «       }|j                  s|sdddœS |j                  sdddœS |j                  xs dj                  «       sdddœS |xs |j                  }| j                  «       }| j                  «       }t        d||z
  «      }|s|nt        ||xs |«      }	|r|r|}	dg ddg dœ}
	 |	dkD  r”| j                  |	|¬	«      }|r;d
|
d<   |	|
d<   |j                  dg «      |
d<   |j                  di «      |
d<   d
|
d<   |
S |}t        |«      |
d<   |D �cg c]$  }|j                  sŒt        |j                  «      ‘Œ& c}|
d<   ng }|sI|sG|	dk(  rBt!        j"                  «       |_        d|_        d|_        |j+                  g d¢¬«       d
d
||dœS |rB|r@|d|xs t        |«       D ]+  }	 | j-                  |j.                  «       |
dxx   dz  cc<   Œ- t!        j"                  «       |_        |
d   sdnd|_        |
d   rt        |
d   dd «      nd|_        |j+                  g d¢¬«       d
|
d<   ||
d <   | j                  «       |
d!<   |
S c c}w # t0        $ rA}|
dxx   dz  cc<   |
d   j3                  |j.                  t        |«      dœ«       Y d}~Œïd}~ww xY w# t0        $ rJ}t!        j"                  «       |_        d|_        t        |«      |_        |j+                  g d¢¬«       ‚ d}~ww xY w)"z³
        Plan posts for the week: research live blogs, refresh trends, plan topics.
        Generation + publish run on each scheduled_date via publish_due_blog_articles.
        Fz$Blog automation disabled in settings)rX   r„   rV   r(   rW   r   )Úplannedr€   rz   re   r�   )rJ   TrJ   Ú
would_planrK   rB   rX   r�   rI   ÚskippedzWeekly schedule already fullra   r6   )rX   r’   Úpublished_this_weekÚscheduled_this_weekNrz   rG   re   r�   rƒ   r`   Úpartialé   r“   r”   )r   rM   Úenabledrf   rh   r*   Úposts_per_weekr   r&   ÚmaxÚminrT   rs   r9   r~   rl   r   rk   rb   rc   rd   r>   rj   r   r:   r=   )rA   ÚlimitrJ   r‹   r.   Útargetrz   Ú	scheduledÚ
slots_leftÚto_planr�   Úplan_resultÚnew_articlesÚar,   rD   s                   r   Ú
run_weeklyz BlogAutomationService.run_weekly  sg  € ô $×(Ñ(Ó*ˆØ×#Ò#©EØÐ*PÑQÐQà×+Ò+ØÐ*UÑVÐVà×(Ñ(Ò.¨B×5Ñ5Ô7ØÐ*QÑRÐRàÒ5˜,×5Ñ5ˆØ×2Ñ2Ó4ˆ	Ø×2Ñ2Ó4ˆ	Ü˜˜F YÑ.Ó/ˆ
á$)‘*¬s°5¸*Ò:MÈÓ/NˆÙ‘TØˆGð ØØØØñ
ˆðA	Ø˜Š{Ø!×3Ñ3°GÀWÐ3ÓM�ÙØ)-�G˜IÑ&Ø,3�G˜LÑ)Ø0;·±Ð@PÐRTÓ0U�GÐ,Ñ-Ø&1§o¡o°f¸bÓ&A�G˜F‘OØ$(�G˜D‘MØ"�Nà*�Ü%(¨Ó%6�˜	Ñ"á3?ó.Ù3?¨aÀ1×CSÓCS”C˜×(Ñ(Õ)°<ñ.�Ð)Ò*ð  "�á¡4¨G°qªLÜ+3¯<©<«>�Ô(Ø/8�Ô,Ø.L�Ô+Ø×!Ñ!Ú"Vð "ô ð Ø#Ø+4Ø+4ñ	ð ñ ™Ø+Ð,J¨uÒ/I¼¸LÓ8IÓK�GðØ×7Ñ7¸¿
¹
ÔCØ Ó,°Ñ1Ô,ð  Lô (0§|¡|£~ˆLÔ$à!(¨Ò!2‘	¸	ð Ô(ð /6°hÒ.?”�G˜HÑ% b qÐ)Ô*ÀRð Ô'ð ×ÑÚRð ô ð !ˆG�D‰MØ-6ˆGÐ)Ñ*Ø-0×-KÑ-KÓ-MˆGÐ)Ñ*ØˆNùòY.øô2 %ò Ø Ó)¨QÑ.Ó)Ø Ñ)×0Ñ0Ø+2¯:©:ÄÀCÃÑI÷ñ ûðûô( ò 	Ü'/§|¡|£~ˆLÔ$Ø+3ˆLÔ(Ü*-¨c«(ˆLÔ'Ø×ÑÚRð ô ð ûð	úsj   Â>AJ1 ÄJ1 Ä'IÄ9IÅAJ1 Æ$J1 Æ>(I$Ç&A8J1 ÉJ1 É$	J.É-7J)Ê$J1 Ê)J.Ê.J1 Ê1	LÊ:AK?Ë?L)N)NF)NFF)Ú__name__Ú
__module__Ú__qualname__Ústaticmethodr   r&   r-   Úclassmethodr   ÚdictrE   rT   ro   rw   rj   rŽ   r£   © r    r   r   r      sß   „ Øòó ðð ò	
ó ð	
ð ñQó ðQð ð°,ð À4ò ó ðð0 òó ðð@ ò<ó ð<ð| ñó ðð" ñ6ó ð6ð òKó ðKðZ òaó ñar    r   )Ú__doc__ÚloggingÚdatetimer   Údjango.utilsr   Úblogs.modelsr   r   Úblogs.services.background_jobsr   Ú$blogs.services.blog_research_servicer   Úblogs.services.content_servicer	   Ú blogs.services.editorial_servicer
   Úblogs.services.image_servicer   Ú!blogs.services.scheduling_servicer   r   Ú#blogs.services.shopify_blog_servicer   Úblogs.services.trends_servicer   Ú	getLoggerr¤   r;   r   rª   r    r   Ú<module>r¹      sJ   ðÙ Mã Ý å !ç 2Ý NÝ PÝ CÝ CÝ 9ß OÝ BÝ Aà	ˆ×	Ñ	˜8Ó	$€÷^ò ^r    