Commit 3ae6bd71 authored by Sofia Papagiannaki's avatar Sofia Papagiannaki
Browse files

Progress IV

parent f196cf0a
......@@ -200,6 +200,11 @@ def get_menu(request, with_extra_links=False, with_signout=True):
# )
)
)
append(item(
url=absolute(request, reverse('project_list')),
name="New Projects",
)
)
append(item(
url=absolute(request, reverse('resource_usage')),
name="Usage"))
......
# 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 astakos.im.models import approve_application, ProjectApplication
class Command(BaseCommand):
args = "<project application serial>"
help = "Update project state"
def handle(self, *args, **options):
if len(args) < 1:
raise CommandError("Please provide a group identifier")
serial = args[0]
try:
approve_application(serial)
except ProjectApplication.DoesNotExist, e:
raise CommandError("Invalid serial")
except Exception, e:
import traceback
traceback.print_exc()
raise CommandError("Project application approval failed with: %s" % e)
else:
self.stdout.write("Project application has been successfully approved")
\ No newline at end of file
# 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 astakos.im.models import approve_application,
class Command(BaseCommand):
args = "<project application serial>"
help = "Update project state"
option_list = BaseCommand.option_list + (
make_option('--terminate',
action='store_true',
dest='terminate',
default=False,
help="Enable group"),
make_option('--suspend',
action='store_true',
dest='suspend',
default=False,
help="Disable group"),
make_option('--activate',
action='store_true',
dest='activate',
default=False,
help="Disable group"),
)
def handle(self, *args, **options):
if len(args) < 1:
raise CommandError("Please provide a group identifier")
group = None
try:
if args[0].isdigit():
group = AstakosGroup.objects.get(id=args[0])
else:
group = AstakosGroup.objects.get(name=args[0])
except AstakosGroup.DoesNotExist, e:
raise CommandError("Invalid group")
try:
pname = options.get('add-permission')
if pname:
r, created = add_group_permission(group, pname)
if created:
self.stdout.write(
'Permission: %s created successfully\n' % pname)
if r == 0:
self.stdout.write(
'Group has already permission: %s\n' % pname)
else:
self.stdout.write(
'Permission: %s added successfully\n' % pname)
pname = options.get('delete-permission')
if pname:
r = remove_group_permission(group, pname)
if r < 0:
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)
if options.get('enable'):
group.enable()
elif options.get('disable'):
group.disable()
except Exception, e:
raise CommandError(e)
......@@ -131,6 +131,7 @@ QH_SYNC_ERROR = 'Failed to get synchronized with quo
UNIQUE_PROJECT_NAME_CONSTRAIN_ERR = 'The project name (as specified in its application\'s definition) must be unique among all active projects.'
INVALID_PROJECT = 'Project %(serial)s is invalid.'
NOT_ALIVE_PROJECT = 'Project %(serial)s is not alive.'
NOT_PROJECT_OWNER = 'Only project owner can perform this action.'
NOT_ALLOWED = 'You do not have the permissions to perform this action.'
MEMBER_NUMBER_LIMIT_REACHED = 'Maximum participant number has been reached.'
MEMBER_ACCEPT_POLICY_CLOSED = 'The project member accept policy is cloesd.'
NO_APPLICANT = 'Project application requires an applicant. None found.'
\ No newline at end of file
......@@ -1111,8 +1111,8 @@ class Project(models.Model):
)
application = models.OneToOneField(ProjectApplication, related_name='project')
creation_date = models.DateTimeField()
last_approval_date = models.DateTimeField()
termination_date = models.DateTimeField()
last_approval_date = models.DateTimeField(null=True)
termination_date = models.DateTimeField(null=True)
members = models.ManyToManyField(AstakosUser, through='ProjectMembership')
last_synced_application = models.OneToOneField(
ProjectApplication, related_name='last_project', null=True, blank=True
......@@ -1192,16 +1192,66 @@ class Project(models.Model):
def sync(self):
c, rejected = send_quota(self.approved_members)
return rejected
def add_member(self, user, request_user=None):
if isinstance(user, int):
user = _lookup_object(AstakosUser, id=user)
if request_user and \
(not self.owner == request_user and not request_user.is_superuser):
raise Exception(_(astakos_messages.NOT_ALLOWED))
if not self.is_alive:
raise Exception(_(astakos_messages.NOT_ALIVE_PROJECT) % project.__dict__)
if self.definition.member_accept_policy == 'closed':
raise Exception(_(astakos_messages.MEMBER_ACCEPT_POLICY_CLOSED))
if len(self.approved_members) + 1 > self.limit_on_members_number:
raise Exception(_(astakos_messages.MEMBER_NUMBER_LIMIT_REACHED))
created, m = ProjectMembership.objects.get_or_create(
person=user, project=project
)
if m.is_accepted:
return
if created:
m.issue_date = datetime.now()
m.is_accepted = True
m.decision_date = datetime.now()
m.save()
notification = build_notification(
settings.SERVER_EMAIL,
[user.email],
_('Your membership on project %(name)s has been accepted.') % project.definition.__dict__,
_('Your membership on project %(name)s has been accepted.') % project.definition.__dict__
)
notification.send()
def remove_member(self, user, request_user=None):
if user.is_digit():
user = _lookup_object(AstakosUser, id=user)
if request_user and \
(not self.owner == request_user and not request_user.is_superuser):
raise Exception(_(astakos_messages.NOT_ALLOWED))
if not self.is_alive:
raise Exception(_(astakos_messages.NOT_ALIVE_PROJECT) % project.__dict__)
m = _lookup_object(ProjectMembership, person=user, project=project)
if not m.is_accepted:
return
m.is_accepted = False
m.decision_date = datetime.now()
m.save()
notification = build_notification(
settings.SERVER_EMAIL,
[user.email],
_('Your membership on project %(name)s has been removed.') % project.definition.__dict__,
_('Your membership on project %(name)s has been removed.') % project.definition.__dict__
)
notification.send()
class ProjectMembership(models.Model):
person = models.ForeignKey(AstakosUser)
project = models.ForeignKey(Project)
issue_date = models.DateField(default=datetime.now())
decision_date = models.DateField(null=True, db_index=True)
is_accepted = models.BooleanField(
_('Whether the membership application is accepted'),
default=False
)
is_accepted = models.BooleanField(default=False)
class Meta:
unique_together = ("person", "project")
......@@ -1253,7 +1303,7 @@ def _update_object(model, id, save=True, **kwargs):
return o
def list_applications():
return ProjectAppication.objects.all()
return ProjectApplication.objects.all()
def submit_application(definition, applicant, comments, precursor_application=None, commit=True):
if precursor_application:
......@@ -1268,7 +1318,7 @@ def submit_application(definition, applicant, comments, precursor_application=No
if commit:
definition.save()
application.save()
notification = build_notification(
notification = build_notification(
settings.SERVER_EMAIL,
[i[1] for i in settings.ADMINS],
_(GROUP_CREATION_SUBJECT) % {'group':application.definition.name},
......@@ -1277,9 +1327,8 @@ def submit_application(definition, applicant, comments, precursor_application=No
notification.send()
return application
def approve_application(serial):
app = _lookup_object(ProjectAppication, serial=serial)
notify = False
def approve_application(serial, request_user=None):
app = _lookup_object(ProjectApplication, serial=serial)
if not app.precursor_application:
kwargs = {
'application':app,
......@@ -1287,6 +1336,7 @@ def approve_application(serial):
'last_approval_date':datetime.now(),
}
project = _create_object(Project, **kwargs)
project.add_member(app.owner, request_user)
else:
project = app.precursor_application.project
last_approval_date = project.last_approval_date
......@@ -1328,51 +1378,6 @@ def list_projects(filter_property=None):
)
return Project.objects.all()
def add_project_member(serial, user_id, request_user):
project = _lookup_object(Project, serial=serial)
user = _lookup_object(AstakosUser, id=user_id)
if not project.owner == request_user:
raise Exception(_(astakos_messages.NOT_PROJECT_OWNER))
if not project.is_alive:
raise Exception(_(astakos_messages.NOT_ALIVE_PROJECT) % project.__dict__)
if len(project.members) + 1 > project.limit_on_members_number:
raise Exception(_(astakos_messages.MEMBER_NUMBER_LIMIT_REACHED))
m = self._lookup_object(ProjectMembership, person=user, project=project)
if m.is_accepted:
return
m.is_accepted = True
m.decision_date = datetime.now()
m.save()
notification = build_notification(
settings.SERVER_EMAIL,
[user.email],
_('Your membership on project %(name)s has been accepted.') % project.definition.__dict__,
_('Your membership on project %(name)s has been accepted.') % project.definition.__dict__,
)
notification.send()
def remove_project_member(serial, user_id, request_user):
project = _lookup_object(Project, serial=serial)
if not project.is_alive:
raise Exception(_(astakos_messages.NOT_ALIVE_PROJECT) % project.__dict__)
if not project.owner == request_user:
raise Exception(_(astakos_messages.NOT_PROJECT_OWNER))
user = self.lookup_user(user_id)
m = _lookup_object(ProjectMembership, person=user, project=project)
if not m.is_accepted:
return
m.is_accepted = False
m.decision_date = datetime.now()
m.save()
notification = build_notification(
settings.SERVER_EMAIL,
[user.email],
_('Your membership on project %(name)s has been removed.') % project.definition.__dict__,
_('Your membership on project %(name)s has been removed.') % project.definition.__dict__
)
notification.send()
def suspend_project(serial):
project = _lookup_object(Project, serial=serial)
project.suspend()
......
......@@ -10,23 +10,21 @@
<h2>
{% if user in members %}
<em>
{% if user == object.owner %}
{% if object.is_active %}
[ ADMINISTRATOR - ACTIVE ]
{% else %}
[ ADMINISTRATOR - PENDING ]
{% endif %}
{% else %}
{% if user in approve_members %}
[ ENROLLED - ACTIVE ]
{% else %}
[ ENROLLED - PENDING ]
{% endif %}
{% endif %}
</em>
{% endif %}
<em>
{% if user == object.owner %}
{% if object.is_active %}
[ ADMINISTRATOR - ACTIVE ]
{% else %}
[ ADMINISTRATOR - PENDING ]
{% endif %}
{% else %}
{% if user in approve_members %}
[ ENROLLED - ACTIVE ]
{% else %}
[ ENROLLED - PENDING ]
{% endif %}
{% endif %}
</em>
<span>{{ object.definition.name|upper }}</span>
</h2>
......@@ -49,9 +47,9 @@
Not set yet
{% endif %}
</dd>
<dt>Moderation</dt>
<dt>Member accept policy</dt>
<dd>
{{ object.definition.member_accept_policy.description }}
{{ object.definition.member_accept_policy }}
</dd>
</dl>
</div>
......@@ -85,11 +83,10 @@
<dt>Activated</dt>
<dd>{% if object.is_active %}Yes{% else %}No{% endif %}</dd>
<dt>Owner</dt>
{{ o.owner }}
<dd>{% if user == o.owner %}
<dd>{% if user == object.owner %}
Me
{% else%}
{{o.owner.realname}} ({{o.owner.email}})
{{object.owner.realname}} ({{object.owner.email}})
{% endif %}
&nbsp;
......
......@@ -66,7 +66,7 @@
<option value="definition__start_date" {% if sorting == 'definition__start_date' %}selected{% endif %}>Sort by Start Date</option>
<option value="definition__end_date" {% if sorting == 'definition__end_date' %}selected{% endif %}>Sort by End Date</option>
<!-- <option value="approved_members_num" {% if sorting == 'approved_members_num' %}selected{% endif %}>Sort by Participants</option> -->
<option value="definition__member_accept_policy" {% if sorting == 'definition__member_accept_policy' %}selected{% endif %}>Sort by Moderation</option>
<option value="definition__member_accept_policy" {% if sorting == 'definition__member_accept_policy' %}selected{% endif %}>Sort by Member Accept Policy</option>
</select>
<input type="hidden" name="q" value="{{q}}"/>
</div>
......@@ -88,7 +88,7 @@
<th>Status</th>
<th>&nbsp;</th>
<th>Moderated</th>
<th>Member accept policy</th>
<!-- <th>&nbsp;</th>-->
</tr>
......@@ -107,28 +107,19 @@
<td style="width:17%">
<div class="msg-wrap">
{% if user in members %}
{% if user in approved_members %}
{% if not user == o.owner %}
Registered
{% else %}
Owner
{% endif %}
{% else %}
Activation pending
{% endif %}
{% else %}
Not member
{% endif %}
{% if user == o.owner %}
Owner
{% else %}
{% if not user in members %}
Not member
{% else %}
{% if user in approved_members %}
Registered
{% else %}
Activation pending
{% endif %}
{% endif %}
{% endif %}
</div>
</td>
<td style="width:15%">
......@@ -160,7 +151,7 @@
&nbsp;
{% endif %}
{% else %}
{% if o.project.is_alive %}
<form action="{% url project_join o.serial %}" method="post" class="link-like">{% csrf_token %}
<input type="submit" value="+ join group" class="join_group join" />
</form>
......@@ -171,11 +162,11 @@
<a href="#" class="yes submit">Yes</a>&nbsp;&nbsp;&nbsp;<a href="#" class="no submit">No</a>
</div>
{% endif %}
{% endif %}
</div>
</td>
<td class="centered" style="width:9%">{% if o.moderation_enabled%}Yes{% else %}No{% endif %}</td>
<td class="centered" style="width:9%">{{o.definition.member_accept_policy}}</td>
<!--td><a href="#" class="more-info" title="more info">+ more info</a></td-->
</tr>
<tr class="{% cycle 'tmore1' 'tmore2' %}" style="display:none">
......
......@@ -1477,9 +1477,13 @@ def project_add(request):
@signed_terms_required
@login_required
def project_list(request):
q = ProjectApplication.objects.filter(owner=request.user)
q |= ProjectApplication.objects.filter(
project__in=request.user.projectmembership_set.values_list('project', flat=True)
)
return object_list(
request,
ProjectApplication.objects.all(),
q,
paginate_by=PAGINATE_BY_ALL,
page=request.GET.get('page') or 1,
template_name='im/projects/project_list.html',
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment