From a06e9c36335a3bb324cdb9d4c70fa45f16467582 Mon Sep 17 00:00:00 2001 From: Robin COuret Date: Fri, 6 Mar 2026 16:31:40 +0100 Subject: [PATCH] add user restriction --- .../app/__pycache__/config.cpython-311.pyc | Bin 1507 -> 1507 bytes .../api/v1/__pycache__/auth.cpython-311.pyc | Bin 2640 -> 2875 bytes .../v1/__pycache__/knowledges.cpython-311.pyc | Bin 3236 -> 3733 bytes .../v1/__pycache__/metrics.cpython-311.pyc | Bin 737 -> 1167 bytes server/src/app/api/v1/auth.py | 28 +++-- server/src/app/api/v1/knowledges.py | 82 +++++++------ server/src/app/api/v1/metrics.py | 10 +- .../__pycache__/dependancies.cpython-311.pyc | Bin 2503 -> 2232 bytes .../auth/__pycache__/security.cpython-311.pyc | Bin 2096 -> 2649 bytes server/src/app/auth/dependancies.py | 30 +++-- server/src/app/auth/security.py | 11 +- server/src/app/config.py | 2 +- .../__pycache__/knowledge.cpython-311.pyc | Bin 3426 -> 3044 bytes .../data/__pycache__/metric.cpython-311.pyc | Bin 2735 -> 2739 bytes .../data/__pycache__/question.cpython-311.pyc | Bin 2688 -> 2692 bytes .../app/data/__pycache__/user.cpython-311.pyc | Bin 3350 -> 3361 bytes server/src/app/data/knowledge.py | 72 +++++++----- server/src/app/data/metric.py | 24 ++-- server/src/app/data/question.py | 16 +-- server/src/app/data/user.py | 4 +- .../__pycache__/knowledge.cpython-311.pyc | Bin 1011 -> 1654 bytes .../models/__pycache__/metric.cpython-311.pyc | Bin 1041 -> 1639 bytes .../__pycache__/question.cpython-311.pyc | Bin 1204 -> 1461 bytes .../models/__pycache__/user.cpython-311.pyc | Bin 732 -> 1465 bytes server/src/app/models/knowledge.py | 11 +- server/src/app/models/metric.py | 9 ++ server/src/app/models/question.py | 4 + server/src/app/models/user.py | 11 +- user-interface/package-lock.json | 108 ++++++------------ user-interface/package.json | 1 + .../src/components/CollectKnowledge.vue | 17 +-- .../src/components/EvaluateQuestion.vue | 23 ++-- .../src/components/GenerateQuestion.vue | 4 +- user-interface/src/router/index.ts | 6 + user-interface/src/services/apiAxios.ts | 26 +++++ user-interface/src/types/types.d.ts | 17 ++- user-interface/src/views/AuthView.vue | 58 ++++++++++ 37 files changed, 359 insertions(+), 215 deletions(-) create mode 100644 user-interface/src/services/apiAxios.ts create mode 100644 user-interface/src/views/AuthView.vue diff --git a/server/src/app/__pycache__/config.cpython-311.pyc b/server/src/app/__pycache__/config.cpython-311.pyc index eed296b05fdc5a9760a3015ae13bb0c574e701af..d2c593173d788d9019d2708598978a5e31110ee0 100644 GIT binary patch delta 50 zcmaFN{g|6~IWI340}yoHT9vtUBX1THkRen>Q_>_;)?{A}R0qt67BLk~@#SDO zY7T0HW=xCua;Q3Fs+wxXwYV>btHWkOOJKwyA{e3}mGPdu!y)t-MwhfCNj^+DGgwuT zF|dO{2ct_yWb4`K5rrg{1S9&Dumh`)dpe}0!7;-eN02di%rQnV$-<^Q8FcD+Bsuhw z_le%NQ^-({dB=&o#2Ldc`HUEe+bExOe#g^`*h}A-Y1qqe-PA4X^BOg7kx=Eb7+{d}KKtYGVp1=^?f^|xk zDqnblt(UE}V4+$oSAP1Hdw{Xx=)(EbAf$xG0P;K?hRGAy26WW}m@C<$%=&77+2}wE*3u|J5l5)ke;m{(BTr_lBFC7&L zOavHT!uZnz_z+?A4YL2IUq^Qir6xlCsis*w06vFg2YVbscUVxL47|tn_sk}?<(?KH z2!G_)AN?M-qkVQxhL@UnkM9q6kF#0&4r!e`7KC5tq3Xg%YgtxJR;Dq%3Y9cg$9jn& zMxLW-2tYFcz@LK2i!STdGBJwv!w$)d6f)dIzLv5x(-5^5C6vrP zyzb^Mv=bNI#Knyp2Xb`#yqi7y%V#vN_p&?E0q03*v>9Qn!t927cI;(LSftdT6?@gs6lJf# zi}xFpmWiob{@d_^wANrPEYxe3P0uiE9-g4bgVcQnEIITI2CVJ<#QhV#V8&`jqe?E( zOR&h=*xGZx4Np(M(?WgUQ#9Fn)whq{YrX1olHxUGd^fQhZi!QEamp2^oV((p!iB%i zY-aAyw(*dQhn(NU!kh|Bhr>A42_jHuH?#LYY2&nu(;ZI2sqGIs2&NbCoJU-yr+u;P GU+X_6F=>kc delta 1215 zcmZ`%&1(}u6rb7Mq`TQ{cH1V~uT*Po(I8T^7p+!W4@OI|qC{muC3MGD%r-i^QPGx` zDz^1j=AeiNPgQ9Tg5W_f{S!72L{@}e1W!`&AP9nQHncQV=i@i;y?O69^XAQa(@!Q| zXj%+GyYutawMUV~L^FQ7xTkm8Q7i=`8`)AJ=BSn$%8^3c(JU>LqlJW{Te@RdMyS^n z>YWCw!D+M_LtQQ;os^ZrNI*ogl`*^$Tfzt}!>l&TBn*e{4K!Wy6Lt>u)tL>`z*OxBCdC$NSz>AyLFu8DWMr0 zNI5rL)lo|F9=TEim0cIkn?Zz&E_den1Jce7 zXy+SofUnSJ(3;xhOHH&J45I?TMw39e5A%n|4AC6NwFS5jAMKua9z7NxN>hR-ZbTt8 zi6(^=yaZIsn{-p67un(=)^bfrlM+0)a5^K zXA6{y0V$t~=ioMxZobd*0M)!1*jEgIffXFHVE%e;C)lom@K zp@DRx=z6q^o3vt{f21q!=s0mmAdV3)5Mi@g8-7um;lOJVChJ;r#fgGbpz{acT zF0(mhpl{em{}^ki%dZ_DQO2(wtS)vk-tI@>y*E#qVbC)sMOXCMW_x`1)>dK3xrT-$8h{Dm?GYieDPz={CAi%2kQ JETK6}>JO#L5SIV| diff --git a/server/src/app/api/v1/__pycache__/knowledges.cpython-311.pyc b/server/src/app/api/v1/__pycache__/knowledges.cpython-311.pyc index d9d22c361d9132d39f66a8988e12c142dcadbde0..5d042c4373fd1aeb06f8e50501943fbaa8b4b8fb 100644 GIT binary patch literal 3733 zcmc&0OKcm*b!NHziKIk|q)3U9Ok1ucx-pqVahnve+ zrCqxeAQ%CvLl3z{N1j}|_Q6LTd(5d=0(&495FnuFq3DHy+lxFgLBLNYI>@DJ#W6v-`FW~F7T#Uq;acea=%D!Pr*-tQ;200?} z4DZ|(rftT%f*kl#d`J_>Ou+Ie4O;SzGPEl>?R!o-)#B~)ogGHj{3w26KMa$P!LQ{h2{duMOs6^x< zF(>TlHA+A}aCmOkiOQs;9A>bYEn^s;?MMv8Ph*_se+w7U@yn<_xdbMzDC->UIPtB z!wzoXTj)97NMRaarWR-f2095qg$jX^$v2lW_o`)*q1A1rlKEV!R7;9tmBL7V)Qj^ zpeMlr?#%BMdB+qKxxh|hH4!H4hOf^77`oVYn2a9xzU`U@x^Ex4fnVZh!1IFf@wOvqZflNELl|+Qqv3#L5jG%T-GypJgHSge zb*h*m4|tKXs!vZbkYvCQASKc{Hs|hUmBS46VpAT7Zf0vRO3x~$t4BZ=0LwVkWdO`D z)6KMT=Hr8kv2sJ-D(FGE9h8lryqi6YFSVxI@ns{v3?A;fkbh1WXSvay%#3<-86zKxf$EXWQ8zZ8cJ{S<4~3kf_Y8F~$Uab`!< z;9a#^Lu?2yog;DQ)L1$lw}x}rVHo{!fxFDL@n-$AD&1COnN-rr+xJM45^e?}C+(n0 zDryp{Us8G~DJ5yUM3Q%_G^qh`jaDBjGSFt%(r~GR81aNJ<>0e^nIW?%ZT>? zK!hdIE&A%ycH**;xXe?pi=0l^;dtUOK5xW7=!C!ML>F6eJ@R4KEl#+;MF9TAKo^N# z*T2V5GzD=OSvDfeyPtOgGhHM&&v3AZ55tM(gI8HSywVP@7~z#Y&!H!_?`eBZ8=liT z?;T%U7vnr^PY%s5;h6vb(1aS`+@L>zvrtwW=^_J508-8of6@zVYl3Zwqi*xsZc|z6 z^c^+M3i*JOSoX6|y#wHX;iS;~zS0gZ8NsEY^16{qnl9~eO{o+qOJLJ|SAuY^DU_X$ zvI090snhTnrQtD3OOOd^ng1S0m4ZT4>S4@rYrhPsP*T%&mi3Ax`*Sv9BQ%ypc(j{S z)-J2{1N^M2@<)^#+l&s8*&>+HdBT`yEdut6Dg~mZOH!p+mx^TIM}TLU>7u>g9S8hP zm=0B={BbfJ3KV*=Rt3ZY6U)+uGM79@JXrZ-_QvxmT(w>zEA%RCu@^^G;H~L8FvcA; zs}J`Mx}^WNeuRFc5BDRqs-M(5=skV7AEDpq@9szFvVKxOLf7@-4v)!LcyD@tc7I&= zF1EdkhIet-b%fo2n0Y$0x6#H411GwIfTzBC+zdC1&7z)OX`fp)&aLXFSB=b+V^{Dko|M5@TnRO$xuAg5wl3Bjj z2TWkn;_L}bJWcHVx{X22Y*%pNx&2kBV|eZ$^_Oek#J-8?H>GxV+sJO~Yum<83Vg2* zn7lcQvpdcX2=eqms*TSZ_seiO-oCj;bULP=l MaFiZrAI(GYKSmRBIsgCw literal 3236 zcmb_d&1)M+6rb5$$&xMEt4OkC%d%y~)Y+twXxu{&t)ZnoxFx2o3k`zSsM?Jpst;#& zoiwQoCIsR`4!OlgpWGPd&_ASyUD$(I2pCEay{Wjp9Fh!S!FpWDhQEp?doR>Pw@9+Xrkw9suqjXjo*KIe!73xGkZnfG*#n4o~_;UU0_Ku-3Tzt`L-*0GY zO@l?`s~t@@>g|>ia^x!0Kw;}gkMB&uhB{d5&SY@Ik$1M$po*+&4Q<$nBJ{QH_D|BC zss2IU4&X?6bA79(wKP^iOwPCuMF$zlsMPd_vC?3(=EC17w8F392QL*kNr{`E(tJME@cV(lO5t-XA zWPzqIbk;)83xNc$n@L?a4dP*mX`xi9?p%vami2208HPRPr>M@ zGe;B5@SRG)(IZ@;BYaA}E9{B}+U&QE*r6}!5k$cWMgniUlHvVBVcn5}b|`szxg$UY z6gHsZL_E~|iQwTdz}O^`Fp@YBB{YaPC+;ceTdZ>5p?BFbi0B9j-?sm_UWN39*$N0; zL&Gsu)PTB)Wlt+08J4oOD3J zH^#50pcF=qv+PM>y{}g_z1XO1v8=!ullE}1ujy-RXtu%D8m8SGv1 zt{Lp7%t9$)W|D z7KTj(l`eZ+SBamiSoEq*ul9s6ojpkQ2n+*)V6S=Hp6uW7ibWNhDm@`Y)6W1N3@Na+D4F4 zsQ-Z;ds16H^w^_+Ko1)TR0aw{>7h4UZ=U*Q*F-~o%)I&Dd-LAR`(}49n@uB-y}zIB z1qq>_!f1>wAL7z->pk}I3CtC&h`%TAB0nyQ;JQ?ac$y{=|zG465F zu5RiWNr=ist>VMfE=K48W+G;WWJd><* zjKX$E%~oPmcH=NO2C6hHSL%#WFD%ysQ6-555L7~|8ober3y;C|1eJ*uT0C<#tpe}R zksd%Y%(D`xZ4`DGL#TmXb}Yc1tOh>ByO47r@?zPL!c-eWp483RhTM>W6KSy^bNyAF z2BGbHWt;G{M=2@W9-*(fA{r_vOockEU#J10dO?9VBd~Zrt|o2qzJwieK~JDSa0KN1 zfwAhl)L{M#+cOp{&v$HV+;VEGmH{WMQDy|JVpz2rOxswSXfsxu^i^qCCQu1ezgcb_} zTn*Q2wpV3>C!Sidf)I{m;-*Z{&U0{+BHX0t`h+?`F=;KKK=8?Lwl|1JY=;FUJl~F3 z^>DRF;*ZJlDmD$6_^Y_elJ88Z`9a9#AY^efk%5 zQyF7?jP69;;~3qIt{W$4D!OhQqw%PF{J--=yRntu$?xcqHrmuiTiWQRdV*6QhTaWr zEjMw#h4ZJ9j0blzrwEoW^It1R(?`?MljY`IsWn%MW=gI5&*Rvo`XeK0u$_77jvN06 Dp^q@| literal 737 zcmY*VziZn-6uu|Pl9kjMS~4iX;K4&(h($AGD521?LriHmbtqTgB@sxGxKjctDVR{& zK$mXG*eR_^|CA0gcrcm_r9(FtZ|Tx^l9fb{_v_yG`0l&=)@Updw0}Q`ehUcsr4FU( zi)Q{2n{&blgMftK0jORJv{3i-yw?LGta&vc8sWf{q0-^hZrPklD{(JbxJ-CS2gb+~JAv`$NbYeZgtM--P)f zvx+Kl$4Ka&d}q6hiJO^4*S`^o#Olc^=50*pB)Nl~kgCx4Z~`a@dZLEA9ZlF+vX$a~ zwh$mS9JX55Pu%?|^AUhznPWzDwg6!*`D!mnysQab^~j zqJdO(47rMFKz=tLecu{2H^ Token: user = authenticate_user(form_data.username, form_data.password) if not user: @@ -24,15 +24,19 @@ async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]) -> T access_token = create_access_token(data={"sub": user.username}) return Token(access_token=access_token, token_type="bearer") -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/v1/token") - -@router.get("/user") +@router.get("/me") async def user(current_user: Annotated[str, Depends(get_current_user)]): return current_user -@router.post("/user") -async def create(username, password): - hashed_password = await hash_password(password) - user = User(username = username, hashed_password = hashed_password) +@router.post("/register") +async def create(user_data: UserCreate): + if get_user_by_username(user_data.username): + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Username already registered" + ) + + hashed_password = hash_password(user_data.plain_password) + user = User(username = user_data.username, hashed_password = hashed_password) created_user = create_user(user) return created_user \ No newline at end of file diff --git a/server/src/app/api/v1/knowledges.py b/server/src/app/api/v1/knowledges.py index 4efbe11..3ba5824 100644 --- a/server/src/app/api/v1/knowledges.py +++ b/server/src/app/api/v1/knowledges.py @@ -1,48 +1,47 @@ from typing import Annotated -from fastapi import APIRouter +from fastapi import APIRouter, Depends, HTTPException, status -from src.app.models.knowledge import Knowledge +from src.app.auth.dependancies import get_current_user + +from src.app.models.knowledge import Knowledge, KnowledgeCreate from src.app.models.question import Question -from src.app.data.knowledge import create_knowledge, read_knowledges, read_knowledge, update_knowledge, delete_knowledge -from src.app.data.question import read_questions as read_questions_crud, create_question +from src.app.data.knowledge import create_knowledge, get_knowledges_by_user, get_knowledge_by_id +#from src.app.data.knowledge update_knowledge, delete_knowledge +from src.app.data.question import get_questions, create_question from src.app.services.language_generation import questions_generation #Added in __ini__ router = APIRouter(tags=["knowledges"]) +@router.get("/knowledges/") +def read(current_user: Annotated[str, Depends(get_current_user)]): + knowledges = get_knowledges_by_user(current_user) + return knowledges + +@router.get("/knowledges/{id}") +def read(id: int, current_user: Annotated[str, Depends(get_current_user)]): + knowledge = get_knowledge_by_id(id, current_user) + return knowledge + @router.post("/knowledges/") -def create(knowledge: Knowledge): +def create(knowledge_data: KnowledgeCreate, current_user: Annotated[str, Depends(get_current_user)]): + knowledge = Knowledge(content=knowledge_data.content, uri=knowledge_data.uri, user=current_user) created_knowledge = create_knowledge(knowledge) # if created_knowledge is None: # raise NotFoundException("Failed to create knowledge") return created_knowledge -@router.get("/knowledges/") -def read(): - knowledges = read_knowledges() - return knowledges - -@router.get("/knowledges/{id}") -def read(id: int): - knowledge = read_knowledge(id) - return knowledge - -#TODO: adapt with correct pattern -@router.post("/knowledges/{id}") -def update(id: int, content: str, uri: str): - knowledge = update_knowledge(id, content, uri) - return knowledge - -@router.delete("/knowledges/{id}") -def delete(id: int): - knowledge = delete_knowledge(id) - return knowledge - @router.post("/knowledges/{id}/questions") -def create_questions(id: int): - knowledge = read_knowledge(id) +def generate_questions(id: int, current_user: Annotated[str, Depends(get_current_user)]): + knowledge: Knowledge = get_knowledge_by_id(id, current_user) + if not knowledge: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Forbidden. The requested knowledge is not available for the provided ID.", + headers={"WWW-Authenticate": "Bearer"}, + ) questions_raw = questions_generation(knowledge) for q in questions_raw: question = Question(question = q, knowledge=knowledge) @@ -50,9 +49,24 @@ def create_questions(id: int): return questions_raw @router.get("/knowledges/{id}/questions") -def read_questions(id: int): - knowledge: Knowledge = read_knowledge(id) - #questions = knowledge.questions - #TODO : refacto ? - questions = read_questions_crud(knowledge) - return questions \ No newline at end of file +def read_questions(id: int, current_user: Annotated[str, Depends(get_current_user)]): + knowledge: Knowledge = get_knowledge_by_id(id, current_user) + if not knowledge: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Forbidden. The requested knowledge is not available for the provided ID.", + headers={"WWW-Authenticate": "Bearer"}, + ) + questions = get_questions(knowledge) + return questions + +#TODO: adapt with correct pattern +# @router.post("/knowledges/{id}") +# def update(id: int, content: str, uri: str): +# knowledge = update_knowledge(id, content, uri) +# return knowledge + +# @router.delete("/knowledges/{id}") +# def delete(id: int): +# knowledge = delete_knowledge(id) +# return knowledge \ No newline at end of file diff --git a/server/src/app/api/v1/metrics.py b/server/src/app/api/v1/metrics.py index e1127b7..de06eee 100644 --- a/server/src/app/api/v1/metrics.py +++ b/server/src/app/api/v1/metrics.py @@ -1,11 +1,15 @@ -from fastapi import APIRouter +from typing import Annotated +from fastapi import APIRouter, Depends -from src.app.models.metric import Metric +from src.app.models.metric import Metric, MetricCreate from src.app.data.metric import create_metric +from src.app.auth.dependancies import get_current_user + router = APIRouter(tags=["metrics"]) @router.post("/metrics/") -def create(metric: Metric): +def create(metric_data: MetricCreate, current_user: Annotated[str, Depends(get_current_user)]): + metric: Metric = Metric(question_id = metric_data.question_id, need_index = metric_data.need_index, user = current_user) created_metric: Metric = create_metric(metric) return created_metric diff --git a/server/src/app/auth/__pycache__/dependancies.cpython-311.pyc b/server/src/app/auth/__pycache__/dependancies.cpython-311.pyc index 369a6408de32678b5d53ef77c2b27317e16a52e3..cab1575cdf58b285aece2a680a5df62832872f06 100644 GIT binary patch delta 1284 zcmZ`&&2Jk;6rb5$d)MB0KjPXB2`!X{!wO=PlmsCqNYts~g49y#NbPbk8}B$a?Aq4s zx+v6DEa-^~idKS3TyhG5=FkI&{sV{}dRR+)uvV%R4jd|RC=y)S3o~oS!U&$;%)EJD zGxK|Ien~%2rSDUzBp~$7Pd_$(j_pY^ul-JT-vSeu&;mBpA*3>6F*d8SHm7rTOpir6 z*4n$8-Q_I7PUwk96SI=GsEd&tx2Eiro+2`D3YKKcx*W*~OR-g5wWsxI2pE8PGkGK) zKmhKMF(f@r^oawqxp$%h`YCe?Wy}=H)HqYR!|7R5Mi6D*BCae-PbR1_FN_0C1&Jg? zB_TO;`Wn#EPpHki2yfIh7;>8q!el+QjoeCy$d#>~Xl)ucdP1*6jEQpVQ`B5HTtj0* z`6j}R+D@fyIL>D+Y=%=Kg-e}2pDq~fM&agS!RWa4g4Nn?c+a5^linj{?o5j03+1}u z)R8$(ps`pXdaQae)|{OoqD+Q!g-kv0SbcTB-d78OTJXMPE#^<){lTv1U7lD+)CFej zD1N{YxX2jNZKligm@fPRcA0(7+v76V_(_azvt4%R;fg0w0Cd?S;a`57OK&}*F89g! zVdOF;n0*XM}%|K zL7~O0b}&ZGVNtP0)U+p@@4Rlju=`gM$a8m>53l>uN?%$Dq?O*rfR}o^1L>SEoI94Y zU*G!b*4^d4d^V8J_DTa@_W9h<_*k9YFZt?1UtI{)h2DF=i7y?_2HL7GuJy&WKwRss z4|uWH9iJAaAir)4&HJwaP literal 2503 zcmZ`)O=ufO6rR=UXQj2Q|2TH!;Ko0xN+Lz3kThuxj_ukZjS~_%KYI}y?b=#*R}!rs6_PPJJ`7WXowrvomkreDh}a zeeXT}7z_pww8ej)D@iXxf09MJ!J4)`jzQ=dl90rxNMi(sA+k$#X{^9fnN{7INAPG~ z!K?WMAJw^4PV) zMH$b7Dsrv#NK_RmSN>cs&0t(6IQN21@!XPZ19xSM!yF zYn}u%VnxY3%4Q5=3=kX@7O?7Y#7arjWQS|R3$Bh65ORae!n5}^49}3!@ijs<)a|{e zu9{0v8b?lV9FY%g)|l>dz$|kI8NQ>4nroTdOxq?{+3r}vc z>+d%r!&YRtK5g@%CSpB_S6ts8T=I7=xqiRFjal57$&J~e_*!+BA6UP%k+ViWYVemW z{&EvBo&?>2qxI{1U=leV%BADQvQfpQ!V!WHN#rl#*_#IKb;KMa@F-Qw9S2K{P`zTegX7XnV@|yGS}DsD=z$Oj@|*cKPVmcIe&l9J32yv%wu)(ltrm?m&6U*4VnM z#(cpT#H9zV#_srz;oPP0Ff!t81VSSSL%|{^SI}ej0a{^SXo3ROLj^2Lgm+QZpM>w-yLXms??Ilk4&SN-`9fKe z9j_!CqM|y!qAW@fgd~kcb*YRMqo_HoUVWHiXr!isnD`VE7di=2Tk;=X$mSR3Cl_*a zH*a4PW~Lo>dBq?WiDgVUa{_l}rf$#V^4Dh`K$-e%7J#|A8x9Ml1NRbhgfp5wtxLT4 z6t#ckTk>+JhWRSus#+E$igf}s=JFEM8%!LjllOxJf`(5LD`8Tg3RR5339Upp59&bz z{TYV8;0MW&Ozp-8toQ{xl(8ej8~4p{y6JNddjCc+{6hxQ-QNuOJR`f&#CIR8FZ?iP zja>Zok~OtpM(;MFcdh8%HJ=?Dcy{I6E9=!pY}AU4u5mUWGx<|?^sL!)b~kZ)i!&41 zMj~q^vTK30!2T|uB#AU~IM}_zCO6zT3)bKTlg~Ezti@*`Q+<5B)>kyy|9CNv9V|LmEm$x==1HDoZUAyvAw;{wgpjW{z)B1pX@u_Q2{0 zrQrj8T9?6Pim{4GIyhbtFO^H<*iX=-MAHi-r#qbJltCxfzE=b4RXt4#8s-T+(%vCF zwe+-D`t(9k)2oJzSiGIU<4A)jw zc>-Sn9VtHgLm0uA3}d5Vv%9}UNwd4#Xxw~vw^7#Y?lyYQ?C$@k3DoJ&M(51#{t}It z-Q7lGW_P#IX|ucAXw>ZPFT*2dcx0<=h9?@~2`fBN58Bb8Z_~D@)8*@iQ=?`b+0`GCw`(}DA|^zu z-HdF&$EQUrY`gx8FK2OW03x`o4$sI~jproJ$0xMYMg?FoeyY9SR|J&klWsI=V_t<# zgux8+vgC7;pO|)|s1tI^*8^93d6(S4Ra3f2JM8e3LNmhSMts0jmp#s0 z!6sbKV^K6A!V9d;cR~D6{N1?d$+snD-g+|vTaDS}A{_wN7MRf(n5$?}(~Zj4QuWr(dk0@x3ww`#s-Ib? zv-y*a`BL*^sku;U&ZT;Vb#wWpubEAY2pg5Z#_ko$b7D>`5}=osmZB`=yf(5IJx`C4 zw|JC5<97pPuaD1})$NH1#RoxgSvD^F%w_TWeKuX*4BPv;72h;#-L(qqmmxpZ5qsDr zk0~ie@P0U}L`EXP6a9P``drFSsVUKE%M(fyT)z1c;!+h#eZQ?kK}ctOHp)kVlRb{c z!NNN*?xC&oTVVe4_0Y!owO=pZml}$Xr5Lv2XDM+cZ(yhkm^(x*56fzKeeB(-H)9I^ I*Qjg#0c~&prT_o{ delta 584 zcmY+BPixdb7{+Ik$!xOOWY_J6Z4pE$2oYTH&r$jTym}}MMOic1Z6uQ{@1(9Ld-2qx zbMWS^mC}pQPvAEYPc>Je;6W&O^W;0x9vqUF-}_AF$@?VVCZ9%!AET&Ga6S2XTI@1H zzT4({@qh5^1HyYEiKHb_R8VT!DIMhsS2@B_Ot4OKOHXmZJ7#51`NCI$2vlG6JIyOY z5#m{14pbx}xEj*bqXn1!w@loSVb>2AOb)Og%P8MiI5I|_ zNbf00hd-=CN?Tv&O;c1$eV))~bn2rDfh{&@>cGHqWR9F&Zv$~?E}hT!M@TK(pX>dU z!UP*lvD}8S)g!AvU(K~%*C1hvT5^8j9?`_J+iq2_!G5dOJ!mpuX6*^OWxjg%==dGq z^6ui+rn$vmJ=#P{lQ!0n&E~7sEUT+Uu>==ouvUP7fc&-Mb6D2Z1L&E`pC0}n0=Dt7 zHh#HoX8G$ZUo}NtX$bAvE{CfdXxWRpF2N@325y-wvIgudrv&UEUAEu;V^zz8GT(uR msM*ju!FuIVN-xOvm+mq_5Slx|8_Lab(8R=}H?M5zeEtBw<$GuV diff --git a/server/src/app/auth/dependancies.py b/server/src/app/auth/dependancies.py index 7affdb4..3761dff 100644 --- a/server/src/app/auth/dependancies.py +++ b/server/src/app/auth/dependancies.py @@ -1,23 +1,19 @@ -from src.app.config import settings - from typing import Annotated from fastapi import Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer from argon2 import PasswordHasher from argon2 import PasswordHasher -import jwt -from jwt.exceptions import InvalidTokenError from src.app.models.user import User -from src.app.data.user import get_user +from src.app.data.user import get_user_by_username from .schemas import TokenData -from .security import verify_password +from .security import verify_password, verify_token -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/token") +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login") password_hasher = PasswordHasher() def authenticate_user(username: str, password: str): - user: User = get_user(username) + user: User = get_user_by_username(username) if not user: # Add timing to prevent attack password_hasher.hash(password) @@ -32,17 +28,19 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]) -> Use detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) - try: - payload = jwt.decode(token, settings.SECRET_KEY, algorithm=settings.ALGORITHM) - username = payload.get("sub") - if username is None: - raise credentials_exception - token_data = TokenData(username=username) - except InvalidTokenError: + payload = verify_token(token, token_type="access") + if payload is None: raise credentials_exception - user = get_user(username=token_data.username) + + username = payload.get("sub") + if username is None: + raise credentials_exception + token_data = TokenData(username=username) + + user = get_user_by_username(username=token_data.username) if user is None: raise credentials_exception + return user diff --git a/server/src/app/auth/security.py b/server/src/app/auth/security.py index f180f94..5cc3c27 100644 --- a/server/src/app/auth/security.py +++ b/server/src/app/auth/security.py @@ -1,4 +1,5 @@ from src.app.config import settings +from typing import Optional from datetime import timedelta, datetime, timezone from argon2 import PasswordHasher from argon2.exceptions import ( @@ -10,6 +11,7 @@ import jwt from jwt.exceptions import InvalidTokenError + password_hasher = PasswordHasher() def verify_password(plain_password: str, hashed_password: str) -> bool: @@ -28,6 +30,11 @@ def create_access_token(data: dict): encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM) return encoded_jwt -#def create_refresh_token(data: dict) -> str: +def verify_token(token: str, token_type: str = "access") -> Optional[dict]: + try: + payload = jwt.decode(jwt = token, key = settings.SECRET_KEY, algorithms = [settings.ALGORITHM]) + return payload + except InvalidTokenError: + return None -#def verify_token(token: str, token_type: str = "access") -> Optional[dict]: \ No newline at end of file +#def create_refresh_token(data: dict) -> str: \ No newline at end of file diff --git a/server/src/app/config.py b/server/src/app/config.py index 254a45a..9595cb1 100644 --- a/server/src/app/config.py +++ b/server/src/app/config.py @@ -12,7 +12,7 @@ class Settings(BaseSettings): # Security ORIGIN: str = Field('http://localhost:5173', env='ORIGIN') SECRET_KEY : str = Field('random_string', env='SECRET_KEY') - ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 + ACCESS_TOKEN_EXPIRE_MINUTES: int = 240 ALGORITHM: str = "HS256" class Config: diff --git a/server/src/app/data/__pycache__/knowledge.cpython-311.pyc b/server/src/app/data/__pycache__/knowledge.cpython-311.pyc index 0376b554841a46967472cb514ace06ef73cfc3f1..9f0aa661dc59ad6ebec2c3ff9b37f9b9a00a9652 100644 GIT binary patch literal 3044 zcmc&$PfQ$T6#u^YvophgVL%EEAW(HuWMhm6jn=?Lsii#-4_(rbWoLkGXLs@Y1}Vvs zc<2F%i55%Xpvj&vwVHS`Jqqd7WS49rnWTw{7rkLHhV6?rI=0@y*PeH}Adu z{{Ft-+pn9O8wkkCZ{H;U(g^t#Kgyz%jH3lGwunt^>XHoKj+nuw_?G zMPd;NXW7rWVGN;(uJtfv)>-R{kQFtWV08f+M;3#vF-3WHG-84n4=HIbf zOY*fThx246?MJxdItkCBzVUuKv+O$dyaOM~2i#%sjyUQ0WZLnY?v#TwN!wSJAexX$ zQ@~dQ9vPmaaf;LNK$pckmA3=_M?vg$vMPCMIgbzzTPaC6Ggn@&a#*}i=id(6$&x#w z$51qAIZG>ugxQ52b_2=FsxS$Nj!f^TwXXvZT3l4L933frlT@c&h+;tMZ zI+tYJvmy+~#0*Tq$GvzoXk&D7#qXGRyqUl=GrIzVV_ncT&Vl~` z>SOZMXxr@ir2o_YLn5og+wVR#d%k+3U|uSkmwq-c@0*vuoA~zH<7@jP@BL&IuTJM@ z62+Oh{i|~YbG~TKuNepJ7q&(=Mz&W9?N+hfTGI~9-mS@v$@@1R+*mUXHE2|{EYu&^ z$DgPwzIxX2@o_!(p-!4Q^NPvaVd$G^g7JY-1xxvyu#~3=YlLP1VReAXS|Q}iao4pJ_8iy@7manG zw;{j;=ZIuP8tcSJO9(NX^?=iahkpU83M@k*u+&3B=f$n*jp_Th9^6`MKqL&|rk*H7 z!Vn_il&=!4SS2LXWC0So@=7PinQdMf>z8-?m9Zgh_eBai5ilA=10W28_Z&c=X9Gfg z5QMlc*!(QHjiV7#;<^z3u1Z<@4_qfzflAKGXW}~LoS;(5psLGutO>@>T2M8kLX5F) zP?jnPt_o=E0)#kD9}!l9SXUTg$V$kY>>{M~Vm>nUze26dOU045e>9&w57bmJCyM68 z{{+DkG8!IN<=%zBZQQMI`bw$=tenU^?G@uf-(%AiAA1=l@;9YPRu=#O literal 3426 zcmb_eO=ufO6rR~xX?HE_r>^YUv1==K5+mYDls1rrG)18ygwRm%DGDJd+OeZnf1O!3 zF(}YO4sHlEO=GM>3qG`IOnS(%mmZXJ4-%*#76O4nX>SV2!Q|98EA6hAGK^N-U zgCK|X&@zgL{}!JS$ENZTEz_dT!e=-7^+8@PhEd+fF!LKWoo#Rxpb8~WOP z&^&asmY?i&dxZWG;g`d4AKw4a`38)Nfd%v~;_@}=I=O(Z!O~nn7>){BMmzX?+{eW5 zOaU-SM%PV$wp1wO3{zorg;9PrE-_UY72f%!TnrwIy*!@0S}M>aD_zMIlOJb_rF<^) zP9|Tznn`lXzMw40SvHv|my>$N$RwQ~ohYxHku0MbgI;!&ECPdyZ{Xhne2JcDkpgy?=Y}KcgexoTc8!= z@NWV7+3_U0@B3qo=)q?6;D**3o7!5syHs6ojK!N{@eQRlKC^Z4?!|8|-Mh3g^8b@! zqArhjNO3YXM{09&YC)+T!hq(eGsDX{eQx-l;0XdZq#>7AvX@tO zm)9h#)UcL!hpGun)K0ZSX%@JvWAoUUuwBUu~Qe#o^w4MfGZ6~x+{`GEW?r?66!F`%hrOGQI) zlB}^@wl^F*TlfCMZWCH64)in?rdkUyE57C z2^TQaZmY=NfB<2iY>P14*SrD2@)J?Nul0{OB)4RnTbj!)wh!K8af`hzq*(z00iyzf z0Fb9F(z$jK4?6S{zX9lHM~}!_88S|9a*2V%G+g|501pKfE4lPju(g<|&z!EFsh)Xs zw)y_)4Xvq8wdUsQlSitgN*-uG2RF3a!Kbg2mBR4OHnQQFkX|@l*RV&j$ZbE=V~cdN z(iqHaGj;sbG&iaR@H{1AvD|#5XlCly$3=JL?T~ ze^cFGSNHF&TSP*d5(P&GM3pins+1m`YuzJtOO;o<@(wM0sYOy-lv9V5S^@)}k4H>p zB?CFRoMU3nrpiCh7fLYU&ZZPQ%AADyEdljg!ZPrLlgv6vK4P0id3PlPHJ=D9Rv~BQ zYm?-Ph86uy!VSh^!YcmY4tfrVtW^I}JprSy<>^Vb1UgYm^FIL~1z_Al({=CJLI>)D z&Zj6*_ns}ZQ1_l~*@wrswKjs=UI_W{gwS;%M8NY+_}RkK3!@sC-fJVcJpvE7{nF`K Tat}<%cuF|J?Uld|!&LtPu_>IV diff --git a/server/src/app/data/__pycache__/metric.cpython-311.pyc b/server/src/app/data/__pycache__/metric.cpython-311.pyc index 10f169aa0514b82050609558d7b418f2f96072d6..4af2578fe0ec4ae77053db71e652029ad552b0ed 100644 GIT binary patch delta 374 zcmZ24x>=NWIWI340}%XqvnsQ4B5#;HXBtxqTMJ7RR|F7a}ftffW0`ixHvOE?-pAwP$o0E z7^GHV@;^o!aRH#(c!+3xQe}K*N|69ij(ze1wpE*DnTr`2c_&X~F%aTLC@U_K2CCqh ze1+vWYY`uiIq||5)*_I@Cm&~2)dGnW@dAlrCLp1pP{a?UZt*4;r6!i7LTxHi0E!7u z_G3Cf*^B+31UHZecJD2=l+>KmlGGwOkO;SUUOf{&F^Xoea{KnR`SV_}q>5j=S!m*nIHT&%1`T0koRPW@ls delta 352 zcmdlix?YrbIWI340}w0|UY=PykvB}9C5GXZ&%cQD$B@Fo|f zCYGeeLv$4h0L9rS*R!49yp^e#k&$n*CX0bE4^T-8R7G)-G*AiOJyNtd-0~G9Xbt5CO8i7^Fx+L7|8rNZ;Z{GPFnmC?YzUn`zZ# zKlXnTazGx~h+AwasX3`7sYN^>5&6w29082{U^jwYaf>-KuVnIJ&gRJlT+&*sjKUun X-~=BtqtFcF4-7yGo#2|>&7}bVp~YAj diff --git a/server/src/app/data/__pycache__/question.cpython-311.pyc b/server/src/app/data/__pycache__/question.cpython-311.pyc index 4ca09b30b121e5bd93bb8acacb9c7ad499173e6a..d424742f3da59486116f90e17ec188661cd5708c 100644 GIT binary patch delta 388 zcmZn=Z4u>N&dbZi00f(+ugYwi$m=D~p2n2I+QJgWk;2x(5XG6op2`9g;Q)$orLd&3 zPb{;YJe75qf!k58(M&rB)e2gq6USx&EMN&XD z+>=kSoMJ8F1u`cuWEGou=^kqlCy29|QB?;dTEqh+ikX0ff%i7eUc_1G o%FHOT!1)6MkU}T8SQ$k>Fu(~uRz{H-86W|mN>qYxas-zK0GJZ4l*M&dbZi00cA6tjuhi$m=D~lE#$6+QJgWp2F6`5XF(gp2`Un;Q)$of!Gtv zY&kg!OH+$WGV}8$Ph=9C?7@1Ec_pLYWNkK8A$Fiix7dqQi;ID>#Y{ln z$$uGFP4;I0Cm{>u6|sVpv8ANuq?V)>af3wUHYakJG4g|*3wF*e=FGg3$;&tkCp&UU dYq2tleqewTe9Vj@Gm1Yj04a2WYjO;i1^`)AVWI#4 diff --git a/server/src/app/data/__pycache__/user.cpython-311.pyc b/server/src/app/data/__pycache__/user.cpython-311.pyc index d8f751b2fd857851aacbf3ffcddd884553da1fb8..4dcb68aa8f455956dee3a3d6f3bcc77d1fc949f6 100644 GIT binary patch delta 66 zcmbOxwNQ$8IWI340}$-Ly(%+)Bkv3rQIYi2lK9f%)S~#LN-&+5n47wJ9Sa8&3nx%& R^KQ1stV|1xCokYB0|3<$7R&$u delta 55 zcmZ1|HBE|lIWI340}xoPTA3NLk#`0QCr5f}NqlK>YSHFhEF4U%Tt%sgDVvY6J!WN^ KP&|1xPZ%}*Og6rbH4cQN6D@RWB0}i=V%Ae5VuH=I?r${~ZMnq0I_08B=K+}%j{5&)7bN2mqf0>-j zA{hSh?~bb@^q1URj)~FY!h^-nh$5=FsHIt2OSklvVHuh{(_P$3St+$P+=*7&N^3|* ztBB&C5KS?iPMoDrFhZv=hr=?J-UNMyrA`dc!5rx_G`oSSxxeMMYKYVq4s)q6Hy*7$ z^eJ;i{u}1nq2qhOuG6k+BGa$~rc|)OTLI(EQ7HA78f`9gOt$m z#tB^f6y|VPn5C%pG>s6Opm-S$m8E``I)MnMFh_Q2W`f1U|5#*{MS5hBr6y#{+{l(= zd77QO3@UTx#t}7|r;}$>Hy+UBmHGWUwi%!E~8J_ z`es!ZY04hk9XAxYHg{S!KOlSTKzm?`h)k>j@{fN zZNJ@trm#RvHSM5jQ%0awEM&rb)M0__mdNanR>9MB2f9>qs7SBe-&nc-;Pa}%B@IRH zvCo^OB$)%Y#xf@Q4gv@i+r>=q+LWC>~cwByQko{;^H?G80u zl8oo2m*K!|3WV66=Z8Z!5yGdGDhN3*NJ~i_J|oYt>%i%4xi3ioa-iSP1t5B}T;KIu ztj_%%$E!cIJ>PZgk8QWTYuBN&?-{QLyji!~?K)J&+@Lowt$_$37CONEDx?-~dY{sH6X7dVX zKta_+)xY&>ioXjk{Eme8B$Or0OIVPg>XEtlhnFB5A4ui3HcU=OYth=XwSk$7R-@Ht zFr(F>yYyVIW`!B-yQ;xMmSGuC_Eebd18RGr)8z7dDvH2{8nB@@WJ68TSMg~`1y#uP z;@+6cLq31T??D9l0Sf*AI5#v+8=z0(|CRxIKfW#lREe+4IX1Nw?Hs)wd*(47>Ru^} Z*H`UkbS;05{tZ3nl{|g@7L|Hv{{W~^q^D*IWI340}#{;EYI|2oX98PU%M#>(Tg;hxCAawF;}i4p@=Fp+GV}9_lcR&P-$sSs$G#hkjn_f#hH_LvZ{H1U}0rU YVEn*X+6aWAK diff --git a/server/src/app/models/__pycache__/metric.cpython-311.pyc b/server/src/app/models/__pycache__/metric.cpython-311.pyc index 4557d95e695ecb998bccf6b93531d32423657e20..5ec8f65c93dd093b25a6f061ad98e39d146d2daa 100644 GIT binary patch delta 940 zcmZuv&u^J?C0B0q&954fvC?rd`_a)&zp>Y3^ddLWQ4?Y;? zgc}b)d_s5+JrDyQ#)3S!LG(~d>Nf&+@|IZJ;i9C|p8BvVtV(fb8#vptge;6o@a-Lb zoc(NlK3GwR@Nmk*+;`;vcX{FEwB{#7_;|#Q(}lT^2>+RxT!nQwg$AZcRsN@7f=k<4dFNIW2dn03mDsceB@f^mw+cbVb};Q=97 zFSI5qvRJq)MZO}Wd(KOcx2}8TJnk1m&=3|7;s^-@x0@womq&orRtlgod~!&-(@}?^ zby&1JHPgs7a?imVxxo@xy{?CPs`a!~#@|8WIV3|s#e3@RGoIhB6bsU4=RAoAD1L9o zl7)1BcQ@^pSZTa5sbYG;!d9w4;E0ptj#$*=8>1-*CK;^uXzcSi0a!xj7 zieS>@p1hn%OPd?0>=tuoUdb)~`1r)Uy!?_xkWt0)@kRVVsUnauMM5BgZ8A5r8$Sn# z2_isFDQ=#ez}zI=;NRe1Bn6WQ(PX^ET9TNQlj^6*KADSEYO*n_q%Ipwx=0el0;`q= zvVL*c FbpWrzP0RoQ diff --git a/server/src/app/models/__pycache__/question.cpython-311.pyc b/server/src/app/models/__pycache__/question.cpython-311.pyc index b8b9649dc8acd99c24dbdd65509b7922cc2e006e..18c887a02e3ebed165fa5aae3d17c240c763c526 100644 GIT binary patch delta 601 zcmdnOxs{u5IWI340}$-%UzNF$X(FElW6(r(RihM!6y_YZT=pn-Mg}GZcZL*}7KRko zRHhWRHSEh+7#LOqF$6?$q;Lc?XmU<0GFH%Jyu}h)oLZC&lLXPMP|jx=#)*56MKLj? zGN&-62&AyD;aJ8DGzo|yAc`-QHHEQ?oq-{hEk)1}*=w+td0yE-)3>J`xrr_iNCM`yu z$<<8qx`IIcMIbj8iGT<;5FrjEZn5NK7MB!BfcTOi0_ZM=$vc=_`8h#65CPIv{9!T= z^YY{eQt~rYSFr5RJdt@pD&nG4#1*NC2KSEO2_~IU7g!>I=pswR4N27*G8>{VNIG7W zbi5+z*x=HkGC`zM`vQw25M2b5Kt_=g%z_YLfU=e(Cgr61X>v}!z--}sOSrfwSue4m zKrc5xB{ip559A-P)4(n&QUqxQ>sJP{esS0Um6hhC+7)R4xu6g%?wxGNVi9|TLFED} d`oO})=*0Me0Xx}IF{1<`_Yth(3l4Q)y8&;mjU@m8 delta 344 zcmdnWy@iu+IWI340}#{-EYJMFIFV0+(QTr-su~l6J3|U{3quM^DpLyU8n$ID3=FG* z7y_c$QrLqTG&v^L8A~L?1VJ<_l=Jxn!^Dfn*ismQsstu~Wb|R=oNUJw%qTQ@5|av( zCg0=>Oj?ZGlYcYG%LxFr6oK>=34;hW5FrL6Zn5NK7MDzRXLjZ10EvMJkOPWWO`grX zT=oJ>6c823!=yqq8E>(cBqrsg`f0LHUdm#j3D!|02T}l5r2u68;;_lhPbtkwwJTBq oav6cRxO%bztA+Om7IwyH#t#hG$&QK{B@nrfU=?3*r~}&s0N3hA&j0`b diff --git a/server/src/app/models/__pycache__/user.cpython-311.pyc b/server/src/app/models/__pycache__/user.cpython-311.pyc index 3fe7359a1e1cced35fab3506889f0274d99e8a65..57af8893c684518e09da96d3362cc7e89e592866 100644 GIT binary patch literal 1465 zcmaJ>&u<$=6rSCkwbzd06cp1GkP9LFFoIg3N+7G^P$Vi!9Vs+U)vd*9;+f)A*1MaT zHB~qniGz_i_|_gHAq7EuK%6R0{0X~~57r!d;l#~Vdg_TcyLJ>q>G;jJ-^}~w*PA!~ zd3m{rppf5xbt4_2zf@yhax-$g3*;`Mh-x0{X|~qWZM|pMhNk*-5BE&l)R2y@AZmP% zC}uh}ALNcOLieF&#m=SvJoqhU9vR?+I`ide;X0}n|5nYKAJN+~IOKh(S+OxQ zsrGFiA(o@~5_GaWF!O}v6ob(g&BJKxU!x1GNDJp?bER_>pQ~R2{nCQI^jv)j^vetS zveHuxg0&)XOEA8_!gUh?5v*(0C*oP1^AiI)pL@0?#5Q3t#xb9goqknJn(jsgTxIp9ys(vamm6 zLgtz*;%-Ogd+ArymZjx5YJJC%MaSs{wC^cia-97>@iGrriNKctq~ZFJTyY%Y`$3f5 zIH(N~ac(Nni%Nt&7dlo|`z3&1&@mu-`cb_b^jMt-yRKhv5pxE~&#wzhS&C zc&ARnunyZ`o~Ww;TnG=irDjr~@<;puFgW#_R9+sn4ln+;9akDjr7^BF2A7A%kp57N zaRV&DjY;{1L37ajt~sf!#aLN_*QPo2<_Cw@{>;TUZp9nzWTQRaXb-NA@aWd~%t?)eC+qfj-5z{Cj7C?-E9YZugC*FWRNuYlJ$x(PYQ@!^q`EV% z?hLLBw@2^%_*IN|z>*Y!@bmM-Y{NS-BeLtUg*P&PbjKSYJpD$P!7$ZSex*!LGtGcZ z!?LI{?NiPmKX?fQvK)HE^-pqXvu5(MYTY#jDq;Dn3SLoARgmuLHO1bTLm7y88(<;W zCy`t|8)Icjia@eC)bP!kB`vYr$4C zpK!GY4XXGFU}|WZHbEc8|8EmijTdc-E$xOjMbF0J$M-H~zQ?KJ$!XoHuB}bce_?d) NvFd&D3|AV6e*jEIbnO5D delta 311 zcmdnVeTS8AIWI340}yO{x-#jd!E^`z!BLfqI zJ3|Un3quNXDpLx}8rEej3=FG*7y_bLQrLnSG}$NisZBg6#^^WkhA&$RBS>WOZbo}1 zO^(TlOj?XwlY5xtCLdvP@c_@LL6iUh diff --git a/server/src/app/models/knowledge.py b/server/src/app/models/knowledge.py index 6e28b2c..68752ec 100644 --- a/server/src/app/models/knowledge.py +++ b/server/src/app/models/knowledge.py @@ -1,8 +1,17 @@ from sqlmodel import Field, SQLModel, Relationship +from pydantic import BaseModel +from src.app.models.user import User class Knowledge(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) content: str = Field(index=True) uri: str = Field(index=True) - questions: list["Question"] = Relationship(back_populates="knowledge", cascade_delete=True) # type: ignore \ No newline at end of file + questions: list["Question"] = Relationship(back_populates="knowledge", cascade_delete=True) # type: ignore + + user_id: int | None = Field(default=None, foreign_key="user.id", ondelete="CASCADE") + user: User | None = Relationship(back_populates="knowledges") + +class KnowledgeCreate(BaseModel): + content: str + uri:str \ No newline at end of file diff --git a/server/src/app/models/metric.py b/server/src/app/models/metric.py index 6671ffe..42ba569 100644 --- a/server/src/app/models/metric.py +++ b/server/src/app/models/metric.py @@ -1,5 +1,7 @@ from sqlmodel import Field, SQLModel, Relationship +from pydantic import BaseModel from src.app.models.question import Question +from src.app.models.user import User class Metric(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) @@ -8,3 +10,10 @@ class Metric(SQLModel, table=True): question: Question | None = Relationship(back_populates="metrics") need_index: int + + user_id: int | None = Field(default=None, foreign_key="user.id", ondelete="CASCADE") + user: User | None = Relationship(back_populates="metrics") + +class MetricCreate(BaseModel): + question_id: int + need_index: int \ No newline at end of file diff --git a/server/src/app/models/question.py b/server/src/app/models/question.py index 86b5aeb..6874925 100644 --- a/server/src/app/models/question.py +++ b/server/src/app/models/question.py @@ -1,5 +1,6 @@ from sqlmodel import Field, SQLModel, Relationship from src.app.models.knowledge import Knowledge +from src.app.models.user import User class Question(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) @@ -9,3 +10,6 @@ class Question(SQLModel, table=True): knowledge: Knowledge | None = Relationship(back_populates="questions") metrics: list["Metric"] = Relationship(back_populates="question", cascade_delete=True) # type: ignore + + user_id: int | None = Field(default=None, foreign_key="user.id", ondelete="CASCADE") + user: User | None = Relationship(back_populates="questions") diff --git a/server/src/app/models/user.py b/server/src/app/models/user.py index 48a4191..9d64ded 100644 --- a/server/src/app/models/user.py +++ b/server/src/app/models/user.py @@ -1,7 +1,16 @@ from sqlmodel import Field, SQLModel, Relationship +from pydantic import BaseModel class User(SQLModel, table=True): id: int | None = Field(default=None, primary_key=True) username: str hashed_password: str - #is_active: bool \ No newline at end of file + #is_active: bool + + knowledges: list["Knowledge"] = Relationship(back_populates="user", cascade_delete=True) # type: ignore + questions: list["Question"] = Relationship(back_populates="user", cascade_delete=True) # type: ignore + metrics: list["Metric"] = Relationship(back_populates="user", cascade_delete=True) # type: ignore + +class UserCreate(BaseModel): + username: str + plain_password: str \ No newline at end of file diff --git a/user-interface/package-lock.json b/user-interface/package-lock.json index 22f01aa..eef1b54 100644 --- a/user-interface/package-lock.json +++ b/user-interface/package-lock.json @@ -8,6 +8,7 @@ "name": "user-interface", "version": "0.0.0", "dependencies": { + "axios": "^1.13.6", "buefy": "^3.0.4", "pinia": "^3.0.4", "vue": "^3.5.27", @@ -1250,9 +1251,9 @@ } }, "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", - "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -3278,7 +3279,6 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, "license": "MIT" }, "node_modules/at-least-node": { @@ -3309,10 +3309,9 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", - "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", - "dev": true, + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", + "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.11", @@ -3324,7 +3323,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true, "license": "MIT" }, "node_modules/balanced-match": { @@ -3564,7 +3562,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -3798,7 +3795,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" @@ -4125,7 +4121,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -4135,7 +4130,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -4172,15 +4166,15 @@ } }, "node_modules/editorconfig": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", - "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.7.tgz", + "integrity": "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==", "dev": true, "license": "MIT", "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", - "minimatch": "9.0.1", + "minimatch": "^9.0.1", "semver": "^7.5.3" }, "bin": { @@ -4190,23 +4184,6 @@ "node": ">=14" } }, - "node_modules/editorconfig/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/editorconfig/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/editorconfig/node_modules/commander": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", @@ -4217,22 +4194,6 @@ "node": ">=14" } }, - "node_modules/editorconfig/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/electron-to-chromium": { "version": "1.5.302", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", @@ -4298,7 +4259,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4308,7 +4268,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4325,7 +4284,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -4338,7 +4296,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -4588,9 +4545,9 @@ } }, "node_modules/eslint/node_modules/minimatch": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", - "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -4965,7 +4922,6 @@ "version": "1.15.11", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "dev": true, "funding": [ { "type": "individual", @@ -5026,7 +4982,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -5081,7 +5036,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5101,7 +5055,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -5126,7 +5079,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -5230,7 +5182,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5260,7 +5211,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5273,7 +5223,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -5306,7 +5255,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -6174,7 +6122,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6231,7 +6178,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -6241,7 +6187,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -6261,13 +6206,13 @@ } }, "node_modules/minimatch": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.6.tgz", - "integrity": "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -6276,6 +6221,23 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimatch/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", diff --git a/user-interface/package.json b/user-interface/package.json index d9e2d5a..a8d7057 100644 --- a/user-interface/package.json +++ b/user-interface/package.json @@ -19,6 +19,7 @@ "format": "prettier --write --experimental-cli src/" }, "dependencies": { + "axios": "^1.13.6", "buefy": "^3.0.4", "pinia": "^3.0.4", "vue": "^3.5.27", diff --git a/user-interface/src/components/CollectKnowledge.vue b/user-interface/src/components/CollectKnowledge.vue index 7a359bc..95c0b3e 100644 --- a/user-interface/src/components/CollectKnowledge.vue +++ b/user-interface/src/components/CollectKnowledge.vue @@ -1,12 +1,15 @@ diff --git a/user-interface/src/components/GenerateQuestion.vue b/user-interface/src/components/GenerateQuestion.vue index e627605..ca74258 100644 --- a/user-interface/src/components/GenerateQuestion.vue +++ b/user-interface/src/components/GenerateQuestion.vue @@ -3,7 +3,7 @@ import { BProgress } from "buefy"; import type { Knowledge } from "@/types/types"; - import { apiClient } from "@/services/api"; + import api from "@/services/apiAxios"; import { useItemStore } from '@/stores/item' import { useStepStore } from '@/stores/step' @@ -17,7 +17,7 @@ }) async function generateQuestions (knowledge: Knowledge) { - await apiClient.post(`api/v1/knowledges/${knowledge.id}/questions`, null) + await api.post(`api/v1/knowledges/${knowledge.id}/questions`) stepStore.nextStep() } diff --git a/user-interface/src/router/index.ts b/user-interface/src/router/index.ts index 3b80ba2..e11d1bf 100644 --- a/user-interface/src/router/index.ts +++ b/user-interface/src/router/index.ts @@ -9,6 +9,12 @@ const router = createRouter({ name: 'app', component: () => import('@/views/ExperimentView.vue'), }, + { + path: '/login', + alias: '/login', + name: 'login', + component: () => import('@/views/AuthView.vue'), + } ], }) diff --git a/user-interface/src/services/apiAxios.ts b/user-interface/src/services/apiAxios.ts new file mode 100644 index 0000000..41befef --- /dev/null +++ b/user-interface/src/services/apiAxios.ts @@ -0,0 +1,26 @@ +import axios from "axios" + +const api = axios.create({ + baseURL: import.meta.env.VITE_API_URL +}); + +api.interceptors.request.use((config) => { + const token = localStorage.getItem('access_token') + if (token){ + config.headers.Authorization = `Bearer ${token}` + } + return config +}) + +export const authAPI = { + register: (data: unknown) => api.post('/api/v1/auth/register', data), + login: (username: string, password: string) => + api.post( + '/api/v1/auth/login', + new URLSearchParams({ username, password }), + { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }} + ), + getMe: () => api.get('/auth/me') +} + +export default api; \ No newline at end of file diff --git a/user-interface/src/types/types.d.ts b/user-interface/src/types/types.d.ts index e84d79f..b0e2d65 100644 --- a/user-interface/src/types/types.d.ts +++ b/user-interface/src/types/types.d.ts @@ -1,7 +1,13 @@ +interface KnowledgeCreate{ + content: string, + uri: string, +} + interface Knowledge { id: number | null, content: string, uri: string, + user: User } interface Question { @@ -9,12 +15,17 @@ interface Question { question: string, knowledgeId: number, metric: Metric | null + user: User } -interface Metric { - //id: number | null, +interface MetricCreate { question_id: number, need_index: number } -export type {Knowledge, Question, Metric} \ No newline at end of file +interface User { + username: string, + token: string +} + +export type {KnowledgeCreate, Knowledge, Question, MetricCreate} \ No newline at end of file diff --git a/user-interface/src/views/AuthView.vue b/user-interface/src/views/AuthView.vue new file mode 100644 index 0000000..ab85492 --- /dev/null +++ b/user-interface/src/views/AuthView.vue @@ -0,0 +1,58 @@ + + + + + \ No newline at end of file