1 # Copyright 2011 GRNET S.A. All rights reserved.
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
7 # 1. Redistributions of source code must retain the above
8 # copyright notice, this list of conditions and the following
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.
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.
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.
38 from datetime import datetime
39 from functools import wraps
41 from random import randint
42 from smtplib import SMTPException
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 _
52 from pithos.im.models import User, Invitation
53 from pithos.im.util import isoformat
56 def render_response(template, tab=None, status=200, **kwargs):
58 tab = template.partition('_')[0]
59 kwargs.setdefault('tab', tab)
60 html = render_to_string(template, kwargs)
61 return HttpResponse(html, status=status)
64 def requires_login(func):
66 def wrapper(request, *args):
67 if not settings.BYPASS_ADMIN_AUTH:
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)
76 def requires_admin(func):
78 def wrapper(request, *args):
79 if not settings.BYPASS_ADMIN_AUTH:
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)
91 # TODO: Get and pass on next variable.
92 return render_response('index.html')
98 stats['users'] = User.objects.count()
100 invitations = Invitation.objects.all()
101 stats['invitations'] = invitations.count()
102 stats['invitations_accepted'] = invitations.filter(is_accepted=True).count()
104 return render_response('admin.html', tab='home', stats=stats)
108 def users_list(request):
109 users = User.objects.order_by('id')
111 filter = request.GET.get('filter', '')
113 if filter.startswith('-'):
114 users = users.exclude(uniq__icontains=filter[1:])
116 users = users.filter(uniq__icontains=filter)
119 page = int(request.GET.get('page', 1))
122 offset = max(0, page - 1) * settings.ADMIN_PAGE_LIMIT
123 limit = offset + settings.ADMIN_PAGE_LIMIT
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],
131 pages=range(1, npages + 1),
138 def users_create(request):
139 if request.method == 'GET':
140 return render_response('users_create.html')
141 if request.method == 'POST':
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
150 return redirect(users_info, user.id)
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',
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')
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
180 return redirect(users_info, user.id)
184 def users_delete(request, user_id):
185 user = User.objects.get(id=user_id)
187 return redirect(users_list)
190 def generate_invitation_code():
191 return randint(1, 2L**63 - 1)
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', {
200 sender = settings.DEFAULT_FROM_EMAIL
201 send_mail(subject, message, sender, [inv.uniq])
202 inv.inviter.invitations = max(0, inv.inviter.invitations - 1)
204 logging.info('Sent invitation %s', inv)
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')
222 send_invitation(invitation)
224 message = _('Invitation sent to %s' % invitation.uniq)
225 except (SMTPException, socket.error) as e:
230 message = _('No invitations left')
232 if request.GET.get('format') == 'json':
233 rep = {'invitations': request.user_obj.invitations}
234 return HttpResponse(json.dumps(rep))
236 html = render_to_string('invitations.html', {
237 'user': request.user_obj,
240 return HttpResponse(html)