Skip to content

Commit 03c5c13

Browse files
Ramadhan0joshuaocero
authored andcommitted
CV3-49-story(Rooms): get avilable Rooms for a specific time (#508)
- ensure admin can get available rooms for a specific time before booking - getting available rooms for a specific location [Delivers CV3-49]
1 parent 596a371 commit 03c5c13

File tree

4 files changed

+230
-2
lines changed

4 files changed

+230
-2
lines changed

api/room/schema_query.py

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@
1515
from helpers.remote_rooms.remote_rooms_location import (
1616
map_remote_room_location_to_filter
1717
)
18-
from helpers.calendar.credentials import get_google_api_calendar_list
18+
from helpers.calendar.credentials import (get_google_api_calendar_list,
19+
credentials
20+
)
21+
from helpers.events_filter.events_filter import (convert_date,
22+
validate_date_input,
23+
format_range_dates,
24+
format_range_time,
25+
empty_string_checker
26+
)
1927
from api.room.schema import (RatioOfCheckinsAndCancellations,
2028
BookingsAnalyticsCount)
2129

@@ -109,6 +117,15 @@ class PaginatedEvents(graphene.ObjectType):
109117
pages = graphene.Int()
110118

111119

120+
class AvailableRooms(graphene.ObjectType):
121+
id = graphene.String()
122+
name = graphene.String()
123+
124+
125+
class AllAvailableRooms(graphene.ObjectType):
126+
availableRoom = graphene.List(AvailableRooms)
127+
128+
112129
class Query(graphene.ObjectType):
113130
"""
114131
Returns paginated rooms
@@ -308,6 +325,90 @@ def resolve_all_remote_rooms(self, info, return_all=None):
308325
if not re.search(match, room.name)]
309326
return AllRemoteRooms(rooms=actual_rooms)
310327

328+
all_available_rooms = graphene.Field(
329+
AllAvailableRooms,
330+
start_date=graphene.String(required=True),
331+
start_time=graphene.String(required=True),
332+
end_date=graphene.String(required=True),
333+
end_time=graphene.String(required=True),
334+
time_zone=graphene.String(required=True),
335+
description="Returns available rooms in a given period \
336+
\n- start_time: Start time and date when you want to book room from\
337+
[required]\n- end_time: time and date you want to book room upto\
338+
[required]\n time_zone: The time zone of the location\
339+
[required]\n location: The location of the office's \
340+
room you want to book"
341+
)
342+
343+
@Auth.user_roles('Admin', 'Super Admin')
344+
def resolve_all_available_rooms(self, info, **kwargs):
345+
346+
time_zone = kwargs['time_zone']
347+
empty_string_checker(time_zone)
348+
validate_date_input(kwargs['start_date'], kwargs['end_date'])
349+
validate_date_input(kwargs['start_time'], kwargs['end_time'])
350+
format_range_dates(kwargs['start_date'], kwargs['end_date'])
351+
format_range_time(kwargs['start_time'], kwargs['end_time'])
352+
353+
start_time = convert_date(kwargs['start_date'],
354+
kwargs['start_time'],
355+
time_zone
356+
)
357+
end_time = convert_date(kwargs['end_date'],
358+
kwargs['end_time'],
359+
time_zone
360+
)
361+
362+
# list of all remote rooms in a user's location
363+
locational_remote_rooms = Query.resolve_all_remote_rooms(
364+
self, info, return_all=False)
365+
all_rooms = []
366+
for room in locational_remote_rooms.rooms:
367+
all_rooms.append({
368+
"id": room.calendar_id,
369+
"name": room.name
370+
})
371+
372+
# list of all remote rooms and
373+
# for each room shows whether it is free or busy in a given period.
374+
service = credentials.set_api_credentials()
375+
all_calendars = get_google_api_calendar_list()['items']
376+
all_remote_rooms = []
377+
for room in all_calendars:
378+
free_busy_rooms_request_object = {
379+
"timeMin": start_time,
380+
"timeMax": end_time,
381+
"timeZone": time_zone,
382+
"items": [
383+
{
384+
"id": room['id']
385+
}
386+
]
387+
}
388+
res = service.freebusy().query(
389+
body=free_busy_rooms_request_object
390+
).execute()
391+
all_remote_rooms.append(res[u'calendars'])
392+
393+
# all busy remote rooms in a given period
394+
busy_rooms = [key for element in all_remote_rooms for key,
395+
value in element.items() if len(value["busy"]) != 0]
396+
397+
# all available rooms in a user's location in a given period
398+
available_rooms = [room for room in all_rooms if room[
399+
'id'
400+
] not in busy_rooms]
401+
all_available_rooms = [AvailableRooms(room['id'],
402+
room['name']
403+
) for room in available_rooms]
404+
405+
def raise_no_available_rooms():
406+
raise GraphQLError("No available rooms at the moment")
407+
408+
return AllAvailableRooms(
409+
availableRoom=all_available_rooms
410+
) if available_rooms else raise_no_available_rooms()
411+
311412
@Auth.user_roles('Admin', 'Super Admin')
312413
def resolve_filter_rooms_by_tag(self, info, tagId):
313414
rooms = Room.get_query(info).join(tags).join(
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
2+
available_rooms_query = '''
3+
query {
4+
allAvailableRooms(
5+
startDate: "Nov 07 2018",
6+
startTime: "08:00:00",
7+
endDate: "Nov 11 2018",
8+
endTime: "09:45:00",
9+
timeZone: "Africa/Kampala"
10+
){
11+
availableRoom{
12+
id
13+
name
14+
}
15+
}
16+
}
17+
'''
18+
19+
available_rooms_query_with_empty_input = '''
20+
query {
21+
allAvailableRooms(
22+
startDate: "",
23+
startTime: "08:00:00",
24+
endDate: "Nov 11 2018",
25+
endTime: "09:45:00",
26+
timeZone: "Africa/Kampala"
27+
){
28+
availableRoom{
29+
name
30+
}
31+
}
32+
}
33+
'''
34+
35+
available_rooms_query_when_startDate_is_bigger_than_endDate = '''
36+
query {
37+
allAvailableRooms(
38+
startDate: "Nov 13 2018",
39+
startTime: "08:00:00",
40+
endDate: "Nov 11 2018",
41+
endTime: "09:45:00",
42+
timeZone: "Africa/Kampala"
43+
){
44+
availableRoom{
45+
name
46+
}
47+
}
48+
}
49+
'''
50+
51+
available_rooms_query_when_startTime_is_bigger_than_endTime = '''
52+
query {
53+
allAvailableRooms(
54+
startDate: "Nov 07 2018",
55+
startTime: "10:00:00",
56+
endDate: "Nov 11 2018",
57+
endTime: "09:45:00",
58+
timeZone: "Africa/Kampala"
59+
){
60+
availableRoom{
61+
name
62+
}
63+
}
64+
}
65+
'''

helpers/events_filter/events_filter.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import inspect
55
from dateutil import parser
66

7-
87
utc = pytz.utc
98

109

@@ -125,3 +124,23 @@ def calendar_dates_format(start_date, start_time, duration):
125124
end_date = end_date.strftime('%Y-%m-%dT%H:%M:%S')
126125

127126
return (start_date, end_date)
127+
128+
129+
def format_range_time(start_time, end_time):
130+
"""
131+
Raises a GraphQL error when
132+
start_time is bigger than end_time
133+
"""
134+
start_time = datetime.strptime(start_time, '%H:%M:%S')
135+
end_time = datetime.strptime(end_time, '%H:%M:%S')
136+
137+
if start_time > end_time:
138+
raise GraphQLError("Start time must be lower than end time")
139+
return start_time, end_time
140+
141+
142+
def convert_date(provided_date, provided_time, time_zone):
143+
date = provided_date + ' ' + provided_time
144+
new_date = parser.parse(date)
145+
new_date_format = str(pytz.timezone(time_zone).localize(new_date))
146+
return new_date_format.replace(new_date_format[10], 'T')
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from unittest.mock import patch
2+
from tests.base import BaseTestCase, CommonTestCases
3+
from helpers.calendar.calendar import get_calendar_list_mock_data
4+
5+
from fixtures.room.available_rooms_fixtures import (
6+
available_rooms_query,
7+
available_rooms_query_with_empty_input,
8+
available_rooms_query_when_startDate_is_bigger_than_endDate,
9+
available_rooms_query_when_startTime_is_bigger_than_endTime
10+
)
11+
12+
13+
class AvailableRooms(BaseTestCase):
14+
15+
@patch("api.room.schema_query.get_google_api_calendar_list", spec=True,
16+
return_value=get_calendar_list_mock_data())
17+
def test_available_rooms(self, mock_get_json):
18+
CommonTestCases.admin_token_assert_in(
19+
self,
20+
available_rooms_query,
21+
"No available rooms at the moment"
22+
)
23+
24+
def available_rooms_query_with_empty_input(self):
25+
CommonTestCases.admin_token_assert_in(
26+
self,
27+
available_rooms_query_with_empty_input,
28+
"startDate argument missing"
29+
)
30+
31+
def available_rooms_query_when_startDate_is_bigger_than_endDate(self):
32+
CommonTestCases.admin_token_assert_in(
33+
self,
34+
available_rooms_query_when_startDate_is_bigger_than_endDate,
35+
"Start date must be lower than end date"
36+
)
37+
38+
def available_rooms_query_when_startTime_is_bigger_than_endTime(self):
39+
CommonTestCases.admin_token_assert_in(
40+
self,
41+
available_rooms_query_when_startTime_is_bigger_than_endTime,
42+
"Start time must be lower than end time"
43+
)

0 commit comments

Comments
 (0)