1 from django.shortcuts import render_to_response, get_object_or_404
2 from django.template import RequestContext
3 from django.core.urlresolvers import reverse
4 from forum.models import User
5 from django.http import HttpResponseRedirect, Http404
6 from forum.http_responses import HttpResponseUnauthorized
7 from django.utils.safestring import mark_safe
8 from django.utils.translation import ugettext as _
9 from django.utils.http import urlquote_plus
10 from django.contrib.auth.decorators import login_required
11 from django.contrib.auth import login, logout
12 from django.http import get_host
13 from forum.actions import SuspendAction
18 from forum.forms import SimpleRegistrationForm, SimpleEmailSubscribeForm, \
19 TemporaryLoginRequestForm, ChangePasswordForm, SetPasswordForm
20 from forum.utils.mail import send_email, send_template_email
22 from forum.authentication.base import InvalidAuthentication
23 from forum.authentication import AUTH_PROVIDERS
25 from forum.models import AuthKeyUserAssociation, ValidationHash, Question, Answer
26 from forum.actions import UserJoinsAction
28 def signin_page(request, action=None):
30 request.session['on_signin_url'] = request.META.get('HTTP_REFERER', '/')
32 request.session['on_signin_action'] = action
33 request.session['on_signin_url'] = reverse('auth_action_signin', kwargs={'action': action})
35 all_providers = [provider.context for provider in AUTH_PROVIDERS.values()]
37 sort = lambda c1, c2: c1.weight - c2.weight
38 can_show = lambda c: not request.user.is_authenticated() or c.show_to_logged_in_user
40 bigicon_providers = sorted([
41 context for context in all_providers if context.mode == 'BIGICON' and can_show(context)
44 smallicon_providers = sorted([
45 context for context in all_providers if context.mode == 'SMALLICON' and can_show(context)
48 top_stackitem_providers = sorted([
49 context for context in all_providers if context.mode == 'TOP_STACK_ITEM' and can_show(context)
52 stackitem_providers = sorted([
53 context for context in all_providers if context.mode == 'STACK_ITEM' and can_show(context)
57 msg = request.session['auth_error']
58 del request.session['auth_error']
62 return render_to_response(
66 'all_providers': all_providers,
67 'bigicon_providers': bigicon_providers,
68 'top_stackitem_providers': top_stackitem_providers,
69 'stackitem_providers': stackitem_providers,
70 'smallicon_providers': smallicon_providers,
72 RequestContext(request))
74 def prepare_provider_signin(request, provider):
75 force_email_request = request.REQUEST.get('validate_email', 'yes') == 'yes'
76 request.session['force_email_request'] = force_email_request
78 if provider in AUTH_PROVIDERS:
79 provider_class = AUTH_PROVIDERS[provider].consumer
82 request_url = provider_class.prepare_authentication_request(request,
83 reverse('auth_provider_done',
84 kwargs={'provider': provider}))
86 return HttpResponseRedirect(request_url)
87 except NotImplementedError, e:
88 return process_provider_signin(request, provider)
89 except InvalidAuthentication, e:
90 request.session['auth_error'] = e.message
92 return HttpResponseRedirect(reverse('auth_signin'))
97 def process_provider_signin(request, provider):
98 if provider in AUTH_PROVIDERS:
99 provider_class = AUTH_PROVIDERS[provider].consumer
102 assoc_key = provider_class.process_authentication_request(request)
103 except InvalidAuthentication, e:
104 request.session['auth_error'] = e.message
105 return HttpResponseRedirect(reverse('auth_signin'))
107 if request.user.is_authenticated():
108 if isinstance(assoc_key, (type, User)):
109 if request.user != assoc_key:
110 request.session['auth_error'] = _(
111 "Sorry, these login credentials belong to anoother user. Plese terminate your current session and try again."
114 request.session['auth_error'] = _("You are already logged in with that user.")
117 assoc = AuthKeyUserAssociation.objects.get(key=assoc_key)
118 if assoc.user == request.user:
119 request.session['auth_error'] = _(
120 "These login credentials are already associated with your account.")
122 request.session['auth_error'] = _(
123 "Sorry, these login credentials belong to anoother user. Plese terminate your current session and try again."
126 uassoc = AuthKeyUserAssociation(user=request.user, key=assoc_key, provider=provider)
128 request.user.message_set.create(
129 message=_('The new credentials are now associated with your account'))
130 return HttpResponseRedirect(reverse('user_authsettings', args=[request.user.id]))
132 return HttpResponseRedirect(reverse('auth_signin'))
134 if isinstance(assoc_key, User):
135 return login_and_forward(request, assoc_key)
138 assoc = AuthKeyUserAssociation.objects.get(key=assoc_key)
140 return login_and_forward(request, user_)
142 request.session['assoc_key'] = assoc_key
143 request.session['auth_provider'] = provider
144 return HttpResponseRedirect(reverse('auth_external_register'))
146 return HttpResponseRedirect(reverse('auth_signin'))
148 def external_register(request):
149 if request.method == 'POST' and 'bnewaccount' in request.POST:
150 form1 = SimpleRegistrationForm(request.POST)
151 email_feeds_form = SimpleEmailSubscribeForm(request.POST)
153 if (form1.is_valid() and email_feeds_form.is_valid()):
154 user_ = User(username=form1.cleaned_data['username'], email=form1.cleaned_data['email'])
155 user_.email_isvalid = request.session.get('auth_validated_email', '') == form1.cleaned_data['email']
156 user_.set_unusable_password()
158 if User.objects.all().count() == 0:
159 user_.is_superuser = True
160 user_.is_staff = True
163 UserJoinsAction(user=user_, ip=request.META['REMOTE_ADDR']).save()
166 assoc_key = request.session['assoc_key']
167 auth_provider = request.session['auth_provider']
169 request.session['auth_error'] = _(
170 "Oops, something went wrong in the middle of this process. Please try again. Note that you need to have cookies enabled for the authentication to work."
172 logging.error("Missing session data when trying to complete user registration: %s" % ", ".join(
173 ["%s: %s" % (k, v) for k, v in request.META.items()]))
174 return HttpResponseRedirect(reverse('auth_signin'))
176 uassoc = AuthKeyUserAssociation(user=user_, key=assoc_key, provider=auth_provider)
179 if email_feeds_form.cleaned_data['subscribe'] == 'n':
180 user_.subscription_settings.enable_notifications = False
181 user_.subscription_settings.save()
183 del request.session['assoc_key']
184 del request.session['auth_provider']
186 return login_and_forward(request, user_, message=_("A welcome email has been sent to your email address. "))
188 auth_provider = request.session.get('auth_provider', None)
189 if not auth_provider:
190 request.session['auth_error'] = _(
191 "Oops, something went wrong in the middle of this process. Please try again.")
192 logging.error("Missing session data when trying to complete user registration: %s" % ", ".join(
193 ["%s: %s" % (k, v) for k, v in request.META.items()]))
194 return HttpResponseRedirect(reverse('auth_signin'))
196 provider_class = AUTH_PROVIDERS[auth_provider].consumer
197 user_data = provider_class.get_user_data(request.session['assoc_key'])
200 user_data = request.session.get('auth_consumer_data', {})
202 username = user_data.get('username', '')
203 email = user_data.get('email', '')
206 request.session['auth_validated_email'] = email
208 form1 = SimpleRegistrationForm(initial={
210 'username': username,
213 email_feeds_form = SimpleEmailSubscribeForm()
215 provider_context = AUTH_PROVIDERS[request.session['auth_provider']].context
217 return render_to_response('auth/complete.html', {
219 'email_feeds_form': email_feeds_form,
220 'provider':mark_safe(provider_context.human_name),
221 'login_type':provider_context.id,
222 'gravatar_faq_url':reverse('faq') + '#gravatar',
223 }, context_instance=RequestContext(request))
225 def request_temp_login(request):
226 if request.method == 'POST':
227 form = TemporaryLoginRequestForm(request.POST)
230 user = form.user_cache
232 if user.is_suspended():
233 return forward_suspended_user(request, user, False)
236 hash = get_object_or_404(ValidationHash, user=user, type='templogin')
237 if hash.expiration < datetime.datetime.now():
239 return request_temp_login(request)
241 hash = ValidationHash.objects.create_new(user, 'templogin', [user.id])
243 send_template_email([user], "auth/temp_login_email.html", {'temp_login_code': hash})
245 request.user.message_set.create(message=_("An email has been sent with your temporary login key"))
247 return HttpResponseRedirect(reverse('index'))
249 form = TemporaryLoginRequestForm()
251 return render_to_response(
252 'auth/temp_login_request.html', {'form': form},
253 context_instance=RequestContext(request))
255 def temp_signin(request, user, code):
256 user = get_object_or_404(User, id=user)
258 if (ValidationHash.objects.validate(code, user, 'templogin', [user.id])):
259 return login_and_forward(request, user, reverse('user_authsettings', kwargs={'id': user.id}),
261 "You are logged in with a temporary access key, please take the time to fix your issue with authentication."
266 def validate_email(request, user, code):
267 user = get_object_or_404(User, id=user)
269 if (ValidationHash.objects.validate(code, user, 'email', [user.email])):
270 user.email_isvalid = True
272 return login_and_forward(request, user, None, _("Thank you, your email is now validated."))
277 def auth_settings(request, id):
278 user_ = get_object_or_404(User, id=id)
280 if not (request.user.is_superuser or request.user == user_):
281 return HttpResponseUnauthorized(request)
283 auth_keys = user_.auth_keys.all()
285 if request.user.is_superuser or (not user_.has_usable_password()):
286 FormClass = SetPasswordForm
288 FormClass = ChangePasswordForm
291 form = FormClass(request.POST, user=user_)
293 is_new_pass = not user_.has_usable_password()
294 user_.set_password(form.cleaned_data['password1'])
298 request.user.message_set.create(message=_("New password set"))
299 if not request.user.is_superuser:
300 form = ChangePasswordForm(user=user_)
302 request.user.message_set.create(message=_("Your password was changed"))
304 return HttpResponseRedirect(reverse('user_authsettings', kwargs={'id': user_.id}))
306 form = FormClass(user=user_)
311 provider = AUTH_PROVIDERS.get(k.provider, None)
313 if provider is not None:
314 name = "%s: %s" % (provider.context.human_name, provider.context.readable_key(k))
316 from forum.authentication.base import ConsumerTemplateContext
317 "unknown: %s" % ConsumerTemplateContext.readable_key(k)
319 auth_keys_list.append({
324 return render_to_response('auth/auth_settings.html', {
326 "can_view_private": (user_ == request.user) or request.user.is_superuser,
328 'has_password': user_.has_usable_password(),
329 'auth_keys': auth_keys_list,
330 }, context_instance=RequestContext(request))
332 def remove_external_provider(request, id):
333 association = get_object_or_404(AuthKeyUserAssociation, id=id)
334 if not (request.user.is_superuser or request.user == association.user):
335 return HttpResponseUnauthorized(request)
337 request.user.message_set.create(message=_("You removed the association with %s") % association.provider)
339 return HttpResponseRedirect(reverse('user_authsettings', kwargs={'id': association.user.id}))
341 def newquestion_signin_action(user):
342 question = Question.objects.filter(author=user).order_by('-added_at')[0]
343 return question.get_absolute_url()
345 def newanswer_signin_action(user):
346 answer = Answer.objects.filter(author=user).order_by('-added_at')[0]
347 return answer.get_absolute_url()
349 POST_SIGNIN_ACTIONS = {
350 'newquestion': newquestion_signin_action,
351 'newanswer': newanswer_signin_action,
354 def login_and_forward(request, user, forward=None, message=None):
355 if user.is_suspended():
356 return forward_suspended_user(request, user)
358 user.backend = "django.contrib.auth.backends.ModelBackend"
361 temp_data = request.session.pop('temp_node_data', None)
363 request.POST = temp_data
364 node_type = request.session.pop('temp_node_type')
366 if node_type == "question":
367 from forum.views.writers import ask
369 elif node_type == "answer":
370 from forum.views.writers import answer
371 return answer(request, request.session.pop('temp_question_id'))
374 signin_action = request.session.get('on_signin_action', None)
375 if not signin_action:
376 forward = request.session.get('on_signin_url', None)
379 forward = reverse('index')
382 forward = POST_SIGNIN_ACTIONS[signin_action](user)
384 forward = reverse('index')
387 message = _("Welcome back %s, you are now logged in") % user.username
389 request.user.message_set.create(message=message)
390 return HttpResponseRedirect(forward)
392 def forward_suspended_user(request, user, show_private_msg=True):
393 message = _("Sorry, but this account is suspended")
395 msg_type = 'privatemsg'
397 msg_type = 'publicmsg'
399 suspension = user.suspension
401 message += (":<br />" + suspension.extra.get(msg_type, ''))
403 request.user.message_set.create(message)
404 return HttpResponseRedirect(reverse('index'))
407 def signout(request):
409 return HttpResponseRedirect(reverse('index'))