aboutsummaryrefslogtreecommitdiffstats
path: root/97suifangqa
diff options
context:
space:
mode:
authorAlvin Li <liweitianux@gmail.com>2013-10-04 23:56:35 +0800
committerAlvin Li <liweitianux@gmail.com>2013-10-04 23:56:35 +0800
commitf552b41f4b337e6844f71c29ff177915abbfa417 (patch)
tree7ade59430c6767a5b379c7a8cb95af3387622b13 /97suifangqa
parent816730ff659e1338ab3e37a1d45ea337e337b3dd (diff)
download97dev-f552b41f4b337e6844f71c29ff177915abbfa417.tar.bz2
* indicator/static/javascripts/card_chart.js:
improved the display position of 'detail_card_info' * indicator/templates/indicator/SheetDefault.html: destroy 'qtip' when close card * added new app 'apps/sfaccount' * implemented 'signup' and 'activate' functions * implemented async sending activation mail (using 'django-celery' and 'redis') * moved 'registration/*' templates to 'sfaccount/templates' * implemented 'password_change' function: o password_change o password_change_done * implemented 'password_reset' function o password_reset o password_reset_done o password_reset_confirm o password_reset_complete o re-write 'sfaccount.fomrs.SFPasswordResetForm' o re-write 'sfaccount.views.password_reset_view' * improved 'sfaccount.functional' send mail functions o to send 'multipart' mail * added 'README.txt' * added app 'apps/recommend': for comparing with the SCI papers and then recommending most related papers for user.
Diffstat (limited to '97suifangqa')
-rw-r--r--97suifangqa/README.txt8
-rw-r--r--97suifangqa/apps/indicator/fixtures_bak/initial_data.json (renamed from 97suifangqa/apps/indicator/fixtures/initial_data.json)0
-rw-r--r--97suifangqa/apps/indicator/static/javascripts/card_chart.js20
-rw-r--r--97suifangqa/apps/indicator/static/javascripts/delete_card_tip.js60
-rw-r--r--97suifangqa/apps/indicator/templates/indicator/SheetDefault.html18
-rw-r--r--97suifangqa/apps/info/fixtures_bak/initial_data.json (renamed from 97suifangqa/apps/info/fixtures/initial_data.json)0
-rw-r--r--97suifangqa/apps/location/fixtures_bak/initial_data.json (renamed from 97suifangqa/apps/location/fixtures/initial_data.json)0
-rw-r--r--97suifangqa/apps/profile/models.py13
-rw-r--r--97suifangqa/apps/profile/urls.py13
-rw-r--r--97suifangqa/apps/profile/views.py31
-rw-r--r--97suifangqa/apps/recommend/__init__.py (renamed from 97suifangqa/templates/registration/logout.html)0
-rw-r--r--97suifangqa/apps/recommend/models.py50
-rw-r--r--97suifangqa/apps/recommend/tests.py16
-rw-r--r--97suifangqa/apps/recommend/urls.py18
-rw-r--r--97suifangqa/apps/recommend/views.py17
-rw-r--r--97suifangqa/apps/sciblog/fixtures_bak/initial_data.json (renamed from 97suifangqa/apps/sciblog/fixtures/initial_data.json)0
-rw-r--r--97suifangqa/apps/sfaccount/README.txt23
-rw-r--r--97suifangqa/apps/sfaccount/__init__.py (renamed from 97suifangqa/templates/registration/password_change_done.html)0
-rw-r--r--97suifangqa/apps/sfaccount/forms.py141
-rw-r--r--97suifangqa/apps/sfaccount/functional/__init__.py21
-rw-r--r--97suifangqa/apps/sfaccount/functional/mail.py45
-rw-r--r--97suifangqa/apps/sfaccount/management/__init__.py (renamed from 97suifangqa/templates/registration/password_change_form.html)0
-rw-r--r--97suifangqa/apps/sfaccount/management/commands/__init__.py (renamed from 97suifangqa/templates/registration/password_reset_complete.html)0
-rw-r--r--97suifangqa/apps/sfaccount/management/commands/cleanupaccounts.py22
-rw-r--r--97suifangqa/apps/sfaccount/models.py172
-rw-r--r--97suifangqa/apps/sfaccount/tasks.py10
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/activate.html98
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_body.txt9
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_subject.txt1
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/login.html57
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/logout.html35
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/password_change.html32
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/password_change_done.html35
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/password_reset.html36
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_complete.html37
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_confirm.html53
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_done.html45
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_email.html25
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_email.txt13
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_subject.txt1
-rw-r--r--97suifangqa/apps/sfaccount/templates/sfaccount/signup.html (renamed from 97suifangqa/templates/registration/signup.html)22
-rw-r--r--97suifangqa/apps/sfaccount/tests.py16
-rw-r--r--97suifangqa/apps/sfaccount/urls.py77
-rw-r--r--97suifangqa/apps/sfaccount/views.py143
-rw-r--r--97suifangqa/env/requirements.pip3
-rw-r--r--97suifangqa/isuifangqa.dbbin400384 -> 376832 bytes
-rw-r--r--97suifangqa/mail_settings.py.example13
-rw-r--r--97suifangqa/settings.py35
-rw-r--r--97suifangqa/socialoauth_settings.py17
-rw-r--r--97suifangqa/templates/base.html2
-rw-r--r--97suifangqa/templates/registration/login.html47
-rw-r--r--97suifangqa/templates/registration/password_reset_confirm.html0
-rw-r--r--97suifangqa/templates/registration/password_reset_done.html0
-rw-r--r--97suifangqa/templates/registration/password_reset_email.html0
-rw-r--r--97suifangqa/templates/registration/password_reset_form.html0
-rw-r--r--97suifangqa/templates/registration/password_reset_subject.txt0
-rw-r--r--97suifangqa/urls.py25
57 files changed, 1435 insertions, 140 deletions
diff --git a/97suifangqa/README.txt b/97suifangqa/README.txt
new file mode 100644
index 0000000..76c5533
--- /dev/null
+++ b/97suifangqa/README.txt
@@ -0,0 +1,8 @@
+## async send mail:
+-> sfaccount/README.txt
+
+## run redis & celery
+$ redis-server
+$ python manage.py celeryd worker -E
+$ python manage.py celerycam (for monitoring)
+
diff --git a/97suifangqa/apps/indicator/fixtures/initial_data.json b/97suifangqa/apps/indicator/fixtures_bak/initial_data.json
index d26f8b9..d26f8b9 100644
--- a/97suifangqa/apps/indicator/fixtures/initial_data.json
+++ b/97suifangqa/apps/indicator/fixtures_bak/initial_data.json
diff --git a/97suifangqa/apps/indicator/static/javascripts/card_chart.js b/97suifangqa/apps/indicator/static/javascripts/card_chart.js
index 92a91c0..ef2eb24 100644
--- a/97suifangqa/apps/indicator/static/javascripts/card_chart.js
+++ b/97suifangqa/apps/indicator/static/javascripts/card_chart.js
@@ -92,6 +92,22 @@ $(document).ready(function(){
// update 'detail_card_id'
detail_card_id = $(this).closest(".index_card").attr("id").replace('index_card_', '');
var card = $("#index_card_"+detail_card_id);
+ // determine the position to show the 'detail_card'
+ var pos_to_insertafter = null;
+ if (card.hasClass("index_card_sec")) {
+ // this card in on the right
+ pos_to_insertafter = card;
+ }
+ else if (card.nextAll(".index_card_sec").length) {
+ // this card is on the left
+ pos_to_insertafter = card.nextAll(".index_card_sec").first();
+ }
+ else {
+ // this card is the last card
+ pos_to_insertafter = card.nextAll(".act_card_container");
+ }
+ // move 'detail_card_info' div
+ $(".detail_card_info").insertAfter(pos_to_insertafter);
// check if this card has data (class "record_empty")
if (card.hasClass("record_empty")) {
$(".detail_card_info").hide();
@@ -142,7 +158,7 @@ $(document).ready(function(){
getdata_type, getdata_num,
begin_date_str, end_date_str
);
- $(".act_card_container").addClass("move_div_2_left");
+ //$(".act_card_container").addClass("move_div_2_left");
return false;
});
@@ -215,7 +231,7 @@ $(document).ready(function(){
//初始化详细卡片id
detail_card_id = "-1";
//添加删除div位置初始化
- $(".act_card_container").removeClass("move_div_2_left");
+ //$(".act_card_container").removeClass("move_div_2_left");
return false;
});
});
diff --git a/97suifangqa/apps/indicator/static/javascripts/delete_card_tip.js b/97suifangqa/apps/indicator/static/javascripts/delete_card_tip.js
index 9365d46..da5c896 100644
--- a/97suifangqa/apps/indicator/static/javascripts/delete_card_tip.js
+++ b/97suifangqa/apps/indicator/static/javascripts/delete_card_tip.js
@@ -1,32 +1,36 @@
// global js var: card_2_delete_id (type: string)
$(document).ready(function(){
-// console.log(parent.card_2_delete_id); //要取消关注的 卡片id 的获取方法
- //点大叉、继续关注按钮,关闭弹层页面
- $(".delete_card_tip_close, .action_confirm_ignore").bind("click", function(){
- parent.TB_remove();
- return false;
- });
-
- //取消关注,关闭弹层页面
- $(".action_confirm_cancel").bind("click", function(){
- // ajax process to unfollow the indicator
- // indicator_id -> parseInt(parent.card_2_delete_id)
- // 底层数据层取消关注(ajax)
- var date = new Date();
- var time = date.getTime();
- $.ajax({
- type: 'get',
- url: parent.indicator_url + 'ajax/unfollow_indicator',
- data: 'indicator_id='+parent.card_2_delete_id+'&time='+time,
- success: function(data) {
- if (data == 'success') {
- parent.delete_card();
- parent.TB_remove();
- }
- },
- });
-
- return false;
- });
+ // console.log(parent.card_2_delete_id); //要取消关注的 卡片id 的获取方法
+ //点大叉、继续关注按钮,关闭弹层页面
+ $(".delete_card_tip_close, .action_confirm_ignore").bind("click", function(){
+ parent.TB_remove();
+ return false;
+ });
+
+ //取消关注,关闭弹层页面
+ $(".action_confirm_cancel").bind("click", function(){
+ // ajax process to unfollow the indicator
+ // indicator_id -> parseInt(parent.card_2_delete_id)
+ // 底层数据层取消关注(ajax)
+ var date = new Date();
+ var time = date.getTime();
+ $.ajax({
+ type: 'get',
+ url: parent.indicator_url + 'ajax/unfollow_indicator',
+ data: 'indicator_id='+parent.card_2_delete_id+'&time='+time,
+ success: function(data) {
+ if (data == 'success') {
+ // destroy the 'qtip' if exist
+ //$('#index_card_'+parent.card_2_delete_id, window.parent.document).qtip('destroy', true);
+ // remove card
+ parent.delete_card();
+ parent.TB_remove();
+ }
+ },
+ });
+
+ return false;
+ });
});
+// vim: set ts=4 sw=4 tw=0 fenc=utf-8 ft=javascript: //
diff --git a/97suifangqa/apps/indicator/templates/indicator/SheetDefault.html b/97suifangqa/apps/indicator/templates/indicator/SheetDefault.html
index 07cf2f0..5a6659f 100644
--- a/97suifangqa/apps/indicator/templates/indicator/SheetDefault.html
+++ b/97suifangqa/apps/indicator/templates/indicator/SheetDefault.html
@@ -284,12 +284,12 @@
{% block page %}
{% csrf_token %}
- <iframe align="left" width="420" height="1020" src="{% url indicator_sidebar %}" style="position:fixed;left:0;top:0;z-index:99;" frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
+ <iframe align="left" width="420" height="1020" src="{% url indicator_sidebar %}" style="position:fixed;left:0;top:0;z-index:99;" frameborder="no" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<!-- TODO -->
<div id="login_container">
<div class="logged-in" id="login">
- <img class="user-photo" alt="" src="{% static "images/userPhoto.jpg" %}" />
+ <img class="user-photo" alt="user_photo" src="{% static "images/userPhoto.jpg" %}" />
<span class="number-block green-block user-level">6</span>
<span class="drop-down-area">
<span class="user-name">username</span>
@@ -344,14 +344,14 @@
<span class="data_value">{{ ind|dict_get:"last_record"|dict_get:"value_html"|safe }}</span>
<span class="data_unit">{% if ind|dict_get:"std_unit_symbol" %}({{ ind|dict_get:"std_unit_symbol" }}){% endif %}</span>
</div>
- <img class="small_edit_icon" src="{% static "images/pen.png" %}" />
+ <img class="small_edit_icon" alt="edit_icon" src="{% static "images/pen.png" %}" />
<!-- explain_icon -->
{% if ind|dict_get:"record_empty" %}
- <img class="explain_icon nodata_icon" src="{% static "images/nodata.png" %}" style="display: block;" />
- <img class="explain_icon lastdata_icon" src="{% static "images/last_edit_data.png" %}" style="display: none;" />
+ <img class="explain_icon nodata_icon" alt="nodata_icon" src="{% static "images/nodata.png" %}" style="display: block;" />
+ <img class="explain_icon lastdata_icon" alt="lastdata_icon" src="{% static "images/last_edit_data.png" %}" style="display: none;" />
{% else %}
- <img class="explain_icon nodata_icon" src="{% static "images/nodata.png" %}" style="display: none;" />
- <img class="explain_icon lastdata_icon" src="{% static "images/last_edit_data.png" %}" style="display: block;" />
+ <img class="explain_icon nodata_icon" alt="nodata_icon" src="{% static "images/nodata.png" %}" style="display: none;" />
+ <img class="explain_icon lastdata_icon" alt="lastdata_icon" src="{% static "images/last_edit_data.png" %}" style="display: block;" />
{% endif %}
<div style="clear:both;"></div>
<!-- last edit date -->
@@ -433,7 +433,7 @@
{% endif %}
<div class="card_bottom">
- <div class="understand_index"><a class="thickbox" href="{% url indicator_indexdesc %}?card_id={{ ind|dict_get:"id" }}&url_type=html&no_title=true&TB_iframe=true&height=367&width=630">了解该指标</a></div>
+ <div class="understand_index"><a class="thickbox" href="{% url indicator_indexdesc %}?card_id={{ ind|dict_get:"id" }}&amp;url_type=html&amp;no_title=true&amp;TB_iframe=true&amp;height=367&amp;width=630">了解该指标</a></div>
<!-- TODO -->
<div class="simulation_sheet"><a href="{% static "images/demo_sheet.png" %}" class="thickbox">仿真化验单</a></div>
<div class="detail_history">
@@ -450,7 +450,7 @@
width参数为弹出层页面宽度+2,
card_id参数为 "卡片id"
{% endcomment %}
- <a class="card_delete_icon card_delete thickbox" href="{% url indicator_deletecardtip %}?card_id={{ ind|dict_get:"id" }}&url_type=html&no_title=true&TB_iframe=true&height=166&width=630"></a>
+ <a class="card_delete_icon card_delete thickbox" href="{% url indicator_deletecardtip %}?card_id={{ ind|dict_get:"id" }}&amp;url_type=html&amp;no_title=true&amp;TB_iframe=true&amp;height=166&amp;width=630"></a>
</div> <!-- end: index_card -->
{% endfor %} {# end: indicators #}
diff --git a/97suifangqa/apps/info/fixtures/initial_data.json b/97suifangqa/apps/info/fixtures_bak/initial_data.json
index 4440490..4440490 100644
--- a/97suifangqa/apps/info/fixtures/initial_data.json
+++ b/97suifangqa/apps/info/fixtures_bak/initial_data.json
diff --git a/97suifangqa/apps/location/fixtures/initial_data.json b/97suifangqa/apps/location/fixtures_bak/initial_data.json
index a06ec34..a06ec34 100644
--- a/97suifangqa/apps/location/fixtures/initial_data.json
+++ b/97suifangqa/apps/location/fixtures_bak/initial_data.json
diff --git a/97suifangqa/apps/profile/models.py b/97suifangqa/apps/profile/models.py
index 2168f39..b926d31 100644
--- a/97suifangqa/apps/profile/models.py
+++ b/97suifangqa/apps/profile/models.py
@@ -10,6 +10,8 @@ from .storage import OverwriteStorage
from .utils import avatar_by_user
from .image import crop
+from sfaccount import models as am
+
class Profile(models.Model):
@@ -25,11 +27,14 @@ class Profile(models.Model):
(3, u"硕士"),
(4, u"博士"))
- user = models.OneToOneField(User, null=True, blank=True)
- name = models.CharField(u"用户名", max_length=20, null=True, blank=True)
- avatar = models.ImageField(u"头像", upload_to="uploads/avatar/", storage=OverwriteStorage())
+ account = models.OneToOneField(am.Account, verbose_name=u"账户")
+ screen_name = models.CharField(u"显示名称",
+ max_length=15, blank=True)
+ #user = models.OneToOneField(User, null=True, blank=True)
+ #name = models.CharField(u"用户名", max_length=20, null=True, blank=True)
+ #avatar = models.ImageField(u"头像", upload_to="uploads/avatar/", storage=OverwriteStorage())
education = models.IntegerField(u"学历", choices=education_choices)
- email = models.EmailField(u"邮箱", primary_key=True)
+ #email = models.EmailField(u"邮箱", primary_key=True)
gender = models.IntegerField(u"性别", choices=gender_choices, default=0)
user_level= models.IntegerField(u"等级", default=0)
medicines = models.ManyToManyField("medicine.Medicine", related_name="users", verbose_name= u"药物", null=True, blank=True)
diff --git a/97suifangqa/apps/profile/urls.py b/97suifangqa/apps/profile/urls.py
index cbc453d..e6c396d 100644
--- a/97suifangqa/apps/profile/urls.py
+++ b/97suifangqa/apps/profile/urls.py
@@ -1,9 +1,10 @@
+# -*- coding: utf-8 -*-
+
from django.conf.urls import patterns, url
-from .views import *
-urlpatterns = patterns('',
- url(r'^login/?$', login, name = "login"),
- url(r'^logout/?$', logout, name = "logout"),
- url(r'^signup/?$', signup, name = "signup"),
- )
+urlpatterns = patterns('profile.views',
+ url(r'^(?P<username>[a-zA-Z_][a-zA-Z0-9_]*)/$',
+ 'profile_view', name='profile_home'),
+)
+
diff --git a/97suifangqa/apps/profile/views.py b/97suifangqa/apps/profile/views.py
index c41e62b..e7d17e9 100644
--- a/97suifangqa/apps/profile/views.py
+++ b/97suifangqa/apps/profile/views.py
@@ -1,30 +1,15 @@
# -*- coding: utf-8 -*-
from django.http import HttpResponse, HttpResponseRedirect
-from django.conf import settings
+from django.conf import settings
from django.shortcuts import render
-from django.contrib.auth.views import login, logout
-from django.contrib.auth import login as auth_login
-from .forms import UserCreationForm
-
-
-def signup(request):
- u'''
- 用户注册
- '''
- if request.user.is_authenticated():
- return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
-
- if request.method == 'POST':
- form = UserCreationForm(request.POST)
- if form.is_valid():
- user = form.save()
- return HttpResponseRedirect(request.REQUEST.get('next'))
- else:
- form = UserCreationForm()
-
- return render(request, 'registration/signup.html',
- locals())
+# profile home {{{
+def profile_view(request, username):
+ """
+ show profile of given user
+ """
+ return HttpResponse('Hi, %s' % username)
+# }}}
diff --git a/97suifangqa/templates/registration/logout.html b/97suifangqa/apps/recommend/__init__.py
index e69de29..e69de29 100644
--- a/97suifangqa/templates/registration/logout.html
+++ b/97suifangqa/apps/recommend/__init__.py
diff --git a/97suifangqa/apps/recommend/models.py b/97suifangqa/apps/recommend/models.py
new file mode 100644
index 0000000..98ae64d
--- /dev/null
+++ b/97suifangqa/apps/recommend/models.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+
+"""
+models for apps/recommend
+"""
+
+
+from django.db import models
+from django.contrib import admin
+
+
+class TreatRespnse(models.Model): # {{{
+ """
+ 治疗反应/结果的描述,以及结果的价值/权重
+ """
+ name = models.CharField(u"名称", max_length=100)
+ description = models.TextField(u"详细描述", blank=True)
+ weight = models.FloatField(u"权重", help_text=u"范围:0-10")
+ # datetime
+ created_at = models.DateTimeField(u"创建时间", auto_now_add=True)
+ updated_at = models.DateTimeField(u"更新时间",
+ auto_now_add=True, auto_now=True)
+
+ class Meta:
+ verbose_name_plural = u"治疗反应"
+
+ def __unicode__(self):
+ return u"< TreatRespnse: %s >" % self.name
+
+ def save(self, **kwargs):
+ if self.is_valid():
+ super(TreatRespnse, self).save(**kwargs)
+ else:
+ return self
+
+ def is_valid(self, **kwargs):
+ # check weight range
+ if (self.weight < 0.0) or (self.weight > 10.0):
+ print u"Error: weight < 0.0 / weight > 10.0"
+ return False
+ #
+ return True
+# }}}
+
+
+# admin
+admin.site.register([
+ TreatRespnse,
+])
+
diff --git a/97suifangqa/apps/recommend/tests.py b/97suifangqa/apps/recommend/tests.py
new file mode 100644
index 0000000..501deb7
--- /dev/null
+++ b/97suifangqa/apps/recommend/tests.py
@@ -0,0 +1,16 @@
+"""
+This file demonstrates writing tests using the unittest module. These will pass
+when you run "manage.py test".
+
+Replace this with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.assertEqual(1 + 1, 2)
diff --git a/97suifangqa/apps/recommend/urls.py b/97suifangqa/apps/recommend/urls.py
new file mode 100644
index 0000000..09dfed4
--- /dev/null
+++ b/97suifangqa/apps/recommend/urls.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+
+"""
+URL configuration for apps/recommend
+"""
+
+from django.conf.urls.defaults import *
+
+from recommend import models as rm
+
+
+urlpatterns = patterns('recommend.views',
+ # app index
+ url(r'^$',
+ 'recommend_index',
+ name='recommend_index'),
+)
+
diff --git a/97suifangqa/apps/recommend/views.py b/97suifangqa/apps/recommend/views.py
new file mode 100644
index 0000000..02d5616
--- /dev/null
+++ b/97suifangqa/apps/recommend/views.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+
+"""
+views for apps/recommend
+"""
+
+from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
+from django.shortcuts import render, get_object_or_404
+
+
+# index
+def recommend_index(request):
+ """
+ index view for apps/recommend
+ """
+ return HttpResponse("recommend index")
+
diff --git a/97suifangqa/apps/sciblog/fixtures/initial_data.json b/97suifangqa/apps/sciblog/fixtures_bak/initial_data.json
index 6038ffe..6038ffe 100644
--- a/97suifangqa/apps/sciblog/fixtures/initial_data.json
+++ b/97suifangqa/apps/sciblog/fixtures_bak/initial_data.json
diff --git a/97suifangqa/apps/sfaccount/README.txt b/97suifangqa/apps/sfaccount/README.txt
new file mode 100644
index 0000000..44eda9e
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/README.txt
@@ -0,0 +1,23 @@
+using 'django-celery' and 'redis' to implement the function
+of 'async sending email' with the activation key for
+newly registered user.
+
+REF:
+(1) use Celery in Django with a Redis backend
+ http://killtheyak.com/django-celery-redis/
+
+HOWTO run:
+1) pip install django-celery redis
+2) OS install package 'redis' (maybe 'redis-server')
+3) add 'djcelery' to 'INSTALLED_APPS'
+4) add settings for 'redis' & 'djcelery' in 'settings.py'
+ SF_MAIL
+5) system: $ redis-server
+6) ./manage.py syncdb
+7) ./manage.py celeryd worker -E
+
+TEST:
+a) ./manage.py shell
+ >>> from sfaccount.tasks import send_mail
+ >>> send_mail(to, subject, body)
+
diff --git a/97suifangqa/templates/registration/password_change_done.html b/97suifangqa/apps/sfaccount/__init__.py
index e69de29..e69de29 100644
--- a/97suifangqa/templates/registration/password_change_done.html
+++ b/97suifangqa/apps/sfaccount/__init__.py
diff --git a/97suifangqa/apps/sfaccount/forms.py b/97suifangqa/apps/sfaccount/forms.py
new file mode 100644
index 0000000..d2a3bf1
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/forms.py
@@ -0,0 +1,141 @@
+# -*- coding: utf-8 -*-
+
+from django import forms
+from django.template import loader
+from django.utils.http import int_to_base36
+from django.contrib.auth.models import User
+from django.contrib.auth.tokens import default_token_generator
+from django.contrib.sites.models import get_current_site
+
+from django.utils.translation import ugettext, ugettext_lazy as _
+
+from sfaccount.tasks import send_mail
+
+import re
+
+
+# AccountForm {{{
+class AccountForm(forms.Form):
+ """
+ form for signing up a new account
+ """
+ username = forms.RegexField(regex=r'^[A-Za-z0-9_-]+$',
+ max_length=30, label=u"用户名",
+ help_text=u"由字母、数字和下划线组成,长度6-30位",
+ error_messages={'invalid': u"用户名仅能包含字母、数字和下划线"},
+ )
+ email = forms.EmailField(max_length=75, label=u"邮箱")
+ password1 = forms.CharField(label=u"密码", max_length=30,
+ help_text=u"密码长度6-30位",
+ widget=forms.PasswordInput)
+ password2 = forms.CharField(label=u"确认密码", max_length=30,
+ widget=forms.PasswordInput)
+
+ def clean_username(self):
+ username = self.cleaned_data['username']
+ # check length
+ if len(username) < 6:
+ raise forms.ValidationError(u'用户名长度需大于6位')
+ # check first letter
+ p = re.compile('[a-zA-Z_]')
+ if p.match(username[0]):
+ pass
+ else:
+ raise forms.ValidationError(u'首字母必须是字母或下划线')
+ # check if exists
+ try:
+ User.objects.get(username=username)
+ except User.DoesNotExist:
+ return username
+ raise forms.ValidationError(u'用户名已经被占用')
+
+ def clean_email(self):
+ try:
+ User.objects.get(email__iexact=self.cleaned_data['email'])
+ except User.DoesNotExist:
+ return self.cleaned_data['email']
+ raise forms.ValidationError(u'邮箱地址已经被占用')
+
+ def clean_password1(self):
+ password1 = self.cleaned_data['password1']
+ if len(password1) < 6:
+ raise forms.ValidationError(u'密码长度需大于6位')
+ return password1
+
+ def clean(self):
+ cd = self.cleaned_data
+ if 'password1' in cd and 'password2' in cd:
+ if cd['password1'] != cd['password2']:
+ raise forms.ValidationError(u'两次输入的密码不一致')
+ #
+ return cd
+# }}}
+
+
+# SFPasswordResetForm {{{
+class SFPasswordResetForm(forms.Form):
+ """
+ to replace django's 'PasswordResetForm'
+ 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?"),
+ 'unusable': _("The user account associated with this e-mail "
+ "address cannot reset the password."),
+ }
+ email = forms.EmailField(label=_("E-mail"), max_length=75)
+
+ def save(self, domain_override=None,
+ subject_template_name='registration/password_reset_subject.txt',
+ email_template_name='registration/password_reset_email.txt',
+ use_https=False, token_generator=default_token_generator,
+ from_email=None, request=None,
+ html_email_template_name=None):
+ """
+ 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
+ if not user.has_usable_password():
+ continue
+ if not domain_override:
+ current_site = get_current_site(request)
+ site_name = current_site.name
+ domain = current_site.domain
+ else:
+ site_name = domain = domain_override
+ c = {
+ 'email': user.email,
+ 'domain': domain,
+ 'site_name': site_name,
+ 'uid': int_to_base36(user.id),
+ 'user': user,
+ 'token': token_generator.make_token(user),
+ 'protocol': 'https' if use_https else 'http',
+ }
+ subject = loader.render_to_string(subject_template_name, c)
+ # Email subject *must not* contain newlines
+ subject = ''.join(subject.splitlines())
+ body_text = loader.render_to_string(email_template_name, c)
+ # html email
+ if html_email_template_name:
+ body_html = loader.render_to_string(html_email_template_name, c)
+ else:
+ body_html = None
+ # send mail
+ to = user.email
+ send_mail(to, subject, body_text, body_html)
+# }}}
+
+
diff --git a/97suifangqa/apps/sfaccount/functional/__init__.py b/97suifangqa/apps/sfaccount/functional/__init__.py
new file mode 100644
index 0000000..6cfbcbf
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/functional/__init__.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+
+from django.conf import settings
+from sfaccount.functional.mail import send_mail_multipart
+
+EMAIL = settings.SF_EMAIL
+
+def send_mail(to, subject, content_text=None, content_html=None):
+ send_mail_multipart(
+ host=EMAIL['smtp_host'],
+ port=EMAIL['smtp_port'],
+ username=EMAIL['username'],
+ password=EMAIL['password'],
+ mail_from=EMAIL['from'],
+ mail_to=to,
+ subject=subject,
+ content_text=content_text,
+ content_html=content_html,
+ display_from=EMAIL['display_from']
+ )
+
diff --git a/97suifangqa/apps/sfaccount/functional/mail.py b/97suifangqa/apps/sfaccount/functional/mail.py
new file mode 100644
index 0000000..30b1701
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/functional/mail.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+
+import smtplib
+
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+
+
+def send_mail_multipart(host,
+ port,
+ username,
+ password,
+ mail_from,
+ mail_to,
+ subject,
+ content_text=None,
+ content_html=None,
+ display_from=None):
+ # create message container
+ # correct MIME type is 'multipart/alternative'
+ msg = MIMEMultipart('alternative')
+ # from & to
+ msg['From'] = display_from or mail_from
+ if isinstance(mail_to, (list, tuple)):
+ msg['To'] = ', '.join(mail_to)
+ else:
+ msg['To'] = mail_to
+ # subject
+ msg['Subject'] = subject
+ # body (utf-8 encode required)
+ if isinstance(content_text, unicode):
+ content_text = content_text.encode('utf-8')
+ if isinstance(content_html, unicode):
+ content_html = content_html.encode('utf-8')
+ text_part = MIMEText(content_text, 'plain')
+ html_part = MIMEText(content_html, 'html')
+ msg.attach(text_part)
+ msg.attach(html_part)
+ # send
+ s = smtplib.SMTP()
+ s.connect(host, port)
+ s.login(username, password)
+ s.sendmail(mail_from, mail_to, msg.as_string())
+ s.quit()
+
diff --git a/97suifangqa/templates/registration/password_change_form.html b/97suifangqa/apps/sfaccount/management/__init__.py
index e69de29..e69de29 100644
--- a/97suifangqa/templates/registration/password_change_form.html
+++ b/97suifangqa/apps/sfaccount/management/__init__.py
diff --git a/97suifangqa/templates/registration/password_reset_complete.html b/97suifangqa/apps/sfaccount/management/commands/__init__.py
index e69de29..e69de29 100644
--- a/97suifangqa/templates/registration/password_reset_complete.html
+++ b/97suifangqa/apps/sfaccount/management/commands/__init__.py
diff --git a/97suifangqa/apps/sfaccount/management/commands/cleanupaccounts.py b/97suifangqa/apps/sfaccount/management/commands/cleanupaccounts.py
new file mode 100644
index 0000000..c79e037
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/management/commands/cleanupaccounts.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+
+"""
+A management command which deletes expired accounts (e.g.,
+accounts which signed up but never activated) from the database.
+
+Calls ``Account.objects.delete_expired_accounts()'',
+which contains the actual logic for determining which
+accounts are deleted.
+"""
+
+from django.core.management.base import NoArgsCommand
+
+from accounts.models import Account
+
+
+class Command(NoArgsCommand):
+ help = "Delete expired accounts from the database"
+
+ def handle_noargs(self, **options):
+ Account.objects.delete_expired_accounts()
+
diff --git a/97suifangqa/apps/sfaccount/models.py b/97suifangqa/apps/sfaccount/models.py
new file mode 100644
index 0000000..bb1fe29
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/models.py
@@ -0,0 +1,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: #
diff --git a/97suifangqa/apps/sfaccount/tasks.py b/97suifangqa/apps/sfaccount/tasks.py
new file mode 100644
index 0000000..94b520a
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/tasks.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+
+from celery import task
+
+from sfaccount.functional import send_mail as _send_mail
+
+@task
+def send_mail(to, subject, content_text, content_html):
+ _send_mail(to, subject, content_text, content_html)
+
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/activate.html b/97suifangqa/apps/sfaccount/templates/sfaccount/activate.html
new file mode 100644
index 0000000..a81af6d
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/activate.html
@@ -0,0 +1,98 @@
+{% extends "picture-base.html" %}
+{% load staticfiles %}
+
+{% block title %}
+激活账户 | 97 随访
+{% endblock %}
+
+{% block bodyclasses %}{{ block.super }} registration signup{% endblock %}
+{% block othercss %}
+<link rel="stylesheet" href="{% static "stylesheets/sass/registration.css" %}">
+{% endblock %}
+
+{% block scripts %}
+ <script type="text/javascript">
+ // activate account url
+ var activate_url = '{% url activate %}';
+
+ $(document).ready(function(){
+ // validate key input
+ $("#activation_key").focus(function() {
+ $(this).removeClass("valid invalid");
+ });
+ $("#activation_key").on("validate", null, function() {
+ var sha1_regex = /^[0-9a-f]{40}$/;
+ var key_raw = $(this).val();
+ var key = htmlEscape(key_raw.toLowerCase());
+ if (sha1_regex.test(key)) {
+ // key in valid format
+ $(this).removeClass("invalid");
+ $(this).addClass("valid");
+ }
+ else {
+ $(this).removeClass("valid");
+ $(this).addClass("invalid");
+ }
+ });
+
+ // sumbit key to activate account
+ $("#activate_account").on('submit', null, function() {
+ // validate key first
+ $("#activation_key").trigger("validate");
+ if ($(".invalid").length) {
+ // there exists invalid input
+ return false;
+ }
+ else {
+ // submit
+ var key_raw = $("#activation_key").val();
+ var key = htmlEscape(key_raw.toLowerCase());
+ var target_url = activate_url + key + '/';
+ //console.log(target_url);
+ window.location.href = target_url;
+ }
+ });
+ $("#activate_account").on('click', null, function() {
+ $(this).trigger('submit');
+ });
+ $("#activation_key").on('keypress', null, function(e) {
+ var keycode = (e.keyCode ? e.keyCode : e.which);
+ if (keycode == 13) {
+ $("#activate_account").trigger('submit');
+ return false;
+ }
+ });
+
+ });
+
+ function htmlEscape(str) {
+ return String(str)
+ .replace(/&/g, '&amp;')
+ .replace(/"/g, '&quot;')
+ .replace(/'/g, '&#39;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;');
+ }
+ </script>
+{% endblock %}
+
+{% block body %}
+ <h2>加入97随访 &emsp; 科学了解乙肝治疗</h2>
+
+ <div class="activate_failed" style="display: {% if activate_failed %}block{% else %}none{% endif %} ;">
+ <h4>激活账户失败</h4>
+ 请检查激活码或激活链接。
+ <br />
+ 您也可以直接在下方输入激活码来完成账户激活。
+ </div>
+
+ <div class="activation">
+ <span class="prompt">激活码</span>
+ <input type="text" id="activation_key" />
+ <br />
+ <input type="button" id="activate_account" 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/activation_email_body.txt b/97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_body.txt
new file mode 100644
index 0000000..32be3e9
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_body.txt
@@ -0,0 +1,9 @@
+尊敬的 {{ username }},
+
+感谢您注册97随访(97suifang.com)。
+
+您的激活码为 {{ activation_key }},请在 {{ expiration_days }} 天内激活账户,直接打开以下链接进行激活:
+http://www.97suifang.com/accounts/activate/{{ activation_key }}/
+
+
+97随访
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_subject.txt b/97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_subject.txt
new file mode 100644
index 0000000..9a9a040
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/activation_email_subject.txt
@@ -0,0 +1 @@
+97随访(97suifang.com)账户激活
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/login.html b/97suifangqa/apps/sfaccount/templates/sfaccount/login.html
new file mode 100644
index 0000000..f5c7942
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/login.html
@@ -0,0 +1,57 @@
+{% extends "picture-base.html" %}
+{% load staticfiles %}
+{% block bodyclasses %}{{ block.super }} registration login{% endblock %}
+{% block othercss %}
+<link rel="stylesheet" href="{% static "stylesheets/sass/registration.css" %}">
+{% endblock %}
+
+{% block title %}
+登录 | 97随访
+{% endblock %}
+
+{% block body %}
+<h2>加入97随访 &emsp; 科学了解乙肝治疗</h2>
+<p></p>
+<p>
+ <img src="{% static "images/sinalogo.png" %}" alt="" style="width: 2.5em; vertical-align: middle;">
+ 新浪微博账号登录
+ </p>
+
+ <p>
+ <img src="{% static "images/qqlogo.png" %}" alt="" style="width: 2.5em; vertical-align: middle;">
+ 腾讯QQ账号登录
+ </p>
+
+ <form method="post">{% csrf_token %}
+ <table class="reg-form login-form">
+ <tr>
+ <!--
+ <td class="login-prompt">
+ <span class="prompt">或者直接用邮箱登陆</span>
+ </td>
+ <td></td>
+ -->
+ </tr>
+ <tr>
+ <td>
+ <input type="text" name="{{ form.username.name }}" value="{{ form.username.value|default_if_none:"" }}" maxlength="80" placeholder="{{ form.username.label }}" class="username ">
+ </td>
+ <td rowspan="2" class="error">
+ {{form.non_field_errors|first}}
+ </td>
+ </tr>
+ <tr>
+ <td><input type="password" name="{{ form.password.name }}" placeholder="{{ form.password.label }}" class="password"></td>
+ </tr>
+ </table>
+
+ <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>
+{% endblock body%}
+
+{# vim: set ts=2 sw=2 tw=0 fenc=utf-8 ft=htmldjango.html: #}
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/logout.html b/97suifangqa/apps/sfaccount/templates/sfaccount/logout.html
new file mode 100644
index 0000000..0d05ae5
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/logout.html
@@ -0,0 +1,35 @@
+{% 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() {
+ $("#re-login").bind("click", function() {
+ window.location.href = login_url;
+ });
+ });
+ </script>
+{% endblock %}
+
+{% block body %}
+ <h2>加入97随访 &emsp; 科学了解乙肝治疗</h2>
+
+ <p>感谢您使用97随访!</p>
+
+ <p>
+ <input type="button" id="re-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/password_change.html b/97suifangqa/apps/sfaccount/templates/sfaccount/password_change.html
new file mode 100644
index 0000000..7918016
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/password_change.html
@@ -0,0 +1,32 @@
+{% extends "picture-base.html" %}
+{% load staticfiles %}
+{% block bodyclasses %}{{ block.super }} registration login{% endblock %}
+{% block othercss %}
+<link rel="stylesheet" href="{% static "stylesheets/sass/registration.css" %}">
+{% endblock %}
+
+{% block title %}
+修改密码 | 97随访
+{% endblock %}
+
+{% block body %}
+ <h2>加入97随访 &emsp; 科学了解乙肝治疗</h2>
+
+ <h3>修改密码</h3>
+ <form action="" method="post">{% csrf_token %}
+ <table class="change-password-form login-form">
+ {% for item in form %}
+ <tr>
+ <td>
+ <input type="{{ item.field.widget.input_type }}" name="{{ item.name }}" {% if item.field.widget.input_type == "text" %}value="{{ item.value|default_if_none:"" }}"{% endif %} placeholder="{{ item.label }}" class="{{ item.name }}" />
+ </td>
+ <td class="error">{{ item.errors|join:"" }}</td>
+ </tr>
+ {% endfor %}
+ </table>
+
+ <input type="submit" value="修改密码" class="submit change-password" />
+ </form>
+{% 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
new file mode 100644
index 0000000..ed91216
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/password_change_done.html
@@ -0,0 +1,35 @@
+{% 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 home_url = '{% url go_home %}';
+
+ $(document).ready(function() {
+ $("#go-home").bind("click", function() {
+ window.location.href = home_url;
+ });
+ });
+ </script>
+{% endblock %}
+
+{% block body %}
+ <h2>加入97随访 &emsp; 科学了解乙肝治疗</h2>
+
+ <h4>密码修改成功!</h4>
+
+ <p>
+ <input type="button" id="go-home" 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/password_reset.html b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset.html
new file mode 100644
index 0000000..87421d3
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset.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="password-reset">
+ <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/password_reset_complete.html b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_complete.html
new file mode 100644
index 0000000..2027cd2
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_complete.html
@@ -0,0 +1,37 @@
+{% 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>重设密码成功!</h4>
+
+ <p>
+ 您的密码已经重新设置,现在您可以继续登录账户。
+ </p>
+
+ <input type="button" id="login" value="登录账户" />
+{% endblock %}
+
+<!-- vim: set ts=8 sw=2 tw=0 fenc=utf-8 ft=htmldjango.html: -->
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_confirm.html b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_confirm.html
new file mode 100644
index 0000000..8522af5
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_confirm.html
@@ -0,0 +1,53 @@
+{% 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">
+ // password_reset url
+ var password_reset_url = '{% url password_reset %}';
+
+ $(document).ready(function() {
+ $("#password-reset").bind("click", function() {
+ window.location.href = password_reset_url;
+ });
+ });
+ </script>
+{% endblock %}
+
+{% block body %}
+ <h2>加入97随访 &emsp; 科学了解乙肝治疗</h2>
+
+ {% if validlink %}
+ <h4>请设置新密码</h4>
+
+ <form action="" method="post">{% csrf_token %}
+ <table class="password-reset">
+ {% for item in form %}
+ <tr>
+ <td>
+ <input type="{{ item.field.widget.input_type }}" name="{{ item.name }}" {% if item.field.widget.input_type == "text" %}value="{{ item.value|default_if_none:"" }}"{% endif %} placeholder="{{ item.label }}" class="{{ item.name }}">
+ </td>
+ <td class="error">{{ item.errors|join:"" }}</td>
+ </tr>
+ {% endfor %}
+ </table>
+ <input type="submit" class="sumbit password-reset" value="重设密码" />
+ </form>
+ {% else %}
+ <h4>重设密码失败</h4>
+
+ <p>您使用的密码重设链接无效,可能因为该链接已被使用过。</p>
+ <p>您可以尝试重新申请重设密码。</p>
+ <input type="button" id="password-reset" value="申请重设密码" />
+ {% endif %}
+{% endblock %}
+
+<!-- vim: set ts=8 sw=2 tw=0 fenc=utf-8 ft=htmldjango.html: -->
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_done.html b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_done.html
new file mode 100644
index 0000000..c7bd9a3
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_done.html
@@ -0,0 +1,45 @@
+{% 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">
+ // password_reset url
+ var password_reset_url = '{% url password_reset %}';
+
+ $(document).ready(function() {
+ $("#password-reset").bind("click", function() {
+ window.location.href = password_reset_url;
+ });
+ });
+ </script>
+{% endblock %}
+
+{% block body %}
+ <h2>加入97随访 &emsp; 科学了解乙肝治疗</h2>
+
+ <h4>
+ 密码重设邮件已发送!
+ </h4>
+ <p>
+ 我们已经向您提交的邮箱地址发送了密码重设说明,
+ 请注意查收邮件,并按邮件说明来重新设置密码。
+ </p>
+
+ <p>
+ 还没收到邮件?您可以尝试再次申请重设密码。
+ </p>
+ <p>
+ <input type="button" id="password-reset" value="申请重设密码" />
+ </p>
+
+{% endblock %}
+
+<!-- vim: set ts=8 sw=2 tw=0 fenc=utf-8 ft=htmldjango.html: -->
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_email.html b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_email.html
new file mode 100644
index 0000000..beae46f
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_email.html
@@ -0,0 +1,25 @@
+{% autoescape off %}
+<html>
+ <head></head>
+ <body>
+ <p>尊敬的 {{ user.username }},</p>
+
+ <p>您收到该邮件是因为您已请求重设97随访({{ domain }})账户的密码。</p>
+
+ <p>请打开以下链接来为您的账户设置新密码:<br />
+ {% block reset_link %}
+ {{ protocol }}://{{ domain }}{% url django.contrib.auth.views.password_reset_confirm uidb36=uid, token=token %}
+ {% endblock %}
+ </p>
+
+ <p>您的登录用户名为: {{ user.username }}</p>
+ <br />
+
+
+ <p>感谢您使用我们的产品!</p>
+ <br />
+
+ <p>97随访 团队</p>
+ </body>
+</html>
+{% endautoescape %}
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_email.txt b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_email.txt
new file mode 100644
index 0000000..20c817c
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_email.txt
@@ -0,0 +1,13 @@
+尊敬的 {{ user.username }},
+
+您收到该邮件是因为您已请求重设97随访({{ domain }})账户的密码。
+
+请打开以下链接来为您的账户设置新密码:
+{{ protocol }}://{{ domain }}{% url django.contrib.auth.views.password_reset_confirm uidb36=uid, token=token %}
+
+您的登录用户名为: {{ user.username }}
+
+
+感谢您使用我们的产品!
+
+97随访 团队
diff --git a/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_subject.txt b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_subject.txt
new file mode 100644
index 0000000..b980ba1
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/password_reset_subject.txt
@@ -0,0 +1 @@
+97随访(97suifang.com)密码重设
diff --git a/97suifangqa/templates/registration/signup.html b/97suifangqa/apps/sfaccount/templates/sfaccount/signup.html
index 935dde2..bf6c193 100644
--- a/97suifangqa/templates/registration/signup.html
+++ b/97suifangqa/apps/sfaccount/templates/sfaccount/signup.html
@@ -1,24 +1,38 @@
{% extends "picture-base.html" %}
{% load staticfiles %}
+
+{% block title %}
+注册账户 | 97随访
+{% endblock %}
+
{% block bodyclasses %}{{ block.super }} registration signup{% endblock %}
{% block othercss %}
<link rel="stylesheet" href="{% static "stylesheets/sass/registration.css" %}">
{% endblock %}
{% block body %}
-<h2>注册97随访 科学了解乙肝治疗</h2>
-<form method="post">{% csrf_token %}
+<h2>加入97随访 &emsp; 科学了解乙肝治疗</h2>
+<form action="" method="post">{% csrf_token %}
<table class="reg-form register-form">
{% for item in form %}
<tr>
<td>
<input type="{{ item.field.widget.input_type }}" name="{{ item.name }}" {% if item.field.widget.input_type == "text" %}value="{{ item.value|default_if_none:"" }}"{% endif %} placeholder="{{ item.label }}" class="{{ item.name }}">
</td>
+ <td class="help">{{ item.help_text }}</td>
<td class="error">{{ item.errors|join:"" }}</td>
</tr>
{% endfor %}
</table>
+ <table class="form-errors">
+ {% for error in form.non_field_errors %}
+ <tr>
+ <td>{{ error }}</td>
+ </tr>
+ {% endfor %}
+ </table>
- <input type="submit" value="注册完毕" class="submit register"/> &emsp; |
- &emsp; <a href="{% url apps.profile.views.login %}">已有账号</a>
+ <input type="submit" value="提交注册" class="submit register"/>
+ &emsp; | &emsp;
+ <a href="{% url login %}">已有账号</a>
</form>
{% endblock body %}
diff --git a/97suifangqa/apps/sfaccount/tests.py b/97suifangqa/apps/sfaccount/tests.py
new file mode 100644
index 0000000..501deb7
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/tests.py
@@ -0,0 +1,16 @@
+"""
+This file demonstrates writing tests using the unittest module. These will pass
+when you run "manage.py test".
+
+Replace this with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+
+class SimpleTest(TestCase):
+ def test_basic_addition(self):
+ """
+ Tests that 1 + 1 always equals 2.
+ """
+ self.assertEqual(1 + 1, 2)
diff --git a/97suifangqa/apps/sfaccount/urls.py b/97suifangqa/apps/sfaccount/urls.py
new file mode 100644
index 0000000..f2a930b
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/urls.py
@@ -0,0 +1,77 @@
+# -*- coding: utf-8 -*-
+
+from django.core.urlresolvers import reverse
+from django.conf import settings
+from django.conf.urls import patterns, url
+from django.views.generic.simple import direct_to_template
+
+from django.contrib.auth import views as auth_views
+
+
+urlpatterns = patterns('sfaccount.views',
+ url(r'^signup/$', 'signup_view', name='signup'),
+ # activate account
+ url(r'^activate/$', 'activate_view', name='activate'),
+ url(r'^activate/(?P<activation_key>.+)/$',
+ 'activate_view'),
+ # go home
+ url(r'^home/$', 'go_home_view', name='go_home'),
+)
+
+urlpatterns += patterns('',
+ # login & logout
+ url(r'^login/$',
+ auth_views.login,
+ {'template_name': 'sfaccount/login.html'},
+ name='login'),
+ url(r'^logout/$',
+ auth_views.logout,
+ {'template_name': 'sfaccount/logout.html'},
+ name='logout'),
+ # change password
+ url(r'^password/change/$',
+ auth_views.password_change,
+ {'template_name': 'sfaccount/password_change.html'},
+ name='password_change'),
+ url(r'^password/change/done/$',
+ auth_views.password_change_done,
+ {'template_name': 'sfaccount/password_change_done.html'},
+ name='password_change_done'),
+ # reset password
+ # use own 'password_reset_view' to able to send multipart mail
+ # use own 'SFPasswordResetForm' to use 'djcelery' to send email
+ url(r'^password/reset/$',
+ 'sfaccount.views.password_reset_view',
+ name='password_reset'),
+ url(r'^password/reset/done/$',
+ auth_views.password_reset_done,
+ {'template_name': 'sfaccount/password_reset_done.html'},
+ name='password_reset_done'),
+ url(r'^password/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
+ auth_views.password_reset_confirm,
+ {'template_name': 'sfaccount/password_reset_confirm.html'},
+ name='password_reset_confirm'),
+ url(r'^password/reset/complete/$',
+ auth_views.password_reset_complete,
+ {'template_name': 'sfaccount/password_reset_complete.html'},
+ name='password_reset_complete'),
+)
+
+
+USING_SOCIAL_LOGIN = getattr(settings, 'USING_SOCIAL_LOGIN', False)
+if USING_SOCIAL_LOGIN:
+ urlpatterns += patterns('sfaccount.views',
+ url(r'^oauth/(?P<sitename>\w+)/$',
+ 'social_login_callback', name='social_login_callback'),
+ )
+
+
+# test view
+urlpatterns += patterns('',
+ ## test
+ url(r'^test/$',
+ direct_to_template,
+ { 'template': 'sfaccount/logout.html' },
+ name='sfaccount_test'),
+)
+
diff --git a/97suifangqa/apps/sfaccount/views.py b/97suifangqa/apps/sfaccount/views.py
new file mode 100644
index 0000000..94670a6
--- /dev/null
+++ b/97suifangqa/apps/sfaccount/views.py
@@ -0,0 +1,143 @@
+# -*- coding: utf-8 -*-
+
+from django.conf import settings
+from django.http import HttpResponse, HttpResponseRedirect
+from django.template.response import TemplateResponse
+from django.core.urlresolvers import reverse
+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.tokens import default_token_generator
+
+from sfaccount.models import Account
+from sfaccount.forms import AccountForm, SFPasswordResetForm
+
+# email address shown in the sent mail
+FROM_EMAIL = getattr(settings, 'SF_EMAIL').get('display_from')
+
+
+# go_home {{{
+def go_home_view(request):
+ """
+ go to home page (profile)
+ """
+ if request.user.is_authenticated():
+ username = request.user.username
+ return redirect(reverse('profile_home',
+ kwargs={'username': username}))
+ else:
+ # not logged in
+ return redirect(reverse('login'))
+# }}}
+
+
+# signup {{{
+def signup_view(request):
+ """
+ 用户注册
+ """
+ if request.user.is_authenticated():
+ return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
+
+ if request.method == 'POST':
+ form = AccountForm(data=request.POST)
+ if form.is_valid():
+ cd = form.cleaned_data
+ new_account = Account.objects.create_inactive_account(
+ username=cd['username'],
+ email=cd['email'],
+ password=cd['password1'],
+ send_email=True
+ )
+ return HttpResponseRedirect(request.REQUEST.get('next'))
+ else:
+ form = AccountForm()
+
+ data = {
+ 'form': form,
+ }
+ return render(request, 'sfaccount/signup.html', data)
+# }}}
+
+
+# activate {{{
+def activate_view(request, activation_key=None):
+ """
+ activate account
+
+ if activation_key=None, then render a page ask user
+ to provide the activation key;
+ otherwise, directly activate the account and redirect
+ """
+ if activation_key:
+ account = Account.objects.activate(activation_key)
+ if account:
+ # activated
+ home_url = '/profile/%s/' % account.user.username
+ return HttpResponseRedirect(home_url)
+ 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')
+# }}}
+
+
+# password_reset_view {{{
+# own password_reset_view: enable to send multipart email
+@csrf_protect
+def password_reset_view(request, is_admin_site=False,
+ template_name='sfaccount/password_reset.html',
+ email_template_name='sfaccount/password_reset_email.txt',
+ subject_template_name='sfaccount/password_reset_subject.txt',
+ password_reset_form=SFPasswordResetForm,
+ token_generator=default_token_generator,
+ post_reset_redirect=None,
+ from_email=FROM_EMAIL,
+ current_app=None,
+ extra_context=None,
+ html_email_template_name='sfaccount/password_reset_email.html'):
+ """
+ re-write view to replace django's one
+ able to send multipart email by using
+ own 'SFPasswordResetForm' and 'send_mail'
+ """
+ if post_reset_redirect is None:
+ post_reset_redirect = reverse('password_reset_done')
+ if request.method == "POST":
+ form = password_reset_form(request.POST)
+ if form.is_valid():
+ opts = {
+ 'use_https': request.is_secure(),
+ 'token_generator': token_generator,
+ 'from_email': from_email,
+ 'email_template_name': email_template_name,
+ 'subject_template_name': subject_template_name,
+ 'request': request,
+ 'html_email_template_name': html_email_template_name,
+ }
+ if is_admin_site:
+ opts = dict(opts, domain_override=request.get_host())
+ form.save(**opts)
+ return HttpResponseRedirect(post_reset_redirect)
+ else:
+ form = password_reset_form()
+ context = {
+ 'form': form,
+ 'title': _('Password reset'),
+ }
+ if extra_context is not None:
+ context.update(extra_context)
+ return TemplateResponse(request, template_name, context,
+ current_app=current_app)
+# }}}
+
+
+# social_login_callback {{{
+def social_login_callback(request, sitename):
+ return HttpResponse('%s' % sitename)
+# }}}
+
diff --git a/97suifangqa/env/requirements.pip b/97suifangqa/env/requirements.pip
index 686397e..067fcfc 100644
--- a/97suifangqa/env/requirements.pip
+++ b/97suifangqa/env/requirements.pip
@@ -8,3 +8,6 @@ lxml
pysolr
uwsgi
git+https://github.com/toastdriven/django-haystack.git@master#egg=django-haystack
+django-celery
+redis
+socialoauth
diff --git a/97suifangqa/isuifangqa.db b/97suifangqa/isuifangqa.db
index 72b3b02..aa285d8 100644
--- a/97suifangqa/isuifangqa.db
+++ b/97suifangqa/isuifangqa.db
Binary files differ
diff --git a/97suifangqa/mail_settings.py.example b/97suifangqa/mail_settings.py.example
new file mode 100644
index 0000000..cb8a1e6
--- /dev/null
+++ b/97suifangqa/mail_settings.py.example
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+
+## smtp settings to send email
+SF_EMAIL = {
+ 'smtp_host': 'smtp.example.com',
+ 'smtp_port': 25,
+ 'username': 'username',
+ 'password': 'password',
+ 'from': 'username@example.com',
+ 'display_from': 'account@97suifang.com',
+}
+
+
diff --git a/97suifangqa/settings.py b/97suifangqa/settings.py
index 9dd3fc9..3245266 100644
--- a/97suifangqa/settings.py
+++ b/97suifangqa/settings.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-import os,sys
+import os, sys
DEBUG = True
@@ -144,6 +144,8 @@ INSTALLED_APPS = (
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'haystack',
+ 'djcelery',
+ 'sfaccount',
'profile',
'location',
'indicator',
@@ -152,15 +154,40 @@ INSTALLED_APPS = (
'subjects',
'sciblog',
'info',
+ 'recommend',
#'97suifangqa',
)
LOGIN_REDIRECT_URL = '/blog/index'
-# django-haystack settings
+##
+ACCOUNT_ACTIVATION_DAYS = 3
+
+## avatar
+AVATAR_DIR = os.path.join(PROJECT_ROOT, 'uploads/avatars')
+
+## socialoauth settings
+USING_SOCIAL_LOGIN = True
+try:
+ from socialoauth_settings import *
+except ImportError:
+ pass
+
+## email
+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 *
+
+
+## django-haystack settings
from haystack_settings import *
-# auto reload when deployed under uWSGI
+## auto reload when deployed under uWSGI
try:
import uwsgi
from uwsgidecorators import timer
@@ -172,3 +199,5 @@ try:
uwsgi.reload()
except:
pass
+
+
diff --git a/97suifangqa/socialoauth_settings.py b/97suifangqa/socialoauth_settings.py
new file mode 100644
index 0000000..f51d5ef
--- /dev/null
+++ b/97suifangqa/socialoauth_settings.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+
+"""
+97suifang local settings
+"""
+
+
+## social accounts settings
+SOCIALOAUTH_SITES = (
+ ('weibo', 'socialoauth.sites.weibo.Weibo', '新浪微博', {
+ 'redirect_uri': 'http://www.97suifang.com/account/oauth/weibo',
+ 'client_id': 'weibo_app_id',
+ 'client_secret': 'weibo_app_secret',
+ }
+ ),
+)
+
diff --git a/97suifangqa/templates/base.html b/97suifangqa/templates/base.html
index ae80e81..a93f207 100644
--- a/97suifangqa/templates/base.html
+++ b/97suifangqa/templates/base.html
@@ -80,7 +80,7 @@
{% block js %}
{% block jquery %}
- <script src="{% static "javascripts/jquery-1.9.1.min.js" %}"></script>
+ <script type="text/javascript" src="{% static "javascripts/jquery-1.9.1.min.js" %}"></script>
{% endblock %}
{% block scripts %}
diff --git a/97suifangqa/templates/registration/login.html b/97suifangqa/templates/registration/login.html
deleted file mode 100644
index d0e98fc..0000000
--- a/97suifangqa/templates/registration/login.html
+++ /dev/null
@@ -1,47 +0,0 @@
-{% extends "picture-base.html" %}
-{% load staticfiles %}
-{% block bodyclasses %}{{ block.super }} registration login{% endblock %}
-{% block othercss %}
-<link rel="stylesheet" href="{% static "stylesheets/sass/registration.css" %}">
-{% endblock %}
-{% block body %}
-<h2>登录97随访 科学了解乙肝治疗</h2>
-<p></p>
-<p>
- <img src="{% static "images/sinalogo.png" %}" alt="" style="width: 2.5em; vertical-align: middle;">
- 新浪微博账号登录
-</p>
-
-
-<p>
- <img src="{% static "images/qqlogo.png" %}" alt="" style="width: 2.5em; vertical-align: middle;">
- 腾讯QQ账号登录
-</p>
-
-<form method="post">{% csrf_token %}
-
- <table class="reg-form login-form">
- <tr>
- <td class="login-prompt">
- <span class="prompt">或者直接用邮箱登陆</span>
- </td>
- <td></td>
- </tr>
- <tr>
- <td>
- <input type="text" name="{{ form.username.name }}" value="{{ form.username.value|default_if_none:"" }}" maxlength="80" placeholder="{{ form.username.label }}" class="username ">
- </td>
- <td rowspan="2" class="error">
- {{form.non_field_errors|first}}
- </td>
- </tr>
- <tr>
- <td><input type="password" name="{{ form.password.name }}" placeholder="{{ form.password.label }}" class="password"></td>
- </tr>
- </table>
-
- <input type="hidden" name="next" value="{{ next }}" />
- <input type="submit" value="登 录" class="submit login"/> &emsp; | &emsp;
- <a href="{% url profile.views.signup %}">还没有帐号?</a>
-</form>
-{% endblock body%}
diff --git a/97suifangqa/templates/registration/password_reset_confirm.html b/97suifangqa/templates/registration/password_reset_confirm.html
deleted file mode 100644
index e69de29..0000000
--- a/97suifangqa/templates/registration/password_reset_confirm.html
+++ /dev/null
diff --git a/97suifangqa/templates/registration/password_reset_done.html b/97suifangqa/templates/registration/password_reset_done.html
deleted file mode 100644
index e69de29..0000000
--- a/97suifangqa/templates/registration/password_reset_done.html
+++ /dev/null
diff --git a/97suifangqa/templates/registration/password_reset_email.html b/97suifangqa/templates/registration/password_reset_email.html
deleted file mode 100644
index e69de29..0000000
--- a/97suifangqa/templates/registration/password_reset_email.html
+++ /dev/null
diff --git a/97suifangqa/templates/registration/password_reset_form.html b/97suifangqa/templates/registration/password_reset_form.html
deleted file mode 100644
index e69de29..0000000
--- a/97suifangqa/templates/registration/password_reset_form.html
+++ /dev/null
diff --git a/97suifangqa/templates/registration/password_reset_subject.txt b/97suifangqa/templates/registration/password_reset_subject.txt
deleted file mode 100644
index e69de29..0000000
--- a/97suifangqa/templates/registration/password_reset_subject.txt
+++ /dev/null
diff --git a/97suifangqa/urls.py b/97suifangqa/urls.py
index fd7d7a9..12b62da 100644
--- a/97suifangqa/urls.py
+++ b/97suifangqa/urls.py
@@ -4,7 +4,7 @@ from django.contrib import admin
from django.conf.urls.defaults import patterns, include, url
from django.views.generic.simple import direct_to_template
from django.contrib.auth import logout, views as auth_views
-from django.shortcuts import redirect, render_to_response
+from django.shortcuts import redirect, render
from django.conf import settings
@@ -24,26 +24,25 @@ def _logout(request, **kwargs):
return redirect('/')
urlpatterns += patterns("",
- url(r"^$", direct_to_template, {"template": "index.html"}, name="index"),
+ url(r"^$", direct_to_template,
+ {"template": "index.html"}, name="index"),
)
urlpatterns += patterns("info.views",
- url(r"^query\/?$", "query"),)
-
-urlpatterns += patterns("",
- url(r"^blog/", include('sciblog.urls')),
- url(r"^accounts/", include('profile.urls')),
- )
-def page_not_found(request):
- return render_to_response('./templates/404.html')
-
-
+ url(r"^query\/?$", "query"),
+)
-## apps/indicator
urlpatterns += patterns('',
+ url(r'^blog/', include('sciblog.urls')),
+ url(r'^accounts/', include('sfaccount.urls')),
+ url(r'^profile/', include('profile.urls')),
url(r'^indicator/', include('indicator.urls')),
+ url(r'^recommend/', include('recommend.urls')),
)
+def page_not_found(request):
+ return render(request, './templates/404.html')
+
## search (haystack)
urlpatterns += patterns('',