Site admin interface
parent
fcaa4855e8
commit
15d92664f9
|
@ -29,13 +29,17 @@ class AuthViewSet(viewsets.ViewSet):
|
|||
def _create_response(self, user):
|
||||
serializer = UserSerializer(user)
|
||||
response_data = serializer.data
|
||||
|
||||
domain = get_active_domain()
|
||||
response_data['is_site_owner'] = domain.user_is_owner(user)
|
||||
response_data['is_site_staff'] = domain.user_is_staff(user)
|
||||
response_data["auth_token"] = auth.get_token_for_user(user)
|
||||
return response_data
|
||||
|
||||
def _create_domain_member(self, user):
|
||||
domain = get_active_domain()
|
||||
|
||||
if DomainMember.objects.filter(domain=domain, user=user).count() == 0:
|
||||
if domain.members.filter(user=user).count() == 0:
|
||||
domain_member = DomainMember(domain=domain, user=user, email=user.email,
|
||||
is_owner=False, is_staff=False)
|
||||
domain_member.save()
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import Domain
|
||||
from .models import Domain, DomainMember
|
||||
|
||||
class DomainMemberInline(admin.TabularInline):
|
||||
model = DomainMember
|
||||
|
||||
class DomainAdmin(admin.ModelAdmin):
|
||||
list_display = ('domain', 'name')
|
||||
search_fields = ('domain', 'name')
|
||||
inlines = [ DomainMemberInline, ]
|
||||
|
||||
admin.site.register(Domain, DomainAdmin)
|
||||
|
|
|
@ -2,13 +2,38 @@
|
|||
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.permissions import AllowAny, IsAuthenticated
|
||||
|
||||
from .serializers import DomainSerializer
|
||||
from django.http import Http404
|
||||
|
||||
from greenmine.base.api import ModelCrudViewSet, UpdateModelMixin
|
||||
from .serializers import DomainSerializer, DomainMemberSerializer
|
||||
from .permissions import DomainMembersPermission, DomainPermission
|
||||
from .models import DomainMember, Domain
|
||||
|
||||
|
||||
class DomainViewSet(viewsets.ViewSet):
|
||||
permission_classes = (AllowAny,)
|
||||
class DomainViewSet(UpdateModelMixin, viewsets.GenericViewSet):
|
||||
permission_classes = (IsAuthenticated, DomainPermission,)
|
||||
serializer_class = DomainSerializer
|
||||
queryset = Domain.objects.all()
|
||||
|
||||
def list(self, request, **kwargs):
|
||||
return Response(DomainSerializer(request.domain).data)
|
||||
domain_data = DomainSerializer(request.domain).data
|
||||
if request.domain.user_is_normal_user(request.user):
|
||||
domain_data['projects'] = None
|
||||
elif request.user.is_anonymous():
|
||||
domain_data['projects'] = None
|
||||
return Response(domain_data)
|
||||
|
||||
def update(self, request, **kwargs):
|
||||
raise Http404
|
||||
|
||||
def create(self, request, **kwargs):
|
||||
self.kwargs['pk'] = request.domain.pk
|
||||
return super().update(request, pk=request.domain.pk, **kwargs)
|
||||
|
||||
|
||||
class DomainMembersViewSet(ModelCrudViewSet):
|
||||
permission_classes = (IsAuthenticated, DomainMembersPermission,)
|
||||
serializer_class = DomainMemberSerializer
|
||||
queryset = DomainMember.objects.all()
|
||||
|
|
|
@ -45,9 +45,18 @@ class Domain(models.Model):
|
|||
def __str__(self):
|
||||
return self.domain
|
||||
|
||||
def user_is_owner(self, user):
|
||||
return self.members.filter(id=user.id, is_owner=True).count() > 0
|
||||
|
||||
def user_is_staff(self, user):
|
||||
return self.members.filter(id=user.id, is_staff=True).count() > 0
|
||||
|
||||
def user_is_normal_user(self, user):
|
||||
return self.members.filter(id=user.id, is_owner=False, is_staff=False).count() > 0
|
||||
|
||||
|
||||
class DomainMember(models.Model):
|
||||
domain = models.ForeignKey("Domain", related_name="+", null=True)
|
||||
domain = models.ForeignKey("Domain", related_name="members", null=True)
|
||||
user = models.ForeignKey("users.User", related_name="+", null=True)
|
||||
|
||||
email = models.EmailField(max_length=255)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
from rest_framework import permissions
|
||||
|
||||
from greenmine.base.domains.models import DomainMember
|
||||
from greenmine.base.domains import get_active_domain
|
||||
|
||||
|
||||
class DomainPermission(permissions.BasePermission):
|
||||
safe_methods = ['HEAD', 'OPTIONS', 'GET']
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
if request.method in self.safe_methods:
|
||||
return True
|
||||
|
||||
domain = get_active_domain()
|
||||
return domain.user_is_owner(request.user)
|
||||
|
||||
|
||||
class DomainMembersPermission(permissions.BasePermission):
|
||||
safe_methods = ['HEAD', 'OPTIONS']
|
||||
|
||||
def has_permission(self, request, view):
|
||||
if request.method in self.safe_methods:
|
||||
return True
|
||||
|
||||
domain = get_active_domain()
|
||||
if request.method in ["POST", "PUT", "PATCH", "GET"]:
|
||||
return domain.user_is_owner(request.user)
|
||||
else:
|
||||
return False
|
|
@ -1,10 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from rest_framework import serializers
|
||||
from .models import Domain
|
||||
from .models import Domain, DomainMember
|
||||
from greenmine.base.users.serializers import UserSerializer
|
||||
|
||||
|
||||
class DomainSerializer(serializers.ModelSerializer):
|
||||
projects = serializers.SerializerMethodField('get_projects')
|
||||
|
||||
class Meta:
|
||||
model = Domain
|
||||
fields = ('public_register', 'default_language')
|
||||
fields = ('public_register', 'default_language', "projects")
|
||||
|
||||
def get_projects(self, obj):
|
||||
return map(lambda x: {"id": x.id, "name": x.name }, obj.projects.all().order_by('name'))
|
||||
|
||||
|
||||
class DomainMemberSerializer(serializers.ModelSerializer):
|
||||
user = UserSerializer()
|
||||
class Meta:
|
||||
model = DomainMember
|
||||
|
|
|
@ -16,6 +16,7 @@ from djmail.template_mail import MagicMailBuilder
|
|||
from greenmine.base import filters
|
||||
from greenmine.base import exceptions as exc
|
||||
from greenmine.base.api import ModelCrudViewSet, ModelListViewSet, RetrieveModelMixin
|
||||
from greenmine.base.domains import get_active_domain
|
||||
from greenmine.base.notifications.api import NotificationSenderMixin
|
||||
from greenmine.projects.aggregates.tags import get_all_tags
|
||||
|
||||
|
@ -27,6 +28,29 @@ from .aggregates import stats
|
|||
from .aggregates import filters as filters_aggr
|
||||
|
||||
|
||||
class ProjectAdminViewSet(ModelCrudViewSet):
|
||||
model = models.Project
|
||||
serializer_class = serializers.ProjectDetailSerializer
|
||||
list_serializer_class = serializers.ProjectSerializer
|
||||
permission_classes = (IsAuthenticated, permissions.ProjectAdminPermission)
|
||||
|
||||
def get_queryset(self):
|
||||
domain = get_active_domain()
|
||||
return domain.projects.all()
|
||||
|
||||
def pre_save(self, obj):
|
||||
obj.owner = self.request.user
|
||||
|
||||
# FIXME
|
||||
|
||||
# Assign domain only if it current
|
||||
# value is None
|
||||
if not obj.domain:
|
||||
obj.domain = self.request.domain
|
||||
|
||||
super().pre_save(obj)
|
||||
|
||||
|
||||
class ProjectViewSet(ModelCrudViewSet):
|
||||
model = models.Project
|
||||
serializer_class = serializers.ProjectDetailSerializer
|
||||
|
|
|
@ -1,17 +1,41 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from greenmine.base.permissions import BasePermission
|
||||
from greenmine.base.domains import get_active_domain
|
||||
|
||||
|
||||
class ProjectPermission(BasePermission):
|
||||
get_permission = "view_project"
|
||||
post_permission = "add_project"
|
||||
post_permission = None
|
||||
put_permission = "change_project"
|
||||
patch_permission = "change_project"
|
||||
delete_permission = "delete_project"
|
||||
delete_permission = None
|
||||
safe_methods = ["HEAD", "OPTIONS"]
|
||||
path_to_project = []
|
||||
|
||||
class ProjectAdminPermission(BasePermission):
|
||||
def has_permission(self, request, view):
|
||||
if request.method in self.safe_methods:
|
||||
return True
|
||||
|
||||
domain = get_active_domain()
|
||||
if request.method in ["POST", "PUT", "GET", "PATCH"]:
|
||||
return domain.user_is_staff(request.user)
|
||||
elif request.method == "DELETE":
|
||||
return domain.user_is_owner(request.user)
|
||||
return super().has_permission(request, view)
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
if request.method in self.safe_methods:
|
||||
return True
|
||||
|
||||
domain = get_active_domain()
|
||||
if request.method in ["POST", "PUT", "GET", "PATCH"]:
|
||||
return domain.user_is_staff(request.user)
|
||||
elif request.method == "DELETE":
|
||||
return domain.user_is_owner(request.user)
|
||||
return super().has_object_permission(request, view, obj)
|
||||
|
||||
|
||||
class MembershipPermission(BasePermission):
|
||||
get_permission = "view_membership"
|
||||
|
|
|
@ -418,8 +418,8 @@ class ProjectsTestCase(test.TestCase):
|
|||
password=self.user3.username)
|
||||
self.assertTrue(response)
|
||||
response = self.client.delete(reverse("projects-detail", args=(self.project1.id,)))
|
||||
self.assertEqual(response.status_code, 204)
|
||||
self.assertEqual(Project.objects.all().count(), 3)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(Project.objects.all().count(), 4)
|
||||
self.client.logout()
|
||||
|
||||
def test_delete_project_by_not_membership(self):
|
||||
|
|
|
@ -4,11 +4,11 @@ from greenmine.base import routers
|
|||
from greenmine.base.auth.api import AuthViewSet
|
||||
from greenmine.base.users.api import RolesViewSet, UsersViewSet
|
||||
from greenmine.base.searches.api import SearchViewSet
|
||||
from greenmine.base.domains.api import DomainViewSet
|
||||
from greenmine.base.domains.api import DomainViewSet, DomainMembersViewSet
|
||||
from greenmine.projects.api import (ProjectViewSet, MembershipViewSet, InvitationViewSet,
|
||||
UserStoryStatusViewSet, PointsViewSet, TaskStatusViewSet,
|
||||
IssueStatusViewSet, IssueTypeViewSet, PriorityViewSet,
|
||||
SeverityViewSet) #, QuestionStatusViewSet)
|
||||
SeverityViewSet, ProjectAdminViewSet) #, QuestionStatusViewSet)
|
||||
from greenmine.projects.milestones.api import MilestoneViewSet
|
||||
from greenmine.projects.userstories.api import UserStoryViewSet, UserStoryAttachmentViewSet
|
||||
from greenmine.projects.tasks.api import TaskViewSet, TaskAttachmentViewSet
|
||||
|
@ -30,6 +30,8 @@ router.register(r"search", SearchViewSet, base_name="search")
|
|||
|
||||
# greenmine.base.domains
|
||||
router.register(r"sites", DomainViewSet, base_name="sites")
|
||||
router.register(r"site-members", DomainMembersViewSet, base_name="site-members")
|
||||
router.register(r"site-projects", ProjectAdminViewSet, base_name="site-projects")
|
||||
|
||||
# greenmine.projects
|
||||
router.register(r"projects", ProjectViewSet, base_name="projects")
|
||||
|
|
Loading…
Reference in New Issue