Source code for common.utils

__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
__license__ = "AGPL v3"


from datetime import timedelta

from django.core.mail import EmailMultiAlternatives
from django.db.models import Q
from django.template import loader

from .constants import CHARACTER_ALTERNATIVES


[docs]def alternative_spellings(text): """ From a string, return a list with alternative spellings. Text searches can be run with accents stripped away. This is however insufficient if character sequences are interpreted as accented characters. This method provides a set of alternative spellings based on beyond-ignoring-accents substitutions. The substitutions which are handled are: * ae to/from ä (also capitalized) * oe to/from ö (also capitalized) * ue to/from ü (also capitalized) Limitations: * each substitution in the substitutions dictionary is applied to the whole of the text string (so this does not cover cases where a text string has inconsistent spelling mixing the different alternatives) """ alternatives = set() for key, val in CHARACTER_ALTERNATIVES.items(): alternatives.add(text.replace(key, val)) return alternatives.difference((text,))
[docs]def Q_with_alternative_spellings(**lookup_dict): """ Dress an existing Q query with alternative spellings. Keyword parameters: - lookup_dict: a single-entry dict giving the query Conditions: - lookup_dict contains a single entry - the to-be-match item must be of string type """ if not len(lookup_dict) == 1: raise TypeError query = Q(**lookup_dict) query.connector = 'OR' lookup = query.children[0][0] text = query.children[0][1] if not isinstance(text, str): raise TypeError(text) alts = alternative_spellings(text) for alt in alts: query.children.append((lookup, alt)) return query
[docs]def hslColorWheel(N=10, index=0, saturation=50, lightness=50): """ Distributes colors into N values around a color wheel, according to hue-saturation-lightness (HSL). index takes values from 0 to N-1. """ hue = int(index * 360/N % 360) saturation = max(saturation, 0) saturation = min(saturation, 100) lightness = max(lightness, 0) lightness = min(lightness, 100) return 'hsl(%s, %s%%, %s%%)' % (str(hue), str(saturation), str(lightness))
[docs]def workdays_between(datetime_from, datetime_until): """Return number of complete workdays. Given two datetime parameters, this function returns the number of complete workdays (defined as weekdays) separating them. """ duration = datetime_until - datetime_from days = int(duration.total_seconds() // 86400) weeks = int(days // 7) daygenerator = (datetime_until - timedelta(x) for x in range(days - 7 * weeks)) workdays = 5 * weeks + sum(1 for day in daygenerator if day.weekday() < 5) return workdays
[docs]class BaseMailUtil(object): mail_sender = 'no-reply@scipost.org' mail_sender_title = ''
[docs] @classmethod def load(cls, _dict, request=None): cls._context = _dict cls._context['request'] = request for var_name in _dict: setattr(cls, var_name, _dict[var_name])
def _send_mail(cls, template_name, recipients, subject, extra_bcc=None, extra_context={}): """ Call this method from a classmethod to send emails. The template will have context variables defined appended from the `load` method. Arguments: template_name -- The .html template to use in the mail. The name be used to get the following two templates: `email/<template_name>.txt` (non-HTML) `email/<template_name>.html` recipients -- List of mailaddresses to send to mail to. subject -- The subject of the mail. """ template = loader.get_template('email/%s.txt' % template_name) html_template = loader.get_template('email/%s.html' % template_name) cls._context.update(extra_context) message = template.render(cls._context) html_message = html_template.render(cls._context) bcc_list = [cls.mail_sender] if extra_bcc: bcc_list += extra_bcc email = EmailMultiAlternatives( 'SciPost: ' + subject, # message, message, '%s <%s>' % (cls.mail_sender_title, cls.mail_sender), recipients, bcc=bcc_list, reply_to=[cls.mail_sender]) email.attach_alternative(html_message, 'text/html') email.send(fail_silently=False)