import logging import unicodedata from datetime import datetime from datetime import timedelta from decimal import Decimal from decimal import ROUND_HALF_DOWN from django.core.exceptions import ValidationError from django.db import models from django.utils import timezone from django.utils.translation import gettext_lazy as _ logger = logging.getLogger(__name__) def file_size_validator(max_upload_size): """ Returns a function checking if the supplied file has file size less or equal than `max_upload_size` in MB. """ def check_file_size(value): limit = max_upload_size * 1024 * 1024 if value.size > limit: raise ValidationError( _("Please keep filesize under {} MiB. Current filesize: {:10.2f} MiB.").format( max_upload_size, value.size / 1024 / 1024 ) ) return check_file_size class RestrictedFileField(models.FileField): def __init__(self, *args, **kwargs): if "max_upload_size" in kwargs: self.max_upload_size = kwargs.pop("max_upload_size") else: self.max_upload_size = None if "content_types" in kwargs: self.content_types = kwargs.pop("content_types") else: self.content_types = None super().__init__(*args, **kwargs) self.validators = [file_size_validator(self.max_upload_size)] def clean(self, *args, **kwargs): data = super().clean(*args, **kwargs) f = data.file try: content_type = f.content_type if self.content_types is not None and content_type not in self.content_types: raise ValidationError(_("Filetype not supported.")) if self.max_upload_size is not None and f._size > self.max_upload_size: raise ValidationError( _("Please keep filesize under {}. Current filesize: {}").format( self.max_upload_size, f._size ) ) except AttributeError as e: logger.warning(e) return data def cvt_to_decimal(f): return Decimal(f).quantize(Decimal(".01"), rounding=ROUND_HALF_DOWN) def get_member(request): if not hasattr(request.user, "member"): return None else: return request.user.member def normalize_name(raw, nospaces=True, noumlaut=True): if noumlaut: raw = raw.replace("ö", "oe").replace("ä", "ae").replace("ü", "ue") if nospaces: raw = raw.replace(" ", "_") return unicodedata.normalize("NFKD", raw).encode("ascii", "ignore").decode("ascii") def normalize_filename(filename, append_date=True, date=None): if append_date and not date: date = datetime.today() if date: filename = filename + "_" + date.strftime("%d_%m_%Y") filename = filename.replace(" ", "_").replace("&", "").replace("/", "_") # drop umlauts, accents etc. return unicodedata.normalize("NFKD", filename).encode("ASCII", "ignore").decode() def coming_midnight(): base = timezone.now() + timezone.timedelta(days=1) return timezone.datetime( year=base.year, month=base.month, day=base.day, hour=0, minute=0, second=0, microsecond=0, tzinfo=base.tzinfo, ) def mondays_until_nth(n): """Returns a list of dates for the next n Mondays, starting from the next Monday. This functions aids in the generation of weekly schedules or reports.""" today = datetime.today() next_monday = today + timedelta(days=(7 - today.weekday()) % 7 or 7) return [(next_monday + timedelta(weeks=i)).date() for i in range(n + 1)]