
    (<i$                        U d Z ddlZddlZddlZddlmZmZ ddlmZm	Z	m
Z
mZmZ g dZee   ed<   g dZee   ed<   g d	Zee   ed
<   ddgZee   ed<    G d de      Z G d ded      Z G d de      Z	 	 d*dededededee   dee   ddfdZ	 	 d*dededededee   dee   defdZdee   dee   fd Zd!edefd"Zdej:                  fd#Zd$ej>                  de fd%Z!d&ede fd'Z"d+d(Z#e$d)k(  r e#        yy),zUTM URL Builder CLI.

Usage examples:
    python3 utm_builder.py --source meta --medium cpc --campaign AB_A_snu \
        --content carousel_a1 --base https://incar-top.tistory.com

    python3 utm_builder.py --batch items.json
    N)Optional	TypedDict)ParseResultparse_qs	urlencodeurlparse
urlunparse)metagooglenaver_sa	naver_gfakakaodanggeunsaraminjobkoreaALLOWED_SOURCES)cpcdisplaysocial	job_boardALLOWED_MEDIUMS)AB_A_snu
AB_B_incarorg_movealways_Aalways_Burgent_AALLOWED_CAMPAIGNSzincar-top.tistory.comzincar-top1.tistory.comALLOWED_LANDING_DOMAINSc                       e Zd ZdZy)ValidationErrorz+Raised when UTM parameter validation fails.N)__name__
__module____qualname____doc__     D/home/jay/workspace/.worktrees/task-2057-dev2/scripts/utm_builder.pyr!   r!   7   s    5r'   r!   c                   N    e Zd ZU dZeed<   eed<   eed<   eed<   eed<   eed<   y)		BatchItemz!Single item in a batch JSON file.sourcemediumcampaigncontenttermbaseN)r"   r#   r$   r%   str__annotations__r&   r'   r(   r*   r*   ;   s#    +KKML
I
Ir'   r*   F)totalc                   <    e Zd ZU dZeed<   ee   ed<   ee   ed<   y)BatchResultzResult for a single batch item.indexurlerrorN)r"   r#   r$   r%   intr2   r   r1   r&   r'   r(   r5   r5   F   s    )J	#C=r'   r5   r+   r,   r-   r0   r.   r/   returnc                    g }| t         vr*|j                  d|  ddj                  t                       |t        vr*|j                  d| ddj                  t                      |t        vr*|j                  d| ddj                  t                      t        |      }|j                  r|j                  s+|j                  d| ddj                  t                      nP|j                  j                  d      d	   }|t        vr*|j                  d
| ddj                  t                      |rt        dj                  |            y)zwValidate UTM parameters against allowed values.

    Raises:
        ValidationError: if any parameter is invalid.
    zInvalid utm_source 'z'. Allowed values: z, zInvalid utm_medium 'zInvalid utm_campaign 'zInvalid base URL 'z'. Allowed landing domains: :r   zInvalid landing page domain 'z'. Allowed domains: 
N)r   appendjoinr   r   r   schemenetlocr   splitr!   )	r+   r,   r-   r0   r.   r/   errorsparseddomains	            r(   validate_paramsrF   Q   sA    F_$,VH4KDIIVeLfKghi_$,VH4KDIIVeLfKghi((.xj8OPTPYPYZkPlOmno"4.F==*4&0PQUQZQZ[rQsPtuv$$S)!,00MM/x7OPTPYPYZqPrOst dii/00 r'   c                 "   t        |       }|||d}|r||d<   |r||d<   t        |j                  d      }|j                         D 	
ci c]  \  }	}
|	|
d    }}	}
i ||}t	        |      }|j                  |      }t        |      S c c}
}	w )zaBuild a UTM-tagged URL from parameters.

    Assumes parameters have already been validated.
    )
utm_source
utm_mediumutm_campaignutm_contentutm_termT)keep_blank_valuesr   )query)r   r   rN   itemsr   _replacer	   )r0   r+   r,   r-   r.   r/   rD   
utm_paramsexisting_qskvflat_existingmerged	new_query
new_parseds                  r(   build_utm_urlrY   w   s     d^F  "J
 $+
=!!%
: 6<<4@K9D9J9J9L$MAQ!W$MM$M -,,F&!Iy1Jj!! %Ns   
BrO   c           	         g }t        |       D ]  \  }}|j                  dd      }|j                  dd      }|j                  dd      }|j                  d      }|j                  d      }|j                  dd      }		 t        ||||	||       t        |	|||||	      }
|j	                  ||
d
d        |S # t
        $ r(}|j	                  |d
t        |      d       Y d
}~d
}~ww xY w)zProcess a list of batch items, returning results for each.

    Validation errors produce BatchResult with url=None, error=<message>.
    r+    r,   r-   r.   r/   r0   r+   r,   r-   r0   r.   r/   r0   r+   r,   r-   r.   r/   N)r6   r7   r8   )	enumerategetrF   rY   r>   r!   r1   )rO   resultsidxitemr+   r,   r-   r.   r/   r0   r7   excs               r(   process_batchrd      s   
 "$Gu% K	T(B'(B'88J+((9%xxxx#	K!  !C NNStDE3K: N  	KNNSCIJJ	Ks   ?7B::	C+C&&C+textc                 b    	 ddl }|j                  |        y# t        $ r Y yt        $ r Y yw xY w)zETry to copy text to clipboard via pyperclip. Returns True on success.r   NTF)	pyperclipcopyImportError	Exception)re   rg   s     r(   _try_copy_to_clipboardrk      s6    t  s    	...c                  `   t        j                  dt         j                        } | j                  dd       | j                  dd       | j                  dd	       | j                  d
d d       | j                  dd d       | j                  dd       | j                  ddd       | S )Nz6Build UTM-tagged URLs following team naming standards.)descriptionformatter_classz--sourcez$UTM source (required unless --batch))helpz--mediumz$UTM medium (required unless --batch)z
--campaignz&UTM campaign (required unless --batch)z	--contentzUTM content (optional))defaultro   z--termz#UTM term (optional, for search ads)z--basez/Base landing page URL (required unless --batch)z--batch	JSON_FILEz;Path to a JSON file containing a list of UTM parameter sets)metavarro   )argparseArgumentParserRawDescriptionHelpFormatteradd_argument)parsers    r(   _build_arg_parserrx      s    $$L <<F 
)OP

)OP
+ST
T8PQ
$5Z[
'XY
J  
 Mr'   argsc                    dD cg c]  }t        | |      r| }}|r#t        d|d    dt        j                         y	 t	        | j
                  | j                  | j                  | j                  | j                  | j                         t        | j                  | j
                  | j                  | j                  | j                  | j                  
      }t        |       t        |      rt        dt        j                         yc c}w # t        $ r(}t        d| t        j                         Y d	}~yd	}~ww xY w)z0Handle single URL generation. Returns exit code.)r+   r,   r-   r0   z	Error: --r   z# is required when not using --batchfile   r\   zValidation error:
Nr]   z(Copied to clipboard))getattrprintsysstderrrF   r+   r,   r-   r0   r.   r/   r!   rY   rk   )ry   fmissingrc   r7   s        r(   _run_singler      s
   B[Q'RVXYJZq[G[
|#FG	
 ;;;;]]LL	
 YY{{{{YYC 
#Jc"%CJJ7E \"  #C5)

;s#   DDAD 	EE  E	json_pathc                 d   	 t        | d      5 }t        j                  |      }ddd       t        t              st	        dt
        j                         y|}t        |      }d	}|D ]M  }|d
   }|d   *t	        d|dz    d|d    t
        j                         d}7t	        d|dz    d|d           O |rdS dS # 1 sw Y   xY w# t        $ r! t	        d|  t
        j                         Y yt        j                  $ r(}t	        d| t
        j                         Y d}~yd}~ww xY w)z>Handle batch URL generation from JSON file. Returns exit code.zutf-8)encodingNzError: batch file not found: r{   r}   z#Error: invalid JSON in batch file: z.Error: batch JSON must be an array of objects.Fr6   r8   [z	] ERROR: Tz] r7   r   )openjsonloadFileNotFoundErrorr   r   r   JSONDecodeError
isinstancelistrd   )	r   r   rawrc   rO   r`   	has_errorresultra   s	            r(   
_run_batchr     s-   )g. 	!))A,C	 c4 >SZZP EE"GI 2Wo'?&AcAgYiw'89

KIAcAgYb012 1 q 3	 	 -i[9

K 3C59

Ks3   C C C  C	C 'D/5D/D**D/c                      t               } | j                         }|j                  rt        |j                        }nt	        |      }t        j                  |       y )N)rx   
parse_argsbatchr   r   r   exit)rw   ry   	exit_codes      r(   mainr   .  sC     FDzztzz*	%	HHYr'   __main__)NN)r:   N)%r%   rs   r   r   typingr   r   urllib.parser   r   r   r   r	   r   r   r1   r2   r   r   r   
ValueErrorr!   r*   r5   rF   rY   rd   boolrk   rt   rx   	Namespacer9   r   r   r   r"   r&   r'   r(   <module>r      s     
 & O O
	c 	c   49  & c 6j 6	 )   "#1#1#1 #1 	#1
 c]#1 3-#1 
#1V """
"""" "" 	""
 c]"" 3-"" 	""J#i #T+-> #R
 
 
 822 &$h(( $S $N!# !# !>	 zF r'   