Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor store and add RoomState #34

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

SirSanctified
Copy link
Owner

@SirSanctified SirSanctified commented Mar 13, 2024

This pull request refactors the store and adds a new RoomState to manage the state of the room form. It also includes various file changes related to the refactoring and addition of the RoomState.

Summary by CodeRabbit

  • New Features
    • Introduced the ability to add rooms to properties, enhancing property management for landlords.
    • Added a new image input component with preview functionality for a better user experience in uploading and managing images.
    • Implemented a confirmation dialog for deleting items, ensuring a safer user interaction.
    • New customizable textarea input component for forms or text input areas.
  • Enhancements
    • Improved the visual layout and interaction in the property details section by restructuring HTML elements.
    • Updated room card component with new icons and a delete confirmation feature based on user authentication and ownership.
  • Refactor
    • Added and modified RoomState in the store for better state management of room information.
  • Documentation, Style, Tests, Chores, Revert
    • Minor backend adjustments for better data handling and representation.

@SirSanctified SirSanctified linked an issue Mar 13, 2024 that may be closed by this pull request
21 tasks
Copy link
Contributor

coderabbitai bot commented Mar 13, 2024

Walkthrough

The updates introduce enhancements across the client and backend, focusing on property and room management. Notable changes include adding image configuration in Next.js, improving room display and addition functionalities, introducing components for image input with preview, room details form, and delete confirmation dialog. Backend adjustments refine serialization and view handling, streamlining data representation and operations like creation and updating. These changes aim to enrich user experience and data interaction within the application.

Changes

Files Summary
client/next.config.js Added configuration for images with remote patterns.
client/src/app/(dashboard)/.../[propertyId]/page.tsx
client/src/app/(dashboard)/.../[propertyId]/rooms-add/page.tsx
Enhanced room management and added functionality to add rooms.
client/src/components/shared/imagesInputWithPreview.tsx
client/src/components/ui/textarea.tsx
Introduced components for image input with preview and customizable textarea.
client/src/components/shared/properties/roomCard.tsx
client/src/components/shared/properties/roomForm.tsx
client/src/components/properties/updateRoomDialog.tsx
Updated room display and interaction, added room addition and update functionalities.
client/src/components/shared/deleteConfirmition.tsx Added a delete confirmation component.
client/src/store/store.ts Enhanced state management with RoomState and related functions.
backend/core/serializers.py
backend/core/views.py
Backend adjustments for improved data handling and representation.

🐰✨

In the realm of code, where changes abound,
A rabbit hopped, leaving footprints profound.
With each leap and bound, new features found,
Enhancing the experience, all around.
"To rooms and images," it did astound,
A digital warren, in bytes and sound.
🌟🐾

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@SirSanctified SirSanctified self-assigned this Mar 13, 2024
@SirSanctified SirSanctified added the enhancement New feature or request label Mar 13, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 5357d3f and 06f75a4.
Files selected for processing (9)
  • client/next.config.js (1 hunks)
  • client/src/app/(dashboard)/profile/[id]/landlords/properties/[propertyId]/page.tsx (1 hunks)
  • client/src/app/(dashboard)/profile/[id]/landlords/properties/[propertyId]/rooms-add/page.tsx (1 hunks)
  • client/src/components/shared/imagesInputWithPreview.tsx (1 hunks)
  • client/src/components/shared/properties/roomCard.tsx (1 hunks)
  • client/src/components/shared/properties/roomForm.tsx (1 hunks)
  • client/src/components/ui/textarea.tsx (1 hunks)
  • client/src/store/store.ts (2 hunks)
  • client/src/types/index.ts (4 hunks)
Check Runs (2)
Analyze (javascript-typescript) completed (1)
Check Formating completed (2)
Additional comments: 10
client/src/app/(dashboard)/profile/[id]/landlords/properties/[propertyId]/rooms-add/page.tsx (1)
  • 1-15: The implementation of the AddRoomPage component looks good. It correctly imports and utilizes the RoomForm component, passing the propertyId and action type as props. Ensure that the RoomForm component is adequately designed to handle the 'Add' action and that the propertyId is utilized as intended within the form.
client/next.config.js (1)
  • 8-17: The addition of remotePatterns in the Next.js configuration for handling images from specific domains is correctly implemented. Ensure that the protocol and hostname (http and localhost) are appropriate for your application's environments. For production, consider using https to enhance security.
client/src/components/ui/textarea.tsx (1)
  • 1-24: The implementation of the Textarea component is well-structured and makes good use of React's forwardRef and props spreading. Ensure that the cn utility function used for className concatenation is thoroughly tested and reliable for various use cases.
client/src/components/shared/imagesInputWithPreview.tsx (1)
  • 1-50: The ImageFileInput component is well-implemented, supporting multiple file selections and providing a clear button for input reset. Ensure that the component behaves as expected in edge cases, such as when a user selects files but then cancels the operation.
client/src/app/(dashboard)/profile/[id]/landlords/properties/[propertyId]/page.tsx (1)
  • 38-49: The modifications to the PropertyDetails component enhance the room management section by providing a structured and interactive way to add new rooms. Ensure that the link's href is correctly formed and that the Button component is accessible to all users.
client/src/components/shared/properties/roomCard.tsx (1)
  • 14-14: The update to use curly braces for the src attribute value assignment in the Image component is a good practice in JSX, enhancing code readability and consistency.
client/src/types/index.ts (1)
  • 153-170: > 📝 NOTE

This review was outside the diff hunks and was mapped to the diff hunk with the greatest overlap. Original lines [90-170]

The additions and modifications to type definitions, including the RoomType enum, changes to the Room type, and the introduction of RoomFormProps and RoomState, enhance type safety and clarity for room management features. Ensure that these new types are consistently used throughout the application and cover all necessary use cases.

client/src/store/store.ts (1)
  • 92-125: The addition of RoomState using Zustand for room state management is well-implemented, providing a structured way to manage room-related data globally. Ensure that the initial state and state management functions align with the application's requirements and handle edge cases appropriately.
client/src/components/shared/properties/roomForm.tsx (2)
  • 1-1: Using "use client"; is a good practice for Next.js 13+ components that are intended to run only on the client side. This ensures that the component will not be accidentally rendered on the server, improving performance and avoiding potential issues.
  • 2-21: The imports are well-organized and follow a logical structure, starting with React-related imports, followed by component imports, type imports, and finally utility and external library imports. This organization enhances readability and maintainability.

client/src/components/shared/properties/roomForm.tsx Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 06f75a4 and 1910e28.
Files selected for processing (5)
  • client/src/components/shared/deleteConfirmition.tsx (1 hunks)
  • client/src/components/shared/properties/roomCard.tsx (1 hunks)
  • client/src/components/shared/properties/roomForm.tsx (1 hunks)
  • client/src/components/ui/textarea.tsx (1 hunks)
  • client/src/types/index.ts (5 hunks)
Files skipped from review as they are similar to previous changes (4)
  • client/src/components/shared/properties/roomCard.tsx
  • client/src/components/shared/properties/roomForm.tsx
  • client/src/components/ui/textarea.tsx
  • client/src/types/index.ts
Additional comments: 4
client/src/components/shared/deleteConfirmition.tsx (4)
  • 1-1: Using the "use client"; directive is a good practice for ensuring this module runs only in the client-side environment. This can help avoid unintended server-side rendering issues.
  • 18-26: The component's props are well-defined, ensuring clarity in what is expected to be passed to DeleteConfirmition. However, consider adding a brief comment describing the component's purpose and its props for better maintainability and readability.
  • 43-61: The structure of the AlertDialog component is clear and follows a logical flow. However, consider adding accessibility attributes such as aria-label or aria-labelledby to improve accessibility for screen reader users.
  • 64-64: Correctly exporting the DeleteConfirmition component as the default export. This follows common practice for React components.

Comment on lines 27 to 40
async function action() {
try {
await axios.delete(actionUrl, {
withCredentials: true,
});
toast.success("Successfully deleted");
window.location.reload();
} catch (error) {
alert(JSON.stringify(error));
const message =
(error as AxiosErrorWithDetails)?.response?.data?.detail ??
"Cannot delete, something went wrong";
toast(`Failed to delete: ${message}`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The action function correctly handles the delete operation and provides feedback to the user. However, there are a few areas for improvement:

  1. Directly using window.location.reload() for updating the UI after a successful delete operation can be inefficient and may lead to a poor user experience. Consider using state management or context to reflect changes without reloading the page.
  2. The error handling could be improved by using toast.error instead of toast for displaying error messages, to make it consistent with the success message which uses toast.success.
  3. Using alert(JSON.stringify(error)); for error debugging is not user-friendly. It's better to remove or replace it with a more subtle logging mechanism.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 1910e28 and 69fd20d.
Files selected for processing (3)
  • client/src/components/properties/updateRoomDialog.tsx (1 hunks)
  • client/src/components/shared/properties/roomCard.tsx (1 hunks)
  • client/src/components/shared/properties/roomForm.tsx (1 hunks)
Files skipped from review as they are similar to previous changes (2)
  • client/src/components/shared/properties/roomCard.tsx
  • client/src/components/shared/properties/roomForm.tsx
Additional comments: 1
client/src/components/properties/updateRoomDialog.tsx (1)
  • 1-3: The import statements are clear and follow best practices by separating external and internal imports. The usage of type import for Room is also a good practice for performance.

Comment on lines +5 to +28
const UpdateRoomDialog = ({
trigger,
roomData,
property,
}: {
trigger: React.ReactNode;
roomData: Room;
property: string;
}) => {
return (
<Dialog>
<DialogTrigger asChild>{trigger}</DialogTrigger>
<DialogContent>
<RoomForm
action="Update"
roomData={roomData}
property={property.split("/").at(-1) ?? ""}
/>
</DialogContent>
</Dialog>
);
};

export default UpdateRoomDialog;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UpdateRoomDialog component is well-structured and utilizes destructuring for props, which enhances readability. However, there are a few areas for improvement:

  1. Prop Types: It's a good practice to define prop types outside of the component function signature for better readability and maintainability. Consider using interface or type for prop definitions.
  2. Property Splitting: The operation property.split("/").at(-1) ?? "" directly within the JSX can be considered a bit complex for inline expressions. It might be more readable to perform this operation outside the return statement and store the result in a variable.

Consider defining prop types using interface or type and refactor the property splitting logic for better readability.

+ interface UpdateRoomDialogProps {
+   trigger: React.ReactNode;
+   roomData: Room;
+   property: string;
+ }
+
- const UpdateRoomDialog = ({
+ const UpdateRoomDialog: React.FC<UpdateRoomDialogProps> = ({
    trigger,
    roomData,
    property,
  }) => {
+   const propertyName = property.split("/").at(-1) ?? "";
    return (
      <Dialog>
        <DialogTrigger asChild>{trigger}</DialogTrigger>
        <DialogContent>
          <RoomForm
            action="Update"
            roomData={roomData}
-           property={property.split("/").at(-1) ?? ""}
+           property={propertyName}
          />
        </DialogContent>
      </Dialog>
    );
  };

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
const UpdateRoomDialog = ({
trigger,
roomData,
property,
}: {
trigger: React.ReactNode;
roomData: Room;
property: string;
}) => {
return (
<Dialog>
<DialogTrigger asChild>{trigger}</DialogTrigger>
<DialogContent>
<RoomForm
action="Update"
roomData={roomData}
property={property.split("/").at(-1) ?? ""}
/>
</DialogContent>
</Dialog>
);
};
export default UpdateRoomDialog;
interface UpdateRoomDialogProps {
trigger: React.ReactNode;
roomData: Room;
property: string;
}
const UpdateRoomDialog: React.FC<UpdateRoomDialogProps> = ({
trigger,
roomData,
property,
}) => {
const propertyName = property.split("/").at(-1) ?? "";
return (
<Dialog>
<DialogTrigger asChild>{trigger}</DialogTrigger>
<DialogContent>
<RoomForm
action="Update"
roomData={roomData}
property={propertyName}
/>
</DialogContent>
</Dialog>
);
};
export default UpdateRoomDialog;

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 69fd20d and 184a589.
Files selected for processing (1)
  • client/src/components/shared/deleteConfirmition.tsx (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • client/src/components/shared/deleteConfirmition.tsx

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 184a589 and 74aa892.
Files selected for processing (2)
  • client/src/store/store.ts (2 hunks)
  • client/src/types/index.ts (4 hunks)
Files skipped from review as they are similar to previous changes (2)
  • client/src/store/store.ts
  • client/src/types/index.ts

else:
error_detail = str(e)
return Response(
{"detail": error_detail}, status=status.HTTP_400_BAD_REQUEST

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.
)
except ValidationError as e:
return Response(
{"detail": str(e).strip("['").strip("']")},

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 2

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 74aa892 and 3a8b9e5.
Files selected for processing (2)
  • backend/core/serializers.py (11 hunks)
  • backend/core/views.py (11 hunks)
Check Runs (1)
CodeQL success (2)
  • backend/core/views.py: 131-131: Stack trace information flows to this location and may be exposed to an external user.
  • backend/core/views.py: 689-689: Stack trace information flows to this location and may be exposed to an external user.
Additional comments: 12
backend/core/serializers.py (8)
  • 6-6: The import of UserSerializer from accounts.serializers is a good addition, ensuring that user-related data can be serialized within other serializers where needed.
  • 44-44: Adding depth = 1 to the Meta class of serializers is beneficial for fetching related objects up to one level deep automatically. This enhances the API response with more detailed information without additional queries, improving the user experience.
  • 58-61: The to_representation method in StudentSerializer is well-implemented. It customizes the representation of the Student model to include serialized user data, which is crucial for front-end applications to display comprehensive student information.
  • 112-115: Similarly, the to_representation method in LandlordSerializer is correctly implemented, ensuring that user data is included in the serialized landlord data. This consistency across serializers is commendable.
  • 163-166: The addition of the to_representation method in BookingSerializer to include owner data is a thoughtful enhancement. It ensures that booking information is accompanied by detailed owner information, which is essential for managing bookings effectively.
  • 236-241: The to_representation method in RoomSerializer is correctly implemented to include property data. This is particularly useful for scenarios where room details need to be displayed along with property information, enhancing data richness.
  • 272-282: The to_representation method in PropertySerializer is comprehensive, including owner, reviews, amenities, and city data. This method significantly enriches the property data presented to the end-user, facilitating a better understanding of property details.
  • 315-318: The to_representation method in ReviewSerializer includes owner data, which is crucial for displaying reviews with information about the reviewer. This addition enhances the transparency and credibility of reviews.
backend/core/views.py (4)
  • 7-8: The addition of imports for DjangoFilterBackend and SearchFilter is a positive change, indicating an enhancement in filtering capabilities for the API endpoints. These tools provide powerful filtering options, improving the API's usability.
  • 37-37: Including RoomImage in the list of models is necessary for the changes made in the RoomViewSet, specifically for handling image data associated with rooms. This ensures that all relevant models are accessible within the viewsets.
  • 213-214: The update to filter_backends and filterset_fields in PropertyViewSet enhances the filtering capabilities, allowing users to filter properties by city name, owner ID, and amenities name. This is a significant improvement in the API's functionality.
  • 586-593: Similarly, the update to filter_backends and filterset_fields in RoomViewSet improves the API's usability by enabling more granular filtering options for rooms. This allows users to find rooms that match their specific criteria more efficiently.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Status

Actionable comments generated: 4

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 3a8b9e5 and 1422306.
Files selected for processing (1)
  • backend/core/views.py (11 hunks)
Check Runs (1)
CodeQL success (2)
  • backend/core/views.py: 131-131: Stack trace information flows to this location and may be exposed to an external user.
  • backend/core/views.py: 690-690: Stack trace information flows to this location and may be exposed to an external user.
Additional comments: 5
backend/core/views.py (5)
  • 7-8: The addition of DjangoFilterBackend and SearchFilter imports is a good practice for enhancing filtering capabilities in viewsets. Ensure that these filters are properly configured and tested for each applicable viewset.
  • 37-37: Adding RoomImage to the list of models is crucial for supporting image management in rooms. Ensure that the RoomImage model is properly integrated with the Room model and that image handling (upload, storage, retrieval) is secure and efficient.
  • 213-214: The configuration of filter_backends and filterset_fields in PropertyViewSet enhances the filtering capabilities, making it easier for users to find properties based on specific criteria. Ensure that these filters are thoroughly tested for accuracy and performance.
  • 404-409: The get_queryset method in BookingViewSet is a good addition for filtering bookings based on the user's role (student or landlord). This enhances the user experience by showing relevant bookings. Ensure that this method is properly tested, especially for edge cases where a user might have both roles.
  • 586-601: The configuration of filter_backends and filterset_fields in RoomViewSet is a positive change for improving room search functionality. It's important to ensure that these filters work as expected and do not impact the performance negatively.

Comment on lines +52 to +86
def create(self, request, *args, **kwargs):
if request.user.is_student:
return Response(
{"detail": "You can not create a student account."},
status=status.HTTP_403_FORBIDDEN,
)
if request.user.is_landlord:
return Response(
{"detail": "You can not create a student account as a landlord."},
status=status.HTTP_403_FORBIDDEN,
)
try:
with transaction.atomic():
institution = Institution.objects.get( # pylint: disable=no-member
pk=request.data.pop("institution")
)
student = Student.objects.create( # pylint: disable=no-member
user=request.user, institution=institution, **request.data
)
request.user.is_student = True
request.user.save()
return Response(
StudentSerializer(student, context={"request": request}).data,
status=status.HTTP_201_CREATED,
)
except ValidationError:
return Response(
{"detail": "Institution does not exist."},
status=status.HTTP_404_NOT_FOUND,
)
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,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The create method in StudentViewSet has been significantly modified to include checks for user roles and to handle student creation with atomic transactions. This approach ensures data integrity and provides clear responses for unauthorized actions. However, consider handling the broad exception more gracefully to avoid exposing stack trace information to the end user.

-                e.args[0].detail if hasattr(e.args[0], "detail") else e.args[0],
+                {"detail": "An error occurred during student creation."}

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def create(self, request, *args, **kwargs):
if request.user.is_student:
return Response(
{"detail": "You can not create a student account."},
status=status.HTTP_403_FORBIDDEN,
)
if request.user.is_landlord:
return Response(
{"detail": "You can not create a student account as a landlord."},
status=status.HTTP_403_FORBIDDEN,
)
try:
with transaction.atomic():
institution = Institution.objects.get( # pylint: disable=no-member
pk=request.data.pop("institution")
)
student = Student.objects.create( # pylint: disable=no-member
user=request.user, institution=institution, **request.data
)
request.user.is_student = True
request.user.save()
return Response(
StudentSerializer(student, context={"request": request}).data,
status=status.HTTP_201_CREATED,
)
except ValidationError:
return Response(
{"detail": "Institution does not exist."},
status=status.HTTP_404_NOT_FOUND,
)
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,
)
def create(self, request, *args, **kwargs):
if request.user.is_student:
return Response(
{"detail": "You can not create a student account."},
status=status.HTTP_403_FORBIDDEN,
)
if request.user.is_landlord:
return Response(
{"detail": "You can not create a student account as a landlord."},
status=status.HTTP_403_FORBIDDEN,
)
try:
with transaction.atomic():
institution = Institution.objects.get( # pylint: disable=no-member
pk=request.data.pop("institution")
)
student = Student.objects.create( # pylint: disable=no-member
user=request.user, institution=institution, **request.data
)
request.user.is_student = True
request.user.save()
return Response(
StudentSerializer(student, context={"request": request}).data,
status=status.HTTP_201_CREATED,
)
except ValidationError:
return Response(
{"detail": "Institution does not exist."},
status=status.HTTP_404_NOT_FOUND,
)
except Exception as e: # pylint: disable=broad-except
return Response(
{"detail": "An error occurred during student creation."}
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)

Comment on lines +98 to +132
def create(self, request, *args, **kwargs):
if request.user.is_student:
return Response(
{"detail": "You can not create a landlord account as a student."},
status=status.HTTP_403_FORBIDDEN,
)
if request.user.is_landlord:
return Response(
{"detail": "You can not create another landlord account."},
status=status.HTTP_403_FORBIDDEN,
)
try:
with transaction.atomic():
city = City.objects.get( # pylint: disable=no-member
pk=request.data.pop("city")
)
landlord = Landlord.objects.create( # pylint: disable=no-member
user=request.user, city=city, **request.data
)
request.user.is_landlord = True
request.user.save()
return Response(
LandlordSerializer(landlord, context={"request": request}).data,
status=status.HTTP_201_CREATED,
)
except ValidationError as e:
if isinstance(e.error_list, list) and e.error_list:
error_detail = {
field: errors[0] for field, errors in e.error_list[0].params.items()
}
else:
error_detail = str(e)
return Response(
{"detail": error_detail}, status=status.HTTP_400_BAD_REQUEST
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The create method in LandlordViewSet includes role checks and atomic transactions for landlord creation, similar to the StudentViewSet. The detailed error handling for ValidationError is commendable. However, ensure that the broad exception handling is refined to prevent potential information exposure.

-                {"detail": error_detail}, status=status.HTTP_400_BAD_REQUEST
+                {"detail": "An error occurred during landlord creation."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def create(self, request, *args, **kwargs):
if request.user.is_student:
return Response(
{"detail": "You can not create a landlord account as a student."},
status=status.HTTP_403_FORBIDDEN,
)
if request.user.is_landlord:
return Response(
{"detail": "You can not create another landlord account."},
status=status.HTTP_403_FORBIDDEN,
)
try:
with transaction.atomic():
city = City.objects.get( # pylint: disable=no-member
pk=request.data.pop("city")
)
landlord = Landlord.objects.create( # pylint: disable=no-member
user=request.user, city=city, **request.data
)
request.user.is_landlord = True
request.user.save()
return Response(
LandlordSerializer(landlord, context={"request": request}).data,
status=status.HTTP_201_CREATED,
)
except ValidationError as e:
if isinstance(e.error_list, list) and e.error_list:
error_detail = {
field: errors[0] for field, errors in e.error_list[0].params.items()
}
else:
error_detail = str(e)
return Response(
{"detail": error_detail}, status=status.HTTP_400_BAD_REQUEST
)
def create(self, request, *args, **kwargs):
if request.user.is_student:
return Response(
{"detail": "You can not create a landlord account as a student."},
status=status.HTTP_403_FORBIDDEN,
)
if request.user.is_landlord:
return Response(
{"detail": "You can not create another landlord account."},
status=status.HTTP_403_FORBIDDEN,
)
try:
with transaction.atomic():
city = City.objects.get( # pylint: disable=no-member
pk=request.data.pop("city")
)
landlord = Landlord.objects.create( # pylint: disable=no-member
user=request.user, city=city, **request.data
)
request.user.is_landlord = True
request.user.save()
return Response(
LandlordSerializer(landlord, context={"request": request}).data,
status=status.HTTP_201_CREATED,
)
except ValidationError as e:
if isinstance(e.error_list, list) and e.error_list:
error_detail = {
field: errors[0] for field, errors in e.error_list[0].params.items()
}
else:
error_detail = str(e)
return Response(
{"detail": "An error occurred during landlord creation."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR
)

Comment on lines +242 to +255
with transaction.atomic():
city = City.objects.get( # pylint: disable=no-member
pk=request.data.pop("city")
)
amenities = request.data.pop("amenities")
property_ = Property.objects.create( # pylint: disable=no-member
owner=landlord, city=city, **request.data
)
property_.amenities.set(amenities)
property_.save()
return Response(
PropertySerializer(property_, context={"request": request}).data,
status=status.HTTP_201_CREATED,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The create method in PropertyViewSet uses atomic transactions for property creation, which is a good practice for ensuring data integrity. However, consider validating the existence of city and amenities before attempting to create the property to avoid unnecessary database transactions in case of invalid data.

Comment on lines +657 to +697
@transaction.atomic
def update(self, request, *args, **kwargs):
instance = self.get_object()
if request.user != instance.property.owner:
return Response(
{"detail": "You can only update rooms that you own."},
status=status.HTTP_403_FORBIDDEN,
)
try:
instance.name = request.data.get("name", instance.name)
instance.num_beds = request.data.get("num_beds", instance.num_beds)
instance.price = request.data.get("price", instance.price)
instance.room_type = request.data.get("room_type", instance.room_type)
instance.available_beds = request.data.get(
"available_beds", instance.available_beds
)
instance.is_available = request.data.get(
"is_available", instance.is_available
)
instance.occupied_beds = request.data.get(
"occupied_beds", instance.occupied_beds
)
instance.display_image = request.data.get(
"display_image", instance.display_image
)
instance.description = request.data.get("description", instance.description)
instance.save()
return Response(
RoomSerializer(instance, context={"request": request}).data,
status=status.HTTP_200_OK,
)
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,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The update method in RoomViewSet has been enhanced to allow room updates only by the property owner, which is a crucial security measure. However, the broad exception handling could potentially expose stack trace information to the end user. It's recommended to refine the error handling to provide a more generic error message.

-                e.args[0].detail if hasattr(e.args[0], "detail") else e.args[0],
+                {"detail": "An error occurred during room update."}

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
@transaction.atomic
def update(self, request, *args, **kwargs):
instance = self.get_object()
if request.user != instance.property.owner:
return Response(
{"detail": "You can only update rooms that you own."},
status=status.HTTP_403_FORBIDDEN,
)
try:
instance.name = request.data.get("name", instance.name)
instance.num_beds = request.data.get("num_beds", instance.num_beds)
instance.price = request.data.get("price", instance.price)
instance.room_type = request.data.get("room_type", instance.room_type)
instance.available_beds = request.data.get(
"available_beds", instance.available_beds
)
instance.is_available = request.data.get(
"is_available", instance.is_available
)
instance.occupied_beds = request.data.get(
"occupied_beds", instance.occupied_beds
)
instance.display_image = request.data.get(
"display_image", instance.display_image
)
instance.description = request.data.get("description", instance.description)
instance.save()
return Response(
RoomSerializer(instance, context={"request": request}).data,
status=status.HTTP_200_OK,
)
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,
)
@transaction.atomic
def update(self, request, *args, **kwargs):
instance = self.get_object()
if request.user != instance.property.owner:
return Response(
{"detail": "You can only update rooms that you own."},
status=status.HTTP_403_FORBIDDEN,
)
try:
instance.name = request.data.get("name", instance.name)
instance.num_beds = request.data.get("num_beds", instance.num_beds)
instance.price = request.data.get("price", instance.price)
instance.room_type = request.data.get("room_type", instance.room_type)
instance.available_beds = request.data.get(
"available_beds", instance.available_beds
)
instance.is_available = request.data.get(
"is_available", instance.is_available
)
instance.occupied_beds = request.data.get(
"occupied_beds", instance.occupied_beds
)
instance.display_image = request.data.get(
"display_image", instance.display_image
)
instance.description = request.data.get("description", instance.description)
instance.save()
return Response(
RoomSerializer(instance, context={"request": request}).data,
status=status.HTTP_200_OK,
)
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(
{"detail": "An error occurred during room update."},
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Room Creation (Frontend)
1 participant