From ab1497b48812bd99ed5235fd9713b2e61e2f5769 Mon Sep 17 00:00:00 2001 From: ebby Date: Sun, 27 Sep 2026 19:59:59 +0200 Subject: [PATCH] added lots of stuff --- backend/src/backend/.env | 3 +- .../__pycache__/config.cpython-314.pyc | Bin 484 -> 563 bytes backend/src/backend/config.py | 1 + .../authentication.cpython-314.pyc | Bin 3515 -> 3877 bytes .../__pycache__/mail_util.cpython-314.pyc | Bin 3696 -> 4744 bytes .../__pycache__/rss_reader.cpython-314.pyc | Bin 1583 -> 2210 bytes .../src/backend/internal/authentication.py | 8 +++- .../internal/jinja_templates/welcome.jinja | 2 +- backend/src/backend/internal/mail_util.py | 39 +++++++++++++----- backend/src/backend/internal/rss_reader.py | 18 ++++---- .../__pycache__/newsletters.cpython-314.pyc | Bin 837 -> 2247 bytes .../routers/__pycache__/users.cpython-314.pyc | Bin 6335 -> 6739 bytes backend/src/backend/routers/newsletters.py | 32 +++++++++++++- backend/src/backend/routers/users.py | 31 ++++++++++---- 14 files changed, 101 insertions(+), 33 deletions(-) diff --git a/backend/src/backend/.env b/backend/src/backend/.env index 6bff5c7..3fcde65 100644 --- a/backend/src/backend/.env +++ b/backend/src/backend/.env @@ -1,4 +1,5 @@ BACKEND_URL="http://localhost:8000" FRONTEND_URL="http://localhost:4321" SECRET="IamALocalSecretAndMustBeReplacedInProduction" -ENVIRONMENT="local" \ No newline at end of file +ENVIRONMENT="local" +MAILTRAP_API_TOKEN="FakedyFake" \ No newline at end of file diff --git a/backend/src/backend/__pycache__/config.cpython-314.pyc b/backend/src/backend/__pycache__/config.cpython-314.pyc index d9ad86485fc9c7c78ca0a9772e0e441083cae60a..25663f5e480aa5b9d13d67f3a2abf9d209a28fc3 100644 GIT binary patch delta 127 zcmaFDyqSepn~#@^fq{WRBXVcfor%1XjAtgQFP+#RF3P4O1rmpV61E^lWd=?5iI>d8 zZVCB1disO}IR?Z#26)DY_vwQ4^ysD41LoHNC_jRK&x;zyJVWvmPG+ delta 70 zcmV-M0J;CO1mpt^D-I0`00000cKEnzr;!aA0j7~Br3O*~BLFD|k@z+ODF%~70VtDk c0bmLZ000010001UK$F`6K?i~hati#V2QmL#cR0|;iBB4N-QGS}S6dzj3vOBa}mfd>i zu26{CYKV!(1j)q22Tl3_iM)~Ur1By$F(y8c)EG0e4?dX4TZtjQnsc`m{EO$|&Ufyd zd(Y2z?)fr%b1=Rw5sv`CFRy;S;9iesS~dfgaT+$WU^2n-gcVCMRiR3(S^*I_4Le|I zW>5s>o@Ry2un0>Wv@}x}y2K$XWJW|p;;(|=l*CPp+C+p~A%)ln}*0KQ7cgEEgOZEWp)q3M1 zCk}kIDayRp`ynuv4v?-NIC|uSZB3fTiUHmafTz46t&ks}pPS0uDG6t`R4zNNJ1ZLJ zojTt}cY9~FGtBV5(hiL#$uh_t(d6}8%vW8(i;QOgxRmr}PFHb?NG=6$S1`{E?_|(t zNpCbXzoUzCQ1~voM_Vj$;kpWdk%Bzw>vN7+cfAKd!TToknqt7)tL$g+t|&%}%Mi3q zcrO4r&bQ0D{C5;16y6}H4S$Ei1|QM#iMl2~?#kq+m*oyO0F>9clM)1=0{CrS9-ao^ zJr3_z*%b43>w~Rf6qO?LBczE36&E+6?Z+Iwy9 zdwV}@u10hB137MZ+3>_H6=~g#>$q;UQ7s#Pn6PItcKtwj2Ax}=d)<8#W&4>*^cGLMoT z^L~xwh60i)ewcPFY0-2Y?vnSBkwSqFc%#w&{86Ao&PMW}@=Sr?9Emk?b15PaQuspJGQEYcEm7PUVZPZ4uBfaeHXx*${1^-zl|+FL2u*5HjFl&ZDXMAO~hXrc^sn= b5JqwIw!XS`&$k!vpE|pGqWq-UrHelR(`8g0 delta 1584 zcmaJ>OKclO82)A-er@d7sULBi#7?6$aS);4BB}%-(zMDh0%|R3!y!&_>`mg<@rKzk zX)A%lL#RSr!XD@qsTFWQ0+mB0;K1X;4H1MY2TPogdP{^5T#(R=?F1pz|1k6Y|NQgM z|D4;yU!;N$g@OS9c>Axrmt#A@WMi5D+gOH44CsWBG{=%5F=-j5Y{tdB5giL%vb_uyrVlsvw80;Q%ws5S=tafZ5+s9x|m-WC!kZ zOLyKOc|s!Yp7gpp03dOvC^twf44^63>@DgSsLo0>;{KuJ`en}hXP=!vZyF2wb6JJP z0MNMmw3;DFx2Pu7Np8n&s4tO}`>T33ALUm()M9m7%aW$-Fq$Q_AArN7IZl(@0)JgB zX?_p~ujZdnNS+*s_48bNrzw|tnk4F;_pUz@0+5wxj=!L87AbQa3BZYru-WvlS?m(C zuUIvD8bI3p&HDmLxq(2wA)HdhS<~xSj#IH~S&2T(y$Euv5Abk|d&vFe9%>|fz?WO2 z`+WOuQE)T`pu~OYk_W(>0Dga$0LMK@V;d&cR4pjchAX@#wCI8E89 zuT*vja6Pza)Lto8E9FePuqOdr4_$C9nyJ|=vuf9C!c zDE|$bzC%y=9Ev1;3^60^LG?YkVVCPw>nUmi;Jf-+H*5!8=>8u8OdOje#gS~YD)w_cyIJf;yp%R5h7ZiNpN zO=?y>jri)(LTOxoxp3-e;miW@rBkNu6g0tCkGgNzwB}YVm-(qEr-q8Kwg&)An1fe=5gnLtF3Q9nsDVy;fk`F!5z&QSa1<8NMJAVkb?DL{Xc1o> zq0BBj)~LzMa_Ao<+*$-s)}H0Qnn=09kpM7}b4mCyvD*!WfQiFy!@2-E48j5_Xp$dc zHghar@n)t1POVs8nc8(`*IZw6Z1*)S;!B?8oTo_upebz9*kk~}L!pL{{ImJ#TGh&1 zQ&Vr}PnV~uWlu5ND^KU^w06-dGcSL{nX%q9nMJ3Z+J*d-S$@rOD|wHWo4oBZi@K(h zM;{q8%yx$BZ~Ka2*sjeC!_T(aV>s+ZM0>s54$EDeK8P*%Z2O>dxo_u^vS~Tf^I>!i ztx-msgm#ev>%rP_060MApakcH=Y9!L5dpTqPslXM!)fvg>=$%01Q7B<8!xu;67uM< zuh7~X*=d3JqQ|Hv`11K0t(wg5G>o!idS1mYGsEz3;f^_)1pq&87^dsin8_@|@HaiE zb894udZYipeGlG&)da+omyWL{fsoY{Br}&zt)`LBK&JbqlwIw@k1VK(OXFX610fVm zrb#Vd2ChXX7ZwyWx@%TZfS6%aYn2%X`M6=cK4UtKk)&aqx2eY*+qK-9VbE?AKiww& z`5Cut7=E{5c+6yW*)SQS_S6isJj1}5O&gRg$1#irLbsw?=&8fp8Z?e3#fIyP$ouv^ zn1incDbjmi1VY{gt_q*?J>#$Yd&XaSq*Arrk$Roh-Y^{=g>o2M0MHRe;bD%x$>vb8 z8EGw=AQOWnX>TKn2VkPuicO41nm~Vufxg_3vS*d4#Wb0A{TEo#r_fj^5|6>5z+!xH z|3jiT1EvQT^>L9`l&(94u&uWOQ1jD`g3sa2wa7l z^9Bv$p_}L6K8R#!6`M~_^Pj*QC`m{NA}-Zi0r0}a29r(T>9DuatCM{Vt}c{>V*54H zpc2GE7xoC@in>@5iwN#@R3f?&d$BGoXp%w4%|!*Tz~O;{zlJY?zvmZ z=jX6R#m7RGN+h1km_t0BCjR^`G6y-cp~P8~sx4yt?oGeJjcI)!FxF z7jq+jO)MoRR^o}P$KOA`xb=ml`2I!pz;b5meC6YdA6=ZETukj+?o8i{M&k0^=)E{Z z5|=B#dbtIzFtz+(sE=X%A~YWbbbgP8=}#v8tJwT{l>fA338`7XeHH*c><1m5I}1?R zjq%==3Q1{0s3YjYlsC{ezXTfrzco`A2Vt@a;v#=hJxJSO5-S!?x)8#@PD-SR_0>8m zt=k*Ra;H`{o$pk9b>uwDWiR9wh#z6K*DSZ7DHH?KkJPE{GWrrn5wqT6^eD0kT*RnZ zf61{emr;ZkR`6~`6Sy~gxy(oS9Xu4|Px@nY6E@rx#{yt=WUgIU>e#xXbY4^EM?XIK z(aHIPi-}!J%9ATf=jF;(`-**A+4N<)>rQ&dXXzbF+Ww{Vfy?r;lDMi~QLl~OR{C1r z3z3BK;NRK{{E$aqsjc+#6qXPTYQJbBJbp9*A1fZCh>b@f4R4Z0@pB(iWXCEtzuCK# zd*<((_wbLF#33~k>%TX~+cSu_5~SeR6MzX8wd16t$2Ul_c-@xBMktHJ9;t=26T7hN z-3EI6|3X~zlCBGrO}t?u)@8jzSMq`$)nj>~1iBig@w!+NidbB)qmtN?2BpwC=}AP& zDNK!0j@5Fs!10AwF2y>S9>fMyCw&ncgy(FoJqzc4o;%V^)wxqVRipo=OwaNa8a&Ot zf)?d4r^Rp=dIUMdIMuO1GgB;Q{MZz}>9d zZWf}+J4)Y8rEh-dwz8eWP)qxX#zT3yTyxLc7lLqBP-Kj8j(2W^z*v};f;1rWQfp7E z!U|p%ycEWYh~FYX*rVzTjaL+Zfhq@r7vDkt4-E`l5AUkGA|d1pc=`(%`T{iG_I(cB u|A5{1r5H)9LX0HtZHkc8ym}8JB=t=~BtzfCq9prGk4*aSr&1({uKxheZ>qWg delta 1779 zcmaJ>OKcle6uobL_IT`Z{7KxnpSW?GbQ&6(5VfcZr9VPHiDNy$2r1xB?4fn**w&j# zK>-m9B$Be}=XJrdVpqf#iABYlRn<~ds!>-6@!7QyRM?^W#!jOk@fLSR_uY5jx#yny zR(C(%W{#M#2mrvB|9o>{O}%DrAs<~E&O4s+4p8NkdQ$VWlOZoO0KKpisG0$)O-OhE zzzYjsC<8S7c6dVWcy+30fJQP<@9`qk$N-Ise}l#{;6aL=)!)X@!LN1L^92w=T&eB*DLsM~KGn$S-Ho0AMMdgX?*se3vpwlH68~XR`p{ z5&$^D5*VO&jmE!KvN|RZK5mm?lH|I2zXHb~NZuQs)(uN%uUc!|XN(IGG*vxDv6;8y;*mM2MmTgy(15{bB= zz_w%f?oA~PqZ18+b+O97SD+1lNRqn!sSJdC0!-97%#Y|N&L9R~soI`x5mBT?1PsB_ zUalVifW*Pjf+YX$UXqHq>@w& zZQKi138;Lq8zb}E@tsDv8&!<*u}E*fLRG3A>}YRp({3t6!`<_vgz6WJau#(#13Y)X0Ms<+I_jKGSZsSo4xyAH7g(TtIe4QK|PL&y!o67^7r@ z?>DSv&w1Y~SUSUQGpxsto^!mi=Pb19w&(a7a~f5L`O<>NkPts~v|443>k8rcy6ZHm z=AzeH^n3+lT+A?(%jI&SG5!vh-!gVYj(1!0!F7FL%iY}m z`|+{%$%nDtE9J}Oo4Z!a_hZBDDgKjjAeCCv)u`4!u@(i@T&;dO%hD)=c_GDPSOYTj ze;Pn(t!qFf*(YdjoDd%&tV*YQVqrFX5B|K#??wB_R{mRbqK7JZm_x$EDu%JE%hHCv zqk3@eHmwqD=#-KNOZC-yvtrkmj2XLD&$&*+JCs}MnS5*Z4O%{0JXL;u_RK4V!xr&X zuX)jF6fBJ)8eeU(TEk;6V!@N>F!?VrbIez;9hM}R@U=?4<}^Gpi$ek9>@c1{BWO6p z_nO;d55glqCsIEq2ER`X-sNY_^m900m5tz07=ng*F+6kYdqs&SBE8RQEh>TxpoB_Y ziBp*>-TwigY91_&jUkY6G%o2B`mcjgcAHy`$lKUEbqBBWr&d~@EeTyz@M(Mq%NZtYw^e;CE=F}o#3BEX`F zF&h_ybXrVO@aBs53>6-5k04k9jd;Xxiv959LbJM9cMh}H008CZVy%y5LI|Hp?n)XY P{ns{?WYcRIXL&~(viS01Lt=j&RpvK502)5S65KTGhHMMY z161(t?8ri)%y5Bc*N(0b5$8^kH)Lw3gHEzvn z67QrUHPKkZyIA8ZC1F$lex4?N;bO65Sv64-MzP3;09*uM_ql-1p|Hp)x%aUX+CKGu z8{F3>-4gG2>CpRaBk^25ui;!`w`5je&Lfsw?*&$+0_I41*9wx(M!MS>Fy2yR;vul) zvcJ;<6r?q&4+99G7dlatd8kcsR#SM4k~lf~W}YBNa5ULffp<}%8yJI4sIH{bP0oo$ z)2b9pT$tsmQCxUd6sD*eTx*k`a_XMU^kFFSa_W_D$G4vv-ivDoA?+}ldY(O15Ko_a z5pD{gbu?j6gNC|LDlZ#WC0njpi{=vdIGaj_Db7bFeY-hWgospVP80eG{#@KIUemYTa{K6lP%C4WM71o6DA1Ph29smFU delta 350 zcmXAjKTE?v7{;G7mt4}uXhE?c{R2{K6{><@2hmAr*UlnndrH(M<#Hl8`4!520L4is z5eNMet`3n5LLHnG>f|JsE-ydc_u=o4AI56l)xm6+M;+n!r5^^u)5j^bL~qOzfQ)*j*JP-A z=KSK&UB26RbJs=%%#=sEMJ*e9hX str: return parts[1] raise HTTPException(status_code=403, detail="Invalid authorization format") +def decode_token(token: str)-> str | None: + payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) + return payload.get("sub") + async def get_current_user(token: str = Depends(get_token), session: Session = Depends(get_session)): try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - user_code: str | None = payload.get("sub") + user_code: str | None = decode_token(token) if user_code is None: raise HTTPException(status_code=401, detail="Invalid token") except PyJWTError: diff --git a/backend/src/backend/internal/jinja_templates/welcome.jinja b/backend/src/backend/internal/jinja_templates/welcome.jinja index d6ad6f6..6322cca 100644 --- a/backend/src/backend/internal/jinja_templates/welcome.jinja +++ b/backend/src/backend/internal/jinja_templates/welcome.jinja @@ -12,7 +12,7 @@

Dein persönlicher Code, um alle Funktionen nutzen zu können: {{data.user_code}}

- + Daten löschen diff --git a/backend/src/backend/internal/mail_util.py b/backend/src/backend/internal/mail_util.py index d8bc083..0cfa910 100644 --- a/backend/src/backend/internal/mail_util.py +++ b/backend/src/backend/internal/mail_util.py @@ -1,3 +1,6 @@ +from backend.config import MAILTRAP_API_TOKEN +from mailtrap import BatchEmailRequest +from mailtrap import BatchSendEmailParams from backend.config import ENVIRONMENT from mailtrap import Mail import mailtrap as mt @@ -22,30 +25,44 @@ class AdminApprovalData(ArticleData): secret: str -def send_newsletter_admin_approval(data: ArticleData ): +def create_html_from_template(template_name: str, data): env = Environment(loader = FileSystemLoader('src/backend/internal/jinja_templates')) - template = env.get_template('approval.jinja') - output = template.render(data=data) + template = env.get_template(f"{template_name}.jinja") + return template.render(data=data) + +def send_newsletter_admin_approval(data: ArticleData ): + html = create_html_from_template("approval", data) mail = mt.Mail( sender=mt.Address(email="newsletter@blauwasser-mausis.de", name="Flaschenpost"), to=[mt.Address(email="blauwasser-mausis@proton.me")], subject=f"[Approval] {data.title}", - text=output, + html=html, ) send_mail(mail) - def send_mail(mail: Mail): if ENVIRONMENT == "local": print(f"Mail sent: {mail.subject}") + print(mail.text) else: - client = mt.MailtrapClient(token="") + client = mt.MailtrapClient(token=MAILTRAP_API_TOKEN) client.send(mail) -def send_batch_mail(): - mt.BatchMail( - sender=mt.Address(email="newsletter@blauwasser-mausis.de", name="Flaschenpost"), - subject="Flaschenpost | Blauwasser-Mausis" - +def send_batch_mail(mails: list[BatchEmailRequest]): + if ENVIRONMENT == "local": + for mail in mails: + print(f"Mail sent: {mail.subject} to {mail.to}") + else: + client = mt.MailtrapClient(token=MAILTRAP_API_TOKEN) + params = BatchSendEmailParams( + base={ + "from": { + "name": "Flaschenpost", + "email": "newsletter@blauwasser-mausis.de" + }, + "subject": "Flaschenpost | Blauwasser Mausis", + }, + requests=mails ) + client.batch_send(params) \ No newline at end of file diff --git a/backend/src/backend/internal/rss_reader.py b/backend/src/backend/internal/rss_reader.py index 0e2cb24..c7e00d8 100644 --- a/backend/src/backend/internal/rss_reader.py +++ b/backend/src/backend/internal/rss_reader.py @@ -1,4 +1,5 @@ +from feedparser import FeedParserDict from backend.config import FRONTEND_URL from backend.internal.authentication import create_access_token from backend.internal.mail_util import AdminApprovalData @@ -18,15 +19,14 @@ def check_blog_rss_and_send_admin_mail(): description = str(article["summary"]) subtitle = str(article["subtitle"]) link = str(article["link"]) - secret = create_access_token({"sub": title}) - + data = AdminApprovalData(title, subtitle, description, link, secret) - send_newsletter_admin_approval(data) - - # TODO: create link - # TODO: create Template with jinja2 - # TODO: send mail to blauwasser-mausis@proton.me - - + +def find_article_by_title(title: str) -> FeedParserDict | None: + feed = feedparser.parse(f"{FRONTEND_URL}/rss.xml") + for article in feed.entries: + if title == str(article["title"]): + return article + return None diff --git a/backend/src/backend/routers/__pycache__/newsletters.cpython-314.pyc b/backend/src/backend/routers/__pycache__/newsletters.cpython-314.pyc index 8ae85747be1c5eaf21d89d8357ce422beaedd009..67174437be50ff9c6b9668276b7487a0545fcc25 100644 GIT binary patch literal 2247 zcmZWqU5pb|6h1SZw$ts;cDp~_Wmk3=bY&FVUDyaF3PN_t6qJ-CVa5wsD?ro8pu&9{|8#Cw@Hhdl2AHuK1#Mz{V~K;0l}uL&||JQE8H6IVbA@8W1>;lXZnE z0xLPtgES~`Fc;FpG%Ro^r|Jk?(_kcxfsB*^BV`O4Ls=;+ z8N+*&c5ZZZc{IP$mw5=^d7l=vOF>k^Bv>zz%(o;=cTr~TQ)}1V2q`~Njj46 zL$?@Pwu3hQm^*0_8?!O8C^9Rw=9nwkt(g?nJjbF)li0vPi`tdNnpJfSbgqF2)g%@X zhwoZdN0V4TLG`j(;%+8)(QG`Po_X;DH6xSUh%O@%WM^u{b|pykH}bR^7TL zu@FHHviX(D34*XDvG8$3NZS})Mbso+HN1d4R4)@vV#6!ddfBuvt=bMUOBYRAr4Ela zRz|j4MkaO7B7VPe$i+1t@PT~Ja2piiOVMl{ohJ^W6k!I{&m;gAEhA#%s)*`R z7?}kK#W>pLGPL62nnekJ=QegKTXAbBi%O-7+2eKvqiTs(iCxKh*gb=6O0ox?20Cw1 zgiDUQnk`xOSyV4)3AVc!i?WgbRgGl4i!5fER=w_0-Z&jFURP6VkG~_~PzLT#P zE)MwTg-|}_ zA--2d(v+i1tgkl`n#^SCGKDV#ErEF^IKdlFK^KsXBV6Y@nFY^R5JoIU8l~>+U``O` zea?c2?*bOGJU%g)^NcwGnDe1U@Hof3Wmr%QFAI0ZnI$_nmQdMj5QGT}@~a3_xQ1U6 z!H5$c%*@PGTks?|q&jnG_A5QmzTe|{N173^WVPnaOb|eJNNxWAMVfJ-Jf4uI(c{h$@QJ5)+gUv zi%m3N%U)glZFI*qX~{@cVE z$%tZerp0PuW4^f?OxdDV$s!2zIl*yW{qg6VFd-&JRvF=T7fn9rVKrz4)oInX_N!Zozm9UTndHP{&*FRtxsFV6+7<{1Hhtqod8f*wvxtz+kgKb#3{pBWpvmYl*qd zNU%@75_*yVS^a4IgYl-4XeI}r1VN5(KtPtCsxb4)H-(?WzeLyHUiycxyNyUdmj6~0 I(k>C}f1|k}(f|Me delta 468 zcmYjNu}T9$5Ph?oT<$Jd05JJ}zTBb*&mZ0axWzFP?O~S; zRT+yt>j?56o+5=-|7Ce%spx*r+MYQ4;fCA!2N_RdxRY|slk rdM$fPbOhi-644m`80+s&c~taA?%Z7^9@y>54{tMdq!3>=(QN!5+VN3f diff --git a/backend/src/backend/routers/__pycache__/users.cpython-314.pyc b/backend/src/backend/routers/__pycache__/users.cpython-314.pyc index a18358a3a8fe0cec3df26d45ea920348cdb5de6a..52ed5ef5b81813521b4914317f22ce4e4b1399ac 100644 GIT binary patch literal 6739 zcmd5=U2Gf25uUv}{zymtOO~i#%5vn;jzvjvEhlju+mURtNf`QU(@iUxpvaZPgyb=M z%i30oLIw&Xerf!W2N(8(gFdt_3^V}>)Ol(U^d&$ZIf_NAD; zJCc?ar$JL71MoQebF(wEGvChM?&hXO0D#2H@4xa+6Tn}v;ZTds++9!rR^SY1Bm!Z= z$q@2V1i})R1TRPAu)-C=D-l=N&E0}`MO7Ct1@DchVITJi zz9FK9n|PDp8zar(7TywW<*lNvM%u#dyj}3VNJqGncM85K(iZOGU4n0pYzueuZo#)i z8p1uiNARtYhOnRe1>Y9w4fpXr!M8`+!u`Bo@Ewtk@BkkWd}pLBJje$H-xV1O2Y6rz z<_3pB+cpMTx7MTiLnK7B-YMDg5g(o#j?FlZtC7}s=A*g(VVDaH!<=^*<~+l2hRnHR zM{9E&+ACSyUSj=g{ZlsQ^o$X0z*$j9?Q=$+B-&s%XhYqQZOxLswn)C?3$zMsp_M%6 zj(x|`rAB84pK#S$Us1>QVQ_TWq_3n6cZ0TllfI*0pzp}n>cbsVwx=Jd-(%gNjc(F! z=iG4Yc+DFQX*)W+nHcDXuCE^3eFA3PC4(_=uwg$^5E`n(4N>Nch`R< z_fh+@ryI1fEu@~VY3Yy_dcf|@Qma1Lq`9n(cY`*uX^khe$q@)X`8O0EBxZv_^XWt` znaKu;=}$45Lv()r zeCR}KiP6kF&lsttP=V>M&=fa9N3unFHpwZQ&+3bz`DE%^<0kT1IwL(9|n$8-wM1a-ZDLBX*Q+jXizaF zu4AI-(-ecXIFIpWDhN{1U^8pSXl~BwX_`&^Aeqgilbo7zGMzTvDLt3VaMQ!+0;9$f z!;Lmw6w%I9^2r=!=sh0p09{_zUKp9>uq)L6Ls+Nxsv+$%5+6(aZRp!Ti#MHs+XqM zynf`HFE+1vdys3n*m7A}^A3F0(y`vs@z(Oi<@Jt<^=%XH?)Xjcz2Lijs|RAMoyR|I z+x3g5-c6U?X`sVZ)KMMCt$oA!iF6Ld2Opf@Oeg z6z78trb5rr6vGRNl~%5^OO#ReH13gWA;S!AB?d0eP~Ypa7!o*EssGr}ce zhfM>(6b{CPk1Ia#b-Z=p;(@E~tNe=ZcF(R`J-cq~{nf$i2XDT7YxmJo&#{skzO6=Y zsnL=eTbcf=+9Kk1qSQRO>Ye;l9lYkc#((~!cYd@ww6CO2ttwMuW0yUl1)VMGJV?Iw zQ&R*gn{=RnVax>|5tCuG*Ez{#(zJn(tIt*N@7GhJ^@w2n)VjQ+hc`?9LmukVMAYYL1kf>ufEV_&!Ekc$RdW- z!J|UurTS1IWMTs!HJ?tWWJYM~8r|_`#-#9H=4|}+J*#7+y9{wgAwsZ#`vT+it9}4wa|DOhcqiR)b_7(jQ&YL zqFrQO;%nZ1oBxBiXTw!RNnehJjN&}rW#{SFR`*rwruw?iXRjmf%(a{d%BC`}>sbpv zzbw~N=n%X-V)f_2T=$T!PusUuWDn{3tbJR>RAB+HN_hp7z%|iGPC}4L~!Oh-q8-Y7gOUe8qO+4TtETHDm z-hfcG;)CHmYsvuP!t)oNzvQ#|=!GgqM1yQqJj^^~FP6xkPzsdKQufPZlx^>s!-nyp|O!SrrCe&&+1ywQMq* zTB5o0WAt1~T;Z&c!PCj~Kcq)G$&>R*gEG7kvo3sKa520Jo89($j=^Kr#~Onn44ZE2 z(t|8xf7>xeB!G%c2r0vO84i`fUxtw~43%Mf86GdgfigV%M>tl7o-*{6VYm#z zGVCbB&N57hp8hfnlp*xzhW2%}W4*0oy`}xq+_mRdJI7a>C+>NaMrp-e@qy%hqwhlB zy5d=H?YPtK|LN}Qi|?gxPTXAjt^U4V+7~U2y|mUFE43eAZPO|qkecp-B1s#K@YEsl zfm+)C!hQT6b5~U)snXa^CM&zDB7IwlT#aeJKd6=VohXf+T@!WxL4!N^4bi)0gV%61vKgwBd!3oj)6W|MUmnFMa#?eJr}~Hpr4x z@yevh@<8u}-Zy718!NpfGIA%hZ*}TeDHOhsHP>Akq#YHBkco;H7azDV@MiJa$jU&8 zjNS?CTz!0hDe%-si>vWuDLQ{2OA35rXGM}oSEccxH~Irtj=p#H=If=Y=g~I5J=sP4 wmTjm=^cONJ^2DG016Q`)@ds9iCrbXwJKckqUoUm9(E6h8O8`Rn|?X{Ynof$8*T%9PR{s1~Fm6p=Sj>i8gpq)f|n`q~aoJMEp@ zNZquo&=4ZzCa8%E7cOixB!-Q;&{W-YqZk^a6BoE7aZxN$cbaowr!6D2@h{etrD;H0h zYpll5nueCO<_)hXkJZTVJYb6B0nl11Ts5U5snh?*75q05CHg> zz6<<@B^WAMsLp2TR6?c-0MHr$D9J@e`DYf^-wXgz04O#9zykaQ4ibKZ(+4M4artyy zEGw^_6Q^qkl3jlYVweB`t8Yyqd`M~M?^-AJpO;eA#@DT*5$fTh=twv$Fxm_dfob_1 zNxArvHS*j=Px<$Y$W)ASCMJjm)ACDlj^yC5ybE$+#rx$0ec{k$pT~Ur(Fx*hTg6T#@N?7{Ajl00?7l zX81o4(k zfsPkgg3us;$CKKR#7kyvaH z5{aXh9Rld%Q3V4yuJlI*cS&5K3F96%ZJ|?~Ht{=3ow*MHj`8o62#F(nkB}Pw648`V zvFf%{`6Q=aM7`}DyI`P}ETei}XFA=BSEWstMJ&H~+;}D@5D2GNkQWyI0z5D|t_@rr zxY@g6s{h%re=_-~px0UP5_gibpRZJx<@DA(IxV=_o~ovJ-l(QQ3Te|rmG5qo@M(U= zH%Q`q(RX>?kgPa6Qq0oaG|LsHHp5NGCDTZukT=xZDUat6u-waJQu_#}k49H<`L0_m zD^s)Ll;YFLVo~thwU;|ZWHL=6?N*#b-q#N{^jt3@6u;9Ss_qAXvj~Y1EWm^MHlFr} z8`1MXVo%9EJx4Q4AI|3{b4;fc!6^0|YUV%qL&U-#`kS*>JiwAIDMgl{d7Ux6y~r|b zwkW!osOge*EK_8e=^S<7pSI#mezGvC=Z%`ej#qLQXY!eRc0!+=YuB%2DRxC8YYLwU zL=`XYu`!D*QXl^?u#434uL9u<*y>7_vnP(fI`FdS38KPE^0>|@K5!vhNuHi%6hmGF zkvyYo+IlAoqqBMa2u%Y3wyK9(24_et9?`?@|kzua<98@Ycf`{R}QRe)nszqAH0 UN6tupqM~auNc;YfWMYW str: +def register_user(new_user: NewUser, session: Session = Depends(get_session)): user = User.model_validate(new_user) try: session.add(user) session.commit() session.refresh(user) - # TODO: send mail + + mail = Mail( + to=user.email, + sender="noreply@blauwasser-mausis.de", + subject=f"[Registrierung] Willkommen {user.name} | Blauwasser Mausis", + html=create_html_from_template("welcome", user) + ) + send_mail(mail) + except IntegrityError as e: session.rollback() raise HTTPException(HTTP_400_BAD_REQUEST) - return user.user_code + @router.post( "/login", @@ -53,6 +64,7 @@ def login(user_code: str = Form(), session: Session = Depends(get_session)) -> s raise HTTPException(HTTP_401_UNAUTHORIZED) return create_access_token({"sub": user.user_code}) + @router.post( "/forgot", dependencies=[Depends(RateLimiter(limiter=Limiter(Rate(1, Duration.MINUTE))))] @@ -62,6 +74,7 @@ def forgot_user_code(email: str = Form(), session: Session = Depends(get_session if user is not None: pass # TODO: send Mail + @router.get("/me", status_code=201) def get_current_user_info(current_user: User = Depends(get_current_user)) -> UserInfo: return UserInfo.model_validate(current_user) @@ -72,6 +85,7 @@ def delete(current_user: User = Depends(get_current_user), session: Session = De session.delete(current_user) session.commit() + @router.delete("/me", status_code=201) def delete(user_code: str = Form(), session: Session = Depends(get_session)) : user = session.exec(select(User).where(User.user_code == user_code)).first() @@ -80,14 +94,17 @@ def delete(user_code: str = Form(), session: Session = Depends(get_session)) : session.delete(user) session.commit() + @router.put("me/subscribe", status_code=201) -def change_subscription(subscription: bool = Form(), current_user: User = Depends(get_current_user), session: Session = Depends(get_session)): +def change_subscription( + subscription: bool = Form(), + current_user: User = Depends(get_current_user), + session: Session = Depends(get_session) +): current_user.subscription = subscription session.add(current_user) session.commit() # TODO: -# Template für Willkommen mit delete link -# change mail <- token, new mail -# delete all deactivated users after 48h \ No newline at end of file +# change mail <- token, new mail \ No newline at end of file