Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 56 additions & 22 deletions spoken/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,23 @@
from cms.models import Notification, Event
from .config import CACHE_RANDOM_TUTORIALS, CACHE_TR_REC, CACHE_TESTIMONIALS, CACHE_NOTIFICATIONS, CACHE_EVENTS, CACHE_TUTORIALS

def normalize_cache_component(value, max_length=50):
"""Normalize user-controlled input for cache key components.

Applies: convert to string, strip whitespace, lowercase, truncate.
Returns empty string if value is None.
"""
if value is None:
return ""
normalized = str(value).strip().lower()
return normalized[:max_length] if max_length > 0 else normalized

def get_key(identifier, key_val):
return f"{identifier}:{key_val.lower().strip().replace(' ','_')}"
"""Build a cache key by combining identifier and normalized value.

Does not perform any normalization; expects key_val to be pre-normalized.
"""
return f"{identifier}:{key_val}"

def is_valid_foss(foss):
if foss is None or foss == '': #for scenerio -- show all foss tutorials
Expand Down Expand Up @@ -102,43 +117,59 @@ def get_home_events():

# ---- Tutorials List ----
def get_tutorials_list(foss, lang):
foss = foss.lower().strip()
lang = lang.lower().strip()
cache_key = get_key("tutorials_list", f"{foss}:{lang}")
foss_norm = normalize_cache_component(foss)
lang_norm = normalize_cache_component(lang)
cache_key = f"tutorials_list:{foss_norm}:{lang_norm}"
tutorials = cache.get(cache_key)
if tutorials is not None:
return tutorials
queryset = TutorialResource.objects.filter(status__in=[1,2], tutorial_detail__foss__show_on_homepage = 1).select_related('tutorial_detail__level', 'tutorial_detail__foss', 'language')
if foss and lang:
collection = queryset.filter(tutorial_detail__foss__foss=foss, language__name=lang).order_by('tutorial_detail__level', 'tutorial_detail__order')
elif foss:
collection = queryset.filter(tutorial_detail__foss__foss=foss).order_by('tutorial_detail__level', 'tutorial_detail__order', 'language__name')
elif lang:
collection = queryset.filter(language__name=lang).order_by('tutorial_detail__foss__foss', 'tutorial_detail__level', 'tutorial_detail__order')
if foss_norm and lang_norm:
collection = queryset.filter(tutorial_detail__foss__foss=foss_norm, language__name=lang_norm).order_by('tutorial_detail__level', 'tutorial_detail__order')
elif foss_norm:
collection = queryset.filter(tutorial_detail__foss__foss=foss_norm).order_by('tutorial_detail__level', 'tutorial_detail__order', 'language__name')
elif lang_norm:
collection = queryset.filter(language__name=lang_norm).order_by('tutorial_detail__foss__foss', 'tutorial_detail__level', 'tutorial_detail__order')
else:
collection = queryset.order_by('tutorial_detail__foss__foss', 'language__name', 'tutorial_detail__level', 'tutorial_detail__order')
cache.set(cache_key, collection, timeout=CACHE_TUTORIALS)
return collection

# ---- Foss Choice For Search Bar ----
def get_foss_choice(show_on_homepage=1, lang=None):
if lang:
cache_key = get_key("tutorial_search_foss", f"{show_on_homepage}:{lang}")
lang_norm = normalize_cache_component(lang)

if lang_norm:
cache_key = f"tutorial_search_foss:{show_on_homepage}:{lang_norm}"
else:
cache_key = f"tutorial_search_foss:{show_on_homepage}:all"

foss_list_choices = cache.get(cache_key)
if foss_list_choices is not None:
return foss_list_choices

foss_list_choices = [('', '-- All Courses --'), ]
foss_qs = TutorialResource.objects.filter(status__in=[1,2], tutorial_detail__foss__show_on_homepage=show_on_homepage)
if lang:
foss_qs = foss_qs.filter(language__name=lang)
foss_list = foss_qs.values('tutorial_detail__foss__foss').annotate(
Count('id')).order_by('tutorial_detail__foss__foss').values_list('tutorial_detail__foss__foss', 'id__count').distinct()
foss_qs = TutorialResource.objects.filter(
status__in=[1,2],
tutorial_detail__foss__show_on_homepage=show_on_homepage
)
if lang_norm:
foss_qs = foss_qs.filter(language__name=lang_norm)

foss_list = foss_qs.values(
'tutorial_detail__foss__foss'
).annotate(
Count('id')
).order_by(
'tutorial_detail__foss__foss'
).values_list(
'tutorial_detail__foss__foss', 'id__count'
).distinct()

for foss_row in foss_list:
foss_list_choices.append((str(foss_row[0]), str(foss_row[0]) + ' (' + str(foss_row[1]) + ')'))
foss_list_choices.append(
(str(foss_row[0]), str(foss_row[0]) + ' (' + str(foss_row[1]) + ')')
)

cache.set(cache_key, foss_list_choices, timeout=CACHE_TUTORIALS)
return foss_list_choices
Expand All @@ -147,17 +178,20 @@ def get_foss_choice(show_on_homepage=1, lang=None):

# ---- Language Choice For Search Bar ----
def get_lang_choice(show_on_homepage=1, foss=None):
foss_norm = normalize_cache_component(foss)

if is_valid_foss(foss):
cache_key = get_key("tutorial_search_lang", f"{show_on_homepage}:{foss}")
cache_key = f"tutorial_search_lang:{show_on_homepage}:{foss_norm}"
else:
cache_key = f"tutorial_search_lang:{show_on_homepage}:all"

lang_list_choices = cache.get(cache_key)
if lang_list_choices is not None:
return lang_list_choices

lang_qs = TutorialResource.objects.filter(status__in=[1,2], tutorial_detail__foss__show_on_homepage=show_on_homepage)
if foss:
lang_qs = lang_qs.filter(tutorial_detail__foss__foss=foss)
if foss_norm:
lang_qs = lang_qs.filter(tutorial_detail__foss__foss=foss_norm)

lang_list_choices = [('', '-- All Languages --'), ]
lang_list = lang_qs.values('language__name').annotate(
Expand Down