<commit_before># -*- coding: utf-8 -*-
"""
Django models for the Perimeter app.
"""
from datetime import date, time, timedelta, datetime
import random

from django.conf import settings
from django.contrib.auth.models import User
from django.core.cache import cache
from django.db import models
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.utils.timezone import now, make_aware

from perimeter.settings import PERIMETER_DEFAULT_EXPIRY


def default_expiry():
    """Return the default expiry date."""
    return (now() + timedelta(days=PERIMETER_DEFAULT_EXPIRY)).date()


class EmptyToken(object):
    """Token-like object that will always return is_valid() == False.

    EmptyToken objects are a bit like Django's AnonymousUser model -
    they return an object that can be used like an AccessToken but that
    is always invalid.
    """
    @property
    def is_valid(self):
        return False


class AccessTokenManager(models.Manager):
    """Custom model manager for AccessTokens."""

    def create_access_token(self, **kwargs):
        """Create a new AccessToken with a random token value."""
        # NB there is a theoretical token clash exception here,
        # when the random_token_value function returns an existing
        # token value, but it is considered so unlikely as to be
        # acceptable.
        kwargs['token'] = kwargs.get('token', AccessToken.random_token_value())
        kwargs['expires_on'] = kwargs.get('expires_on', default_expiry())
        return AccessToken(**kwargs).save()

    def get_access_token(self, token_value):
        """Fetch an AccessToken, return EmptyToken if not found.

        This method is cache-aware, and will check the cache first,
        re-filling it if empty.

        Args:
            token - string, the token value to look up.

        """
        cache_key = AccessToken.get_cache_key(token_value)
        token = cache.get(cache_key)
        if token is None:
            try:
                token = self.get(token=token_value)
                cache.set(token.cache_key, token, token.seconds_to_expiry)
                return token
            except AccessToken.DoesNotExist:
                return EmptyToken()
        else:
            return token


class AccessToken(models.Model):
    """
    A token that allows a user entry to the site via Perimeter.
    """
    token = models.CharField(max_length=50, unique=True)
    is_active = models.BooleanField(default=True)
    # NB pass in a callable, not the result of the callable, see:
    # http://stackoverflow.com/a/29549675/45698
    expires_on = models.DateField(default=default_expiry)
    created_by = models.ForeignKey(User, null=True)
    created_at = models.DateTimeField()
    updated_at = models.DateTimeField()

    objects = AccessTokenManager()

    def __unicode__(self):
        return (
            u"%s - %s" % (
                self.token,
                'valid' if self.is_valid else 'invalid'
            )
        )

    def __str__(self):
        return self.__unicode__().encode('UTF-8')

    @classmethod
    def random_token_value(cls):
        """Generate a random token value."""
        return "".join(
            random.sample(
                population=list(
                    "abcdefghijklmnopqrstuvwxyz"
                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                    "1234567890"
                ),
                k=cls._meta.get_field('token').max_length
            )
        )

    @classmethod
    def get_cache_key(cls, token_value):
        return (
            '%s.%s-%s' % (
                cls.__module__,
                cls.__name__,
                token_value
            )
        )

    def save(self, *args, **kwargs):
        "Sets the created_at timestamp."
        self.updated_at = now()
        self.created_at = self.created_at or self.updated_at
        super(AccessToken, self).save(*args, **kwargs)
        return self

    @property
    def cache_key(self):
        """Return object cache key (from get `get_cache_key`)."""
        return AccessToken.get_cache_key(self.token)

    @property
    def seconds_to_expiry(self):
        """Retun the number of seconds till expiry (used for caching)."""
        expires_at = make_aware(
            datetime.combine(self.expires_on, time.min),
            now().tzinfo
        )
        return int((expires_at - now()).total_seconds())

    @property
    def has_expired(self):
        """Return True if the token has passed expiry date."""
        return self.expires_on < date.today()

    @property
    def is_valid(self):
        """Return True if the token is active and has not expired."""
        return self.is_active and not self.has_expired

    def record(self, user_email, user_name,
        client_ip='unknown', client_user_agent='unknown'):
        """Record the fact that someone has used the token."""
        atu = AccessTokenUse(
            token=self,
            user_email=user_email,
            user_name=user_name,
            client_ip=client_ip,
            client_user_agent=client_user_agent
        )
        atu.save()
        return atu<commit_msg>Handle Django 1.8 utils.timezone changes<commit_after># -*- coding: utf-8 -*-
"""
Django models for the Perimeter app.
"""
from datetime import date, time, timedelta, datetime
import random

from django.conf import settings
from django.contrib.auth.models import User
from django.core.cache import cache
from django.db import models
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.utils.timezone import now, make_aware, is_naive

from perimeter.settings import PERIMETER_DEFAULT_EXPIRY


def default_expiry():
    """Return the default expiry date."""
    return (now() + timedelta(days=PERIMETER_DEFAULT_EXPIRY)).date()


class EmptyToken(object):
    """Token-like object that will always return is_valid() == False.

    EmptyToken objects are a bit like Django's AnonymousUser model -
    they return an object that can be used like an AccessToken but that
    is always invalid.
    """
    @property
    def is_valid(self):
        return False


class AccessTokenManager(models.Manager):
    """Custom model manager for AccessTokens."""

    def create_access_token(self, **kwargs):
        """Create a new AccessToken with a random token value."""
        # NB there is a theoretical token clash exception here,
        # when the random_token_value function returns an existing
        # token value, but it is considered so unlikely as to be
        # acceptable.
        kwargs['token'] = kwargs.get('token', AccessToken.random_token_value())
        kwargs['expires_on'] = kwargs.get('expires_on', default_expiry())
        return AccessToken(**kwargs).save()

    def get_access_token(self, token_value):
        """Fetch an AccessToken, return EmptyToken if not found.

        This method is cache-aware, and will check the cache first,
        re-filling it if empty.

        Args:
            token - string, the token value to look up.

        """
        cache_key = AccessToken.get_cache_key(token_value)
        token = cache.get(cache_key)
        if token is None:
            try:
                token = self.get(token=token_value)
                cache.set(token.cache_key, token, token.seconds_to_expiry)
                return token
            except AccessToken.DoesNotExist:
                return EmptyToken()
        else:
            return token


class AccessToken(models.Model):
    """
    A token that allows a user entry to the site via Perimeter.
    """
    token = models.CharField(max_length=50, unique=True)
    is_active = models.BooleanField(default=True)
    # NB pass in a callable, not the result of the callable, see:
    # http://stackoverflow.com/a/29549675/45698
    expires_on = models.DateField(default=default_expiry)
    created_by = models.ForeignKey(User, null=True)
    created_at = models.DateTimeField()
    updated_at = models.DateTimeField()

    objects = AccessTokenManager()

    def __unicode__(self):
        return (
            u"%s - %s" % (
                self.token,
                'valid' if self.is_valid else 'invalid'
            )
        )

    def __str__(self):
        return self.__unicode__().encode('UTF-8')

    @classmethod
    def random_token_value(cls):
        """Generate a random token value."""
        return "".join(
            random.sample(
                population=list(
                    "abcdefghijklmnopqrstuvwxyz"
                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                    "1234567890"
                ),
                k=cls._meta.get_field('token').max_length
            )
        )

    @classmethod
    def get_cache_key(cls, token_value):
        return (
            '%s.%s-%s' % (
                cls.__module__,
                cls.__name__,
                token_value
            )
        )

    def save(self, *args, **kwargs):
        "Sets the created_at timestamp."
        self.updated_at = now()
        self.created_at = self.created_at or self.updated_at
        super(AccessToken, self).save(*args, **kwargs)
        return self

    @property
    def cache_key(self):
        """Return object cache key (from get `get_cache_key`)."""
        return AccessToken.get_cache_key(self.token)

    @property
    def seconds_to_expiry(self):
        """Retun the number of seconds till expiry (used for caching)."""

        expires_at = make_aware(
            datetime.combine(self.expires_on, time.min),
            now().tzinfo
        )
        if is_naive(expires_at):
            return int((expires_at - now()).total_seconds())
        else:
            # Django 1.8 will automagically localize dates even if
            # now().tzinfo is None, in which case this would fail if
            # we don't localise now() - sounds crazy, I know.
            # 1.8 - https://github.com/django/django/blob/1.8c1/django/utils/timezone.py#L354:
            #   if timezone is None:
            #     timezone = get_current_timezone()
            # 1.7 - https://github.com/django/django/blob/1.7.8/django/utils/timezone.py#L352
            now_ = make_aware(now())
            return int((expires_at - now_).total_seconds())

    @property
    def has_expired(self):
        """Return True if the token has passed expiry date."""
        return self.expires_on < date.today()

    @property
    def is_valid(self):
        """Return True if the token is active and has not expired."""
        return self.is_active and not self.has_expired

    def record(self, user_email, user_name,
        client_ip='unknown', client_user_agent='unknown'):
        """Record the fact that someone has used the token."""
        atu = AccessTokenUse(
            token=self,
            user_email=user_email,
            user_name=user_name,
            client_ip=client_ip,
            client_user_agent=client_user_agent
        )
        atu.save()
        return atu
{'fraction_non_alphanumeric': 0.09538461538461539, 'fraction_numerical': 0.0066968325791855205, 'mean_word_length': 2.2569997052755673, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7348927', 'n_tokens_mistral': 3225, 'n_tokens_neox': 3049, 'n_words': 864}