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({})