views.py 10.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# Copyright 2011 GRNET S.A. All rights reserved.
# 
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
# 
#   1. Redistributions of source code must retain the above
#      copyright notice, this list of conditions and the following
#      disclaimer.
# 
#   2. Redistributions in binary form must reproduce the above
#      copyright notice, this list of conditions and the following
#      disclaimer in the documentation and/or other materials
#      provided with the distribution.
# 
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# 
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.

import json
import logging
import socket
import csv
import sys

from datetime import datetime
from functools import wraps
from math import ceil
from random import randint
from smtplib import SMTPException
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
45
46
from hashlib import new as newhasher
from urllib import quote
47
48
49
50
51
52
53
54
55
56
57
58

from django.conf import settings
from django.core.mail import send_mail
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
from django.shortcuts import redirect
from django.template.loader import render_to_string
from django.shortcuts import render_to_response
from django.utils.http import urlencode
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse

#from astakos.im.openid_store import PithosOpenIDStore
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
59
60
from astakos.im.models import AstakosUser, Invitation
from astakos.im.util import isoformat, get_or_create_user, get_context
61
from astakos.im.forms import *
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
62
from astakos.im.backends import get_backend
63

Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
64
def render_response(template, tab=None, status=200, context_instance=None, **kwargs):
65
66
67
    if tab is None:
        tab = template.partition('_')[0]
    kwargs.setdefault('tab', tab)
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
68
    html = render_to_string(template, kwargs, context_instance=context_instance)
69
70
71
72
73
74
75
76
77
78
79
80
81
    return HttpResponse(html, status=status)

def requires_login(func):
    @wraps(func)
    def wrapper(request, *args):
        if not settings.BYPASS_ADMIN_AUTH:
            if not request.user:
                next = urlencode({'next': request.build_absolute_uri()})
                login_uri = reverse(index) + '?' + next
                return HttpResponseRedirect(login_uri)
        return func(request, *args)
    return wrapper

Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
82
83
84
85
86
def index(request, template_name='index.html', extra_context={}):
    print '#', get_context(request, extra_context)
    return render_response(template_name,
                           form = LoginForm(),
                           context_instance = get_context(request, extra_context))
87

Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
88
def _generate_invitation_code():
89
90
91
92
93
94
95
96
    while True:
        code = randint(1, 2L**63 - 1)
        try:
            Invitation.objects.get(code=code)
            # An invitation with this code already exists, try again
        except Invitation.DoesNotExist:
            return code

Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
97
def _send_invitation(baseurl, inv):
98
99
100
101
102
103
104
105
106
    url = settings.SIGNUP_TARGET % (baseurl, inv.code, quote(baseurl))
    subject = _('Invitation to Pithos')
    message = render_to_string('invitation.txt', {
                'invitation': inv,
                'url': url,
                'baseurl': baseurl,
                'service': settings.SERVICE_NAME,
                'support': settings.DEFAULT_CONTACT_EMAIL})
    sender = settings.DEFAULT_FROM_EMAIL
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
107
    send_mail(subject, message, sender, [inv.username])
108
109
110
    logging.info('Sent invitation %s', inv)

@requires_login
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
111
def invite(request, template_name='invitations.html', extra_context={}):
112
113
114
115
116
    status = None
    message = None
    inviter = request.user

    if request.method == 'POST':
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
117
        username = request.POST.get('uniq')
118
119
120
        realname = request.POST.get('realname')
        
        if inviter.invitations > 0:
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
121
            code = _generate_invitation_code()
122
123
            invitation, created = Invitation.objects.get_or_create(
                inviter=inviter,
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
124
                username=username,
125
126
127
                defaults={'code': code, 'realname': realname})
            
            try:
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
128
                _send_invitation(request.build_absolute_uri('/').rstrip('/'), invitation)
129
130
131
132
                if created:
                    inviter.invitations = max(0, inviter.invitations - 1)
                    inviter.save()
                status = 'success'
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
133
                message = _('Invitation sent to %s' % username)
134
135
136
137
138
139
140
141
            except (SMTPException, socket.error) as e:
                status = 'error'
                message = getattr(e, 'strerror', '')
        else:
            status = 'error'
            message = _('No invitations left')

    if request.GET.get('format') == 'json':
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
142
        sent = [{'email': inv.username,
143
144
145
146
147
148
                 'realname': inv.realname,
                 'is_accepted': inv.is_accepted}
                    for inv in inviter.invitations_sent.all()]
        rep = {'invitations': inviter.invitations, 'sent': sent}
        return HttpResponse(json.dumps(rep))
    
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
149
150
151
152
    kwargs = {'user': inviter, 'status': status, 'message': message}
    context = get_context(request, extra_context, **kwargs)
    return render_response(template_name,
                           context_instance = context)
153

Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
154
def _send_password(baseurl, user):
155
    url = settings.PASSWORD_RESET_TARGET % (baseurl,
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
156
                                            quote(user.username),
157
158
159
160
161
162
163
164
165
166
167
                                            quote(baseurl))
    message = render_to_string('password.txt', {
            'user': user,
            'url': url,
            'baseurl': baseurl,
            'service': settings.SERVICE_NAME,
            'support': settings.DEFAULT_CONTACT_EMAIL})
    sender = settings.DEFAULT_FROM_EMAIL
    send_mail('Pithos password recovering', message, sender, [user.email])
    logging.info('Sent password %s', user)

Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
168
def reclaim_password(request, template_name='reclaim.html', extra_context={}):
169
    if request.method == 'GET':
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
170
171
        return render_response(template_name,
                               context_instance = get_context(request, extra_context))
172
    elif request.method == 'POST':
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
173
        username = request.POST.get('username')
174
        try:
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
175
            user = AstakosUser.objects.get(username=username)
176
            try:
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
177
                _send_password(request.build_absolute_uri('/').rstrip('/'), user)
178
179
                status = 'success'
                message = _('Password reset sent to %s' % user.email)
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
180
                user.is_active = False
181
182
183
184
185
                user.save()
            except (SMTPException, socket.error) as e:
                status = 'error'
                name = 'strerror'
                message = getattr(e, name) if hasattr(e, name) else e
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
186
        except AstakosUser.DoesNotExist:
187
188
189
            status = 'error'
            message = 'Username does not exist'
        
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
190
191
192
        kwargs = {'status': status, 'message': message}
        return render_response(template_name,
                                context_instance = get_context(request, extra_context, **kwargs))
193
194

@requires_login
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
195
def users_profile(request, template_name='users_profile.html', extra_context={}):
196
    try:
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
197
198
199
200
201
202
203
204
        user = AstakosUser.objects.get(username=request.user)
    except AstakosUser.DoesNotExist:
        token = request.GET.get('auth', None)
        user = AstakosUser.objects.get(auth_token=token)
    return render_response(template_name,
                           context_instance = get_context(request,
                                                          extra_context,
                                                          user=user))
205
206

@requires_login
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
207
def users_edit(request, template_name='users_profile.html', extra_context={}):
208
    try:
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
209
210
        user = AstakosUser.objects.get(username=request.user)
    except AstakosUser.DoesNotExist:
211
        token = request.POST.get('auth', None)
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
212
213
214
215
        #users = AstakosUser.objects.all()
        user = AstakosUser.objects.get(auth_token=token)
    user.first_name = request.POST.get('first_name')
    user.last_name = request.POST.get('last_name')
216
217
218
219
220
221
222
223
224
    user.affiliation = request.POST.get('affiliation')
    user.is_verified = True
    user.save()
    next = request.POST.get('next')
    if next:
        return redirect(next)
    
    status = 'success'
    message = _('Profile has been updated')
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
225
226
    return render_response(template_name,
                           context_instance = get_context(request, extra_context, **kwargs))
227
    
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
228
229
230
def signup(request, template_name='signup.html', extra_context={}, backend=None, success_url = None):
    if not backend:
        backend = get_backend()
231
232
    if request.method == 'GET':
        try:
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
233
234
235
236
237
238
            form = backend.get_signup_form(request)
            return render_response(template_name,
                               form=form,
                               context_instance = get_context(request, extra_context))
        except Exception, e:
            return _on_failure(e, template_name=template_name)
239
    elif request.method == 'POST':
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
        try:
            form = backend.get_signup_form(request)
            if not form.is_valid():
                return render_response(template_name,
                                       form = form,
                                       context_instance = get_context(request, extra_context))
            status, message = backend.signup(request, form, success_url)
            next = request.POST.get('next')
            if next:
                return redirect(next)
            return _info(status, message)
        except Exception, e:
            return _on_failure(e, template_name=template_name)

def _info(status, message, template_name='base.html'):
    html = render_to_string(template_name, {
256
257
258
259
260
            'status': status,
            'message': message})
    response = HttpResponse(html)
    return response

Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
261
262
def _on_success(message, template_name='base.html'):
    return _info('success', message, template_name)
263
    
Sofia Papagiannaki's avatar
Sofia Papagiannaki committed
264
265
def _on_failure(message, template_name='base.html'):
    return _info('error', message, template_name)