Revision 8327782d

b/snf-astakos-app/astakos/im/forms.py
922 922
    
923 923
    class Meta:
924 924
        model = ProjectDefinition
925
        exclude = ('resource_grants')
926
    
925
        exclude = ('resource_grants', 'serial')
927 926
    
928 927
    def clean(self):
929 928
        userid = self.data.get('user', None)[0]
......
976 975
            precursor_application,
977 976
            commit
978 977
        )
978

  
979
class ProjectSortForm(forms.Form):
980
    sorting = forms.ChoiceField(
981
        label='Sort by',
982
        choices=(('definition__name', 'Sort by Name'),
983
                 ('issue_date', 'Sort by Issue date'),
984
                 ('definition__start_date', 'Sort by Start Date'),
985
                 ('definition__end_date', 'Sort by End Date'),
986
#                  ('approved_members_num', 'Sort by Participants'),
987
                 ('definition__member_accept_policy', 'Sort by Member Accept Policy'),
988
                 ('definition__member_reject_policy', 'Sort by Member Reject Policy')
989
        ),
990
        required=True
991
    )
b/snf-astakos-app/astakos/im/migrations/0035_auto__add_projectmembershiphistory__add_unique_projectmembershiphistor.py
13 13
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
14 14
            ('person', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['im.AstakosUser'])),
15 15
            ('project', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['im.Project'])),
16
            ('request_date', self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2012, 12, 7, 16, 55, 19, 659537))),
16
            ('request_date', self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2012, 12, 8, 1, 2, 7, 352304))),
17 17
            ('removal_date', self.gf('django.db.models.fields.DateField')(null=True)),
18 18
            ('rejection_date', self.gf('django.db.models.fields.DateField')(null=True)),
19 19
        ))
......
52 52
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
53 53
            ('person', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['im.AstakosUser'])),
54 54
            ('project', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['im.Project'])),
55
            ('request_date', self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2012, 12, 7, 16, 55, 19, 658816))),
55
            ('request_date', self.gf('django.db.models.fields.DateField')(default=datetime.datetime(2012, 12, 8, 1, 2, 7, 351571))),
56 56
            ('acceptance_date', self.gf('django.db.models.fields.DateField')(null=True, db_index=True)),
57 57
        ))
58 58
        db.send_create_signal('im', ['ProjectMembership'])
......
70 70

  
71 71
        # Adding model 'ProjectDefinition'
72 72
        db.create_table('im_projectdefinition', (
73
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
73
            ('serial', self.gf('django.db.models.fields.CharField')(unique=True, max_length=30, primary_key=True)),
74 74
            ('name', self.gf('django.db.models.fields.CharField')(max_length=80)),
75 75
            ('homepage', self.gf('django.db.models.fields.URLField')(max_length=255, null=True, blank=True)),
76 76
            ('description', self.gf('django.db.models.fields.TextField')(null=True)),
......
185 185
        },
186 186
        'im.approvalterms': {
187 187
            'Meta': {'object_name': 'ApprovalTerms'},
188
            'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 12, 7, 16, 55, 19, 649024)', 'db_index': 'True'}),
188
            'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 12, 8, 1, 2, 7, 341713)', 'db_index': 'True'}),
189 189
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
190 190
            'location': ('django.db.models.fields.CharField', [], {'max_length': '255'})
191 191
        },
192 192
        'im.astakosgroup': {
193 193
            'Meta': {'object_name': 'AstakosGroup', '_ormbases': ['auth.Group']},
194 194
            'approval_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
195
            'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 12, 7, 16, 55, 19, 641334)'}),
195
            'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 12, 8, 1, 2, 7, 333863)'}),
196 196
            'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
197 197
            'estimated_participants': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
198 198
            'expiration_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
......
258 258
            'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
259 259
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
260 260
            'new_email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
261
            'requested_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 12, 7, 16, 55, 19, 650690)'}),
261
            'requested_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2012, 12, 8, 1, 2, 7, 343372)'}),
262 262
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emailchange_user'", 'unique': 'True', 'to': "orm['im.AstakosUser']"})
263 263
        },
264 264
        'im.groupkind': {
......
292 292
        'im.membership': {
293 293
            'Meta': {'unique_together': "(('person', 'group'),)", 'object_name': 'Membership'},
294 294
            'date_joined': ('django.db.models.fields.DateField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
295
            'date_requested': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 12, 7, 16, 55, 19, 646801)', 'blank': 'True'}),
295
            'date_requested': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 12, 8, 1, 2, 7, 339429)', 'blank': 'True'}),
296 296
            'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosGroup']"}),
297 297
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
298 298
            'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
......
337 337
            'description': ('django.db.models.fields.TextField', [], {'null': 'True'}),
338 338
            'end_date': ('django.db.models.fields.DateTimeField', [], {}),
339 339
            'homepage': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
340
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
341 340
            'limit_on_members_number': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
342 341
            'member_accept_policy': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.MemberAcceptPolicy']"}),
343 342
            'member_reject_policy': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.MemberRejectPolicy']"}),
344 343
            'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
345 344
            'resource_grants': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.ProjectResourceGrant']", 'blank': 'True'}),
345
            'serial': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30', 'primary_key': 'True'}),
346 346
            'start_date': ('django.db.models.fields.DateTimeField', [], {})
347 347
        },
348 348
        'im.projectmembership': {
......
351 351
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
352 352
            'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"}),
353 353
            'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Project']"}),
354
            'request_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 12, 7, 16, 55, 19, 658816)'})
354
            'request_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 12, 8, 1, 2, 7, 351571)'})
355 355
        },
356 356
        'im.projectmembershiphistory': {
357 357
            'Meta': {'unique_together': "(('person', 'project'),)", 'object_name': 'ProjectMembershipHistory'},
......
360 360
            'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Project']"}),
361 361
            'rejection_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
362 362
            'removal_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
363
            'request_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 12, 7, 16, 55, 19, 659537)'})
363
            'request_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2012, 12, 8, 1, 2, 7, 352304)'})
364 364
        },
365 365
        'im.projectresourcegrant': {
366 366
            'Meta': {'unique_together': "(('resource', 'project_definition'),)", 'object_name': 'ProjectResourceGrant'},
b/snf-astakos-app/astakos/im/models.py
185 185
        _('Creation date'),
186 186
        default=datetime.now()
187 187
    )
188
    issue_date = models.DateTimeField('Start date', null=True)
188
    issue_date = models.DateTimeField(
189
        _('Start date'),
190
        null=True
191
    )
189 192
    expiration_date = models.DateTimeField(
190 193
        _('Expiration date'),
191 194
        null=True
......
1037 1040
    return auto_accept
1038 1041

  
1039 1042
class ProjectDefinition(models.Model):
1043
    serial = models.CharField(
1044
        primary_key=True,
1045
        max_length=30,
1046
        unique=True
1047
    )
1040 1048
    name = models.CharField(max_length=80)
1041 1049
    homepage = models.URLField(max_length=255, null=True, blank=True)
1042 1050
    description = models.TextField(null=True)
......
1053 1061
    )
1054 1062
    
1055 1063
    def save(self):
1064
        if not self.serial:
1065
            self.serial = uuid.uuid4().hex[:30]
1056 1066
        self.validate_name()
1057 1067
        super(ProjectDefinition, self).save()
1058 1068
        
......
1140 1150
            self.serial = uuid.uuid4().hex[:30]
1141 1151
        super(ProjectApplication, self).save()
1142 1152

  
1153
    @property
1154
    def status(self):
1155
        try:
1156
            self.project
1157
        except Project.DoesNotExist:
1158
            return 'PENDING'
1159
        else:
1160
            if self.project.is_terminated:
1161
                return 'ALIVE'
1162
            else:
1163
                return 'TERMINATED'
1164
        
1143 1165
    @staticmethod
1144 1166
    def submit(definition, applicant, comments, precursor_application=None, commit=True):
1145
        if precursor_application and precursor_application.project.is_valid:
1146
            application = precursor_application.copy()
1147
            application.precursor_application = precursor_application
1148
        else:
1167
        application = None
1168
        if precursor_application:
1169
            try:
1170
                precursor_application.project
1171
            except:
1172
                pass
1173
            else:
1174
                if precursor_application.project.is_valid:
1175
                    application = precursor_application.copy()
1176
                    application.precursor_application = precursor_application
1177
        if not application:
1149 1178
            application = ProjectApplication(owner=applicant)
1150 1179
        application.definition = definition
1151 1180
        application.applicant = applicant
1152 1181
        application.comments = comments
1153 1182
        application.issue_date = datetime.now()
1154 1183
        if commit:
1155
            definition.save()
1156 1184
            application.save()
1157 1185
        if applicant.is_superuser:
1158 1186
            self.approve_application()
......
1165 1193
        notification.send()
1166 1194
        return application
1167 1195

  
1196

  
1168 1197
class Project(models.Model):
1169 1198
    serial = models.CharField(
1170 1199
        primary_key=True,
......
1186 1215
        if not self.serial:
1187 1216
            self.serial = uuid.uuid4().hex[:30]
1188 1217
        super(ProjectApplication, self).save()
1189

  
1218
    
1190 1219
    @property
1191 1220
    def definition(self):
1192 1221
        return self.application.definition
b/snf-astakos-app/astakos/im/templates/im/projects/project_detail.html
5 5
{% block page.body %}
6 6
{% with object.project.members as members %}
7 7
{% with object.project.approved_members as approved_members %}
8

  
9 8
<div class="projects">
10 9
	
11 10

  
......
28 27
	 	<span>{{ object.definition.name|upper }}</span>
29 28
	 </h2>
30 29
	 
30
<!-- 
31 31
	 <div class="details">
32 32
	 	<h3>
33 33
	 		GENERAL INFO
......
39 39
	 	<div class="data">
40 40
		 	<p class="restricted">{{ object.definition.description|safe }}</p>
41 41
		 	<dl class="alt-style">
42
			 	<dt>Homepage url</dt>
43
			 	<dd>
44
			 		{% if object.definition.homepage%}
45
			 			<a href="{{ object.definition.homepage }}">{{ object.definition.homepage }}</a>
46
			 		{% else %}
47
			 			Not set yet
48
			 		{% endif %}
49
			 	</dd>
50
			 	<dt>Member accept policy</dt>
51
			 	<dd>
52
			 		{{ object.definition.member_accept_policy }}
53
			 	</dd>
54 42
			 </dl>
55 43
		</div>
56 44
		<div class="editable" style="display:none;">
......
65 53
	    </form>
66 54
		</div>
67 55
	 </div>
56
 -->
68 57
	 <div class="full-dotted">
69 58
		 <h3>DETAILS</h3>
70 59
		 <dl class="alt-style">
71 60
		 	<dt>Name</dt>
72 61
		 	<dd>{{ object.definition.name }}&nbsp;</dd>
62
		 	<dt>Description</dt>
63
		 	<dd>{{ object.definition.description|safe }}&nbsp;</dd>
64
            <dt>Homepage url</dt>
65
            <dd>
66
                {% if object.definition.homepage%}
67
                    <a href="{{ object.definition.homepage }}">{{ object.definition.homepage }}</a>
68
                {% else %}
69
                    Not set yet
70
                {% endif %}
71
            </dd>
72
            <dt>Member accept policy</dt>
73
            <dd>
74
                {{ object.definition.member_accept_policy }}
75
            </dd>
73 76
		 	<dt>Issue date:</dt>
74 77
		 	<dd>{{object.issue_date|date:"d/m/Y"}}&nbsp;</dd>
75 78
		 	<dt>Start date:</dt>
76 79
		 	<dd>{{object.definition.start_date|date:"d/m/Y"}}&nbsp;</dd>
77 80
		 	<dt>End Date</dt>
78 81
		 	<dd>{{object.definition.end_date|date:"d/m/Y"}}&nbsp;</dd>
79
<!--
80
		 	<dt>Moderation</dt>
81
		 	<dd>{% if object.moderation_enabled%}Yes{% else %}No{% endif %}</dd>
82
 -->
83 82
		 	<dt>Activated</dt>
84 83
		 	<dd>{% if object.is_active %}Yes{% else %}No{% endif %}</dd>
85 84
		 	<dt>Owner</dt>
86 85
		 	<dd>{% if user == object.owner %}
87 86
                        Me
88 87
                {% else%}
89
                    {{object.owner.realname}} ({{object.owner.email}})
90
                
88
                    {{object.owner.realname}} {% if user.is_superuser %}({{object.owner.email}}){% endif %}
91 89
                {% endif %}
92 90
                &nbsp;
93 91
            </dd>
......
96 94
		 </dl>
97 95
	 </div>
98 96
	 <div class="full-dotted">
99
		 <h3>RESOURCES</h3>		 
97
		 <h3>RESOURCES</h3>
100 98
		 {% if object.definition.projectresourcegrant_set.all %}
101
		 <dl class="alt-style">	
102
	 		{% for q in object.definition.projectresourcegrant_set.all %}
103
		 		 q.resource
99
	     <dl class="alt-style">	
100
	 		{% for rp in object.definition.projectresourcegrant_set.all %}
101
	 		    <dt>
102
	 		        {{rp.resource}}
103
	 		    </dt>
104
	 		    <dd>
105
	 		        {{rp.member_limit}}
106
	 		    <dd/>
107
<!-- 
104 108
		 		<dt>
105 109
       				Max {% if q.is_abbreviation %}{{ q.verbose_name|upper }}{% else %}{{ q.verbose_name }}{% endif %}{% if not q.unit %}s {% endif  %}  per user
106 110
       			</dt>
107 111
		 		<dd>
108
       			{% if q.member_limit %}
112
       			{% if q.value %}
109 113
       				 {% if q.unit %}
110
       				 	{{ q.member_limit|sizeof_fmt }}
114
       				 	{{ q.value|sizeof_fmt }}
111 115
       				 {% else %}
112
       				 	{{ q.member_limit|isinf }}
116
       				 	{{ q.value|isinf }}
113 117
       				 {% endif %}
114 118
       			{% else %}
115 119
       				Unlimited
116 120
       			{% endif %}
117 121
       			</dd>
122
 -->
118 123
       		{% empty %}
119 124
       			No resources
120 125
	 		{% endfor %}
......
125 130
            <p>No resources</p>
126 131
        {% endif %} 
127 132
	 </div>
128
     {% if user == object.owner %}
133
     {% if object.is_alive %}
129 134
	 <div class="full-dotted">
130 135
	    {% with page|concat:sorting as args %}
131 136
	    {% with object.project.projectmembership_set.select_related.all|paginate:args as membership %}
......
143 148
                <caption>MEMBERS:</caption>
144 149
                <thead>
145 150
                    <tr>
146
                        <th>User Id</th>
151
                        <th>User Email</th>
147 152
                        <th>Name</th>
148 153
                        <th>Status</th>
149 154
                    </tr>
......
151 156
                <tbody>
152 157
                {% for m in membership.object_list %}
153 158
                  <tr>
154
                    <td>{{m.person.email}}</td>
159
                    <td>{%if user.is_superuser or user == o.owner %}{{m.person.email}}{% endif %}</td>
155 160
                    <td>{{m.person.realname}}</td>
156 161
                    {% if m.person == o.owner %}
157 162
                    <td>Owner</td>
b/snf-astakos-app/astakos/im/templates/im/projects/project_list.html
66 66
			            <option value="definition__start_date" {% if sorting == 'definition__start_date' %}selected{% endif %}>Sort by Start Date</option>
67 67
			            <option value="definition__end_date" {% if sorting == 'definition__end_date' %}selected{% endif %}>Sort by End Date</option>
68 68
			            <!-- <option value="approved_members_num" {% if sorting == 'approved_members_num' %}selected{% endif %}>Sort by Participants</option> --> 
69
			            <!-- <option value="status" {% if sorting == '' %}selected{% endif %}>Sort by Member Accept Policy</option> --> 
69 70
			            <option value="definition__member_accept_policy" {% if sorting == 'definition__member_accept_policy' %}selected{% endif %}>Sort by Member Accept Policy</option> 
71
			            <option value="definition__member_reject_policy" {% if sorting == 'definition__member_reject_policy' %}selected{% endif %}>Sort by Member Reject Policy</option> 
70 72
					</select>
71 73
					<input type="hidden" name="q" value="{{q}}"/>
72 74
				</div>
......
81 83
                    <!--<th>Type</th>-->
82 84
                    <th>Issued</th>
83 85
                    <th>Starts</th>
84
                    <th>Expires</th>
85
                     
86
                    <th>Ends</th>               
86 87
                    <th>Enrolled</th>
87
                   
88
                     
89 88
                    <th>Status</th>
89
                    <th>Membership Status</th>
90 90
                    <th>&nbsp;</th>
91 91
			        <th>Member accept policy</th>
92
			        <th>Member reject policy</th>
92 93
                   <!-- <th>&nbsp;</th>-->
93 94
                  
94 95
                  </tr>
......
104 105
	                    <td style="width:13%">{{o.definition.start_date|date:"d/m/Y"}}</td>
105 106
	                    <td style="width:13%">{{o.definition.end_date|date:"d/m/Y"}}</td>
106 107
	                    <td style="width:11%">{{approved_members|length}}</td>
107
	                    
108
	                    <td style="width:11%">
109
	                        {{o.status}} <a href="{% url project_update o.serial %}">Update</a>
110
	                    </td>
108 111
	                    <td style="width:17%">
109 112
	                    	<div class="msg-wrap">
110 113
	                        {% if user == o.owner %}
......
126 129
	                    	<div class="msg-wrap">
127 130
	                    		 
128 131
		                    {% if user in members %}
129
		                        {% if user in approved_members %}
130
		    
131
		                        
132
		                        {% if user in approved_members %}    
132 133
			                       	{% if not user == o.owner %}
133
			                             
134 134
			                            <form action="{% url project_leave o.serial %}" method="post" class="link-like">{% csrf_token %}
135 135
			                                 <input type="submit"  value="x leave group" class="leave"/>
136 136
			                            </form>
137 137
			                            <div class="dialog">
138 138
					                		Are you sure you what to leave this group?<br>
139 139
					                		Name: <a  href="{% url project_detail o.serial %}" title="visit group page">{{o.groupname}}</a><br>
140
					                		{% if o.definition.description %}Description:{{o.definition.description|truncatewords:30}}{% endif %}<br><br>
141
					                		
140
					                		{% if o.definition.description %}Description:{{o.definition.description|truncatewords:30}}{% endif %}<br><br>       		
142 141
					                		<a href="#" class="yes submit">Yes</a>&nbsp;&nbsp;&nbsp;<a href="#" class="no submit">No</a>
143 142
					                	</div>
144 143
			                        {% else %}
145 144
			                        	 &nbsp;
146 145
			                        {% endif %}
147
		                        
148
		                            
149
		
150 146
		                        {% else %}
151 147
		                            &nbsp;
152 148
		                        {% endif %}
......
167 163
	                    	</div>
168 164
	                    </td>
169 165
			            <td class="centered" style="width:9%">{{o.definition.member_accept_policy}}</td>
166
	                    <td class="centered" style="width:9%">{{o.definition.member_reject_policy}}</td>
170 167
	                    <!--td><a href="#" class="more-info" title="more info">+ more info</a></td-->
171 168
                  </tr>
172 169
                  <tr class="{% cycle 'tmore1' 'tmore2' %}" style="display:none">
b/snf-astakos-app/astakos/im/templates/im/projects/projectapplication_form.html
6 6
	<script src="{{ IM_STATIC_URL }}js/quotas.js"></script>	
7 7
{% endblock %}	
8 8
{% block page.body %}
9

  
9 10
<form action="#top" method="post" class="withlabels quotas-form" id="group_create_form">{% csrf_token %}
10 11

  
11 12
    <fieldset class="with-info" id="top">
......
18 19
    	</legend>
19 20
        
20 21
        {% include "im/form_render.html" %}
21

  
22
        
23
        {% for g, resources in resource_catalog.get_groups_resources %}
24
	    	{% for rname in resources.keys %}
25
	    	    {% with object|resource_grants|lookup:rname as value %}
26
	    	        <input type="hidden" id="{{'id_'|add:rname|add:'_uplimit'}}" name="{{rname|add:'_uplimit'}}" autocomplete="off" {% if value %}value="{{value}}"{% endif %}">
27
                {% endwith %}
28
            {% endfor %}
29
        {% endfor %}
22 30
    </fieldset>
23 31
    
24 32
    <fieldset id="icons">
......
30 38
	    	</span>    
31 39
    	</legend>
32 40
    	<ul class="clearfix">
41
    	    {% with object|resource_groups as groups %}
33 42
            {% for g, group_info in resource_catalog.groups.items %}  
34 43
            	{% if g %}
35 44
	    		<li>
36
	    			<a href="#{{ g }}" id="{{'group_'|add:g}}"><img src="/static/im/images/create-{{ g }}.png" alt="vm"/></a>
37
	    			<input type="hidden" name="proxy_{{ 'is_selected_'|add:g }}"  id="proxy_{{ 'id_is_selected_'|add:g }}">
38
	    			<input type="hidden" name="{{ 'is_selected_'|add:g }}"  id="{{ 'id_is_selected_'|add:g }}">
45
	    		    <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>
46
	    			<input type="hidden" name="proxy_{{ 'is_selected_'|add:g }}"  id="proxy_{{ 'id_is_selected_'|add:g }}" {% if g in groups %}checked="checked"{% endif %}>
47
	    			<input type="hidden" name="{{ 'is_selected_'|add:g }}"  id="{{ 'id_is_selected_'|add:g }}" {% if g in groups %}checked="checked"{% endif %}>
39 48
	                <p class="msg">{{ group_info.help_text }}</p>
40 49
	    		</li>
41 50
	    		{% endif %}
42 51
            {% endfor %}
52
            {% endwith %}
43 53
    	</ul>
44 54
    	
45 55
    </fieldset>
......
78 88
										 	class="dehumanize"
79 89
										{% endif  %}
80 90
			       						/> 
81
			       			<input type="hidden" name="{{rname|add:'_uplimit'}}" id="{{'id_'|add:rname|add:'_uplimit'}}" ">
82
			    			<span class="extra-img">&nbsp;</span>
91
			       			<span class="extra-img">&nbsp;</span>
83 92
			         		<span class="info"><em>more info</em><span>Leave this field blank if you don't want to specify this resource</span></span>
84 93
			         		<p class="error-msg">Invalid format</p>
85 94
			    		</p>
b/snf-astakos-app/astakos/im/templatetags/filters.py
43 43

  
44 44

  
45 45
from astakos.im.settings import PAGINATE_BY
46

  
46
from astakos.im.models import RESOURCE_SEPARATOR
47 47

  
48 48
register = template.Library()
49 49

  
......
200 200
        return v[:max]+'...'
201 201
    else:
202 202
        return v[:20]
203

  
204
@register.filter
205
def resource_groups(project_definition):
206
    try:
207
        grants = project_definition.projectresourcegrant_set
208
        return grants.values_list('resource__group', flat=True)
209
    except:
210
        return ()
211

  
212
@register.filter
213
def resource_grants(project_definition):
214
    try:
215
        grants = project_definition.projectresourcegrant_set
216
        grants = grants.values_list(
217
            'resource__name',
218
            'resource__service__name',
219
            'member_limit'
220
        )
221
        return dict((RESOURCE_SEPARATOR.join([e[1], e[0]]), e[2]) for e in grants)
222
    except:
223
        return {}
b/snf-astakos-app/astakos/im/urls.py
68 68
    url(r'^group/how_it_works/?$', 'how_it_works', {}, name='how_it_works'),
69 69
    
70 70
    url(r'^project/add/?$', 'project_add', {}, name='project_add'),
71
    url(r'^project/update/(?P<serial>\w+)/?$', 'project_update', {}, name='project_update'),
71 72
    url(r'^project/list/?$', 'project_list', {}, name='project_list'),
72 73
    url(r'^project/search/?$', 'project_search', {}, name='project_search'),
73 74
    url(r'^project/all/?$', 'project_all', {}, name='project_all'),
b/snf-astakos-app/astakos/im/views.py
54 54
from django.utils.http import urlencode
55 55
from django.utils.translation import ugettext as _
56 56
from django.views.generic.create_update import (
57
    create_object, delete_object, get_model_and_form_class
57
    create_object, update_object, delete_object, get_model_and_form_class
58 58
)
59 59
from django.views.generic.list_detail import object_list, object_detail
60 60
from django.core.xheaders import populate_xheaders
......
80 80
    MembersSortForm, AstakosGroupSortForm,
81 81
    TimelineForm, PickResourceForm,
82 82
    AstakosGroupCreationSummaryForm,
83
    ProjectApplicationForm
83
    ProjectApplicationForm, ProjectSortForm
84 84
)
85 85
from astakos.im.functions import (
86 86
    send_feedback, SendMailError,
......
783 783
            yield g, self.get_group_resources(g)
784 784

  
785 785
    def get_quota(self, group_quotas):
786
        for r, v in group_quotas.iteritems():
786
        for r, v in group_quotas:
787 787
            rname = str(r)
788 788
            quota = self.data['resources'].get(rname)
789 789
            quota['value'] = v
......
1481 1481
    q |= ProjectApplication.objects.filter(
1482 1482
        project__in=request.user.projectmembership_set.values_list('project', flat=True)
1483 1483
    )
1484
    sorting = 'definition__name'
1485
    sort_form = ProjectSortForm(request.GET)
1486
    if sort_form.is_valid():
1487
        sorting = sort_form.cleaned_data.get('sorting')
1488
    q = q.order_by(sorting)
1489
    
1484 1490
    return object_list(
1485 1491
        request,
1486 1492
        q,
......
1489 1495
        template_name='im/projects/project_list.html',
1490 1496
        extra_context={
1491 1497
            'is_search':False,
1492
            'sorting':request.GET.get('sorting'),
1498
            'sorting':request.GET.get('sorting')
1493 1499
        }
1494 1500
    )
1495 1501

  
1496

  
1497 1502
@require_http_methods(["GET", "POST"])
1498 1503
@signed_terms_required
1499 1504
@login_required
1500
def project_application_detail(request, serial):
1501
    return object_detail(
1505
def project_update(request, serial):
1506
    result = callpoint.list_resources()
1507
    resource_catalog = ResourcePresentation(RESOURCES_PRESENTATION_DATA)
1508
    resource_catalog.update_from_result(result)
1509

  
1510
    if not result.is_success:
1511
        messages.error(
1512
            request,
1513
            'Unable to retrieve system resources: %s' % result.reason
1514
    )
1515
    extra_context = {'resource_catalog':resource_catalog}
1516
    return update_object(
1502 1517
        request,
1503
        queryset=ProjectApplication.objects.select_related(), 
1504 1518
        slug=serial,
1505
        slug_field='serial',
1506
        template_name='im/projects/projectapplication_detail.html'
1507
    )
1519
        slug_field='projectapplication__serial',
1520
        template_name='im/projects/projectapplication_form.html',
1521
        extra_context=extra_context, post_save_redirect='/im/project/list/',
1522
        form_class=ProjectApplicationForm)
1523
   
1524
# @require_http_methods(["GET", "POST"])
1525
# @signed_terms_required
1526
# @login_required
1527
# def project_application_detail(request, serial):
1528
#     return object_detail(
1529
#         request,
1530
#         queryset=ProjectApplication.objects.select_related(),
1531
#         slug=serial,
1532
#         slug_field='serial',
1533
#         template_name='im/projects/projectapplication_detail.html'
1534
#     )
1508 1535

  
1509 1536
@require_http_methods(["GET", "POST"])
1510 1537
@signed_terms_required
1511 1538
@login_required
1512 1539
def project_detail(request, serial):
1540
    result = callpoint.list_resources()
1541
    resource_catalog = ResourcePresentation(RESOURCES_PRESENTATION_DATA)
1542
    resource_catalog.update_from_result(result)
1513 1543
    return object_detail(
1514 1544
        request,
1515 1545
        queryset=ProjectApplication.objects.select_related(),
......
1517 1547
        slug_field='serial',
1518 1548
        template_name='im/projects/project_detail.html',
1519 1549
        extra_context={
1520
            'sorting':request.GET.get('sorting', request.POST.get('sorting')),
1550
            'resource_catalog':resource_catalog,
1551
            'sorting':request.GET.get('sorting', request.POST.get('sorting'))
1521 1552
        }
1522 1553
    )
1523 1554

  

Also available in: Unified diff