Commit c323519dd4538463109e4b588e0f727fb269575a

Authored by zhenchaozhu
1 parent b6c4f3cc38
Exists in de

m

File was created 1 # coding: utf-8
2
3 import django.http
4 from functools import wraps
5 from django.conf import settings
6 from django.utils.decorators import available_attrs
7 from django.shortcuts import resolve_url
8 from django.utils.six.moves.urllib.parse import urlparse
9
10 def weapp_django_logout(request, response):
11 assert isinstance(request, django.http.HttpRequest)
12 assert isinstance(response, django.http.HttpResponse)
13 # 请求统一认证登出
14 response.delete_cookie('pt')
15 response.delete_cookie('pu')
16 response.delete_cookie('username')
17 return response
18
19 def weapp_logout(func=weapp_django_logout):
20 """
21 Django登出视图函数装饰器
22 :param func: 处理登出逻辑的函数,接受request和response两个参数
23 :return:
24 """
25 return auth_decorator_factory(func)
26
27
28 def auth_decorator_factory(func=None):
29 """
30 登录登出装饰器工厂函数,允许用户自定义外部登录登出函数
31 :param func:
32 :return:
33 """
34
35 def decorator(view_func):
36 @wraps(view_func)
37 def _wrapped_view(request, *args, **kwargs):
38 response = view_func(request, *args, **kwargs)
39 if func:
40 func(request, response)
41 return response
42
43 return _wrapped_view
44
45 return decorator
46
47 import json
48
49 from django.http import JsonResponse
50
51
52 class QCCRJsonResponse(JsonResponse):
53 """
54 封装了返回码和信息的JsonResponse类
55 """
56 def __init__(self, obj=None, code=200, msg="success", status=200, **kwargs):
57 data = {"code": code, "msg": msg, "result": json.loads(obj) if isinstance(obj, (str, unicode)) else obj}
58 super(QCCRJsonResponse, self).__init__(data=data, status=status, **kwargs)
59
60
61 class QCCRErrorResponse(QCCRJsonResponse):
62 """
63 请求错误
64 """
65 def __init__(self, obj=None, code=400, msg="failure", status=400, **kwargs):
66 super(QCCRErrorResponse, self).__init__(obj=obj, code=code, msg=msg, status=status, **kwargs)
67
68 def user_passes_test(test_func, login_url=None,
69 redirect_field_name=getattr(settings, "QCCR_REDIRECT_FIELD_NAME", 'redirect')):
70 """
71 本装饰器通过test_func函数,检查views是否通过相应的检测,未通过则跳转到登录页面;test_func函数接受user对象作为参数,通过则返回True
72 """
73
74 def decorator(view_func):
75 @wraps(view_func, assigned=available_attrs(view_func))
76 def _wrapped_view(request, *args, **kwargs):
77 if test_func(request.user):
78 return view_func(request, *args, **kwargs)
79 # 如果未通过检查,且为ajax请求,返回403
80 if request.is_ajax():
81 return QCCRErrorResponse(code=403, msg="用户身份检查失败", status=403)
82 # 非ajax请求,跳转到登录页面
83 path = request.build_absolute_uri()
84 resolved_login_url = resolve_url(login_url or getattr(settings, "QCCR_LOGIN_URL", '/login/'))
85 login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
86 current_scheme, current_netloc = urlparse(path)[:2]
87 if ((not login_scheme or login_scheme == current_scheme) and
88 (not login_netloc or login_netloc == current_netloc)):
89 path = request.get_full_path()
90 from django.contrib.auth.views import redirect_to_login
91 return redirect_to_login(path, resolved_login_url, redirect_field_name)
92
93 return _wrapped_view
94
95 return decorator
96
97
98 def weapp_login_required(function=None,
99 redirect_field_name=getattr(settings, "QCCR_REDIRECT_FIELD_NAME", 'redirect'),
100 login_url=None):
101 """
102 登录状态检查装饰器,如果未登录,则直接跳转到登录页面
103 """
104 actual_decorator = user_passes_test(
105 lambda u: u.is_authenticated(),
106 login_url=login_url,
107 redirect_field_name=redirect_field_name
108 )
109 if function:
110 return actual_decorator(function)
111 return actual_decorator
forum/forms/user.py
1 # coding: utf-8 1 # coding: utf-8
2 2
3 import requests
3 from django import forms 4 from django import forms
4 from django.contrib.auth import authenticate 5 from django.contrib.auth import authenticate
5 from django.conf import settings 6 from django.conf import settings
6 from forum.models import ForumUser 7 from forum.models import ForumUser
7 8
8 9
9 error_messages = { 10 error_messages = {
10 'username': { 11 'username': {
11 'required': u'必须填写用户名', 12 'required': u'必须填写用户名',
12 'min_length': u'用户名长度过短(3-12个字符)', 13 'min_length': u'用户名长度过短(3-12个字符)',
13 'max_length': u'用户名长度过长(3-12个字符)', 14 'max_length': u'用户名长度过长(3-12个字符)',
14 'invalid': u'用户名格式错误(英文字母开头,数字,下划线构成)' 15 'invalid': u'用户名格式错误(英文字母开头,数字,下划线构成)'
15 }, 16 },
16 'email': { 17 'email': {
17 'required': u'必须填写E-mail', 18 'required': u'必须填写E-mail',
18 'min_length': u'Email长度有误', 19 'min_length': u'Email长度有误',
19 'max_length': u'Email长度有误', 20 'max_length': u'Email长度有误',
20 'invalid': u'Email地址无效' 21 'invalid': u'Email地址无效'
21 }, 22 },
22 'password': { 23 'password': {
23 'required': u'必须填写密码', 24 'required': u'必须填写密码',
24 'min_length': u'密码长度过短(6-64个字符)', 25 'min_length': u'密码长度过短(6-64个字符)',
25 'max_length': u'密码长度过长(6-64个字符)' 26 'max_length': u'密码长度过长(6-64个字符)'
26 }, 27 },
27 } 28 }
28 29
29 30
30 class SettingPasswordForm(forms.Form): 31 class SettingPasswordForm(forms.Form):
31 password_old = forms.CharField(min_length=6, max_length=64, 32 password_old = forms.CharField(min_length=6, max_length=64,
32 error_messages=error_messages.get('password')) 33 error_messages=error_messages.get('password'))
33 password = forms.CharField(min_length=6, max_length=64, 34 password = forms.CharField(min_length=6, max_length=64,
34 error_messages=error_messages.get('password')) 35 error_messages=error_messages.get('password'))
35 password_confirm = forms.CharField(required=False) 36 password_confirm = forms.CharField(required=False)
36 37
37 def __init__(self, request): 38 def __init__(self, request):
38 self.user = request.user 39 self.user = request.user
39 super(SettingPasswordForm, self).__init__(request.POST) 40 super(SettingPasswordForm, self).__init__(request.POST)
40 41
41 def clean(self): 42 def clean(self):
42 password_old = self.cleaned_data.get('password_old') 43 password_old = self.cleaned_data.get('password_old')
43 password = self.cleaned_data.get('password') 44 password = self.cleaned_data.get('password')
44 password_confirm = self.cleaned_data.get('password_confirm') 45 password_confirm = self.cleaned_data.get('password_confirm')
45 46
46 if not (password_old and self.user.check_password(password_old)): 47 if not (password_old and self.user.check_password(password_old)):
47 raise forms.ValidationError(u'当前输入旧密码有误') 48 raise forms.ValidationError(u'当前输入旧密码有误')
48 49
49 if password and password_confirm and password != password_confirm: 50 if password and password_confirm and password != password_confirm:
50 raise forms.ValidationError(u'两次输入新密码不一致') 51 raise forms.ValidationError(u'两次输入新密码不一致')
51 return self.cleaned_data 52 return self.cleaned_data
52 53
53 54
54 class ForgotPasswordForm(forms.Form): 55 class ForgotPasswordForm(forms.Form):
55 username = forms.RegexField(min_length=3, max_length=12, 56 username = forms.RegexField(min_length=3, max_length=12,
56 regex=r'^[a-zA-Z][a-zA-Z0-9_]*$', 57 regex=r'^[a-zA-Z][a-zA-Z0-9_]*$',
57 error_messages=error_messages.get('username')) 58 error_messages=error_messages.get('username'))
58 email = forms.EmailField(min_length=4, max_length=64, 59 email = forms.EmailField(min_length=4, max_length=64,
59 error_messages=error_messages.get('email')) 60 error_messages=error_messages.get('email'))
60 61
61 def __init__(self, *args, **kwargs): 62 def __init__(self, *args, **kwargs):
62 self.user_cache = None 63 self.user_cache = None
63 super(ForgotPasswordForm, self).__init__(*args, **kwargs) 64 super(ForgotPasswordForm, self).__init__(*args, **kwargs)
64 65
65 def clean(self): 66 def clean(self):
66 username = self.cleaned_data.get('username') 67 username = self.cleaned_data.get('username')
67 email = self.cleaned_data.get('email') 68 email = self.cleaned_data.get('email')
68 69
69 if username and email: 70 if username and email:
70 try: 71 try:
71 self.user_cache = ForumUser.objects.get(username=username, email=email) 72 self.user_cache = ForumUser.objects.get(username=username, email=email)
72 except ForumUser.DoesNotExist: 73 except ForumUser.DoesNotExist:
73 raise forms.ValidationError(u'所填用户名和邮箱有误') 74 raise forms.ValidationError(u'所填用户名和邮箱有误')
74 return self.cleaned_data 75 return self.cleaned_data
75 76
76 def get_user(self): 77 def get_user(self):
77 return self.user_cache 78 return self.user_cache
78 79
79 80
80 class LoginForm(forms.Form): 81 class LoginForm(forms.Form):
81 username = forms.CharField(min_length=3, max_length=12, 82 username = forms.CharField(min_length=3, max_length=12,
82 error_messages=error_messages.get('username')) 83 error_messages=error_messages.get('username'))
83 password = forms.CharField(min_length=6, max_length=64, 84 password = forms.CharField(min_length=6, max_length=64,
84 error_messages=error_messages.get('password')) 85 error_messages=error_messages.get('password'))
85 86
86 def __init__(self, *args, **kwargs): 87 def __init__(self, *args, **kwargs):
87 self.user_cache = None 88 self.user_cache = None
89 self.pu = ''
90 self.pt = ''
91 self.username = ''
88 super(LoginForm, self).__init__(*args, **kwargs) 92 super(LoginForm, self).__init__(*args, **kwargs)
89 93
90 def clean(self): 94 def clean(self):
91 username = self.cleaned_data.get('username') 95 username = self.cleaned_data.get('username')
92 password = self.cleaned_data.get('password') 96 password = self.cleaned_data.get('password')
93 97
94 if username and password: 98 if username and password:
95 self.user_cache = authenticate(username=username, password=password) 99 post_params = {
96 if self.user_cache is None: 100 'comefrom': 2,
97 raise forms.ValidationError(u'用户名或者密码不正确') 101 'user_name': username,
98 elif not self.user_cache.is_active: 102 'password': password,
99 raise forms.ValidationError(u'用户已被锁定,请联系管理员解锁') 103 }
104 resp = requests.post(settings.AUTH_DOMAIN, data=post_params, verify=False)
105 if resp.status_code == 200:
106 rst = resp.json()
107 if rst.get('status') == 1:
108 data = rst.get('data')
109 self.pt = data.get('token')
110 self.pu = data.get('suid')
111 self.username = username
112 else:
113 raise forms.ValidationError(u'用户名或者密码不正确')
114 else:
115 raise forms.ValidationError(u'连接登录中心失败')
116
100 return self.cleaned_data 117 return self.cleaned_data
101 118
102 def get_user(self): 119 def get_user(self):
103 return self.user_cache 120 return {
121 'pt': self.pt,
122 'pu': self.pu,
123 'username': self.username,
124 }
104 125
105 126
106 class RegisterForm(forms.ModelForm): 127 class RegisterForm(forms.ModelForm):
107 username = forms.RegexField(min_length=3, max_length=12, 128 username = forms.RegexField(min_length=3, max_length=12,
108 regex=r'^[a-zA-Z][a-zA-Z0-9_]*$', 129 regex=r'^[a-zA-Z][a-zA-Z0-9_]*$',
109 error_messages=error_messages.get('username')) 130 error_messages=error_messages.get('username'))
110 email = forms.EmailField(min_length=4, max_length=64, 131 email = forms.EmailField(min_length=4, max_length=64,
111 error_messages=error_messages.get('email')) 132 error_messages=error_messages.get('email'))
112 password = forms.CharField(min_length=6, max_length=64, 133 password = forms.CharField(min_length=6, max_length=64,
113 error_messages=error_messages.get('password')) 134 error_messages=error_messages.get('password'))
114 password_confirm = forms.CharField(required=False) 135 password_confirm = forms.CharField(required=False)
115 136
116 class Meta: 137 class Meta:
117 model = ForumUser 138 model = ForumUser
118 fields = ('username', 'email') 139 fields = ('username', 'email')
119 140
120 def clean_username(self): 141 def clean_username(self):
121 username = self.cleaned_data['username'] 142 username = self.cleaned_data['username']
122 try: 143 try:
123 ForumUser.objects.get(username=username) 144 ForumUser.objects.get(username=username)
124 raise forms.ValidationError(u'所填用户名已经被注册过') 145 raise forms.ValidationError(u'所填用户名已经被注册过')
125 except ForumUser.DoesNotExist: 146 except ForumUser.DoesNotExist:
126 if username in settings.RESERVED: 147 if username in settings.RESERVED:
127 raise forms.ValidationError(u'用户名被保留不可用') 148 raise forms.ValidationError(u'用户名被保留不可用')
128 return username 149 return username
129 150
130 def clean_email(self): 151 def clean_email(self):
131 email = self.cleaned_data['email'] 152 email = self.cleaned_data['email']
132 try: 153 try:
133 ForumUser.objects.get(email=email) 154 ForumUser.objects.get(email=email)
134 raise forms.ValidationError(u'所填邮箱已经被注册过') 155 raise forms.ValidationError(u'所填邮箱已经被注册过')
135 except ForumUser.DoesNotExist: 156 except ForumUser.DoesNotExist:
136 return email 157 return email
137 158
138 def clean_password_confirm(self): 159 def clean_password_confirm(self):
139 password1 = self.cleaned_data.get('password') 160 password1 = self.cleaned_data.get('password')
140 password2 = self.cleaned_data.get('password_confirm') 161 password2 = self.cleaned_data.get('password_confirm')
141 if password1 and password2 and password1 != password2: 162 if password1 and password2 and password1 != password2:
142 raise forms.ValidationError(u'两次输入密码不一致') 163 raise forms.ValidationError(u'两次输入密码不一致')
143 return password2 164 return password2
144 165
145 def save(self, commit=True): 166 def save(self, commit=True):
146 user = super(RegisterForm, self).save(commit=False) 167 user = super(RegisterForm, self).save(commit=False)
147 user.set_password(self.cleaned_data['password']) 168 user.set_password(self.cleaned_data['password'])
148 if commit: 169 if commit:
149 user.save() 170 user.save()
150 return user 171 return user
151 172
152 173
153 class SettingForm(forms.Form): 174 class SettingForm(forms.Form):
154 username = forms.CharField() # readonly 175 username = forms.CharField() # readonly
155 email = forms.EmailField() # readonly 176 email = forms.EmailField() # readonly
156 nickname = forms.CharField(min_length=3, max_length=12, required=False, 177 nickname = forms.CharField(min_length=3, max_length=12, required=False,
157 error_messages={ 178 error_messages={
158 'min_length': u'昵称长度过短(3-12个字符)', 179 'min_length': u'昵称长度过短(3-12个字符)',
159 'max_length': u'昵称长度过长(3-12个字符)', 180 'max_length': u'昵称长度过长(3-12个字符)',
160 }) 181 })
161 signature = forms.CharField(required=False) 182 signature = forms.CharField(required=False)
162 location = forms.CharField(required=False) 183 location = forms.CharField(required=False)
163 website = forms.URLField(required=False, 184 website = forms.URLField(required=False,
164 error_messages={ 185 error_messages={
165 'invalid': u'请填写合法的URL地址(如:http://f2e.im)', 186 'invalid': u'请填写合法的URL地址(如:http://f2e.im)',
166 }) 187 })
167 company = forms.CharField(required=False) 188 company = forms.CharField(required=False)
168 github = forms.CharField(required=False) 189 github = forms.CharField(required=False)
169 twitter = forms.CharField(required=False) 190 twitter = forms.CharField(required=False)
170 douban = forms.CharField(required=False) 191 douban = forms.CharField(required=False)
171 self_intro = forms.CharField(required=False) 192 self_intro = forms.CharField(required=False)
172 193
forum/views/user.py
1 # coding: utf-8 1 # coding: utf-8
2 2
3 import requests
3 import os, uuid, copy, urllib 4 import os, uuid, copy, urllib
4 from PIL import Image 5 from PIL import Image
5 from django.shortcuts import render_to_response, redirect 6 from django.shortcuts import render_to_response, redirect
6 from django.contrib import auth 7 from django.contrib import auth
7 from django.contrib.auth.decorators import login_required 8 from django.contrib.auth.decorators import login_required
8 from django.template import RequestContext, Context, loader 9 from django.template import RequestContext, Context, loader
9 from django.utils import timezone 10 from django.utils import timezone
10 from django.conf import settings 11 from django.conf import settings
11 from forum.models import ForumUser 12 from forum.models import ForumUser
12 from forum.forms.user import RegisterForm, LoginForm, ForgotPasswordForm, SettingPasswordForm, SettingForm 13 from forum.forms.user import RegisterForm, LoginForm, ForgotPasswordForm, SettingPasswordForm, SettingForm
13 from common import sendmail 14 from common import sendmail
14 15
15 16
16 @login_required 17 @login_required
17 def get_setting(request, **kwargs): 18 def get_setting(request, **kwargs):
18 return render_to_response('user/setting.html', kwargs, 19 return render_to_response('user/setting.html', kwargs,
19 context_instance=RequestContext(request)) 20 context_instance=RequestContext(request))
20 21
21 22
22 @login_required 23 @login_required
23 def post_setting(request): 24 def post_setting(request):
24 form = SettingForm(request.POST) 25 form = SettingForm(request.POST)
25 if not form.is_valid(): 26 if not form.is_valid():
26 return get_setting(request, errors=form.errors) 27 return get_setting(request, errors=form.errors)
27 28
28 user = request.user 29 user = request.user
29 cd = copy.copy(form.cleaned_data) 30 cd = copy.copy(form.cleaned_data)
30 cd.pop('username') 31 cd.pop('username')
31 cd.pop('email') 32 cd.pop('email')
32 for k, v in cd.iteritems(): 33 for k, v in cd.iteritems():
33 setattr(user, k, v) 34 setattr(user, k, v)
34 user.updated = timezone.now() 35 user.updated = timezone.now()
35 user.save() 36 user.save()
36 return get_setting(request, success_message=u'用户基本资料更新成功') 37 return get_setting(request, success_message=u'用户基本资料更新成功')
37 38
38 39
39 @login_required 40 @login_required
40 def get_setting_avatar(request, **kwargs): 41 def get_setting_avatar(request, **kwargs):
41 return render_to_response('user/setting_avatar.html', kwargs, 42 return render_to_response('user/setting_avatar.html', kwargs,
42 context_instance=RequestContext(request)) 43 context_instance=RequestContext(request))
43 44
44 45
45 @login_required 46 @login_required
46 def post_setting_avatar(request): 47 def post_setting_avatar(request):
47 if not 'avatar' in request.FILES: 48 if not 'avatar' in request.FILES:
48 errors = {'invalid_avatar': [u'请先选择要上传的头像'],} 49 errors = {'invalid_avatar': [u'请先选择要上传的头像'],}
49 return get_setting_avatar(request, errors=errors) 50 return get_setting_avatar(request, errors=errors)
50 51
51 user = request.user 52 user = request.user
52 avatar_name = '%s' % uuid.uuid5(uuid.NAMESPACE_DNS, str(user.id)) 53 avatar_name = '%s' % uuid.uuid5(uuid.NAMESPACE_DNS, str(user.id))
53 avatar = Image.open(request.FILES['avatar']) 54 avatar = Image.open(request.FILES['avatar'])
54 55
55 # crop avatar if it's not square 56 # crop avatar if it's not square
56 avatar_w, avatar_h = avatar.size 57 avatar_w, avatar_h = avatar.size
57 avatar_border = avatar_w if avatar_w < avatar_h else avatar_h 58 avatar_border = avatar_w if avatar_w < avatar_h else avatar_h
58 avatar_crop_region = (0, 0, avatar_border, avatar_border) 59 avatar_crop_region = (0, 0, avatar_border, avatar_border)
59 avatar = avatar.crop(avatar_crop_region) 60 avatar = avatar.crop(avatar_crop_region)
60 61
61 avatar_96x96 = avatar.resize((96, 96), Image.ANTIALIAS) 62 avatar_96x96 = avatar.resize((96, 96), Image.ANTIALIAS)
62 avatar_48x48 = avatar.resize((48, 48), Image.ANTIALIAS) 63 avatar_48x48 = avatar.resize((48, 48), Image.ANTIALIAS)
63 avatar_32x32 = avatar.resize((32, 32), Image.ANTIALIAS) 64 avatar_32x32 = avatar.resize((32, 32), Image.ANTIALIAS)
64 path = os.path.dirname(__file__) 65 path = os.path.dirname(__file__)
65 avatar_96x96.save(os.path.join(path, '../static/avatar/b_%s.png' % avatar_name), 'PNG') 66 avatar_96x96.save(os.path.join(path, '../static/avatar/b_%s.png' % avatar_name), 'PNG')
66 avatar_48x48.save(os.path.join(path, '../static/avatar/m_%s.png' % avatar_name), 'PNG') 67 avatar_48x48.save(os.path.join(path, '../static/avatar/m_%s.png' % avatar_name), 'PNG')
67 avatar_32x32.save(os.path.join(path, '../static/avatar/s_%s.png' % avatar_name), 'PNG') 68 avatar_32x32.save(os.path.join(path, '../static/avatar/s_%s.png' % avatar_name), 'PNG')
68 user.avatar = '%s.png' % avatar_name 69 user.avatar = '%s.png' % avatar_name
69 user.updated = timezone.now() 70 user.updated = timezone.now()
70 user.save() 71 user.save()
71 return get_setting_avatar(request) 72 return get_setting_avatar(request)
72 73
73 74
74 @login_required 75 @login_required
75 def get_settingpwd(request, **kwargs): 76 def get_settingpwd(request, **kwargs):
76 return render_to_response('user/setting_password.html', kwargs, 77 return render_to_response('user/setting_password.html', kwargs,
77 context_instance=RequestContext(request)) 78 context_instance=RequestContext(request))
78 79
79 80
80 @login_required 81 @login_required
81 def post_settingpwd(request): 82 def post_settingpwd(request):
82 form = SettingPasswordForm(request) 83 form = SettingPasswordForm(request)
83 if not form.is_valid(): 84 if not form.is_valid():
84 return get_settingpwd(request, errors=form.errors) 85 return get_settingpwd(request, errors=form.errors)
85 86
86 user = request.user 87 user = request.user
87 password = form.cleaned_data.get('password') 88 password = form.cleaned_data.get('password')
88 user.set_password(password) 89 user.set_password(password)
89 user.updated = timezone.now() 90 user.updated = timezone.now()
90 user.save() 91 user.save()
91 return get_settingpwd(request, success_message=u'您的用户密码已更新') 92 return get_settingpwd(request, success_message=u'您的用户密码已更新')
92 93
93 94
94 def get_forgotpwd(request, **kwargs): 95 def get_forgotpwd(request, **kwargs):
95 auth.logout(request) 96 auth.logout(request)
96 return render_to_response('user/forgot_password.html', kwargs, 97 return render_to_response('user/forgot_password.html', kwargs,
97 context_instance=RequestContext(request)) 98 context_instance=RequestContext(request))
98 99
99 100
100 def post_forgotpwd(request): 101 def post_forgotpwd(request):
101 form = ForgotPasswordForm(request.POST) 102 form = ForgotPasswordForm(request.POST)
102 if not form.is_valid(): 103 if not form.is_valid():
103 return get_login(request, errors=form.errors) 104 return get_login(request, errors=form.errors)
104 105
105 user = form.get_user() 106 user = form.get_user()
106 107
107 new_password = uuid.uuid1().hex 108 new_password = uuid.uuid1().hex
108 user.set_password(new_password) 109 user.set_password(new_password)
109 user.updated = timezone.now() 110 user.updated = timezone.now()
110 user.save() 111 user.save()
111 112
112 # 给用户发送新密码 113 # 给用户发送新密码
113 mail_title = u'前端社区(F2E.im)找回密码' 114 mail_title = u'前端社区(F2E.im)找回密码'
114 var = {'email': user.email, 'new_password': new_password} 115 var = {'email': user.email, 'new_password': new_password}
115 mail_content = loader.get_template('user/forgot_password_mail.html').render(Context(var)) 116 mail_content = loader.get_template('user/forgot_password_mail.html').render(Context(var))
116 sendmail(mail_title, mail_content, user.email) 117 sendmail(mail_title, mail_content, user.email)
117 118
118 return get_forgotpwd(request, success_message=u'新密码已发送至您的注册邮箱') 119 return get_forgotpwd(request, success_message=u'新密码已发送至您的注册邮箱')
119 120
120 121
121 def get_login(request, **kwargs): 122 def get_login(request, **kwargs):
122 auth.logout(request) 123 auth.logout(request)
123 return render_to_response('user/login.html', kwargs, 124 return render_to_response('user/login.html', kwargs,
124 context_instance=RequestContext(request)) 125 context_instance=RequestContext(request))
125 126
126 def post_login(request): 127 def post_login(request):
127 form = LoginForm(request.POST) 128 form = LoginForm(request.POST)
128 if not form.is_valid(): 129 if not form.is_valid():
129 return get_login(request, errors=form.errors) 130 return get_login(request, errors=form.errors)
130 131
131 user = form.get_user() 132 user_info = form.get_user()
132 auth.login(request, user) 133 pt = user_info.get('pt')
133 134 pu = user_info.get('pu')
134 if user.is_staff: 135 t = redirect(request.REQUEST.get('next', '/'))
135 return redirect(request.REQUEST.get('next', '/manage/admin/')) 136 t.set_cookie('pt', pt, 864000)
137 t.set_cookie('pu', pu, 864000)
136 138
137 return redirect(request.REQUEST.get('next', '/')) 139 return t
138 140
139 141
140 def get_logout(request): 142 def get_logout(request):
141 auth.logout(request) 143 auth.logout(request)
142 return redirect(request.REQUEST.get('next', '/')) 144 return redirect(request.REQUEST.get('next', '/'))
143 145
144 146
145 def get_register(request, **kwargs): 147 def get_register(request, **kwargs):
146 auth.logout(request) 148 auth.logout(request)
147 return render_to_response('user/register.html', kwargs, 149 return render_to_response('user/register.html', kwargs,
148 context_instance=RequestContext(request)) 150 context_instance=RequestContext(request))
149 151
150 152
151 def post_register(request): 153 def post_register(request):
152 form = RegisterForm(request.POST) 154 form = RegisterForm(request.POST)
153 155
154 if not form.is_valid(): 156 if not form.is_valid():
155 return get_register(request, errors=form.errors) 157 return get_register(request, errors=form.errors)
156 158
157 user = form.save() 159 user = form.save()
158 if user: 160 if user:
159 # 注册成功,发送邮件到用户邮箱 161 # 注册成功,发送邮件到用户邮箱
160 # mail_title = u'微信小程序开发社区注册成功通知' 162 # mail_title = u'微信小程序开发社区注册成功通知'
161 # mail_content = loader.get_template('user/register_mail.html').render(Context({})) 163 # mail_content = loader.get_template('user/register_mail.html').render(Context({}))
162 # sendmail(mail_title, mail_content, user.email) 164 # sendmail(mail_title, mail_content, user.email)
163 pass 165 pass
164 166
165 return redirect(settings.LOGIN_URL) 167 return redirect(settings.LOGIN_URL)
166 168
middlewares/__init__.py
middlewares/session_middleware.py
File was created 1 # coding: utf-8
2
3 import requests
4 from django.conf import settings
5 from django.core.cache import caches
6 from django.contrib.auth import get_user_model
7 from django.contrib.auth.models import AnonymousUser
8
9
10 class SessionWithoutLocalUserMiddleware(object):
11 """
12 统一权限(认证)中间件,Django系统本地不保存用户的情况使用
13 """
14
15 def __init__(self):
16 self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS
17 self.cache = caches[self.cache_alias]
18 self.UserModel = get_user_model()
19
20 def process_request(self, request):
21 if hasattr(request, "user") and getattr(request.user, "is_superuser", False):
22 # 对于Django系统的admin用户,这里不做任何处理
23 pass
24 else:
25 pt = request.COOKIES.get('pt')
26 pu = request.COOKIES.get('pu')
27 username = request.COOKIES.get('username')
28 if pt and pu:
29 # 查询session状态成功的情况,构造QCCRUser
30 user = XYTUser(username, pu, pt)
31 request.user = user
32 else:
33 # 拿不到统一认证的session,将当前用户设为匿名用户
34 request.user = AnonymousUser()
35
36
37 class Manager(object):
38
39 def __init__(self):
40 self.auth_domain = 'https://api.xiuyetang.com/sys/user/login'
41
42
43 class XYTUser(object):
44 id = None
45 pk = None
46 username = ''
47 sessionId = ''
48 accountNo = ''
49 employeeName = ''
50 employeeId = 0
51 employeeNo = ''
52 employeeTel = ''
53 deptIds = ''
54 email = ''
55 entryTime = ''
56 uid = ''
57 is_staff = False
58 is_active = False
59 is_superuser = False
60 _groups = ''
61 _user_permissions = ''
62
63 def __init__(self, username, pu, pt):
64 self.username = username
65 self.id = pu
66 self.pk = pu
67 self.sessionId = pt
68
69 def __str__(self):
70 return self.username
71
72 def __eq__(self, other):
73 return self.username == other.username
74
75 def __ne__(self, other):
76 return not self.__eq__(other)
77
78 def __hash__(self):
79 return hash(self.username)
80
81 def save(self):
82 raise NotImplementedError("Django doesn't provide a DB representation for QCCRUser. User info in LDAP.")
83
84 def delete(self):
85 raise NotImplementedError("Django doesn't provide a DB representation for QCCRUser. User info in LDAP.")
86
87 def set_password(self, raw_password):
88 raise NotImplementedError("Django doesn't provide a DB representation for QCCRUser. Password in LDAP.")
89
90 def check_password(self, raw_password):
91 raise NotImplementedError("Django doesn't provide a DB representation for QCCRUser. Password in LDAP.")
92
93 def _get_groups(self):
94 return self._groups
95
96 groups = property(_get_groups)
97
98 def _get_user_permissions(self):
99 return self._user_permissions
100
101 user_permissions = property(_get_user_permissions)
102
103 def get_group_permissions(self, obj=None):
104 return set()
105
106 @property
107 def is_anonymous(self):
108 return lambda: False
109
110 @property
111 def is_authenticated(self):
112 return lambda: True
113
114 def get_username(self):
115 return self.username
1 # coding: utf-8 1 # coding: utf-8
2 # Django settings for xp project. 2 # Django settings for xp project.
3 3
4 DEBUG = True 4 DEBUG = True
5 TEMPLATE_DEBUG = DEBUG 5 TEMPLATE_DEBUG = DEBUG
6 6
7 ADMINS = ( 7 ADMINS = (
8 # ('Your Name', 'your_email@example.com'), 8 # ('Your Name', 'your_email@example.com'),
9 ) 9 )
10 10
11 MANAGERS = ADMINS 11 MANAGERS = ADMINS
12 12
13 DATABASES = { 13 DATABASES = {
14 'default': { 14 'default': {
15 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 15 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
16 'NAME': 'forum', # Or path to database file if using sqlite3. 16 'NAME': 'forum', # Or path to database file if using sqlite3.
17 # The following settings are not used with sqlite3: 17 # The following settings are not used with sqlite3:
18 'USER': 'root', 18 'USER': 'root',
19 'PASSWORD': 'nineteen', 19 'PASSWORD': 'zzc',
20 'HOST': '127.0.0.1', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. 20 'HOST': '127.0.0.1', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
21 'PORT': '3306', # Set to empty string for default. 21 'PORT': '3306', # Set to empty string for default.
22 } 22 }
23 } 23 }
24 24
25 # Hosts/domain names that are valid for this site; required if DEBUG is False 25 # Hosts/domain names that are valid for this site; required if DEBUG is False
26 # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts 26 # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
27 ALLOWED_HOSTS = ['*'] 27 ALLOWED_HOSTS = ['*']
28 28
29 # Local time zone for this installation. Choices can be found here: 29 # Local time zone for this installation. Choices can be found here:
30 # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 30 # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
31 # although not all choices may be available on all operating systems. 31 # although not all choices may be available on all operating systems.
32 # In a Windows environment this must be set to your system time zone. 32 # In a Windows environment this must be set to your system time zone.
33 TIME_ZONE = 'Asia/Shanghai' 33 TIME_ZONE = 'Asia/Shanghai'
34 34
35 # Language code for this installation. All choices can be found here: 35 # Language code for this installation. All choices can be found here:
36 # http://www.i18nguy.com/unicode/language-identifiers.html 36 # http://www.i18nguy.com/unicode/language-identifiers.html
37 LANGUAGE_CODE = 'zh-CN' 37 LANGUAGE_CODE = 'zh-CN'
38 38
39 SITE_ID = 1 39 SITE_ID = 1
40 40
41 # If you set this to False, Django will make some optimizations so as not 41 # If you set this to False, Django will make some optimizations so as not
42 # to load the internationalization machinery. 42 # to load the internationalization machinery.
43 USE_I18N = True # 只有用admin的时候需要开启 43 USE_I18N = True # 只有用admin的时候需要开启
44 44
45 # If you set this to False, Django will not format dates, numbers and 45 # If you set this to False, Django will not format dates, numbers and
46 # calendars according to the current locale. 46 # calendars according to the current locale.
47 USE_L10N = False 47 USE_L10N = False
48 48
49 # If you set this to False, Django will not use timezone-aware datetimes. 49 # If you set this to False, Django will not use timezone-aware datetimes.
50 USE_TZ = False 50 USE_TZ = False
51 51
52 # Absolute filesystem path to the directory that will hold user-uploaded files. 52 # Absolute filesystem path to the directory that will hold user-uploaded files.
53 # Example: "/var/www/example.com/media/" 53 # Example: "/var/www/example.com/media/"
54 MEDIA_ROOT = '' 54 MEDIA_ROOT = ''
55 55
56 # URL that handles the media served from MEDIA_ROOT. Make sure to use a 56 # URL that handles the media served from MEDIA_ROOT. Make sure to use a
57 # trailing slash. 57 # trailing slash.
58 # Examples: "http://example.com/media/", "http://media.example.com/" 58 # Examples: "http://example.com/media/", "http://media.example.com/"
59 MEDIA_URL = '' 59 MEDIA_URL = ''
60 60
61 # Absolute path to the directory static files should be collected to. 61 # Absolute path to the directory static files should be collected to.
62 # Don't put anything in this directory yourself; store your static files 62 # Don't put anything in this directory yourself; store your static files
63 # in apps' "static/" subdirectories and in STATICFILES_DIRS. 63 # in apps' "static/" subdirectories and in STATICFILES_DIRS.
64 # Example: "/var/www/example.com/static/" 64 # Example: "/var/www/example.com/static/"
65 STATIC_ROOT = '' 65 STATIC_ROOT = ''
66 66
67 # URL prefix for static files. 67 # URL prefix for static files.
68 # Example: "http://example.com/static/", "http://static.example.com/" 68 # Example: "http://example.com/static/", "http://static.example.com/"
69 STATIC_URL = '/static/' 69 STATIC_URL = '/static/'
70 70
71 # Additional locations of static files 71 # Additional locations of static files
72 STATICFILES_DIRS = ( 72 STATICFILES_DIRS = (
73 # Put strings here, like "/home/html/static" or "C:/www/django/static". 73 # Put strings here, like "/home/html/static" or "C:/www/django/static".
74 # Always use forward slashes, even on Windows. 74 # Always use forward slashes, even on Windows.
75 # Don't forget to use absolute paths, not relative paths. 75 # Don't forget to use absolute paths, not relative paths.
76 ) 76 )
77 77
78 # List of finder classes that know how to find static files in 78 # List of finder classes that know how to find static files in
79 # various locations. 79 # various locations.
80 STATICFILES_FINDERS = ( 80 STATICFILES_FINDERS = (
81 'django.contrib.staticfiles.finders.FileSystemFinder', 81 'django.contrib.staticfiles.finders.FileSystemFinder',
82 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 82 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
83 # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 83 # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
84 ) 84 )
85 85
86 # Make this unique, and don't share it with anybody. 86 # Make this unique, and don't share it with anybody.
87 SECRET_KEY = 'h6=yzee&jze#4p1@twhksg1wg6hv%pzwomw(!o($qsly%lzlhe' 87 SECRET_KEY = 'h6=yzee&jze#4p1@twhksg1wg6hv%pzwomw(!o($qsly%lzlhe'
88 88
89 # List of callables that know how to import templates from various sources. 89 # List of callables that know how to import templates from various sources.
90 TEMPLATE_LOADERS = ( 90 TEMPLATE_LOADERS = (
91 'django.template.loaders.filesystem.Loader', 91 'django.template.loaders.filesystem.Loader',
92 'django.template.loaders.app_directories.Loader', 92 'django.template.loaders.app_directories.Loader',
93 # 'django.template.loaders.eggs.Loader', 93 # 'django.template.loaders.eggs.Loader',
94 ) 94 )
95 95
96 MIDDLEWARE_CLASSES = ( 96 MIDDLEWARE_CLASSES = (
97 'django.middleware.common.CommonMiddleware', 97 'django.middleware.common.CommonMiddleware',
98 'django.contrib.sessions.middleware.SessionMiddleware', 98 'django.contrib.sessions.middleware.SessionMiddleware',
99 'django.middleware.csrf.CsrfViewMiddleware', # 开启了CSRF,记得在POST表单中加{% csrf_token %},使用RequestContext 99 'django.middleware.csrf.CsrfViewMiddleware', # 开启了CSRF,记得在POST表单中加{% csrf_token %},使用RequestContext
100 'django.contrib.auth.middleware.AuthenticationMiddleware', 100 'django.contrib.auth.middleware.AuthenticationMiddleware',
101 'django.contrib.messages.middleware.MessageMiddleware', 101 'django.contrib.messages.middleware.MessageMiddleware',
102 # Uncomment the next line for simple clickjacking protection: 102 # Uncomment the next line for simple clickjacking protection:
103 # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 103 # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
104 'django.middleware.cache.FetchFromCacheMiddleware', # 缓存中间件,必须放在最后 104 'django.middleware.cache.FetchFromCacheMiddleware', # 缓存中间件,必须放在最后
105 ) 105 )
106 106
107 ROOT_URLCONF = 'xp.urls' 107 ROOT_URLCONF = 'xp.urls'
108 108
109 # Python dotted path to the WSGI application used by Django's runserver. 109 # Python dotted path to the WSGI application used by Django's runserver.
110 WSGI_APPLICATION = 'xp.wsgi.application' 110 WSGI_APPLICATION = 'xp.wsgi.application'
111 111
112 TEMPLATE_DIRS = ( 112 TEMPLATE_DIRS = (
113 # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 113 # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
114 # Always use forward slashes, even on Windows. 114 # Always use forward slashes, even on Windows.
115 # Don't forget to use absolute paths, not relative paths. 115 # Don't forget to use absolute paths, not relative paths.
116 ) 116 )
117 117
118 TEMPLATE_CONTEXT_PROCESSORS = ( # F2E中有current_user对象和request对象,这里设置可在模板中使用RquestContext 118 TEMPLATE_CONTEXT_PROCESSORS = ( # F2E中有current_user对象和request对象,这里设置可在模板中使用RquestContext
119 'django.contrib.auth.context_processors.auth', # user对象等等 119 'django.contrib.auth.context_processors.auth', # user对象等等
120 'django.core.context_processors.request', # request对象等等 120 'django.core.context_processors.request', # request对象等等
121 'django.core.context_processors.static', # 在模板中使用{{ STATIC_URL }}获取静态文件路径 121 'django.core.context_processors.static', # 在模板中使用{{ STATIC_URL }}获取静态文件路径
122 'forum.context_processors.custom_proc', # 自定义模板上下文处理器 122 'forum.context_processors.custom_proc', # 自定义模板上下文处理器
123 ) 123 )
124 124
125 INSTALLED_APPS = ( 125 INSTALLED_APPS = (
126 'django.contrib.auth', 126 'django.contrib.auth',
127 'django.contrib.contenttypes', 127 'django.contrib.contenttypes',
128 'django.contrib.sessions', 128 'django.contrib.sessions',
129 'django.contrib.sites', 129 'django.contrib.sites',
130 'django.contrib.messages', 130 'django.contrib.messages',
131 'django.contrib.staticfiles', 131 'django.contrib.staticfiles',
132 # Uncomment the next line to enable the admin: 132 # Uncomment the next line to enable the admin:
133 'django.contrib.admin', 133 'django.contrib.admin',
134 # Uncomment the next line to enable admin documentation: 134 # Uncomment the next line to enable admin documentation:
135 # 'django.contrib.admindocs', 135 # 'django.contrib.admindocs',
136 'django.contrib.sitemaps', # Django sitemap framework 136 'django.contrib.sitemaps', # Django sitemap framework
137 'gunicorn', 137 'gunicorn',
138 'forum', 138 'forum',
139 ) 139 )
140 140
141 # A sample logging configuration. The only tangible logging 141 # A sample logging configuration. The only tangible logging
142 # performed by this configuration is to send an email to 142 # performed by this configuration is to send an email to
143 # the site admins on every HTTP 500 error when DEBUG=False. 143 # the site admins on every HTTP 500 error when DEBUG=False.
144 # See http://docs.djangoproject.com/en/dev/topics/logging for 144 # See http://docs.djangoproject.com/en/dev/topics/logging for
145 # more details on how to customize your logging configuration. 145 # more details on how to customize your logging configuration.
146 LOGGING = { 146 LOGGING = {
147 'version': 1, 147 'version': 1,
148 'disable_existing_loggers': False, 148 'disable_existing_loggers': False,
149 'filters': { 149 'filters': {
150 'require_debug_false': { 150 'require_debug_false': {
151 '()': 'django.utils.log.RequireDebugFalse' 151 '()': 'django.utils.log.RequireDebugFalse'
152 } 152 }
153 }, 153 },
154 'handlers': { 154 'handlers': {
155 'mail_admins': { 155 'mail_admins': {
156 'level': 'ERROR', 156 'level': 'ERROR',
157 'filters': ['require_debug_false'], 157 'filters': ['require_debug_false'],
158 'class': 'django.utils.log.AdminEmailHandler' 158 'class': 'django.utils.log.AdminEmailHandler'
159 }, 159 },
160 'console': { 160 'console': {
161 'level': 'DEBUG', 161 'level': 'DEBUG',
162 'class': 'logging.StreamHandler', 162 'class': 'logging.StreamHandler',
163 }, 163 },
164 }, 164 },
165 'loggers': { 165 'loggers': {
166 'django.request': { 166 'django.request': {
167 'handlers': ['mail_admins'], 167 'handlers': ['mail_admins'],
168 'level': 'ERROR', 168 'level': 'ERROR',
169 'propagate': True, 169 'propagate': True,
170 }, 170 },
171 'django.db.backends': { 171 'django.db.backends': {
172 'level': 'DEBUG', 172 'level': 'DEBUG',
173 'handlers': ['console'], 173 'handlers': ['console'],
174 }, 174 },
175 } 175 }
176 } 176 }
177 # 177 #
178 # CACHES = { # memcached缓存设置 178 # CACHES = { # memcached缓存设置
179 # 'default': { 179 # 'default': {
180 # 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 180 # 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
181 # 'LOCATION': '127.0.0.1:11211', 181 # 'LOCATION': '127.0.0.1:11211',
182 # } 182 # }
183 # } 183 # }
184 184
185 # SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 使用memcached存储session 185 # SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 使用memcached存储session
186 AUTH_DOMAIN = 'https://api.xiuyetang.com/service/user/login'
186 187
187 # 自定义User类 188 # 自定义User类
188 AUTH_USER_MODEL = 'forum.ForumUser' 189 AUTH_USER_MODEL = 'forum.ForumUser'
189 190
190 # 用户认证BackEnds 191 # 用户认证BackEnds
191 # AUTHENTICATION_BACKENDS = ('forum.backends.EmailAuthBackend',) 192 AUTHENTICATION_BACKENDS = ('forum.backends.EmailAuthBackend',)
192 193
193 # 默认登陆uri 194 # 默认登陆uri
194 LOGIN_URL = '/login/' 195 LOGIN_URL = '/login/'
195 196
196 # 发送邮件设置 197 # 发送邮件设置
197 EMAIL_HOST = 'smtp.qq.com' 198 EMAIL_HOST = 'smtp.qq.com'
198 EMAIL_PORT = 25 199 EMAIL_PORT = 25
199 EMAIL_HOST_USER= '*********' 200 EMAIL_HOST_USER= '*********'
200 EMAIL_HOST_PASSWORD= '******' 201 EMAIL_HOST_PASSWORD= '******'
201 DEFAULT_FROM_EMAIL = '*********@qq.com' 202 DEFAULT_FROM_EMAIL = '*********@qq.com'
202 203
203 # 注册用户保留关键字,非Django设置 204 # 注册用户保留关键字,非Django设置
204 RESERVED = ["user", "topic", "home", "setting", "forgot", "login", "logout", "register", "admin"] 205 RESERVED = ["user", "topic", "home", "setting", "forgot", "login", "logout", "register", "admin"]
205 206