Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8da87e8
Create & Migrate Room Model
jasonkeo Nov 22, 2025
3d429db
Add Serializer
jasonkeo Nov 22, 2025
a7d522c
rebase
jasonkeo Dec 7, 2025
805e9bd
Add more test cases
jasonkeo Dec 3, 2025
94c9cf2
Add comments to explain api
jasonkeo Dec 3, 2025
63aac92
added location + amenties table
jasonkeo Dec 3, 2025
5138bab
Fixing chatgpted test cases
jasonkeo Dec 3, 2025
40e818f
Fixing Api responses to match requirement description
jasonkeo Dec 3, 2025
541e107
fix merge errors
jasonkeo Dec 6, 2025
adc116b
more fixes
jasonkeo Dec 6, 2025
4ac62fd
added location & capicity to django admin page
jasonkeo Dec 6, 2025
4e29146
fix add model to admin
jasonkeo Dec 6, 2025
3609faa
add amenties to admin
jasonkeo Dec 6, 2025
17a7c6e
add image upload to local file
jasonkeo Dec 6, 2025
aca4760
fix api response
jasonkeo Dec 6, 2025
08e9e08
fix naming of fields from location_id to location? might cause errors?
jasonkeo Dec 6, 2025
01769cd
add status & change capicity to int
jasonkeo Dec 6, 2025
62315a0
Make test better
jasonkeo Dec 6, 2025
490d725
More fixes to test
jasonkeo Dec 6, 2025
dd19130
edit room app
ErikaKK Dec 10, 2025
f04b843
Merge branch 'main' into Add-room-app-#7
ErikaKK Dec 10, 2025
48d8380
add pagination, edit tests
ErikaKK Dec 10, 2025
eba808c
add api for crud location and amenities
ErikaKK Dec 10, 2025
97600de
edit tests
ErikaKK Dec 10, 2025
30d4054
fix url routing issue
ErikaKK Dec 10, 2025
640f538
edit model and params, add docs
ErikaKK Dec 11, 2025
de6560f
edit model and refactor a bit
ErikaKK Dec 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -297,4 +297,6 @@ pyrightconfig.json
opt/

# google api
server/api/booking/google_calendar/google_calendar_service.json
server/api/booking/google_calendar/google_calendar_service.json

server/media/
96 changes: 96 additions & 0 deletions server/api/room/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Room API Endpoints

## Authentication

- **Read (GET):** Anyone can list or retrieve rooms.
- **Write (POST, PATCH, PUT):** Only authenticated users can create or update rooms.
- **Delete:** Not allowed (returns 405).

---

## List Rooms

**GET** `/api/rooms/`

### Query Parameters (all optional):

- `name`: Filter rooms by name (case-insensitive, partial match).
- `location`: Filter by location name (case-insensitive, partial match).
- `min_capacity`: Minimum capacity (integer).
- `max_capacity`: Maximum capacity (integer).
- `min_datetime`: Start datetime after or equal to (ISO 8601).
- `max_datetime`: End datetime before or equal to (ISO 8601).
- `amenity`: Filter by amenity name(s). Comma-separated for multiple.
Example: `?amenity=Projector,Whiteboard`

**Pagination:**
Results are paginated (10 per page by default). Use `?page=2` for next page.

**Example Request:**

```
GET /api/rooms/?name=meeting&location=Main&min_capacity=5&amenity=Projector,Whiteboard
```

---

## Retrieve Room

**GET** `/api/rooms/{id}/`

Returns details for a single room.

---

## Create Room

**POST** `/api/rooms/`
**Auth required**

**Body Example:**

```json
{
"name": "Conference Room",
"location": 1,
"capacity": 20,
"amenities_id": [1, 2],
"start_datetime": "2025-12-11T09:00:00Z",
"end_datetime": "2025-12-11T18:00:00Z",
"recurrence_rule": "FREQ=DAILY;BYDAY=MO,TU,WE",
"is_active": true
}
```

---

## Update Room

**PATCH/PUT** `/api/rooms/{id}/`
**Auth required**

**Body:** Same as create. Partial updates allowed.

---

## Delete Room

**DELETE** `/api/rooms/{id}/`
**Not allowed** (returns 405 Method Not Allowed).

---

## Notes

- Unauthenticated users only see rooms where `is_active=true`.
- A room cannot be deleted but you can change its `is_active`
- Filtering by multiple amenities returns rooms that have **all** specified amenities.
- Validation: `end_datetime` must be after `start_datetime`.
- Validation: `recurrence_rule` must start with FREQ= and contain valid frequency

---

## Related Endpoints

- **Locations:** `/api/locations/`
- **Amenities:** `/api/amenities/`
Empty file added server/api/room/__init__.py
Empty file.
25 changes: 25 additions & 0 deletions server/api/room/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from django.contrib import admin
from .models import Room, Location, Amenity
# Register your models here.


@admin.register(Room)
class RoomAdmin(admin.ModelAdmin):
list_display = ("id", "name", "location",
"start_datetime", "end_datetime", "recurrence_rule", "is_active")
search_fields = ("name", "location__name", "amenities__name")
list_display_links = ("name",)


@admin.register(Location)
class LocationAdmin(admin.ModelAdmin):
list_display = ("id", "name")
search_fields = ("name",)
list_display_links = ("name",)


@admin.register(Amenity)
class AmenitiesAdmin(admin.ModelAdmin):
list_display = ("id", "name")
search_fields = ("name",)
list_display_links = ("name",)
6 changes: 6 additions & 0 deletions server/api/room/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class RoomConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "api.room"
50 changes: 50 additions & 0 deletions server/api/room/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Generated by Django 5.2.9 on 2025-12-10 13:13

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = []

operations = [
migrations.CreateModel(
name="Amenities",
fields=[
("id", models.AutoField(primary_key=True, serialize=False)),
("name", models.CharField(max_length=32)),
],
),
migrations.CreateModel(
name="Location",
fields=[
("id", models.AutoField(primary_key=True, serialize=False)),
("name", models.CharField(max_length=64)),
],
),
migrations.CreateModel(
name="Room",
fields=[
("id", models.AutoField(primary_key=True, serialize=False)),
("name", models.CharField(max_length=32)),
("img", models.ImageField(upload_to="room_images/")),
("capacity", models.IntegerField()),
("is_active", models.BooleanField(default=True)),
("start_datetime", models.DateTimeField()),
("end_datetime", models.DateTimeField()),
("recurrence_rule", models.CharField(blank=True, max_length=64)),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("amenities", models.ManyToManyField(blank=True, to="room.amenities")),
(
"location",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="room.location"
),
),
],
),
]
21 changes: 21 additions & 0 deletions server/api/room/migrations/0002_alter_room_capacity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 5.2.9 on 2025-12-10 13:48

import django.core.validators
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("room", "0001_initial"),
]

operations = [
migrations.AlterField(
model_name="room",
name="capacity",
field=models.PositiveIntegerField(
validators=[django.core.validators.MinValueValidator(1)]
),
),
]
18 changes: 18 additions & 0 deletions server/api/room/migrations/0003_alter_room_img.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.2.9 on 2025-12-10 14:59

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("room", "0002_alter_room_capacity"),
]

operations = [
migrations.AlterField(
model_name="room",
name="img",
field=models.ImageField(blank=True, null=True, upload_to="room_images/"),
),
]
21 changes: 21 additions & 0 deletions server/api/room/migrations/0004_alter_room_location.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 5.2.9 on 2025-12-10 15:35

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("room", "0003_alter_room_img"),
]

operations = [
migrations.AlterField(
model_name="room",
name="location",
field=models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT, to="room.location"
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 5.2.9 on 2025-12-11 16:24

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("room", "0004_alter_room_location"),
]

operations = [
migrations.AlterModelOptions(
name="amenities",
options={"ordering": ["id"]},
),
migrations.AlterModelOptions(
name="location",
options={"ordering": ["id"]},
),
]
17 changes: 17 additions & 0 deletions server/api/room/migrations/0006_rename_amenities_amenity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 5.2.9 on 2025-12-11 16:40

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("room", "0005_alter_amenities_options_alter_location_options"),
]

operations = [
migrations.RenameModel(
old_name="Amenities",
new_name="Amenity",
),
]
Empty file.
43 changes: 43 additions & 0 deletions server/api/room/models.py
Copy link
Contributor

Choose a reason for hiding this comment

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

all the TextField need to be replaced with CharField

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from django.db import models
from django.core.validators import MinValueValidator


class Location(models.Model):
id = models.AutoField(primary_key=True)
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

Explicitly defining id as AutoField is unnecessary since Django automatically creates this field. Consider removing this line to reduce redundancy unless there's a specific reason for the explicit declaration.

Copilot uses AI. Check for mistakes.
name = models.CharField(max_length=64, blank=False)

class Meta:
ordering = ['id']

def __str__(self):
return self.name


class Amenity(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32, blank=False)

class Meta:
ordering = ['id']

def __str__(self):
return self.name


class Room(models.Model):
id = models.AutoField(primary_key=True)
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

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

The id field is explicitly defined but Django automatically creates an AutoField primary key named id for models. This redundant field definition should be removed unless there's a specific reason to override the default behavior.

Suggested change
id = models.AutoField(primary_key=True)

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

Explicitly defining id as AutoField is unnecessary since Django automatically creates this field. Consider removing this line to reduce redundancy unless there's a specific reason for the explicit declaration.

Copilot uses AI. Check for mistakes.
name = models.CharField(max_length=32, blank=False)
img = models.ImageField(upload_to='room_images/', blank=True, null=True)
location = models.ForeignKey(
Location, on_delete=models.PROTECT, blank=False)
capacity = models.PositiveIntegerField(validators=[MinValueValidator(1)])
amenities = models.ManyToManyField(Amenity, blank=True)
is_active = models.BooleanField(default=True)
start_datetime = models.DateTimeField(blank=False)
end_datetime = models.DateTimeField(blank=False)
Comment on lines +36 to +37
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

The purpose and expected format of start_datetime and end_datetime fields needs documentation. It's unclear whether these represent the availability window for the room, a specific booking, or the room's operating hours. Adding docstrings or field-level help_text would clarify their intended use.

Suggested change
start_datetime = models.DateTimeField(blank=False)
end_datetime = models.DateTimeField(blank=False)
start_datetime = models.DateTimeField(
blank=False,
help_text="The start of the room's availability window (inclusive). Format: YYYY-MM-DD HH:MM:SS."
)
end_datetime = models.DateTimeField(
blank=False,
help_text="The end of the room's availability window (exclusive). Format: YYYY-MM-DD HH:MM:SS."
)

Copilot uses AI. Check for mistakes.
recurrence_rule = models.CharField(max_length=64, blank=True)
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

There's no validation for the recurrence_rule field to ensure it follows valid iCalendar RRULE syntax. Consider adding validation to prevent invalid recurrence rules from being stored.

Copilot uses AI. Check for mistakes.
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

def __str__(self):
return self.name
Loading