mirror of https://github.com/jumpserver/jumpserver
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
6.0 KiB
148 lines
6.0 KiB
import textwrap
|
|
|
|
from django.db.models import Q
|
|
from django.utils.translation import ugettext_lazy as _
|
|
from rest_framework.mixins import ListModelMixin
|
|
from rest_framework.decorators import action
|
|
from rest_framework.response import Response
|
|
|
|
from orgs.models import Organization, ROLE as ORG_ROLE
|
|
from users.models.user import User
|
|
from common.const.http import POST
|
|
from common.drf.api import JMSModelViewSet, JmsGenericViewSet
|
|
from common.permissions import IsValidUser, IsObjectOwner
|
|
from common.utils.timezone import dt_parser
|
|
from common.drf.serializers import EmptySerializer
|
|
from perms.models.asset_permission import AssetPermission, Asset
|
|
from perms.models import Action
|
|
from assets.models.user import SystemUser
|
|
from ..exceptions import (
|
|
ConfirmedAssetsChanged, ConfirmedSystemUserChanged,
|
|
TicketClosed, TicketActionAlready, NotHaveConfirmedAssets,
|
|
NotHaveConfirmedSystemUser
|
|
)
|
|
from .. import serializers
|
|
from ..models import Ticket
|
|
from ..permissions import IsAssignee
|
|
|
|
|
|
class RequestAssetPermTicketViewSet(JMSModelViewSet):
|
|
queryset = Ticket.origin_objects.filter(type=Ticket.TYPE.REQUEST_ASSET_PERM)
|
|
serializer_classes = {
|
|
'default': serializers.RequestAssetPermTicketSerializer,
|
|
'approve': EmptySerializer,
|
|
'reject': EmptySerializer,
|
|
'close': EmptySerializer,
|
|
'assignees': serializers.AssigneeSerializer,
|
|
}
|
|
permission_classes = (IsValidUser,)
|
|
filter_fields = ['status', 'title', 'action', 'user_display', 'org_id']
|
|
search_fields = ['user_display', 'title']
|
|
|
|
def _check_can_set_action(self, instance, action):
|
|
if instance.status == instance.STATUS.CLOSED:
|
|
raise TicketClosed
|
|
if instance.action == action:
|
|
action_display = instance.ACTION.get(action)
|
|
raise TicketActionAlready(detail=_('Ticket has %s') % action_display)
|
|
|
|
def _get_extra_comment(self, instance):
|
|
meta = instance.meta
|
|
ips = ', '.join(meta.get('ips', []))
|
|
confirmed_assets = ', '.join(meta.get('confirmed_assets', []))
|
|
confirmed_system_users = ', '.join(meta.get('confirmed_system_users', []))
|
|
|
|
return textwrap.dedent(f'''\
|
|
{_('IP group')}: {ips}
|
|
{_('Hostname')}: {meta.get('hostname', '')}
|
|
{_('System user')}: {meta.get('system_user', '')}
|
|
{_('Confirmed assets')}: {confirmed_assets}
|
|
{_('Confirmed system users')}: {confirmed_system_users}
|
|
''')
|
|
|
|
@action(detail=True, methods=[POST], permission_classes=[IsAssignee, IsValidUser])
|
|
def reject(self, request, *args, **kwargs):
|
|
instance = self.get_object()
|
|
action = instance.ACTION.REJECT
|
|
self._check_can_set_action(instance, action)
|
|
instance.perform_action(action, request.user, self._get_extra_comment(instance))
|
|
return Response()
|
|
|
|
@action(detail=True, methods=[POST], permission_classes=[IsAssignee, IsValidUser])
|
|
def approve(self, request, *args, **kwargs):
|
|
instance = self.get_object()
|
|
action = instance.ACTION.APPROVE
|
|
self._check_can_set_action(instance, action)
|
|
|
|
meta = instance.meta
|
|
confirmed_assets = meta.get('confirmed_assets', [])
|
|
assets = list(Asset.objects.filter(id__in=confirmed_assets))
|
|
if not assets:
|
|
raise NotHaveConfirmedAssets(detail=_('Confirm assets first'))
|
|
|
|
if len(assets) != len(confirmed_assets):
|
|
raise ConfirmedAssetsChanged(detail=_('Confirmed assets changed'))
|
|
|
|
confirmed_system_users = meta.get('confirmed_system_users', [])
|
|
if not confirmed_system_users:
|
|
raise NotHaveConfirmedSystemUser(detail=_('Confirm system-users first'))
|
|
|
|
system_users = SystemUser.objects.filter(id__in=confirmed_system_users)
|
|
if system_users is None:
|
|
raise ConfirmedSystemUserChanged(detail=_('Confirmed system-users changed'))
|
|
|
|
instance.perform_action(instance.ACTION.APPROVE,
|
|
request.user,
|
|
self._get_extra_comment(instance))
|
|
self._create_asset_permission(instance, assets, system_users)
|
|
return Response({'detail': _('Succeed')})
|
|
|
|
@action(detail=True, methods=[POST], permission_classes=[IsAssignee | IsObjectOwner])
|
|
def close(self, request, *args, **kwargs):
|
|
instance = self.get_object()
|
|
instance.status = Ticket.STATUS.CLOSED
|
|
instance.save()
|
|
return Response({'detail': _('Succeed')})
|
|
|
|
def _create_asset_permission(self, instance: Ticket, assets, system_users):
|
|
meta = instance.meta
|
|
actions = meta.get('actions', Action.CONNECT)
|
|
|
|
ap_kwargs = {
|
|
'name': _('From request ticket: {} {}').format(instance.user_display, instance.id),
|
|
'created_by': self.request.user.username,
|
|
'comment': _('{} request assets, approved by {}').format(instance.user_display,
|
|
instance.assignee_display),
|
|
'actions': actions,
|
|
}
|
|
date_start = dt_parser(meta.get('date_start'))
|
|
date_expired = dt_parser(meta.get('date_expired'))
|
|
if date_start:
|
|
ap_kwargs['date_start'] = date_start
|
|
if date_expired:
|
|
ap_kwargs['date_expired'] = date_expired
|
|
|
|
ap = AssetPermission.objects.create(**ap_kwargs)
|
|
ap.system_users.add(*system_users)
|
|
ap.assets.add(*assets)
|
|
ap.users.add(instance.user)
|
|
|
|
return ap
|
|
|
|
|
|
class AssigneeViewSet(ListModelMixin, JmsGenericViewSet):
|
|
serializer_class = serializers.AssigneeSerializer
|
|
permission_classes = (IsValidUser,)
|
|
filter_fields = ('username', 'email', 'name', 'id', 'source')
|
|
search_fields = filter_fields
|
|
|
|
def get_queryset(self):
|
|
user = self.request.user
|
|
org_id = self.request.query_params.get('org_id', Organization.DEFAULT_ID)
|
|
|
|
q = Q(role=User.ROLE.ADMIN)
|
|
if org_id != Organization.DEFAULT_ID:
|
|
q |= Q(m2m_org_members__role=ORG_ROLE.ADMIN, orgs__id=org_id, orgs__members=user)
|
|
org_admins = User.objects.filter(q).distinct()
|
|
return org_admins
|