14.3.119. crate_anon.crateweb.core.utils

crate_anon/crateweb/core/utils.py


Copyright (C) 2015, University of Cambridge, Department of Psychiatry. Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

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 <https://www.gnu.org/licenses/>.


Core utility functions for the web interface.

class crate_anon.crateweb.core.utils.JavascriptBranchNode(text: str, children: List[JavascriptTreeNode] | None = None, branch_class: str = 'caret', child_ul_class: str = 'nested')[source]

Represents a leaf node of a JavascriptTree, i.e. one that has children but does not itself perform an action.

__init__(text: str, children: List[JavascriptTreeNode] | None = None, branch_class: str = 'caret', child_ul_class: str = 'nested') None[source]
Parameters:
  • text – text to display

  • children – children of this node

  • branch_class – CSS class for the branch with caret/indicator

  • child_ul_class – CSS class for the sublist with the children

add_child(child: JavascriptTreeNode) None[source]

Adds a child at the end of our list.

html() str[source]

Returns HTML for this node.

class crate_anon.crateweb.core.utils.JavascriptLeafNode(text: str, action_html: str)[source]

Represents a leaf node of a JavascriptTree, i.e. one that launches some action.

__init__(text: str, action_html: str) None[source]
Parameters:
  • text – text to display

  • action_html – HTML associated with the action (e.g. to attach to part of the page, in order to load other content)

html() str[source]

Returns HTML for this node.

js_action_dict_key_value() str[source]

Returns a Javascript snippet for incorporating into a dictionary: node_id: action_html.

class crate_anon.crateweb.core.utils.JavascriptTree(tree_id: str, child_id_prefix: str, children: List[JavascriptTreeNode] | None = None, tree_class: str = 'tree')[source]

Represents the root node of an expanding tree implemented via Javascript.

Demo:

# Django debugging preamble
import os
import django
os.environ['DJANGO_SETTINGS_MODULE'] = 'crate_anon.crateweb.config.settings'
django.setup()

from crate_anon.crateweb.core.utils import (
    JavascriptBranchNode,
    JavascriptLeafNode,
    JavascriptTree,
)

t = JavascriptTree(
    tree_id="my_tree",
    child_id_prefix="my_tree_child_",
    children=[
        JavascriptBranchNode("RiO", [
            JavascriptLeafNode("Clinical Documents", "<p>Clinical docs</p>"),
            JavascriptLeafNode("Progress Notes", "<p>Prog notes</p>"),
        ]),
        JavascriptLeafNode("Test PDF", "<p>Test a PDF</p>"),
    ]
)
print(t.html())
print(t.js_str_html())
print(t.js_data())
__init__(tree_id: str, child_id_prefix: str, children: List[JavascriptTreeNode] | None = None, tree_class: str = 'tree') None[source]
Parameters:
  • tree_id – CSS ID for this tree

  • child_id_prefix – CSS ID prefix for children

  • children – child nodes

  • tree_class – CSS class for this tree

add_child(child: JavascriptTreeNode) None[source]

Adds a child at the end of our list.

html() str[source]

Returns HTML for this tree.

js_data() str[source]

Returns Javascript code for a dictionary mapping node IDs to action HTML.

js_str_html() str[source]

Returns HTML for this tree, as a quoted Javascript string, for embedding in Javascript code directly.

property tree_id: str

Synonym for node_id for the root node.

class crate_anon.crateweb.core.utils.JavascriptTreeNode(text: str = '', node_id: str = '', children: List[JavascriptTreeNode] | None = None)[source]

Represents a node of a JavascriptTree.

__init__(text: str = '', node_id: str = '', children: List[JavascriptTreeNode] | None = None) None[source]
Parameters:
  • text – text to display

  • node_id – CSS node ID (only the root node will use this mechanism; the rest will be autoset by the root node)

  • children – child nodes, if any

gen_descendants() Generator[JavascriptTreeNode, None, None][source]

Yields all descendants, recursively.

abstract html() str[source]

Returns HTML for this node.

set_node_id(node_id: str) None[source]

Sets the node’s ID.

crate_anon.crateweb.core.utils.get_friendly_date(date: datetime) str[source]

Returns a string form of a date/datetime.

crate_anon.crateweb.core.utils.guess_mimetype(filename: str, default: str | None = None) str | None[source]

Guesses a file’s MIME type (HTTP Content-Type) from its filename.

Parameters:
  • filename – filename

  • default – value to return if guessing fails

crate_anon.crateweb.core.utils.is_clinician(user: auth.User) bool[source]

Is the user a clinician?

crate_anon.crateweb.core.utils.is_developer(user: auth.User) bool[source]

Is the user a developer?

(Developers are a subset of superusers.)

crate_anon.crateweb.core.utils.is_superuser(user: auth.User) bool[source]

Is the user a superuser?

Function for use with a decorator, e.g.

@user_passes_test(is_superuser)
def some_view(request: HttpRequest) -> HttpResponse:
    pass

Superuser equates to Research Database Manager.

crate_anon.crateweb.core.utils.javascript_quoted_string_from_html(html: str) str[source]

Takes some HTML, which may be multiline, and makes it into a single quoted Javascript string, for when we want to muck around with the DOM.

We elect to use double-quotes.

crate_anon.crateweb.core.utils.paginate(request: HttpRequest, all_items: QuerySet | List[Any], per_page: int | None = None) Page[source]

Paginate a list or a Django QuerySet.

Parameters:
  • request – the django.http.request.HttpRequest

  • all_items – a list or a django.db.models.QuerySet

  • per_page – number of items per page

Returns:

a django.core.paginator.Page

crate_anon.crateweb.core.utils.site_absolute_url(path: str) str[source]

Returns an absolute URL for the site, given a relative part. Use like:

url = site_absolute_url(static('red.png'))
    # ... determined in part by STATIC_URL.
url = site_absolute_url(reverse(UrlNames.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:

IMPORTANT

BEWARE: reverse() will produce something different inside a request and outside it.

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).

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.

crate_anon.crateweb.core.utils.string_time_now() str[source]

Returns the current time in short-form ISO-8601 UTC, for filenames.

crate_anon.crateweb.core.utils.url_with_querystring(path: str, querydict: QueryDict | None = None, **kwargs: Any) str[source]

Add GET arguments to a URL from named arguments or a QueryDict.

Parameters:
  • path – a base URL path

  • querydict – a django.http.QueryDict

  • **kwargs – as an alternative to the querydict, we can use kwargs as a dictionary of query attribute-value pairs

Returns:

the URL with query parameters

Note

This does not currently sort query parameters. Doing that might be slightly advantageous for caching, i.e. to ensure that “path?a=1&b=2” is treated as identical to “path?b=2&a=1”. However, it is legal for servers to treat them as ordered. See https://stackoverflow.com/questions/43893853/http-cache-control-and-params-order.