1+ from rest_framework import serializers
2+ from users .models import User , USER_TYPE_CHOICES
3+ from django .core .cache import cache
4+ from rest_framework .validators import UniqueValidator
5+ from django .contrib .auth import authenticate
6+ from django .core .mail import send_mail
7+ from django .conf import settings
8+ from sensors .models import SensorData
9+ from devices .models import MCU
10+ import random
11+ import os
12+
13+
14+ class UserSerializer (serializers .ModelSerializer ):
15+ password = serializers .CharField (write_only = True , required = False )
16+ image = serializers .ImageField (required = False , allow_null = True )
17+ device_id = serializers .CharField (required = False , allow_blank = True )
18+
19+ class Meta :
20+ model = User
21+ fields = [
22+ "id" , "username" , "first_name" , "last_name" , "phone_number" , "email" ,
23+ "password" , "user_type" , "image" , "date_joined" , "device_id"
24+ ]
25+ read_only_fields = ["id" , "date_joined" ]
26+
27+ def validate (self , attrs ):
28+ user_type = attrs .get ('user_type' )
29+ device_id = attrs .get ('device_id' )
30+
31+
32+ if user_type == 'Farmer' and (not device_id or device_id .strip () == '' ):
33+ raise serializers .ValidationError ({
34+ 'device_id' : 'This field is required for Farmer users.'
35+ })
36+
37+ if device_id and not MCU .objects .filter (device_id = device_id ).exists ():
38+ raise serializers .ValidationError ({
39+ 'device_id' : f"The device ID '{ device_id } ' does not exist."
40+ })
41+
42+ return attrs
43+
44+ def create (self , validated_data ):
45+ device_id_str = validated_data .pop ('device_id' , None )
46+ if device_id_str :
47+ validated_data ['device_id' ] = MCU .objects .get (device_id = device_id_str )
48+ else :
49+ validated_data ['device_id' ] = None
50+
51+ password = validated_data .pop ("password" , None )
52+ user = User (** validated_data )
53+ if password :
54+ user .set_password (password )
55+ user .save ()
56+
57+ if user .user_type == 'Farmer' and user .email :
58+ set_password_base = os .getenv ('SET_PASSWORD_LINK' )
59+ if not set_password_base :
60+ raise Exception ('SET_PASSWORD_LINK environment variable is not set.' )
61+ set_password_link = set_password_base + user .email
62+ send_mail (
63+ subject = 'Welcome to Kukukonnect - Set Your Password' ,
64+ message = (
65+ f'Welcome to Kukukonnect!\n '
66+ f'Set your password: { set_password_link } \n '
67+ ),
68+ from_email = settings .DEFAULT_FROM_EMAIL ,
69+ recipient_list = [user .email ],
70+ fail_silently = True
71+ )
72+ return user
73+
74+
75+ class SignupSerializer (serializers .ModelSerializer ):
76+ username = serializers .CharField (
77+ validators = [UniqueValidator (queryset = User .objects .all (), message = "Username already taken." )]
78+ )
79+ password = serializers .CharField (
80+ write_only = True ,
81+ min_length = 8 ,
82+ style = {'input_type' : 'password' },
83+ required = False
84+ )
85+ phone_number = serializers .CharField (
86+ validators = [UniqueValidator (queryset = User .objects .all (), message = "Phone number already registered." )]
87+ )
88+ email = serializers .EmailField (
89+ validators = [UniqueValidator (queryset = User .objects .all (), message = "Email already registered." )]
90+ )
91+ device_id = serializers .CharField (
92+ required = False ,
93+ allow_blank = True ,
94+ )
95+
96+ class Meta :
97+ model = User
98+ fields = [
99+ "id" , "username" , "first_name" , "last_name" , "phone_number" , "email" ,
100+ "password" , "user_type" , "image" , "date_joined" , "device_id"
101+ ]
102+ read_only_fields = ["id" , "date_joined" ]
103+
104+ def validate (self , attrs ):
105+ user_type = attrs .get ('user_type' )
106+ device_id = attrs .get ('device_id' )
107+
108+ if user_type == 'Farmer' and (not device_id or device_id .strip () == '' ):
109+ raise serializers .ValidationError ({
110+ 'device_id' : 'This field is required for Farmer users.'
111+ })
112+
113+ if device_id and not MCU .objects .filter (device_id = device_id ).exists ():
114+ raise serializers .ValidationError ({
115+ 'device_id' : f"The device ID '{ device_id } ' does not exist."
116+ })
117+
118+ return attrs
119+
120+ def create (self , validated_data ):
121+ device_id_str = validated_data .pop ('device_id' , None )
122+ if device_id_str :
123+ validated_data ['device_id' ] = MCU .objects .get (device_id = device_id_str )
124+ else :
125+ validated_data ['device_id' ] = None
126+
127+ password = validated_data .pop ("password" , None )
128+ user = User (** validated_data )
129+ if user .user_type == "Agrovet" :
130+ if not password :
131+ raise serializers .ValidationError ({"password" : "Password is required for Agrovets." })
132+ user .set_password (password )
133+ else :
134+ user .set_unusable_password ()
135+ user .save ()
136+
137+ if user .user_type == 'Farmer' and user .email :
138+ set_password_base = os .getenv ('SET_PASSWORD_LINK' )
139+ if not set_password_base :
140+ raise Exception ('SET_PASSWORD_LINK environment variable is not set.' )
141+ set_password_link = set_password_base + user .email
142+ from django .conf import settings
143+ send_mail (
144+ subject = 'Welcome to Kukukonnect - Set Your Password' ,
145+ message = (
146+ f'Welcome to Kukukonnect { user .username } !\n '
147+ f'Set your password: { set_password_link } \n '
148+ ),
149+ from_email = settings .DEFAULT_FROM_EMAIL ,
150+ recipient_list = [user .email ],
151+ fail_silently = False
152+ )
153+ return user
154+
155+ class LoginSerializer (serializers .Serializer ):
156+ email = serializers .EmailField ()
157+ password = serializers .CharField (write_only = True )
158+ def validate (self , data ):
159+ user = authenticate (username = data ["email" ], password = data ["password" ])
160+ if not user :
161+ raise serializers .ValidationError ("Invalid credentials." )
162+ if not user .is_active :
163+ raise serializers .ValidationError ("This account is inactive." )
164+ data ["user" ] = user
165+ return data
166+ class SetPasswordSerializer (serializers .Serializer ):
167+ email = serializers .EmailField ()
168+ password = serializers .CharField (write_only = True , min_length = 8 )
169+ confirm_password = serializers .CharField (write_only = True , min_length = 8 )
170+ def validate (self , data ):
171+ if data ["password" ] != data ["confirm_password" ]:
172+ raise serializers .ValidationError ("Passwords do not match" )
173+ try :
174+ user = User .objects .get (email = data ["email" ])
175+ except User .DoesNotExist :
176+ raise serializers .ValidationError ("User with this email does not exist." )
177+ if user .user_type != "Farmer" :
178+ raise serializers .ValidationError ("Only farmers can set their password using this endpoint." )
179+ return data
180+ def save (self , ** kwargs ):
181+ user = User .objects .get (email = self .validated_data ["email" ])
182+ user .set_password (self .validated_data ["password" ])
183+ user .save ()
184+ return user
185+ class ForgotPasswordSerializer (serializers .Serializer ):
186+ email = serializers .EmailField ()
187+ def validate_email (self , value ):
188+ try :
189+ user = User .objects .get (email = value )
190+ except User .DoesNotExist :
191+ raise serializers .ValidationError ("User with this email does not exist." )
192+ otp = random .randint (1000 , 9999 )
193+ cache .set (f"otp_{ user .id } " , otp , timeout = 600 )
194+ return value
195+ class VerifyCodeSerializer (serializers .Serializer ):
196+ email = serializers .EmailField ()
197+ otp = serializers .CharField (max_length = 4 )
198+ def validate (self , data ):
199+ try :
200+ user = User .objects .get (email = data ["email" ])
201+ except User .DoesNotExist :
202+ raise serializers .ValidationError ("Invalid email" )
203+ cached_otp = cache .get (f"otp_{ user .id } " )
204+ if not cached_otp or str (cached_otp ) != str (data ["otp" ]):
205+ raise serializers .ValidationError ("Invalid or expired OTP" )
206+ cache .set (f"otp_verified_{ user .id } " , True , timeout = 600 )
207+ return data
208+ class ResetPasswordSerializer (serializers .Serializer ):
209+ email = serializers .EmailField ()
210+ password = serializers .CharField (write_only = True , min_length = 8 )
211+ confirm_password = serializers .CharField (write_only = True , min_length = 8 )
212+ def validate (self , data ):
213+ if data ["password" ] != data ["confirm_password" ]:
214+ raise serializers .ValidationError ("Passwords do not match" )
215+ try :
216+ user = User .objects .get (email = data ["email" ])
217+ except User .DoesNotExist :
218+ raise serializers .ValidationError ("User with this email does not exist." )
219+ otp_verified = cache .get (f"otp_verified_{ user .id } " )
220+ if not otp_verified :
221+ raise serializers .ValidationError ("OTP not verified. Please verify OTP before resetting password." )
222+ return data
223+ def save (self , ** kwargs ):
224+ user = User .objects .get (email = self .validated_data ["email" ])
225+ user .set_password (self .validated_data ["password" ])
226+ user .save ()
227+ cache .delete (f"otp_{ user .id } " )
228+ cache .delete (f"otp_verified_{ user .id } " )
229+ return user
230+ class ThresholdSerializer (serializers .ModelSerializer ):
231+ class Meta :
232+ model = MCU
233+ fields = [
234+ 'device_id' ,
235+ 'temp_threshold_min' ,
236+ 'temp_threshold_max' ,
237+ 'humidity_threshold_min' ,
238+ 'humidity_threshold_max'
239+ ]
240+ extra_kwargs = {
241+ 'humidity_threshold_min' : {'required' : False , 'allow_null' : True },
242+ 'humidity_threshold_max' : {'required' : False , 'allow_null' : True }
243+ }
244+
245+ class SensorDataSerializer (serializers .ModelSerializer ):
246+ device_id = serializers .CharField (source = 'device_id.device_id' , read_only = True )
247+
248+ class Meta :
249+ model = SensorData
250+ fields = ['sensor_data_id' , 'temperature' , 'humidity' , 'timestamp' , 'device_id' ]
251+ read_only_fields = ['sensor_data_id' , 'timestamp' ]
0 commit comments