1+ import logging
2+ from datetime import datetime , timedelta
3+
14from rest_framework import serializers
25
3- from coldfront .core .allocation .models import Allocation , AllocationAttribute
4- from coldfront .core .allocation .models import Project
6+ from coldfront .core .allocation .models import (
7+ Allocation ,
8+ AllocationAttribute ,
9+ AllocationStatusChoice ,
10+ AllocationAttributeType ,
11+ )
12+ from coldfront .core .allocation .models import Project , Resource
13+ from coldfront .core .allocation import signals
14+
15+
16+ logger = logging .getLogger (__name__ )
17+ logger .setLevel (logging .INFO )
518
619
720class ProjectSerializer (serializers .ModelSerializer ):
821 class Meta :
922 model = Project
1023 fields = ["id" , "title" , "pi" , "description" , "field_of_science" , "status" ]
24+ read_only_fields = ["title" , "pi" , "description" , "field_of_science" , "status" ]
1125
26+ id = serializers .IntegerField ()
1227 pi = serializers .SerializerMethodField ()
1328 field_of_science = serializers .SerializerMethodField ()
1429 status = serializers .SerializerMethodField ()
@@ -23,28 +38,97 @@ def get_status(self, obj: Project) -> str:
2338 return obj .status .name
2439
2540
41+ class AllocationAttributeSerializer (serializers .ModelSerializer ):
42+ class Meta :
43+ model = AllocationAttribute
44+ fields = ["attribute_type" , "value" ]
45+
46+ attribute_type = (
47+ serializers .SlugRelatedField ( # Peforms validation to ensure attribute exists
48+ read_only = False ,
49+ slug_field = "name" ,
50+ queryset = AllocationAttributeType .objects .all (),
51+ source = "allocation_attribute_type" ,
52+ )
53+ )
54+ value = serializers .CharField (read_only = False )
55+
56+
57+ class ResourceSerializer (serializers .ModelSerializer ):
58+ class Meta :
59+ model = Resource
60+ fields = ["id" , "name" , "resource_type" ]
61+
62+ id = serializers .IntegerField ()
63+ name = serializers .CharField (required = False )
64+ resource_type = serializers .SerializerMethodField (required = False )
65+
66+ def get_resource_type (self , obj : Resource ):
67+ return obj .resource_type .name
68+
69+
2670class AllocationSerializer (serializers .ModelSerializer ):
2771 class Meta :
2872 model = Allocation
29- fields = ["id" , "project" , "description" , "resource " , "status" , "attributes" ]
73+ fields = ["id" , "project" , "description" , "resources " , "status" , "attributes" ]
3074
31- resource = serializers . SerializerMethodField ( )
75+ resources = ResourceSerializer ( many = True )
3276 project = ProjectSerializer ()
33- attributes = serializers .SerializerMethodField ()
34- status = serializers .SerializerMethodField ()
77+ attributes = AllocationAttributeSerializer (
78+ many = True , source = "allocationattribute_set" , required = False
79+ )
80+ status = serializers .SlugRelatedField (
81+ slug_field = "name" , queryset = AllocationStatusChoice .objects .all ()
82+ )
3583
36- def get_resource (self , obj : Allocation ) -> dict :
37- resource = obj .resources .first ()
38- return {"name" : resource .name , "resource_type" : resource .resource_type .name }
84+ def create (self , validated_data ):
85+ project_obj = Project .objects .get (id = validated_data ["project" ]["id" ])
86+ resource_obj = Resource .objects .get (id = validated_data ["resources" ][0 ]["id" ])
87+ allocation = Allocation .objects .create (
88+ project = project_obj ,
89+ status = validated_data ["status" ],
90+ justification = "" ,
91+ start_date = datetime .now (),
92+ end_date = datetime .now () + timedelta (days = 365 ),
93+ )
94+ allocation .resources .add (resource_obj )
95+ allocation .save ()
3996
40- def get_attributes ( self , obj : Allocation ):
41- attrs = AllocationAttribute .objects .filter ( allocation = obj )
42- return {
43- a . allocation_attribute_type . name : obj . get_attribute (
44- a . allocation_attribute_type . name
97+ for attribute in validated_data . pop ( "allocationattribute_set" , [] ):
98+ AllocationAttribute .objects .create (
99+ allocation = allocation ,
100+ allocation_attribute_type = attribute [ "allocation_attribute_type" ],
101+ value = attribute [ "value" ],
45102 )
46- for a in attrs
47- }
48103
49- def get_status (self , obj : Allocation ) -> str :
50- return obj .status .name
104+ logger .info (
105+ f"Created allocation { allocation .id } for project { project_obj .title } "
106+ )
107+ return allocation
108+
109+ def update (self , allocation : Allocation , validated_data ):
110+ """
111+ Only allow updating allocation status for now
112+
113+ Certain status transitions will have side effects (activating/deactivating allocations)
114+ """
115+
116+ old_status = allocation .status .name
117+ new_status = validated_data .get ("status" , old_status ).name
118+
119+ allocation .status = validated_data .get ("status" , allocation .status )
120+ allocation .save ()
121+
122+ if old_status == "New" and new_status == "Active" :
123+ signals .allocation_activate .send (
124+ sender = self .__class__ , allocation_pk = allocation .pk
125+ )
126+ elif old_status == "Active" and new_status in ["Denied" , "Revoked" ]:
127+ signals .allocation_disable .send (
128+ sender = self .__class__ , allocation_pk = allocation .pk
129+ )
130+
131+ logger .info (
132+ f"Updated allocation { allocation .id } for project { allocation .project .title } "
133+ )
134+ return allocation
0 commit comments