From eec8f54eab349f3556098557972bacd96bb83abe Mon Sep 17 00:00:00 2001 From: Moritz Kowalski Date: Mon, 19 May 2025 17:49:29 +0200 Subject: [PATCH] Add delete prepaid and show prepaid users Shows only prepaid users which postpaid_id equals logged in id an deletes only users whose money equals 0. Additionally a lot of style improvements in base.html and new favicons which actually load in. --- db/models.py | 9 + main.py | 91 ++- .../fachschaftslogo.png | Bin static/favicon-16x16.png | Bin 0 -> 546 bytes static/favicon-32x32.png | Bin 0 -> 939 bytes static/favicon.ico | Bin 0 -> 15406 bytes templates/base.html | 695 +++++------------- 7 files changed, 253 insertions(+), 542 deletions(-) rename fachschaftslogo.png => static/fachschaftslogo.png (100%) create mode 100644 static/favicon-16x16.png create mode 100644 static/favicon-32x32.png create mode 100644 static/favicon.ico diff --git a/db/models.py b/db/models.py index 2cecafc..a8f6d50 100644 --- a/db/models.py +++ b/db/models.py @@ -320,3 +320,12 @@ def set_prepaid_user_money(user_id: int, money: int, postpaid_user_id: int): raise HTTPException(status_code=404, detail="User not found") connection.commit() return result.rowcount + +def del_user_prepaid(user_id: int): + t = text("DELETE FROM users_prepaid WHERE id = :id") + with engine.connect() as connection: + result = connection.execute(t, {"id": user_id}) + if result.rowcount == 0: + raise HTTPException(status_code=404, detail="User not found") + connection.commit() + return result.rowcount diff --git a/main.py b/main.py index 2d090f0..615b978 100644 --- a/main.py +++ b/main.py @@ -19,6 +19,7 @@ from db.models import create_prepaid_user from db.models import drink_prepaid_user from db.models import toggle_activate_prepaid_user from db.models import set_prepaid_user_money +from db.models import del_user_prepaid from auth import oidc @@ -37,6 +38,8 @@ templates = Jinja2Templates(directory="templates") @app.get("/", response_class=HTMLResponse) def home(request: Request): + + # Check if user is logged in and has a valid session user_db_id = request.session.get("user_db_id") user_authentik = request.session.get("user_authentik") if not user_db_id or not user_authentik: @@ -45,9 +48,9 @@ def home(request: Request): user_db_id = request.session.get("user_db_id") user_authentik = request.session.get("user_authentik") if not user_db_id or not user_authentik: - raise HTTPException(status_code=404, detail="User nicht gefunden") - print(f"Current user: {user_authentik}") - print(f"Current user db id: {user_db_id}") + raise HTTPException(status_code=404, detail="User not found") + + # if user is Admin, load all postpaid users users = None db_users_prepaid = None if ADMIN_GROUP in user_authentik["groups"]: @@ -60,6 +63,9 @@ def home(request: Request): user_db = get_postpaid_user(row[0]) if user_db: users.append(user_db) + + # if user is in Fachschaft, load all prepaid users + prepaid_users_from_curr_user = [] if FS_GROUP in user_authentik["groups"]: with engine.connect() as conn: t = text("SELECT id FROM users_prepaid") @@ -70,15 +76,23 @@ def home(request: Request): prepaid_user = get_prepaid_user(row[0]) if prepaid_user: db_users_prepaid.append(prepaid_user) + # additionally load all prepaid users from the current user + t = text("SELECT id, username, user_key, money, last_drink FROM users_prepaid WHERE postpaid_user_id = :user_db_id") + result = conn.execute(t, {"user_db_id": user_db_id}).fetchall() + if result: + prepaid_users_from_curr_user = [] + for row in result: + prepaid_user = get_prepaid_user(row[0]) + if prepaid_user: + prepaid_users_from_curr_user.append(prepaid_user) + + # load current user from database try: if user_authentik["prepaid"]: - print("Prepaid user") db_user = get_prepaid_user(user_db_id) else: - print("Postpaid user") db_user = get_postpaid_user(user_db_id) except KeyError: - print("Postpaid user") db_user = get_postpaid_user(user_db_id) return templates.TemplateResponse("index.html", { "request": request, @@ -86,7 +100,8 @@ def home(request: Request): "users": users, "user_db_id": user_db_id, "db_user": db_user, - "db_users_prepaid": db_users_prepaid}) + "db_users_prepaid": db_users_prepaid, + "prepaid_users_from_curr_user": prepaid_users_from_curr_user,}) @app.get("/login", response_class=HTMLResponse) def login_form(request: Request): @@ -120,13 +135,8 @@ def set_money_postpaid(request: Request, username = Form(...), money: float = Fo if not user_authentik or ADMIN_GROUP not in user_authentik["groups"]: raise HTTPException(status_code=403, detail="Nicht erlaubt") - with engine.connect() as conn: - t = text("SELECT id FROM users_postpaid WHERE username = :username") - result = conn.execute(t, {"username": username}).fetchone() - if result: - requested_user_id = result[0] - else: - raise HTTPException(status_code=404, detail="User nicht gefunden") + user = get_postpaid_user_by_username(username) + requested_user_id = user["id"] set_postpaid_user_money(requested_user_id, money*100) return RedirectResponse(url="/", status_code=303) @@ -150,11 +160,11 @@ def drink(request: Request): user_authentik = request.session.get("user_authentik") if not user_authentik or FS_GROUP not in user_authentik["groups"]: - raise HTTPException(status_code=403, detail="Nicht erlaubt") + raise HTTPException(status_code=403, detail="Not allowed") user_db_id = request.session.get("user_db_id") if not user_db_id: - raise HTTPException(status_code=404, detail="User nicht gefunden") + raise HTTPException(status_code=404, detail="User not found") drink_postpaid_user(user_db_id) return RedirectResponse(url="/", status_code=303) @@ -163,18 +173,18 @@ def drink(request: Request): def payup(request: Request, username: str = Form(...), money: float = Form(...)): user_auth = request.session.get("user_authentik") if not user_auth or ADMIN_GROUP not in user_auth["groups"]: - raise HTTPException(status_code=403, detail="Nicht erlaubt") + raise HTTPException(status_code=403, detail="Not allowed") user_db_id = get_postpaid_user_by_username(username)["id"] if not user_db_id: - raise HTTPException(status_code=404, detail="User nicht gefunden") + raise HTTPException(status_code=404, detail="User not found") curr_user_money = get_postpaid_user(user_db_id)["money"] set_postpaid_user_money(user_db_id, curr_user_money + money*100) current_user_db_id = request.session.get("user_db_id") if not current_user_db_id: - raise HTTPException(status_code=404, detail="Aktueller User nicht gefunden") + raise HTTPException(status_code=404, detail="Current user not found") current_user_money = get_postpaid_user(current_user_db_id)["money"] set_postpaid_user_money(current_user_db_id, current_user_money - money*100) return RedirectResponse(url="/", status_code=303) @@ -183,11 +193,11 @@ def payup(request: Request, username: str = Form(...), money: float = Form(...)) def toggle_activated_user_postpaid(request: Request, username: str = Form(...)): user_auth = request.session.get("user_authentik") if not user_auth or ADMIN_GROUP not in user_auth["groups"]: - raise HTTPException(status_code=403, detail="Nicht erlaubt") + raise HTTPException(status_code=403, detail="Not allowed") user_db_id = get_postpaid_user_by_username(username)["id"] if not user_db_id: - raise HTTPException(status_code=404, detail="User nicht gefunden") + raise HTTPException(status_code=404, detail="User not found") toggle_activate_postpaid_user(user_db_id) @@ -199,11 +209,11 @@ def add_prepaid_user(request: Request, username: str = Form(...), start_money: f active_user_auth = request.session.get("user_authentik") active_user_db_id = request.session.get("user_db_id") if not active_user_auth or ADMIN_GROUP not in active_user_auth["groups"]: - raise HTTPException(status_code=403, detail="Nicht erlaubt") + raise HTTPException(status_code=403, detail="Not allowed") if not active_user_db_id: - raise HTTPException(status_code=404, detail="Aktueller User nicht gefunden") + raise HTTPException(status_code=404, detail="Current user not found") if not username: - raise HTTPException(status_code=400, detail="Username ist leer") + raise HTTPException(status_code=400, detail="Username is empty") user_exists = False try: @@ -215,7 +225,7 @@ def add_prepaid_user(request: Request, username: str = Form(...), start_money: f pass if user_exists: - raise HTTPException(status_code=400, detail="User existiert bereits") + raise HTTPException(status_code=400, detail="User already exists") create_prepaid_user(username, active_user_db_id, int(start_money*100)) @@ -228,12 +238,12 @@ def add_prepaid_user(request: Request, username: str = Form(...), start_money: f def drink_prepaid(request: Request): user_db_id = request.session.get("user_db_id") if not user_db_id: - raise HTTPException(status_code=404, detail="User nicht gefunden") + raise HTTPException(status_code=404, detail="User not found") user_authentik = request.session.get("user_authentik") if not user_authentik: - raise HTTPException(status_code=404, detail="User nicht gefunden") + raise HTTPException(status_code=404, detail="User not found") if not user_authentik["prepaid"]: - raise HTTPException(status_code=403, detail="Nicht erlaubt") + raise HTTPException(status_code=403, detail="Not allowed") drink_prepaid_user(user_db_id) return RedirectResponse(url="/", status_code=303) @@ -242,11 +252,11 @@ def drink_prepaid(request: Request): def toggle_activated_user_prepaid(request: Request, username: str = Form(...)): user_auth = request.session.get("user_authentik") if not user_auth or ADMIN_GROUP not in user_auth["groups"]: - raise HTTPException(status_code=403, detail="Nicht erlaubt") + raise HTTPException(status_code=403, detail="Not allowed") user_db_id = get_prepaid_user_by_username(username)["id"] if not user_db_id: - raise HTTPException(status_code=404, detail="User nicht gefunden") + raise HTTPException(status_code=404, detail="User not found") toggle_activate_prepaid_user(user_db_id) @@ -256,7 +266,7 @@ def toggle_activated_user_prepaid(request: Request, username: str = Form(...)): def add_money_prepaid_user(request: Request, username: str = Form(...), money: float = Form(...)): curr_user_auth = request.session.get("user_authentik") if not curr_user_auth or FS_GROUP not in curr_user_auth["groups"]: - raise HTTPException(status_code=403, detail="Nicht erlaubt") + raise HTTPException(status_code=403, detail="Not allowed") curr_user_db_id = request.session.get("user_db_id") if not curr_user_db_id: raise HTTPException(status_code=404, detail="Logged In User not found") @@ -273,5 +283,24 @@ def add_money_prepaid_user(request: Request, username: str = Form(...), money: f return RedirectResponse(url="/", status_code=303) +@app.post("/del_prepaid_user") +def delete_prepaid_user(request: Request, username: str = Form(...)): + + # check if user is in ADMIN_GROUP + user_auth = request.session.get("user_authentik") + if not user_auth or ADMIN_GROUP not in user_auth["groups"]: + raise HTTPException(status_code=403, detail="Nicht erlaubt") + + user_to_del = get_prepaid_user_by_username(username) + if not user_to_del["id"]: + raise HTTPException(status_code=404, detail="User not found") + + if user_to_del["money"] > 0: + raise HTTPException(status_code=400, detail="User still has money") + + del_user_prepaid(user_to_del["id"]) + + return RedirectResponse(url="/", status_code=303) + if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000) diff --git a/fachschaftslogo.png b/static/fachschaftslogo.png similarity index 100% rename from fachschaftslogo.png rename to static/fachschaftslogo.png diff --git a/static/favicon-16x16.png b/static/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..f98a40bb2ea8d05501c0e5c2a676b20ef0a4e877 GIT binary patch literal 546 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uuz(rC1}QWNE&K#j*5m2o7-At< zd-<&P(m;meA5WXkocJX5RFBcJ3=hrDR!(khRqe<6GuEUfDo1xmo-6vc*kjr!^$1VH z;3-#HG7kAXshx4~?DyYys&}0){kZykah%-qJD=wis|fGRT=Y{^{6`1dmPC#;?bww0 zt~awnc0a3Z@RoTfv(o2pmytf}_o`DFuQ$&5@JQ$1CC;di^1Ela-!pp2y>hWp$Jq;s zmW}!=j`R2!?^+b4^s#S~*tGW_nMFGu$(?zazf00qy3#L+KmUW&x^)8F5$>i|0gqU8 zEsnAIXy&|MAf$MC;Uvw!3yahXmOs{xSoSvXm-hV&eRFyj=gI^>*%b3izU9Z-^BX$s z);wTt6YNj^7UO8nw~;Nl+3(H);ZH?B%b6owJE{Yoc5D9O-pfD5{-t#5_rq7)&IDDu=Av>#@Fod;Lc7Olkk4r>}5-*MG_Kv7)6)Yu>Cy zD$c6GRgaH7;QRhq_1+?OzF#c%uSEjyG*{TzvF~lTezksH$g+QPE|ps*zhiJ;@Arf$ Rus9DCKc23BF6*2UngCBB+ll}H literal 0 HcmV?d00001 diff --git a/static/favicon-32x32.png b/static/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..0407988618ff715a7a2a70f0bcadbbb9f32c160f GIT binary patch literal 939 zcmV;c162HpP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91AfN*P1ONa40RR91AOHXW0IY^$^8f$?6-h)vR9FesmRpETVHC$_hA5W| z5#?GGMH!Ji3>_x&K#6$pLb*I>3gwok@#Ok2FC#>flDmeNc`_#y5*kEAE(sx*LK&m+ z`=9eIt+svk+0Mi?tA4Yt-?!KK&ieM5va)1ZK)M~ICG{Y`QVwz(Zse?dOu6mBPo*kS zRsF-FPH&)lkq`Htd={i7k0A?fAh`)Yb5=f<#eN$6uA#~k+Ei`|bW5m7O8p?I6Dmpc z@CMLScZ8kAo~{{K?uy=EH$ev0zy&x9rO09yZ3+uFCvD(AVRI;)gI3(`f71FwxgI3W zgZ9}~s7UdQqe=lJu7MH6b)<)2A$Zw`vmpffqW8cAP!l>uHK9FIOSFNZtb7aFs5NLi zUfi)B$dv`*lKtGtH2#QEMliX-AgHzci`q;Q%Q zs{#LgJ+eeZ55^w?8Z3R<;V=L+6DB&%(V!o$j~0y4dWNoNqC~G@9o3rlVPTbSj-UQ< z_-aluHRxYFMX%v_7MN(lpPBO)`UtfnVH@apH^NoWphjgBf!-F>S8&f9bQWehKaJUo zqN#8I>YzV-faws|fKD$1IZ*@agDv&a*=fyh6utu84mDB(lIMB#$KM7bjTTh{_2zUy z>m6|nu7^D|*aw3hRi}MG4XkwmoxmCAo7sf%89s%;arB*FOPzwdpqI=$(9wT~I9Wu{ zhB=qlIe-=H2+e74hN!7wz;0egWDlz(9b8${hdz N002ovPDHLkV1kERm!1Fs literal 0 HcmV?d00001 diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..88f8e3f6e5453a362265d62a8dea117702d9fd25 GIT binary patch literal 15406 zcmeI1dyHLG6^9Q{tU`e)53Ql<<wW96f#7sajAHJhn@c2WG~kfJ!6KA2!J zR!_1s((FrcDy)X{;k=YTne@xhfI1yP!#Y?9m%%ykwv>Mz=?yRw>NJgp853Zivh2@{ zN2hx)={G09J_ms|+I|Oa17mmY`@<{XK!{jpk+-k1kI(5g&~^bF3t_*A{HI_U48iH} zL(s3|hP^i0-UwGio&5)C`#3l+`-i6lcO*SOWXNAow0t*lVNh`{CUX z_GCw6UPa2v8ufXMl}TZ*jkZ_9#Sr%M$lnFVb`g94Tmzx7*G5~P(;Fb{k0SqbxC53$ z*t?bvhp^X1+x2igggx2fmGF8q$mj90lpasI38q7+Nyh#Ia4&3Vfwsm_C)bW^rjGsU z3{$;xSO*KC>ibFEYLkh+-&(^?8+6!!Md1F_p?r_efT)v0_2 zspUnf+)46$_wTnd0`blG-CCXo>K3?pG&fdfoBM-05iBoN zfqg;c^B=4I@4uIj4ZI(ycKtts%~qHXmxD3H+;ac=2!Ey#v*`$^cKmyf(KhxW&v471 z29^8QhwXuPn4m#kwd3FZcf$@Cg71Q3zX??Czd>F2Gp$m){#|>&0{yxUu7gnSKk6gh zKqj~*Rp$O*Lj7FWJGFanvRu}l6lQ_XzpUK9KEj{r?@N3o8Rq^|bw^3=UmssC(!HPum!%6@@0RIrh1b9(?tINfkp8BWS#r> zTXJp9NbR?iJ`J%R+VQWC@MpTd#D~eN-2WhT`dkI(_@w)UnI^QEqcC6~U>gG43DQM_aq;x3JZ> z&#Ya!uKb-E&!y9}6WrHP z41)FkhTaR*Tv!9w!yHhy*~h+DL450ubw#RQNII$A?+MIiO77|Y{h^=e!{aM{gOTl8 z-gkcuo;%M558}uF`{~6Tj$@pNeFyo6`;32w@EOG%$hMU4E62SfbSW9f+YV>L;eEzE z?$4mlk3q=K&~UGSPOT;?XVc8Kv{Lq-*Bwk z&c4sjfoHI4z&5ac2tuB_OCi3^SO@;i=xXq9BB8qYqrKg<7x5p9)8B$|n|>8Gf`5B_ z8p`jg-S~Z%ITuqG>P7sH@f7?CJo^p+&!`b_PIp7xh3eurraVr|@h;2h&g?%syMA2X z-s2p9D;x~UdcR5Qx4;0Xy7=q%AOG&1vvPE#v46UK{+^-!P1NV_zJ5CRJsbujVEjLY z_y+3YH>NyJ%llUlze{PV-G6rW`8&pI;ZbnC{}GJ)L2ypSe*uK*;y0$MSi`O^?e_V{ zxbG$N82k&2S=^6q1>aGqF8*lG(LWwkmfp>itE7l zZod^U4a%yE-rizGLglYmnl&+-L0LnGts5jb!TL zH>RpscTk@*TpF-0{!*8oX6xcNraVr|@2cSVQbeudcOPkj-=DvUmxKQ&naex)hrn;Z zJ4P$j#cxbiv9=n^wpQ`KllI@i-@)(lFR&S21!bL2!Dsa_cow%(UHq+VTD8^1e-cKX z{qBkG>(1k^;J)%pDDMHr?;Ib2UdQiy&sj`es4D&`G~NludLNtyv*Ai`Py8F42ccfX zZ%lcdmVNIzH-ux-s`wA4ek&NicL3+3UJ4I^^{c_}L-itlW6I;SysZN7w4ti_-Lvlp z{3prBnM}6w`Mb~l7_{+S z#yMOUKV2$y2(>w$t)aU3Z9fp!!Eaz2+yg5i*W0P^d-)k0lNwz+SHKqV-6_A9vtT z2ltw7ec;J7{$|n>pqFxeFMybX^XLc0-h_T>4g;S9?j^luIb-^LPipsm0!x{md#m?8 z_jKj&z(KJ7Oo%(%T=Hwc`<-h~*=8U6UIlx@v#D!v=C`{E4o!}ohkKs&YawD - - - {% block title %}Getränkeliste{% endblock %} - - - -
- Logo -

Getränkeliste

- {% if user %} + + + {% block title %}Getränkeliste{% endblock %} + + + + +
+ Logo +

Getränkeliste

+ {% if user %}

Angemeldet als {{ user.preferred_username }}{% if 'Fachschaft Admins' in user.groups %} (Admin){% endif %} – Logout

- {% endif %} -
-
- {% block content %}{% endblock %} {% if user %} {% if 'Fachschaft' - in user.groups %} -

Du bist Teil der Fachschaft Informatik.

-

Füge Nutzer zur Prepaid Liste hinzu:

-
- - - - - -
-

Füge bestehendem Prepaid-User Geld hinzu:

- {% if db_users_prepaid %} -
- - - - - + {% endif %} +
+
+ {% block content %}{% endblock %} + {% if user %} + {% if 'Fachschaft' in user.groups %} +

Du bist Teil der Fachschaft Informatik.

+ {% if prepaid_users_from_curr_user %} +

Liste deiner Prepaid-User:

+ + + + + + + + + + + + + + {% for prepaid_user_i in prepaid_users_from_curr_user %} + + + + + + + + + + {% endfor %} + +
IDUsernameKeyPostpaid_User IDMoney (€)Activatedlast drink
{{ prepaid_user_i.id }}{{ prepaid_user_i.username }}{{ prepaid_user_i.user_key }}{{ prepaid_user_i.postpaid_user_id }}{{ prepaid_user_i.money / 100 }}{{ prepaid_user_i.activated }}{{ prepaid_user_i.last_drink }}
+ {% endif %} +

Füge Nutzer zur Prepaid Liste hinzu:

+ + + + + + - {% else %} -

Es sind keine Prepaid-User vorhanden.

- {% endif %} +

Füge bestehendem Prepaid-User Geld hinzu:

+ {% if db_users_prepaid %} +
+ + + + + +
+ {% else %} +

Es sind keine Prepaid-User vorhanden.

+ {% endif %} {% endif %} {% if 'Fachschaft Admins' in user.groups %} -

Admin Interface

-

Ausgleichszahlung:

-

- Der eingegebene Betrag wird vom aktuell eingeloggten Nutzer - abgezogen und dem eingetragenem Nutzer gutgeschrieben. -

-
- - - - - -
-

Postpaid Liste

-

Users in postpaid database:

- - - - - - - - - - - - {% for db_user_i in users %} - - - - - - - - {% endfor %} - -
IDUsernameMoney (€)Activatedlast drink
- {{ db_user_i.id }} - - {{ db_user_i.username }} - - {{ db_user_i.money / 100 }} - - {{ db_user_i.activated }} - - {{ db_user_i.last_drink }} -
-

(De-)Activate User

-
- - - -
-

Set user money:

-
- - - - - -
-

Prepaid Liste

-

Users in prepaid database:

- {% if db_users_prepaid %} - - - - - - - - - - - - - - {% for prepaid_user_i in db_users_prepaid %} - - - - - - - - - +

Admin Interface

+

Ausgleichszahlung:

+

Der eingegebene Betrag wird vom aktuell eingeloggten Nutzer abgezogen und dem eingetragenem Nutzer gutgeschrieben.

+ + + -
IDUsernameKeyPostpaid_User IDMoney (€)Activatedlast drink
- {{ prepaid_user_i.id }} - - {{ prepaid_user_i.username }} - - {{ prepaid_user_i.user_key }} - - {{ prepaid_user_i.postpaid_user_id }} - - {{ prepaid_user_i.money / 100 }} - - {{ prepaid_user_i.activated }} - - {{ prepaid_user_i.last_drink }} -
-

(De-)Activate User

- - - - - - {% else %} + + + + + +

Postpaid Liste

+

Users in postpaid database:

+ + + + + + + + + + + + {% for db_user_i in users %} + + + + + + + + {% endfor %} + +
IDUsernameMoney (€)Activatedlast drink
{{ db_user_i.id }}{{ db_user_i.username }}{{ db_user_i.money / 100 }}{{ db_user_i.activated }}{{ db_user_i.last_drink }}
+

(De-)Activate User

+
+ + + +
+

Set user money:

+
+ + + + + +
+

Prepaid Liste

+

Users in prepaid database:

+ {% if db_users_prepaid %} + + + + + + + + + + + + + + {% for prepaid_user_i in db_users_prepaid %} + + + + + + + + + + {% endfor %} + +
IDUsernameKeyPostpaid_User IDMoney (€)Activatedlast drink
{{ prepaid_user_i.id }}{{ prepaid_user_i.username }}{{ prepaid_user_i.user_key }}{{ prepaid_user_i.postpaid_user_id }}{{ prepaid_user_i.money / 100 }}{{ prepaid_user_i.activated }}{{ prepaid_user_i.last_drink }}
+

(De-)Activate User

+
+ + + +
+

Delete User

+
+ + + + {% else %} - - No users in prepaid database - + No users in prepaid database - {% endif %} - {% endif %} {% endif %} -
- + {% endif %} + {% endif %} + {% endif %} + +