diff --git a/app/database/models.py b/app/database/models.py index a9885d37..816e7c8b 100644 --- a/app/database/models.py +++ b/app/database/models.py @@ -72,6 +72,7 @@ class Event(Base): is_google_event = Column(Boolean, default=False) vc_link = Column(String) color = Column(String, nullable=True) + all_day = Column(Boolean, default=False) invitees = Column(String) emotion = Column(String, nullable=True) availability = Column(Boolean, default=True, nullable=False) diff --git a/app/locales/en/LC_MESSAGES/base.mo b/app/locales/en/LC_MESSAGES/base.mo index cabeb8c0..a2af11c0 100644 Binary files a/app/locales/en/LC_MESSAGES/base.mo and b/app/locales/en/LC_MESSAGES/base.mo differ diff --git a/app/locales/he/LC_MESSAGES/base.mo b/app/locales/he/LC_MESSAGES/base.mo index 40170b4a..2233662f 100644 Binary files a/app/locales/he/LC_MESSAGES/base.mo and b/app/locales/he/LC_MESSAGES/base.mo differ diff --git a/app/routers/dayview.py b/app/routers/dayview.py index 23157df1..7887a151 100644 --- a/app/routers/dayview.py +++ b/app/routers/dayview.py @@ -104,11 +104,27 @@ def _check_multiday_event(self) -> Tuple[bool]: return (start_multiday, end_multiday) -def event_in_day(event: Event, day: datetime, day_end: datetime) -> bool: +def is_specific_time_event_in_day( + event: Event, day: datetime, day_end: datetime +) -> bool: + if event.all_day: + return False return ( - (event.start >= day and event.start < day_end) or - (event.end >= day and event.end < day_end) or - (event.start < day_end < event.end) + (event.start >= day and event.start < day_end) + or (event.end >= day and event.end < day_end) + or (event.start < day_end < event.end) + ) + + +def is_all_day_event_in_day( + event: Event, day: datetime, day_end: datetime +) -> bool: + if not event.all_day: + return False + return ( + (event.start >= day and event.start < day_end) + or (event.end >= day and event.end < day_end) + or (event.start < day_end < event.end) ) @@ -118,16 +134,28 @@ def get_events_and_attributes( events = get_all_user_events(session, user_id) day_end = day + timedelta(hours=24) for event in events: - if event_in_day(event=event, day=day, day_end=day_end): + if is_specific_time_event_in_day( + event=event, day=day, day_end=day_end + ): yield (event, DivAttributes(event, day)) +def get_all_day_events( + day: datetime, session, user_id: int, +) -> Event: + events = get_all_user_events(session, user_id) + day_end = day + timedelta(hours=24) + for event in events: + if is_all_day_event_in_day(event=event, day=day, day_end=day_end): + yield (event) + + @router.get('/day/{date}', include_in_schema=False) async def dayview( request: Request, date: str, session=Depends(get_db), view='day', ): # TODO: add a login session - user = session.query(User).filter_by(username='test_username').first() + user = session.query(User).first() try: day = datetime.strptime(date, '%Y-%m-%d') except ValueError as err: @@ -136,10 +164,14 @@ async def dayview( events_n_attrs = get_events_and_attributes( day=day, session=session, user_id=user.id, ) + all_day_events = get_all_day_events( + day=day, session=session, user_id=user.id, + ) month = day.strftime("%B").upper() return templates.TemplateResponse("dayview.html", { "request": request, "events": events_n_attrs, + "all_day_events": all_day_events, "month": month, "day": day.day, "zodiac": zodiac_obj, diff --git a/app/routers/event.py b/app/routers/event.py index 00303f9d..b7bc1a9a 100644 --- a/app/routers/event.py +++ b/app/routers/event.py @@ -31,6 +31,7 @@ 'start': dt, 'end': dt, 'availability': bool, + 'all_day': bool, 'is_google_event': bool, 'content': (str, type(None)), 'location': (str, type(None)), @@ -94,6 +95,8 @@ async def create_new_event(request: Request, owner_id = get_current_user(session).id availability = data.get('availability', 'True') == 'True' location = data['location'] + all_day = data['event_type'] and data['event_type'] == 'on' + vc_link = data['vc_link'] category_id = data.get('category_id') is_google_event = data.get('is_google_event', 'True') == 'True' @@ -106,7 +109,7 @@ async def create_new_event(request: Request, raise_if_zoom_link_invalid(vc_link) event = create_event(db=session, title=title, start=start, end=end, - owner_id=owner_id, content=content, + owner_id=owner_id, all_day=all_day, content=content, location=location, vc_link=vc_link, invitees=invited_emails, category_id=category_id, @@ -123,12 +126,16 @@ async def create_new_event(request: Request, async def eventview(request: Request, event_id: int, db: Session = Depends(get_db)) -> Response: event, comments, end_format = get_event_data(db, event_id) + start_format = START_FORMAT + if event.all_day: + start_format = '%A, %d/%m/%Y' + end_format = "" messages = request.query_params.get('messages', '').split("---") return templates.TemplateResponse("event/eventview.html", {"request": request, "event": event, "comments": comments, - "start_format": START_FORMAT, + "start_format": start_format, "end_format": end_format, "messages": messages}) @@ -267,6 +274,7 @@ def update_event(event_id: int, event: Dict, db: Session def create_event(db: Session, title: str, start, end, owner_id: int, + all_day: bool = False, content: Optional[str] = None, location: Optional[str] = None, vc_link: str = None, @@ -292,6 +300,7 @@ def create_event(db: Session, title: str, start, end, owner_id: int, color=color, emotion=get_emotion(title, content), invitees=invitees_concatenated, + all_day=all_day, category_id=category_id, availability=availability, is_google_event=is_google_event diff --git a/app/templates/dayview.html b/app/templates/dayview.html index b8eefd73..8270c9f9 100644 --- a/app/templates/dayview.html +++ b/app/templates/dayview.html @@ -23,6 +23,11 @@ {{day}} / {{month}} {% endif %} +
+ {% for event in all_day_events %} +

{{ event.title }}

+ {% endfor %} +
{% if view == 'day'%} diff --git a/app/templates/event/partials/edit_event_details_tab.html b/app/templates/event/partials/edit_event_details_tab.html index eb92b291..132a0299 100644 --- a/app/templates/event/partials/edit_event_details_tab.html +++ b/app/templates/event/partials/edit_event_details_tab.html @@ -49,6 +49,13 @@
+
+ + +
diff --git a/app/templates/event/partials/view_event_details_tab.html b/app/templates/event/partials/view_event_details_tab.html index 35c439b0..a886cc1a 100644 --- a/app/templates/event/partials/view_event_details_tab.html +++ b/app/templates/event/partials/view_event_details_tab.html @@ -10,8 +10,10 @@

{{ event.title }}

ICON + {% if end_format != "" %} - - + + {% endif %}
{{ 'Busy' if event.availability == True else 'Free' }}
diff --git a/tests/asyncio_fixture.py b/tests/asyncio_fixture.py index a36d76c1..db6645c5 100644 --- a/tests/asyncio_fixture.py +++ b/tests/asyncio_fixture.py @@ -35,6 +35,7 @@ def fake_user_events(session): title='Cool today event', start=today_date, end=today_date + timedelta(days=2), + all_day=False, content='test event', owner_id=user.id, location="Here", @@ -45,6 +46,7 @@ def fake_user_events(session): title='Cool (somewhen in two days) event', start=today_date + timedelta(days=1), end=today_date + timedelta(days=3), + all_day=False, content='this week test event', owner_id=user.id, location="Here", diff --git a/tests/dayview_fixture.py b/tests/dayview_fixture.py index d20d97c2..769651a3 100644 --- a/tests/dayview_fixture.py +++ b/tests/dayview_fixture.py @@ -29,6 +29,14 @@ def event3(): start=start, end=end, owner_id=1) +@pytest.fixture +def all_day_event1(): + start = datetime(year=2021, month=2, day=3, hour=7, minute=5) + end = datetime(year=2021, month=2, day=3, hour=9, minute=15) + return Event(title='test3', content='test', all_day=True, + start=start, end=end, owner_id=1) + + @pytest.fixture def small_event(): start = datetime(year=2021, month=2, day=3, hour=7) diff --git a/tests/event_fixture.py b/tests/event_fixture.py index 981939cb..989c41fb 100644 --- a/tests/event_fixture.py +++ b/tests/event_fixture.py @@ -31,6 +31,7 @@ def today_event(sender: User, session: Session) -> Event: title='event 1', start=today_date + timedelta(hours=7), end=today_date + timedelta(hours=9), + all_day=False, content='test event', owner_id=sender.id, ) @@ -43,6 +44,7 @@ def today_event_2(sender: User, session: Session) -> Event: title='event 2', start=today_date + timedelta(hours=3), end=today_date + timedelta(days=2, hours=3), + all_day=False, content='test event', owner_id=sender.id, ) @@ -55,6 +57,7 @@ def yesterday_event(sender: User, session: Session) -> Event: title='event 3', start=today_date - timedelta(hours=8), end=today_date, + all_day=False, content='test event', owner_id=sender.id, ) @@ -67,6 +70,7 @@ def next_week_event(sender: User, session: Session) -> Event: title='event 4', start=today_date + timedelta(days=7, hours=2), end=today_date + timedelta(days=7, hours=4), + all_day=False, content='test event', owner_id=sender.id, ) @@ -79,6 +83,7 @@ def next_month_event(sender: User, session: Session) -> Event: title='event 5', start=today_date + timedelta(days=20, hours=4), end=today_date + timedelta(days=20, hours=6), + all_day=False, content='test event', owner_id=sender.id, ) @@ -91,6 +96,22 @@ def old_event(sender: User, session: Session) -> Event: title='event 6', start=today_date - timedelta(days=5), end=today_date - timedelta(days=1), + all_day=False, content='test event', owner_id=sender.id, ) + + +@pytest.fixture +def all_day_event(sender: User, category: Category, session: Session) -> Event: + return create_event( + db=session, + title='event', + start=today_date, + end=today_date, + all_day=True, + content='test event', + owner_id=sender.id, + location="Some random location", + category_id=category.id, + ) diff --git a/tests/test_dayview.py b/tests/test_dayview.py index 11933abb..70cfb971 100644 --- a/tests/test_dayview.py +++ b/tests/test_dayview.py @@ -4,7 +4,11 @@ import pytest from app.database.models import Event -from app.routers.dayview import DivAttributes +from app.routers.dayview import ( + DivAttributes, is_all_day_event_in_day, + is_specific_time_event_in_day +) + from app.routers.event import create_event @@ -64,6 +68,32 @@ def test_div_attr_multiday(multiday_event): assert DivAttributes(multiday_event, day).grid_position == '1 / 57' +def test_is_specific_time_event_in_day(all_day_event1, event3): + day = datetime(year=2021, month=2, day=3, hour=0, minute=0) + day_end = day + timedelta(hours=24) + function_returns_true = is_specific_time_event_in_day( + event=event3, day=day, day_end=day_end + ) + function_returns_false = is_specific_time_event_in_day( + event=all_day_event1, day=day, day_end=day_end + ) + assert function_returns_true + assert not function_returns_false + + +def test_is_all_day_event_in_day(all_day_event1, event3): + day = datetime(year=2021, month=2, day=3, hour=0, minute=0) + day_end = day + timedelta(hours=24) + function_returns_true = is_all_day_event_in_day( + event=all_day_event1, day=day, day_end=day_end + ) + function_returns_false = is_all_day_event_in_day( + event=event3, day=day, day_end=day_end + ) + assert function_returns_true + assert not function_returns_false + + def test_div_attributes_with_costume_color(event2): div_attr = DivAttributes(event2) assert div_attr.color == 'blue' diff --git a/tests/test_emotion.py b/tests/test_emotion.py index 0d68fcf0..f16c88d8 100644 --- a/tests/test_emotion.py +++ b/tests/test_emotion.py @@ -53,13 +53,13 @@ create_event_tests = [ (HAPPY_MESSAGE, datetime.datetime(2019, 5, 21, 0, 0), - datetime.datetime(2019, 5, 22, 0, 0), 1, HAPPY_MESSAGE, "location", + datetime.datetime(2019, 5, 22, 0, 0), False, 1, HAPPY_MESSAGE, "location", "😃"), (SAD_MESSAGE, datetime.datetime(2019, 5, 21, 0, 0), - datetime.datetime(2019, 5, 22, 0, 0), 1, HAPPY_MESSAGE, "location", + datetime.datetime(2019, 5, 22, 0, 0), False, 1, HAPPY_MESSAGE, "location", "🙁"), (" ", datetime.datetime(2019, 5, 21, 0, 0), - datetime.datetime(2019, 5, 22, 0, 0), 1, " ", "location", + datetime.datetime(2019, 5, 22, 0, 0), False, 1, " ", "location", None) ] @@ -89,10 +89,10 @@ def test_get_emotion(title, content, result): assert get_emotion(title, content) == result -@pytest.mark.parametrize("title, start, end, owner_id, content, " + +@pytest.mark.parametrize("title, start, end, all_day, owner_id, content, " + "location, result", create_event_tests) -def test_create_event(title, start, end, +def test_create_event(title, start, end, all_day, owner_id, content, location, result, session): event = create_event(session, title, start, - end, owner_id, content, location) + end, all_day, owner_id, content, location) assert event.emotion == result diff --git a/tests/test_event.py b/tests/test_event.py index 13a5556f..a1f4be3a 100644 --- a/tests/test_event.py +++ b/tests/test_event.py @@ -29,7 +29,24 @@ 'availability': 'True', 'privacy': 'public', 'invited': 'a@a.com,b@b.com', + 'event_type': 'on' +} + +CORRECT_EVENT_FORM_DATA_WITHOUT_EVENT_TYPE = { + 'title': 'test title', + 'start_date': '2021-01-28', + 'start_time': '15:59', + 'end_date': '2021-01-27', + 'end_time': '15:01', + 'location_type': 'vc_url', + 'location': 'https://us02web.zoom.us/j/875384596', + 'description': 'content', + 'color': 'red', + 'availability': 'busy', + 'privacy': 'public', + 'event_type': 'on', 'is_google_event': 'False', + } WRONG_EVENT_FORM_DATA = { @@ -45,6 +62,7 @@ 'availability': 'True', 'privacy': 'public', 'invited': 'a@a.com,b@b.com', + 'event_type': 'on', 'is_google_event': 'False', } @@ -61,6 +79,7 @@ 'availability': 'busy', 'privacy': 'public', 'invited': 'a@a.com,b@b.com,ccc', + 'event_type': 'on', 'is_google_event': 'False', } @@ -76,6 +95,7 @@ 'color': 'red', 'availability': 'busy', 'privacy': 'public', + 'event_type': 'on', 'invited': 'a@a.com,b@b.com', 'is_google_event': 'False', } @@ -93,6 +113,7 @@ 'availability': 'busy', 'privacy': 'public', 'invited': 'a@a.com,b@b.com', + 'event_type': 'on', 'is_google_event': 'False', } @@ -141,6 +162,13 @@ def test_eventview_with_id(event_test_client, session, event): assert b"View Event" in response.content +def test_all_day_eventview_with_id(event_test_client, session, all_day_event): + event_id = all_day_event.id + response = event_test_client.get(f"/event/{event_id}") + assert response.ok + assert b"View Event" in response.content + + def test_create_event_with_default_availability(client, user, session): """ Test create event with default availability. (busy) @@ -226,6 +254,18 @@ def test_eventedit_post_correct(client, user): in response.headers['location']) +def test_eventedit_post_without_event_type(client, user): + """ + Test create new event successfully, + When the event type is not defined by the user. + """ + response = client.post(client.app.url_path_for('create_new_event'), + data=CORRECT_EVENT_FORM_DATA) + assert response.status_code == status.HTTP_302_FOUND + assert (client.app.url_path_for('eventview', event_id=1).strip('1') + in response.headers['location']) + + def test_create_event_with_category(client, user, category, session): """ Test create event with category successfully.