Commit 93d03b12 authored by Sofia Papagiannaki's avatar Sofia Papagiannaki
Browse files

Merge branch 'feature-change-astakos-commands' into feature-quotas

Conflicts:
	snf-astakos-app/astakos/im/management/commands/resource-list.py
	snf-astakos-app/astakos/im/management/commands/service-list.py
	snf-astakos-app/astakos/im/management/commands/service-modify.py
	snf-astakos-app/astakos/im/management/commands/user-modify.py
	snf-astakos-app/astakos/im/management/commands/user-set-initial-quota.py
	snf-astakos-app/astakos/im/management/commands/user-show.py
parents 2be9bc4f 48104feb
......@@ -76,7 +76,6 @@ class Command(BaseCommand):
user_ident = options['user']
list_only = not sync and not verify
if user_ident is not None:
users = [self.get_user(user_ident)]
else:
......
......@@ -31,49 +31,21 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from optparse import make_option
from django.core.management.base import NoArgsCommand, CommandError
from astakos.im.models import Invitation
from synnefo.webproject.management.commands import ListCommand
from ._common import format_bool
class Command(NoArgsCommand):
class Command(ListCommand):
help = "List invitations"
option_list = NoArgsCommand.option_list + (
make_option('-c',
action='store_true',
dest='csv',
default=False,
help="Use pipes to separate values"),
)
def handle_noargs(self, **options):
invitations = Invitation.objects.all().order_by('id')
labels = ('id', 'inviter', 'email', 'real name', 'code', 'consumed')
columns = (3, 24, 24, 24, 20, 4, 8)
if not options['csv']:
line = ' '.join(l.rjust(w) for l, w in zip(labels, columns))
self.stdout.write(line + '\n')
sep = '-' * len(line)
self.stdout.write(sep + '\n')
for invitation in invitations:
id = str(invitation.id)
code = str(invitation.code)
consumed = format_bool(invitation.is_consumed)
fields = (format(elem) for elem in \
(id, invitation.inviter.email, invitation.username,
invitation.realname, code, consumed))
object_class = Invitation
if options['csv']:
line = '|'.join(fields)
else:
line = ' '.join(f.rjust(w) for f, w in zip(fields, columns))
FIELDS = {
"id": ("id", "The ID of the invitation"),
"inviter": ("inviter.username", "The inviter of the invitation"),
"username": ("username", "The receiver username"),
"realname": ("realname", "The receiver name"),
"code": ("code", "The code of the invitation"),
"is_consumed": ("is_consumed", "Whether the invitation is consumed or not"),
}
self.stdout.write(line + '\n')
fields = ["id", "inviter", "username", "realname", "code", "is_consumed"]
......@@ -31,15 +31,16 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from django.core.management.base import BaseCommand, CommandError
from django.core.management.base import CommandError
from astakos.im.models import Invitation
from synnefo.webproject.management.commands import SynnefoCommand
from ._common import format
from synnefo.webproject.management import utils
class Command(BaseCommand):
args = "<invitation ID>"
class Command(SynnefoCommand):
args = "<invitation ID or code>"
help = "Show invitation info"
def handle(self, *args, **options):
......@@ -49,7 +50,10 @@ class Command(BaseCommand):
try:
invitation = Invitation.objects.get(id=int(args[0]))
except Invitation.DoesNotExist:
raise CommandError("Unknown invitation id '%s'" % (args[0],))
try:
invitation = Invitation.objects.get(code=args[0])
except Invitation.DoesNotExist:
raise CommandError("Unknown invitation id '%s'" % (args[0],))
kv = {
'id': invitation.id,
......@@ -63,6 +67,5 @@ class Command(BaseCommand):
'invitater email': invitation.inviter.email,
}
for key, val in sorted(kv.items()):
line = '%s: %s\n' % (key.rjust(18), format(val))
self.stdout.write(line)
utils.pprint_table(self.stdout, [kv.values()], kv.keys(),
options["output_format"], vertical=True)
......@@ -33,13 +33,55 @@
from optparse import make_option
from django.core.management.base import NoArgsCommand
from astakos.im.models import Chain, Project
from synnefo.webproject.management.commands import ListCommand
from astakos.im.models import Chain
from ._common import format, shortened
def get_name(chain):
try:
p = Project.objects.get(pk=chain.pk)
except Project.DoesNotExist:
app = chain.last_application()
return app.name
else:
return p.name
class Command(NoArgsCommand):
def get_owner_name(chain):
return chain.last_application().owner.realname
def get_owner_email(chain):
return chain.last_application().owner.email
def get_state(chain):
try:
p = Project.objects.get(pk=chain.pk)
except Project.DoesNotExist:
p = None
app = chain.last_application()
return chain.get_state(p, app)[0]
def get_state_display(chain):
return Chain.state_display(get_state(chain))
def get_appid(chain):
try:
p = Project.objects.get(pk=chain.pk)
except Project.DoesNotExist:
p = None
app = chain.last_application()
state = chain.get_state(p, app)[0]
if state in Chain.PENDING_STATES:
return str(app.id)
else:
return ""
class Command(ListCommand):
help = """
List projects and project status.
......@@ -69,7 +111,20 @@ class Command(NoArgsCommand):
by a new project
"""
option_list = NoArgsCommand.option_list + (
object_class = Chain
FIELDS = {
'ProjID': ('pk', 'The id of the project'),
'Name': (get_name, 'The name of the project'),
'Owner': (get_owner_name, 'The name of the project owner'),
'Email': (get_owner_email, 'The email of the project owner'),
'Status': (get_state_display, 'The status of the project'),
'AppID': (get_appid, 'The project application identification'),
}
fields = ['ProjID', 'Name', 'Owner', 'Email', 'Status', 'AppID']
option_list = ListCommand.option_list + (
make_option('--all',
action='store_true',
dest='all',
......@@ -101,99 +156,24 @@ class Command(NoArgsCommand):
dest='full',
default=False,
help="Do not shorten long names"),
make_option('-c',
action='store_true',
dest='csv',
default=False,
help="Use pipes to separate values"),
)
def handle_noargs(self, **options):
allow_shorten = not options['full']
csv = options['csv']
chain_dict = Chain.objects.all_full_state()
if not options['all']:
f_states = []
if options['new']:
f_states.append(Chain.PENDING)
if options['modified']:
f_states += Chain.MODIFICATION_STATES
if options['pending']:
f_states.append(Chain.PENDING)
f_states += Chain.MODIFICATION_STATES
if options['skip']:
if not f_states:
def handle_db_objects(self, objects, **options):
if options['all']:
return
f_states = []
if options['new']:
f_states.append(Chain.PENDING)
if options['modified']:
f_states += Chain.MODIFICATION_STATES
if options['pending']:
f_states.append(Chain.PENDING)
f_states += Chain.MODIFICATION_STATES
if options['skip']:
if not f_states:
f_states = Chain.RELEVANT_STATES
if f_states:
chain_dict = filter_by_state(chain_dict, f_states)
self.show(csv, allow_shorten, chain_dict)
def show(self, csv, allow_shorten, chain_dict):
labels = ('ProjID', 'Name', 'Owner', 'Email', 'Status', 'AppID')
columns = (7, 23, 20, 20, 17, 7)
if not csv:
line = ' '.join(l.rjust(w) for l, w in zip(labels, columns))
self.stdout.write(line + '\n')
sep = '-' * len(line)
self.stdout.write(sep + '\n')
for info in chain_info(chain_dict):
fields = [
(info['projectid'], False),
(info['name'], True),
(info['owner'], True),
(info['email'], True),
(info['status'], False),
(info['appid'], False),
]
fields = [(format(elem), flag) for (elem, flag) in fields]
if csv:
line = '|'.join(fields)
else:
output = []
for (field, shorten), width in zip(fields, columns):
s = (shortened(field, width) if shorten and allow_shorten
else field)
s = s.rjust(width)
output.append(s)
line = ' '.join(output)
self.stdout.write(line + '\n')
def filter_by_state(chain_dict, states):
d = {}
for chain, (state, project, app) in chain_dict.iteritems():
if state in states:
d[chain] = (state, project, app)
return d
def chain_info(chain_dict):
l = []
for chain, (state, project, app) in chain_dict.iteritems():
status = Chain.state_display(state)
if state in Chain.PENDING_STATES:
appid = str(app.id)
else:
appid = ""
d = {
'projectid': str(chain),
'name': project.application.name if project else app.name,
'owner': app.owner.realname,
'email': app.owner.email,
'status': status,
'appid': appid,
}
l.append(d)
return l
if f_states:
map(objects.remove,
filter(lambda o: get_state(o) not in f_states, objects))
......@@ -32,15 +32,15 @@
# or implied, of GRNET S.A.
from optparse import make_option
from django.core.management.base import BaseCommand, CommandError
from django.core.management.base import CommandError
from synnefo.lib.ordereddict import OrderedDict
from synnefo.webproject.management.commands import SynnefoCommand
from synnefo.webproject.management import utils
from astakos.im.models import Chain, ProjectApplication
from ._common import format
class Command(BaseCommand):
class Command(SynnefoCommand):
args = "<id or name>"
help = """
Show project details.
......@@ -52,7 +52,7 @@ class Command(BaseCommand):
contains the given string
"""
option_list = BaseCommand.option_list + (
option_list = SynnefoCommand.option_list + (
make_option('--app',
action='store_true',
dest='app',
......@@ -63,17 +63,17 @@ class Command(BaseCommand):
action='store_true',
dest='pending',
default=False,
help=("For a given project, show also pending modifications "
help=("For a given project, show also pending modifications"
"(applications), if any")
),
)
)
def handle(self, *args, **options):
if len(args) != 1:
raise CommandError("Please provide project ID or name")
show_pending = bool(options['pending'])
search_apps = options['app']
search_apps = options['app']
name_or_id = args[0]
is_id = name_or_id.isdigit()
......@@ -93,13 +93,8 @@ class Command(BaseCommand):
raise CommandError(msg)
for info in infolist:
self.show_info(info)
def show_info(self, info):
for key, val in info.items():
line = '%s: %s\n' % (key.rjust(22), format(val))
self.stdout.write(line)
self.stdout.write('\n')
utils.pprint_table(self.stdout, [info.values()], info.keys(),
options["output_format"], vertical=True)
def app_info(name_or_id, is_id):
......@@ -111,6 +106,7 @@ def app_info(name_or_id, is_id):
except ProjectApplication.DoesNotExist:
return []
def get_chains(name_or_id, is_id):
if is_id:
try:
......@@ -120,6 +116,7 @@ def get_chains(name_or_id, is_id):
else:
return Chain.objects.search_by_name(name_or_id)
def collect_info(chains, pending):
states = [chain.full_state() for chain in chains]
......@@ -128,6 +125,7 @@ def collect_info(chains, pending):
infolist += (chain_fields(state, pending))
return infolist
def chain_fields((s, project, app), request=False):
l = []
if project:
......@@ -138,28 +136,29 @@ def chain_fields((s, project, app), request=False):
l = [app_fields(app)]
return l
def app_fields(app):
mem_limit = app.limit_on_members_number
mem_limit_show = mem_limit if mem_limit is not None else "unlimited"
d = OrderedDict([
('project id', app.chain),
('application id', app.id),
('name', app.name),
('status', app.state_display()),
('owner', app.owner),
('applicant', app.applicant),
('homepage', app.homepage),
('description', app.description),
('comments for review', app.comments),
('request issue date', app.issue_date),
('request start date', app.start_date),
('request end date', app.end_date),
('resources', app.resource_policies),
('join policy', app.member_join_policy_display),
('leave policy', app.member_leave_policy_display),
('max members', mem_limit_show),
])
('project id', app.chain),
('application id', app.id),
('name', app.name),
('status', app.state_display()),
('owner', app.owner),
('applicant', app.applicant),
('homepage', app.homepage),
('description', app.description),
('comments for review', app.comments),
('request issue date', app.issue_date),
('request start date', app.start_date),
('request end date', app.end_date),
('resources', app.resource_policies),
('join policy', app.member_join_policy_display),
('leave policy', app.member_leave_policy_display),
('max members', mem_limit_show),
])
return d
......@@ -168,11 +167,11 @@ def project_fields(s, project, last_app):
app = project.application
d = OrderedDict([
('project id', project.id),
('application id', app.id),
('name', app.name),
('status', Chain.state_display(s)),
])
('project id', project.id),
('application id', app.id),
('name', app.name),
('status', Chain.state_display(s)),
])
if s in Chain.PENDING_STATES:
d.update([('pending application', last_app.id)])
......@@ -200,10 +199,10 @@ def project_fields(s, project, last_app):
('leave policy', app.member_leave_policy_display),
('max members', mem_limit_show),
('total members', project.members_count()),
])
])
memberships = project.projectmembership_set
accepted = [str(m.person) for m in memberships.any_accepted()]
accepted = [str(m.person) for m in memberships.any_accepted()]
requested = [str(m.person) for m in memberships.requested()]
suspended = [str(m.person) for m in memberships.suspended()]
......
......@@ -31,9 +31,8 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from synnefo.webproject.management.commands import ListCommand
from astakos.im.models import Service
from synnefo.webproject.management.commands import ListCommand
class Command(ListCommand):
......
......@@ -32,13 +32,10 @@
# 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.core.exceptions import ValidationError
from astakos.im.models import Service
from ._common import remove_user_permission, add_user_permission
class Command(BaseCommand):
......@@ -62,7 +59,7 @@ class Command(BaseCommand):
dest='auth_token',
default=None,
help="Set a custom service auth token"),
make_option('--renew-auth-token',
make_option('--renew-token',
action='store_true',
dest='renew_token',
default=False,
......@@ -102,3 +99,7 @@ class Command(BaseCommand):
service.save()
if renew_token:
self.stdout.write(
'Service\'s new token: %s\n' % service.auth_token
)
# 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 datetime import datetime, timedelta
from django.core.management.base import BaseCommand, CommandError
from astakos.im.models import Service
class Command(BaseCommand):
args = "<name>"
help = "Renew service token"
option_list = BaseCommand.option_list + (
make_option('--duration',
dest='duration',
metavar='NUM',
help="In how many days token is going to expire."),)
def handle(self, *args, **options):
if len(args) != 1:
raise CommandError("Invalid number of arguments")
try:
service = Service.objects.get(name=args[0])
expires = None
if options['duration']:
try:
duration = int(options['duration'])
except ValueError, e:
raise CommandError('Invalid duration')
expires = datetime.now() + timedelta(days=duration)
service.renew_token(expires)
service.save()
self.stdout.write('New service token: %s\n' % service.auth_token)