Revision 2dc27ac1

b/snf-astakos-app/astakos/api/services.py
48 48
                'name': "astakos.pending_app",
49 49
                'service_type': "account",
50 50
                'service_origin': "astakos_account",
51
                'allow_in_projects': False},
51
                'ui_visible': False,
52
                'api_visible': False},
52 53
        },
53 54
    },
54 55

  
b/snf-astakos-app/astakos/im/forms.py
886 886
                # keep only resource limits for selected resource groups
887 887
                if self.data.get('is_selected_%s' %
888 888
                                 resource.group, "0") == "1":
889
                    if not resource.allow_in_projects:
889
                    if not resource.ui_visible:
890 890
                        raise forms.ValidationError("Invalid resource %s" %
891 891
                                                    resource.name)
892 892
                    d = model_to_dict(resource)
b/snf-astakos-app/astakos/im/management/commands/resource-list.py
55 55
        "service origin": ("service_origin", "Service"),
56 56
        "default_quota": ("limit_with_unit", "Default Quota"),
57 57
        "description": ("desc", "Description"),
58
        "allow_in_projects": ("allow_in_projects",
59
                              "Make resource available in projects"),
58
        "api_visible": ("api_visible",
59
                        "Resource accessibility through the API"),
60
        "ui_visible": ("ui_visible",
61
                       "Resource accessibility through the UI"),
60 62
    }
61 63

  
62
    fields = ["id", "name", "service origin", "default_quota",
63
              "description"]
64
    fields = ["id", "name", "default_quota", "api_visible", "ui_visible"]
64 65

  
65 66
    def show_limit(self, resource):
66 67
        limit = resource.uplimit
b/snf-astakos-app/astakos/im/management/commands/resource-modify.py
64 64
                    default='mb',
65 65
                    help=("Specify display unit for resource values "
66 66
                          "(one of %s); defaults to mb") % style_options),
67
        make_option('--allow-in-projects',
67
        make_option('--api-visible',
68 68
                    metavar='True|False',
69
                    help=("Specify whether to allow this resource "
70
                          "in projects.")),
69
                    help="Control visibility of this resource in the API"),
70
        make_option('--ui-visible',
71
                    metavar='True|False',
72
                    help="Control visibility of this resource in the UI"),
71 73
    )
72 74

  
73 75
    def handle(self, *args, **options):
......
77 79
            'default_quota': self.change_limit,
78 80
            'default_quota_interactive': self.change_interactive,
79 81
            'default_quota_from_file': self.change_from_file,
80
            'allow_in_projects': self.set_allow_in_projects,
82
            'api_visible': self.set_api_visible,
83
            'ui_visible': self.set_ui_visible,
81 84
        }
82 85

  
83 86
        opts = [(key, value)
......
88 91
            raise CommandError("Please provide exactly one of the options: "
89 92
                               "--default-quota, --default-quota-interactive, "
90 93
                               "--default-quota-from-file, "
91
                               "--allow-in-projects.")
94
                               "--api-visible, --ui-visible.")
92 95

  
93 96
        self.unit_style = options['unit_style']
94 97
        check_style(self.unit_style)
......
97 100
        action = actions[key]
98 101
        action(resource_name, value)
99 102

  
100
    def set_allow_in_projects(self, resource_name, allow):
103
    def set_api_visible(self, resource_name, allow):
104
        if resource_name is None:
105
            raise CommandError("Please provide a resource name.")
106

  
107
        try:
108
            allow = utils.parse_bool(allow)
109
        except ValueError:
110
            raise CommandError("Expecting a boolean value.")
111
        resource = self.get_resource(resource_name)
112
        resource.api_visible = allow
113
        if not allow and resource.ui_visible:
114
            self.stdout.write("Also resetting 'ui_visible' for consistency.\n")
115
            resource.ui_visible = False
116
        resource.save()
117

  
118
    def set_ui_visible(self, resource_name, allow):
101 119
        if resource_name is None:
102 120
            raise CommandError("Please provide a resource name.")
103 121

  
......
106 124
        except ValueError:
107 125
            raise CommandError("Expecting a boolean value.")
108 126
        resource = self.get_resource(resource_name)
109
        resource.allow_in_projects = allow
127

  
128
        resource.ui_visible = allow
129
        if allow and not resource.api_visible:
130
            self.stdout.write("Also setting 'api_visible' for consistency.\n")
131
            resource.api_visible = True
110 132
        resource.save()
111 133

  
112 134
    def get_resource(self, resource_name):
b/snf-astakos-app/astakos/im/migrations/0057_auto__del_field_resource_allow_in_projects__add_field_resource_ui_visi.py
1
# -*- coding: utf-8 -*-
2
import datetime
3
from south.db import db
4
from south.v2 import SchemaMigration
5
from django.db import models
6

  
7

  
8
class Migration(SchemaMigration):
9

  
10
    def forwards(self, orm):
11
        db.rename_column('im_resource', 'allow_in_projects', 'ui_visible')
12

  
13
        # Adding field 'Resource.api_visible'
14
        db.add_column('im_resource', 'api_visible',
15
                      self.gf('django.db.models.fields.BooleanField')(default=True),
16
                      keep_default=False)
17

  
18

  
19
    def backwards(self, orm):
20
        db.rename_column('im_resource', 'ui_visible', 'allow_in_projects')
21

  
22
        # Deleting field 'Resource.api_visible'
23
        db.delete_column('im_resource', 'api_visible')
24

  
25

  
26
    models = {
27
        'auth.group': {
28
            'Meta': {'object_name': 'Group'},
29
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
30
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
31
            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
32
        },
33
        'auth.permission': {
34
            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
35
            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
36
            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
37
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
38
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
39
        },
40
        'auth.user': {
41
            'Meta': {'object_name': 'User'},
42
            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
43
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
44
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
45
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
46
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
47
            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
48
            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
49
            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
50
            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
51
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
52
            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
53
            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
54
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
55
        },
56
        'contenttypes.contenttype': {
57
            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
58
            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
59
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
60
            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
61
            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
62
        },
63
        'im.additionalmail': {
64
            'Meta': {'object_name': 'AdditionalMail'},
65
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
66
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
67
            'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
68
        },
69
        'im.approvalterms': {
70
            'Meta': {'object_name': 'ApprovalTerms'},
71
            'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
72
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
73
            'location': ('django.db.models.fields.CharField', [], {'max_length': '255'})
74
        },
75
        'im.astakosuser': {
76
            'Meta': {'object_name': 'AstakosUser', '_ormbases': ['auth.User']},
77
            'accepted_email': ('django.db.models.fields.EmailField', [], {'default': 'None', 'max_length': '75', 'null': 'True', 'blank': 'True'}),
78
            'accepted_policy': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
79
            'activation_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
80
            'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
81
            'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
82
            'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
83
            'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
84
            'date_signed_terms': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
85
            'deactivated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
86
            'deactivated_reason': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True'}),
87
            'disturbed_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
88
            'email_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
89
            'has_credits': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
90
            'has_signed_terms': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
91
            'invitations': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
92
            'is_rejected': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
93
            'is_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
94
            'level': ('django.db.models.fields.IntegerField', [], {'default': '4'}),
95
            'moderated': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
96
            'moderated_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
97
            'moderated_data': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
98
            'policy': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.AstakosUserQuota']", 'symmetrical': 'False'}),
99
            'rejected_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
100
            'updated': ('django.db.models.fields.DateTimeField', [], {}),
101
            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
102
            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True', 'null': 'True'}),
103
            'verification_code': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True', 'null': 'True'}),
104
            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
105
        },
106
        'im.astakosuserauthprovider': {
107
            'Meta': {'ordering': "('module', 'created')", 'unique_together': "(('identifier', 'module', 'user'),)", 'object_name': 'AstakosUserAuthProvider'},
108
            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
109
            'affiliation': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
110
            'auth_backend': ('django.db.models.fields.CharField', [], {'default': "'astakos'", 'max_length': '255'}),
111
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
112
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
113
            'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
114
            'info_data': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
115
            'module': ('django.db.models.fields.CharField', [], {'default': "'local'", 'max_length': '255'}),
116
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_providers'", 'to': "orm['im.AstakosUser']"})
117
        },
118
        'im.astakosuserquota': {
119
            'Meta': {'unique_together': "(('resource', 'user'),)", 'object_name': 'AstakosUserQuota'},
120
            'capacity': ('django.db.models.fields.BigIntegerField', [], {}),
121
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
122
            'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}),
123
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
124
        },
125
        'im.authproviderpolicyprofile': {
126
            'Meta': {'ordering': "['priority']", 'object_name': 'AuthProviderPolicyProfile'},
127
            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
128
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authpolicy_profiles'", 'symmetrical': 'False', 'to': "orm['auth.Group']"}),
129
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
130
            'is_exclusive': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
131
            'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
132
            'policy_add': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
133
            'policy_automoderate': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
134
            'policy_create': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
135
            'policy_limit': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'}),
136
            'policy_login': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
137
            'policy_remove': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
138
            'policy_required': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
139
            'policy_switch': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
140
            'priority': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
141
            'provider': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
142
            'users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authpolicy_profiles'", 'symmetrical': 'False', 'to': "orm['im.AstakosUser']"})
143
        },
144
        'im.chain': {
145
            'Meta': {'object_name': 'Chain'},
146
            'chain': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
147
        },
148
        'im.component': {
149
            'Meta': {'object_name': 'Component'},
150
            'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
151
            'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
152
            'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
153
            'base_url': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'}),
154
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
155
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
156
            'url': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'})
157
        },
158
        'im.emailchange': {
159
            'Meta': {'object_name': 'EmailChange'},
160
            'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
161
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
162
            'new_email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
163
            'requested_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
164
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emailchanges'", 'unique': 'True', 'to': "orm['im.AstakosUser']"})
165
        },
166
        'im.endpoint': {
167
            'Meta': {'object_name': 'Endpoint'},
168
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
169
            'service': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'endpoints'", 'to': "orm['im.Service']"})
170
        },
171
        'im.endpointdata': {
172
            'Meta': {'unique_together': "(('endpoint', 'key'),)", 'object_name': 'EndpointData'},
173
            'endpoint': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'data'", 'to': "orm['im.Endpoint']"}),
174
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
175
            'key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
176
            'value': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
177
        },
178
        'im.invitation': {
179
            'Meta': {'object_name': 'Invitation'},
180
            'code': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
181
            'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
182
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
183
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
184
            'inviter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invitations_sent'", 'null': 'True', 'to': "orm['im.AstakosUser']"}),
185
            'is_consumed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
186
            'realname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
187
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
188
        },
189
        'im.pendingthirdpartyuser': {
190
            'Meta': {'unique_together': "(('provider', 'third_party_identifier'),)", 'object_name': 'PendingThirdPartyUser'},
191
            'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
192
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
193
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
194
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
195
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
196
            'info': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
197
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
198
            'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
199
            'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
200
            'token': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
201
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
202
        },
203
        'im.project': {
204
            'Meta': {'object_name': 'Project'},
205
            'application': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'project'", 'unique': 'True', 'to': "orm['im.ProjectApplication']"}),
206
            'creation_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
207
            'id': ('django.db.models.fields.BigIntegerField', [], {'primary_key': 'True', 'db_column': "'id'"}),
208
            'members': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.AstakosUser']", 'through': "orm['im.ProjectMembership']", 'symmetrical': 'False'}),
209
            'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'unique': 'True', 'null': 'True', 'db_index': 'True'}),
210
            'state': ('django.db.models.fields.IntegerField', [], {'default': '1', 'db_index': 'True'})
211
        },
212
        'im.projectapplication': {
213
            'Meta': {'unique_together': "(('chain', 'id'),)", 'object_name': 'ProjectApplication'},
214
            'applicant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projects_applied'", 'to': "orm['im.AstakosUser']"}),
215
            'chain': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'chained_apps'", 'db_column': "'chain'", 'to': "orm['im.Project']"}),
216
            'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
217
            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
218
            'end_date': ('django.db.models.fields.DateTimeField', [], {}),
219
            'homepage': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True'}),
220
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
221
            'issue_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
222
            'limit_on_members_number': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
223
            'member_join_policy': ('django.db.models.fields.IntegerField', [], {}),
224
            'member_leave_policy': ('django.db.models.fields.IntegerField', [], {}),
225
            'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
226
            'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projects_owned'", 'to': "orm['im.AstakosUser']"}),
227
            'resource_grants': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.ProjectResourceGrant']", 'blank': 'True'}),
228
            'response': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
229
            'response_actor': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'responded_apps'", 'null': 'True', 'to': "orm['im.AstakosUser']"}),
230
            'response_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
231
            'start_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
232
            'state': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_index': 'True'}),
233
            'waive_actor': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'waived_apps'", 'null': 'True', 'to': "orm['im.AstakosUser']"}),
234
            'waive_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
235
            'waive_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
236
        },
237
        'im.projectlock': {
238
            'Meta': {'object_name': 'ProjectLock'},
239
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
240
        },
241
        'im.projectlog': {
242
            'Meta': {'object_name': 'ProjectLog'},
243
            'actor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']", 'null': 'True'}),
244
            'comments': ('django.db.models.fields.TextField', [], {'null': 'True'}),
245
            'date': ('django.db.models.fields.DateTimeField', [], {}),
246
            'from_state': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
247
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
248
            'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'log'", 'to': "orm['im.Project']"}),
249
            'reason': ('django.db.models.fields.TextField', [], {'null': 'True'}),
250
            'to_state': ('django.db.models.fields.IntegerField', [], {})
251
        },
252
        'im.projectmembership': {
253
            'Meta': {'unique_together': "(('person', 'project'),)", 'object_name': 'ProjectMembership'},
254
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
255
            'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"}),
256
            'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Project']"}),
257
            'state': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_index': 'True'})
258
        },
259
        'im.projectmembershiplog': {
260
            'Meta': {'object_name': 'ProjectMembershipLog'},
261
            'actor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']", 'null': 'True'}),
262
            'comments': ('django.db.models.fields.TextField', [], {'null': 'True'}),
263
            'date': ('django.db.models.fields.DateTimeField', [], {}),
264
            'from_state': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
265
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
266
            'membership': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'log'", 'to': "orm['im.ProjectMembership']"}),
267
            'reason': ('django.db.models.fields.TextField', [], {'null': 'True'}),
268
            'to_state': ('django.db.models.fields.IntegerField', [], {})
269
        },
270
        'im.projectresourcegrant': {
271
            'Meta': {'unique_together': "(('resource', 'project_application'),)", 'object_name': 'ProjectResourceGrant'},
272
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
273
            'member_capacity': ('django.db.models.fields.BigIntegerField', [], {'default': '0'}),
274
            'project_application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.ProjectApplication']", 'null': 'True'}),
275
            'project_capacity': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}),
276
            'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"})
277
        },
278
        'im.resource': {
279
            'Meta': {'object_name': 'Resource'},
280
            'api_visible': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
281
            'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
282
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
283
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
284
            'service_origin': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
285
            'service_type': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
286
            'ui_visible': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
287
            'unit': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
288
            'uplimit': ('django.db.models.fields.BigIntegerField', [], {'default': '0'})
289
        },
290
        'im.service': {
291
            'Meta': {'object_name': 'Service'},
292
            'component': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Component']"}),
293
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
294
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
295
            'type': ('django.db.models.fields.CharField', [], {'max_length': '255'})
296
        },
297
        'im.sessioncatalog': {
298
            'Meta': {'object_name': 'SessionCatalog'},
299
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
300
            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
301
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sessions'", 'null': 'True', 'to': "orm['im.AstakosUser']"})
302
        },
303
        'im.usersetting': {
304
            'Meta': {'unique_together': "(('user', 'setting'),)", 'object_name': 'UserSetting'},
305
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
306
            'setting': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
307
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"}),
308
            'value': ('django.db.models.fields.IntegerField', [], {})
309
        }
310
    }
311

  
312
    complete_apps = ['im']
b/snf-astakos-app/astakos/im/models.py
233 233
    service_origin = models.CharField(max_length=255, db_index=True)
234 234
    unit = models.CharField(_('Unit'), null=True, max_length=255)
235 235
    uplimit = models.BigIntegerField(default=0)
236
    allow_in_projects = models.BooleanField(default=True)
236
    ui_visible = models.BooleanField(default=True)
237
    api_visible = models.BooleanField(default=True)
237 238

  
238 239
    def __str__(self):
239 240
        return self.name
......
245 246
        return {'service': self.service_origin,
246 247
                'description': self.desc,
247 248
                'unit': self.unit,
248
                'allow_in_projects': self.allow_in_projects,
249
                'ui_visible': self.ui_visible,
250
                'api_visible': self.api_visible,
249 251
                }
250 252

  
251 253
    @property
b/snf-astakos-app/astakos/im/presentation.py
195 195
                        'cyclades.floating_ip',
196 196
                        'astakos.pending_app'
197 197
                        ],
198
    'exclude_from_usage': ['astakos.pending_app']
199 198
}
200 199

  
201 200
# extend from settings
b/snf-astakos-app/astakos/im/register.py
38 38

  
39 39
logger = logging.getLogger(__name__)
40 40

  
41
resource_fields = ['desc', 'unit', 'allow_in_projects']
41
resource_fields = ['desc', 'unit', 'ui_visible', 'api_visible']
42 42

  
43 43

  
44 44
class RegisterException(Exception):
......
93 93
        if value is not None:
94 94
            setattr(r, field, value)
95 95

  
96
    if r.ui_visible and not r.api_visible:
97
        m = "Flag 'ui_visible' should entail 'api_visible'."
98
        raise RegisterException(m)
99

  
96 100
    r.save()
97 101
    if not exists:
98 102
        quotas.qh_sync_new_resource(r)
b/snf-astakos-app/astakos/im/tests/api.py
62 62
                      "desc": "resource11 desc",
63 63
                      "service_type": "type1",
64 64
                      "service_origin": "service1",
65
                      "allow_in_projects": True}
65
                      "ui_visible": True}
66 66
        r, _ = register.add_resource(resource11)
67 67
        register.update_resources([(r, 100)])
68 68
        resource12 = {"name": "service1.resource12",
......
89 89
                      "desc": "resource11 desc",
90 90
                      "service_type": "type2",
91 91
                      "service_origin": "service2",
92
                      "allow_in_projects": False}
92
                      "ui_visible": False}
93 93
        r, _ = register.add_resource(resource21)
94 94
        register.update_resources([(r, 3)])
95 95

  
b/snf-astakos-app/astakos/im/tests/projects.py
46 46
                      "desc": "resource11 desc",
47 47
                      "service_type": "type1",
48 48
                      "service_origin": "service1",
49
                      "allow_in_projects": True}
49
                      "ui_visible": True}
50 50
        r, _ = register.add_resource(resource11)
51 51
        register.update_resources([(r, 100)])
52 52
        resource12 = {"name": "service1.resource12",
......
74 74
                       "desc": "pend app desc",
75 75
                       "service_type": "account",
76 76
                       "service_origin": "astakos_account",
77
                       "allow_in_projects": False}
77
                       "ui_visible": False,
78
                       "api_visible": False}
78 79
        r, _ = register.add_resource(pending_app)
79 80
        register.update_resources([(r, 3)])
80 81

  
......
598 599
        # astakos resources
599 600
        self.resource = Resource.objects.create(name="astakos.pending_app",
600 601
                                                uplimit=0,
601
                                                allow_in_projects=False,
602
                                                ui_visible=False,
603
                                                api_visible=False,
602 604
                                                service_type="astakos")
603 605

  
604 606
        # custom service resources
......
638 640
        self.assertRedirects(r, reverse('project_add'))
639 641

  
640 642
    @im_settings(PROJECT_ADMINS=['uuid1'])
641
    def test_allow_in_project(self):
643
    def test_ui_visible(self):
642 644
        dfrom = datetime.now()
643 645
        dto = datetime.now() + timedelta(days=30)
644 646

  
645
        # astakos.pending_uplimit allow_in_project flag is False
647
        # astakos.pending_app ui_visible flag is False
646 648
        # we shouldn't be able to create a project application using this
647 649
        # resource.
648 650
        application_data = {
b/snf-astakos-app/astakos/im/views/im.py
826 826

  
827 827
    current_usage = quotas.get_user_quotas(request.user)
828 828
    current_usage = json.dumps(current_usage['system'])
829
    resource_catalog, resource_groups = _resources_catalog(for_usage=True)
829
    resource_catalog, resource_groups = _resources_catalog()
830 830
    if resource_catalog is False:
831 831
        # on fail resource_groups contains the result object
832 832
        result = resource_groups
b/snf-astakos-app/astakos/im/views/projects.py
97 97
                      "end_date", "comments"]
98 98
    membership_fields = ["member_join_policy", "member_leave_policy",
99 99
                         "limit_on_members_number"]
100
    resource_catalog, resource_groups = _resources_catalog(for_project=True)
100
    resource_catalog, resource_groups = _resources_catalog()
101 101
    if resource_catalog is False:
102 102
        # on fail resource_groups contains the result object
103 103
        result = resource_groups
......
235 235
                      "end_date", "comments"]
236 236
    membership_fields = ["member_join_policy", "member_leave_policy",
237 237
                         "limit_on_members_number"]
238
    resource_catalog, resource_groups = _resources_catalog(for_project=True)
238
    resource_catalog, resource_groups = _resources_catalog()
239 239
    if resource_catalog is False:
240 240
        # on fail resource_groups contains the result object
241 241
        result = resource_groups
b/snf-astakos-app/astakos/im/views/util.py
190 190
    return response
191 191

  
192 192

  
193
def _resources_catalog(for_project=False, for_usage=False):
193
def _resources_catalog():
194 194
    """
195 195
    `resource_catalog` contains a list of tuples. Each tuple contains the group
196 196
    key the resource is assigned to and resources list of dicts that contain
......
252 252
                    resource_groups.pop(gindex)
253 253

  
254 254
    # filter out resources which user cannot request in a project application
255
    exclude = resources_meta.get('exclude_from_usage', [])
256
    for group_index, group_resources in enumerate(list(resource_catalog)):
257
        group, resources = group_resources
258
        for index, resource in list(enumerate(resources)):
259
            if for_project and not resource.get('allow_in_projects'):
260
                resources.remove(resource)
261
            if resource.get('str_repr') in exclude and for_usage:
255
    for group, resources in list(resource_catalog):
256
        for resource in resources:
257
            if not resource.get('ui_visible'):
262 258
                resources.remove(resource)
263 259

  
264 260
    # cleanup empty groups
b/snf-astakos-app/astakos/scripts/snf_service_export.py
21 21
                'name': "astakos.pending_app",
22 22
                'service_type': "account",
23 23
                'service_origin': "astakos_account",
24
                'allow_in_projects': False},
24
                "ui_visible": False,
25
                "api_visible": False},
25 26
        },
26 27
    },
27 28

  
......
93 94
                "desc": "Number of virtual machine processors",
94 95
                "service_type": "compute",
95 96
                "service_origin": "cyclades_compute",
97
                "ui_visible": False,
98
                "api_visible": False,
96 99
            },
97 100
            'cpu': {
98 101
                "name": "cyclades.cpu",
......
107 110
                "unit": "bytes",
108 111
                "service_type": "compute",
109 112
                "service_origin": "cyclades_compute",
113
                "ui_visible": False,
114
                "api_visible": False,
110 115
            },
111 116
            'ram': {
112 117
                "name": "cyclades.ram",
b/snf-cyclades-app/synnefo/api/services.py
56 56
                "desc": "Number of virtual machine processors",
57 57
                "service_type": "compute",
58 58
                "service_origin": "cyclades_compute",
59
                "ui_visible": False,
60
                "api_visible": False,
59 61
            },
60 62
            'cpu': {
61 63
                "name": "cyclades.cpu",
......
70 72
                "unit": "bytes",
71 73
                "service_type": "compute",
72 74
                "service_origin": "cyclades_compute",
75
                "ui_visible": False,
76
                "api_visible": False,
73 77
            },
74 78
            'ram': {
75 79
                "name": "cyclades.ram",

Also available in: Unified diff