Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / views.py @ d9484003

History | View | Annotate | Download (22 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 176023aa Kostas Papadimitriou
#
3 64cd4730 Antony Chazapis
# Redistribution and use in source and binary forms, with or
4 64cd4730 Antony Chazapis
# without modification, are permitted provided that the following
5 64cd4730 Antony Chazapis
# conditions are met:
6 176023aa Kostas Papadimitriou
#
7 64cd4730 Antony Chazapis
#   1. Redistributions of source code must retain the above
8 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
9 64cd4730 Antony Chazapis
#      disclaimer.
10 176023aa Kostas Papadimitriou
#
11 64cd4730 Antony Chazapis
#   2. Redistributions in binary form must reproduce the above
12 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
13 64cd4730 Antony Chazapis
#      disclaimer in the documentation and/or other materials
14 64cd4730 Antony Chazapis
#      provided with the distribution.
15 176023aa Kostas Papadimitriou
#
16 64cd4730 Antony Chazapis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 64cd4730 Antony Chazapis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 64cd4730 Antony Chazapis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 64cd4730 Antony Chazapis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 64cd4730 Antony Chazapis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 64cd4730 Antony Chazapis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 64cd4730 Antony Chazapis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 64cd4730 Antony Chazapis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 64cd4730 Antony Chazapis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 64cd4730 Antony Chazapis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 64cd4730 Antony Chazapis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 64cd4730 Antony Chazapis
# POSSIBILITY OF SUCH DAMAGE.
28 176023aa Kostas Papadimitriou
#
29 64cd4730 Antony Chazapis
# The views and conclusions contained in the software and
30 64cd4730 Antony Chazapis
# documentation are those of the authors and should not be
31 64cd4730 Antony Chazapis
# interpreted as representing official policies, either expressed
32 64cd4730 Antony Chazapis
# or implied, of GRNET S.A.
33 64cd4730 Antony Chazapis
34 64cd4730 Antony Chazapis
import logging
35 64cd4730 Antony Chazapis
import socket
36 64cd4730 Antony Chazapis
37 64cd4730 Antony Chazapis
from smtplib import SMTPException
38 0905ccd2 Sofia Papagiannaki
from urllib import quote
39 63ecdd20 Sofia Papagiannaki
from functools import wraps
40 64cd4730 Antony Chazapis
41 64cd4730 Antony Chazapis
from django.core.mail import send_mail
42 27e26a41 Sofia Papagiannaki
from django.http import HttpResponse, HttpResponseBadRequest
43 64cd4730 Antony Chazapis
from django.shortcuts import redirect
44 64cd4730 Antony Chazapis
from django.template.loader import render_to_string
45 64cd4730 Antony Chazapis
from django.utils.translation import ugettext as _
46 64cd4730 Antony Chazapis
from django.core.urlresolvers import reverse
47 890b0eaf Sofia Papagiannaki
from django.contrib.auth.decorators import login_required
48 890b0eaf Sofia Papagiannaki
from django.contrib import messages
49 890b0eaf Sofia Papagiannaki
from django.db import transaction
50 63ecdd20 Sofia Papagiannaki
from django.utils.http import urlencode
51 683cf244 Sofia Papagiannaki
from django.http import HttpResponseRedirect, HttpResponseBadRequest
52 8316698a Sofia Papagiannaki
from django.db.utils import IntegrityError
53 270dd48d Sofia Papagiannaki
from django.contrib.auth.views import password_change
54 27e26a41 Sofia Papagiannaki
from django.core.exceptions import ValidationError
55 64cd4730 Antony Chazapis
56 270dd48d Sofia Papagiannaki
from astakos.im.models import AstakosUser, Invitation, ApprovalTerms
57 4e30244e Sofia Papagiannaki
from astakos.im.activation_backends import get_backend, SimpleBackend
58 1662ac2d Sofia Papagiannaki
from astakos.im.util import get_context, prepare_response, set_cookie, get_query
59 15efc749 Sofia Papagiannaki
from astakos.im.forms import *
60 111f3da6 Sofia Papagiannaki
from astakos.im.functions import send_greeting, send_feedback, SendMailError, \
61 111f3da6 Sofia Papagiannaki
    invite as invite_func, logout as auth_logout
62 4e30244e Sofia Papagiannaki
from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, COOKIE_NAME, COOKIE_DOMAIN, IM_MODULES, SITENAME, LOGOUT_NEXT
63 64cd4730 Antony Chazapis
64 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
65 e015e9e6 Sofia Papagiannaki
66 c301698f Sofia Papagiannaki
def render_response(template, tab=None, status=200, reset_cookie=False, context_instance=None, **kwargs):
67 890b0eaf Sofia Papagiannaki
    """
68 890b0eaf Sofia Papagiannaki
    Calls ``django.template.loader.render_to_string`` with an additional ``tab``
69 890b0eaf Sofia Papagiannaki
    keyword argument and returns an ``django.http.HttpResponse`` with the
70 890b0eaf Sofia Papagiannaki
    specified ``status``.
71 890b0eaf Sofia Papagiannaki
    """
72 64cd4730 Antony Chazapis
    if tab is None:
73 881c856c Sofia Papagiannaki
        tab = template.partition('_')[0].partition('.html')[0]
74 64cd4730 Antony Chazapis
    kwargs.setdefault('tab', tab)
75 0905ccd2 Sofia Papagiannaki
    html = render_to_string(template, kwargs, context_instance=context_instance)
76 c301698f Sofia Papagiannaki
    response = HttpResponse(html, status=status)
77 c301698f Sofia Papagiannaki
    if reset_cookie:
78 c301698f Sofia Papagiannaki
        set_cookie(response, context_instance['request'].user)
79 c301698f Sofia Papagiannaki
    return response
80 64cd4730 Antony Chazapis
81 63ecdd20 Sofia Papagiannaki
82 63ecdd20 Sofia Papagiannaki
def requires_anonymous(func):
83 63ecdd20 Sofia Papagiannaki
    """
84 270dd48d Sofia Papagiannaki
    Decorator checkes whether the request.user is not Anonymous and in that case
85 7482228b Sofia Papagiannaki
    redirects to `logout`.
86 63ecdd20 Sofia Papagiannaki
    """
87 63ecdd20 Sofia Papagiannaki
    @wraps(func)
88 63ecdd20 Sofia Papagiannaki
    def wrapper(request, *args):
89 63ecdd20 Sofia Papagiannaki
        if not request.user.is_anonymous():
90 63ecdd20 Sofia Papagiannaki
            next = urlencode({'next': request.build_absolute_uri()})
91 270dd48d Sofia Papagiannaki
            logout_uri = reverse(logout) + '?' + next
92 270dd48d Sofia Papagiannaki
            return HttpResponseRedirect(logout_uri)
93 63ecdd20 Sofia Papagiannaki
        return func(request, *args)
94 63ecdd20 Sofia Papagiannaki
    return wrapper
95 63ecdd20 Sofia Papagiannaki
96 270dd48d Sofia Papagiannaki
def signed_terms_required(func):
97 270dd48d Sofia Papagiannaki
    """
98 270dd48d Sofia Papagiannaki
    Decorator checkes whether the request.user is Anonymous and in that case
99 270dd48d Sofia Papagiannaki
    redirects to `logout`.
100 270dd48d Sofia Papagiannaki
    """
101 270dd48d Sofia Papagiannaki
    @wraps(func)
102 270dd48d Sofia Papagiannaki
    def wrapper(request, *args, **kwargs):
103 1662ac2d Sofia Papagiannaki
        if request.user.is_authenticated() and not request.user.signed_terms():
104 270dd48d Sofia Papagiannaki
            params = urlencode({'next': request.build_absolute_uri(),
105 270dd48d Sofia Papagiannaki
                              'show_form':''})
106 270dd48d Sofia Papagiannaki
            terms_uri = reverse('latest_terms') + '?' + params
107 270dd48d Sofia Papagiannaki
            return HttpResponseRedirect(terms_uri)
108 270dd48d Sofia Papagiannaki
        return func(request, *args, **kwargs)
109 270dd48d Sofia Papagiannaki
    return wrapper
110 270dd48d Sofia Papagiannaki
111 270dd48d Sofia Papagiannaki
@signed_terms_required
112 1e685275 Sofia Papagiannaki
def index(request, login_template_name='im/login.html', profile_template_name='im/profile.html', extra_context={}):
113 890b0eaf Sofia Papagiannaki
    """
114 dcf55476 Sofia Papagiannaki
    If there is logged on user renders the profile page otherwise renders login page.
115 176023aa Kostas Papadimitriou

116 890b0eaf Sofia Papagiannaki
    **Arguments**
117 176023aa Kostas Papadimitriou

118 dcf55476 Sofia Papagiannaki
    ``login_template_name``
119 dcf55476 Sofia Papagiannaki
        A custom login template to use. This is optional; if not specified,
120 1e685275 Sofia Papagiannaki
        this will default to ``im/login.html``.
121 176023aa Kostas Papadimitriou

122 dcf55476 Sofia Papagiannaki
    ``profile_template_name``
123 dcf55476 Sofia Papagiannaki
        A custom profile template to use. This is optional; if not specified,
124 1e685275 Sofia Papagiannaki
        this will default to ``im/profile.html``.
125 176023aa Kostas Papadimitriou

126 890b0eaf Sofia Papagiannaki
    ``extra_context``
127 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
128 176023aa Kostas Papadimitriou

129 890b0eaf Sofia Papagiannaki
    **Template:**
130 176023aa Kostas Papadimitriou

131 1e685275 Sofia Papagiannaki
    im/profile.html or im/login.html or ``template_name`` keyword argument.
132 176023aa Kostas Papadimitriou

133 890b0eaf Sofia Papagiannaki
    """
134 dcf55476 Sofia Papagiannaki
    template_name = login_template_name
135 dcf55476 Sofia Papagiannaki
    if request.user.is_authenticated():
136 f534fb96 Sofia Papagiannaki
        return HttpResponseRedirect(reverse('astakos.im.views.edit_profile'))
137 0905ccd2 Sofia Papagiannaki
    return render_response(template_name,
138 672d445a Sofia Papagiannaki
                           login_form = LoginForm(request=request),
139 0905ccd2 Sofia Papagiannaki
                           context_instance = get_context(request, extra_context))
140 64cd4730 Antony Chazapis
141 890b0eaf Sofia Papagiannaki
@login_required
142 270dd48d Sofia Papagiannaki
@signed_terms_required
143 890b0eaf Sofia Papagiannaki
@transaction.commit_manually
144 1e685275 Sofia Papagiannaki
def invite(request, template_name='im/invitations.html', extra_context={}):
145 890b0eaf Sofia Papagiannaki
    """
146 890b0eaf Sofia Papagiannaki
    Allows a user to invite somebody else.
147 176023aa Kostas Papadimitriou

148 890b0eaf Sofia Papagiannaki
    In case of GET request renders a form for providing the invitee information.
149 890b0eaf Sofia Papagiannaki
    In case of POST checks whether the user has not run out of invitations and then
150 890b0eaf Sofia Papagiannaki
    sends an invitation email to singup to the service.
151 176023aa Kostas Papadimitriou

152 890b0eaf Sofia Papagiannaki
    The view uses commit_manually decorator in order to ensure the number of the
153 890b0eaf Sofia Papagiannaki
    user invitations is going to be updated only if the email has been successfully sent.
154 176023aa Kostas Papadimitriou

155 2cbaacd5 Sofia Papagiannaki
    If the user isn't logged in, redirects to settings.LOGIN_URL.
156 176023aa Kostas Papadimitriou

157 890b0eaf Sofia Papagiannaki
    **Arguments**
158 176023aa Kostas Papadimitriou

159 890b0eaf Sofia Papagiannaki
    ``template_name``
160 890b0eaf Sofia Papagiannaki
        A custom template to use. This is optional; if not specified,
161 1e685275 Sofia Papagiannaki
        this will default to ``im/invitations.html``.
162 176023aa Kostas Papadimitriou

163 890b0eaf Sofia Papagiannaki
    ``extra_context``
164 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
165 176023aa Kostas Papadimitriou

166 890b0eaf Sofia Papagiannaki
    **Template:**
167 176023aa Kostas Papadimitriou

168 1e685275 Sofia Papagiannaki
    im/invitations.html or ``template_name`` keyword argument.
169 176023aa Kostas Papadimitriou

170 890b0eaf Sofia Papagiannaki
    **Settings:**
171 176023aa Kostas Papadimitriou

172 890b0eaf Sofia Papagiannaki
    The view expectes the following settings are defined:
173 176023aa Kostas Papadimitriou

174 890b0eaf Sofia Papagiannaki
    * LOGIN_URL: login uri
175 2cbaacd5 Sofia Papagiannaki
    * ASTAKOS_DEFAULT_CONTACT_EMAIL: service support email
176 2cbaacd5 Sofia Papagiannaki
    * ASTAKOS_DEFAULT_FROM_EMAIL: from email
177 890b0eaf Sofia Papagiannaki
    """
178 64cd4730 Antony Chazapis
    status = None
179 64cd4730 Antony Chazapis
    message = None
180 8f5a3a06 Sofia Papagiannaki
    form = InvitationForm()
181 5ed6816e Sofia Papagiannaki
    
182 18ffbee1 Sofia Papagiannaki
    inviter = request.user
183 64cd4730 Antony Chazapis
    if request.method == 'POST':
184 8f5a3a06 Sofia Papagiannaki
        form = InvitationForm(request.POST)
185 64cd4730 Antony Chazapis
        if inviter.invitations > 0:
186 8f5a3a06 Sofia Papagiannaki
            if form.is_valid():
187 8f5a3a06 Sofia Papagiannaki
                try:
188 8f5a3a06 Sofia Papagiannaki
                    invitation = form.save()
189 8f5a3a06 Sofia Papagiannaki
                    invite_func(invitation, inviter)
190 8f5a3a06 Sofia Papagiannaki
                    status = messages.SUCCESS
191 8f5a3a06 Sofia Papagiannaki
                    message = _('Invitation sent to %s' % invitation.username)
192 8f5a3a06 Sofia Papagiannaki
                except SendMailError, e:
193 18ffbee1 Sofia Papagiannaki
                    status = messages.ERROR
194 8f5a3a06 Sofia Papagiannaki
                    message = e.message
195 8f5a3a06 Sofia Papagiannaki
                    transaction.rollback()
196 18ffbee1 Sofia Papagiannaki
                except BaseException, e:
197 18ffbee1 Sofia Papagiannaki
                    status = messages.ERROR
198 18ffbee1 Sofia Papagiannaki
                    message = _('Something went wrong.')
199 18ffbee1 Sofia Papagiannaki
                    logger.exception(e)
200 18ffbee1 Sofia Papagiannaki
                    transaction.rollback()
201 18ffbee1 Sofia Papagiannaki
                else:
202 18ffbee1 Sofia Papagiannaki
                    transaction.commit()
203 64cd4730 Antony Chazapis
        else:
204 890b0eaf Sofia Papagiannaki
            status = messages.ERROR
205 64cd4730 Antony Chazapis
            message = _('No invitations left')
206 890b0eaf Sofia Papagiannaki
    messages.add_message(request, status, message)
207 176023aa Kostas Papadimitriou
208 a196eb7e Sofia Papagiannaki
    sent = [{'email': inv.username,
209 d6ae71a2 root
             'realname': inv.realname,
210 d6ae71a2 root
             'is_consumed': inv.is_consumed}
211 18ffbee1 Sofia Papagiannaki
             for inv in request.user.invitations_sent.all()]
212 77e2ad52 root
    kwargs = {'inviter': inviter,
213 a196eb7e Sofia Papagiannaki
              'sent':sent}
214 0905ccd2 Sofia Papagiannaki
    context = get_context(request, extra_context, **kwargs)
215 0905ccd2 Sofia Papagiannaki
    return render_response(template_name,
216 8f5a3a06 Sofia Papagiannaki
                           invitation_form = form,
217 0905ccd2 Sofia Papagiannaki
                           context_instance = context)
218 64cd4730 Antony Chazapis
219 890b0eaf Sofia Papagiannaki
@login_required
220 270dd48d Sofia Papagiannaki
@signed_terms_required
221 1e685275 Sofia Papagiannaki
def edit_profile(request, template_name='im/profile.html', extra_context={}):
222 890b0eaf Sofia Papagiannaki
    """
223 890b0eaf Sofia Papagiannaki
    Allows a user to edit his/her profile.
224 176023aa Kostas Papadimitriou

225 890b0eaf Sofia Papagiannaki
    In case of GET request renders a form for displaying the user information.
226 ce86cd44 Sofia Papagiannaki
    In case of POST updates the user informantion and redirects to ``next``
227 ce86cd44 Sofia Papagiannaki
    url parameter if exists.
228 176023aa Kostas Papadimitriou

229 2cbaacd5 Sofia Papagiannaki
    If the user isn't logged in, redirects to settings.LOGIN_URL.
230 176023aa Kostas Papadimitriou

231 890b0eaf Sofia Papagiannaki
    **Arguments**
232 176023aa Kostas Papadimitriou

233 890b0eaf Sofia Papagiannaki
    ``template_name``
234 890b0eaf Sofia Papagiannaki
        A custom template to use. This is optional; if not specified,
235 1e685275 Sofia Papagiannaki
        this will default to ``im/profile.html``.
236 176023aa Kostas Papadimitriou

237 890b0eaf Sofia Papagiannaki
    ``extra_context``
238 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
239 176023aa Kostas Papadimitriou

240 890b0eaf Sofia Papagiannaki
    **Template:**
241 176023aa Kostas Papadimitriou

242 1e685275 Sofia Papagiannaki
    im/profile.html or ``template_name`` keyword argument.
243 176023aa Kostas Papadimitriou

244 92defad4 Sofia Papagiannaki
    **Settings:**
245 176023aa Kostas Papadimitriou

246 92defad4 Sofia Papagiannaki
    The view expectes the following settings are defined:
247 176023aa Kostas Papadimitriou

248 92defad4 Sofia Papagiannaki
    * LOGIN_URL: login uri
249 890b0eaf Sofia Papagiannaki
    """
250 15efc749 Sofia Papagiannaki
    form = ProfileForm(instance=request.user)
251 15efc749 Sofia Papagiannaki
    extra_context['next'] = request.GET.get('next')
252 c301698f Sofia Papagiannaki
    reset_cookie = False
253 64cd4730 Antony Chazapis
    if request.method == 'POST':
254 15efc749 Sofia Papagiannaki
        form = ProfileForm(request.POST, instance=request.user)
255 890b0eaf Sofia Papagiannaki
        if form.is_valid():
256 64cd4730 Antony Chazapis
            try:
257 c301698f Sofia Papagiannaki
                prev_token = request.user.auth_token
258 c301698f Sofia Papagiannaki
                user = form.save()
259 c301698f Sofia Papagiannaki
                reset_cookie = user.auth_token != prev_token
260 c301698f Sofia Papagiannaki
                form = ProfileForm(instance=user)
261 1a3675a0 Sofia Papagiannaki
                next = request.POST.get('next')
262 1a3675a0 Sofia Papagiannaki
                if next:
263 1a3675a0 Sofia Papagiannaki
                    return redirect(next)
264 0f4a8a68 Olga Brani
                msg = _('<p>Profile has been updated successfully</p>')
265 890b0eaf Sofia Papagiannaki
                messages.add_message(request, messages.SUCCESS, msg)
266 890b0eaf Sofia Papagiannaki
            except ValueError, ve:
267 890b0eaf Sofia Papagiannaki
                messages.add_message(request, messages.ERROR, ve)
268 0905ccd2 Sofia Papagiannaki
    return render_response(template_name,
269 c301698f Sofia Papagiannaki
                           reset_cookie = reset_cookie,
270 8f5a3a06 Sofia Papagiannaki
                           profile_form = form,
271 0905ccd2 Sofia Papagiannaki
                           context_instance = get_context(request,
272 c301698f Sofia Papagiannaki
                                                          extra_context))
273 64cd4730 Antony Chazapis
274 8f5a3a06 Sofia Papagiannaki
def signup(request, template_name='im/signup.html', on_success='im/signup_complete.html', extra_context={}, backend=None):
275 890b0eaf Sofia Papagiannaki
    """
276 890b0eaf Sofia Papagiannaki
    Allows a user to create a local account.
277 176023aa Kostas Papadimitriou

278 890b0eaf Sofia Papagiannaki
    In case of GET request renders a form for providing the user information.
279 890b0eaf Sofia Papagiannaki
    In case of POST handles the signup.
280 176023aa Kostas Papadimitriou

281 890b0eaf Sofia Papagiannaki
    The user activation will be delegated to the backend specified by the ``backend`` keyword argument
282 8f5a3a06 Sofia Papagiannaki
    if present, otherwise to the ``astakos.im.activation_backends.InvitationBackend``
283 8f5a3a06 Sofia Papagiannaki
    if settings.ASTAKOS_INVITATIONS_ENABLED is True or ``astakos.im.activation_backends.SimpleBackend`` if not
284 8f5a3a06 Sofia Papagiannaki
    (see activation_backends);
285 890b0eaf Sofia Papagiannaki
    
286 890b0eaf Sofia Papagiannaki
    Upon successful user creation if ``next`` url parameter is present the user is redirected there
287 890b0eaf Sofia Papagiannaki
    otherwise renders the same page with a success message.
288 64cd4730 Antony Chazapis
    
289 8f5a3a06 Sofia Papagiannaki
    On unsuccessful creation, renders ``template_name`` with an error message.
290 890b0eaf Sofia Papagiannaki
    
291 890b0eaf Sofia Papagiannaki
    **Arguments**
292 890b0eaf Sofia Papagiannaki
    
293 8f5a3a06 Sofia Papagiannaki
    ``template_name``
294 8f5a3a06 Sofia Papagiannaki
        A custom template to render. This is optional;
295 1e685275 Sofia Papagiannaki
        if not specified, this will default to ``im/signup.html``.
296 176023aa Kostas Papadimitriou

297 176023aa Kostas Papadimitriou

298 f7e8a159 Sofia Papagiannaki
    ``on_success``
299 f7e8a159 Sofia Papagiannaki
        A custom template to render in case of success. This is optional;
300 1e685275 Sofia Papagiannaki
        if not specified, this will default to ``im/signup_complete.html``.
301 176023aa Kostas Papadimitriou

302 890b0eaf Sofia Papagiannaki
    ``extra_context``
303 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
304 176023aa Kostas Papadimitriou

305 890b0eaf Sofia Papagiannaki
    **Template:**
306 890b0eaf Sofia Papagiannaki
    
307 8f5a3a06 Sofia Papagiannaki
    im/signup.html or ``template_name`` keyword argument.
308 1e685275 Sofia Papagiannaki
    im/signup_complete.html or ``on_success`` keyword argument. 
309 890b0eaf Sofia Papagiannaki
    """
310 0d02a287 Sofia Papagiannaki
    if request.user.is_authenticated():
311 0d02a287 Sofia Papagiannaki
        return HttpResponseRedirect(reverse('astakos.im.views.index'))
312 4e30244e Sofia Papagiannaki
    
313 0a569195 Sofia Papagiannaki
    provider = get_query(request).get('provider', 'local')
314 890b0eaf Sofia Papagiannaki
    try:
315 18ffbee1 Sofia Papagiannaki
        if not backend:
316 18ffbee1 Sofia Papagiannaki
            backend = get_backend(request)
317 8f5a3a06 Sofia Papagiannaki
        form = backend.get_signup_form(provider)
318 0a569195 Sofia Papagiannaki
    except Exception, e:
319 4e30244e Sofia Papagiannaki
        form = SimpleBackend(request).get_signup_form(provider)
320 18ffbee1 Sofia Papagiannaki
        messages.add_message(request, messages.ERROR, e)
321 8f5a3a06 Sofia Papagiannaki
    if request.method == 'POST':
322 8f5a3a06 Sofia Papagiannaki
        if form.is_valid():
323 18ffbee1 Sofia Papagiannaki
            user = form.save(commit=False)
324 8f5a3a06 Sofia Papagiannaki
            try:
325 8f5a3a06 Sofia Papagiannaki
                result = backend.handle_activation(user)
326 8f5a3a06 Sofia Papagiannaki
                status = messages.SUCCESS
327 18ffbee1 Sofia Papagiannaki
                message = result.message
328 18ffbee1 Sofia Papagiannaki
                user.save()
329 ca828a10 Sofia Papagiannaki
                if 'additional_email' in form.cleaned_data:
330 ca828a10 Sofia Papagiannaki
                    additional_email = form.cleaned_data['additional_email']
331 ca828a10 Sofia Papagiannaki
                    if additional_email != user.email:
332 ca828a10 Sofia Papagiannaki
                        user.additionalmail_set.create(email=additional_email)
333 8f5a3a06 Sofia Papagiannaki
                if user and user.is_active:
334 8f5a3a06 Sofia Papagiannaki
                    next = request.POST.get('next', '')
335 8f5a3a06 Sofia Papagiannaki
                    return prepare_response(request, user, next=next)
336 8f5a3a06 Sofia Papagiannaki
                messages.add_message(request, status, message)
337 8f5a3a06 Sofia Papagiannaki
                return render_response(on_success,
338 8f5a3a06 Sofia Papagiannaki
                                       context_instance=get_context(request, extra_context))
339 18ffbee1 Sofia Papagiannaki
            except SendMailError, e:
340 18ffbee1 Sofia Papagiannaki
                status = messages.ERROR
341 18ffbee1 Sofia Papagiannaki
                message = e.message
342 18ffbee1 Sofia Papagiannaki
                messages.add_message(request, status, message)
343 18ffbee1 Sofia Papagiannaki
            except BaseException, e:
344 18ffbee1 Sofia Papagiannaki
                status = messages.ERROR
345 18ffbee1 Sofia Papagiannaki
                message = _('Something went wrong.')
346 18ffbee1 Sofia Papagiannaki
                messages.add_message(request, status, message)
347 0a569195 Sofia Papagiannaki
                logger.exception(e)
348 8f5a3a06 Sofia Papagiannaki
    return render_response(template_name,
349 18ffbee1 Sofia Papagiannaki
                           signup_form = form,
350 0a569195 Sofia Papagiannaki
                           provider = provider,
351 890b0eaf Sofia Papagiannaki
                           context_instance=get_context(request, extra_context))
352 64cd4730 Antony Chazapis
353 890b0eaf Sofia Papagiannaki
@login_required
354 270dd48d Sofia Papagiannaki
@signed_terms_required
355 8f5a3a06 Sofia Papagiannaki
def feedback(request, template_name='im/feedback.html', email_template_name='im/feedback_mail.txt', extra_context={}):
356 890b0eaf Sofia Papagiannaki
    """
357 890b0eaf Sofia Papagiannaki
    Allows a user to send feedback.
358 176023aa Kostas Papadimitriou

359 890b0eaf Sofia Papagiannaki
    In case of GET request renders a form for providing the feedback information.
360 890b0eaf Sofia Papagiannaki
    In case of POST sends an email to support team.
361 176023aa Kostas Papadimitriou

362 2cbaacd5 Sofia Papagiannaki
    If the user isn't logged in, redirects to settings.LOGIN_URL.
363 176023aa Kostas Papadimitriou

364 890b0eaf Sofia Papagiannaki
    **Arguments**
365 176023aa Kostas Papadimitriou

366 890b0eaf Sofia Papagiannaki
    ``template_name``
367 890b0eaf Sofia Papagiannaki
        A custom template to use. This is optional; if not specified,
368 1e685275 Sofia Papagiannaki
        this will default to ``im/feedback.html``.
369 176023aa Kostas Papadimitriou

370 890b0eaf Sofia Papagiannaki
    ``extra_context``
371 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
372 176023aa Kostas Papadimitriou

373 890b0eaf Sofia Papagiannaki
    **Template:**
374 176023aa Kostas Papadimitriou

375 1e685275 Sofia Papagiannaki
    im/signup.html or ``template_name`` keyword argument.
376 176023aa Kostas Papadimitriou

377 890b0eaf Sofia Papagiannaki
    **Settings:**
378 176023aa Kostas Papadimitriou

379 92defad4 Sofia Papagiannaki
    * LOGIN_URL: login uri
380 2cbaacd5 Sofia Papagiannaki
    * ASTAKOS_DEFAULT_CONTACT_EMAIL: List of feedback recipients
381 890b0eaf Sofia Papagiannaki
    """
382 64cd4730 Antony Chazapis
    if request.method == 'GET':
383 890b0eaf Sofia Papagiannaki
        form = FeedbackForm()
384 890b0eaf Sofia Papagiannaki
    if request.method == 'POST':
385 890b0eaf Sofia Papagiannaki
        if not request.user:
386 890b0eaf Sofia Papagiannaki
            return HttpResponse('Unauthorized', status=401)
387 176023aa Kostas Papadimitriou
388 890b0eaf Sofia Papagiannaki
        form = FeedbackForm(request.POST)
389 890b0eaf Sofia Papagiannaki
        if form.is_valid():
390 8f5a3a06 Sofia Papagiannaki
            msg = form.cleaned_data['feedback_msg'],
391 8f5a3a06 Sofia Papagiannaki
            data = form.cleaned_data['feedback_data']
392 538ccdd5 Sofia Papagiannaki
            try:
393 8f5a3a06 Sofia Papagiannaki
                send_feedback(msg, data, request.user, email_template_name)
394 8f5a3a06 Sofia Papagiannaki
            except SendMailError, e:
395 8f5a3a06 Sofia Papagiannaki
                message = e.message
396 8f5a3a06 Sofia Papagiannaki
                status = messages.ERROR
397 8f5a3a06 Sofia Papagiannaki
            else:
398 538ccdd5 Sofia Papagiannaki
                message = _('Feedback successfully sent')
399 538ccdd5 Sofia Papagiannaki
                status = messages.SUCCESS
400 538ccdd5 Sofia Papagiannaki
            messages.add_message(request, status, message)
401 890b0eaf Sofia Papagiannaki
    return render_response(template_name,
402 8f5a3a06 Sofia Papagiannaki
                           feedback_form = form,
403 6b4f9fb2 Sofia Papagiannaki
                           context_instance = get_context(request, extra_context))
404 15efc749 Sofia Papagiannaki
405 7482228b Sofia Papagiannaki
def logout(request, template='registration/logged_out.html', extra_context={}):
406 63ecdd20 Sofia Papagiannaki
    """
407 7482228b Sofia Papagiannaki
    Wraps `django.contrib.auth.logout` and delete the cookie.
408 63ecdd20 Sofia Papagiannaki
    """
409 7482228b Sofia Papagiannaki
    auth_logout(request)
410 7482228b Sofia Papagiannaki
    response = HttpResponse()
411 28ff5b5d Antony Chazapis
    response.delete_cookie(COOKIE_NAME, path='/', domain=COOKIE_DOMAIN)
412 63ecdd20 Sofia Papagiannaki
    next = request.GET.get('next')
413 63ecdd20 Sofia Papagiannaki
    if next:
414 63ecdd20 Sofia Papagiannaki
        response['Location'] = next
415 63ecdd20 Sofia Papagiannaki
        response.status_code = 302
416 63ecdd20 Sofia Papagiannaki
        return response
417 0d02a287 Sofia Papagiannaki
    elif LOGOUT_NEXT:
418 0d02a287 Sofia Papagiannaki
        response['Location'] = LOGOUT_NEXT
419 0d02a287 Sofia Papagiannaki
        response.status_code = 301
420 0d02a287 Sofia Papagiannaki
        return response
421 0f4a8a68 Olga Brani
    messages.add_message(request, messages.SUCCESS, _('<p>You have successfully logged out.</p>'))
422 49df775e Sofia Papagiannaki
    context = get_context(request, extra_context)
423 49df775e Sofia Papagiannaki
    response.write(render_to_string(template, context_instance=context))
424 49df775e Sofia Papagiannaki
    return response
425 2126d85d Sofia Papagiannaki
426 683cf244 Sofia Papagiannaki
@transaction.commit_manually
427 d186cf77 Sofia Papagiannaki
def activate(request, email_template_name='im/welcome_email.txt', on_failure='im/signup.html'):
428 2126d85d Sofia Papagiannaki
    """
429 683cf244 Sofia Papagiannaki
    Activates the user identified by the ``auth`` request parameter, sends a welcome email
430 683cf244 Sofia Papagiannaki
    and renews the user token.
431 176023aa Kostas Papadimitriou

432 683cf244 Sofia Papagiannaki
    The view uses commit_manually decorator in order to ensure the user state will be updated
433 683cf244 Sofia Papagiannaki
    only if the email will be send successfully.
434 2126d85d Sofia Papagiannaki
    """
435 2126d85d Sofia Papagiannaki
    token = request.GET.get('auth')
436 2126d85d Sofia Papagiannaki
    next = request.GET.get('next')
437 2126d85d Sofia Papagiannaki
    try:
438 2126d85d Sofia Papagiannaki
        user = AstakosUser.objects.get(auth_token=token)
439 2126d85d Sofia Papagiannaki
    except AstakosUser.DoesNotExist:
440 683cf244 Sofia Papagiannaki
        return HttpResponseBadRequest(_('No such user'))
441 0a569195 Sofia Papagiannaki
    
442 0a569195 Sofia Papagiannaki
    try:
443 55a2cc0e root
        local_user = AstakosUser.objects.get(email=user.email, is_active=True)
444 0a569195 Sofia Papagiannaki
    except AstakosUser.DoesNotExist:
445 0a569195 Sofia Papagiannaki
        user.is_active = True
446 0a569195 Sofia Papagiannaki
        user.email_verified = True
447 27e26a41 Sofia Papagiannaki
        try:
448 27e26a41 Sofia Papagiannaki
            user.save()
449 27e26a41 Sofia Papagiannaki
        except ValidationError, e:
450 27e26a41 Sofia Papagiannaki
            return HttpResponseBadRequest(e)
451 0a569195 Sofia Papagiannaki
    else:
452 d186cf77 Sofia Papagiannaki
        # switch the existing account to shibboleth one
453 0a569195 Sofia Papagiannaki
        local_user.provider = 'shibboleth'
454 0a569195 Sofia Papagiannaki
        local_user.set_unusable_password()
455 0a569195 Sofia Papagiannaki
        local_user.third_party_identifier = user.third_party_identifier
456 27e26a41 Sofia Papagiannaki
        try:
457 27e26a41 Sofia Papagiannaki
            local_user.save()
458 27e26a41 Sofia Papagiannaki
        except ValidationError, e:
459 27e26a41 Sofia Papagiannaki
            return HttpResponseBadRequest(e)
460 0a569195 Sofia Papagiannaki
        user.delete()
461 0a569195 Sofia Papagiannaki
        user = local_user
462 0a569195 Sofia Papagiannaki
    
463 683cf244 Sofia Papagiannaki
    try:
464 683cf244 Sofia Papagiannaki
        send_greeting(user, email_template_name)
465 683cf244 Sofia Papagiannaki
        response = prepare_response(request, user, next, renew=True)
466 683cf244 Sofia Papagiannaki
        transaction.commit()
467 683cf244 Sofia Papagiannaki
        return response
468 0a569195 Sofia Papagiannaki
    except SendMailError, e:
469 8f5a3a06 Sofia Papagiannaki
        message = e.message
470 683cf244 Sofia Papagiannaki
        messages.add_message(request, messages.ERROR, message)
471 683cf244 Sofia Papagiannaki
        transaction.rollback()
472 d186cf77 Sofia Papagiannaki
        return render_response(on_failure)
473 18ffbee1 Sofia Papagiannaki
    except BaseException, e:
474 18ffbee1 Sofia Papagiannaki
        status = messages.ERROR
475 18ffbee1 Sofia Papagiannaki
        message = _('Something went wrong.')
476 d186cf77 Sofia Papagiannaki
        messages.add_message(request, messages.ERROR, message)
477 18ffbee1 Sofia Papagiannaki
        logger.exception(e)
478 18ffbee1 Sofia Papagiannaki
        transaction.rollback()
479 d186cf77 Sofia Papagiannaki
        return signup(request, on_failure)
480 270dd48d Sofia Papagiannaki
481 270dd48d Sofia Papagiannaki
def approval_terms(request, term_id=None, template_name='im/approval_terms.html', extra_context={}):
482 270dd48d Sofia Papagiannaki
    term = None
483 270dd48d Sofia Papagiannaki
    terms = None
484 270dd48d Sofia Papagiannaki
    if not term_id:
485 270dd48d Sofia Papagiannaki
        try:
486 270dd48d Sofia Papagiannaki
            term = ApprovalTerms.objects.order_by('-id')[0]
487 270dd48d Sofia Papagiannaki
        except IndexError:
488 270dd48d Sofia Papagiannaki
            pass
489 270dd48d Sofia Papagiannaki
    else:
490 270dd48d Sofia Papagiannaki
        try:
491 270dd48d Sofia Papagiannaki
             term = ApprovalTerms.objects.get(id=term_id)
492 270dd48d Sofia Papagiannaki
        except ApprovalTermDoesNotExist, e:
493 270dd48d Sofia Papagiannaki
            pass
494 176023aa Kostas Papadimitriou
495 270dd48d Sofia Papagiannaki
    if not term:
496 176023aa Kostas Papadimitriou
        return HttpResponseRedirect(reverse('astakos.im.views.index'))
497 270dd48d Sofia Papagiannaki
    f = open(term.location, 'r')
498 270dd48d Sofia Papagiannaki
    terms = f.read()
499 176023aa Kostas Papadimitriou
500 270dd48d Sofia Papagiannaki
    if request.method == 'POST':
501 270dd48d Sofia Papagiannaki
        next = request.POST.get('next')
502 270dd48d Sofia Papagiannaki
        if not next:
503 8f5a3a06 Sofia Papagiannaki
            next = reverse('astakos.im.views.index')
504 270dd48d Sofia Papagiannaki
        form = SignApprovalTermsForm(request.POST, instance=request.user)
505 270dd48d Sofia Papagiannaki
        if not form.is_valid():
506 270dd48d Sofia Papagiannaki
            return render_response(template_name,
507 270dd48d Sofia Papagiannaki
                           terms = terms,
508 8f5a3a06 Sofia Papagiannaki
                           approval_terms_form = form,
509 270dd48d Sofia Papagiannaki
                           context_instance = get_context(request, extra_context))
510 270dd48d Sofia Papagiannaki
        user = form.save()
511 270dd48d Sofia Papagiannaki
        return HttpResponseRedirect(next)
512 270dd48d Sofia Papagiannaki
    else:
513 586967c0 Sofia Papagiannaki
        form = None
514 1662ac2d Sofia Papagiannaki
        if request.user.is_authenticated() and not request.user.signed_terms():
515 586967c0 Sofia Papagiannaki
            form = SignApprovalTermsForm(instance=request.user)
516 270dd48d Sofia Papagiannaki
        return render_response(template_name,
517 270dd48d Sofia Papagiannaki
                               terms = terms,
518 8f5a3a06 Sofia Papagiannaki
                               approval_terms_form = form,
519 270dd48d Sofia Papagiannaki
                               context_instance = get_context(request, extra_context))
520 270dd48d Sofia Papagiannaki
521 270dd48d Sofia Papagiannaki
@signed_terms_required
522 270dd48d Sofia Papagiannaki
def change_password(request):
523 176023aa Kostas Papadimitriou
    return password_change(request, post_change_redirect=reverse('astakos.im.views.edit_profile'))
524 49790d9d Sofia Papagiannaki
525 49790d9d Sofia Papagiannaki
@transaction.commit_manually
526 49790d9d Sofia Papagiannaki
def change_email(request, activation_key=None,
527 49790d9d Sofia Papagiannaki
                 email_template_name='registration/email_change_email.txt',
528 49790d9d Sofia Papagiannaki
                 form_template_name='registration/email_change_form.html',
529 49790d9d Sofia Papagiannaki
                 confirm_template_name='registration/email_change_done.html',
530 49790d9d Sofia Papagiannaki
                 extra_context={}):
531 49790d9d Sofia Papagiannaki
    if activation_key:
532 49790d9d Sofia Papagiannaki
        try:
533 49790d9d Sofia Papagiannaki
            user = EmailChange.objects.change_email(activation_key)
534 49790d9d Sofia Papagiannaki
            if request.user.is_authenticated() and request.user == user:
535 49790d9d Sofia Papagiannaki
                msg = _('Email changed successfully.')
536 49790d9d Sofia Papagiannaki
                messages.add_message(request, messages.SUCCESS, msg)
537 49790d9d Sofia Papagiannaki
                auth_logout(request)
538 49790d9d Sofia Papagiannaki
                response = prepare_response(request, user)
539 49790d9d Sofia Papagiannaki
                transaction.commit()
540 49790d9d Sofia Papagiannaki
                return response
541 49790d9d Sofia Papagiannaki
        except ValueError, e:
542 49790d9d Sofia Papagiannaki
            messages.add_message(request, messages.ERROR, e)
543 49790d9d Sofia Papagiannaki
        return render_response(confirm_template_name,
544 49790d9d Sofia Papagiannaki
                               modified_user = user if 'user' in locals() else None,
545 49790d9d Sofia Papagiannaki
                               context_instance = get_context(request,
546 49790d9d Sofia Papagiannaki
                                                              extra_context))
547 49790d9d Sofia Papagiannaki
    
548 49790d9d Sofia Papagiannaki
    if not request.user.is_authenticated():
549 49790d9d Sofia Papagiannaki
        path = quote(request.get_full_path())
550 49790d9d Sofia Papagiannaki
        url = request.build_absolute_uri(reverse('astakos.im.views.index'))
551 49790d9d Sofia Papagiannaki
        return HttpResponseRedirect(url + '?next=' + path)
552 49790d9d Sofia Papagiannaki
    form = EmailChangeForm(request.POST or None)
553 49790d9d Sofia Papagiannaki
    if request.method == 'POST' and form.is_valid():
554 49790d9d Sofia Papagiannaki
        try:
555 49790d9d Sofia Papagiannaki
            ec = form.save(email_template_name, request)
556 49790d9d Sofia Papagiannaki
        except SendMailError, e:
557 49790d9d Sofia Papagiannaki
            status = messages.ERROR
558 49790d9d Sofia Papagiannaki
            msg = e
559 49790d9d Sofia Papagiannaki
            transaction.rollback()
560 49790d9d Sofia Papagiannaki
        except IntegrityError, e:
561 49790d9d Sofia Papagiannaki
            status = messages.ERROR
562 49790d9d Sofia Papagiannaki
            msg = _('There is already a pending change email request.')
563 49790d9d Sofia Papagiannaki
        else:
564 49790d9d Sofia Papagiannaki
            status = messages.SUCCESS
565 49790d9d Sofia Papagiannaki
            msg = _('Change email request has been registered succefully.\
566 49790d9d Sofia Papagiannaki
                    You are going to receive a verification email in the new address.')
567 49790d9d Sofia Papagiannaki
            transaction.commit()
568 49790d9d Sofia Papagiannaki
        messages.add_message(request, status, msg)
569 49790d9d Sofia Papagiannaki
    return render_response(form_template_name,
570 49790d9d Sofia Papagiannaki
                           form = form,
571 49790d9d Sofia Papagiannaki
                           context_instance = get_context(request,
572 2bc206d4 Kostas Papadimitriou
                                                          extra_context))