Source code for crate_anon.crateweb.core.utils

#!/usr/bin/env python
# crate_anon/crateweb/core/utils.py

"""
===============================================================================

    Copyright (C) 2015-2018 Rudolf Cardinal (rudolf@pobox.com).

    This file is part of CRATE.

    CRATE is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CRATE is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CRATE. If not, see <http://www.gnu.org/licenses/>.

===============================================================================
"""

import datetime
import logging
import urllib.parse
from typing import Any, Dict, List, Union

from django.conf import settings
from django.core.paginator import Paginator, EmptyPage, Page, PageNotAnInteger
from django.db.models import QuerySet
from django.http import QueryDict
from django.http.request import HttpRequest
from django.utils import timezone
from crate_anon.crateweb.userprofile.models import get_per_page

log = logging.getLogger(__name__)


# =============================================================================
# User tests/user profile
# =============================================================================

[docs]def is_superuser(user: settings.AUTH_USER_MODEL) -> bool: """ Function for user with decorator, e.g. @user_passes_test(is_superuser) Superuser equates to Research Database Manager. """ # https://docs.djangoproject.com/en/dev/topics/auth/default/#django.contrib.auth.decorators.user_passes_test # noqa return user.is_superuser
def is_developer(user: settings.AUTH_USER_MODEL) -> bool: if not user.is_authenticated: return False # won't have a profile return user.profile.is_developer def is_clinician(user: settings.AUTH_USER_MODEL) -> bool: if not user.is_authenticated: return False # won't have a profile return user.profile.is_clinician # ============================================================================= # Forms # ============================================================================= def paginate(request: HttpRequest, all_items: Union[QuerySet, List[Any]], per_page: int = None) -> Page: if per_page is None: per_page = get_per_page(request) paginator = Paginator(all_items, per_page) # noinspection PyCallByClass,PyArgumentList requested_page = request.GET.get('page') try: return paginator.page(requested_page) except PageNotAnInteger: return paginator.page(1) except EmptyPage: return paginator.page(paginator.num_pages) # ============================================================================= # URL creation # =============================================================================
[docs]def url_with_querystring(path: str, querydict: Dict[str, Any] = None, **kwargs) -> str: """Add GET arguments to a URL from named arguments or a QueryDict.""" if querydict is not None and not isinstance(querydict, QueryDict): raise ValueError("Bad querydict value") if querydict and kwargs: raise ValueError("Pass either a QueryDict or kwargs") if querydict: querystring = querydict.urlencode() else: querystring = urllib.parse.urlencode(kwargs) return path + '?' + querystring
[docs]def site_absolute_url(path: str) -> str: """ Returns an absolute URL for the site, given a relative part. Use like: .. code-block:: python url = site_absolute_url(static('red.png')) # ... determined in part by STATIC_URL. url = site_absolute_url(reverse('clinician_response', args=[self.id])) # ... determined by SCRIPT_NAME or FORCE_SCRIPT_NAME # ... which is context-dependent: see below We need to generate links to our site outside the request environment, e.g. for inclusion in e-mails, even when we're generating the e-mails offline via Celery. There's no easy way to do this automatically (site path information comes in only via requests), so we put it in the settings. See also: - http://stackoverflow.com/questions/4150258/django-obtaining-the-absolute-url-without-access-to-a-request-object # noqa - https://fragmentsofcode.wordpress.com/2009/02/24/django-fully-qualified-url/ # noqa **IMPORTANT** BEWARE: reverse() will produce something different inside a request and outside it. - http://stackoverflow.com/questions/32340806/django-reverse-returns-different-values-when-called-from-wsgi-or-shell # noqa So the only moderately clean way of doing this is to do this in the Celery backend jobs, for anything that uses Django URLs (e.g. reverse) -- NOT necessary for anything using only static URLs (e.g. pictures in PDFs). .. code-block:: python from django.conf import settings from django.urls import set_script_prefix set_script_prefix(settings.FORCE_SCRIPT_NAME) But that does at least mean we can use the same method for static and Django URLs. """ url = settings.DJANGO_SITE_ROOT_ABSOLUTE_URL + path log.debug("site_absolute_url: {} -> {}".format(path, url)) return url
# ============================================================================= # Formatting # ============================================================================= def get_friendly_date(date: datetime.datetime) -> str: if date is None: return "" try: return date.strftime("%d %B %Y") # e.g. 03 December 2013 except Exception as e: raise type(e)(str(e) + ' [value was {}]'.format(repr(date))) # ============================================================================= # Date/time # =============================================================================
[docs]def string_time_now() -> str: """Returns current time in short-form ISO-8601 UTC, for filenames.""" return timezone.now().strftime("%Y%m%dT%H%M%SZ")