Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend changes for admin panel #96

Draft
wants to merge 1 commit into
base: development
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
252 changes: 224 additions & 28 deletions events/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
from rest_framework.views import get_view_name as original_get_view_name
from rest_framework.routers import APIRootView
from rest_framework.fields import DateTimeField

from django.db.models import Prefetch, Q, QuerySet
from django.contrib.auth.models import AnonymousUser

# 3rd party
from isodate import Duration, duration_isoformat, parse_duration
Expand Down Expand Up @@ -68,6 +69,7 @@
)
from events.translation import EventTranslationOptions, ImageTranslationOptions
from helevents.models import User
from helevents.api import UserSerializer
from events.renderers import DOCXRenderer
from events.signals import post_save, post_update

Expand Down Expand Up @@ -630,25 +632,9 @@ def validate_publisher(self, value):
" must be left blank or set to %(required)s or any other organization"
" the user belongs to.") %
{'given': str(value),
'required': str(self.publisher
if not self.publisher.replaced_by
else self.publisher.replaced_by)}})
if value.replaced_by:
# for replaced organizations, we automatically update to the current organization
# even if the POST uses the old id
return value.replaced_by
return value

def validate(self, data):
if 'name' in self.translated_fields:
name_exists = False
languages = [x[0] for x in settings.LANGUAGES]
for language in languages:
# null or empty strings are not allowed, they are the same as missing name!
if 'name_%s' % language in data and data['name_%s' % language]:
name_exists = True
break
else:
'required': str(self.publisher
if not self.publisher.replaced_by
else self.publisher.replaced_by)}})
# null or empty strings are not allowed, they are the same as missing name!
name_exists = 'name' in data and data['name']
if not name_exists:
Expand Down Expand Up @@ -1162,9 +1148,109 @@ class LanguageViewSet(JSONAPIViewMixin, viewsets.ReadOnlyModelViewSet):
LOCAL_TZ = pytz.timezone(settings.TIME_ZONE)


class OrganizationSerializer(LinkedEventsSerializer):
class OrganizationBaseSerializer(LinkedEventsSerializer):
view_name = 'organization-detail'

class Meta:
model = Organization
fields = '__all__'


class OrganizationCreateSerializer(OrganizationBaseSerializer):

def validate(self, data):
if Organization.objects.filter(id=str(self.request.data['id'])):
raise DRFPermissionDenied(f"Organization with id {self.request.data['id']} already exists.")

if 'parent' in data.keys():
user = self.request.user
if user and user.get_default_organization():
if user.get_default_organization().id == self.request.data['parent']:
pass
else:
raise DRFPermissionDenied('User has no rights to this organization')
else:
raise DRFPermissionDenied('User must be logged in to create organizations.')
data = super().validate(data)
return data

def connected_organizations(self, org_type, org):
internal_types = {'sub_organizations': Organization.NORMAL,
'affiliated_organizations': Organization.AFFILIATED}
if org_type in self.request.data.keys():
for conn_org_id in self.request.data[org_type]:
conn_org = Organization.objects.filter(id=str(conn_org_id), internal_type=internal_types[org_type])
if conn_org:
org.children.add(conn_org[0])

def create(self, validated_data):
org = super().create(validated_data)
self.connected_organizations('sub_organizations', org)
self.connected_organizations('affiliated_organizations', org)
return org

class Meta:
model = Organization
fields = '__all__'

class OrganizationUpdateSerializer(OrganizationBaseSerializer):
# admin_users = UserSerializer(many=True)
# regular_users = UserSerializer(many=True)

class Meta:
model = Organization
fields = [
# Organization
'internal_type',
'classification',
'name',
'founding_date',
'dissolution_date',
'parent',
'admin_users',
'private_users',
'regular_users',
'created_by',
'last_modified_by',
'replaced_by',
# DataModel
'last_modified_time',
]

def validate(self, data):
if 'parent' in data.keys():
user = self.request.user
if user and user.get_default_organization():
if user.get_default_organization().id == self.request.data['parent']:
pass
else:
raise DRFPermissionDenied('User has no rights to this organization')
else:
raise DRFPermissionDenied('User must be logged in to create organizations.')
data = super().validate(data)
return data

def connected_organizations(self, org_type, org):
internal_types = {'sub_organizations': Organization.NORMAL,
'affiliated_organizations': Organization.AFFILIATED}
if org_type in self.request.data.keys():
for conn_org_id in self.request.data[org_type]:
conn_org = Organization.objects.filter(id=str(conn_org_id), internal_type=internal_types[org_type])
if conn_org:
org.children.add(conn_org[0])

def update(self, instance, validated_data):
# admin_users = validated_data.pop('admin_users', None)
# regular_users = validated_data.pop('regular_users', None)
print(validated_data)
print(instance.__dict__)
org = super().update(instance, validated_data)
# self.connected_organizations('sub_organizations', org)
# self.connected_organizations('affiliated_organizations', org)
return org


class OrganizationListSerializer(OrganizationBaseSerializer):
parent_organization = serializers.HyperlinkedRelatedField(
queryset=Organization.objects.all(),
source='parent',
Expand All @@ -1186,6 +1272,90 @@ class OrganizationSerializer(LinkedEventsSerializer):
)
is_affiliated = serializers.SerializerMethodField()
has_regular_users = serializers.SerializerMethodField()
created_time = DateTimeField(default_timezone=pytz.UTC, required=False, allow_null=True)
last_modified_time = DateTimeField(default_timezone=pytz.UTC, required=False, allow_null=True)

class Meta:
model = Organization
fields = (
'id', 'data_source', 'origin_id',
'classification', 'name', 'founding_date',
'dissolution_date',
'parent_organization',
'sub_organizations',
'affiliated_organizations',
'created_time', 'last_modified_time', 'created_by',
'last_modified_by', 'replaced_by',
'has_regular_users',
'is_affiliated',
)

def get_is_affiliated(self, obj):
return obj.internal_type == Organization.AFFILIATED

def get_has_regular_users(self, obj):
return obj.regular_users.count() > 0


class OrganizationDetailSerializer(OrganizationListSerializer):
regular_users = serializers.SerializerMethodField()
admin_users = serializers.SerializerMethodField()

def get_regular_users(self, obj):
user = self.context['user']
if not isinstance(user, AnonymousUser) and user.is_admin(obj):
return UserSerializer(obj.regular_users.all(), read_only=True, many=True).data
else:
return ''

def get_admin_users(self, obj):
user = self.context['user']
if not isinstance(user, AnonymousUser) and user.is_admin(obj):
return UserSerializer(obj.admin_users.all(), read_only=True, many=True).data
else:
return ''

class Meta:
model = Organization
fields = (
'id', 'data_source', 'origin_id',
'classification', 'name', 'founding_date',
'dissolution_date', 'parent_organization',
'sub_organizations', 'affiliated_organizations',
'created_time', 'last_modified_time', 'created_by',
'last_modified_by', 'is_affiliated', 'replaced_by',
'has_regular_users', 'regular_users', 'admin_users'
)

class OrganizationSerializer(LinkedEventsSerializer):
view_name = 'organization-detail'

parent_organization = serializers.HyperlinkedRelatedField(
queryset=Organization.objects.all(),
source='parent',
view_name='organization-detail',
required=False,
allow_null=True,
)
sub_organizations = serializers.HyperlinkedRelatedField(
# queryset=Organization.objects.all(),
view_name='organization-detail',
many=True,
read_only=True,
)
affiliated_organizations = serializers.HyperlinkedRelatedField(
queryset=Organization.objects.all(),
view_name='organization-detail',
many=True,
)
replaced_by = serializers.HyperlinkedRelatedField(
queryset=Organization.objects.all(),
view_name='organization-detail',
required=False,
allow_null=True,
)
is_affiliated = serializers.SerializerMethodField()
has_regular_users = serializers.SerializerMethodField()
created_time = DateTimeField(
default_timezone=pytz.UTC, required=False, allow_null=True)
last_modified_time = DateTimeField(
Expand All @@ -1202,6 +1372,7 @@ class Meta:
'last_modified_by', 'is_affiliated', 'replaced_by',
'has_regular_users'
)
read_only_fields = ['origin_id']

def get_is_affiliated(self, obj):
return obj.internal_type == Organization.AFFILIATED
Expand All @@ -1210,21 +1381,46 @@ def get_has_regular_users(self, obj):
return obj.regular_users.count() > 0


class OrganizationViewSet(JSONAPIViewMixin, viewsets.ReadOnlyModelViewSet):
class OrganizationViewSet(JSONAPIViewMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
mixins.CreateModelMixin,
viewsets.GenericViewSet):
queryset = Organization.objects.all()
serializer_class = OrganizationSerializer

def get_queryset(self):
queryset = Organization.objects.all()
def get_serializer_class(self, *args, **kwargs):
if self.action == 'retrieve':
return OrganizationDetailSerializer
elif self.action == 'create':
return OrganizationCreateSerializer
elif self.action == 'update':
return OrganizationUpdateSerializer
else:
return OrganizationListSerializer

def get_queryset(self):
queryset = Organization.objects.prefetch_related('regular_users', 'admin_users')\
.prefetch_related(Prefetch('children',
queryset=Organization.objects.filter(internal_type='normal'), # noqa E501
to_attr='sub_organizations'),
Prefetch('children',
queryset=Organization.objects.filter(internal_type='affiliated'), # noqa E501
to_attr='affiliated_organizations'))
id = self.request.query_params.get('child', None)
if id:
queryset = queryset.get(id=id).get_ancestors()
try:
queryset = queryset.get(id=id).get_ancestors()
except Organization.DoesNotExist:
queryset = queryset.none()

id = self.request.query_params.get('parent', None)
if id:
queryset = queryset.get(id=id).get_descendants()

try:
queryset = queryset.get(id=id).get_descendants()
except Organization.DoesNotExist:
queryset = queryset.none()
return queryset


Expand Down
4 changes: 2 additions & 2 deletions helevents/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ def to_representation(self, obj):

class Meta:
fields = [
'last_login', 'username', 'email', 'date_joined',
'pk', 'last_login', 'username', 'email', 'date_joined',
'first_name', 'last_name', 'uuid', 'department_name',
'is_staff', 'display_name',
]
model = get_user_model()


class UserViewSet(viewsets.ReadOnlyModelViewSet):
class UserViewSet(viewsets.ModelViewSet):

def get_queryset(self):
user = self.request.user
Expand Down