Ë
    æ!jí1  ã                  óØ  — U d 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	m
Z
mZmZmZ ddlmZmZmZ ddlmZ d	Zd
ed<    edddddd¬«      Z eddd¬«      Zd9d„Zd:d„Zd9d„Zd;d„Z G d„ de«      Z G d„ de«      Z G d„ d e«      Z G d!„ d"e«      Z G d#„ d$e«      Z d<d%„Z!d&d'd(d)d*d	œZ"d+ed,<   d=d-„Z#d.d/d0d1d2d3dœZ$d+ed4<   d>d5„Z% ejL                  d6ejN                  «      Z(d?d7„Z)d@d8„Z*y)AzVProgramme hierarchy: levels, modules, weeks (intro + 12 weeks), sessions, assessments.é    )ÚannotationsN)ÚPath)ÚSimpleNamespace)ÚCheckConstraintÚ
ForeignKeyÚIntegerÚStringÚUniqueConstraint)ÚMappedÚmapped_columnÚrelationship)ÚBase)ÚbeginnerÚhbÚintermediateÚhiÚadvancedztuple[str, ...]ÚCSV_LEVEL_SLUGSr   r   r   r   r   Úcustom)r   r   r   r   r   r   ÚfoundationsÚdevelopmentalÚ
creativity)r   r   r   c                óŒ   — t        j                  dd| j                  «       j                  «       «      }|st	        d«      ‚|d d S )Nú\s+Ú_zlevel slug is requiredé@   ©ÚreÚsubÚstripÚlowerÚ
ValueError©ÚvalueÚ
normalizeds     úC/var/www/html/kelly/kelly-backend/app/programme/models_programme.pyÚnormalize_programme_level_slugr'   "   s>   € Ü—‘˜  U§[¡[£]×%8Ñ%8Ó%:Ó;€JÙÜÐ1Ó2Ð2Ø�c�rˆ?Ðó    c                ó   — | €yt        | «      S ©NÚ ©Ústr)Úslugs    r&   Úprogramme_level_slug_strr/   )   ó   € Ø€|ØÜˆt‹9Ðr(   c                óŒ   — t        j                  dd| j                  «       j                  «       «      }|st	        d«      ‚|d d S )Nr   r   zmodule kind is requiredr   r   r#   s     r&   Únormalize_programme_module_kindr2   /   s>   € Ü—‘˜  U§[¡[£]×%8Ñ%8Ó%:Ó;€JÙÜÐ2Ó3Ð3Ø�c�rˆ?Ðr(   c                ó   — | €yt        | «      S r*   r,   )Úkinds    r&   Úprogramme_module_kind_strr5   6   r0   r(   c                  óÄ   — e Zd ZU dZ ed¬«      Zded<    e ed«      dd¬«      Zd	ed
<    e ed«      d¬«      Z	d	ed<    ee
d¬«      Zded<    edddd¬«      Zded<   y)ÚProgrammeLevelÚprogramme_levelsT©Úprimary_keyúMapped[int]Úidr   F)ÚuniqueÚnullableúMapped[str]r.   éÿ   ©r>   Údisplay_namer   ©ÚdefaultÚ
sort_orderÚProgrammeModuleÚlevelúall, delete-orphanzProgrammeModule.sort_order©Úback_populatesÚcascadeÚorder_byzMapped[list['ProgrammeModule']]ÚmodulesN)Ú__name__Ú
__module__Ú__qualname__Ú__tablename__r   r<   Ú__annotations__r	   r.   rB   r   rE   r   rM   © r(   r&   r7   r7   <   sp   … Ø&€Má#°Ô5€BˆÓ5Ù%¡f¨R£j¸ÈÔN€Dˆ+ÓNÙ -©f°S«kÀEÔ J€L�+ÓJÙ+¨G¸QÔ?€J�Ó?á/;Ø¨'Ð;OÐZvô0€GÐ,ô r(   r7   c                  ó&  — e Zd ZU dZ ed¬«      Zded<    e edd¬«      d	¬
«      Zded<    e e	d«      d	¬
«      Z
ded<    e e	d«      d	¬
«      Zded<    eed¬«      Zded<    edd¬«      Zded<    edddd¬«      Zded<    eddd ¬!«      fZy")#rF   Úprogramme_modulesTr9   r;   r<   zprogramme_levels.idÚCASCADE©ÚondeleteFrA   Úlevel_idr   r?   r4   r@   rB   r   rC   rE   r7   rM   ©rJ   zMapped['ProgrammeLevel']rG   ÚProgrammeWeekÚmodulerH   zProgrammeWeek.week_indexrI   zMapped[list['ProgrammeWeek']]ÚweeksÚuq_programme_module_level_kind©ÚnameN)rN   rO   rP   rQ   r   r<   rR   r   rY   r	   r4   rB   r   rE   r   rG   r]   r
   Ú__table_args__rS   r(   r&   rF   rF   I   s±   … Ø'€Má#°Ô5€BˆÓ5Ù)©*Ð5JÐU^Ô*_ÐjoÔp€HˆkÓpÙ%¡f¨R£j¸5ÔA€Dˆ+ÓAÙ -©f°S«kÀEÔ J€L�+ÓJÙ+¨G¸QÔ?€J�Ó?á&2Ð3CÐT]Ô&^€EÐ#Ó^Ù+7Ø¨Ð:NÐYsô,€EÐ(ó ñ ' z°6Ð@`ÔaÐc�Nr(   rF   c                  ó  — e Zd ZU dZ ed¬«      Zded<    e edd¬«      d	¬
«      Zded<    ee	d	¬
«      Z
ded<    e ed«      d	¬
«      Zded<    edd¬«      Zded<    edddd¬«      Zded<    eddd¬«       edd¬«      fZy )!r[   Úprogramme_weeksTr9   r;   r<   zprogramme_modules.idrV   rW   FrA   Ú	module_idÚ
week_indexr   r?   Údisplay_labelrF   r]   rZ   zMapped['ProgrammeModule']r\   ÚProgrammeSessionÚweekrH   zProgrammeSession.session_numberrI   z Mapped[list['ProgrammeSession']]ÚsessionsÚuq_programme_week_module_indexr_   z$week_index >= 0 AND week_index <= 12Úck_programme_week_index_rangeN)rN   rO   rP   rQ   r   r<   rR   r   rd   r   re   r	   rf   r   r\   ri   r
   r   ra   rS   r(   r&   r[   r[   Z   s«   … Ø%€Má#°Ô5€BˆÓ5Ù*©:Ð6LÐW`Ô+aÐlqÔr€Iˆ{ÓrÙ+¨G¸eÔD€J�ÓDÙ!.©v°b«zÀEÔ!J€M�;ÓJá(4Ð5FÐW^Ô(_€FÐ%Ó_Ù1=ØØØ$Ø2ô	2€HÐ.ó ñ 	˜ lÐ9YÔZÙÐ>ÐEdÔeð�Nr(   r[   c                  ó*  — e Zd ZU dZ ed¬«      Zded<    e edd¬«      d	¬
«      Zded<    ee	d	¬
«      Z
ded<    e ed«      d	¬
«      Zded<    ed	¬«      Zded<    edd¬«      Zded<    edddd¬«      Zded<    eddd¬ «       ed!d"¬ «      fZy#)$rg   Úprogramme_sessionsTr9   r;   r<   zprogramme_weeks.idrV   rW   FrA   Úweek_idÚsession_numberé   r?   ÚtitlerC   zMapped[bool]Úadmin_checkedr[   ri   rZ   zMapped['ProgrammeWeek']rh   ÚProgrammeAssessmentÚsessionrH   zProgrammeAssessment.sort_orderrI   z#Mapped[list['ProgrammeAssessment']]ÚassessmentsÚ uq_programme_session_week_numberr_   zsession_number >= 1Ú$ck_programme_session_number_positiveN)rN   rO   rP   rQ   r   r<   rR   r   rn   r   ro   r	   rq   rr   r   rh   ru   r
   r   ra   rS   r(   r&   rg   rg   p   sº   … Ø(€Má#°Ô5€BˆÓ5Ù(©Ð4HÐS\Ô)]ÐhmÔn€Gˆ[ÓnÙ"/°À%Ô"H€N�KÓHÙ&¡v¨c£{¸UÔC€Eˆ;ÓCÙ"/¸Ô">€M�<Ó>á$0°ÐQ[Ô$\€DÐ
!Ó\Ù7CØØ Ø$Ø1ô	8€KÐ4ó ñ 	˜Ð$4Ð;]Ô^ÙÐ-Ð4ZÔ[ð�Nr(   rg   c                  óÚ   — e Zd ZU dZ ed¬«      Zded<    e edd¬«      d	¬
«      Zded<    ee	d	¬
«      Z
ded<    e ed«      d	¬
«      Zded<    edd¬«      Zded<    eddd¬«      fZy)rs   Úprogramme_assessmentsTr9   r;   r<   zprogramme_sessions.idrV   rW   FrA   Ú
session_idrE   rp   r?   rq   rg   ru   rZ   zMapped['ProgrammeSession']rt   Ú%uq_programme_assessment_session_orderr_   N)rN   rO   rP   rQ   r   r<   rR   r   rz   r   rE   r	   rq   r   rt   r
   ra   rS   r(   r&   rs   rs   ‡   s}   … Ø+€Má#°Ô5€BˆÓ5Ù+©JÐ7NÐYbÔ,cÐnsÔt€J�ÓtÙ+¨G¸eÔD€J�ÓDÙ&¡v¨c£{¸UÔC€Eˆ;ÓCá*6Ð7IÐZgÔ*h€GÐ'Óhá& |°\ÐHoÔpÐr�Nr(   rs   c                 óV   — t        t        «      j                  «       j                  d   S )z9Project root (directory that contains the `app` package).é   )r   Ú__file__ÚresolveÚparentsrS   r(   r&   Ú	repo_rootr�   ”   s    € ä”‹>×!Ñ!Ó#×+Ñ+¨AÑ.Ð.r(   z UPP - Assessments - Beginner.csvzUPP - Assessments - HB.csvz$UPP - Assessments - Intermediate.csvzUPP - Assessments - HI.csvz UPP - Assessments - Advanced.csvzdict[str, str]ÚLEVEL_CSV_FILESc                óØ  — ddl m} t        j                  | «      }|syt	        «       j                  «       }t         |«       dd«      xs dj                  «       }|rNt        |j                  «       «      }|j                  «       r|j                  «       n||z  j                  «       g}n |dz  dz  ||dz  |dz  |dz  dz  |dz  d	z  g}|D ]  }||z  }|j                  «       sŒ|c S  y)
z¢
    Locate one UPP CSV on disk. Uses `programme_csv_dir` from settings when set; otherwise
    tries common locations (repo root, app/, app/all csv/, etc.).
    r   )Úget_settingsNÚprogramme_csv_dirr+   ÚappÚ	programmezall csvÚall_csv)Ú
app.configr„   r‚   Úgetr�   r   Úgetattrr    r   Úis_absoluteÚis_file)	r.   r„   ÚfilenameÚrootÚrawÚpÚbasesÚbaseÚ	candidates	            r&   Úresolve_upp_csv_pathr•   ¢   sï   € õ
 (ä×"Ñ" 4Ó(€HÙàÜ‹;×ÑÓ €DÜ‘<“>Ð#6¸Ó=ÒCÀ×
JÑ
JÓ
L€Cá
Ü�—‘“ÓˆØ !§¡¤�—‘”°d¸Q±h×5GÑ5GÓ5IÐJ‰ð �5‰L˜;Ñ&ØØ�5‰LØ�9ÑØ�5‰L˜9Ñ$Ø�5‰L˜9Ñ$ð
ˆó ˆØ˜8‘Oˆ	Ø×ÑÕØÒð ð r(   ÚBeginnerzHigher Beginner (HB)ÚIntermediatezHigher Intermediate (HI)ÚAdvancedÚCustomÚLEVEL_DISPLAY_DEFAULTSc                óB   — | j                  «       }d|v ryd|v ryd|v ryy )Nr   r   Ú
foundationr   )r!   )ÚcellÚcls     r&   Ú_module_kind_from_cellrŸ   Í   s1   € Ø	�‰‹€BØ�rÑØØ˜"ÑØØ�rÑØØr(   z^session\s+(\d+)\s*-?\s*(.*)$c                ó  — ddl }| j                  dd¬«      }t        |j                  |j	                  «       «      «      }g }d}|t        |«      k  �r(||   }|r|d   ndj                  «       }|rt        |«      nd}|€|dz  }ŒB|dz   }	|	t        |«      k\  r	 |S ||	   }
g }t        dt        |
«      d«      D ]X  }|
|   xs dj                  «       }|s n=|j                  «       }|d	v r n'|j                  «       d
k(  rŒH|j                  |«       ŒZ t        |«      }|dk(  r|dz  }Œæt        |«      D �cg c]
  }||   i dœ‘Œ }}dg|z  }|	dz   }|t        |«      k  r>t        d„ ||   D «       «      s)|dz  }|t        |«      k  rt        d„ ||   D «       «      sŒ)|t        |«      k  �r¨||   }|r|d   ndj                  «       }|rt        |«      ��n}|j                  «       dk(  r�nht        |«      D �]D  }|dz  }|t        |«      k\  rŒ||   xs dj                  «       }|sŒ2t        j                  |«      }|rst        |j!                  d«      «      }|j!                  d«      xs dj                  «       xs d|› �}|||<   ||   d   j#                  ||g dœ«       |||   d   |   d<   Œ¼|j                  «       }|j%                  d«      sŒÞd|v r#|j'                  dd«      d   j                  «       n|}|j                  «       dv r�Œ||   }|€�Œ$|s�Œ(||   d   |   d   j                  |«       �ŒG |dz  }|t        |«      k  r�Œ¨|j                  ||f«       |}|t        |«      k  r�Œ(|S c c}w )zË
    Parse one UPP assessment CSV into module payloads.
    Each module payload is a list of week dicts:
      {"display_label": str, "sessions": {1: {"title": str, "assessments": [str,...]}}, ...}}
    r   Nzutf-8Úreplace)ÚencodingÚerrorsr+   é   é   )zprogress assessmentÚgradingzTO COMPLETE)rf   ri   c              3  óD   K  — | ]  }|xs d j                  «       –— Œ y­w)r+   N)r    )Ú.0Úcs     r&   Ú	<genexpr>z+parse_upp_assessment_csv.<locals>.<genexpr>  s   è ø€ Ð,UÉÀ1¨aªg°2¯_©_×->Éùs   ‚ r¦   r}   zSession ri   )rq   ru   rq   zassessment:Ú:)ÚNONEr+   ru   )ÚcsvÚ	read_textÚlistÚreaderÚ
splitlinesÚlenr    rŸ   Úranger!   ÚupperÚappendÚanyÚ_SESSION_REÚmatchÚintÚgroupÚ
setdefaultÚ
startswithÚsplit)Úpathr­   ÚtextÚrowsÚmodules_outÚrÚrowÚc0r4   Úweek_row_idxÚweek_rowÚweek_labelsr©   ÚlabelÚllÚ	num_weeksÚiÚweeks_payloadÚ
current_snÚdata_rÚdrÚc0bÚwiÚcolr�   ÚsmÚsnrq   Úlows                                r&   Úparse_upp_assessment_csvrÖ   Û   s¼  € ó à�>‰> 7°9ˆ>Ó=€DÜ�—
‘
˜4Ÿ?™?Ó,Ó-Ó.€Dà02€KØ	€AØ
Œc�$‹i‹-Ø�1‰gˆÙˆc�!Šf ×*Ñ*Ó,ˆÙ-/Ô% bÔ)°TˆØˆ<Ø�‰FˆAØà˜1‘uˆØœ3˜t›9Ò$ØðB ÐðA ˜Ñ%ˆØ!#ˆÜ�qœ#˜h›-¨Ö+ˆAØ˜a‘[Ò& B×-Ñ-Ó/ˆEÙÙØ—‘“ˆBØÐ7Ñ7ÙØ�{‰{‹} Ò-ØØ×Ñ˜uÕ%ð ,ô ˜Ó$ˆ	Ø˜Š>Ø�‰FˆAØä`eÐfoÔ`pÓ$qÑ`pÐ[\°{À1±~ÐSUÓ%VÐ`pˆÐ$qØ(, v°	Ñ'9ˆ
à Ñ!ˆð ”s˜4“yÒ ¬Ñ,UÈÈVÊÓ,UÔ)UØ�a‰KˆFð ”s˜4“yÒ ¬Ñ,UÈÈVÊÓ,UÕ)Uð ”s˜4“yÓ Ø�f‘ˆBÙ�2�a’5 B×-Ñ-Ó/ˆCÙÔ-¨cÓ2Ð>ÙØ�y‰y‹{˜iÒ'Ùä˜I×&�Ø˜1‘f�Øœ#˜b›'’>ØØ˜3™š 2×,Ñ,Ó.�ÙØÜ ×&Ñ& tÓ,�ÙÜ˜RŸX™X a›[Ó)�BØŸX™X a›[Ò.¨B×5Ñ5Ó7ÒJ¸XÀbÀT¸?�EØ%'�J˜r‘NØ! "Ñ% jÑ1×<Ñ<¸RÈ5ÐacÑAdÔeØAF�M "Ñ% jÑ1°"Ñ5°gÑ>ØØ—j‘j“l�Ø—>‘> -Õ0Ø=@ÀD¹[˜DŸJ™J s¨AÓ.¨qÑ1×7Ñ7Ô9Èd�EØ—{‘{“}¨Ñ4Ù Ø# B™�BØ’~«%Ø% bÑ)¨*Ñ5°bÑ9¸-ÑH×OÑOÐPUÖVð- 'ð0 �a‰KˆFðA ”s˜4“yÔ ðD 	×Ñ˜D -Ð0Ô1ØˆðS Œc�$‹iŒ-ðV Ðùò] %rs   Ä7M=c                ó@  — t        | «      }|€yg }t        t        |«      «      D ]³  \  }\  }}g }t        |«      D ]g  \  }}g }	t        |d   j	                  «       «      D ])  \  }
}|	j                  |
|d   t        |d   «      dœ«       Œ+ |j                  ||d   |	dœ«       Œi |j                  ||j                  dd	«      j                  «       ||d
œ«       Œµ | t        j                  | | j                  dd	«      j                  «       «      dœ|j                  |dœS )u•   
    Full programme tree for one level (levels â†’ modules â†’ weeks â†’ sessions â†’ assessments).
    Returns None if the CSV file is missing.
    Nri   rq   ru   )ro   rq   ru   rf   )re   rf   ri   r   Ú )r4   rB   rE   r]   )r.   rB   )rG   Ú
source_csvrM   )r•   Ú	enumeraterÖ   ÚsortedÚitemsrµ   r¯   r¡   rq   rš   rŠ   r`   )r.   r¾   rM   Ú	mod_orderr4   rÌ   r]   re   rh   ri   ro   Úsdatas               r&   Ú programme_level_payload_from_csvrß   6  s<  € ô
   Ó%€DØ€|Øà€GÜ,5Ô6NÈtÓ6TÖ,UÑ(ˆ	Ñ(�D˜-ØˆÜ )¨-Ö 8ÑˆJ˜Ø#%ˆHÜ)/°°ZÑ0@×0FÑ0FÓ0HÖ)IÑ%� Ø—‘à*8Ø!& w¡Ü'+¨E°-Ñ,@Ó'Añõð *Jð �L‰Là",Ø%)¨/Ñ%:Ø (ñõð !9ð" 	�‰àØ $§¡¨S°#Ó 6× <Ñ <Ó >Ø'Øñ	õ	
ð' -Vð< Ü2×6Ñ6°t¸T¿\¹\È#ÈsÓ=S×=YÑ=YÓ=[Ó\ñ
ð —i‘iØñð r(   )r$   r-   Úreturnr-   )r.   ú
str | Nonerà   r-   )r4   rá   rà   r-   )rà   r   )r.   r-   rà   zPath | None)r�   r-   rà   rá   )r¾   r   rà   z,list[tuple[ProgrammeModuleKind, list[dict]]])r.   r-   rà   zdict | None)+Ú__doc__Ú
__future__r   r   Úpathlibr   Útypesr   Ú
sqlalchemyr   r   r   r	   r
   Úsqlalchemy.ormr   r   r   Úapp.databaser   r   rR   ÚProgrammeLevelSlugÚProgrammeModuleKindr'   r/   r2   r5   r7   rF   r[   rg   rs   r�   r‚   r•   rš   rŸ   ÚcompileÚ
IGNORECASEr·   rÖ   rß   rS   r(   r&   Ú<module>rí      s0  ðÚ \å "ã 	Ý Ý !ç UÕ Uß >Ñ >å ð $X€�Ó Wñ %ØØØØØØôÐ ñ &ØØ!ØôÐ óóóóô
�Tô 
ôd�dô dô"�Dô ô,�tô ô.
s˜$ô 
só/ð 3Ø
&Ø:Ø
&Ø2ñ#€�ó óðD Ø
 Ø"Ø
$ØØñ*Ð ˜ó óð ˆb�j‰jÐ9¸2¿=¹=ÓI€óXôv-r(   