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 }} </dd> |
62 |
<dt>Description</dt> |
|
63 |
<dd>{{ object.definition.description|safe }} </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"}} </dd> |
75 | 78 |
<dt>Start date:</dt> |
76 | 79 |
<dd>{{object.definition.start_date|date:"d/m/Y"}} </dd> |
77 | 80 |
<dt>End Date</dt> |
78 | 81 |
<dd>{{object.definition.end_date|date:"d/m/Y"}} </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 |
|
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> </th> |
91 | 91 |
<th>Member accept policy</th> |
92 |
<th>Member reject policy</th> |
|
92 | 93 |
<!-- <th> </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> <a href="#" class="no submit">No</a> |
143 | 142 |
</div> |
144 | 143 |
{% else %} |
145 | 144 |
|
146 | 145 |
{% endif %} |
147 |
|
|
148 |
|
|
149 |
|
|
150 | 146 |
{% else %} |
151 | 147 |
|
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"> </span> |
|
91 |
<span class="extra-img"> </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