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

128
server/app/views.py Normal file
View File

@@ -0,0 +1,128 @@
from app import app
from datetime import datetime, timedelta, timezone
import os
import caldav
import datetime
from icalendar import cal, Event
from flask import render_template, url_for, send_file, send_from_directory
from .models import Event
import requests
import imgkit
from PIL import Image, ImageOps
import io
caldav_url = os.getenv('caldav_url')
username = os.getenv('username')
password = os.getenv('password')
cal_id = os.getenv('cal_id')
from .weather import weather
def remove_emoji(string):
import re
emoji_pattern = re.compile("["
u"\U0001F600-\U0001F64F" # emoticons
u"\U0001F300-\U0001F5FF" # symbols & pictographs
u"\U0001F680-\U0001F6FF" # transport & map symbols
u"\U0001F1E0-\U0001F1FF" # flags (iOS)
u"\U00002500-\U00002BEF" # chinese char
u"\U00002702-\U000027B0"
u"\U00002702-\U000027B0"
u"\U000024C2-\U0001F251"
u"\U0001f926-\U0001f937"
u"\U00010000-\U0010ffff"
u"\u2640-\u2642"
u"\u2600-\u2B55"
u"\u200d"
u"\u23cf"
u"\u23e9"
u"\u231a"
u"\ufe0f" # dingbats
u"\u3030"
"]+", flags=re.UNICODE)
return emoji_pattern.sub(r'', string)
def daterange(start_date, end_date):
for n in range(int((end_date - start_date).days)):
yield datetime.datetime.date(start_date + timedelta(n))
@app.route('/')
def dashboard():
today = datetime.datetime.now(tz=datetime.datetime.now(timezone.utc).astimezone().tzinfo)
# today = datetime.datetime(2022,6,5, tzinfo=datetime.datetime.now(timezone.utc).astimezone().tzinfo)
start_of_week = today - timedelta(days=(today.weekday()+1)) # Monday
end_of_week = start_of_week + timedelta(days=8) # Sunday
events = []
for url in [
'https://www.calendarlabs.com/ical-calendar/ics/76/US_Holidays.ics',
]:
r = requests.get(url)
c = cal.Calendar.from_ical(r.content)
events += Event.fromIcalendar(c)
with caldav.DAVClient(url=caldav_url, username=username, password=password) as client:
my_principal = client.principal()
calendars = my_principal.calendars()
for id in [cal_id]:
calendar = my_principal.calendar(cal_id=id)
events += Event.fromCalDavEvents(calendar.date_search(
start=start_of_week, end=end_of_week, expand=False))
for url in [
'http://ical-cdn.teamsnap.com/team_schedule/5f1ddc9e-15b0-4912-84a2-11cc70e9e375.ics'
]:
r = requests.get(url)
c = cal.Calendar.from_ical(r.content)
events += Event.fromIcalendar(c)
days = []
for single_date in daterange(start_of_week, end_of_week):
days_events = []
for e in events:
if (e.dtstart.date() <= single_date <= e.dtend.date()):
e.summary = remove_emoji(e.summary)
days_events.append(e)
days.append((single_date, days_events))
# breakpoint()
pass
# r = "<br>".join([event.vobject_instance.vevent.summary.value for event in events_fetched if event.vobject_instance.vevent.dtstart.value < datetime.now()])
return render_template("dashboard_static.html",
days=days,
today=today,
weather=weather()
)
@app.route('/image')
def dashboard_image():
page = dashboard()
out_file = os.path.join(os.path.dirname(__file__),
'static', "out.bmp"
)
s = imgkit.from_string(
page,
out_file,
options={
'width':600,
'height':800,
"disable-smart-width": "",
'enable-local-file-access': "",
'allow': os.path.join(os.path.dirname(__file__),
'static',
)
},
css=os.path.join(os.path.dirname(__file__),
'static',
'style.css'
)
)
image_file = Image.open(out_file) # open colour image
image_file = ImageOps.grayscale(image_file)
image_file.save(out_file, 'BMP')
return send_from_directory(directory = 'static', path='out.bmp', as_attachment=False, attachment_filename='out.bmp')