Commit 612c385e authored by Sofia Papagiannaki's avatar Sofia Papagiannaki
Browse files

Progress V

parent 7af1dcf1
......@@ -922,8 +922,7 @@ class ProjectApplicationForm(forms.ModelForm):
class Meta:
model = ProjectDefinition
exclude = ('resource_grants')
exclude = ('resource_grants', 'serial')
def clean(self):
userid = self.data.get('user', None)[0]
......@@ -976,3 +975,17 @@ class ProjectApplicationForm(forms.ModelForm):
precursor_application,
commit
)
class ProjectSortForm(forms.Form):
sorting = forms.ChoiceField(
label='Sort by',
choices=(('definition__name', 'Sort by Name'),
('issue_date', 'Sort by Issue date'),
('definition__start_date', 'Sort by Start Date'),
('definition__end_date', 'Sort by End Date'),
# ('approved_members_num', 'Sort by Participants'),
('definition__member_accept_policy', 'Sort by Member Accept Policy'),
('definition__member_reject_policy', 'Sort by Member Reject Policy')
),
required=True
)
\ No newline at end of file
......@@ -13,7 +13,7 @@ class Migration(SchemaMigration):
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('person', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['im.AstakosUser'])),
('project', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['im.Project'])),
('request_date', self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2012, 12, 7, 16, 55, 19, 659537))),
('request_date', self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2012, 12, 8, 1, 2, 7, 352304))),
('removal_date', self.gf('django.db.models.fields.DateField')(null=True)),
('rejection_date', self.gf('django.db.models.fields.DateField')(null=True)),
))
......@@ -52,7 +52,7 @@ class Migration(SchemaMigration):
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('person', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['im.AstakosUser'])),
('project', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['im.Project'])),
('request_date', self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2012, 12, 7, 16, 55, 19, 658816))),
('request_date', self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2012, 12, 8, 1, 2, 7, 351571))),
('acceptance_date', self.gf('django.db.models.fields.DateField')(null=True, db_index=True)),
))
db.send_create_signal('im', ['ProjectMembership'])
......@@ -70,7 +70,7 @@ class Migration(SchemaMigration):
# Adding model 'ProjectDefinition'
db.create_table('im_projectdefinition', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('serial', self.gf('django.db.models.fields.CharField')(unique=True, max_length=30, primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(max_length=80)),
('homepage', self.gf('django.db.models.fields.URLField')(max_length=255, null=True, blank=True)),
('description', self.gf('django.db.models.fields.TextField')(null=True)),
......@@ -185,14 +185,14 @@ class Migration(SchemaMigration):
},
'im.approvalterms': {
'Meta': {'object_name': 'ApprovalTerms'},
'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 12, 7, 16, 55, 19, 649024)', 'db_index': 'True'}),
'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 12, 8, 1, 2, 7, 341713)', '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, 12, 7, 16, 55, 19, 641334)'}),
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 12, 8, 1, 2, 7, 333863)'}),
'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
'estimated_participants': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'expiration_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
......@@ -258,7 +258,7 @@ class Migration(SchemaMigration):
'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, 12, 7, 16, 55, 19, 650690)'}),
'requested_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 12, 8, 1, 2, 7, 343372)'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emailchange_user'", 'unique': 'True', 'to': "orm['im.AstakosUser']"})
},
'im.groupkind': {
......@@ -292,7 +292,7 @@ class Migration(SchemaMigration):
'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, 12, 7, 16, 55, 19, 646801)', 'blank': 'True'}),
'date_requested': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 12, 8, 1, 2, 7, 339429)', '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']"})
......@@ -337,12 +337,12 @@ class Migration(SchemaMigration):
'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
'end_date': ('django.db.models.fields.DateTimeField', [], {}),
'homepage': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'limit_on_members_number': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
'member_accept_policy': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.MemberAcceptPolicy']"}),
'member_reject_policy': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.MemberRejectPolicy']"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
'resource_grants': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.ProjectResourceGrant']", 'blank': 'True'}),
'serial': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30', 'primary_key': 'True'}),
'start_date': ('django.db.models.fields.DateTimeField', [], {})
},
'im.projectmembership': {
......@@ -351,7 +351,7 @@ class Migration(SchemaMigration):
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"}),
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Project']"}),
'request_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 12, 7, 16, 55, 19, 658816)'})
'request_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 12, 8, 1, 2, 7, 351571)'})
},
'im.projectmembershiphistory': {
'Meta': {'unique_together': "(('person', 'project'),)", 'object_name': 'ProjectMembershipHistory'},
......@@ -360,7 +360,7 @@ class Migration(SchemaMigration):
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Project']"}),
'rejection_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'removal_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'request_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 12, 7, 16, 55, 19, 659537)'})
'request_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 12, 8, 1, 2, 7, 352304)'})
},
'im.projectresourcegrant': {
'Meta': {'unique_together': "(('resource', 'project_definition'),)", 'object_name': 'ProjectResourceGrant'},
......
......@@ -185,7 +185,10 @@ class AstakosGroup(Group):
_('Creation date'),
default=datetime.now()
)
issue_date = models.DateTimeField('Start date', null=True)
issue_date = models.DateTimeField(
_('Start date'),
null=True
)
expiration_date = models.DateTimeField(
_('Expiration date'),
null=True
......@@ -1037,6 +1040,11 @@ def get_auto_accept():
return auto_accept
class ProjectDefinition(models.Model):
serial = models.CharField(
primary_key=True,
max_length=30,
unique=True
)
name = models.CharField(max_length=80)
homepage = models.URLField(max_length=255, null=True, blank=True)
description = models.TextField(null=True)
......@@ -1053,6 +1061,8 @@ class ProjectDefinition(models.Model):
)
def save(self):
if not self.serial:
self.serial = uuid.uuid4().hex[:30]
self.validate_name()
super(ProjectDefinition, self).save()
......@@ -1140,19 +1150,37 @@ class ProjectApplication(models.Model):
self.serial = uuid.uuid4().hex[:30]
super(ProjectApplication, self).save()
@property
def status(self):
try:
self.project
except Project.DoesNotExist:
return 'PENDING'
else:
if self.project.is_terminated:
return 'ALIVE'
else:
return 'TERMINATED'
@staticmethod
def submit(definition, applicant, comments, precursor_application=None, commit=True):
if precursor_application and precursor_application.project.is_valid:
application = None
if precursor_application:
try:
precursor_application.project
except:
pass
else:
if precursor_application.project.is_valid:
application = precursor_application.copy()
application.precursor_application = precursor_application
else:
if not application:
application = ProjectApplication(owner=applicant)
application.definition = definition
application.applicant = applicant
application.comments = comments
application.issue_date = datetime.now()
if commit:
definition.save()
application.save()
if applicant.is_superuser:
self.approve_application()
......@@ -1165,6 +1193,7 @@ class ProjectApplication(models.Model):
notification.send()
return application
class Project(models.Model):
serial = models.CharField(
primary_key=True,
......
......@@ -5,7 +5,6 @@
{% block page.body %}
{% with object.project.members as members %}
{% with object.project.approved_members as approved_members %}
<div class="projects">
......@@ -28,6 +27,7 @@
<span>{{ object.definition.name|upper }}</span>
</h2>
<!--
<div class="details">
<h3>
GENERAL INFO
......@@ -39,18 +39,6 @@
<div class="data">
<p class="restricted">{{ object.definition.description|safe }}</p>
<dl class="alt-style">
<dt>Homepage url</dt>
<dd>
{% if object.definition.homepage%}
<a href="{{ object.definition.homepage }}">{{ object.definition.homepage }}</a>
{% else %}
Not set yet
{% endif %}
</dd>
<dt>Member accept policy</dt>
<dd>
{{ object.definition.member_accept_policy }}
</dd>
</dl>
</div>
<div class="editable" style="display:none;">
......@@ -65,29 +53,39 @@
</form>
</div>
</div>
-->
<div class="full-dotted">
<h3>DETAILS</h3>
<dl class="alt-style">
<dt>Name</dt>
<dd>{{ object.definition.name }}&nbsp;</dd>
<dt>Description</dt>
<dd>{{ object.definition.description|safe }}&nbsp;</dd>
<dt>Homepage url</dt>
<dd>
{% if object.definition.homepage%}
<a href="{{ object.definition.homepage }}">{{ object.definition.homepage }}</a>
{% else %}
Not set yet
{% endif %}
</dd>
<dt>Member accept policy</dt>
<dd>
{{ object.definition.member_accept_policy }}
</dd>
<dt>Issue date:</dt>
<dd>{{object.issue_date|date:"d/m/Y"}}&nbsp;</dd>
<dt>Start date:</dt>
<dd>{{object.definition.start_date|date:"d/m/Y"}}&nbsp;</dd>
<dt>End Date</dt>
<dd>{{object.definition.end_date|date:"d/m/Y"}}&nbsp;</dd>
<!--
<dt>Moderation</dt>
<dd>{% if object.moderation_enabled%}Yes{% else %}No{% endif %}</dd>
-->
<dt>Activated</dt>
<dd>{% if object.is_active %}Yes{% else %}No{% endif %}</dd>
<dt>Owner</dt>
<dd>{% if user == object.owner %}
Me
{% else%}
{{object.owner.realname}} ({{object.owner.email}})
{{object.owner.realname}} {% if user.is_superuser %}({{object.owner.email}}){% endif %}
{% endif %}
&nbsp;
</dd>
......@@ -99,22 +97,29 @@
<h3>RESOURCES</h3>
{% if object.definition.projectresourcegrant_set.all %}
<dl class="alt-style">
{% for q in object.definition.projectresourcegrant_set.all %}
q.resource
{% for rp in object.definition.projectresourcegrant_set.all %}
<dt>
{{rp.resource}}
</dt>
<dd>
{{rp.member_limit}}
<dd/>
<!--
<dt>
Max {% if q.is_abbreviation %}{{ q.verbose_name|upper }}{% else %}{{ q.verbose_name }}{% endif %}{% if not q.unit %}s {% endif %} per user
</dt>
<dd>
{% if q.member_limit %}
{% if q.value %}
{% if q.unit %}
{{ q.member_limit|sizeof_fmt }}
{{ q.value|sizeof_fmt }}
{% else %}
{{ q.member_limit|isinf }}
{{ q.value|isinf }}
{% endif %}
{% else %}
Unlimited
{% endif %}
</dd>
-->
{% empty %}
No resources
{% endfor %}
......@@ -125,7 +130,7 @@
<p>No resources</p>
{% endif %}
</div>
{% if user == object.owner %}
{% if object.is_alive %}
<div class="full-dotted">
{% with page|concat:sorting as args %}
{% with object.project.projectmembership_set.select_related.all|paginate:args as membership %}
......@@ -143,7 +148,7 @@
<caption>MEMBERS:</caption>
<thead>
<tr>
<th>User Id</th>
<th>User Email</th>
<th>Name</th>
<th>Status</th>
</tr>
......@@ -151,7 +156,7 @@
<tbody>
{% for m in membership.object_list %}
<tr>
<td>{{m.person.email}}</td>
<td>{%if user.is_superuser or user == o.owner %}{{m.person.email}}{% endif %}</td>
<td>{{m.person.realname}}</td>
{% if m.person == o.owner %}
<td>Owner</td>
......
......@@ -66,7 +66,9 @@
<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="status" {% if sorting == '' %}selected{% endif %}>Sort by Member Accept Policy</option> -->
<option value="definition__member_accept_policy" {% if sorting == 'definition__member_accept_policy' %}selected{% endif %}>Sort by Member Accept Policy</option>
<option value="definition__member_reject_policy" {% if sorting == 'definition__member_reject_policy' %}selected{% endif %}>Sort by Member Reject Policy</option>
</select>
<input type="hidden" name="q" value="{{q}}"/>
</div>
......@@ -81,14 +83,13 @@
<!--<th>Type</th>-->
<th>Issued</th>
<th>Starts</th>
<th>Expires</th>
<th>Ends</th>
<th>Enrolled</th>
<th>Status</th>
<th>Membership Status</th>
<th>&nbsp;</th>
<th>Member accept policy</th>
<th>Member reject policy</th>
<!-- <th>&nbsp;</th>-->
</tr>
......@@ -104,7 +105,9 @@
<td style="width:13%">{{o.definition.start_date|date:"d/m/Y"}}</td>
<td style="width:13%">{{o.definition.end_date|date:"d/m/Y"}}</td>
<td style="width:11%">{{approved_members|length}}</td>
<td style="width:11%">
{{o.status}} <a href="{% url project_update o.serial %}">Update</a>
</td>
<td style="width:17%">
<div class="msg-wrap">
{% if user == o.owner %}
......@@ -127,10 +130,7 @@
{% if user in members %}
{% if user in approved_members %}
{% if not user == o.owner %}
<form action="{% url project_leave o.serial %}" method="post" class="link-like">{% csrf_token %}
<input type="submit" value="x leave group" class="leave"/>
</form>
......@@ -138,15 +138,11 @@
Are you sure you what to leave this group?<br>
Name: <a href="{% url project_detail o.serial %}" title="visit group page">{{o.groupname}}</a><br>
{% if o.definition.description %}Description:{{o.definition.description|truncatewords:30}}{% endif %}<br><br>
<a href="#" class="yes submit">Yes</a>&nbsp;&nbsp;&nbsp;<a href="#" class="no submit">No</a>
</div>
{% else %}
&nbsp;
{% endif %}
{% else %}
&nbsp;
{% endif %}
......@@ -167,6 +163,7 @@
</div>
</td>
<td class="centered" style="width:9%">{{o.definition.member_accept_policy}}</td>
<td class="centered" style="width:9%">{{o.definition.member_reject_policy}}</td>
<!--td><a href="#" class="more-info" title="more info">+ more info</a></td-->
</tr>
<tr class="{% cycle 'tmore1' 'tmore2' %}" style="display:none">
......
......@@ -6,6 +6,7 @@
<script src="{{ IM_STATIC_URL }}js/quotas.js"></script>
{% endblock %}
{% block page.body %}
<form action="#top" method="post" class="withlabels quotas-form" id="group_create_form">{% csrf_token %}
<fieldset class="with-info" id="top">
......@@ -19,6 +20,13 @@
{% include "im/form_render.html" %}
{% for g, resources in resource_catalog.get_groups_resources %}
{% for rname in resources.keys %}
{% with object|resource_grants|lookup:rname as value %}
<input type="hidden" id="{{'id_'|add:rname|add:'_uplimit'}}" name="{{rname|add:'_uplimit'}}" autocomplete="off" {% if value %}value="{{value}}"{% endif %}">
{% endwith %}
{% endfor %}
{% endfor %}
</fieldset>
<fieldset id="icons">
......@@ -30,16 +38,18 @@
</span>
</legend>
<ul class="clearfix">
{% with object|resource_groups as groups %}
{% for g, group_info in resource_catalog.groups.items %}
{% if g %}
<li>
<a href="#{{ g }}" id="{{'group_'|add:g}}"><img src="/static/im/images/create-{{ g }}.png" alt="vm"/></a>
<input type="hidden" name="proxy_{{ 'is_selected_'|add:g }}" id="proxy_{{ 'id_is_selected_'|add:g }}">
<input type="hidden" name="{{ 'is_selected_'|add:g }}" id="{{ 'id_is_selected_'|add:g }}">
<a href="#{{ g }}" id="{{'group_'|add:g}}" {% if g in groups %}class="selected"{% endif %}><img src="/static/im/images/create-{{ g }}.png" alt="vm"/></a>
<input type="hidden" name="proxy_{{ 'is_selected_'|add:g }}" id="proxy_{{ 'id_is_selected_'|add:g }}" {% if g in groups %}checked="checked"{% endif %}>
<input type="hidden" name="{{ 'is_selected_'|add:g }}" id="{{ 'id_is_selected_'|add:g }}" {% if g in groups %}checked="checked"{% endif %}>
<p class="msg">{{ group_info.help_text }}</p>
</li>
{% endif %}
{% endfor %}
{% endwith %}
</ul>
</fieldset>
......@@ -78,7 +88,6 @@
class="dehumanize"
{% endif %}
/>
<input type="hidden" name="{{rname|add:'_uplimit'}}" id="{{'id_'|add:rname|add:'_uplimit'}}" ">
<span class="extra-img">&nbsp;</span>
<span class="info"><em>more info</em><span>Leave this field blank if you don't want to specify this resource</span></span>
<p class="error-msg">Invalid format</p>
......
......@@ -43,7 +43,7 @@ from django.db.models.query import QuerySet
from astakos.im.settings import PAGINATE_BY
from astakos.im.models import RESOURCE_SEPARATOR
register = template.Library()
......@@ -200,3 +200,24 @@ def truncatename(v):
return v[:max]+'...'
else:
return v[:20]
@register.filter
def resource_groups(project_definition):
try:
grants = project_definition.projectresourcegrant_set
return grants.values_list('resource__group', flat=True)
except:
return ()
@register.filter
def resource_grants(project_definition):
try:
grants = project_definition.projectresourcegrant_set
grants = grants.values_list(
'resource__name',
'resource__service__name',
'member_limit'
)
return dict((RESOURCE_SEPARATOR.join([e[1], e[0]]), e[2]) for e in grants)
except:
return {}
\ No newline at end of file
......@@ -68,6 +68,7 @@ urlpatterns = patterns('astakos.im.views',
url(r'^group/how_it_works/?$', 'how_it_works', {}, name='how_it_works'),
url(r'^project/add/?$', 'project_add', {}, name='project_add'),
url(r'^project/update/(?P<serial>\w+)/?$', 'project_update', {}, name='project_update'),
url(r'^project/list/?$', 'project_list', {}, name='project_list'),
url(r'^project/search/?$', 'project_search', {}, name='project_search'),
url(r'^project/all/?$', 'project_all', {}, name='project_all'),
......
......@@ -54,7 +54,7 @@ from django.template import RequestContext, loader as template_loader
from django.utils.http import urlencode
from django.utils.translation import ugettext as _
from django.views.generic.create_update import (
create_object, delete_object, get_model_and_form_class
create_object, update_object, delete_object, get_model_and_form_class
)
from django.views.generic.list_detail import object_list, object_detail
from django.core.xheaders import populate_xheaders
......@@ -80,7 +80,7 @@ from astakos.im.forms import (
MembersSortForm, AstakosGroupSortForm,
TimelineForm, PickResourceForm,
AstakosGroupCreationSummaryForm,
ProjectApplicationForm
ProjectApplicationForm, ProjectSortForm
)
from astakos.im.functions import (
send_feedback, SendMailError,
......@@ -783,7 +783,7 @@ class ResourcePresentation():
yield g, self.get_group_resources(g)
def get_quota(self, group_quotas):
for r, v in group_quotas.iteritems():
for r, v in group_quotas:
rname = str(r)
quota = self.data['resources'].get(rname)
quota['value'] = v
......@@ -1481,6 +1481,12 @@ def project_list(request):
q |= ProjectApplication.objects.filter(
project__in=request.user.projectmembership_set.values_list('project', flat=True)
)
sorting = 'definition__name'
sort_form = ProjectSortForm(request.GET)
if sort_form.is_valid():
sorting = sort_form.cleaned_data.get('sorting')
q = q.order_by(sorting)
return object_list(
request,
q,
......@@ -1489,27 +1495,51 @@ def project_list(request):
template_name='im/projects/project_list.html',
extra_context={
'is_search':False,
'sorting':request.GET.get('sorting'),
'sorting':request.GET.get('sorting')
}
)
@require_http_methods(["GET", "POST"])
@signed_terms_required
@login_required
def project_application_detail(request, serial):
return object_detail(
def project_update(request, serial):
result = callpoint.list_resources()
resource_catalog = ResourcePresentation(RESOURCES_PRESENTATION_DATA)
resource_catalog.update_from_result(result)
if not result.is_success:
messages.error(
request,
queryset=ProjectApplication.objects.select_related(),
slug=serial,
slug_field='serial',
template_name='im/projects/projectapplication_detail.html'
'Unable to retrieve system resources: %s' % result.reason
)
extra_context = {'resource_catalog':resource_catalog}
return update_object(
request,
slug=serial,
slug_field='projectapplication__serial',
template_name='im/projects/projectapplication_form.html',
extra_context=extra_context, post_save_redirect='/im/project/list/',
form_class=ProjectApplicationForm)
# @require_http_methods(["GET", "POST"])
# @signed_terms_required
# @login_required
# def project_application_detail(request, serial):
# return object_detail(
# request,