From: Siobhan Tully Date: Tue, 3 Sep 2013 16:59:24 +0000 (-0400) Subject: Django-suit, add in Roles for specific classes site, slice, deployment, planetstack... X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=bfd11dcba19b93cf3cc4c074bf9d71547806d47d;p=plstackapi.git Django-suit, add in Roles for specific classes site, slice, deployment, planetstack, change admin to leverage suit options --- diff --git a/planetstack/core/admin.py b/planetstack/core/admin.py index a1a21d6..730937a 100644 --- a/planetstack/core/admin.py +++ b/planetstack/core/admin.py @@ -12,12 +12,19 @@ from django.contrib.auth.forms import ReadOnlyPasswordHashField from django.contrib.auth.signals import user_logged_in from django.utils import timezone from django.contrib.contenttypes import generic +from suit.widgets import LinkedSelect import django_evolution class PlStackTabularInline(admin.TabularInline): exclude = ['enacted'] +class ReservationInline(PlStackTabularInline): + model = Reservation + extra = 0 + suit_classes = 'suit-tab suit-tab-reservations' + + class ReadonlyTabularInline(PlStackTabularInline): can_delete = False extra = 0 @@ -34,10 +41,27 @@ class ReadonlyTabularInline(PlStackTabularInline): def has_add_permission(self, request): return False +class UserMembershipInline(generic.GenericTabularInline): + model = Member + exclude = ['enacted'] + extra = 1 + suit_classes = 'suit-tab suit-tab-membership' + + def queryset(self, request): + qs = super(UserMembershipInline, self).queryset(request) + return qs.filter(user=request.user) + +class MemberInline(generic.GenericTabularInline): + model = Member + exclude = ['enacted'] + extra = 1 + suit_classes = 'suit-tab suit-tab-members' + class TagInline(generic.GenericTabularInline): model = Tag exclude = ['enacted'] - extra = 1 + extra = 0 + suit_classes = 'suit-tab suit-tab-tags' class SliverInline(PlStackTabularInline): model = Sliver @@ -45,32 +69,51 @@ class SliverInline(PlStackTabularInline): extra = 0 #readonly_fields = ['ip', 'instance_name', 'image'] readonly_fields = ['ip', 'instance_name'] + suit_classes = 'suit-tab suit-tab-slivers' class SiteInline(PlStackTabularInline): model = Site extra = 0 + suit_classes = 'suit-tab suit-tab-sites' class UserInline(PlStackTabularInline): model = User fields = ['email', 'firstname', 'lastname'] extra = 0 + suit_classes = 'suit-tab suit-tab-users' class SliceInline(PlStackTabularInline): model = Slice + fields = ['name','enabled','description','slice_url'] extra = 0 + suit_classes = 'suit-tab suit-tab-slices' + class RoleInline(PlStackTabularInline): model = Role extra = 0 + suit_classes = 'suit-tab suit-tab-roles' class NodeInline(PlStackTabularInline): model = Node extra = 0 + suit_classes = 'suit-tab suit-tab-nodes' + +class SlicePrivilegeInline(PlStackTabularInline): + model = SlicePrivilege + extra = 0 + suit_classes = 'suit-tab suit-tab-sliceprivileges' + +class DeploymentPrivilegeInline(PlStackTabularInline): + model = DeploymentPrivilege + extra = 0 + suit_classes = 'suit-tab suit-tab-deploymentprivileges' class SitePrivilegeInline(PlStackTabularInline): model = SitePrivilege extra = 0 + suit_classes = 'suit-tab suit-tab-siteprivileges' def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == 'site': @@ -94,10 +137,17 @@ class SitePrivilegeInline(PlStackTabularInline): kwargs['queryset'] = users return super(SitePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs) -class SliceMembershipInline(PlStackTabularInline): - model = SliceMembership +class SitePrivilegeInline(PlStackTabularInline): + model = SitePrivilege + suit_classes = 'suit-tab suit-tab-siteprivileges' + extra = 0 + fields = ('user', 'site','role') + +class SlicePrivilegeInline(PlStackTabularInline): + model = SlicePrivilege + suit_classes = 'suit-tab suit-tab-sliceprivileges' extra = 0 - fields = ('user', 'role') + fields = ('user', 'slice','role') def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == 'slice': @@ -119,7 +169,7 @@ class SliceMembershipInline(PlStackTabularInline): users = User.objects.filter(email__in=emails) kwargs['queryset'] = list(users) - return super(SliceMembershipInline, self).formfield_for_foreignkey(db_field, request, **kwargs) + return super(SlicePrivilegeInline, self).formfield_for_foreignkey(db_field, request, **kwargs) class SliceTagInline(PlStackTabularInline): model = SliceTag @@ -137,11 +187,38 @@ class PlanetStackBaseAdmin(admin.ModelAdmin): save_on_top = False exclude = ['enacted'] +#class RoleMemberForm(forms.ModelForm): +# request=None +# member=forms.ModelChoiceField(queryset=Member.objects.all()) #first get all +# +# def __init__(self,fata=None,files=None,auto_id='id_%s',prefix=None,initial=None,error_class=ErrorList,label_suffix=':',empty_permitted=False,instance=None): +# super(RoleMemberForm,self).__init__data,files,auto_id,prefix,initial,error_class,label_suffix,empty_permitted,instance) +# +# self.fields["member"].queryset = member.objects.filter( + +class RoleMemberInline (admin.StackedInline): + model = Member +# form = RoleMemberForm + + def get_formset(self,request,obj=None, **kwargs): + self.form.request=request + return super(RoleMemberInline, self).get_formset(request, obj, **kwargs) + +class SliceRoleAdmin(PlanetStackBaseAdmin): + model = SliceRole + pass + +class SiteRoleAdmin(PlanetStackBaseAdmin): + model = SiteRole + pass + class RoleAdmin(PlanetStackBaseAdmin): fieldsets = [ - ('Role', {'fields': ['role_type']}) + ('Role', {'fields': ['role_type', 'description','content_type'], + 'classes':['collapse']}) ] - list_display = ('role_type',) + inlines = [ MemberInline,] + list_display = ('role_type','description','content_type') class DeploymentAdminForm(forms.ModelForm): @@ -155,47 +232,30 @@ class DeploymentAdminForm(forms.ModelForm): class Meta: model = Deployment - def __init__(self, *args, **kwargs): - super(DeploymentAdminForm, self).__init__(*args, **kwargs) - - if self.instance and self.instance.pk: - self.fields['sites'].initial = self.instance.sites.all() - - def save(self, commit=True): - deploymentNetwork = super(DeploymentAdminForm, self).save(commit=False) - if commit: - deploymentNetwork.save() - - if deploymentNetwork.pk: - deploymentNetwork.sites = self.cleaned_data['sites'] - self.save_m2m() - - return deploymentNetwork class DeploymentAdmin(PlanetStackBaseAdmin): form = DeploymentAdminForm - inlines = [NodeInline,SliverInline] - - def get_formsets(self, request, obj=None): - for inline in self.get_inline_instances(request, obj): - # hide MyInline in the add view - if obj is None: - continue - # give inline object access to driver and caller - auth = request.session.get('auth', {}) - if request.user.site: - auth['tenant'] = request.user.site.login_base - inline.model.os_manager = OpenStackManager(auth=auth, caller=request.user) - yield inline.get_formset(request, obj) + inlines = [MemberInline,NodeInline,SliverInline,TagInline] + fieldsets = [ + (None, {'fields': ['sites'], 'classes':['suit-tab suit-tab-sites']}),] + suit_form_tabs =(('sites', 'Sites'),('nodes','Nodes'),('members','Members'),('tags','Tags')) class SiteAdmin(PlanetStackBaseAdmin): fieldsets = [ - (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'location']}), - ('Deployment Networks', {'fields': ['deployments']}) + (None, {'fields': ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'location'], 'classes':['suit-tab suit-tab-general']}), + ('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}), ] + suit_form_tabs =(('general', 'Site Details'), + ('users','Users'), + ('members','Privileges'), + ('deployments','Deployments'), + ('slices','Slices'), + ('nodes','Nodes'), + ('tags','Tags'), + ) list_display = ('name', 'login_base','site_url', 'enabled') filter_horizontal = ('deployments',) - inlines = [TagInline, NodeInline, UserInline, SitePrivilegeInline] + inlines = [SliceInline,UserInline,TagInline, NodeInline, MemberInline] search_fields = ['name'] def queryset(self, request): @@ -229,7 +289,7 @@ class SiteAdmin(PlanetStackBaseAdmin): class SitePrivilegeAdmin(PlanetStackBaseAdmin): fieldsets = [ - (None, {'fields': ['user', 'site', 'role']}) + (None, {'fields': ['user', 'site', 'role'], 'classes':['collapse']}) ] list_display = ('user', 'site', 'role') @@ -269,9 +329,17 @@ class SitePrivilegeAdmin(PlanetStackBaseAdmin): return qs class SliceAdmin(PlanetStackBaseAdmin): - fields = ['name', 'site', 'serviceClass', 'description', 'slice_url'] + fieldsets = [('Slice Details', {'fields': ['name', 'site', 'serviceClass', 'description', 'slice_url'], 'classes':['suit-tab suit-tab-general']}),] list_display = ('name', 'site','serviceClass', 'slice_url') - inlines = [SliverInline, SliceMembershipInline, TagInline, SliceTagInline] + inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline] + + + suit_form_tabs =(('general', 'Slice Details'), + ('sliceprivileges','Privileges'), + ('slivers','Slivers'), + ('tags','Tags'), + ('reservations','Reservations'), + ) def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == 'site': @@ -317,7 +385,7 @@ class SliceAdmin(PlanetStackBaseAdmin): obj.caller = request.user obj.save() -class SliceMembershipAdmin(PlanetStackBaseAdmin): +class SlicePrivilegeAdmin(PlanetStackBaseAdmin): fieldsets = [ (None, {'fields': ['user', 'slice', 'role']}) ] @@ -344,12 +412,12 @@ class SliceMembershipAdmin(PlanetStackBaseAdmin): users = User.objects.filter(email__in=emails) kwargs['queryset'] = users - return super(SliceMembershipAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs) + return super(SlicePrivilegeAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs) def queryset(self, request): # admins can see all memberships. Users can only see memberships of # slices where they have the admin role. - qs = super(SliceMembershipAdmin, self).queryset(request) + qs = super(SlicePrivilegeAdmin, self).queryset(request) if not request.user.is_admin: roles = Role.objects.filter(role_type__in=['admin', 'pi']) site_privileges = SitePrivilege.objects.filter(user=request.user).filter(role__in=roles) @@ -374,13 +442,33 @@ class SliceMembershipAdmin(PlanetStackBaseAdmin): obj.delete() -class ImageAdmin(admin.ModelAdmin): - fields = ['image_id', 'name', 'disk_format', 'container_format'] +class ImageAdmin(PlanetStackBaseAdmin): + + fieldsets = [('Image Details', + {'fields': ['image_id', 'name', 'disk_format', 'container_format'], + 'classes': ['suit-tab suit-tab-general']}) + ] + + suit_form_tabs =(('general','Image Details'),('slivers','Slivers')) + + inlines = [SliverInline] + +class NodeForm(forms.ModelForm): + class Meta: + widgets = { + 'site': LinkedSelect, + 'deployment': LinkedSelect + } class NodeAdmin(admin.ModelAdmin): + form = NodeForm + exclude = ['enacted'] list_display = ('name', 'site', 'deployment') list_filter = ('deployment',) - inlines = [TagInline] + inlines = [TagInline,SliverInline] + fieldsets = [('Node Details', {'fields': ['name','site','deployment'], 'classes':['suit-tab suit-tab-details']})] + + suit_form_tabs =(('details','Node Details'),('slivers','Slivers'),('tags','Tags')) class SliverForm(forms.ModelForm): @@ -391,26 +479,41 @@ class SliverForm(forms.ModelForm): widgets = { 'ip': PlainTextWidget(), 'instance_name': PlainTextWidget(), + 'slice': LinkedSelect, + 'deploymentNetwork': LinkedSelect, + 'node': LinkedSelect, + 'image': LinkedSelect } class ProjectAdmin(admin.ModelAdmin): exclude = ['enacted'] + inlines = [TagInline] + +class MemberAdmin(admin.ModelAdmin): + exclude = ['enacted'] + list_display = ['role', 'rightContent_type', 'content_type', 'content_object',] class TagAdmin(admin.ModelAdmin): exclude = ['enacted'] + list_display = ['project', 'name', 'value', 'content_type', 'content_object',] class SliverAdmin(PlanetStackBaseAdmin): form = SliverForm fieldsets = [ - ('Sliver', {'fields': ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']}) + ('Sliver Details', {'fields': ['slice', 'deploymentNetwork', 'node', 'ip', 'instance_name', 'numberCores', 'image', ], 'classes': ['suit-tab suit-tab-general'], }) ] list_display = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork'] + + suit_form_tabs =(('general', 'Sliver Details'), + ('tags','Tags'), + ) + inlines = [TagInline] def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == 'slice': if not request.user.is_admin: - slices = set([sm.slice.name for sm in SliceMembership.objects.filter(user=request.user)]) + slices = set([sm.slice.name for sm in SlicePrivilege.objects.filter(user=request.user)]) kwargs['queryset'] = Slice.objects.filter(name__in=list(slices)) return super(SliverAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs) @@ -470,7 +573,7 @@ class UserCreationForm(forms.ModelForm): class Meta: model = User - fields = ('email', 'firstname', 'lastname', 'phone', 'public_key', 'site') + fields = ('email', 'firstname', 'lastname', 'phone', 'public_key') def clean_password2(self): # Check that the two password entries match @@ -518,24 +621,26 @@ class UserAdmin(UserAdmin): # The fields to be used in displaying the User model. # These override the definitions on the base UserAdmin # that reference specific fields on auth.User. - list_display = ('email', 'site', 'firstname', 'lastname', 'is_admin', 'last_login') - list_filter = ('site',) - inlines = [SitePrivilegeInline, SliceMembershipInline] + list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login') + list_filter = () + inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline] fieldsets = ( - (None, {'fields': ('email', 'password', 'site', 'is_admin', 'timezone')}), - ('Personal info', {'fields': ('firstname','lastname','phone', 'public_key')}), + ('Login Details', {'fields': ('email', 'username','site','password', 'is_admin', 'public_key'), 'classes':['suit-tab suit-tab-general']}), + ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}), #('Important dates', {'fields': ('last_login',)}), ) add_fieldsets = ( (None, { 'classes': ('wide',), - 'fields': ('email', 'firstname', 'lastname', 'phone', 'site', 'public_key','password1', 'password2', 'is_admin')} + 'fields': ('email', 'username','firstname', 'lastname', 'phone', 'public_key','password1', 'password2')} ), ) search_fields = ('email',) ordering = ('email',) filter_horizontal = () + suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges')) + def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == 'site': if not request.user.is_admin: @@ -562,6 +667,7 @@ class ReservedResourceInline(admin.TabularInline): exclude = ['enacted'] model = ReservedResource extra = 0 + suit_classes = 'suit-tab suit-tab-reservedresources' def formfield_for_foreignkey(self, db_field, request=None, **kwargs): field = super(ReservedResourceInline, self).formfield_for_foreignkey(db_field, request, **kwargs) @@ -586,6 +692,9 @@ class ReservedResourceInline(admin.TabularInline): class ReservationChangeForm(forms.ModelForm): class Meta: model = Reservation + widgets = { + 'slice' : LinkedSelect + } class ReservationAddForm(forms.ModelForm): slice = forms.ModelChoiceField(queryset=Slice.objects.all(), widget=forms.Select(attrs={"onChange":"document.getElementById('id_refresh').value=1; submit()"})) @@ -603,6 +712,10 @@ class ReservationAddForm(forms.ModelForm): class Meta: model = Reservation + widgets = { + 'slice' : LinkedSelect + } + class ReservationAddRefreshForm(ReservationAddForm): """ This form is displayed when the Reservation Form receives an update @@ -629,10 +742,14 @@ class ReservationAddRefreshForm(ReservationAddForm): class ReservationAdmin(admin.ModelAdmin): exclude = ['enacted'] + fieldsets = [('Reservation Details', {'fields': ['startTime', 'duration','slice'], 'classes': ['suit-tab suit-tab-general']})] list_display = ('startTime', 'duration') - inlines = [ReservedResourceInline] form = ReservationAddForm + suit_form_tabs = (('general','Reservation Details'), ('reservedresources','Reserved Resources')) + + inlines = [ReservedResourceInline] + def add_view(self, request, form_url='', extra_context=None): timezone.activate(request.user.timezone) request._refresh = False @@ -700,7 +817,7 @@ admin.site.unregister(Evolution) # When debugging it is often easier to see all the classes, but for regular use # only the top-levels should be displayed -showAll = False +showAll = True admin.site.register(Deployment, DeploymentAdmin) admin.site.register(Site, SiteAdmin) @@ -708,13 +825,19 @@ admin.site.register(Slice, SliceAdmin) admin.site.register(Project, ProjectAdmin) admin.site.register(ServiceClass, ServiceClassAdmin) admin.site.register(Reservation, ReservationAdmin) +#admin.site.register(SliceRole, SliceRoleAdmin) +#admin.site.register(SiteRole, SiteRoleAdmin) +#admin.site.register(PlanetStackRole) +#admin.site.register(DeploymentRole) if showAll: + #admin.site.register(PlanetStack) admin.site.register(Tag, TagAdmin) admin.site.register(Node, NodeAdmin) - admin.site.register(SliceMembership, SliceMembershipAdmin) - admin.site.register(SitePrivilege, SitePrivilegeAdmin) + #admin.site.register(SlicePrivilege, SlicePrivilegeAdmin) + #admin.site.register(SitePrivilege, SitePrivilegeAdmin) admin.site.register(Role, RoleAdmin) + admin.site.register(Member, MemberAdmin) admin.site.register(Sliver, SliverAdmin) admin.site.register(Image, ImageAdmin) diff --git a/planetstack/core/fixtures/initial_data.json b/planetstack/core/fixtures/initial_data.json index a86728a..f034820 100644 --- a/planetstack/core/fixtures/initial_data.json +++ b/planetstack/core/fixtures/initial_data.json @@ -314,5 +314,229 @@ "maxDuration": 8760, "enacted": null } +}, +{ + "pk": 1, + "model": "core.role", + "fields": { + "updated": "2013-07-30T10:35:50.572Z", + "description": "PlanetStack Application Administrator", + "created": "2013-07-30T10:30:28.633Z", + "content_type": 8, + "role_type": "Admin", + "enacted": null + } +}, +{ + "pk": 2, + "model": "core.role", + "fields": { + "updated": "2013-07-30T10:36:30.174Z", + "description": "User level role for PlanetStack Application", + "created": "2013-07-30T10:31:02.627Z", + "content_type": 8, + "role_type": "Default", + "enacted": null + } +}, +{ + "pk": 3, + "model": "core.role", + "fields": { + "updated": "2013-07-30T10:36:07.877Z", + "description": "Administrative role for a Slice", + "created": "2013-07-30T10:31:25.829Z", + "content_type": 21, + "role_type": "Admin", + "enacted": null + } +}, +{ + "pk": 4, + "model": "core.role", + "fields": { + "updated": "2013-07-30T10:36:20.679Z", + "description": "User level access for a particular Slice", + "created": "2013-07-30T10:31:48.791Z", + "content_type": 21, + "role_type": "Default", + "enacted": null + } +}, +{ + "pk": 5, + "model": "core.role", + "fields": { + "updated": "2013-07-30T10:35:59.388Z", + "description": "Administrator role for a particular Site", + "created": "2013-07-30T10:32:20.600Z", + "content_type": 15, + "role_type": "Admin", + "enacted": null + } +}, +{ + "pk": 6, + "model": "core.role", + "fields": { + "updated": "2013-07-30T10:34:39.494Z", + "description": "Principal Investigator for a particular Site", + "created": "2013-07-30T10:34:39.494Z", + "content_type": 15, + "role_type": "PI", + "enacted": null + } +}, +{ + "pk": 7, + "model": "core.role", + "fields": { + "updated": "2013-07-30T10:35:27.633Z", + "description": "Technical support for a particular Site. Allows for Read/Write access to a Site's Nodes.", + "created": "2013-07-30T10:35:27.633Z", + "content_type": 15, + "role_type": "Tech", + "enacted": null + } +}, +{ + "pk": 8, + "model": "core.role", + "fields": { + "updated": "2013-07-30T10:38:04.554Z", + "description": "Responsibility for a particular Site's accounting and invoices.", + "created": "2013-07-30T10:38:04.554Z", + "content_type": 15, + "role_type": "Billing", + "enacted": null + } +}, +{ + "pk": 9, + "model": "core.role", + "fields": { + "updated": "2013-07-30T10:39:07.062Z", + "description": "Default access for a particular Site which allows for Read-only access to the Site's objects.", + "created": "2013-07-30T10:39:07.062Z", + "content_type": 15, + "role_type": "Default", + "enacted": null + } +}, +{ + "pk": 10, + "model": "core.role", + "fields": { + "updated": "2013-07-30T10:39:55.479Z", + "description": "Represents the Site through which a particular user is managed through.", + "created": "2013-07-30T10:39:55.479Z", + "content_type": 15, + "role_type": "Homed", + "enacted": null + } +}, +{ + "pk": 11, + "model": "core.role", + "fields": { + "updated": "2013-07-30T17:35:59.815Z", + "description": "Administrative responsibility for a particular Deployment.", + "created": "2013-07-30T17:35:59.815Z", + "content_type": 9, + "role_type": "Admin", + "enacted": null + } +}, +{ + "pk": 12, + "model": "core.role", + "fields": { + "updated": "2013-07-30T17:36:54.728Z", + "description": "Default access for a particular Deployment.", + "created": "2013-07-30T17:36:54.728Z", + "content_type": 9, + "role_type": "Default", + "enacted": null + } +}, +{ + "pk": 1, + "model": "core.planetstackrole", + "fields": { + "updated": "2013-09-03T11:47:42.611Z", + "enacted": "2013-09-03T11:47:51Z", + "role": "admin", + "created": "2013-09-03T11:47:42.611Z" + } +}, +{ + "pk": 1, + "model": "core.siterole", + "fields": { + "updated": "2013-09-03T11:48:34.966Z", + "enacted": null, + "role": "admin", + "created": "2013-09-03T11:48:34.966Z" + } +}, +{ + "pk": 2, + "model": "core.siterole", + "fields": { + "updated": "2013-09-03T11:48:49.480Z", + "enacted": null, + "role": "pi", + "created": "2013-09-03T11:48:49.480Z" + } +}, +{ + "pk": 3, + "model": "core.siterole", + "fields": { + "updated": "2013-09-03T11:49:03.678Z", + "enacted": null, + "role": "tech", + "created": "2013-09-03T11:49:03.678Z" + } +}, +{ + "pk": 4, + "model": "core.siterole", + "fields": { + "updated": "2013-09-03T11:49:17.254Z", + "enacted": null, + "role": "billing", + "created": "2013-09-03T11:49:17.254Z" + } +}, +{ + "pk": 1, + "model": "core.slicerole", + "fields": { + "updated": "2013-09-03T11:48:02.080Z", + "enacted": null, + "role": "admin", + "created": "2013-09-03T11:48:02.080Z" + } +}, +{ + "pk": 2, + "model": "core.slicerole", + "fields": { + "updated": "2013-09-03T11:48:17.688Z", + "enacted": null, + "role": "default", + "created": "2013-09-03T11:48:17.688Z" + } +}, +{ + "pk": 1, + "model": "core.deploymentrole", + "fields": { + "updated": "2013-09-03T11:48:02.080Z", + "enacted": null, + "role": "admin", + "created": "2013-09-03T11:48:02.080Z" + } } ] diff --git a/planetstack/core/models/__init__.py b/planetstack/core/models/__init__.py index 2280822..1cc4d07 100644 --- a/planetstack/core/models/__init__.py +++ b/planetstack/core/models/__init__.py @@ -1,17 +1,25 @@ from .plcorebase import PlCoreBase -from .deployment import Deployment +from .planetstack import PlanetStack from .project import Project from .tag import Tag +from .role import Role +from .deployment import Deployment from .site import Site +from .user import User +from .serviceclass import ServiceClass +from .slice import Slice from .site import SitePrivilege from .image import Image -from .user import User -from .role import Role from .node import Node -from .serviceclass import ServiceClass from .serviceresource import ServiceResource -from .slice import Slice -from .slice import SliceMembership +from .slice import SliceRole +from .slice import SlicePrivilege +from .site import SiteRole +from .site import SitePrivilege +from .deployment import DeploymentRole +from .deployment import DeploymentPrivilege +from .planetstack import PlanetStackRole +from .planetstack import PlanetStackPrivilege from .slicetag import SliceTag from .sliver import Sliver from .reservation import ReservedResource diff --git a/planetstack/core/models/deployment.py b/planetstack/core/models/deployment.py index d38115f..4e835d0 100644 --- a/planetstack/core/models/deployment.py +++ b/planetstack/core/models/deployment.py @@ -1,11 +1,30 @@ import os from django.db import models from core.models import PlCoreBase +from core.models import Member +from django.contrib.contenttypes import generic # Create your models here. class Deployment(PlCoreBase): name = models.CharField(max_length=200, unique=True, help_text="Name of the Deployment") + members = generic.GenericRelation(Member) def __unicode__(self): return u'%s' % (self.name) + +class DeploymentRole(PlCoreBase): + + ROLE_CHOICES = (('admin','Admin'),) + role = models.CharField(choices=ROLE_CHOICES, unique=True, max_length=30) + + def __unicode__(self): return u'%s' % (self.role) + +class DeploymentPrivilege(PlCoreBase): + + user = models.ForeignKey('User', related_name='deployment_privileges') + deployment = models.ForeignKey('Deployment', related_name='deployment_privileges') + role = models.ForeignKey('DeploymentRole') + + def __unicode__(self): return u'%s %s %s' % (self.deployment, self.user, self.role) + diff --git a/planetstack/core/models/planetstack.py b/planetstack/core/models/planetstack.py new file mode 100644 index 0000000..9007a51 --- /dev/null +++ b/planetstack/core/models/planetstack.py @@ -0,0 +1,30 @@ +import os +from django.db import models +from core.models import PlCoreBase + +# Create your models here. + +class PlanetStack(PlCoreBase): + description = models.CharField(max_length=200, unique=True, default="PlanetStack", help_text="Used for scoping of roles at the PlanetStack Application level") + + class Meta: + verbose_name_plural = "PlanetStack" + app_label = "core" + + def __unicode__(self): return u'%s' % (self.description) + +class PlanetStackRole(PlCoreBase): + ROLE_CHOICES = (('admin','Admin'),) + role = models.CharField(choices=ROLE_CHOICES, unique=True, max_length=30) + + def __unicode__(self): return u'%s' % (self.role) + +class PlanetStackPrivilege(PlCoreBase): + user = models.ForeignKey('User', related_name='planetstack_privileges') + planetstack = models.ForeignKey('PlanetStack', related_name='planetstack_privileges', default=1) + role = models.ForeignKey('PlanetStackRole') + + def __unicode__(self): return u'%s %s %s' % (self.planetstack, self.user, self.role) + + + diff --git a/planetstack/core/models/role.py b/planetstack/core/models/role.py index fd29848..234868e 100644 --- a/planetstack/core/models/role.py +++ b/planetstack/core/models/role.py @@ -2,14 +2,16 @@ import os import datetime from django.db import models from core.models import PlCoreBase +from django.contrib.contenttypes.models import ContentType +from django.contrib.contenttypes import generic class Role(PlCoreBase): - ROLE_CHOICES = (('admin', 'Admin'), ('pi', 'Principle Investigator'), ('tech', 'Technician'), ('user','User')) - role = models.CharField(null=True, blank=True,max_length=256, unique=True, choices=ROLE_CHOICES) - role_type = models.CharField(max_length=80, unique=True) + role_type = models.CharField(max_length=80, verbose_name="Name") + description = models.CharField(max_length=120, verbose_name="Description") + content_type = models.ForeignKey(ContentType, verbose_name="Role Scope") - def __unicode__(self): return u'%s' % (self.role_type) + def __unicode__(self): return u'%s:%s' % (self.content_type,self.role_type) def save(self, *args, **kwds): diff --git a/planetstack/core/models/site.py b/planetstack/core/models/site.py index 8a6d7c4..aee3843 100644 --- a/planetstack/core/models/site.py +++ b/planetstack/core/models/site.py @@ -24,11 +24,18 @@ class Site(PlCoreBase): def __unicode__(self): return u'%s' % (self.name) +class SiteRole(PlCoreBase): + + ROLE_CHOICES = (('admin','Admin'),('pi','PI'),('tech','Tech'),('billing','Billing')) + role = models.CharField(choices=ROLE_CHOICES, unique=True, max_length=30) + + def __unicode__(self): return u'%s' % (self.role) + class SitePrivilege(PlCoreBase): user = models.ForeignKey('User', related_name='site_privileges') site = models.ForeignKey('Site', related_name='site_privileges') - role = models.ForeignKey('Role') + role = models.ForeignKey('SiteRole') def __unicode__(self): return u'%s %s %s' % (self.site, self.user, self.role) diff --git a/planetstack/core/models/slice.py b/planetstack/core/models/slice.py index 74815b2..e584c07 100644 --- a/planetstack/core/models/slice.py +++ b/planetstack/core/models/slice.py @@ -40,15 +40,16 @@ class Slice(PlCoreBase): self.creator = self.caller super(Slice, self).save(*args, **kwds) -class SliceMembership(PlCoreBase): - user = models.ForeignKey('User', related_name='slice_memberships') - slice = models.ForeignKey('Slice', related_name='slice_memberships') - role = models.ForeignKey('Role') +class SliceRole(PlCoreBase): + ROLE_CHOICES = (('admin','Admin'),('default','Default')) - def __unicode__(self): return u'%s %s %s' % (self.slice, self.user, self.role) + role = models.CharField(choices=ROLE_CHOICES, unique=True, max_length=30) - def save(self, *args, **kwds): - super(SliceMembership, self).save(*args, **kwds) + def __unicode__(self): return u'%s' % (self.role) - def delete(self, *args, **kwds): - super(SliceMembership, self).delete(*args, **kwds) +class SlicePrivilege(PlCoreBase): + user = models.ForeignKey('User', related_name='slice_privileges') + slice = models.ForeignKey('Slice', related_name='slice_privileges') + role = models.ForeignKey('SliceRole') + + def __unicode__(self): return u'%s %s %s' % (self.slice, self.user, self.role) diff --git a/planetstack/core/models/user.py b/planetstack/core/models/user.py index 758bcbf..2b63dda 100644 --- a/planetstack/core/models/user.py +++ b/planetstack/core/models/user.py @@ -2,11 +2,11 @@ import os import datetime from collections import defaultdict from django.db import models -from core.models import PlCoreBase -from core.models import Site +from core.models import PlCoreBase,Site from django.contrib.auth.models import AbstractBaseUser, BaseUserManager from timezones.fields import TimeZoneField + # Create your models here. class UserManager(BaseUserManager): def create_user(self, email, firstname, lastname, password=None): @@ -54,6 +54,7 @@ class User(AbstractBaseUser): unique=True, db_index=True, ) + username = models.CharField(max_length=200, default="Something" ) kuser_id = models.CharField(null=True, blank=True, help_text="keystone user id", max_length=200) firstname = models.CharField(help_text="person's given name", max_length=200) @@ -61,7 +62,7 @@ class User(AbstractBaseUser): phone = models.CharField(null=True, blank=True, help_text="phone number contact", max_length=100) user_url = models.URLField(null=True, blank=True) - site = models.ForeignKey(Site, related_name='users', verbose_name="Site this user will be homed too", null=True) + site = models.ForeignKey(Site, related_name='users', help_text="Site this user will be homed too", null=True) public_key = models.TextField(null=True, blank=True, max_length=1024, help_text="Public key string") is_active = models.BooleanField(default=True) @@ -104,18 +105,21 @@ class User(AbstractBaseUser): # Simplest possible answer: Yes, always return True - def get_roles(self): - from core.models.site import SitePrivilege - from core.models.slice import SliceMembership - - site_privileges = SitePrivilege.objects.filter(user=self) - slice_memberships = SliceMembership.objects.filter(user=self) - roles = defaultdict(list) - for site_privilege in site_privileges: - roles[site_privilege.role.role_type].append(site_privilege.site.login_base) - for slice_membership in slice_memberships: - roles[slice_membership.role.role_type].append(slice_membership.slice.name) - return roles + def is_superuser(self): + return False + +# def get_roles(self): +# from core.models.site import SitePrivilege +# from core.models.slice import SliceMembership +# +# site_privileges = SitePrivilege.objects.filter(user=self) +# slice_memberships = SliceMembership.objects.filter(user=self) +# roles = defaultdict(list) +# for site_privilege in site_privileges: +# roles[site_privilege.role.role_type].append(site_privilege.site.login_base) +# for slice_membership in slice_memberships: +# roles[slice_membership.role.role_type].append(slice_membership.slice.name) +# return roles def save(self, *args, **kwds): if not self.id: diff --git a/planetstack/core/serializers.py b/planetstack/core/serializers.py index 94f5c3c..b83157b 100644 --- a/planetstack/core/serializers.py +++ b/planetstack/core/serializers.py @@ -3,38 +3,108 @@ from rest_framework import serializers from core.models import * +class DeploymentSerializer(serializers.HyperlinkedModelSerializer): + + # HyperlinkedModelSerializer doesn't include the id by default + id = serializers.Field() + sites = serializers.HyperlinkedRelatedField(view_name='site-detail') + class Meta: + model = Deployment + fields = ('id', + 'url', + 'name', + 'sites' + ) + +class ImageSerializer(serializers.HyperlinkedModelSerializer): + # HyperlinkedModelSerializer doesn't include the id by default + id = serializers.Field() + class Meta: + model = Image + fields = ('id', + 'url', + 'image_id', + 'name', + 'disk_format', + 'container_format') + +class NodeSerializer(serializers.HyperlinkedModelSerializer): + # HyperlinkedModelSerializer doesn't include the id by default + id = serializers.Field() + class Meta: + model = Node + fields = ('id', + 'url', + 'name') + +class ProjectSerializer(serializers.HyperlinkedModelSerializer): + # HyperlinkedModelSerializer doesn't include the id by default + id = serializers.Field() + class Meta: + model = Project + fields = ('id', + 'url', + 'name') + +class ReservationSerializer(serializers.HyperlinkedModelSerializer): + # HyperlinkedModelSerializer doesn't include the id by default + id = serializers.Field() + class Meta: + model = Reservation + fields = ('id', + 'url', + 'startTime', + 'slice', + 'duration', + 'endTime', + ) + class RoleSerializer(serializers.HyperlinkedModelSerializer): # HyperlinkedModelSerializer doesn't include the id by default id = serializers.Field() class Meta: model = Role fields = ('id', - 'role', - 'role_type') + 'url', + 'role', + 'role_type') -class UserSerializer(serializers.HyperlinkedModelSerializer): +class ServiceClassSerializer(serializers.HyperlinkedModelSerializer): # HyperlinkedModelSerializer doesn't include the id by default id = serializers.Field() - site = serializers.HyperlinkedRelatedField(view_name='site-detail') - slice_memberships = serializers.HyperlinkedRelatedField(view_name='slice-membership-detail') - site_privileges = serializers.HyperlinkedRelatedField(view_name='siteprivilege-detail') class Meta: - model = User + model = ServiceClass fields = ('id', - 'kuser_id', - 'firstname', - 'lastname', - 'email', - 'password', - 'phone', - 'public_key', - 'user_url', - 'is_admin', - 'site', - 'slice_memberships', - 'site_privileges') - + 'url', + 'name', + 'description', + 'commitment', + 'membershipFee', + 'membershipFeeMonths', + 'upgradeRequiresApproval', + 'upgradeFrom', + ) + +class ServiceResourceSerializer(serializers.HyperlinkedModelSerializer): + # HyperlinkedModelSerializer doesn't include the id by default + id = serializers.Field() + serviceClass = serializers.HyperlinkedRelatedField(view_name='serviceclass-detail') + class Meta: + model = ServiceResource + fields = ('id', + 'url', + 'name', + 'serviceClass', + 'maxUnitsDeployment', + 'maxUnitsNode', + 'maxDuration', + 'bucketInRate', + 'bucketMaxSize', + 'cost', + 'calendarReservable', + ) + class SliceSerializer(serializers.HyperlinkedModelSerializer): # HyperlinkedModelSerializer doesn't include the id by default id = serializers.Field() @@ -43,6 +113,7 @@ class SliceSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Slice fields = ('id', + 'url', 'tenant_id', 'enabled', 'name', @@ -58,14 +129,15 @@ class SliceSerializer(serializers.HyperlinkedModelSerializer): 'updated', 'created') -class SliceMembershipSerializer(serializers.HyperlinkedModelSerializer): +class SlicePrivilegeSerializer(serializers.HyperlinkedModelSerializer): id = serializers.Field() slice = serializers.HyperlinkedRelatedField(view_name='slice-detail') user = serializers.HyperlinkedRelatedField(view_name='user-detail') role = serializers.HyperlinkedRelatedField(view_name='role-detail') class Meta: - model = SliceMembership + model = SlicePrivilege fields = ('id', + 'url', 'user', 'slice', 'role') @@ -105,75 +177,90 @@ class SitePrivilegeSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = SitePrivilege fields = ('id', + 'url', 'user', 'site', 'role') -class DeploymentSerializer(serializers.HyperlinkedModelSerializer): - - # HyperlinkedModelSerializer doesn't include the id by default - id = serializers.Field() - sites = serializers.HyperlinkedRelatedField(view_name='site-detail') - class Meta: - model = Deployment - fields = ('id', - 'name', - 'sites' - ) - class SliverSerializer(serializers.HyperlinkedModelSerializer): # HyperlinkedModelSerializer doesn't include the id by default id = serializers.Field() image = serializers.HyperlinkedRelatedField(view_name='image-detail') slice = serializers.HyperlinkedRelatedField(view_name='slice-detail') - deployment = serializers.HyperlinkedRelatedField(view_name='deployment-detail') + deploymentNetwork = serializers.HyperlinkedRelatedField(view_name='deployment-detail') node = serializers.HyperlinkedRelatedField(view_name='node-detail') - #slice = serializers.PrimaryKeyRelatedField(read_only=True) class Meta: model = Sliver fields = ('id', + 'url', 'instance_id', 'name', 'instance_name', 'ip', 'image', 'slice', - 'deployment', + 'deploymentNetwork', 'node') -class NodeSerializer(serializers.HyperlinkedModelSerializer): +class UserSerializer(serializers.HyperlinkedModelSerializer): # HyperlinkedModelSerializer doesn't include the id by default id = serializers.Field() + site = serializers.HyperlinkedRelatedField(view_name='site-detail') + slice_privileges = serializers.HyperlinkedRelatedField(view_name='sliceprivilege-detail') + site_privileges = serializers.HyperlinkedRelatedField(view_name='siteprivilege-detail') class Meta: - model = Node + model = User fields = ('id', - 'name') - -class ImageSerializer(serializers.HyperlinkedModelSerializer): + 'url', + 'kuser_id', + 'firstname', + 'lastname', + 'email', + 'password', + 'phone', + 'public_key', + 'user_url', + 'is_admin', + 'slice_privileges', + 'site_privileges') + +class TagSerializer(serializers.HyperlinkedModelSerializer): # HyperlinkedModelSerializer doesn't include the id by default id = serializers.Field() + project = serializers.HyperlinkedRelatedField(view_name='project-detail') + #content_type = serializers.PrimaryKeyRelatedField(read_only=True) + content_type = serializers.RelatedField(source = "content_type") + content_object = serializers.RelatedField(source='content_object') class Meta: - model = Image - fields = ('id', - 'image_id', - 'name', - 'disk_format', - 'container_format') + model = Tag + fields = ('id', + 'url', + 'project', + 'value', + 'content_type', + 'object_id', + 'content_object', + 'name') serializerLookUp = { + Deployment: DeploymentSerializer, + Image: ImageSerializer, + Node: NodeSerializer, + Project: ProjectSerializer, + Reservation: ReservationSerializer, Role: RoleSerializer, - User: UserSerializer, + ServiceClass: ServiceClassSerializer, + ServiceResource: ServiceResourceSerializer, Site: SiteSerializer, SitePrivilege: SitePrivilegeSerializer, Slice: SliceSerializer, - SliceMembership: SliceMembershipSerializer, - Node: NodeSerializer, + SlicePrivilege: SlicePrivilegeSerializer, Sliver: SliverSerializer, - Deployment: DeploymentSerializer, - Image: ImageSerializer, + Tag: TagSerializer, + User: UserSerializer, None: None, } diff --git a/planetstack/core/static/planetstack.css b/planetstack/core/static/planetstack.css index 2034708..b517eac 100644 --- a/planetstack/core/static/planetstack.css +++ b/planetstack/core/static/planetstack.css @@ -1 +1,2 @@ -.field-refresh { display: none; } +.required:after {color: red ! important; font-size: 18px } +#.btn-success {color:black} diff --git a/planetstack/core/views/slice_memberships.py b/planetstack/core/views/slice_memberships.py deleted file mode 100644 index 13f0707..0000000 --- a/planetstack/core/views/slice_memberships.py +++ /dev/null @@ -1,13 +0,0 @@ -from core.serializers import SliceMembershipSerializer -from rest_framework import generics -from core.models import SliceMembership - -class SliceMembershipList(generics.ListCreateAPIView): - queryset = SliceMembership.objects.all() - serializer_class = SliceMembershipSerializer - -class SliceMembershipDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = SliceMembership.objects.all() - serializer_class = SliceMembershipSerializer - - diff --git a/planetstack/core/views/slice_privileges.py b/planetstack/core/views/slice_privileges.py new file mode 100644 index 0000000..4dd1f93 --- /dev/null +++ b/planetstack/core/views/slice_privileges.py @@ -0,0 +1,13 @@ +from core.serializers import SlicePrivilegeSerializer +from rest_framework import generics +from core.models import SlicePrivilege + +class SlicePrivilegeList(generics.ListCreateAPIView): + queryset = SlicePrivilege.objects.all() + serializer_class = SlicePrivilegeSerializer + +class SlicePrivilegeDetail(generics.RetrieveUpdateDestroyAPIView): + queryset = SlicePrivilege.objects.all() + serializer_class = SlicePrivilegeSerializer + + diff --git a/planetstack/hpc/__init__.py b/planetstack/hpc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/planetstack/hpc/admin.py b/planetstack/hpc/admin.py new file mode 100644 index 0000000..3afb448 --- /dev/null +++ b/planetstack/hpc/admin.py @@ -0,0 +1,68 @@ +from django.contrib import admin + +from hpc.models import * +from django import forms +from django.utils.safestring import mark_safe +from django.contrib.auth.admin import UserAdmin +from django.contrib.admin.widgets import FilteredSelectMultiple +from django.contrib.auth.forms import ReadOnlyPasswordHashField +from django.contrib.auth.signals import user_logged_in +from django.utils import timezone +from django.contrib.contenttypes import generic +from suit.widgets import LinkedSelect + +#class HPCRRBaseAdmin(admin.ModelAdmin): + #exclude = ['enacted'] + +class CDNPrefixInline(admin.TabularInline): + model = CDNPrefix + extra = 0 + suit_classes = 'suit-tab suit-tab-prefixes' + +class ContentProviderInline(admin.TabularInline): + model = ContentProvider + extra = 0 + suit_classes = 'suit-tab suit-tab-cps' + +class OriginServerAdmin(admin.ModelAdmin): + list_display = ('url','protocol','redirects','contentProvider','authenticated','enabled' ) + +class ContentProviderForm(forms.ModelForm): + class Meta: + widgets = { + 'serviceProvider' : LinkedSelect + } + +class ContentProviderAdmin(admin.ModelAdmin): + form = ContentProviderForm + list_display = ('name','description','enabled' ) + fieldsets = [ (None, {'fields': ['name','enabled','description','serviceProvider','users'], 'classes':['suit-tab suit-tab-general']})] + + inlines = [CDNPrefixInline] + + suit_form_tabs = (('general','Details'),('prefixes','CDN Prefixes')) + +class ServiceProviderAdmin(admin.ModelAdmin): + list_display = ('name', 'description', 'enabled') + fieldsets = [ + (None, {'fields': ['name','description','enabled'], 'classes':['suit-tab suit-tab-general']})] +#, ('Content Providers', {'fields':['contentProviders'],'classes':['suit-tab suit-tab-cps']})] + + suit_form_tabs = (('general','Details'),('cps','Content Providers')) + inlines = [ContentProviderInline] + +class CDNPrefixForm(forms.ModelForm): + class Meta: + widgets = { + 'contentProvider' : LinkedSelect + } + +class CDNPrefixAdmin(admin.ModelAdmin): + form = CDNPrefixForm + list_display = ['prefix','contentProvider'] + +admin.site.register(ServiceProvider, ServiceProviderAdmin) +admin.site.register(ContentProvider, ContentProviderAdmin) +admin.site.register(CDNPrefix, CDNPrefixAdmin) +admin.site.register(OriginServer,OriginServerAdmin) + diff --git a/planetstack/hpc/models.py b/planetstack/hpc/models.py new file mode 100644 index 0000000..d257032 --- /dev/null +++ b/planetstack/hpc/models.py @@ -0,0 +1,92 @@ +from django.db import models +from core.models import User +import os +from django.db import models +from django.forms.models import model_to_dict + + +# Create your models here. + +class HpcCoreBase(models.Model): + + created = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) + + class Meta: + abstract = True + app_label = "hpc" + + def __init__(self, *args, **kwargs): + super(HpcCoreBase, self).__init__(*args, **kwargs) + self.__initial = self._dict + + @property + def diff(self): + d1 = self.__initial + d2 = self._dict + diffs = [(k, (v, d2[k])) for k, v in d1.items() if v != d2[k]] + return dict(diffs) + + @property + def has_changed(self): + return bool(self.diff) + + @property + def changed_fields(self): + return self.diff.keys() + + def get_field_diff(self, field_name): + return self.diff.get(field_name, None) + + def save(self, *args, **kwargs): + super(HpcCoreBase, self).save(*args, **kwargs) + + self.__initial = self._dict + + @property + def _dict(self): + return model_to_dict(self, fields=[field.name for field in + self._meta.fields]) + + +class ServiceProvider(HpcCoreBase): + name = models.CharField(max_length=254,help_text="Service Provider Name") + description = models.TextField(max_length=254,null=True, blank=True, help_text="Description of Service Provider") + enabled = models.BooleanField(default=True) + + def __unicode__(self): return u'%s' % (self.name) + +class ContentProvider(HpcCoreBase): + name = models.CharField(max_length=254) + enabled = models.BooleanField(default=True) + description = models.TextField(max_length=254,null=True, blank=True,help_text="Description of Content Provider") + serviceProvider = models.ForeignKey(ServiceProvider) + + # Note user relationships are directed not requiring a role. + users = models.ManyToManyField(User) + + def __unicode__(self): return u'%s' % (self.name) + +class OriginServer(HpcCoreBase): + url = models.URLField() + contentProvider = models.ForeignKey(ContentProvider) + + authenticated = models.BooleanField(default=False, help_text="Status for this Site") + enabled = models.BooleanField(default=True, help_text="Status for this Site") + PROTOCOL_CHOICES = (('http', 'HTTP'),('rtmp', 'RTMP'), ('rtp', 'RTP'),('shout', 'SHOUTcast')) + protocol = models.CharField(default="HTTP", max_length = 12, choices=PROTOCOL_CHOICES) + redirects = models.BooleanField(default=True, help_text="Indicates whether Origin Server redirects should be used for this Origin Server") + description = models.TextField(null=True, blank=True, max_length=255) + + def __unicode__(self): return u'%s' % (self.url) + +class CDNPrefix(HpcCoreBase): + prefix = models.CharField(max_length=200, help_text="Registered Prefix for Domain") + contentProvider = models.ForeignKey(ContentProvider) + description = models.TextField(max_length=254,null=True, blank=True,help_text="Description of Content Provider") + + defaultOriginServer = models.ForeignKey(OriginServer) + enabled = models.BooleanField(default=True) + + def __unicode__(self): return u'%s' % (self.prefix) + diff --git a/planetstack/hpc/tests.py b/planetstack/hpc/tests.py new file mode 100644 index 0000000..501deb7 --- /dev/null +++ b/planetstack/hpc/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.assertEqual(1 + 1, 2) diff --git a/planetstack/hpc/views.py b/planetstack/hpc/views.py new file mode 100644 index 0000000..60f00ef --- /dev/null +++ b/planetstack/hpc/views.py @@ -0,0 +1 @@ +# Create your views here. diff --git a/planetstack/planetstack/settings.py b/planetstack/planetstack/settings.py index 91be3dc..7593650 100644 --- a/planetstack/planetstack/settings.py +++ b/planetstack/planetstack/settings.py @@ -1,3 +1,5 @@ +from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS as TCP + # Django settings for planetstack project. from config import Config config = Config() @@ -25,6 +27,7 @@ DATABASES = { AUTH_USER_MODEL = 'core.User' + # Hosts/domain names that are valid for this site; required if DEBUG is False # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts ALLOWED_HOSTS = [] @@ -72,7 +75,7 @@ STATIC_ROOT = '' STATIC_URL = '/static/' # Additional locations of static files -STATICFILES_DIRS = ( +STATICFILES_DIRS = ( "/opt/planetstack/core/static/", # Put strings here, like "/home/html/static" or "C:/www/django/static". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. @@ -126,6 +129,7 @@ INSTALLED_APPS = ( 'django.contrib.messages', 'django.contrib.staticfiles', # Uncomment the next line to enable the admin: + 'suit', 'django.contrib.admin', # Uncomment the next line to enable admin documentation: 'django.contrib.admindocs', @@ -133,9 +137,47 @@ INSTALLED_APPS = ( 'django_extensions', 'django_evolution', 'core', - 'geoposition' + 'hpc', + 'geoposition', ) + +# Added for django-suit form +TEMPLATE_CONTEXT_PROCESSORS = TCP + ( + 'django.core.context_processors.request', +) + +# Django Suit configuration example +SUIT_CONFIG = { + # header + 'ADMIN_NAME': 'PlanetStack', + # 'HEADER_DATE_FORMAT': 'l, j. F Y', + # 'HEADER_TIME_FORMAT': 'H:i', + + # forms + #'SHOW_REQUIRED_ASTERISK': True, # Default True + 'CONFIRM_UNSAVED_CHANGES': True, # Default True + + # menu + # 'SEARCH_URL': '/admin/auth/user/', + # 'MENU_ICONS': { + # 'sites': 'icon-leaf', + # 'auth': 'icon-lock', + # }, + # 'MENU_OPEN_FIRST_CHILD': True, # Default True + 'MENU_EXCLUDE': ('auth.group','auth'), + 'MENU': ( + ), + # 'sites', + # {'app': 'auth', 'icon':'icon-lock', 'models': ('user', 'group')}, + # {'label': 'Settings', 'icon':'icon-cog', 'models': ('auth.user', 'auth.group')}, + # {'label': 'Support', 'icon':'icon-question-sign', 'url': '/support/'}, + # ), + + # misc + # 'LIST_PER_PAGE': 15 +} + # A sample logging configuration. The only tangible logging # performed by this configuration is to send an email to # the site admins on every HTTP 500 error when DEBUG=False. diff --git a/planetstack/planetstack/urls.py b/planetstack/planetstack/urls.py index 638e3b1..039c206 100644 --- a/planetstack/planetstack/urls.py +++ b/planetstack/planetstack/urls.py @@ -2,16 +2,21 @@ from django.conf.urls import patterns, include, url # Uncomment the next two lines to enable the admin: from django.contrib import admin +from core.views.deployment import DeploymentList, DeploymentDetail +from core.views.images import ImageList, ImageDetail +from core.views.nodes import NodeList, NodeDetail +from core.views.projects import ProjectList, ProjectDetail +from core.views.reservations import ReservationList, ReservationDetail from core.views.roles import RoleList, RoleDetail +from core.views.serviceclasses import ServiceClassList, ServiceClassDetail +from core.views.serviceresources import ServiceResourceList, ServiceResourceDetail from core.views.sites import SiteList, SiteDetail from core.views.site_privileges import SitePrivilegeList, SitePrivilegeDetail -from core.views.users import UserList, UserDetail from core.views.slices import SliceList, SliceDetail -from core.views.slice_memberships import SliceMembershipList, SliceMembershipDetail +from core.views.slice_privileges import SlicePrivilegeList, SlicePrivilegeDetail from core.views.slivers import SliverList, SliverDetail -from core.views.deployment_networks import DeploymentList, DeploymentDetail -from core.views.images import ImageList, ImageDetail -from core.views.nodes import NodeList, NodeDetail +from core.views.tags import TagList, TagDetail +from core.views.users import UserList, UserDetail from core.models import * from core.api_root import api_root from rest_framework import generics @@ -31,36 +36,51 @@ urlpatterns = patterns('', url(r'^plstackapi/$', api_root), + url(r'^plstackapi/deployments/$', DeploymentList.as_view(), name='deployment-list'), + url(r'^plstackapi/deployments/(?P[a-zA-Z0-9\-]+)/$', DeploymentDetail.as_view(), name='deployment-detail'), + + url(r'^plstackapi/images/$', ImageList.as_view(), name='image-list'), + url(r'^plstackapi/images/(?P[a-zA-Z0-9_\-]+)/$', ImageDetail.as_view(), name='image-detail'), + + url(r'^plstackapi/nodes/$', NodeList.as_view(), name='node-list'), + url(r'^plstackapi/nodes/(?P[a-zA-Z0-9_\-]+)/$', NodeDetail.as_view(), name='node-detail'), + + url(r'^plstackapi/projects/$', ProjectList.as_view(), name='project-list'), + url(r'^plstackapi/projects/(?P[a-zA-Z0-9_\-]+)/$', ProjectDetail.as_view(), name='project-detail'), + + url(r'^plstackapi/reservations/$', ReservationList.as_view(), name='reservation-list'), + url(r'^plstackapi/reservations/(?P[a-zA-Z0-9_\-]+)/$', ReservationDetail.as_view(), name='reservation-detail'), + url(r'^plstackapi/roles/$', RoleList.as_view(), name='role-list'), url(r'^plstackapi/roles/(?P[a-zA-Z0-9]+)/$', RoleDetail.as_view(), name='role-detail'), - url(r'^plstackapi/users/$', UserList.as_view(), name='user-list'), - url(r'^plstackapi/users/(?P[a-zA-Z0-9_\-]+)/$', UserDetail.as_view(), name='user-detail'), + url(r'^plstackapi/serviceclasses/$', ServiceClassList.as_view(), name='serviceclass-list'), + url(r'^plstackapi/serviceclasses/(?P[a-zA-Z0-9]+)/$', ServiceClassDetail.as_view(), name='serviceclass-detail'), - url(r'^plstackapi/sites/$', SiteList.as_view(), name='site-list'), - url(r'^plstackapi/sites/(?P[a-zA-Z0-9_\-]+)/$', SiteDetail.as_view(), name='site-detail'), + url(r'^plstackapi/serviceresources/$', ServiceResourceList.as_view(), name='serviceresource-list'), + url(r'^plstackapi/serviceresources/(?P[a-zA-Z0-9]+)/$', ServiceResourceDetail.as_view(), name='serviceresource-detail'), url(r'^plstackapi/site_privileges/$', SitePrivilegeList.as_view(), name='siteprivilege-list'), url(r'^plstackapi/site_privileges/(?P[a-zA-Z0-9_]+)/$', SitePrivilegeDetail.as_view(), name='siteprivilege-detail'), + url(r'^plstackapi/sites/$', SiteList.as_view(), name='site-list'), + url(r'^plstackapi/sites/(?P[a-zA-Z0-9_\-]+)/$', SiteDetail.as_view(), name='site-detail'), + url(r'^plstackapi/slices/$', SliceList.as_view(), name='slice-list'), url(r'^plstackapi/slices/(?P[a-zA-Z0-9_\-]+)/$', SliceDetail.as_view(), name='slice-detail'), - url(r'^plstackapi/slice_memberships/$', SliceMembershipList.as_view(), name='slice-membership-list'), - url(r'^plstackapi/slice_memberships/(?P[0-9]+)/$', SliceMembershipDetail.as_view(), name='slice-membership-detail'), + url(r'^plstackapi/slice_memberships/$', SlicePrivilegeList.as_view(), name='sliceprivilege-list'), + url(r'^plstackapi/slice_memberships/(?P[0-9]+)/$', SlicePrivilegeDetail.as_view(), name='sliceprivilege-detail'), url(r'^plstackapi/slivers/$', SliverList.as_view(), name='sliver-list'), url(r'^plstackapi/slivers/(?P[a-zA-Z0-9_\-]+)/$', SliverDetail.as_view(), name='sliver-detail'), - url(r'^plstackapi/nodes/$', NodeList.as_view(), name='node-list'), - url(r'^plstackapi/nodes/(?P[a-zA-Z0-9_\-]+)/$', NodeDetail.as_view(), name='node-detail'), - - url(r'^plstackapi/deployments/$', DeploymentList.as_view(), name='deployment-list'), - url(r'^plstackapi/deployments/(?P[a-zA-Z0-9\-]+)/$', DeploymentDetail.as_view(), name='deployment-detail'), + url(r'^plstackapi/tags/$', TagList.as_view(), name='tag-list'), + url(r'^plstackapi/tags/(?P[a-zA-Z0-9_\-]+)/$', TagDetail.as_view(), name='tag-detail'), - url(r'^plstackapi/images/$', ImageList.as_view(), name='image-list'), - url(r'^plstackapi/images/(?P[a-zA-Z0-9_\-]+)/$', ImageDetail.as_view(), name='image-detail'), + url(r'^plstackapi/users/$', UserList.as_view(), name='user-list'), + url(r'^plstackapi/users/(?P[a-zA-Z0-9_\-]+)/$', UserDetail.as_view(), name='user-detail'), #Adding in rest_framework urls url(r'^plstackapi/', include('rest_framework.urls', namespace='rest_framework')), diff --git a/planetstack/templates/admin/base.html b/planetstack/templates/admin/base.html new file mode 100644 index 0000000..477e941 --- /dev/null +++ b/planetstack/templates/admin/base.html @@ -0,0 +1,212 @@ +{% load admin_static %}{% load suit_tags %}{% load url from future %} + + + {% block title %}{{ title }} | {{ 'ADMIN_NAME'|suit_conf }}{% endblock %} + + + + + {% block extrastyle %}{% endblock %} + {% if LANGUAGE_BIDI %}{% endif %} + + + + {% if 'SHOW_REQUIRED_ASTERISK'|suit_conf %} + + {% endif %} + {% block extrahead %}{% endblock %} + {% block blockbots %} + {% endblock %} + +{% load i18n %} + + + + +
+ + + {% block container %} +
+ + {% block header %} + {% if not is_popup %} + + + {% endif %} + + {% endblock %} + + +
+ + {% block content-center %} +
+ + {% if not is_popup %} + {% block breadcrumbs %} + + {% endblock %} + {% endif %} + + {% block messages %} + {% if messages %} + + {% for message in messages %} +
+ + + {% if message.tags %}{{ message.tags|capfirst }}{% else %} + Message{% endif %}! + {{ message }} +
+ {% endfor %} + {% endif %} + {% endblock messages %} + + +
+ {% block pretitle %}{% endblock %} + {% block content_title %}{% if title %} +

{{ title }}

+ {% endif %}{% endblock %} + {% block content %} + {% block object-tools %}{% endblock %} + {{ content }} + {% endblock %} + {% block sidebar_content %} + {% block sidebar %}{% endblock %} + {% endblock %} +
+ +
+ {% endblock %} + + + {% block content-left %} + {% if not is_popup %} +
+ {% block quick-search %} + {% with 'SEARCH_URL'|suit_conf as search_url %} + {% if search_url %} + + {% endif %} + {% endwith %} + {% endblock %} + + {% include 'suit/menu.html' %} + +
+ {% endif %} + {% endblock %} + +
+
+ {% endblock %} + + {% if not is_popup %} + +
+ {% endif %} + +
+ +{% block footer %} + {% if not is_popup %} + + {% endif %} +{% endblock %} + + + + {% block extrajs %}{% endblock %} + + + diff --git a/planetstack/templates/admin/base_site.html b/planetstack/templates/admin/base_site.html index 2bd6c82..eae91f6 100644 --- a/planetstack/templates/admin/base_site.html +++ b/planetstack/templates/admin/base_site.html @@ -1,18 +1,57 @@ {% extends "admin/base.html" %} -{% load i18n %} -{% block title %}{{ title }} | {% trans 'PlanetStack' %}{% endblock %} -{% block extrastyle %} - -{% endblock %} +{% load admin_static %} + +{# Additional content here, some extra meta tags or favicon #} +{#{% block extrahead %}#} +{#{% endblock %}#} + + +{# Additional CSS includes #} +{# {% block extrastyle %} #} +{# {% endblock %} #} + + +{# Additional JS files in footer, right before #} +{#{% block extrajs %}#} +{# #} +{#{% endblock %}#} -{% block branding %} -

{% trans 'PlanetStack Administration' %}

+ +{# Footer links (left side) #} +{#{% block footer_links %}#} +{# Documentation#} +{#{% endblock %}#} + +{# Additional header content like notifications or language switcher #} +{#{% block header_content %}#} +{# {{ block.super }}#} +{#
#} +{# #} +{#
#} +{#
#} +{# #} +{#
#} +{#
#} +{# Front-end
#} +{# One more link#} +{#
#} +{# #} +{#
#} +{# #} +{#
#} +{#
#} +{# 5 new messages#} +{#
#} +{#
#} +{#{% endblock %}#} + +{# Footer branding name (center) #} +{% block footer_branding %} +PlanetStack {% endblock %} -{% block nav-global %}{% endblock %} + +{# Footer copyright (right side) #} +{% block copyright %} +{# Copyright © 2013 Client
Developed by YourName #} +{% endblock %}