mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-15 07:20:17 +02:00
Refactor Group extension models into a single OneToOne model
Added group leader field
This commit is contained in:
parent
648753a68a
commit
bf345361b2
@ -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)
|
||||
|
20
groupmanagement/managers.py
Normal file
20
groupmanagement/managers.py
Normal file
@ -0,0 +1,20 @@
|
||||
from django.contrib.auth.models import Group
|
||||
from django.conf import settings
|
||||
|
||||
class GroupManager:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def get_joinable_groups():
|
||||
return Group.objects.exclude(authgroup__internal=True)
|
||||
|
||||
@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
|
112
groupmanagement/migrations/0004_authgroup.py
Normal file
112
groupmanagement/migrations/0004_authgroup.py
Normal file
@ -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.<br>Used for groups such as Members, Corp_*, Alliance_* etc.<br><b>Overrides Hidden and Open options when selected.</b>')),
|
||||
('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. <br>If the group is not open users will need their request manually approved.')),
|
||||
('description', models.CharField(max_length=512, help_text='Description of the group shown to users.', )),
|
||||
|
||||
('group_leaders', models.ManyToManyField(related_name='leads_groups', to=settings.AUTH_USER_MODEL, 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',
|
||||
),
|
||||
]
|
@ -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.<br>"
|
||||
"Used for groups such as Members, Corp_*, Alliance_* etc.<br>"
|
||||
"<b>Overrides Hidden and Open options when selected.</b>")
|
||||
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. <br>"
|
||||
"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',
|
||||
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, 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()
|
||||
|
@ -1,22 +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.models import Group
|
||||
from django.contrib import messages
|
||||
from notifications import notify
|
||||
from groupmanagement.models import GroupDescription
|
||||
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 _
|
||||
from django.db.models import Count
|
||||
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
||||
from django.http import Http404
|
||||
from itertools import chain
|
||||
|
||||
import logging
|
||||
|
||||
@ -48,8 +44,7 @@ def group_management(request):
|
||||
def group_membership(request):
|
||||
logger.debug("group_membership called by user %s" % request.user)
|
||||
# Get all open and closed groups
|
||||
groups = [group for group in Group.objects.all().annotate(num_members=Count('user')).order_by('name')
|
||||
if joinable_group(group)]
|
||||
groups = Group.objects.exclude(authgroup__internal=True).annotate(num_members=Count('user')).order_by('name')
|
||||
|
||||
render_items = {'groups': groups}
|
||||
|
||||
@ -64,7 +59,7 @@ def group_membership_list(request, group_id):
|
||||
group = Group.objects.get(id=group_id)
|
||||
|
||||
# Check its a joinable group i.e. not corp or internal
|
||||
if not joinable_group(group):
|
||||
if not GroupManager.joinable_group(group):
|
||||
raise PermissionDenied
|
||||
|
||||
except ObjectDoesNotExist:
|
||||
@ -214,31 +209,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 not joinable_group(group):
|
||||
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)
|
||||
|
||||
|
||||
@ -246,12 +226,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 not joinable_group(group):
|
||||
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 OpenGroup.objects.filter(group=group).exists():
|
||||
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")
|
||||
@ -272,7 +252,7 @@ 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 not joinable_group(group):
|
||||
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")
|
||||
@ -282,7 +262,7 @@ def group_request_leave(request, group_id):
|
||||
(request.user, group_id))
|
||||
messages.warning(request, "You are not a member of that group")
|
||||
return redirect('auth_groups')
|
||||
if OpenGroup.objects.filter(group=group).exists():
|
||||
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")
|
||||
@ -297,18 +277,3 @@ def group_request_leave(request, group_id):
|
||||
logger.info("Created group leave request for user %s to group %s" % (request.user, Group.objects.get(id=group_id)))
|
||||
messages.success(request, 'Applied to leave group %s.' % group)
|
||||
return redirect("auth_groups")
|
||||
|
||||
|
||||
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 (
|
||||
"Corp_" not in group.name and
|
||||
"Alliance_" not in group.name and
|
||||
settings.DEFAULT_AUTH_GROUP not in group.name and
|
||||
settings.DEFAULT_BLUE_GROUP not in group.name
|
||||
)
|
||||
|
@ -24,11 +24,11 @@
|
||||
{% for group in groups %}
|
||||
<tr>
|
||||
<td class="text-center">{{ group.name }}</td>
|
||||
<td class="text-center">{{ group.groupdescription.description }}</td>
|
||||
<td class="text-center">{{ group.authgroup.description }}</td>
|
||||
<td class="text-center">
|
||||
{% if group.hiddengroup %}
|
||||
{% if group.authgroup.hidden %}
|
||||
<span class="label label-info">{% trans "Hidden" %}</span>
|
||||
{% elif group.opengroup %}
|
||||
{% elif group.authgroup.open %}
|
||||
<span class="label label-success">{% trans "Open" %}</span>
|
||||
{% else %}
|
||||
<span class="label label-default">{% trans "Requestable" %}</span>
|
||||
|
@ -11,36 +11,36 @@
|
||||
<div class="col-lg-12">
|
||||
<h1 class="page-header text-center">{% trans "Available Groups" %}</h1>
|
||||
{% if STATE == MEMBER_STATE or user.is_superuser %}
|
||||
{% if pairs %}
|
||||
{% if groups %}
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th class="text-center">{% trans "GroupName" %}</th>
|
||||
<th class="text-center">{% trans "GroupDesc" %}</th>
|
||||
<th class="text-center">{% trans "Name" %}</th>
|
||||
<th class="text-center">{% trans "Description" %}</th>
|
||||
<th class="text-center">{% trans "Action" %}</th>
|
||||
</tr>
|
||||
|
||||
{% for pair in pairs %}
|
||||
{% for g in groups %}
|
||||
<tr>
|
||||
<td class="text-center">{{ pair.0.name }}</td>
|
||||
<td class="text-center">{{ pair.1.description }}</td>
|
||||
<td class="text-center">{{ g.group.name }}</td>
|
||||
<td class="text-center">{{ g.group.authgroup.description }}</td>
|
||||
<td class="text-center">
|
||||
{% if pair.0 in user.groups.all %}
|
||||
{% if pair.2 == "" %}
|
||||
<a href="{% url 'auth_group_request_leave' pair.0.id %}" class="btn btn-danger">
|
||||
{% if g.group in user.groups.all %}
|
||||
{% if not g.request %}
|
||||
<a href="{% url 'auth_group_request_leave' g.group.id %}" class="btn btn-danger">
|
||||
{% trans "Leave" %}
|
||||
</a>
|
||||
{% else %}
|
||||
<button type="button" class="btn btn-primary" disabled>
|
||||
{{ pair.2.status }}
|
||||
{{ g.request.status }}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% elif pair.2 == "" %}
|
||||
<a href="{% url 'auth_group_request_add' pair.0.id %}" class="btn btn-success">
|
||||
{% elif not g.request %}
|
||||
<a href="{% url 'auth_group_request_add' g.group.id %}" class="btn btn-success">
|
||||
{% trans "Request" %}
|
||||
</a>
|
||||
{% else %}
|
||||
<button type="button" class="btn btn-primary" disabled>
|
||||
{{ pair.2.status }}
|
||||
{{ g.request.status }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
Loading…
x
Reference in New Issue
Block a user