aboutsummaryrefslogtreecommitdiffstats
path: root/97suifangqa/apps/sfaccount/models.py
blob: bb1fe295873eaf5d5f97ea7b7a8a0e6abf1b3a06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# -*- coding: utf-8 -*-

from django.conf import settings
from django.db import models
from django.contrib import admin
from django.contrib.auth.models import User
from django.utils.hashcompat import sha_constructor
from django.utils.timezone import utc
from django.template.loader import render_to_string

from sfaccount.tasks import send_mail

import re
import random
import datetime


# SHA1 Hash regex
SHA1 = re.compile('^[a-f0-9]{40}$')


class AccountManager(models.Manager):                           # {{{
    """
    custom manager for 'Account' model
    """
    def activate(self, activation_key):
        """
        validate an activation key and activate the corresponding
        'User' if valid.

        if the key is valid and not expired, return the 'Account'
        if the key is invalid or expired, return 'False'
        if the key is valid but the 'User' is already activated,
            return 'False'

        reset the key string to prevent reactivation of an account
        which has been deactivated by the admin
        """
        if SHA1.search(activation_key):
            try:
                account = self.get(activation_key=activation_key)
            except self.model.DoesNotExist:
                return False
            if not account.activation_key_expired():
                user = account.user
                user.is_active = True
                user.save()
                account.activation_key = self.model.ACTIVATED
                account.save()
                return account
        return False

    def create_inactive_account(self, username, email, password,
            send_email=True):
        """
        create a new, *local*, inactive 'User',
        and generate an 'Account' and
        email the activation key. return the new 'User'

        the activation key is a SHA1 hash, generated from
        a combination of the 'username' and a random slat
        """
        new_user = User.objects.create_user(username, email, password)
        new_user.is_active = False
        new_user.save()
        # create corresponding 'Account'
        salt = sha_constructor(str(random.random())).hexdigest()[:5]
        activation_key = sha_constructor(salt+username).hexdigest()
        new_account = self.create(user=new_user, is_social=False,
                activation_key=activation_key)
        new_account.save()
        # send email
        if send_email:
            new_account.send_activation_email()
        return new_account

    def delete_expired_accounts(self):
        """
        Remove expired instances of 'Account's and their
        associated 'User's.
        """
        for account in self.all():
            if account.activation_key_expired():
                user = account.user
                if not user.is_active:
                    user.delete()
                    account.delete()
# }}}


class Account(models.Model):                                    # {{{
    """
    Account model for 97suifang
    """
    ACTIVATED = u'ALREADY_ACTIVATED'

    user = models.OneToOneField(User, related_name="account")
    # username -> user.username
    # date_joined -> user.date_joined
    screen_name = models.CharField(u"昵称", max_length=30,
            null=True, blank=True)
    avatar = models.ImageField(u"头像", upload_to="uploads/avatars/",
            null=True, blank=True)
    # if social account
    is_social = models.BooleanField(default=False)
    # activation (SHA1 hash)
    activation_key = models.CharField(u"激活密钥", max_length=40)

    objects = AccountManager()

    class Meta:
        verbose_name_plural = u"账户信息"

    def __unicode__(self):
        if self.is_social:
            type = u"social"
        else:
            type = u"local"
        if self.user.is_active:
            state = u"activated"
        else:
            state = u"nonactivated"
        #
        return u'< Account: %s, %s, %s >' % (self.user.username,
                type, state)

    def activation_key_expired(self):
        """
        determine whether the activation 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_days = datetime.timedelta(
                days=settings.ACCOUNT_ACTIVATION_DAYS)
        now_utc = datetime.datetime.utcnow().replace(tzinfo=utc)
        return self.user.is_active or (
                self.user.date_joined + expiration_days <= now_utc)

    def send_activation_email(self):
        """
        send an activation email to the newly registered user
        """
        ctx_dict = {
            'username': self.user.username,
            'activation_key': self.activation_key,
            'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS,
        }
        subject = render_to_string('sfaccount/activation_email_subject.txt', ctx_dict)
        subject = ''.join(subject.splitlines())
        body_text = render_to_string('sfaccount/activation_email_body.txt', ctx_dict).encode('utf-8')
        to = self.user.email
        # send email
        send_mail.delay(to, subject, body_text, None)
# }}}


admin.site.register([Account])

# vim: set ts=4 sw=4 tw=0 fenc=utf-8 ft=python: #