import datetime
import ipaddress
import logging
import string
import subprocess
from typing import Collection, Dict, Set # noqa
from urllib import parse
from django.conf import settings
from django.utils import timezone
from ..apps.emerg.views import get_emerg
logger = logging.getLogger("intranet.settings")
[docs]def awaredate():
# Note that date objects are always naive, so we have to use datetime for proper timezone support.
return timezone.localtime().replace(hour=0, minute=0, second=0, microsecond=0)
[docs]def get_id(obj):
if obj is None:
return None
try:
return int(obj)
except ValueError:
return None
[docs]def parse_db_url(db_url):
parse.uses_netloc.append("postgres")
if db_url is None:
raise Exception("You must set SECRET_DATABASE_URL in secret.py")
url = parse.urlparse(db_url)
args = {"NAME": url.path[1:], "USER": url.username, "PASSWORD": url.password}
if url.hostname:
args.update({"HOST": url.hostname})
return args
[docs]def get_current_commit_short_hash(workdir):
cmd = ["git", "-C", workdir, "rev-parse", "--short", "HEAD"]
return subprocess.check_output(cmd, universal_newlines=True).strip()
[docs]def get_current_commit_long_hash(workdir):
cmd = ["git", "-C", workdir, "rev-parse", "HEAD"]
return subprocess.check_output(cmd, universal_newlines=True).strip()
[docs]def get_current_commit_info():
cmd = ["git", "show", "-s", "--format='Commit %h\n%ad'", "HEAD"]
return subprocess.check_output(cmd, universal_newlines=True).strip()
[docs]def get_current_commit_date():
cmd = ["git", "show", "-s", "--format=%ci", "HEAD"]
return subprocess.check_output(cmd, universal_newlines=True).strip()
[docs]def get_current_commit_github_url(workdir):
return "https://github.com/tjcsl/ion/commit/{}".format(get_current_commit_short_hash(workdir))
[docs]class InvalidString(str):
"""An error for undefined context variables in templates."""
def __mod__(self, other):
logger.warning('Undefined variable or unknown value for: "%s"', other)
return ""
[docs]class MigrationMock:
seen = set() # type: Set[str]
def __contains__(self, mod):
return True
def __getitem__(self, mod):
if mod in self.seen:
return "migrations"
self.seen.add(mod)
return None
[docs]class GlobList(list):
"""A list of glob-style strings."""
[docs] def __contains__(self, key):
"""Check if a string matches a glob in the list."""
# request.HTTP_X_FORWARDED_FOR contains can contain a comma delimited
# list of IP addresses, if the user is using a proxy
if "," in key:
key = key.split(",", 1)[0]
try:
for item in self:
if ipaddress.ip_address(key) in ipaddress.ip_network(item) and key != "127.0.0.1":
return True
except ValueError:
pass
return False
[docs]def is_entirely_digit(digit_str):
return all(c in string.digits for c in digit_str)
[docs]def join_nicely(items: Collection) -> str:
"""Joins together a list of items in a human-readable format. Examples:
>>> join_nicely([])
''
>>> join_nicely(['a'])
'a'
>>> join_nicely(['a', 'b'])
'a and b'
>>> join_nicely(['a', 'b', 'c'])
'a, b, and c'
Args:
items: The items to join together.
Returns:
The resulting joined-together string.
"""
items = tuple(map(str, items))
return " and ".join(items) if len(items) <= 2 else ", ".join(items[:-1]) + ", and " + items[-1]
[docs]def single_css_map(name):
return {name: {"source_filenames": ["css/%s.scss" % name], "output_filename": "css/%s.css" % name}}
[docs]def get_fcps_emerg(request):
"""Return FCPS emergency information."""
try:
emerg = get_emerg()
except Exception as e:
logger.info("Unable to fetch FCPS emergency info: %s", e)
emerg = {"status": False}
if emerg["status"] or ("show_emerg" in request.GET):
msg = emerg["message"]
return msg
return False
[docs]def get_ap_week_warning(request):
"""
ap_day = timezone.localtime()
if ap_day.hour > 16:
ap_day += datetime.timedelta(days=1)
while ap_day.weekday() >= 5: # Saturday or Sunday
ap_day += datetime.timedelta(days=1)
data = {"day": ap_day.day, "date": request.GET.get("date", None)}
if ap_day.month == 5 and 4 <= ap_day.day <= 17:
return get_template("auth/ap_week_schedule.html").render(data)
"""
return False
[docs]def get_warning_html(warnings, dashboard=False, login=False):
"""
Returns HTML for announcements.models.WarningAnnouncement objects.
Dashboard and login logic is processed here because they cannot be filtered using .filter().
Global warnings are pre-filtered and passed directly to this function from the context processor.
"""
if dashboard:
warnings = [warning for warning in warnings if warning.show_on_dashboard]
elif login:
warnings = [warning for warning in warnings if warning.show_on_login]
html = ""
counter = 0
for warning in warnings:
html += f"""\
<h3 class='warning-title'>\
<i class='fas fa-exclamation-triangle'></i> \
{warning.title}\
{'<i class="fa fa-chevron-down warning-toggle-icon"></i>' if counter == 0 else ''} \
</h3>\
<div class='warning-content'>\
{warning.content}
</div>\
"""
counter += 1
return html
GLOBAL_THEMES = {
"snow": {"js": "themes/snow/snow.js", "css": "themes/snow/snow.css"},
"piday": {"js": "themes/piday/piday.js", "css": "themes/piday/piday.css"},
"halloween": {"js": "themes/halloween/halloween.js", "css": "themes/halloween/halloween.css"},
"april_fools": {"js": "themes/april_fools/april_fools.js", "css": "themes/april_fools/april_fools.css"},
}
[docs]def get_theme_name() -> str:
"""Get the name of the currently active special event theme."""
today = timezone.localdate()
if today.month in (12, 1):
first_monday_of_month = (8 - datetime.date(today.year, today.month, 1).weekday()) % 7
if (today.month == 12 and today.day >= first_monday_of_month) or (today.month == 1 and today.day < first_monday_of_month + 7):
return "snow"
elif today.month == 3 and (14 <= today.day <= 16):
return "piday"
elif (today.month == 10 and 27 <= today.day <= 31) or (today.month == 11 and today.day == 1):
return "halloween"
# Enable when a new idea for April Fools 2024 comes around
elif (today.month == 3 and (30 <= today.day <= 31)) or (today.month == 4 and (1 <= today.day <= 7)):
return "april_fools"
return None
[docs]def get_theme() -> Dict[str, Dict[str, str]]:
"""Return JS and CSS for the currently active special event theme."""
return GLOBAL_THEMES.get(get_theme_name(), {})
[docs]def dark_mode_enabled(request):
if request.GET.get("dark", None):
return request.GET["dark"] in ["1", "True"]
if get_theme_name() == "halloween" and request.COOKIES.get("disable-halloween", None) != "1":
return True
if request.user.is_authenticated:
return request.user.dark_mode_properties.dark_mode_enabled
else:
return request.COOKIES.get("dark-mode-enabled", "") == "1"