# -*- coding: utf-8 -*- # # portal/models.py: models for the portal application # This file is part of the Manifold project. # # Authors: # Jordan Augé # Copyright 2013, UPMC Sorbonne Universités / LIP6 # # This program 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, or (at your option) any later version. # # This program 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 # this program; see the file COPYING. If not, write to the Free Software # Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. import datetime import hashlib import random import re from django.conf import settings from django.core.mail import send_mail from django.db import models from django.db import transaction from django.utils.translation import ugettext_lazy as _ from django.template.loader import render_to_string #from django.core.validators import validate_email try: from django.contrib.auth import get_user_model User = get_user_model() except ImportError: from django.contrib.auth.models import User try: from django.utils.timezone import now as datetime_now except ImportError: datetime_now = datetime.datetime.now SHA1_RE = re.compile('^[a-f0-9]{40}$') # Create your models here. class Institution(models.Model): name = models.TextField() # list of associated email domains # code borrowed from django-registration # https://bitbucket.org/ubernostrum/django-registration/ #DEPRECATED #class RegistrationManager(models.Manager): # """ # Custom manager for the ``RegistrationProfile`` model. # # The methods defined here provide shortcuts for account creation # and activation (including generation and emailing of activation # keys), and for cleaning out expired inactive accounts. # # """ # def activate_user(self, activation_key): # """ # Validate an activation key and activate the corresponding # ``User`` if valid. # # If the key is valid and has not expired, return the ``User`` # after activating. # # If the key is not valid or has expired, return ``False``. # # If the key is valid but the ``User`` is already active, # return ``False``. # # To prevent reactivation of an account which has been # deactivated by site administrators, the activation key is # reset to the string constant ``RegistrationProfile.ACTIVATED`` # after successful activation. # # """ # # Make sure the key we're trying conforms to the pattern of a # # SHA1 hash; if it doesn't, no point trying to look it up in # # the database. # if SHA1_RE.search(activation_key): # try: # profile = self.get(activation_key=activation_key) # except self.model.DoesNotExist: # return False # if not profile.activation_key_expired(): # user = profile.user # user.is_active = True # user.save() # profile.activation_key = self.model.ACTIVATED # profile.save() # return user # return False # # def create_user(self, first_name, last_name, email, password): # pending_user = self.create(first_name=first_name, last_name=last_name, email=email, password=password) # return pending_user # # def create_inactive_user(self, first_name, last_name, email, password, site, # send_email=True): # """ # Create a new, inactive ``User``, generate a # ``RegistrationProfile`` and email its activation key to the # ``User``, returning the new ``User``. # # By default, an activation email will be sent to the new # user. To disable this, pass ``send_email=False``. # # """ # salt = hashlib.sha1(str(random.random())).hexdigest()[:5] # if isinstance(email, unicode): # email = email.encode('utf-8') # activation_key = hashlib.sha1(salt+email).hexdigest() # # new_user = PendingUser.objects.create_user(first_name, last_name, email, password) # new_user.is_active = False # new_user.activation_key=activation_key # new_user.save() # # # We might not need this # #registration_profile = self.create_profile(new_user) # # if send_email: # new_user.send_activation_email(site) # #registration_profile.send_activation_email(site) # # return new_user # create_inactive_user = transaction.commit_on_success(create_inactive_user) # # def create_profile(self, user): # """ # Create a ``RegistrationProfile`` for a given # ``User``, and return the ``RegistrationProfile``. # # The activation key for the ``RegistrationProfile`` will be a # SHA1 hash, generated from a combination of the ``User``'s # username and a random salt. # # """ # salt = hashlib.sha1(str(random.random())).hexdigest()[:5] # username = user.username # if isinstance(username, unicode): # username = username.encode('utf-8') # activation_key = hashlib.sha1(salt+username).hexdigest() # return self.create(user=user, # activation_key=activation_key) # # def delete_expired_users(self): # """ # Remove expired instances of ``RegistrationProfile`` and their # associated ``User``s. # # Accounts to be deleted are identified by searching for # instances of ``RegistrationProfile`` with expired activation # keys, and then checking to see if their associated ``User`` # instances have the field ``is_active`` set to ``False``; any # ``User`` who is both inactive and has an expired activation # key will be deleted. # # It is recommended that this method be executed regularly as # part of your routine site maintenance; this application # provides a custom management command which will call this # method, accessible as ``manage.py cleanupregistration``. # # Regularly clearing out accounts which have never been # activated serves two useful purposes: # # 1. It alleviates the ocasional need to reset a # ``RegistrationProfile`` and/or re-send an activation email # when a user does not receive or does not act upon the # initial activation email; since the account will be # deleted, the user will be able to simply re-register and # receive a new activation key. # # 2. It prevents the possibility of a malicious user registering # one or more accounts and never activating them (thus # denying the use of those usernames to anyone else); since # those accounts will be deleted, the usernames will become # available for use again. # # If you have a troublesome ``User`` and wish to disable their # account while keeping it in the database, simply delete the # associated ``RegistrationProfile``; an inactive ``User`` which # does not have an associated ``RegistrationProfile`` will not # be deleted. # # """ # for profile in self.all(): # try: # if profile.activation_key_expired(): # user = profile.user # if not user.is_active: # user.delete() # profile.delete() # except User.DoesNotExist: # profile.delete() #DEPRECATED class PendingUser(models.Model): # NOTE We might consider migrating the fields to CharField, which would # simplify form creation in forms.py first_name = models.TextField() last_name = models.TextField() # affiliation = models.TextField() email = models.EmailField() #validators=[validate_email]) password = models.TextField() keypair = models.TextField() # institution authority_hrn = models.TextField() # models.ForeignKey(Institution) #DEPRECATED # objects = RegistrationManager() # # class Meta: # verbose_name = _('registration profile') # verbose_name_plural = _('registration profiles') # # def __unicode__(self): # return u"Registration information for %s" % self.email # # def activation_key_expired(self): # """ # Determine whether this ``RegistrationProfile``'s activation # key has expired, returning a boolean -- ``True`` if the key # has expired. # # Key expiration is determined by a two-step process: # # 1. If the user has already activated, the key will have been # reset to the string constant ``ACTIVATED``. Re-activating # is not permitted, and so this method returns ``True`` in # this case. # # 2. Otherwise, the date the user signed up is incremented by # the number of days specified in the setting # ``ACCOUNT_ACTIVATION_DAYS`` (which should be the number of # days after signup during which a user is allowed to # activate their account); if the result is less than or # equal to the current date, the key has expired and this # method returns ``True``. # # """ # expiration_date = datetime.timedelta(days=settings.ACCOUNT_ACTIVATION_DAYS) # return self.activation_key == self.ACTIVATED or \ # (self.user.date_joined + expiration_date <= datetime_now()) # activation_key_expired.boolean = True # # def send_activation_email(self, site): # """ # Send an activation email to the user associated with this # ``RegistrationProfile``. # # The activation email will make use of two templates: # # ``user_register_email_subject.txt`` # This template will be used for the subject line of the # email. Because it is used as the subject line of an email, # this template's output **must** be only a single line of # text; output longer than one line will be forcibly joined # into only a single line. # # ``user_register_email.txt`` # This template will be used for the body of the email. # # These templates will each receive the following context # variables: # # ``activation_key`` # The activation key for the new account. # # ``expiration_days`` # The number of days remaining during which the account may # be activated. # # ``site`` # An object representing the site on which the user # registered; depending on whether ``django.contrib.sites`` # is installed, this may be an instance of either # ``django.contrib.sites.models.Site`` (if the sites # application is installed) or # ``django.contrib.sites.models.RequestSite`` (if # not). Consult the documentation for the Django sites # framework for details regarding these objects' interfaces. # # """ # ctx_dict = {'activation_key': self.activation_key, # 'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS, # 'site': site} # subject = render_to_string('user_register_email_subject.txt', # ctx_dict) # # Email subject *must not* contain newlines # subject = ''.join(subject.splitlines()) # # message = render_to_string('user_register_email.txt', # ctx_dict) # # send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [self.email]) #DEPRECATED class PendingSlice(models.Model): slice_name = models.TextField() authority_hrn = models.TextField(null=True) number_of_nodes = models.TextField(default=0) type_of_nodes = models.TextField(default='NA') purpose = models.TextField(default='NA')