Merge pull request #85 from open-cloud/service_permissions
Service permissions
diff --git a/xos/core/admin.py b/xos/core/admin.py
index 1ded815..fa9ca55 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -503,6 +503,24 @@
def queryset(self, request):
return SitePrivilege.select_by_user(request.user)
+
+class ServicePrivilegeInline(XOSTabularInline):
+ model = ServicePrivilege
+ extra = 0
+ suit_classes = 'suit-tab suit-tab-serviceprivileges'
+ fields = ['backend_status_icon', 'user','service', 'role']
+ readonly_fields = ('backend_status_icon', )
+
+ def formfield_for_foreignkey(self, db_field, request, **kwargs):
+ if db_field.name == 'service':
+ kwargs['queryset'] = Service.select_by_user(request.user)
+ if db_field.name == 'user':
+ kwargs['queryset'] = User.select_by_user(request.user)
+ return super(ServicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+ def queryset(self, request):
+ return ServicePrivilege.select_by_user(request.user)
+
class SiteDeploymentInline(XOSTabularInline):
model = SiteDeployment
extra = 0
@@ -783,7 +801,7 @@
list_display_links = ('backend_status_icon', 'name', )
fieldList = ["backend_status_text","name","kind","description","versionNumber","enabled","published","view_url","icon_url","public_key"]
fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']})]
- inlines = [ServiceAttrAsTabInline,SliceInline,ProviderTenantInline,SubscriberTenantInline]
+ inlines = [ServiceAttrAsTabInline,SliceInline,ProviderTenantInline,SubscriberTenantInline,ServicePrivilegeInline]
readonly_fields = ('backend_status_text', )
user_readonly_fields = fieldList
@@ -792,6 +810,7 @@
('slices','Slices'),
('serviceattrs','Additional Attributes'),
('servicetenants','Tenancy'),
+ ('serviceprivileges','Privileges')
)
class SiteNodeInline(XOSTabularInline):
diff --git a/xos/core/models/__init__.py b/xos/core/models/__init__.py
index 81bf4cc..b13e449 100644
--- a/xos/core/models/__init__.py
+++ b/xos/core/models/__init__.py
@@ -1,7 +1,7 @@
from .plcorebase import PlCoreBase,PlCoreBaseManager,PlCoreBaseDeletionManager,PlModelMixIn
from .project import Project
from .singletonmodel import SingletonModel
-from .service import Service, Tenant, CoarseTenant
+from .service import Service, Tenant, CoarseTenant, ServicePrivilege
from .service import ServiceAttribute
from .tag import Tag
from .role import Role
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index 8a10f37..d2cc302 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -29,6 +29,9 @@
def __unicode__(self): return u'%s' % (self.name)
+ def can_update(self, user):
+ return user.can_update_service(self, allow=['admin'])
+
def get_scalable_nodes(self, slice, max_per_node=None, exclusive_slices=[]):
"""
Get a list of nodes that can be used to scale up a slice.
@@ -107,6 +110,45 @@
value = StrippedCharField(help_text="Attribute Value", max_length=1024)
service = models.ForeignKey(Service, related_name='serviceattributes', help_text="The Service this attribute is associated with")
+class ServiceRole(PlCoreBase):
+ ROLE_CHOICES = (('admin','Admin'),)
+ role = StrippedCharField(choices=ROLE_CHOICES, unique=True, max_length=30)
+
+ def __unicode__(self): return u'%s' % (self.role)
+
+class ServicePrivilege(PlCoreBase):
+ user = models.ForeignKey('User', related_name='serviceprivileges')
+ service = models.ForeignKey('Service', related_name='serviceprivileges')
+ role = models.ForeignKey('ServiceRole',related_name='serviceprivileges')
+
+ class Meta:
+ unique_together = ('user', 'service', 'role')
+
+ def __unicode__(self): return u'%s %s %s' % (self.service, self.user, self.role)
+
+ def can_update(self, user):
+ if not self.service.enabled:
+ raise PermissionDenied, "Cannot modify permission(s) of a disabled service"
+ return self.service.can_update(user)
+
+ def save(self, *args, **kwds):
+ if not self.service.enabled:
+ raise PermissionDenied, "Cannot modify permission(s) of a disabled service"
+ super(ServicePrivilege, self).save(*args, **kwds)
+
+ def delete(self, *args, **kwds):
+ if not self.service.enabled:
+ raise PermissionDenied, "Cannot modify permission(s) of a disabled service"
+ super(ServicePrivilege, self).delete(*args, **kwds)
+
+ @staticmethod
+ def select_by_user(user):
+ if user.is_admin:
+ qs = ServicePrivilege.objects.all()
+ else:
+ qs = SitePrivilege.objects.filter(user=user)
+ return qs
+
class Tenant(PlCoreBase):
""" A tenant is a relationship between two entities, a subscriber and a
provider.
diff --git a/xos/core/models/user.py b/xos/core/models/user.py
index e34abdb..e62d6db 100644
--- a/xos/core/models/user.py
+++ b/xos/core/models/user.py
@@ -314,6 +314,15 @@
return True
return False
+ def can_update_service(self, service, allow=[]):
+ from core.models.service import ServicePrivilege
+ if self.can_update_root():
+ return True
+ if ServicePrivilege.objects.filter(
+ service=service, user=self, role__role__in=['admin', 'Admin']+allow):
+ return True
+ return False
+
@staticmethod
def select_by_user(user):
if user.is_admin: