Merged in feature/refactor-frontend-url-backend (pull request #46)
Feature/refactor frontend url backend Approved-by: Christian Cueni
This commit is contained in:
commit
0c0c65cc22
|
|
@ -532,11 +532,6 @@ if "django_redis.cache.RedisCache" in env("IT_DJANGO_CACHE_BACKEND", default="")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
CACHES["api_page_cache"] = {
|
|
||||||
"BACKEND": "django.core.cache.backends.db.DatabaseCache",
|
|
||||||
"LOCATION": "django_cache_table_api_page",
|
|
||||||
}
|
|
||||||
|
|
||||||
# OAuth/OpenId Connect
|
# OAuth/OpenId Connect
|
||||||
IT_OAUTH_TENANT_ID = env.str("IT_OAUTH_TENANT_ID", default=None)
|
IT_OAUTH_TENANT_ID = env.str("IT_OAUTH_TENANT_ID", default=None)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ class CompetenceProfilePage(CourseBasePage):
|
||||||
super(CompetenceProfilePage, self).full_clean(*args, **kwargs)
|
super(CompetenceProfilePage, self).full_clean(*args, **kwargs)
|
||||||
|
|
||||||
def get_frontend_url(self):
|
def get_frontend_url(self):
|
||||||
return f"/course/{self.get_parent().slug}/competence"
|
return f"/course/{self.slug.replace('-competence', '')}/competence"
|
||||||
|
|
||||||
|
|
||||||
class CompetencePage(CourseBasePage):
|
class CompetencePage(CourseBasePage):
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import logging
|
||||||
|
|
||||||
import structlog
|
import structlog
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import caches
|
|
||||||
from rest_framework.throttling import UserRateThrottle
|
from rest_framework.throttling import UserRateThrottle
|
||||||
from structlog.types import EventDict
|
from structlog.types import EventDict
|
||||||
|
|
||||||
|
|
@ -51,16 +50,3 @@ def first_true(iterable, default=False, pred=None):
|
||||||
# first_true([a,b,c], x) --> a or b or c or x
|
# first_true([a,b,c], x) --> a or b or c or x
|
||||||
# first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
|
# first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
|
||||||
return next(filter(pred, iterable), default)
|
return next(filter(pred, iterable), default)
|
||||||
|
|
||||||
|
|
||||||
def get_api_page_cache():
|
|
||||||
return caches["api_page_cache"]
|
|
||||||
|
|
||||||
|
|
||||||
def api_page_cache_get_or_set(key, func, timeout=60 * 60 * 8):
|
|
||||||
cache = get_api_page_cache()
|
|
||||||
value = cache.get(key)
|
|
||||||
if value is None:
|
|
||||||
value = func()
|
|
||||||
cache.set(key, value, timeout=timeout)
|
|
||||||
return value
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
from django.core.cache import caches
|
|
||||||
from django.core.management.base import BaseCommand
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
self.stdout.write("Clearing course cache")
|
|
||||||
caches["api_page_cache"].clear()
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
import structlog
|
|
||||||
from django.core.cache import caches
|
|
||||||
from django.db.models.signals import post_delete, post_save
|
|
||||||
from wagtail.models import Page
|
|
||||||
|
|
||||||
logger = structlog.get_logger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def get_all_subclasses(cls):
|
|
||||||
all_subclasses = []
|
|
||||||
|
|
||||||
for subclass in cls.__subclasses__():
|
|
||||||
all_subclasses.append(subclass)
|
|
||||||
all_subclasses.extend(get_all_subclasses(subclass))
|
|
||||||
|
|
||||||
return all_subclasses
|
|
||||||
|
|
||||||
|
|
||||||
def invalidate_api_page_cache(sender, **kwargs):
|
|
||||||
logger.debug("invalidate api_page_cache", label="api_page_cache")
|
|
||||||
caches["api_page_cache"].clear()
|
|
||||||
|
|
||||||
|
|
||||||
for subclass in get_all_subclasses(Page):
|
|
||||||
post_save.connect(invalidate_api_page_cache, subclass)
|
|
||||||
post_delete.connect(invalidate_api_page_cache, subclass)
|
|
||||||
|
|
@ -5,7 +5,6 @@ from rest_framework.exceptions import PermissionDenied
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from wagtail.models import Page
|
from wagtail.models import Page
|
||||||
|
|
||||||
from vbv_lernwelt.core.utils import api_page_cache_get_or_set
|
|
||||||
from vbv_lernwelt.course.models import (
|
from vbv_lernwelt.course.models import (
|
||||||
CircleDocument,
|
CircleDocument,
|
||||||
CourseCompletion,
|
CourseCompletion,
|
||||||
|
|
@ -39,10 +38,7 @@ def course_page_api_view(request, slug):
|
||||||
if not has_course_access_by_page_request(request, page):
|
if not has_course_access_by_page_request(request, page):
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
|
|
||||||
data = api_page_cache_get_or_set(
|
data = page.specific.get_serializer_class()(page.specific).data
|
||||||
key=request.get_full_path(),
|
|
||||||
func=lambda: page.specific.get_serializer_class()(page.specific).data,
|
|
||||||
)
|
|
||||||
|
|
||||||
return Response(data)
|
return Response(data)
|
||||||
except PermissionDenied as e:
|
except PermissionDenied as e:
|
||||||
|
|
|
||||||
|
|
@ -937,12 +937,12 @@ def create_circle_vernetzen(lp, title="Vernetzen"):
|
||||||
LearningSequenceFactory(title="Training", parent=circle, icon="it-icon-ls-watch")
|
LearningSequenceFactory(title="Training", parent=circle, icon="it-icon-ls-watch")
|
||||||
LearningUnitFactory(title="Onlinetrainings", parent=circle)
|
LearningUnitFactory(title="Onlinetrainings", parent=circle)
|
||||||
LearningContentFactory(
|
LearningContentFactory(
|
||||||
title="???",
|
title="Unknown ???",
|
||||||
parent=circle,
|
parent=circle,
|
||||||
)
|
)
|
||||||
LearningUnitFactory(title="Webinare", parent=circle)
|
LearningUnitFactory(title="Webinare", parent=circle)
|
||||||
LearningContentFactory(
|
LearningContentFactory(
|
||||||
title="???",
|
title="Unknown ???",
|
||||||
parent=circle,
|
parent=circle,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -968,7 +968,7 @@ def create_circle_pruefungsvorbereitung(lp, title="Prüfungsvorbereitung"):
|
||||||
LearningSequenceFactory(title="Aufbau", parent=circle, icon="it-icon-ls-watch")
|
LearningSequenceFactory(title="Aufbau", parent=circle, icon="it-icon-ls-watch")
|
||||||
LearningUnitFactory(title="Aufbau und Struktur", parent=circle)
|
LearningUnitFactory(title="Aufbau und Struktur", parent=circle)
|
||||||
LearningContentFactory(
|
LearningContentFactory(
|
||||||
title="???",
|
title="Unknown ???",
|
||||||
parent=circle,
|
parent=circle,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import re
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
from wagtail.admin.panels import FieldPanel, StreamFieldPanel
|
from wagtail.admin.panels import FieldPanel, StreamFieldPanel
|
||||||
|
|
@ -42,7 +44,7 @@ class LearningPath(CourseBasePage):
|
||||||
return f"{self.title}"
|
return f"{self.title}"
|
||||||
|
|
||||||
def get_frontend_url(self):
|
def get_frontend_url(self):
|
||||||
return f"/course/{self.get_parent().slug}/learn"
|
return f"/course/{self.slug.replace('-lp', '')}/learn"
|
||||||
|
|
||||||
|
|
||||||
class Topic(CourseBasePage):
|
class Topic(CourseBasePage):
|
||||||
|
|
@ -95,8 +97,11 @@ class Circle(CourseBasePage):
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_frontend_url(self):
|
def get_frontend_url(self):
|
||||||
short_slug = self.slug.replace(f"{self.get_parent().slug}-circle-", "")
|
r = re.compile(r"^(?P<coursePart>.+?)-lp-circle-(?P<circlePart>.+?)$")
|
||||||
return f"{self.get_parent().specific.get_frontend_url()}/{short_slug}"
|
m = r.match(self.slug)
|
||||||
|
if m is None:
|
||||||
|
return "ERROR: could not parse slug"
|
||||||
|
return f"/course/{m.group('coursePart')}/learn/{m.group('circlePart')}"
|
||||||
|
|
||||||
def full_clean(self, *args, **kwargs):
|
def full_clean(self, *args, **kwargs):
|
||||||
self.slug = find_slug_with_parent_prefix(self, "circle")
|
self.slug = find_slug_with_parent_prefix(self, "circle")
|
||||||
|
|
@ -145,8 +150,13 @@ class LearningSequence(CourseBasePage):
|
||||||
super(LearningSequence, self).full_clean(*args, **kwargs)
|
super(LearningSequence, self).full_clean(*args, **kwargs)
|
||||||
|
|
||||||
def get_frontend_url(self):
|
def get_frontend_url(self):
|
||||||
short_slug = self.slug.replace(f"{self.get_parent().slug}-", "")
|
r = re.compile(
|
||||||
return f"{self.get_parent().specific.get_frontend_url()}#{short_slug}"
|
r"^(?P<coursePart>.+?)-lp-circle-(?P<circlePart>.+?)-ls-(?P<lsPart>.+?)$"
|
||||||
|
)
|
||||||
|
m = r.match(self.slug)
|
||||||
|
if m is None:
|
||||||
|
return "ERROR: could not parse slug"
|
||||||
|
return f"/course/{m.group('coursePart')}/learn/{m.group('circlePart')}#ls-{m.group('lsPart')}"
|
||||||
|
|
||||||
|
|
||||||
class LearningUnit(CourseBasePage):
|
class LearningUnit(CourseBasePage):
|
||||||
|
|
@ -186,12 +196,20 @@ class LearningUnit(CourseBasePage):
|
||||||
super(LearningUnit, self).full_clean(*args, **kwargs)
|
super(LearningUnit, self).full_clean(*args, **kwargs)
|
||||||
|
|
||||||
def get_frontend_url(self):
|
def get_frontend_url(self):
|
||||||
short_slug = self.slug.replace(f"{self.get_parent().slug}-lu-", "")
|
r = re.compile(
|
||||||
return f"{self.get_parent().specific.get_frontend_url()}#lu-{short_slug}"
|
r"^(?P<coursePart>.+?)-lp-circle-(?P<circlePart>.+?)-lu-(?P<luPart>.+?)$"
|
||||||
|
)
|
||||||
|
m = r.match(self.slug)
|
||||||
|
if m is None:
|
||||||
|
return "ERROR: could not parse slug"
|
||||||
|
return f"/course/{m.group('coursePart')}/learn/{m.group('circlePart')}#lu-{m.group('luPart')}"
|
||||||
|
|
||||||
def get_evaluate_url(self):
|
def get_evaluate_url(self):
|
||||||
short_slug = self.slug.replace(f"{self.get_parent().slug}-lu-", "")
|
r = re.compile(
|
||||||
return f"{self.get_parent().specific.get_frontend_url()}/evaluate/{short_slug}"
|
r"^(?P<coursePart>.+?)-lp-circle-(?P<circlePart>.+?)-lu-(?P<luPart>.+?)$"
|
||||||
|
)
|
||||||
|
m = r.match(self.slug)
|
||||||
|
return f"/course/{m.group('coursePart')}/learn/{m.group('circlePart')}/evaluate/{m.group('luPart')}"
|
||||||
|
|
||||||
def get_admin_display_title(self):
|
def get_admin_display_title(self):
|
||||||
return f"LE: {self.draft_title}"
|
return f"LE: {self.draft_title}"
|
||||||
|
|
@ -263,8 +281,13 @@ class LearningContent(CourseBasePage):
|
||||||
verbose_name = "Learning Content"
|
verbose_name = "Learning Content"
|
||||||
|
|
||||||
def get_frontend_url(self):
|
def get_frontend_url(self):
|
||||||
short_slug = self.slug.replace(f"{self.get_parent().slug}-lc-", "")
|
r = re.compile(
|
||||||
return f"{self.get_parent().specific.get_frontend_url()}/{short_slug}"
|
r"^(?P<coursePart>.+?)-lp-circle-(?P<circlePart>.+?)-lc-(?P<lcPart>.+)$"
|
||||||
|
)
|
||||||
|
m = r.match(self.slug)
|
||||||
|
if m is None:
|
||||||
|
return "ERROR: could not parse slug"
|
||||||
|
return f"/course/{m.group('coursePart')}/learn/{m.group('circlePart')}/{m.group('lcPart')}"
|
||||||
|
|
||||||
def full_clean(self, *args, **kwargs):
|
def full_clean(self, *args, **kwargs):
|
||||||
self.slug = find_slug_with_parent_prefix(self, "lc")
|
self.slug = find_slug_with_parent_prefix(self, "lc")
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import re
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
from wagtail import blocks, fields
|
from wagtail import blocks, fields
|
||||||
|
|
@ -89,8 +91,9 @@ class MediaCategoryPage(CourseBasePage):
|
||||||
super(MediaCategoryPage, self).full_clean(*args, **kwargs)
|
super(MediaCategoryPage, self).full_clean(*args, **kwargs)
|
||||||
|
|
||||||
def get_frontend_url(self):
|
def get_frontend_url(self):
|
||||||
short_slug = self.slug.replace(f"{self.get_parent().slug}-cat-", "")
|
r = re.compile(r"^(?P<coursePart>.+?)-media-cat-(?P<catPart>.+)$")
|
||||||
return f"{self.get_parent().specific.get_frontend_url()}/category/{short_slug}"
|
m = r.match(self.slug)
|
||||||
|
return f"/media/{m.group('coursePart')}-media/category/{m.group('catPart')}"
|
||||||
|
|
||||||
|
|
||||||
class LibraryDocument(AbstractDocument):
|
class LibraryDocument(AbstractDocument):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue