initial commit
This commit is contained in:
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
16
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
16
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredPackages">
|
||||||
|
<value>
|
||||||
|
<list size="2">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="psycopg2" />
|
||||||
|
<item index="1" class="java.lang.String" itemvalue="django-bootstrap-v5" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
4
.idea/misc.xml
generated
Normal file
4
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (webcalDashboard)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/webcalDashboard.iml" filepath="$PROJECT_DIR$/.idea/webcalDashboard.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
21
.idea/webcalDashboard.iml
generated
Normal file
21
.idea/webcalDashboard.iml
generated
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="Flask">
|
||||||
|
<option name="enabled" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
<component name="TemplatesService">
|
||||||
|
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
|
||||||
|
<option name="TEMPLATE_FOLDERS">
|
||||||
|
<list>
|
||||||
|
<option value="$MODULE_DIR$/templates" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
6
Dockerfile
Normal file
6
Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
FROM tiangolo/uwsgi-nginx-flask:python3.8-alpine
|
||||||
|
RUN apk --update add bash nano
|
||||||
|
ENV STATIC_URL /static
|
||||||
|
ENV STATIC_PATH /var/www/app/static
|
||||||
|
COPY ./requirements.txt /var/www/requirements.txt
|
||||||
|
RUN pip install -r /var/www/requirements.txt
|
||||||
3
app/__init__.py
Normal file
3
app/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from flask import Flask
|
||||||
|
app = Flask(__name__)
|
||||||
|
from app import views
|
||||||
BIN
app/static/hellovetica.ttf
Executable file
BIN
app/static/hellovetica.ttf
Executable file
Binary file not shown.
BIN
app/static/sun.gif
Executable file
BIN
app/static/sun.gif
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
118
app/templates/dashboard.html
Normal file
118
app/templates/dashboard.html
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title></title>
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: "Hellovetica";
|
||||||
|
src: url("hellovetica.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
.dashboard {
|
||||||
|
font-family: "Helvetica";
|
||||||
|
height: 699px;
|
||||||
|
width: 600px;
|
||||||
|
{#border-style: solid;#}
|
||||||
|
text-align: left;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
position: relative;
|
||||||
|
height: 50%;
|
||||||
|
{#border-style: dotted;#}
|
||||||
|
verical-align: top;
|
||||||
|
/* height: 250px; */
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel.top {
|
||||||
|
height: 35%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel.bottom {
|
||||||
|
height: 65%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subpanel {
|
||||||
|
position: relative;
|
||||||
|
height:100%;
|
||||||
|
width:48%;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
align-items: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.weather-icon {
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
object-fit: scale-down;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week {
|
||||||
|
/* height:100% */
|
||||||
|
}
|
||||||
|
|
||||||
|
.day {
|
||||||
|
border-style: solid;
|
||||||
|
display: inline-block;
|
||||||
|
min-height: 220px;
|
||||||
|
max-height: 220px;
|
||||||
|
width: 135px;
|
||||||
|
vertical-align: top;
|
||||||
|
margin: 1px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.day-title{
|
||||||
|
background-color: black;
|
||||||
|
text-align: center;
|
||||||
|
color: white;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.event {
|
||||||
|
margin: 3pt;
|
||||||
|
background-color: white;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="dashboard">
|
||||||
|
<div class="panel top">
|
||||||
|
<div class="subpanel">
|
||||||
|
{# <img class="weather-icon" src="sun.gif"></img>#}
|
||||||
|
</div>
|
||||||
|
<div class="subpanel" style="font-size: 60px;font-weight: bold;vertical-align:top; text-align:right;">
|
||||||
|
{{ today.strftime('%a') }}<br>
|
||||||
|
{{ today.strftime('%b %-d') }}<br>
|
||||||
|
{{ today.strftime('%Y') }}<br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel bottom week">
|
||||||
|
|
||||||
|
{% for day, event in days %}
|
||||||
|
<div class="day">
|
||||||
|
<div id="dotw-1" class="day-title">
|
||||||
|
{{ day.strftime('%A') }}
|
||||||
|
</div>
|
||||||
|
{% if event %}
|
||||||
|
<div class="event">
|
||||||
|
{{ event.summary.value }}<br>
|
||||||
|
{% if event.dtstart.value.strftime('%H') != "00" %}
|
||||||
|
{{ event.dtstart.value.strftime('%-I:%M %p') }}<br>{{ event.dtend.value.strftime('%-I:%M %p') }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
54
app/views.py
Normal file
54
app/views.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
from app import app
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import os
|
||||||
|
import caldav
|
||||||
|
import datetime
|
||||||
|
from icalendar import cal, Event
|
||||||
|
import requests
|
||||||
|
url = os.getenv('caldav_url')
|
||||||
|
username = os.getenv('username')
|
||||||
|
password = os.getenv('password')
|
||||||
|
cal_id = os.getenv('cal_id')
|
||||||
|
|
||||||
|
|
||||||
|
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 hello_world():
|
||||||
|
date_obj = datetime.datetime.now()
|
||||||
|
|
||||||
|
start_of_week = date_obj - timedelta(days=date_obj.weekday()) # Monday
|
||||||
|
end_of_week = start_of_week + timedelta(days=7) # Sunday
|
||||||
|
|
||||||
|
with caldav.DAVClient(url=url, username=username, password=password) as client:
|
||||||
|
my_principal = client.principal()
|
||||||
|
|
||||||
|
calendars = my_principal.calendars()
|
||||||
|
calendar = my_principal.calendar(cal_id=cal_id)
|
||||||
|
events_fetched = calendar.date_search(
|
||||||
|
start=start_of_week, end=end_of_week, expand=False)
|
||||||
|
|
||||||
|
events_fetched_by_date = {}
|
||||||
|
for event in events_fetched:
|
||||||
|
value = event.vobject_instance.vevent.dtstart.value
|
||||||
|
if isinstance(value, datetime.datetime):
|
||||||
|
events_fetched_by_date[datetime.datetime.date(value)] = event
|
||||||
|
elif isinstance(value, datetime.date):
|
||||||
|
events_fetched_by_date[value] = event
|
||||||
|
else:
|
||||||
|
raise Exception
|
||||||
|
|
||||||
|
days = []
|
||||||
|
for single_date in daterange(start_of_week, end_of_week):
|
||||||
|
event = events_fetched_by_date.get(single_date)
|
||||||
|
if event:
|
||||||
|
days.append((single_date, event.vobject_instance.vevent))
|
||||||
|
else:
|
||||||
|
days.append((single_date,[]))
|
||||||
|
|
||||||
|
# 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.html", days=days, today=datetime.datetime.now())
|
||||||
4
requirements.txt
Normal file
4
requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
caldav~=0.9.0
|
||||||
|
requests~=2.27.1
|
||||||
|
icalendar~=4.0.9
|
||||||
|
Flask~=2.1.2
|
||||||
6
start.sh
Executable file
6
start.sh
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
app="webcal-dashboard"
|
||||||
|
docker build -t ${app} .
|
||||||
|
docker run -d -p 56733:80 \
|
||||||
|
--name=${app} \
|
||||||
|
-v $PWD:/app ${app}
|
||||||
28
test.py
Normal file
28
test.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import os
|
||||||
|
import caldav
|
||||||
|
from datetime import datetime
|
||||||
|
import requests
|
||||||
|
from icalendar import Calendar, cal, Event
|
||||||
|
|
||||||
|
url = 'http://ical-cdn.teamsnap.com/team_schedule/5f1ddc9e-15b0-4912-84a2-11cc70e9e375.ics'
|
||||||
|
r = requests.get(url)
|
||||||
|
username = os.getenv('username')
|
||||||
|
password = os.getenv('password')
|
||||||
|
c = cal.Calendar.from_ical(r.content)
|
||||||
|
|
||||||
|
calendar_ical = [{
|
||||||
|
'dtstart':e['DTSTART'].dt,
|
||||||
|
'dtstart': e['DTEND'].dt,
|
||||||
|
'summary': e['summary']
|
||||||
|
}
|
||||||
|
for e in c.subcomponents
|
||||||
|
if isinstance(e, Event)]
|
||||||
|
|
||||||
|
with caldav.DAVClient(url=url, username=username, password=password) as client:
|
||||||
|
my_principal = client.principal()
|
||||||
|
|
||||||
|
calendars = my_principal.calendars()
|
||||||
|
calendar = my_principal.calendar(cal_id="9E2AC562-4328-4CA0-B4D1-D730D9F5E9EF")
|
||||||
|
events_fetched = calendar.date_search(
|
||||||
|
start=datetime(2022, 5, 23), end=datetime(2022, 5, 24), expand=True)
|
||||||
|
pass
|
||||||
Reference in New Issue
Block a user