Files
webcal-dashboard/server/app/models.py
Anthony Correa 9a180f973b Here’s a detailed commit message based on the provided diff:
Commit Message:

feat: Implement web calendar application with Flask, Docker, and calendar integration

Description:
	1.	Server Refactor:
	•	Moved application logic from main.py to a structured directory server/app/.
	•	Added server/app/__init__.py for Flask app initialization.
	•	Introduced server/app/views.py to handle routes (dashboard and dashboard_image).
	•	Created server/app/models.py for event modeling, supporting CalDAV and iCalendar events.
	•	Added server/app/weather.py to fetch weather data using OpenWeatherMap API.
	2.	New Features:
	•	Added an image generation route (/image) to render calendar views as BMP images.
	•	Integrated OpenWeatherMap API for weather data on the dashboard.
	3.	Environment and Configurations:
	•	Added a Dockerfile to build and deploy the app using uwsgi-nginx-flask.
	•	Introduced compose.yml for running the app with Docker Compose.
	•	Moved uwsgi.ini configuration to server/uwsgi.ini for modular organization.
	4.	Dependencies:
	•	Updated requirements.txt to include new dependencies: imgkit, pillow, and Werkzeug==2.2.2.
	5.	Static Assets:
	•	Added placeholder images out.png and test.png.
	6.	Code Cleanup:
	•	Removed old files (main.py and root-level uwsgi.ini).
	•	Updated .gitignore to include .idea/ folder.

Additional Notes:
	•	Enhanced event parsing to handle all-day and time-specific events using server/app/models.py.
	•	Utilized Flask’s render_template for dynamic HTML rendering and imgkit for HTML-to-image conversion.
	•	Integrated multiple calendar sources (CalDAV and public iCal feeds).

Let me know if you need further adjustments!
2024-12-15 08:42:51 -06:00

99 lines
3.5 KiB
Python

from datetime import datetime, date, timedelta, timezone
from caldav.objects import Event as CaldavEvent
import dataclasses
from icalendar import Event as IcEvent
from icalendar import Calendar as Icalendar
@dataclasses.dataclass
class Event():
summary: str
dtstart: datetime
dtend: datetime
is_all_day: bool
@classmethod
def fromCalDavEvents(cls, caldav_events: [CaldavEvent]) -> list['Event']:
events = []
for event in caldav_events:
date_value = event.vobject_instance.vevent.dtstart.value
if isinstance(date_value, datetime):
dt_start = date_value
is_all_day = False
elif isinstance(date_value, date):
d_start = date_value
dt_start = datetime(d_start.year, d_start.month, d_start.day, tzinfo=datetime.now(timezone.utc).astimezone().tzinfo)
is_all_day = True
else:
raise Exception
date_value = event.vobject_instance.vevent.dtend.value
if isinstance(date_value, datetime):
dt_end = date_value
elif isinstance(date_value, date):
d_end = date_value - timedelta(days=1)
dt_end = datetime(d_end.year, d_end.month, d_end.day,tzinfo=datetime.now(timezone.utc).astimezone().tzinfo)
else:
raise Exception
events.append(Event(
summary=event.vobject_instance.vevent.summary.value,
dtstart=dt_start,
dtend=dt_end,
is_all_day = is_all_day
))
return events
@classmethod
def fromIcalendar(cls, icalendar: Icalendar) -> list['Event']:
events = []
for event in [e for e in icalendar.subcomponents if isinstance(e, IcEvent)]:
date_value = event['DTSTART'].dt
if isinstance(date_value, datetime):
dt_start = date_value
is_all_day = False
elif isinstance(date_value, date):
d_start = date_value
dt_start = datetime(d_start.year, d_start.month, d_start.day, tzinfo=datetime.now(timezone.utc).astimezone().tzinfo)
is_all_day = True
else:
raise Exception
date_value = event['DTEND'].dt if event.get('DTEND') else event['DTSTART'].dt
if isinstance(date_value, datetime):
dt_end = date_value
elif isinstance(date_value, date):
d_end = date_value
dt_end = datetime(d_end.year, d_end.month, d_end.day,tzinfo=datetime.now(timezone.utc).astimezone().tzinfo)
else:
raise Exception
events.append(Event(
summary=event['summary'],
dtstart=dt_start,
dtend=dt_end,
is_all_day = is_all_day
))
return events
@property
def range_str(self) -> str:
start_time_str = self.dtstart.strftime('%-I')
end_time_str = self.dtend.strftime('%-I')
if not(self.dtstart.hour and self.dtend.hour):
return ""
if self.dtstart.minute: start_time_str += self.dtstart.strftime(':%M')
if self.dtend.minute: end_time_str += self.dtend.strftime(':%M')
if not ((self.dtstart.hour < 12 and self.dtend.hour < 12) or (self.dtstart.hour > 12 and self.dtend.hour > 12)):
start_time_str += self.dtstart.strftime("%p")
end_time_str += self.dtend.strftime("%p")
return f"{start_time_str}-{end_time_str}"