from functools import wraps
from django.core.mail import send_mail
-from django.http import HttpResponse
+from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import redirect
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.db import transaction
-from django.contrib.auth import logout as auth_logout
from django.utils.http import urlencode
from django.http import HttpResponseRedirect, HttpResponseBadRequest
from django.db.utils import IntegrityError
from django.contrib.auth.views import password_change
+from django.core.exceptions import ValidationError
+from django.db.models import Q
from astakos.im.models import AstakosUser, Invitation, ApprovalTerms
-from astakos.im.backends import get_backend
-from astakos.im.util import get_context, prepare_response, set_cookie, has_signed_terms
+from astakos.im.activation_backends import get_backend, SimpleBackend
+from astakos.im.util import get_context, prepare_response, set_cookie, get_query
from astakos.im.forms import *
-from astakos.im.functions import send_greeting
-from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, COOKIE_NAME, COOKIE_DOMAIN, IM_MODULES, SITENAME, BASEURL, LOGOUT_NEXT
-from astakos.im.functions import invite as invite_func
+from astakos.im.functions import send_greeting, send_feedback, SendMailError, \
+ invite as invite_func, logout as auth_logout, activate as activate_func, switch_account_to_shibboleth
+from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, COOKIE_NAME, COOKIE_DOMAIN, IM_MODULES, SITENAME, LOGOUT_NEXT, LOGGING_LEVEL
logger = logging.getLogger(__name__)
"""
@wraps(func)
def wrapper(request, *args, **kwargs):
- if request.user.is_authenticated() and not has_signed_terms(request.user):
+ if request.user.is_authenticated() and not request.user.signed_terms():
params = urlencode({'next': request.build_absolute_uri(),
'show_form':''})
terms_uri = reverse('latest_terms') + '?' + params
"""
template_name = login_template_name
- formclass = 'LoginForm'
- kwargs = {}
if request.user.is_authenticated():
return HttpResponseRedirect(reverse('astakos.im.views.edit_profile'))
return render_response(template_name,
- form = globals()[formclass](**kwargs),
+ login_form = LoginForm(request=request),
context_instance = get_context(request, extra_context))
@login_required
"""
status = None
message = None
- inviter = AstakosUser.objects.get(username = request.user.username)
-
+ form = InvitationForm()
+
+ inviter = request.user
if request.method == 'POST':
- username = request.POST.get('uniq')
- realname = request.POST.get('realname')
-
+ form = InvitationForm(request.POST)
if inviter.invitations > 0:
- try:
- invite_func(inviter, username, realname)
- status = messages.SUCCESS
- message = _('Invitation sent to %s' % username)
- transaction.commit()
- except (SMTPException, socket.error) as e:
- status = messages.ERROR
- message = getattr(e, 'strerror', '')
- transaction.rollback()
- except IntegrityError, e:
- status = messages.ERROR
- message = _('There is already invitation for %s' % username)
- transaction.rollback()
+ if form.is_valid():
+ try:
+ invitation = form.save()
+ invite_func(invitation, inviter)
+ status = messages.SUCCESS
+ message = _('Invitation sent to %s' % invitation.username)
+ except SendMailError, e:
+ status = messages.ERROR
+ message = e.message
+ transaction.rollback()
+ except BaseException, e:
+ status = messages.ERROR
+ message = _('Something went wrong.')
+ logger.exception(e)
+ transaction.rollback()
+ else:
+ transaction.commit()
else:
status = messages.ERROR
message = _('No invitations left')
sent = [{'email': inv.username,
'realname': inv.realname,
'is_consumed': inv.is_consumed}
- for inv in inviter.invitations_sent.all()]
+ for inv in request.user.invitations_sent.all()]
kwargs = {'inviter': inviter,
'sent':sent}
context = get_context(request, extra_context, **kwargs)
return render_response(template_name,
+ invitation_form = form,
context_instance = context)
@login_required
next = request.POST.get('next')
if next:
return redirect(next)
- msg = _('Profile has been updated successfully')
+ msg = _('<p>Profile has been updated successfully</p>')
messages.add_message(request, messages.SUCCESS, msg)
except ValueError, ve:
messages.add_message(request, messages.ERROR, ve)
+ elif request.method == "GET":
+ request.user.is_verified = True
+ request.user.save()
return render_response(template_name,
reset_cookie = reset_cookie,
- form = form,
+ profile_form = form,
context_instance = get_context(request,
extra_context))
-def signup(request, on_failure='im/signup.html', on_success='im/signup_complete.html', extra_context={}, backend=None):
+def signup(request, template_name='im/signup.html', on_success='im/signup_complete.html', extra_context={}, backend=None):
"""
Allows a user to create a local account.
- In case of GET request renders a form for providing the user information.
+ In case of GET request renders a form for entering the user information.
In case of POST handles the signup.
The user activation will be delegated to the backend specified by the ``backend`` keyword argument
- if present, otherwise to the ``astakos.im.backends.InvitationBackend``
- if settings.ASTAKOS_INVITATIONS_ENABLED is True or ``astakos.im.backends.SimpleBackend`` if not
- (see backends);
-
- Upon successful user creation if ``next`` url parameter is present the user is redirected there
+ if present, otherwise to the ``astakos.im.activation_backends.InvitationBackend``
+ if settings.ASTAKOS_INVITATIONS_ENABLED is True or ``astakos.im.activation_backends.SimpleBackend`` if not
+ (see activation_backends);
+
+ Upon successful user creation, if ``next`` url parameter is present the user is redirected there
otherwise renders the same page with a success message.
-
- On unsuccessful creation, renders ``on_failure`` with an error message.
-
+
+ On unsuccessful creation, renders ``template_name`` with an error message.
+
**Arguments**
-
- ``on_failure``
- A custom template to render in case of failure. This is optional;
+
+ ``template_name``
+ A custom template to render. This is optional;
if not specified, this will default to ``im/signup.html``.
-
``on_success``
A custom template to render in case of success. This is optional;
if not specified, this will default to ``im/signup_complete.html``.
An dictionary of variables to add to the template context.
**Template:**
-
- im/signup.html or ``on_failure`` keyword argument.
- im/signup_complete.html or ``on_success`` keyword argument.
+
+ im/signup.html or ``template_name`` keyword argument.
+ im/signup_complete.html or ``on_success`` keyword argument.
"""
if request.user.is_authenticated():
- return HttpResponseRedirect(reverse('astakos.im.views.index'))
+ return HttpResponseRedirect(reverse('astakos.im.views.edit_profile'))
+
+ provider = get_query(request).get('provider', 'local')
try:
if not backend:
backend = get_backend(request)
- for provider in IM_MODULES:
- extra_context['%s_form' % provider] = backend.get_signup_form(provider)
- if request.method == 'POST':
- provider = request.POST.get('provider')
- next = request.POST.get('next', '')
- form = extra_context['%s_form' % provider]
- if form.is_valid():
- if provider != 'local':
- url = reverse('astakos.im.target.%s.login' % provider)
- url = '%s?email=%s&next=%s' % (url, form.data['email'], next)
- if backend.invitation:
- url = '%s&code=%s' % (url, backend.invitation.code)
- return redirect(url)
- else:
- status, message, user = backend.signup(form)
- if user and user.is_active:
- return prepare_response(request, user, next=next)
- messages.add_message(request, status, message)
- return render_response(on_success,
- context_instance=get_context(request, extra_context))
- except (Invitation.DoesNotExist, ValueError), e:
+ form = backend.get_signup_form(provider)
+ except Exception, e:
+ form = SimpleBackend(request).get_signup_form(provider)
messages.add_message(request, messages.ERROR, e)
- for provider in IM_MODULES:
- main = provider.capitalize() if provider == 'local' else 'ThirdParty'
- formclass = '%sUserCreationForm' % main
- extra_context['%s_form' % provider] = globals()[formclass]()
- return render_response(on_failure,
+ if request.method == 'POST':
+ if form.is_valid():
+ user = form.save(commit=False)
+ try:
+ result = backend.handle_activation(user)
+ status = messages.SUCCESS
+ message = result.message
+ user.save()
+ if 'additional_email' in form.cleaned_data:
+ additional_email = form.cleaned_data['additional_email']
+ if additional_email != user.email:
+ user.additionalmail_set.create(email=additional_email)
+ msg = 'Additional email: %s saved for user %s.' % (additional_email, user.email)
+ logger._log(LOGGING_LEVEL, msg, [])
+ if user and user.is_active:
+ next = request.POST.get('next', '')
+ return prepare_response(request, user, next=next)
+ messages.add_message(request, status, message)
+ return render_response(on_success,
+ context_instance=get_context(request, extra_context))
+ except SendMailError, e:
+ status = messages.ERROR
+ message = e.message
+ messages.add_message(request, status, message)
+ except BaseException, e:
+ status = messages.ERROR
+ message = _('Something went wrong.')
+ messages.add_message(request, status, message)
+ logger.exception(e)
+ return render_response(template_name,
+ signup_form = form,
+ provider = provider,
context_instance=get_context(request, extra_context))
@login_required
@signed_terms_required
-def send_feedback(request, template_name='im/feedback.html', email_template_name='im/feedback_mail.txt', extra_context={}):
+def feedback(request, template_name='im/feedback.html', email_template_name='im/feedback_mail.txt', extra_context={}):
"""
Allows a user to send feedback.
form = FeedbackForm(request.POST)
if form.is_valid():
- subject = _("Feedback from %s alpha2 testing" % SITENAME)
- from_email = request.user.email
- recipient_list = [DEFAULT_CONTACT_EMAIL]
- content = render_to_string(email_template_name, {
- 'message': form.cleaned_data['feedback_msg'],
- 'data': form.cleaned_data['feedback_data'],
- 'request': request})
-
+ msg = form.cleaned_data['feedback_msg']
+ data = form.cleaned_data['feedback_data']
try:
- send_mail(subject, content, from_email, recipient_list)
+ send_feedback(msg, data, request.user, email_template_name)
+ except SendMailError, e:
+ message = e.message
+ status = messages.ERROR
+ else:
message = _('Feedback successfully sent')
status = messages.SUCCESS
- except (SMTPException, socket.error) as e:
- status = messages.ERROR
- message = getattr(e, 'strerror', '')
messages.add_message(request, status, message)
return render_response(template_name,
- form = form,
+ feedback_form = form,
context_instance = get_context(request, extra_context))
def logout(request, template='registration/logged_out.html', extra_context={}):
"""
Wraps `django.contrib.auth.logout` and delete the cookie.
"""
- auth_logout(request)
response = HttpResponse()
- response.delete_cookie(COOKIE_NAME, path='/', domain=COOKIE_DOMAIN)
+ if request.user.is_authenticated():
+ email = request.user.email
+ auth_logout(request)
+ response.delete_cookie(COOKIE_NAME, path='/', domain=COOKIE_DOMAIN)
+ msg = 'Cookie deleted for %s' % email
+ logger._log(LOGGING_LEVEL, msg, [])
next = request.GET.get('next')
if next:
response['Location'] = next
response['Location'] = LOGOUT_NEXT
response.status_code = 301
return response
- messages.add_message(request, messages.SUCCESS, _('You have successfully logged out.'))
+ messages.add_message(request, messages.SUCCESS, _('<p>You have successfully logged out.</p>'))
context = get_context(request, extra_context)
response.write(render_to_string(template, context_instance=context))
return response
@transaction.commit_manually
-def activate(request, email_template_name='im/welcome_email.txt', on_failure=''):
+def activate(request, greeting_email_template_name='im/welcome_email.txt', helpdesk_email_template_name='im/helpdesk_notification.txt'):
"""
Activates the user identified by the ``auth`` request parameter, sends a welcome email
and renews the user token.
user = AstakosUser.objects.get(auth_token=token)
except AstakosUser.DoesNotExist:
return HttpResponseBadRequest(_('No such user'))
-
- user.is_active = True
- user.email_verified = True
- user.save()
- try:
- send_greeting(user, email_template_name)
- response = prepare_response(request, user, next, renew=True)
- transaction.commit()
- return response
- except (SMTPException, socket.error) as e:
- message = getattr(e, 'name') if hasattr(e, 'name') else e
+
+ if user.is_active:
+ message = _('Account already active.')
messages.add_message(request, messages.ERROR, message)
- transaction.rollback()
- return signup(request, on_failure='im/signup.html')
+ return index(request)
+
+ try:
+ local_user = AstakosUser.objects.get(~Q(id = user.id), email=user.email, is_active=True)
+ except AstakosUser.DoesNotExist:
+ try:
+ activate_func(user, greeting_email_template_name, helpdesk_email_template_name, verify_email=True)
+ response = prepare_response(request, user, next, renew=True)
+ transaction.commit()
+ return response
+ except SendMailError, e:
+ message = e.message
+ messages.add_message(request, messages.ERROR, message)
+ transaction.rollback()
+ return index(request)
+ except BaseException, e:
+ status = messages.ERROR
+ message = _('Something went wrong.')
+ messages.add_message(request, messages.ERROR, message)
+ logger.exception(e)
+ transaction.rollback()
+ return index(request)
+ else:
+ try:
+ user = switch_account_to_shibboleth(user, local_user, greeting_email_template_name)
+ response = prepare_response(request, user, next, renew=True)
+ transaction.commit()
+ return response
+ except SendMailError, e:
+ message = e.message
+ messages.add_message(request, messages.ERROR, message)
+ transaction.rollback()
+ return index(request)
+ except BaseException, e:
+ status = messages.ERROR
+ message = _('Something went wrong.')
+ messages.add_message(request, messages.ERROR, message)
+ logger.exception(e)
+ transaction.rollback()
+ return index(request)
def approval_terms(request, term_id=None, template_name='im/approval_terms.html', extra_context={}):
term = None
if not form.is_valid():
return render_response(template_name,
terms = terms,
- form = form,
+ approval_terms_form = form,
context_instance = get_context(request, extra_context))
user = form.save()
return HttpResponseRedirect(next)
else:
form = None
- if request.user.is_authenticated() and not has_signed_terms(request.user):
+ if request.user.is_authenticated() and not request.user.signed_terms():
form = SignApprovalTermsForm(instance=request.user)
return render_response(template_name,
terms = terms,
- form = form,
+ approval_terms_form = form,
context_instance = get_context(request, extra_context))
@signed_terms_required
def change_password(request):
- return password_change(request, post_change_redirect=reverse('astakos.im.views.edit_profile'))
+ return password_change(request,
+ post_change_redirect=reverse('astakos.im.views.edit_profile'),
+ password_change_form=ExtendedPasswordChangeForm)
+
+@transaction.commit_manually
+def change_email(request, activation_key=None,
+ email_template_name='registration/email_change_email.txt',
+ form_template_name='registration/email_change_form.html',
+ confirm_template_name='registration/email_change_done.html',
+ extra_context={}):
+ if activation_key:
+ try:
+ user = EmailChange.objects.change_email(activation_key)
+ if request.user.is_authenticated() and request.user == user:
+ msg = _('Email changed successfully.')
+ messages.add_message(request, messages.SUCCESS, msg)
+ auth_logout(request)
+ response = prepare_response(request, user)
+ transaction.commit()
+ return response
+ except ValueError, e:
+ messages.add_message(request, messages.ERROR, e)
+ return render_response(confirm_template_name,
+ modified_user = user if 'user' in locals() else None,
+ context_instance = get_context(request,
+ extra_context))
+
+ if not request.user.is_authenticated():
+ path = quote(request.get_full_path())
+ url = request.build_absolute_uri(reverse('astakos.im.views.index'))
+ return HttpResponseRedirect(url + '?next=' + path)
+ form = EmailChangeForm(request.POST or None)
+ if request.method == 'POST' and form.is_valid():
+ try:
+ ec = form.save(email_template_name, request)
+ except SendMailError, e:
+ status = messages.ERROR
+ msg = e
+ transaction.rollback()
+ except IntegrityError, e:
+ status = messages.ERROR
+ msg = _('There is already a pending change email request.')
+ else:
+ status = messages.SUCCESS
+ msg = _('Change email request has been registered succefully.\
+ You are going to receive a verification email in the new address.')
+ transaction.commit()
+ messages.add_message(request, status, msg)
+ return render_response(form_template_name,
+ form = form,
+ context_instance = get_context(request,
+ extra_context))