Statistics
| Branch: | Tag: | Revision:

root / pithos / im / views.py @ d3205c49

History | View | Annotate | Download (7.7 kB)

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

    
34
import json
35
import logging
36
import socket
37

    
38
from datetime import datetime
39
from functools import wraps
40
from math import ceil
41
from random import randint
42
from smtplib import SMTPException
43

    
44
from django.conf import settings
45
from django.core.mail import send_mail
46
from django.http import HttpResponse, HttpResponseRedirect
47
from django.shortcuts import redirect
48
from django.template.loader import render_to_string
49
from django.utils.http import urlencode
50
from django.utils.translation import ugettext as _
51

    
52
from pithos.im.models import User, Invitation
53
from pithos.im.util import isoformat
54

    
55

    
56
def render_response(template, tab=None, status=200, **kwargs):
57
    if tab is None:
58
        tab = template.partition('_')[0]
59
    kwargs.setdefault('tab', tab)
60
    html = render_to_string(template, kwargs)
61
    return HttpResponse(html, status=status)
62

    
63

    
64
def requires_login(func):
65
    @wraps(func)
66
    def wrapper(request, *args):
67
        if not settings.BYPASS_ADMIN_AUTH:
68
            if not request.user:
69
                next = urlencode({'next': request.build_absolute_uri()})
70
                login_uri = settings.LOGIN_URL + '?' + next
71
                return HttpResponseRedirect(login_uri)
72
        return func(request, *args)
73
    return wrapper
74

    
75

    
76
def requires_admin(func):
77
    @wraps(func)
78
    def wrapper(request, *args):
79
        if not settings.BYPASS_ADMIN_AUTH:
80
            if not request.user:
81
                next = urlencode({'next': request.build_absolute_uri()})
82
                login_uri = settings.LOGIN_URL + '?' + next
83
                return HttpResponseRedirect(login_uri)
84
            if not request.user_obj.is_admin:
85
                return HttpResponse('Forbidden', status=403)
86
        return func(request, *args)
87
    return wrapper
88

    
89

    
90
def index(request):
91
    # TODO: Get and pass on next variable.
92
    return render_response('index.html')
93

    
94

    
95
@requires_admin
96
def admin(request):
97
    stats = {}
98
    stats['users'] = User.objects.count()
99
    return render_response('admin.html', tab='home', stats=stats)
100

    
101

    
102
@requires_admin
103
def users_list(request):
104
    users = User.objects.order_by('id')
105
    
106
    filter = request.GET.get('filter', '')
107
    if filter:
108
        if filter.startswith('-'):
109
            users = users.exclude(uniq__icontains=filter[1:])
110
        else:
111
            users = users.filter(uniq__icontains=filter)
112
    
113
    try:
114
        page = int(request.GET.get('page', 1))
115
    except ValueError:
116
        page = 1
117
    offset = max(0, page - 1) * settings.ADMIN_PAGE_LIMIT
118
    limit = offset + settings.ADMIN_PAGE_LIMIT
119
    
120
    npages = int(ceil(1.0 * users.count() / settings.ADMIN_PAGE_LIMIT))
121
    prev = page - 1 if page > 1 else None
122
    next = page + 1 if page < npages else None
123
    return render_response('users_list.html',
124
                            users=users[offset:limit],
125
                            filter=filter,
126
                            pages=range(1, npages + 1),
127
                            page=page,
128
                            prev=prev,
129
                            next=next)
130

    
131

    
132
@requires_admin
133
def users_create(request):
134
    if request.method == 'GET':
135
        return render_response('users_create.html')
136
    if request.method == 'POST':
137
        user = User()
138
        user.uniq = request.POST.get('uniq')
139
        user.realname = request.POST.get('realname')
140
        user.is_admin = True if request.POST.get('admin') else False
141
        user.affiliation = request.POST.get('affiliation')
142
        user.quota = int(request.POST.get('quota') or 0) * (1024 ** 3)  # In GiB
143
        user.renew_token()
144
        user.save()
145
        return redirect(users_info, user.id)
146

    
147

    
148
@requires_admin
149
def users_info(request, user_id):
150
    user = User.objects.get(id=user_id)
151
    return render_response('users_info.html', user=user)
152

    
153

    
154
@requires_admin
155
def users_modify(request, user_id):
156
    user = User.objects.get(id=user_id)
157
    user.uniq = request.POST.get('uniq')
158
    user.realname = request.POST.get('realname')
159
    user.is_admin = True if request.POST.get('admin') else False
160
    user.affiliation = request.POST.get('affiliation')
161
    user.quota = int(request.POST.get('quota') or 0) * (1024 ** 3)  # In GiB
162
    user.auth_token = request.POST.get('auth_token')
163
    try:
164
        auth_token_expires = request.POST.get('auth_token_expires')
165
        d = datetime.strptime(auth_token_expires, '%Y-%m-%dT%H:%MZ')
166
        user.auth_token_expires = d
167
    except ValueError:
168
        pass
169
    user.save()
170
    return redirect(users_info, user.id)
171

    
172

    
173
@requires_admin
174
def users_delete(request, user_id):
175
    user = User.objects.get(id=user_id)
176
    user.delete()
177
    return redirect(users_list)
178

    
179

    
180
def generate_invitation_code():
181
    return randint(1, 2L**63 - 1)
182

    
183

    
184
def send_invitation(inv):
185
    url = settings.INVITATION_LOGIN_TARGET % inv.code
186
    subject = _('Invitation to Pithos')
187
    message = render_to_string('invitation.txt', {
188
                'invitation': inv,
189
                'url': url})
190
    sender = settings.DEFAULT_FROM_EMAIL
191
    send_mail(subject, message, sender, [inv.uniq])
192
    inv.inviter.invitations = max(0, inv.inviter.invitations - 1)
193
    inv.inviter.save()
194
    logging.info('Sent invitation %s', inv)
195

    
196

    
197
@requires_login
198
def invite(request):
199
    status = None
200
    message = None
201

    
202
    if request.method == 'POST':
203
        if request.user_obj.invitations > 0:
204
            code = generate_invitation_code()
205
            invitation, created = Invitation.objects.get_or_create(code=code)
206
            invitation.inviter=request.user_obj
207
            invitation.realname=request.POST.get('realname')
208
            invitation.uniq=request.POST.get('uniq')
209
            invitation.save()
210
            
211
            try:
212
                send_invitation(invitation)
213
                status = 'success'
214
                message = _('Invitation sent to %s' % invitation.uniq)
215
            except (SMTPException, socket.error) as e:
216
                status = 'error'
217
                message = e.strerror
218
        else:
219
            status = 'error'
220
            message = _('No invitations left')
221

    
222
    if request.GET.get('format') == 'json':
223
        rep = {'invitations': request.user_obj.invitations}
224
        return HttpResponse(json.dumps(rep))
225
    
226
    html = render_to_string('invitations.html', {
227
            'user': request.user_obj,
228
            'status': status,
229
            'message': message})
230
    return HttpResponse(html)