+++ /dev/null
-# 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
+++ /dev/null
-# 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
+++ /dev/null
-{% 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 %}
+++ /dev/null
-<!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>
-
+++ /dev/null
-{% 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 %}">← Previous</a></li>
- {% else %}
- <li class="prev disabled"><a href="#">← 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 %}">→ Next</a></li>
- {% else %}
- <li class="next disabled"><a href="#">→ 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 %}
+++ /dev/null
-{% 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 %}">← Previous</a></li>
- {% else %}
- <li class="prev disabled"><a href="#">← 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 %}">→ Next</a></li>
- {% else %}
- <li class="next disabled"><a href="#">→ Next</a></li>
- {% endif %}
- </ul>
-</div>
-{% endif %}
-
-<br /><br />
-{% endblock body %}
+++ /dev/null
-{% 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 %}
+++ /dev/null
-{% 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>
-
- <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 %}
+++ /dev/null
-{% 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 %}">← Previous</a></li>
- {% else %}
- <li class="prev disabled"><a href="#">← 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 %}">→ Next</a></li>
- {% else %}
- <li class="next disabled"><a href="#">→ 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 %}
+++ /dev/null
---- 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
+++ /dev/null
-# 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.conf.urls.defaults import patterns, url
-
-urlpatterns = patterns('astakos.im.admin.views',
- url(r'^$', 'admin'),
-
- url(r'^users/?$', 'users_list'),
- url(r'^users/(\d+)/?$', 'users_info'),
- url(r'^users/create$', 'users_create'),
- url(r'^users/(\d+)/modify/?$', 'users_modify'),
- url(r'^users/(\d+)/delete/?$', 'users_delete'),
- url(r'^users/export/?$', 'users_export'),
- url(r'^users/pending/?$', 'pending_users'),
- url(r'^users/activate/(\d+)/?$', 'users_activate'),
-
- url(r'^invitations/?$', 'invitations_list'),
- url(r'^invitations/export/?$', 'invitations_export'),
-)
\ No newline at end of file
+++ /dev/null
-# 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 socket
-import csv
-
-from functools import wraps
-from math import ceil
-from smtplib import SMTPException
-
-from django.http import HttpResponse, HttpResponseRedirect
-from django.shortcuts import redirect
-from django.template.loader import render_to_string
-from django.utils.http import urlencode
-from django.utils.translation import ugettext as _
-from django.core.urlresolvers import reverse
-from django.contrib import messages
-from django.db import transaction
-
-from astakos.im.models import AstakosUser, Invitation
-from astakos.im.util import get_context
-from astakos.im.forms import *
-from astakos.im.views import render_response, index
-from astakos.im.admin.forms import AdminProfileForm
-from astakos.im.admin.forms import AdminUserCreationForm
-from astakos.im.settings import BYPASS_ADMIN_AUTH, ADMIN_PAGE_LIMIT, DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL
-from astakos.im.admin.functions import activate
-
-def requires_admin(func):
- """
- Decorator checkes whether the request.user is a superuser and if not
- redirects to login page.
- """
- @wraps(func)
- def wrapper(request, *args):
- if not BYPASS_ADMIN_AUTH:
- if request.user.is_anonymous():
- next = urlencode({'next': request.build_absolute_uri()})
- login_uri = reverse(index) + '?' + next
- return HttpResponseRedirect(login_uri)
- if not request.user.is_superuser:
- return HttpResponse('Forbidden', status=403)
- return func(request, *args)
- return wrapper
-
-@requires_admin
-def admin(request, template_name='admin.html', extra_context={}):
- """
- Renders the admin page
-
- If the ``request.user`` is not a superuser redirects to login page.
-
- **Arguments**
-
- ``template_name``
- A custom template to use. This is optional; if not specified,
- this will default to ``admin.html``.
-
- ``extra_context``
- An dictionary of variables to add to the template context.
-
- **Template:**
-
- admin.html or ``template_name`` keyword argument.
-
- **Template Context:**
-
- The template context is extended by:
-
- * tab: the name of the active tab
- * stats: dictionary containing the number of all and prending users
- """
- stats = {}
- stats['users'] = AstakosUser.objects.count()
- stats['pending'] = AstakosUser.objects.filter(is_active = False).count()
-
- invitations = Invitation.objects.all()
- stats['invitations'] = invitations.count()
- stats['invitations_consumed'] = invitations.filter(is_consumed=True).count()
-
- kwargs = {'tab': 'home', 'stats': stats}
- context = get_context(request, extra_context,**kwargs)
- return render_response(template_name, context_instance = context)
-
-@requires_admin
-def users_list(request, template_name='users_list.html', extra_context={}):
- """
- Displays the list of all users.
-
- If the ``request.user`` is not a superuser redirects to login page.
-
- **Arguments**
-
- ``template_name``
- A custom template to use. This is optional; if not specified,
- this will default to ``users_list.html``.
-
- ``extra_context``
- An dictionary of variables to add to the template context.
-
- **Template:**
-
- users_list.html or ``template_name`` keyword argument.
-
- **Template Context:**
-
- The template context is extended by:
-
- * users: list of users fitting in current page
- * filter: search key
- * pages: the number of pages
- * prev: the previous page
- * next: the current page
-
- **Settings:**
-
- * ADMIN_PAGE_LIMIT: Show these many users per page in admin interface
- """
- users = AstakosUser.objects.order_by('id')
-
- filter = request.GET.get('filter', '')
- if filter:
- if filter.startswith('-'):
- users = users.exclude(username__icontains=filter[1:])
- else:
- users = users.filter(username__icontains=filter)
-
- try:
- page = int(request.GET.get('page', 1))
- except ValueError:
- page = 1
- offset = max(0, page - 1) * ADMIN_PAGE_LIMIT
- limit = offset + ADMIN_PAGE_LIMIT
-
- npages = int(ceil(1.0 * users.count() / ADMIN_PAGE_LIMIT))
- prev = page - 1 if page > 1 else None
- next = page + 1 if page < npages else None
-
- kwargs = {'users':users[offset:limit],
- 'filter':filter,
- 'pages':range(1, npages + 1),
- 'prev':prev,
- 'next':next}
- context = get_context(request, extra_context,**kwargs)
- return render_response(template_name, context_instance = context)
-
-@requires_admin
-def users_info(request, user_id, template_name='users_info.html', extra_context={}):
- """
- Displays the specific user profile.
-
- If the ``request.user`` is not a superuser redirects to login page.
-
- **Arguments**
-
- ``template_name``
- A custom template to use. This is optional; if not specified,
- this will default to ``users_info.html``.
-
- ``extra_context``
- An dictionary of variables to add to the template context.
-
- **Template:**
-
- users_info.html or ``template_name`` keyword argument.
-
- **Template Context:**
-
- The template context is extended by:
-
- * user: the user instance identified by ``user_id`` keyword argument
- """
- if not extra_context:
- extra_context = {}
- user = AstakosUser.objects.get(id=user_id)
- return render_response(template_name,
- form = AdminProfileForm(instance=user),
- user = user,
- context_instance = get_context(request, extra_context))
-
-@requires_admin
-def users_modify(request, user_id, template_name='users_info.html', extra_context={}):
- """
- Update the specific user information. Upon success redirects to ``user_info`` view.
-
- If the ``request.user`` is not a superuser redirects to login page.
- """
- user = AstakosUser.objects.get(id = user_id)
- form = AdminProfileForm(request.POST, instance=user)
- if form.is_valid():
- form.save()
- return users_info(request, user.id, template_name, extra_context)
- return render_response(template_name,
- form = form,
- context_instance = get_context(request, extra_context))
-
-@requires_admin
-def users_delete(request, user_id):
- """
- Deletes the specified user
-
- If the ``request.user`` is not a superuser redirects to login page.
- """
- user = AstakosUser.objects.get(id=user_id)
- user.delete()
- return redirect(users_list)
-
-@requires_admin
-def pending_users(request, template_name='pending_users.html', extra_context={}):
- """
- Displays the list of the pending users.
-
- If the ``request.user`` is not a superuser redirects to login page.
-
- **Arguments**
-
- ``template_name``
- A custom template to use. This is optional; if not specified,
- this will default to ``users_list.html``.
-
- ``extra_context``
- An dictionary of variables to add to the template context.
-
- **Template:**
-
- pending_users.html or ``template_name`` keyword argument.
-
- **Template Context:**
-
- The template context is extended by:
-
- * users: list of pending users fitting in current page
- * filter: search key
- * pages: the number of pages
- * prev: the previous page
- * next: the current page
-
- **Settings:**
-
- * ADMIN_PAGE_LIMIT: Show these many users per page in admin interface
- """
- users = AstakosUser.objects.order_by('id')
-
- users = users.filter(is_active = False)
-
- filter = request.GET.get('filter', '')
- if filter:
- if filter.startswith('-'):
- users = users.exclude(username__icontains=filter[1:])
- else:
- users = users.filter(username__icontains=filter)
-
- try:
- page = int(request.GET.get('page', 1))
- except ValueError:
- page = 1
- offset = max(0, page - 1) * ADMIN_PAGE_LIMIT
- limit = offset + ADMIN_PAGE_LIMIT
-
- npages = int(ceil(1.0 * users.count() / ADMIN_PAGE_LIMIT))
- prev = page - 1 if page > 1 else None
- next = page + 1 if page < npages else None
- kwargs = {'users':users[offset:limit],
- 'filter':filter,
- 'pages':range(1, npages + 1),
- 'page':page,
- 'prev':prev,
- 'next':next}
- return render_response(template_name,
- context_instance = get_context(request, extra_context,**kwargs))
-
-@requires_admin
-@transaction.commit_manually
-def users_activate(request, user_id, template_name='pending_users.html', extra_context={}, email_template_name='welcome_email.txt'):
- """
- Activates the specific user and sends an email. Upon success renders the
- ``template_name`` keyword argument if exists else renders ``pending_users.html``.
-
- If the ``request.user`` is not a superuser redirects to login page.
-
- **Arguments**
-
- ``template_name``
- A custom template to use. This is optional; if not specified,
- this will default to ``users_list.html``.
-
- ``extra_context``
- An dictionary of variables to add to the template context.
-
- **Templates:**
-
- pending_users.html or ``template_name`` keyword argument.
- welcome_email.txt or ``email_template_name`` keyword argument.
-
- **Template Context:**
-
- The template context is extended by:
-
- * users: list of pending users fitting in current page
- * filter: search key
- * pages: the number of pages
- * prev: the previous page
- * next: the current page
- """
- user = AstakosUser.objects.get(id=user_id)
- status = messages.SUCCESS
- try:
- activate(user, email_template_name)
- message = _('Greeting sent to %s' % user.email)
- transaction.commit()
- except (SMTPException, socket.error) as e:
- status = messages.ERROR
- name = 'strerror'
- message = getattr(e, name) if hasattr(e, name) else e
- transaction.rollback()
- messages.add_message(request, status, message)
-
- users = AstakosUser.objects.order_by('id')
- users = users.filter(is_active = False)
-
- try:
- page = int(request.POST.get('page', 1))
- except ValueError:
- page = 1
- offset = max(0, page - 1) * ADMIN_PAGE_LIMIT
- limit = offset + ADMIN_PAGE_LIMIT
-
- npages = int(ceil(1.0 * users.count() / ADMIN_PAGE_LIMIT))
- prev = page - 1 if page > 1 else None
- next = page + 1 if page < npages else None
- kwargs = {'users':users[offset:limit],
- 'filter':'',
- 'pages':range(1, npages + 1),
- 'page':page,
- 'prev':prev,
- 'next':next}
- return render_response(template_name,
- context_instance = get_context(request, extra_context,**kwargs))
-
-@requires_admin
-def invitations_list(request, template_name='invitations_list.html', extra_context={}):
- """
- Displays a list with the Invitations.
-
- If the ``request.user`` is not a superuser redirects to login page.
-
- **Arguments**
-
- ``template_name``
- A custom template to use. This is optional; if not specified,
- this will default to ``invitations_list.html``.
-
- ``extra_context``
- An dictionary of variables to add to the template context.
-
- **Templates:**
-
- invitations_list.html or ``template_name`` keyword argument.
-
- **Template Context:**
-
- The template context is extended by:
-
- * invitations: list of invitations fitting in current page
- * filter: search key
- * pages: the number of pages
- * prev: the previous page
- * next: the current page
- """
- invitations = Invitation.objects.order_by('id')
-
- filter = request.GET.get('filter', '')
- if filter:
- if filter.startswith('-'):
- invitations = invitations.exclude(username__icontains=filter[1:])
- else:
- invitations = invitations.filter(username__icontains=filter)
-
- try:
- page = int(request.GET.get('page', 1))
- except ValueError:
- page = 1
- offset = max(0, page - 1) * ADMIN_PAGE_LIMIT
- limit = offset + ADMIN_PAGE_LIMIT
-
- npages = int(ceil(1.0 * invitations.count() / ADMIN_PAGE_LIMIT))
- prev = page - 1 if page > 1 else None
- next = page + 1 if page < npages else None
- kwargs = {'invitations':invitations[offset:limit],
- 'filter':filter,
- 'pages':range(1, npages + 1),
- 'page':page,
- 'prev':prev,
- 'next':next}
- return render_response(template_name,
- context_instance = get_context(request, extra_context,**kwargs))
-
-@requires_admin
-def invitations_export(request):
- """
- Exports the invitation list in csv file.
- """
- # Create the HttpResponse object with the appropriate CSV header.
- response = HttpResponse(mimetype='text/csv')
- response['Content-Disposition'] = 'attachment; filename=invitations.csv'
-
- writer = csv.writer(response)
- writer.writerow(['ID',
- 'Username',
- 'Real Name',
- 'Code',
- 'Inviter username',
- 'Inviter Real Name',
- 'Is_accepted',
- 'Created',
- 'Consumed',])
- invitations = Invitation.objects.order_by('id')
- for inv in invitations:
-
- writer.writerow([inv.id,
- inv.username.encode("utf-8"),
- inv.realname.encode("utf-8"),
- inv.code,
- inv.inviter.username.encode("utf-8"),
- inv.inviter.realname.encode("utf-8"),
- inv.is_accepted,
- inv.created,
- inv.consumed])
-
- return response
-
-
-@requires_admin
-def users_export(request):
- """
- Exports the user list in csv file.
- """
- # Create the HttpResponse object with the appropriate CSV header.
- response = HttpResponse(mimetype='text/csv')
- response['Content-Disposition'] = 'attachment; filename=users.csv'
-
- writer = csv.writer(response)
- writer.writerow(['ID',
- 'Username',
- 'Real Name',
- 'Admin',
- 'Affiliation',
- 'Is active?',
- 'Quota (GiB)',
- 'Updated',])
- users = AstakosUser.objects.order_by('id')
- for u in users:
- writer.writerow([u.id,
- u.username.encode("utf-8"),
- u.realname.encode("utf-8"),
- u.is_superuser,
- u.affiliation.encode("utf-8"),
- u.is_active,
- u.quota,
- u.updated])
-
- return response
-
-@requires_admin
-def users_create(request, template_name='users_create.html', extra_context={}):
- """
- Creates a user. Upon success redirect to ``users_info`` view.
-
- **Arguments**
-
- ``template_name``
- A custom template to use. This is optional; if not specified,
- this will default to ``users_create.html``.
-
- ``extra_context``
- An dictionary of variables to add to the template context.
-
- **Templates:**
-
- users_create.html or ``template_name`` keyword argument.
- """
- if request.method == 'GET':
- form = AdminUserCreationForm()
- elif request.method == 'POST':
- form = AdminUserCreationForm(request.POST)
- if form.is_valid():
- try:
- user = form.save()
- return users_info(request, user.id)
- except ValueError, e:
- messages.add_message(request, messages.ERROR, e)
- return render_response(template_name,
- form = form,
- context_instance=get_context(request, extra_context))
+++ /dev/null
-# Copyright 2011-2012 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 astakos.im.settings import BACKEND_BLOCK_MODULE, BACKEND_BLOCK_PATH, BACKEND_DB_CONNECTION, BACKEND_DB_MODULE, BACKEND_QUOTA, BACKEND_VERSIONING
-
-from pithos.backends import connect_backend
-
-def get_backend():
- backend = connect_backend(db_module=BACKEND_DB_MODULE,
- db_connection=BACKEND_DB_CONNECTION,
- block_module=BACKEND_BLOCK_MODULE,
- block_path=BACKEND_BLOCK_PATH)
- backend.default_policy['quota'] = BACKEND_QUOTA
- backend.default_policy['versioning'] = BACKEND_VERSIONING
- return backend
-
-def get_quota(user):
- backend = get_backend()
- quota = backend.get_account_policy(user, user)['quota']
- backend.close()
- return quota
-
-def set_quota(user, quota):
- backend = get_backend()
- backend.update_account_policy(user, user, {'quota': quota})
- backend.close()
- return quota
from django.db import models
from django.contrib.auth.models import User, UserManager
-from astakos.im.interface import get_quota, set_quota
from astakos.im.settings import DEFAULT_USER_LEVEL, INVITATIONS_PER_LEVEL, AUTH_TOKEN_DURATION
class AstakosUser(User):
self.last_name = parts[0]
@property
- def quota(self):
- return get_quota(self.username)
-
- @quota.setter
- def quota(self, value):
- set_quota(self.username, value)
-
- @property
def invitation(self):
try:
return Invitation.objects.get(username=self.email)
# to be this many hours after their creation time.
AUTH_TOKEN_DURATION = getattr(settings, 'ASTAKOS_AUTH_TOKEN_DURATION', 30 * 24)
-# Bypass authentication for user administration.
-BYPASS_ADMIN_AUTH = getattr(settings, 'ASTAKOS_BYPASS_ADMIN_AUTH', False)
-
-# Show these many users per page in admin interface.
-ADMIN_PAGE_LIMIT = getattr(settings, 'ASTAKOS_ADMIN_PAGE_LIMIT', 100)
-
# Authenticate via Twitter.
TWITTER_KEY = getattr(settings, 'ASTAKOS_TWITTER_KEY', '')
TWITTER_SECRET = getattr(settings, 'ASTAKOS_TWITTER_SECRET', '')
# Set service name
SITENAME = getattr(settings, 'ASTAKOS_SITENAME', 'Pithos+')
-
-# SQLAlchemy (choose SQLite/MySQL/PostgreSQL).
-BACKEND_DB_MODULE = getattr(settings, 'PITHOS_BACKEND_DB_MODULE', 'pithos.backends.lib.sqlalchemy')
-BACKEND_DB_CONNECTION = getattr(settings, 'PITHOS_BACKEND_DB_CONNECTION', 'sqlite:///' + join(PROJECT_PATH, 'backend.db'))
-
-# Block storage.
-BACKEND_BLOCK_MODULE = getattr(settings, 'PITHOS_BACKEND_BLOCK_MODULE', 'pithos.backends.lib.hashfiler')
-BACKEND_BLOCK_PATH = getattr(settings, 'PITHOS_BACKEND_BLOCK_PATH', join(PROJECT_PATH, 'data/'))
-
-# Default setting for new accounts.
-BACKEND_QUOTA = getattr(settings, 'PITHOS_BACKEND_QUOTA', 50 * 1024 * 1024 * 1024)
-BACKEND_VERSIONING = getattr(settings, 'PITHOS_BACKEND_VERSIONING', 'auto')
url(r'^feedback/?$', 'send_feedback'),
url(r'^signup/?$', 'signup'),
url(r'^logout/?$', 'logout'),
- url(r'^activate/?$', 'activate'),
- url(r'^admin/', include('astakos.im.admin.urls')),
+ url(r'^activate/?$', 'activate')
)
urlpatterns += patterns('astakos.im.target',
if INVITATIONS_ENABLED:
urlpatterns += patterns('astakos.im.views',
- url(r'^invite/?$', 'invite'),
+ url(r'^invite/?$', 'invite')
)
if 'shibboleth' in IM_MODULES:
urlpatterns += patterns('astakos.im.api',
url(r'^authenticate/?$', 'authenticate')
)
-