Statistics
| Branch: | Tag: | Revision:

root / pithos / im / views.py @ 552ea518

History | View | Annotate | Download (8.1 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
from django.core.urlresolvers import reverse
52

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

    
56

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

    
64

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

    
76

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

    
90

    
91
def index(request):
92
    return render_response('index.html', next=request.GET.get('next', ''))
93

    
94

    
95
@requires_admin
96
def admin(request):
97
    stats = {}
98
    stats['users'] = User.objects.count()
99
    
100
    invitations = Invitation.objects.all()
101
    stats['invitations'] = invitations.count()
102
    stats['invitations_accepted'] = invitations.filter(is_accepted=True).count()
103
    
104
    return render_response('admin.html', tab='home', stats=stats)
105

    
106

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

    
136

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

    
152

    
153
@requires_admin
154
def users_info(request, user_id):
155
    user = User.objects.get(id=user_id)
156
    states = [x[0] for x in User.ACCOUNT_STATE]
157
    return render_response('users_info.html',
158
                            user=user,
159
                            states=states)
160

    
161

    
162
@requires_admin
163
def users_modify(request, user_id):
164
    user = User.objects.get(id=user_id)
165
    user.uniq = request.POST.get('uniq')
166
    user.realname = request.POST.get('realname')
167
    user.is_admin = True if request.POST.get('admin') else False
168
    user.affiliation = request.POST.get('affiliation')
169
    user.state = request.POST.get('state')
170
    user.invitations = int(request.POST.get('invitations') or 0)
171
    user.quota = int(request.POST.get('quota') or 0) * (1024 ** 3)  # In GiB
172
    user.auth_token = request.POST.get('auth_token')
173
    try:
174
        auth_token_expires = request.POST.get('auth_token_expires')
175
        d = datetime.strptime(auth_token_expires, '%Y-%m-%dT%H:%MZ')
176
        user.auth_token_expires = d
177
    except ValueError:
178
        pass
179
    user.save()
180
    return redirect(users_info, user.id)
181

    
182

    
183
@requires_admin
184
def users_delete(request, user_id):
185
    user = User.objects.get(id=user_id)
186
    user.delete()
187
    return redirect(users_list)
188

    
189

    
190
def generate_invitation_code():
191
    return randint(1, 2L**63 - 1)
192

    
193

    
194
def send_invitation(inv):
195
    url = settings.INVITATION_LOGIN_TARGET % inv.code
196
    subject = _('Invitation to Pithos')
197
    message = render_to_string('invitation.txt', {
198
                'invitation': inv,
199
                'url': url})
200
    sender = settings.DEFAULT_FROM_EMAIL
201
    send_mail(subject, message, sender, [inv.uniq])
202
    inv.inviter.invitations = max(0, inv.inviter.invitations - 1)
203
    inv.inviter.save()
204
    logging.info('Sent invitation %s', inv)
205

    
206

    
207
@requires_login
208
def invite(request):
209
    status = None
210
    message = None
211

    
212
    if request.method == 'POST':
213
        if request.user_obj.invitations > 0:
214
            code = generate_invitation_code()
215
            invitation, created = Invitation.objects.get_or_create(code=code)
216
            invitation.inviter=request.user_obj
217
            invitation.realname=request.POST.get('realname')
218
            invitation.uniq=request.POST.get('uniq')
219
            invitation.save()
220
            
221
            try:
222
                send_invitation(invitation)
223
                status = 'success'
224
                message = _('Invitation sent to %s' % invitation.uniq)
225
            except (SMTPException, socket.error) as e:
226
                status = 'error'
227
                message = e.strerror
228
        else:
229
            status = 'error'
230
            message = _('No invitations left')
231

    
232
    if request.GET.get('format') == 'json':
233
        rep = {'invitations': request.user_obj.invitations}
234
        return HttpResponse(json.dumps(rep))
235
    
236
    html = render_to_string('invitations.html', {
237
            'user': request.user_obj,
238
            'status': status,
239
            'message': message})
240
    return HttpResponse(html)