From f37ddce7a256bbcad96e6d8b90aba5722810cf7e Mon Sep 17 00:00:00 2001 From: Samm-05 Date: Wed, 8 Jul 2026 20:48:40 +0530 Subject: [PATCH 1/2] feat(follow): implement follow/unfollow functionality --- .../app/__pycache__/__init__.cpython-312.pyc | Bin 240 -> 197 bytes .../__pycache__/dependencies.cpython-312.pyc | Bin 0 -> 3184 bytes backend/app/__pycache__/main.cpython-312.pyc | Bin 0 -> 5097 bytes .../core/__pycache__/__init__.cpython-312.pyc | Bin 500 -> 457 bytes .../core/__pycache__/config.cpython-312.pyc | Bin 4589 -> 4536 bytes .../core/__pycache__/logging.cpython-312.pyc | Bin 4133 -> 4079 bytes .../core/__pycache__/security.cpython-312.pyc | Bin 5991 -> 5938 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 334 -> 291 bytes .../database/__pycache__/base.cpython-312.pyc | Bin 471 -> 428 bytes .../__pycache__/database.cpython-312.pyc | Bin 476 -> 433 bytes .../__pycache__/session.cpython-312.pyc | Bin 929 -> 886 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 339 bytes .../__pycache__/rate_limit.cpython-312.pyc | Bin 0 -> 750 bytes .../__pycache__/request_id.cpython-312.pyc | Bin 0 -> 1162 bytes .../security_headers.cpython-312.pyc | Bin 0 -> 2111 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 294 -> 251 bytes .../__pycache__/activity.cpython-312.pyc | Bin 4185 -> 4142 bytes .../__pycache__/application.cpython-312.pyc | Bin 3542 -> 3499 bytes .../__pycache__/audit_log.cpython-312.pyc | Bin 4299 -> 4247 bytes .../__pycache__/bookmark.cpython-312.pyc | Bin 2068 -> 2017 bytes .../__pycache__/builder_flare.cpython-312.pyc | Bin 3595 -> 3547 bytes .../__pycache__/conversation.cpython-312.pyc | Bin 3021 -> 2970 bytes .../conversation_member.cpython-312.pyc | Bin 3293 -> 3250 bytes .../__pycache__/follower.cpython-312.pyc | Bin 2098 -> 2052 bytes .../__pycache__/message.cpython-312.pyc | Bin 3836 -> 3782 bytes .../__pycache__/notification.cpython-312.pyc | Bin 4394 -> 4351 bytes .../__pycache__/organization.cpython-312.pyc | Bin 4201 -> 4158 bytes .../__pycache__/project.cpython-312.pyc | Bin 4329 -> 4286 bytes .../project_member.cpython-312.pyc | Bin 3193 -> 3150 bytes .../__pycache__/project_skill.cpython-312.pyc | Bin 2559 -> 2516 bytes .../__pycache__/refresh_token.cpython-312.pyc | Bin 3226 -> 3183 bytes .../__pycache__/repository.cpython-312.pyc | Bin 4362 -> 4319 bytes .../models/__pycache__/skill.cpython-312.pyc | Bin 2005 -> 1962 bytes .../models/__pycache__/user.cpython-312.pyc | Bin 4159 -> 4105 bytes .../__pycache__/user_skill.cpython-312.pyc | Bin 2996 -> 2953 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 167 bytes .../__pycache__/activities.cpython-312.pyc | Bin 0 -> 5463 bytes .../__pycache__/applications.cpython-312.pyc | Bin 0 -> 5241 bytes .../routers/__pycache__/auth.cpython-312.pyc | Bin 0 -> 7747 bytes .../__pycache__/bookmarks.cpython-312.pyc | Bin 0 -> 4577 bytes .../builder_flares.cpython-312.pyc | Bin 0 -> 4267 bytes .../__pycache__/conversations.cpython-312.pyc | Bin 0 -> 5789 bytes .../__pycache__/followers.cpython-312.pyc | Bin 0 -> 6777 bytes .../__pycache__/messages.cpython-312.pyc | Bin 0 -> 5113 bytes .../__pycache__/notifications.cpython-312.pyc | Bin 0 -> 5122 bytes .../__pycache__/organizations.cpython-312.pyc | Bin 0 -> 7353 bytes .../__pycache__/projects.cpython-312.pyc | Bin 0 -> 7593 bytes .../__pycache__/repositories.cpython-312.pyc | Bin 0 -> 5331 bytes .../__pycache__/skills.cpython-312.pyc | Bin 0 -> 4294 bytes .../routers/__pycache__/users.cpython-312.pyc | Bin 0 -> 5249 bytes backend/app/routers/followers.py | 143 +++++++++++++++--- .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 172 bytes .../__pycache__/activity.cpython-312.pyc | Bin 0 -> 2774 bytes .../schemas/__pycache__/auth.cpython-312.pyc | Bin 0 -> 4923 bytes .../__pycache__/follower.cpython-312.pyc | Bin 0 -> 1514 bytes .../schemas/__pycache__/user.cpython-312.pyc | Bin 0 -> 3965 bytes backend/app/schemas/follower.py | 58 +++++++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 174 bytes .../activity_service.cpython-312.pyc | Bin 0 -> 7592 bytes .../application_service.cpython-312.pyc | Bin 0 -> 5053 bytes .../audit_log_service.cpython-312.pyc | Bin 0 -> 5498 bytes .../__pycache__/auth_service.cpython-312.pyc | Bin 0 -> 9623 bytes .../bookmark_service.cpython-312.pyc | Bin 0 -> 5185 bytes .../builder_flare_service.cpython-312.pyc | Bin 0 -> 4240 bytes .../conversation_service.cpython-312.pyc | Bin 0 -> 6188 bytes .../follower_service.cpython-312.pyc | Bin 0 -> 6079 bytes .../message_service.cpython-312.pyc | Bin 0 -> 6127 bytes .../notification_service.cpython-312.pyc | Bin 0 -> 6226 bytes .../organization_service.cpython-312.pyc | Bin 0 -> 7409 bytes .../project_service.cpython-312.pyc | Bin 0 -> 7560 bytes .../refresh_token_service.cpython-312.pyc | Bin 0 -> 3666 bytes .../repository_service.cpython-312.pyc | Bin 0 -> 6700 bytes .../__pycache__/skill_service.cpython-312.pyc | Bin 0 -> 4618 bytes .../__pycache__/user_service.cpython-312.pyc | Bin 0 -> 5733 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 169 bytes .../__pycache__/validators.cpython-312.pyc | Bin 0 -> 6027 bytes frontend/package-lock.json | 12 -- .../src/components/shared/FollowButton.tsx | 86 +++++++++++ frontend/src/features/dashboard/sections.tsx | 1 + frontend/src/hooks/useFollow.ts | 112 ++++++++++++++ frontend/src/lib/api.ts | 46 ++++++ .../src/routes/_app.builders.$builderId.tsx | 7 +- .../src/routes/_app.profile.$username.tsx | 16 +- .../src/routes/_app.projects.$projectId.tsx | 14 -- 84 files changed, 442 insertions(+), 53 deletions(-) create mode 100644 backend/app/__pycache__/dependencies.cpython-312.pyc create mode 100644 backend/app/__pycache__/main.cpython-312.pyc create mode 100644 backend/app/middleware/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/app/middleware/__pycache__/rate_limit.cpython-312.pyc create mode 100644 backend/app/middleware/__pycache__/request_id.cpython-312.pyc create mode 100644 backend/app/middleware/__pycache__/security_headers.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/activities.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/applications.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/auth.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/bookmarks.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/builder_flares.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/conversations.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/followers.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/messages.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/notifications.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/organizations.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/projects.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/repositories.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/skills.cpython-312.pyc create mode 100644 backend/app/routers/__pycache__/users.cpython-312.pyc create mode 100644 backend/app/schemas/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/app/schemas/__pycache__/activity.cpython-312.pyc create mode 100644 backend/app/schemas/__pycache__/auth.cpython-312.pyc create mode 100644 backend/app/schemas/__pycache__/follower.cpython-312.pyc create mode 100644 backend/app/schemas/__pycache__/user.cpython-312.pyc create mode 100644 backend/app/schemas/follower.py create mode 100644 backend/app/services/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/activity_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/application_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/audit_log_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/auth_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/bookmark_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/builder_flare_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/conversation_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/follower_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/message_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/notification_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/organization_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/project_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/refresh_token_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/repository_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/skill_service.cpython-312.pyc create mode 100644 backend/app/services/__pycache__/user_service.cpython-312.pyc create mode 100644 backend/app/utils/__pycache__/__init__.cpython-312.pyc create mode 100644 backend/app/utils/__pycache__/validators.cpython-312.pyc create mode 100644 frontend/src/components/shared/FollowButton.tsx create mode 100644 frontend/src/hooks/useFollow.ts diff --git a/backend/app/__pycache__/__init__.cpython-312.pyc b/backend/app/__pycache__/__init__.cpython-312.pyc index 66e390eb5e673b3e0144861b7c621d40a01ff19a..3e691e69572c1fc7f876156ef1a488699dd953d5 100644 GIT binary patch delta 34 ocmeysc$AU%G%qg~0}xDp?V05;k++CbJSj0bJ2fvwf8u6a0I-M(%>V!Z delta 77 zcmX@g_<@o4G%qg~0}zyD*=5;Hej`2y&%P-51@y|Zn_&5=Z^8GWD1y~2cL9AYe!*Yo(!RMPVHrxVp)005Q6#c6na*^E z>4%5}-8?|sw6kZ2#}yUktesY-r{C2WJ-DFi*vw4N+7afdSjxBptEdP26#UIPsD43D z=h03W#T!4mu_`2&h2%3c0{Yw06!!_&DBSa>IMoLVw}>FXl)3F;7PTSIvdU=6YgzSh z_xF~s?3<$A2a3k+TJUAwJZuGA11soCQ!I`i*LtZ~GBg=-Q)WHF ztYmdB(K2%}nl=odD3%IZCLJPlD{aYRW%Cf8ghmGOQ>=kzXATyS8yo5!8@+sWcrZKA zZ-;jCoWMzn>^KeTDl<9CMA}adQNX8-+kt6i)+j2P9iT`~*X#)8A_oncxwb&nCLNBF zCCh~70%>up;~rpP`DCCk@)^HSyFI2npw-On z<@-4FHFvzPgI9Nt99RpzZ&>Dzg0O%fTj6`KKrVodQ>^L@h0qjb>Oj%BN4~xME29yV z=I7e?#cr`cLsqr)8O&nUbRur9cCb*@Dyj-`VP!}XdQS^>NH=p1AWNE&QL;BRK2f}M?`NNQDTTb9~fUb~i3U2An6 z9$sM!QjdisNr20L&SuB+Y|db!Pw3U$clm4{$U`>D4hBa9Oa zmvq3w$O+1dhr%W=g|3rB;wdnlq~`lbJhm(y+fQQG|CmHY%j*T*w1{FAiA!QjuU89U ztHQJ3c^V@?qgk59gq|RO$78LRM>Z-s4cy&&j=%P0seM0x=l+DhA$Z;R3A-Ff2>Pj> zdW7DZq?J}wOU}@$2CB3`I$hbLZL-6;+(ZfP7@W%yn(}sFLV+`WS|>E^_f}@dtNM(I zA?0*y))|Xl&UVziW+;X_iSx6WBFVF{?OJ$)WYi+Tdmil2ucvyg`V0Y#y}Ag!KJ6HV z@^G~nW`+?r>-_2l*wJUz)4{rxRv-KW_4z)dQ>so0# oTj6WC)LNpEeK*C>wg~O5Qw;A}X?o?a@QW)=uO7sAs6SieA6|6WHUIzs literal 0 HcmV?d00001 diff --git a/backend/app/__pycache__/main.cpython-312.pyc b/backend/app/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d36d02b5e0ef3872b2997d9db35ae0499be7f4a1 GIT binary patch literal 5097 zcmbVPO>7&-6`uVeDN3Xyl9p)MvQ62NWy%sIJFy!java%~9oaG^NJ`Rf3lMAWNLqQh z%giqAh`l&%fb=M%KxMQ68swC~4&Y;sx%VO=3PcPlAV5=~MSGxQ6=-wno7r7bika9D zv3&c@d+(c__h#PA?q8zOW(2?A|7&vjS^}ZJv4;N(d*JE6g9xo54QYab3W6dC42yHCBU(41PdW0#BsoADuk6V$3dgH(4w?(95Nz>s1oJ4$!IOKDQz5wjrKxJ ziE-R)#0v=}!EuXmpwOXo2nY*W1WOB|7X3he=nYTl6cLuRR;^8I*J4^+OW@8&2Ofr8 zvy#MZIJrFH2UWl4+I$T5mwa5m;~4IED7tNUa&q}x-R2{lcqlx_qvg3C(dT*uaCrH= z|IGSb>sUlu=O+Tl^O4r29ahIh_uu$?;cn+J;w3E3FQQz)#HGBm0pfd0Pa)zIPL{}QaQb|D81Nb8496pY&njm*u8kkEuvm}YNBG3@l8@_m?TmI7^7+z3$<^_d)rj5O zko~fD?uFQW4cX_lpS=*fzaje-ZS;lMry8ZVpYS$-eU|IdO>&ib7QlrgQr+?;=Me^ z8rFaun=`DtFql20?i>Nv9H-{6=bT$oO&BMkl3Fb0y@QKyLu@mW;H-Ok3BU~`z;W-? z?3z$djwXIC|3O%TSAbo1scv5pKbP(bX}Nr|IR(EtMUS$EA8zJpE2 z&TxlP3LaSf^B?b}uHZXUx_LWwNzLEJ;LfR#woE3I^}POczk!!kEV^Ehia?R*rjr&3 zJKAj)KQ^OSm>raKwgH#3XguG7R;W z1@od?W@^Sz9q=uDA2^d4$&8c(!{gnGaaGBkTf81vgNHev4pQmb#5|Q}rsw9VH1pOx4a|(sUw)GY zuS`r$%umqJ^vwL^bapN+(dc-|S+a;;=Ho3#F0&#qouT=aA}+W8e8^kLSQ~mrcb3vJ zjj9GL#2io-bYm)tc^g<&esS{6(nl^u1_&O@?mKbHC5 z!vAR}2zP;Mf+lK`CVwQ&A-?DWS#kiZqyq#Ek&;iucrsyciNA!ueHa8^4Amft9jzn|RpN)AgycxDisV4hTL_`BP!0{l@C|2) z2BCD}zGu*^s`#K;zy6>d!0vC^d%5)6?5>F)iC#ETmWJHUSJEOG0wZm~<{h0_W&tt^ zx+boh$i6)}JDt5bk)7vJkzr7~Q3YK-VegI_{OzM4{J0X`e@!0SN}k?Go_-RLSZGo$ zv;&<&e)s6$1Hg@B0Kl{RgEtZ4qk#Wv>BSJt>N`+|SIZrfuzHB88mT!?pJ-BFCw^V~~ zcf3IS{f@j2Uhl%+?g7E$|F$JrIgtD&*kzM$uMDKUkp>L9}luq9Y`-44RH zEbDebCAXQqShck^T5-(~Or1&zA>Y zZoA~>q~A_mWts3;ellp&O?R5@a-4U!Co?pf-JK|?Eoy3NIi?HIN zp#?aI!H2N@fhN6HrcgVNGkJ^Hgnbv$m~SQC*=!T`jY!)dSIiBAFc|sbVc*5{*bnTscY^1j_8w9z`#1$qcn7GQsH74FpL zOx$2%iiw*{WI@nY-OL*$4d>hk(4c$&;ojCXR=ij)i67dE4{XE-DxHVE6GMsMckOZ_SnWbW zVh6>b`w=7tK1{x!{9R)8>gp@^l3xkkPsD%_WI-IMGE{B%UAi8edT@xj^ga<~*QKw@ zQ1u|VYzdtkLg(trS3=JdG31($R~hY|9bt^>+7R8)=_*DP1V9)J-0S?f9%u97uUWR<)(?c>6NvM_b+~W z@ymfPySXV_H(l6D^lv2kA4k@&ytRJ$ZEk+2ZvJs*MUHLB2RGz{>pkbb$gPjvtV%qa zB4jgIo14|MYoqr^KmNsI?XlbUSiSGjt;C6q#EDJR`_sBtw-UV@eA4TF-mo{(sh`%3 kZ6!`_B=)S2)kfS#e&^RN+`q7idg@Q$DgGLz`1`>B0W^BHlmGw# literal 0 HcmV?d00001 diff --git a/backend/app/core/__pycache__/__init__.cpython-312.pyc b/backend/app/core/__pycache__/__init__.cpython-312.pyc index e0b1f44f7bb55fd517c09da59636e385ac63081a..a7e22260c22652138d8c68194c18ccd70d22cf50 100644 GIT binary patch delta 36 qcmeyue3F^>G%qg~0}xDp?U^-gBX1fbr%X~}a&~H7ivHx~jJ^QN6$?-R delta 79 zcmX@f{DqnKG%qg~0}y0p*=0@H$eYG!;_hq}6Iz^FR2<`znwMXeALE~w>QatGr5M*7XS$v8`S^+ diff --git a/backend/app/core/__pycache__/config.cpython-312.pyc b/backend/app/core/__pycache__/config.cpython-312.pyc index dd81e831ce9bd5d82b848339fae2f47304a60919..4eb59219ddce636d333e17bf1265379c71a9b5cb 100644 GIT binary patch delta 149 zcmaE>yhEAyG%qg~0}xDp?U|LikvD*gQz|JjIXg8kMSt={E_233n@@5TF*2^&Y{PS( zk+E^I4Btu}9tOz>#s;4W%9mNfKkzV!88moy6klf1|G>w<8N~R3nSoVgLhxq>CRVl& z0+YY;0Yra@n0!=F0|35e BFNFXA delta 202 zcmdm?{8pLwG%qg~0}z<_+Gnlb$Q!_A;_7S_6Iz^FR2<`znwMXeALE~w>QatGdYdRoN?9Wd0a(|jGHzK^4w=+?4JCQcclRz z1E&Y$2WAFV!3oNr8JJkvJ_s;~88moy6klf1|G>w@sQ{7`nGpP$fdwcjGWi%^uJ8vo rCQeb1xWo)$sQ6|F{soMTyC**sSjbn%#K_fA^MwIKf5@0TK~Mt#F0MeS diff --git a/backend/app/core/__pycache__/logging.cpython-312.pyc b/backend/app/core/__pycache__/logging.cpython-312.pyc index cd6c69f7403fd57ea3953de13fbe2911d72930c8..9b066424de8c1fc8ceaef2488a6e29d752401867 100644 GIT binary patch delta 252 zcmZ3g@LrzxG%qg~0}xDp?U|Lkk(Y~=Q#vUzIXg8kMSrq4s|us<<^t9(CdTB=zu9vb z*$ROwi`6G_sBNCi+0V#Wvssy2laWz>vM-OM_zal^*$ZMfXzhqTA$-Bc_e9VIj)1Ss zOq1JrmN72ftjFuZ$hdNHF<+K48-qkR;|+1GkF3lhTpzd?ctt-ju?Wh3VC4|z`pC^E z%=STPG9!ODrz4}f5K{x+hnUHU{3473lgs#(xCPi4r9R6rGfI7sn!K3b!o-M!k?jT# u{|9Cu{eX)XXa*zO2Q~&F(GTn(76*fn_yoYfqr7)RaKnwu2FhlbI delta 351 zcmaDazf^(uG%qg~0}vQz*<~Hs$jilQ;^u4>6Iz^FR2<`znwMXeALE~w>QatGg*OEg)wlmD{B`MW7_5m>^Y2##hYz8cQG>7 zZvMfg$!Ki}w4#CG3l9S;ce{6^_YH2r4vh(l6I>>kePCde61pKIJ3$u6k{7rkAU(tR z0>8onrVp%4oGM?LStbYZEMr`@`6rJHBjc*cc6?bX9L$1pAGjDKv_JB5h;V%nVc-@0 zz{Dab`+=21nCqjcurS*Poyn*9!sWafb%dB2_&%gDGB9$q^EL8aXOO(eAUQ+t3WMec zzR3>!O5A*Gj8dPam>H!$NKDS{lE&OKd>NjT%Wl?EG0%p`3aRk*E7m52>Ak{iWGp}1pst5V<-Rs diff --git a/backend/app/core/__pycache__/security.cpython-312.pyc b/backend/app/core/__pycache__/security.cpython-312.pyc index c8f18e90affb4a1394dcc9f99407b5c9ed2564ac..f7c049bebc625cc621562bcdc8faf15a3a71fa3c 100644 GIT binary patch delta 274 zcmaE^w@HupG%qg~0}xDp?U~iEk@pT0r%X~}a&~H7ivDI__UcA zS8w(aU}9ukH`!nC8RN#uW>daeih8u@tzWYJv0vR*uiCK>CB)qM$Kc zr|cJQHjp;9%@LfPjEuRPA93k0GPX?S=Xu50H~BTM@?=@wvy3w~zvk6uVqCvjT!4v@ zanoce!DozHCo>A&W85+MfzUd}<(vD3Ss57*Z=Nc0n30p8k?jVrzz1gj$%$ejDnK64 eiENyo*+DE7UZ^CHe!$A{nH5NX(3(6`Y$gCEFkUYJ diff --git a/backend/app/database/__pycache__/__init__.cpython-312.pyc b/backend/app/database/__pycache__/__init__.cpython-312.pyc index 14ac7785f34316656db466533aa55084348da912..4435d43bfff0cf31fd29cbfd356717be225594c4 100644 GIT binary patch delta 35 pcmX@dw3vzaG%qg~0}xDp?U^-aBJW{Ng`~vf?9{vz{mCqhUI4rZ3Zei2 delta 77 zcmZ3?bdHJlG%qg~0}wQ4*=5a|$a~nt+u156v^ce>IL0S6FTX55#y>CBr6{v3HO3`B fximL5ucSC8CABOkGcP+PDKR-aH7_M*;!Q6A=J^~x diff --git a/backend/app/database/__pycache__/base.cpython-312.pyc b/backend/app/database/__pycache__/base.cpython-312.pyc index ad4deebc9aa129896f42323f12cf08bf34d6a381..2a82ddebc9283df0f5d688e80fbbfd699494954a 100644 GIT binary patch delta 35 pcmcc4yoQIL0S6FTX55#y>CBr6{v3HO3`B gximL5ucSC8CABOkGcP+PDKR-aH7_M*vJm4e0Qc4#r~m)} diff --git a/backend/app/database/__pycache__/database.cpython-312.pyc b/backend/app/database/__pycache__/database.cpython-312.pyc index ffa69707837ae2f56f8310744ab8ceee69aa8abe..fb019bbc34ca2d9fc53174d9ee250e149b4c0e26 100644 GIT binary patch delta 36 qcmcb^ypfsrG%qg~0}xDp?U^-qBd;+dr$SO+hxt($ZO1K;_Yk|6Iz^FR2<`znwMXeALE~w>QatGue|d0|4Hz8y^4w diff --git a/backend/app/database/__pycache__/session.cpython-312.pyc b/backend/app/database/__pycache__/session.cpython-312.pyc index aac40166c6d3a1998e88a3c11b1b526957c49b61..3bfbd0f65632eea956ed1b13d5cb487591eb85c4 100644 GIT binary patch delta 71 zcmZ3;{*8_IG%qg~0}xDp?U~iPk=KlgQ$8s%IXg8kMSpTRlM18cVis6EP+ek4YCPB^u-;qj@$rc{Iq~r;89oDzV)&($l$e~InwO%VSWpm?3wK;h ze0*kJW=VX!UP0w84x8Nkl+v73yCPno7Lb>UMS;WzW=2NFyA0ZQ8O-l8$bVvC;bv-N JFX9Hu0026XTebiI literal 0 HcmV?d00001 diff --git a/backend/app/middleware/__pycache__/rate_limit.cpython-312.pyc b/backend/app/middleware/__pycache__/rate_limit.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e20d0b2c2f9d390d54ecf34194255ea05c1806d GIT binary patch literal 750 zcmYjOO^ez<7@j0%6HSaCmAYFGJ*==uSzTM&Qz?WsYi-?C5|=_)2w7*e*-ca?kws7T zH}p{GKPc@#>7|}5fd!%TPz634Of<6F!T7{pHsX`gfL{*^hfFnLMfi)&UKdX|lY$Mh5CU{GxLF(ON^ zV|6hbsOgGwB%jt>hAOudqh33%wR~=Q7li#}y-}^5+zkmUW#zl4D%G0SQq;Q+=~i5s zGEG_2-Za#Tp(>ivT9*({oAriVS+n@DqG@t9tS@SctRB7$gH5&ZN;wQOg`>KxuAQI2 z4e0^=%b%O=OVooU(&Cw8L1?2Z6QeV1k{?($Qyh$Z{<+hKLmR!o4@eS4rh8771w&EP zHOO6qM?XRSj|hbH_xQs(pPcc#Q+{{B(3!2jEGy6xZgC$ZvNLIKD(y{#d1_~t+MlNO hC(=Bd{{}Mi#P&p-Cv%hdJdq2~4nb1(oq)GVng2Zm%T53Q literal 0 HcmV?d00001 diff --git a/backend/app/middleware/__pycache__/request_id.cpython-312.pyc b/backend/app/middleware/__pycache__/request_id.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..18fd8c19fe111d0f6a2ade2f9b756456920793fd GIT binary patch literal 1162 zcmY*Y?MoCv7@ygf+x0q=^v+HbTPnmuy}lGiNMJ}Ml7tn+A}s68oSyByIJ29boe(K; zLDYvJi-P(Z)_+icL0=LBVM4fwpyP!pFS%_fQ zBe_)22)_bR#|r;yZ#kI&kk{fuU&4vIr#auKw;|&9dVtph{bji%m*9M8pGp9&J!=V+ zq!Mgctnk6z;W3^{Yw~?n15PTGaSbaroDrkl=_g(A~Yh8Ao$HMi6gB)5O&$%a%!p%a|^ z0Dtd-oe1dcdKrDy{k;1{&t|Nz9IhN6Dr=8hAGChfjjvtDUJq|}4QzD`l=aHM>9W41 z$2au&v)&E8ztVQN+*WM?(ZO9RoZdS-8inuSXuI;ElcULm#&pZd*;#B^ENofXJn|fY zBbK$`*-jwQEDPmRmPN#@h$x!GIC%qVoB|RRL~9VyGTO_@D)=oas$Pv8RO6LH@v6%2 zst&^KJ1rcMBMpOuP9hw$Esk6q zb&EiLG?6INN9t9cBS$$a_S4U{DnkgrfCJybnQhRw4f=ONF&O{UJ@^Ok+qeG*0V^R& literal 0 HcmV?d00001 diff --git a/backend/app/middleware/__pycache__/security_headers.cpython-312.pyc b/backend/app/middleware/__pycache__/security_headers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3c53468c2f4923253f825cfff257a2a70bc9e24 GIT binary patch literal 2111 zcmaJ?-EZ7P5MQ5tcfQ<(OVSpS5K;?J(`)M^1lp8d8>vY{Q$CU?mxpqyWI5iw#KB&> zyFS`8L8@ql@_^t0iM;Y!RsBnN>6M36mMS6v0>sNz2@>iPyZ*=}MaN1W&&+RTXLe_I z_Q&4d9>B(Te_dM-G64L-g=C~-X7>ZeYyk+MU;$gG2?FO+R>~G@V#te@WT$KCke95C zovmdBkOEf$Oy2`AgMw@#_Z83%g^d+Ku2Me2g?@R1;e!M$E~yR}bP)_w)w@*PAYy%HK#6vM$7v4S1Up&pi0 z#|CRH4x!2zW))#!oR#%`(^$2_+LFq;#D4yDhuEra@R}t$|CQtfB})IcYMK-x%JMo}XILjZYDV zZ|Sak!`|ra-}qtj zr=io^M^10bJ7=dh3L}qRJKrk2 zwFtro_S9D*c!hqOiu~l2-6p(Z>P(Q zoiAkrS<^7PZJHMJXqxT7hQ;}Urrm7lR*Ymd4LXLV5nd0%pG9(vk^5kmQ9zDzA}541 zbd-^M;8`k_mfLbEJ-E|9*iN%Q+lZcly&U7ntBJ#WDHjY;PbU_8;83|!-7-Iiguf!e zKnIUs92zDQ961O?ZzT;g42tZil-bQkjNrPt8Xm?d&0!uojL%aK1-7fTAW%`9OILkmtU42GJqDQ~PM~1`KW7~< diff --git a/backend/app/models/__pycache__/activity.cpython-312.pyc b/backend/app/models/__pycache__/activity.cpython-312.pyc index a04906d8a62fa8828d379d8abc6846652fb8e7b2..576c99abea7d3c463d833fbb811a96a8e56ea8c5 100644 GIT binary patch delta 37 rcmcbquug&ZG%qg~0}xDp?U|Lhk@qJvr(9BEa&~H7ivDIR7I_{3+dB(N delta 80 zcmZ3da8rTzG%qg~0}$v&*=NOXQatvzeboo(BLYQyYW; diff --git a/backend/app/models/__pycache__/application.cpython-312.pyc b/backend/app/models/__pycache__/application.cpython-312.pyc index 5a0478bbc084462721fc520b8fd518e7b4f79f6b..32c4dd70f68e3f7adb449d6aa5ce740424741be7 100644 GIT binary patch delta 37 rcmca6y;_?0G%qg~0}xDp?U}{5k=L7vQ!yzqIXg8kMSpV-lNUDt$gB#r delta 80 zcmZ22eNCG8G%qg~0}y-*v(Mt$$m`8y;^S-;6Iz^FR2<`znwMXeALE~w>QatvpJE;iyHtM(i^k@ diff --git a/backend/app/models/__pycache__/audit_log.cpython-312.pyc b/backend/app/models/__pycache__/audit_log.cpython-312.pyc index 7d503c7df30cf9178e0da68ad55dca685fecf303..5ba8103fc125f5a3898d0671177f7b468b646003 100644 GIT binary patch delta 112 zcmX@DI9-wNG%qg~0}xDp?V0sTa3kLpR!;e(#N_PMycGS-Vr)fh+L}Pw28IWGDhooE zM=y-Nu4;Bs)$D?b`G%SUF2{Wi`W&#k5E_1gC*lJ$)8;)qCz%+TH@ESdFbd`{GIDj4 Md}RR9MZQ2o077Xbm;e9( delta 164 zcmbQPcv_L~G%qg~0}woqvd`id+Q@f>)x^u$DkiizwWv78Cp9m>EI-CSFV&?evn(~n zB|o_|H#M)MI3^{vEGIKBJ0>YHIXg8kC1&$$)*?0&BcMSI3?En+`NeODOHZ$!Sbbew z^CIA2c diff --git a/backend/app/models/__pycache__/bookmark.cpython-312.pyc b/backend/app/models/__pycache__/bookmark.cpython-312.pyc index f85b47458ed9a65c33e19a39890342d0cc06e011..793d039d7b9c108e1d424d9af4ec41482c7d75c1 100644 GIT binary patch delta 117 zcmbOt@Q|PPG%qg~0}xDp?U^OHk+++LQ!XhnIXg8kMSt=c77JBHpj-pP4MCL!AFlQ%>n?sW+eXr delta 168 zcmaFJKShA|G%qg~0}v!c+Gj;<NofVKCmZ?DkL51o&&hXKe=@VNa!tO;cAC*>@=|tf SeoIEKj*_noK&nUsXeIztw>E+R diff --git a/backend/app/models/__pycache__/builder_flare.cpython-312.pyc b/backend/app/models/__pycache__/builder_flare.cpython-312.pyc index 685463cb6c4b14badfa9164102c80301de6b9d3c..b05d01b714bb8ba0cd443e1312b79449a533411f 100644 GIT binary patch delta 120 zcmeB{xh>6mnwOW00SG3)_RLzbkyn6;Q#mOyIXg8kMSpW3(=|3_d7xwi!wo^T1trU? z7FI3D*`RxXI$Sc5P;^%A?6Iz^FR2<`znwMXeALE~w>QatvssPl8k@E{(3}Q_2Ykv4T$Xz+^jcu^fq~IL z^oFS9^vH>k6TD{>e_&?hRr$co%*nM`o>PXAF=(?5R}d333oF;;NjzT|y(YKwItqF- RF>*~X`N{yIi{yYt0sunwGh+Y% diff --git a/backend/app/models/__pycache__/conversation.cpython-312.pyc b/backend/app/models/__pycache__/conversation.cpython-312.pyc index c7d98bffda72cf763d610a9521330cb9b6bb2400..19ee20b3dea17bb78378c8920aed1f012b71a489 100644 GIT binary patch delta 125 zcmX>rK1-bUG%qg~0}xDp?U_}!k(ZB&QzQatvsr~{GOLLJ(3}Q_4=jxQqBle(r$QatvssR53Ksw!R~yIx diff --git a/backend/app/models/__pycache__/follower.cpython-312.pyc b/backend/app/models/__pycache__/follower.cpython-312.pyc index 6ff2650fbb135753ff6dd05a4c1c5915cf8efcfd..676b2864f887d7532f4e7bd057457a8eaab63555 100644 GIT binary patch delta 126 zcmdla&?3NhnwOW00SG3)_RPA(v5~Krg;OpmF*!RmFGYXyc@_&THK1ez!wo^{1uWMU z3@$1dT#z^1AhJW{x|R1uEAI=IJ{JOlF7O9m;0T^<&iaOtWwQz!Gb0NlYY5|HE%wul aW|P0MYYV$EGKMgAlze3XGm12TW&!}OiX|EV delta 172 zcmZn>*d)MrnwOW00SI^^?Xv_qH}dten0Pu{#e^2878S?%q~_(9<;VEvrMeVlmZiqH zv$1kb{>65h(PZ*5c5Oj# RMn(yW8|yEaxgRLM!0&&7!+*03mo_6~!DbKcd?pq~)&R!IyLjI- a`b=KM=P2yX#2CQXk@A%R%qUU>8VLYAYA03z delta 180 zcmX>m`$v}VG%qg~0}vbyx6hIj*vKctWa8m$6%$&VT2vh4lbV-bmLKDvm+DfKS(X~( zlAm0fo0?Zr9Fvk-mXn#69g~!poSmAN60_Nuse|3j2xw3P!v_{dexVyeV$;G2ceFNmlDh13K;url)sePCwgbH{3Oq diff --git a/backend/app/models/__pycache__/notification.cpython-312.pyc b/backend/app/models/__pycache__/notification.cpython-312.pyc index 1f6329d2265e82154f6c4872b330ce15c4fa7559..c40d5390de913d42e6f37b1d5e85ddf3210ed608 100644 GIT binary patch delta 37 rcmZ3b^k0$pG%qg~0}xDp?U|LmkynD5Qz|&)7lGd delta 80 zcmeybxJrrlG%qg~0}z--*k@&KJ diff --git a/backend/app/models/__pycache__/organization.cpython-312.pyc b/backend/app/models/__pycache__/organization.cpython-312.pyc index c37dae956a0388b655f7e314d7c82b116d40cc24..c24b05dd23b4e2d3cff2671d7e99b9b438736617 100644 GIT binary patch delta 37 rcmaEQatv$>e*G%o-|3>@MB diff --git a/backend/app/models/__pycache__/project.cpython-312.pyc b/backend/app/models/__pycache__/project.cpython-312.pyc index cc8f6e44cf496660828d1a4e7b1fd6c9cf4475a1..90c01178d7d8660078bf794db4259fa17a8c6842 100644 GIT binary patch delta 37 rcmaEQatvpJV3kPiSTQ5*sQ diff --git a/backend/app/models/__pycache__/project_member.cpython-312.pyc b/backend/app/models/__pycache__/project_member.cpython-312.pyc index a01da99dac1b326cab8d744a93292a8a98404b94..5980465573ea38469facbdf36d2bb876d65c34da 100644 GIT binary patch delta 37 rcmewn@l%5LG%qg~0}!Nz*=OC`$ZN)A;_qw~6Iz^FR2<`znwMXeALE~w>Qatv)PAQatv-t_@2W9{ynH=>1 diff --git a/backend/app/models/__pycache__/refresh_token.cpython-312.pyc b/backend/app/models/__pycache__/refresh_token.cpython-312.pyc index 2685a7c4a8a1625eda25573319dfc2ad6342b15a..2e7851809c781f959af552fabe33389878681c35 100644 GIT binary patch delta 37 rcmbOw`CfweG%qg~0}xDp?U_})k#{FMr*cwaa&~H7ivH$b>#Lw9(CbT%Us5r(aH7~y`KgK^V)ukx2EH%a@ iKe;qFHLs*NCMC5jCo?ZQCMhvFJ2fvQX7hRW1uOtMkR0{^ diff --git a/backend/app/models/__pycache__/repository.cpython-312.pyc b/backend/app/models/__pycache__/repository.cpython-312.pyc index 0b806412c23379cae6b348bdb7846c20b178f3cf..f500c6d79c4fd2efa9afcac7d839ce82abe821a3 100644 GIT binary patch delta 37 rcmeBDy06H4nwOW00SG3)_RRXSkynw4Qz0oaIXg8kMSpV=(+WNS)yoT< delta 80 zcmcbw*rmjKnwOW00SIPC*k^s($g9X?;_Yk|6Iz^FR2<`znwMXeALE~w>Qatv)P6Iz^FR2<`znwMXeALE~w>Qatv$>f?of!Zgl^ezY diff --git a/backend/app/models/__pycache__/user.cpython-312.pyc b/backend/app/models/__pycache__/user.cpython-312.pyc index 77ef6b60567e215b7c11bb583cdf44404d58897e..c878084a5328bce2d6ae604a121acbb9a825e7f8 100644 GIT binary patch delta 147 zcmdn5(5b+CnwOW00SG3)_RQkn$UB>pQz|JjIXg8kMSt=gP6K6mpj-pP4MEifDa&&g z<}Qfe;CH~}xYa?c13D+tFYt$5;0W7n%jLz$xM6b#_en-EHRGEcd>zHz+&2V8zpyf^ vu{C&I5K!8j&U=B8g^@L!ak3TvX-4D8Yyuj>p3IElj2$Ll8NiGpJD^Pf;7cs^ delta 201 zcmeBF*ss8QnwOW00SGd4?6Q0}^3LWoadoze2`x@7Dvt3<&C4&#kMYk-bt%d$OO0{K zPcF?(%_}L6Nl7is$;``+NlHx4PR&b+nY@wHz)%-xOasFQ7Dj%_8ucNq|`-Y(C x7glCfwg#^Y0*agUcrP$Av$1kbX5v51XgK*CzlNY6Gb2}r$yWvtU1SHe6aY0mJK+ET diff --git a/backend/app/models/__pycache__/user_skill.cpython-312.pyc b/backend/app/models/__pycache__/user_skill.cpython-312.pyc index 23de37301d4f730968210716a5952eb0aa5281da..e03cb20388bd18647ce202ce32234cfc4d0c5cbc 100644 GIT binary patch delta 37 rcmdlY-YL#|nwOW00SG3)_RQkm$g9W1sgRVIoSmANqQ5zx$(0iTyG;rt delta 80 zcmeAa-y+U?nwOW00SHco+GlZYWGPt&&5}#Sb$srr9&w& literal 0 HcmV?d00001 diff --git a/backend/app/routers/__pycache__/activities.cpython-312.pyc b/backend/app/routers/__pycache__/activities.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fdc28b1f86ec7db116d3ed4a984e67ad84a169be GIT binary patch literal 5463 zcmcIoTW=f36`sA36qh&gs=Fx3wn8Z;BcX24G&P`FYHb9S9ZP;8Qm_k^Se5cp)sy#By?Jldm-n$TVr8i6&- zT#e?VOdhJls_}fhn#d=r$$XOO{FPL7BtOCto~WWCD}f#EIQW#e_L(15M|W>IoA1<0 zNKL4|-EVd@j&vM;Dp)e$NowFJ=W2zV);2#xoPWv&0HDprZVfo zyAF6i=y;7IUB!FQhm@=`=R%tYw09khP7P?j-G`mFBOPBG=%3eJ=nG9gllu}UXE;MH z?(Nm|qF%1;Y3muu7+QI7?_sT>tJLtWs&#cw(Tw2T&CLgEAC}ZQ4l|^88!BxY9u1~7 zG{Ep~sG0^nAbNIGy`XG?6hW!fpj6${3k^-BpbM;&^zsK~y}8+}tI!r7pur5}__>b{&STIgj}GyHZh$Qj=7)Tz2%{?HKh z;*Mr;IZ%bD4PB_#6t!Z=7Mnr|S|$4>VfK}vgf@5jJrJG{-F{aH*|py)Hp(szxkG*z zUf7GjLvqYH_j`k6_;n!7D_e#Swp^oyvce>0nv6h)VY(46F@?1yp(&W2#uA7wb21a--63Z%~r_5g${7>qd1 z`w@T09|d(ZIQuD_!XFDx@6W)r8{|`Qz5H7^g8k@TqId=lvp8eMmgwT;wO8$B z7QQf;E(09Cu-&|JEjh<{g)j0-j9rU_&!qx9$eH$46 zw1@SrmVAq`PF!T2$mtM|T`xN}U(MAGFuq&O0xkh(8??7=DS8=3JG2V+EQ;^ZuX^as zx8(W0^!i8heE=BvwDO0Y;3OOh|0y`R@&fx?3l=#49rB05p(_KRv(S|h*+Xr`8JuK< z8!WqVoS+FKu7lnc^krr1yjK&U4`ROcdec=LiN){WzqSDdyw`COn>~qUThT1D4Th_j z=ja^_SFvZ_u|DDI48oO@39ty)_C-$5vjFzWL)6DW+y8C9l3_WQVFyJ00fvRFz{wCe z(j=D|7E(M_SI5DNR`zaDBd%1ZXpqkF5JQP6i2h8RM5&kEuc=Yn<#XWzx* z91*nm8QrV>R$uLR`f68D8^EH2>#+>TR%1CS{KdiDzi9Xih3$skplYE&(Yl6+Tnz7a z5mN1XnTj|8lRcJ`Q7=k992e5wuM{h#AFI`7wnnRroe_t8HVdhLajU4QS?XmfWo*pBxp?HRG5Na z9Gy`GTVo|&9xLrOM0nJ7BZ41Kh2=Mv3U?l^t!%EXveerUAS-1z-w^RhWQi8bN?6Qh zfs5ih&R#o1s5f+Ww=uazPc~vU>^BPQ_X~IKuWzocZ!(wtl(0K$Wpuu`!2peldYk?b zurTk`=HV<%f#bO6WcCXp|AValg{*@7cQXH++;zf>sL7@1`Pq?@KHWY2k zBW-{3ms60|`uQV|86dpx7vqn|+oHD}n`=jsCz1J9WZv`=K6pw*o_`S{v9V8Xe4P7i zH2rL5=})7}rq|DT+Mx+kfckS^*p#3)JtUTTi9M$>%rgC`8$hGA`o4u0@Mr=Y8w(HGkFe~=m*)^8NvjUgJIw!p?7E9Fp<&0FxLmeB&G(# z%nXK!!O0D>%@s(+rU%1ZICjUCOm6~=i^mT2=io^a)Zjrwk(bzGpBC!gz|)$1Jc%BJ ezPZqfET98~FZxl;285a&I@Ap2g%2clk^T*Ff_q2+ literal 0 HcmV?d00001 diff --git a/backend/app/routers/__pycache__/applications.cpython-312.pyc b/backend/app/routers/__pycache__/applications.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..62c05cf483b77a0eb0f19fd484dd3ebb4b9d0770 GIT binary patch literal 5241 zcmdT|TW=f36`sBFvb--ziPXiEd{Jn-qN2JrTGVYF*+7jHiebqwL;!-~u57BL#Lkk9 zrO1F?6e!x4qDTSvFBsBG|3>p7A`jXuVjx8j6h&Xwrh@=^$~m*U;!>hYHEACrgEMDm z&VF;wH)qbA^@q`Dn84o$|Gu-Ks)T%o58j{T2wd-v0wK?cMl`NLnp~OVQ05zanTK9z z2u-mpHl?!El*@86P!6zpu@P*B${{98jc`*bD@>Lfk!G|UWpbbqYsSlQCI=gdX0n`Y zrpl?NT2|RusF7}F${CLEL>INNraa*GBYV7KS2?R^H%gwd{a%aeDLt^U&>!)n{n#FO zf`5P~>B=7Gdy0Bb>wJiK|FnV@|DCkwsF89GR{Vkc;On%6p4v}(b`4^$a}Jg^qosUE z6Q>}l`lO!90roMxBkPW#yS8exTH1#`bqads6!aq|j;uYeWqo+lfcG<>!>)K1ztMZ` zf;Q$uD*)Qk5VY|#v6%BA&7OjkKNHe~59$0VNU$5ncH$&gGuo67=>j0VJ;b{N#N;ne zj_*&8jGJ>l^to-mc=2BdQ{*hAy1BX4uD0u2o5pfcv_d!U-nqBcY3tMq+|pb6re;{t zU#za)z5S@Bw@}TJ4bblx@N!^9Hw+j8QGTGeE7}@J36yFbO7+clrDNz6#>D&B3s&-G ztJSF2*m6r$ueNnd^$p$AjTYFU59r-*X`lxnDWB$wPJdIc={wOj!@Qk$GgHFhXn>?77 z+w5|?{D$ZsapYaHArBo54jbL)_S}TILW=xyQL=b#&5F1#0-bfu3b*LihF)WGaJ^Bb zI*uwn8j2E)1G<%}F@`I?DT}Xb6jKAuLsJy!1j=Km9r16OfkYGvg|E)9RcpV3AV8Ym zr7SLtcYT1yd~2IdA_z9)@H2i0%@guEOCr;U%0gFJFqNp8nR!>~CQoSIBd5x&9Z}@14xeesmS!oD|l#I-6RNrx{q)k~O_utv7&1 z#&;Y8-)B0-oqsM^G2a-tA5P(0FntyZ zhXuGt9FWE>drV{-b;CLP13uCzSP00QhK{jd;Eomw%xNp$+#b}v0+UPdGiIP+1Yks6 z>nhh60qH-*{}2ZfFn9z>cAU(V+~ZMtzkg014|jVWV9(-q-$h!4SHJJai5o4G|j1H%=%}th-oK z#kmz|fR^-s9sjQ({=FQ;j*J;pdjSyxM)U$^{6w}XRcmm#D>bt|IWA6w) zv4p4CJVW98*c71I$)Aj;_v-D38m+$fonavDSv-P+>*zH$e}kX#ZDVS&t1KSfZ2qJU z*FRpj!|6Ly-uu5CNRDiun)jfv)Z6+9`hJA;Ve=uoIc zc-5E(+50S^jI1cAP;|m7Fg@pUV?eP2Q1}hvR0Fb899v>*%V=8({9>vsF1%S;x_A5L z>g`*sJhlX=5ZU!;iC8?)E4T_?|CZ3|wAqbkNv&$T_K>A&mS5Nb!%`C?%2Hk6YnA19 zDogJyuijo>Wij;J$v;jh75oXf+iB=OrON=0A1=n_8=h?@WFr4LFU=L!ciZ+?_pv;z@NHj}fq0R5-IxGh0%%S0V} zg)=<`-m=3uHjUuK(pl5i{yLcek*&{qCt54$f%|e(&ZZym> zzdWw&Kn4KNFX%r7swC)vqEO-$&bSug*aBKK`E=40r(KF-$0<@>DCn6>(7OO2*;oH} g0EKU1!PL_!++~cP%iY9f+@$zf9eEi9N7!BaHPdJy-2eap literal 0 HcmV?d00001 diff --git a/backend/app/routers/__pycache__/auth.cpython-312.pyc b/backend/app/routers/__pycache__/auth.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6706c2454156cb31360041f559c0558c490055b2 GIT binary patch literal 7747 zcmcIpO>7&-6`tMYKbI0MO0s?^X)Q~lXj_uy*iK>_Nfb+tl{m5?$qlkdK&-eci4K=k zW+}^Jox%wMG(ipxkVAaPAw9K*jiQI5=%JUKi=rkJK9 zl&H9AY8slEotgdi{l7QkKSUxS0>6*`HGS<*eT4iKADo}h8gM%oJcN8qRHAZOqH{9G z;h4|zx*!X>NA~Dm*{l0xADb7lemx)u*w~W|>LEGA#@=jL7iCe8$Pv9sZenx3Y_lGf zqipQY9?)Cl7LM>l6V!kjT;lG9?(!B5a!iX|OFD$rdNr&?HQ%)(wHarmiuWRSfo}W( zqDKqe<*cVgE=cg7I<7Xo>%D7D61jb!FEneS8ohVmu3&B42kV5|;=(!z@`+_T^iH`` z?~=P1f34YWJub)f9=V4-w}Cu*(Ny9 zxsZoIz7ohUAt&@Kz|NSUn z7IRuX?4siMKKu=6Np)}+`d(Q*sSdfY#`nQW0Hwo^#Cl3iy0A{{gLOn3QI9?n>uL3v z3+st}uttEc(MMvPQO8_ZC)bZB&;Ap2kmSs;lFQ`_N+FZa8A*>BoVYSQn_n$x)bvkk zD_Tx9%*e(0`72X5(%K5{GJOVYUp3%e|D0wRFa<;3l2%Bm3rWEgCsqr~vzoC2fSM^@ z$}eSdv)Y@hno%&DXSJn_0pRuoyeM8Z@X^|i^x*4r8oi!LYsKK0vXU87V8(31c`aAS zq#3PA-t?_dZ83Ah^c0jO1GZ8dyBKr6A}LZ%Ta#Ad3qV*CwZD?m^Qx9L!xkT@G(4Gp zV^!A`x}LTJ9kWmjHSovnJOhJ|Nx=?WgxusDXMT&n$zQWW5_`vPZj$N_;ifPLk}f7f z68z3nO(|$LWs}kS_22u<$`k}c+9>hs&-);KQ zv$rm7g%56qrBYb>^x#G~d24bj+9cWKQBUG}68N$`)HHCt8@usM1Xh^9-9;9zZGe!!m z6D)4ongRO*vt$$VxWn;?CXgp6$#DQPc7Byo_=4Lj(p9?yvb^vI%yB#K!Qf*^pDwE; z*WA_%>-ekMA$OBgIh4>GIZO(6N+x80&^Sj5ezqB!LckeaV}aY;|{6w}w#jRIBD1qobLN?V*Tr6mk$dQw`Xd7Ul2_{zMcMpH0W7mA0cbJvw@ zMwQS`Yd$WeYtkOQ!_yd$VER<8pk%U1A05EQuxpPQtOhBHH4{ai%r;b0>g4h9)YX}Z ztMeBx&rZuzlVHIkxCPC|K&jcbV#Y9#*`%k?-clKr9)}H>zl>>UZjnk;&>Q-qrT6xa zH~UVP`c7}OJo%n~tGWHd)%SmLKhX2d-@>h55f5x>>i(jmceCSUspDih_S6Hf&>X4| zAsDI%u==eL1hjWLqW4c!Cvi0v4g{CqYJ`P8_!_7G1Cc2yPJA&zV1kl*A zOkUUMX<%XvWn=qQYrS6$m%_upgm5x`-!snqsu+Ms%^aZ^wmm`ud#K~CYUE&<-_OYT zLIh}GznkCb4o3HXZSvebzGm`;<|=+I2|$Q%m;`uLK*>2S_=6m;j*6P&%@o@m@3F-y zu@E#$kHVKJR^-WmI2l%0dD0E_Vh0<0Bb zO}`CI&%*Qv@MmBHp3>?EH|QAn^p(xQGo`^Z8y#ogi#&)DF@F1n&G>jJKK^<5M7^6F zt+~mAP`xb;mcoOd>c5^U4V~EtpS|xn`^|$MBDOW~H5Z8OYhj@0owkV~^4ZYf^I@Ur z$Akuv*YsHtxX%7Cd$1t;!_pW%0XU9-`K<5JlQ37Gp0K*0*!&8Y8oN<%DcpN|Z6lnx z?@3tcDPXppUsiHU+7-nx*78(!QcBx}JYC8cc2BqOp0+ErR>(ctp54uJtLZdUch$ty z@*|CA7T2eA2)@pjVs&#iUN7S1RJLRnYwnkd(Xlimdt}9?yVz{;AvqMMQT)!Y8VZ(S zrmmvk9k+UGKlkGx1fZSn`oXMyq;@ad=&>9{Pm5FCs;PCJ3kGT!b9a~&uy&~9jLjemxzfS zBA|&1Uf(wl4m8eN$y)NO&s#kCj31mx2*t?Qbry(6nBNpdD+Eg{#Mb4os!jhMD1ZDm zeb+vuJO@#Tf6)?P$_hLU6hDivV>1Xm85#`Sh0MN+ zA1H+f%7L~IwNfBni$?pZ`uHAIv*SS9Y4Y2_iEg3T$^uwU9dWZhzSoMWyvyeg+cDEow;gR5xOV~vvD;sW#ME9m#j`K*d(bvDE31OLydncR}J zmVxlFph+2hC9COh+yk#y7BO@(A zb^~sdjAN1_xdkOL?Mlmv0iV)x`0>Ih9Mj>Rht)NvA7Y%LENR7#I#F7$S-b6&bpQ`W z>>#wTZX3Q7xyY+?3E)VBaKK(n~Oa946JL^<*iWEW2{pt;y{G z5u;lNySJj3xBcEI92vcEWb7cV9p%`_w$}+FEYHt4<%NhOv11yZ-t275E@B)SHtUP&j_jXpf4Asy2ta|2Ioc)fso~wV$u7aL#I6K*J_Co#aDKnHx zEv^F5S}H}+!cG680+)Cz8S25U81ZTc8nelGGpl6N%bLDEnx{HNxtOhREjFqu1!X}o zv{A#lzoh7SW)znU+^-m;coRWG2*^Z;(yiZs20`(xX?C*rENiu1bnfP?lE-J=!kM0x zJY0cB*>%JTxQ;kKJ2f#sHECVSN$dkQJ3tqt%1mLMqNeC!TsweYNkfXPEe_z~AT~@x zSR&D3+#9IAj~5rF00zvC>FjjIP8yVH?>T&90vo25^EhIvn8Fc?-}J61h4ivjpR$UK zWknVt(XQ_hW`&mZ2hPF8>S|VdhF*gu%m>B-sHq}w9QP&Zf9UaY{0@QUYmsn=|4tGQ zc@M{L6KK8;5$?#BWc)9|mU6hg9O}9s?1uOl;&1sX?Sv2fwEOMuvZuKm>nlgwH=~JC zG*K20Rf2?%03y$CM@g*f_RvRT6|cxe%aM3RfPO2`{1ra$L|{urgi&R<3ML|$7=z*& zF+70LRK*B!iE^Z~B0$eDpx+6@mP!al54#9=fqUo?IR0V4VPIP%V*3Z@ZUwem$oNyg z3v3*ps0dLmR6a1m`Ymr@#|zJu<48c)+g)W(upApIi^E8OXb~Wi*6#b=qZ_fYKeu#R z-1xZ@89c(HRV#nW(mp$#}SbtgULF^_++Pj(ci=3|<=||Q1 zwt#6+ov-2}!RS}GVt)naYDxsyqz$`Ai9s6;dPXVqHU^9;{Z+Qx7-?}A+ciUoBgUbM z06oKi-o}7Y3Kmrp&H}AT0>eR}r9RAkf<&FshuaVstS=5)CmV#5h_Jpl2A+ MGmPyJjF=Dp2MC3rYybcN literal 0 HcmV?d00001 diff --git a/backend/app/routers/__pycache__/bookmarks.cpython-312.pyc b/backend/app/routers/__pycache__/bookmarks.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fc391d611f214cc681517a1b3a0182a09ad0a329 GIT binary patch literal 4577 zcmbVP&2JmW6`x)1F2Bj;hbfb?Y{?4ZP>#vUE(#Y-+QzW~8wDi8mVtr|z*5|iN_i== zvt(c?G9VX4Tc1)O2GVie`#0mKZU&N!jgf#edfRN9LK@7Nkzo#)fu>SX znrcODY89;+tOWVGVuqUGN|@8C8EHl5!>6QyBf2i_#a_s+K9wxZZd?{hj%FiHQ#82o?ua9(y~GQ!03X0pY4nBUdy9*= zH91VgpK;zu{$73Iijm3`d~wlx@lA$KQ+p|)*Esf?hvs025Dew4pgI5ASwKJ>X`(9fL;{RE#t+-7{=y0|45=l_K&7bQDd z+uUq*YMn-F(^@JjcKCz4ckZ>i9m?$BP1>fLhGoZZudLj?^{7tUC}wLG$agK+9K260 z3s^vE>$FofR)Nxys&^Tqo1JRcq6~P-19#SMv|10FHTLixwc7AS3TsKhyHDB2jXK?q zlvh0|%MOc0t0>!Ao6)t#BU|az)~)R`DPC8zp60+eHKbP``9cf42Q2ZR1-XWsg9|v{&g=wrs50F@Ip~5Pj6JI*rYB3mr2H z&-b&dwfaNInsTk({)q8JvOW@kR;j&Z>*7sl!p_6yEc~or!LUo-~#X^E(VQxbV*bL0< zq8P3MVZ8?fcs9*Fd%2gq%w3cjr~!1T69JdL3{DBJUK)87mSWl6Wp)7oY^gliO*dfi zG;W$yKf-n37->nEo-rY>+;kmU$EM&bkloWTamy_XnP;vYYiY3*Y*`8RpT@G073>|@Qk2~g=C~cAhK8nq6?pm{wIX#yl$Am7 zm+-SNszXy2d(lO1O8Sr)+nI9xH?;n6tSOFlJuG#e+_!;%isvh&aX@)-Wp6;1Pr+Zu=;V{IfBb`4Zmho6NZ-6c+zgwH%{ z?dPuba@YE?L_c=+)8(hj{a6mV!&JlxXc$w?i|O|C#51B?hg$251$=lEV6~jWDH53P zIZK$Ya#Rudgm4BNJMb}viR4dM_9I~MVGCE@f&r{cld%5m!hWjUOO?5GIS6kW%u>-T z)iVoP7Pj~?0~BEJsBQ!Czhvx5Ez5UmVdflq@YE8HkjNHcSa3y!XTRHm+>?dTX6xh8 z$-?GAY`kAx2M)vGDK7m2hX1Qy!6~3-_m%mcGSBNn|Bosvd^=cf(sIo-Cp+#YeDXAo zn^X*AF5nHo>*0CNaQNz^cE%RaSbrbO`ZkCZve-{R?5`+#4hHTQH1bMMxiac!BSVWC zFR|~#-EPAuJ$P{EChs&1Zyj#?i~q1P%PSKl#<;v_56QaUaS z>RPwcWwcslSm(BaI@!Us8eGcS4W{5{u=x1-#_;ZBC#>I^H52+kbF0*1O|G_`h5JOw zsC8AFSNE$*(eY01j@R{I-JqpPxp& zkMnNEiyp6MChbr=<3aqey0l#VaCvFv*3t?u10M6|gr80PM7Kllfi+!|{**0&x^ROa z)*m2soPZ=r2jt>6B>EkB|4Z^d(BG0v2jt2DnLQwj2js{945$0isea_lpJw1>kI1{4 z6C-lykJC@4`wHBm=KFeXU%%ATFF8RX#|K1_lDHX3WEMR9(vUQw1jg zGeEt@_dys$oDfjX+e3h0KQs06>^r?o(FYSDg*jKJuhMzc(NRO7S~}+hVCHx*dw4)O zxgj1{dlYY^7Q&!~C&A=da~POCmjLCwJA{c(f;np0 Nu`YfU0&np={V%+DtV;j@ literal 0 HcmV?d00001 diff --git a/backend/app/routers/__pycache__/builder_flares.cpython-312.pyc b/backend/app/routers/__pycache__/builder_flares.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cbd14e305775ba0333ffd69263f8f77819497a07 GIT binary patch literal 4267 zcmcInTW=f36`sBFvb?Ogx?gPiD$tfi$99ndZCWI-e|B=n62|SZX33*0LVhR>%3Kc;>S+vB82)$%UO}QdB zm5S0-D{3=QN$_#mN;XrK6qgk%-P9@?msKm%%vQ2oPFT5SzLMv1($bqlm7!*#QfL|# zgX>b(aC4+GA`p>K*-V?-BVjkQ1FONOGD=6+%Yhtk%`7d@#QOEPE|7O~J5nG4o%IEFRz7OaueVBzY_v*u_F?+oDmGUi?=p2ka#Ry48 z9Ll`JZQ7^nA0PApT~1{H|vBkEMmRgiR)>K(@DhEwg> zlz~oufW71uKIk+old@k~HAWX0tvS>ij_dAIyA3O$gO(54CRhTF5w~5Y?Dvg2-OQI) z1JrA42y1WVLaQSGj9n5vwaw^S zSKQ7zVIe0_z)f*iibnqcQCTL><)y}7A$pr*1Nl*e{4cJxIvZw5WW(@XPc^AiYgj-g zr#giR&6mwEhLFa|$O%p~r##}9%^<=MP8p=`66mkOzx^|4fVu+77WXryUZ&(G({57l zD^gb7Ui8x>ncd#{XKuV33JKD4;2I7#t&@H*&? zfn%6`#n7{<0plaiA*&z3zl{Or@x#==(bI15_!S_2nCgfih+U~GL^lCo<{W%JEFkOx$UL9DOox}(AmT855l0ToNYY#llR<_7 zC?O$R!{M|6o)}(6uu$5|&;U)tM8B|~pX=r44$@p#x9?z@>wAf@WAgkB$FPVK`Hp4JNoC{&zM;%SCFiYdYkau@qtB&)Y}{fD zFL;Ah#0X3W3BCnp=$4HolIP(MB=|~CyK)edcN?AB9nYJb7yd!vRhm z8j#9vB0E?O4^uT9A7t`fF!>AG{sx*K%A_*BFJJ7*7Xv20QlkA|QiCm&0qo$ENTM{2 zjRsA)&%Q}@It_FF!GpWE53Qg;@r=M3V21}T`zbbuS~W-0ec!dv6!{pDw z(T+ub!9Ii`JSOdT;Y{%*K@eV&^IsC}zvR6a9c-&zDlx`h<49kFS$-OI(+EEKbkdcF0NhuI znCTMhujs;%n;Y{b=mF|AzV}mL;wM4!FCPGCt}(VZKG!p@#bDAAj3f)UT$ql1 zI2|NEcQ75UINzOqxQZk=q)+$~^n4Z2hcF=dqX#fY+=!_06C(hCZb1J9Frz>ZjHL9} zI1)mk?m9wEKb>~vv5=A6QAUgq3VOa4=tBUI{5b@ec{+oXVz93C^ef0n{s#KrgXsVO literal 0 HcmV?d00001 diff --git a/backend/app/routers/__pycache__/conversations.cpython-312.pyc b/backend/app/routers/__pycache__/conversations.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52db38f0e8a6d69303c35a4be2c05981afef6b69 GIT binary patch literal 5789 zcmdT{-ESMm5#RgZ@mr)xiljuzq8!-@Wk+)4G)9d$MIyVX(Ly#X`Gp8TP`s5*l_#=$ zq-!Y(AQuISKD9*xI8O!oXjo7AH`)ggdC=t$0}g_=DEe|XZ4}5;XZG&MBTHFIf&>kT zo1NR8ot^p3?CjoOqtOt7--rLcw(-#@Az$K)`}5h1(D_&<bhn9!2NB<~B>Qrc*7R3IXuvKmsuw}rjPBhj|2n5OBC1=rYKt43*p`Zvz^dR%UA zX>JRJgl(fTG?w=T;WRZ-R1U>qceYqf; z!FO(4yIF5FDKq_7XoGI5x*7f1>gtWF_bRl3Vy2>ld`pMP{uQe0&;_h=n>I`88gOys zDlNw7X0z1NDT6-w7PgX^SgLQ{rA+7REiqbdQZwc4yGiv1SVH?HZ#7hq1U*Tw>Ncq4%rjjBDz8zipv0nsIHlT`mZ-BD^*o9 z;&tJn#A2YrOjbBTU{nt@Q>>~mJ`Uq7i$W1E)H<4;&*#6ISu0n53Bg+^HyZCT9#8!} zuO5BAvBf4(3lh}SnE|p(o~KD<>L9$>4lf$vsBvQQ!PK9ojM3@memSC8MD{5ikR#tU zNGt=3upE+;KwQUI9(%fW&*9rNl2btbKWuud&!+9f!uwv_A=n=j1eQW`y%~gA!}IJ0 zFvrL<;+E16#2s-r+H|fR1g;yZxF@-zzk!T|jFXqEA3^4Br{*tRh~ntxYdhimk~&Hx|NF~yFK&2J90sz+8Ufo3-9BB`kj^Sq;l%GUG6TxI79MBc=S9Fjtx3m zXom|nHbx*e;OKDM7h(F>vt1xtgn6xxGOE?@QpW-I23pl;@I~lhNdAIDSj4%(zU+Z~ zx-FmX8vMc!$B7-3@gYGev&x<7T{^r@-UF>i`XP9>!Vz`yh^+v1v{xq%*$64e;J!R( z1;n5ao*zRGL-Gkc9W3~~CVbtp=;Zo^cKCu_Mg~gA_ApH0-qWnJ9}uRF!AD`rPhBK` zgNI#0atg@s+&NYm{Z4X+@1;Y^DBMG7lOE;h+vpmSf54;v9LP6K9^8&++wxgEd0zP3 zqo<(Q*UJd5gf~MLK*CSFFmO(7|0>vORn_@hx2|33Nx@iG&eN;dr@>E94?hw{kn8G( z75Qnw$MNHrajrN1su?Pk)?3XMqooqV&1A~By6Imp!_B=>WirmfOAtSkm>)$(^k3D= zwaOi;ZOzx2#@#Sea3h|F&x!I{S*P>5{Q<**C?DrT{G*3%R;pBIA?%J}H~&n~=dnmL z1i{Q=ua3&g`n>l(#5itIkYVVhIn4#_Z}$FyH|l!RjN>;~Y4QB) zrKOu!-&wtSg6F6Uj_ED&8n9UoS0PUtYbs zyvnPx>1&jml{>ryF}`sypB~yfh95a*;4N^tRikgS6&Ql6Bhmj1uv?NK2#?9BFG={H zA<4`$9O;B%mKDOj@gKJG@%!V3oCR1c9}y!RA^{o^2Mx;?7qZ6aNlStjKzN4l zogj!<0pP4N=sH&bxMudV=i15FJZeH@eA-6yv&0ypYxx2QYTA;Z<@%s?^Z{q3yZQzU za>HZ!M?nD^1nm=ujt^RhN-+KmM;ukycfK2yxn8`%Lx?we*i#502~dMuiw= z+t+TGC+|-hvaN8g9iKyAW8X^Q#Qh0F&O7Lj45FWOY=f4g1+8NdaMn3=@mnk4E@e4J S11|Nl;4nL$24IArc>e|RR$pxZ literal 0 HcmV?d00001 diff --git a/backend/app/routers/__pycache__/followers.cpython-312.pyc b/backend/app/routers/__pycache__/followers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bd651ff15f3f35fa59192bee08b7ce6edd2ad407 GIT binary patch literal 6777 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 F;J^N&1kV5f literal 0 HcmV?d00001 diff --git a/backend/app/routers/__pycache__/notifications.cpython-312.pyc b/backend/app/routers/__pycache__/notifications.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6e95df417ef45b4ce8b7968e26f46cad61aefbb1 GIT binary patch literal 5122 zcmcIo-ESMm5#RgfHz|@LsZUdm8kv?&T0+vKMqR+M-NtP|xt9Dw7+@*h$)R$T*gdka zRT_|s0!8`~6e-|7^dB&!KcN3ZUqqyZE{7OM5fnwym$T`hK%P3YyrYg18L37~L%Vak z!{5#PW_EVyKZnBs0-sO+b$fGpjF7MJ!Tm@*f$Q!IgghlGQ8}H|xe~{r%yqHQc0@ICAqGY6t*wwzPi8UXR@RR>cLWw$+8}*hf855D|)0JEk&8^(_{6q(pWuS ziq{jR1Y7g#$@+L{oFhEZL^YrWA8`AjJ-%mGDW#=03$C$8vl`aonzDK2XvLNGBYWTp zegIF>f_t3jDeOLN@P6X{Q_rc@H@@vWcqTQb#rMZty9Tj0xE_|8RpTC{ zsS!wFZCZ;@0QNDwzIDgY9b45oHQ_;@8G)XBZS-*u`s@hwl*=Hq@pOyR9?WxqdEG;) zBdVD*F+1Twnj3*M`CnQ$<-t4;m_Hg~-5KJJ(O1u_(;l>WK>Nv1G-dOHlk594r)Jiy z2YulYpL^q<2$SQiU}bA-yIE=0wzrI8PPF{j@7%t--D+yoQf_JuZA&$*@cV0PcWynb zY7JDgWCQeD27Fmr)eHlcK$IV7&9b@Ky7xhNN}5hVAY{`iGEB=E+FYA# zir$r;+~zkC=h&xB_PISrdzIvPq@P#Utq|3!wMGr;tEraXfEZ{L#gNy}oJgYpXeFwQ z#^Jl4mFh?EibAE)xKCN+jr(3OBj0#Lrw|1P zL^dwNuuER0Na);QaJds)HiKbveC}{O-x<%F@!6+^-xc8bm0t?UHjyN`3tu2R@xm{? zz~Iv397mI|RrQjIlrYNgfN&Pd-RytNxB1<0)47!h+(s(DFSxtE;@bQwc_tQXzlR|1 zq>7%T$%0+kjqTQ!n&as>yw;Lcty!t*KpT(4`kugA;%N8$l`gzTZ+9C8-50Yfn@9wJ5Kzuzl_ZvjxBY@mdsGZ3}rr9`FI6l z84uWkd*XWmO`kmRh0y_i2roEG=DLoZcHTX-4J*G;4_u^GLNRnsP3;|4{E8K-SLjFO zicvf3k%k39qU(ctl@Mlc7lt&j5&TX{EW8C6{L&0R(A`~s94tIOyfwq&quIpGIk8ap3lA@{EijhTH+>DC#xYG4LUsxqh zX4PA`ioD z8u&JG*K-XG}$Wp>E@;UpTnv)Pqn`jTBmL}o>Y zS-6t%1{|JeXCfH7pgzH;T*;>p>^Y(wc{J*fCZL1Un%V$;L(b~=z$=QwpWx5H{`z&# zDyHgUM|95W*O;cP-sR+8KtuQ@?76592X;#aL2{!0jlb2Zsrh^NZr?o8g1x?;XI1Xy z$yLN*ty~19K6dVc6)2ZCTFn;K%4G_*fLJ1;TgpZSdfG;fVjfXEA*^Mg3aUhmpX(L9 z`k_{Tl;5UxW~P;d4loamc4fU{XnCX8+EYL3$JiG8IiPJ-YnnmvKLxBPF0%&O$YZBZ z(Mc0>1v z;J3=fmGX_1;@Yj^8q1ewghiJ%Hyze(tPo_*! zF%t`BEOi)L=)@Lmh4A4n5qbVagd`^a@aCt5&nL16b4#C1EZa(ulg;?NEx`PxFKSCL z+cHU{U*b+T2;Z^;xHgU8lTRj1F$3VXMEFpb2!I)KFl{NuWz6weTYwp$UgC4t4=T0~ zB>T-i09cnk$Xx0qE_+}CWOA-&)93LCw9%G)Xj;k^U}ktQJ9r@3sXku#e~g#tg3=3t#&1N)N}64*yCVtOhJ`!lylGA zx%0c{{LZ-DnUMQLC904o1tBE}sEc_qB|<6X zrGlK23rb2UI8u&+GvzF}QZC*`&bteql!xm|-dpgcd|Y?r{e?g(z;$Q7rw~j9x$esM z7Wz_sg-|L~2&cll&YkZsL{brfh=j_jNA<1<+rCGlVOuInqpLHP!Oc?j(-3v7&Ngc- zZ9DKtGIYRGsPBP zgSMVWI`ll$wr7Pl7~aQ_$+vn+J!C_VcR(NRfZm8^gYg;lunlh%@aCE^v$SqvhYYB* z>WB^PD4<=kFq)+r?;?Iv>ZlFrcn72-T_GK{A&qrFI@T4^aU0Tj2c)sCkj8CDCpsXV z=n5%eLrMVBwItf>cGyFUu=-y1RxK_@T zb8AIyKB4ID^OrAOS*w&O)14P-i568&_y73n)ys3Yvb2QFbmeCi%GPy<2A@?lz;G^7 zO@lX}I#y^otuBEUL@irkj26r3ibfgK$=9%y^u7hQk}2jkc()fA&6KGgw%1*uS_urI ztu3#WRA>n}A$!|J%5LVebR&>lv!R03_C{Jl)Ey;8mvgstxtv+ibRh{<0cLiTF083E zuX_!j(ph-Qn)4^;Spf;p!rntr?vt`Pn-a2W&d|J-DK>>ovI=X-{+|^k<}aIT4uQ2s z6}Khp&2I!7vTOhMgaER*%2%@1cbjBew&t`&l2GPzpMr%OaXSTZEniuQXYxR|x*n&u za#~s25?KV0bcagInOq)1BdSZfYweRFW$B!%`|Ok^94v^9y%^c0^)%w?GD_ya`cRff zGHw4x7jtStVu#>8gLRkaK6^@NNO3$K|Mu8YCVK;NEtx5mK4v`qw2$pL+H`51jUWn& z82oDsAnuZv5#k!!b&ge?V-MLE=XNK~RVU7U>HOgDfuUM#s22L(OGWDO)QRNwyz~&? z$gX#`>Yc55{k7iV`y+oEsr8S(bjm(Qoydw~4OD<0T9ar!iSpO zWFC(#N$;^&f*(8tJQx=9>#i$dm4;%S-X)d=}JCV$dx%StvP{vN`~SW@UO)|Ku(1D z2%4#SXAJLaF8^L*^cZ26k_Fm6+8+YOfnFRibuJQy+h8m6V}@sZy0V8)V`wn=KMIB6 z91h)hoaeh9EUdTE!EmR$2LBp^=RinCR(k^JF5_WZsFLXGo;q&N&udy^W?u(D3MV)q9$U zZofC}SG$dFOozm?Our*-O5ZiL*;Y4PGWPv8#ZAec!p2aRc@i6Ql(EiK_&%V8kc7-m z0Ge%~=~0(jT4*x7hqcB?0d@{sqxb{-Yl|RwdPh(0M&7SR-fv8KQODf{obsYO&ckh{ zJo}o$XUUo?ynjRtytLee3f#;-WEdH zI5KCh;Kn-gL#SaWw(!+u5Ipf-cOBVJYIy(18*0O7CR@(kgze!w!)d=|@jZ3STWX00V}Z&eb=ddGDM4(+r|4;trqd&N*pAb&pv<$qn5 zl-RC3QI#hQ{=QbM%^;kO`5D)bJ@G?^8?{jsJ`m>q*lAvyE0)Jlblh0nKh4tw*R$%D29)@%LG+fqX zmNFWh){N^Rh8GulkiX(LOSG8HQH^=Ax(BQIC5$$Ww?&*aJ%+U!f@d^9Z(bTPPILgi zWax@M${QLtL9H#*0EYKN#!<*&TrTKxX-zBZLA=;X&z_n|U$`=N{_5OCe!HMca2hoB zn|S)uWjti?qYytP@SU|Tl`3Vvf7F#yrkuUbw>^B7<_ij+0{M`|yA{k)J!E!vCOyB9 zzOXQVb#DGDPs%OA&lASc#B~lxsO0Gn*e{`PNLQlmK|Jb`AP7&$k*|pN-{j)o$VJfq zNyeX$sV5}>s50%hGn zLeUraX3q;>)je1@hTwzu25WK*!0QSTeS1U#OrME~pT=tahY>0UP%rR#&karLF3@ZM zecuJ(@gEET?nQTElhx3a%?=OgjeMGUaQ^eaV^G+G%)<*`_MUj$H-HY;ogVNLv7vnG z4b&AV!B2Pa1->!O#Ja(TpYHa(42~MqS;&eD8I05=D7o8Ens}hqBMrQ0JG>@)2;&bP z46~1ZE2MR2KL8;8P(Fo-Do~mpf@WHTb*IpxL-!8V2>s_Yiol|NGQRBSy&Q_+mYhA#jbq2!z}qGLg9)$#Y4LLz&O< zNgi@X&XE_ALS9UYd1um@my%N6m2|N-Le8D{Bt1+PbKbl!>0`1p=g$X{0VYeiU_O)# zG1-;t%ZHQUd?Xpk_b2;VnLD>9A5BI%!V^W1J+gP1+w$Gwjj<&Ml!28a)__~N>{lX+ zYvpLG#FDlGw;YBHc%tIF#o68h*4q;ACe}|*$ibhBw@iR!48Hhn3$2yQAtkcaXN{{J zdx^zw(k28H7Q$jZ6a8$kra)SS2|s56FAB2D|HK z$zkcjP2@vz%=YEc9$y~n`ejjRYPdr~roQEAdDw;?2lNvy9b3|qbj@&^U$OIubC74` z5gYzE;J;y^wsIM?)~2zivy)kQ)P}vU2X_2RVvpId_xHda?~QGZ!bkj^Tq3N;`)mz8o#UIZzGQl>(wQYfb?szRYmIFGqQ^Dofiijpaxph~)|XhHM! zjG~rc7)rDLd`X6S=om0toK@)MY(`mg&z1}XRdbnDYJ%6CC8{iCuV_L!y{u~7EEEN( z37X0mWhJM1jZvpE@Rl(>BGau1DZF!yn;_gEWz#LDs>ID-*ohhx- zQ3SwbFZ|UXL$XdDMTslAEsfQrv76&Jmw%W0P3|-48-EQ9)%On7BZnV}j-W>;4!7r# zhxlUK-l>{*s_ymI`$lezelS`O4Lp(rpHnA-=xhKWS@X}nXMPiAd^N$*Jy4plGm0!S z-m4%y4eu6{SNSTx?k}U=u;&RpqZ&IN>vNR>ZJHih~79|EV3`xXq_j>E!?FBK~V znWBmkf{i9~QU*c6Yyl|B<3hWfRo+!M9h#>#Yeo{I%i@NP100>QlEWaV=*B?*VGIem_9nM;~)vh9tq$8OSs~*TX3xN4qMBuY&t%If+ef9&mB` znm-2)!J3x}oE8S@TXZrhRpnztLQ7 z2Gy?FyfTa5>Q3_y0BF})?BZI1*jE6?Bvy;CnHfIKUj>0)^eJH0Y?2uPnp#gYYJ37EyG{)Vvex`n zp(;GddsKy$ZeGK&(j{hGf_*teoR%jNWU)uY=@wb|s?cUO&Urckv!Roipy$b62SZ)! zTTo~|%L08|Rti}~HUo#@NpQ4u2$MJ@TA;#Wx25TXNDpFNGioq$G>^P!wNP>R5I9Vl z==ZQWCO?C}x&{f*6D8sJcHhBT-@&GP3Om=|LiZHDEe&?@PpoQNiq)jpM(*R{N5xO2 z=`PLe@q{_Px+~ae+3z`FNPW=Fku{}Qi z5K1T}|H7)%kg(YCj0S8vo!*uiZudBFbfMj~xDF%uYP1M2aiFY zw}O6GhN%;In*+>l{)FSSZTIU zrg#NS&tTHThF(o{TdB*~h%8`RHlko#uT~!zG25H6mQ7S!{UObhN-b3|h^0~#!WPj4 z9K9wjrD5HavJ`ES;s%zTF)7~tP~50%0rj0+I+wYqo;QZPsj*0tmcEGY*GN<90?9N=3D-h48X3b@cF&)QK}EkDog^$L?q}2ONxz7>TE0 zO~7LpJ0Y?ol;$W^%51l;iKTQobCK=t*xrDJNs8VYFQU+jDf$pCVt(h9)conxiPQ7v zPR^fW_Pc59B8lnz@8!4#VAqhhKN-*W|Z5pvy0A_EVxrs0KN zx(CZ95IlA*Ru>`wu8V~CHHZT+eI}+Z?%^W!(4g*s9H1WJd&3P)bQeha;U+-17eELA zJboOD0RXuP0FrG4Fuj3|U@bCb8-|DUMc+?v9RDzI2L!s2zIo!azNtImL7cBHd0?6d z4f#E9Ko=p0X}UuXvBvxemc^Q*40QcSY|K!c1uVJ%I2_d-kh4icZo+}2N1JdRTHDEl zdl-;VeURS+MnuTj5OoP97jlAaOmr-J4bg|M4c7&@Mr51>+BvcD95c}&XFNl0@(hxR ziDj>T6_~mhF^2~^QzPW&pg__O;h>mh?`?oV@ee#rqZ=?gLe4ru-jJY)?gUAH1v`#h f8>tIlx+B;$ETjXq&;hiz;QyfD2QE-BizfdCud%S% literal 0 HcmV?d00001 diff --git a/backend/app/routers/__pycache__/repositories.cpython-312.pyc b/backend/app/routers/__pycache__/repositories.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..60766535a40bcb47a3f3c3dfb08d9b99bd91032d GIT binary patch literal 5331 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 P4)5b6n3q17VV?SLvC2Uz literal 0 HcmV?d00001 diff --git a/backend/app/routers/__pycache__/skills.cpython-312.pyc b/backend/app/routers/__pycache__/skills.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6a1cfc37de4adcb4af2a99031fd429659c8ded32 GIT binary patch literal 4294 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 URkVMW*cD-N^Y$ME2L82w0ax6BnE(I) literal 0 HcmV?d00001 diff --git a/backend/app/schemas/__pycache__/auth.cpython-312.pyc b/backend/app/schemas/__pycache__/auth.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..80c62ebaf1044dbdbaffbc4308453d2096d2773b GIT binary patch literal 4923 zcmcInO>7&-72f48$>l#KQnYAAKep=FY#TLc+9H8sqmF-N$h09V0m7tMtT-cT+vSgE zmra7XnSKtWLyLN5ixUV6%VZ~3!gwpIeP3(VWM z-Nlaq0CDrAMEF&MXLiJE3 zM7&}tb+w`ruUg@Hq!Ot|E77`E(dw~EOqN2@9f^gvB^Ke4&lPXpN}SLrpqdX&5E=tC z?n9G=CIC(P&=jF5K+`@nO=t$ttPjl)ItJ*t56u#q12peL#|WJOwBSR>2|Wksqz}yz zS_JgG56u%g1?WpYbb`=nKxcetfzVk%=X~fnLN5S%(T7eFIuGcNd}xu-OMt%YL(g|E zm#!S6u}iX>FdB`fV>o8BVZ*1!42L^rog@FCg|K0jR5$jvVe|V<#w|B~quE$DYd6iR z<7&6+hG{)=gd4tXa*I_x7kYFMC%f?dnZ%`v%%n=_9q>9=n9M>v&dV} zH&7lSdDJJ@Sj;y*O7b|$SpsHC`g*2V+SgN~o*9&PvZXOMv%+hp?QpTeAGf*fEF6bG zbj*P4h1_`EZ0Htm)SM0AjgR`gVuRN4byL`m-Z1Lijaf#IJ;q2r{y7j=Yuj9)SZMee z=4h{DUz5aaupm1&T-j1@bUi)g|{O;>dUwfWAn7F#R^u*p*uYQv+?#@5G@H}*oU);R= zq`I#z9wl;H4*);Z5{J3`VXn}PsuK|ub|p0&5pys-{VX_2-T<*bN|+2$66$$TWeS4` zc{a=vVHO3sMqZ4S;%;)eSu-0w7m~HbIhb)lOyX~gNYY3kn|TH*mm*>cKVCvIjbsK1 zSr{!SW|7PxxqxK8Pw>k|@`-f#eRRfwr*u{TfJZ)g6=<-|q`iXLG033w6((IHrKlTT zZGuZl6*p;AtK7DA2O&2l_`2ZsM(;DS#tp$CPD!deofa>b!hvd+;8&v>UqTECuG2GLLnV`>!0qAJ!An!m zLZ3q!#0T9}2{VO9m`aWd14juB5>A9s>LQMUmc=TVvLcL9Rwq$Py2XDMYFCOjw8&qw!>{#U28TiH)^-Z=bllbb#T8?<0w_<}rcfIyCz=Adn++(@)t!?)A;(qx|INohPgN>f~W6yS4nH z=)gIGEsK%mx9o81cN8c-xfL&{DIoegoc1wlTNW6dqoMmIVn`lBvoYa*&5o9Re&t0+c-|2)B1gT*Cs+Yh|e^d*3MkK(=L6Aa!LSsg4sObvz6 zwe_~l(DFX}?tLfU4edLUBz_Hx5J+m!PI^gVXxdbEd)dioNKWfm5qmGFX}4jP(O|lX7?Q`(1~o0cb?=+W zX@4CrMmCps=6!V>$NXO`FmYqUXw>*<+>r^g)wU44;SBU0wT3_)%i<2uQB9W+L$V3Y zz6b;&vrybui)X2dgHEYB2--8Y(D=JtnCl%nBlq_Y>LG3c3En@;C`R%JXm)@9q_^*R zafg!NrTn1%lRLGr7i}JaNq^LoWyFwtip<+c=8zy1yt*?CHG@&#V6-Z;N|%vSMmrrK%Mj)ffEHg;s=Fo zrdLh-=35QS_kkgcwNfDYD>B27Md*L9veYdhngh4q{{HKFAD4sV3uyggX};(ksfuu< z>Q@}>Q!Y*6&2YW#v<2P;6&y@Xj=-7NY}5pnAy;d4n9*>|s)%3*Od{TWD25!~_Pndi zCFJN_j3+ZXEYZ1w>Nk}^stlAgDJRher(H#%LH4A@k3^5Fz2)6ruL&Jy#^bSl1ms_e zEX!X@7ym9ze=SY@Lt5OI7Q5-B9N96u61=)sqQJk|mEhH#QRLYtOI-PqnHj)&xho%gyDyt;W=&hNrlcy+aqJhn^tST_$7@Al_M9{SL~ sWI3~2#QqttKgTTL4N7q$WyR?3n1O;vj6}9 literal 0 HcmV?d00001 diff --git a/backend/app/schemas/__pycache__/follower.cpython-312.pyc b/backend/app/schemas/__pycache__/follower.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f7a951807c7088f6f8113666839fd9de2abd4c8e GIT binary patch literal 1514 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 literal 0 HcmV?d00001 diff --git a/backend/app/schemas/follower.py b/backend/app/schemas/follower.py new file mode 100644 index 00000000..1dac4765 --- /dev/null +++ b/backend/app/schemas/follower.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import uuid +from datetime import datetime + +from pydantic import BaseModel, ConfigDict + + +# ========================================================== +# Follower Response +# ========================================================== + + +class FollowerResponse(BaseModel): + model_config = ConfigDict(from_attributes=True) + + id: uuid.UUID + follower_id: uuid.UUID + following_id: uuid.UUID + created_at: datetime + + +# ========================================================== +# Follow Status +# ========================================================== + + +class FollowStatusResponse(BaseModel): + is_following: bool + follower_count: int + following_count: int + + +# ========================================================== +# Follow Action Response +# ========================================================== + + +class FollowActionResponse(BaseModel): + model_config = ConfigDict(from_attributes=True) + + id: uuid.UUID + follower_id: uuid.UUID + following_id: uuid.UUID + created_at: datetime + follower_count: int + following_count: int + + +# ========================================================== +# Unfollow Response +# ========================================================== + + +class UnfollowResponse(BaseModel): + message: str + follower_count: int + following_count: int diff --git a/backend/app/services/__pycache__/__init__.cpython-312.pyc b/backend/app/services/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59719c6b3d74cbed6c01e6eeb100c6e949b5a3f9 GIT binary patch literal 174 zcmX@j%ge<81e0HTW~l+`#~=<2FhUuhIe?7m3@Hpz43&(UOjR;mPNl_}d8x(43dN~K zWtqvT#R>(9$=QkNsd`*~nvA#DqMuk$5ChW^6Ca2KczG$)vkyQr~zbgG00sXm>C%vKQS>evJ|lZxd2C-EKdLc literal 0 HcmV?d00001 diff --git a/backend/app/services/__pycache__/activity_service.cpython-312.pyc b/backend/app/services/__pycache__/activity_service.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ab34ff045fb811db553092f9af1a95a2897b4767 GIT binary patch literal 7592 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 literal 0 HcmV?d00001 diff --git a/backend/app/services/__pycache__/auth_service.cpython-312.pyc b/backend/app/services/__pycache__/auth_service.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..190fb577ae27cd955f2b15625f22d42bd009e509 GIT binary patch literal 9623 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 literal 0 HcmV?d00001 diff --git a/backend/app/services/__pycache__/builder_flare_service.cpython-312.pyc b/backend/app/services/__pycache__/builder_flare_service.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7acece4369a98acfbc182301802d063273dbca8e GIT binary patch literal 4240 zcmcImO>7&-6`o!0lFKC}(i9~zk|{C%sj{-opm2%?t&`eLkT^al1r+zd*x69ru|;|L zli8(e2^5fn4-(+Q5^6x{rOB~|eC|2-UQEb^h(!VjNOMSXVWa>7eCm6%yW~=mm0mgo z-aNkd&FsuK@4cCS4GgFR+FyToZ(%!1$T#@MZ<4DB`yYd{Nep5LCaDMoK|ozJ#exWZ z$P87ag2Zi-DObXUFxO=>Qc(&D*TZJCq88LjtPm53NZutzWq}#g_|-<)G$?z=EHbKzPAd5SEk=tr?YG^i z8(=HBA9Q8N?S%dBLD?jf6a<67o`gb(N>Ot7XQ+mFU)u8KD9HUNBW8pG-f+)r#0@Fn ziS#`94P(HN174-y%MpV{IDm-uBa8&F*;|!*z?(FbfH$@j)lN7=LAGWoTP&C8@_97} z?P|j+SApi7S-Vp%FHuTdP#cc7;}LCrR(sDJ#=ziRva@q^6_P>a<#}-m#o8qm`OXwKzkf z8M49>D3A$u0!0c1Zkwf1;P#wQ(J-8_`wb_;=xs)=c};diW6p^*EXrV=Yygq+ZOlkV zG3IoxSu$8LuyW5Y%oR&_Y1MeOSg+rNF&K5$%{e!^T(s_)^YtYs?$Y5pmi;K?LFk2S zK8V1@TFW3lB|jxeI@cbZXpg?!PK|D!+c?+GWOp)JE2FhfjBJi=jJ1cyHb2_kSI|^qN=(ccFF2}NHjRMRgDtkn3=ezD#0d3)teo8uVl1x2ZTw8o(esOI(ap9?Q zflY#^6kH;n9^b$tP=cx5TeP1H3y3|?dZ?ok+Ys))LWneEa<@VK2ifgPgM|Fz_0{G}NZi zAL2plTF-&O!aEmgfg80$oJhaYx#ePc>V=H=125xr9_bLt2T8xun!fU7p*8*fcH)o6 zk&X-U8K?EeG>vQ<1PTMgk!myVSX+#$gkyqWy^|2DY=)$}GD?25D^+ua0#dr@l2 zTi!^4JV;Ae8zTNfdc8jrze&33(ew9G0uTbELulp$cpeSVdnL1BP`y#Ls11c$t<(%^ z>PDkdcjU57D;A^!h3v2y!wZUKK)`WgjbSHIjDv6_cr+EA&|SLZ$csg@K`rD64iK7q zhVce}SRGfTgNW-e+?oXe^=FVIhj$W_t;FO%jHijo?Zm}ZX?JYm^Xb1$|NZ>h_0_l5 zhrfystzY}B^u=%f9oIS`GCtJ_V<|qm{2tCCB$yxQpFn{Ztk4v6(A)-uA9Hk^@a}>6 zW8l%ytwA2);tX7jX3e4oL_3r-(&O{7TeCTzeRU?r2Y8%K9u@Ebz=trWbru9K+2f~I zl?RF47v4d~knj%7@uEAZZ(F}W%#xS9u&R5F zdLhmSpGF7=Uj}Wt?^T>@=4NVDs!4&5A?kSwi`Iw1GrQ&I4WATWLA^=Y75J+ufk}9B z@y8cmA--(cWfW-Zo2iHVU;K{5*Bf^fU9T1^RM#C<*CFj2ChBor|D;hgJx@f}jamuK zcte&;6>87d3^sx5ID_Im3VgIMyxiFDQM?J_G2w^6bD!ZmnG1YDTDRbCzE6G>MOo=6 zB%JDq89CFA4|PJ&@17Xz$k0Rn4o`F|2rr||3qJKlPb}ORa331s_Kh3K|bOdh80%4ixMCU4`%H=r@Wxm4a zd1!@-P!;oHRmw|MIWMy@u@b5(d4O z0Rdw4OuaT|P?KrEbISYtQ=>X<&@AuoJwuJ6W%&Cp&Fausa=yr^1*hS*e#W6u43g(` z0*2u7f+2>9|4)zU{B7~EtDl$r2tBR~o>6(*sHTga(U5->-=imV$%9Y=5J_G3Ai@EN zlpgXR)Br>uIHtFTh##S+^{{6&x?@!JjK;Q&?$INj(fE8c+i&-IJvC*}xpK+4c~s3n zd8=WTYvAHcrGB+s%3P__Ov&SBGsjRR*F((cA*kV*+pvZ&Vqwx&-Pyd5SQ6Fv9x*mSXU-Kgou zi?g$rO~-MPiN zk1G$~UC~ZGRZh|UFydPka+$5_B?#UK>aC>1<{6jw0PGg48#z6EP~7xzGi*cZPQZlg z6NGfE6%;QX?YLhPpPC%gcfE0ow~*zmfRFk*a<6UjofUQ3DMAmxcvhvj9OffioT-;< zGz`x+U)JesC`j*LGpJ#Q8bD?Y53y128R@E{wS3!I@9vwh* zf$4f3Z{9o_;GG>bn~f)HJJRi6^AungWV zN+rmDN~ykQ>G8F6u9eO`8E>V(<9`D7B~x31^L8Vc|7H=~HP}~YdpEYadtp${Z|)vj0Vk%OTW*O>k&Z%U z@5VV8$t_K>6Qk^8)!hd=C+jo6vWP?y_Iydd1&_9@!!^V*n9sA4 zljvCtBP&>FQkI%AnlV1z0F6ge2O-HjCDQJ4vc$BwzrlK0@$c^L?COS~mn zXe3r3s>P=C*wy67owSGtt1ittIIrVi99^}oz;O#GjRjoK!I4>*ya*S=nDOgUrJ);z zM$I%VI7F+}I(V|6H>$I?RJM$&3H!GJS5J$2;#qbaycedULr~cwTojA8aNU@xYhxlK?P9?8|v_B^fw#$*JTED2g~+KkpOOx&NBi0Wv>T~?Z3$Y)qyyP@2qlH6{hMKswuBD4J;5YN zI?eQ;-545eOVEOzx_>hSl8eT^I726-afXI=Be}ONL5t|&%@9Z~8vDi=I_-WFv>S<` zwgfGpK`(?7eAE8TFi5T*_8nt-n$*wU0xkO{Xh9EF6+#L0hBw0?xq8?)%Jh=bAk%}E z=|Su2p#*yI%`ix=9`=nhy}0|G&~6MJYD>_99@-8i$95pOdf1m?daA1jEz^S*^uW>~ zkX$tO4SoZ(ET!36pk;GIi*v^}Lm;uazvMx37=q-;CXtd?8W8nBNs9ZPEn;S{Rr5xr zSSejIs`FGt8sVPD4vKcXHD#Z+855O;9Id--%b0yC&SJ{>ky6`uN=+1>l{nI;u4 ztvV<#%x71}N^+rD8A}q_|%X6~oyugIIJDsp3_n2JW-Y zY}v>Ho00xT{$v28ex_?G93?Kp;`jKK5E)~p$ zpDoO5@L!xN>w5XJh5?Uyv>6RwDkz%b%;iAN>6ncPhHO(qSw=;$H73hxd;oR+)R4+v zMX%kg!qXs*vWS{Cb zHPFTp>f}&ks?YBu4;HOKn(lZyk0SEzfn;XuzJRC zv+8+U%qwP@Y6$~IlOtzBcG!YhFm=ris+ytT!aPYYn=dE;1*NQ)aVCI8Sh3CJRn_(> zvAmK0p z#5#7U!~3MlkcfFcdOokbua(r-^YioPU`r%XjdM*~xFZwu3!Z^;WaEpwT$A7#M`Xg0 zpu`yHHi`f~M9(59ky=aaT^ksFCU6PqTBsqRK=6id*>|n_P)x3g(v84!;ChfC(z0~( z*h4Y(wYZ}$j#%QzT6Ejm_SB=D>H5xt*3N@#vGk+FuG^<;iOkxzA%hLYFw_}(V3^M+Y84bR(n4~W_F zMa|5$N5f*O+ne1S6Ch{&6aaOp+`lqgiw@SK!&Y?oQAmCyC+hN$B@f*VTJizaS?mag%Q2$Ewr7M2%o_x<`;tKuG<0*$?0_B){bce+eP6=nwES78Hq zF9B%)T^WZ(Cr_I4&GO!2Yt7QD>91)hxS zEU3QCEW<+};FL`f$}OA;=ND{A!CKzbp!k|LPinZ$>jeWUw3BlZl}=;w%nEuA}J#YgTQvf}$| z;R7$nxy{q?bC~!)D6QWiw;>Cg*=+`4I@%x~dt~tDeC*E4w$raIFF9Q+z1SU2frV65 z%9WD2*&UtqIas6d0|1a~kS^^f+-I}(^ieB)^uc8-JynaIyvBbWjjbHK&3-CoRZmfywZ3Ai@^KKIXHdv;LO`j4-YBtj%v#erFCa=&Q{`L zI9s8)7u#aRtmO5!19sEJwwvRZpu+eqfDch4hIS8rdg_x?k0AT6)Z|oMPFr&Nvn%zH zqt?jL2bZjo$(lU%jAM64HUuFlJ>>zrDKRh=l9Tby!*O?aIp`p-5a|H` z;EoV^D8l3L=J-Q#(0wTWCP;5B(;3m3jYI%_20af{Dg|}o?Af23p!YU>0w}f*Yi0$P z=*wx72xVz8<4KTMY<^ftRa4XDlJ>2nZ2o+?th-^1>6-SFg^@K-wa@9r?-$t!wQi@N)-wsX0_H?gwQk$n6h}dE-SIQT)T+WtqxnfzZ=mZbtavwml zxD*FsN>MXs%PJlu8sX)N@IC?#5bzcOhY2`Bzz+%dF@SrB`i7<=CZ|3H zB+HFILC9T2PgzzFA>w_p20I`m*Fy0I2mO=ndl~}t4IkQ(YWN8zA}O{W0BnQvxEtT2 zSXdaOa?n#b=v_I2f!x4)05DgMjO}sd#$35ES8l8+H%8iqT z4FP(PlM?HGz+7%Jwv)~R*mvOe3(lILr@Emhy2I;!z+ByAEJk$$Ms-8~Ex6-?M7g1V zA`dhK=s`E^z)vvPZ(=$6mBZ#qF4~gufu7fuS*^I>e6Aq%-;T6KC(5`;v&D|X$EOL1Oiec?IzMf- zQ=BrQVdq20ZX)A;o@z0R_Ui}IM d|BChk@)tDz7>zzg-~Xp?nq~Ud5rI_CzW^iDs9pd7 literal 0 HcmV?d00001 diff --git a/backend/app/services/__pycache__/message_service.cpython-312.pyc b/backend/app/services/__pycache__/message_service.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..306058c8cd182649b9f93458b90ae11b7868cb3e GIT binary patch literal 6127 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 literal 0 HcmV?d00001 diff --git a/backend/app/services/__pycache__/notification_service.cpython-312.pyc b/backend/app/services/__pycache__/notification_service.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a1fb42a4ba4bc7dad6a4519f44c0296937c94fba GIT binary patch literal 6226 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 literal 0 HcmV?d00001 diff --git a/backend/app/services/__pycache__/project_service.cpython-312.pyc b/backend/app/services/__pycache__/project_service.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9f16593c60ff9ec0e5a269426f1d84b3877b6713 GIT binary patch literal 7560 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 literal 0 HcmV?d00001 diff --git a/backend/app/services/__pycache__/user_service.cpython-312.pyc b/backend/app/services/__pycache__/user_service.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4a9518b618eff475cfbc51ebb1e57369a53df74e GIT binary patch literal 5733 zcmdT|>u=lE6~ClJiF#P{Lw>|gTE%hV$g9<2P11G?1|+qUB@4X3k73gi2#QG8RH#QU zDW?_`B-jGXMl-}73OGZtwFL$&hVvo+$G+Hb1`9-j8EE^V-_)eTfPUIJm!w3=YJvhA zuw4U(hv#v5@44r9?vel2(Gest{*a!^{UW?(Le*nxnk%`P{B*!H=4tZYV zlRP{`?XLmoDAnWk{#?_)FL@4DRG1+ z=ZPG+L*(ElZ+$u0xx~jqU*SufGehZozF?#cwUF1R;N7PynvyYq^Uo-{4q{-#XEKJm zs2WSNOGO3Vy>q%koq9h}?;^@h5l5!X2SLlW18r^x)Ag z`&{z`+F10+ewRhC*+P!WqDvcU(e^^%8#@W_(*|AIj(ysYOB-1V$NS6>hT9Hkc{~_{ zakiwZc{rz-R(Ma%#O4b$hDNbMQK8nMCYW8uK71BdjK7Bv?s)>3by6W&IEU6@)IBPk zlR7hGgPVeL_q?YV)DIrO^YS&*UxII@R9Q!#SnS)8Yw65&B`?38E*7tV3Nt{z!i?;< zL~+R!VU`pM%TZkOjAfT_q&+Z~j^sAkle+FLt}K2e-#@=2jckb{&p}Mu@98(7Stmw) zM~!`K+On*G-p!+7mGw1i@U6mKKTe3_f0KuZ1=?8gj>Qb25zxm4ilJtaGKCup3RO%& z$)!~dV3tX1X&U#?PPFI;VtREWXXtP+5W*PkMo}1pacwEZoXP{OVRAI+u8#w`O}>zN zKaxMJ>`I5XrNe(2`RmwcV~>RG;gdVksby~!;<&W3bU*sxtu65t8U>I4t02-o42p<3 zlTYUqIsmUu2oC~J4*+S7pkznT@hK0r38JIKIld!~a|R|D z1K27s-#-}va89Zs$XZ6Fo@O^aMm-H7B||NS@LKUWGdWKuHGQts^cCjkb;U3RP0gu> z>D5%-F#T4B>TxeiQOM5gYLUiZQY*@s*^sApq6X22fmtv2xg*?=9|i~gEg-kaH(}D* zXQk=zwlw_di5=y4c*(Lb zFG9H7VXko5di4Sudw>)d-7-Mh7V%lJ#SmUA{6lWjt{yi%FAF(`l@+f4*5TYpOfR)+ z-G{~zqs!4}u^_aJ3LJ12QQR^N#0eW&ghs_< z;+>C~yed=78dI8^nVe2dPoBRpGdnpwIZ;OoE}p`rK}^4V%>qUfq=%Azx2$*2c$u@&4y}MLt{qwtU7)FB z)|rD4&c8b!krw7v4SIB#tK1(e zv9?@}84HR^9c7{%VF;szQeGY}Du|RkG>|_4pLo~|<_fZ+rQ}ksXbP&K)W(iq~Z-Wz;;sQA79|O5fY7x>Iy?1Nn)`QvQTRYMZm%V#~uY5B0 z$FV=ZwsLX#-PPVF;hxp=_h&vm`uFhhnuiRH)_e$;?}?EkFTlvJwg!^buEW*tf&Cb9 z*Imq6c7L4%=DYfEcUD4PzW^Z|S+e_1-t@uQDTcyMYJ+b?-R{t>?h?u*8np?nOCe)u zv9E&AhV4MDjy@I#?ZWc=(EdKMzOi4hjmcbvO95w%mu&*{b#OaA&ETv605-%D=I@0zy$>Ji-f&`XYa$|+u$oD|zK=uk?koS2)tFk$+rVw7n9TlNz@R*6j& z@=B8fYlA#G6wg`op99jQXMG4JjZ4o{Os%i5!HbI)hS|rDfWY*qdBbYQf9ZIYSr`6m z%(DAw^mQ<b`-C1M)2O&@#oMT@-@#3VofBz?q@tF9DVKqu7(_32`J-* zS8W+^w%vXi829#7d;4pCpKz=i?x}g;xfkiG3Gf7EXAjeWe=zzi05W?{)ONBj9u)eS zA3XOW12qAj;5RT-^CJg-k!JzmY(JEpW_|;;&`k z2~m5UQRWBl;0IrU9YpJ^i`uIT+FyYuvxcW_4V-O_vH>Pe@P`+YojNecHVAV zTpDbQtbf~dqEyFO(|Ur58IBMb<{_rD|Gib8Ed{>#4=<}XVrhq$Un3Pw@wAorKcNet vfJ`KM97xT>aokff{5c7INe%(?C3)>BiT#7T`INl#FW&^u^**;M}qxNMPF literal 0 HcmV?d00001 diff --git a/backend/app/utils/__pycache__/__init__.cpython-312.pyc b/backend/app/utils/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..adc91fbef0f1aae065e4b8260b13ed1e8144072e GIT binary patch literal 169 zcmX@j%ge<81e0HTW~l(_#~=<2FhUuhIe?7m3@Hpz43&(UOjS}`p(U9)nI)A98L2r1 zsYS&K1&PVoiRr0&Tz;C2x7g$3Q}UDJ<5x0#1{v^6HVG)3nwO%VSWpmC3e;H~6Ca2KczG$)vkyQs2XHvF~~_Dm>C%vKQS>evJ|lZxd1(jDog+X literal 0 HcmV?d00001 diff --git a/backend/app/utils/__pycache__/validators.cpython-312.pyc b/backend/app/utils/__pycache__/validators.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4279f6bc07ee8a3d3c7aaa633497a212f0bfd4ce GIT binary patch literal 6027 zcmd5ATTmO<^{#d$fu4X6Z-+GmY}p`_kcaUr!9ljE!FIqTwhU1h?E=EmO1Zm=jVwB9 z(`ikd8R+!GWYSJNlOKDWkNma&{cJzLcxt+n&SViu>cQo_qHp34@zV`_Ze> zy=U(|=j^@bp6CA2>vbV$zy8PY{M)SveM271#_9mG^&*4NZ6u;75*g8!WKy=MjUh0b zWTPyMT#`%KqjoxHPdZZ0s54a+tzwW3N$h-`$*?qvj{Crqw5UsL6rDfkqHeKCtb)s(g1vbRzqOKw7gOP-Mm48P_CPYC^q-B0W zO(YX)LQ-6=F)6DE(@BZ{ptL-bmE#0Y;j@Y)@;JGS`lNkXkQpl!x&s@BCA#yz~We7vfp#WZ1$u+!pMd-~9_D1`92V&vg zsT=)0{e6os#*I55j1dQaxN&Cd7XaKwc{E?XN-&_^*9WwSRGR^!dAkXf#ym3RsyDgl{83Xu7XxzuWI-sghZRje!-P=Wk)Le z)uCso92HcS-p&&#Zfl|wc3^0uQu*$xAHb!0S1zs}z{R~Q7tasi;@y>tubd0DJb$i> z>b_-p89`C5rLo9^UP|(;Iv1wv-x8Dlb_K32*K@%{No5t)G7~`sBN1TYaG7z2F{LX2 zaV}`lCBW;Y(|j^5&xUjME8wrDatEx{O0F`W&44Av1w}H9kdT0vo63cDApyqMwo%w7 z#a#Pt=(VzS;R=*L&Ru_J?8zCwq@iUYVS_v3PXfk;#t9$$U@v*oi}L?7mZ8 z$w={pkSrZP9O5)KDaq7?H5&%IS0n+)=ZMW_3@Pe1i)%ncWp-(SRh;NDj_HjoGm88feHkVZ+T#8VCB;4^@r~L zCdwQC8Rf)IC=;vT6S_<;uk3)b7CioYc+(jZr|eBd7xfpIqz<{h_lPRM)k5?N$GQ&o zP91!+Yz7`D!^ZQ}jhB1=o47V_`51Vy(aK^TiIKF;TQSX?K@c(T8{P~2MYTCkGNvzB z(~}r+jXQ^lPt7$9%hcoYQVP62FNh+R6h$|VkX^G=g~e__)!dQM!Ql}-3SckHP~`!I zu~XV|ZSh%NoGxJ=u;<~goPe%?Ha)e=XP3_28hzwxU-z_cc=i?|kKGNA-2A$mzY~1u z-e+FO!P2FX3#l!P&-&EcnI{Q(yCf#$lF;^;LL(`?Bo52ZiVcT|ybf#=RL~NX$&`w!7tlW6T~xu<@y{-Q za{1FM>rTu6zWhBzMYIL}%+?D4JWsnIr)HpL&@X!Xp6jeVXVO@mNhcF&dm3wc}K@~MmH<7ST3E0zl}IhN`bIJYx*oMtR11tk&ZFO83rt5hXgc^TzI zM2QO-NY&3=933e|Yemm=&gHo7qRq9~FzSmG4b9ueO z36xbhOrHG|>YO|SJ^Nd(B0uNyHd@;}i*L`{cEBfUf$)Ps6tbGcV71%5|N} zGUw;x^eY1|!M6nXCK0k>ut_85fW!numz6YUDj_FQ*%Sc6bqd&L5)!Dh1Cm=P5foyP zM57Ir_FEFy*YPP>CpDom3mqh}9^|WC3Eqm*K)d36;A}JkMnmh$yK8OXyVvd}zRa%$ zhAL!V<=c+Bdj9U|y8~a2td(cLa;ZdU080J1)3;9+Zc-5EARa8H>G zSyXk1YHtFeJG&I(azn#D36gBe(8fq}w!+=O7Z-GnP!X3nZ@-5&~Du zl5~7Kdlw$GW={g7u?bnlZ;`nP(hXUw3A%r zxni-IESy)0#W2xb+ytHGfs`(pm=4oSSY1kEVdQJN zIkp^Kimo;FZFpZQxClW_v7?@;-E{kkER0`!Yl?OlNi41{Itf&TJpN)efn3N@z2yez cpNF|d+ZqaN`Rt4fKBU#|EqI?e0H&w?H-AMukN^Mx literal 0 HcmV?d00001 diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7bdbe075..d11e36d1 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -7711,18 +7711,6 @@ } } }, - "node_modules/nitro/node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", - "dev": true, - "license": "BlueOak-1.0.0", - "optional": true, - "peer": true, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/nitro/node_modules/unstorage": { "version": "2.0.0-alpha.7", "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-2.0.0-alpha.7.tgz", diff --git a/frontend/src/components/shared/FollowButton.tsx b/frontend/src/components/shared/FollowButton.tsx new file mode 100644 index 00000000..744260cf --- /dev/null +++ b/frontend/src/components/shared/FollowButton.tsx @@ -0,0 +1,86 @@ +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { useFollowStatus, useFollow, useUnfollow } from "@/hooks/useFollow"; +import { Loader2, UserPlus, UserCheck, UserMinus } from "lucide-react"; +import { cn } from "@/lib/utils"; +import type { UUID } from "@/lib/api"; + +export function FollowButton({ + userId, + className, +}: { + userId: UUID; + className?: string; +}) { + const { data: status, isLoading: statusLoading } = useFollowStatus(userId); + const followMutation = useFollow(userId); + const unfollowMutation = useUnfollow(userId); + + const [hovered, setHovered] = useState(false); + + const isFollowing = status?.is_following ?? false; + const isBusy = followMutation.isPending || unfollowMutation.isPending; + + function handleClick() { + if (isBusy) return; + if (isFollowing) { + unfollowMutation.mutate(); + } else { + followMutation.mutate(); + } + } + + if (statusLoading) { + return ( + + ); + } + + if (isFollowing) { + return ( + + ); + } + + return ( + + ); +} diff --git a/frontend/src/features/dashboard/sections.tsx b/frontend/src/features/dashboard/sections.tsx index 3d82a180..09b5335f 100644 --- a/frontend/src/features/dashboard/sections.tsx +++ b/frontend/src/features/dashboard/sections.tsx @@ -26,6 +26,7 @@ import { Users2, FileText, BarChart3, + Trophy, } from "lucide-react"; import { Link } from "@tanstack/react-router"; import { cn } from "@/lib/utils"; diff --git a/frontend/src/hooks/useFollow.ts b/frontend/src/hooks/useFollow.ts new file mode 100644 index 00000000..7c937b26 --- /dev/null +++ b/frontend/src/hooks/useFollow.ts @@ -0,0 +1,112 @@ +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { toast } from "sonner"; +import { + followUser, + unfollowUser, + getFollowStatus, + toastError, + type UUID, + type FollowStatusResponse, +} from "@/lib/api"; + +export function useFollowStatus(userId: UUID | undefined) { + return useQuery({ + queryKey: ["follow-status", userId], + queryFn: () => getFollowStatus(userId!), + enabled: !!userId, + }); +} + +export function useFollow(userId: UUID) { + const queryClient = useQueryClient(); + const queryKey = ["follow-status", userId]; + + return useMutation({ + mutationFn: () => followUser(userId), + + onMutate: async () => { + await queryClient.cancelQueries({ queryKey }); + + const previous = queryClient.getQueryData(queryKey); + + queryClient.setQueryData(queryKey, (old) => + old + ? { + ...old, + is_following: true, + follower_count: old.follower_count + 1, + } + : { is_following: true, follower_count: 1, following_count: 0 }, + ); + + return { previous }; + }, + + onError: (err, _vars, context) => { + if (context?.previous) { + queryClient.setQueryData(queryKey, context.previous); + } + toastError(err, "Failed to follow"); + }, + + onSuccess: (data) => { + queryClient.setQueryData(queryKey, { + is_following: true, + follower_count: data.follower_count, + following_count: data.following_count, + }); + toast.success("Followed successfully"); + }, + + onSettled: () => { + queryClient.invalidateQueries({ queryKey }); + }, + }); +} + +export function useUnfollow(userId: UUID) { + const queryClient = useQueryClient(); + const queryKey = ["follow-status", userId]; + + return useMutation({ + mutationFn: () => unfollowUser(userId), + + onMutate: async () => { + await queryClient.cancelQueries({ queryKey }); + + const previous = queryClient.getQueryData(queryKey); + + queryClient.setQueryData(queryKey, (old) => + old + ? { + ...old, + is_following: false, + follower_count: Math.max(0, old.follower_count - 1), + } + : { is_following: false, follower_count: 0, following_count: 0 }, + ); + + return { previous }; + }, + + onError: (err, _vars, context) => { + if (context?.previous) { + queryClient.setQueryData(queryKey, context.previous); + } + toastError(err, "Failed to unfollow"); + }, + + onSuccess: (data) => { + queryClient.setQueryData(queryKey, { + is_following: false, + follower_count: data.follower_count, + following_count: data.following_count, + }); + toast.success("Unfollowed successfully"); + }, + + onSettled: () => { + queryClient.invalidateQueries({ queryKey }); + }, + }); +} diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 4dd18b3d..951c5e6f 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -168,3 +168,49 @@ export function toastError(err: unknown, fallback = "Something went wrong") { toast.error(message); } +// ------------------------------------------------------------------ +// Follow / Unfollow +// ------------------------------------------------------------------ + +export type FollowStatusResponse = { + is_following: boolean; + follower_count: number; + following_count: number; +}; + +export type FollowActionResponse = { + id: UUID; + follower_id: UUID; + following_id: UUID; + created_at: string; + follower_count: number; + following_count: number; +}; + +export type UnfollowResponse = { + message: string; + follower_count: number; + following_count: number; +}; + +export async function followUser(userId: UUID): Promise { + return requestJson({ + url: `/users/${userId}/follow`, + method: "POST", + }); +} + +export async function unfollowUser(userId: UUID): Promise { + return requestJson({ + url: `/users/${userId}/follow`, + method: "DELETE", + }); +} + +export async function getFollowStatus(userId: UUID): Promise { + return requestJson({ + url: `/users/${userId}/follow-status`, + method: "GET", + }); +} + diff --git a/frontend/src/routes/_app.builders.$builderId.tsx b/frontend/src/routes/_app.builders.$builderId.tsx index b8dbe26f..a5c98c6b 100644 --- a/frontend/src/routes/_app.builders.$builderId.tsx +++ b/frontend/src/routes/_app.builders.$builderId.tsx @@ -2,7 +2,8 @@ import { createFileRoute, Link, notFound } from "@tanstack/react-router"; import { useQuery } from "@tanstack/react-query"; import { buildersService } from "@/services"; import { Card, TagChip, Avatar } from "@/components/shared/primitives"; -import { ArrowLeft, MessageSquare, UserPlus } from "lucide-react"; +import { FollowButton } from "@/components/shared/FollowButton"; +import { ArrowLeft, MessageSquare } from "lucide-react"; import { BackButton } from "@/components/shared/BackButton"; export const Route = createFileRoute("/_app/builders/$builderId")({ @@ -35,9 +36,7 @@ function BuilderProfile() {
- + diff --git a/frontend/src/routes/_app.profile.$username.tsx b/frontend/src/routes/_app.profile.$username.tsx index 25b0bb0c..12e533ad 100644 --- a/frontend/src/routes/_app.profile.$username.tsx +++ b/frontend/src/routes/_app.profile.$username.tsx @@ -1,6 +1,8 @@ import { createFileRoute, notFound } from "@tanstack/react-router"; import { Card, TagChip, Avatar } from "@/components/shared/primitives"; +import { FollowButton } from "@/components/shared/FollowButton"; import { builders, currentUser, projects } from "@/mocks/seed"; +import { useFollowStatus } from "@/hooks/useFollow"; import { MapPin, Calendar, Link as LinkIcon } from "lucide-react"; export const Route = createFileRoute("/_app/profile/$username")({ @@ -21,6 +23,8 @@ function ProfilePage() { : builders.find((x) => x.handle === username); if (!b) throw notFound(); + const { data: followStatus } = useFollowStatus(me ? undefined : b.id); + return (
@@ -34,13 +38,15 @@ function ProfilePage() { {b.country} Joined 2024 devlink.io/{b.handle} + {followStatus && ( + <> + {followStatus.follower_count} followers + {followStatus.following_count} following + + )}
- {!me && ( - - )} + {!me && } diff --git a/frontend/src/routes/_app.projects.$projectId.tsx b/frontend/src/routes/_app.projects.$projectId.tsx index 6ef81a33..209971e7 100644 --- a/frontend/src/routes/_app.projects.$projectId.tsx +++ b/frontend/src/routes/_app.projects.$projectId.tsx @@ -7,10 +7,6 @@ import { useState } from "react"; import { cn } from "@/lib/utils"; import { builders, activity, currentUser } from "@/mocks/seed"; import { Markdown } from "@/components/shared/Markdown"; -import { ArrowLeft, Star, GitFork, Users2, Github } from "lucide-react"; -import { useState } from "react"; -import { cn } from "@/lib/utils"; -import { builders, activity } from "@/mocks/seed"; import { BackButton } from "@/components/shared/BackButton"; export const Route = createFileRoute("/_app/projects/$projectId")({ @@ -97,16 +93,6 @@ function ProjectDetail() { {p.members} -
- - {p.stars} - - - {p.forks} - - - {p.members} -
From d6da31ca5a179a4a807dc8ccb1085c5c55736a45 Mon Sep 17 00:00:00 2001 From: Samyak Mahatme Date: Sat, 11 Jul 2026 20:24:35 +0530 Subject: [PATCH 2/2] Resolve merge conflicts: keep merged code for followers API and frontend files (remove conflict markers) --- backend/app/routers/followers.py | 156 ++++-------------- frontend/src/lib/api.ts | 66 +------- .../src/routes/_app.profile.$username.tsx | 58 ++++--- 3 files changed, 77 insertions(+), 203 deletions(-) diff --git a/backend/app/routers/followers.py b/backend/app/routers/followers.py index b097f9a5..84589a0c 100644 --- a/backend/app/routers/followers.py +++ b/backend/app/routers/followers.py @@ -8,33 +8,20 @@ from app.database.session import get_db from app.dependencies import get_current_user from app.models.user import User -from app.schemas.follower import ( - FollowActionResponse, - FollowerResponse, - FollowStatusResponse, - UnfollowResponse, -) +from app.schemas.follower import FollowerResponse from app.services.follower_service import FollowerService -from app.services.user_service import UserService +from app.models.notification import NotificationType +from app.services.notification_service import NotificationService router = APIRouter( + prefix="/followers", tags=["Followers"], ) -# ------------------------------------------------------------------ -# POST /users/{user_id}/follow — Follow a user -# ------------------------------------------------------------------ - - @router.post( - "/users/{user_id}/follow", - response_model=FollowActionResponse, - status_code=status.HTTP_201_CREATED, -) -@router.post( - "/followers/{user_id}", - response_model=FollowActionResponse, + "/{user_id}", + response_model=FollowerResponse, status_code=status.HTTP_201_CREATED, ) def follow_user( @@ -49,20 +36,6 @@ def follow_user( detail="You cannot follow yourself", ) - target_user = UserService.get_user(db, user_id) - - if target_user is None: - raise HTTPException( - status_code=404, - detail="User not found", - ) - - if not target_user.is_active: - raise HTTPException( - status_code=400, - detail="Cannot follow a deactivated user", - ) - relationship = FollowerService.get_relationship( db, current_user.id, @@ -75,34 +48,31 @@ def follow_user( detail="Already following this user", ) - new_relationship = FollowerService.follow_user( + follow = FollowerService.follow_user( db, current_user.id, user_id, ) - return FollowActionResponse( - id=new_relationship.id, - follower_id=new_relationship.follower_id, - following_id=new_relationship.following_id, - created_at=new_relationship.created_at, - follower_count=FollowerService.follower_count(db, user_id), - following_count=FollowerService.following_count(db, user_id), - ) - + try: + NotificationService.enqueue( + db, + recipient_id=user_id, + sender_id=current_user.id, + type=NotificationType.FOLLOW, + title="New follower", + message=f"{current_user.username} started following you.", + action_url=f"/users/{current_user.id}", + ) + except Exception: + db.rollback() -# ------------------------------------------------------------------ -# DELETE /users/{user_id}/follow — Unfollow a user -# ------------------------------------------------------------------ + return follow @router.delete( - "/users/{user_id}/follow", - response_model=UnfollowResponse, -) -@router.delete( - "/followers/{user_id}", - response_model=UnfollowResponse, + "/{user_id}", + status_code=status.HTTP_204_NO_CONTENT, ) def unfollow_user( user_id: uuid.UUID, @@ -127,24 +97,9 @@ def unfollow_user( relationship, ) - return UnfollowResponse( - message="Unfollowed successfully", - follower_count=FollowerService.follower_count(db, user_id), - following_count=FollowerService.following_count(db, user_id), - ) - -# ------------------------------------------------------------------ -# GET /followers/ — Current user's following list -# ------------------------------------------------------------------ - - -@router.get( - "/followers", - response_model=list[FollowerResponse], -) @router.get( - "/followers/", + "/", response_model=list[FollowerResponse], ) def my_following( @@ -158,17 +113,8 @@ def my_following( ) -# ------------------------------------------------------------------ -# GET /users/{user_id}/followers — User's followers -# ------------------------------------------------------------------ - - -@router.get( - "/users/{user_id}/followers", - response_model=list[FollowerResponse], -) @router.get( - "/followers/{user_id}", + "/{user_id}", response_model=list[FollowerResponse], ) def user_followers( @@ -182,17 +128,8 @@ def user_followers( ) -# ------------------------------------------------------------------ -# GET /users/{user_id}/following — User's following list -# ------------------------------------------------------------------ - - -@router.get( - "/users/{user_id}/following", - response_model=list[FollowerResponse], -) @router.get( - "/followers/{user_id}/following", + "/{user_id}/following", response_model=list[FollowerResponse], ) def user_following( @@ -206,13 +143,8 @@ def user_following( ) -# ------------------------------------------------------------------ -# GET /followers/{user_id}/count — Follower count -# ------------------------------------------------------------------ - - @router.get( - "/followers/{user_id}/count", + "/{user_id}/count", ) def follower_count( user_id: uuid.UUID, @@ -227,13 +159,8 @@ def follower_count( } -# ------------------------------------------------------------------ -# GET /followers/{user_id}/following-count — Following count -# ------------------------------------------------------------------ - - @router.get( - "/followers/{user_id}/following-count", + "/{user_id}/following-count", ) def following_count( user_id: uuid.UUID, @@ -248,18 +175,8 @@ def following_count( } -# ------------------------------------------------------------------ -# GET /users/{user_id}/follow-status — Check follow status -# ------------------------------------------------------------------ - - -@router.get( - "/users/{user_id}/follow-status", - response_model=FollowStatusResponse, -) @router.get( - "/followers/{user_id}/is-following", - response_model=FollowStatusResponse, + "/{user_id}/is-following", ) def is_following( user_id: uuid.UUID, @@ -267,24 +184,17 @@ def is_following( db: Session = Depends(get_db), ): - return FollowStatusResponse( - is_following=FollowerService.is_following( + return { + "following": FollowerService.is_following( db, current_user.id, user_id, - ), - follower_count=FollowerService.follower_count(db, user_id), - following_count=FollowerService.following_count(db, user_id), - ) - - -# ------------------------------------------------------------------ -# GET /followers/mutual/{user_id} — Mutual followers -# ------------------------------------------------------------------ + ) + } @router.get( - "/followers/mutual/{user_id}", + "/mutual/{user_id}", response_model=list[FollowerResponse], ) def mutual_followers( diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 951c5e6f..f469a0f0 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -3,12 +3,7 @@ import { toast } from "sonner"; type JsonPrimitive = string | number | boolean | null; type JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue }; -export type ApplicationStatus = - | "pending" - | "reviewing" - | "accepted" - | "rejected" - | "withdrawn"; +export type ApplicationStatus = "pending" | "reviewing" | "accepted" | "rejected" | "withdrawn"; export type UUID = string; @@ -63,13 +58,11 @@ function assertJson(data: unknown): T { return data as T; } -async function requestJson( - input: { - url: string; - method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE"; - body?: TBody; - }, -): Promise { +async function requestJson(input: { + url: string; + method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE"; + body?: TBody; +}): Promise { const { baseUrl } = getApiConfig(); const res = await fetch(`${baseUrl}${input.url}`, { @@ -167,50 +160,3 @@ export function toastError(err: unknown, fallback = "Something went wrong") { const message = err instanceof Error ? err.message : fallback; toast.error(message); } - -// ------------------------------------------------------------------ -// Follow / Unfollow -// ------------------------------------------------------------------ - -export type FollowStatusResponse = { - is_following: boolean; - follower_count: number; - following_count: number; -}; - -export type FollowActionResponse = { - id: UUID; - follower_id: UUID; - following_id: UUID; - created_at: string; - follower_count: number; - following_count: number; -}; - -export type UnfollowResponse = { - message: string; - follower_count: number; - following_count: number; -}; - -export async function followUser(userId: UUID): Promise { - return requestJson({ - url: `/users/${userId}/follow`, - method: "POST", - }); -} - -export async function unfollowUser(userId: UUID): Promise { - return requestJson({ - url: `/users/${userId}/follow`, - method: "DELETE", - }); -} - -export async function getFollowStatus(userId: UUID): Promise { - return requestJson({ - url: `/users/${userId}/follow-status`, - method: "GET", - }); -} - diff --git a/frontend/src/routes/_app.profile.$username.tsx b/frontend/src/routes/_app.profile.$username.tsx index 12e533ad..a48b9ae0 100644 --- a/frontend/src/routes/_app.profile.$username.tsx +++ b/frontend/src/routes/_app.profile.$username.tsx @@ -1,15 +1,16 @@ import { createFileRoute, notFound } from "@tanstack/react-router"; import { Card, TagChip, Avatar } from "@/components/shared/primitives"; -import { FollowButton } from "@/components/shared/FollowButton"; import { builders, currentUser, projects } from "@/mocks/seed"; -import { useFollowStatus } from "@/hooks/useFollow"; import { MapPin, Calendar, Link as LinkIcon } from "lucide-react"; export const Route = createFileRoute("/_app/profile/$username")({ head: ({ params }) => ({ meta: [ { title: `@${params.username} — DevLink` }, - { name: "description", content: `${params.username}'s DevLink profile: skills, projects and activity.` }, + { + name: "description", + content: `${params.username}'s DevLink profile: skills, projects and activity.`, + }, ], }), component: ProfilePage, @@ -19,12 +20,17 @@ function ProfilePage() { const { username } = Route.useParams(); const me = username === currentUser.handle; const b = me - ? { ...builders[0], name: currentUser.name, handle: currentUser.handle, avatar: currentUser.avatar, bio: "Product engineer. Ships fast, sleeps sometimes.", role: "Full Stack Developer" } + ? { + ...builders[0], + name: currentUser.name, + handle: currentUser.handle, + avatar: currentUser.avatar, + bio: "Product engineer. Ships fast, sleeps sometimes.", + role: "Full Stack Developer", + } : builders.find((x) => x.handle === username); if (!b) throw notFound(); - const { data: followStatus } = useFollowStatus(me ? undefined : b.id); - return (
@@ -32,21 +38,27 @@ function ProfilePage() {

{b.name}

-

@{b.handle} · {b.role}

+

+ @{b.handle} · {b.role} +

{b.bio}

- {b.country} - Joined 2024 - devlink.io/{b.handle} - {followStatus && ( - <> - {followStatus.follower_count} followers - {followStatus.following_count} following - - )} + + {b.country} + + + Joined 2024 + + + devlink.io/{b.handle} +
- {!me && } + {!me && ( + + )}
@@ -54,7 +66,9 @@ function ProfilePage() {

Skills

- {b.skills.map((s) => {s})} + {b.skills.map((s) => ( + {s} + ))}
@@ -62,10 +76,14 @@ function ProfilePage() {
    {projects.slice(0, 4).map((p) => (
  • - {p.icon} + + {p.icon} +

    {p.name}

    -

    {p.stack.join(" · ")}

    +

    + {p.stack.join(" · ")} +

  • ))}