Newer
Older
from django.conf import settings
# This is called during offline validation, where Django isn't really set up.
# The getattr makes this usable.
facilities = getattr(settings, "RELATE_FACILITIES", None)
if facilities is None:
# Only happens during offline validation. Suppresses errors there.
return None
if callable(facilities):
from course.views import get_now_or_fake_time
now_datetime = get_now_or_fake_time(request)
result = facilities(now_datetime)
if not isinstance(result, dict):
raise RuntimeError("RELATE_FACILITIES must return a dictionary")
return result
else:
return facilities
class FacilityFindingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
pretend_facilities = request.session.get("relate_pretend_facilities")
if pretend_facilities is not None:
facilities = pretend_facilities
else:
import ipaddress
remote_address = ipaddress.ip_address(
str(request.META["REMOTE_ADDR"]))
facilities = set()
for name, props in get_facilities_config(request).items():
ip_ranges = props.get("ip_ranges", [])
for ir in ip_ranges:
if remote_address in ipaddress.ip_network(str(ir)):
facilities.add(name)
request.relate_facilities = frozenset(facilities)
return self.get_response(request)
def get_col_contents_or_empty(row, index):
if index >= len(row):
return ""
else:
return row[index]
def csv_data_importable(file_contents, column_idx_list, header_count):
import csv
spamreader = csv.reader(file_contents)
n_header_row = 0
except Exception as e:
err_msg = type(e).__name__
err_str = str(e)
if err_msg == "Error":
err_msg = ""
else:
err_msg += ": "
err_msg += err_str
if "line contains NUL" in err_str:
# This message changed over time.
# Make the message uniform to please the tests.
err_msg = err_msg.replace("NULL byte", "NUL")
err_msg += _("Are you sure the file is a CSV file other "
"than a Microsoft Excel file?")
return False, (
string_concat(
pgettext_lazy("Starting of Error message", "Error"),
": %s" % err_msg))
from itertools import chain
for row in chain([row0], spamreader):
n_header_row += 1
if n_header_row <= header_count:
continue
try:
for column_idx in column_idx_list:
if column_idx is not None:
str(get_col_contents_or_empty(row, column_idx-1))
except UnicodeDecodeError:
return False, (
_("Error: Columns to be imported contain "
"non-ASCII characters. "
"Please save your CSV file as utf-8 encoded "
"and import again.")
)
except Exception as e:
return False, (
string_concat(
pgettext_lazy("Starting of Error message",
"Error"),
": %(err_type)s: %(err_str)s")
% {
"err_type": type(e).__name__,
"err_str": str(e)}
)
return True, ""
def will_use_masked_profile_for_email(
recipient_email: None | str | list[str]) -> bool:
if not recipient_email:
return False
if not isinstance(recipient_email, list):
recipient_email = [recipient_email]
from course.models import Participation
recepient_participations = (
Participation.objects.filter(
user__email__in=recipient_email
))
from course.constants import participation_permission as pperm
for part in recepient_participations:
if part.has_permission(pperm.view_participant_masked_profile):
return True
return False
def get_course_specific_language_choices() -> tuple[tuple[str, Any], ...]:
from collections import OrderedDict
all_options = ((settings.LANGUAGE_CODE, None),) + tuple(settings.LANGUAGES)
filtered_options_dict = OrderedDict(all_options)
def get_default_option() -> tuple[str, str]:
# For the default language used, if USE_I18N is True, display
# "Disabled". Otherwise display its lang info.
if not settings.USE_I18N:
formatted_descr = (
get_formatted_options(settings.LANGUAGE_CODE, None)[1])
else:
formatted_descr = _("disabled (i.e., displayed language is "
"determined by user's browser preference)")
return "", string_concat("%s: " % _("Default"), formatted_descr)
def get_formatted_options(
lang_code: str, lang_descr: str | None) -> tuple[str, str]:
if lang_descr is None:
lang_descr = OrderedDict(settings.LANGUAGES).get(lang_code)
if lang_descr is None:
try:
lang_info = translation.get_language_info(lang_code)
lang_descr = lang_info["name_translated"]
except KeyError:
return (lang_code.strip(), lang_code)
return (lang_code.strip(),
string_concat(_(lang_descr), " (%s)" % lang_code))
filtered_options = (
[get_default_option()]
+ [get_formatted_options(k, v)
for k, v in filtered_options_dict.items()])
# filtered_options[1] is the option for settings.LANGUAGE_CODE
# it's already displayed when settings.USE_I18N is False
if not settings.USE_I18N:
filtered_options.pop(1)
return tuple(filtered_options)
class LanguageOverride(ContextDecorator):
def __init__(self, course: Course, deactivate: bool = False) -> None:
self.course = course
self.deactivate = deactivate
if course.force_lang:
self.language = course.force_lang
else:
from django.conf import settings
self.language = settings.RELATE_ADMIN_EMAIL_LOCALE
def __enter__(self) -> None:
self.old_language = translation.get_language()
if self.language is not None:
translation.activate(self.language)
else:
translation.deactivate_all()
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
if self.old_language is None:
translation.deactivate_all()
elif self.deactivate:
translation.deactivate()
else:
translation.activate(self.old_language)
class RelateJinjaMacroBase:
def __init__(
self,
course: Course | None,
repo: Repo_ish,
commit_sha: bytes) -> None:
self.course = course
self.repo = repo
self.commit_sha = commit_sha
@property
def name(self):
# The name of the method used in the template
raise NotImplementedError()
def __call__(self, *args: Any, **kwargs: Any) -> str:
raise NotImplementedError()