Skip to content

Commit b84a9fe

Browse files
authored
Feature/event categories (#212)
* Support adding category to a new or exisiting event
1 parent e5e43a5 commit b84a9fe

13 files changed

+119
-52
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,5 @@ app/.vscode/
148148

149149
# PyCharm
150150
.idea
151+
152+
junit/

app/routers/agenda.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def calc_dates_range_for_agenda(
1717
start: Optional[date],
1818
end: Optional[date],
1919
days: Optional[int],
20-
) -> Tuple[date, date]:
20+
) -> Tuple[date, date]:
2121
"""Create start and end dates according to the parameters in the page."""
2222
if days is not None:
2323
start = date.today()
@@ -35,17 +35,17 @@ def agenda(
3535
start_date: Optional[date] = None,
3636
end_date: Optional[date] = None,
3737
days: Optional[int] = None,
38-
) -> _TemplateResponse:
38+
) -> _TemplateResponse:
3939
"""Route for the agenda page, using dates range or exact amount of days."""
4040

41-
user_id = 1 # there is no user session yet, so I use user id- 1.
41+
user_id = 1 # there is no user session yet, so I use user id- 1.
4242
start_date, end_date = calc_dates_range_for_agenda(
4343
start_date, end_date, days
44-
)
44+
)
4545

4646
events_objects = agenda_events.get_events_per_dates(
4747
db, user_id, start_date, end_date
48-
)
48+
)
4949
events = defaultdict(list)
5050
for event_obj in events_objects:
5151
event_duration = agenda_events.get_time_delta_string(

app/routers/calendar_grid.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def __init__(self, date: datetime):
2929
self.date: datetime = date
3030
self.sday: str = self.date.strftime("%A")
3131
self.dailyevents: List[Tuple] = []
32-
self.events: List[Tuple] = []
32+
self.events: List[Tuple] = []
3333
self.css: Dict[str, str] = {
3434
'day_container': 'day',
3535
'date': 'day-number',
@@ -79,7 +79,7 @@ def __init__(self, date: datetime):
7979
super().__init__(date)
8080
self.css = {
8181
'day_container': 'day ',
82-
'date': ' '.join(['day-number', 'text-gray']),
82+
'date': ' '.join(['day-number', 'text-gray']),
8383
'daily_event': 'month-event',
8484
'daily_event_front': ' '.join([
8585
'daily',
@@ -100,7 +100,7 @@ class Today(Day):
100100
def __init__(self, date: datetime):
101101
super().__init__(date)
102102
self.css = {
103-
'day_container': ' '.join([
103+
'day_container': ' '.join([
104104
'day',
105105
'text-darkblue',
106106
'background-yellow'
@@ -134,7 +134,7 @@ def __init__(self, date: datetime):
134134
]),
135135
'date': 'day-number',
136136
'daily_event': 'month-event',
137-
'daily_event_front': ' '.join([
137+
'daily_event_front': ' '.join([
138138
'daily front',
139139
'text-lightgray',
140140
'background-red'
@@ -196,8 +196,8 @@ def get_n_days(date: datetime, n: int) -> Iterator[Day]:
196196

197197

198198
def create_weeks(
199-
days: Iterator[Day],
200-
length: int = Week.WEEK_DAYS
199+
days: Iterator[Day],
200+
length: int = Week.WEEK_DAYS
201201
) -> List[Week]:
202202
"""Return lists of Weeks objects."""
203203
ndays: List[Day] = list(days)

app/routers/categories.py

+9
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ class CategoryModel(BaseModel):
2121
color: str
2222
user_id: int
2323

24+
class Config:
25+
schema_extra = {
26+
"example": {
27+
"name": "Guitar lessons",
28+
"color": "#aabbcc",
29+
"user_id": 1,
30+
}
31+
}
32+
2433

2534
# TODO(issue#29): get current user_id from session
2635
@router.get("/")

app/routers/event.py

+18-12
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,20 @@ async def create_new_event(request: Request, session=Depends(get_db)):
4040
end = datetime.strptime(data['end_date'] + ' ' + data['end_time'],
4141
'%Y-%m-%d %H:%M')
4242
user = session.query(User).filter_by(id=1).first()
43-
user = user if user else create_user("u", "p", "[email protected]", session)
43+
user = user if user else create_user(username="u", password="p",
44+
email="[email protected]", language="",
45+
session=session)
4446
owner_id = user.id
4547
location_type = data['location_type']
4648
is_zoom = location_type == 'vc_url'
4749
location = data['location']
50+
category_id = data.get('category_id')
4851

4952
if is_zoom:
5053
validate_zoom_link(location)
5154

5255
event = create_event(session, title, start, end, owner_id, content,
53-
location)
56+
location, category_id=category_id)
5457
return RedirectResponse(router.url_path_for('eventview',
5558
event_id=event.id),
5659
status_code=status.HTTP_302_FOUND)
@@ -74,7 +77,8 @@ async def eventview(request: Request, event_id: int,
7477
'start': datetime,
7578
'end': datetime,
7679
'content': (str, type(None)),
77-
'location': (str, type(None))
80+
'location': (str, type(None)),
81+
'category_id': (int, type(None))
7882
}
7983

8084

@@ -109,14 +113,13 @@ def by_id(db: Session, event_id: int) -> Event:
109113

110114

111115
def is_end_date_before_start_date(
112-
start_date: datetime, end_date: datetime) -> bool:
116+
start_date: datetime, end_date: datetime) -> bool:
113117
"""Check if the start date is earlier than the end date"""
114118

115119
return start_date > end_date
116120

117121

118-
def check_change_dates_allowed(
119-
old_event: Event, event: Dict[str, Any]):
122+
def check_change_dates_allowed(old_event: Event, event: Dict[str, Any]):
120123
allowed = 1
121124
try:
122125
start_date = event.get('start', old_event.start)
@@ -127,8 +130,8 @@ def check_change_dates_allowed(
127130
allowed = 0
128131
if allowed == 0:
129132
raise HTTPException(
130-
status_code=status.HTTP_400_BAD_REQUEST,
131-
detail="Invalid times")
133+
status_code=status.HTTP_400_BAD_REQUEST,
134+
detail="Invalid times")
132135

133136

134137
def is_fields_types_valid(to_check: Dict[str, Any], types: Dict[str, Any]):
@@ -163,8 +166,8 @@ def _update_event(db: Session, event_id: int, event_to_update: Dict) -> Event:
163166
except (AttributeError, SQLAlchemyError) as e:
164167
logger.exception(str(e))
165168
raise HTTPException(
166-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
167-
detail="Internal server error")
169+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
170+
detail="Internal server error")
168171

169172

170173
def update_event(event_id: int, event: Dict, db: Session
@@ -181,7 +184,10 @@ def update_event(event_id: int, event: Dict, db: Session
181184
return event_updated
182185

183186

184-
def create_event(db, title, start, end, owner_id, content=None, location=None):
187+
def create_event(db: Session, title: str, start, end, owner_id: int,
188+
content: str = None,
189+
location: str = None,
190+
category_id: int = None):
185191
"""Creates an event and an association."""
186192

187193
event = create_model(
@@ -192,6 +198,7 @@ def create_event(db, title, start, end, owner_id, content=None, location=None):
192198
content=content,
193199
owner_id=owner_id,
194200
location=location,
201+
category_id=category_id,
195202
)
196203
create_model(
197204
db, UserEvent,
@@ -240,7 +247,6 @@ def _delete_event(db: Session, event: Event):
240247
@router.delete("/{event_id}")
241248
def delete_event(event_id: int,
242249
db: Session = Depends(get_db)):
243-
244250
# TODO: Check if the user is the owner of the event.
245251
event = by_id(db, event_id)
246252
participants = get_participants_emails_by_event(db, event_id)

app/templates/agenda.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77

88
{% block content %}
99
<form method="GET" action="/agenda">
10-
<div class="mb-3 agenda_filters">
10+
<div class="mb-3 agenda_filters">
1111
<label for="start_date">From</label><br>
12-
<input class="filter" type="date" id="start_date" name="start_date" value={{ start_date }}><br>
12+
<input class="filter" type="date" id="start_date" name="start_date" value='{{ start_date }}'><br>
1313
<label for="end_date">To</label><br>
14-
<input class="filter" type="date" id="end_date" name="end_date" value={{ end_date }}><br>
14+
<input class="filter" type="date" id="end_date" name="end_date" value='{{ end_date }}'><br>
1515
<input class="filter" type="submit" value="Get Agenda">
1616
</div>
1717
</form>

app/templates/search.html

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ <h1>Hello, {{ username }}</h1>
1515
<div class="col my-1">
1616
<input type="submit" class="btn btn-primary" value="Search">
1717
</div>
18+
</div>
1819
</form>
1920
</div>
2021

schema.md

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
│ ├── agenda_style.css
3232
│ ├── popover.js
3333
│ ├── style.css
34-
│ ├── popover.js
3534
│ ├── templates
3635
│ ├── base.html
3736
│ ├── home.html

tests/category_fixture.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66

77
@pytest.fixture
8-
def category(session: Session, user: User) -> Category:
8+
def category(session: Session, sender: User) -> Category:
99
category = Category.create(session, name="Guitar Lesson", color="121212",
10-
user_id=user.id)
10+
user_id=sender.id)
1111
yield category
1212
session.delete(category)
1313
session.commit()

tests/event_fixture.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
import pytest
44
from sqlalchemy.orm import Session
55

6-
from app.database.models import Event, User
6+
from app.database.models import Event, User, Category
77
from app.routers.event import create_event
88

99
today_date = datetime.today().replace(hour=0, minute=0, second=0)
1010

1111

1212
@pytest.fixture
13-
def event(sender: User, session: Session) -> Event:
13+
def event(sender: User, category: Category, session: Session) -> Event:
1414
return create_event(
1515
db=session,
1616
title='event',
@@ -19,6 +19,7 @@ def event(sender: User, session: Session) -> Event:
1919
content='test event',
2020
owner_id=sender.id,
2121
location="Some random location",
22+
category_id=category.id,
2223
)
2324

2425

tests/test_agenda_route.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def test_agenda_page_no_arguments_when_today_events_exist(
2727
next_month_event, old_event
2828
):
2929
resp = agenda_test_client.get(TestAgenda.AGENDA)
30-
assert resp.status_code == status.HTTP_200_OK
30+
assert resp.ok
3131
assert b"event 1" in resp.content
3232
assert b"event 2" in resp.content
3333
assert b"event 3" not in resp.content

tests/test_categories.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ def test_creating_new_category(client, user):
2727
set(response.json()['category'].items()))
2828

2929
@staticmethod
30-
def test_creating_not_unique_category_failed(client, user, category):
31-
response = client.post("/categories/", json={"user_id": user.id,
30+
def test_creating_not_unique_category_failed(client, sender, category):
31+
response = client.post("/categories/", json={"user_id": sender.id,
3232
"name": "Guitar Lesson",
3333
"color": "121212"})
3434
assert response.status_code == status.HTTP_400_BAD_REQUEST
@@ -42,6 +42,13 @@ def test_create_event_with_category(category):
4242
assert event.category_id is not None
4343
assert event.category_id == category.id
4444

45+
@staticmethod
46+
def test_update_event_with_category(today_event, category):
47+
assert today_event.category_id is None
48+
today_event.category_id = category.id
49+
assert today_event.category_id is not None
50+
assert today_event.category_id == category.id
51+
4552
@staticmethod
4653
def test_get_user_categories(client, category):
4754
response = client.get(f"/categories/?user_id={category.user_id}"
@@ -52,7 +59,7 @@ def test_get_user_categories(client, category):
5259
("name", "Guitar Lesson"), ("id", category.id)}
5360

5461
@staticmethod
55-
def test_get_category_by_name(client, user, category):
62+
def test_get_category_by_name(client, sender, category):
5663
response = client.get(f"/categories/?user_id={category.user_id}"
5764
f"&name={category.name}")
5865
assert response.ok
@@ -61,7 +68,7 @@ def test_get_category_by_name(client, user, category):
6168
("name", "Guitar Lesson"), ("id", category.id)}
6269

6370
@staticmethod
64-
def test_get_category_by_color(client, user, category):
71+
def test_get_category_by_color(client, sender, category):
6572
response = client.get(f"/categories/?user_id={category.user_id}&"
6673
f"color={category.color}")
6774
assert response.ok

0 commit comments

Comments
 (0)