diff --git a/alliance_auth/settings.py.example b/alliance_auth/settings.py.example
index fa6a5aa3..b9dc87fd 100644
--- a/alliance_auth/settings.py.example
+++ b/alliance_auth/settings.py.example
@@ -111,6 +111,7 @@ TEMPLATES = [
'authentication.context_processors.states',
'authentication.context_processors.membership_state',
'authentication.context_processors.sso',
+ 'groupmanagement.context_processors.can_manage_groups',
],
},
},
diff --git a/alliance_auth/urls.py b/alliance_auth/urls.py
index bbea8f80..056d4579 100755
--- a/alliance_auth/urls.py
+++ b/alliance_auth/urls.py
@@ -190,6 +190,12 @@ urlpatterns += i18n_patterns(
url(_(r'^groups/'), groupmanagement.views.groups_view, name='auth_groups'),
url(_(r'^group/management/'), groupmanagement.views.group_management,
name='auth_group_management'),
+ url(_(r'^group/membership/$'), groupmanagement.views.group_membership,
+ name='auth_group_membership'),
+ url(_(r'^group/membership/(\w+)/$'), groupmanagement.views.group_membership_list,
+ name='auth_group_membership_list'),
+ url(_(r'^group/membership/(\w+)/remove/(\w+)/$'), groupmanagement.views.group_membership_remove,
+ name='auth_group_membership_remove'),
url(_(r'^group/request_add/(\w+)'), groupmanagement.views.group_request_add,
name='auth_group_request_add'),
url(_(r'^group/request/accept/(\w+)'), groupmanagement.views.group_accept_request,
diff --git a/authentication/context_processors.py b/authentication/context_processors.py
index d403df83..7f1c39f1 100644
--- a/authentication/context_processors.py
+++ b/authentication/context_processors.py
@@ -1,14 +1,11 @@
from __future__ import unicode_literals
-from authentication.models import AuthServicesInfo
from authentication.states import NONE_STATE, BLUE_STATE, MEMBER_STATE
+from authentication.managers import UserState
from django.conf import settings
def membership_state(request):
- if request.user.is_authenticated:
- auth = AuthServicesInfo.objects.get_or_create(user=request.user)[0]
- return {'STATE': auth.state}
- return {'STATE': NONE_STATE}
+ return UserState.get_membership_state(request)
def states(request):
@@ -19,6 +16,7 @@ def states(request):
'MEMBER_BLUE_STATE': [MEMBER_STATE, BLUE_STATE],
}
+
def sso(request):
return {
'EVE_SSO_CALLBACK_URL': settings.EVE_SSO_CALLBACK_URL,
diff --git a/authentication/decorators.py b/authentication/decorators.py
index 1d3167cb..c08fc8cb 100644
--- a/authentication/decorators.py
+++ b/authentication/decorators.py
@@ -1,33 +1,23 @@
from __future__ import unicode_literals
from django.contrib.auth.decorators import user_passes_test
-from authentication.models import AuthServicesInfo
-from authentication.states import MEMBER_STATE, BLUE_STATE, NONE_STATE
-from django.conf import settings
+from authentication.managers import UserState
-def _state_required(states, *args, **kwargs):
- def test_func(user):
- if user.is_superuser and settings.SUPERUSER_STATE_BYPASS:
- return True
- if user.is_authenticated:
- auth = AuthServicesInfo.objects.get_or_create(user=user)[0]
- return auth.state in states
- return False
-
- return user_passes_test(test_func, *args, **kwargs)
+def _state_required(state_test, *args, **kwargs):
+ return user_passes_test(state_test, *args, **kwargs)
def members(*args, **kwargs):
- return _state_required([MEMBER_STATE], *args, **kwargs)
+ return _state_required(UserState.member_state, *args, **kwargs)
def blues(*args, **kwargs):
- return _state_required([BLUE_STATE], *args, **kwargs)
+ return _state_required(UserState.blue_state, *args, **kwargs)
def members_and_blues(*args, **kwargs):
- return _state_required([MEMBER_STATE, BLUE_STATE], *args, **kwargs)
+ return _state_required(UserState.member_or_blue_state, *args, **kwargs)
def none_state(*args, **kwargs):
- return _state_required([NONE_STATE], *args, **kwargs)
+ return _state_required(UserState.none_state, *args, **kwargs)
diff --git a/authentication/managers.py b/authentication/managers.py
index 6471880b..a577a05a 100755
--- a/authentication/managers.py
+++ b/authentication/managers.py
@@ -1,6 +1,7 @@
from __future__ import unicode_literals
from django.contrib.auth.models import User
-
+from django.conf import settings
+from authentication.states import NONE_STATE, BLUE_STATE, MEMBER_STATE
from authentication.models import AuthServicesInfo
import logging
@@ -143,3 +144,44 @@ class AuthServicesInfoManager:
logger.info("Updated user %s market info in authservicesinfo model." % user)
else:
logger.error("Failed to update user %s market info: user does not exist." % user)
+
+
+class UserState:
+ def __init__(self):
+ pass
+
+ MEMBER_STATE = MEMBER_STATE
+ BLUE_STATE = BLUE_STATE
+ NONE_STATE = NONE_STATE
+
+ @classmethod
+ def member_state(cls, user):
+ return cls.state_required(user, [cls.MEMBER_STATE])
+
+ @classmethod
+ def member_or_blue_state(cls, user):
+ return cls.state_required(user, [cls.MEMBER_STATE, cls.BLUE_STATE])
+
+ @classmethod
+ def blue_state(cls, user):
+ return cls.state_required(user, [cls.BLUE_STATE])
+
+ @classmethod
+ def none_state(cls, user):
+ return cls.state_required(user, [cls.NONE_STATE])
+
+ @classmethod
+ def get_membership_state(cls, request):
+ if request.user.is_authenticated:
+ auth = AuthServicesInfo.objects.get_or_create(user=request.user)[0]
+ return {'STATE': auth.state}
+ return {'STATE': cls.NONE_STATE}
+
+ @staticmethod
+ def state_required(user, states):
+ if user.is_superuser and settings.SUPERUSER_STATE_BYPASS:
+ return True
+ if user.is_authenticated:
+ auth = AuthServicesInfo.objects.get_or_create(user=user)[0]
+ return auth.state in states
+ return False
diff --git a/groupmanagement/admin.py b/groupmanagement/admin.py
index 4d21a00f..aa7ea35a 100644
--- a/groupmanagement/admin.py
+++ b/groupmanagement/admin.py
@@ -1,13 +1,15 @@
from __future__ import unicode_literals
from django.contrib import admin
-from groupmanagement.models import GroupDescription
from groupmanagement.models import GroupRequest
-from groupmanagement.models import HiddenGroup
-from groupmanagement.models import OpenGroup
+from groupmanagement.models import AuthGroup
-admin.site.register(GroupDescription)
+class AuthGroupAdmin(admin.ModelAdmin):
+ """
+ Admin model for AuthGroup
+ """
+ filter_horizontal = ('group_leaders',)
+
admin.site.register(GroupRequest)
-admin.site.register(HiddenGroup)
-admin.site.register(OpenGroup)
+admin.site.register(AuthGroup, AuthGroupAdmin)
diff --git a/groupmanagement/context_processors.py b/groupmanagement/context_processors.py
new file mode 100644
index 00000000..0d60be3f
--- /dev/null
+++ b/groupmanagement/context_processors.py
@@ -0,0 +1,5 @@
+from groupmanagement.managers import GroupManager
+
+
+def can_manage_groups(request):
+ return {'can_manage_groups': GroupManager.can_manage_groups(request.user)}
diff --git a/groupmanagement/managers.py b/groupmanagement/managers.py
new file mode 100644
index 00000000..41188257
--- /dev/null
+++ b/groupmanagement/managers.py
@@ -0,0 +1,56 @@
+from django.contrib.auth.models import Group
+from django.conf import settings
+from authentication.managers import UserState
+
+class GroupManager:
+ def __init__(self):
+ pass
+
+ @staticmethod
+ def get_joinable_groups():
+ return Group.objects.exclude(authgroup__internal=True)
+
+ @staticmethod
+ def get_group_leaders_groups(user):
+ return Group.objects.filter(authgroup__group_leaders__in=[user])
+
+ @staticmethod
+ def joinable_group(group):
+ """
+ Check if a group is a user joinable group, i.e.
+ not an internal group for Corp, Alliance, Members etc
+ :param group: django.contrib.auth.models.Group object
+ :return: bool True if its joinable, False otherwise
+ """
+ return not group.authgroup.internal
+
+ @staticmethod
+ def has_management_permission(user):
+ return user.has_perm('auth.group_management')
+
+ @classmethod
+ def can_manage_groups(cls, user):
+ """
+ For use with user_passes_test decorator.
+ Check if the user can manage groups. Either has the
+ auth.group_management permission or is a leader of at least one group
+ and is also a Member.
+ :param user: django.contrib.auth.models.User for the request
+ :return: bool True if user can manage groups, False otherwise
+ """
+ if user.is_authenticated:
+ return cls.has_management_permission(user) or (user.leads_groups.all() and UserState.member_state(user))
+ return False
+
+ @classmethod
+ def can_manage_group(cls, user, group):
+ """
+ Check user has permission to manage the given group
+ :param user: User object to test permission of
+ :param group: Group object the user is attempting to manage
+ :return: True if the user can manage the group
+ """
+ if user.is_authenticated:
+ return cls.has_management_permission(user) or (
+ user.leads_groups.filter(group=group).exists() and UserState.member_state(user))
+ return False
diff --git a/groupmanagement/migrations/0004_authgroup.py b/groupmanagement/migrations/0004_authgroup.py
new file mode 100644
index 00000000..a7bbda98
--- /dev/null
+++ b/groupmanagement/migrations/0004_authgroup.py
@@ -0,0 +1,112 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.2 on 2016-12-04 10:25
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.db import migrations, models
+from django.core.exceptions import ObjectDoesNotExist
+import django.db.models.deletion
+
+
+def internal_group(group):
+ return (
+ "Corp_" in group.name or
+ "Alliance_" in group.name or
+ settings.DEFAULT_AUTH_GROUP in group.name or
+ settings.DEFAULT_BLUE_GROUP in group.name
+ )
+
+
+def combine_group_models(apps, schema_editor):
+ Group = apps.get_model("auth", "Group")
+ AuthGroup = apps.get_model("groupmanagement", "AuthGroup")
+
+ for group in Group.objects.all():
+ authgroup = AuthGroup(group=group)
+ if not hasattr(group, 'hiddengroup'):
+ authgroup.hidden = False
+ if hasattr(group, 'opengroup'):
+ authgroup.open = True
+
+ if hasattr(group, 'groupdescription'):
+ authgroup.description = group.groupdescription.description
+
+ authgroup.internal = internal_group(group)
+ authgroup.save()
+
+
+def reverse_group_models(apps, schema_editor):
+ Group = apps.get_model("auth", "Group")
+ GroupDescription = apps.get_model("groupmanagement", "GroupDescription")
+ OpenGroup = apps.get_model("groupmanagement", "OpenGroup")
+ HiddenGroup = apps.get_model("groupmanagement", "HiddenGroup")
+
+ for group in Group.objects.all():
+ if not hasattr(group, 'authgroup') or group.authgroup is None:
+ continue
+ if group.authgroup.open:
+ OpenGroup.objects.get_or_create(group=group)
+ else:
+ try:
+ OpenGroup.objects.get(group=group).delete()
+ except ObjectDoesNotExist:
+ pass
+
+ if group.authgroup.hidden:
+ HiddenGroup.objects.get_or_create(group=group)
+ else:
+ try:
+ HiddenGroup.objects.get(group=group).delete()
+ except ObjectDoesNotExist:
+ pass
+
+ if len(group.authgroup.description):
+ GroupDescription.objects.update_or_create(group=group,
+ defaults={'description': group.authgroup.description})
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('auth', '0008_alter_user_username_max_length'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('groupmanagement', '0003_default_groups'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='AuthGroup',
+ fields=[
+ ('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True,
+ serialize=False, to='auth.Group')),
+ ('internal', models.BooleanField(default=True, help_text='Internal group, users cannot see, join or request to join this group.
Used for groups such as Members, Corp_*, Alliance_* etc.
Overrides Hidden and Open options when selected.')),
+ ('hidden', models.BooleanField(default=True, help_text='Group is hidden from users but can still join with the correct link.')),
+ ('open', models.BooleanField(default=False, help_text='Group is open and users will be automatically added upon request.
If the group is not open users will need their request manually approved.')),
+ ('description', models.CharField(max_length=512, blank=True, help_text='Description of the group shown to users.', )),
+
+ ('group_leaders', models.ManyToManyField(related_name='leads_groups', to=settings.AUTH_USER_MODEL, blank=True, help_text='Group leaders can process group requests for this group specifically. Use the auth.group_management permission to allow a user to manage all groups.',)),
+ ],
+ ),
+ migrations.RunPython(combine_group_models, reverse_group_models),
+ migrations.RemoveField(
+ model_name='groupdescription',
+ name='group',
+ ),
+ migrations.RemoveField(
+ model_name='hiddengroup',
+ name='group',
+ ),
+ migrations.RemoveField(
+ model_name='opengroup',
+ name='group',
+ ),
+ migrations.DeleteModel(
+ name='GroupDescription',
+ ),
+ migrations.DeleteModel(
+ name='HiddenGroup',
+ ),
+ migrations.DeleteModel(
+ name='OpenGroup',
+ ),
+ ]
diff --git a/groupmanagement/models.py b/groupmanagement/models.py
index ffad61aa..52d98343 100644
--- a/groupmanagement/models.py
+++ b/groupmanagement/models.py
@@ -3,19 +3,12 @@ from django.utils.encoding import python_2_unicode_compatible
from django.db import models
from django.contrib.auth.models import User
from django.contrib.auth.models import Group
+from django.db.models.signals import post_save
+from django.dispatch import receiver
from eveonline.models import EveCharacter
-@python_2_unicode_compatible
-class GroupDescription(models.Model):
- description = models.CharField(max_length=512)
- group = models.OneToOneField(Group)
-
- def __str__(self):
- return self.group.name + " - Description"
-
-
@python_2_unicode_compatible
class GroupRequest(models.Model):
status = models.CharField(max_length=254)
@@ -29,16 +22,57 @@ class GroupRequest(models.Model):
@python_2_unicode_compatible
-class HiddenGroup(models.Model):
- group = models.OneToOneField(Group)
+class AuthGroup(models.Model):
+ """
+ Extends Django Group model with a one-to-one field
+ Attributes are accessible via group as if they were in the model
+ e.g. group.authgroup.internal
+
+ Logic:
+ Internal - not requestable by users, at all. Covers Corp_, Alliance_, Members etc groups.
+ Groups are internal by default
+
+ Not Internal and:
+ Hidden - users cannot view, can request if they have the direct link.
+ Not Hidden - Users can view and request the group
+ Open - Users are automatically accepted into the group
+ Not Open - Users requests must be approved before they are added to the group
+ """
+ group = models.OneToOneField(Group, on_delete=models.CASCADE, primary_key=True)
+
+ internal = models.BooleanField(default=True,
+ help_text="Internal group, users cannot see, join or request to join this group.
"
+ "Used for groups such as Members, Corp_*, Alliance_* etc.
"
+ "Overrides Hidden and Open options when selected.")
+ hidden = models.BooleanField(default=True,
+ help_text="Group is hidden from users but can still join with the correct link.")
+ open = models.BooleanField(default=False,
+ help_text="Group is open and users will be automatically added upon request.
"
+ "If the group is not open users will need their request manually approved.")
+ # Group leaders have management access to this group
+ group_leaders = models.ManyToManyField(User, related_name='leads_groups', blank=True,
+ help_text="Group leaders can process group requests for this group "
+ "specifically. Use the auth.group_management permission to allow "
+ "a user to manage all groups.")
+
+ description = models.CharField(max_length=512, blank=True, help_text="Description of the group shown to users.")
def __str__(self):
- return self.group.name + " - Hidden"
+ return self.group.name
-@python_2_unicode_compatible
-class OpenGroup(models.Model):
- group = models.OneToOneField(Group)
+@receiver(post_save, sender=Group)
+def create_auth_group(sender, instance, created, **kwargs):
+ """
+ Creates the AuthGroup model when a group is created
+ """
+ if created:
+ AuthGroup.objects.create(group=instance)
- def __str__(self):
- return self.group.name + " - Open"
+
+@receiver(post_save, sender=Group)
+def save_auth_group(sender, instance, **kwargs):
+ """
+ Ensures AuthGroup model is saved automatically
+ """
+ instance.authgroup.save()
diff --git a/groupmanagement/views.py b/groupmanagement/views.py
index 9a9eaf91..d0a00b4d 100755
--- a/groupmanagement/views.py
+++ b/groupmanagement/views.py
@@ -1,18 +1,18 @@
from __future__ import unicode_literals
from django.shortcuts import render, redirect
-from django.conf import settings
from django.contrib.auth.decorators import login_required
-from django.contrib.auth.decorators import permission_required
+from django.contrib.auth.decorators import user_passes_test
from django.contrib.auth.models import Group
from django.contrib import messages
from notifications import notify
-from groupmanagement.models import GroupDescription
+from django.utils.translation import ugettext_lazy as _
+from django.db.models import Count
+from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
+from django.http import Http404
+from groupmanagement.managers import GroupManager
from groupmanagement.models import GroupRequest
-from groupmanagement.models import HiddenGroup
-from groupmanagement.models import OpenGroup
from authentication.models import AuthServicesInfo
from eveonline.managers import EveManager
-from django.utils.translation import ugettext_lazy as _
import logging
@@ -20,17 +20,25 @@ logger = logging.getLogger(__name__)
@login_required
-@permission_required('auth.group_management')
+@user_passes_test(GroupManager.can_manage_groups)
def group_management(request):
logger.debug("group_management called by user %s" % request.user)
acceptrequests = []
leaverequests = []
- for grouprequest in GroupRequest.objects.all():
+ if GroupManager.has_management_permission(request.user):
+ # Full access
+ group_requests = GroupRequest.objects.all()
+ else:
+ # Group specific leader
+ group_requests = GroupRequest.objects.filter(group__authgroup__group_leaders__in=[request.user])
+
+ for grouprequest in group_requests:
if grouprequest.leave_request:
leaverequests.append(grouprequest)
else:
acceptrequests.append(grouprequest)
+
logger.debug("Providing user %s with %s acceptrequests and %s leaverequests." % (
request.user, len(acceptrequests), len(leaverequests)))
@@ -40,12 +48,98 @@ def group_management(request):
@login_required
-@permission_required('auth.group_management')
+@user_passes_test(GroupManager.can_manage_groups)
+def group_membership(request):
+ logger.debug("group_membership called by user %s" % request.user)
+ # Get all open and closed groups
+ if GroupManager.has_management_permission(request.user):
+ # Full access
+ groups = GroupManager.get_joinable_groups()
+ else:
+ # Group leader specific
+ groups = GroupManager.get_group_leaders_groups(request.user)
+
+ groups = groups.exclude(authgroup__internal=True).annotate(num_members=Count('user')).order_by('name')
+
+ render_items = {'groups': groups}
+
+ return render(request, 'registered/groupmembership.html', context=render_items)
+
+
+@login_required
+@user_passes_test(GroupManager.can_manage_groups)
+def group_membership_list(request, group_id):
+ logger.debug("group_membership_list called by user %s for group id %s" % (request.user, group_id))
+ try:
+ group = Group.objects.get(id=group_id)
+
+ # Check its a joinable group i.e. not corp or internal
+ # And the user has permission to manage it
+ if not GroupManager.joinable_group(group) or not GroupManager.can_manage_group(request.user, group):
+ logger.warning("User %s attempted to view the membership of group %s but permission was denied" %
+ (request.user, group_id))
+ raise PermissionDenied
+
+ except ObjectDoesNotExist:
+ raise Http404("Group does not exist")
+
+ members = list()
+
+ for member in group.user_set.all().order_by('username'):
+ authinfo = AuthServicesInfo.objects.get_or_create(user=member)[0]
+
+ members.append({
+ 'user': member,
+ 'main_char': EveManager.get_character_by_id(authinfo.main_char_id)
+ })
+
+ render_items = {'group': group, 'members': members}
+
+ return render(request, 'registered/groupmembers.html', context=render_items)
+
+
+@login_required
+@user_passes_test(GroupManager.can_manage_groups)
+def group_membership_remove(request, group_id, user_id):
+ logger.debug("group_membership_remove called by user %s for group id %s on user id %s" %
+ (request.user, group_id, user_id))
+ try:
+ group = Group.objects.get(id=group_id)
+
+ # Check its a joinable group i.e. not corp or internal
+ # And the user has permission to manage it
+ if not GroupManager.joinable_group(group) or not GroupManager.can_manage_group(request.user, group):
+ logger.warning("User %s attempted to remove a user from group %s but permission was denied" % (request.user,
+ group_id))
+ raise PermissionDenied
+
+ try:
+ user = group.user_set.get(id=user_id)
+ # Remove group from user
+ user.groups.remove(group)
+ logger.info("User %s removed user %s from group %s" % (request.user, user, group))
+ messages.success(request, "Removed user %s from group %s" % (user, group))
+ except ObjectDoesNotExist:
+ messages.warning(request, "User does not exist in that group")
+
+ except ObjectDoesNotExist:
+ messages.warning(request, "Group does not exist")
+
+ return redirect('auth_group_membership_list', group_id)
+
+
+@login_required
+@user_passes_test(GroupManager.can_manage_groups)
def group_accept_request(request, group_request_id):
logger.debug("group_accept_request called by user %s for grouprequest id %s" % (request.user, group_request_id))
try:
group_request = GroupRequest.objects.get(id=group_request_id)
group, created = Group.objects.get_or_create(name=group_request.group.name)
+
+ if not GroupManager.joinable_group(group_request.group) or \
+ not GroupManager.can_manage_group(request.user, group_request.group):
+ raise PermissionDenied
+
group_request.user.groups.add(group)
group_request.user.save()
group_request.delete()
@@ -55,6 +149,11 @@ def group_accept_request(request, group_request_id):
message="Your application to %s has been accepted." % group_request.group)
messages.success(request,
'Accepted application from %s to %s.' % (group_request.main_char, group_request.group))
+
+ except PermissionDenied as p:
+ logger.warning("User %s attempted to accept group join request %s but permission was denied" %
+ (request.user, group_request_id))
+ raise p
except:
messages.error(request, 'An unhandled error occurred while processing the application from %s to %s.' % (
group_request.main_char, group_request.group))
@@ -66,12 +165,15 @@ def group_accept_request(request, group_request_id):
@login_required
-@permission_required('auth.group_management')
+@user_passes_test(GroupManager.can_manage_groups)
def group_reject_request(request, group_request_id):
logger.debug("group_reject_request called by user %s for group request id %s" % (request.user, group_request_id))
try:
group_request = GroupRequest.objects.get(id=group_request_id)
+ if not GroupManager.can_manage_group(request.user, group_request.group):
+ raise PermissionDenied
+
if group_request:
logger.info("User %s rejected group request from user %s to group %s" % (
request.user, group_request.user, group_request.group.name))
@@ -80,6 +182,11 @@ def group_reject_request(request, group_request_id):
message="Your application to %s has been rejected." % group_request.group)
messages.success(request,
'Rejected application from %s to %s.' % (group_request.main_char, group_request.group))
+
+ except PermissionDenied as p:
+ logger.warning("User %s attempted to reject group join request %s but permission was denied" %
+ (request.user, group_request_id))
+ raise p
except:
messages.error(request, 'An unhandled error occured while processing the application from %s to %s.' % (
group_request.main_char, group_request.group))
@@ -91,12 +198,16 @@ def group_reject_request(request, group_request_id):
@login_required
-@permission_required('auth.group_management')
+@user_passes_test(GroupManager.can_manage_groups)
def group_leave_accept_request(request, group_request_id):
logger.debug(
"group_leave_accept_request called by user %s for group request id %s" % (request.user, group_request_id))
try:
group_request = GroupRequest.objects.get(id=group_request_id)
+
+ if not GroupManager.can_manage_group(request.user, group_request.group):
+ raise PermissionDenied
+
group, created = Group.objects.get_or_create(name=group_request.group.name)
group_request.user.groups.remove(group)
group_request.user.save()
@@ -107,6 +218,10 @@ def group_leave_accept_request(request, group_request_id):
message="Your request to leave %s has been accepted." % group_request.group)
messages.success(request,
'Accepted application from %s to leave %s.' % (group_request.main_char, group_request.group))
+ except PermissionDenied as p:
+ logger.warning("User %s attempted to accept group leave request %s but permission was denied" %
+ (request.user, group_request_id))
+ raise p
except:
messages.error(request, 'An unhandled error occured while processing the application from %s to leave %s.' % (
group_request.main_char, group_request.group))
@@ -118,13 +233,16 @@ def group_leave_accept_request(request, group_request_id):
@login_required
-@permission_required('auth.group_management')
+@user_passes_test(GroupManager.can_manage_groups)
def group_leave_reject_request(request, group_request_id):
logger.debug(
"group_leave_reject_request called by user %s for group request id %s" % (request.user, group_request_id))
try:
group_request = GroupRequest.objects.get(id=group_request_id)
+ if not GroupManager.can_manage_group(request.user, group_request.group):
+ raise PermissionDenied
+
if group_request:
group_request.delete()
logger.info("User %s rejected group leave request from user %s for group %s" % (
@@ -133,6 +251,10 @@ def group_leave_reject_request(request, group_request_id):
message="Your request to leave %s has been rejected." % group_request.group)
messages.success(request, 'Rejected application from %s to leave %s.' % (
group_request.main_char, group_request.group))
+ except PermissionDenied as p:
+ logger.warning("User %s attempted to reject group leave request %s but permission was denied" %
+ (request.user, group_request_id))
+ raise p
except:
messages.error(request, 'An unhandled error occured while processing the application from %s to leave %s.' % (
group_request.main_char, group_request.group))
@@ -146,37 +268,16 @@ def group_leave_reject_request(request, group_request_id):
@login_required
def groups_view(request):
logger.debug("groups_view called by user %s" % request.user)
- paired_list = []
+ groups = []
- for group in Group.objects.all():
- # Check if group is a corp
- if "Corp_" in group.name:
- pass
- elif "Alliance_" in group.name:
- pass
- elif settings.DEFAULT_AUTH_GROUP in group.name:
- pass
- elif settings.DEFAULT_BLUE_GROUP in group.name:
- pass
- elif HiddenGroup.objects.filter(group=group).exists():
- pass
- else:
- # Get the descriptionn
- group_desc = GroupDescription.objects.filter(group=group)
+ for group in GroupManager.get_joinable_groups():
+ # Exclude hidden
+ if not group.authgroup.hidden:
group_request = GroupRequest.objects.filter(user=request.user).filter(group=group)
- if group_desc:
- if group_request:
- paired_list.append((group, group_desc[0], group_request[0]))
- else:
- paired_list.append((group, group_desc[0], ""))
- else:
- if group_request:
- paired_list.append((group, "", group_request[0]))
- else:
- paired_list.append((group, "", ""))
+ groups.append({'group': group, 'request': group_request[0] if group_request else None})
- render_items = {'pairs': paired_list}
+ render_items = {'groups': groups}
return render(request, 'registered/groups.html', context=render_items)
@@ -184,7 +285,12 @@ def groups_view(request):
def group_request_add(request, group_id):
logger.debug("group_request_add called by user %s for group id %s" % (request.user, group_id))
group = Group.objects.get(id=group_id)
- if OpenGroup.objects.filter(group=group).exists():
+ if not GroupManager.joinable_group(group):
+ logger.warning("User %s attempted to join group id %s but it is not a joinable group" %
+ (request.user, group_id))
+ messages.warning(request, "You cannot join that group")
+ return redirect('auth_groups')
+ if group.authgroup.open:
logger.info("%s joining %s as is an open group" % (request.user, group))
request.user.groups.add(group)
return redirect("auth_groups")
@@ -205,7 +311,17 @@ def group_request_add(request, group_id):
def group_request_leave(request, group_id):
logger.debug("group_request_leave called by user %s for group id %s" % (request.user, group_id))
group = Group.objects.get(id=group_id)
- if OpenGroup.objects.filter(group=group).exists():
+ if not GroupManager.joinable_group(group):
+ logger.warning("User %s attempted to leave group id %s but it is not a joinable group" %
+ (request.user, group_id))
+ messages.warning(request, "You cannot leave that group")
+ return redirect('auth_groups')
+ if group not in request.user.groups.all():
+ logger.debug("User %s attempted to leave group id %s but they are not a member" %
+ (request.user, group_id))
+ messages.warning(request, "You are not a member of that group")
+ return redirect('auth_groups')
+ if group.authgroup.open:
logger.info("%s leaving %s as is an open group" % (request.user, group))
request.user.groups.remove(group)
return redirect("auth_groups")
diff --git a/stock/templates/public/base.html b/stock/templates/public/base.html
index 595dbfc5..7e6a6ce1 100755
--- a/stock/templates/public/base.html
+++ b/stock/templates/public/base.html
@@ -153,7 +153,7 @@
{% endif %}
- {% if perms.auth.group_management %}
+ {% if can_manage_groups %}