Skip to content

Commit

Permalink
groupadmin: manage group owners
Browse files Browse the repository at this point in the history
  • Loading branch information
timhawes committed Nov 26, 2023
1 parent 77d12e3 commit 93926ef
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 25 deletions.
17 changes: 17 additions & 0 deletions groupadmin/migrations/0002_groupproperties_owners_manage_owners.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.7 on 2023-11-25 20:13

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("groupadmin", "0001_initial"),
]

operations = [
migrations.AddField(
model_name="groupproperties",
name="owners_manage_owners",
field=models.BooleanField(default=False),
),
]
3 changes: 2 additions & 1 deletion groupadmin/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022 Tim Hawes <[email protected]>
# SPDX-FileCopyrightText: 2023 Tim Hawes <[email protected]>
#
# SPDX-License-Identifier: MIT

Expand Down Expand Up @@ -26,6 +26,7 @@ class GroupProperties(models.Model):
)
description = models.CharField(max_length=255, blank=True, null=True)
self_service = models.BooleanField(default=False)
owners_manage_owners = models.BooleanField(default=False)

def __str__(self):
return self.group.name
24 changes: 19 additions & 5 deletions groupadmin/urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022 Tim Hawes <[email protected]>
# SPDX-FileCopyrightText: 2023 Tim Hawes <[email protected]>
#
# SPDX-License-Identifier: MIT

Expand All @@ -9,11 +9,25 @@
urlpatterns = [
path("", views.groupadmin_list, name="groupadmin_list"),
path("<str:group_name>", views.groupadmin_view, name="groupadmin_view"),
path("<str:group_name>/add", views.groupadmin_add_user, name="groupadmin_add_user"),
path(
"<str:group_name>/remove/<int:user_id>",
views.groupadmin_remove_user,
name="groupadmin_remove_user",
"<str:group_name>/members/add",
views.groupadmin_add_member,
name="groupadmin_add_member",
),
path(
"<str:group_name>/members/remove/<int:user_id>",
views.groupadmin_remove_member,
name="groupadmin_remove_member",
),
path(
"<str:group_name>/owners/add",
views.groupadmin_add_owner,
name="groupadmin_add_owner",
),
path(
"<str:group_name>/owners/remove/<int:user_id>",
views.groupadmin_remove_owner,
name="groupadmin_remove_owner",
),
path("<str:group_name>/join", views.groupadmin_join, name="groupadmin_join"),
path("<str:group_name>/leave", views.groupadmin_leave, name="groupadmin_leave"),
Expand Down
76 changes: 62 additions & 14 deletions groupadmin/views.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
# SPDX-FileCopyrightText: 2022 Tim Hawes <[email protected]>
# SPDX-FileCopyrightText: 2023 Tim Hawes <[email protected]>
#
# SPDX-License-Identifier: MIT

from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import Group
from django.http import HttpResponseRedirect
from django.http import HttpResponseRedirect, HttpResponseForbidden
from django.shortcuts import render
from django.urls import reverse
from django.views.decorators.http import require_POST

from .models import GroupOwnership


@login_required
def groupadmin_list(request):
Expand Down Expand Up @@ -40,26 +42,43 @@ def groupadmin_list(request):
def groupadmin_view(request, group_name):
group = request.user.groupownerships.get(group__name=group_name).group

new_users = {}
new_members = {}
for user in get_user_model().objects.filter(is_active=True):
new_users[user.username] = user.id
new_members[user.username] = user.id
new_owners = new_members.copy()

users = {}
members = {}
for user in group.user_set.all():
try:
del new_users[user.username]
del new_members[user.username]
except KeyError:
pass
members[user.username] = {
"id": user.id,
"username": user.username,
}

owners = {}
for groupownership in group.owners.all():
user = groupownership.user
try:
del new_owners[user.username]
except KeyError:
pass
users[user.username] = {
owners[user.username] = {
"id": user.id,
"username": user.username,
}

context = {
"group": group,
"users": [users[username] for username in sorted(users.keys())],
"new_users": [
(new_users[username], username) for username in sorted(new_users.keys())
"members": [members[username] for username in sorted(members.keys())],
"owners": [owners[username] for username in sorted(owners.keys())],
"new_members": [
(new_members[username], username) for username in sorted(new_members.keys())
],
"new_owners": [
(new_owners[username], username) for username in sorted(new_owners.keys())
],
}

Expand All @@ -68,21 +87,50 @@ def groupadmin_view(request, group_name):

@login_required
@require_POST
def groupadmin_add_user(request, group_name):
def groupadmin_add_member(request, group_name):
group = request.user.groupownerships.get(group__name=group_name).group
user = get_user_model().objects.get(id=int(request.POST["user_id"]))
group.user_set.add(user)
messages.add_message(request, messages.SUCCESS, f"User {user.username} added.")
messages.add_message(request, messages.SUCCESS, f"Member {user.username} added.")
return HttpResponseRedirect(reverse("groupadmin_view", args=[group_name]))


@login_required
@require_POST
def groupadmin_remove_user(request, group_name, user_id):
def groupadmin_remove_member(request, group_name, user_id):
group = request.user.groupownerships.get(group__name=group_name).group
user = get_user_model().objects.get(id=user_id)
group.user_set.remove(user)
messages.add_message(request, messages.SUCCESS, f"User {user.username} removed.")
messages.add_message(request, messages.SUCCESS, f"Member {user.username} removed.")
return HttpResponseRedirect(reverse("groupadmin_view", args=[group_name]))


@login_required
@require_POST
def groupadmin_add_owner(request, group_name):
group = request.user.groupownerships.get(group__name=group_name).group
user = get_user_model().objects.get(id=int(request.POST["user_id"]))
if request.user == user:
# this condition should never match, added just-in-case
return HttpResponseForbidden("Cannot add self")
if not group.properties.owners_manage_owners:
return HttpResponseForbidden("Cannot manage owners")
GroupOwnership.objects.create(group=group, user=user)
messages.add_message(request, messages.SUCCESS, f"Owner {user.username} added.")
return HttpResponseRedirect(reverse("groupadmin_view", args=[group_name]))


@login_required
@require_POST
def groupadmin_remove_owner(request, group_name, user_id):
group = request.user.groupownerships.get(group__name=group_name).group
user = get_user_model().objects.get(id=user_id)
if request.user == user:
return HttpResponseForbidden("Cannot remove self")
if not group.properties.owners_manage_owners:
return HttpResponseForbidden("Cannot manage owners")
GroupOwnership.objects.get(group=group, user=user).delete()
messages.add_message(request, messages.SUCCESS, f"Owner {user.username} removed.")
return HttpResponseRedirect(reverse("groupadmin_view", args=[group_name]))


Expand Down
59 changes: 54 additions & 5 deletions hackdb/templates/groupadmin/group_view.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ <h1>Group {{ group.name }}</h1>
</tr>
</thead>
<tbody>
{% for user in users %}
{% for user in members %}
<tr>
<td>{{ user.username }}</td>
<td>
<form method="POST" action="{% url 'groupadmin_remove_user' group.name user.id %}">
<form method="POST" action="{% url 'groupadmin_remove_member' group.name user.id %}">
{% csrf_token %}
<button type="submit" class="btn btn-xs btn-link">
<i class="bi-trash" style="color:black"></i>
Expand All @@ -32,18 +32,67 @@ <h1>Group {{ group.name }}</h1>
</div>
<div class="container">
<p>
<form method="POST" action="{% url 'groupadmin_add_user' group.name %}">
<form method="POST" action="{% url 'groupadmin_add_member' group.name %}">
{% csrf_token %}
<select name="user_id">
<option value=""></option>
{% for user_id, user_name in new_users %}
{% for user_id, user_name in new_members %}
<option value="{{ user_id }}">{{ user_name }}</option>
{% endfor %}
</select>
<button type="submit" class="btn btn-default">Add</button>
<button type="submit" class="btn btn-default">
{% if group.properties.owners_manage_owners %}
Add Member
{% else %}
Add
{% endif %}
</button>
</form>
</p>
</div>
{% if group.properties.owners_manage_owners %}
<div class="container">
<table class="table table-striped align-middle">
<thead>
<tr>
<th>Owner</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{% for user in owners %}
<tr>
<td>{{ user.username }}</td>
<td>
{% if user.username != request.user.username %}
<form method="POST" action="{% url 'groupadmin_remove_owner' group.name user.id %}">
{% csrf_token %}
<button type="submit" class="btn btn-xs btn-link">
<i class="bi-trash" style="color:black"></i>
</button>
</form>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="container">
<p>
<form method="POST" action="{% url 'groupadmin_add_owner' group.name %}">
{% csrf_token %}
<select name="user_id">
<option value=""></option>
{% for user_id, user_name in new_owners %}
<option value="{{ user_id }}">{{ user_name }}</option>
{% endfor %}
</select>
<button type="submit" class="btn btn-default">Add Owner</button>
</form>
</p>
</div>
{% endif %}
<div class="container">
<a href="{% url 'home' %}" class="btn btn-outline-secondary">Home</a>
<a href="{% url 'groupadmin_list' %}" class="btn btn-outline-secondary">Groups</a>
Expand Down

0 comments on commit 93926ef

Please sign in to comment.