+
    žkëiè  ã                  ó�  € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RI	H
t
 ^ RIt^ RIHt ]! ]4      P                  4       P                   P                   t]! ]4      ]P&                  9  d#   ]P&                  P)                  ^ ]! ]4      4       ^ RIHtHt 0 RmtR R ltR	 tR
 R ltR R ltR t]R8X  d
   ]! 4        R# R# )añ  
Migrate PartKeepr PartAttachment image records into parts_inventory.part_images.

Default source files path matches your server layout:
  /var/www/html/Server/files/PartAttachment

Example:
  python3 scripts/migrate_partkeepr_attachments.py     --source-host 192.168.50.5 --source-port 3306     --source-db PartKeepr --source-user partkeepr --source-password partkeepr     --target-host 192.168.50.5 --target-port 3306     --target-db parts_inventory --target-user bill --target-password 5074367
)ÚannotationsN)ÚPath)ÚOptional)Ú
DictCursor)Ú_effective_upload_dirÚ_ensure_tablesc          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )é   ÚhostÚstrÚportÚintÚuserÚpasswordÚdatabase© )Úformats   "ÚFC:\Users\Bill\Software\Server\scripts\migrate_partkeepr_attachments.pyÚ__annotate__r   $   s/   € ÷ 	ñ 	�#ð 	˜Sð 	¨ð 	°sð 	Àcñ 	ó    c           
     óD   € \         P                  ! V VVVV\        R R7      # )F)r
   r   r   r   r   ÚcursorclassÚ
autocommit)ÚpymysqlÚconnectr   )r
   r   r   r   r   s   &&&&&r   r   r   $   s(   € Ü�?Š?ØØØØØÜØôð r   c                 ó.  € \         P                  ! R R7      p V P                  RRR7       V P                  R\        RR7       V P                  RRR7       V P                  R	RR7       V P                  R
RR7       V P                  RRR7       V P                  R\        RR7       V P                  RRR7       V P                  RRR7       V P                  RRR7       V P                  RRR7       V P                  RRRR7       V P	                  4       # )zGMigrate PartKeepr PartAttachment images to parts_inventory part_images.)Údescriptionz--source-hostT)Úrequiredz--source-portiê  )ÚtypeÚdefaultz--source-dbz--source-userz--source-passwordz--target-hostz--target-portz--target-dbz--target-userz--target-passwordz--source-files-dirz)/var/www/html/Server/files/PartAttachment)r   z	--dry-runÚ
store_truez/Show intended actions without writing files/DB.)ÚactionÚhelp)ÚargparseÚArgumentParserÚadd_argumentr   Ú
parse_args)Úparsers    r   r&   r&   0   s  € Ü×$Ò$Ð1zÔ{€FØ
×Ñ˜°$ÐÔ7Ø
×Ñ˜¬c¸4ÐÔ@Ø
×Ñ˜°ÐÔ5Ø
×Ñ˜°$ÐÔ7Ø
×ÑÐ+°dÐÔ;Ø
×Ñ˜°$ÐÔ7Ø
×Ñ˜¬c¸4ÐÔ@Ø
×Ñ˜°ÐÔ5Ø
×Ñ˜°$ÐÔ7Ø
×ÑÐ+°dÐÔ;Ø
×ÑÐ,Ð6aÐÔbØ
×Ñ˜¨LÐ?pÐÔqØ×ÑÓÐr   c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r	   Úbase_dirr   Úfilenamer   Ú	extensionzOptional[str]ÚreturnzOptional[Path]r   )r   s   "r   r   r   A   s)   € ÷ ñ  Dð °Cð ÀMð ÐVdñ r   c                óô   € W,          .pV'       d,   VP                  W R VP                  R 4       2,          4       V F5  pVP                  4       '       g   K  VP                  4       '       g   K3  Vu # 	  R# )Ú.N)ÚappendÚlstripÚexistsÚis_file)r)   r*   r+   Ú
candidatesÚcs   &&&  r   Úcandidate_source_filer5   A   sa   € ØÕ%Ð&€JßØ×Ñ˜( z°°9×3CÑ3CÀCÓ3HÐ2IÐ%JÕJÔKÛˆØ�8‰8�:Œ:˜!Ÿ)™)Ÿ+œ+ØŠHñ ñ r   c               ó    € V ^8„  d   QhRRRR/# )r	   ÚrowÚdictr,   Úboolr   )r   s   "r   r   r   K   s   € ÷ =ñ =˜Tð = dñ =r   c                óN  a€ V P                  R4      pV^8X  d   R# V P                  R4      ;'       g    RP                  4       pVP                  R4      '       d   R# V P                  R4      ;'       g    RP                  4       P                  4       pV'       d    RVP	                  R4       2\
        9   d   R# V P                  R4      ;'       g    RP                  4       o\        ;QJ d#    V3R	 l\
         4       F  '       g   K   R# 	  R
# ! V3R	 l\
         4       4      # )zo
PartKeepr data is inconsistent: many image attachments have isImage=NULL.
Detect images using multiple hints.
ÚisImageTÚmimetypeÚ zimage/r+   r.   Úoriginalnamec              3  óF   <"  € T F  pSP                  V4      x € K  	  R # 5i)N)Úendswith)Ú.0ÚextÚoriginals   & €r   Ú	<genexpr>Ú&is_image_attachment.<locals>.<genexpr>Z   s   øé € Ð<±¨#ˆx× Ñ  ×%Ð%³ùs   ƒ!F)ÚgetÚlowerÚ
startswithÚstripr0   Ú
IMAGE_EXTSÚany)r7   Úis_imager<   r+   rC   s   &   @r   Úis_image_attachmentrM   K   sà   ø€ ð
 �w‰w�yÓ!€HØ�1„}ÙØ—‘˜
Ó#×)Ð) r×0Ñ0Ó2€HØ×Ñ˜8×$Ò$ÙØ—‘˜Ó%×+Ð+¨×2Ñ2Ó4×:Ñ:Ó<€Iß�q˜×)Ñ)¨#Ó.Ð/Ð0´JÔ>ÙØ—‘˜Ó'×-Ð-¨2×4Ñ4Ó6€Hß‹3Ô<µÓ<�3Œ3Ð<Š3Ð<ˆ3Ô<µÓ<Ó<Ð<r   c                 óP
  € \        4       p \        V P                  4      pVP                  4       '       g   \	        R V 24      h\        V P                  V P                  V P                  V P                  V P                  4      p\        V P                  V P                  V P                  V P                  V P                  4      p^ p^ p^ p^ p^ p \!        V4       VP#                  4       ;_uu_ 4       q“P#                  4       ;_uu_ 4       p
V	P%                  R4       V	P'                  4        Uu. uF  p\)        V4      '       g   K  VNK  	  pp\        \+        4       4      pV EF»  pVR,          pVP-                  R4      ;'       g    RpVP-                  R4      pVP-                  R4      ;'       g    TpV
P%                  RV34       V
P/                  4       pV'       g   V^,          pKŠ  \1        VR,          4      p\3        VVV4      pVf   V^,          pK¸  V
P%                  R
VV34       V
P/                  4       '       d   V^,          pKí  VP4                  ;'       g    Rp\        R4      \7        V4      ,          VP8                   V 2,          pVV,          p\7        V4      P;                  RR4      pV P<                  '       gÝ   VP>                  PA                  RRR7       VP                  4       '       d“   VP8                  p^p VP>                  V RV V 2,          pVP                  4       '       gI   Tp\7        \        R4      \7        V4      ,          VPB                  ,          4      P;                  RR4      pMV^,          pK„  \D        PF                  ! VV4       V^,          pV
P%                  RV34       \1        V
P/                  4       R,          4      ^ 8X  d   ^M^ pV P<                  '       g   V
P%                  RVVVV34       V^,          pEK¾  	  R	R	R	4       R	R	R	4       V P<                  '       d   VPI                  4        MVPK                  4        \M        RRV 2RV 2RV 2RV 2RV 2RV P<                   24        TPQ                  4        TPQ                  4        R	# u upi   + '       g   i     L ; i  + '       g   i     L«; i  \N         d    TPI                  4        h i ; i  TPQ                  4        TPQ                  4        i ; i)z"Source files directory not found: zª
                SELECT id, part_id, filename, originalname, extension, isImage, mimetype
                FROM PartAttachment
                ORDER BY id
                Úpart_idr*   r=   r+   r>   z;SELECT id FROM parts WHERE source_partkeepr_id = %s LIMIT 1ÚidNz¢
                    SELECT id FROM part_images
                    WHERE part_id = %s AND original_filename = %s
                    LIMIT 1
                    ú.jpgÚpartsÚ\Ú/T)ÚparentsÚexist_okÚ_z8SELECT COUNT(*) AS c FROM part_images WHERE part_id = %sr4   zÁ
                        INSERT INTO part_images (part_id, file_path, original_filename, source, is_primary)
                        VALUES (%s, %s, %s, 'uploaded', %s)
                        z"PartAttachment migration complete:zcopied=z	inserted=zskipped_no_part=zskipped_missing_file=zskipped_duplicate=zdry_run=))r&   r   Úsource_files_dirr1   ÚRuntimeErrorr   Úsource_hostÚsource_portÚsource_userÚsource_passwordÚ	source_dbÚtarget_hostÚtarget_portÚtarget_userÚtarget_passwordÚ	target_dbr   ÚcursorÚexecuteÚfetchallrM   r   rF   Úfetchoner   r5   Úsuffixr   ÚstemÚreplaceÚdry_runÚparentÚmkdirÚnameÚshutilÚcopy2ÚrollbackÚcommitÚprintÚ	ExceptionÚclose)ÚargsrX   Úsrc_connÚdst_connÚcopiedÚinsertedÚskipped_no_partÚskipped_missing_fileÚskipped_duplicateÚsrcÚdstÚrÚattachmentsÚupload_rootr7   Úsrc_part_idÚsrc_filenameÚsrc_extensionÚoriginal_nameÚpart_rowÚdst_part_idÚsrc_filerB   Úrelative_pathÚ	dest_fileÚrelative_path_strri   ÚidxÚaltÚ
is_primarys                                 r   Úmainr�   ]   sx  € Ü‹<€DÜ˜D×1Ñ1Ó2ÐØ×"Ñ"×$Ò$ÜÐ?Ð@PÐ?QÐRÓSÐSä�t×'Ñ'¨×)9Ñ)9¸4×;KÑ;KÈT×MaÑMaÐcg×cqÑcqÓr€HÜ�t×'Ñ'¨×)9Ñ)9¸4×;KÑ;KÈT×MaÑMaÐcg×cqÑcqÓr€Hà€FØ€HØ€OØÐØÐðdÜ�xÔ à�_‰_×Ô #§¡×'8Ô'8¸CØ�K‰Kðôð '*§l¡l¤nÓO¡n Ô8KÈA×8NŸ1˜1¡nˆKÐOäÔ4Ó6Ó7ˆKÜ"�Ø! )�n�Ø"Ÿw™w zÓ2×8Ð8°b�Ø #§¡¨Ó 4�Ø #§¡¨Ó 7× GÐ G¸<�ð —‘ÐYÐ\gÐ[iÔjØŸ<™<›>�ßØ# qÕ(�OÙÜ! (¨4¥.Ó1�ä0Ð1AÀ<ÐQ^Ó_�ØÒ#Ø(¨AÕ-Ð(Ùð —‘ðð
 ! -Ð0ôð —<‘<—>’>Ø%¨Õ*Ð%Ùà—o‘o×/Ð/¨�Ü $ W£´°KÓ0@Õ @ÀhÇmÁmÀ_ÐUXÐTYÐCZÕ Z�Ø'¨-Õ7�	Ü$'¨Ó$6×$>Ñ$>¸tÀSÓ$IÐ!à—|—|�|Ø×$Ñ$×*Ñ*°4À$Ð*ÔGà ×'Ñ'×)Ò)Ø'Ÿ}™}˜Ø˜Ø"Ø"+×"2Ñ"2¸°v¸Q¸s¸eÀCÀ5Ð5IÕ"I˜CØ#&§:¡:§<¢<Ø,/ 	Ü47¼¸W»ÌÈKÓHXÕ8XÐ[^×[cÑ[cÕ8cÓ4d×4lÑ4lÐmqÐsvÓ4wÐ 1Ø %Ø 1�HšCÜ—L’L ¨9Ô5Ø˜!•�ð —‘ÐVÐYdÐXfÔgÜ"% c§l¡l£n°SÕ&9Ó":¸aÔ"?™QÀQ�
à—|—|�|Ø—K‘Kðð %Ð&7¸È
ÐSôð ˜A•“ñC #÷ (9×ð\ �<�<ˆ<Ø×ÑÕà�O‰OÔäØ0Ø�f�XÐØ˜�zÐ"Ø˜Ð/Ð0Ø#Ð$8Ð#9Ð:Ø Ð!2Ð 3Ð4Ø�t—|‘|�nÐ%õ	
ð 	�‰ÔØ�‰Öùòs P÷ (9×'8ú××ûôx ô Ø×ÑÔØðûð 	�‰ÔØ�‰Õúsš   Ã#S# Ã4SÄ$R=	Ä0R8ÅR8Å;R=	Æ
+R=	Æ6-R=	Ç$A"R=	ÉR=	É%BR=	Ì>R=	Í C R=	Ð$R=	Ð%SÐ-S# ÑAS# Ò8R=	Ò=SÓSÓS 	ÓS# Ó#T Ô T Ô"T%Ú__main__>	   ú.bmpú.gifrQ   ú.pngú.svgú.tifú.jpegú.tiffú.webp)Ú__doc__Ú
__future__r   r#   Úosro   ÚsysÚpathlibr   Útypingr   r   Úpymysql.cursorsr   Ú__file__Úresolverl   ÚROOTr   ÚpathÚinsertÚblueprints.partsinventoryr   r   rJ   r   r&   r5   rM   r�   Ú__name__r   r   r   Ú<module>r¨      s¤   ðñõ #ã Û 	Û Û 
Ý Ý ã Ý &ñ ˆHƒ~×ÑÓ×&Ñ&×-Ñ-€Ù€tƒ9�C—H‘HÔØ‡H�H‡O�O�A‘s˜4“yÔ!ç KâX€
õ	òõ"õ=ò$sðl ˆzÔÙ†Fñ r   