Skip to content

Commit

Permalink
Merge pull request #17 from SirSanctified/15-implement-landlord-verif…
Browse files Browse the repository at this point in the history
…ication

Add email notifications for landlord account status changes and booking confirmations
  • Loading branch information
SirSanctified committed Mar 11, 2024
2 parents 091057f + ae3a0e9 commit 3bb1700
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 32 deletions.
21 changes: 6 additions & 15 deletions backend/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ class Meta:
verbose_name_plural = "Rooms"
verbose_name = "Room"
ordering = ["-created_at"]
unique_together = (("property", "name"),)

ROOM_TYPES = [
("single", "Single"),
Expand Down Expand Up @@ -222,7 +223,6 @@ class Meta:
null=False,
blank=False,
default=0,
validators=[MinValueValidator(1)],
)
is_available = models.BooleanField(default=True)
display_image = models.ImageField(
Expand All @@ -235,6 +235,7 @@ class Meta:
updated_at = models.DateTimeField(auto_now=True)

def save(self, *args, **kwargs):
self.clean()
if not self.pk and self.occupied_beds == 0:
self.available_beds = self.num_beds
else:
Expand All @@ -252,29 +253,19 @@ def clean(self):
"""
if self.occupied_beds > self.num_beds:
raise ValidationError(
{
"occupied_beds": "Occupied beds cannot exceed the total number of beds."
}
"Occupied beds cannot exceed the total number of beds."
)
if self.available_beds > self.num_beds:
raise ValidationError(
{
"available_beds": "Available beds cannot exceed the total number of beds."
}
"Available beds cannot exceed the total number of beds."
)
if self.available_beds + self.occupied_beds > self.num_beds:
raise ValidationError(
{
"available_beds": "Available and occupied beds (sum) cannot exceed the \
total number of beds."
}
"Available and occupied beds (sum) cannot exceed the total number of beds."
)
if self.occupied_beds + self.available_beds != self.num_beds:
raise ValidationError(
{
"occupied_beds": "Occupied and available beds (sum) must equal the total \
number of beds."
}
"Occupied and available beds (sum) must equal the total number of beds."
)

def __str__(self):
Expand Down
26 changes: 21 additions & 5 deletions backend/core/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from django.utils import timezone
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from .models import (
Student,
Landlord,
Expand Down Expand Up @@ -280,12 +281,27 @@ class Meta:

def create(self, validated_data):
images_data = validated_data.pop("images", [])
room = Room.objects.create(**validated_data) # pylint: disable=no-member
for image_data in images_data:
RoomImage.objects.create( # pylint: disable=no-member
room=room, **image_data
property_ = validated_data.pop("property")
name = validated_data.pop("name")
if Room.objects.filter( # pylint: disable=no-member
property=property_, name=name
).exists():
raise serializers.ValidationError(
"Room with same name already exists in this property"
)
return room
try:
room = Room.objects.create( # pylint: disable=no-member
property=property_, name=name, **validated_data
)
for image_data in images_data:
RoomImage.objects.create( # pylint: disable=no-member
room=room, **image_data
)
return room
except ValidationError as e:
raise serializers.ValidationError(str(e.detail))
except Exception as e: # pylint: disable=broad-except
raise e

def update(self, instance, validated_data):
instance.property = validated_data.get("property", instance.property)
Expand Down
87 changes: 78 additions & 9 deletions backend/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,59 @@ def update(self, request, *args, **kwargs):
if request.user.is_staff:
if request.data["status"] == "banned":
landlord.ban()
sendmail.delay(
subject="Landlord Account Banned",
recipient_list=[landlord.user.email],
message=f"""
Dear {landlord.user.first_name},
Your landlord account has been banned. You won't be able to \
publish rooms and properties anymore. If you think this was \
an error, please contact us.
Best regards,
Roomio Team
""",
)
return Response(
{"detail": "Landlord account has been banned."},
status=status.HTTP_200_OK,
)
if request.data["status"] == "active":
landlord.activate()
sendmail.delay(
subject="Landlord Account Activated",
recipient_list=[landlord.user.email],
message=f"""
Dear {landlord.user.first_name},
Your landlord account has been activated. You can now publish \
rooms and properties.
Best regards,
Roomio Team
""",
)
return Response(
{"detail": "Landlord account has been activated."},
status=status.HTTP_200_OK,
)
if request.data["status"] == "suspended":
landlord.suspend()
sendmail.delay(
subject="Landlord Account Suspended",
recipient_list=[landlord.user.email],
message=f"""
Dear {landlord.user.first_name},
Your landlord account has been suspended. You won't be able to \
publish rooms and properties until the suspension is lifted. If you think this was \
an error, please contact us.
Best regards,
Roomio Team
""",
)
return Response(
{"detail": "Landlord account has been suspended."},
status=status.HTTP_200_OK,
Expand Down Expand Up @@ -106,6 +147,11 @@ class PropertyViewSet(ModelViewSet):
serializer_class = PropertySerializer

def create(self, request, *args, **kwargs):
if not request.user.is_landlord:
return Response(
{"detail": "Only landlord can create property."},
status=status.HTTP_403_FORBIDDEN,
)
try:
landlord = Landlord.objects.get( # pylint: disable=no-member
user=request.user
Expand Down Expand Up @@ -273,15 +319,15 @@ def create(self, request, *args, **kwargs):
room.is_available = False
room.clean()
room.save()
sendmail(
sendmail.delay(
subject="Booking Confirmation",
recipient_list=[request.user.email],
message=f"Your booking has been confirmed for {room.name} at \
{room.property.name} on {booking.start_date} to {booking.end_date}. \
The property is located at {room.property.location}, {room.property.street}, \
{room.property.number}. Thank you for using our service.",
)
sendmail(
sendmail.delay(
subject="Booking Confirmation",
recipient_list=[room.property.owner.email],
message=f"Your room ({room.name} at {room.property.name}) has been booked from \
Expand Down Expand Up @@ -334,12 +380,12 @@ def destroy(self, request, *args, **kwargs):
room.save()
instance.status = "cancelled"
instance.save()
sendmail(
sendmail.delay(
subject="Booking Cancelled",
recipient_list=[instance.owner.email],
message=f"Your booking for {room.name} at {room.property.name} has been cancelled.",
)
sendmail(
sendmail.delay(
subject="Booking Cancelled",
recipient_list=[room.property.owner.email],
message=f"Your room ({room.name} at {room.property.name}) has been cancelled.",
Expand Down Expand Up @@ -384,13 +430,13 @@ def update(self, request, *args, **kwargs):
room.save()
instance.status = data["status"]
instance.save()
sendmail(
sendmail.delay(
subject="Booking Status",
recipient_list=[instance.owner.email],
message=f"Your booking for {room.name} at {room.property.name} \
has been {data['status'].title()}.",
)
sendmail(
sendmail.delay(
subject="Booking Status",
recipient_list=[room.property.owner.email],
message=f"Your room ({room.name} at {room.property.name}) \
Expand Down Expand Up @@ -460,6 +506,16 @@ def create(self, request, *args, **kwargs):
{"detail": "Landlord does not exist."},
status=status.HTTP_404_NOT_FOUND,
)
except ValidationError as e:
return Response(
{"detail": str(e).strip("['").strip("']")},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e: # pylint: disable=broad-except
return Response(
e.args[0].detail if hasattr(e.args[0], "detail") else e.args[0],
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)


class LandlordVerificationRequestViewSet(ModelViewSet):
Expand Down Expand Up @@ -519,7 +575,7 @@ def create(self, request, *args, **kwargs):
)
)
request_.save()
sendmail(
sendmail.delay(
subject="Verification Request",
recipient_list=[request.user.email],
message=f"""
Expand Down Expand Up @@ -560,9 +616,15 @@ def update(self, request, *args, **kwargs):
instance = self.get_object()
try:
if request.data["status"] == "approved":
if instance.status == "approved":
return Response(
{"detail": "Verification request already approved."},
status=status.HTTP_400_BAD_REQUEST,
)
instance.verify()
instance.landlord.is_verified = True
sendmail(
instance.landlord.save()
sendmail.delay(
subject="Verification Request",
recipient_list=[instance.landlord.user.email],
message=f"""
Expand All @@ -581,8 +643,15 @@ def update(self, request, *args, **kwargs):
status=status.HTTP_200_OK,
)
elif request.data["status"] == "rejected":
if instance.status == "rejected":
return Response(
{"detail": "Verification request already rejected."},
status=status.HTTP_400_BAD_REQUEST,
)
instance.reject()
sendmail(
instance.landlord.is_verified = False
instance.landlord.save()
sendmail.delay(
subject="Verification Request",
recipient_list=[instance.landlord.user.email],
message=f"""
Expand Down
8 changes: 5 additions & 3 deletions backend/utils/sendmail.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import os
from django.core.mail import send_mail
from celery import shared_task


@shared_task
def sendmail(subject, message, recipient_list):
"""Sends an email to the specified recipient list."""
from_email = (os.getenv("DEFAULT_FROM_EMAIL"),)
auth_password = (os.getenv("EMAIL_HOST_PASSWORD"),)
auth_user = (os.getenv("EMAIL_HOST_USER"),)
from_email = os.getenv("DEFAULT_FROM_EMAIL")
auth_password = os.getenv("EMAIL_HOST_PASSWORD")
auth_user = os.getenv("EMAIL_HOST_USER")
send_mail(
subject,
message,
Expand Down

0 comments on commit 3bb1700

Please sign in to comment.