def get_group_or_404(group_name):
    try:
        group_object = Group.objects.get(name=group_name)
    except ObjectDoesNotExist:
        raise Http404('Non-existent Group')
    else:
        return group_object def group_member(request):
    group_name = request.resolver_match.kwargs.get('group_name')

    if request.user.groups.filter(name=group_name).exists():
        return True

    return False class IsGroupOwner(BasePermission):

    def has_permission(self, request, view):
        if group_member(request) and group_owner(request):
            return True

        return False class IsGroupAdmin(BasePermission):

    def has_permission(self, request, view):
        if group_member(request) and group_admin(request):
            return True

        return False class IsGroupAdminOrMemberReadOnly(BasePermission):

    def has_permission(self, request, view):
        if group_member(request):
            if group_admin(request):
                return True
            elif request.method in permissions.SAFE_METHODS:
                return True

        return False class IsGroupOwnerOrPublicReadOnly(BasePermission):

    def has_permission(self, request, view):
        if group_member(request) and group_owner(request):
            return True
        elif request.method in permissions.SAFE_METHODS:
            return True

        return False class PublicGroupSerializer(serializers.Serializer):
    name = serializers.CharField(read_only=True)
    owner = serializers.SerializerMethodField()
    rule_count = serializers.SerializerMethodField()
    member_count = serializers.SerializerMethodField()

    def get_owner(self, obj):
        return obj.groupmeta.owner.username

    def get_rule_count(self, obj):
        return YaraRule.objects.filter(owner=obj).count()

    def get_member_count(self, obj):
        return obj.user_set.count() class GroupMetaUpdateSerializer(serializers.Serializer):
    source_required = serializers.BooleanField()
    category_required = serializers.BooleanField()
    nonprivileged_submission_status = serializers.ChoiceField(YaraRule.STATUS_CHOICES)

    def update(self, instance, validated_data):
        instance.source_required = validated_data.get('source_required',
                                                      instance.source_required)

        instance.category_required = validated_data.get('category_required',
                                                        instance.category_required)

        instance.nonprivileged_submission_status = validated_data.get('nonprivileged_submission_status',
                                                                      instance.nonprivileged_submission_status)

        instance.save()
        return instance class PrivateUserSerializer(serializers.Serializer):

    username = serializers.CharField(read_only=True)

    email = serializers.EmailField()

    api_token = serializers.CharField(source='auth_token', read_only=True)

    groups = serializers.SerializerMethodField()

    def get_groups(self, obj):
        group_listing = {}
        groups = obj.groups.all()

        for group_object in groups:
            group_meta = group_object.groupmeta

            if group_meta.owner == obj:
                group_membership_status = 'owner'

            elif obj in group_meta.admins.all():
                group_membership_status = 'admin'

            else:
                group_membership_status = 'member'

            group_listing[group_object.name] = {'membership': group_membership_status,
                                                'member_count': group_object.user_set.count(),
                                                'admin_count': group_object.groupmeta.admins.count(),
                                                'rule_count': YaraRule.objects.filter(owner=group_object).count()}

        return group_listing class PrivateGroupSerializer(serializers.Serializer):

    name = serializers.CharField(read_only=True)
    owner = serializers.SerializerMethodField()
    members = serializers.SerializerMethodField()

    source_required = serializers.SerializerMethodField()
    source_options = serializers.SerializerMethodField()

    category_required = serializers.SerializerMethodField()
    category_options = serializers.SerializerMethodField()

    nonprivileged_submission_status = serializers.SerializerMethodField()

    rule_count = serializers.SerializerMethodField()

    def get_owner(self, obj):
        return obj.groupmeta.owner.username

    def get_rule_count(self, obj):
        return YaraRule.objects.filter(owner=obj).count()

    def get_members(self, obj):
        member_listing = {}
        members = obj.user_set.all()

        for member_object in members:

            if obj.groupmeta.owner == member_object:
                group_membership_status = 'owner'

            elif member_object in obj.groupmeta.admins.all():
                group_membership_status = 'admin'

            else:
                group_membership_status = 'member'

            member_listing[member_object.username] = {'membership': group_membership_status}

        return member_listing

    def get_source_required(self, obj):
        return obj.groupmeta.source_required

    def get_source_options(self, obj):
        return obj.groupmeta.source_options

    def get_category_required(self, obj):
        return obj.groupmeta.category_required

    def get_category_options(self, obj):
        return obj.groupmeta.category_options

    def get_nonprivileged_submission_status(self, obj):
        return obj.groupmeta.nonprivileged_submission_status class GroupMeta(models.Model):
    group = models.OneToOneField(Group, on_delete=models.CASCADE, primary_key=True)
    owner = models.ForeignKey(User, related_name="group_owner", on_delete=models.CASCADE)
    admins = models.ManyToManyField(User)

    source_required = models.BooleanField(default=True)
    source_options = ArrayField(models.CharField(max_length=75), default=list)

    category_required = models.BooleanField(default=True)
    category_options = ArrayField(models.CharField(max_length=75), default=list)

    nonprivileged_submission_status = models.CharField(max_length=75,
                                                       choices=YaraRule.STATUS_CHOICES,
                                                       default=YaraRule.PENDING_STATUS)

    def save(self, *args, **kwargs):
        self.source_options = list(set(self.source_options))
        self.category_options = list(set(self.category_options))

        super(GroupMeta, self).save(*args, **kwargs)
import re
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.generics import ListAPIView, RetrieveAPIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from .services import get_group_or_404
from .REST_permissions import (group_member,
                               IsGroupOwner,
                               IsGroupAdmin,
                               IsGroupAdminOrMemberReadOnly,
                               IsGroupOwnerOrPublicReadOnly)
from .REST_serializers import (PublicGroupSerializer,
                               GroupMetaUpdateSerializer,
                               PrivateUserSerializer,
                               PrivateGroupSerializer)
from .patterns import group_name_pattern
from .models import GroupMeta
        for member in new_members:
            member.groups.add(group_object)

        return Response(group_object.user_set.all().values_list('username', flat=True))

    def delete(self, request, group_name):
        group_object = get_group_or_404(group_name)
        group_owner_name = group_object.groupmeta.owner.username

        # Gather user objects for processing
        member_name_list = request.query_params.getlist('member')
        removed_members = User.objects.filter(username__in=member_name_list)

        # Remove from group
        for member in removed_members.exclude(username=group_owner_name):
            group_object.groupmeta.admins.remove(member)
            member.groups.remove(group_object)

        return Response(group_object.user_set.all().values_list('username', flat=True))


class GroupAdminsView(APIView):
    """
    get:
    List group admins.

    patch:
    Add new specified group admins.

    delete:
    Remove specified admins from group.
    """
    permission_classes = [IsGroupOwner]

    def get(self, request, group_name):
        group_object = get_group_or_404(group_name)
        return Response(group_object.groupmeta.admins.all().values_list('username', flat=True))

    def patch(self, request, group_name):
        group_object = get_group_or_404(group_name)
        group_owner_name = group_object.groupmeta.owner.username

        # Gather the submitted admin name list
        try:
            new_admin_names = request.data.getlist('admin')
        except AttributeError:
            new_admin_names = request.data.get('admin', list())

        if not isinstance(new_admin_names, list):
            new_admin_names = [new_admin_names]

        # Ensure group owner doesn't get inadvertently processed
        if group_owner_name in new_admin_names:
            new_admin_names = list(set(new_admin_names))
            new_admin_names.remove(group_owner_name)

        # Gather user objects for processing
        new_admin_users = User.objects.filter(username__in=new_admin_names)

        # Add admins
        for admin in new_admin_users:
            admin.groups.add(group_object)
            group_object.groupmeta.admins.add(admin)

        return Response(group_object.groupmeta.admins.all().values_list('username', flat=True))

    def delete(self, request, group_name):
        group_object = get_group_or_404(group_name)
        admin_name_list = request.query_params.getlist('admin')

        # Gather user objects for processing
        removed_admins = User.objects.filter(username__in=admin_name_list)

        # Remove from group
        for admin in removed_admins:
            group_object.groupmeta.admins.remove(admin)

        return Response(group_object.groupmeta.admins.all().values_list('username', flat=True))


class GroupSourcesView(APIView):
    """
    get:
    List group sources.

    patch:
    Add new specified group sources.

    delete:
    Remove specified sources from group.
    """
    permission_classes = [IsGroupAdminOrMemberReadOnly]

    def get(self, request, group_name):
        group_object = get_group_or_404(group_name)
        group_metadata = group_object.groupmeta
        return Response(group_metadata.source_options)

    def patch(self, request, group_name):
        group_object = get_group_or_404(group_name)
        group_metadata = group_object.groupmeta

        # Gather the submitted source list
        try:
            new_sources = request.data.getlist('source')
        except AttributeError:
            new_sources = request.data.get('source', list())

        if not isinstance(new_sources, list):
            new_sources = [new_sources]

        for source in new_sources:
            if source not in group_metadata.source_options:
                group_metadata.source_options.append(source)

        group_metadata.save()

        return Response(group_metadata.source_options)

    def delete(self, request, group_name):

        group_object = get_group_or_404(group_name)