diff --git a/docker-compose.yml b/docker-compose.yml index db8ea0d..c0e5858 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,6 +19,7 @@ services: - ./lumi2/static/images/base:/app/lumi2/static/images/base:ro - ./lumi2/static/images/default:/app/lumi2/static/images/default:ro - ./lumi2/templates/:/app/lumi2/templates/:ro + - ./tests/fakedata.py/:/app/tests/fakedata.py:ro ports: - "8000:80" depends_on: diff --git a/lumi2/static/js/user_tables.js b/lumi2/static/js/user_tables.js new file mode 100644 index 0000000..909aa32 --- /dev/null +++ b/lumi2/static/js/user_tables.js @@ -0,0 +1,10 @@ +$(function() { + $("table").tablesorter({ + theme: 'bootstrap', + headerTemplate: '{content} {icon}', + cssIcon: 'bi-arrow-down-up', + cssIconNone: '', + cssIconAsc: 'bi-arrow-up', + cssIconDesc: 'bi-arrow-down', + }); +}); diff --git a/lumi2/templates/usermanager/user_list.html b/lumi2/templates/usermanager/user_list.html index f4e2038..2927bc3 100644 --- a/lumi2/templates/usermanager/user_list.html +++ b/lumi2/templates/usermanager/user_list.html @@ -50,5 +50,5 @@

There are currently no users.

{% endif %} - + {% endblock content %} diff --git a/lumi2/usermanager.py b/lumi2/usermanager.py index 7e22538..27ada87 100644 --- a/lumi2/usermanager.py +++ b/lumi2/usermanager.py @@ -294,6 +294,7 @@ def user_delete(username: str): if request.method == 'POST': ldap.delete_user(conn, user.username) + # FIXME delete user's static image folder!!! conn.unbind() flash(f"The user '{user.username}' was deleted.") for groupname in deleted_groups: diff --git a/lumi2/webapi.py b/lumi2/webapi.py index 090351e..8668f75 100644 --- a/lumi2/webapi.py +++ b/lumi2/webapi.py @@ -147,7 +147,7 @@ class GroupResource(Resource): def get(self, groupname: str): """Retrieves the group specified by the groupname as a JSON object. - Attributes + Parameters ---------- groupname : str The name of the group to be retrieved. @@ -266,3 +266,39 @@ class GroupResource(Resource): ldap.update_group(conn, group) conn.unbind() return {"username": username}, 200 + + +class GroupMemberResource(Resource): + """This resource represents the member of a group. + + In JSON, a GroupMember is represented as follows: + { + "username": "myuser" + } + """ + + def post(self, groupname): + """Adds the user specified in the POST data to the specified Group.""" + + pass + + + def delete(self, groupname): + """Removes the user specified in the POST data from the specified Group. + + Parameters + ---------- + groupname : str + The name of the Group from which a member will be deleted. + + Returns + ------- + json : str , status : int + A JSON string and HTTP status code. + If the request was handled successfully, the POST-data is + replied to the client and HTTP code 200 is returned. + If a failure occurred while processing the request, an appropriate + error message and HTTP error code are returned. + """ + + pass diff --git a/requirements.txt b/requirements.txt index 57faf1f..9b13df4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,5 @@ WTForms==3.0.1 wtforms[email]==3.0.1 Flask-WTF==1.0.1 Flask-RESTful==0.3.9 +Faker==15.3.3 +requests==2.28.1 diff --git a/tests/fakedata.py b/tests/fakedata.py new file mode 100644 index 0000000..1f35547 --- /dev/null +++ b/tests/fakedata.py @@ -0,0 +1,37 @@ +"""Generates fake user accounts.""" + +from io import BytesIO + +import requests +from PIL import Image +from faker import Faker + +from lumi2.usermodel import User + + +def get_random_avatar() -> Image.Image: + """Returns a PIL JPEG Image of an AI-generated person.""" + + url = "https://thispersondoesnotexist.com/image" + response = requests.get(url) + if response.status_code != 200: + raise RuntimeError( + f"Request to '{url}' failed with code {response.status_code}." + ) + + return Image.open(BytesIO(response.content)) + + +def generate_random_user() -> User: + """Generates a randomized user object and returns it.""" + + faker = Faker() + + return User( + faker.user_name(), + User.generate_password_hash(faker.password()), + faker.email(), + faker.first_name(), + faker.last_name(), + picture=get_random_avatar(), + )