
    e;im                     8   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mZm	Z	m
Z
mZ d dlmZmZ d dlmZ d dl d dlmZ d dlmZmZmZmZmZmZ d dlmZ d dlZd dlmZm Z m!Z! d d	l"m#Z# d d
l$m%Z%m&Z&m'Z' d dl(m)Z) d dl*m+Z+ d dl,m-Z-m.Z. d dl/Z/d dl0Z0 e       Z1 e)         e       Z2 ejf                  ejh                          ejj                  e6      Z7 e+d      Z8defdZ9e1ju                  d      	 	 	 d<de	de;dz  de<dz  de<dz  fd       Z=e1ju                  d      de	fd       Z>dd eej~                        fde<dz  de;dz  defdZ@de;de;de<fdZAde;de;fd ZB ee2      fde	d!efd"ZCe1ju                  d#       eeC      fd$e;fd%       ZDe1j                  d&       eeC      fde<d'e;d$e;fd(       ZFe1j                  d)       eeC       eej~                        fd*e<d+e;d$e;defd,       ZGe1j                  d-       eeC      fd*e<d+e;d$e;fd.       ZHd*e<d+e;d$e;fd/ZIde;d$e;fd0ZJe1ju                  d1      de;de<fd2       ZKe1ju                  d3      d4 eeC      fd*e<d5e<d6eLde;fd7       ZM eej~                        fd*e;de<d'e;d8e;d9edefd:ZNd*e<de<de;d$e;fd;ZOy)=    N)	APIRouterDependsRequestHTTPExceptionstatus)
HTTPBearerHTTPAuthorizationCredentials)Session)*)CoursesUserAccessTokenLMSPlatform
DeploymentLMSCourseLog)Dict)datetimetimezone	timedelta)jsonable_encoder)JSONResponseFileResponseRedirectResponse)load_dotenv)Config)OAuth
OAuthError)levelz.envplatformc           	         t               }| j                  j                  d      }|j                  dt	        d      dk(  r| j
                  n
t	        d      t	        d      dk(  r| j                  n
t	        d      | d| dd	d
i       |S )N/canvas_dynamicENABLE_GLOBAL_KEYFalseCANVAS_CLIENT_IDCANVAS_CLIENT_SECRETz/login/oauth2/tokenz/login/oauth2/authscopeaf  url:GET|/api/v1/course_creation_accounts url:GET|/api/v1/courses url:GET|/api/v1/courses/:id url:GET|/api/v1/users/:user_id/courses url:GET|/api/v1/users/:id url:POST|/api/v1/accounts/:account_id/courses url:POST|/api/v1/courses/:course_id/files url:POST|/api/v1/courses/:course_id/content_migrations url:GET|/api/v1/courses/:course_id/content_migrations/:id)name	client_idclient_secretaccess_token_urlauthorize_urlclient_kwargs)r   tenant_domainrstripregisterconfigrest_client_idrest_client_secret)r   oauthbase_urls      ,/var/www/html/content_weaver/routers/user.pyget_oauth_clientr7   =   s    GE%%,,S1H	NN-34G-HG-S())Y_`rYs5;<O5PT[5[h11agh~a$:%89!
"45L
  * L    z/loginrequestr.   user_idlms_platform_idc                   K   	 t        j                         }|j                  t              j	                  t        j
                  |k(        j                         }|st        dddi      S t        |      }| j                  d      }|||d}t        j                  t        j                  |      j                               j                         }	t         j#                  d|||       t         j#                  d|       t         j#                  d	|	       |j$                  j'                  | ||	
       d {   S 7 # t(        $ r"}
t        ddt+        |
      i      cY d }
~
S d }
~
ww xY ww)N  errorzInvalid LMS platform IDstatus_codecontentauth)r.   r:   r;   zEInitiating login for tenant_domain=%s, user_id=%s, lms_platform_id=%szRedirect URI: %s	State: %s)state  )dbaseSessionLocalqueryr   filteridfirstr   r7   url_forbase64urlsafe_b64encodejsondumpsencodedecodeloggerinfor"   authorize_redirect	Exceptionstr)r9   r.   r:   r;   dbr   r4   redirect_uripayloadrD   es              r6   loginr\   Y   s3    H!88K(///0QRXXZC'C\9]^^ !*v.$1gZij((G)<)C)C)EFMMO[]jls  vE  	F&5K'))<<WlZ_<```` Hgs1v5FGGHsT   E,A'D> +E,,CD> 7D<8D> ;E,<D> >	E)E$E)E,$E))E,z/authc                 0
  K   t        d       | j                  j                  d      }|st        dddi      S 	 t	        j
                  |j                               j                         }t        j                  |      }|j                  d	      }|j                  d
      }|j                  d      }t        j                  d|       t        j                  d|||       t        j                  d|       t        j                         }|j!                  t"              j%                  t"        j&                  |k(        j)                         }	t+        |	      }
	 |
j,                  j/                  |        d {   }|| j0                  d<   t3        |d   |	j4                         d {   }|j!                  t"              j%                  t"        j&                  t7        |      k(        j)                         }|r*t        j8                  |      |_        |j=                          |r|d   d   nd }|| j0                  d<   |j!                  t>              j%                  t>        j@                  t7        |      k(        jC                  t>        j&                  jE                               j)                         }|j!                  tF              j%                  tF        jH                  t7        |      k(        jC                  tF        j&                  jE                               j)                         }|sat        tK        jL                               }tG        t7        |      |      }|jO                  |       |j=                          |j&                  }n|j&                  }|st?        t7        |      t7        |      t7        |      |d   |d   |j                  d      tQ        jR                         tU        |j                  dd            z         }|jO                  |       |j=                          nf|d   |_+        |j                  d      |_,        tQ        jR                         tU        |j                  dd            z   |_-        |j=                          d| d| d| }t]        |d       S # t        $ r#}t        ddt        |      d      cY d }~S d }~ww xY w7 h# t        $ r#}t        ddt        |      d      cY d }~S d }~ww xY w7 iw)!NzIn auth callbackrD   i  r>   zMissing state parameterr?   zInvalid state parameter)r>   detailsr.   r:   r;   rC   z3Tenant Domain: %s, User ID: %s, LMS Platform ID: %szB64 State: %szAuthorization failedstokenaccess_token)r`   r.   r   rJ   
account_id)platform_iddeployment_idrefresh_token
expires_in  seconds)rb   rc   r:   r_   rest_api_tokenrd   
expires_atz?https://answerous.contactous.com:9001/my-library?tenant_domain=	&user_id=&lms_platform_id=i.  )urlr@   )/printquery_paramsgetr   rM   urlsafe_b64decoderQ   rR   rO   loadsrV   rW   rS   rT   rF   rG   rH   r   rI   rJ   rK   r7   r"   authorize_access_tokensessionget_course_creation_accountsr.   intrP   accountscommitr   r:   order_bydescr   rb   uuiduuid4addr   utcnowr   ri   rd   rj   r   )r9   	state_b64
state_jsonrD   r[   r.   r:   r;   rX   r   r4   r_   rw   	plateformra   r`   
deploymentdeployment_codenew_deploymentrc   new_token_entryredirect_urls                         r6   rB   rB   u   s'    	
$$((1Ig?X5YZZn--i.>.>.@AHHJ


:& IIo.Mii	"Gii 12O
KKU#
KKE}V]_no
KK+				Bxx$++KNNo,MNTTVHX&El**AA'JJ  %GOOG1u^?Tfnf|f|}}H%,,[^^s??S-STZZ\I!ZZ1	
		&.!T"DJ %/GOOL!88K(//0C0Cs7|0ST]]^i^l^l^q^q^stzz|L*%,,Z-C-Cs?G[-[\eefpfsfsfxfxfz{  B  B  DJdjjl+#O,)
 	~
		&))"%O,m,L' 0))O4(9UYY|UY=Z+[[
 	
		&+N&;#%*YY%?""*//"3i		R^`dHe6f"f
		TUbTcclmtlu  vG  HW  GX  YL#>>}  n?Xehijek5lmmn K l?Vcfghci5jkkl ~s   8TAR2 CTS$ 9S!:S$ >,T*T+LT2	S;SSTST!S$ $	T-TTTTTemailrX   c           	      0  K   | rD|j                  t              j                  t        j                  | k(        j	                         }nE|rC|j                  t              j                  t        j
                  |k(        j	                         }r|j                  t              j                  t        j                  |j                  k(        j	                         }t        |      }|r|j                  t              j                  t        j                  |j                  k(        j                  t        j                  j                               j	                         }t        j                  d|j                         t        j                  d|j                         t        j                  d|j                         t        j                  d|r|j                  nd       |rk|j                  }|r%|j                   t#        j$                         k  r|j&                  s8d dt)        d       d|j*                   d	|j                   d
|j                   dS |j,                  j/                  d|j&                         d {   }t        j                  d|       |d   }|d   |_        d|v r
|d   |_        t#        j$                         t1        |j3                  dd            z   |_        |j5                          |d   |j3                  d      dS |r2||j                   t#        j$                         z
  j7                         dS d }nd }|s8|dt)        d       d|j*                   d	|j                   d
|j                   dS y 7 	w)NzUser: %szPlatform: %szAccess Token: %szAPI token: %szN/AzNo access tokenAPP_URLz/user/login?tenant_domain=rk   rl   )r`   r>   r   rd   )
grant_typerd   zRefreshed token: %sr`   re   rf   rg   )r`   re   )rH   r   rI   rJ   rK   r   r   rb   r7   r   r:   ry   rz   rS   rT   ri   rj   r   r~   rd   r1   r.   r"   fetch_access_tokenr   rp   rx   total_seconds)	r:   r   rX   userr   r4   access_token_entryr`   	new_tokens	            r6   validate_tokenr      s    
 xx~$$TWW%78>>@	xx~$$TZZ5%89??AHH[)004CSCS1STZZ\	 +!#+!6!=!=k>Q>QUYU\U\>\!]!f!fgrgugugzgzg|!}  "D  "D  "FKK
DGG,KK	5KK*,>,A,ABKKN`);)J)Jfkl!1@@$6$A$AHOODU$U-;;04?Pekluevdw  xR  S\  Sj  Sj  Rk  kt  uy  u|  u|  t}  }N  OX  O[  O[  N\  c]   ^  ^&+&:&:&M&M#2&8&F&F 'N ' !I KK 5yA#,^#<L8A.8Q&5&)3;D_;U*84<OO4E	ZcZgZghtvzZ{H|4|&1IIK,5n,EU^UbUbcoUpqq!,8I[IfIfiqixixizIz  IJ  IJ  IL  M  M#'L#(4?Pekluevdw  xR  S\  Sj  Sj  Rk  kt  uy  u|  u|  t}  }N  OX  O[  O[  N\  c]  ^  ^-!s   JN
ND	Nr`   ra   c                    K   dd|  i}t        j                  | d| d|      }|j                  dk7  r t        |j                  |j                        S |j                         S w)NAuthorizationBearer /api/v1/accounts/z/developer_keysheaders   httpxrp   r@   errorResponsetextrO   )r`   r.   ra   r   resps        r6   get_developer_keysr      so     ', 89G99&7
|?S]deD3II
 	
 99;s   A$A&c                    K   dd|  i}t        j                  | d|      }|j                  dk7  r t        |j                  |j                        S |j                         S w)Nr   r   z /api/v1/course_creation_accountsr   r   r   )r`   r.   r   r   s       r6   ru   ru      si     ', 89G99&FGQXYD3II
 	
 99;s   A!A#credentialsc                    K   |r|j                   S | j                  j                  di       j                  d      }|r|S t        dd      S w)Nr_   r`   Missing access token  )r   rt   rp   r   )r9   r   session_tokens      r6   get_current_tokenr     sT      &&&OO''488HM s   A
A/coursesr_   c                    K   dd|  i}t        j                  t        d       d|      }|j                  dk7  r!t	        |j                  |j
                        |j                         S w)Nr   r   CANVAS_BASE_URLz/api/v1/coursesr   r   r@   detail)r   rp   r1   r@   r   r   rO   )r_   r   r   s      r6   list_coursesr     sf     '% 12G99012/BGTD3(8(8KK99;s   A+A-z/create_coursecourse_namec                   K   |st        dd      S t        d       d|  d}dd| i}|dd	}t        j                         4 d {   }|j	                  |||
       d {   }d d d       d {    j
                  dk7  r t        |j                  |j
                        S |j                         S 7 o7 U7 G# 1 d {  7  sw Y   WxY ww)Nr   r   r   r   r   r   r   Fzcourse[name]zcourse[is_public]r   datar   )r   r1   r   AsyncClientpostr@   r   rO   )ra   r   r_   rm   r   r   clientresponses           r6   create_courser     s      "
 	

 %&''8H
MC'% 12G'eDD  " F FfS'EEF F s"MM  
 	

 ==?FEF F F Fs[   ACB6C
B<"B8#B<'C2B:3AC8B<:C<CCC
Cz/content_migration	course_id
imscc_pathc                 X  K   |st        dd      d}dd| i}t        d       d|  d	}|j                  t              j	                  t        j
                  |k(        j                         }|st        d
      S |j                  }|st        d      S t        |j                  dd      j                  dd            }	|	 d}
t        | ||       d {   }t        |       |
d|d   d   d}i }t        j                         4 d {   }|j                  |||       d {   }|j                   dk7  r!t        |j                   |j"                        |j%                         }t        |       d d d       d {    d||dS 7 7 7 i7 # 1 d {  7  sw Y    xY ww)Nr   r   r      r   r   r   /api/v1/courses//content_migrationszCourse not found.z+Course topic is required to generate IMSCC. _r!   z.imscccommon_cartridge_importerupload_info
upload_url)zpre_attachment[name]migration_typesettings[file_url]r   r   success)r   r   migration_info)r   r1   rH   r   rI   rJ   rK   r   topictruncate_filenamereplaceupload_file_to_canvasrn   r   r   r   r@   r   rO   )r   r   r_   rX   dbcourse_idr   init_urlcourser   article_titlefilenamer   	init_datar   r   	init_resps                   r6   content_migrationsr   =  s     4JKKK'% 12G*+,,<YKGZ[HXXg%%gjjK&?@FFHF
 	
 LLE9
 	
 &c3''S1M  'H-iUKKK	+ (5)-8FI
 N  "  f ++hi+PP	  C'I,A,A)..YY#..*n   ~^^# LP   sm   CF*F5F*FF*F'F(AF7F*FF*F*FF*F'FF'#F*z/upload_filesc                 `   K   |st        dd      t        | ||       d {   }d|dS 7 	w)Nr   r   r   r   r   r   )r   r   )r   r   r_   r   s       r6   upload_imsccr   l  s;      4JKK-iUKKK<< Ls    .,
.c                 ~  K   dd| i}t        d       d|  d}t        j                  j                  |      ddd}t	        j
                         4 d {   }|j                  |||	       d {   }|j                  d
k7  r&t        |j                        cd d d       d {    S |j                         }|d   }	|d   }
t        j                  |d      4 d {   }|j                          d {   }d d d       d {    |j                  |	|
di       d {   }|j                  dvr1t        |j                  |j                        cd d d       d {    S d d d       d {    ddS 7 )7 7 7 7 7 # 1 d {  7  sw Y   xY w7 {7 ?7 0# 1 d {  7  sw Y   @xY ww)Nr   r   r   r   z/fileszapplication/ziprename)r(   content_typeon_duplicater   r   r   upload_paramsrbfile)r   files)r         i/  r   r   )r1   ospathbasenamer   r   r   r@   r   r   rO   aiofilesopenread)r   r   r_   r   r   r   r   r   r   r   r   f	file_dataupload_resps                 r6   r   r   y  s    '% 12G*+,,<YKvNH  ,) I   "  f ++hi+PP	  C' 	    nn& !.
#O4==T2 	' 	'affhI	' 	'
 #KK
vW`NaKbb""*>>   ''/    8  <<9P	'&	' 	' 	' 	'
 c'    s   AF=E?F=F(2F3'F(F=&F'F=,4F( F!F($F8F	9F=F(F	F(&F"'1F(F=$F$%F=5F&6
F=F(F=F(	FF(F	FF	F($F=&F=(F:.F1/F:6F=c                 f  K   dd| i}|  d}t        j                         4 d {   }|j                  ||       d {   }d d d       d {    j                  dk7  r t	        |j
                  |j                        S |j                         S 7 n7 U7 G# 1 d {  7  sw Y   WxY ww)Nr   r   z/api/v1/users/selfr   r   )r   r   rp   r@   r   r   rO   )r.   r_   r   rm   r   r   s         r6   get_self_profiler     s     '% 12GO-
.C  " : :fC99: :s"MM  
 	
 ==?:9: : : :sW   %B1BB1BBBB1BAB1BB1B."B%#B.*B1z/find-account_idc                   K   dd|  i}t        |       t        d       d| d}t        j                         4 d {   }|j	                  ||       d {   }d d d       d {    j                          |j                         }|st        d      |d   d	   S 7 d7 K7 =# 1 d {  7  sw Y   MxY ww)
Nr   r   r   z/api/v1/users/r   r   zNo courses found for this user.r   ra   )rn   r1   r   r   rp   raise_for_statusrO   rV   )r`   r:   r   rm   r   r   coursess          r6   get_account_id_from_coursesr     s     ', 89G	'N%&'~gYh
GC  " : :fC99: :mmoG9::1:l##:9: : : :sW   <B>B#B>B)B%B)B>)B'*:B>%B)'B>)B;/B20B;7B>z/migration_statusFmigration_idwaitc                   K   dd| i}t        d       d|  d| }t        j                         4 d{   }	 |j                  ||       d{   }|j                  dk7  r!t        |j                  |j                  	      |j                         }|j                  d
      }	|j                  d      }
d}|
r:|j                  |
|       d{   }|j                  dk(  r|j                         }||	||d}|r|	dv r|cddd      d{    S t        j                  d       d{    7 7 7 e7 )7 # 1 d{  7  sw Y   yxY ww)z
    Check the status of a content migration in Canvas.
    If `wait=True`, polls the API every 3 seconds until the migration is finished.
    r   r   r   r   z/content_migrations/Nr   r   r   workflow_stateprogress_url)r   r   progressr   )	completedfailed   )
r1   r   r   rp   r@   r   r   rO   asynciosleep)r   r   r   r`   r   
status_urlr   r   	migrationr   r   r   progress_respresults                 r6   get_migration_statusr     sk     ', 89G,-..>ykI]^j]klJ  " # #f#ZZ
GZDDH##s*#0D0DX]][[ I&]]+;<N$==8L H&,jjwj&O O ,,3,113H !-"0$"+	F >-DD5# # #: --"""9 #D !P#: #;# # #s   3ED4ED>D6B D>D81D>ED:ED>.D</D>4E6D>8D>:E<D>>EEEEs3_imscc_urlr   c           
      	  K   |st        dddi      S dd| i}	 t        |j                  |       d{   }|d   }	|j                  t              j                  t        j                  | k(        j                         }
|
j                  rN|
j                  }|j                   d	| }t        j                         4 d{   }|j                  ||
       d{   }ddd      d{    j                  dk7  r#t        |j                  d|j                  i      S |j                  dk(  r|j                   d| d}|dd}t        j                         4 d{   }|j                  |||       d{   }ddd      d{    j                  dk7  r#t        |j                  d|j                  i      S |j                         }|d   }n|j                   d| d}|dd}t        j                         4 d{   }|j                  |||       d{   }ddd      d{    j                  dk7  r#t        |j                  d|j                  i      S |j                         }|d   }|j                   d	| d}d|d}t        j                         4 d{   }|j                  |||       d{   }ddd      d{    j                  dvr#t        |j                  d|j                  i      S |j                         }|j                  t              j                  t        j                  | k(        j                         }||_        |j!                          |j#                  |       t%        ||	|j                  |       d{    t'        |j(                  |t        j*                  t-        |            t        j*                  t-        |                  }|j/                  |       |j!                          d|||dS 7 7 h7 P7 C# 1 d{  7  sw Y   TxY w7 7 7 # 1 d{  7  sw Y   xY w7 ^7 E7 8# 1 d{  7  sw Y   IxY w7 7 7 # 1 d{  7  sw Y   xY w7 # t0        $ rA}t2        j5                  dt7        |             t        ddt7        |      i      cY d}~S d}~ww xY ww)zx
    1. Creates a Canvas course
    2. Runs a content migration using IMSCC from AWS S3 URL (no file upload needed)
    r   r>   r   r?   r   r   NrJ   r   r   r   r=   r   r   Fr   r   r   r   )r   r   )r   r   )r   lms_course_idcourse_infor   r   )r   new_course_idcourse_createdmigration_startedz&Error in create_and_migrate_course: %srE   )r   r   r.   rH   r   rI   r   rK   canvas_course_idr   r   rp   r@   r   r   rO   rx   refreshenroll_teacherr   rJ   rP   r   r}   rV   rS   r>   rW   )r   ra   r   r   r_   r   rX   r   self_profile_responsecanvas_user_idexisting_courser   get_course_details_urlr   course_responsecreate_course_urlcourse_datacreate_responsecreated_coursemigration_urlmigration_datamigration_responser   r   lms_course_logr[   s                             r6   create_and_migrate_courser    s     g?U5VWW'% 12GoH
 '7y7N7Nu&U U.t4 ((7+2273D3D	3QRXXZ+++<<M(1(?(?'@@PQ^P_%`"((* \ \f(.

3ISZ
(["[\ \**c1#0K0KV]_n_s_sUtuu**c1'0'>'>&??PQ[P\\d$e!$/).
 !,,. n n&,2KK8ISZalK,m&mOn n #..#5'O4O4OZacrcwcwYxyy,113N*40M $-#:#:";;LZLX` a +%*K
 ((* j jf(.4Ew]h(i"ij j **c1#0K0KV]_n_s_sUtuu,113N*40M %2233CM?Ref :".

 $$& 	h 	h&'-{{='Xf{'g!g	h 	h ));,>,J,JU\^p^u^uTvww+002 '"))'*;*;y*HIOOQ"/
		


6]NI<S<SUZ[[[%ii'

#3N#CD::&6~&FG	
 	~
		  *,!/	
 	
C !V\"[\ \ \ \n&mn n n n$j"ij j j j2	h!g	h 	h 	h 	h  	\"  H=s1vFgs1v5FGGHs  S7R* P)BR* P,R* P5P/ P5$R* /P205R* %S7&>R* $Q%R* (Q QQR* Q5R* S7AR* Q*R* Q3(Q-)Q3-R* 8Q095R* .S7/AR* 3R	4R* 7RRRR* R 4R* S7BR* +R(,A<R* (S7)R* ,R* /P52R* 5Q;P><Q	R* QR* Q'QQ'"	R* -Q30R* 3R9Q<:R	R* RR* R%RR% 	R* *	S436S/)S4*S7/S44S7c                   K   | d|  d}dd| i}|ddd}t        j                         4 d {   }|j                  |||       d {   }d d d       d {    j                  d	k7  r#t	        |j                  d
|j
                  i      S |j                         S 7 r7 X7 J# 1 d {  7  sw Y   ZxY ww)Nr   z/enrollmentsr   r   TeacherEnrollmentactive)zenrollment[user_id]zenrollment[type]zenrollment[enrollment_state]r   r   r>   r?   )r   r   r   r@   r   r   rO   )	r   r:   r.   r_   rm   r   r   r   r   s	            r6   r  r  |  s     O+I;l
CC'% 12G&/(0D   " B Bf[[gD[AAB B 3(8(87DIIBVWW99;BAB B B BsW   .B>B#B>B)B%B)B>B'AB>%B)'B>)B;/B20B;7B>)NNN)Pr   r{   rer   r   loggingfastapir   r   r   r   r   fastapi.securityr   r	   sqlalchemy.ormr
   dependencies.helperdb_config.databasedatabaserF   db_config.modelsr   r   r   r   r   r   typingr   r   r   r   r   fastapi.encodersr   fastapi.responsesr   r   r   dotenvr   starlette.configr   %authlib.integrations.starlette_clientr   r   rO   rM   routerbearerbasicConfigINFO	getLogger__name__rS   r1   r7   rp   rW   rv   r\   rB   get_dbr   r   ru   r   r   r   r   r   r   r   r   r   boolr   r  r   r8   r6   <module>r/     s   	  	    F F E " ! " ^ ^   2 2 - J J  # C  
 	   ',, '			8	$	:{ 8 H !%"&	HH:H 4ZH 4Z	H H6 GG? G? G?V %,,'/4Z/:/ 	/b	3 	s 	PS 		S 	 	 18-  J$+,=$> c    *+  : !" *+%,,'	+_+_+_ +_ 		+_ #+_\ _ *+
=
=
= 
= 
=&=3 &=C &= &=j# c  $C $# $  $    12	*#*#*# *# 	*# !*#h %,,'BHBHBH BH 	BH BH 	BHJC # c RU r8   