Revision ffb1e7a8
b/snf-astakos-app/astakos/im/api/__init__.py | ||
---|---|---|
172 | 172 |
l.append(dict(url=absolute(reverse('invite')), name="Invitations")) |
173 | 173 |
l.append(dict(url=absolute(reverse('feedback')), name="Feedback")) |
174 | 174 |
l.append(dict(url=absolute(reverse('group_list')), name="Groups")) |
175 |
l.append(dict(url=absolute(reverse('resource_list')), name="Resources")) |
|
175 | 176 |
if with_signout: |
176 | 177 |
l.append(dict(url=absolute(reverse('logout')), name="Sign out")) |
177 | 178 |
|
b/snf-astakos-app/astakos/im/management/commands/group_add.py | ||
---|---|---|
39 | 39 |
from os.path import abspath |
40 | 40 |
|
41 | 41 |
from django.core.management.base import BaseCommand, CommandError |
42 |
from django.contrib.auth.models import Group |
|
42 |
|
|
43 |
from astakos.im.models import AstakosGroup |
|
43 | 44 |
|
44 | 45 |
from ._common import add_group_permission |
45 | 46 |
|
... | ... | |
54 | 55 |
name = args[0].decode('utf8') |
55 | 56 |
|
56 | 57 |
try: |
57 |
Group.objects.get(name=name) |
|
58 |
AstakosGroup.objects.get(name=name)
|
|
58 | 59 |
raise CommandError("A group with this name already exists") |
59 |
except Group.DoesNotExist, e: |
|
60 |
group = Group(name=name) |
|
60 |
except AstakosGroup.DoesNotExist, e:
|
|
61 |
group = AstakosGroup(name=name)
|
|
61 | 62 |
group.save() |
62 | 63 |
msg = "Created group id %d" % (group.id,) |
63 | 64 |
self.stdout.write(msg + '\n') |
/dev/null | ||
---|---|---|
1 |
# Copyright 2012 GRNET S.A. All rights reserved. |
|
2 |
# |
|
3 |
# Redistribution and use in source and binary forms, with or |
|
4 |
# without modification, are permitted provided that the following |
|
5 |
# conditions are met: |
|
6 |
# |
|
7 |
# 1. Redistributions of source code must retain the above |
|
8 |
# copyright notice, this list of conditions and the following |
|
9 |
# disclaimer. |
|
10 |
# |
|
11 |
# 2. Redistributions in binary form must reproduce the above |
|
12 |
# copyright notice, this list of conditions and the following |
|
13 |
# disclaimer in the documentation and/or other materials |
|
14 |
# provided with the distribution. |
|
15 |
# |
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 |
# POSSIBILITY OF SUCH DAMAGE. |
|
28 |
# |
|
29 |
# The views and conclusions contained in the software and |
|
30 |
# documentation are those of the authors and should not be |
|
31 |
# interpreted as representing official policies, either expressed |
|
32 |
# or implied, of GRNET S.A. |
|
33 |
|
|
34 |
from optparse import make_option |
|
35 |
|
|
36 |
from django.core.management.base import BaseCommand, CommandError |
|
37 |
from django.contrib.auth.models import Group, Permission |
|
38 |
from django.contrib.contenttypes.models import ContentType |
|
39 |
from django.core.exceptions import ValidationError |
|
40 |
|
|
41 |
from astakos.im.models import AstakosUser |
|
42 |
from ._common import add_group_permission |
|
43 |
|
|
44 |
class Command(BaseCommand): |
|
45 |
args = "<groupname> <permission> [<permissions> ...]" |
|
46 |
help = "Add group permissions" |
|
47 |
|
|
48 |
def handle(self, *args, **options): |
|
49 |
if len(args) < 2: |
|
50 |
raise CommandError("Please provide a group name and at least one permission") |
|
51 |
|
|
52 |
group = None |
|
53 |
try: |
|
54 |
if args[0].isdigit(): |
|
55 |
group = Group.objects.get(id=args[0]) |
|
56 |
else: |
|
57 |
group = Group.objects.get(name=args[0]) |
|
58 |
except Group.DoesNotExist, e: |
|
59 |
raise CommandError("Invalid group") |
|
60 |
|
|
61 |
try: |
|
62 |
content_type = ContentType.objects.get(app_label='im', |
|
63 |
model='astakosuser') |
|
64 |
for pname in args[1:]: |
|
65 |
r, created = add_group_permission(group, pname) |
|
66 |
if created: |
|
67 |
self.stdout.write('Permission: %s created successfully\n' % pname) |
|
68 |
if r == 0: |
|
69 |
self.stdout.write('Group has already permission: %s\n' % pname) |
|
70 |
else: |
|
71 |
self.stdout.write('Permission: %s added successfully\n' % pname) |
|
72 |
except Exception, e: |
|
73 |
raise CommandError(e) |
b/snf-astakos-app/astakos/im/management/commands/group_list.py | ||
---|---|---|
34 | 34 |
from optparse import make_option |
35 | 35 |
|
36 | 36 |
from django.core.management.base import BaseCommand, CommandError |
37 |
from django.contrib.auth.models import Group |
|
38 | 37 |
|
39 |
from astakos.im.models import AstakosUser |
|
38 |
from astakos.im.models import AstakosUser, AstakosGroup
|
|
40 | 39 |
|
41 | 40 |
from ._common import format_bool |
42 | 41 |
|
43 | 42 |
|
44 | 43 |
class Command(BaseCommand): |
45 |
help = "List g" |
|
44 |
help = "List groups"
|
|
46 | 45 |
|
47 | 46 |
option_list = BaseCommand.option_list + ( |
48 | 47 |
make_option('-c', |
... | ... | |
50 | 49 |
dest='csv', |
51 | 50 |
default=False, |
52 | 51 |
help="Use pipes to separate values"), |
52 |
make_option('-p', |
|
53 |
action='store_true', |
|
54 |
dest='pending', |
|
55 |
default=False, |
|
56 |
help="List only groups pending enable"), |
|
53 | 57 |
) |
54 | 58 |
|
55 | 59 |
def handle(self, *args, **options): |
56 | 60 |
if args: |
57 | 61 |
raise CommandError("Command doesn't accept any arguments") |
58 | 62 |
|
59 |
groups = Group.objects.all() |
|
63 |
groups = AstakosGroup.objects.all() |
|
64 |
|
|
65 |
if options.get('pending'): |
|
66 |
groups = filter(lambda g: g.is_disabled, groups) |
|
60 | 67 |
|
61 |
labels = ('id', 'name', 'permissions') |
|
62 |
columns = (3, 12, 50) |
|
68 |
labels = ('id', 'name', 'enabled', 'permissions')
|
|
69 |
columns = (3, 12, 12, 50)
|
|
63 | 70 |
|
64 |
if not options['csv']:
|
|
71 |
if not options.get('csv'):
|
|
65 | 72 |
line = ' '.join(l.rjust(w) for l, w in zip(labels, columns)) |
66 | 73 |
self.stdout.write(line + '\n') |
67 | 74 |
sep = '-' * len(line) |
68 | 75 |
self.stdout.write(sep + '\n') |
69 | 76 |
|
70 | 77 |
for group in groups: |
71 |
fields = (str(group.id), group.name, |
|
72 |
','.join(p.codename for p in group.permissions.all())) |
|
78 |
fields = ( str(group.id), |
|
79 |
group.name, |
|
80 |
format_bool(group.is_enabled), |
|
81 |
','.join(p.codename for p in group.permissions.all())) |
|
73 | 82 |
|
74 |
if options['csv']:
|
|
83 |
if options.get('csv'):
|
|
75 | 84 |
line = '|'.join(fields) |
76 | 85 |
else: |
77 | 86 |
line = ' '.join(f.rjust(w) for f, w in zip(fields, columns)) |
/dev/null | ||
---|---|---|
1 |
# Copyright 2012 GRNET S.A. All rights reserved. |
|
2 |
# |
|
3 |
# Redistribution and use in source and binary forms, with or |
|
4 |
# without modification, are permitted provided that the following |
|
5 |
# conditions are met: |
|
6 |
# |
|
7 |
# 1. Redistributions of source code must retain the above |
|
8 |
# copyright notice, this list of conditions and the following |
|
9 |
# disclaimer. |
|
10 |
# |
|
11 |
# 2. Redistributions in binary form must reproduce the above |
|
12 |
# copyright notice, this list of conditions and the following |
|
13 |
# disclaimer in the documentation and/or other materials |
|
14 |
# provided with the distribution. |
|
15 |
# |
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 |
# POSSIBILITY OF SUCH DAMAGE. |
|
28 |
# |
|
29 |
# The views and conclusions contained in the software and |
|
30 |
# documentation are those of the authors and should not be |
|
31 |
# interpreted as representing official policies, either expressed |
|
32 |
# or implied, of GRNET S.A. |
|
33 |
|
|
34 |
from optparse import make_option |
|
35 |
|
|
36 |
from django.core.management.base import BaseCommand, CommandError |
|
37 |
from django.contrib.auth.models import Group |
|
38 |
from django.core.exceptions import ValidationError |
|
39 |
|
|
40 |
from astakos.im.models import AstakosUser |
|
41 |
from ._common import remove_group_permission |
|
42 |
|
|
43 |
class Command(BaseCommand): |
|
44 |
args = "<groupname> <permission> [<permissions> ...]" |
|
45 |
help = "Remove group permissions" |
|
46 |
|
|
47 |
def handle(self, *args, **options): |
|
48 |
if len(args) < 2: |
|
49 |
raise CommandError("Please provide a group name and at least one permission") |
|
50 |
|
|
51 |
group = None |
|
52 |
try: |
|
53 |
if args[0].isdigit(): |
|
54 |
group = Group.objects.get(id=args[0]) |
|
55 |
else: |
|
56 |
group = Group.objects.get(name=args[0]) |
|
57 |
except Group.DoesNotExist, e: |
|
58 |
raise CommandError("Invalid group") |
|
59 |
|
|
60 |
try: |
|
61 |
for pname in args[1:]: |
|
62 |
r = remove_group_permission(group, pname) |
|
63 |
if r < 0: |
|
64 |
self.stdout.write('Invalid permission codename: %s\n' % pname) |
|
65 |
elif r == 0: |
|
66 |
self.stdout.write('Group has not permission: %s\n' % pname) |
|
67 |
elif r > 0: |
|
68 |
self.stdout.write('Permission: %s removed successfully\n' % pname) |
|
69 |
except Exception, e: |
|
70 |
raise CommandError(e) |
b/snf-astakos-app/astakos/im/management/commands/group_update.py | ||
---|---|---|
1 |
# Copyright 2012 GRNET S.A. All rights reserved. |
|
2 |
# |
|
3 |
# Redistribution and use in source and binary forms, with or |
|
4 |
# without modification, are permitted provided that the following |
|
5 |
# conditions are met: |
|
6 |
# |
|
7 |
# 1. Redistributions of source code must retain the above |
|
8 |
# copyright notice, this list of conditions and the following |
|
9 |
# disclaimer. |
|
10 |
# |
|
11 |
# 2. Redistributions in binary form must reproduce the above |
|
12 |
# copyright notice, this list of conditions and the following |
|
13 |
# disclaimer in the documentation and/or other materials |
|
14 |
# provided with the distribution. |
|
15 |
# |
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 |
# POSSIBILITY OF SUCH DAMAGE. |
|
28 |
# |
|
29 |
# The views and conclusions contained in the software and |
|
30 |
# documentation are those of the authors and should not be |
|
31 |
# interpreted as representing official policies, either expressed |
|
32 |
# or implied, of GRNET S.A. |
|
33 |
|
|
34 |
from optparse import make_option |
|
35 |
|
|
36 |
from django.core.management.base import BaseCommand, CommandError |
|
37 |
from django.contrib.auth.models import Permission |
|
38 |
from django.contrib.contenttypes.models import ContentType |
|
39 |
from django.core.exceptions import ValidationError |
|
40 |
|
|
41 |
from astakos.im.models import AstakosUser, AstakosGroup |
|
42 |
from ._common import add_group_permission |
|
43 |
|
|
44 |
class Command(BaseCommand): |
|
45 |
args = "<groupname>" |
|
46 |
help = "Update group" |
|
47 |
|
|
48 |
option_list = BaseCommand.option_list + ( |
|
49 |
make_option('--add-permission', |
|
50 |
dest='add-permission', |
|
51 |
help="Add user permission"), |
|
52 |
make_option('--delete-permission', |
|
53 |
dest='delete-permission', |
|
54 |
help="Delete user permission"), |
|
55 |
make_option('--enable', |
|
56 |
action='store_true', |
|
57 |
dest='enable', |
|
58 |
default=False, |
|
59 |
help="Enable group"), |
|
60 |
) |
|
61 |
|
|
62 |
def handle(self, *args, **options): |
|
63 |
if len(args) < 1: |
|
64 |
raise CommandError("Please provide a group identifier") |
|
65 |
|
|
66 |
group = None |
|
67 |
try: |
|
68 |
if args[0].isdigit(): |
|
69 |
group = AstakosGroup.objects.get(id=args[0]) |
|
70 |
else: |
|
71 |
group = AstakosGroup.objects.get(name=args[0]) |
|
72 |
except AstakosGroup.DoesNotExist, e: |
|
73 |
raise CommandError("Invalid group") |
|
74 |
|
|
75 |
try: |
|
76 |
content_type = ContentType.objects.get(app_label='im', |
|
77 |
model='astakosuser') |
|
78 |
|
|
79 |
pname = options.get('add-permission') |
|
80 |
if pname: |
|
81 |
r, created = add_group_permission(group, pname) |
|
82 |
if created: |
|
83 |
self.stdout.write('Permission: %s created successfully\n' % pname) |
|
84 |
if r == 0: |
|
85 |
self.stdout.write('Group has already permission: %s\n' % pname) |
|
86 |
else: |
|
87 |
self.stdout.write('Permission: %s added successfully\n' % pname) |
|
88 |
|
|
89 |
pname = options.get('delete-permission') |
|
90 |
if pname: |
|
91 |
r = remove_group_permission(group, pname) |
|
92 |
if r < 0: |
|
93 |
self.stdout.write('Invalid permission codename: %s\n' % pname) |
|
94 |
elif r == 0: |
|
95 |
self.stdout.write('Group has not permission: %s\n' % pname) |
|
96 |
elif r > 0: |
|
97 |
self.stdout.write('Permission: %s removed successfully\n' % pname) |
|
98 |
|
|
99 |
if options.get('enable'): |
|
100 |
group.enable() |
|
101 |
except Exception, e: |
|
102 |
raise CommandError(e) |
b/snf-astakos-app/astakos/im/models.py | ||
---|---|---|
41 | 41 |
from base64 import b64encode |
42 | 42 |
from urlparse import urlparse, urlunparse |
43 | 43 |
from random import randint |
44 |
from collections import defaultdict |
|
44 | 45 |
|
45 | 46 |
from django.db import models, IntegrityError |
46 | 47 |
from django.contrib.auth.models import User, UserManager, Group |
... | ... | |
120 | 121 |
|
121 | 122 |
@property |
122 | 123 |
def is_disabled(self): |
123 |
if not approval_date: |
|
124 |
return False
|
|
125 |
return True
|
|
124 |
if not self.approval_date:
|
|
125 |
return True
|
|
126 |
return False
|
|
126 | 127 |
|
127 | 128 |
@property |
128 |
def is_active(self):
|
|
129 |
def is_enabled(self):
|
|
129 | 130 |
if self.is_disabled: |
130 | 131 |
return False |
131 | 132 |
if not self.issue_date: |
... | ... | |
143 | 144 |
def participants(self): |
144 | 145 |
return len(self.approved_members) |
145 | 146 |
|
146 |
def approve(self):
|
|
147 |
def enable(self):
|
|
147 | 148 |
self.approval_date = datetime.now() |
148 | 149 |
self.save() |
149 | 150 |
|
150 |
def disapprove(self):
|
|
151 |
def disable(self):
|
|
151 | 152 |
self.approval_date = None |
152 | 153 |
self.save() |
153 | 154 |
|
... | ... | |
172 | 173 |
return map(lambda m:m.person, f) |
173 | 174 |
|
174 | 175 |
@property |
175 |
def policies(self): |
|
176 |
return self.astakosgroupquota_set.all() |
|
176 |
def quota(self): |
|
177 |
d = {} |
|
178 |
for q in self.astakosgroupquota_set.all(): |
|
179 |
d[q.resource.name] = q.limit |
|
180 |
return d |
|
177 | 181 |
|
178 | 182 |
@property |
179 | 183 |
def has_undefined_policies(self): |
... | ... | |
255 | 259 |
return Invitation.objects.get(username=self.email) |
256 | 260 |
except Invitation.DoesNotExist: |
257 | 261 |
return None |
258 |
|
|
262 |
|
|
263 |
@property |
|
264 |
def quota(self): |
|
265 |
d = defaultdict(int) |
|
266 |
for q in self.astakosuserquota_set.all(): |
|
267 |
d[q.resource.name] += q.limit |
|
268 |
for g in self.astakos_groups.all(): |
|
269 |
if not g.is_enabled: |
|
270 |
continue |
|
271 |
for r, limit in g.quota.iteritems(): |
|
272 |
d[r] += limit |
|
273 |
# TODO set default for remaining |
|
274 |
return d |
|
275 |
|
|
259 | 276 |
def save(self, update_timestamps=True, **kwargs): |
260 | 277 |
if update_timestamps: |
261 | 278 |
if not self.id: |
... | ... | |
340 | 357 |
self.save() |
341 | 358 |
return False |
342 | 359 |
return True |
343 |
|
|
344 |
def enroll_group(self, group): |
|
345 |
self.membership_set.add(group) |
|
346 |
|
|
347 |
def get_astakos_groups(self, approved=True): |
|
348 |
if approved: |
|
349 |
return self.membership_set().filter(is_approved=True) |
|
350 |
return self.membership_set().all() |
|
351 | 360 |
|
352 | 361 |
class Membership(models.Model): |
353 | 362 |
person = models.ForeignKey(AstakosUser) |
... | ... | |
358 | 367 |
class Meta: |
359 | 368 |
unique_together = ("person", "group") |
360 | 369 |
|
361 |
def save(self): |
|
370 |
def save(self, *args, **kwargs):
|
|
362 | 371 |
if not self.id: |
363 | 372 |
if not self.group.moderation_enabled: |
364 | 373 |
self.date_joined = datetime.now() |
365 |
super(Membership, self).save() |
|
374 |
super(Membership, self).save(*args, **kwargs)
|
|
366 | 375 |
|
367 | 376 |
@property |
368 | 377 |
def is_approved(self): |
b/snf-astakos-app/astakos/im/templates/im/astakosgroup_detail.html | ||
---|---|---|
1 | 1 |
{% extends "im/account_base.html" %} |
2 | 2 |
|
3 |
{% load filters %} |
|
4 |
|
|
3 | 5 |
{% block page.body %} |
4 | 6 |
<div class="maincol {% block innerpage.class %}{% endblock %}"> |
5 | 7 |
<table class="zebra-striped id-sorted"> |
... | ... | |
10 | 12 |
<th>Type: {{object.kind}}</th> |
11 | 13 |
</tr> |
12 | 14 |
<tr> |
13 |
<th>Issue date: {{object.issue_date}}</th> |
|
15 |
<th>Issue date: {{object.issue_date|date:"d/m/Y"}}</th>
|
|
14 | 16 |
</tr> |
15 | 17 |
<tr> |
16 |
<th>Expiration date: {{object.expiration_date}}</th> |
|
18 |
<th>Expiration date: {{object.expiration_date|date:"d/m/Y"}}</th>
|
|
17 | 19 |
</tr> |
18 | 20 |
<tr> |
19 | 21 |
<th>Moderation: {% if object.moderation_enabled%}Yes{% else %}No{% endif %}</th> |
... | ... | |
21 | 23 |
<tr> |
22 | 24 |
<th>Owner: {% for o in object.owner.all %} |
23 | 25 |
{% if user == o %} |
24 |
Me!
|
|
26 |
Me |
|
25 | 27 |
{% else%} |
26 | 28 |
{{o.realname}} ({{o.email}}) |
27 | 29 |
|
... | ... | |
29 | 31 |
{% endfor %} |
30 | 32 |
</th> |
31 | 33 |
</tr> |
34 |
<tr> |
|
35 |
<th>Enabled: {% if object.is_enabled %}Yes{% else %}No{% endif %}</th> |
|
36 |
</tr> |
|
32 | 37 |
</table> |
33 | 38 |
<div class="section"> |
34 | 39 |
<h2>Members:</h2> |
... | ... | |
54 | 59 |
{% else %} |
55 | 60 |
<td>Pending</td> |
56 | 61 |
{% if user in m.group.owner.all %} |
57 |
<td><a href="{% url approve_member m.id %}">Approve</a></td> |
|
58 |
<td><a href="{% url disapprove_member m.id %}">Disapprove</a></td>
|
|
62 |
<td><a href="{% url approve_member m.group.id m.person.id %}">Approve</a></td>
|
|
63 |
<td><a href="{% url disapprove_member m.group.id m.person.id %}">Disapprove</a></td>
|
|
59 | 64 |
{% endif %} |
60 | 65 |
{% endif %} |
61 | 66 |
{% endif %} |
... | ... | |
78 | 83 |
</tr> |
79 | 84 |
</thead> |
80 | 85 |
<tbody> |
81 |
{% for q in quota %}
|
|
86 |
{% for k in quota|dkeys %}
|
|
82 | 87 |
<tr> |
83 |
<td>{{q.resource.name}}</td>
|
|
84 |
<td>{{q.limit}}</td>
|
|
88 |
<td>{{ k }}</td>
|
|
89 |
<td>{{ quota|lookup:k }}</td>
|
|
85 | 90 |
</tr> |
86 | 91 |
{% endfor %} |
87 | 92 |
</tbody> |
... | ... | |
90 | 95 |
<p>No policies</p> |
91 | 96 |
{% endif %} |
92 | 97 |
</div> |
93 |
{% if more_policies %} |
|
98 |
{% if user in object.owner.all and more_policies %}
|
|
94 | 99 |
<div class="rightcol"> |
95 | 100 |
<form action="{% url group_policies_add object.id %}" method="post" class="innerlabels signup">{% csrf_token %} |
96 | 101 |
<h2><span>NEW POLICY</span></h2> |
b/snf-astakos-app/astakos/im/templates/im/astakosgroup_list.html | ||
---|---|---|
29 | 29 |
<th>Expiration date</th> |
30 | 30 |
<th>Owner?</th> |
31 | 31 |
<th>Participants</th> |
32 |
<th>Enabled?</th> |
|
32 | 33 |
<th>Moderation?</th> |
33 | 34 |
<th>Enrollment status</th> |
34 | 35 |
</tr> |
... | ... | |
38 | 39 |
<tr> |
39 | 40 |
<td><a class="extra-link" href="{% url group_detail o.id %}">{{o.name}}</a></td> |
40 | 41 |
<td>{{o.kind}}</td> |
41 |
<td>{{o.issue_date|date:"D d M Y"}}</td>
|
|
42 |
<td>{{o.expiration_date|date:"D d M Y"}}</td>
|
|
42 |
<td>{{o.issue_date|date:"d/m/Y"}}</td>
|
|
43 |
<td>{{o.expiration_date|date:"d/m/Y"}}</td>
|
|
43 | 44 |
<td>{% if user in o.owner.all %}Yes{% else %}No{% endif %}</td> |
44 | 45 |
<td>{{ o.approved_members|length }}/{{ o.members|length }}</td> |
46 |
<td>{% if o.is_enabled %}Yes{% else %}No{% endif %}</td> |
|
45 | 47 |
<td>{% if o.moderation_enabled%}Yes{% else %}No{% endif %}</td> |
46 | 48 |
{% if user in o.approved_members %} |
47 | 49 |
<td>Active</td> |
b/snf-astakos-app/astakos/im/templates/im/astakosuserquota_list.html | ||
---|---|---|
1 |
{% extends "im/account_base.html" %} |
|
2 |
|
|
3 |
{% load filters %} |
|
4 |
|
|
5 |
{% block page.body %} |
|
6 |
<div class="maincol {% block innerpage.class %}{% endblock %}"> |
|
7 |
<div class="section"> |
|
8 |
{% if quota %} |
|
9 |
<table class="zebra-striped id-sorted"> |
|
10 |
<thead> |
|
11 |
<tr> |
|
12 |
<th>Resource</th> |
|
13 |
<th>Limit</th> |
|
14 |
</tr> |
|
15 |
</thead> |
|
16 |
<tbody> |
|
17 |
{% for k in quota|dkeys %} |
|
18 |
<tr> |
|
19 |
<td>{{ k }}</td> |
|
20 |
<td>{{ quota|lookup:k }}</td> |
|
21 |
</tr> |
|
22 |
{% endfor %} |
|
23 |
</tbody> |
|
24 |
</table> |
|
25 |
{% else %} |
|
26 |
<p>No policies</p> |
|
27 |
{% endif %} |
|
28 |
</div> |
|
29 |
</div> |
|
30 |
{% endblock %} |
b/snf-astakos-app/astakos/im/urls.py | ||
---|---|---|
49 | 49 |
url(r'^approval_terms/?$', 'approval_terms', {}, name='latest_terms'), |
50 | 50 |
url(r'^approval_terms/(?P<term_id>\d+)/?$', 'approval_terms'), |
51 | 51 |
url(r'^password/?$', 'change_password', {}, name='password_change'), |
52 |
url(r'^resources/?$', 'resource_list', {}, name='resource_list'), |
|
52 | 53 |
url(r'^group/add/?$', 'group_add', {}, name='group_add'), |
53 | 54 |
url(r'^group/list/?$', 'group_list', {}, name='group_list'), |
54 | 55 |
url(r'^group/(?P<group_id>\d+)/?$', 'group_detail', {}, name='group_detail'), |
55 |
url(r'^group/(?P<group_id>\d+)/policies/list/?$', 'group_policies_list', {}, name='group_policies_list'), |
|
56 |
#url(r'^group/(?P<group_id>\d+)/policies/list/?$', 'group_policies_list', {}, name='group_policies_list'),
|
|
56 | 57 |
url(r'^group/(?P<group_id>\d+)/policies/add/?$', 'group_policies_add', {}, name='group_policies_add'), |
57 | 58 |
url(r'^group/search/?$', 'group_search', {}, name='group_search'), |
58 | 59 |
url(r'^group/(?P<group_id>\d+)/join/?$', 'group_join', {}, name='group_join'), |
59 | 60 |
url(r'^group/(?P<group_id>\d+)/leave/?$', 'group_leave', {}, name='group_leave'), |
60 |
url(r'^group/(?P<group_id>\d+)/request/approval/?$', 'group_approval_request', {}, name='group_approval_request'), |
|
61 |
url(r'^group/(?P<membership_id>\d+)/approve/?$', 'approve_member', {}, name='approve_member'),
|
|
62 |
url(r'^group/(?P<membership_id>\d+)/disapprove/?$', 'disapprove_member', {}, name='disapprove_member'),
|
|
61 |
#url(r'^group/(?P<group_id>\d+)/request/approval/?$', 'group_approval_request', {}, name='group_approval_request'),
|
|
62 |
url(r'^group/(?P<group_id>\d+)/(?P<user_id>\d+)/approve/?$', 'approve_member', {}, name='approve_member'),
|
|
63 |
url(r'^group/(?P<group_id>\d+)/(?P<user_id>\d+)/disapprove/?$', 'disapprove_member', {}, name='disapprove_member'),
|
|
63 | 64 |
) |
64 | 65 |
|
65 | 66 |
if EMAILCHANGE_ENABLED: |
b/snf-astakos-app/astakos/im/views.py | ||
---|---|---|
610 | 610 |
AstakosGroup.objects.all(), |
611 | 611 |
object_id=group_id, |
612 | 612 |
extra_context = {'form':get_astakos_group_policy_creation_form(group), |
613 |
'quota':group.policies,
|
|
613 |
'quota':group.quota,
|
|
614 | 614 |
'more_policies':group.has_undefined_policies}) |
615 | 615 |
|
616 | 616 |
@signed_terms_required |
... | ... | |
631 | 631 |
template_name = 'im/astakosgroup_detail.html', |
632 | 632 |
post_save_redirect = reverse('group_detail', kwargs=dict(group_id=group_id)), |
633 | 633 |
extra_context = {'group':group, |
634 |
'quota':group.policies,
|
|
634 |
'quota':group.quota,
|
|
635 | 635 |
'more_policies':group.has_undefined_policies}) |
636 | 636 |
@signed_terms_required |
637 | 637 |
@login_required |
... | ... | |
686 | 686 |
def handle_membership(): |
687 | 687 |
def decorator(func): |
688 | 688 |
@wraps(func) |
689 |
def wrapper(request, membership_id):
|
|
689 |
def wrapper(request, group_id, user_id):
|
|
690 | 690 |
try: |
691 |
m = Membership.objects.select_related().get(id=membership_id)
|
|
691 |
m = Membership.objects.select_related().get(group__id=group_id, person__id=user_id)
|
|
692 | 692 |
except Membership.DoesNotExist: |
693 | 693 |
return HttpResponseBadRequest(_('Invalid membership.')) |
694 | 694 |
else: |
... | ... | |
698 | 698 |
return render_response(template='im/astakosgroup_detail.html', |
699 | 699 |
context_instance=get_context(request), |
700 | 700 |
object=m.group, |
701 |
quota=m.group.policies,
|
|
701 |
quota=m.group.quota,
|
|
702 | 702 |
more_policies=m.group.has_undefined_policies) |
703 | 703 |
return wrapper |
704 | 704 |
return decorator |
... | ... | |
730 | 730 |
logger.exception(e) |
731 | 731 |
msg = _('Something went wrong during %s\'s disapproval.' % realname) |
732 | 732 |
messages.error(request, msg) |
733 |
|
|
734 |
@signed_terms_required |
|
735 |
@login_required |
|
736 |
def resource_list(request): |
|
737 |
return render_response(template='im/astakosuserquota_list.html', |
|
738 |
context_instance=get_context(request), |
|
739 |
quota=request.user.quota) |
Also available in: Unified diff