55from django .contrib .auth .mixins import PermissionRequiredMixin
66from django .db import transaction
77from django .shortcuts import get_object_or_404
8+ from django .utils .translation import gettext_lazy as _
89from rest_framework import serializers
910from rest_framework import status
1011from rest_framework import viewsets
12+ from rest_framework .exceptions import PermissionDenied
1113from rest_framework .response import Response
14+ from utilities .permissions import get_permission_for_model
15+
16+
17+ def get_device_name (device ):
18+ if device .virtual_chassis :
19+ name = f"{ device .virtual_chassis .name } :{ device .vc_position } "
20+ elif device .name :
21+ name = device .name
22+ else :
23+ name = str (device .device_type )
24+
25+ return name
1226
1327
1428class ReorderRackSerializer (serializers .Serializer ):
@@ -26,34 +40,103 @@ class SaveViewSet(PermissionRequiredMixin, viewsets.ViewSet):
2640
2741 def update (self , request , pk ):
2842 rack = get_object_or_404 (Rack , pk = pk )
43+ permission = get_permission_for_model (Device , "change" )
44+
45+ # Validate input using serializer
46+ serializer = ReorderRackSerializer (data = request .data )
47+ serializer .is_valid (raise_exception = True )
48+
2949 try :
30- serializer = ReorderRackSerializer (request .data )
31- with transaction .atomic ():
32- for device in rack .devices .all ():
33- device .position = None
34- device .clean ()
35- device .save ()
50+ changes_made = False # Flag to track if any changes were made
3651
37- for new in request .data ["front" ]:
38- device = rack .devices .filter (pk = new ["id" ]).first ()
39- device .position = decimal .Decimal (new ["y" ])
40- device .face = new ["face" ]
41- device .clean ()
42- device .save ()
52+ with transaction .atomic ():
53+ # Update devices in different categories
54+ changes_made |= self ._update_device_positions (
55+ request ,
56+ rack ,
57+ serializer .validated_data ["front" ],
58+ permission ,
59+ "front" ,
60+ )
61+ changes_made |= self ._update_device_positions (
62+ request , rack , serializer .validated_data ["rear" ], permission , "rear"
63+ )
64+ changes_made |= self ._update_device_positions (
65+ request ,
66+ rack ,
67+ serializer .validated_data ["other" ],
68+ permission ,
69+ "other" ,
70+ is_other = True ,
71+ )
4372
44- for new in request . data [ "rear" ]:
45- device = rack . devices . filter ( pk = new [ "id" ]). first ()
46- device . position = decimal . Decimal ( new [ "y" ])
47- device . face = new [ "face" ]
48- device . clean ()
49- device . save ( )
73+ # If no changes were made, return 304 or a custom response
74+ if not changes_made :
75+ return Response (
76+ { "message" : "No changes detected." },
77+ status = status . HTTP_304_NOT_MODIFIED ,
78+ )
5079
5180 return Response (
52- {"message" : "POST request received" , "data" : serializer .data },
81+ {
82+ "message" : "Devices reordered successfully" ,
83+ "data" : serializer .data ,
84+ },
5385 status = status .HTTP_201_CREATED ,
5486 )
87+ except PermissionDenied as e :
88+ return Response (
89+ {"message" : "Permission denied" , "error" : str (e )},
90+ status = status .HTTP_403_FORBIDDEN ,
91+ )
5592 except Exception as e :
5693 return Response (
5794 {"message" : "Error saving data" , "error" : str (e )},
5895 status = status .HTTP_500_INTERNAL_SERVER_ERROR ,
5996 )
97+
98+ def _update_device_positions (
99+ self , request , rack , device_data_list , permission , device_type , is_other = False
100+ ):
101+ """Helper method to update device positions based on the category."""
102+ changes_made = False # Local flag to track if changes are made
103+
104+ for device_data in device_data_list :
105+ device = rack .devices .filter (pk = device_data ["id" ]).first ()
106+ current_device = get_object_or_404 (
107+ Device .objects .restrict (request .user ), pk = device_data ["id" ]
108+ )
109+
110+ if is_other :
111+ if device .position != device_data ["y" ]:
112+ device .position = None
113+ device .face = ""
114+ self ._check_permission (request , device , permission )
115+
116+ # Save the device and mark changes as made
117+ device .clean ()
118+ device .save ()
119+ changes_made = True
120+ # Update position and face for 'front' and 'rear' devices if changed
121+ elif not is_other :
122+ if current_device .face != device_data [
123+ "face"
124+ ] or device .position != decimal .Decimal (device_data ["y" ]):
125+ device .position = decimal .Decimal (device_data ["y" ])
126+ device .face = device_data ["face" ]
127+
128+ self ._check_permission (request , device , permission )
129+
130+ # Save the device and mark changes as made
131+ device .clean ()
132+ device .save ()
133+ changes_made = True
134+
135+ return changes_made # Return whether changes were made
136+
137+ def _check_permission (self , request , device , permission ):
138+ """Helper method to check if the user has permission for the device."""
139+ if not request .user .has_perm (permission , obj = device ):
140+ raise PermissionDenied (
141+ _ (f"You do not have permissions to edit { get_device_name (device )} ." )
142+ )
0 commit comments