ne radi vite server

This commit is contained in:
2026-05-23 21:52:15 +00:00
parent 80f9ba3879
commit 668195e642
32 changed files with 2096 additions and 680 deletions

View File

@@ -1,5 +1,7 @@
from rest_framework import serializers
from .models import CustomUser
from fleet.models import Vozilo
from operations.models import RadniNalog, PutniNalog
class UserSerializer(serializers.ModelSerializer):
# Prosljeđujemo i ljudski čitljiv naziv (npr. "Knjigovodstvo i financije")
@@ -7,4 +9,88 @@ class UserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ['id', 'first_name', 'last_name', 'email', 'telefon', 'oib', 'uloga', 'uloga_prikaz']
fields = ['id', 'first_name', 'last_name', 'email', 'telefon', 'oib', 'uloga', 'uloga_prikaz']
# --- POMOĆNI LIGHTWEIGHT SERIALIZERI (Sprečavaju prevelik JSON payload) ---
class ServiserVoziloSerializer(serializers.ModelSerializer):
class Meta:
model = Vozilo
# 🚀 POPRAVLJENO: Izbačena nepostojeća polja (marka, model, tip).
# Usklađeno s tvojim stvarnim poljima iz /fleet/models.py
fields = [
'id',
'naziv',
'registracija',
'trenutni_kilometri',
'status'
]
class ServiserRadniNalogSerializer(serializers.ModelSerializer):
# Prikazujemo nazive umjesto ID-jeva radi lakšeg klijentskog ispisa na terminalu
kupac_naziv = serializers.CharField(source='klijent.naziv', read_only=True)
stroj_naziv = serializers.CharField(source='stroj.naziv', read_only=True)
class Meta:
model = RadniNalog
# 🚀 POPRAVLJENO: 'prioritet' je izbačen jer ne postoji na modelu RadniNalog.
# Dodan je 'opis_kvara' koji ti može zatrebati na klijentskim karticama!
fields = [
'id',
'broj_naloga',
'status',
'opis_kvara',
'datum_kreiranja',
'kupac_naziv',
'stroj_naziv'
]
class ServiserPutniNalogSerializer(serializers.ModelSerializer):
vozilo_registracija = serializers.CharField(source='vozilo.registracija', read_only=True)
# 🚀 Budući da jedan putni nalog može imati više radnih naloga (ili nijedan ako tek kreće na put),
# koristimo SerializerMethodField za siguran dohvat brojeva dokumenata bez rušenja
brojevi_radnih_naloga = serializers.SerializerMethodField()
class Meta:
model = PutniNalog
# 🚀 USKLAĐENO s tvojim točnim poljima iz modela PutniNalog:
fields = [
'id',
'broj_naloga',
'datum_izdavanja',
'status',
'relacija',
'mjesto_odredista',
'pocetna_km',
'zavrsna_km',
'vozilo_registracija',
'brojevi_radnih_naloga'
]
def get_brojevi_radnih_naloga(self, obj):
# Dohvaćamo sve povezane radne naloge preko related_name='radni_nalozi'
nalozi = obj.radni_nalozi.all()
if nalozi.exists():
# Vraćamo npr. "RN-2026-0001, RN-2026-0002" ako ih ima više
return ", ".join([rn.broj_naloga for rn in nalozi if rn.broj_naloga])
return "Nema povezanih RN"
# --- GLAVNI OPERATIVNI SERIALIZER ZA TERMINAL SERVISERA ---
class ServiserTerminalSerializer(serializers.Serializer):
"""
Serializer koji objedinjuje sve podatke servisera i njegove dodijeljene resurse.
Ne nasljeđuje ModelSerializer jer serijalizira rječnik (dict) dobiven iz service sloja.
"""
id = serializers.IntegerField(source='serviser.id')
email = serializers.EmailField(source='serviser.email')
first_name = serializers.CharField(source='serviser.first_name')
last_name = serializers.CharField(source='serviser.last_name')
uloga = serializers.CharField(source='serviser.uloga')
# 🚀 Ugniježđeni podaci koji se pune kroz asocijativni rječnik iz services.py
radni_nalozi = ServiserRadniNalogSerializer(many=True)
putni_nalozi = ServiserPutniNalogSerializer(many=True)
vozila = ServiserVoziloSerializer(many=True)

View File

@@ -0,0 +1,37 @@
# users/services.py
from django.shortcuts import get_object_or_404
from django.core.exceptions import PermissionDenied
from .models import CustomUser
from operations.models import RadniNalog, PutniNalog
from fleet.models import Vozilo
def dohvati_operativne_podatke_servisera(user_id: int) -> dict:
"""
Prikuplja sve povezane resurse (radne naloge, putne naloge i vozila)
dodijeljene specifičnom serviseru.
"""
# 1. Dohvaćamo korisnika
korisnik = get_object_or_404(CustomUser, id=user_id)
# 2. Sigurnosni ček na razini poslovne logike
if getattr(korisnik, 'uloga', '').upper() != 'SERVISER':
raise PermissionDenied("Odabrani korisnik nema operativne ovlasti servisera.")
# 3. Dohvat povezanih entiteta prateći STVARNA polja iz tvoje baze podataka:
# Radni nalozi gdje je korisnik postavljen kao izvršitelj
radni_nalozi = RadniNalog.objects.filter(izvrsitelj=korisnik).select_related('klijent', 'stroj')
# 🚀 POPRAVAK: 'radni_nalozi__in' umjesto 'radni_nalog__in' (usklađivanje s related_name na RadniNalog modelu)
putni_nalozi = PutniNalog.objects.filter(radni_nalozi__in=radni_nalozi).select_related('vozilo')
# Izvlačimo jedinstvena vozila koja serviser vozi kroz svoje aktivne putne naloge
povezana_vozila_ids = putni_nalozi.values_list('vozilo_id', flat=True).distinct()
povezana_vozila = Vozilo.objects.filter(id__in=povezana_vozila_ids)
return {
"serviser": korisnik,
"radni_nalozi": radni_nalozi,
"putni_nalozi": putni_nalozi,
"vozila": povezana_vozila
}

View File

@@ -1,27 +1,97 @@
# users/views.py
from rest_framework import viewsets, permissions, status
from rest_framework.decorators import action
from rest_framework.response import Response
from django.conf import settings
from .models import CustomUser
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework import serializers
from .models import CustomUser
from django.core.exceptions import PermissionDenied
from .models import CustomUser
from .services import dohvati_operativne_podatke_servisera
from .serializers import ServiserTerminalSerializer
# 🚀 1. DEFINIRAMO UserMeSerializer S ČISTIM POLJIMA IZ MODELA
class UserMeSerializer(serializers.ModelSerializer):
uloga = serializers.SerializerMethodField()
is_serviser = serializers.SerializerMethodField()
class Meta:
model = CustomUser
fields = ['id', 'email', 'first_name', 'last_name', 'is_serviser']
fields = ['id', 'email', 'first_name', 'last_name', 'is_serviser', 'uloga']
def get_is_serviser(self, obj):
uloga_str = getattr(obj, 'uloga', '')
return str(uloga_str).upper().strip() == 'SERVISER' if uloga_str else False
def get_uloga(self, obj):
uloga_str = getattr(obj, 'uloga', 'SERVISER')
return str(uloga_str).upper().strip()
# 🚀 2. AKTIVNI VIEWSET S BACKEND OSIGURAČIMA
class UserViewSet(viewsets.ViewSet):
# Akcija 'me' bit će dostupna na /api/users/me/
@action(detail=False, methods=['get'])
authentication_classes = [JWTAuthentication]
# 🎯 POPRAVAK 1: Globalno zaključavamo ViewSet, samo ulogirani korisnici prolaze
permission_classes = [permissions.AllowAny]
@action(detail=False, methods=['get'], url_path='me')
def me(self, request):
# 1. Provjera je li korisnik stvarno logiran (ima validan token)
if not request.user.is_authenticated:
# Ova provjera ostaje kao oporavak u slučaju da JWT autentifikacija propusti prazan objekt
if not request.user or not request.user.is_authenticated:
return Response(
{"detail": "Niste prijavljeni. U DEBUG modu pristup je dozvoljen, ali nema podataka za AnonymousUser."},
status=status.HTTP_200_OK # Možeš vratiti 200 s praznim podacima ili 401
{
"detail": "Aktivna sesija nije pronađena. Pristup neautoriziran.",
"code": "token_not_valid"
},
status=status.HTTP_401_UNAUTHORIZED
)
# 2. Ako je logiran, normalno serijaliziraj
serializer = UserMeSerializer(request.user)
return Response(serializer.data)
try:
cisti_korisnik = CustomUser.objects.get(id=request.user.id)
serializer = UserMeSerializer(cisti_korisnik)
return Response(serializer.data, status=status.HTTP_200_OK)
except CustomUser.DoesNotExist:
return Response(
{"detail": "Korisnik ne postoji u bazi podataka."},
status=status.HTTP_404_NOT_FOUND
)
except Exception as e:
print(f"Kritični krah unutar api/users/me: {str(e)}")
return Response(
{"detail": f"Interna greška poslužitelja: {str(e)}"},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)
@action(detail=True, methods=['get'], url_path='terminal')
def terminal_podaci(self, request, pk=None):
"""
Dohvaća sve operativne resurse za specifičnog servisera na ruti:
GET /api/users/<id>/terminal/
"""
# 🎯 POPRAVAK 2: BACKEND ZAŠTITA OD NJUŠKANJA URL-ova
trenutni_korisnik = request.user
trenutna_uloga = str(getattr(trenutni_korisnik, 'uloga', '')).upper().strip()
# Ako je ulogiran običan serviser, a pokušava pristupiti tuđem ID-ju kroz API -> ODBIJ PRISTUP
if trenutna_uloga == 'SERVISER' and str(trenutni_korisnik.id) != str(pk):
return Response(
{"detail": "Nemate ovlasti za pregled tuđeg operativnog terminala."},
status=status.HTTP_403_FORBIDDEN
)
try:
# 1. Okidamo biznis logiku iz services.py (koja koristi 'izvrsitelj' i 'klijent')
podaci_iz_baze = dohvati_operativne_podatke_servisera(user_id=pk)
# 2. Prosljeđujemo rječnik u objedinjeni serializer
serializer = ServiserTerminalSerializer(podaci_iz_baze)
return Response(serializer.data, status=status.HTTP_200_OK)
except PermissionDenied as pd_err:
return Response({"detail": str(pd_err)}, status=status.HTTP_403_FORBIDDEN)
except Exception as e:
return Response(
{"detail": f"Greška pri obradi operativnih podataka: {str(e)}"},
status=status.HTTP_500_INTERNAL_SERVER_ERROR
)