aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--97suifangqa/apps/sfaccount/README.txt8
-rw-r--r--97suifangqa/apps/sfaccount/forms.py51
-rw-r--r--97suifangqa/apps/sfaccount/models.py28
-rw-r--r--97suifangqa/apps/sfaccount/tasks.py5
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/activate.html15
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/activate_done.html36
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/activate_send_mail.html36
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_body.html2
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_body.txt2
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/login.html11
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/password_change_done.html2
-rw-r--r--97suifangqa/apps/sfaccount/urls.py10
-rw-r--r--97suifangqa/apps/sfaccount/views.py51
-rw-r--r--97suifangqa/isuifangqa.dbbin379904 -> 379904 bytes
-rw-r--r--97suifangqa/settings.py14
15 files changed, 234 insertions, 37 deletions
diff --git a/97suifangqa/apps/sfaccount/README.txt b/97suifangqa/apps/sfaccount/README.txt
index c55a405..651122c 100644
--- a/97suifangqa/apps/sfaccount/README.txt
+++ b/97suifangqa/apps/sfaccount/README.txt
@@ -15,11 +15,17 @@ HOWTO run:
5) ajust 'SF_MAIL' settings in 'mail_settings.py'
6) $ redis-server
7) $ ./manage.py syncdb
-8) $ ./manage.py celeryd worker -E
+8) $ ./manage.py celery worker --loglevel=info
9) $ ./manage.py celerycam (for monitoring)
TEST:
a) ./manage.py shell
>>> from sfaccount.tasks import send_mail
>>> send_mail(to, subject, body_text, body_html)
+ # async task
+ >>> r = send_mail.delay(to, subject, body_text, body_html)
+ >>> r.ready()
+ >>> r.result
+ >>> r.successful()
+ >>>
diff --git a/97suifangqa/apps/sfaccount/forms.py b/97suifangqa/apps/sfaccount/forms.py
index d2a3bf1..5502263 100644
--- a/97suifangqa/apps/sfaccount/forms.py
+++ b/97suifangqa/apps/sfaccount/forms.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from django import forms
+from django.conf import settings
from django.template import loader
from django.utils.http import int_to_base36
from django.contrib.auth.models import User
@@ -34,8 +35,10 @@ class AccountForm(forms.Form):
def clean_username(self):
username = self.cleaned_data['username']
# check length
- if len(username) < 6:
+ if len(username) < settings.MIN_USERNAME_LENGTH:
raise forms.ValidationError(u'用户名长度需大于6位')
+ if len(username) > settings.MAX_USERNAME_LENGTH:
+ raise forms.ValidationError(u'用户名长度不能超过30位')
# check first letter
p = re.compile('[a-zA-Z_]')
if p.match(username[0]):
@@ -58,8 +61,11 @@ class AccountForm(forms.Form):
def clean_password1(self):
password1 = self.cleaned_data['password1']
- if len(password1) < 6:
+ # check length
+ if len(password1) < settings.MIN_PASSWORD_LENGTH:
raise forms.ValidationError(u'密码长度需大于6位')
+ if len(password1) > settings.MAX_PASSWORD_LENGTH:
+ raise forms.ValidationError(u'密码长度不能超过30位')
return password1
def clean(self):
@@ -79,13 +85,19 @@ class SFPasswordResetForm(forms.Form):
to use djcelery's async send mail
"""
error_messages = {
- 'unknown': _("That e-mail address doesn't have an associated "
- "user account. Are you sure you've registered?"),
+ 'unknown': u"该邮箱未在系统中注册,请填写您注册时使用的邮箱地址",
'unusable': _("The user account associated with this e-mail "
"address cannot reset the password."),
}
email = forms.EmailField(label=_("E-mail"), max_length=75)
+ def clean_email(self):
+ email = self.cleaned_data['email']
+ users = User.objects.filter(email__iexact=email)
+ if not len(users):
+ raise forms.ValidationError(self.error_messages['unknown'])
+ return email
+
def save(self, domain_override=None,
subject_template_name='registration/password_reset_subject.txt',
email_template_name='registration/password_reset_email.txt',
@@ -96,14 +108,8 @@ class SFPasswordResetForm(forms.Form):
Generates a one-use only link for resetting password
and sends to the user.
"""
- # validate first
- if not self.is_valid():
- return self
- # validated: has 'self.cleaned_data'
email = self.cleaned_data['email']
users = User.objects.filter(email__iexact=email)
- if not len(users):
- raise forms.ValidationError(self.error_messages['unknown'])
for user in users:
# make sure that no email is sent to a user that actually
# has a password marked as unusable
@@ -135,7 +141,30 @@ class SFPasswordResetForm(forms.Form):
body_html = None
# send mail
to = user.email
- send_mail(to, subject, body_text, body_html)
+ if getattr(settings, 'ASYNC_SEND_MAIL', False):
+ send_mail.delay(to, subject, body_text, body_html)
+ else:
+ send_mail(to, subject, body_text, body_html)
+# }}}
+
+
+# SFEmailForm {{{
+class SFEmailForm(forms.Form):
+ """
+ get input email address and validate it
+ used in sending activation mail
+ """
+ error_messages = {
+ 'unknown': u"该邮箱未在系统中注册,请填写您注册时使用的邮箱地址",
+ }
+ email = forms.EmailField(label=_("E-mail"), max_length=75)
+
+ def clean_email(self):
+ email = self.cleaned_data['email']
+ users = User.objects.filter(email__iexact=email)
+ if not len(users):
+ raise forms.ValidationError(self.error_messages['unknown'])
+ return email
# }}}
diff --git a/97suifangqa/apps/sfaccount/models.py b/97suifangqa/apps/sfaccount/models.py
index 72904c4..5ebba1c 100644
--- a/97suifangqa/apps/sfaccount/models.py
+++ b/97suifangqa/apps/sfaccount/models.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
+from django.core.urlresolvers import reverse
from django.conf import settings
from django.db import models
from django.contrib import admin
@@ -150,22 +151,39 @@ class Account(models.Model): # {{{
self.user.date_joined + expiration_days <= now_utc)
# }}}
- def send_activation_email(self): # {{{
+ def get_activation_url(self):
+ return reverse('activate_key',
+ kwargs={'activation_key': self.activation_key})
+
+ # send_activation_email {{{
+ def send_activation_email(self,
+ async=None,
+ subject_template_name='sfaccount/activation_email_subject.txt',
+ email_template_name='sfaccount/activation_email_body.txt',
+ html_email_template_name='sfaccount/activation_email_body.html'):
"""
send an activation email to the newly registered user
"""
ctx_dict = {
'username': self.user.username,
'activation_key': self.activation_key,
+ 'activation_url': self.get_activation_url(),
'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS,
}
- subject = render_to_string('sfaccount/activation_email_subject.txt', ctx_dict)
+ subject = render_to_string(subject_template_name, ctx_dict)
subject = ''.join(subject.splitlines())
- body_text = render_to_string('sfaccount/activation_email_body.txt', ctx_dict)
- body_html = render_to_string('sfaccount/activation_email_body.html', ctx_dict)
+ body_text = render_to_string(email_template_name, ctx_dict)
+ body_html = render_to_string(html_email_template_name, ctx_dict)
to = self.user.email
# send email
- send_mail.delay(to, subject, body_text, body_html)
+ if async is None:
+ async_send_mail = getattr(settings, 'ASYNC_SEND_MAIL', False)
+ else:
+ async_send_mail = async
+ if async_send_mail:
+ send_mail.delay(to, subject, body_text, body_html)
+ else:
+ send_mail(to, subject, body_text, body_html)
# }}}
def delete_account(self):
diff --git a/97suifangqa/apps/sfaccount/tasks.py b/97suifangqa/apps/sfaccount/tasks.py
index 1613646..86cf6ea 100644
--- a/97suifangqa/apps/sfaccount/tasks.py
+++ b/97suifangqa/apps/sfaccount/tasks.py
@@ -11,3 +11,8 @@ def send_mail(to, subject, content_text=None, content_html=None):
content_text=content_text,
content_html=content_html)
+
+@task
+def test_add(x, y):
+ return x + y
+
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/activate.html b/97suifangqa/apps/sfaccount/templates/sfaccount/activate.html
index a81af6d..1a6c6f9 100644
--- a/97suifangqa/apps/sfaccount/templates/sfaccount/activate.html
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/activate.html
@@ -13,7 +13,8 @@
{% block scripts %}
<script type="text/javascript">
// activate account url
- var activate_url = '{% url activate %}';
+ var activate_key_url = '{{ activate_key_url }}';
+ var send_activation_mail_url = '{% url send_activation_mail %}';
$(document).ready(function(){
// validate key input
@@ -47,7 +48,7 @@
// submit
var key_raw = $("#activation_key").val();
var key = htmlEscape(key_raw.toLowerCase());
- var target_url = activate_url + key + '/';
+ var target_url = activate_key_url + key + '/';
//console.log(target_url);
window.location.href = target_url;
}
@@ -63,6 +64,10 @@
}
});
+ // send_activation_mail
+ $("#send_activation_mail").bind("click", function() {
+ window.location.href = send_activation_mail_url;
+ });
});
function htmlEscape(str) {
@@ -93,6 +98,12 @@
<input type="button" id="activate_account" value="激活账户" />
</div>
+ <div class="no-mail">
+ 还未收到激活邮件?您可以尝试重发激活邮件。
+ <br />
+ <input type="button" id="send_activation_mail" value="重发激活邮件" />
+ </div>
+
{% endblock body %}
<!-- vim: set ts=8 sw=2 tw=0 fenc=utf-8 ft=htmldjango.html: -->
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/activate_done.html b/97suifangqa/apps/sfaccount/templates/sfaccount/activate_done.html
new file mode 100644
index 0000000..8432a39
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/activate_done.html
@@ -0,0 +1,36 @@
+{% extends "picture-base.html" %}
+{% load staticfiles %}
+
+{% block title %}
+账户已激活 | 97 随访
+{% endblock %}
+
+{% block othercss %}
+<link rel="stylesheet" href="{% static "stylesheets/sass/registration.css" %}">
+{% endblock %}
+
+{% block scripts %}
+ <script type="text/javascript">
+ // login url
+ var login_url = '{% url login %}';
+
+ $(document).ready(function() {
+ $("#login").bind("click", function() {
+ window.location.href = login_url;
+ });
+ });
+ </script>
+{% endblock %}
+
+{% block body %}
+ <h2>加入97随访 &emsp; 科学了解乙肝治疗</h2>
+
+ <h4>欢迎加入97随访!</h4>
+
+ <p>您的账户已成功激活,现在您可以登录使用。</p>
+ <p>
+ <input type="button" id="login" value="登录" />
+ </p>
+{% endblock body %}
+
+<!-- vim: set ts=8 sw=2 tw=0 fenc=utf-8 ft=htmldjango.html: -->
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/activate_send_mail.html b/97suifangqa/apps/sfaccount/templates/sfaccount/activate_send_mail.html
new file mode 100644
index 0000000..e95a881
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/activate_send_mail.html
@@ -0,0 +1,36 @@
+{% extends "picture-base.html" %}
+{% load staticfiles %}
+
+{% block title %}
+重发激活邮件 | 97 随访
+{% endblock %}
+
+{% block othercss %}
+<link rel="stylesheet" href="{% static "stylesheets/sass/registration.css" %}">
+{% endblock %}
+
+{% block body %}
+ <h2>加入97随访 &emsp; 科学了解乙肝治疗</h2>
+
+ <p>
+ 还未收到激活邮件?
+ </p>
+ <p>
+ 请在下面输入您注册时使用的邮箱地址,
+ 我们将为您重新发送激活邮件。
+ </p>
+
+ <form action="" method="post">{% csrf_token %}
+ <table class="send-activation-mail">
+ <tr>
+ <td>
+ <input type="text" name="email" value="{{ form.email.value|default_if_none:"" }}" placeholder="您注册时的邮箱地址" class="email">
+ </td>
+ <td class="error">{{ form.email.errors|join:"" }}</td>
+ </tr>
+ </table>
+ <input type="submit" value="重发激活邮件" />
+ </form>
+{% endblock %}
+
+<!-- vim: set ts=8 sw=2 tw=0 fenc=utf-8 ft=htmldjango.html: -->
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_body.html b/97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_body.html
index 9792ad5..51b1751 100644
--- a/97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_body.html
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_body.html
@@ -5,7 +5,7 @@
<p>
您的激活码为 {{ activation_key }},请在 {{ expiration_days }} 天内激活账户,直接打开以下链接进行激活:<br />
-http://www.97suifang.com/accounts/activate/{{ activation_key }}/
+http://www.97suifang.com{{ activation_url }}
</p>
<br />
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_body.txt b/97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_body.txt
index b479ff0..44a2c4d 100644
--- a/97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_body.txt
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_body.txt
@@ -3,7 +3,7 @@
欢迎您加入97随访(97suifang.com)。
您的激活码为 {{ activation_key }},请在 {{ expiration_days }} 天内激活账户,直接打开以下链接进行激活:
-http://www.97suifang.com/accounts/activate/{{ activation_key }}/
+http://www.97suifang.com{{ activation_url }}
97随访 团队
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/login.html b/97suifangqa/apps/sfaccount/templates/sfaccount/login.html
index f5c7942..6e3be80 100644
--- a/97suifangqa/apps/sfaccount/templates/sfaccount/login.html
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/login.html
@@ -47,11 +47,14 @@
<input type="hidden" name="next" value="{{ next }}" />
<input type="submit" value="登 录" class="submit login"/>
- &emsp; | &emsp;
- <a href="{% url signup %}">还没有帐号?</a>
- &emsp; | &emsp;
- <a href="{% url password_reset %}">忘记密码?</a>
</form>
+ <br />
+
+ <p>
+ <a href="{% url signup %}">还没有帐号?</a>
+ &emsp; | &emsp;
+ <a href="{% url password_reset %}">忘记密码?</a>
+ </p>
{% endblock body%}
{# vim: set ts=2 sw=2 tw=0 fenc=utf-8 ft=htmldjango.html: #}
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/password_change_done.html b/97suifangqa/apps/sfaccount/templates/sfaccount/password_change_done.html
index ed91216..ac22668 100644
--- a/97suifangqa/apps/sfaccount/templates/sfaccount/password_change_done.html
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/password_change_done.html
@@ -11,7 +11,7 @@
{% block scripts %}
<script type="text/javascript">
- // login url
+ // home url
var home_url = '{% url go_home %}';
$(document).ready(function() {
diff --git a/97suifangqa/apps/sfaccount/urls.py b/97suifangqa/apps/sfaccount/urls.py
index f2a930b..29925e1 100644
--- a/97suifangqa/apps/sfaccount/urls.py
+++ b/97suifangqa/apps/sfaccount/urls.py
@@ -10,10 +10,16 @@ from django.contrib.auth import views as auth_views
urlpatterns = patterns('sfaccount.views',
url(r'^signup/$', 'signup_view', name='signup'),
+ # send activation mail
+ url(r'^activate/send_mail/$', 'send_activation_mail_view',
+ name='send_activation_mail'),
# activate account
url(r'^activate/$', 'activate_view', name='activate'),
- url(r'^activate/(?P<activation_key>.+)/$',
- 'activate_view'),
+ url(r'^activate/key/(?P<activation_key>[0-9a-zA-Z]+)/$',
+ 'activate_view',
+ name='activate_key'),
+ url(r'^activate/done/$', 'activate_done_view',
+ name='activate_done'),
# go home
url(r'^home/$', 'go_home_view', name='go_home'),
)
diff --git a/97suifangqa/apps/sfaccount/views.py b/97suifangqa/apps/sfaccount/views.py
index 9cc2868..014dc32 100644
--- a/97suifangqa/apps/sfaccount/views.py
+++ b/97suifangqa/apps/sfaccount/views.py
@@ -8,10 +8,14 @@ from django.views.decorators.csrf import csrf_protect
from django.utils.translation import ugettext as _
from django.shortcuts import render, redirect
+from django.contrib.auth.models import User
from django.contrib.auth.tokens import default_token_generator
from sfaccount.models import Account
-from sfaccount.forms import AccountForm, SFPasswordResetForm
+from sfaccount.forms import (
+ AccountForm, SFPasswordResetForm,
+ SFEmailForm,
+)
# email address shown in the sent mail
FROM_EMAIL = getattr(settings, 'SF_EMAIL').get('display_from')
@@ -28,7 +32,9 @@ def go_home_view(request):
kwargs={'username': username}))
else:
# not logged in
- return redirect(reverse('login'))
+ cur_url = request.get_full_path()
+ target_url = reverse('login') + '?next=' + cur_url
+ return redirect(target_url)
# }}}
@@ -74,15 +80,50 @@ def activate_view(request, activation_key=None):
account = Account.objects.activate(activation_key)
if account:
# activated
- home_url = '/profile/%s/' % account.user.username
- return HttpResponseRedirect(home_url)
+ return HttpResponseRedirect(reverse('activate_done'))
else:
# activate failed
data = {'activate_failed': True}
return render(request, 'sfaccount/activate.html', data)
else:
# ask user for the 'activation_key'
- return render(request, 'sfaccount/activate.html')
+ activate_key_url = reverse('activate_key',
+ kwargs={'activation_key': 'XXX'})
+ activate_key_url = activate_key_url.replace('XXX/', '')
+ data = {'activate_key_url': activate_key_url}
+ return render(request, 'sfaccount/activate.html', data)
+# }}}
+
+
+# activate_done {{{
+def activate_done_view(request):
+ template_name = 'sfaccount/activate_done.html'
+ context = {}
+ return render(request, template_name, context)
+# }}}
+
+
+# send_activation_mail_view {{{
+def send_activation_mail_view(request,
+ template_name='sfaccount/activate_send_mail.html'):
+ """
+ send activation mail to the given email address
+ """
+ if request.method == "POST":
+ form = SFEmailForm(request.POST)
+ if form.is_valid():
+ email = form.cleaned_data['email']
+ accounts = Account.objects.filter(user__email__iexact=email)
+ for account in accounts:
+ account.send_activation_email(async=False)
+ return HttpResponseRedirect(reverse('activate'))
+ else:
+ form = SFEmailForm()
+ context = {
+ 'form': form,
+ 'title': u"重发激活邮件",
+ }
+ return TemplateResponse(request, template_name, context)
# }}}
diff --git a/97suifangqa/isuifangqa.db b/97suifangqa/isuifangqa.db
index 9494aaf..1f13435 100644
--- a/97suifangqa/isuifangqa.db
+++ b/97suifangqa/isuifangqa.db
Binary files differ
diff --git a/97suifangqa/settings.py b/97suifangqa/settings.py
index 3245266..9dda171 100644
--- a/97suifangqa/settings.py
+++ b/97suifangqa/settings.py
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
import os, sys
+import djcelery
+djcelery.setup_loader()
DEBUG = True
@@ -160,8 +162,15 @@ INSTALLED_APPS = (
LOGIN_REDIRECT_URL = '/blog/index'
-##
+## account settings
ACCOUNT_ACTIVATION_DAYS = 3
+MIN_USERNAME_LENGTH = 6
+MAX_USERNAME_LENGTH = 30
+MIN_PASSWORD_LENGTH = 6
+MAX_PASSWORD_LENGTH = 30
+
+## async send mail
+ASYNC_SEND_MAIL = True
## avatar
AVATAR_DIR = os.path.join(PROJECT_ROOT, 'uploads/avatars')
@@ -177,9 +186,6 @@ except ImportError:
BROKER_URL = 'redis://127.0.0.1:6379/0'
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/0'
-import djcelery
-djcelery.setup_loader()
-
## mail server settings
from mail_settings import *