Read user display names from kubernetes
All checks were successful
ci/woodpecker/manual/woodpecker Pipeline was successful

This commit is contained in:
Madis Mägi 2023-08-05 19:28:10 +03:00
parent 2e65de8c2a
commit 8b9ac4b92b
8 changed files with 43 additions and 57 deletions

View File

@ -4,13 +4,11 @@ import const
from functools import wraps from functools import wraps
from pymongo import MongoClient from pymongo import MongoClient
from flask import Blueprint, abort, g, make_response, redirect, render_template, request, jsonify from flask import Blueprint, abort, g, make_response, redirect, render_template, request, jsonify
from common import CustomForm, build_query, flatten, format_name, spam from common import CustomForm, build_query, flatten, format_name, spam, users
from kubernetes import client, config
page_api = Blueprint("api", __name__) page_api = Blueprint("api", __name__)
db = MongoClient(const.MONGO_URI).get_default_database() db = MongoClient(const.MONGO_URI).get_default_database()
api_key = os.getenv("INVENTORY_API_KEY") api_key = os.getenv("INVENTORY_API_KEY")
OIDC_USERS_NAMESPACE = os.getenv("OIDC_USERS_NAMESPACE")
def check_api_key(f): def check_api_key(f):
@wraps(f) @wraps(f)
@ -24,19 +22,10 @@ def check_api_key(f):
return f(*args, **kwargs) return f(*args, **kwargs)
return decorated_function return decorated_function
def get_users():
config.load_incluster_config()
api_instance = client.CustomObjectsApi()
ret = api_instance.list_namespaced_custom_object("codemowers.io", "v1alpha1", OIDC_USERS_NAMESPACE, "oidcgatewayusers")
resp = []
for item in ret["items"]:
resp.append(item)
return resp
@page_api.route("/users") @page_api.route("/users")
@check_api_key @check_api_key
def view_users(): def view_users():
resp = get_users() resp = users
print(resp) print(resp)
return jsonify(resp) return jsonify(resp)
@ -47,7 +36,6 @@ def get_group_cards():
if not groups: if not groups:
return "must specify groups in parameter", 400 return "must specify groups in parameter", 400
print(f"groups requested are: {groups}") print(f"groups requested are: {groups}")
users = get_users()
print(f"found users: {users}") print(f"found users: {users}")
gu = [] gu = []
for u in users: for u in users:
@ -73,10 +61,7 @@ def get_group_cards():
} }
found = [] found = []
for obj in db.inventory.find(flt, prj): for obj in db.inventory.find(flt, prj):
del obj["_id"] found.append({"token": obj["token"]})
if obj["inventory"] and obj["inventory"]["owner"] and type(obj["inventory"]["owner"]["foreign_id"]) != str:
del obj["inventory"]
found.append(obj)
fl = list(found) fl = list(found)
print(f"found tokens are: {fl}") print(f"found tokens are: {fl}")
return jsonify(fl) return jsonify(fl)

View File

@ -1,3 +1,4 @@
import os
import collections.abc import collections.abc
from functools import wraps from functools import wraps
@ -6,13 +7,23 @@ from bson.objectid import ObjectId
from flask import g, request from flask import g, request
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from pymongo import MongoClient from pymongo import MongoClient
from kubernetes import client, config
import const import const
devenv = const.ENVIRONMENT_TYPE == "DEV" devenv = const.ENVIRONMENT_TYPE == "DEV"
OIDC_USERS_NAMESPACE = os.getenv("OIDC_USERS_NAMESPACE")
db = MongoClient(const.MONGO_URI).get_default_database() db = MongoClient(const.MONGO_URI).get_default_database()
def get_users():
config.load_incluster_config()
api_instance = client.CustomObjectsApi()
ret = api_instance.list_namespaced_custom_object("codemowers.io", "v1alpha1", OIDC_USERS_NAMESPACE, "oidcgatewayusers")
return ret["items"]
users = get_users()
users_lookup = {u['metadata']['name'] : u for u in users}
class CustomForm(FlaskForm): class CustomForm(FlaskForm):
# quite hacky # quite hacky
@ -33,7 +44,7 @@ def inventory_fetch(owner=True, item_type=None):
if item_type: if item_type:
d["type"] = item_type d["type"] = item_type
if owner: if owner:
d["inventory.owner.foreign_id"] = user["username"] d["inventory.owner.username"] = user["username"]
kwargs["item"] = db.inventory.find_one(d) kwargs["item"] = db.inventory.find_one(d)
return f(*args, **kwargs) return f(*args, **kwargs)
return decorated_function return decorated_function
@ -70,23 +81,23 @@ def build_query(base_query, fields=[], sort_fields={}):
q = base_query.copy() q = base_query.copy()
for attr, title, tp in fields: for attr, title, tp in fields:
key = attr.replace(".", "_") key = attr.replace(".", "_")
if tp == list: if key in ("inventory_owner_username", "inventory_user_username"):
val = request.args.get(key, type=dict)
elif tp == list:
val = request.args.getlist(key) val = request.args.getlist(key)
val = list(map(str, val)) val = list(map(str, val))
else: else:
val = request.args.get(key, type=tp) val = request.args.get(key, type=tp)
results = db.inventory.find(base_query).distinct(attr) results = db.inventory.find(base_query).distinct(attr)
if tp == ObjectId: if key in ("inventory_owner_username", "inventory_user_username"):
results = [{"username": u, "display_name": users_lookup[u]["spec"]["customProfile"]["name"]} for u in results]
results = sorted(results, key = lambda k: k["display_name"]) results = sorted(results, key = lambda k: k["display_name"])
elif tp != list: elif tp != list:
results = sorted(results) results = sorted(results)
results = list(map(tp, results)) results = list(map(tp, results))
selectors.append((key, title, results, val)) selectors.append((key, title, results, val))
if val: if val:
if tp == ObjectId: if tp == list and attr == "type":
attr = attr + ".foreign_id"
q[attr] = val
elif tp == list and attr == "type":
q[attr] = { "$nin" : val } q[attr] = { "$nin" : val }
elif tp == list: elif tp == list:
q[attr] = { "$in" : val } q[attr] = { "$in" : val }

View File

@ -360,8 +360,8 @@ def view_inventory(slug=None):
template = "inventory_public.html" template = "inventory_public.html"
public_view = True public_view = True
else: else:
fields.append(("inventory.owner", "Owner", ObjectId)) fields.append(("inventory.owner.username", "Owner", list))
fields.append(("inventory.user", "User", ObjectId)) fields.append(("inventory.user.username", "User", list))
if slug and not public_view: if slug and not public_view:
template = "inventory_pick.html" template = "inventory_pick.html"
if request.path.startswith("/m/inventory/clone-with-slug"): if request.path.startswith("/m/inventory/clone-with-slug"):
@ -378,9 +378,9 @@ def view_inventory(slug=None):
if grid: if grid:
template = "inventory_grid.html" template = "inventory_grid.html"
if user: if user:
q["inventory.user.foreign_id"] = user q["inventory.user.username"] = user
if owner: if owner:
q["inventory.owner.foreign_id"] = owner q["inventory.owner.username"] = owner
q2 = {"type": {"$ne": "token"}} q2 = {"type": {"$ne": "token"}}
if not public_view and owner_disabled: if not public_view and owner_disabled:
@ -390,22 +390,6 @@ def view_inventory(slug=None):
q, selectors, sort_field, sort_field_final, sort_direction = build_query(dict(q), fields, sort_fields) q, selectors, sort_field, sort_field_final, sort_direction = build_query(dict(q), fields, sort_fields)
items = db.inventory.aggregate([ items = db.inventory.aggregate([
{ "$match": q }, { "$match": q },
{
"$lookup": {
"from": 'member',
"localField": 'inventory.owner.foreign_id',
"foreignField": '_id',
"as": 'Owner'
}
},
{
"$lookup": {
"from": 'member',
"localField": 'inventory.user.foreign_id',
"foreignField": '_id',
"as": 'User'
}
},
{ "$match": q2 }, { "$match": q2 },
{ "$sort": { sort_field_final : 1 if sort_direction == "asc" else -1 } } { "$sort": { sort_field_final : 1 if sort_direction == "asc" else -1 } }
]) ])
@ -421,7 +405,7 @@ def view_inventory_claim(item_id):
"inventory.owner.foreign_id": None "inventory.owner.foreign_id": None
}, { }, {
"$set": { "$set": {
"inventory.owner.foreign_id": user["username"], "inventory.owner.username": user["username"],
"inventory.owner.display_name": user["name"], "inventory.owner.display_name": user["name"],
}, },
}) })
@ -444,7 +428,7 @@ def view_inventory_use(item_id):
"_id": ObjectId(item["_id"]) "_id": ObjectId(item["_id"])
}, { }, {
"$set": { "$set": {
"inventory.user.foreign_id": ObjectId(user["username"]), "inventory.user.username": user["username"],
"inventory.user.display_name": user["name"], "inventory.user.display_name": user["name"],
}, },
}) })
@ -463,7 +447,7 @@ def view_inventory_vacate(item_id):
item = db.inventory.find_one({ item = db.inventory.find_one({
"_id": ObjectId(item_id), "_id": ObjectId(item_id),
"inventory.usable": True, "inventory.usable": True,
"inventory.user.foreign_id": ObjectId(user["username"]) "inventory.user.username": user["username"]
}) })
if not item: if not item:
return abort(404) return abort(404)

View File

@ -20,7 +20,6 @@ import markdown
import pymongo import pymongo
import requests import requests
import safe import safe
from bson.objectid import ObjectId
from flask import Flask, abort, g, make_response, redirect, render_template, request, session from flask import Flask, abort, g, make_response, redirect, render_template, request, session
from flask_wtf import FlaskForm, RecaptchaField from flask_wtf import FlaskForm, RecaptchaField
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
@ -45,7 +44,7 @@ from wtforms.form import Form
from wtforms.validators import DataRequired from wtforms.validators import DataRequired
import const import const
from common import CustomForm, devenv, flatten, format_name, spam from common import CustomForm, devenv, flatten, format_name, spam, users_lookup
from inventory import page_inventory from inventory import page_inventory
from oidc import page_oidc, login_required, read_user from oidc import page_oidc, login_required, read_user
from api import page_api from api import page_api
@ -58,6 +57,12 @@ def check_foreign_key_format(item):
if user.get("foreign_id", False): if user.get("foreign_id", False):
return not bool(user.get("username")) return not bool(user.get("username"))
def render_user_display_name(username):
if not username:
return ""
display_name = users_lookup.get(username, {}).get("spec", {}).get("customProfile", {}).get("name", False)
return display_name or username
def render_markdown(text): def render_markdown(text):
if not text: if not text:
return "" return ""
@ -104,6 +109,7 @@ jinja2.filters.FILTERS['user_link'] = render_user_link
jinja2.filters.FILTERS['is_list'] = is_list jinja2.filters.FILTERS['is_list'] = is_list
jinja2.filters.FILTERS['quote_plus'] = lambda u: urllib.parse.quote_plus(u) jinja2.filters.FILTERS['quote_plus'] = lambda u: urllib.parse.quote_plus(u)
jinja2.filters.FILTERS['check_foreign_key_format'] = check_foreign_key_format jinja2.filters.FILTERS['check_foreign_key_format'] = check_foreign_key_format
jinja2.filters.FILTERS['display_name'] = render_user_display_name
env = Environment(loader=FileSystemLoader('templates/')) env = Environment(loader=FileSystemLoader('templates/'))

View File

@ -18,7 +18,7 @@
<option value="" disabled {% if not selected %}selected{% endif %}>All</option> <option value="" disabled {% if not selected %}selected{% endif %}>All</option>
{% for value in values %} {% for value in values %}
{% if value is mapping %} {% if value is mapping %}
<option value="{{ value.foreign_id }}" {% if value.foreign_id == selected %}selected{% endif %}> <option value="{{ value.username }}" {% if value.username == selected %}selected{% endif %}>
{{ value.display_name }} {{ value.display_name }}
</option> </option>
{% else %} {% else %}

View File

@ -15,8 +15,8 @@
{% if public_view %} {% if public_view %}
{% if item.inventory.user %}<p>In use</p>{% endif %} {% if item.inventory.user %}<p>In use</p>{% endif %}
{% else %} {% else %}
<p>Owner: {% if item.inventory.owner %}{{item.inventory.owner.display_name}}{% endif %}</p> <p>Owner: {% if item.inventory.owner %}{{item.inventory.owner.username | display_name}}{% endif %}</p>
<p>Current user: {% if item.inventory.user %}{{item.inventory.user.display_name}}{% endif %}</p> <p>Current user: {% if item.inventory.user %}{{item.inventory.user.username | display_name}}{% endif %}</p>
{% endif %} {% endif %}
<p><a href="/m/inventory/{{ item._id }}/view">more</a></p> <p><a href="/m/inventory/{{ item._id }}/view">more</a></p>
</div> </div>

View File

@ -16,8 +16,8 @@
{% for item in items %} {% for item in items %}
<tr> <tr>
<td>{{ item | format_name }} {{ item.comment }}</td> <td>{{ item | format_name }} {{ item.comment }}</td>
<td>{% if item.inventory.owner %}<a href="/m/user/{{ item.inventory.owner.foreign_id }}">{{ item.inventory.owner.display_name }}</a>{% endif %}</td> <td>{% if item.inventory.owner %}<a href="/m/user/{{ item.inventory.owner.foreign_id }}">{{ item.inventory.owner.username | display_name }}</a>{% endif %}</td>
<td>{% if item.inventory.user %}<a href="/m/user/{{ item.inventory.user.foreign_id }}">{{ item.inventory.user.display_name }}</a>{% endif %}</td> <td>{% if item.inventory.user %}<a href="/m/user/{{ item.inventory.user.foreign_id }}">{{ item.inventory.user.username | display_name }}</a>{% endif %}</td>
<td> <td>
<form action="/m/inventory/{{item._id}}/{{action_path}}/{{slug}}" method="get"> <form action="/m/inventory/{{item._id}}/{{action_path}}/{{slug}}" method="get">
<button class="waves-effect waves-light btn" type="submit">{{action_label}}</button> <button class="waves-effect waves-light btn" type="submit">{{action_label}}</button>

View File

@ -57,12 +57,12 @@
<tr> <tr>
<td>Owner</td> <td>Owner</td>
<td>{{ item.inventory.get("owner").display_name }}</td> <td>{{ item.inventory.get("owner").username | display_name }}</td>
</tr> </tr>
<tr> <tr>
<td>Current user</td> <td>Current user</td>
<td>{{ item.inventory.get("user").display_name }}</td> <td>{{ item.inventory.get("user").username | display_name }}</td>
</tr> </tr>
<tr> <tr>