forked from enviPath/enviPy
Implement basic Group handling (#3)
Co-authored-by: Tim Lorsbach <tim@lorsba.ch> Reviewed-on: enviPath/enviPy#3
This commit is contained in:
@ -44,15 +44,22 @@ class UserManager(object):
|
|||||||
def get_users():
|
def get_users():
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_user_lp(user_url: str):
|
||||||
|
uuid = user_url.strip().split('/')[-1]
|
||||||
|
return get_user_model().objects.get(uuid=uuid)
|
||||||
|
|
||||||
class GroupManager(object):
|
class GroupManager(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_group(owner):
|
def create_group(current_user, name, description):
|
||||||
g = Group()
|
g = Group()
|
||||||
g.name = 'enviPath Users'
|
g.name = name
|
||||||
g.description = 'All enviPath Users'
|
g.description = description
|
||||||
g.owner = owner
|
g.owner = current_user
|
||||||
|
g.save()
|
||||||
|
|
||||||
|
g.user_member.add(current_user)
|
||||||
g.save()
|
g.save()
|
||||||
|
|
||||||
return g
|
return g
|
||||||
@ -78,6 +85,26 @@ class GroupManager(object):
|
|||||||
def get_groups(user):
|
def get_groups(user):
|
||||||
return Group.objects.filter(user_member=user)
|
return Group.objects.filter(user_member=user)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
@transaction.atomic
|
||||||
|
def update_members(caller: User, group: Group, member: Union[User, Group], add_or_remove: str):
|
||||||
|
|
||||||
|
if caller != group.owner:
|
||||||
|
raise ValueError('Only the group Owner is allowed to add members!')
|
||||||
|
|
||||||
|
if isinstance(member, Group):
|
||||||
|
if add_or_remove == 'add':
|
||||||
|
group.group_member.add(member)
|
||||||
|
else:
|
||||||
|
group.group_member.remove(member)
|
||||||
|
else:
|
||||||
|
if add_or_remove == 'add':
|
||||||
|
group.user_member.add(member)
|
||||||
|
else:
|
||||||
|
group.user_member.remove(member)
|
||||||
|
|
||||||
|
group.save()
|
||||||
|
|
||||||
|
|
||||||
class PackageManager(object):
|
class PackageManager(object):
|
||||||
package_pattern = re.compile(r".*/package/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$")
|
package_pattern = re.compile(r".*/package/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$")
|
||||||
|
|||||||
@ -25,7 +25,7 @@ class Command(BaseCommand):
|
|||||||
else:
|
else:
|
||||||
admin = User.objects.get(email='admin@lorsba.ch')
|
admin = User.objects.get(email='admin@lorsba.ch')
|
||||||
|
|
||||||
g = GroupManager.create_group(admin)
|
g = GroupManager.create_group(admin, 'enviPath Users', 'All enviPath Users')
|
||||||
g.user_member.add(anon)
|
g.user_member.add(anon)
|
||||||
g.save()
|
g.save()
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,7 @@ class User(AbstractUser):
|
|||||||
on_delete=models.SET_NULL, related_name='default_group')
|
on_delete=models.SET_NULL, related_name='default_group')
|
||||||
default_setting = models.ForeignKey('epdb.Setting', on_delete=models.SET_NULL,
|
default_setting = models.ForeignKey('epdb.Setting', on_delete=models.SET_NULL,
|
||||||
verbose_name='The users default settings', null=True, blank=False)
|
verbose_name='The users default settings', null=True, blank=False)
|
||||||
|
# TODO remove
|
||||||
groups = models.ManyToManyField("Group", verbose_name='groups')
|
groups = models.ManyToManyField("Group", verbose_name='groups')
|
||||||
|
|
||||||
USERNAME_FIELD = "email"
|
USERNAME_FIELD = "email"
|
||||||
|
|||||||
@ -1248,6 +1248,8 @@ def user(request, user_uuid):
|
|||||||
|
|
||||||
|
|
||||||
def groups(request):
|
def groups(request):
|
||||||
|
current_user = _anonymous_or_real(request)
|
||||||
|
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context['title'] = f'enviPath - Groups'
|
context['title'] = f'enviPath - Groups'
|
||||||
@ -1266,13 +1268,7 @@ def groups(request):
|
|||||||
group_name = request.POST.get('group-name')
|
group_name = request.POST.get('group-name')
|
||||||
group_description = request.POST.get('group-description', s.DEFAULT_VALUES['description'])
|
group_description = request.POST.get('group-description', s.DEFAULT_VALUES['description'])
|
||||||
|
|
||||||
g = Group()
|
g = GroupManager.create_group(current_user, group_name, group_description)
|
||||||
g.name = group_name
|
|
||||||
g.description = group_description
|
|
||||||
g.save()
|
|
||||||
|
|
||||||
g.user_member.add(request.user)
|
|
||||||
g.save()
|
|
||||||
|
|
||||||
return redirect(g.url)
|
return redirect(g.url)
|
||||||
|
|
||||||
@ -1294,8 +1290,39 @@ def group(request, group_uuid):
|
|||||||
|
|
||||||
context['group'] = current_group
|
context['group'] = current_group
|
||||||
|
|
||||||
|
# TODO use managers
|
||||||
|
context['users'] = get_user_model().objects.exclude(id__in=current_group.user_member.all())
|
||||||
|
context['groups'] = Group.objects.exclude(id__in=current_group.group_member.all()).exclude(id=current_group.pk)
|
||||||
|
|
||||||
|
context['packages'] = Package.objects.filter(id__in=GroupPackagePermission.objects.filter(group=current_group).values('package').distinct())
|
||||||
|
|
||||||
return render(request, 'objects/group.html', context)
|
return render(request, 'objects/group.html', context)
|
||||||
|
|
||||||
|
elif request.method == 'POST':
|
||||||
|
|
||||||
|
if s.DEBUG:
|
||||||
|
for k, v in request.POST.items():
|
||||||
|
print(k, v)
|
||||||
|
|
||||||
|
if hidden := request.POST.get('hidden', None):
|
||||||
|
if hidden == 'delete-group':
|
||||||
|
current_group.delete()
|
||||||
|
return redirect(s.SERVER_URL + '/group')
|
||||||
|
else:
|
||||||
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
member_url = request.POST.get('member')
|
||||||
|
action = request.POST.get('action')
|
||||||
|
|
||||||
|
if all([member_url, action]) and action in ['add', 'remove']:
|
||||||
|
if 'user' in member_url:
|
||||||
|
member = UserManager.get_user_lp(member_url)
|
||||||
|
else:
|
||||||
|
member = GroupManager.get_group_lp(member_url)
|
||||||
|
|
||||||
|
GroupManager.update_members(current_user, current_group, member, action)
|
||||||
|
|
||||||
|
return redirect(current_group.url)
|
||||||
|
|
||||||
def settings(request):
|
def settings(request):
|
||||||
current_user = _anonymous_or_real(request)
|
current_user = _anonymous_or_real(request)
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#delete_group_modal">
|
||||||
|
<i class="glyphicon glyphicon-trash"></i> Delete Group</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#edit_group_member_modal">
|
||||||
|
<i class="glyphicon glyphicon-trash"></i> Add/Remove Member</a>
|
||||||
|
</li>
|
||||||
38
templates/modals/objects/delete_group_modal.html
Normal file
38
templates/modals/objects/delete_group_modal.html
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{% load static %}
|
||||||
|
<!-- Delete Group -->
|
||||||
|
<div id="delete_group_modal" class="modal" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3 class="modal-title">Delete Group</h3>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
Clicking "Delete" will <strong>permanently</strong> delete the Group.
|
||||||
|
This action can't be undone!
|
||||||
|
</div>
|
||||||
|
<form id="delete-group-modal-form" accept-charset="UTF-8" action="" data-remote="true" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="hidden" value="delete-group">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
|
<button type="button" class="btn btn-danger" id="delete-group-modal-submit">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
|
||||||
|
$('#delete-group-modal-submit').click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
$('#delete-group-modal-form').submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<form id="delete-user-modal-form" accept-charset="UTF-8" action="" data-remote="true" method="post">
|
<form id="delete-user-modal-form" accept-charset="UTF-8" action="" data-remote="true" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" name="hidden" value="delete-model">
|
<input type="hidden" name="hidden" value="delete-user">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
|||||||
120
templates/modals/objects/edit_group_member_modal.html
Normal file
120
templates/modals/objects/edit_group_member_modal.html
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
{% load static %}
|
||||||
|
<!-- Edit Package Permission -->
|
||||||
|
<div id="edit_group_member_modal" class="modal" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Add or Remove Group Member</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>
|
||||||
|
To add member (either User or entire Groups) to this group select the entity you want to add below
|
||||||
|
and click the check mark.
|
||||||
|
<br>
|
||||||
|
To remove member simply click the <code>X</code> next to the member.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<legend>User or Group</legend>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<legend>Add/Remove</legend>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<form id="modal-form-group-member" class="form-inline" role="form" accept-charset="UTF-8" action=""
|
||||||
|
data-remote="true" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="col-xs-8">
|
||||||
|
<select id="select_member" name="member" data-actions-box='true'
|
||||||
|
class="selPackages" data-width='100%'>
|
||||||
|
<option disabled selected>User</option>
|
||||||
|
{% for u in users %}
|
||||||
|
<option value="{{ u.url }}">{{ u.username }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
<option disabled>Groups</option>
|
||||||
|
{% for g in groups %}
|
||||||
|
<option value="{{ g.url }}">{{ g.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<input type="hidden" name="action" value="add">
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-2">
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-2">
|
||||||
|
<button type="submit" style="width:60%;" class="btn col-xs-2">
|
||||||
|
<span class="glyphicon glyphicon-ok"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<p></p>
|
||||||
|
{% for u in group.user_member.all %}
|
||||||
|
<div class="row">
|
||||||
|
<form id="modal-form-group-member_{{ u.uuid }}" class="form-inline" role="form"
|
||||||
|
accept-charset="UTF-8" action="" data-remote="true" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="col-xs-8">
|
||||||
|
{{ u.username }}
|
||||||
|
<input type="hidden" name="member" value="{{ u.url }}"/>
|
||||||
|
<input type="hidden" name="action" value="remove">
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-2">
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-2">
|
||||||
|
<button type="submit" style="width:60%;" class="btn col-xs-2">
|
||||||
|
<span class="glyphicon glyphicon-trash"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
<p></p>
|
||||||
|
{% for g in group.group_member.all %}
|
||||||
|
<div class="row">
|
||||||
|
<form id="modal-form-group-member_{{ g.uuid }}" class="form-inline" role="form"
|
||||||
|
accept-charset="UTF-8" action="" data-remote="true" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="col-xs-8">
|
||||||
|
{{ g.name }}
|
||||||
|
<input type="hidden" name="member" value="{{ g.url }}"/>
|
||||||
|
<input type="hidden" name="action" value="remove">
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-2">
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-2">
|
||||||
|
<button type="submit" style="width:60%;" class="btn col-xs-2">
|
||||||
|
<span class="glyphicon glyphicon-trash"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="edit-package-modal-submit">Update</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
|
||||||
|
$('#edit-package-modal-submit').click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
$('#edit-package-modal-form').submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#select_member").selectpicker();
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -66,7 +66,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<p></p>
|
||||||
{% for up in user_permissions %}
|
{% for up in user_permissions %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<form id="modal-form-permissions_{{ up.user.uuid }}" class="form-inline" role="form"
|
<form id="modal-form-permissions_{{ up.user.uuid }}" class="form-inline" role="form"
|
||||||
@ -93,7 +93,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
<p></p>
|
||||||
{% for gp in group_permissions %}
|
{% for gp in group_permissions %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<form id="modal-form-permissions_{{ gp.user.uuid }}" class="form-inline" role="form"
|
<form id="modal-form-permissions_{{ gp.user.uuid }}" class="form-inline" role="form"
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
{% block action_modals %}
|
{% block action_modals %}
|
||||||
{% include "modals/objects/edit_group_modal.html" %}
|
{% include "modals/objects/edit_group_modal.html" %}
|
||||||
|
{% include "modals/objects/edit_group_member_modal.html" %}
|
||||||
|
{% include "modals/objects/delete_group_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
|
|
||||||
<div class="panel-group" id="package-detail">
|
<div class="panel-group" id="package-detail">
|
||||||
@ -27,5 +29,36 @@
|
|||||||
<p> {{ group.description }} </p>
|
<p> {{ group.description }} </p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<p></p>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div id="member-panel" style="font-size:2rem;height: 46px" class="panel-heading">Members</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>List of members of this group</p>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
{% for um in group.user_member.all %}
|
||||||
|
<a class="list-group-item" href="{{ um.url }}">{{ um.username }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
{% for gm in group.group_member.all %}
|
||||||
|
<a class="list-group-item" href="{{ gm.url }}">{{ gm.name }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p></p>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div id="package-panel" style="font-size:2rem;height: 46px" class="panel-heading">Packages</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>Packages where this group has access to</p>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
{% for p in packages %}
|
||||||
|
<a class="list-group-item" href="{{ p.url }}">{{ p.name }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
Reference in New Issue
Block a user