parent
4ee81de1fd
commit
1acb555f14
|
@ -340,12 +340,17 @@ def windmill_hill_market_days(start_date: date) -> list[Event]:
|
||||||
"""Windmill Hill Market days for the next 12 months from a given date."""
|
"""Windmill Hill Market days for the next 12 months from a given date."""
|
||||||
events: list[Event] = []
|
events: list[Event] = []
|
||||||
current_date = start_date
|
current_date = start_date
|
||||||
|
url = (
|
||||||
|
"https://www.windmillhillcityfarm.org.uk"
|
||||||
|
+ "/visit-us/shops-more/windmill-hill-market-bristol-market/"
|
||||||
|
)
|
||||||
|
|
||||||
# To keep count of how many market days have been calculated
|
# To keep count of how many market days have been calculated
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
tz = pytz.timezone("Europe/London")
|
tz = pytz.timezone("Europe/London")
|
||||||
t = time(10, 0)
|
start = time(10, 0)
|
||||||
|
end = time(15, 0)
|
||||||
|
|
||||||
while count < 12:
|
while count < 12:
|
||||||
# Skip months outside of April to December
|
# Skip months outside of April to December
|
||||||
|
@ -363,7 +368,9 @@ def windmill_hill_market_days(start_date: date) -> list[Event]:
|
||||||
Event(
|
Event(
|
||||||
name="market",
|
name="market",
|
||||||
title="Windmill Hill Market",
|
title="Windmill Hill Market",
|
||||||
date=tz.localize(datetime.combine(first_saturday, t)),
|
date=tz.localize(datetime.combine(first_saturday, start)),
|
||||||
|
end_date=tz.localize(datetime.combine(first_saturday, end)),
|
||||||
|
url=url,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
count += 1
|
count += 1
|
||||||
|
@ -381,8 +388,11 @@ def tobacco_factory_market_days(start_date: date) -> list[Event]:
|
||||||
current_date = start_date
|
current_date = start_date
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
|
url = "https://tobaccofactory.com/whats-on/sunday-market/"
|
||||||
|
|
||||||
tz = pytz.timezone("Europe/London")
|
tz = pytz.timezone("Europe/London")
|
||||||
t = time(10, 0)
|
start = time(10, 0)
|
||||||
|
end = time(14, 30)
|
||||||
|
|
||||||
while count < 52: # 52 weeks in a year
|
while count < 52: # 52 weeks in a year
|
||||||
# Calculate the next Sunday from the current date
|
# Calculate the next Sunday from the current date
|
||||||
|
@ -394,7 +404,9 @@ def tobacco_factory_market_days(start_date: date) -> list[Event]:
|
||||||
Event(
|
Event(
|
||||||
name="market",
|
name="market",
|
||||||
title="Tobacco Factory Sunday Market",
|
title="Tobacco Factory Sunday Market",
|
||||||
date=tz.localize(datetime.combine(next_sunday, t)),
|
date=tz.localize(datetime.combine(next_sunday, start)),
|
||||||
|
end_date=tz.localize(datetime.combine(next_sunday, end)),
|
||||||
|
url=url,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
count += 1
|
count += 1
|
||||||
|
@ -454,14 +466,16 @@ def get_conferences(input_date: date, filepath: str) -> List[Event]:
|
||||||
|
|
||||||
events = []
|
events = []
|
||||||
for conf in data.get("conferences", []):
|
for conf in data.get("conferences", []):
|
||||||
event_date = conf["start"]
|
start_date = conf["start"]
|
||||||
|
end_date = conf["end"]
|
||||||
|
|
||||||
# Skip the conference if it is before the input date.
|
# Skip the conference if it is before the input date.
|
||||||
if as_date(event_date) < input_date:
|
if as_date(end_date) < input_date:
|
||||||
continue
|
continue
|
||||||
event = Event(
|
event = Event(
|
||||||
name="conference",
|
name="conference",
|
||||||
date=event_date,
|
date=start_date,
|
||||||
|
end_date=end_date,
|
||||||
title=f'{conf["name"]} ({conf["location"]})',
|
title=f'{conf["name"]} ({conf["location"]})',
|
||||||
url=conf.get("url"),
|
url=conf.get("url"),
|
||||||
)
|
)
|
||||||
|
@ -516,21 +530,24 @@ def get_accommodation(from_date: date, filepath: str) -> list[Event]:
|
||||||
)
|
)
|
||||||
from_date = item["from"]
|
from_date = item["from"]
|
||||||
to_date = item["to"]
|
to_date = item["to"]
|
||||||
nights = (to_date.date() - from_date.date()).days
|
# nights = (to_date.date() - from_date.date()).days
|
||||||
night_str = f"{nights} nights" if nights != 1 else "1 night"
|
# night_str = f"{nights} nights" if nights != 1 else "1 night"
|
||||||
checkin = Event(
|
e = Event(
|
||||||
date=from_date,
|
date=from_date,
|
||||||
|
end_date=to_date,
|
||||||
name="accommodation",
|
name="accommodation",
|
||||||
title=f"check-in {title} ({night_str})",
|
# title=f"check-in {title} ({night_str})",
|
||||||
|
title=title,
|
||||||
url=item.get("url"),
|
url=item.get("url"),
|
||||||
)
|
)
|
||||||
checkout = Event(
|
events.append(e)
|
||||||
date=to_date,
|
# checkout = Event(
|
||||||
name="accommodation",
|
# date=to_date,
|
||||||
title="check-out " + title,
|
# name="accommodation",
|
||||||
url=item.get("url"),
|
# title="check-out " + title,
|
||||||
)
|
# url=item.get("url"),
|
||||||
events += [checkin, checkout]
|
# )
|
||||||
|
# events += [checkin, checkout]
|
||||||
return events
|
return events
|
||||||
|
|
||||||
|
|
||||||
|
@ -554,6 +571,7 @@ def get_travel(
|
||||||
return [
|
return [
|
||||||
Event(
|
Event(
|
||||||
date=item["depart"],
|
date=item["depart"],
|
||||||
|
end_date=item["arrive"],
|
||||||
name="transport",
|
name="transport",
|
||||||
title=title(item),
|
title=title(item),
|
||||||
url=item.get("url"),
|
url=item.get("url"),
|
||||||
|
@ -618,6 +636,27 @@ def sunset(observer: ephem.Observer) -> datetime:
|
||||||
return typing.cast(datetime, observer.next_setting(ephem.Sun(observer)).datetime())
|
return typing.cast(datetime, observer.next_setting(ephem.Sun(observer)).datetime())
|
||||||
|
|
||||||
|
|
||||||
|
def build_events_for_calendar(events: list[Event]) -> list[dict[str, typing.Any]]:
|
||||||
|
"""Build list of events for FullCalendar."""
|
||||||
|
items: list[dict[str, typing.Any]] = []
|
||||||
|
|
||||||
|
for e in events:
|
||||||
|
if e.has_time:
|
||||||
|
end = e.end_date or e.date + timedelta(hours=1)
|
||||||
|
else:
|
||||||
|
end = (e.end_as_date if e.end_date else e.as_date) + timedelta(days=1)
|
||||||
|
item = {
|
||||||
|
"allDay": not e.has_time,
|
||||||
|
"title": e.display_title,
|
||||||
|
"start": e.date.isoformat(),
|
||||||
|
"end": end.isoformat(),
|
||||||
|
}
|
||||||
|
if e.url:
|
||||||
|
item["url"] = e.url
|
||||||
|
items.append(item)
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
def get_data(now: datetime) -> typing.Mapping[str, str | object]:
|
def get_data(now: datetime) -> typing.Mapping[str, str | object]:
|
||||||
"""Get data to display on agenda dashboard."""
|
"""Get data to display on agenda dashboard."""
|
||||||
rocket_dir = os.path.join(data_dir, "thespacedevs")
|
rocket_dir = os.path.join(data_dir, "thespacedevs")
|
||||||
|
@ -684,4 +723,6 @@ def get_data(now: datetime) -> typing.Mapping[str, str | object]:
|
||||||
|
|
||||||
reply["events"] = events
|
reply["events"] = events
|
||||||
|
|
||||||
|
reply["fullcalendar_events"] = build_events_for_calendar(events)
|
||||||
|
|
||||||
return reply
|
return reply
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import datetime
|
import datetime
|
||||||
from datetime import date, timezone
|
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
|
@ -10,7 +9,8 @@ class Event:
|
||||||
"""Event."""
|
"""Event."""
|
||||||
|
|
||||||
name: str
|
name: str
|
||||||
date: date | datetime.datetime
|
date: datetime.date | datetime.datetime
|
||||||
|
end_date: datetime.date | datetime.datetime | None = None
|
||||||
title: str | None = None
|
title: str | None = None
|
||||||
url: str | None = None
|
url: str | None = None
|
||||||
|
|
||||||
|
@ -22,9 +22,14 @@ class Event:
|
||||||
return (
|
return (
|
||||||
d
|
d
|
||||||
if isinstance(d, datetime.datetime)
|
if isinstance(d, datetime.datetime)
|
||||||
else datetime.datetime.combine(d, t0).replace(tzinfo=timezone.utc)
|
else datetime.datetime.combine(d, t0).replace(tzinfo=datetime.timezone.utc)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_time(self) -> bool:
|
||||||
|
"""Event has a time associated with it."""
|
||||||
|
return isinstance(self.date, datetime.datetime)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def as_date(self) -> datetime.date:
|
def as_date(self) -> datetime.date:
|
||||||
"""Date of event."""
|
"""Date of event."""
|
||||||
|
@ -32,6 +37,16 @@ class Event:
|
||||||
self.date.date() if isinstance(self.date, datetime.datetime) else self.date
|
self.date.date() if isinstance(self.date, datetime.datetime) else self.date
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def end_as_date(self) -> datetime.date:
|
||||||
|
"""Date of event."""
|
||||||
|
assert self.end_date
|
||||||
|
return (
|
||||||
|
self.end_date.date()
|
||||||
|
if isinstance(self.end_date, datetime.datetime)
|
||||||
|
else self.end_date
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def display_time(self) -> str | None:
|
def display_time(self) -> str | None:
|
||||||
"""Time for display on web page."""
|
"""Time for display on web page."""
|
||||||
|
@ -69,3 +84,8 @@ class Event:
|
||||||
return self.date.strftime("%a, %d, %b %Y %H:%M %z")
|
return self.date.strftime("%a, %d, %b %Y %H:%M %z")
|
||||||
else:
|
else:
|
||||||
return self.date.strftime("%a, %d, %b %Y")
|
return self.date.strftime("%a, %d, %b %Y")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def display_title(self) -> str:
|
||||||
|
"""Name for display."""
|
||||||
|
return self.name + ": " + self.title if self.title else self.name
|
||||||
|
|
|
@ -7,6 +7,41 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Agenda</title>
|
<title>Agenda</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
|
||||||
|
|
||||||
|
<script type='importmap'>
|
||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"@fullcalendar/core": "https://cdn.skypack.dev/@fullcalendar/core@6.1.9",
|
||||||
|
"@fullcalendar/daygrid": "https://cdn.skypack.dev/@fullcalendar/daygrid@6.1.9",
|
||||||
|
"@fullcalendar/timegrid": "https://cdn.skypack.dev/@fullcalendar/timegrid@6.1.9",
|
||||||
|
"@fullcalendar/list": "https://cdn.skypack.dev/@fullcalendar/list@6.1.9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script type='module'>
|
||||||
|
import { Calendar } from '@fullcalendar/core'
|
||||||
|
import dayGridPlugin from '@fullcalendar/daygrid'
|
||||||
|
import timeGridPlugin from '@fullcalendar/timegrid'
|
||||||
|
import listPlugin from '@fullcalendar/list'
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const calendarEl = document.getElementById('calendar')
|
||||||
|
const calendar = new Calendar(calendarEl, {
|
||||||
|
plugins: [dayGridPlugin, timeGridPlugin, listPlugin ],
|
||||||
|
themeSystem: 'bootstrap5',
|
||||||
|
firstDay: 1,
|
||||||
|
initialView: 'timeGridWeek',
|
||||||
|
headerToolbar: {
|
||||||
|
left: 'prev,next today',
|
||||||
|
center: 'title',
|
||||||
|
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
|
||||||
|
},
|
||||||
|
events: {{ fullcalendar_events | tojson(indent=2) }}
|
||||||
|
})
|
||||||
|
calendar.render()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
{% set event_labels = {
|
{% set event_labels = {
|
||||||
|
@ -64,7 +99,11 @@
|
||||||
<p>{{ market }}</p>
|
<p>{{ market }}</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<table class="table table-hover w-auto">
|
<div class="mb-3" id="calendar"></div>
|
||||||
|
|
||||||
|
<h3>Agenda</h3>
|
||||||
|
|
||||||
|
<table class="mt-2 table table-hover">
|
||||||
{% for event in events %}
|
{% for event in events %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
|
|
Loading…
Reference in a new issue