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!
This commit is contained in:
2024-12-15 08:42:51 -06:00
parent dc90143c09
commit 9a180f973b
18 changed files with 110 additions and 112 deletions

98
server/app/models.py Normal file
View File

@@ -0,0 +1,98 @@
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}"