production-taskbar / backend / taskbar / views.py
views.py
Raw
import re
from datetime import datetime
from typing import Any

from django.core.cache import cache
from django.db.models import Prefetch
from django.shortcuts import get_object_or_404
from django.utils.decorators import method_decorator
from django.utils.timezone import make_aware
from django.views.decorators.cache import cache_page
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.status import HTTP_404_NOT_FOUND, HTTP_501_NOT_IMPLEMENTED
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet

from taskbar.models import (ExclusiveProgram, Location, Program, Site,
                            UtilitySoftware, Workplace, WorkplaceType)
from taskbar.serializers import (ExclusiveProgramSerializer,
                                 LocationSerializer, WorkplaceSerializer,
                                 WorkplaceTypeFullInfoSerializer)


def get_now() -> datetime:
    return make_aware(datetime.now())


def get_location(request: Request, use_cache: bool = True) -> Any:
    ip = request.META.get("HTTP_X_FORWARDED_FOR",
                          request.META.get('REMOTE_ADDR'))
    hostname = request.query_params.get('hostname')
    if use_cache:
        key = f'{hostname}_location'
        cached_location: Location | None = cache.get(key, None)
        if cached_location:
            return cached_location

    locations = Location.objects.all()
    if (hostname):
        location = locations.filter(name=hostname[0:3]).first()
        if location:
            if use_cache: cache.set(key, location)
            return location
    elif ip:
        for loc in locations:
            pattern = re.compile(loc.ip_adresses, re.IGNORECASE)
            if pattern.match(ip):
                if use_cache: cache.set(key, loc)
                return loc
    return None


class WorkplaceTypeViewSet(ReadOnlyModelViewSet):    # type: ignore
    '''
    Viewset for getting workplace types in location
    and full workplace info by id
    '''

    queryset = WorkplaceType.objects.all()
    serializer_class = WorkplaceTypeFullInfoSerializer

    @method_decorator(cache_page(0))
    def list(self, request: Request) -> Response:    # type: ignore
        location = get_location(request)
        if location:
            serializer = LocationSerializer(location, many=False)
            result = serializer.data
            return Response(result)

        return Response({})


class WorkplaceViewSet(ModelViewSet):    # type: ignore
    '''
    Viewset for getting workplace info by hostname
    or creating new 
    '''

    queryset = Workplace.objects.all()
    serializer_class = WorkplaceSerializer

    def list(self, request: Request) -> Response:    # type: ignore
        return Response(status=HTTP_501_NOT_IMPLEMENTED)

    @method_decorator(cache_page(0))
    def retrieve(    # type: ignore
            self,
            request: Request,
            pk: str = None) -> Response:    # type: ignore

        prefetch_sources = Prefetch('sources')
        prefetch_process = Prefetch('process')
        prefetch_sub_process = Prefetch('sub_process')
        prefetch_sites = Prefetch('sites',
                                  queryset=Site.objects.filter(is_active=True))

        prefetch_wpt_programs = Prefetch(
            'workplace_type__programs',
            queryset=Program.objects.filter(is_active=True))
        prefetch_wpt_utility = Prefetch(
            'workplace_type__utility_software',
            queryset=UtilitySoftware.objects.filter(is_active=True))
        prefetch_wpt_sites = Prefetch(
            'workplace_type__sites',
            queryset=Site.objects.filter(is_active=True))
        prefetch_wp_location_utility_software = Prefetch(
            'workplace_type__location__default_utility_software',
            queryset=UtilitySoftware.objects.filter(is_active=True))
        prefetch_wp_location_sites = Prefetch(
            'workplace_type__location__default_sites',
            queryset=Site.objects.filter(is_active=True))
        prefetch_ou = Prefetch('organizationalunit_set')

        workplaces = Workplace.objects.select_related(
            'workplace_type',
            'workplace_type__location',
            'exclusive_program',
        ).filter().prefetch_related(
            prefetch_wp_location_utility_software,
            prefetch_wp_location_sites,
            prefetch_sources,
            prefetch_process,
            prefetch_sub_process,
            prefetch_sites,
            prefetch_wpt_programs,
            prefetch_wpt_utility,
            prefetch_wpt_sites,
            prefetch_ou,
        ).filter(hostname=pk)

        # workplaces = Workplace.objects.filter(hostname=pk)
        workplace = workplaces.first()
        if (workplace):
            # update used to prevent history record for excluded fields
            workplaces.update(last_seen=get_now())
            serializer = WorkplaceSerializer(workplace, many=False)
            return Response(serializer.data)
        return Response(status=HTTP_404_NOT_FOUND)

    def create(self, request: Request) -> Response:    # type: ignore
        hostname = request.data["hostname"]
        workplace_type_id = request.data["workplace_type"]
        description = ''
        exclusive_program = None

        if "description" in request.data:
            description = request.data["description"]

        if "exclusive_program" in request.data:
            exclusive_program_id = request.data["exclusive_program"]
            exclusive_program = get_object_or_404(ExclusiveProgram,
                                                  id=exclusive_program_id)

        workplace_type = get_object_or_404(WorkplaceType, id=workplace_type_id)

        workplace = Workplace(hostname=hostname,
                              workplace_type=workplace_type,
                              description=description,
                              exclusive_program=exclusive_program,
                              is_active=True,
                              last_seen=get_now())
        workplace.save()
        serializer = WorkplaceSerializer(workplace, many=False)
        return Response(serializer.data)


class ExclusiveProgramViewSet(ReadOnlyModelViewSet):    # type: ignore
    '''
    Viewset for getting exclusive for wp program (like shared executable on network)
    '''

    queryset = ExclusiveProgram.objects.all()
    serializer_class = ExclusiveProgramSerializer

    @method_decorator(cache_page(0))
    def list(self, request: Request) -> Response:    # type: ignore
        location = get_location(request)
        if location:
            queryset = ExclusiveProgram.objects.filter(location=location,
                                                       workplace__isnull=True,
                                                       is_active=True)
            serializer = ExclusiveProgramSerializer(queryset, many=True)
            result = serializer.data
            return Response(result)

        return Response({})