Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / views.py @ 217994f8

History | View | Annotate | Download (22.9 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 dda2e499 Sofia Papagiannaki
from django.views.decorators.http import require_http_methods
56 64cd4730 Antony Chazapis
57 270dd48d Sofia Papagiannaki
from astakos.im.models import AstakosUser, Invitation, ApprovalTerms
58 4e30244e Sofia Papagiannaki
from astakos.im.activation_backends import get_backend, SimpleBackend
59 217994f8 Sofia Papagiannaki
from astakos.im.util import (
60 217994f8 Sofia Papagiannaki
    get_context, prepare_response, set_cookie, get_query, restrict_next
61 217994f8 Sofia Papagiannaki
)
62 15efc749 Sofia Papagiannaki
from astakos.im.forms import *
63 ef20ea07 Sofia Papagiannaki
from astakos.im.functions import (send_greeting, send_feedback, SendMailError,
64 ef20ea07 Sofia Papagiannaki
    invite as invite_func, logout as auth_logout, activate as activate_func
65 ef20ea07 Sofia Papagiannaki
)
66 ef20ea07 Sofia Papagiannaki
from astakos.im.settings import (DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL,
67 ef20ea07 Sofia Papagiannaki
    COOKIE_NAME, COOKIE_DOMAIN, IM_MODULES, SITENAME, LOGOUT_NEXT, LOGGING_LEVEL
68 ef20ea07 Sofia Papagiannaki
)
69 64cd4730 Antony Chazapis
70 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
71 e015e9e6 Sofia Papagiannaki
72 c301698f Sofia Papagiannaki
def render_response(template, tab=None, status=200, reset_cookie=False, context_instance=None, **kwargs):
73 890b0eaf Sofia Papagiannaki
    """
74 890b0eaf Sofia Papagiannaki
    Calls ``django.template.loader.render_to_string`` with an additional ``tab``
75 890b0eaf Sofia Papagiannaki
    keyword argument and returns an ``django.http.HttpResponse`` with the
76 890b0eaf Sofia Papagiannaki
    specified ``status``.
77 890b0eaf Sofia Papagiannaki
    """
78 64cd4730 Antony Chazapis
    if tab is None:
79 881c856c Sofia Papagiannaki
        tab = template.partition('_')[0].partition('.html')[0]
80 64cd4730 Antony Chazapis
    kwargs.setdefault('tab', tab)
81 0905ccd2 Sofia Papagiannaki
    html = render_to_string(template, kwargs, context_instance=context_instance)
82 c301698f Sofia Papagiannaki
    response = HttpResponse(html, status=status)
83 c301698f Sofia Papagiannaki
    if reset_cookie:
84 c301698f Sofia Papagiannaki
        set_cookie(response, context_instance['request'].user)
85 c301698f Sofia Papagiannaki
    return response
86 64cd4730 Antony Chazapis
87 63ecdd20 Sofia Papagiannaki
88 63ecdd20 Sofia Papagiannaki
def requires_anonymous(func):
89 63ecdd20 Sofia Papagiannaki
    """
90 270dd48d Sofia Papagiannaki
    Decorator checkes whether the request.user is not Anonymous and in that case
91 7482228b Sofia Papagiannaki
    redirects to `logout`.
92 63ecdd20 Sofia Papagiannaki
    """
93 63ecdd20 Sofia Papagiannaki
    @wraps(func)
94 63ecdd20 Sofia Papagiannaki
    def wrapper(request, *args):
95 63ecdd20 Sofia Papagiannaki
        if not request.user.is_anonymous():
96 63ecdd20 Sofia Papagiannaki
            next = urlencode({'next': request.build_absolute_uri()})
97 270dd48d Sofia Papagiannaki
            logout_uri = reverse(logout) + '?' + next
98 270dd48d Sofia Papagiannaki
            return HttpResponseRedirect(logout_uri)
99 63ecdd20 Sofia Papagiannaki
        return func(request, *args)
100 63ecdd20 Sofia Papagiannaki
    return wrapper
101 63ecdd20 Sofia Papagiannaki
102 270dd48d Sofia Papagiannaki
def signed_terms_required(func):
103 270dd48d Sofia Papagiannaki
    """
104 270dd48d Sofia Papagiannaki
    Decorator checkes whether the request.user is Anonymous and in that case
105 270dd48d Sofia Papagiannaki
    redirects to `logout`.
106 270dd48d Sofia Papagiannaki
    """
107 270dd48d Sofia Papagiannaki
    @wraps(func)
108 270dd48d Sofia Papagiannaki
    def wrapper(request, *args, **kwargs):
109 1662ac2d Sofia Papagiannaki
        if request.user.is_authenticated() and not request.user.signed_terms():
110 270dd48d Sofia Papagiannaki
            params = urlencode({'next': request.build_absolute_uri(),
111 270dd48d Sofia Papagiannaki
                              'show_form':''})
112 270dd48d Sofia Papagiannaki
            terms_uri = reverse('latest_terms') + '?' + params
113 270dd48d Sofia Papagiannaki
            return HttpResponseRedirect(terms_uri)
114 270dd48d Sofia Papagiannaki
        return func(request, *args, **kwargs)
115 270dd48d Sofia Papagiannaki
    return wrapper
116 270dd48d Sofia Papagiannaki
117 dda2e499 Sofia Papagiannaki
@require_http_methods(["GET", "POST"])
118 270dd48d Sofia Papagiannaki
@signed_terms_required
119 1e685275 Sofia Papagiannaki
def index(request, login_template_name='im/login.html', profile_template_name='im/profile.html', extra_context={}):
120 890b0eaf Sofia Papagiannaki
    """
121 dcf55476 Sofia Papagiannaki
    If there is logged on user renders the profile page otherwise renders login page.
122 176023aa Kostas Papadimitriou

123 890b0eaf Sofia Papagiannaki
    **Arguments**
124 176023aa Kostas Papadimitriou

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

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

133 890b0eaf Sofia Papagiannaki
    ``extra_context``
134 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
135 176023aa Kostas Papadimitriou

136 890b0eaf Sofia Papagiannaki
    **Template:**
137 176023aa Kostas Papadimitriou

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

140 890b0eaf Sofia Papagiannaki
    """
141 dcf55476 Sofia Papagiannaki
    template_name = login_template_name
142 dcf55476 Sofia Papagiannaki
    if request.user.is_authenticated():
143 f534fb96 Sofia Papagiannaki
        return HttpResponseRedirect(reverse('astakos.im.views.edit_profile'))
144 ef20ea07 Sofia Papagiannaki
    
145 ef20ea07 Sofia Papagiannaki
    return render_response(
146 ef20ea07 Sofia Papagiannaki
        template_name,
147 ef20ea07 Sofia Papagiannaki
        login_form = LoginForm(request=request),
148 ef20ea07 Sofia Papagiannaki
        context_instance = get_context(request, extra_context)
149 ef20ea07 Sofia Papagiannaki
    )
150 64cd4730 Antony Chazapis
151 dda2e499 Sofia Papagiannaki
@require_http_methods(["GET", "POST"])
152 890b0eaf Sofia Papagiannaki
@login_required
153 270dd48d Sofia Papagiannaki
@signed_terms_required
154 890b0eaf Sofia Papagiannaki
@transaction.commit_manually
155 1e685275 Sofia Papagiannaki
def invite(request, template_name='im/invitations.html', extra_context={}):
156 890b0eaf Sofia Papagiannaki
    """
157 890b0eaf Sofia Papagiannaki
    Allows a user to invite somebody else.
158 176023aa Kostas Papadimitriou

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

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

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

168 890b0eaf Sofia Papagiannaki
    **Arguments**
169 176023aa Kostas Papadimitriou

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

174 890b0eaf Sofia Papagiannaki
    ``extra_context``
175 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
176 176023aa Kostas Papadimitriou

177 890b0eaf Sofia Papagiannaki
    **Template:**
178 176023aa Kostas Papadimitriou

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

181 890b0eaf Sofia Papagiannaki
    **Settings:**
182 176023aa Kostas Papadimitriou

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

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

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

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

243 890b0eaf Sofia Papagiannaki
    **Arguments**
244 176023aa Kostas Papadimitriou

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

249 890b0eaf Sofia Papagiannaki
    ``extra_context``
250 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
251 176023aa Kostas Papadimitriou

252 890b0eaf Sofia Papagiannaki
    **Template:**
253 176023aa Kostas Papadimitriou

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

256 92defad4 Sofia Papagiannaki
    **Settings:**
257 176023aa Kostas Papadimitriou

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

260 92defad4 Sofia Papagiannaki
    * LOGIN_URL: login uri
261 890b0eaf Sofia Papagiannaki
    """
262 15efc749 Sofia Papagiannaki
    form = ProfileForm(instance=request.user)
263 15efc749 Sofia Papagiannaki
    extra_context['next'] = request.GET.get('next')
264 c301698f Sofia Papagiannaki
    reset_cookie = False
265 64cd4730 Antony Chazapis
    if request.method == 'POST':
266 15efc749 Sofia Papagiannaki
        form = ProfileForm(request.POST, instance=request.user)
267 890b0eaf Sofia Papagiannaki
        if form.is_valid():
268 64cd4730 Antony Chazapis
            try:
269 c301698f Sofia Papagiannaki
                prev_token = request.user.auth_token
270 c301698f Sofia Papagiannaki
                user = form.save()
271 c301698f Sofia Papagiannaki
                reset_cookie = user.auth_token != prev_token
272 c301698f Sofia Papagiannaki
                form = ProfileForm(instance=user)
273 217994f8 Sofia Papagiannaki
                next = restrict_next(
274 217994f8 Sofia Papagiannaki
                    request.POST.get('next'),
275 217994f8 Sofia Papagiannaki
                    domain=COOKIE_DOMAIN
276 217994f8 Sofia Papagiannaki
                )
277 1a3675a0 Sofia Papagiannaki
                if next:
278 1a3675a0 Sofia Papagiannaki
                    return redirect(next)
279 0f4a8a68 Olga Brani
                msg = _('<p>Profile has been updated successfully</p>')
280 890b0eaf Sofia Papagiannaki
                messages.add_message(request, messages.SUCCESS, msg)
281 890b0eaf Sofia Papagiannaki
            except ValueError, ve:
282 890b0eaf Sofia Papagiannaki
                messages.add_message(request, messages.ERROR, ve)
283 23447441 Sofia Papagiannaki
    elif request.method == "GET":
284 23447441 Sofia Papagiannaki
        request.user.is_verified = True
285 23447441 Sofia Papagiannaki
        request.user.save()
286 0905ccd2 Sofia Papagiannaki
    return render_response(template_name,
287 c301698f Sofia Papagiannaki
                           reset_cookie = reset_cookie,
288 8f5a3a06 Sofia Papagiannaki
                           profile_form = form,
289 0905ccd2 Sofia Papagiannaki
                           context_instance = get_context(request,
290 c301698f Sofia Papagiannaki
                                                          extra_context))
291 64cd4730 Antony Chazapis
292 dda2e499 Sofia Papagiannaki
@require_http_methods(["GET", "POST"])
293 8f5a3a06 Sofia Papagiannaki
def signup(request, template_name='im/signup.html', on_success='im/signup_complete.html', extra_context={}, backend=None):
294 890b0eaf Sofia Papagiannaki
    """
295 890b0eaf Sofia Papagiannaki
    Allows a user to create a local account.
296 176023aa Kostas Papadimitriou

297 b669d9c0 Sofia Papagiannaki
    In case of GET request renders a form for entering the user information.
298 890b0eaf Sofia Papagiannaki
    In case of POST handles the signup.
299 176023aa Kostas Papadimitriou

300 890b0eaf Sofia Papagiannaki
    The user activation will be delegated to the backend specified by the ``backend`` keyword argument
301 8f5a3a06 Sofia Papagiannaki
    if present, otherwise to the ``astakos.im.activation_backends.InvitationBackend``
302 8f5a3a06 Sofia Papagiannaki
    if settings.ASTAKOS_INVITATIONS_ENABLED is True or ``astakos.im.activation_backends.SimpleBackend`` if not
303 8f5a3a06 Sofia Papagiannaki
    (see activation_backends);
304 890b0eaf Sofia Papagiannaki
    
305 b669d9c0 Sofia Papagiannaki
    Upon successful user creation, if ``next`` url parameter is present the user is redirected there
306 890b0eaf Sofia Papagiannaki
    otherwise renders the same page with a success message.
307 64cd4730 Antony Chazapis
    
308 8f5a3a06 Sofia Papagiannaki
    On unsuccessful creation, renders ``template_name`` with an error message.
309 890b0eaf Sofia Papagiannaki
    
310 890b0eaf Sofia Papagiannaki
    **Arguments**
311 890b0eaf Sofia Papagiannaki
    
312 8f5a3a06 Sofia Papagiannaki
    ``template_name``
313 8f5a3a06 Sofia Papagiannaki
        A custom template to render. This is optional;
314 1e685275 Sofia Papagiannaki
        if not specified, this will default to ``im/signup.html``.
315 176023aa Kostas Papadimitriou

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

320 890b0eaf Sofia Papagiannaki
    ``extra_context``
321 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
322 176023aa Kostas Papadimitriou

323 890b0eaf Sofia Papagiannaki
    **Template:**
324 890b0eaf Sofia Papagiannaki
    
325 8f5a3a06 Sofia Papagiannaki
    im/signup.html or ``template_name`` keyword argument.
326 1e685275 Sofia Papagiannaki
    im/signup_complete.html or ``on_success`` keyword argument. 
327 890b0eaf Sofia Papagiannaki
    """
328 0d02a287 Sofia Papagiannaki
    if request.user.is_authenticated():
329 7fa28b5e Sofia Papagiannaki
        return HttpResponseRedirect(reverse('astakos.im.views.edit_profile'))
330 4e30244e Sofia Papagiannaki
    
331 0a569195 Sofia Papagiannaki
    provider = get_query(request).get('provider', 'local')
332 890b0eaf Sofia Papagiannaki
    try:
333 18ffbee1 Sofia Papagiannaki
        if not backend:
334 18ffbee1 Sofia Papagiannaki
            backend = get_backend(request)
335 8f5a3a06 Sofia Papagiannaki
        form = backend.get_signup_form(provider)
336 0a569195 Sofia Papagiannaki
    except Exception, e:
337 4e30244e Sofia Papagiannaki
        form = SimpleBackend(request).get_signup_form(provider)
338 18ffbee1 Sofia Papagiannaki
        messages.add_message(request, messages.ERROR, e)
339 8f5a3a06 Sofia Papagiannaki
    if request.method == 'POST':
340 8f5a3a06 Sofia Papagiannaki
        if form.is_valid():
341 18ffbee1 Sofia Papagiannaki
            user = form.save(commit=False)
342 8f5a3a06 Sofia Papagiannaki
            try:
343 8f5a3a06 Sofia Papagiannaki
                result = backend.handle_activation(user)
344 8f5a3a06 Sofia Papagiannaki
                status = messages.SUCCESS
345 18ffbee1 Sofia Papagiannaki
                message = result.message
346 18ffbee1 Sofia Papagiannaki
                user.save()
347 ca828a10 Sofia Papagiannaki
                if 'additional_email' in form.cleaned_data:
348 ca828a10 Sofia Papagiannaki
                    additional_email = form.cleaned_data['additional_email']
349 ca828a10 Sofia Papagiannaki
                    if additional_email != user.email:
350 ca828a10 Sofia Papagiannaki
                        user.additionalmail_set.create(email=additional_email)
351 b669d9c0 Sofia Papagiannaki
                        msg = 'Additional email: %s saved for user %s.' % (additional_email, user.email)
352 b669d9c0 Sofia Papagiannaki
                        logger._log(LOGGING_LEVEL, msg, [])
353 8f5a3a06 Sofia Papagiannaki
                if user and user.is_active:
354 8f5a3a06 Sofia Papagiannaki
                    next = request.POST.get('next', '')
355 8f5a3a06 Sofia Papagiannaki
                    return prepare_response(request, user, next=next)
356 8f5a3a06 Sofia Papagiannaki
                messages.add_message(request, status, message)
357 8f5a3a06 Sofia Papagiannaki
                return render_response(on_success,
358 8f5a3a06 Sofia Papagiannaki
                                       context_instance=get_context(request, extra_context))
359 18ffbee1 Sofia Papagiannaki
            except SendMailError, e:
360 18ffbee1 Sofia Papagiannaki
                status = messages.ERROR
361 18ffbee1 Sofia Papagiannaki
                message = e.message
362 18ffbee1 Sofia Papagiannaki
                messages.add_message(request, status, message)
363 18ffbee1 Sofia Papagiannaki
            except BaseException, e:
364 678b2236 Sofia Papagiannaki
                logger.exception(e)
365 18ffbee1 Sofia Papagiannaki
                status = messages.ERROR
366 18ffbee1 Sofia Papagiannaki
                message = _('Something went wrong.')
367 18ffbee1 Sofia Papagiannaki
                messages.add_message(request, status, message)
368 0a569195 Sofia Papagiannaki
                logger.exception(e)
369 8f5a3a06 Sofia Papagiannaki
    return render_response(template_name,
370 18ffbee1 Sofia Papagiannaki
                           signup_form = form,
371 0a569195 Sofia Papagiannaki
                           provider = provider,
372 890b0eaf Sofia Papagiannaki
                           context_instance=get_context(request, extra_context))
373 64cd4730 Antony Chazapis
374 dda2e499 Sofia Papagiannaki
@require_http_methods(["GET", "POST"])
375 890b0eaf Sofia Papagiannaki
@login_required
376 270dd48d Sofia Papagiannaki
@signed_terms_required
377 8f5a3a06 Sofia Papagiannaki
def feedback(request, template_name='im/feedback.html', email_template_name='im/feedback_mail.txt', extra_context={}):
378 890b0eaf Sofia Papagiannaki
    """
379 890b0eaf Sofia Papagiannaki
    Allows a user to send feedback.
380 176023aa Kostas Papadimitriou

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

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

386 890b0eaf Sofia Papagiannaki
    **Arguments**
387 176023aa Kostas Papadimitriou

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

392 890b0eaf Sofia Papagiannaki
    ``extra_context``
393 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
394 176023aa Kostas Papadimitriou

395 890b0eaf Sofia Papagiannaki
    **Template:**
396 176023aa Kostas Papadimitriou

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

399 890b0eaf Sofia Papagiannaki
    **Settings:**
400 176023aa Kostas Papadimitriou

401 92defad4 Sofia Papagiannaki
    * LOGIN_URL: login uri
402 2cbaacd5 Sofia Papagiannaki
    * ASTAKOS_DEFAULT_CONTACT_EMAIL: List of feedback recipients
403 890b0eaf Sofia Papagiannaki
    """
404 64cd4730 Antony Chazapis
    if request.method == 'GET':
405 890b0eaf Sofia Papagiannaki
        form = FeedbackForm()
406 890b0eaf Sofia Papagiannaki
    if request.method == 'POST':
407 890b0eaf Sofia Papagiannaki
        if not request.user:
408 890b0eaf Sofia Papagiannaki
            return HttpResponse('Unauthorized', status=401)
409 176023aa Kostas Papadimitriou
410 890b0eaf Sofia Papagiannaki
        form = FeedbackForm(request.POST)
411 890b0eaf Sofia Papagiannaki
        if form.is_valid():
412 e9083112 Sofia Papagiannaki
            msg = form.cleaned_data['feedback_msg']
413 8f5a3a06 Sofia Papagiannaki
            data = form.cleaned_data['feedback_data']
414 538ccdd5 Sofia Papagiannaki
            try:
415 8f5a3a06 Sofia Papagiannaki
                send_feedback(msg, data, request.user, email_template_name)
416 8f5a3a06 Sofia Papagiannaki
            except SendMailError, e:
417 8f5a3a06 Sofia Papagiannaki
                message = e.message
418 8f5a3a06 Sofia Papagiannaki
                status = messages.ERROR
419 8f5a3a06 Sofia Papagiannaki
            else:
420 538ccdd5 Sofia Papagiannaki
                message = _('Feedback successfully sent')
421 538ccdd5 Sofia Papagiannaki
                status = messages.SUCCESS
422 538ccdd5 Sofia Papagiannaki
            messages.add_message(request, status, message)
423 890b0eaf Sofia Papagiannaki
    return render_response(template_name,
424 8f5a3a06 Sofia Papagiannaki
                           feedback_form = form,
425 6b4f9fb2 Sofia Papagiannaki
                           context_instance = get_context(request, extra_context))
426 15efc749 Sofia Papagiannaki
427 217994f8 Sofia Papagiannaki
@require_http_methods(["GET"])
428 7482228b Sofia Papagiannaki
def logout(request, template='registration/logged_out.html', extra_context={}):
429 63ecdd20 Sofia Papagiannaki
    """
430 7482228b Sofia Papagiannaki
    Wraps `django.contrib.auth.logout` and delete the cookie.
431 63ecdd20 Sofia Papagiannaki
    """
432 7482228b Sofia Papagiannaki
    response = HttpResponse()
433 06828466 Sofia Papagiannaki
    if request.user.is_authenticated():
434 06828466 Sofia Papagiannaki
        email = request.user.email
435 06828466 Sofia Papagiannaki
        auth_logout(request)
436 06828466 Sofia Papagiannaki
        response.delete_cookie(COOKIE_NAME, path='/', domain=COOKIE_DOMAIN)
437 06828466 Sofia Papagiannaki
        msg = 'Cookie deleted for %s' % email
438 06828466 Sofia Papagiannaki
        logger._log(LOGGING_LEVEL, msg, [])
439 217994f8 Sofia Papagiannaki
    next = restrict_next(
440 217994f8 Sofia Papagiannaki
        request.GET.get('next'),
441 217994f8 Sofia Papagiannaki
        domain=COOKIE_DOMAIN
442 217994f8 Sofia Papagiannaki
    )
443 63ecdd20 Sofia Papagiannaki
    if next:
444 63ecdd20 Sofia Papagiannaki
        response['Location'] = next
445 63ecdd20 Sofia Papagiannaki
        response.status_code = 302
446 63ecdd20 Sofia Papagiannaki
        return response
447 0d02a287 Sofia Papagiannaki
    elif LOGOUT_NEXT:
448 0d02a287 Sofia Papagiannaki
        response['Location'] = LOGOUT_NEXT
449 0d02a287 Sofia Papagiannaki
        response.status_code = 301
450 0d02a287 Sofia Papagiannaki
        return response
451 0f4a8a68 Olga Brani
    messages.add_message(request, messages.SUCCESS, _('<p>You have successfully logged out.</p>'))
452 49df775e Sofia Papagiannaki
    context = get_context(request, extra_context)
453 49df775e Sofia Papagiannaki
    response.write(render_to_string(template, context_instance=context))
454 49df775e Sofia Papagiannaki
    return response
455 2126d85d Sofia Papagiannaki
456 dda2e499 Sofia Papagiannaki
@require_http_methods(["GET", "POST"])
457 683cf244 Sofia Papagiannaki
@transaction.commit_manually
458 3e295388 Sofia Papagiannaki
def activate(request, greeting_email_template_name='im/welcome_email.txt', helpdesk_email_template_name='im/helpdesk_notification.txt'):
459 2126d85d Sofia Papagiannaki
    """
460 683cf244 Sofia Papagiannaki
    Activates the user identified by the ``auth`` request parameter, sends a welcome email
461 683cf244 Sofia Papagiannaki
    and renews the user token.
462 176023aa Kostas Papadimitriou

463 683cf244 Sofia Papagiannaki
    The view uses commit_manually decorator in order to ensure the user state will be updated
464 683cf244 Sofia Papagiannaki
    only if the email will be send successfully.
465 2126d85d Sofia Papagiannaki
    """
466 2126d85d Sofia Papagiannaki
    token = request.GET.get('auth')
467 2126d85d Sofia Papagiannaki
    next = request.GET.get('next')
468 2126d85d Sofia Papagiannaki
    try:
469 2126d85d Sofia Papagiannaki
        user = AstakosUser.objects.get(auth_token=token)
470 2126d85d Sofia Papagiannaki
    except AstakosUser.DoesNotExist:
471 683cf244 Sofia Papagiannaki
        return HttpResponseBadRequest(_('No such user'))
472 0a569195 Sofia Papagiannaki
    
473 d1757ca7 Sofia Papagiannaki
    if user.is_active:
474 23b9b72f Sofia Papagiannaki
        message = _('Account already active.')
475 d1757ca7 Sofia Papagiannaki
        messages.add_message(request, messages.ERROR, message)
476 23b9b72f Sofia Papagiannaki
        return index(request)
477 d1757ca7 Sofia Papagiannaki
    
478 0a569195 Sofia Papagiannaki
    try:
479 ef20ea07 Sofia Papagiannaki
        activate_func(user, greeting_email_template_name, helpdesk_email_template_name, verify_email=True)
480 ef20ea07 Sofia Papagiannaki
        response = prepare_response(request, user, next, renew=True)
481 ef20ea07 Sofia Papagiannaki
        transaction.commit()
482 ef20ea07 Sofia Papagiannaki
        return response
483 ef20ea07 Sofia Papagiannaki
    except SendMailError, e:
484 ef20ea07 Sofia Papagiannaki
        message = e.message
485 ef20ea07 Sofia Papagiannaki
        messages.add_message(request, messages.ERROR, message)
486 ef20ea07 Sofia Papagiannaki
        transaction.rollback()
487 ef20ea07 Sofia Papagiannaki
        return index(request)
488 ef20ea07 Sofia Papagiannaki
    except BaseException, e:
489 ef20ea07 Sofia Papagiannaki
        status = messages.ERROR
490 ef20ea07 Sofia Papagiannaki
        message = _('Something went wrong.')
491 ef20ea07 Sofia Papagiannaki
        messages.add_message(request, messages.ERROR, message)
492 ef20ea07 Sofia Papagiannaki
        logger.exception(e)
493 ef20ea07 Sofia Papagiannaki
        transaction.rollback()
494 ef20ea07 Sofia Papagiannaki
        return index(request)
495 270dd48d Sofia Papagiannaki
496 dda2e499 Sofia Papagiannaki
@require_http_methods(["GET", "POST"])
497 270dd48d Sofia Papagiannaki
def approval_terms(request, term_id=None, template_name='im/approval_terms.html', extra_context={}):
498 270dd48d Sofia Papagiannaki
    term = None
499 270dd48d Sofia Papagiannaki
    terms = None
500 270dd48d Sofia Papagiannaki
    if not term_id:
501 270dd48d Sofia Papagiannaki
        try:
502 270dd48d Sofia Papagiannaki
            term = ApprovalTerms.objects.order_by('-id')[0]
503 270dd48d Sofia Papagiannaki
        except IndexError:
504 270dd48d Sofia Papagiannaki
            pass
505 270dd48d Sofia Papagiannaki
    else:
506 270dd48d Sofia Papagiannaki
        try:
507 270dd48d Sofia Papagiannaki
             term = ApprovalTerms.objects.get(id=term_id)
508 270dd48d Sofia Papagiannaki
        except ApprovalTermDoesNotExist, e:
509 270dd48d Sofia Papagiannaki
            pass
510 176023aa Kostas Papadimitriou
511 270dd48d Sofia Papagiannaki
    if not term:
512 176023aa Kostas Papadimitriou
        return HttpResponseRedirect(reverse('astakos.im.views.index'))
513 270dd48d Sofia Papagiannaki
    f = open(term.location, 'r')
514 270dd48d Sofia Papagiannaki
    terms = f.read()
515 176023aa Kostas Papadimitriou
516 270dd48d Sofia Papagiannaki
    if request.method == 'POST':
517 217994f8 Sofia Papagiannaki
        next = restrict_next(
518 217994f8 Sofia Papagiannaki
            request.POST.get('next'),
519 217994f8 Sofia Papagiannaki
            domain=COOKIE_DOMAIN
520 217994f8 Sofia Papagiannaki
        )
521 270dd48d Sofia Papagiannaki
        if not next:
522 8f5a3a06 Sofia Papagiannaki
            next = reverse('astakos.im.views.index')
523 270dd48d Sofia Papagiannaki
        form = SignApprovalTermsForm(request.POST, instance=request.user)
524 270dd48d Sofia Papagiannaki
        if not form.is_valid():
525 270dd48d Sofia Papagiannaki
            return render_response(template_name,
526 270dd48d Sofia Papagiannaki
                           terms = terms,
527 8f5a3a06 Sofia Papagiannaki
                           approval_terms_form = form,
528 270dd48d Sofia Papagiannaki
                           context_instance = get_context(request, extra_context))
529 270dd48d Sofia Papagiannaki
        user = form.save()
530 270dd48d Sofia Papagiannaki
        return HttpResponseRedirect(next)
531 270dd48d Sofia Papagiannaki
    else:
532 586967c0 Sofia Papagiannaki
        form = None
533 1662ac2d Sofia Papagiannaki
        if request.user.is_authenticated() and not request.user.signed_terms():
534 586967c0 Sofia Papagiannaki
            form = SignApprovalTermsForm(instance=request.user)
535 270dd48d Sofia Papagiannaki
        return render_response(template_name,
536 270dd48d Sofia Papagiannaki
                               terms = terms,
537 8f5a3a06 Sofia Papagiannaki
                               approval_terms_form = form,
538 270dd48d Sofia Papagiannaki
                               context_instance = get_context(request, extra_context))
539 270dd48d Sofia Papagiannaki
540 dda2e499 Sofia Papagiannaki
@require_http_methods(["GET", "POST"])
541 270dd48d Sofia Papagiannaki
@signed_terms_required
542 270dd48d Sofia Papagiannaki
def change_password(request):
543 1039bab1 Sofia Papagiannaki
    return password_change(request,
544 1039bab1 Sofia Papagiannaki
                            post_change_redirect=reverse('astakos.im.views.edit_profile'),
545 1039bab1 Sofia Papagiannaki
                            password_change_form=ExtendedPasswordChangeForm)
546 49790d9d Sofia Papagiannaki
547 dda2e499 Sofia Papagiannaki
@require_http_methods(["GET", "POST"])
548 dda2e499 Sofia Papagiannaki
@login_required
549 dda2e499 Sofia Papagiannaki
@signed_terms_required
550 49790d9d Sofia Papagiannaki
@transaction.commit_manually
551 49790d9d Sofia Papagiannaki
def change_email(request, activation_key=None,
552 49790d9d Sofia Papagiannaki
                 email_template_name='registration/email_change_email.txt',
553 49790d9d Sofia Papagiannaki
                 form_template_name='registration/email_change_form.html',
554 49790d9d Sofia Papagiannaki
                 confirm_template_name='registration/email_change_done.html',
555 49790d9d Sofia Papagiannaki
                 extra_context={}):
556 49790d9d Sofia Papagiannaki
    if activation_key:
557 49790d9d Sofia Papagiannaki
        try:
558 49790d9d Sofia Papagiannaki
            user = EmailChange.objects.change_email(activation_key)
559 49790d9d Sofia Papagiannaki
            if request.user.is_authenticated() and request.user == user:
560 49790d9d Sofia Papagiannaki
                msg = _('Email changed successfully.')
561 49790d9d Sofia Papagiannaki
                messages.add_message(request, messages.SUCCESS, msg)
562 49790d9d Sofia Papagiannaki
                auth_logout(request)
563 49790d9d Sofia Papagiannaki
                response = prepare_response(request, user)
564 49790d9d Sofia Papagiannaki
                transaction.commit()
565 49790d9d Sofia Papagiannaki
                return response
566 49790d9d Sofia Papagiannaki
        except ValueError, e:
567 49790d9d Sofia Papagiannaki
            messages.add_message(request, messages.ERROR, e)
568 49790d9d Sofia Papagiannaki
        return render_response(confirm_template_name,
569 49790d9d Sofia Papagiannaki
                               modified_user = user if 'user' in locals() else None,
570 49790d9d Sofia Papagiannaki
                               context_instance = get_context(request,
571 49790d9d Sofia Papagiannaki
                                                              extra_context))
572 49790d9d Sofia Papagiannaki
    
573 49790d9d Sofia Papagiannaki
    if not request.user.is_authenticated():
574 49790d9d Sofia Papagiannaki
        path = quote(request.get_full_path())
575 49790d9d Sofia Papagiannaki
        url = request.build_absolute_uri(reverse('astakos.im.views.index'))
576 49790d9d Sofia Papagiannaki
        return HttpResponseRedirect(url + '?next=' + path)
577 49790d9d Sofia Papagiannaki
    form = EmailChangeForm(request.POST or None)
578 49790d9d Sofia Papagiannaki
    if request.method == 'POST' and form.is_valid():
579 49790d9d Sofia Papagiannaki
        try:
580 49790d9d Sofia Papagiannaki
            ec = form.save(email_template_name, request)
581 49790d9d Sofia Papagiannaki
        except SendMailError, e:
582 49790d9d Sofia Papagiannaki
            status = messages.ERROR
583 49790d9d Sofia Papagiannaki
            msg = e
584 49790d9d Sofia Papagiannaki
            transaction.rollback()
585 49790d9d Sofia Papagiannaki
        except IntegrityError, e:
586 49790d9d Sofia Papagiannaki
            status = messages.ERROR
587 49790d9d Sofia Papagiannaki
            msg = _('There is already a pending change email request.')
588 49790d9d Sofia Papagiannaki
        else:
589 49790d9d Sofia Papagiannaki
            status = messages.SUCCESS
590 49790d9d Sofia Papagiannaki
            msg = _('Change email request has been registered succefully.\
591 49790d9d Sofia Papagiannaki
                    You are going to receive a verification email in the new address.')
592 49790d9d Sofia Papagiannaki
            transaction.commit()
593 49790d9d Sofia Papagiannaki
        messages.add_message(request, status, msg)
594 49790d9d Sofia Papagiannaki
    return render_response(form_template_name,
595 49790d9d Sofia Papagiannaki
                           form = form,
596 49790d9d Sofia Papagiannaki
                           context_instance = get_context(request,
597 2bc206d4 Kostas Papadimitriou
                                                          extra_context))