Ë
    4Õ´jõ*  ã                   ó˜  — d Z ddlZddlZddlZddlZddlZddlZddlZddlm	Z	 ddl
Z
ddlmZ ddlmZmZ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  ej8                  d«      Z eed¬«       G d„ de«      «       Z eed¬«       G d„ de«      «       Z eed¬«       G d„ de«      «       Z  eed¬«       G d„ de«      «       Z!y)z&Webhook and Shopify integration views.é    N)Úparse_qs)Úsettings)ÚJsonResponseÚHttpResponseÚHttpResponseBadRequestÚHttpResponseRedirect)Úmethod_decorator)ÚView)Úcsrf_exempt)ÚShopifyStore)ÚWebhookServiceÚwebhooksÚdispatch)Únamec                   ó(   — e Zd ZdZdefd„Zdefd„Zy)ÚShopifyWebhookViewzW
    POST /webhooks/shopify/<topic>/
    topic e.g. orders-create, products-update
    Úreturnc                 ó¸  — t         j                  xs dj                  «       }|sy|j                  j	                  d«      xs dj                  «       }|syt        j                  |j                  d«      |j                  t        j                  «      j                  «       }t        j                  |«      j                  d«      }t        j                  ||«      S )NÚ TzX-Shopify-Hmac-Sha256Fúutf-8)r   ÚSHOPIFY_API_SECRETÚstripÚheadersÚgetÚhmacÚnewÚencodeÚbodyÚhashlibÚsha256ÚdigestÚbase64Ú	b64encodeÚdecodeÚcompare_digest)ÚselfÚrequestÚsecretÚheader_hmacr!   Úcomputeds         ú4/var/www/html/shopify_to_digistore/webhooks/views.pyÚ_is_valid_hmacz!ShopifyWebhookView._is_valid_hmac+   s®   € Ü×-Ñ-Ò3°×:Ñ:Ó<ˆÙØØ—‘×*Ñ*Ð+BÓCÒIÀr×PÑPÓRˆÙØÜ—‘Ø�M‰M˜'Ó"Ø�L‰LÜ�N‰Nó
÷ ‰&‹(ð	 	ô
 ×#Ñ# FÓ+×2Ñ2°7Ó;ˆÜ×"Ñ" 8¨[Ó9Ð9ó    Útopicc                 ó   — | j                  |«      st        dddœd¬«      S 	 t        j                  |j                  «      }t
        j                  d||«       |j                  d
d«      }|dv rt        j                  |«      }n›|dk(  rt        j                  |«      }n€|dk(  r8|j                  j                  d«      xs d}	 t        j                  ||¬«      }nC|dv r9|j                  j                  d«      xs d}	 t        j&                  |||¬«      }ndd|dœ}|j                  d«      rdnd	}t        ||¬«      S # t        j                  $ r4 t
        j                  d||j                  «       t        dddœd	¬«      cY S w xY w# t         $ r.}t
        j#                  d|«       dt%        |«      dœ}Y d }~Œžd }~ww xY w# t         $ r.}t
        j#                  d|«       dt%        |«      dœ}Y d }~ŒØd }~ww xY w)NFÚinvalid_hmac)ÚokÚerrori‘  )Ústatusz0Shopify webhook received | topic=%s | payload=%sz1Shopify webhook invalid JSON | topic=%s | body=%sÚinvalid_jsoni�  Ú-Ú/)zproducts/updatezproducts/createzproducts/deletezrefunds/createzX-Shopify-Webhook-Idr   )Ú
webhook_idzRefund webhook failed: %s)zfulfillments/createzfulfillments/update)r7   r.   zFulfillment webhook failed: %sT)r1   Úskippedr.   r1   éÈ   )r,   r   ÚjsonÚloadsr   ÚloggerÚinfoÚJSONDecodeErrorr2   Úreplacer   Úhandle_product_updatedÚhandle_product_deletedr   r   Úhandle_refund_createdÚ	ExceptionÚ	exceptionÚstrÚ%handle_fulfillment_created_or_updated)	r&   r'   r.   ÚpayloadÚtopic_normalizedÚresultr7   Úexcr3   s	            r+   ÚpostzShopifyWebhookView.post:   sã  € Ø×"Ñ" 7Ô+Ü u°~Ñ FÈsÔSÐSð	TÜ—j‘j §¡Ó.ˆGÜ�K‰KÐJÈEÐSZÔ[ð
 !Ÿ=™=¨¨cÓ2ÐàÐEÑEÜ#×:Ñ:¸7ÓC‰FØÐ!2Ò2Ü#×:Ñ:¸7ÓC‰FØÐ!1Ò1Ø Ÿ™×,Ñ,Ð-CÓDÒJÈˆJð:Ü'×=Ñ=ØØ)ô‘ð Ð!OÑOØ Ÿ™×,Ñ,Ð-CÓDÒJÈˆJð:Ü'×MÑMØØ)Ø*ô‘ð !¨T¸EÑBˆFàŸ
™
 4Ô(‘¨cˆÜ˜F¨6Ô2Ð2øôG ×#Ñ#ò 	TÜ�L‰LÐLÈeÐU\×UaÑUaÔbÜ u°~Ñ FÈsÔSÒSð	Tûô" ò :Ü× Ñ Ð!<¸cÔBØ %´°C³Ñ9•ûð:ûô ò :Ü× Ñ Ð!AÀ3ÔGØ %´°C³Ñ9•ûð:úsB   £6E ÃF ÄG ÅAF	ÆF	Æ	GÆ$F>Æ>GÇ	G=Ç$G8Ç8G=N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Úboolr,   rE   rK   © r-   r+   r   r   $   s   „ ñð
:¨ó :ð*3 3ô *3r-   r   c                   ó   — e Zd ZdZd„ Zy)ÚShopifyInstallViewzA
    GET /webhooks/shopify/install/?shop=store.myshopify.com
    c                 ó´  — |j                   j                  d«      }|st        d«      S t        j                  rt        j
                  st        d«      S t        j                  j                  t        j                  t        j
                  ¬«       t        j                  }t        j                  t        j                  d«      «      j                  d«      }||j                  d<   ||j                  d<   t!        t        d	d
«      xs |j#                  d«      d d }|› d�}g d¢}t        j                  ||«      }|j%                  |||«      }	t'        |	«      S )NÚshopzMissing 'shop' query parameter.ú'Shopify API credentials not configured.©Úapi_keyr(   é   r   Úshopify_oauth_stateÚshopify_oauth_shopÚHOST_URLr   r6   éÿÿÿÿz/webhooks/shopify/callback/)Úread_productsÚwrite_productsÚread_ordersÚwrite_ordersÚread_customersÚwrite_customersÚread_fulfillmentsÚread_contentÚwrite_contentÚ
read_filesÚwrite_files)ÚGETr   r   r   ÚSHOPIFY_API_KEYr   ÚshopifyÚSessionÚsetupÚSHOPIFY_API_VERSIONÚbinasciiÚb2a_hexÚosÚurandomr$   ÚsessionÚgetattrÚbuild_absolute_uriÚcreate_permission_urlr   )
r&   r'   rU   Úapi_versionÚstateÚbase_urlÚredirect_uriÚscopesrs   Úauth_urls
             r+   r   zShopifyInstallView.getp   s$  € Ø�{‰{�‰˜vÓ&ˆáÜ)Ð*KÓLÐLä×'Ò'¬x×/JÒ/JÜ)Ð*SÓTÐTä�‰×ÑÜ×,Ñ,Ü×.Ñ.ð 	ô 	
ô
 ×2Ñ2ˆä× Ñ ¤§¡¨B£Ó0×7Ñ7¸Ó@ˆà16ˆ�‰Ð-Ñ.Ø04ˆ�‰Ð,Ñ-äœ8 Z°Ó4Ò\¸×8RÑ8RÐSVÓ8WÐX[ÐY[Ð8\ˆØ"˜Ð#>Ð?ˆò
ˆô —/‘/ $¨Ó4ˆØ×0Ñ0°¸ÀuÓMˆä# HÓ-Ð-r-   N©rL   rM   rN   rO   r   rQ   r-   r+   rS   rS   j   s   „ ñó*.r-   rS   c                   ó   — e Zd ZdZd„ Zy)ÚShopifyCallbackViewz)
    GET /webhooks/shopify/callback/
    c                 óÌ  — |j                   j                  d«      }|j                   j                  d«      }|j                   j                  «       }|r|st        d«      S |j                  j                  d«      }|j                  j                  d«      }|r
||k7  s||k7  rt        d«      S t
        j                  rt
        j                  st        d«      S t        j                  j                  t
        j                  t
        j                  ¬«       t        j                  |t
        j                  «      }	 |j                  |«      }t        j                  j!                  |d
|i¬«      \  }
}|j                  j#                  dd «       |j                  j#                  dd «       t%        d|
j&                  |dœ«      S # t        $ r}	t        d	|	› �«      cY d }	~	S d }	~	ww xY w)NrU   rx   z&Missing 'shop' or 'state' in callback.rZ   r[   zInvalid OAuth state.rV   rW   z#Failed to exchange code for token: Úaccess_token)Úshop_domainÚdefaultsT)r1   r‚   Úcreated)ri   r   Údictr   rs   r   rj   r   rk   rl   rm   rn   Úrequest_tokenrC   r   ÚobjectsÚupdate_or_createÚpopr   r‚   )r&   r'   rU   rx   ÚparamsÚexpected_stateÚexpected_shoprs   r�   rJ   Ústorer„   s               r+   r   zShopifyCallbackView.get§   s¥  € Ø�{‰{�‰˜vÓ&ˆØ—‘—‘ Ó(ˆØ—‘×!Ñ!Ó#ˆá™5Ü)Ð*RÓSÐSà Ÿ™×,Ñ,Ð-BÓCˆØŸ™×+Ñ+Ð,@ÓAˆá ¨.Ò!8¸MÈTÒ<QÜ)Ð*@ÓAÐAä×'Ò'¬x×/JÒ/JÜ)Ð*SÓTÐTä�‰×ÑÜ×,Ñ,Ü×.Ñ.ð 	ô 	
ô
 —/‘/ $¬×(DÑ(DÓEˆð	WØ"×0Ñ0°Ó8ˆLô &×-Ñ-×>Ñ>ØØ$ lÐ3ð ?ó 
‰ˆˆwð
 	�‰×ÑÐ1°4Ô8Ø�‰×ÑÐ0°$Ô7äàØ$×0Ñ0Ø"ñó
ð 	
øô ò 	WÜ)Ð,OÐPSÈuÐ*UÓVÕVûð	Wús   Ä:G Ç	G#ÇGÇG#ÇG#Nr}   rQ   r-   r+   r   r   ¡   s   „ ñó+
r-   r   c                   ó   — e Zd ZdZd„ Zd„ Zy)ÚDigistoreIPNViewz'
    POST /webhooks/digistore/ipn/
    c                 ó~   — |j                   j                  «       }t        j                  d|«       t	        dddœ«      S )NzDigistore IPN GET | query=%sTri   )r1   Úmethod)ri   r…   r<   r=   r   )r&   r'   Úquery_paramss      r+   r   zDigistoreIPNView.getß   s8   € Ø—{‘{×'Ñ'Ó)ˆÜ�‰Ø*Øô	
ô  4°5Ñ9Ó:Ð:r-   c           	      ó¸  — 	 |j                   r|j                   j                  d«      nd}|j                  j	                  «       }|j
                  j	                  «       }|sN|rL|dk7  rGt        |d¬«      }|j                  «       D ��ci c]  \  }}|t        |t        «      r|r|d   nd“Œ! }}}|j                  d«      xs d}t        j                  d|||«       t        j                  d	«      xs d}	|	�r|j                  d
«      xs |j                  d«      xs dj                  «       j!                  «       }
g }t#        |j%                  «       «      D ]<  }|dv rŒ|j                  |«      }|�	|dk(  s|du rŒ%|j'                  |› d|› |	› �«       Œ> dj)                  |«      }t+        j,                  |j/                  d«      «      j1                  «       j!                  «       }|
r||
k7  r t        j3                  d«       t5        d«      S |dk(  rt5        d«      S |dk(  r	 ddlm} t;        |j                  d«      xs d«      j                  «       }|st5        d«      S |j=                  ||d¬«      }|j                  d«      dk(  rt5        d«      S 	 t5        d«      S t5        d«      S # t        $ r d}Y �Œ�w xY wc c}}w # t>        $ r‹}t        jA                  d|«       	 ddlm} t;        |j                  d«      xs d«      j                  «       }|r|jC                  |t;        |«      «       n# t>        $ r Y nw xY wt5        d«      cY d }~S d }~ww xY w)Nr   r   z<non-utf8-body>T)Úkeep_blank_valuesr   Úeventz5Digistore IPN POST | event=%s | query=%s | payload=%sÚIPN_SHA_PASSPHRASEÚsha_signÚSHASIGN)r—   r˜   FÚ=zDigistore IPN invalid signaturezERROR: invalid sha signatureÚconnection_testÚOKÚ
on_payment)ÚOrderServiceÚorder_idzERROR: missing_order_id)Úipn_dataÚfetch_purchaserI   ÚfailedzERROR: shopify_order_failedz#Digistore IPN on_payment failed: %s)"r   r$   ÚUnicodeDecodeErrorri   r…   ÚPOSTr   ÚitemsÚ
isinstanceÚlistr   r<   r=   rq   Úgetenvr   ÚupperÚsortedÚkeysÚappendÚjoinr   Úsha512r   Ú	hexdigestÚwarningr   Úorders.servicesr�   rE   Úsync_order_to_shopifyrC   rD   Úset_order_sync_error)r&   r'   Ú	body_textr’   Ú	post_dataÚparsedÚkÚvr•   r(   Úreceived_sigr¤   ÚkeyÚvalueÚ
sha_stringÚcomputed_sigr�   Údigistore_order_idrI   rJ   Ú_OrderServiceÚoids                         r+   rK   zDigistoreIPNView.postç   s9  € ð	*Ø8?¿º˜Ÿ™×+Ñ+¨GÔ4È"ˆIð —{‘{×'Ñ'Ó)ˆØ—L‘L×%Ñ%Ó'ˆ	á™Y¨9Ð8IÒ+IÜ˜i¸4Ô@ˆFð #ŸL™LœNôá*‘D�A�qð œ: a¬Ô.±1�1�Q’4¸"Ñ<Ø*ð ñ ð
 —‘˜gÓ&Ò,¨"ˆÜ�‰ØCØØØô		
ô —‘Ð/Ó0Ò6°Bˆâà—‘˜zÓ*ÒL¨i¯m©m¸IÓ.FÒLÈ"ß‘“ß‘“ð ð ˆEÜ˜iŸn™nÓ.Ö/�ØÐ1Ñ1Øà!Ÿ™ cÓ*�à�= E¨R¢K°5¸E±>Øà—‘ ˜u A e W¨V¨HÐ5Õ6ð 0ð Ÿ™ ›ˆJä"Ÿ>™>Ø×!Ñ! 'Ó*óç‰i‹kŸ%™%›'ð ñ   <°<Ò#?Ü—‘Ð@ÔAÜ#Ð$BÓCÐCàÐ%Ò%Ü Ó%Ð%à�LÒ ð CÝ8ä%(Ø—M‘M *Ó-Ò3°ó&ç‘%“'ð #ñ *Ü'Ð(AÓBÐBà%×;Ñ;Ø&Ø&Ø#'ð <ó �ð —:‘:˜hÓ'¨8Ò3Ü'Ð(EÓFÐFð 4ô$   Ó%Ð%ä˜DÓ!Ð!øô{ "ò 	*Ø)‹Ið	*üóøôH ò CÜ× Ñ Ø9ØôðÝMä˜iŸm™m¨JÓ7Ò=¸2Ó>×DÑDÓF�CÙØ%×:Ñ:¸3ÄÀCÃÔIùÜ ò Ùðúä#Ð$AÓBÕBûðCús`   ‚)J- Â$J?È$>K É#2K Ê-J<Ê;J<Ë	MËMË%AL5Ì4MÌ5	MÌ>MÍ MÍMÍMÍMN)rL   rM   rN   rO   r   rK   rQ   r-   r+   r�   r�   Ù   s   „ ñò;ó`"r-   r�   )"rO   r:   Úloggingrq   r   r   r"   ro   Úurllib.parser   rk   Údjango.confr   Údjango.httpr   r   r   r   Údjango.utils.decoratorsr	   Údjango.viewsr
   Údjango.views.decorators.csrfr   Úwebhooks.modelsr   Úwebhooks.servicesr   Ú	getLoggerr<   r   rS   r   r�   rQ   r-   r+   Ú<module>rÊ      sã   ðÙ ,ã Û Û 	Û Û Û Û Ý !ã å  ÷ó õ 5Ý Ý 4å (Ý ,ð 
ˆ×	Ñ	˜:Ó	&€ñ �+ JÔ/ô?3˜ó ?3ó 0ð?3ñJ �+ JÔ/ô/.˜ó /.ó 0ð/.ñl �+ JÔ/ô0
˜$ó 0
ó 0ð0
ñn �+ JÔ/ôm"�tó m"ó 0ñm"r-   