Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (15.3 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 63ecdd20 Sofia Papagiannaki
from django.http import HttpResponse
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 7482228b Sofia Papagiannaki
from django.contrib.auth import logout as auth_logout
51 63ecdd20 Sofia Papagiannaki
from django.utils.http import urlencode
52 63ecdd20 Sofia Papagiannaki
from django.http import HttpResponseRedirect
53 64cd4730 Antony Chazapis
54 0905ccd2 Sofia Papagiannaki
from astakos.im.models import AstakosUser, Invitation
55 0905ccd2 Sofia Papagiannaki
from astakos.im.backends import get_backend
56 c301698f Sofia Papagiannaki
from astakos.im.util import get_context, prepare_response, set_cookie
57 15efc749 Sofia Papagiannaki
from astakos.im.forms import *
58 eeb3fe84 Sofia Papagiannaki
from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, COOKIE_NAME, COOKIE_DOMAIN, IM_MODULES, SITENAME, BASEURL
59 f36af44a Antony Chazapis
from astakos.im.functions import invite as invite_func
60 64cd4730 Antony Chazapis
61 e015e9e6 Sofia Papagiannaki
logger = logging.getLogger(__name__)
62 e015e9e6 Sofia Papagiannaki
63 c301698f Sofia Papagiannaki
def render_response(template, tab=None, status=200, reset_cookie=False, context_instance=None, **kwargs):
64 890b0eaf Sofia Papagiannaki
    """
65 890b0eaf Sofia Papagiannaki
    Calls ``django.template.loader.render_to_string`` with an additional ``tab``
66 890b0eaf Sofia Papagiannaki
    keyword argument and returns an ``django.http.HttpResponse`` with the
67 890b0eaf Sofia Papagiannaki
    specified ``status``.
68 890b0eaf Sofia Papagiannaki
    """
69 64cd4730 Antony Chazapis
    if tab is None:
70 881c856c Sofia Papagiannaki
        tab = template.partition('_')[0].partition('.html')[0]
71 64cd4730 Antony Chazapis
    kwargs.setdefault('tab', tab)
72 0905ccd2 Sofia Papagiannaki
    html = render_to_string(template, kwargs, context_instance=context_instance)
73 c301698f Sofia Papagiannaki
    response = HttpResponse(html, status=status)
74 c301698f Sofia Papagiannaki
    if reset_cookie:
75 c301698f Sofia Papagiannaki
        set_cookie(response, context_instance['request'].user)
76 c301698f Sofia Papagiannaki
    return response
77 64cd4730 Antony Chazapis
78 63ecdd20 Sofia Papagiannaki
79 63ecdd20 Sofia Papagiannaki
def requires_anonymous(func):
80 63ecdd20 Sofia Papagiannaki
    """
81 63ecdd20 Sofia Papagiannaki
    Decorator checkes whether the request.user is Anonymous and in that case
82 7482228b Sofia Papagiannaki
    redirects to `logout`.
83 63ecdd20 Sofia Papagiannaki
    """
84 63ecdd20 Sofia Papagiannaki
    @wraps(func)
85 63ecdd20 Sofia Papagiannaki
    def wrapper(request, *args):
86 63ecdd20 Sofia Papagiannaki
        if not request.user.is_anonymous():
87 63ecdd20 Sofia Papagiannaki
            next = urlencode({'next': request.build_absolute_uri()})
88 7482228b Sofia Papagiannaki
            login_uri = reverse(logout) + '?' + next
89 63ecdd20 Sofia Papagiannaki
            return HttpResponseRedirect(login_uri)
90 63ecdd20 Sofia Papagiannaki
        return func(request, *args)
91 63ecdd20 Sofia Papagiannaki
    return wrapper
92 63ecdd20 Sofia Papagiannaki
93 1e685275 Sofia Papagiannaki
def index(request, login_template_name='im/login.html', profile_template_name='im/profile.html', extra_context={}):
94 890b0eaf Sofia Papagiannaki
    """
95 dcf55476 Sofia Papagiannaki
    If there is logged on user renders the profile page otherwise renders login page.
96 64cd4730 Antony Chazapis
    
97 890b0eaf Sofia Papagiannaki
    **Arguments**
98 64cd4730 Antony Chazapis
    
99 dcf55476 Sofia Papagiannaki
    ``login_template_name``
100 dcf55476 Sofia Papagiannaki
        A custom login template to use. This is optional; if not specified,
101 1e685275 Sofia Papagiannaki
        this will default to ``im/login.html``.
102 dcf55476 Sofia Papagiannaki
    
103 dcf55476 Sofia Papagiannaki
    ``profile_template_name``
104 dcf55476 Sofia Papagiannaki
        A custom profile template to use. This is optional; if not specified,
105 1e685275 Sofia Papagiannaki
        this will default to ``im/profile.html``.
106 64cd4730 Antony Chazapis
    
107 890b0eaf Sofia Papagiannaki
    ``extra_context``
108 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
109 64cd4730 Antony Chazapis
    
110 890b0eaf Sofia Papagiannaki
    **Template:**
111 64cd4730 Antony Chazapis
    
112 1e685275 Sofia Papagiannaki
    im/profile.html or im/login.html or ``template_name`` keyword argument.
113 64cd4730 Antony Chazapis
    
114 890b0eaf Sofia Papagiannaki
    """
115 dcf55476 Sofia Papagiannaki
    template_name = login_template_name
116 dcf55476 Sofia Papagiannaki
    formclass = 'LoginForm'
117 dcf55476 Sofia Papagiannaki
    kwargs = {}
118 dcf55476 Sofia Papagiannaki
    if request.user.is_authenticated():
119 dcf55476 Sofia Papagiannaki
        template_name = profile_template_name
120 dcf55476 Sofia Papagiannaki
        formclass = 'ProfileForm'
121 dcf55476 Sofia Papagiannaki
        kwargs.update({'instance':request.user})
122 0905ccd2 Sofia Papagiannaki
    return render_response(template_name,
123 dcf55476 Sofia Papagiannaki
                           form = globals()[formclass](**kwargs),
124 0905ccd2 Sofia Papagiannaki
                           context_instance = get_context(request, extra_context))
125 64cd4730 Antony Chazapis
126 890b0eaf Sofia Papagiannaki
@login_required
127 890b0eaf Sofia Papagiannaki
@transaction.commit_manually
128 1e685275 Sofia Papagiannaki
def invite(request, template_name='im/invitations.html', extra_context={}):
129 890b0eaf Sofia Papagiannaki
    """
130 890b0eaf Sofia Papagiannaki
    Allows a user to invite somebody else.
131 890b0eaf Sofia Papagiannaki
    
132 890b0eaf Sofia Papagiannaki
    In case of GET request renders a form for providing the invitee information.
133 890b0eaf Sofia Papagiannaki
    In case of POST checks whether the user has not run out of invitations and then
134 890b0eaf Sofia Papagiannaki
    sends an invitation email to singup to the service.
135 890b0eaf Sofia Papagiannaki
    
136 890b0eaf Sofia Papagiannaki
    The view uses commit_manually decorator in order to ensure the number of the
137 890b0eaf Sofia Papagiannaki
    user invitations is going to be updated only if the email has been successfully sent.
138 890b0eaf Sofia Papagiannaki
    
139 2cbaacd5 Sofia Papagiannaki
    If the user isn't logged in, redirects to settings.LOGIN_URL.
140 890b0eaf Sofia Papagiannaki
    
141 890b0eaf Sofia Papagiannaki
    **Arguments**
142 890b0eaf Sofia Papagiannaki
    
143 890b0eaf Sofia Papagiannaki
    ``template_name``
144 890b0eaf Sofia Papagiannaki
        A custom template to use. This is optional; if not specified,
145 1e685275 Sofia Papagiannaki
        this will default to ``im/invitations.html``.
146 890b0eaf Sofia Papagiannaki
    
147 890b0eaf Sofia Papagiannaki
    ``extra_context``
148 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
149 890b0eaf Sofia Papagiannaki
    
150 890b0eaf Sofia Papagiannaki
    **Template:**
151 890b0eaf Sofia Papagiannaki
    
152 1e685275 Sofia Papagiannaki
    im/invitations.html or ``template_name`` keyword argument.
153 890b0eaf Sofia Papagiannaki
    
154 890b0eaf Sofia Papagiannaki
    **Settings:**
155 890b0eaf Sofia Papagiannaki
    
156 890b0eaf Sofia Papagiannaki
    The view expectes the following settings are defined:
157 890b0eaf Sofia Papagiannaki
    
158 890b0eaf Sofia Papagiannaki
    * LOGIN_URL: login uri
159 2cbaacd5 Sofia Papagiannaki
    * ASTAKOS_DEFAULT_CONTACT_EMAIL: service support email
160 2cbaacd5 Sofia Papagiannaki
    * ASTAKOS_DEFAULT_FROM_EMAIL: from email
161 890b0eaf Sofia Papagiannaki
    """
162 64cd4730 Antony Chazapis
    status = None
163 64cd4730 Antony Chazapis
    message = None
164 5ed6816e Sofia Papagiannaki
    inviter = AstakosUser.objects.get(username = request.user.username)
165 5ed6816e Sofia Papagiannaki
    
166 64cd4730 Antony Chazapis
    if request.method == 'POST':
167 0905ccd2 Sofia Papagiannaki
        username = request.POST.get('uniq')
168 64cd4730 Antony Chazapis
        realname = request.POST.get('realname')
169 64cd4730 Antony Chazapis
        
170 64cd4730 Antony Chazapis
        if inviter.invitations > 0:
171 64cd4730 Antony Chazapis
            try:
172 374611bc Sofia Papagiannaki
                invite_func(inviter, username, realname)
173 890b0eaf Sofia Papagiannaki
                status = messages.SUCCESS
174 0905ccd2 Sofia Papagiannaki
                message = _('Invitation sent to %s' % username)
175 890b0eaf Sofia Papagiannaki
                transaction.commit()
176 64cd4730 Antony Chazapis
            except (SMTPException, socket.error) as e:
177 890b0eaf Sofia Papagiannaki
                status = messages.ERROR
178 64cd4730 Antony Chazapis
                message = getattr(e, 'strerror', '')
179 890b0eaf Sofia Papagiannaki
                transaction.rollback()
180 64cd4730 Antony Chazapis
        else:
181 890b0eaf Sofia Papagiannaki
            status = messages.ERROR
182 64cd4730 Antony Chazapis
            message = _('No invitations left')
183 890b0eaf Sofia Papagiannaki
    messages.add_message(request, status, message)
184 890b0eaf Sofia Papagiannaki
    
185 a196eb7e Sofia Papagiannaki
    sent = [{'email': inv.username,
186 d6ae71a2 root
             'realname': inv.realname,
187 d6ae71a2 root
             'is_consumed': inv.is_consumed}
188 d6ae71a2 root
             for inv in inviter.invitations_sent.all()]
189 77e2ad52 root
    kwargs = {'inviter': inviter,
190 a196eb7e Sofia Papagiannaki
              'sent':sent}
191 0905ccd2 Sofia Papagiannaki
    context = get_context(request, extra_context, **kwargs)
192 0905ccd2 Sofia Papagiannaki
    return render_response(template_name,
193 0905ccd2 Sofia Papagiannaki
                           context_instance = context)
194 64cd4730 Antony Chazapis
195 890b0eaf Sofia Papagiannaki
@login_required
196 1e685275 Sofia Papagiannaki
def edit_profile(request, template_name='im/profile.html', extra_context={}):
197 890b0eaf Sofia Papagiannaki
    """
198 890b0eaf Sofia Papagiannaki
    Allows a user to edit his/her profile.
199 64cd4730 Antony Chazapis
    
200 890b0eaf Sofia Papagiannaki
    In case of GET request renders a form for displaying the user information.
201 ce86cd44 Sofia Papagiannaki
    In case of POST updates the user informantion and redirects to ``next``
202 ce86cd44 Sofia Papagiannaki
    url parameter if exists.
203 890b0eaf Sofia Papagiannaki
    
204 2cbaacd5 Sofia Papagiannaki
    If the user isn't logged in, redirects to settings.LOGIN_URL.
205 890b0eaf Sofia Papagiannaki
    
206 890b0eaf Sofia Papagiannaki
    **Arguments**
207 890b0eaf Sofia Papagiannaki
    
208 890b0eaf Sofia Papagiannaki
    ``template_name``
209 890b0eaf Sofia Papagiannaki
        A custom template to use. This is optional; if not specified,
210 1e685275 Sofia Papagiannaki
        this will default to ``im/profile.html``.
211 890b0eaf Sofia Papagiannaki
    
212 890b0eaf Sofia Papagiannaki
    ``extra_context``
213 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
214 890b0eaf Sofia Papagiannaki
    
215 890b0eaf Sofia Papagiannaki
    **Template:**
216 890b0eaf Sofia Papagiannaki
    
217 1e685275 Sofia Papagiannaki
    im/profile.html or ``template_name`` keyword argument.
218 92defad4 Sofia Papagiannaki
    
219 92defad4 Sofia Papagiannaki
    **Settings:**
220 92defad4 Sofia Papagiannaki
    
221 92defad4 Sofia Papagiannaki
    The view expectes the following settings are defined:
222 92defad4 Sofia Papagiannaki
    
223 92defad4 Sofia Papagiannaki
    * LOGIN_URL: login uri
224 890b0eaf Sofia Papagiannaki
    """
225 15efc749 Sofia Papagiannaki
    form = ProfileForm(instance=request.user)
226 15efc749 Sofia Papagiannaki
    extra_context['next'] = request.GET.get('next')
227 c301698f Sofia Papagiannaki
    reset_cookie = False
228 64cd4730 Antony Chazapis
    if request.method == 'POST':
229 15efc749 Sofia Papagiannaki
        form = ProfileForm(request.POST, instance=request.user)
230 890b0eaf Sofia Papagiannaki
        if form.is_valid():
231 64cd4730 Antony Chazapis
            try:
232 c301698f Sofia Papagiannaki
                prev_token = request.user.auth_token
233 c301698f Sofia Papagiannaki
                user = form.save()
234 c301698f Sofia Papagiannaki
                reset_cookie = user.auth_token != prev_token
235 c301698f Sofia Papagiannaki
                form = ProfileForm(instance=user)
236 1a3675a0 Sofia Papagiannaki
                next = request.POST.get('next')
237 1a3675a0 Sofia Papagiannaki
                if next:
238 1a3675a0 Sofia Papagiannaki
                    return redirect(next)
239 890b0eaf Sofia Papagiannaki
                msg = _('Profile has been updated successfully')
240 890b0eaf Sofia Papagiannaki
                messages.add_message(request, messages.SUCCESS, msg)
241 890b0eaf Sofia Papagiannaki
            except ValueError, ve:
242 890b0eaf Sofia Papagiannaki
                messages.add_message(request, messages.ERROR, ve)
243 0905ccd2 Sofia Papagiannaki
    return render_response(template_name,
244 c301698f Sofia Papagiannaki
                           reset_cookie = reset_cookie,
245 890b0eaf Sofia Papagiannaki
                           form = form,
246 0905ccd2 Sofia Papagiannaki
                           context_instance = get_context(request,
247 c301698f Sofia Papagiannaki
                                                          extra_context))
248 64cd4730 Antony Chazapis
249 1463659a Sofia Papagiannaki
@requires_anonymous
250 1e685275 Sofia Papagiannaki
def signup(request, on_failure='im/signup.html', on_success='im/signup_complete.html', extra_context={}, backend=None):
251 890b0eaf Sofia Papagiannaki
    """
252 890b0eaf Sofia Papagiannaki
    Allows a user to create a local account.
253 64cd4730 Antony Chazapis
    
254 890b0eaf Sofia Papagiannaki
    In case of GET request renders a form for providing the user information.
255 890b0eaf Sofia Papagiannaki
    In case of POST handles the signup.
256 890b0eaf Sofia Papagiannaki
    
257 890b0eaf Sofia Papagiannaki
    The user activation will be delegated to the backend specified by the ``backend`` keyword argument
258 890b0eaf Sofia Papagiannaki
    if present, otherwise to the ``astakos.im.backends.InvitationBackend``
259 92defad4 Sofia Papagiannaki
    if settings.ASTAKOS_INVITATIONS_ENABLED is True or ``astakos.im.backends.SimpleBackend`` if not
260 890b0eaf Sofia Papagiannaki
    (see backends);
261 890b0eaf Sofia Papagiannaki
    
262 890b0eaf Sofia Papagiannaki
    Upon successful user creation if ``next`` url parameter is present the user is redirected there
263 890b0eaf Sofia Papagiannaki
    otherwise renders the same page with a success message.
264 64cd4730 Antony Chazapis
    
265 890b0eaf Sofia Papagiannaki
    On unsuccessful creation, renders the same page with an error message.
266 890b0eaf Sofia Papagiannaki
    
267 890b0eaf Sofia Papagiannaki
    **Arguments**
268 890b0eaf Sofia Papagiannaki
    
269 f7e8a159 Sofia Papagiannaki
    ``on_failure``
270 f7e8a159 Sofia Papagiannaki
        A custom template to render in case of failure. This is optional;
271 1e685275 Sofia Papagiannaki
        if not specified, this will default to ``im/signup.html``.
272 f7e8a159 Sofia Papagiannaki
    
273 f7e8a159 Sofia Papagiannaki
    
274 f7e8a159 Sofia Papagiannaki
    ``on_success``
275 f7e8a159 Sofia Papagiannaki
        A custom template to render in case of success. This is optional;
276 1e685275 Sofia Papagiannaki
        if not specified, this will default to ``im/signup_complete.html``.
277 890b0eaf Sofia Papagiannaki
    
278 890b0eaf Sofia Papagiannaki
    ``extra_context``
279 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
280 890b0eaf Sofia Papagiannaki
    
281 890b0eaf Sofia Papagiannaki
    **Template:**
282 890b0eaf Sofia Papagiannaki
    
283 1e685275 Sofia Papagiannaki
    im/signup.html or ``on_failure`` keyword argument.
284 1e685275 Sofia Papagiannaki
    im/signup_complete.html or ``on_success`` keyword argument. 
285 890b0eaf Sofia Papagiannaki
    """
286 890b0eaf Sofia Papagiannaki
    try:
287 81c94f7b Sofia Papagiannaki
        if not backend:
288 81c94f7b Sofia Papagiannaki
            backend = get_backend(request)
289 92defad4 Sofia Papagiannaki
        for provider in IM_MODULES:
290 15efc749 Sofia Papagiannaki
            extra_context['%s_form' % provider] = backend.get_signup_form(provider)
291 890b0eaf Sofia Papagiannaki
        if request.method == 'POST':
292 15efc749 Sofia Papagiannaki
            provider = request.POST.get('provider')
293 15efc749 Sofia Papagiannaki
            next = request.POST.get('next', '')
294 15efc749 Sofia Papagiannaki
            form = extra_context['%s_form' % provider]
295 890b0eaf Sofia Papagiannaki
            if form.is_valid():
296 15efc749 Sofia Papagiannaki
                if provider != 'local':
297 15efc749 Sofia Papagiannaki
                    url = reverse('astakos.im.target.%s.login' % provider)
298 15efc749 Sofia Papagiannaki
                    url = '%s?email=%s&next=%s' % (url, form.data['email'], next)
299 15efc749 Sofia Papagiannaki
                    if backend.invitation:
300 15efc749 Sofia Papagiannaki
                        url = '%s&code=%s' % (url, backend.invitation.code)
301 15efc749 Sofia Papagiannaki
                    return redirect(url)
302 890b0eaf Sofia Papagiannaki
                else:
303 15efc749 Sofia Papagiannaki
                    status, message, user = backend.signup(form)
304 63ecdd20 Sofia Papagiannaki
                    if user and user.is_active:
305 63ecdd20 Sofia Papagiannaki
                        return prepare_response(request, user, next=next)
306 f7e8a159 Sofia Papagiannaki
                    messages.add_message(request, status, message)
307 f7e8a159 Sofia Papagiannaki
                    return render_response(on_success,
308 f7e8a159 Sofia Papagiannaki
                           context_instance=get_context(request, extra_context))
309 15efc749 Sofia Papagiannaki
    except (Invitation.DoesNotExist, ValueError), e:
310 890b0eaf Sofia Papagiannaki
        messages.add_message(request, messages.ERROR, e)
311 92defad4 Sofia Papagiannaki
        for provider in IM_MODULES:
312 15efc749 Sofia Papagiannaki
            main = provider.capitalize() if provider == 'local' else 'ThirdParty'
313 15efc749 Sofia Papagiannaki
            formclass = '%sUserCreationForm' % main
314 15efc749 Sofia Papagiannaki
            extra_context['%s_form' % provider] = globals()[formclass]()
315 f7e8a159 Sofia Papagiannaki
    return render_response(on_failure,
316 890b0eaf Sofia Papagiannaki
                           context_instance=get_context(request, extra_context))
317 64cd4730 Antony Chazapis
318 890b0eaf Sofia Papagiannaki
@login_required
319 1e685275 Sofia Papagiannaki
def send_feedback(request, template_name='im/feedback.html', email_template_name='im/feedback_mail.txt', extra_context={}):
320 890b0eaf Sofia Papagiannaki
    """
321 890b0eaf Sofia Papagiannaki
    Allows a user to send feedback.
322 890b0eaf Sofia Papagiannaki
    
323 890b0eaf Sofia Papagiannaki
    In case of GET request renders a form for providing the feedback information.
324 890b0eaf Sofia Papagiannaki
    In case of POST sends an email to support team.
325 890b0eaf Sofia Papagiannaki
    
326 2cbaacd5 Sofia Papagiannaki
    If the user isn't logged in, redirects to settings.LOGIN_URL.
327 890b0eaf Sofia Papagiannaki
    
328 890b0eaf Sofia Papagiannaki
    **Arguments**
329 890b0eaf Sofia Papagiannaki
    
330 890b0eaf Sofia Papagiannaki
    ``template_name``
331 890b0eaf Sofia Papagiannaki
        A custom template to use. This is optional; if not specified,
332 1e685275 Sofia Papagiannaki
        this will default to ``im/feedback.html``.
333 890b0eaf Sofia Papagiannaki
    
334 890b0eaf Sofia Papagiannaki
    ``extra_context``
335 890b0eaf Sofia Papagiannaki
        An dictionary of variables to add to the template context.
336 890b0eaf Sofia Papagiannaki
    
337 890b0eaf Sofia Papagiannaki
    **Template:**
338 64cd4730 Antony Chazapis
    
339 1e685275 Sofia Papagiannaki
    im/signup.html or ``template_name`` keyword argument.
340 890b0eaf Sofia Papagiannaki
    
341 890b0eaf Sofia Papagiannaki
    **Settings:**
342 890b0eaf Sofia Papagiannaki
    
343 92defad4 Sofia Papagiannaki
    * LOGIN_URL: login uri
344 2cbaacd5 Sofia Papagiannaki
    * ASTAKOS_DEFAULT_CONTACT_EMAIL: List of feedback recipients
345 890b0eaf Sofia Papagiannaki
    """
346 64cd4730 Antony Chazapis
    if request.method == 'GET':
347 890b0eaf Sofia Papagiannaki
        form = FeedbackForm()
348 890b0eaf Sofia Papagiannaki
    if request.method == 'POST':
349 890b0eaf Sofia Papagiannaki
        if not request.user:
350 890b0eaf Sofia Papagiannaki
            return HttpResponse('Unauthorized', status=401)
351 64cd4730 Antony Chazapis
        
352 890b0eaf Sofia Papagiannaki
        form = FeedbackForm(request.POST)
353 890b0eaf Sofia Papagiannaki
        if form.is_valid():
354 374611bc Sofia Papagiannaki
            subject = _("Feedback from %s" % SITENAME)
355 890b0eaf Sofia Papagiannaki
            from_email = request.user.email
356 d552ecb7 Antony Chazapis
            recipient_list = [DEFAULT_CONTACT_EMAIL]
357 890b0eaf Sofia Papagiannaki
            content = render_to_string(email_template_name, {
358 538ccdd5 Sofia Papagiannaki
                        'message': form.cleaned_data['feedback_msg'],
359 538ccdd5 Sofia Papagiannaki
                        'data': form.cleaned_data['feedback_data'],
360 890b0eaf Sofia Papagiannaki
                        'request': request})
361 64cd4730 Antony Chazapis
            
362 538ccdd5 Sofia Papagiannaki
            try:
363 538ccdd5 Sofia Papagiannaki
                send_mail(subject, content, from_email, recipient_list)
364 538ccdd5 Sofia Papagiannaki
                message = _('Feedback successfully sent')
365 538ccdd5 Sofia Papagiannaki
                status = messages.SUCCESS
366 538ccdd5 Sofia Papagiannaki
            except (SMTPException, socket.error) as e:
367 538ccdd5 Sofia Papagiannaki
                status = messages.ERROR
368 538ccdd5 Sofia Papagiannaki
                message = getattr(e, 'strerror', '')
369 538ccdd5 Sofia Papagiannaki
            messages.add_message(request, status, message)
370 890b0eaf Sofia Papagiannaki
    return render_response(template_name,
371 890b0eaf Sofia Papagiannaki
                           form = form,
372 6b4f9fb2 Sofia Papagiannaki
                           context_instance = get_context(request, extra_context))
373 15efc749 Sofia Papagiannaki
374 7482228b Sofia Papagiannaki
def logout(request, template='registration/logged_out.html', extra_context={}):
375 63ecdd20 Sofia Papagiannaki
    """
376 7482228b Sofia Papagiannaki
    Wraps `django.contrib.auth.logout` and delete the cookie.
377 63ecdd20 Sofia Papagiannaki
    """
378 7482228b Sofia Papagiannaki
    auth_logout(request)
379 7482228b Sofia Papagiannaki
    response = HttpResponse()
380 28ff5b5d Antony Chazapis
    response.delete_cookie(COOKIE_NAME, path='/', domain=COOKIE_DOMAIN)
381 63ecdd20 Sofia Papagiannaki
    next = request.GET.get('next')
382 63ecdd20 Sofia Papagiannaki
    if next:
383 63ecdd20 Sofia Papagiannaki
        response['Location'] = next
384 63ecdd20 Sofia Papagiannaki
        response.status_code = 302
385 63ecdd20 Sofia Papagiannaki
        return response
386 49df775e Sofia Papagiannaki
    context = get_context(request, extra_context)
387 49df775e Sofia Papagiannaki
    response.write(render_to_string(template, context_instance=context))
388 49df775e Sofia Papagiannaki
    return response
389 2126d85d Sofia Papagiannaki
390 2126d85d Sofia Papagiannaki
def activate(request):
391 2126d85d Sofia Papagiannaki
    """
392 2126d85d Sofia Papagiannaki
    Activates the user identified by the ``auth`` request parameter
393 2126d85d Sofia Papagiannaki
    """
394 2126d85d Sofia Papagiannaki
    token = request.GET.get('auth')
395 2126d85d Sofia Papagiannaki
    next = request.GET.get('next')
396 2126d85d Sofia Papagiannaki
    try:
397 2126d85d Sofia Papagiannaki
        user = AstakosUser.objects.get(auth_token=token)
398 2126d85d Sofia Papagiannaki
    except AstakosUser.DoesNotExist:
399 2126d85d Sofia Papagiannaki
        return HttpResponseBadRequest('No such user')
400 2126d85d Sofia Papagiannaki
    
401 2126d85d Sofia Papagiannaki
    user.is_active = True
402 2126d85d Sofia Papagiannaki
    user.save()
403 f36af44a Antony Chazapis
    return prepare_response(request, user, next, renew=True)