Revision 3cbd5e47

b/snf-astakos-app/astakos/im/forms.py
539 539
        initial=True
540 540
    )
541 541
    max_participants = forms.IntegerField(
542
        required=False, min_value=1
542
        required=True, min_value=1
543 543
    )
544 544

  
545 545
    class Meta:
......
661 661
        super(AstakosGroupCreationSummaryForm, self).clean()
662 662
        self.cleaned_data['policies'] = []
663 663
        append = self.cleaned_data['policies'].append
664
        print '#', self.cleaned_data
664 665
        #tbd = [f for f in self.fields if (f.startswith('is_selected_') and (not f.endswith('_proxy')))]
665 666
        tbd = [f for f in self.fields if f.startswith('is_selected_')]
666 667
        for name, uplimit in self.cleaned_data.iteritems():
668
            print '####', name, uplimit
667 669
            subs = name.split('_uplimit')
668 670
            if len(subs) == 2:
669 671
                tbd.append(name)
......
671 673
                s, sep, r = prefix.partition(RESOURCE_SEPARATOR)
672 674
                resource = Resource.objects.get(service__name=s, name=r)
673 675
                
676
                print '#### ####', resource
674 677
                # keep only resource limits for selected resource groups
675 678
                if self.cleaned_data.get(
676
                    'is_selected_%s' % resource.group, True
679
                    'is_selected_%s' % resource.group, False
677 680
                ):
678 681
                    append(dict(service=s, resource=r, uplimit=uplimit))
679 682
        for name in tbd:
b/snf-astakos-app/astakos/im/messages.py
36 36
ACCOUNT_ALREADY_ACTIVE                  =   'Account is already active.'
37 37
TOKEN_UNKNOWN                           =   'There is no user matching this token.'
38 38

  
39
INVITATION_SENT                         =   'Invitation sent to %(emails.'
39
INVITATION_SENT                         =   'Invitation sent to %(email)s.'
40 40
PROFILE_UPDATED                         =   'Profile has been updated successfully.'
41 41
FEEDBACK_SENT                           =   'Feedback successfully sent.'
42 42
EMAIL_CHANGED                           =   'Account email has been changed successfully.'
......
44 44
                                               You are going to receive a verification email in the new address.'
45 45

  
46 46
OBJECT_CREATED                          =   'The %(verbose_name)s was created successfully.'
47
MEMBER_JOINED_GROUP                     =   '%(realnames has been successfully joined the group.'
48
MEMBER_REMOVED                          =   '%(realnames has been successfully removed from the group.'
47
MEMBER_JOINED_GROUP                     =   '%(realname)s has been successfully joined the group.'
48
MEMBER_REMOVED                          =   '%(realname)s has been successfully removed from the group.'
49 49
BILLING_ERROR                           =   'Service response status: %(status)d' 
50 50
LOGOUT_SUCCESS                          =   'You have successfully logged out.'
51 51

  
......
56 56
GROUP_MAX_PARTICIPANT_NUMBER_REACHED    =   'Group maximum participant number has been reached.'
57 57
NO_APPROVAL_TERMS                       =   'There are no approval terms.'
58 58
PENDING_EMAIL_CHANGE_REQUEST            =   'There is already a pending change email request.'
59
OBJECT_CREATED_FAILED                   =   'The %(verbose_names creation failed: %(reasons.'
59
OBJECT_CREATED_FAILED                   =   'The %(verbose_name)s creation failed: %(reason)s.'
60 60
GROUP_JOIN_FAILURE                      =   'Failed to join group.'
61 61
GROUPKIND_UNKNOWN                       =   'There is no such a group kind'
62 62
NOT_MEMBER                              =   'User is not member of the group.'
......
105 105
VERIFICATION_SENT                       =   'Verification sent.'
106 106

  
107 107
SWITCH_ACCOUNT_LINK_SENT                =   'This email is already associated with another local account. \
108
                                               To change this account to a shibboleth one follow the link in the verification email sent to %(emails. \
108
                                               To change this account to a shibboleth one follow the link in the verification email sent to %(email)s. \
109 109
                                               Otherwise just ignore it.'
110 110
NOTIFACATION_SENT                       =   'Your request for an account was successfully received and is now pending approval. \
111 111
                                               You will be notified by email in the next few days. \
b/snf-astakos-app/astakos/im/settings.py
186 186
# Enforce token renewal on password change/reset
187 187
NEWPASSWD_INVALIDATE_TOKEN = getattr(
188 188
    settings, 'ASTAKOS_NEWPASSWD_INVALIDATE_TOKEN', True)
189

  
190

  
191
RESOURCES_PRESENTATION_DATA = getattr(
192
    settings, 'ASTAKOS_RESOURCES_PRESENTATION_DATA', {
193
        'groups': {
194
             'compute': {
195
                'help_text':'group compute help text',
196
                'is_abbreviation':False,
197
                'report_desc':'',
198
                 'verbose_name':'compute', 
199
            },
200
            'storage': {
201
                'help_text':'group storage help text',
202
                'is_abbreviation':False,
203
                'report_desc':'',
204
                 'verbose_name':'storage', 
205
            },
206
        },
207
        'resources': {
208
            'pithos+.diskspace': {
209
                'help_text':'resource pithos+.diskspace help text',
210
                'is_abbreviation':False,
211
                'report_desc':'Pithos+ Diskspace',
212
                'placeholder':'eg. 10GB',
213
                'verbose_name':'diskspace', 
214
            },
215
            'cyclades.vm': {
216
                'help_text':'resource cyclades.vm help text resource cyclades.vm help text resource cyclades.vm help text resource cyclades.vm help text',
217
                'is_abbreviation':True,
218
                'report_desc':'Virtual Machines',
219
                'placeholder':'eg. 2',
220
                'verbose_name':'vm', 
221
            },
222
            'cyclades.disk': {
223
                'help_text':'resource cyclades.disk help text',
224
                'is_abbreviation':False,
225
                'report_desc':'Disk',
226
                'placeholder':'eg. 5GB, 2GB etc',
227
                'verbose_name':'disk'
228
            },
229
            'cyclades.ram': {
230
                'help_text':'resource cyclades.ram help text',
231
                'is_abbreviation':True,
232
                'report_desc':'RAM',
233
                'placeholder':'eg. 4GB',
234
                'verbose_name':'ram'
235
            },
236
            'cyclades.cpu': {
237
                'help_text':'resource cyclades.cpu help text',
238
                'is_abbreviation':True,
239
                'report_desc':'CPUs',
240
                'placeholder':'eg. 1',
241
                'verbose_name':'cpu'
242
            },
243
            'cyclades.network.private': {
244
                'help_text':'resource cyclades.network.private help text',
245
                'is_abbreviation':False,
246
                'report_desc':'Network',
247
                'placeholder':'eg. 1',
248
                'verbose_name':'private network'
249
            }
250
        
251
        }
252
        
253
    })
b/snf-astakos-app/astakos/im/static/im/css/dropkick.css
14 14
/* dropkick select extra styles */
15 15

  
16 16
.form-row .dk_container							{ border-radius:0; margin-bottom:0; border: 1px solid #ccc; height: 21px; letter-spacing: 1px; line-height: 22px; margin-bottom: -1px; width:240px; padding:5px 0; font-weight:normal; font-family: 'Didact Gothic', Verdana, sans-serif; font-size:1em; background:transparent; color:#808080;}
17
.form-row .dk_toggle  							{ border-radius:0;  padding:0;  border:0 none; text-indent:1.5em; text-decoration:none;background-image:url(../images/arrow-down_black.png); background-position:90% 5px;}
17
.form-row .dk_toggle  							{ border-radius:0;  padding:0;  border:0 none; text-indent:1.5em; text-decoration:none;background-image:url(../images/arrow-down_grey.png); background-position:90% 5px;}
18 18
.form-row .dk_toggle:hover						{ text-decoration:none; }
19 19
.form-row .dk_open								{ background:transparent; box-shadow: none; }
20 20
.form-row .dk_open .dk_toggle					{ background-color:transparent; border:0 none; color:#000; box-shadow: none;}
b/snf-astakos-app/astakos/im/static/im/js/common.js
115 115
	$('select.dropkicked').dropkick({
116 116
		change: function (value, label) {
117 117
		    $(this).parents('form').submit();
118
		    
118 119
		}
119 120
	});
120 121
    
b/snf-astakos-app/astakos/im/static/im/js/quotas.js
4 4
	var id = el.attr('id');
5 5
	$('.quotas-form .group').each(function() {
6 6
		if( $(this).hasClass(id) ) {
7
			$(this).appendTo('.foo');
7
			$(this).appendTo('.visible');
8 8
			$(this).show('slow');
9 9
			$(this).find('input')[0].focus()
10 10
		}
......
68 68
		 
69 69
		// hide relevant fieldset 
70 70
		$(this).parents('.group').hide('slow', function() {
71
		    $(this).appendTo('.not-foo');	
71
		    $(this).appendTo('.not-visible');	
72 72
		});
73 73
		
74 74
		group_class = $(this).parents('.group').attr('class').replace('group ', '');
......
114 114
		 	if ($(this).hasClass('dehumanize')){
115 115
		 		
116 116
		 		var flag = 0;
117

  
118
				// check if the value is not float
119
		 		var num_float = parseFloat(value);
120
		 		num_float= String(num_float);
121

  
122
		 		if (num_float.indexOf(".") == 1){
123
		 			flag = 1 ; 
124
		 			msg="Please enter an integer";
125
		 		} else {
126
		 			var num = parseInt(value);
127
					if ( num == '0' ) { 
128
						flag = 1 ; msg="zero"
129
					} else {
130
						if ( value && !num ) { flag = 1 ; msg="Invalid format"}
131
				 	
132
					 	var bytes = num;
133
				 		
134
						// remove any numbers and get suffix		 		
135
				 		var suffix = value.replace( num, '');
136
		
137
				 		 // validate suffix. 'i' renders it case insensitive
138
					 	var suf = suffix.match( new RegExp('^(GB|KB|MB|TB|bytes|G|K|M|T|byte)$', 'i'));
139
					 	if (suf){
140
					 		
141
					 		suf = suf[0].toLowerCase(); 
142
					 		suf = suf.substr(0,1);
143
					 	
144
						 	// transform to bytes
145
						 	switch (suf){
146
						 		case 'b': 
147
						 		  bytes = num*Math.pow(1024,0);
148
						 		  break;
149
						 		case 'k':
150
						 		  bytes = num*Math.pow(1024,1);
151
						 		  break;
152
						 		case 'm':
153
						 		  bytes = num*Math.pow(1024,2);
154
						 		  break;
155
						 		case 'g':
156
						 		  bytes = num*Math.pow(1024,3);
157
						 		  break;
158
						 		case 't':
159
						 		  bytes = num*Math.pow(1024,4);
160
						 		  break;    
161
						 		default:
162
						 		  bytes = num; 
163
					 		}
164
					 	} else {
165
					 		if (num) {
166
					 		 	flag = 1;
167
					 		 	msg ="You must specify correct units" 
168
					 		}  
169
					 		 
170
					 	}
171
					}
172
				 	
173
		 			
174
		 			
175
		 		}
117 176
		 		
118
		 		// replace , with .  and get number 
119
			 	value = value.replace(",",".");
120
			 	var num = parseFloat(value);
121
			 	
122
			 	if ( value && !num ) { flag = 1 ; msg="Invalid format"}
123
			 	
124
			 	var bytes = num;
125
		 		
126
		 		 // get suffix. 'i' renders it case insensitive
127
			 	var suf = value.match( new RegExp('GB|KB|MB|TB|bytes|G|K|M|T|byte', 'i'));
128
			 	if (suf){
129
			 		
130
			 		suf = suf[0].toLowerCase(); 
131
			 		suf = suf.substr(0,1);
177
		 		 
132 178
			 	
133
				 	// transform to bytes
134
				 	switch (suf){
135
				 		case 'b': 
136
				 		  bytes = num*Math.pow(1024,0);
137
				 		  break;
138
				 		case 'k':
139
				 		  bytes = num*Math.pow(1024,1);
140
				 		  break;
141
				 		case 'm':
142
				 		  bytes = num*Math.pow(1024,2);
143
				 		  break;
144
				 		case 'g':
145
				 		  bytes = num*Math.pow(1024,3);
146
				 		  break;
147
				 		case 't':
148
				 		  bytes = num*Math.pow(1024,4);
149
				 		  break;    
150
				 		default:
151
				 		  bytes = num; 
152
			 		}
153
			 	} else {
154
			 		if (num) {
155
			 		 	flag = 1;
156
			 		 	msg ="You must specify correct units" 
157
			 		}  
158
			 		 
159
			 	}
160 179
			 	
161 180
			 	if ( flag == '1' ){ 
162 181
			 		$(this).parents('.form-row').addClass('with-errors');
......
171 190
			 	
172 191
			 	hidden_input.val(bytes);
173 192
			 	
193
			 	
174 194
		 	}
175 195
		 	 
176
		 	// actions for int fields
196
		 	// validation actions for int fields
177 197
		 	else {
178 198
	
179 199
		 		var is_int = value.match (new RegExp('^[0-9]*$'));
180 200
		 		if ( !is_int ){ 
181
		 			$(this).parents('.form-row').find('.error-msg').html('Enter a positive intiger');
201
		 			$(this).parents('.form-row').find('.error-msg').html('Enter a positive integer');
182 202
			 		$(this).parents('.form-row').addClass('with-errors');
183 203
			 		 
184 204
			 	} else {
......
198 218
	 	} else {
199 219
	 		hidden_input.removeAttr('value');
200 220
	 	}
221
	 	$('#icons span.info').removeClass('error-msg');
201 222
	 	
202 223
	 });
203 224
	 
b/snf-astakos-app/astakos/im/templates/im/astakosgroup_detail.html
4 4

  
5 5
{% block page.body %}
6 6
{% with object.owners as owners %}
7
{% with object.quota as quota %}
7
 
8 8
<div class="projects">
9
	
9

  
10 10
	<h2>
11 11
	 	{% if object.is_member %}
12 12
			<em>
......
79 79
		 	<dd>{% if object.max_participants%}{{object.max_participants}}{% else %}&nbsp;{% endif %}</dd>
80 80
		 </dl>
81 81
	 </div>
82
	 
83
     <div class="full-dotted">
82
	 <div class="full-dotted">
84 83
		 <h3>RESOURCES:</h3>		 
85 84
		 {% if quota %}
86
		 <dl class="alt-style">
87
		 	{% for k in quota|dkeys %}
88
			 	{% with resource_catalog|lookup:'resources' as resources %}
89
			 		{% with resources|lookup_uni:k as info %}
90
			 		{% with resource_presentation|lookup_uni:k as resource_info %}
91
						<dt>
92
	           				Max {% if resource_info.is_abbreviation %}{{ info.name|upper }}{% else %}{{ info.name }}{% endif %}{% if not info.unit %}s {% endif  %}  per user
93
	           			</dt>		                
94
						<dd>
95
						{% with quota|lookup:k as uplimit%}	
96
		           			 {% if uplimit %}
97
		           				 {% if info.unit %}
98
		           				 	{{ uplimit|sizeof_fmt }}
99
		           				 {% else %}
100
		           				 	{{ uplimit|isinf }}
101
		           				 {% endif %}
102
		           			
103
		           			{% endif %}
104
		           			 
105
	           			{% endwith%}
106
	           			</dd>
107
	           		 
108
	                {% endwith%}
109
	                {% endwith %}
110
                {% endwith %}
111
            {% endfor %}
112
		</dl>
85
		 <dl class="alt-style">	
86
	 		{% for q in quota %}
87
		 		 
88
		 		<dt>
89
       				Max {% if q.is_abbreviation %}{{ q.verbose_name|upper }}{% else %}{{ q.verbose_name }}{% endif %}{% if not q.unit %}s {% endif  %}  per user
90
       			</dt>
91
		 		<dd>
92
       			{% if q.value %}
93
       				 {% if q.unit %}
94
       				 	{{ q.value|sizeof_fmt }}
95
       				 {% else %}
96
       				 	{{ q.value|isinf }}
97
       				 {% endif %}
98
       			{% else %}
99
       				Unlimited
100
       			{% endif %}
101
       			</dd>
102
	 		{% endfor %}
103
	 	</dl>
113 104
		{% else %}
114
            <p>No policies</p>
105
            <p>No resources</p>
115 106
        {% endif %} 
116 107
	 </div>
108
     
117 109
	 <div class="full-dotted">
118 110
	    {% with page|concat:sorting as args %}
119 111
	    {% with object.membership_set.select_related.all|paginate:args as membership %}
120 112
            {% if membership %}
121
            <form method="GET" class="minimal" action="">
113
            <form method="GET" class="minimal" action="#members-table">
122 114
                <div class="form-row">
123 115
                    <select name="sorting" onchange="this.form.submit();" class="dropkicked">
124 116
                        <option value="">Sort by</option>
......
128 120
                    </select>
129 121
                </div>
130 122
            </form>
131
             <table class="alt-style">
123
             <table class="alt-style" id="members-table">
132 124
                <caption>MEMBERS:</caption>
133 125
                <thead>
134 126
                    <tr>
......
199 191
     
200 192
    
201 193
</div>
202
{% endwith %}
194
 
203 195
{% endwith %}
204 196
{% endblock %}
b/snf-astakos-app/astakos/im/templates/im/astakosgroup_form.html
6 6
	<script src="{{ IM_STATIC_URL }}js/quotas.js"></script>	
7 7
{% endblock %}	
8 8
{% block page.body %}
9
 
10
	
11 9
<form action="#top" method="post" class="withlabels quotas-form" id="group_create_form">{% csrf_token %}
12
	 
10

  
13 11
    <fieldset class="with-info" id="top">
14 12
    	<legend>
15 13
    		1. CREATE GROUP
......
31 29
		    	<span>You need to specify at least one resource</span>
32 30
	    	</span>    
33 31
    	</legend>
34

  
35
    {% with resource_catalog|lookup:'resources' as resources %}
36
    {% with resource_catalog|lookup:'groups' as groups %}    	
37 32
    	<ul class="clearfix">
38
            {% for g, rs in groups.items %}   
39
            {% with resource_presentation|lookup:g as group_info %} 		
40
    		<li>
41
    			<a href="#{{ g }}" id="{{'group_'|add:g}}"><img src="/static/im/images/create-{{ g }}.png" alt="vm"/></a>
42
    			<input type="hidden" name="proxy_{{ 'is_selected_'|add:g }}"  id="proxy_{{ 'id_is_selected_'|add:g }}">
43
    			<p class="msg">{{ group_info.help_text }}</p>
44
    		</li>
45
    		{% endwith %}
33
            {% for g, group_info in resource_catalog.groups.items %}  
34
            	{% if g %}
35
	    		<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
	    			<p class="msg">{{ group_info.help_text }}</p>
39
	    		</li>
40
	    		{% endif %}
46 41
            {% endfor %}
47 42
    	</ul>
48 43
    	
49 44
    </fieldset>
50 45
   
51
    <div class="foo">
52
    
46
    <div class="visible">
47
    	
48
    </div>
49
    <div class="not-visible">
50
    	{% for gname, resources in resource_catalog.get_groups_resources %}
51
	    	<div class="group {{'group_'|add:gname}}" id="{{ g }}">
52
	    		<a href="#icons" class="delete">X remove resource</a>	
53
	    		{% for rname, rdata in resources.items %}
54
	    		<fieldset class="quota">
55
			    	
56
			    	<legend>
57
			    		{% if rdata.is_abbreviation %}
58
			    			{{ rdata.verbose_name|upper }}
59
			    		{% else %}
60
			    			{{ rdata.verbose_name|capfirst }}
61
			    		{% endif %}
62
			    		<span class="info"> 
63
					    	<em>more info</em>
64
					    	<span>{{ rdata.help_text }}</span>
65
				    	</span>  
66
			    	</legend>
67
			    	<div class="form-row">
68
			    		<p class="clearfix">
69
			    			<label for="{{'id_'|add:rname|add:'_uplimit'}}_proxy" >
70
								Max {% if rdata.is_abbreviation %}{{ rdata.verbose_name|upper }}{% else %}{{ rdata.verbose_name }}{% endif %}{% if not rdata.unit %}s {% endif  %} per user
71
							</label>
72
			    			<input 	type="text" 
73
			       						id="{{'id_'|add:rname|add:'_uplimit'}}_proxy" 
74
			       						name="{{rname|add:'_uplimit'}}_proxy" 
75
			       						placeholder="{{ rdata.placeholder}} " 
76
			       						{% if rdata.unit == 'bytes' %} 
77
										 	class="dehumanize"
78
										{% endif  %}
79
			       						/> 
80
			    			<span class="extra-img">&nbsp;</span>
81
			         		<span class="info"><em>more info</em><span>Leave this field blank if you don't want to specify this resource</span></span>
82
			         		<p class="error-msg">Invalid format</p>
83
			    		</p>
84
			    		<p class="msg"></p>
85
			    	</div>
86
				</fieldset>	
87
				{% endfor %}
88
	    	</div>
89
	    	 
90
	    {% endfor %}
53 91
    </div>
54
    <div class="not-foo">
55
        {% for g, rs in groups.items %}
56
        
57
        <div class="group {{'group_'|add:g}}" id="{{ g }}">
58
			<a href="#icons" class="delete">X remove resource</a>	
59
		    {% for r in rs %}
60
		    {% with resource_presentation|lookup:r as resource_info %}
61
		    {% with resources|lookup:r as resource%}
62
		    <fieldset class="quota">
63
		    	<legend>
64
		    		{% if resource_info.is_abbreviation %}
65
		    			{{ r|get_value_after_dot|upper }}
66
		    		{% else %}
67
		    			{{ r|get_value_after_dot|capfirst }}
68
		    		{% endif %}
69
		    		<span class="info"> 
70
				    	<em>more info</em>
71
				    	<span>{{ resource_info.help_text }}</span>
72
			    	</span>  
73
		    	</legend>
74
<!--	    	<div class="form-row">
75
		    		<p class="clearfix">
76
		    			<label for="num_storage">Total storage</label>
77
		    			<input type="text" name="num_storage">
78
		    			<span class="extra-img">&nbsp;</span>
79
		         		<span class="info"><em>more info</em><span>Help Text</span></span>
80
		    		</p>
81
		    	</div>-->
82
 				 
83
		    	
84
		    	<div class="form-row">
85
		    		<p class="clearfix">
86
		    			<label for="{{'id_'|add:r|add:'_uplimit'}}_proxy" >
87
							Max {% if resource_info.is_abbreviation %}{{ r|get_value_after_dot|upper }}{% else %}{{ r|get_value_after_dot }}{% endif %}{% if not resource.unit %}s {% endif  %} per user
88
						</label>
89
		    			<input 	type="text" 
90
		       						id="{{'id_'|add:r|add:'_uplimit'}}_proxy" 
91
		       						name="{{r|add:'_uplimit'}}_proxy" 
92
		       						placeholder="{{ resource_info.placeholder}} " 
93
		       						{% if resource.unit == 'bytes' %} 
94
									 	class="dehumanize"
95
									{% endif  %}
96
		       						/> 
97
		    			<span class="extra-img">&nbsp;</span>
98
		         		<span class="info"><em>more info</em><span>Leave this field blank if you don't want to specify this resource</span></span>
99
		         		<p class="error-msg">Invalid format</p>
100
		    		</p>
101
		    		<p class="msg"></p>
102
		    	</div>
103
		    	 
104
 
105
 
106
		    </fieldset>
107
		    {% endwith %}
108
		    {% endwith %}
109
		    {% endfor %}
110
	    </div>
111
	    
112
    	{% endfor %}
113
	</div>
114
    {% endwith %}
115
    {% endwith %}
116
	 
117 92
    <div class="form-row submit">
118
 
119 93
   		<input type="submit" value="CONTINUE" class="submit altcol" autocomplete="off">
120
 
121 94
	</div>     
122 95
</form>
123 96
	 
b/snf-astakos-app/astakos/im/templates/im/astakosgroup_form_summary.html
6 6
 
7 7
{% with form.data as data %}	 	
8 8
<div class="projects summary">
9
	 
10 9
	<form action="{% url group_add_complete %}" method="post" class="quotas-form">{% csrf_token %}
11 10
		<legend>3. CONFIRM YOUR REQUEST</legend>
12 11
<!-- 
......
39 38
			 	<dd>{% if  data.max_participants %}{{ data.max_participants }}{% else %}Unlimited{% endif %}</dd>
40 39
			 </dl>
41 40
		 </div>
41
		 
42
		 
42 43
		 <div class="full-dotted">
43
			 <h3>RESOURCES:</h3>
44
	           <dl class="alt-style">	           	
45
	           	{% for r in policies %}
46
	           		{% with r.service|add:'.'|add:r.resource as t %}
47
	           		{% with resource_catalog|lookup:'resources' as resources %}
48
	           		{% with resources|lookup:t as info %}
49
	           		{% with resource_presentation|lookup:t as resource_info %}
50
	           			<dt>
51
	           				Max {% if resource_info.is_abbreviation %}{{ r.resource|upper }}{% else %}{{ r.resource }}{% endif %}{% if not info.unit %}s {% endif  %}  per user
52
	           			</dt>
53
	           			
54
	           			<dd>
55
	           			{% if r.uplimit %}
56
	           				 {% if info.unit %}
57
	           				 	{{ r.uplimit|sizeof_fmt }}
58
	           				 {% else %}
59
	           				 	{{ r.uplimit }}
60
	           				 {% endif %}
61
	           			{% else %}
62
	           				Unlimited
63
	           			{% endif %}
64
	           			</dd>
65
	           		{% endwith %}
66
	           		{% endwith %}
67
	           		{% endwith %}
68
	           		{% endwith %}
69
	           	{% endfor %}
70
			 	
71
			 </dl>
72
	         
44
			<h3>RESOURCES:</h3>
45
		 	<dl class="alt-style">	
46
		 		{% for p in policies %}
47
			 		 
48
			 		<dt>
49
           				Max {% if p.is_abbreviation %}{{ p.name|upper }}{% else %}{{ p.name }}{% endif %}{% if not p.unit %}s {% endif  %}  per user
50
           			</dt>
51
			 		<dd>
52
           			{% if p.uplimit %}
53
           				 {% if p.unit %}
54
           				 	{{ p.uplimit|sizeof_fmt }}
55
           				 {% else %}
56
           				 	{{ p.uplimit }}
57
           				 {% endif %}
58
           			{% else %}
59
           				Unlimited
60
           			{% endif %}
61
           			</dd>
62
		 		{% endfor %}
63
		 	</dl>      
73 64
		 </div>
65
		 
74 66
		 <div class="full-dotted">
75 67
		 	 
76 68
		 </div>
69
		
77 70
		 
78 71
		 <div class="form-row submit">
79 72
	   		<input type="submit" value="SUBMIT" class="submit altcol" autocomplete="off">
b/snf-astakos-app/astakos/im/templates/im/astakosgroup_list.html
65 65
        <div class="full-dotted">
66 66
        	<form method="GET" class="minimal" action="#searchResults"> 
67 67
				<div class="form-row">
68
					<select name="sorting" onchange="this.form.submit();" class="dropkicked">
69
					    <option value="">Sort by</option>
68
					<select name="sorting" onchange="this.form.submit();" class="dropkicked" tabindex="1">
69
					    <option value="">Sort by Creation Date</option>
70 70
					    <option value="groupname" {% if sorting == 'groupname' %}selected{% endif %}>Name</option>
71 71
			            <!--option value="kindname" {% if sorting == 'kindname' %}selected{% endif %}>Type</option-->			
72 72
			            <option value="issue_date" {% if sorting == 'issue_date' %}selected{% endif %}>Issue date</option>			
......
193 193
	      	    <div >
194 194
					<form method="GET" class="minimal" action="#allGroups" id="mygroups">
195 195
						<div class="form-row">
196
						    <select name="sorting"  class="dropkicked">
197
							    <option value="">Sort by</option>
198
							    <option value="groupname" {% if sorting == 'groupname' %}selected{% endif %}>Name</option>
196
						    <select name="sorting"  class="dropkicked"  tabindex="1">
197
							    <option value="">Sort by Creation Date</option>
198
							    <option value="groupname" {% if sorting == 'groupname' %}selected{% endif %}>Sort by Name</option>
199 199
					            <!--<option value="kindname" {% if sorting == 'kindname' %}selected{% endif %}>Type</option>-->			
200
					            <option value="issue_date" {% if sorting == 'issue_date' %}selected{% endif %}>Issue date</option>			
201
					            <option value="expiration_date" {% if sorting == 'expiration_date' %}selected{% endif %}>Expiration Date</option>
202
					            <option value="approved_members_num" {% if sorting == 'approved_members_num' %}selected{% endif %}>Participants</option>
203
					            <option value="is_enabled" {% if sorting == 'is_enabled' %}selected{% endif %}>Status</option>
204
					            <option value="moderation_enabled" {% if sorting == 'moderation_enabled' %}selected{% endif %}>Moderation</option>		
200
					            <option value="issue_date" {% if sorting == 'issue_date' %}selected{% endif %}>Sort by Issue date</option>			
201
					            <option value="expiration_date" {% if sorting == 'expiration_date' %}selected{% endif %}>Sort by Expiration Date</option>
202
					            <option value="approved_members_num" {% if sorting == 'approved_members_num' %}selected{% endif %}>Sort by Participants</option>
203
					            <option value="moderation_enabled" {% if sorting == 'moderation_enabled' %}selected{% endif %}>Sort by Moderation</option>		
205 204
							</select>
206 205
						</div>
207 206
					</form>
b/snf-astakos-app/astakos/im/templates/im/resource_list.html
4 4

  
5 5
{% block page.body %}
6 6
<div class="maincol {% block innerpage.class %}{% endblock %}">
7
    <div class="stats clearfix">
7
	<div class="stats clearfix">
8 8
		<ul>
9
			{% for r in data %}
10
			{% with resource_presentation|lookup:r.name as resource_info %}
11
    		<li class="clearfix  {{ r.load_class }} {{ r.name|get_value_after_dot}}">
12
    			<div class="img-wrap">&nbsp;</div>
13
    			<div class="info">
14
    				<h3>{{ resource_info.report_desc }}</h3>
15
    				<p>
16
    					{{ r.ratio|floatformat }}% Used<br>
17
    					You are using 
18
    					{% if r.unit == 'bytes' %}
19
    						{{ r.currValue|sizeof_fmt  }} out of your {{ r.maxValue|sizeof_fmt }}
20
    					{% else %}
21
    						{{ r.currValue }} {{ r.unit }} out of your {{ r.maxValue }} {{ r.unit }}
22
    					{% endif %}
23
    					 
24
    					{% if resource_info.is_abbreviation %}{{ r.name|get_value_after_dot|upper }}{% else %}{{ r.name|get_value_after_dot }}{% endif %}{% if r.maxValue|floatformat:"0" != "1" and not r.unit %}s {% endif  %}
25
    					  
26
    				</p>
27
    			</div>
28
    			<div class="bar">
29
    				<div><span style="width:{{ r.ratio|floatformat }}%;">{{ r.ratio|floatformat }}% &nbsp;&nbsp;</span></div>
30
    			</div>
31
    		</li>
32
    		{% endwith %}
33
    		{% endfor %}
34
    	</ul>
35
    </div>    
9
			{% for rname, rdata in resource_catalog.resources.items %}
10
		 		<li class="clearfix  {{ rdata.load_class }} {{ rdata.verbose_name}}">
11
		 			<div class="img-wrap">&nbsp;</div>
12
		 			<div class="info">
13
						<h3>{{ rdata.report_desc }}</h3>
14
						<p>
15
						{{ rdata.ratio|floatformat }}% Used<br>
16
						You are using 
17
						{% if rdata.unit == 'bytes' %}
18
							{{ rdata.currValue|sizeof_fmt  }} out of your {{ rdata.maxValue|sizeof_fmt }}
19
						{% else %}
20
							{{ rdata.currValue }} {{ rdata.unit }} out of your {{ rdata.maxValue }} {{ rdata.unit }}
21
						{% endif %}		
22
						{% if rdata.is_abbreviation %}{{ rdata.verbose_name|upper }}{% else %}{{ rdata.verbose_name }}{% endif %}{% if rdata.maxValue|floatformat:"0" != "1" and not rdata.unit %}s {% endif  %}
23
						</p>
24
					</div>
25
					<div class="bar">
26
						<div><span style="width:{{ rdata.ratio|floatformat }}%;">{{ rdata.ratio|floatformat }}% &nbsp;&nbsp;</span></div>
27
					</div>
28
		 		</li>
29
		 	{% endfor%}
30
		</ul>
31
			 
32
	</div>    
36 33
</div>
37 34
{% endblock %}
b/snf-astakos-app/astakos/im/views.py
87 87
                                  SendNotificationError)
88 88
from astakos.im.endpoints.qh import timeline_charge
89 89
from astakos.im.settings import (COOKIE_NAME, COOKIE_DOMAIN, LOGOUT_NEXT,
90
                                 LOGGING_LEVEL, PAGINATE_BY)
90
                                 LOGGING_LEVEL, PAGINATE_BY, RESOURCES_PRESENTATION_DATA)
91 91
from astakos.im.tasks import request_billing
92 92
from astakos.im.api.callpoint import AstakosCallpoint
93 93

  
......
667 667
                           context_instance=get_context(request,
668 668
                                                        extra_context))
669 669

  
670

  
671

  
672
resource_presentation = {
673
       'compute': {
674
            'help_text':'group compute help text',
675
            'is_abbreviation':False,
676
            'report_desc':''
677
        },
678
        'storage': {
679
            'help_text':'group storage help text',
680
            'is_abbreviation':False,
681
            'report_desc':''
682
        },
683
        'pithos+.diskspace': {
684
            'help_text':'resource pithos+.diskspace help text',
685
            'is_abbreviation':False,
686
            'report_desc':'Pithos+ Diskspace',
687
            'placeholder':'eg. 10GB'
688
        },
689
        'cyclades.vm': {
690
            'help_text':'resource cyclades.vm help text resource cyclades.vm help text resource cyclades.vm help text resource cyclades.vm help text',
691
            'is_abbreviation':True,
692
            'report_desc':'Virtual Machines',
693
            'placeholder':'eg. 2'
694
        },
695
        'cyclades.disksize': {
696
            'help_text':'resource cyclades.disksize help text',
697
            'is_abbreviation':False,
698
            'report_desc':'Disksize',
699
            'placeholder':'eg. 5GB, 2GB etc'
700
        },
701
        'cyclades.disk': {
702
            'help_text':'resource cyclades.disk help text',
703
            'is_abbreviation':False,
704
            'report_desc':'Disk',
705
            'placeholder':'eg. 5GB, 2GB etc'
706
        },
707
        'cyclades.ram': {
708
            'help_text':'resource cyclades.ram help text',
709
            'is_abbreviation':True,
710
            'report_desc':'RAM',
711
            'placeholder':'eg. 4GB'
712
        },
713
        'cyclades.cpu': {
714
            'help_text':'resource cyclades.cpu help text',
715
            'is_abbreviation':True,
716
            'report_desc':'CPUs',
717
            'placeholder':'eg. 1'
718
        },
719
        'cyclades.network.private': {
720
            'help_text':'resource cyclades.network.private help text',
721
            'is_abbreviation':False,
722
            'report_desc':'Network',
723
            'placeholder':'eg. 1'
724
        }
725
    }
670
class ResourcePresentation():
671
    
672
    def __init__(self, data):
673
        self.data = data
674
        
675
    def update_from_result(self, result):
676
        if result.is_success:
677
            for r in result.data:
678
                rname = '%s%s%s' % (r.get('service'), RESOURCE_SEPARATOR, r.get('name'))
679
                if not rname in self.data['resources']:
680
                    self.data['resources'][rname] = {}
681
                    
682
                self.data['resources'][rname].update(r)
683
                self.data['resources'][rname]['id'] = rname
684
                group = r.get('group')
685
                if not group in self.data['groups']:
686
                    self.data['groups'][group] = {}
687
                    
688
                self.data['groups'][r.get('group')].update({'name': r.get('group')})
689
    
690
    def test(self, quota_dict):
691
        for k, v in quota_dict.iteritems():
692
            rname = k
693
            value = v
694
            if not rname in self.data['resources']:
695
                    self.data['resources'][rname] = {}
696
                    
697
 
698
            self.data['resources'][rname]['value'] = value
699
            
700
    
701
    def update_from_result_report(self, result):
702
        if result.is_success:
703
            for r in result.data:
704
                rname = r.get('name')
705
                if not rname in self.data['resources']:
706
                    self.data['resources'][rname] = {}
707
                    
708
                self.data['resources'][rname].update(r)
709
                self.data['resources'][rname]['id'] = rname
710
                group = r.get('group')
711
                if not group in self.data['groups']:
712
                    self.data['groups'][group] = {}
713
                    
714
                self.data['groups'][r.get('group')].update({'name': r.get('group')})
715
                
716
    def get_group_resources(self, group):
717
        return dict(filter(lambda t: t[1].get('group') == group, self.data['resources'].iteritems()))
718
    
719
    def get_groups_resources(self):
720
        for g in self.data['groups']:
721
            yield g, self.get_group_resources(g)
722
    
723
    def get_quota(self, group_quotas):
724
        print '!!!!!', group_quotas
725
        for r, v in group_quotas.iteritems():
726
            rname = str(r)
727
            quota = self.data['resources'].get(rname)
728
            quota['value'] = v
729
            yield quota
730
    
731
    
732
    def get_policies(self, policies_data):
733
        for policy in policies_data:
734
            rname = '%s%s%s' % (policy.get('service'), RESOURCE_SEPARATOR, policy.get('resource'))
735
            policy.update(self.data['resources'].get(rname))
736
            yield policy
737
        
738
    def __repr__(self):
739
        return self.data.__repr__()
740
                
741
    def __iter__(self, *args, **kwargs):
742
        return self.data.__iter__(*args, **kwargs)
743
    
744
    def __getitem__(self, *args, **kwargs):
745
        return self.data.__getitem__(*args, **kwargs)
746
    
747
    def get(self, *args, **kwargs):
748
        return self.data.get(*args, **kwargs)
749
        
750
        
726 751

  
727 752
@require_http_methods(["GET", "POST"])
728 753
@signed_terms_required
729 754
@login_required
730 755
def group_add(request, kind_name='default'):
756
    
731 757
    result = callpoint.list_resources()
732
    print '###', result
733
    resource_catalog = {'resources':defaultdict(defaultdict),
734
                        'groups':defaultdict(list)}
735
    if result.is_success:
736
        for r in result.data:
737
            service = r.get('service', '')
738
            name = r.get('name', '')
739
            group = r.get('group', '')
740
            unit = r.get('unit', '')
741
            fullname = '%s%s%s' % (service, RESOURCE_SEPARATOR, name)
742
            resource_catalog['resources'][fullname] = dict(unit=unit)
743
            resource_catalog['groups'][group].append(fullname)
744
        
745
        resource_catalog = dict(resource_catalog)
746
        for k, v in resource_catalog.iteritems():
747
            resource_catalog[k] = dict(v)
748
    else:
758
    resource_catalog = ResourcePresentation(RESOURCES_PRESENTATION_DATA)
759
    resource_catalog.update_from_result(result)
760
    
761
    if not result.is_success:
749 762
        messages.error(
750 763
            request,
751 764
            'Unable to retrieve system resources: %s' % result.reason
......
765 778
        form_class=AstakosGroupCreationForm
766 779
    )
767 780
    
768
    resources = resource_catalog['resources']
769
    
770
 
771 781
    if request.method == 'POST':
772 782
        form = form_class(request.POST, request.FILES)
773 783
        if form.is_valid():
784
            print '!!!!!!!!!! CLEANED DATA', form.cleaned_data
774 785
            return render_response(
775 786
                template='im/astakosgroup_form_summary.html',
776 787
                context_instance=get_context(request),
777 788
                form = AstakosGroupCreationSummaryForm(form.cleaned_data),
778
                policies = form.policies(),
779
                resource_presentation=resource_presentation,
789
                policies = resource_catalog.get_policies(form.policies()),
780 790
                resource_catalog= resource_catalog,
781
                resources = resources,
782
            
783 791
            )
792
         
784 793
    else:
785 794
        now = datetime.now()
786 795
        data = {
787 796
            'kind': kind,
788 797
        }
789
        for group, resources in resource_catalog['groups'].iteritems():
798
        for group, resources in resource_catalog.get_groups_resources():
790 799
            data['is_selected_%s' % group] = False
791 800
            for resource in resources:
792 801
                data['%s_uplimit' % resource] = ''
......
803 812
        'form': form,
804 813
        'kind': kind,
805 814
        'resource_catalog':resource_catalog,
806
        'resource_presentation':resource_presentation,
807 815
    }, context_processors)
808 816
    return HttpResponse(t.render(c))
809 817

  
......
840 848
            post_save_redirect = '/im/group/%(id)s/'
841 849
            return HttpResponseRedirect(post_save_redirect % new_object)
842 850
        else:
843
            msg = _(astakos_messages.OBJECT_CREATED_FAILED) %\
844
                {"verbose_name": model._meta.verbose_name,
851
            d = {"verbose_name": model._meta.verbose_name,
845 852
                 "reason":result.reason}
853
            msg = _(astakos_messages.OBJECT_CREATED_FAILED) % d 
846 854
            messages.error(request, msg, fail_silently=True)
847 855
    return render_response(
848 856
        template='im/astakosgroup_form_summary.html',
......
857 865
def group_list(request):
858 866
    none = request.user.astakos_groups.none()
859 867
    sorting = request.GET.get('sorting')
860
    q = AstakosGroup.objects.raw("""
868
    query = """
861 869
        SELECT auth_group.id,
862 870
        %s AS groupname,
863 871
        im_groupkind.name AS kindname,
......
880 888
            im_astakosuser_owner.astakosgroup_id = im_astakosgroup.group_ptr_id)
881 889
        LEFT JOIN auth_user as owner ON (
882 890
            im_astakosuser_owner.astakosuser_id = owner.id)
883
        WHERE im_membership.person_id = %s
884
        """ % (DB_REPLACE_GROUP_SCHEME, request.user.id, request.user.id))
891
        WHERE im_membership.person_id = %s 
892
        """ % (DB_REPLACE_GROUP_SCHEME, request.user.id, request.user.id)
893
       
894
    if sorting:
895
        query = query+" ORDER BY %s ASC" %sorting    
896
    else:
897
        query = query+" ORDER BY creation_date DESC"     
898
    q = AstakosGroup.objects.raw(query)
885 899

  
886
            
900
       
901
       
887 902
    # Create the template, context, response
888 903
    template_name = "%s/%s_list.html" % (
889 904
        q.model._meta.app_label,
......
965 980
        form = MembersSortForm({'sort_by': sorting})
966 981
        if form.is_valid():
967 982
            sorting = form.cleaned_data.get('sort_by')
968

  
983
    
984
 
985
    
969 986
    result = callpoint.list_resources()
970
    resource_catalog = {'resources':defaultdict(defaultdict),
971
                        'groups':defaultdict(list)}
972
    if result.is_success:
973
        for r in result.data:
974
            service = r.get('service', '')
975
            name = r.get('name', '')
976
            group = r.get('group', '')
977
            unit = r.get('unit', '')
978
            fullname = '%s%s%s' % (service, RESOURCE_SEPARATOR, name)
979
            resource_catalog['resources'][fullname] = dict(unit=unit, name=name)
980
            resource_catalog['groups'][group].append(fullname)
981
        
982
        resource_catalog = dict(resource_catalog)
983
        for k, v in resource_catalog.iteritems():
984
            resource_catalog[k] = dict(v)
987
    resource_catalog = ResourcePresentation(RESOURCES_PRESENTATION_DATA)
988
    resource_catalog.update_from_result(result)
989

  
990
    
991
    if not result.is_success:
992
        messages.error(
993
            request,
994
            'Unable to retrieve system resources: %s' % result.reason
995
    )
985 996
    
986
    print '####', resource_catalog, obj.quota
997
    print '######', obj.quota
998
   
987 999
    extra_context = {'update_form': update_form,
988 1000
                     'addmembers_form': addmembers_form,
989 1001
                     'page': request.GET.get('page', 1),
990 1002
                     'sorting': sorting,
991 1003
                     'resource_catalog':resource_catalog,
992
                     'resource_presentation':resource_presentation,}
1004
                     'quota':resource_catalog.get_quota(obj.quota)}
993 1005
    for key, value in extra_context.items():
994 1006
        if callable(value):
995 1007
            c[key] = value()
......
1005 1017
@signed_terms_required
1006 1018
@login_required
1007 1019
def group_search(request, extra_context=None, **kwargs):
1008
    print '###', request
1009 1020
    q = request.GET.get('q')
1010 1021
    sorting = request.GET.get('sorting')
1011 1022
    if request.method == 'GET':
......
1050 1061
        if sorting:
1051 1062
            # TODO check sorting value
1052 1063
            queryset = queryset.order_by(sorting)
1064

  
1053 1065
    else:
1054 1066
        queryset = AstakosGroup.objects.none()
1055 1067
    return object_list(
......
1251 1263
    else:
1252 1264
        data = None
1253 1265
        messages.error(request, result.reason)
1266
    resource_catalog = ResourcePresentation(RESOURCES_PRESENTATION_DATA)
1267
    resource_catalog.update_from_result_report(result)
1268
    
1269

  
1270
    
1254 1271
    return render_response('im/resource_list.html',
1255 1272
                           data=data,
1256
                           resource_presentation=resource_presentation,
1257
                           context_instance=get_context(request))
1273
                           context_instance=get_context(request),
1274
			               resource_catalog=resource_catalog,
1275
                           result=result)
1258 1276

  
1259 1277

  
1260 1278
def group_create_list(request):

Also available in: Unified diff