Source code for mep.common.utils

from collections import OrderedDict
from functools import wraps
import uuid

from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.sites.models import Site


[docs]def absolutize_url(local_url, request=None): '''Convert a local url to an absolute url, with scheme and server name, based on the current configured :class:`~django.contrib.sites.models.Site`. :param local_url: local url to be absolutized, e.g. something generated by :meth:`~django.urls.reverse` ''' if local_url.startswith('https'): return local_url # add scheme and server (i.e., the http://example.com) based # on the django Sites infrastructure. root = Site.objects.get_current().domain # add http:// if necessary, since most sites docs # suggest using just the domain name if not root.startswith('http'): # if in debug mode and request is passed in, use # the current scheme (i.e. http for localhost/runserver) if settings.DEBUG and request: root = '%s://%s' % (request.scheme, root) # assume https for production sites else: root = 'https://' + root # make sure there is no double slash between site url and local url if local_url.startswith('/'): root = root.rstrip('/') return root + local_url
[docs]def alpha_pagelabels(paginator, objects, attr_meth, max_chars=None): """Generate abbreviated, alphabetical page labels for pagination items. Label format should be something like 'Ab - Ad', 'Ard - Art'. :param paginator: a django paginator :param objects: the complete list of objects paginated by the paginator :param attr_meth: method or lambda to retrieve the attribute on the object that should be used for page labels :returns: :class:`~collections.OrderedDict` where keys are page numbers and values are page labels """ # adapted from Emory findingaids # https://github.com/emory-libraries/findingaids/blob/master/findingaids/fa/utils.py#L163 page_labels = OrderedDict() labels = [] if paginator.count <= 1: # if there is not enough content to paginate, bail out return page_labels # get all labels for first and last objects on each page for i in range(paginator.num_pages): page = paginator.page(i + 1) # paginator page is 1-based # get objects at start & end of each page (paginator index also 1-based) page_label = attr_meth(objects[page.start_index() - 1]) if max_chars: page_label = page_label[:max_chars] labels.append(page_label) # don't go beyond the end of the actual number of objects end_index = min(page.end_index() - 1, paginator.count) # add end label only if not the same as first # (e.g., page of a single item) if page.start_index() - 1 != end_index: end_label = attr_meth(objects[end_index]) if max_chars: end_label = end_label[:max_chars] labels.append(end_label) # if maximum length not specified, use abbreviation logic if not max_chars: labels = abbreviate_labels(labels) # iterate over the abbreviate labels in pairs and generate page labels for i in range(0, len(labels), 2): page_index = int((i + 2) / 2) try: page_labels[page_index] = '%s%s' % \ (labels[i].strip(), labels[i + 1].strip()) except IndexError: # paginator was not created with orphan protection, # it's possible we could get a single item at the end page_labels[page_index] = labels[i].strip() return page_labels
[docs]def abbreviate_labels(labels): '''Abbreviate labels so they are as short as possible but distinct from preceding and following labels. Optionally used with :meth:`alpha_pagelabels` ''' abbreviated_labels = [] # iterate over all labels and generate the shortest distinct version for i, label in enumerate(labels): next_label = labels[i + 1] if i + 1 < len(labels) else '' prev_label = labels[i - 1] if i > 0 else '' # In the rare case that two labels are *exactly* the same, # just add the full label. if label in (next_label, prev_label): abbreviated_labels.append(label) continue # iterate through the label one letter at a time # to determine the minimum length needed to differentiate # start with one letter, go up to full length of the label if necessary abbr = '' for j, char in enumerate(label, 1): abbr += char # or abbr = label[:j] # if abbreviation is different from neighboring labels # at the current length, then use it # - compare case-insensitively # NOTE: should possibly ignore trailing punctuation here... # possible to get "Gray" / "Gray," if abbr.lower() not in (next_label[:j].lower(), prev_label[:j].lower()): break # if we don't break before the loop finishes, use # the whole label abbreviated_labels.append(abbr) return abbreviated_labels
[docs]def login_temporarily_required(func): '''Test decorator for views that have LoginRequiredOr404 enabled. Creates a user with no permissions on first run for a given class, and logs in as that user before running the decorated test method. Intended for use on Django TestCase class methods. ''' @wraps(func) def wrapper(testclass, *args, **kwargs): # if no login info is set, create the user if not hasattr(testclass, 'loginrequired_login_info'): # define login required user testclass.loginrequired_login_info = { 'username': 'loginrequired', 'password': str(uuid.uuid4()) } User.objects.create_user(**testclass.loginrequired_login_info) # login with test client as the user testclass.client.login(**testclass.loginrequired_login_info) # then call the test method func(testclass, *args, **kwargs) return wrapper