mirror of
https://github.com/ae-utbm/sith.git
synced 2025-01-08 16:11:17 +00:00
Create dedicated class to manage ics calendar files
This commit is contained in:
parent
0a0f44607e
commit
a60e1f1fdc
37
com/api.py
37
com/api.py
@ -1,15 +1,14 @@
|
|||||||
from datetime import datetime, timedelta
|
from datetime import timedelta
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import urllib3
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import HttpResponse
|
from django.http import Http404
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from ics import Calendar, Event
|
from ics import Calendar, Event
|
||||||
from ninja_extra import ControllerBase, api_controller, route
|
from ninja_extra import ControllerBase, api_controller, route
|
||||||
|
|
||||||
from com.models import NewsDate
|
from com.models import IcsCalendar, NewsDate
|
||||||
from core.views.files import send_raw_file
|
from core.views.files import send_raw_file
|
||||||
|
|
||||||
|
|
||||||
@ -19,28 +18,18 @@ class CalendarController(ControllerBase):
|
|||||||
|
|
||||||
@route.get("/external.ics")
|
@route.get("/external.ics")
|
||||||
def calendar_external(self):
|
def calendar_external(self):
|
||||||
file = self.CACHE_FOLDER / "external.ics"
|
"""Return the ICS file of the AE Google Calendar
|
||||||
# Return cached file if updated less than an our ago
|
|
||||||
if (
|
|
||||||
file.exists()
|
|
||||||
and timezone.make_aware(datetime.fromtimestamp(file.stat().st_mtime))
|
|
||||||
+ timedelta(hours=1)
|
|
||||||
> timezone.now()
|
|
||||||
):
|
|
||||||
return send_raw_file(file)
|
|
||||||
|
|
||||||
calendar = urllib3.request(
|
Because of Google's cors rules, we can't "just" do a request to google ics
|
||||||
"GET",
|
from the frontend. Google is blocking CORS request in it's responses headers.
|
||||||
"https://calendar.google.com/calendar/ical/ae.utbm%40gmail.com/public/basic.ics",
|
The only way to do it from the frontend is to use Google Calendar API with an API key
|
||||||
)
|
This is not especially desirable as your API key is going to be provided to the frontend.
|
||||||
if calendar.status != 200:
|
|
||||||
return HttpResponse(status=calendar.status)
|
|
||||||
|
|
||||||
self.CACHE_FOLDER.mkdir(parents=True, exist_ok=True)
|
This is why we have this backend based solution.
|
||||||
with open(file, "wb") as f:
|
"""
|
||||||
_ = f.write(calendar.data)
|
if (calendar := IcsCalendar.get_external()) is not None:
|
||||||
|
return send_raw_file(calendar)
|
||||||
return send_raw_file(file)
|
raise Http404
|
||||||
|
|
||||||
@route.get("/internal.ics")
|
@route.get("/internal.ics")
|
||||||
def calendar_internal(self):
|
def calendar_internal(self):
|
||||||
|
@ -17,11 +17,16 @@
|
|||||||
# details.
|
# details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License along with
|
# You should have received a copy of the GNU General Public License along with
|
||||||
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
|
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
# Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import final
|
||||||
|
|
||||||
|
import urllib3
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.mail import EmailMultiAlternatives
|
from django.core.mail import EmailMultiAlternatives
|
||||||
@ -37,6 +42,39 @@ from club.models import Club
|
|||||||
from core.models import Notification, Preferences, User
|
from core.models import Notification, Preferences, User
|
||||||
|
|
||||||
|
|
||||||
|
@final
|
||||||
|
class IcsCalendar:
|
||||||
|
_CACHE_FOLDER: Path = settings.MEDIA_ROOT / "com" / "calendars"
|
||||||
|
_EXTERNAL_CALENDAR = _CACHE_FOLDER / "external.ics"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_external(cls, expiration: timedelta = timedelta(hours=1)) -> Path | None:
|
||||||
|
if (
|
||||||
|
cls._EXTERNAL_CALENDAR.exists()
|
||||||
|
and timezone.make_aware(
|
||||||
|
datetime.fromtimestamp(cls._EXTERNAL_CALENDAR.stat().st_mtime)
|
||||||
|
)
|
||||||
|
+ expiration
|
||||||
|
> timezone.now()
|
||||||
|
):
|
||||||
|
return cls._EXTERNAL_CALENDAR
|
||||||
|
return cls.make_external()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def make_external(cls) -> Path | None:
|
||||||
|
calendar = urllib3.request(
|
||||||
|
"GET",
|
||||||
|
"https://calendar.google.com/calendar/ical/ae.utbm%40gmail.com/public/basic.ics",
|
||||||
|
)
|
||||||
|
if calendar.status != 200:
|
||||||
|
return None
|
||||||
|
|
||||||
|
cls._CACHE_FOLDER.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(cls._EXTERNAL_CALENDAR, "wb") as f:
|
||||||
|
_ = f.write(calendar.data)
|
||||||
|
return cls._EXTERNAL_CALENDAR
|
||||||
|
|
||||||
|
|
||||||
class Sith(models.Model):
|
class Sith(models.Model):
|
||||||
"""A one instance class storing all the modifiable infos."""
|
"""A one instance class storing all the modifiable infos."""
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user