Commit 17bebf7e authored by Antony Chazapis's avatar Antony Chazapis
Browse files

Remove custom web admin.

Refs #1996
parent 28ff5b5d
# 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.
from django import forms
from django.utils.translation import ugettext as _
from astakos.im.models import AstakosUser
from astakos.im.forms import LocalUserCreationForm
import logging
logger = logging.getLogger(__name__)
class AdminProfileForm(forms.ModelForm):
"""
Subclass of ``ModelForm`` for permiting user to edit his/her profile.
Most of the fields are readonly since the user is not allowed to change them.
The class defines a save method which sets ``is_verified`` to True so as the user
during the next login will not to be redirected to profile page.
"""
quota = forms.CharField(label=_('Quota (GiB)'))
class Meta:
model = AstakosUser
fields = ('email', 'first_name', 'last_name', 'is_superuser',
'affiliation', 'is_active', 'invitations', 'quota',
'auth_token', 'auth_token_created', 'auth_token_expires',
'date_joined', 'updated')
def __init__(self, *args, **kwargs):
super(AdminProfileForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
ro_fields = ('date_joined', 'auth_token', 'auth_token_created',
'auth_token_expires', 'updated', 'email')
if instance and instance.id:
for field in ro_fields:
self.fields[field].widget.attrs['readonly'] = True
user = kwargs['instance']
if user:
quota = lambda x: int(x) / 1024 ** 3
self.fields['quota'].widget.attrs['value'] = quota(user.quota)
def save(self, commit=True):
user = super(AdminProfileForm, self).save(commit=False)
quota = lambda x: int(x or 0) * (1024 ** 3)
user.quota = quota(self.cleaned_data['quota'])
user.save()
class AdminUserCreationForm(LocalUserCreationForm):
class Meta:
model = AstakosUser
fields = ("email", "first_name", "last_name", "is_superuser",
"is_active", "affiliation")
def __init__(self, *args, **kwargs):
"""
Changes the order of fields, and removes the username field.
"""
super(AdminUserCreationForm, self).__init__(*args, **kwargs)
self.fields.keyOrder = ['email', 'first_name', 'last_name',
'is_superuser', 'is_active', 'affiliation',
'password1', 'password2']
def save(self, commit=True):
user = super(AdminUserCreationForm, self).save(commit=False)
user.renew_token()
if commit:
user.save()
logger.info('Created user %s', user)
return user
\ No newline at end of file
# 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 logging
from django.utils.translation import ugettext as _
from django.template.loader import render_to_string
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
from urlparse import urljoin
from random import randint
from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, SITEURL, SITENAME, BASEURL
from astakos.im.models import Invitation
logger = logging.getLogger(__name__)
def activate(user, email_template_name='welcome_email.txt'):
"""
Activates the specific user and sends email.
Raises SMTPException, socket.error
"""
user.is_active = True
user.save()
subject = _('Welcome to %s' % SITENAME)
message = render_to_string(email_template_name, {
'user': user,
'url': SITEURL,
'baseurl': BASEURL,
'site_name': SITENAME,
'support': DEFAULT_CONTACT_EMAIL % SITENAME.lower()})
sender = DEFAULT_FROM_EMAIL % SITENAME
send_mail(subject, message, sender, [user.email])
logger.info('Sent greeting %s', user)
def _generate_invitation_code():
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
def invite(inviter, username, realname):
"""
Send an invitation email and upon success reduces inviter's invitation by one.
Raises SMTPException, socket.error
"""
code = _generate_invitation_code()
invitation = Invitation(inviter=inviter,
username=username,
code=code,
realname=realname)
invitation.save()
subject = _('Invitation to %s' % SITENAME)
url = '%s?code=%d' % (urljoin(BASEURL, reverse('astakos.im.views.signup')), code)
message = render_to_string('im/invitation.txt', {
'invitation': invitation,
'url': url,
'baseurl': BASEURL,
'service': SITENAME,
'support': DEFAULT_CONTACT_EMAIL % SITENAME.lower()})
sender = DEFAULT_FROM_EMAIL % SITENAME
send_mail(subject, message, sender, [invitation.username])
logger.info('Sent invitation %s', invitation)
inviter.invitations = max(0, inviter.invitations - 1)
inviter.save()
\ No newline at end of file
{% extends "admin_base.html" %}
{% block body %}
<ul class="unstyled">
<li><strong>{{ stats.users }}</strong> User{{ stats.users|pluralize }} (<strong>{{ stats.pending }}</strong> pending)</li>
<li><strong>{{ stats.invitations }}</strong> Invitation{{ stats.invitations|pluralize }} sent (<strong>{{ stats.invitations_consumed }}</strong> used)</li>
</ul>
{% endblock body %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>{{ title|default:"Astakos Login" }}</title>
<link rel="stylesheet" href="{{ IM_STATIC_URL }}css/bootstrap.css">
<script src="{{ IM_STATIC_URL }}js/jquery.js"></script>
<script src="{{ IM_STATIC_URL }}js/jquery.tablesorter.js"></script>
<script src="{{ IM_STATIC_URL }}js/main.js"></script>
{% block head %}{% endblock %}
</head>
<body>
<div class="container">
<div style="padding: 5px 0px 0px 0px">
<img src="{{ IM_STATIC_URL }}images/banner.png" width="900" height="200">
</div>
{% block title %}{% endblock %}
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="alert-message.{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% block tabs %}
<ul class="tabs">
<li{% ifequal tab "admin" %} class="active"{% endifequal %}>
<a href="{% url astakos.im.admin.views.admin %}">Home</a>
</li>
<li{% ifequal tab "users" %} class="active"{% endifequal %}>
<a href="{% url astakos.im.admin.views.users_list %}">Users</a>
</li>
<li{% ifequal tab "pending" %} class="active"{% endifequal %}>
<a href="{% url astakos.im.admin.views.pending_users %}">Pending Users</a>
</li>
<li{% ifequal tab "invitations" %} class="active"{% endifequal %}>
<a href="{% url astakos.im.admin.views.invitations_list %}">Invitations</a>
</li>
<li{% ifequal tab "logout" %} class="active"{% endifequal %}>
<a href="{% url astakos.im.views.logout %}">Logout</a>
</li>
</ul>
{% endblock %}
{% block body %}{% endblock %}
</div>
</body>
</html>
{% extends "admin_base.html" %}
{% load formatters %}
{% block body %}
<div class="row">
<div class="offset10 span3">
<form method="get">
<div class="input">
<input class="span3" name="filter" type="search" placeholder="search" value="{{ filter }}">
</div>
</form>
</div>
</div>
<table class="zebra-striped id-sorted">
<thead>
<tr>
<th>ID</th>
<th>Email</th>
<th>Real Name</th>
<th>Code</th>
<th>Inviter email</th>
<th>Inviter Real Name</th>
<th>Is used?</th>
<th>Created</th>
<th>Consumed</th>
</tr>
</thead>
<tbody>
{% for inv in invitations %}
<tr>
<td>{{ inv.id }}</td>
<td>{{ inv.username }}</td>
<td>{{ inv.realname }}</td>
<td>{{ inv.code }}</td>
<td>{{ inv.inviter.email }}</td>
<td>{{ inv.inviter.realname }}</td>
<td>{{ inv.is_consumed }}</td>
<td>{{ inv.created }}</td>
<td>{{ inv.consumed }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if pages|length > 1 %}
<div class="pagination">
<ul>
{% if prev %}
<li class="prev"><a href="?page={{ prev }}{% if filter %}&filter={{ filter }}{% endif %}">&larr; Previous</a></li>
{% else %}
<li class="prev disabled"><a href="#">&larr; Previous</a></li>
{% endif %}
{% for p in pages %}
<li{% if page == p %} class="active"{% endif %}><a href="?page={{ p }}{% if filter %}&filter={{ filter }}{% endif %}">{{ p }}</a></li>
{% endfor %}
{% if next %}
<li class="next"><a href="?page={{ next }}{% if filter %}&filter={{ filter }}{% endif %}">&rarr; Next</a></li>
{% else %}
<li class="next disabled"><a href="#">&rarr; Next</a></li>
{% endif %}
</ul>
</div>
{% endif %}
<a class="btn success" href="{% url astakos.im.admin.views.invitations_export %}">Export</a>
<br /><br />
{% endblock body %}
{% extends "admin_base.html" %}
{% load formatters %}
{% block body %}
<div class="row">
<div class="offset10 span3">
<form method="get">
<div class="input">
<input class="span3" name="filter" type="search" placeholder="search" value="{{ filter }}">
</div>
</form>
</div>
</div>
<table class="zebra-striped id-sorted">
<thead>
<tr>
<th>ID</th>
<th>Email</th>
<th>Real Name</th>
<th>Affiliation</th>
<th>Email</th>
<th>Inviter</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{ user.id }}</td>
<td>{{ user.email }}</td>
<td>{{ user.realname }}</td>
<td>{{ user.affiliation }}</td>
<td>{{ user.email }}</td>
<td>{{ user.inviter.realname }}</td>
<td>
<form action="{% url astakos.im.admin.views.users_activate user.id %}" method="post">{% csrf_token %}
<input type="hidden" name="page" value="{{ page }}">
<button type="submit" class="btn primary">Activate</button>
</form>
</tr>
{% endfor %}
</tbody>
</table>
{% if pages|length > 1 %}
<div class="pagination">
<ul>
{% if prev %}
<li class="prev"><a href="?page={{ prev }}{% if filter %}&filter={{ filter }}{% endif %}">&larr; Previous</a></li>
{% else %}
<li class="prev disabled"><a href="#">&larr; Previous</a></li>
{% endif %}
{% for p in pages %}
<li{% if page == p %} class="active"{% endif %}><a href="?page={{ p }}{% if filter %}&filter={{ filter }}{% endif %}">{{ p }}</a></li>
{% endfor %}
{% if next %}
<li class="next"><a href="?page={{ next }}{% if filter %}&filter={{ filter }}{% endif %}">&rarr; Next</a></li>
{% else %}
<li class="next disabled"><a href="#">&rarr; Next</a></li>
{% endif %}
</ul>
</div>
{% endif %}
<br /><br />
{% endblock body %}
{% extends "admin_base.html" %}
{% block body %}
<form action="{% url astakos.im.admin.views.users_create %}" method="post">{% csrf_token %}
{{ form.as_p }}
<div class="actions">
<button type="submit" class="btn primary">Create</button>
<button type="reset" class="btn">Reset</button>
</div>
</form>
{% endblock body %}
{% extends "admin_base.html" %}
{% load formatters %}
{% block body %}
<form action="{% url astakos.im.admin.views.users_modify user.id %}" method="post">{% csrf_token %}
{{ form.as_p }}
<div class="actions">
<button type="submit" class="btn primary">Save Changes</button>
<button type="reset" class="btn">Reset</button>
&nbsp;&nbsp;
<a class="btn danger needs-confirm" href="{% url astakos.im.admin.views.users_delete user.id %}">Delete User</a>
</div>
<div class="alert-message block-message error">
<p><strong>WARNING:</strong> Are you sure you want to delete this user?</p>
<div class="alert-actions">
<a class="btn danger" href="{% url astakos.im.admin.views.users_delete user.id %}">Delete</a>
<a class="btn alert-close">Cancel</a>
</div>
</div>
</form>
{% endblock body %}
{% extends "admin_base.html" %}
{% load formatters %}
{% block body %}
<div class="row">
<div class="offset10 span3">
<form method="get">
<div class="input">
<input class="span3" name="filter" type="search" placeholder="search" value="{{ filter }}">
</div>
</form>
</div>
</div>
<table class="zebra-striped id-sorted">
<thead>
<tr>
<th>ID</th>
<th>Email</th>
<th>Real Name</th>
<th>Admin</th>
<th>Affiliation</th>
<th>Is active?</th>
<th>Quota</th>
<th>Updated</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td><a href="{% url astakos.im.admin.views.users_info user.id %}">{{ user.id }}</a></td>
<td><a href="{% url astakos.im.admin.views.users_info user.id %}">{{ user.email }}</a></td>
<td>{{ user.realname }}</td>
<td>{{ user.is_superuser }}</td>
<td>{{ user.affiliation }}</td>
<td>{{ user.is_active }}</td>
<td>{{ user.quota|GiB }} GiB</td>
<td>{{ user.updated }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if pages|length > 1 %}
<div class="pagination">
<ul>
{% if prev %}
<li class="prev"><a href="?page={{ prev }}{% if filter %}&filter={{ filter }}{% endif %}">&larr; Previous</a></li>
{% else %}
<li class="prev disabled"><a href="#">&larr; Previous</a></li>
{% endif %}
{% for p in pages %}
<li{% if page == p %} class="active"{% endif %}><a href="?page={{ p }}{% if filter %}&filter={{ filter }}{% endif %}">{{ p }}</a></li>
{% endfor %}
{% if next %}
<li class="next"><a href="?page={{ next }}{% if filter %}&filter={{ filter }}{% endif %}">&rarr; Next</a></li>
{% else %}
<li class="next disabled"><a href="#">&rarr; Next</a></li>
{% endif %}
</ul>
</div>
{% endif %}
<a class="btn success" href="{% url astakos.im.admin.views.users_create %}">Create a user</a>
<a class="btn success" href="{% url astakos.im.admin.views.users_export %}">Export</a>
<br /><br />
{% endblock body %}
--- A translation in English follows ---
Αγαπητέ/η {{ user.realname }},
Ο λογαρισμός σας για την υπηρεσία {{ site_name }} της ΕΔΕΤ κατά την Alpha (πιλοτική)
φάση λειτουργίας της έχει ενεργοποιηθεί.
Για να συνδεθείτε, χρησιμοποιήστε τον παρακάτω σύνδεσμο:
{{ url }}
Σημείωση:
Η υπηρεσία θα είναι για μερικές εβδομάδες σε φάση λειτουργίας Alpha. Αν
και έχουμε κάνει ό,τι είναι δυνατό για να εξασφαλίσουμε την ποιότητα της
υπηρεσίας, δεν αποκλείεται να εμφανιστούν προβλήματα στο λογισμικό
διαχείρισης ή η υπηρεσία να μην είναι διαθέσιμη κατά διαστήματα. Για
αυτό το λόγο, σας παρακαλούμε να μη μεταφέρετε ακόμη σημαντικά αρχεία
στην υπηρεσία {{ site_name }}. Επίσης, παρακαλούμε να έχετε
υπόψη σας ότι όλα τα δεδομένα, θα διαγραφούν κατά τη μετάβαση από την
έκδοση Alpha στην έκδοση Beta. Θα υπάρξει έγκαιρη ειδοποίησή σας πριν
από τη μετάβαση αυτή.
Περισσότερα για την υπηρεσία θα βρείτε στο {{ baseurl }}, αφού
ενεργοποιήσετε την πρόσκλησή σας.
Αναμένουμε τα σχόλια και τις παρατηρήσεις σας, για να βελτιώσουμε τη
λειτουργικότητα και την αξιοπιστία της καινοτομικής αυτής υπηρεσίας.
Για όποιες παρατηρήσεις ή προβλήματα στη λειτουργεία της υπηρεσίας μπορείτε να
απευθυνθείτε στο {{ support }}.
Σας ευχαριστούμε πολύ για τη συμμετοχή στην Alpha λειτουργία του {{ site_name }}.
Με εκτίμηση,
Εθνικό Δίκτυο Έρευνας και Τεχνολογίας (ΕΔΕΤ/GRNET)
--
Dear {{ user.realname }},
Your account for GRNET's {{ site_name }} service for its Alpha test phase has been
activated.
To login, please use the following link:
{{ url }}
Please note:
This service is, for a few weeks, in Alpha. Although every care has been
taken to ensure high quality, it is possible there may still be software
bugs, or periods of limited service availability. For this reason we kindly
request you not to transfer important files to {{ site_name}} yet.
Also, please bear in mind that all data will be deleted when the service moves to Beta.
We will notify you before the transition.
For more information, please visit {{ baseurl }}, after
activating your invitation.
We look forward to your feedback, to improve the functionality and
reliability of this innovative service.
For any remarks or problems you can contact {{ support }}.
Thank you for participating in the Alpha test of {{ site_name }}.
Greek Research and Technonogy Network - GRNET
# 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