.project
.pydevproject
snf-astakos-app/astakos/version.py
++snf-astakos-app/distribute-0.6.10-py2.6.egg
++snf-astakos-app/distribute-0.6.10.tar.gz
ASTAKOS_GREETING_EMAIL_SUBJECT 'Welcome to %s alpha2 testing' % SITENAME Welcome email subject
ASTAKOS_FEEDBACK_EMAIL_SUBJECT 'Feedback from %s alpha2 testing' % SITENAME Feedback email subject
ASTAKOS_VERIFICATION_EMAIL_SUBJECT '%s alpha2 testing account activation is needed' % SITENAME Account activation email subject
--ASTAKOS_ADMIN_NOTIFICATION_EMAIL_SUBJECT '%s alpha2 testing account created (%%(user)s)' % SITENAME Account creation admin notification email subject
++ASTAKOS_ACCOUNT_CREATION_SUBJECT = getattr(settings, 'ASTAKOS_ACCOUNT_CREATION_SUBJECT',
++ '%s alpha2 testing account created (%%(user)s)' % SITENAME)
++ASTAKOS_GROUP_CREATION_SUBJECT = getattr(settings, 'ASTAKOS_',
++ '%s alpha2 testing group created (%%(group)s)' % SITENAME)
ASTAKOS_HELPDESK_NOTIFICATION_EMAIL_SUBJECT '%s alpha2 testing account activated (%%(user)s)' % SITENAME Account activation helpdesk notification email subject
ASTAKOS_EMAIL_CHANGE_EMAIL_SUBJECT 'Email change on %s alpha2 testing' % SITENAME Email change subject
ASTAKOS_PASSWORD_RESET_EMAIL_SUBJECT 'Password reset on %s alpha2 testing' % SITENAME Password change email subject
from astakos.im.models import AstakosUser
from astakos.im.forms import LocalUserCreationForm, ShibbolethUserCreationForm
from astakos.im.util import get_invitation
--from astakos.im.functions import send_verification, send_activation, \
-- send_admin_notification, activate
++from astakos.im.functions import (send_verification, send_activation,
++ send_account_creation_notification,
++ send_group_creation_notification, activate)
from astakos.im.settings import INVITATIONS_ENABLED, MODERATION_ENABLED, SITENAME, RE_USER_EMAIL_PATTERNS
import logging
send_activation(user, activation_template_name)
return VerificationSent()
else:
-- send_admin_notification(
++ send_account_creation_notification(
template_name=admin_email_template_name,
-- dictionary={'user': user, 'group_creation': True},
-- subject='%s alpha2 testing account notification' % SITENAME
++ dictionary={'user': user, 'group_creation': True}
)
return NotificationSent()
except BaseException, e:
item = MenuItem
item.current_path = absolute(request, request.path)
append(item(
-- url=absolute(request, reverse('index')),
-- name=user.email))
++ url=absolute(request, reverse('index')),
++ name=user.email))
append(item(url=absolute(request, reverse('edit_profile')),
name="My account"))
if with_extra_links:
if user.has_usable_password() and user.provider in ('local', ''):
append(item(
-- url=absolute(request, reverse('password_change')),
-- name="Change password"))
++ url=absolute(request, reverse('password_change')),
++ name="Change password"))
if EMAILCHANGE_ENABLED:
append(item(
-- url=absolute(request, reverse('email_change')),
-- name="Change email"))
++ url=absolute(request, reverse('email_change')),
++ name="Change email"))
if INVITATIONS_ENABLED:
append(item(
-- url=absolute(request, reverse('invite')),
-- name="Invitations"))
++ url=absolute(request, reverse('invite')),
++ name="Invitations"))
append(item(
-- url=absolute(request, reverse('feedback')),
-- name="Feedback"))
++ url=absolute(request, reverse('feedback')),
++ name="Feedback"))
append(item(
-- url=absolute(request, reverse('group_list')),
-- name="Groups",
-- submenu=(item(
-- url=absolute(request,
-- reverse('group_list')),
-- name="Overview"),
++ url=absolute(request, reverse('group_list')),
++ name="Groups",
++ submenu=(item(
++ url=absolute(request,
++ reverse('group_list')),
++ name="Overview"),
item(
url=absolute(request,
reverse('group_create_list')),
reverse('group_search')),
name="Join"),)))
append(item(
-- url=absolute(request, reverse('resource_list')),
-- name="Resources"))
++ url=absolute(request, reverse('resource_list')),
++ name="Resources"))
append(item(
-- url=absolute(request, reverse('billing')),
-- name="Billing"))
++ url=absolute(request, reverse('billing')),
++ name="Billing"))
append(item(
-- url=absolute(request, reverse('timeline')),
-- name="Timeline"))
++ url=absolute(request, reverse('timeline')),
++ name="Timeline"))
if with_signout:
append(item(
-- url=absolute(request, reverse('logout')),
-- name="Sign out"))
++ url=absolute(request, reverse('logout')),
++ name="Sign out"))
callback = request.GET.get('callback', None)
data = json.dumps(tuple(l))
--- /dev/null
--- /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.api.backends.lib.django import DjangoBackend
++
++
++def get_backend():
++ return DjangoBackend()
--- /dev/null
--- /dev/null
++class ItemNotExists(NameError):
++ pass
++
++
++class ItemExists(NameError):
++ pass
++
++
++class MissingIdentifier(IOError):
++ pass
++
++
++class BaseBackend(object):
++ def update_user():
++ pass
++
++ def create_user():
++ pass
--- /dev/null
--- /dev/null
--- /dev/null
--- /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 django.db import IntegrityError, transaction
++from django.core.exceptions import ObjectDoesNotExist
++
++from functools import wraps
++from smtplib import SMTPException
++
++from astakos.im.models import AstakosUser, Resource, Service, RESOURCE_SEPARATOR
++from astakos.im.api.backends.base import (BaseBackend, ItemNotExists,
++ ItemExists, MissingIdentifier)
++from astakos.im.util import reserved_email, model_to_dict
++from astakos.im.endpoints.quotaholder import get_quota
++
++import logging
++
++logger = logging.getLogger(__name__)
++
++DEFAULT_CONTENT_TYPE = None
++
++
++def safe(propagate_exceptions=False):
++ """Decorator function for views that implement an API method."""
++
++ def decorator(func):
++ @transaction.commit_manually
++ @wraps(func)
++ def wrapper(self, *args, **kwargs):
++ logger.debug('%s %s %s' % (func, args, kwargs))
++ try:
++ r = func(self, *args, **kwargs) or ()
++ except Exception, e:
++ logger.exception(e)
++ transaction.rollback()
++ if propagate_exceptions:
++ raise e
++ else:
++ args = list(args)
++ args.append(e)
++ r = args
++ else:
++ transaction.commit()
++ r = filter(bool, r) # filter out None elements
++ return list(r)
++ return wrapper
++ return decorator
++
++
++class DjangoBackend(BaseBackend):
++ def _lookup_object(self, model, **kwargs):
++ """
++ Returns an object of the specific model having this id.
++ """
++ if not kwargs:
++ raise MissingIdentifier
++ try:
++ return model.objects.get(**kwargs)
++ except model.DoesNotExist:
++ raise ItemNotExists()
++
++ def _lookup_user(self, id):
++ """
++ Returns an AstakosUser having this id.
++ """
++ return self._lookup_object(AstakosUser, id=id)
++
++ def _lookup_service(self, id):
++ """
++ Returns an Service having this id.
++ """
++ return self._lookup_object(Service, id=id)
++
++ def _list(self, model, filter=()):
++ q = model.objects.all()
++ if filter:
++ q = q.filter(id__in=filter)
++ return map(lambda o: model_to_dict(o, exclude=[]), q)
++
++ def _create_object(self, model, **kwargs):
++ o = model(**kwargs)
++ o.save()
++ return o
++
++ def _update_object(self, model, id, save=True, **kwargs):
++ o = self._lookup_object(model, id=id)
++ if kwargs:
++ o.__dict__.update(kwargs)
++ if save:
++ o.save()
++ return o
++
++ @safe()
++ def update_user(self, user_id, renew_token=False, **kwargs):
++ user = self._update_object(AstakosUser, user_id, save=False, **kwargs)
++ if renew_token:
++ user.renew_token()
++ if kwargs or renew_token:
++ user.save()
++
++ @safe()
++ def create_user(self, **kwargs):
++ policies = kwargs.pop('policies', ())
++ permissions = kwargs.pop('permissions', ())
++ groups = kwargs.pop('groups', ())
++ password = kwargs.pop('password', None)
++
++ u = self._create_object(AstakosUser, **kwargs)
++
++ if password:
++ u.set_password(password)
++ u.permissions = permissions
++ u.policies = policies
++ u.extended_groups = groups
++
++ @safe()
++ def add_policies(self, user_id, update=False, policies=()):
++ user = self._lookup_user(user_id)
++ rejected = []
++ append = rejected.append
++ for p in policies:
++ service = p.get('service')
++ resource = p.get('resource')
++ uplimit = p.get('uplimit')
++ try:
++ user.add_policy(service, resource, uplimit, update)
++ except (ObjectDoesNotExist, IntegrityError), e:
++ append((service, resource, e))
++ if rejected:
++ raise Exception(rejected)
++
++ @safe()
++ def remove_policies(self, user_id, policies=()):
++ user = self._lookup_user(user_id)
++ if not user:
++ return user_id
++ rejected = []
++ append = rejected.append
++ for p in policies:
++ service = p.get('service')
++ resource = p.get('resource')
++ try:
++ user.delete_policy(service, resource)
++ except ObjectDoesNotExist, e:
++ append((service, resource, e))
++ if rejected:
++ raise Exception(rejected)
++
++ @safe()
++ def add_permissions(self, user_id, permissions=()):
++ user = self._lookup_user(user_id)
++ rejected = []
++ append = rejected.append
++ for p in permissions:
++ try:
++ user.add_permission(p)
++ except IntegrityError, e:
++ append((p, e))
++ if rejected:
++ raise Exception(rejected)
++
++ @safe()
++ def remove_permissions(self, user_id, permissions=()):
++ user = self._lookup_user(user_id)
++ rejected = []
++ append = rejected.append
++ for p in permissions:
++ try:
++ user.remove_permission(p)
++ except (ObjectDoesNotExist, IntegrityError), e:
++ append((p, e))
++ if rejected:
++ raise Exception(rejected)
++
++ @safe()
++ def invite_users(self, senderid, recipients=()):
++ user = self._lookup_user(senderid)
++ rejected = []
++ append = rejected.append
++ for r in recipients:
++ try:
++ user.invite(r.get('email'), r.get('realname'))
++ except (IntegrityError, SMTPException), e:
++ append((email, e))
++ if rejected:
++ raise Exception(rejected)
++
++ @safe(propagate_exceptions=True)
++ def list_users(self, filter=()):
++ return self._list(AstakosUser, filter=filter)
++
++ @safe(propagate_exceptions=True)
++ def get_resource_usage(self, user_id):
++ user = self._lookup_user(user_id)
++ c, data = get_quota((user,))
++ resources = []
++ append = resources.append
++ for t in data:
++ t = (i if i else 0 for i in t)
++ (entity, name, quantity, capacity, importLimit, exportLimit,
++ imported, exported, returned, released, flags) = t
++ service, sep, resource = name.partition(RESOURCE_SEPARATOR)
++ resource = Resource.objects.select_related().get(
++ service__name=service, name=resource)
++ d = dict(name=name,
++ description=resource.desc,
++ unit=resource.unit.name if resource.unit else '',
++ maxValue=quantity + capacity,
++ currValue=quantity + imported - released - exported + returned)
++ append(d)
++ return resources
++
++ @safe(propagate_exceptions=True)
++ def list_resources(self, filter=()):
++ return self._list(Resource, filter=filter)
++
++ @safe()
++ def create_service(self, **kwargs):
++ resources = kwargs.pop('resources', ())
++ s = self._create_object(Service, **kwargs)
++ s.resources = resources
++
++ @safe()
++ def remove_services(self, ids=()):
++ # TODO return information for unknown ids
++ q = Service.objects.filter(id__in=ids)
++ q.delete()
++
++ @safe()
++ def update_service(self, service_id, renew_token=False, **kwargs):
++ s = self._update_object(Service, service_id, save=False, **kwargs)
++ if renew_token:
++ s.renew_token()
++
++ if kwargs or renew_token:
++ s.save()
++
++ @safe()
++ def add_resources(self, service_id, update=False, resources=()):
++ s = self._lookup_service(service_id)
++ rejected = []
++ append = rejected.append
++ for r in resources:
++ try:
++ rr = r.copy()
++ resource_id = rr.pop('id', None)
++ if update:
++ if not resource_id:
++ raise MissingIdentifier
++ resource = self._update_object(Resource, resource_id, **rr)
++ else:
++ resource = self._create_object(Resource, service=s, **rr)
++ except Exception, e:
++ append((r, e))
++ if rejected:
++ raise Exception(rejected)
++
++ @safe()
++ def remove_resources(self, service_id, ids=()):
++ # TODO return information for unknown ids
++ q = Resource.objects.filter(service__id=service_id,
++ id__in=ids)
++ q.delete()
++
++ @safe()
++ def create_group(self, **kwargs):
++ policies = kwargs.pop('policies', ())
++ permissions = kwargs.pop('permissions', ())
++ members = kwargs.pop('members', ())
++ owners = kwargs.pop('owners', ())
++
++ g = self._create_object(AstakosGroup, **kwargs)
++
++ g.permissions = permissions
++ g.policies = policies
++ g.members = members
++ g.owners = owners
--- /dev/null
--- /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.api.spec import AstakosAPI
++from backends import get_backend
++
++from commissioning import (Callpoint,
++ # CommissionException,
++ # CorruptedError, InvalidDataError,
++ # InvalidKeyError, NoEntityError,
++ # NoQuantityError, NoCapacityError,
++ # ExportLimitError, ImportLimitError
++ )
++
++
++# from commissioning.utils.newname import newname
++# from django.db.models import Model, BigIntegerField, CharField, ForeignKey, Q
++# from django.db import transaction, IntegrityError
++# from .models import (Holder, Entity, Policy, Holding,
++# Commission, Provision, ProvisionLog, now)
++
++class AstakosDjangoDBCallpoint():
++
++ api_spec = AstakosAPI()
++
++# http_exc_lookup = {
++# CorruptedError: 550,
++# InvalidDataError: 400,
++# InvalidKeyError: 401,
++# NoEntityError: 404,
++# NoQuantityError: 413,
++# NoCapacityError: 413,
++# }
++
++ def init_connection(self, connection):
++ if connection is not None:
++ raise ValueError("Cannot specify connection args with %s" %
++ type(self).__name__)
++ pass
++
++ def commit(self):
++ transaction.commit()
++
++ def rollback(self):
++ transaction.rollback()
++
++ def do_make_call(self, call_name, data):
++ call_fn = getattr(self, call_name, None)
++ if not call_fn:
++ m = "cannot find call '%s'" % (call_name,)
++ raise CorruptedError(m)
++
++ return call_fn(**data)
++
++ def create_users(self, users=()):
++ b = get_backend()
++ rejected = (b.create_user(**u) for u in users)
++ return rejected
++
++ def update_users(self, users=()):
++ b = get_backend()
++ rejected = (b.update_user(**u) for u in users)
++ return rejected
++
++ def add_user_policies(self, user_id, update=False, policies=()):
++ b = get_backend()
++ rejected = b.add_policies(user_id, update, policies)
++ return rejected
++
++ def remove_user_policies(self, user_id, policies=()):
++ b = get_backend()
++ rejected = b.remove_policies(user_id, policies)
++ return rejected
++
++ def add_user_permissions(self, user_id, permissions=()):
++ b = get_backend()
++ rejected = b.add_permissions(user_id, permissions)
++ return rejected
++
++ def remove_user_permissions(self, user_id, permissions=()):
++ b = get_backend()
++ rejected = b.remove_permissions(user_id, permissions)
++ return rejected
++
++ def invite_users(self, sender_id, recipients=()):
++ b = get_backend()
++ rejected = b.invite_users(sender_id, recipients)
++ return rejected
++
++ def list_users(self, filter=()):
++ b = get_backend()
++ return b.list_users(filter)
++
++ def get_user_status(self, user_id):
++ b = get_backend()
++ return b.get_resource_usage(user_id)
++
++ def list_resources(self, filter=()):
++ b = get_backend()
++ return b.list_resources(filter)
++
++ def add_services(self, services=()):
++ b = get_backend()
++ rejected = (b.create_service(**s) for s in services)
++ return rejected
++
++ def update_services(self, services=()):
++ b = get_backend()
++ rejected = (b.update_service(**s) for s in services)
++ return rejected
++
++ def remove_services(self, ids=()):
++ b = get_backend()
++ rejected = b.remove_services(ids)
++ return rejected
++
++ def add_resources(self, service_id, update=False, resources=()):
++ b = get_backend()
++ rejected = b.add_resources(service_id, update, resources)
++ return rejected
++
++ def remove_resources(self, service_id, ids=()):
++ b = get_backend()
++ rejected = b.remove_resources(service_id, ids)
++ return rejected
++
++ def create_groups(self, groups=()):
++ b = get_backend()
++ rejected = (b.create_group(**g) for g in groups)
++ return rejected
++
++API_Callpoint = AstakosDjangoDBCallpoint
--- /dev/null
--- /dev/null
++#!/usr/bin/env python
++from commissioning.clients.http import main, HTTP_API_Client
++from astakos.im.api.spec import AstakosAPI
++
++
++class AstakosHTTP(HTTP_API_Client):
++ api_spec = AstakosAPI()
++
++
++if __name__ == '__main__':
++ main(callpoint=AstakosHTTP())
--- /dev/null
--- /dev/null
++from commissioning.api.specificator import (
++ CanonifyException, SpecifyException,
++ Specificator, Null, Integer, Text,
++ Tuple, ListOf, Dict, Args)
++
++
++class Name(Text):
++ def init(self):
++ self.opts.update({'regex': "[\w.:]+", 'maxlen': 512})
++Name = Name()
++
++
++class Email(Text):
++ def init(self):
++ pattern = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"
++ self.opts.update({'regex': pattern, 'maxlen': 512})
++Email = Email()
++
++
++class Url(Text):
++ def init(self):
++ pattern = "(((f|ht){1}tp://)[-a-zA-Z0-9@:%_\+.~#?&//=]+)"
++ self.opts.update({'regex': pattern, 'maxlen': 512})
++Url = Url()
++
++
++class Filepath(Text):
++ def init(self):
++ self.opts.update({'regex': "", 'maxlen': 512})
++Filepath = Filepath()
++
++
++class Nonnegative(Integer):
++ def init(self):
++ self.opts.update({'minimum': 0})
++Nonnegative = Nonnegative()
++
++
++class Boolean(Integer):
++ def init(self):
++ self.opts.update({'minimum': 0, 'maximum': 1})
++Boolean = Boolean()
++
++
++class GroupKind(Integer):
++ def init(self):
++ self.opts.update({'minimum': 1, 'maximum': 5})
++GroupKind = GroupKind()
++
++Timepoint = Text(classname='Timepoint', maxlen=24)
++
++
++class AstakosAPI(Specificator):
++ def create_users(
++ self,
++ users=ListOf(
++ email=Email,
++ first_name=Name,
++ last_name=Name,
++ is_active=Boolean,
++ is_superuser=Boolean,
++ affiliation=Name,
++ password=Name,
++ provider=Name,
++ level=Nonnegative,
++ invitations=Nonnegative,
++ is_verified=Boolean,
++ third_party_identifier=Name,
++ email_verified=Boolean),
++ policies=ListOf(resource=Name, supimit=Nonnegative),
++ groups=ListOf(Name),
++ permissions=ListOf(Name)
++ ):
++ rejected = ListOf(user=Email, reason=Text())
++ return rejected
++
++ def update_users(
++ self,
++ users=ListOf(
++ pk=Nonnegative,
++ renew_token=Boolean,
++ data=ListOf(
++ first_name=Name,
++ last_name=Name,
++ is_active=Boolean,
++ is_superuser=Boolean,
++ affiliation=Name,
++ password=Name,
++ provider=Name,
++ level=Nonnegative,
++ invitations=Nonnegative,
++ is_verified=Boolean,
++ third_party_identifier=Name,
++ email_verified=Boolean
++ )
++ )
++ ):
++ rejected = ListOf(user_id=Nonnegative, reason=Text())
++ return rejected
++
++ def add_user_policies(
++ self,
++ pk=Nonnegative,
++ update=Boolean,
++ policies=ListOf(service=Name, resource=Name, upimit=Nonnegative)
++ ):
++ rejected = ListOf(resource=Name, reason=Text())
++ return rejected
++
++ def remove_user_policies(
++ self,
++ pk=Nonnegative,
++ policies=ListOf(service=Name, resource=Name)
++ ):
++ rejected = ListOf(service=Name, resource=Name)
++ return rejected
++
++ def add_user_permissions(
++ self,
++ pk=Nonnegative,
++ permissions=ListOf(permission=Name)
++ ):
++ rejected = ListOf(permission=Name)
++ return rejected
++
++ def remove_user_permissions(
++ self,
++ pk=Nonnegative,
++ permissions=ListOf(permission=Name)
++ ):
++ rejected = ListOf(permission=Name)
++ return rejected
++
++ def invite_users(
++ self,
++ sender=Email,
++ data=ListOf(email=Email, realname=Name)
++ ):
++ rejected = ListOf(receiver=Email)
++ return rejected
++
++ def list_users(
++ self,
++ filter=ListOf(id=Nonnegative)
++ ):
++ return ListOf(
++ activation_sent=Timepoint,
++ affiliation=Name,
++ auth_token=Name,
++ auth_token_created=Timepoint,
++ auth_token_expires=Timepoint,
++ date_joined=Timepoint,
++ date_signed_terms=Timepoint,
++ email=Email,
++ email_verified=Boolean,
++ first_name=Name,
++ has_credits=Boolean,
++ has_signed_terms=Boolean,
++ id=Nonnegative,
++ invitations=Nonnegative,
++ invitations_sent=ListOf(
++ code=Name,
++ consumed=Boolean,
++ created=Timepoint,
++ id=Nonnegative,
++ realname=Name,
++ username=Email
++ ),
++ is_active=Boolean,
++ is_staff=Boolean,
++ is_superuser=Boolean,
++ is_verified=Boolean,
++ last_login=Timepoint,
++ last_name=Name,
++ level=Nonnegative,
++ password=Name,
++ provider=Name,
++ third_party_identifier=Name,
++ updated=Timepoint,
++ user_permissions=ListOf(
++ codename=Name,
++ id=Nonnegative,
++ name=Name
++ ),
++ username=Name,
++ astakos_groups=ListOf(
++ approval_date=Timepoint,
++ creation_date=Timepoint,
++ desc=Text(),
++ estimated_participants=Nonnegative,
++ expiration_date=Timepoint,
++ group_ptr=Url,
++ homepage=Url,
++ id=Nonnegative,
++ issue_date=Timepoint,
++ kind=Name,
++ moderation_enabled=Boolean,
++ name=Name,
++ #permissions=ListOf(),
++ policy=ListOf(id=Nonnegative, name=Name)
++ )
++ )
++
++ def get_user_status(
++ self,
++ user_id=Nonnegative
++ ):
++ return ListOf(
++ name=Name,
++ description=Text(),
++ unit=Name,
++ maxValue=Integer(),
++ currValue=Integer()
++ )
++
++ def list_resources(self, filter=ListOf(id=Nonnegative)):
++ return ListOf(
++ desc=Text(),
++ group=Name,
++ id=Nonnegative,
++ meta=ListOf(key=Name, value=Name),
++ name=Name,
++ service=Name,
++ unit=Name
++ )
++
++ def add_services(
++ self,
++ services=ListOf(
++ name=Name,
++ url=Url,
++ icon=Filepath,
++ resources=ListOf(
++ name=Name,
++ desc=Text(),
++ unit=Name,
++ group=Name
++ )
++ )
++ ):
++ rejected = ListOf(service=Name)
++ return rejected
++
++ def update_services(
++ self,
++ services=ListOf(id=Nonnegative, url=Url, icon=Filepath)
++ ):
++ rejected = ListOf(service=Name)
++ return rejected
++
++ def remove_services(self, ids=ListOf(Nonnegative)):
++ rejected = ListOf(service=Name)
++ return rejected
++
++ def add_resources(
++ self,
++ service_id=Nonnegative,
++ update=Boolean,
++ resources=ListOf(
++ name=Name,
++ resources=ListOf(
++ name=Name,
++ desc=Text(),
++ unit=Name,
++ group=Name)
++ )
++ ):
++ rejected = ListOf(service=Name)
++ return rejected
++
++ def remove_resources(
++ self,
++ service_id=Nonnegative,
++ ids=ListOf(Nonnegative)
++ ):
++ rejected = ListOf(Name)
++ return rejected
++
++ def create_groups(
++ self,
++ groups=ListOf(
++ name=Name,
++ kind=GroupKind,
++ homepage=Url,
++ desc=Text(),
++ policies=ListOf(resource=Name, upimit=Nonnegative),
++ issue_date=Timepoint,
++ expiration_date=Timepoint,
++ moderation_enabled=Boolean,
++ participants=Nonnegative,
++ permissions=ListOf(permission=Name),
++ members=ListOf(user=Email, is_approved=Boolean),
++ owners=ListOf(user=Email)
++ )
++ ):
++ rejected = ListOf(group=Name)
++ return rejected
++
++ def enable_groups(self, data=ListOf(group=Name)):
++ rejected = ListOf(group=Name)
++ return rejected
++
++ def search_groups(self, key=Name):
++ return ListOf(
++ group=Name,
++ kind=GroupKind,
++ homepage=Url,
++ desc=Text(),
++ creation_date=Timepoint,
++ issue_date=Timepoint,
++ expiration_date=Timepoint,
++ moderation_enabled=Boolean,
++ participants=Nonnegative,
++ owner=ListOf(user=Email),
++ policies=ListOf(resource=Name, upimit=Nonnegative),
++ members=ListOf(user=Email, is_approved=Boolean)
++ )
++
++ def list_groups(self):
++ return ListOf(
++ group=Name,
++ kind=GroupKind,
++ homepage=Url,
++ desc=Text(),
++ creation_date=Timepoint,
++ issue_date=Timepoint,
++ expiration_date=Timepoint,
++ moderation_enabled=Boolean,
++ participants=Nonnegative,
++ owners=ListOf(user=Email),
++ policies=ListOf(resource=Name, upimit=Nonnegative),
++ members=ListOf(user=Email, is_approved=Boolean)
++ )
++
++ def add_owners(
++ self,
++ data=ListOf(group=Name, owners=ListOf(user=Email))
++ ):
++ rejected = ListOf(user=Email)
++ return rejected
++
++ def remove_owners(
++ self,
++ data=ListOf(group=Name, owners=ListOf(user=Email))
++ ):
++ rejected = ListOf(user=Email)
++ return rejected
++
++ def add_members(
++ self,
++ data=ListOf(group=Name, members=ListOf(user=Email))
++ ):
++ rejected = ListOf(user=Email)
++ return rejected
++
++ def remove_members(
++ self,
++ data=ListOf(group=Name, members=ListOf(user=Email))
++ ):
++ rejected = ListOf(user=Email)
++ return rejected
++
++ def add_policies(
++ self,
++ data=ListOf(group=Name, resource=Name, upimit=Nonnegative)
++ ):
++ rejected = ListOf(group=Name, resource=Name)
++ return rejected
++
++ def remove_group_policies(
++ self,
++ data=ListOf(group=Name, resource=Name, upimit=Nonnegative)
++ ):
++ rejected = ListOf(group=Name, resource=Name)
++ return rejected
++
++ def update_group_policies(
++ self, data=ListOf(group=Name, resource=Name, upimit=Nonnegative)
++ ):
++ rejected = ListOf(group=Name, resource=Name)
++ return rejected
++
++ def approve_members(
++ self,
++ data=ListOf(group=Name, members=ListOf(user=Email))
++ ):
++ rejected = ListOf(user=Email)
++ return rejected
++
++ def disapprove_members(
++ self,
++ data=ListOf(group=Name, members=ListOf(user=Email))
++ ):
++ rejected = ListOf(user=Email)
++ return rejected
++
++ def add_group_permissions(
++ self,
++ data=ListOf(group=Name, permission=Name)
++ ):
++ rejected = ListOf(group=Name, permission=Name)
++ return rejected
++
++ def delete_group_permissions(
++ self,
++ data=ListOf(group=Name, permission=Name)
++ ):
++ rejected = ListOf(group=Name, permission=Name)
++ return rejected
++
++ def list_resource_units(self):
++ return ListOf(Name)
++
++ def get_approval_terms(term=Nonnegative):
++ return Text()
++
++ def add_approval_terms(location=Filepath):
++ return Nonnegative
++
++# def change_emails():
++# pass
if type(PROFILE_MESSAGES) == dict:
PROFILE_MESSAGES = PROFILE_MESSAGES.items()
-- EXTRA_MESSAGES_SET = bool(GLOBAL_MESSAGES or SIGNUP_MESSAGES or \
-- LOGIN_MESSAGES or PROFILE_MESSAGES)
++ EXTRA_MESSAGES_SET = bool(GLOBAL_MESSAGES or SIGNUP_MESSAGES or
++ LOGIN_MESSAGES or PROFILE_MESSAGES)
return {
'GLOBAL_MESSAGES': GLOBAL_MESSAGES,
import logging
logging.basicConfig(format='%(asctime)s [%(levelname)s] %(name)s %(message)s',
-- datefmt='%Y-%m-%d %H:%M:%S'
--)
++ datefmt='%Y-%m-%d %H:%M:%S'
++ )
logger = logging.getLogger('endpoint.aquarium')
from astakos.im.models import AstakosUser
def wrapper(entities=(), client=None, **kwargs):
if not entities:
return ()
--
++
if not QUOTA_HOLDER_URL:
return ()
--
++
c = client or QuotaholderHTTP(QUOTA_HOLDER_URL)
func = c.__dict__.get(func_name)
if not func:
return c,
--
++
data = payload_func(entities, client, **kwargs)
if not data:
-- return c,
--
++ return c, data
++
funcname = func.__name__
kwargs = {'context': {}, funcname: data}
rejected = func(**kwargs)
return wrapper
return decorator
++
@call('set_quota')
def send_quota(users, client=None):
data = []
import_limit = None
export_limit = None
flags = 0
-- args = (user.email, resource, key, quantity, capacity, import_limit,
-- export_limit, flags)
++ args = (
++ user.email, resource, key, quantity, capacity, import_limit,
++ export_limit, flags)
append(args)
return data
SECOND_RESOLUTION = 1
++
def total_seconds(timedelta_object):
return timedelta_object.seconds + timedelta_object.days * 86400
++
def iter_timeline(timeline, before):
if not timeline:
return
t['issue_time'] = before
yield t
++
def _usage_units(timeline, after, before, details=0):
t_total = 0
'total',
point['resource'],
issue_time,
-- uu_total/t_total,
++ uu_total / t_total,
uu_total)
++
def usage_units(timeline, after, before, details=0):
return list(_usage_units(timeline, after, before, details=details))
++
def traffic_units(timeline, after, before, details=0):
tu_total = 0
target = None
'total',
point['resource'],
issue_time,
-- tu_total//len(timeline),
++ tu_total // len(timeline),
tu_total)
++
def timeline_charge(entity, resource, after, before, details, charge_type):
key = '1'
if charge_type == 'charge_usage':
quotaholder = QuotaholderHTTP(QUOTA_HOLDER_URL)
timeline = quotaholder.get_timeline(
-- context = {},
-- after = after,
-- before = before,
-- get_timeline = [[entity, resource, key]])
++ context={},
++ after=after,
++ before=before,
++ get_timeline=[[entity, resource, key]])
cu = charge_units(timeline, after, before, details=details)
return cu
--
from astakos.im.settings import (INVITATIONS_PER_LEVEL, BASEURL, SITENAME,
RECAPTCHA_PRIVATE_KEY, RECAPTCHA_ENABLED,
DEFAULT_CONTACT_EMAIL, LOGGING_LEVEL,
- PASSWORD_RESET_EMAIL_SUBJECT,
- PASSWORD_RESET_EMAIL_SUBJECT)
-
++ PASSWORD_RESET_EMAIL_SUBJECT,
+ NEWPASSWD_INVALIDATE_TOKEN)
from astakos.im.widgets import DummyWidget, RecaptchaWidget
from astakos.im.functions import send_change_email
ro = ('email', 'username',)
for f in ro:
self.fields[f].widget.attrs['readonly'] = True
--
++
def save(self, commit=True):
user = super(InvitedLocalUserCreationForm, self).save(commit=False)
level = user.invitation.inviter.level + 1
model = AstakosUser
fields = ("email", "first_name", "last_name",
"third_party_identifier", "has_signed_terms")
--
++
def __init__(self, *args, **kwargs):
"""
Changes the order of fields, and removes the username field.
% (reverse('latest_terms'), _("the terms"))
self.fields['has_signed_terms'].label = \
mark_safe("I agree with %s" % terms_link_html)
--
++
def clean_email(self):
email = self.cleaned_data['email']
if not email:
class ShibbolethUserCreationForm(ThirdPartyUserCreationForm):
additional_email = forms.CharField(
widget=forms.HiddenInput(), label='', required=False)
--
++
def __init__(self, *args, **kwargs):
super(ShibbolethUserCreationForm, self).__init__(*args, **kwargs)
self.fields.keyOrder.append('additional_email')
field = self.fields[name]
self.initial['additional_email'] = self.initial.get(name,
field.initial)
--
++
def clean_email(self):
email = self.cleaned_data['email']
for user in AstakosUser.objects.filter(email=email):
recaptcha_challenge_field = forms.CharField(widget=DummyWidget)
recaptcha_response_field = forms.CharField(
widget=RecaptchaWidget, label='')
--
++
def __init__(self, *args, **kwargs):
was_limited = kwargs.get('was_limited', False)
request = kwargs.get('request', None)
if was_limited and RECAPTCHA_ENABLED:
self.fields.keyOrder.extend(['recaptcha_challenge_field',
'recaptcha_response_field', ])
--
++
+ def clean_username(self):
+ if 'username' in self.cleaned_data:
+ return self.cleaned_data['username'].lower()
-
++
def clean_recaptcha_response_field(self):
if 'recaptcha_challenge_field' in self.cleaned_data:
self.validate_captcha()
if not check.is_valid:
raise forms.ValidationError(
_('You have not entered the correct words'))
--
++
def clean(self):
super(LoginForm, self).clean()
if self.user_cache and self.user_cache.provider not in ('local', ''):
super(ExtendedPasswordChangeForm, self).__init__(user, *args, **kwargs)
def save(self, commit=True):
-- user = super(ExtendedPasswordChangeForm, self).save(commit=False)
- if self.cleaned_data.get('renew'):
- user.renew_token()
- if commit:
- user.save()
- return user
+ if NEWPASSWD_INVALIDATE_TOKEN or self.cleaned_data.get('renew'):
- user.renew_token()
- if commit:
- user.save()
- return user
++ self.user.renew_token()
++ return super(ExtendedPasswordChangeForm, self).save(commit=commit)
class AstakosGroupCreationForm(forms.ModelForm):
name = forms.URLField()
moderation_enabled = forms.BooleanField(
help_text="Check if you want to approve members participation manually",
-- required=False
++ required=False
)
--
++
class Meta:
model = AstakosGroup
except KeyError:
resources = {}
super(AstakosGroupCreationForm, self).__init__(*args, **kwargs)
-- self.fields.keyOrder = ['kind', 'name', 'homepage', 'desc', 'issue_date',
-- 'expiration_date', 'estimated_participants',
++ self.fields.keyOrder = ['kind', 'name', 'homepage', 'desc',
++ 'issue_date', 'expiration_date',
++ 'estimated_participants',
'moderation_enabled']
for id, r in resources.iteritems():
self.fields['resource_%s' % id] = forms.IntegerField(
-- label=r,
-- required=False,
-- help_text=_('Leave it blank for no additional quota.')
-- )
++ label=r, required=False,
++ help_text=_('Leave it blank for no additional quota.'))
def resources(self):
for name, value in self.cleaned_data.items():
continue
yield (suffix, value)
++
class AstakosGroupUpdateForm(forms.ModelForm):
class Meta:
model = AstakosGroup
fields = ('homepage', 'desc')
++
class AddGroupMembersForm(forms.Form):
-- q = forms.CharField(max_length=800, widget=forms.Textarea, label=_('Search users'),
-- help_text=_('Add comma separated user emails'),
-- required=True)
--
++ q = forms.CharField(
++ max_length=800, widget=forms.Textarea, label=_('Search users'),
++ help_text=_('Add comma separated user emails'),
++ required=True)
++
def clean(self):
q = self.cleaned_data.get('q') or ''
users = q.split(',')
_('Unknown users: %s' % ','.join(unknown)))
self.valid_users = db_entries
return self.cleaned_data
--
++
def get_valid_users(self):
"""Should be called after form cleaning"""
try:
class AstakosGroupSearchForm(forms.Form):
q = forms.CharField(max_length=200, label='Search group')
++
class TimelineForm(forms.Form):
# entity = forms.CharField(
# widget=forms.HiddenInput(), label='')
entity = forms.ModelChoiceField(
-- queryset=AstakosUser.objects.filter(is_active = True)
++ queryset=AstakosUser.objects.filter(is_active=True)
)
resource = forms.ModelChoiceField(
queryset=Resource.objects.all()
end_date = forms.DateTimeField()
details = forms.BooleanField(required=False, label="Detailed Listing")
operation = forms.ChoiceField(
-- label = 'Charge Method',
-- choices = ( ('', '-------------'),
-- ('charge_usage', 'Charge Usage'),
-- ('charge_traffic', 'Charge Traffic'), )
-- )
++ label='Charge Method',
++ choices=(('', '-------------'),
++ ('charge_usage', 'Charge Usage'),
++ ('charge_traffic', 'Charge Traffic'), )
++ )
++
def clean(self):
super(TimelineForm, self).clean()
d = self.cleaned_data
if 'resource' in d:
d['resource'] = str(d['resource'])
if 'start_date' in d:
-- d['start_date'] = d['start_date'].strftime("%Y-%m-%dT%H:%M:%S.%f")[:24]
++ d['start_date'] = d['start_date'].strftime(
++ "%Y-%m-%dT%H:%M:%S.%f")[:24]
if 'end_date' in d:
d['end_date'] = d['end_date'].strftime("%Y-%m-%dT%H:%M:%S.%f")[:24]
-- if 'entity' in d:
++ if 'entity' in d:
d['entity'] = d['entity'].email
return d
++
class AstakosGroupSortForm(forms.Form):
sort_by = forms.ChoiceField(label='Sort by',
choices=(('groupname', 'Name'),
('kindname', 'Type'),
('issue_date', 'Issue Date'),
-- ('expiration_date', 'Expiration Date'),
-- ('approved_members_num', 'Participants'),
++ ('expiration_date',
++ 'Expiration Date'),
++ ('approved_members_num',
++ 'Participants'),
('is_enabled', 'Status'),
('moderation_enabled', 'Moderation'),
-- ('membership_status','Enrollment Status')
++ ('membership_status',
++ 'Enrollment Status')
),
required=False)
++
class MembersSortForm(forms.Form):
sort_by = forms.ChoiceField(label='Sort by',
choices=(('person__email', 'User Id'),
),
required=False)
++
class PickResourceForm(forms.Form):
resource = forms.ModelChoiceField(
queryset=Resource.objects.select_related().all()
)
-- resource.widget.attrs["onchange"]="this.form.submit()"
++ resource.widget.attrs["onchange"] = "this.form.submit()"
++
+
+class ExtendedSetPasswordForm(SetPasswordForm):
+ """
+ Extends SetPasswordForm by enabling user
+ to optionally renew also the token.
+ """
+ if not NEWPASSWD_INVALIDATE_TOKEN:
+ renew = forms.BooleanField(label='Renew token', required=False,
+ initial=True,
+ help_text='Unsetting this may result in security risk.')
-
++
+ def __init__(self, user, *args, **kwargs):
+ super(ExtendedSetPasswordForm, self).__init__(user, *args, **kwargs)
-
++
+ def save(self, commit=True):
- user = super(ExtendedSetPasswordForm, self).save(commit=False)
+ if NEWPASSWD_INVALIDATE_TOKEN or self.cleaned_data.get('renew'):
- try:
- user = AstakosUser.objects.get(id=user.id)
- except AstakosUser.DoesNotExist:
- pass
- else:
- user.renew_token()
- if commit:
- user.save()
- return user
++ if isinstance(self.user, AstakosUser):
++ self.user.renew_token()
++ return super(ExtendedSetPasswordForm, self).save(commit=commit)
from astakos.im.settings import (DEFAULT_CONTACT_EMAIL, SITENAME, BASEURL,
LOGGING_LEVEL, VERIFICATION_EMAIL_SUBJECT,
-- ADMIN_NOTIFICATION_EMAIL_SUBJECT,
++ ACCOUNT_CREATION_SUBJECT,
++ GROUP_CREATION_SUBJECT,
HELPDESK_NOTIFICATION_EMAIL_SUBJECT,
INVITATION_EMAIL_SUBJECT,
GREETING_EMAIL_SUBJECT,
FEEDBACK_EMAIL_SUBJECT,
EMAIL_CHANGE_EMAIL_SUBJECT)
--from astakos.im.models import AstakosUser
logger = logging.getLogger(__name__)
def with_logging(*args, **kwargs):
email = ''
user = None
-- if len(args) == 2 and isinstance(args[1], AstakosUser):
-- user = args[1]
-- elif len(args) == 1 and isinstance(args[0], HttpRequest):
++ try:
request = args[0]
-- user = request.user
-- email = user.email if user and user.is_authenticated() else ''
++ email = request.user.email
++ except (KeyError, AttributeError), e:
++ email = ''
r = func(*args, **kwargs)
if LOGGING_LEVEL:
logger.log(LOGGING_LEVEL, msg % email)
user.save()
- def send_admin_notification(user, template_name,
- dictionary=None,
- subject='alpha2 testing notification',
- ):
-def send_admin_notification(template_name,
- dictionary=None,
- subject='alpha2 testing notification',
- ):
++def _send_admin_notification(template_name,
++ dictionary=None,
++ subject='alpha2 testing notification',):
"""
Send notification email to settings.ADMINS.
message = render_to_string(template_name, dictionary)
sender = settings.SERVER_EMAIL
try:
-- send_mail(_(ADMIN_NOTIFICATION_EMAIL_SUBJECT) % {'user': user.email},
++ send_mail(subject,
message, sender, [i[1] for i in settings.ADMINS])
except (SMTPException, socket.error) as e:
logger.exception(e)
logger.log(LOGGING_LEVEL, msg)
++def send_account_creation_notification(template_name, dictionary=None):
++ user = dictionary.get('user', AstakosUser())
++ subject = _(ACCOUNT_CREATION_SUBJECT) % {'user': user.email}
++ return _send_admin_notification(template_name, dictionary, subject=subject)
++
++
++def send_group_creation_notification(template_name, dictionary=None):
++ group = dictionary.get('group', AstakosGroup())
++ subject = _(GROUP_CREATION_SUBJECT) % {'group': group.name}
++ return _send_admin_notification(template_name, dictionary, subject=subject)
++
++
def send_helpdesk_notification(user, template_name='im/account_notification.txt'):
"""
Send email to DEFAULT_CONTACT_EMAIL to notify for a new user activation.
)
sender = settings.SERVER_EMAIL
try:
-- send_mail(_(HELPDESK_NOTIFICATION_EMAIL_SUBJECT) % {'user': user.email},
-- message, sender, [DEFAULT_CONTACT_EMAIL])
++ send_mail(
++ _(HELPDESK_NOTIFICATION_EMAIL_SUBJECT) % {'user': user.email},
++ message, sender, [DEFAULT_CONTACT_EMAIL])
except (SMTPException, socket.error) as e:
logger.exception(e)
raise SendNotificationError()
else:
msg = 'Sent invitation %s' % invitation
logger.log(LOGGING_LEVEL, msg)
++ invitation.inviter.invitations = max(0, self.invitations - 1)
++ invitation.inviter.save()
def send_greeting(user, email_template_name='im/welcome_email.txt'):
c = {'url': url, 'site_name': SITENAME}
from_email = settings.SERVER_EMAIL
send_mail(_(EMAIL_CHANGE_EMAIL_SUBJECT),
-- t.render(Context(c)), from_email, [ec.new_email_address])
++ t.render(Context(c)), from_email, [ec.new_email_address])
except (SMTPException, socket.error) as e:
logger.exception(e)
raise ChangeEmailError()
send_greeting(user, email_template_name)
--def switch_account_to_shibboleth(user, local_user, greeting_template_name='im/welcome_email.txt'):
-- if not user or not isinstance(user, AstakosUser):
-- return
--
-- if not local_user or not isinstance(user, AstakosUser):
-- return
--
-- if not user.provider == 'shibboleth':
++def switch_account_to_shibboleth(user, local_user,
++ greeting_template_name='im/welcome_email.txt'):
++ try:
++ provider = user.provider
++ except AttributeError:
return
--
-- user.delete()
-- local_user.provider = 'shibboleth'
-- local_user.third_party_identifier = user.third_party_identifier
-- local_user.save()
-- send_greeting(local_user, greeting_template_name)
-- return local_user
--
--
--def invite(invitation, inviter, email_template_name='im/welcome_email.txt'):
-- """
-- Send an invitation email and upon success reduces inviter's invitation by one.
--
-- Raises SendInvitationError
-- """
-- invitation.inviter = inviter
-- invitation.save()
-- send_invitation(invitation, email_template_name)
-- inviter.invitations = max(0, inviter.invitations - 1)
-- inviter.save()
++ else:
++ if not provider == 'shibboleth':
++ return
++ user.delete()
++ local_user.provider = 'shibboleth'
++ local_user.third_party_identifier = user.third_party_identifier
++ local_user.save()
++ send_greeting(local_user, greeting_template_name)
++ return local_user
class SendMailError(Exception):
--- /dev/null
+# Copyright 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 optparse import make_option
+
+from django.core.management.base import BaseCommand, CommandError
+from django.contrib.auth.models import Group, Permission
+from django.contrib.contenttypes.models import ContentType
+from django.core.exceptions import ValidationError
+
+from astakos.im.models import AstakosUser
+from ._common import add_group_permission
+
++
+class Command(BaseCommand):
+ args = "<groupname> <permission> [<permissions> ...]"
+ help = "Add group permissions"
-
++
+ def handle(self, *args, **options):
+ if len(args) < 2:
- raise CommandError("Please provide a group name and at least one permission")
-
++ raise CommandError(
++ "Please provide a group name and at least one permission")
++
+ group = None
+ try:
+ if args[0].isdigit():
+ group = Group.objects.get(id=args[0])
+ else:
+ group = Group.objects.get(name=args[0])
+ except Group.DoesNotExist, e:
+ raise CommandError("Invalid group")
-
++
+ try:
+ content_type = ContentType.objects.get(app_label='im',
- model='astakosuser')
++ model='astakosuser')
+ for pname in args[1:]:
+ r, created = add_group_permission(group, pname)
+ if created:
- self.stdout.write('Permission: %s created successfully\n' % pname)
++ self.stdout.write(
++ 'Permission: %s created successfully\n' % pname)
+ if r == 0:
- self.stdout.write('Group has already permission: %s\n' % pname)
++ self.stdout.write(
++ 'Group has already permission: %s\n' % pname)
+ else:
- self.stdout.write('Permission: %s added successfully\n' % pname)
++ self.stdout.write(
++ 'Permission: %s added successfully\n' % pname)
+ except Exception, e:
- raise CommandError(e)
++ raise CommandError(e)
--- /dev/null
+# Copyright 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 optparse import make_option
+
+from django.core.management.base import BaseCommand, CommandError
+from django.contrib.auth.models import Group
+from django.core.exceptions import ValidationError
+
+from astakos.im.models import AstakosUser
+from ._common import remove_group_permission
+
++
+class Command(BaseCommand):
+ args = "<groupname> <permission> [<permissions> ...]"
+ help = "Remove group permissions"
-
++
+ def handle(self, *args, **options):
+ if len(args) < 2:
- raise CommandError("Please provide a group name and at least one permission")
-
++ raise CommandError(
++ "Please provide a group name and at least one permission")
++
+ group = None
+ try:
+ if args[0].isdigit():
+ group = Group.objects.get(id=args[0])
+ else:
+ group = Group.objects.get(name=args[0])
+ except Group.DoesNotExist, e:
+ raise CommandError("Invalid group")
-
++
+ try:
+ for pname in args[1:]:
+ r = remove_group_permission(group, pname)
+ if r < 0:
- self.stdout.write('Invalid permission codename: %s\n' % pname)
++ self.stdout.write(
++ 'Invalid permission codename: %s\n' % pname)
+ elif r == 0:
+ self.stdout.write('Group has not permission: %s\n' % pname)
+ elif r > 0:
- self.stdout.write('Permission: %s removed successfully\n' % pname)
++ self.stdout.write(
++ 'Permission: %s removed successfully\n' % pname)
+ except Exception, e:
- raise CommandError(e)
++ raise CommandError(e)
from astakos.im.models import AstakosUser, Resource
from astakos.im.endpoints.quotaholder import register_users, register_resources
++import logging
++logger = logging.getLogger(__name__)
++
class Command(BaseCommand):
help = "Send user information and resource quota in the Quotaholder"
def handle(self, *args, **options):
try:
register_resources(Resource.objects.all())
-- register_users(AstakosUser.objects.all())
++ register_users(AstakosUser.objects.filter(disturbed_quota=True))
except BaseException, e:
-- raise CommandError("Bootstrap failed.")
++ logger.exception(e)
++ raise CommandError("Syncing failed.")
class Command(BaseCommand):
-- args = "<service> <resource> [<key>=<value>...]"
++ args = "<service> <resource> <desc> <unit>"
help = "Add a resource"
def handle(self, *args, **options):
from django.core.validators import validate_email
from django.core.exceptions import ValidationError
--from astakos.im.models import AstakosUser, AstakosGroup, Membership
--from astakos.im.util import reserved_email
++from astakos.im.models import AstakosUser
++from astakos.im.api.callpoint import AstakosDjangoDBCallpoint
from ._common import add_user_permission
++def filter_custom_options(options):
++ base_dests = list(
++ getattr(o, 'dest', None) for o in BaseCommand.option_list)
++ return dict((k, v) for k, v in options.iteritems() if k not in base_dests)
++
++
class Command(BaseCommand):
-- args = "<email> <first name> <last name> <affiliation>"
++ args = "<email>"
help = "Create a user"
option_list = BaseCommand.option_list + (
++ make_option('--first-name',
++ dest='first_name',
++ metavar='NAME',
++ help="Set user's first name"),
++ make_option('--last-name',
++ dest='last_name',
++ metavar='NAME',
++ help="Set user's last name"),
++ make_option('--affiliation',
++ dest='affiliation',
++ metavar='AFFILIATION',
++ help="Set user's affiliation"),
++ make_option('--password',
++ dest='password',
++ metavar='PASSWORD',
++ help="Set user's password"),
make_option('--active',
action='store_true',
-- dest='active',
++ dest='is_active',
default=False,
help="Activate user"),
make_option('--admin',
action='store_true',
-- dest='admin',
++ dest='is_superuser',
default=False,
help="Give user admin rights"),
-- make_option('--password',
-- dest='password',
-- metavar='PASSWORD',
-- help="Set user's password"),
-- make_option('--add-group',
-- dest='add-group',
-- help="Add user group"),
-- make_option('--add-permission',
-- dest='add-permission',
-- help="Add user permission")
++ make_option('-g',
++ action='append',
++ dest='groups',
++ help="Add user group (may be used multiple times)"),
++ make_option('-p',
++ action='append',
++ dest='permissions',
++ help="Add user permission (may be used multiple times)")
)
def handle(self, *args, **options):
-- if len(args) != 4:
++ if len(args) != 1:
raise CommandError("Invalid number of arguments")
-- args = [a.decode('utf8') for a in args]
-- email, first, last, affiliation = args
--
-- #try:
-- # validate_email(email)
-- #except ValidationError:
-- # raise CommandError("Invalid email")
--
-- username = uuid4().hex[:30]
-- password = options.get('password')
-- if password is None:
-- password = AstakosUser.objects.make_random_password()
++ email = args[0].decode('utf8')
-- if reserved_email(email):
-- raise CommandError("A user with this email already exists")
--
-- user = AstakosUser(username=username, first_name=first, last_name=last,
-- email=email, affiliation=affiliation,
-- provider='local')
-- user.set_password(password)
-- user.renew_token()
++ try:
++ validate_email(email)
++ except ValidationError:
++ raise CommandError("Invalid email")
-- if options['active']:
-- user.is_active = True
-- if options['admin']:
-- user.is_superuser = True
++ u = {'email': email}
++ u.update(filter_custom_options(options))
++ if not u.get('password'):
++ u['password'] = AstakosUser.objects.make_random_password()
try:
-- user.save()
++ c = AstakosDjangoDBCallpoint()
++ c.create_users((u,))
except socket.error, e:
raise CommandError(e)
except ValidationError, e:
raise CommandError(e)
-- else:
-- msg = "Created user id %d" % (user.id,)
-- if options['password'] is None:
-- msg += " with password '%s'" % (password,)
-- self.stdout.write(msg + '\n')
--
-- groupname = options.get('add-group')
-- if groupname is not None:
-- try:
-- group = AstakosGroup.objects.get(name=groupname)
-- Membership(group=group,
-- person=user, date_joined=datetime.now()).save()
-- self.stdout.write(
-- 'Group: %s added successfully\n' % groupname)
-- except AstakosGroup.DoesNotExist, e:
-- self.stdout.write(
-- 'Group named %s does not exist\n' % groupname)
--
-- pname = options.get('add-permission')
-- if pname is not None:
-- try:
-- r, created = add_user_permission(user, pname)
-- if created:
-- self.stdout.write(
-- 'Permission: %s created successfully\n' % pname)
-- if r > 0:
-- self.stdout.write(
-- 'Permission: %s added successfully\n' % pname)
-- elif r == 0:
-- self.stdout.write(
-- 'User has already permission: %s\n' % pname)
-- except Exception, e:
-- raise CommandError(e)
++# else:
++# msg = "Created user id %d" % (user.id,)
++# if options['password'] is None:
++# msg += " with password '%s'" % (password,)
++# self.stdout.write(msg + '\n')
++#
++# groupname = options.get('add-group')
++# if groupname is not None:
++# try:
++# group = AstakosGroup.objects.get(name=groupname)
++# Membership(group=group,
++# person=user, date_joined=datetime.now()).save()
++# self.stdout.write(
++# 'Group: %s added successfully\n' % groupname)
++# except AstakosGroup.DoesNotExist, e:
++# self.stdout.write(
++# 'Group named %s does not exist\n' % groupname)
++#
++# pname = options.get('add-permission')
++# if pname is not None:
++# try:
++# r, created = add_user_permission(user, pname)
++# if created:
++# self.stdout.write(
++# 'Permission: %s created successfully\n' % pname)
++# if r > 0:
++# self.stdout.write(
++# 'Permission: %s added successfully\n' % pname)
++# elif r == 0:
++# self.stdout.write(
++# 'User has already permission: %s\n' % pname)
++# except Exception, e:
++# raise CommandError(e)
from django.db.utils import IntegrityError
from django.db import transaction
--from astakos.im.functions import invite, SendMailError
++from astakos.im.functions import SendMailError
from astakos.im.models import Invitation
from ._common import get_user
realname = args[2]
try:
-- invitation = Invitation(
-- username=email, realname=realname, inviter=inviter)
-- invite(invitation, inviter)
++ inviter.invite(email, realname)
self.stdout.write("Invitation sent to '%s'\n" % (email,))
except SendMailError, e:
transaction.rollback()
# or implied, of GRNET S.A.
from optparse import make_option
--from datetime import datetime
from django.core.management.base import BaseCommand, CommandError
++from django.contrib.auth.models import Group, Permission
++from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
--from django.db.utils import IntegrityError
--from astakos.im.models import (AstakosUser, AstakosGroup, Membership, Resource,
-- AstakosUserQuota)
--from astakos.im.endpoints.aquarium.producer import report_user_credits_event
++from astakos.im.models import AstakosUser
from ._common import remove_user_permission, add_user_permission
args = "<user ID>"
help = "Modify a user's attributes"
-- option_list = list(BaseCommand.option_list) + [
++ option_list = BaseCommand.option_list + (
make_option('--invitations',
dest='invitations',
metavar='NUM',
make_option('--delete-permission',
dest='delete-permission',
help="Delete user permission"),
-- make_option('--refill-credits',
-- action='store_true',
-- dest='refill',
-- default=False,
-- help="Refill user credits"),
-- ]
-- resources = Resource.objects.select_related().all()
-- append = option_list.append
-- for r in resources:
-- append(make_option('--%s-set-quota' % r,
-- dest='%s-set-quota' % r,
-- metavar='QUANTITY',
-- help="Set resource quota"))
--
++ )
++
def handle(self, *args, **options):
if len(args) != 1:
raise CommandError("Please provide a user ID")
groupname = options.get('add-group')
if groupname is not None:
try:
-- group = AstakosGroup.objects.get(name=groupname)
-- m = Membership(
-- person=user, group=group, date_joined=datetime.now())
-- m.save()
-- except AstakosGroup.DoesNotExist, e:
++ group = Group.objects.get(name=groupname)
++ user.groups.add(group)
++ except Group.DoesNotExist, e:
self.stdout.write(
"Group named %s does not exist\n" % groupname)
-- except IntegrityError, e:
-- self.stdout.write("User is already member of %s\n" % groupname)
groupname = options.get('delete-group')
if groupname is not None:
try:
-- group = AstakosGroup.objects.get(name=groupname)
-- m = Membership.objects.get(person=user, group=group)
-- m.delete()
-- except AstakosGroup.DoesNotExist, e:
++ group = Group.objects.get(name=groupname)
++ user.groups.remove(group)
++ except Group.DoesNotExist, e:
self.stdout.write(
"Group named %s does not exist\n" % groupname)
-- except Membership.DoesNotExist, e:
-- self.stdout.write("User is not a member of %s\n" % groupname)
pname = options.get('add-permission')
if pname is not None:
if options['renew_token']:
user.renew_token()
-- if options['refill']:
-- report_user_credits_event(user)
--
try:
user.save()
except ValidationError, e:
if password:
self.stdout.write('User\'s new password: %s\n' % password)
--
-- for r in self.resources:
-- limit = options.get('%s-set-quota' % r)
-- if not limit:
-- continue
-- if not limit.isdigit():
-- raise CommandError('Invalid limit')
--
-- q = AstakosUserQuota.objects
-- q, created = q.get_or_create(resource=r, user=user,
-- defaults={'uplimit': limit})
-- verb = 'set' if created else 'updated'
-- self.stdout.write('User\'s quota %s successfully\n' % verb)
from south.v2 import DataMigration
++
class Migration(DataMigration):
def forwards(self, orm):
"Obsolete migration."
return
--
++
def backwards(self, orm):
"Obsolete migration."
return
--
++
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
from south.v2 import SchemaMigration
from django.db import models
++
class Migration(SchemaMigration):
def forwards(self, orm):
--
-- # Changing field 'AstakosGroup.homepage'
-- db.alter_column('im_astakosgroup', 'homepage', self.gf('django.db.models.fields.URLField')(max_length=255, null=True))
++ # Changing field 'AstakosGroup.homepage'
++ db.alter_column('im_astakosgroup', 'homepage', self.gf(
++ 'django.db.models.fields.URLField')(max_length=255, null=True))
def backwards(self, orm):
--
-- # Changing field 'AstakosGroup.homepage'
-- db.alter_column('im_astakosgroup', 'homepage', self.gf('django.db.models.fields.CharField')(max_length=255, null=True))
++ # Changing field 'AstakosGroup.homepage'
++ db.alter_column('im_astakosgroup', 'homepage', self.gf(
++ 'django.db.models.fields.CharField')(max_length=255, null=True))
models = {
'auth.group': {
from south.v2 import SchemaMigration
from django.db import models
++
class Migration(SchemaMigration):
def forwards(self, orm):
--
++
# Adding field 'AstakosGroupQuota.uplimit'
db.add_column('im_astakosgroupquota', 'uplimit', self.gf('django.db.models.fields.BigIntegerField')(null=True), keep_default=False)
# Adding field 'AstakosUserQuota.uplimit'
db.add_column('im_astakosuserquota', 'uplimit', self.gf('django.db.models.fields.BigIntegerField')(null=True), keep_default=False)
--
def backwards(self, orm):
--
++
# Deleting field 'AstakosGroupQuota.uplimit'
db.delete_column('im_astakosgroupquota', 'uplimit')
# Deleting field 'AstakosUserQuota.uplimit'
db.delete_column('im_astakosuserquota', 'uplimit')
--
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
from south.v2 import DataMigration
from django.db import models
++
class Migration(DataMigration):
def forwards(self, orm):
for q in orm.AstakosGroupQuota.objects.all():
q.uplimit = q.limit
q.save()
--
++
def backwards(self, orm):
return
def create_policies(args):
sn, dict = args
-- url = dict.get('url')
++ url = dict.get('url')
policy = dict.get('quota') or ()
s, created = orm.Service.objects.get_or_create(name=sn,
defaults={'url': url})
if not created and not s.url:
s.url = url
-- s.save()
++ s.save()
for rn, l in policy.iteritems():
try:
def destroy_policies(args):
sn, dict = args
-- url = dict.get('url')
++ url = dict.get('url')
policy = dict.get('quota') or ()
for rn, l in policy.iteritems():
try:
q.delete()
except orm.AstakosGroupQuota.DoesNotExist:
continue
--
++
map(destroy_policies, SERVICES.iteritems())
--
++
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
from south.v2 import SchemaMigration
from django.db import models
++
class Migration(SchemaMigration):
def forwards(self, orm):
--
++
# Changing field 'AstakosGroupQuota.limit'
-- db.alter_column('im_astakosgroupquota', 'limit', self.gf('django.db.models.fields.PositiveIntegerField')(null=True))
++ db.alter_column('im_astakosgroupquota', 'limit', self.gf(
++ 'django.db.models.fields.PositiveIntegerField')(null=True))
# Changing field 'AstakosUserQuota.limit'
-- db.alter_column('im_astakosuserquota', 'limit', self.gf('django.db.models.fields.PositiveIntegerField')(null=True))
--
++ db.alter_column('im_astakosuserquota', 'limit', self.gf(
++ 'django.db.models.fields.PositiveIntegerField')(null=True))
def backwards(self, orm):
--
++
# Changing field 'AstakosGroupQuota.limit'
-- db.alter_column('im_astakosgroupquota', 'limit', self.gf('django.db.models.fields.PositiveIntegerField')(default=None))
++ db.alter_column('im_astakosgroupquota', 'limit', self.gf(
++ 'django.db.models.fields.PositiveIntegerField')(default=None))
# Changing field 'AstakosUserQuota.limit'
-- db.alter_column('im_astakosuserquota', 'limit', self.gf('django.db.models.fields.PositiveIntegerField')(default=None))
--
++ db.alter_column('im_astakosuserquota', 'limit', self.gf(
++ 'django.db.models.fields.PositiveIntegerField')(default=None))
models = {
'auth.group': {
--- /dev/null
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
++
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ for u in orm.AstakosUser.objects.all():
+ u.email = u.email.lower()
+ u.save()
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+
-
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'im.additionalmail': {
+ 'Meta': {'object_name': 'AdditionalMail'},
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
+ },
+ 'im.approvalterms': {
+ 'Meta': {'object_name': 'ApprovalTerms'},
+ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 10, 4, 9, 47, 13, 40029)', 'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'im.astakosgroup': {
+ 'Meta': {'object_name': 'AstakosGroup', '_ormbases': ['auth.Group']},
+ 'approval_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 10, 4, 9, 47, 13, 34050)'}),
+ 'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'estimated_participants': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+ 'expiration_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'homepage': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'issue_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.GroupKind']"}),
+ 'moderation_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'policy': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.AstakosGroupQuota']", 'blank': 'True'})
+ },
+ 'im.astakosgroupquota': {
+ 'Meta': {'unique_together': "(('resource', 'group'),)", 'object_name': 'AstakosGroupQuota'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosGroup']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'limit': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+ 'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}),
+ 'uplimit': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'})
+ },
+ 'im.astakosuser': {
+ 'Meta': {'unique_together': "(('provider', 'third_party_identifier'),)", 'object_name': 'AstakosUser', '_ormbases': ['auth.User']},
+ 'activation_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'astakos_groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.AstakosGroup']", 'symmetrical': 'False', 'through': "orm['im.Membership']", 'blank': 'True'}),
+ 'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
+ 'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'date_signed_terms': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'email_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'has_credits': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'has_signed_terms': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'invitations': ('django.db.models.fields.IntegerField', [], {'default': '100'}),
+ 'is_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'level': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'owner': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'owner'", 'null': 'True', 'to': "orm['im.AstakosGroup']"}),
+ 'policy': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.AstakosUserQuota']", 'symmetrical': 'False'}),
+ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
+ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'})
+ },
+ 'im.astakosuserquota': {
+ 'Meta': {'unique_together': "(('resource', 'user'),)", 'object_name': 'AstakosUserQuota'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'limit': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+ 'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}),
+ 'uplimit': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
+ },
+ 'im.emailchange': {
+ 'Meta': {'object_name': 'EmailChange'},
+ 'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'new_email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+ 'requested_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 10, 4, 9, 47, 13, 41566)'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emailchange_user'", 'unique': 'True', 'to': "orm['im.AstakosUser']"})
+ },
+ 'im.groupkind': {
+ 'Meta': {'object_name': 'GroupKind'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'})
+ },
+ 'im.invitation': {
+ 'Meta': {'object_name': 'Invitation'},
+ 'code': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
+ 'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'inviter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invitations_sent'", 'null': 'True', 'to': "orm['im.AstakosUser']"}),
+ 'is_consumed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'realname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
+ },
+ 'im.membership': {
+ 'Meta': {'unique_together': "(('person', 'group'),)", 'object_name': 'Membership'},
+ 'date_joined': ('django.db.models.fields.DateField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
+ 'date_requested': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 10, 4, 9, 47, 13, 37772)', 'blank': 'True'}),
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosGroup']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
+ },
+ 'im.resource': {
+ 'Meta': {'object_name': 'Resource'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'meta': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.ResourceMetadata']", 'symmetrical': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
+ 'service': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Service']"})
+ },
+ 'im.resourcemetadata': {
+ 'Meta': {'object_name': 'ResourceMetadata'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'im.service': {
+ 'Meta': {'object_name': 'Service'},
+ 'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
+ 'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'icon': ('django.db.models.fields.FilePathField', [], {'max_length': '100', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
+ 'url': ('django.db.models.fields.FilePathField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['im']
--- /dev/null
--- /dev/null
++# encoding: utf-8
++import datetime
++from south.db import db
++from south.v2 import SchemaMigration
++from django.db import models
++
++
++class Migration(SchemaMigration):
++
++ def forwards(self, orm):
++
++ # Adding field 'Resource.desc'
++ db.add_column('im_resource', 'desc', self.gf('django.db.models.fields.TextField')(null=True), keep_default=False)
++
++ # Adding field 'Resource.unit'
++ db.add_column('im_resource', 'unit', self.gf('django.db.models.fields.CharField')(max_length=255, null=True), keep_default=False)
++
++ def backwards(self, orm):
++
++ # Deleting field 'Resource.desc'
++ db.delete_column('im_resource', 'desc')
++
++ # Deleting field 'Resource.unit'
++ db.delete_column('im_resource', 'unit')
++
++ models = {
++ 'auth.group': {
++ 'Meta': {'object_name': 'Group'},
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
++ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
++ },
++ 'auth.permission': {
++ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
++ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
++ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
++ },
++ 'auth.user': {
++ 'Meta': {'object_name': 'User'},
++ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
++ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
++ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
++ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
++ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
++ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
++ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
++ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
++ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
++ },
++ 'contenttypes.contenttype': {
++ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
++ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
++ },
++ 'im.additionalmail': {
++ 'Meta': {'object_name': 'AdditionalMail'},
++ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
++ },
++ 'im.approvalterms': {
++ 'Meta': {'object_name': 'ApprovalTerms'},
++ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 10, 30, 16, 37, 5, 608037)', 'db_index': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'location': ('django.db.models.fields.CharField', [], {'max_length': '255'})
++ },
++ 'im.astakosgroup': {
++ 'Meta': {'object_name': 'AstakosGroup', '_ormbases': ['auth.Group']},
++ 'approval_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
++ 'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 10, 30, 16, 37, 5, 601308)'}),
++ 'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
++ 'estimated_participants': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
++ 'expiration_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
++ 'homepage': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
++ 'issue_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.GroupKind']"}),
++ 'moderation_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
++ 'policy': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.AstakosGroupQuota']", 'blank': 'True'})
++ },
++ 'im.astakosgroupquota': {
++ 'Meta': {'unique_together': "(('resource', 'group'),)", 'object_name': 'AstakosGroupQuota'},
++ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosGroup']", 'blank': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'limit': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
++ 'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}),
++ 'uplimit': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'})
++ },
++ 'im.astakosuser': {
++ 'Meta': {'unique_together': "(('provider', 'third_party_identifier'),)", 'object_name': 'AstakosUser', '_ormbases': ['auth.User']},
++ 'activation_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
++ 'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
++ 'astakos_groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.AstakosGroup']", 'symmetrical': 'False', 'through': "orm['im.Membership']", 'blank': 'True'}),
++ 'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
++ 'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'date_signed_terms': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
++ 'email_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'has_credits': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'has_signed_terms': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'invitations': ('django.db.models.fields.IntegerField', [], {'default': '100'}),
++ 'is_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'level': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
++ 'owner': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'owner'", 'null': 'True', 'to': "orm['im.AstakosGroup']"}),
++ 'policy': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.AstakosUserQuota']", 'symmetrical': 'False'}),
++ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
++ 'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
++ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
++ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'})
++ },
++ 'im.astakosuserquota': {
++ 'Meta': {'unique_together': "(('resource', 'user'),)", 'object_name': 'AstakosUserQuota'},
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'limit': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
++ 'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}),
++ 'uplimit': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}),
++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
++ },
++ 'im.emailchange': {
++ 'Meta': {'object_name': 'EmailChange'},
++ 'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'new_email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
++ 'requested_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 10, 30, 16, 37, 5, 609676)'}),
++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emailchange_user'", 'unique': 'True', 'to': "orm['im.AstakosUser']"})
++ },
++ 'im.groupkind': {
++ 'Meta': {'object_name': 'GroupKind'},
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'})
++ },
++ 'im.invitation': {
++ 'Meta': {'object_name': 'Invitation'},
++ 'code': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
++ 'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
++ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'inviter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invitations_sent'", 'null': 'True', 'to': "orm['im.AstakosUser']"}),
++ 'is_consumed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'realname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
++ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
++ },
++ 'im.membership': {
++ 'Meta': {'unique_together': "(('person', 'group'),)", 'object_name': 'Membership'},
++ 'date_joined': ('django.db.models.fields.DateField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
++ 'date_requested': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 10, 30, 16, 37, 5, 605488)', 'blank': 'True'}),
++ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosGroup']"}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
++ },
++ 'im.resource': {
++ 'Meta': {'object_name': 'Resource'},
++ 'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'meta': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.ResourceMetadata']", 'symmetrical': 'False'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
++ 'service': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Service']"}),
++ 'unit': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'})
++ },
++ 'im.resourcemetadata': {
++ 'Meta': {'object_name': 'ResourceMetadata'},
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
++ 'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
++ },
++ 'im.service': {
++ 'Meta': {'object_name': 'Service'},
++ 'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
++ 'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'icon': ('django.db.models.fields.FilePathField', [], {'max_length': '100', 'blank': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
++ 'url': ('django.db.models.fields.FilePathField', [], {'max_length': '100'})
++ }
++ }
++
++ complete_apps = ['im']
--- /dev/null
--- /dev/null
++# encoding: utf-8
++import datetime
++from south.db import db
++from south.v2 import SchemaMigration
++from django.db import models
++
++class Migration(SchemaMigration):
++
++ def forwards(self, orm):
++
++ # Adding field 'AstakosUser.dirsturbed_quota'
++ db.add_column('im_astakosuser', 'dirsturbed_quota', self.gf('django.db.models.fields.BooleanField')(default=False, db_index=True), keep_default=False)
++
++
++ def backwards(self, orm):
++
++ # Deleting field 'AstakosUser.dirsturbed_quota'
++ db.delete_column('im_astakosuser', 'dirsturbed_quota')
++
++
++ models = {
++ 'auth.group': {
++ 'Meta': {'object_name': 'Group'},
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
++ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
++ },
++ 'auth.permission': {
++ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
++ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
++ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
++ },
++ 'auth.user': {
++ 'Meta': {'object_name': 'User'},
++ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
++ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
++ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
++ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
++ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
++ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
++ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
++ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
++ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
++ },
++ 'contenttypes.contenttype': {
++ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
++ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
++ },
++ 'im.additionalmail': {
++ 'Meta': {'object_name': 'AdditionalMail'},
++ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
++ },
++ 'im.approvalterms': {
++ 'Meta': {'object_name': 'ApprovalTerms'},
++ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 11, 2, 11, 49, 56, 479805)', 'db_index': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'location': ('django.db.models.fields.CharField', [], {'max_length': '255'})
++ },
++ 'im.astakosgroup': {
++ 'Meta': {'object_name': 'AstakosGroup', '_ormbases': ['auth.Group']},
++ 'approval_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
++ 'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 11, 2, 11, 49, 56, 473295)'}),
++ 'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
++ 'estimated_participants': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
++ 'expiration_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
++ 'homepage': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
++ 'issue_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.GroupKind']"}),
++ 'moderation_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
++ 'policy': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.AstakosGroupQuota']", 'blank': 'True'})
++ },
++ 'im.astakosgroupquota': {
++ 'Meta': {'unique_together': "(('resource', 'group'),)", 'object_name': 'AstakosGroupQuota'},
++ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosGroup']", 'blank': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'limit': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
++ 'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}),
++ 'uplimit': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'})
++ },
++ 'im.astakosuser': {
++ 'Meta': {'unique_together': "(('provider', 'third_party_identifier'),)", 'object_name': 'AstakosUser', '_ormbases': ['auth.User']},
++ 'activation_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
++ 'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
++ 'astakos_groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.AstakosGroup']", 'symmetrical': 'False', 'through': "orm['im.Membership']", 'blank': 'True'}),
++ 'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
++ 'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'date_signed_terms': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
++ 'dirsturbed_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
++ 'email_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'has_credits': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'has_signed_terms': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'invitations': ('django.db.models.fields.IntegerField', [], {'default': '100'}),
++ 'is_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'level': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
++ 'owner': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'owner'", 'null': 'True', 'to': "orm['im.AstakosGroup']"}),
++ 'policy': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.AstakosUserQuota']", 'symmetrical': 'False'}),
++ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
++ 'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
++ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
++ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'})
++ },
++ 'im.astakosuserquota': {
++ 'Meta': {'unique_together': "(('resource', 'user'),)", 'object_name': 'AstakosUserQuota'},
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'limit': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
++ 'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}),
++ 'uplimit': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}),
++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
++ },
++ 'im.emailchange': {
++ 'Meta': {'object_name': 'EmailChange'},
++ 'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'new_email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
++ 'requested_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 11, 2, 11, 49, 56, 481329)'}),
++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emailchange_user'", 'unique': 'True', 'to': "orm['im.AstakosUser']"})
++ },
++ 'im.groupkind': {
++ 'Meta': {'object_name': 'GroupKind'},
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'})
++ },
++ 'im.invitation': {
++ 'Meta': {'object_name': 'Invitation'},
++ 'code': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
++ 'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
++ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'inviter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invitations_sent'", 'null': 'True', 'to': "orm['im.AstakosUser']"}),
++ 'is_consumed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'realname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
++ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
++ },
++ 'im.membership': {
++ 'Meta': {'unique_together': "(('person', 'group'),)", 'object_name': 'Membership'},
++ 'date_joined': ('django.db.models.fields.DateField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
++ 'date_requested': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 11, 2, 11, 49, 56, 477491)', 'blank': 'True'}),
++ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosGroup']"}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
++ },
++ 'im.resource': {
++ 'Meta': {'object_name': 'Resource'},
++ 'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'meta': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.ResourceMetadata']", 'symmetrical': 'False'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
++ 'service': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Service']"}),
++ 'unit': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'})
++ },
++ 'im.resourcemetadata': {
++ 'Meta': {'object_name': 'ResourceMetadata'},
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
++ 'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
++ },
++ 'im.service': {
++ 'Meta': {'object_name': 'Service'},
++ 'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
++ 'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'icon': ('django.db.models.fields.FilePathField', [], {'max_length': '100', 'blank': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
++ 'url': ('django.db.models.fields.FilePathField', [], {'max_length': '100'})
++ }
++ }
++
++ complete_apps = ['im']
--- /dev/null
--- /dev/null
++# encoding: utf-8
++import datetime
++from south.db import db
++from south.v2 import SchemaMigration
++from django.db import models
++
++class Migration(SchemaMigration):
++
++ def forwards(self, orm):
++
++ # Adding field 'Resource.group'
++ db.add_column('im_resource', 'group', self.gf('django.db.models.fields.CharField')(max_length=255, null=True), keep_default=False)
++
++
++ def backwards(self, orm):
++
++ # Deleting field 'Resource.group'
++ db.delete_column('im_resource', 'group')
++
++
++ models = {
++ 'auth.group': {
++ 'Meta': {'object_name': 'Group'},
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
++ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
++ },
++ 'auth.permission': {
++ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
++ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
++ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
++ },
++ 'auth.user': {
++ 'Meta': {'object_name': 'User'},
++ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
++ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
++ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
++ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
++ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
++ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
++ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
++ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
++ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
++ },
++ 'contenttypes.contenttype': {
++ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
++ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
++ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
++ },
++ 'im.additionalmail': {
++ 'Meta': {'object_name': 'AdditionalMail'},
++ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
++ },
++ 'im.approvalterms': {
++ 'Meta': {'object_name': 'ApprovalTerms'},
++ 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 11, 2, 11, 50, 15, 262158)', 'db_index': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'location': ('django.db.models.fields.CharField', [], {'max_length': '255'})
++ },
++ 'im.astakosgroup': {
++ 'Meta': {'object_name': 'AstakosGroup', '_ormbases': ['auth.Group']},
++ 'approval_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
++ 'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 11, 2, 11, 50, 15, 255876)'}),
++ 'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
++ 'estimated_participants': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
++ 'expiration_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
++ 'homepage': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
++ 'issue_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'kind': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.GroupKind']"}),
++ 'moderation_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
++ 'policy': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.AstakosGroupQuota']", 'blank': 'True'})
++ },
++ 'im.astakosgroupquota': {
++ 'Meta': {'unique_together': "(('resource', 'group'),)", 'object_name': 'AstakosGroupQuota'},
++ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosGroup']", 'blank': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'limit': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
++ 'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}),
++ 'uplimit': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'})
++ },
++ 'im.astakosuser': {
++ 'Meta': {'unique_together': "(('provider', 'third_party_identifier'),)", 'object_name': 'AstakosUser', '_ormbases': ['auth.User']},
++ 'activation_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
++ 'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
++ 'astakos_groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.AstakosGroup']", 'symmetrical': 'False', 'through': "orm['im.Membership']", 'blank': 'True'}),
++ 'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
++ 'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'date_signed_terms': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
++ 'dirsturbed_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
++ 'email_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'has_credits': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'has_signed_terms': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'invitations': ('django.db.models.fields.IntegerField', [], {'default': '100'}),
++ 'is_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'level': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
++ 'owner': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'owner'", 'null': 'True', 'to': "orm['im.AstakosGroup']"}),
++ 'policy': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.AstakosUserQuota']", 'symmetrical': 'False'}),
++ 'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
++ 'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
++ 'updated': ('django.db.models.fields.DateTimeField', [], {}),
++ 'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'})
++ },
++ 'im.astakosuserquota': {
++ 'Meta': {'unique_together': "(('resource', 'user'),)", 'object_name': 'AstakosUserQuota'},
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'limit': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
++ 'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}),
++ 'uplimit': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}),
++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
++ },
++ 'im.emailchange': {
++ 'Meta': {'object_name': 'EmailChange'},
++ 'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'new_email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
++ 'requested_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 11, 2, 11, 50, 15, 263696)'}),
++ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emailchange_user'", 'unique': 'True', 'to': "orm['im.AstakosUser']"})
++ },
++ 'im.groupkind': {
++ 'Meta': {'object_name': 'GroupKind'},
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'})
++ },
++ 'im.invitation': {
++ 'Meta': {'object_name': 'Invitation'},
++ 'code': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
++ 'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
++ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'inviter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invitations_sent'", 'null': 'True', 'to': "orm['im.AstakosUser']"}),
++ 'is_consumed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
++ 'realname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
++ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
++ },
++ 'im.membership': {
++ 'Meta': {'unique_together': "(('person', 'group'),)", 'object_name': 'Membership'},
++ 'date_joined': ('django.db.models.fields.DateField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
++ 'date_requested': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 11, 2, 11, 50, 15, 259896)', 'blank': 'True'}),
++ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosGroup']"}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
++ },
++ 'im.resource': {
++ 'Meta': {'object_name': 'Resource'},
++ 'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
++ 'group': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'meta': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.ResourceMetadata']", 'symmetrical': 'False'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
++ 'service': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Service']"}),
++ 'unit': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'})
++ },
++ 'im.resourcemetadata': {
++ 'Meta': {'object_name': 'ResourceMetadata'},
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
++ 'value': ('django.db.models.fields.CharField', [], {'max_length': '255'})
++ },
++ 'im.service': {
++ 'Meta': {'object_name': 'Service'},
++ 'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
++ 'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
++ 'icon': ('django.db.models.fields.FilePathField', [], {'max_length': '100', 'blank': 'True'}),
++ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
++ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
++ 'url': ('django.db.models.fields.FilePathField', [], {'max_length': '100'})
++ }
++ }
++
++ complete_apps = ['im']
from random import randint
from collections import defaultdict
--from django.db import models
--from django.contrib.auth.models import User, UserManager, Group
++from django.db import models, IntegrityError
++from django.contrib.auth.models import User, UserManager, Group, Permission
from django.utils.translation import ugettext as _
from django.core.exceptions import ValidationError
from django.db import transaction
-from django.db.models.signals import pre_save, post_save, post_syncdb, post_delete
+from django.db.models.signals import (pre_save, post_save, post_syncdb,
+ post_delete)
++from django.contrib.contenttypes.models import ContentType
++
from django.dispatch import Signal
from django.db.models import Q
from astakos.im.endpoints.quotaholder import (register_users, send_quota,
register_resources)
from astakos.im.endpoints.aquarium.producer import report_user_event
--
++from astakos.im.functions import send_invitation
from astakos.im.tasks import propagate_groupmembers_quota
++from astakos.im.functions import send_invitation
logger = logging.getLogger(__name__)
++DEFAULT_CONTENT_TYPE = None
++try:
++ content_type = ContentType.objects.get(app_label='im', model='astakosuser')
++except:
++ content_type = DEFAULT_CONTENT_TYPE
++
++RESOURCE_SEPARATOR = '.'
++
class Service(models.Model):
name = models.CharField('Name', max_length=255, unique=True, db_index=True)
def save(self, **kwargs):
if not self.id:
self.renew_token()
-- self.full_clean()
super(Service, self).save(**kwargs)
def renew_token(self):
def __str__(self):
return self.name
++ @property
++ def resources(self):
++ return self.resource_set.all()
++
++ @resources.setter
++ def resources(self, resources):
++ for s in resources:
++ self.resource_set.create(**s)
++
++ def add_resource(self, service, resource, uplimit, update=True):
++ """Raises ObjectDoesNotExist, IntegrityError"""
++ resource = Resource.objects.get(service__name=service, name=resource)
++ if update:
++ AstakosUserQuota.objects.update_or_create(user=self,
++ resource=resource,
++ defaults={'uplimit': uplimit})
++ else:
++ q = self.astakosuserquota_set
++ q.create(resource=resource, uplimit=uplimit)
++
class ResourceMetadata(models.Model):
key = models.CharField('Name', max_length=255, unique=True, db_index=True)
name = models.CharField('Name', max_length=255, unique=True, db_index=True)
meta = models.ManyToManyField(ResourceMetadata)
service = models.ForeignKey(Service)
++ desc = models.TextField('Description', null=True)
++ unit = models.CharField('Name', null=True, max_length=255)
++ group = models.CharField('Group', null=True, max_length=255)
def __str__(self):
-- return '%s.%s' % (self.service, self.name)
++ return '%s%s%s' % (self.service, RESOURCE_SEPARATOR, self.name)
class GroupKind(models.Model):
def members(self):
q = self.membership_set.select_related().all()
return [m.person for m in q]
--
++
@property
def approved_members(self):
q = self.membership_set.select_related().all()
for q in self.astakosgroupquota_set.select_related().all():
d[q.resource] += q.uplimit
return d
--
++
++ def add_policy(self, service, resource, uplimit, update=True):
++ """Raises ObjectDoesNotExist, IntegrityError"""
++ print '#', locals()
++ resource = Resource.objects.get(service__name=service, name=resource)
++ if update:
++ AstakosGroupQuota.objects.update_or_create(
++ group=self,
++ resource=resource,
++ defaults={'uplimit': uplimit}
++ )
++ else:
++ q = self.astakosgroupquota_set
++ q.create(resource=resource, uplimit=uplimit)
++
++ @property
++ def policies(self):
++ return self.astakosgroupquota_set.select_related().all()
++
++ @policies.setter
++ def policies(self, policies):
++ for p in policies:
++ service = policies.get('service', None)
++ resource = policies.get('resource', None)
++ uplimit = policies.get('uplimit', 0)
++ update = policies.get('update', True)
++ self.add_policy(service, resource, uplimit, update)
++
@property
def owners(self):
return self.owner.all()
has_credits = models.BooleanField('Has credits?', default=False)
has_signed_terms = models.BooleanField(
-- 'Agree with the terms?', default=False)
++ 'I agree with the terms', default=False)
date_signed_terms = models.DateTimeField(
'Signed terms date', null=True, blank=True)
through='Membership')
__has_signed_terms = False
++ dirsturbed_quota = models.BooleanField('Needs quotaholder syncing',
++ default=False, db_index=True)
owner = models.ManyToManyField(
AstakosGroup, related_name='owner', null=True)
def __init__(self, *args, **kwargs):
super(AstakosUser, self).__init__(*args, **kwargs)
self.__has_signed_terms = self.has_signed_terms
-- if not self.id:
++ if not self.id and not self.is_active:
self.is_active = False
@property
else:
self.last_name = parts[0]
++ def add_permission(self, pname):
++ if self.has_perm(pname):
++ return
++ p, created = Permission.objects.get_or_create(codename=pname,
++ name=pname.capitalize(),
++ content_type=content_type)
++ self.user_permissions.add(p)
++
++ def remove_permission(self, pname):
++ if self.has_perm(pname):
++ return
++ p = Permission.objects.get(codename=pname,
++ content_type=content_type)
++ self.user_permissions.remove(p)
++
@property
def invitation(self):
try:
except Invitation.DoesNotExist:
return None
++ def invite(self, email, realname):
++ inv = Invitation(inviter=self, username=email, realname=realname)
++ inv.save()
++ send_invitation(inv)
++ self.invitations = max(0, self.invitations - 1)
++ self.save()
++
@property
def quota(self):
++ """Returns a dict with the sum of quota limits per resource"""
d = defaultdict(int)
-- for q in self.astakosuserquota_set.select_related().all():
++ for q in self.policies:
d[q.resource] += q.uplimit
-- for m in self.membership_set.select_related().all():
++ for m in self.extended_groups:
if not m.is_approved:
continue
g = m.group
continue
for r, uplimit in g.quota.iteritems():
d[r] += uplimit
--
++
# TODO set default for remaining
return d
++ @property
++ def policies(self):
++ return self.astakosuserquota_set.select_related().all()
++
++ @policies.setter
++ def policies(self, policies):
++ for p in policies:
++ service = policies.get('service', None)
++ resource = policies.get('resource', None)
++ uplimit = policies.get('uplimit', 0)
++ update = policies.get('update', True)
++ self.add_policy(service, resource, uplimit, update)
++
++ def add_policy(self, service, resource, uplimit, update=True):
++ """Raises ObjectDoesNotExist, IntegrityError"""
++ resource = Resource.objects.get(service__name=service, name=resource)
++ if update:
++ AstakosUserQuota.objects.update_or_create(user=self,
++ resource=resource,
++ defaults={'uplimit': uplimit})
++ else:
++ q = self.astakosuserquota_set
++ q.create(resource=resource, uplimit=uplimit)
++
++ def remove_policy(self, service, resource):
++ """Raises ObjectDoesNotExist, IntegrityError"""
++ resource = Resource.objects.get(service__name=service, name=resource)
++ q = self.policies.get(resource=resource).delete()
++
++ @property
++ def extended_groups(self):
++ return self.membership_set.select_related().all()
++
++ @extended_groups.setter
++ def extended_groups(self, groups):
++ #TODO exceptions
++ for name in groups:
++ group = AstakosGroup.objects.get(name=name)
++ self.membership_set.create(group=group)
++
def save(self, update_timestamps=True, **kwargs):
if update_timestamps:
if not self.id:
return False
return True
++ def store_disturbed_quota(self, set=True):
++ self.disturbed_quota = set
++ self.save()
++
class Membership(models.Model):
person = models.ForeignKey(AstakosUser)
self.delete()
quota_disturbed.send(sender=self, users=(self.person,))
++class AstakosQuotaManager(models.Manager):
++ def _update_or_create(self, **kwargs):
++ assert kwargs, \
++ 'update_or_create() must be passed at least one keyword argument'
++ obj, created = self.get_or_create(**kwargs)
++ defaults = kwargs.pop('defaults', {})
++ if created:
++ return obj, True, False
++ else:
++ try:
++ params = dict(
++ [(k, v) for k, v in kwargs.items() if '__' not in k])
++ params.update(defaults)
++ for attr, val in params.items():
++ if hasattr(obj, attr):
++ setattr(obj, attr, val)
++ sid = transaction.savepoint()
++ obj.save(force_update=True)
++ transaction.savepoint_commit(sid)
++ return obj, False, True
++ except IntegrityError, e:
++ transaction.savepoint_rollback(sid)
++ try:
++ return self.get(**kwargs), False, False
++ except self.model.DoesNotExist:
++ raise e
++
++ update_or_create = _update_or_create
class AstakosGroupQuota(models.Model):
++ objects = AstakosQuotaManager()
limit = models.PositiveIntegerField('Limit', null=True) # obsolete field
uplimit = models.BigIntegerField('Up limit', null=True)
resource = models.ForeignKey(Resource)
class Meta:
unique_together = ("resource", "group")
--
class AstakosUserQuota(models.Model):
++ objects = AstakosQuotaManager()
limit = models.PositiveIntegerField('Limit', null=True) # obsolete field
uplimit = models.BigIntegerField('Up limit', null=True)
resource = models.ForeignKey(Resource)
class EmailChange(models.Model):
- new_email_address = models.EmailField(_(u'new e-mail address'), help_text=_(u'Your old email address will be used until you verify your new one.'))
+ new_email_address = models.EmailField(_(u'new e-mail address'),
- help_text=_(u'Your old email address will be used until you verify your new one.'))
++ help_text=_(u'Your old email address will be used until you verify your new one.'))
user = models.ForeignKey(
AstakosUser, unique=True, related_name='emailchange_user')
requested_at = models.DateTimeField(default=datetime.now())
else:
get = AstakosUser.__getattribute__
l = filter(lambda f: get(db_instance, f) != get(instance, f),
-- BILLING_FIELDS
-- )
++ BILLING_FIELDS)
instance.aquarium_report = True if l else False
set_default_group(instance)
# TODO handle socket.error & IOError
register_users((instance,))
++ instance.renew_token()
def resource_post_save(sender, instance, created, **kwargs):
elif sender == AstakosGroup:
if not instance.is_enabled:
return
-- quota_disturbed.send(sender=sender, users=users)
++ map(lambda u: u.store_disturbed_quota, users)
--
--def on_quota_disturbed(sender, users, **kwargs):
-- print '>>>', locals()
-- if not users:
-- return
-- send_quota(users)
++# def on_quota_disturbed(sender, users, **kwargs):
++# print '>>>', locals()
++# if not users:
++# return
++# send_quota(users)
post_syncdb.connect(fix_superusers)
post_save.connect(user_post_save, sender=User)
post_save.connect(resource_post_save, sender=Resource)
quota_disturbed = Signal(providing_args=["users"])
--quota_disturbed.connect(on_quota_disturbed)
++# quota_disturbed.connect(on_quota_disturbed)
post_delete.connect(send_quota_disturbed, sender=AstakosGroup)
post_delete.connect(send_quota_disturbed, sender=Membership)
LOGGING_LEVEL = getattr(settings, 'ASTAKOS_LOGGING_LEVEL', INFO)
# Configurable email subjects
--INVITATION_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_INVITATION_EMAIL_SUBJECT',
-- 'Invitation to %s alpha2 testing' % SITENAME)
++INVITATION_EMAIL_SUBJECT = getattr(
++ settings, 'ASTAKOS_INVITATION_EMAIL_SUBJECT',
++ 'Invitation to %s alpha2 testing' % SITENAME)
GREETING_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_GREETING_EMAIL_SUBJECT',
-- 'Welcome to %s alpha2 testing' % SITENAME)
++ 'Welcome to %s alpha2 testing' % SITENAME)
FEEDBACK_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_FEEDBACK_EMAIL_SUBJECT',
-- 'Feedback from %s alpha2 testing' % SITENAME)
--VERIFICATION_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_VERIFICATION_EMAIL_SUBJECT',
-- '%s alpha2 testing account activation is needed' % SITENAME)
--ADMIN_NOTIFICATION_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_ADMIN_NOTIFICATION_EMAIL_SUBJECT',
-- '%s alpha2 testing account created (%%(user)s)' % SITENAME)
--HELPDESK_NOTIFICATION_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_HELPDESK_NOTIFICATION_EMAIL_SUBJECT',
-- '%s alpha2 testing account activated (%%(user)s)' % SITENAME)
--EMAIL_CHANGE_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_EMAIL_CHANGE_EMAIL_SUBJECT',
-- 'Email change on %s alpha2 testing' % SITENAME)
--PASSWORD_RESET_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_PASSWORD_RESET_EMAIL_SUBJECT',
-- 'Password reset on %s alpha2 testing' % SITENAME)
-
-# Configurable email subjects
-INVITATION_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_INVITATION_EMAIL_SUBJECT',
- 'Invitation to %s alpha2 testing' % SITENAME)
-GREETING_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_GREETING_EMAIL_SUBJECT',
- 'Welcome to %s alpha2 testing' % SITENAME)
-FEEDBACK_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_FEEDBACK_EMAIL_SUBJECT',
- 'Feedback from %s alpha2 testing' % SITENAME)
-VERIFICATION_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_VERIFICATION_EMAIL_SUBJECT',
- '%s alpha2 testing account activation is needed' % SITENAME)
-ADMIN_NOTIFICATION_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_ADMIN_NOTIFICATION_EMAIL_SUBJECT',
- '%s alpha2 testing account created (%%(user)s)' % SITENAME)
-HELPDESK_NOTIFICATION_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_HELPDESK_NOTIFICATION_EMAIL_SUBJECT',
- '%s alpha2 testing account activated (%%(user)s)' % SITENAME)
-EMAIL_CHANGE_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_EMAIL_CHANGE_EMAIL_SUBJECT',
- 'Email change on %s alpha2 testing' % SITENAME)
-PASSWORD_RESET_EMAIL_SUBJECT = getattr(settings, 'ASTAKOS_PASSWORD_RESET_EMAIL_SUBJECT',
- 'Password reset on %s alpha2 testing' % SITENAME)
++ 'Feedback from %s alpha2 testing' % SITENAME)
++VERIFICATION_EMAIL_SUBJECT = getattr(
++ settings, 'ASTAKOS_VERIFICATION_EMAIL_SUBJECT',
++ '%s alpha2 testing account activation is needed' % SITENAME)
++ACCOUNT_CREATION_SUBJECT = getattr(
++ settings, 'ASTAKOS_ACCOUNT_CREATION_SUBJECT',
++ '%s alpha2 testing account created (%%(user)s)' % SITENAME)
++GROUP_CREATION_SUBJECT = getattr(settings, 'ASTAKOS_GROUP_CREATION_SUBJECT',
++ '%s alpha2 testing group created (%%(group)s)' % SITENAME)
++HELPDESK_NOTIFICATION_EMAIL_SUBJECT = getattr(
++ settings, 'ASTAKOS_HELPDESK_NOTIFICATION_EMAIL_SUBJECT',
++ '%s alpha2 testing account activated (%%(user)s)' % SITENAME)
++EMAIL_CHANGE_EMAIL_SUBJECT = getattr(
++ settings, 'ASTAKOS_EMAIL_CHANGE_EMAIL_SUBJECT',
++ 'Email change on %s alpha2 testing' % SITENAME)
++PASSWORD_RESET_EMAIL_SUBJECT = getattr(
++ settings, 'ASTAKOS_PASSWORD_RESET_EMAIL_SUBJECT',
++ 'Password reset on %s alpha2 testing' % SITENAME)
# Set the quota holder component URI
QUOTA_HOLDER_URL = getattr(settings, 'ASTAKOS_QUOTA_HOLDER_URL', '')
# Set the cloud service properties
SERVICES = getattr(settings, 'ASTAKOS_SERVICES',
-- {'cyclades': {'url':'https://node1.example.com/ui/',
++ {'cyclades': {'url': 'https://node1.example.com/ui/',
'quota': {'vm': 2}},
-- 'pithos+': {'url':'https://node2.example.com/ui/',
-- 'quota': {'diskspace': 50 * 1024 * 1024 * 1024}}})
++ 'pithos+': {'url': 'https://node2.example.com/ui/',
++ 'quota': {'diskspace': 50 * 1024 * 1024 * 1024}}})
# Set the billing URI
AQUARIUM_URL = getattr(settings, 'ASTAKOS_AQUARIUM_URL', '')
# Set how many objects should be displayed per page
-PAGINATE_BY = getattr(settings, 'ASTAKOS_PAGINATE_BY', 8)
+PAGINATE_BY = getattr(settings, 'ASTAKOS_PAGINATE_BY', 8)
+
+# Enforce token renewal on password change/reset
- NEWPASSWD_INVALIDATE_TOKEN = getattr(settings, 'ASTAKOS_NEWPASSWD_INVALIDATE_TOKEN', True)
++NEWPASSWD_INVALIDATE_TOKEN = getattr(
++ settings, 'ASTAKOS_NEWPASSWD_INVALIDATE_TOKEN', True)
table.alt-style tr td a.open { background-position:-16px 0} \r
\r
.projects .details a.edit { float:right; margin-left:20px; }\r
- .projects .details .data { overflow:hidden; }\r
- .projects .editable form textarea { width:70%; height:50px; max-width:70%; width:270px; height:120px;}
+ .projects .details .data { overflow:hidden; }
+ .projects .editable form textarea { width:70%; height:50px; max-width:70%; width:270px; height:120px;}\r
+ \r
+ \r
+ /* quotas-form */\r
+ \r
+ .quotas-form fieldset { background:url(../images/dots.jpg) repeat-x scroll center bottom transparent; margin-bottom:3em; padding-bottom:3em; position:relative; }\r
-.quotas-form fieldset legend { color:#55B577; font-size:1.154em; margin-bottom:3em; position:relative; }\r
+ .quotas-form fieldset legend span { color:#222; }\r
+ .quotas-form .with-checkbox .checkbox-widget { margin-top:12px; } \r
+ .quotas-form .with-checkbox span.info { bottom:22px; }\r
-.quotas-form .form-row.submit { text-align:center; }\r
+ .quotas-form input[type="submit"] { margin:15px 0; background-color:#B3B3B3 }\r
+ .quotas-form input[type="submit"]:hover { background:#55B577 }\r
+ .quotas-form input[type="submit"]:focus { border-color: #B3B3B3}\r
+ .quotas-form input[type="submit"]:focus:hover { border-color: #55B577}\r
+ .quotas-form fieldset ul { padding:0; margin:0 0 1em; }\r
+ .quotas-form fieldset ul li { list-style:none outside none; float:left; padding:0 0 0 60px; margin:0; }\r
+ .quotas-form fieldset ul li:first-child { padding-left:0; }\r
+ .quotas-form fieldset ul li a { display:block; width:82px; height:82px; overflow:hidden; }\r
+ .quotas-form fieldset ul li a:hover img { margin-top:-151px; }\r
+ .quotas-form fieldset ul li a.selected img { margin-top:-313px; }\r
-.quotas-form fieldset ul li a.selected:focus { outline:0 none; }\r
+ .quotas-form p.msg { color:#B3B3B3; }\r
+ .quotas-form a.delete { position:absolute; right:0; top:0; color:#B3B3B3; z-index:2 }\r
+ .quotas-form .group { display:none; position:relative; background:url(../images/dots.jpg) repeat-x scroll center bottom; margin-bottom:2em; padding-bottom:2em;}\r
+ .quotas-form .group fieldset { background:transparent; margin-bottom:1em; padding-bottom:1em; }\r
+ .quotas-form .group fieldset legend { margin-bottom:1em; padding-bottom:1em; }\r
+ .quotas-form fieldset ul li.rel+li.rel { background:url(../images/quota-related-bg.png) no-repeat left center; }\r
+ .quotas-form .double-checks label { font-size:1.077em; }\r
+ .quotas-form .double-checks .form-row { float:left; margin-right:10px;}\r
+ .quotas-form .double-checks .with-checkbox .checkbox-widget { left:0; }\r
+ .quotas-form .double-checks .with-checkbox input[type="text"] { width:60px; float:left; margin:9px 15px -9px; display:none; padding:6px; }\r
+ .quotas-form .double-checks .with-checkbox label{ width:auto; float:left; margin-left:35px; }\r
+ .quotas-form .double-checks .with-checkbox input[type="text"].hideshow { display:block; }\r
+ form.quotas-form legend span.info { top:0; bottom:auto; left:250px; }\r
+ form.quotas-form legend span.info span { width:400px; }\r
+ .quotas-form .with-checkbox+.with-checkbox { width:196px; }\r
+ \r
-/* stats */\r
+ .stats ul { margin:0; padding:0; list-style:none outside none; }\r
+ .stats ul li { margin:0 0 1em 0; padding:0 0 1em 0; list-style:none outside none; background:url(../images/stats-line.jpg) repeat-x left bottom}\r
+ .stats .bar { padding:20px 0; text-align:center; float:left; width:200px;}\r
+ .stats .bar div { width:340px; height:30px; border:1px solid #000;}\r
+ .stats .bar span { text-align:right; display:block; height:100%; color:#fff; line-height:30px; font-size:1.231em; text-indent:50px;}\r
+ .stats .red .bar span { background:#ef4f54; }\r
+ .stats .yellow .bar span { background:#f6921e; }\r
+ .stats .green .bar span { background:#55b577; }\r
+ .stats .img-wrap { float:left; width:100px; background:url(../images/statistics_icons.png) no-repeat center center; padding:30px 0; }\r
+ .stats .info { margin:0 25px ; width:320px; float:left; }\r
+ .stats .info p { color:#999; margin:0; }\r
+ .stats .info h3 { font-size:1.231em; color:#222222 }\r
+ .stats .vm .img-wrap { background-image:url(../images/vm-stats.png) }\r
+ .stats .ram .img-wrap { background-image:url(../images/ram-stats.png) }\r
+ .stats .network .img-wrap { background-image:url(../images/network-stats.png) }\r
+ .stats .disk .img-wrap { background-image:url(../images/disk-stats.png) }\r
+ .stats .storage .img-wrap { background-image:url(../images/storage-stats.png) }\r
+ .stats .bandwidth .img-wrap { background-image:url(../images/bandwidth-stats.png) }\r
+ \r
+ .stats .red .img-wrap { background-position: 15px 7px; }\r
+ .stats .yellow .img-wrap { background-position: -124px 7px; }\r
+ .stats .green .img-wrap { background-position: -263px 7px; }\r
+ .projects .editable form textarea { width:70%; height:50px; max-width:70%; width:270px; height:120px;}
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
-# 'djcelery',
-# 'debug_toolbar',
+ 'djcelery',
- # 'debug_toolbar'
- ]
++ 'debug_toolbar',
+ ]
context_processors = [
'django.core.context_processors.media',
'synnefo.lib.middleware.LoggingConfigMiddleware',
'synnefo.lib.middleware.SecureMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
- # 'debug_toolbar.middleware.DebugToolbarMiddleware'
-# 'debug_toolbar.middleware.DebugToolbarMiddleware',
++ 'debug_toolbar.middleware.DebugToolbarMiddleware',
]
loggers = {
BROKER_URL = ''
--INTERNAL_IPS = ('127.0.0.1',)
++INTERNAL_IPS = ('127.0.0.1',)
return render_response(on_creation_template,
signup_form=form,
provider='shibboleth',
- context_instance=get_context(
- request,
- extra_context
- )
- )
+ context_instance=get_context(request,
- extra_context))
++ extra_context))
{% block page.body %}
<div class="maincol {% block innerpage.class %}{% endblock %}">
+ <div class="stats clearfix">
+ <ul>
+ {% for r in data.resources %}
+
+ <li class="clearfix {{ r.load_class }} {{ r.name}}">
+ <div class="img-wrap"> </div>
+ <div class="info">
+ <h3>{{ r.description }}</h3>
+ <p>
+ {{ r.ratio|floatformat }}% Used<br>
+ You are using {{ r.currValue }} {{ r.unit }} out of your {{ r.maxValue }}{{ r.unit }}
+ {% if r.maxValue == '1' %}
+ {{ r.name|capfirst}}
+ {% else %}
+ {{ r.plural|capfirst }}
+ {% endif %}
+ - Aouch!
+ </p>
+ </div>
+ <div class="bar">
+ <div><span style="width:{{ r.ratio|floatformat }}%;">{{ r.ratio|floatformat }}% </span></div>
+ </div>
+ </li>
+ {% endfor %}
+ </ul>
+ </div>
+ <!--
<div class="section">
+ {% for k, v in user.quota|items %}
+ <strong>{{k}}</strong>
+ <table class="zebra-striped id-sorted">
-<!--
+ <thead>
+ <tr>
+ <th>Limit (Group)</th>
+ </tr>
+ </thead>
- -->
- <!--
+ <tbody>
+ {% for m in user.membership_set.select_related.all %}
+ {% if m.group.is_enabled %}
+ {% with m.group.quota as quota %}
+ {% if quota %}
+ {% for kk, vv in quota|items %}
+ {% if k == kk %}
+ <tr>
+ <td>{{ vv }} ({{m.group.name}})</td>
+ </tr>
+ {% endif %}
+ {% endfor %}
+ {% endif %}
+ {% endwith %}
+ {% endif %}
+ {% endfor %}
+ <tr>
+ <td><strong>{{ v }}</strong></td>
+ </tr>
+ <tr/>
+ </tbody>
+ </table>
+ {% endfor %}
+ </div>
<form action="" method="post"
class="withlabels">{% csrf_token %}
{% include "im/form_render.html" %}
--- /dev/null
--- /dev/null
++{% extends "im/account_base.html" %}
++
++{% load filters %}
++
++{% block page.body %}
++<div class="maincol {% block innerpage.class %}{% endblock %}">
++ <div class="stats clearfix">
++ <ul>
++ {% for r in data %}
++
++ <li class="clearfix {{ r.load_class }} {{ r.name}}">
++ <div class="img-wrap"> </div>
++ <div class="info">
++ <h3>{{ r.description }}</h3>
++ <p>
++ {{ r.ratio|floatformat }}% Used<br>
++ You are using {{ r.currValue }} {{ r.unit }} out of your {{ r.maxValue }}{{ r.unit }} {{ r.plural|capfirst }} - Aouch!
++ </p>
++ </div>
++ <div class="bar">
++ <div><span style="width:{{ r.ratio|floatformat }}%;">{{ r.ratio|floatformat }}% </span></div>
++ </div>
++ </li>
++ {% endfor %}
++ </ul>
++ </div>
++</div>
++{% endblock %}
'astakos.im.views.feedback': 'PROFILE_MESSAGES',
})
++
@register.tag(name='display_messages')
def display_messages(parser, token):
return MessagesNode()
++
class DummyMessage(object):
def __init__(self, type, msg):
self.message = msg
def __repr__(self):
return "%s: %s" % (self.tags, self.message)
++
class MessagesNode(template.Node):
def get_view_messages(self, context):
cls = messages[-1].tags
content = '<div class="top-msg active %s">' % cls
for msg in messages:
-- content += '<div class="msg %s">%s</div>' % (msg.tags, msg.message)
++ content += '<div class="msg %s">%s</div>' % (
++ msg.tags, msg.message)
content += '<a href="#" title="close" class="close">X</a>'
content += '</div>'
DELIM = ','
++
@register.filter
def monthssince(joined_date):
now = datetime.datetime.now()
-- date = datetime.datetime(year=joined_date.year, month=joined_date.month, day=1)
++ date = datetime.datetime(
++ year=joined_date.year, month=joined_date.month, day=1)
months = []
--
++
month = date.month
year = date.year
-- timestamp=calendar.timegm( date.utctimetuple() )
--
++ timestamp = calendar.timegm(date.utctimetuple())
++
while date < now:
months.append((year, month, timestamp))
--
++
if date.month < 12:
month = date.month + 1
year = date.year
else:
month = 1
year = date.year + 1
--
++
date = datetime.datetime(year=year, month=month, day=1)
-- timestamp=calendar.timegm( date.utctimetuple() )
--
++ timestamp = calendar.timegm(date.utctimetuple())
++
return months
--
++
++
@register.filter
def lookup(d, key):
return d.get(key)
@register.filter
def month_name(month_number):
return calendar.month_name[month_number]
--
++
@register.filter
--def todate(value, arg = ''):
++def todate(value, arg=''):
secs = int(value) / 1000
return datetime.datetime.fromtimestamp(secs)
@register.filter
--def rcut(value, chars = '/'):
++def rcut(value, chars='/'):
return value.rstrip(chars)
++
@register.filter
def paginate(l, args):
page, delim, sorting = args.partition(DELIM)
default = ''
if sorting.endswith('_date'):
default = datetime.datetime.utcfromtimestamp(0)
-- l.sort(key=lambda i: getattr(i, sorting) \
-- if getattr(i, sorting) else default)
--
++ l.sort(key=lambda i: getattr(i, sorting)
++ if getattr(i, sorting) else default)
++
paginator = Paginator(l, PAGINATE_BY)
--
++
try:
page_number = int(page)
except ValueError:
page = paginator.page(1)
return page
++
@register.filter
def concat(str1, str2):
if not str2:
return str(str1)
return '%s%s%s' % (str1, DELIM, str2)
++
@register.filter
def items(d):
if isinstance(d, defaultdict):
return d.iteritems()
-- return d
++ return d
{}, name='group_join'),
url(r'^group/(?P<group_id>\d+)/leave/?$', 'group_leave',
{}, name='group_leave'),
-- url(r'^group/(?P<group_id>\d+)/(?P<user_id>\d+)/approve/?$',
++ url(
++ r'^group/(?P<group_id>\d+)/(?P<user_id>\d+)/approve/?$',
'approve_member', {}, name='approve_member'),
-- url(r'^group/(?P<group_id>\d+)/(?P<user_id>\d+)/disapprove/?$',
++ url(
++ r'^group/(?P<group_id>\d+)/(?P<user_id>\d+)/disapprove/?$',
'disapprove_member', {}, name='disapprove_member'),
url(r'^group/create/?$', 'group_create_list', {},
name='group_create_list'),
url(r'^local/?$', 'local.login')
)
urlpatterns += patterns('django.contrib.auth.views',
- url(r'^local/password_reset/?$', 'password_reset',
- {'email_template_name':'registration/password_email.txt',
- 'password_reset_form':ExtendedPasswordResetForm}),
- url(r'^local/password_reset_done/?$', 'password_reset_done'),
- url(r'^local/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/?$',
- 'password_reset_confirm', {'set_password_form':ExtendedSetPasswordForm}),
- url(r'^local/password/reset/complete/?$', 'password_reset_complete'),
- url(r'^password_change/?$', 'password_change', {'post_change_redirect':'profile',
- 'password_change_form':ExtendedPasswordChangeForm})
- )
+ url(r'^local/password_reset/?$', 'password_reset',
+ {'email_template_name': 'registration/password_email.txt',
+ 'password_reset_form': ExtendedPasswordResetForm}),
+ url(r'^local/password_reset_done/?$',
+ 'password_reset_done'),
+ url(
+ r'^local/reset/confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/?$',
- 'password_reset_confirm'),
++ 'password_reset_confirm', {'set_password_form': ExtendedSetPasswordForm}),
+ url(r'^local/password/reset/complete/?$',
+ 'password_reset_complete'),
+ url(
+ r'^password_change/?$', 'password_change', {'post_change_redirect': 'profile',
+ 'password_change_form': ExtendedPasswordChangeForm})
+ )
if INVITATIONS_ENABLED:
urlpatterns += patterns('astakos.im.views',
from django.utils.translation import ugettext as _
from django.contrib.auth import authenticate
from django.core.urlresolvers import reverse
--from django.core.exceptions import ValidationError
--
++from django.core.exceptions import ValidationError, ObjectDoesNotExist
++from django.db.models.fields import Field
from astakos.im.models import AstakosUser, Invitation
from astakos.im.settings import COOKIE_NAME, \
COOKIE_DOMAIN, COOKIE_SECURE, FORCE_PROFILE_UPDATE, LOGGING_LEVEL
try:
return request.__getattribute__(request.method)
except AttributeError:
- return {}
- return request.GET
++ return {}
++
++
++def model_to_dict(obj, exclude=['AutoField', 'ForeignKey', 'OneToOneField'],
++ include_empty=True):
++ '''
++ serialize model object to dict with related objects
++
++ author: Vadym Zakovinko <vp@zakovinko.com>
++ date: January 31, 2011
++ http://djangosnippets.org/snippets/2342/
++ '''
++ tree = {}
++ for field_name in obj._meta.get_all_field_names():
++ try:
++ field = getattr(obj, field_name)
++ except (ObjectDoesNotExist, AttributeError):
++ continue
++
++ if field.__class__.__name__ in ['RelatedManager', 'ManyRelatedManager']:
++ if field.model.__name__ in exclude:
++ continue
++
++ if field.__class__.__name__ == 'ManyRelatedManager':
++ exclude.append(obj.__class__.__name__)
++ subtree = []
++ for related_obj in getattr(obj, field_name).all():
++ value = model_to_dict(related_obj, exclude=exclude)
++ if value or include_empty:
++ subtree.append(value)
++ if subtree or include_empty:
++ tree[field_name] = subtree
++ continue
++
++ field = obj._meta.get_field_by_name(field_name)[0]
++ if field.__class__.__name__ in exclude:
++ continue
++
++ if field.__class__.__name__ == 'RelatedObject':
++ exclude.append(field.model.__name__)
++ tree[field_name] = model_to_dict(getattr(obj, field_name),
++ exclude=exclude)
++ continue
++
++ value = getattr(obj, field_name)
++ if field.__class__.__name__ == 'ForeignKey':
++ value = unicode(value) if value is not None else value
++ if value or include_empty:
++ tree[field_name] = value
++
++ return tree
import logging
import calendar
++import inflect
++
++engine = inflect.engine()
from urllib import quote
from functools import wraps
from django.core.urlresolvers import reverse
from django.db import transaction
from django.db.models import Q
- <<<<<<< HEAD
from django.db.utils import IntegrityError
from django.forms.fields import URLField
--from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, \
-- HttpResponseRedirect, HttpResponseBadRequest, Http404
++from django.http import (HttpResponse, HttpResponseBadRequest,
++ HttpResponseForbidden, HttpResponseRedirect,
++ HttpResponseBadRequest, Http404)
from django.shortcuts import redirect
from django.template import RequestContext, loader as template_loader
from django.utils.http import urlencode
from django.http import HttpResponseBadRequest
from django.core.xheaders import populate_xheaders
--from astakos.im.models import (
-- AstakosUser, ApprovalTerms, AstakosGroup, Resource,
-- EmailChange, GroupKind, Membership, AstakosGroupQuota)
++from astakos.im.models import (AstakosUser, ApprovalTerms, AstakosGroup,
++ Resource, EmailChange, GroupKind, Membership,
++ AstakosGroupQuota)
+from django.views.decorators.http import require_http_methods
+
from astakos.im.activation_backends import get_backend, SimpleBackend
from astakos.im.util import get_context, prepare_response, set_cookie, get_query
from astakos.im.forms import (LoginForm, InvitationForm, ProfileForm,
AstakosGroupSortForm, MembersSortForm,
TimelineForm, PickResourceForm)
from astakos.im.functions import (send_feedback, SendMailError,
-- invite as invite_func, logout as auth_logout,
++ logout as auth_logout,
activate as activate_func,
switch_account_to_shibboleth,
-- send_admin_notification,
++ send_group_creation_notification,
SendNotificationError)
from astakos.im.endpoints.quotaholder import timeline_charge
--from astakos.im.settings import (
-- COOKIE_NAME, COOKIE_DOMAIN, SITENAME, LOGOUT_NEXT,
-- LOGGING_LEVEL, PAGINATE_BY)
++from astakos.im.settings import (COOKIE_NAME, COOKIE_DOMAIN, LOGOUT_NEXT,
++ LOGGING_LEVEL, PAGINATE_BY)
from astakos.im.tasks import request_billing
++from astakos.im.api.callpoint import AstakosDjangoDBCallpoint
logger = logging.getLogger(__name__)
DB_REPLACE_GROUP_SCHEME = """REPLACE(REPLACE("auth_group".name, 'http://', ''),
'https://', '')"""
++
def render_response(template, tab=None, status=200, reset_cookie=False,
context_instance=None, **kwargs):
"""
if inviter.invitations > 0:
if form.is_valid():
try:
-- invitation = form.save()
-- invite_func(invitation, inviter)
-- message = _('Invitation sent to %s' % invitation.username)
++ email = form.cleaned_data.get('username')
++ realname = form.cleaned_data.get('realname')
++ inviter.invite(email, realname)
++ message = _('Invitation sent to %s' % email)
messages.success(request, message)
except SendMailError, e:
message = e.message
return response
messages.success(request, _('You have successfully logged out.'))
context = get_context(request, extra_context)
-- response.write(template_loader.render_to_string(template, context_instance=context))
++ response.write(
++ template_loader.render_to_string(template, context_instance=context))
return response
pass
if not term:
++ messages.error(request, 'There are no approval terms.')
return HttpResponseRedirect(reverse('index'))
f = open(term.location, 'r')
terms = f.read()
post_change_redirect=reverse('edit_profile'),
password_change_form=ExtendedPasswordChangeForm)
+
-@signed_terms_required
+@require_http_methods(["GET", "POST"])
@login_required
+@signed_terms_required
@transaction.commit_manually
def change_email(request, activation_key=None,
email_template_name='registration/email_change_email.txt',
# send notification
try:
-- send_admin_notification(
++ send_group_creation_notification(
template_name='im/group_creation_notification.txt',
dictionary={
'group': new_object,
'owner': request.user,
'policies': policies,
-- },
-- subject='%s alpha2 testing group creation notification' % SITENAME
++ }
)
except SendNotificationError, e:
messages.error(request, e, fail_silently=True)
d['own'].append(g)
else:
d['other'].append(g)
--
++
# validate sorting
fields = ('own', 'other')
for f in fields:
if not form.is_valid():
globals()['%s_sorting' % f] = form.cleaned_data.get('sort_by')
return object_list(request, queryset=none,
-- extra_context={'is_search':False,
++ extra_context={'is_search': False,
'mine': d['own'],
'other': d['other'],
'own_sorting': own_sorting,
THEN 1 ELSE 0 END""" % request.user.id,
'kindname': """SELECT name FROM im_groupkind
WHERE id = im_astakosgroup.kind_id"""})
--
++
model = q.model
context_processors = None
mimetype = None
except AstakosGroup.DoesNotExist:
raise Http404("No %s found matching the query" % (
model._meta.verbose_name))
--
++
update_form = AstakosGroupUpdateForm(instance=obj)
addmembers_form = AddGroupMembersForm()
if request.method == 'POST':
update_data = {}
addmembers_data = {}
-- for k,v in request.POST.iteritems():
++ for k, v in request.POST.iteritems():
if k in update_form.fields:
update_data[k] = v
if k in addmembers_form.fields:
if addmembers_form.is_valid():
map(obj.approve_member, addmembers_form.valid_users)
addmembers_form = AddGroupMembersForm()
--
-- template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower())
++
++ template_name = "%s/%s_detail.html" % (
++ model._meta.app_label, model._meta.object_name.lower())
t = template_loader.get_template(template_name)
c = RequestContext(request, {
'object': obj,
}, context_processors)
--
++
# validate sorting
-- sorting= request.GET.get('sorting')
++ sorting = request.GET.get('sorting')
if sorting:
form = MembersSortForm({'sort_by': sorting})
if form.is_valid():
sorting = form.cleaned_data.get('sort_by')
--
++
extra_context = {'update_form': update_form,
'addmembers_form': addmembers_form,
'page': request.GET.get('page', 1),
else:
c[key] = value
response = HttpResponse(t.render(c), mimetype=mimetype)
-- populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
++ populate_xheaders(
++ request, response, model, getattr(obj, obj._meta.pk.name))
return response
queryset = queryset.filter(name__contains=q)
queryset = queryset.filter(approval_date__isnull=False)
queryset = queryset.extra(select={
-- 'groupname': DB_REPLACE_GROUP_SCHEME,
-- 'kindname': "im_groupkind.name",
-- 'approved_members_num': """
++ 'groupname': DB_REPLACE_GROUP_SCHEME,
++ 'kindname': "im_groupkind.name",
++ 'approved_members_num': """
SELECT COUNT(*) FROM im_membership
WHERE group_id = im_astakosgroup.group_ptr_id
AND date_joined IS NOT NULL""",
-- 'membership_approval_date': """
++ 'membership_approval_date': """
SELECT date_joined FROM im_membership
WHERE group_id = im_astakosgroup.group_ptr_id
AND person_id = %s""" % request.user.id,
-- 'is_member': """
++ 'is_member': """
SELECT CASE WHEN EXISTS(
SELECT date_joined FROM im_membership
WHERE group_id = im_astakosgroup.group_ptr_id
AND person_id = %s)
THEN 1 ELSE 0 END""" % request.user.id,
-- 'is_owner': """
++ 'is_owner': """
SELECT CASE WHEN EXISTS(
SELECT id FROM im_astakosuser_owner
WHERE astakosgroup_id = im_astakosgroup.group_ptr_id
q=q,
sorting=sorting))
++
@signed_terms_required
@login_required
def group_all(request, extra_context=None, **kwargs):
# TODO check sorting value
q = q.order_by(sorting)
return object_list(
-- request,
-- q,
-- paginate_by=PAGINATE_BY,
-- page=request.GET.get('page') or 1,
-- template_name='im/astakosgroup_list.html',
-- extra_context=dict(form=AstakosGroupSearchForm(),
-- is_search=True,
-- sorting=sorting))
++ request,
++ q,
++ paginate_by=PAGINATE_BY,
++ page=request.GET.get('page') or 1,
++ template_name='im/astakosgroup_list.html',
++ extra_context=dict(form=AstakosGroupSearchForm(),
++ is_search=True,
++ sorting=sorting))
@signed_terms_required
@signed_terms_required
@login_required
def resource_list(request):
-- if request.method == 'POST':
-- form = PickResourceForm(request.POST)
-- if form.is_valid():
-- r = form.cleaned_data.get('resource')
-- if r:
-- groups = request.user.membership_set.only('group').filter(
-- date_joined__isnull=False)
-- groups = [g.group_id for g in groups]
-- q = AstakosGroupQuota.objects.select_related().filter(
-- resource=r, group__in=groups)
- else:
- form = PickResourceForm()
- q = AstakosGroupQuota.objects.none()
-
- data ={
- 'resources':[{
- 'name': 'vm',
- 'description': 'Number Of Vms',
- 'unit':'',
- 'maxValue':'1',
- 'currValue':'1'
- },{
- 'name': 'ram',
- 'description':'Total Ram Usage',
- 'unit':'GB',
- 'maxValue':'4',
- 'currValue':'1'
- },{
- 'name': 'storage',
- 'description':'Total Disk Space Used',
- 'unit':'GB',
- 'maxValue':'200',
- 'currValue':'180'
- },{
- 'name': 'disk',
- 'description':'Disks Used',
- 'unit':'GB',
- 'maxValue':'16',
- 'currValue':'16'
- },{
- 'name': 'network',
- 'description':'Private Networks Used',
- 'unit':'',
- 'maxValue':'2',
- 'currValue':'1'
- },{
- 'name': 'bandwidth',
- 'description':'Bandwidth Monitoring Device',
- 'unit':'Gbps',
- 'maxValue':'200',
- 'currValue':'50'
- }]
- }
-
++# if request.method == 'POST':
++# form = PickResourceForm(request.POST)
++# if form.is_valid():
++# r = form.cleaned_data.get('resource')
++# if r:
++# groups = request.user.membership_set.only('group').filter(
++# date_joined__isnull=False)
++# groups = [g.group_id for g in groups]
++# q = AstakosGroupQuota.objects.select_related().filter(
++# resource=r, group__in=groups)
++# else:
++# form = PickResourceForm()
++# q = AstakosGroupQuota.objects.none()
++#
++# return object_list(request, q,
++# template_name='im/astakosuserquota_list.html',
++# extra_context={'form': form, 'data':data})
++
+ def with_class(entry):
+ entry['load_class'] = 'red'
+ max_value = float(entry['maxValue'])
+ curr_value = float(entry['currValue'])
- entry['ratio'] = (curr_value/max_value)*100
++ entry['ratio'] = (curr_value / max_value) * 100
+ if entry['ratio'] < 66:
- entry['load_class']='yellow'
++ entry['load_class'] = 'yellow'
+ if entry['ratio'] < 33:
- entry['load_class']='green'
-
- return entry
-
- def pluralize(entry):
- if entry['unit'] == '':
- entry['plural'] = entry['name']+'s'
- else:
- entry['plural'] = entry['name']
-
- return entry
++ entry['load_class'] = 'green'
+
- data['resources'] = map(with_class, data['resources'])
- data['resources'] = map(pluralize, data['resources'])
-
- return object_list(request, q,
- template_name='im/astakosuserquota_list.html',
- extra_context={'form': form, 'data':data})
++ return entry
+
++ def pluralize(entry):
++ entry['plural'] = engine.plural(entry.get('name'))
++ return entry
+
++ c = AstakosDjangoDBCallpoint()
++ try:
++ data = c.get_user_status(request.user.id)
++ except Exception, e:
++ data = None
++ messages.error(request, e)
+ else:
- form = PickResourceForm()
- q = AstakosGroupQuota.objects.none()
- return object_list(request, q,
- template_name='im/astakosuserquota_list.html',
- extra_context={'form': form})
++ backenddata = map(with_class, data)
++ data = map(pluralize, data)
++ return render_response('im/resource_list.html',
++ data=data,
++ context_instance=get_context(request))
+
+ def group_create_demo(request):
+
+ resource_catalog = {
+ 'groups': {
+ 'compute': {
+ 'cyclades.vm': { 'unit': 'number' },
+ 'cyclades.ram': { 'unit': 'bytes' },
+ 'cyclades.cpu': { 'unit': 'number' }
+ },
+ 'storage': {
+ 'pithos.diskspace' : { 'unit': 'mebibytes' }
+ }
+ }
+ }
+
+
+ return render_response(
+ template='im/astakosgroup_form_demo.html',
+ context_instance=get_context(request),
+ resource_catalog=resource_catalog,
+ groups=resource_catalog['groups'] )
-
def group_create_list(request):
@signed_terms_required
@login_required
def billing(request):
--
++
today = datetime.today()
-- month_last_day= calendar.monthrange(today.year, today.month)[1]
-
- data['resources'] = map(with_class,data['resources'])
++ month_last_day = calendar.monthrange(today.year, today.month)[1]
++ data['resources'] = map(with_class, data['resources'])
start = request.POST.get('datefrom', None)
if start:
today = datetime.fromtimestamp(int(start))
-- month_last_day= calendar.monthrange(today.year, today.month)[1]
--
++ month_last_day = calendar.monthrange(today.year, today.month)[1]
++
start = datetime(today.year, today.month, 1).strftime("%s")
end = datetime(today.year, today.month, month_last_day).strftime("%s")
r = request_billing.apply(args=('pgerakios@grnet.gr',
int(start) * 1000,
int(end) * 1000))
data = {}
--
++
try:
status, data = r.result
-- data=_clear_billing_data(data)
++ data = _clear_billing_data(data)
if status != 200:
messages.error(request, _('Service response status: %d' % status))
except:
messages.error(request, r.result)
--
++
print type(start)
--
++
return render_response(
template='im/billing.html',
context_instance=get_context(request),
data=data,
-- zerodate=datetime(month=1,year=1970, day=1),
++ zerodate=datetime(month=1, year=1970, day=1),
today=today,
start=int(start),
-- month_last_day=month_last_day)
--
++ month_last_day=month_last_day)
++
++
def _clear_billing_data(data):
--
++
# remove addcredits entries
def isnotcredit(e):
return e['serviceName'] != "addcredits"
--
--
--
-- # separate services
++
++ # separate services
def servicefilter(service_name):
service = service_name
++
def fltr(e):
return e['serviceName'] == service
return fltr
--
--
++
data['bill_nocredits'] = filter(isnotcredit, data['bill'])
data['bill_vmtime'] = filter(servicefilter('vmtime'), data['bill'])
data['bill_diskspace'] = filter(servicefilter('diskspace'), data['bill'])
data['bill_addcredits'] = filter(servicefilter('addcredits'), data['bill'])
- return data
-
+ return data
-
-
+
+
@signed_terms_required
@login_required
def timeline(request):
'event name', 'event date',
'incremental cost', 'total cost')
timeline_body = timeline_charge(
-- data['entity'], data['resource'],
-- data['start_date'], data['end_date'],
-- data['details'], data['operation'])
--
++ data['entity'], data['resource'],
++ data['start_date'], data['end_date'],
++ data['details'], data['operation'])
++
return render_response(template='im/timeline.html',
context_instance=get_context(request),
form=form,
#ASTAKOS_GREETING_EMAIL_SUBJECT = 'Welcome to %s alpha2 testing' % SITENAME
#ASTAKOS_FEEDBACK_EMAIL_SUBJECT = 'Feedback from %s alpha2 testing' % SITENAME
#ASTAKOS_VERIFICATION_EMAIL_SUBJECT = '%s alpha2 testing account activation is needed' % SITENAME
--#ASTAKOS_ADMIN_NOTIFICATION_EMAIL_SUBJECT = '%s alpha2 testing account created (%%(user)s)' % SITENAME
++#ASTAKOS_ACCOUNT_CREATION_SUBJECT = '%s alpha2 testing account created (%%(user)s)' % SITENAME)
++#ASTAKOS_GROUP_CREATION_SUBJECT = '%s alpha2 testing group created (%%(group)s)' % SITENAME)
#ASTAKOS_HELPDESK_NOTIFICATION_EMAIL_SUBJECT = '%s alpha2 testing account activated (%%(user)s)' % SITENAME
#ASTAKOS_EMAIL_CHANGE_EMAIL_SUBJECT = 'Email change on %s alpha2 testing' % SITENAME
#ASTAKOS_PASSWORD_RESET_EMAIL_SUBJECT = 'Password reset on %s alpha2 testing' % SITENAME
'commissioning',
'celery',
'requests',
++ 'inflect'
]
EXTRAS_REQUIRES = {