From c5c856e6e9ef01674bb35f4746757b80914e9673 Mon Sep 17 00:00:00 2001 From: decentral1se Date: Sat, 12 Jun 2021 02:15:50 +0200 Subject: [PATCH] Further into invite link display --- keycloak_collective_portal.py | 46 ++++++++++++++++++++++++++++++----- poetry.lock | 17 ++++++++++++- pyproject.toml | 1 + templates/admin.html | 16 +++++++++++- 4 files changed, 72 insertions(+), 8 deletions(-) diff --git a/keycloak_collective_portal.py b/keycloak_collective_portal.py index 97144a5..9aff685 100644 --- a/keycloak_collective_portal.py +++ b/keycloak_collective_portal.py @@ -1,6 +1,8 @@ """Community Keycloak SSO user management.""" import json +from datetime import datetime as dt +from datetime import timedelta from os import environ from uuid import uuid4 @@ -10,6 +12,7 @@ from authlib.integrations.starlette_client import OAuth, OAuthError from fastapi import Depends, FastAPI, HTTPException, Request from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.templating import Jinja2Templates +from humanize import naturaldelta from starlette.exceptions import HTTPException from starlette.middleware.sessions import SessionMiddleware @@ -26,6 +29,8 @@ REDIS_DB = environ.get("REDIS_DB") REDIS_HOST = environ.get("REDIS_HOST") REDIS_PORT = environ.get("REDIS_PORT") +INVITE_TIME_LIMIT = environ.get("INVITE_TIME_LIMIT") + app = FastAPI(docs_url=None, redoc_url=None) app.add_middleware(SessionMiddleware, secret_key=APP_SECRET_KEY) templates = Jinja2Templates(directory="templates") @@ -68,9 +73,24 @@ async def get_user(request: Request): return request.session.get("user") +async def get_invites(request: Request, user=Depends(get_user)): + username = user["preferred_username"] + invites = await app.state.redis.get(username) + if invites: + humanised = [] + for invite in json.loads(invites): + invite["human_time"] = naturaldelta( + dt.fromisoformat(invite["time"]) + + timedelta(days=int(INVITE_TIME_LIMIT)) + ) + humanised.append(invite) + return humanised + return [] + + @app.on_event("startup") async def starup_event(): - app.state.redis = create_redis_pool( + app.state.redis = await create_redis_pool( f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}?encoding=utf-8" ) @@ -82,8 +102,10 @@ async def shutdown_event(): @app.get("/", dependencies=[Depends(logged_in)]) -async def home(request: Request, user=Depends(get_user)): - context = {"request": request, "user": user} +async def home( + request: Request, user=Depends(get_user), invites=Depends(get_invites) +): + context = {"request": request, "user": user, "invites": invites} return templates.TemplateResponse("admin.html", context=context) @@ -125,6 +147,18 @@ async def logout(request: Request): return RedirectResponse(request.url_for("login")) -@app.get("/invite/keycloak", dependencies=[Depends(logged_in)]) -async def invite_keycloak(request: Request): - pass +@app.get("/invite/keycloak/create", dependencies=[Depends(logged_in)]) +async def invite_keycloak_create( + request: Request, user=Depends(get_user), invites=Depends(get_invites) +): + invites.append({"link": str(uuid4()), "time": str(dt.now())}) + app.state.redis.set(user["preferred_username"], json.dumps(invites)) + return RedirectResponse(request.url_for("home")) + + +@app.get("/invite/keycloak/delete", dependencies=[Depends(logged_in)]) +async def invite_keycloak_delete( + request: Request, user=Depends(get_user), invites=Depends(get_invites) +): + invite =request.query_params.get("invite") + # TODO diff --git a/poetry.lock b/poetry.lock index 8a0b21d..85b655c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -239,6 +239,17 @@ sniffio = "*" brotli = ["brotlicffi (>=1.0.0,<2.0.0)"] http2 = ["h2 (>=3.0.0,<4.0.0)"] +[[package]] +name = "humanize" +version = "3.7.1" +description = "Python humanize utilities" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +tests = ["freezegun", "pytest", "pytest-cov"] + [[package]] name = "idna" version = "3.2" @@ -501,7 +512,7 @@ python-versions = ">=3.6.1" [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "3b87d7d886ec83f9a136e2535f8e9b2802f1c680464022c2938abce0033e55bd" +content-hash = "0ba44935dd5a68706610677a7e54fa3ebcd6f5a68edd05a1e1ecb8dbd9ca5947" [metadata.files] aioredis = [ @@ -689,6 +700,10 @@ httpx = [ {file = "httpx-0.18.1-py3-none-any.whl", hash = "sha256:ad2e3db847be736edc4b272c4d5788790a7e5789ef132fc6b5fef8aeb9e9f6e0"}, {file = "httpx-0.18.1.tar.gz", hash = "sha256:0a2651dd2b9d7662c70d12ada5c290abcf57373b9633515fe4baa9f62566086f"}, ] +humanize = [ + {file = "humanize-3.7.1-py3-none-any.whl", hash = "sha256:a0dca9eb010dd1fab61819acaea54be344a4c22c77261f72ac4dbee183dd9a59"}, + {file = "humanize-3.7.1.tar.gz", hash = "sha256:b8e7878f3063174b212bb82b9e5bee3b24bc47931e44df0bd34bcb1d8e0acf2f"}, +] idna = [ {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, diff --git a/pyproject.toml b/pyproject.toml index 022ceba..c8156bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ itsdangerous = "^2.0.1" Authlib = "^0.15.4" httpx = "^0.18.1" aioredis = "^1.3.1" +humanize = "^3.7.1" [tool.poetry.dev-dependencies] black = "^21.6b0" diff --git a/templates/admin.html b/templates/admin.html index 75c2d0e..12f3739 100644 --- a/templates/admin.html +++ b/templates/admin.html @@ -7,8 +7,22 @@ Hello, {{ user.preferred_username }} (logout)

+ + + + + + + {% for invite in invites %} + + + + + + {% endfor %} +
LinkValidity Operations
{{ url_for('home') }}{{ invite.link }} {{ invite.human_time }} copy delete

- Generate an invite link + Generate an invite link