
    Bi[                        d dl mZmZmZmZ d dlmZmZ d dlZd dl	m	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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 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'm(Z( dZ)n# e*$ r dZ)Y nw xY w	 d dl+Z,dZ-n# e*$ r dZ-Y nw xY w ede.          Z/d Z0d Z1d Z2 ej3        dd          Z4 e5 ej3        dd                    Z6 ej3        d          Z7 ej3        d          Z8 ej3        dd          Z9d Z:d  Z;d! Z&d" Z<d+d#Z=e/>                    d$d%g&          d'             Z?e/>                    d(d)g&          d*             Z@dS ),    )	Blueprintrequestjsonifycurrent_app)MailMessageN)datetime)MIMEText)MIMEMultipart)MIMEBase)	MIMEImage)encoders)Header)
formataddr)encode_rfc2231)unquote_plus)text)db)validate_emailEmailNotValidErrorTFfeedbackc                     | dS t          |           }t          d          D ]-}	 t          |          }||k    r n|}# t          $ r Y  nw xY w|S )uV   URL query 스타일로 전달된 문자열을 안전하게 디코딩(+ 처리 포함).N    )strranger   	Exception)valuedecoded_
next_values       L/var/www/html/web/mlink/mlink_AI_Server/mlink-backend/src/routes/feedback.pydecode_query_like_valuer#   '   s|    }r%jjG1XX  	%g..JW$$ GG 	 	 	EE	Ns   A A  
AAc                 l    t          |                                                                           dv S )N)1trueyyeson)r   striplower)r   s    r"   
_is_truthyr,   7   s,    u::##%%)HHH    c                 b   	 t           j                            t          d          || |d          }t           j                                         dt          |j        pd          dfS # t          $ r:}t           j                                         ddt          |          fcY d}~S d}~ww xY w)u   
    userinf.USERID + COMPNO 기준으로 EMAIL 업데이트.
    Returns:
        (success: bool, updated_rows: int, error: str|None)
    z
                UPDATE mlinkdw.userinf
                SET EMAIL = :email
                WHERE USERID = :user_id
                  AND COMPNO = :compno
            )emailuser_idcompnoTr   NF)
r   sessionexecuter   commitintrowcountr   rollbackr   )r0   r1   r/   resultes        r"   %update_userinf_email_by_userid_compnor:   ;   s     ##    6BB
 
 	
S-A..44      

aQ s   A'A* *
B.4/B)#B.)B.SMTP_SERVERzsmtp.gmail.com	SMTP_PORT587SMTP_USERNAMESMTP_PASSWORDSMTP_FROM_EMAILznoreply@sellmall.co.krc                    | rt          | t                    sdS t          rC	 t          | d          }d|j        fS # t
          $ r}dt          |          fcY d}~S d}~ww xY wd}t          j        ||           rd| fS dS )u   
    1단계: 이메일 형식 검사 (email-validator 사용)
    
    Args:
        email: 검증할 이메일 주소
        
    Returns:
        tuple: (성공 여부, 오류 메시지 또는 정규화된 이메일)
    )Fu1   이메일 주소가 입력되지 않았습니다.F)check_deliverabilityTNz0^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$Fu.   이메일 형식이 올바르지 않습니다.)
isinstancer   EMAIL_VALIDATOR_AVAILABLEemail_validator_validater/   r   rematch)r/   validr9   patterns       r"   validate_email_formatrK   Y   s      J
5#.. JII ! K	!,UOOOE$$! 	! 	! 	!#a&&=      	! F8GU## 	K;JJs   < 
A!AA!A!c                    | rd| vrdS |                      d          d         }t          r	 t          j                            |d          }t          |          dk    rdS n# t          j        j        t          j        j        t          j        j        f$ rx 	 t          j                            |d          }t          |          dk    rY dS n=# t          j        j        t          j        j        t          j        j        f$ r Y Y dS w xY wY nt          $ r
}Y d	}~nd	}~ww xY w	 t          j        |           dS # t          j        $ r Y d
S t          $ r}ddt          |           fcY d	}~S d	}~ww xY w)u   
    2단계: 도메인 DNS 검사 (MX 레코드 또는 A 레코드 확인)
    
    Args:
        email: 검증할 이메일 주소
        
    Returns:
        tuple: (성공 여부, 오류 메시지)
    @rC      MXr   TNA)FuI   도메인이 존재하지 않거나 이메일을 받을 수 없습니다.N)Fu'   도메인이 존재하지 않습니다.Fu3   도메인 검증 중 오류가 발생했습니다: )splitDNS_AVAILABLEdnsresolverresolvelenNXDOMAINNoAnswerTimeoutr   socketgethostbynamegaierrorr   )r/   domain
mx_records	a_recordsr9   s        r"   validate_email_domainra   v   s     GCu$$FF[[a F  	--fd;;J:""!z #%s|'<cl>RS 	j 	j 	jjL00==	y>>A%%%:: &L)3<+@#,BVW j j jiiiij &%  	 	 	DDDD	
UV$$$z? @ @ @??? U U UTCPQFFTTTTTTTTTUs_   3A" "5D!3CD!5D	D!D		D!	D!D!%D; ;E4	E4E/)E4/E4c                     t          |           \  }}|sd|fS t          |t                    r|n| }t          |          \  }}|sd|pdfS dS )u   
    이메일 주소 전체 검증 (형식 + DNS)
    
    Args:
        email: 검증할 이메일 주소
        
    Returns:
        tuple: (성공 여부, 오류 메시지)
    Fu'   도메인 검증에 실패했습니다.rP   )rK   rD   r   ra   )r/   format_validformat_resultnormalized_emailsuccess	error_msgs         r"   r   r      sx     #8">">L- $m## )3=#(F(FQ}}E //?@@GY MiL#LLL:r-   c                 R    g dd}fd}t          j        |||           }|fS )u   
    HTML에서 base64 이미지를 추출하여 파일로 변환
    
    Returns:
        tuple: (수정된 HTML, 이미지 파일 리스트)
    r   zI(<img[^>]*src=["\']?)data:image/([^;]+);base64,([^"\'>\s]+)(["\']?[^>]*>)c                    |                      d          }|                      d          }|                      d          }|                      d          }	 t          j        |          }	dz  	d	 d| }d	 dt          j                    j        d d          }
                    ||d	| |d
           | d| | S # t          $ r1}t          d|            |                      d          cY d }~S d }~ww xY w)NrN   r         image_.r       zimage/)filenamedatacontent_typecidzcid:u    Base64 이미지 추출 실패: r   )	groupbase64	b64decodeuuiduuid4hexappendr   print)rH   prefix
image_typebase64_datasuffix
image_dataro   rr   r9   image_counterimagess            r"   replace_imagez,extract_base64_images.<locals>.replace_image   s@   Q[[^^
kk!nnQ	")+66J QM<<<
<<HA=AA4:<<+;BQB+?AACMM$" 5 5 5	     //#/v/// 	" 	" 	"8Q88999;;q>>!!!!!!	"s   A,C 
C?&C:4C?:C?)rG   sub)html_contentrJ   r   modified_htmlr   r   s       @@r"   extract_base64_imagesr      sV     FM [G" " " " " ": F7M<@@M&  r-   c                    	 dddddddd}|                      d	d
          }|                     ||          }t          d          }|                      dd          }t          t          t	          dd                    t
          f          |d<   t          |d<   |r
||d<   ||d<   d| dt          j                    	                    d           }t	          |d          |d<   d|v r|d= t          d          }|                      dd          }	|                      d|	          }
t          |	          \  }}d| d| d}d| d |
 d!}t          |d"d          }t          |d#d          }|                    |           |                    |           |                    |           |D ]}t          |d$         |d%                             d&          d'         (          }|                    d)d*|d+          d,           |                    d-d.|d/         0           |                    |           |rt!          |          D ]\  }}|r|j        rt%          d1d2          }|                    |                                           t+          j        |           |                    d-d3dd|j        f0           |                    |           t/          j        t2          t4                    }|                                 |                    t          t:                     d|v r|d= 	 t          g}|r|                    |           |                    |t          |4          }tA          |tB                    rQt          |v rHtE          d5t           d6|                     t                                |#                                 d7S n># tH          $ r1}tE          d8|            |#                                 Y d9}~d7S d9}~ww xY w|#                                 d:S # tH          $ r}tE          d8|            Y d9}~d7S d9}~ww xY w);u*   피드백을 관리자 이메일로 전송u   기능 요청u   문제 보고u   전화번호 인증u   회원 및 결제 문제u   계정 문제u*   공개적으로 공유할 수 없습니다u   기타)feature_request
bug_reportphone_verificationmembership_paymentaccount_issuescannot_shareotherproblemTyper   mixedr/   r   u   M-Link 피드백 시스템zutf-8FromToCczReply-Tou   [피드백] z - z%Y-%m-%d %H:%MSubjectBccalternativedescriptiondescriptionTextud  
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <style>
                body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
                .container { max-width: 800px; margin: 0 auto; padding: 20px; }
                .header { background-color: #4CAF50; color: white; padding: 10px 20px; text-align: center; }
                .header h1 { margin: 0; font-size: 1.2em; line-height: 1.2; }
                .content { padding: 20px; background-color: #f9f9f9; }
                .info-section { margin: 20px 0; padding: 15px; background-color: white; border-left: 4px solid #4CAF50; }
                .info-label { font-weight: bold; color: #4CAF50; }
                .description { margin-top: 10px; padding: 15px; background-color: white; border: 1px solid #ddd; }
                .description-content { word-wrap: break-word; }
                .footer { padding: 20px; text-align: center; color: #666; font-size: 12px; }
            </style>
        </head>
        <body>
            <div class="container">
                <div class="header">
                    <h1>새로운 피드백이 접수되었습니다</h1>
                </div>
                <div class="content">
                    <div class="info-section">
                        <div><span class="info-label">문의 유형:</span> u   </div>
                    </div>
                    <div class="description">
                        <div class="info-label">문제 설명:</div>
                        <div class="description-content">u   </div>
                    </div>
                </div>
                <div class="footer">
                    <p>© 2024 M-Link. All rights reserved.</p>
                </div>
            </div>
        </body>
        </html>
        u[   
새로운 피드백이 접수되었습니다.

===== 사용자 정보 =====
문의유형: u   

===== 문제 설명 =====
z	
        plainhtmlrp   rq   /rN   )_subtypez
Content-ID<rr   >zContent-Dispositioninlinero   )ro   applicationzoctet-stream
attachment)	from_addrto_addrsu#   관리자 수신자 전달 실패: z	, reason=Fu   이메일 전송 오류: NT)%getr   r   r   r   r@   r>   r	   nowstrftimer   r
   attachr   rR   
add_header	enumeratero   r   set_payloadreadr   encode_base64smtplibSMTPr;   r<   starttlsloginr?   ry   send_messagerD   dictrz   quitr   )feedback_dataattachmentsproblem_type_labelsproblem_type_rawproblem_type_labelmsg
user_emailsubjectmsg_bodyr   description_textdescription_with_cidextracted_images	html_body	text_body	text_part	html_partimgimg_partir   partserver
recipientsrefusedr9   s                             r"   send_feedback_emailr      s   n  /)"7"<-H
 
 ),,]GDD0445EGWXX G$$ #&&w33
 !#f-I7&S&S"T"TVe!fggF!D	  	)"CI(C
O d!3cc8O8OP`8a8acc11I C<<E
 !// $''r::(,,->LL 2G{1S1S..&2 N`3& &: ;O;& & &	R "	    	 Y99	Y88	 		"""	""" 	

8 $ 	! 	!C Vs>7J7P7PQT7U7UVW7XYYYH.?#e*.?.?.?@@@ 5x#j/ZZZJJx      	%!*;!7!7 
% 
%: 	%*"5 	%#M>BBD$$Z__%6%6777*4000OO-$")2z/B!C $   
 JJt$$$ k955]M222 C<<E
	'J .!!*---))#Q[)\\G'4(( ]g-E-EpMppT[T_T_`mTnTnppqqqu 	 	 	1a11222KKMMM55555	
 	t   -!--...uuuuusC   L3P- 6B O P- 
P#&P	P- PP- -
Q7QQz/api/feedback/submitPOST)methodsc                  
   	 ddl } |                     t                    }t          j        pd}|                    d| d|dz  dd           ddlm} 	 t          j        }n# |$ r}t          j
                            d	d
          }t          |t                    r|dz  nd}|                    d| d|dz  dd| d           t          dd|dz  dd| di          dfcY d}~S d}~wt           $ r@}|                    dt#          |          j         dt%          |                       d}~ww xY wt          j                            d          }t          j                            d          }	t          j                            d          }
t'          t          j                            dd                    }t'          t          j                            dd                    }t'          t          j                            dd                    }t'          t          j                            dd                    }t'          t          j                            dd                    }t)          t          j                            dd                     }|r|	r|
st          dd!i          d"fS t+          |
          \  }}|st          d|pd#i          d"fS |r|r|s|                    d$| d%| d&           n	 t          |          }n+# t,          $ r |                    d'| d&           d}Y nw xY w|tt1          |
          d(k    rt          dd)i          d"fS t3          |||
          \  }}}|st          dd*| i          d+fS |dk    r|                    d,| d%|            d-}d.}g }d}t          j        D ]}|                    d/          rt          j        |         }|r|j        r|                    dd0           |                                }|                    d           ||k    r$t          dd1|dz   d2|j         d&i          d"fc S ||z  }||k    rt          dd3|dz   d4i          d"fc S |                    |           ||	|
||||||tA          j!                    "                                d5
}tG          ||          }|rt          d6|d7         d8          d9fS t          dd:i          d+fS # t           $ r/}tI          d;|            t          dd<i          d+fcY d}~S d}~ww xY w)=u   피드백 제출 처리r   Nu   피드백 요청 크기: z bytes (i   z.2fz MB))RequestEntityTooLargeMAX_CONTENT_LENGTHznot setunknownu   Flask 요청 크기 초과: zMB), Flask MAX_CONTENT_LENGTH: MBerrorul   요청 크기가 너무 큽니다. 파일 크기를 줄이거나 파일 개수를 줄여주세요. (현재: u   MB, 최대: zMB)i  u+   요청 데이터 접근 중 예외 발생: z: r   r   r/   sourcer   supportUserIdsupportCompnosupportUserNamesupportUserEmailupdateMemberEmailfalseu+   모든 필수 필드를 입력해주세요.i  u.   이메일 주소가 올바르지 않습니다.uQ   회원 이메일 업데이트 스킵: user_id/compno 파라미터 없음 (USERID=z	, COMPNO=)u9   회원 이메일 업데이트 스킵: compno 값 오류 (   u4   이메일 길이가 너무 깁니다. (최대 30자)u#   회원 정보 업데이트 실패: i  u4   회원 이메일 업데이트 대상 없음: USERID=i   i  attachment_r   u8   파일 크기가 너무 큽니다. 각 파일은 최대 u%   MB까지 업로드 가능합니다. (u.   전체 파일 크기가 너무 큽니다. 총 u#   MB까지 업로드 가능합니다.)
r   r   r/   r   r   r   r   r   r   	timestampu3   피드백이 성공적으로 전송되었습니다.r   )messager      uM   이메일 전송에 실패했습니다. 잠시 후 다시 시도해주세요.u   피드백 처리 오류: u2   피드백 처리 중 오류가 발생했습니다.)%logging	getLogger__name__r   content_lengthinfowerkzeug.exceptionsr   formr   configr   rD   r5   r   r   r   typer   r#   r,   r   
ValueErrorwarningrW   r:   files
startswithro   seektellry   r	   r   	isoformatr   rz   ) r   loggerr   r   r    r9   max_sizemax_size_mbproblem_typer   r/   r   support_user_idsupport_compno_rawsupport_user_namesupport_user_emailupdate_member_emailemail_validemail_errorsupport_compnookupdated_rowsupdate_errorMAX_FILE_SIZEMAX_TOTAL_SIZEr   
total_sizekeyfile	file_sizer   
email_sents                                    r"   submit_feedbackr    sv   A]""8,, /41nnnZcHdnnnnooo 	>=====	AA$ 	 	 	")--.BINNH4>x4M4M\(i00S\KLL  a  a  aP^bkPl  a  a  a  R]  a  a  a  b  b  b  G  IW  [d  Ie  G  G  G  wB  G  G  G          	 	 	LLctAwwGWcc[^_`[a[accddd	
 |''66l&&}55  ))()9)9(B)G)GHH1',2B2B?TV2W2WXX4W\5E5EoWY5Z5Z[[3GL4D4DEVXZ4[4[\\4W\5E5EFXZ\5]5]^^()9)9:Mw)W)WXX  	Z; 	Ze 	ZG%RSTTVYYY $2%#8#8 [ 	lG[%d4deffhkkk
  	" *< O.O O9KO O O   
*%();%<%<NN! * * *NN#t_q#t#t#tuuu%)NNN* "-5zzB&1g'hiiknnn5Z'6 62Bl  m&1eWc1e1e'fggilll#q((Q&5Q Q@NQ Q   ))
= 	- 	-C~~m,, -}S) -DM -IIaOOO $		IIIaLLL =00&#  &t`mr{`|  &t  &t  dh  dq  &t  &t  &t(             )+J!N22&#  &YVdirVs  &Y  &Y  &Y(              &&t,,, (&,/0 2!4!1133
 
 )DD
 	|P*;7     
 G%tuvvx{{{ ] ] ]-!--...!UVWWY\\\\\\\\]s   AT A" !T "D6'A<C)#D6$T )D66;D11D66FT =(T &#T 
L T %M?T M*T -,T CT *&T A1T T 
U $U
U
Uz/api/feedback/healthGETc                      t          dt          t          ot                    t	          j                                                    d          dfS )u!   피드백 서비스 상태 확인healthy)statussmtp_configuredr   r   )r   boolr>   r?   r	   r   r    r-   r"   feedback_healthr     sR      ?-@@\^^--//    		 r-   )N)Aflaskr   r   r   r   
flask_mailr   r   osr	   r   r   rG   rt   rv   r[   email.mime.textr
   email.mime.multipartr   email.mime.baser   email.mime.imager   r/   r   email.headerr   email.utilsr   r   urllib.parser   
sqlalchemyr   src.models.dbr   email_validatorr   rF   r   rE   ImportErrordns.resolverrT   rS   r   feedback_bpr#   r,   r:   getenvr;   r5   r<   r>   r?   r@   rK   ra   r   r   router  r  r  r-   r"   <module>r"     s`   : : : : : : : : : : : : $ $ $ $ $ $ $ $ 				         				    $ $ $ $ $ $ . . . . . . $ $ $ $ $ $ & & & & & &             " " " " " " & & & & & & % % % % % %            &^^^^^^^^ $ & & & %&MM   MMM i
H--   I I I     . bi'788C		+u--..		/**	/**")-/GHHK K K:(U (U (UT  2-! -! -!^p p p pd )F8<<C] C] =<C]J )E7;;  <;  s$   :
B BBB B$#B$