+
    p.i~                     "   R t ^ RIt^ RIt^ RIt^ RIt^ RIHt ]! ]P                  P                  RR4      4      t]P                  P                  R4      t]P                  P                  ]RR4      tRtR	t]P                  P                  R
4      t ! R R]P(                  P*                  4      tR R ltR R ltR R ltR R ltRR R lltR R ltR R lt ! R R]P(                  P<                  4      tR t ]!R8X  d
   ] ! 4        R# R# ) a_  
Launch27 cancellation zap receiver.

Accepts webhook/zap POSTs for cancellation events and posts a structured alert to Slack.
Designed to be simple, stdlib-only, and easy to run behind the existing preview/tailscale setup.

Endpoints:
- GET  /health
- HEAD /launch27-cancellation-webhook
- POST /launch27-cancellation-webhook

Expected payload:
The receiver is intentionally forgiving. It accepts either a flat JSON body or a nested
payload under `data` / `booking` / `event` keys.

Useful fields it will try to extract:
- booking_id / bookingId / id
- customer_name / customer / full_name / name
- address / service_address
- scheduled_at / booking_date / date + time
- cancellation_reason / reason / notes
- cancellation_scope / scope
- cancelled_by / actor / source
- event / event_type / zap / trigger

Slack target:
- defaults to #cancellations (CLXFQ8NBW)
N)datetimeL27_CANCEL_WEBHOOK_PORT8782z~/.openclaw/workspacememoryz"launch27-cancellation-events.jsonlz//tmp/openclaw/launch27-cancellation-webhook.log	CLXFQ8NBWz#~/.openclaw/secrets/slack-token.txtc                       ] tR t^-tRtRtR# )ReusableTCPServerT N)__name__
__module____qualname____firstlineno__allow_reuse_address__static_attributes__r	       -scripts/launch27-cancellation-zap-receiver.pyr   r   -   s    r   r   c                (    V ^8  d   QhR\         RR/# )   msgreturnNstr)formats   "r   __annotate__r   1   s     	 	S 	T 	r   c                    \         P                  ! 4       P                  R 4      pRV RV  2p\        VRR7        \        P
                  ! \        P                  P                  \        4      RR7       \        \        R4      ;_uu_ 4       pVP                  VR,           4       RRR4       R#   + '       g   i     R# ; i  \         d     R# i ; i)	z%Y-%m-%d %H:%M:%S[z] T)flushexist_oka
N)r   nowstrftimeprintosmakedirspathdirnameLOG_FILEopenwrite	Exception)r   tslinefs   &   r   logr/   1   s    		 	 !4	5Brd"SE?D	$d
BGGOOH-=(C  AGGD4K  !    s0   AC B/%C /C 	:C  C CCc                0    V ^8  d   QhR\         R\         /# )r   r&   r   r   )r   s   "r   r   r   =   s        c  c  r   c                     \        V 4      ;_uu_ 4       pVP                  4       P                  4       uuR R R 4       #   + '       g   i     R # ; iN)r)   readstrip)r&   r.   s   & r   read_secretr5   =   s)    	dqvvx~~ 
s	   =A	c                4    V ^8  d   QhR\         R\         RR/# )r   payloadsummaryr   Ndict)r   s   "r   r   r   B   s!     ( ($ ( ($ (r   c                    \         P                  ! \         P                  P                  \        4      R R7       R\
        P                  ! 4       P                  4       R,           RVRV /p\        \        R4      ;_uu_ 4       pVP                  \        P                  ! V4      R,           4       RRR4       R#   + '       g   i     R# ; i)	Tr   received_atZr8   r7   r   r    N)r$   r%   r&   r'   EVENTS_FILEr   utcnow	isoformatr)   r*   jsondumps)r7   r8   rowr.   s   &&  r   append_eventrD   B   s    KK,t<x(224s:77C
 
k3		1	

3$&' 
 			s   -B99C
	c                0    V ^8  d   QhR\         R\         /# r   r7   r   r9   )r   s   "r   r   r   M   s      T d r   c                     \        V 4      pR FV  pV P                  V4      p\        V\         4      '       g   K,  VP                  4        F  w  rEVP	                  WE4       K  	  KX  	  V# )data)rH   bookingevent)r:   get
isinstanceitems
setdefault)r7   outkeyvaluekvs   &     r   flatten_payloadrT   M   sU    
w-C+C eT""q$ & ,
 Jr   c                $    V ^8  d   QhR\         /# )r   rH   r9   )r   s   "r   r   r   W   s      d r   c                 P    V F  pV P                  V4      pVR9  g   K  Vu # 	  V# )N)N )rK   )rH   keysdefaultrP   rQ   s   &&&  r   first_valuerZ   W   s-    
"L  Nr   c                0    V ^8  d   QhR\         R\         /# rF   r9   )r   s   "r   r   r   _   s      t  r   c                 \   \        V 4      p\        V. RO4      p\        V. RO4      pV'       g   TMV RV 2P                  4       pR\        V. RO4      R\        V. RO4      R\        VRR.4      RVR\        V. RO4      R\        VR	R.4      R
\        V. RO4      R\        V. ROR4      /# )scheduled_at 
booking_idcustomeraddressservice_addresswhenreasonscopecancellation_scopecancelled_by
event_typelaunch27_cancellation)r]   booking_datedateservice_date)timebooking_time
start_time)r_   	bookingIdid)customer_namer`   	full_namename)cancellation_reasonrd   notescomment)rg   actorsource)rJ   rh   triggerzap)rT   rZ   r4   )r7   rH   rk   rm   rc   s   &    r   	summarizer|   _   s    7#DtUVDtCDD4D64&!1!7!7!9D 	k$(IJK&XY;t&7%CD+d$YZT$8'#BCD*MNk$(QSjk	 	r   c                0    V ^8  d   QhR\         R\         /# )r   r8   r   r9   )r   s   "r   r   r   q   s     &0 &04 &0D &0r   c           
         \        \        4      pR pV.pV R,          '       d   VP                  RV R,           24       V R,          '       d   VP                  RV R,           R24       V R,          '       d   VP                  RV R,           24       V R,          '       d   VP                  R	V R,           24       V R
,          '       d   VP                  RV R
,           24       V R,          '       d   VP                  RV R,           24       V R,          '       d   VP                  RV R,           24       VP                  RV R,           R24       VP                  R4       R\        RRP	                  V4      RRRR/p\
        P                  P                  R\        P                  ! V4      P                  4       RRV 2RRRR/R 7      p\
        P                  P                  V^R!7      ;_uu_ 4       p\        P                  ! VP                  4       P                  4       4      uuR"R"R"4       #   + '       g   i     R"# ; i)#z+:no_entry_sign: Launch27 cancellation alertr`   z*Customer:* r_   z*Booking ID:* ``rc   z*When:* ra   z*Address:* re   z	*Scope:* rd   z
*Reason:* rg   z*Cancelled by:* z
*Event:* `rh   z@
Please confirm reason + scope if missing, and handle in thread.channeltextr    unfurl_linksFunfurl_mediaz&https://slack.com/api/chat.postMessageAuthorizationzBearer Content-Typeapplication/jsonz
User-Agentz#Harvey Launch27 Cancel Receiver/1.0)rH   headers)timeoutN)r5   SLACK_TOKEN_FILEappendSLACK_CHANNELjoinurllibrequestRequestrA   rB   encodeurlopenloadsr3   decode)r8   tokentitlelinesr7   reqresps   &      r   post_to_slackr   q   s   ()E9EGEz|GJ$7#89:|w|'<&=Q?@vx012y{79#5"678wy!1 234xz'("3!456~'(?'@AB	LL:gl34A67	LLTU 	=		% 	G ..
 
 0ZZ '')wug..?
 ! C 
		R		0	0Dzz$))+,,./ 
1	0	0	0s   <2H99I
	c                   8   a  ] tR t^t o R tR tR tR tRtV t	R# )Handlerc                    R # r2   r	   )selfr   argss   &&*r   log_messageHandler.log_message   s    r   c                    V P                   R 8X  d$   V P                  ^4       V P                  4        R# V P                  R4       V P                  4        R# )/launch27-cancellation-webhook  N)r&   send_responseend_headersr   s   &r   do_HEADHandler.do_HEAD   sC    9988s#s#r   c                
   V P                   R 8X  dQ   V P                  ^4       V P                  RR4       V P                  4        V P                  P                  R4       R# V P                  R4       V P                  4        R# )z/healthr   z
text/plains!   Launch27 cancellation receiver OKr   N)r&   r   send_headerr   wfiler*   r   s   &r   do_GETHandler.do_GET   se    99	!s#^\:JJABs#r   c                N   V P                   R 8w  d$   V P                  R4       V P                  4        R#  \        V P                  P                  R^ 4      4      pV^ 8  d   V P                  P                  V4      MRp\        P                  ! VP                  RRR7      4      p\        V4      p\        W44       \        V4      p\        VP                  R4      4      p\        R	VP                  R
4      ;'       g    R RV 24       V P                  ^4       V P!                  RR4       V P                  4        V P"                  P%                  \        P&                  ! RRRVRV/4      P)                  4       4       R#   \*         d   p\        RT 24       T P                  R4       T P!                  RR4       T P                  4        T P"                  P%                  \        P&                  ! RRR\-        T4      /4      P)                  4       4        Rp?R# Rp?ii ; i)r   r   NzContent-Lengths   {}zutf-8replace)errorsokz%Cancellation event received, booking=r_   ?z
 slack_ok=r   r   Tslack_okr8   zPOST error: i  Ferror)r&   r   r   intr   rK   rfiler3   rA   r   r   r|   rD   r   boolr/   r   r   r*   rB   r   r+   r   )r   content_lengthrawr7   r8   slack_resultr   es   &       r   do_POSTHandler.do_POST   s   9988s#	R !1!12BA!FGN5Ca5G$**//.1UCjjGI!FGG(G*(1Ll&&t,-B7L8Q8X8XUX7YYcdfcghis#^-?@JJTZZtZYPW(XY``bc 	R,qc"#s#^-?@JJTZZugs1v(FGNNPQQ	Rs   EF H$BHH$r	   N)
r
   r   r   r   r   r   r   r   r   __classdictcell__)__classdict__s   @r   r   r      s      R Rr   r   c                     \         P                  ! R RR7       \        R\         24       \	        R\        3\
        4      p  V P                  4        R#   \         d     \        R4       T P                  4         R# i ; i)z/tmp/openclawTr   z0Starting Launch27 cancellation receiver on port z0.0.0.0zShutting downN)	r$   r%   r/   PORTr   r   serve_foreverKeyboardInterruptshutdown)servers    r   mainr      sc    KK$/
:4&AB	40':F Os   A &A>=A>__main__)rW   )"__doc__http.serverhttprA   r$   urllib.requestr   r   r   environrK   r   r&   
expanduser	WORKSPACEr   r>   r(   r   r   r   
HTTPServerr   r/   r5   rD   rT   rZ   r|   r   BaseHTTPRequestHandlerr   r   r
   r	   r   r   <module>r      s   :   	  
2::>>3V<=GG67	ggll9h0TU<77%%&KL .. 	 
($&0R/Rdkk00 /Rd zF r   