1
0
mirror of https://github.com/dkmstr/openuds.git synced 2024-12-22 13:34:04 +03:00

* Added "Service Pool Group" full logic, so new we can add services pools to groups, so we can visualzize them grouped. (already needs the visualizarion part)

* Finished basic taglist edition (fixed a bug & added the possibility of insert serveral comma separated values at once')
This commit is contained in:
Adolfo Gómez García 2016-02-12 04:47:44 +01:00
parent e1b8c43cca
commit a08fe53383
22 changed files with 349 additions and 29 deletions

View File

@ -52,7 +52,7 @@ class Authenticators(ModelHandler):
# Custom get method "search" that requires authenticator id # Custom get method "search" that requires authenticator id
custom_methods = [('search', True)] custom_methods = [('search', True)]
detail = {'users': Users, 'groups': Groups} detail = {'users': Users, 'groups': Groups}
save_fields = ['name', 'comments', 'priority', 'small_name'] save_fields = ['name', 'comments', 'tags', 'priority', 'small_name']
table_title = _('Current authenticators') table_title = _('Current authenticators')
table_fields = [ table_fields = [
@ -80,7 +80,7 @@ class Authenticators(ModelHandler):
def getGui(self, type_): def getGui(self, type_):
try: try:
return self.addDefaultFields(auths.factory().lookup(type_).guiDescription(), ['name', 'comments', 'priority', 'small_name']) return self.addDefaultFields(auths.factory().lookup(type_).guiDescription(), ['name', 'comments', 'tags', 'priority', 'small_name'])
except: except:
raise NotFound('type not found') raise NotFound('type not found')

View File

@ -53,7 +53,7 @@ class Calendars(ModelHandler):
model = Calendar model = Calendar
detail = {'rules': CalendarRules} detail = {'rules': CalendarRules}
save_fields = ['name', 'comments'] save_fields = ['name', 'comments', 'tags']
table_title = _('Calendars') table_title = _('Calendars')
table_fields = [ table_fields = [
@ -73,4 +73,4 @@ class Calendars(ModelHandler):
} }
def getGui(self, type_): def getGui(self, type_):
return self.addDefaultFields([], ['name', 'comments']) return self.addDefaultFields([], ['name', 'comments', 'tags'])

View File

@ -78,7 +78,7 @@ class Images(ModelHandler):
'value': '', 'value': '',
'label': ugettext('Image'), 'label': ugettext('Image'),
'tooltip': ugettext('Image object'), 'tooltip': ugettext('Image object'),
'type': gui.InputField.IMAGE_TYPE, 'type': gui.InputField.IMAGECHOICE_TYPE,
'order': 100, # At end 'order': 100, # At end
} }
) )

View File

@ -53,7 +53,7 @@ class Networks(ModelHandler):
Implements specific handling for network related requests using GUI Implements specific handling for network related requests using GUI
''' '''
model = Network model = Network
save_fields = ['name', 'net_string'] save_fields = ['name', 'net_string', 'tags']
table_title = _('Current Networks') table_title = _('Current Networks')
table_fields = [ table_fields = [
@ -74,7 +74,7 @@ class Networks(ModelHandler):
def getGui(self, type_): def getGui(self, type_):
return self.addField( return self.addField(
self.addDefaultFields([], ['name']), { self.addDefaultFields([], ['name', 'tags']), {
'name': 'net_string', 'name': 'net_string',
'value': '', 'value': '',
'label': ugettext('Network range'), 'label': ugettext('Network range'),

View File

@ -50,7 +50,7 @@ logger = logging.getLogger(__name__)
class OsManagers(ModelHandler): class OsManagers(ModelHandler):
model = OSManager model = OSManager
save_fields = ['name', 'comments'] save_fields = ['name', 'comments', 'tags']
table_title = _('Current OS Managers') table_title = _('Current OS Managers')
table_fields = [ table_fields = [
@ -89,6 +89,6 @@ class OsManagers(ModelHandler):
# Gui related # Gui related
def getGui(self, type_): def getGui(self, type_):
try: try:
return self.addDefaultFields(factory().lookup(type_).guiDescription(), ['name', 'comments']) return self.addDefaultFields(factory().lookup(type_).guiDescription(), ['name', 'comments', 'tags'])
except: except:
raise NotFound('type not found') raise NotFound('type not found')

View File

@ -56,7 +56,7 @@ class Providers(ModelHandler):
detail = {'services': DetailServices} detail = {'services': DetailServices}
custom_methods = [('allservices', False), ('service', False), ('maintenance', True)] custom_methods = [('allservices', False), ('service', False), ('maintenance', True)]
save_fields = ['name', 'comments'] save_fields = ['name', 'comments', 'tags']
table_title = _('Service providers') table_title = _('Service providers')

View File

@ -35,7 +35,7 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from uds.models import Service, UserService from uds.models import Service, UserService, Tag
from uds.core.services import Service as coreService from uds.core.services import Service as coreService
from uds.core.util import log from uds.core.util import log
@ -130,7 +130,9 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
# Extract item db fields # Extract item db fields
# We need this fields for all # We need this fields for all
logger.debug('Saving service {0} / {1}'.format(parent, item)) logger.debug('Saving service {0} / {1}'.format(parent, item))
fields = self.readFieldsFromParams(['name', 'comments', 'data_type']) fields = self.readFieldsFromParams(['name', 'comments', 'data_type', 'tags'])
tags = fields['tags']
del fields['tags']
service = None service = None
try: try:
if item is None: # Create new if item is None: # Create new
@ -139,6 +141,8 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
service = parent.services.get(uuid=processUuid(item)) service = parent.services.get(uuid=processUuid(item))
service.__dict__.update(fields) service.__dict__.update(fields)
service.tags = [Tag.objects.get_or_create(tag=val)[0] for val in tags]
service.data = service.getInstance(self._params).serialize() service.data = service.getInstance(self._params).serialize()
service.save() service.save()
except Service.DoesNotExist: except Service.DoesNotExist:
@ -209,7 +213,7 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
parentInstance = parent.getInstance() parentInstance = parent.getInstance()
serviceType = parentInstance.getServiceByType(forType) serviceType = parentInstance.getServiceByType(forType)
service = serviceType(Environment.getTempEnv(), parentInstance) # Instantiate it so it has the opportunity to alter gui description based on parent service = serviceType(Environment.getTempEnv(), parentInstance) # Instantiate it so it has the opportunity to alter gui description based on parent
return self.addDefaultFields(service.guiDescription(service), ['name', 'comments']) return self.addDefaultFields(service.guiDescription(service), ['name', 'comments', 'tags'])
except Exception as e: except Exception as e:
logger.exception('getGui') logger.exception('getGui')
raise ResponseError(unicode(e)) raise ResponseError(unicode(e))

View File

@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
@itemor: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _, ugettext
from uds.models import ServicesPoolGroup, Image
from uds.core.util.model import processUuid
from uds.core.ui.UserInterface import gui
from uds.core.ui.images import DEFAULT_THUMB_BASE64
from uds.REST.model import ModelHandler
import logging
logger = logging.getLogger(__name__)
# Enclosed methods under /item path
class ServicesPoolGroups(ModelHandler):
'''
Handles the gallery REST interface
'''
needs_admin = True
path = 'gallery'
model = ServicesPoolGroup
save_fields = ['name', 'comments', 'image_id']
table_title = _('Services Pool Groups')
table_fields = [
{'name': {'title': _('Name')}},
{'thumb': {'title': _('Image'), 'visible': True, 'type': 'image'}},
]
def beforeSave(self, fields):
imgId = fields['image_id']
fields['image_id'] = None
logger.debug('Image id: {}'.format(imgId))
try:
if imgId != '-1':
image = Image.objects.get(uuid=processUuid(imgId))
fields['image_id'] = image.id
except Exception:
logger.exception('At image recovering')
# Gui related
def getGui(self, type_):
g = self.addDefaultFields([], ['name', 'comments'])
for f in [{
'name': 'image_id',
'values': [gui.choiceImage(-1, '--------', DEFAULT_THUMB_BASE64)] + gui.sortedChoices([gui.choiceImage(v.uuid, v.name, v.thumb64) for v in Image.objects.all()]),
'label': ugettext('Associated Image'),
'tooltip': ugettext('Image assocciated with this service'),
'type': gui.InputField.IMAGECHOICE_TYPE,
'order': 102,
}]:
self.addField(g, f)
return g
def item_as_dict(self, item):
return {
'id': item.uuid,
'name': item.name,
'image_id': item.image.uuid,
}
def item_as_dict_overview(self, item):
return {
'id': item.uuid,
'name': item.name,
'thumb': item.image.thumb64,
}

View File

@ -33,7 +33,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.utils.translation import ugettext, ugettext_lazy as _ from django.utils.translation import ugettext, ugettext_lazy as _
from uds.models import DeployedService, OSManager, Service, Image from uds.models import DeployedService, OSManager, Service, Image, ServicesPoolGroup
from uds.core.ui.images import DEFAULT_THUMB_BASE64 from uds.core.ui.images import DEFAULT_THUMB_BASE64
from uds.core.util.State import State from uds.core.util.State import State
from uds.core.util.model import processUuid from uds.core.util.model import processUuid
@ -64,7 +64,7 @@ class ServicesPools(ModelHandler):
'changelog': Changelog 'changelog': Changelog
} }
save_fields = ['name', 'comments', 'service_id', 'osmanager_id', 'image_id', 'initial_srvs', 'cache_l1_srvs', 'cache_l2_srvs', 'max_srvs', 'show_transports'] save_fields = ['name', 'comments', 'tags', 'service_id', 'osmanager_id', 'image_id', 'servicesPoolGroup_id', 'initial_srvs', 'cache_l1_srvs', 'cache_l2_srvs', 'max_srvs', 'show_transports']
remove_fields = ['osmanager_id', 'service_id'] remove_fields = ['osmanager_id', 'service_id']
table_title = _('Service Pools') table_title = _('Service Pools')
@ -73,7 +73,7 @@ class ServicesPools(ModelHandler):
{'parent': {'title': _('Parent Service')}}, {'parent': {'title': _('Parent Service')}},
{'state': {'title': _('status'), 'type': 'dict', 'dict': State.dictionary()}}, {'state': {'title': _('status'), 'type': 'dict', 'dict': State.dictionary()}},
{'show_transports': {'title': _('Shows transports'), 'type': 'callback'}}, {'show_transports': {'title': _('Shows transports'), 'type': 'callback'}},
{'comments': {'title': _('Comments')}}, {'servicesPoolGroup': {'title': _('Services Pool Group')}},
] ]
# Field from where to get "class" and prefix for that class, so this will generate "row-state-A, row-state-X, .... # Field from where to get "class" and prefix for that class, so this will generate "row-state-A, row-state-X, ....
table_row_style = {'field': 'state', 'prefix': 'row-state-'} table_row_style = {'field': 'state', 'prefix': 'row-state-'}
@ -93,6 +93,8 @@ class ServicesPools(ModelHandler):
'service_id': item.service.uuid, 'service_id': item.service.uuid,
'provider_id': item.service.provider.uuid, 'provider_id': item.service.provider.uuid,
'image_id': item.image.uuid if item.image is not None else None, 'image_id': item.image.uuid if item.image is not None else None,
'servicesPoolGroup_id': item.servicesPoolGroup.uuid if item.servicesPoolGroup is not None else None,
'servicesPoolGroup': item.servicesPoolGroup.name if item.servicesPoolGroup is not None else _('Default'),
'initial_srvs': item.initial_srvs, 'initial_srvs': item.initial_srvs,
'cache_l1_srvs': item.cache_l1_srvs, 'cache_l1_srvs': item.cache_l1_srvs,
'cache_l2_srvs': item.cache_l2_srvs, 'cache_l2_srvs': item.cache_l2_srvs,
@ -116,7 +118,7 @@ class ServicesPools(ModelHandler):
if Service.objects.count() < 1: if Service.objects.count() < 1:
raise ResponseError(ugettext('Create at least a service before creating a new service pool')) raise ResponseError(ugettext('Create at least a service before creating a new service pool'))
g = self.addDefaultFields([], ['name', 'comments']) g = self.addDefaultFields([], ['name', 'comments', 'tags'])
for f in [{ for f in [{
'name': 'service_id', 'name': 'service_id',
@ -141,6 +143,13 @@ class ServicesPools(ModelHandler):
'tooltip': ugettext('Image assocciated with this service'), 'tooltip': ugettext('Image assocciated with this service'),
'type': gui.InputField.IMAGECHOICE_TYPE, 'type': gui.InputField.IMAGECHOICE_TYPE,
'order': 102, 'order': 102,
}, {
'name': 'servicesPoolGroup_id',
'values': [gui.choiceImage(-1, _('Default'), DEFAULT_THUMB_BASE64)] + gui.sortedChoices([gui.choiceImage(v.uuid, v.name, v.image.thumb64) for v in ServicesPoolGroup.objects.all()]),
'label': ugettext('Pool group'),
'tooltip': ugettext('Pool group for this pool (for pool clasify on display)'),
'type': gui.InputField.IMAGECHOICE_TYPE,
'order': 103,
}, { }, {
'name': 'initial_srvs', 'name': 'initial_srvs',
'value': '0', 'value': '0',
@ -148,7 +157,7 @@ class ServicesPools(ModelHandler):
'label': ugettext('Initial available services'), 'label': ugettext('Initial available services'),
'tooltip': ugettext('Services created initially for this service pool'), 'tooltip': ugettext('Services created initially for this service pool'),
'type': gui.InputField.NUMERIC_TYPE, 'type': gui.InputField.NUMERIC_TYPE,
'order': 103, 'order': 110,
}, { }, {
'name': 'cache_l1_srvs', 'name': 'cache_l1_srvs',
'value': '0', 'value': '0',
@ -156,7 +165,7 @@ class ServicesPools(ModelHandler):
'label': ugettext('Services to keep in cache'), 'label': ugettext('Services to keep in cache'),
'tooltip': ugettext('Services kept in cache for improved user service assignation'), 'tooltip': ugettext('Services kept in cache for improved user service assignation'),
'type': gui.InputField.NUMERIC_TYPE, 'type': gui.InputField.NUMERIC_TYPE,
'order': 104, 'order': 111,
}, { }, {
'name': 'cache_l2_srvs', 'name': 'cache_l2_srvs',
'value': '0', 'value': '0',
@ -164,7 +173,7 @@ class ServicesPools(ModelHandler):
'label': ugettext('Services to keep in L2 cache'), 'label': ugettext('Services to keep in L2 cache'),
'tooltip': ugettext('Services kept in cache of level2 for improved service generation'), 'tooltip': ugettext('Services kept in cache of level2 for improved service generation'),
'type': gui.InputField.NUMERIC_TYPE, 'type': gui.InputField.NUMERIC_TYPE,
'order': 105, 'order': 112,
}, { }, {
'name': 'max_srvs', 'name': 'max_srvs',
'value': '0', 'value': '0',
@ -172,14 +181,14 @@ class ServicesPools(ModelHandler):
'label': ugettext('Maximum number of services to provide'), 'label': ugettext('Maximum number of services to provide'),
'tooltip': ugettext('Maximum number of service (assigned and L1 cache) that can be created for this service'), 'tooltip': ugettext('Maximum number of service (assigned and L1 cache) that can be created for this service'),
'type': gui.InputField.NUMERIC_TYPE, 'type': gui.InputField.NUMERIC_TYPE,
'order': 106, 'order': 113,
}, { }, {
'name': 'show_transports', 'name': 'show_transports',
'value': True, 'value': True,
'label': ugettext('Show transports'), 'label': ugettext('Show transports'),
'tooltip': ugettext('If active, alternative transports for user will be shown'), 'tooltip': ugettext('If active, alternative transports for user will be shown'),
'type': gui.InputField.CHECKBOX_TYPE, 'type': gui.InputField.CHECKBOX_TYPE,
'order': 107, 'order': 120,
}]: }]:
self.addField(g, f) self.addField(g, f)
@ -226,6 +235,17 @@ class ServicesPools(ModelHandler):
except Exception: except Exception:
logger.exception('At image recovering') logger.exception('At image recovering')
# Servicepool Group
spgrpId = fields['servicesPoolGroup_id']
fields['servicesPoolGroup_id'] = None
logger.debug('servicesPoolGroup_id: {}'.format(spgrpId))
try:
if imgId != '-1':
spgrp = ServicesPoolGroup.objects.get(uuid=processUuid(spgrpId))
fields['servicesPoolGroup_id'] = spgrp.id
except Exception:
logger.exception('At service pool group recovering')
except (RequestError, ResponseError): except (RequestError, ResponseError):
raise raise
except Exception as e: except Exception as e:

View File

@ -48,7 +48,7 @@ logger = logging.getLogger(__name__)
class Transports(ModelHandler): class Transports(ModelHandler):
model = Transport model = Transport
save_fields = ['name', 'comments', 'priority', 'nets_positive'] save_fields = ['name', 'comments', 'tags', ' priority', 'nets_positive']
table_title = _('Current Transports') table_title = _('Current Transports')
table_fields = [ table_fields = [
@ -64,7 +64,7 @@ class Transports(ModelHandler):
def getGui(self, type_): def getGui(self, type_):
try: try:
return self.addField( return self.addField(
self.addField(self.addDefaultFields(factory().lookup(type_).guiDescription(), ['name', 'comments', 'priority']), { self.addField(self.addDefaultFields(factory().lookup(type_).guiDescription(), ['name', 'comments', 'tags', 'priority']), {
'name': 'nets_positive', 'name': 'nets_positive',
'value': True, 'value': True,
'label': ugettext('Network access'), 'label': ugettext('Network access'),

View File

@ -42,6 +42,8 @@ from uds.REST.handlers import Handler, HandlerError
from uds.core.util import log from uds.core.util import log
from uds.core.util import permissions from uds.core.util import permissions
from uds.core.util.model import processUuid from uds.core.util.model import processUuid
from uds.models import Tag
import fnmatch import fnmatch
import re import re
@ -52,7 +54,7 @@ import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
__updated__ = '2016-02-10' __updated__ = '2016-02-12'
# a few constants # a few constants
@ -841,6 +843,13 @@ class ModelHandler(BaseModelHandler):
args = self.readFieldsFromParams(self.save_fields) args = self.readFieldsFromParams(self.save_fields)
logger.debug('Args: {}'.format(args)) logger.debug('Args: {}'.format(args))
self.beforeSave(args) self.beforeSave(args)
# If tags is in save fields, treat it "specially"
if 'tags' in self.save_fields:
tags = args['tags']
del args['tags']
else:
tags = None
deleteOnError = False deleteOnError = False
if len(self._args) == 0: # create new if len(self._args) == 0: # create new
item = self.model.objects.create(**args) item = self.model.objects.create(**args)
@ -852,6 +861,12 @@ class ModelHandler(BaseModelHandler):
if v in args: if v in args:
del args[v] del args[v]
item.__dict__.update(args) # Update fields from args item.__dict__.update(args) # Update fields from args
# Now if tags, update them
if tags is not None:
logger.debug('Updating tags: {}'.format(tags))
item.tags = [ Tag.objects.get_or_create(tag=val)[0] for val in tags]
except self.model.DoesNotExist: except self.model.DoesNotExist:
raise NotFound('Item not found') raise NotFound('Item not found')
except IntegrityError: # Duplicate key probably except IntegrityError: # Duplicate key probably

View File

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('uds', '0019_auto_20160210_0144'),
]
operations = [
migrations.CreateModel(
name='ServicesPoolGroup',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('uuid', models.CharField(default=None, max_length=50, unique=True, null=True)),
('name', models.CharField(default='', max_length=128)),
('comments', models.CharField(default='', max_length=256)),
('image', models.ForeignKey(related_name='servicesPoolsGrou', on_delete=django.db.models.deletion.SET_NULL, blank=True, to='uds.Image', null=True)),
],
options={
'abstract': False,
'db_table': 'uds__pools_groups',
},
),
migrations.AddField(
model_name='deployedservice',
name='servicesPoolGroup',
field=models.ForeignKey(related_name='servicesPools', on_delete=django.db.models.deletion.SET_NULL, blank=True, to='uds.ServicesPoolGroup', null=True),
),
]

View File

@ -49,6 +49,7 @@ from uds.models.Service import Service
from uds.models.Transport import Transport from uds.models.Transport import Transport
from uds.models.Group import Group from uds.models.Group import Group
from uds.models.Image import Image from uds.models.Image import Image
from uds.models.ServicesPoolGroup import ServicesPoolGroup
from uds.models.Util import NEVER from uds.models.Util import NEVER
from uds.models.Util import getSqlDatetime from uds.models.Util import getSqlDatetime
@ -56,7 +57,7 @@ from uds.models.Util import getSqlDatetime
from datetime import timedelta from datetime import timedelta
import logging import logging
__updated__ = '2016-02-10' __updated__ = '2016-02-12'
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -78,12 +79,16 @@ class DeployedService(UUIDModel, TaggingMixin):
state_date = models.DateTimeField(default=NEVER) state_date = models.DateTimeField(default=NEVER)
show_transports = models.BooleanField(default=True) show_transports = models.BooleanField(default=True)
image = models.ForeignKey(Image, null=True, blank=True, related_name='deployedServices', on_delete=models.SET_NULL) image = models.ForeignKey(Image, null=True, blank=True, related_name='deployedServices', on_delete=models.SET_NULL)
servicesPoolGroup = models.ForeignKey(ServicesPoolGroup, null=True, blank=True, related_name='servicesPools', on_delete=models.SET_NULL)
initial_srvs = models.PositiveIntegerField(default=0) initial_srvs = models.PositiveIntegerField(default=0)
cache_l1_srvs = models.PositiveIntegerField(default=0) cache_l1_srvs = models.PositiveIntegerField(default=0)
cache_l2_srvs = models.PositiveIntegerField(default=0) cache_l2_srvs = models.PositiveIntegerField(default=0)
max_srvs = models.PositiveIntegerField(default=0) max_srvs = models.PositiveIntegerField(default=0)
current_pub_revision = models.PositiveIntegerField(default=1) current_pub_revision = models.PositiveIntegerField(default=1)
# Meta service related # Meta service related
meta_pools = models.ManyToManyField('self', symmetrical=False) meta_pools = models.ManyToManyField('self', symmetrical=False)

View File

@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012 Virtual Cable S.L.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
'''
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from django.db import models
from django.db.models import signals
from django.utils.encoding import python_2_unicode_compatible
from uds.models.UUIDModel import UUIDModel
from uds.models.Image import Image
import logging
__updated__ = '2016-02-12'
logger = logging.getLogger(__name__)
@python_2_unicode_compatible
class ServicesPoolGroup(UUIDModel):
'''
A deployed service is the Service produced element that is assigned finally to an user (i.e. a Virtual Machine, etc..)
'''
# pylint: disable=model-missing-unicode
name = models.CharField(max_length=128, default='')
comments = models.CharField(max_length=256, default='')
image = models.ForeignKey(Image, null=True, blank=True, related_name='servicesPoolsGrou', on_delete=models.SET_NULL)
class Meta(UUIDModel.Meta):
'''
Meta class to declare the name of the table at database
'''
db_table = 'uds__pools_groups'
app_label = 'uds'
def __str__(self):
return u"Service Pool group {0}({1})".format(self.name, self.comments)

View File

@ -65,6 +65,7 @@ from .Group import Group
# Provisioned services # Provisioned services
from .ServicesPool import DeployedService # Old name, will continue here for a while already from .ServicesPool import DeployedService # Old name, will continue here for a while already
from .ServicesPool import ServicePool # New name from .ServicesPool import ServicePool # New name
from .ServicesPoolGroup import ServicesPoolGroup
from .ServicesPoolPublication import DeployedServicePublication from .ServicesPoolPublication import DeployedServicePublication
from .UserService import UserService from .UserService import UserService
from .UserServiceProperty import UserServiceProperty from .UserServiceProperty import UserServiceProperty
@ -101,7 +102,7 @@ from .CalendarRule import CalendarRule
# Tagging # Tagging
from .Tag import Tag from .Tag import Tag
__updated__ = '2016-02-10' __updated__ = '2016-02-12'
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -425,6 +425,7 @@ api.networks = new BasicModelRest("networks")
api.servicesPools = new BasicModelRest("servicespools") api.servicesPools = new BasicModelRest("servicespools")
api.configuration = new BasicModelRest("config") api.configuration = new BasicModelRest("config")
api.gallery = new BasicModelRest("gallery/images") api.gallery = new BasicModelRest("gallery/images")
api.sPoolGroups = new BasicModelRest("gallery/servicespoolgroups")
api.system = new BasicModelRest("system") api.system = new BasicModelRest("system")
api.reports = new BasicModelRest("reports") # Not fully used, but basic usage is common api.reports = new BasicModelRest("reports") # Not fully used, but basic usage is common
api.calendars = new BasicModelRest("calendars") api.calendars = new BasicModelRest("calendars")

View File

@ -0,0 +1,28 @@
gui.sPoolGroups = new GuiElement(api.sPoolGroups, "spal")
gui.sPoolGroups.link = ->
gui.doLog 'Executing pool groups'
"use strict"
if api.config.admin is false
return
api.templates.get "services_pool_groups", (tmpl) ->
gui.clearWorkspace()
gui.appendToWorkspace api.templates.evaluate(tmpl,
sPoolGroups: "sPoolGroups-placeholder"
)
gui.sPoolGroups.table
icon: 'sPoolGroups'
container: "sPoolGroups-placeholder"
rowSelect: "single"
buttons: [
"new"
"edit"
"delete"
]
onNew: gui.methods.typedNew(gui.sPoolGroups, gettext("New services Services Pool Group"), gettext("Services Services Pool Group creation error"))
onEdit: gui.methods.typedEdit(gui.sPoolGroups, gettext("Edit services Services Pool Group"), gettext("Services Provider saving error"))
onDelete: gui.methods.del(gui.sPoolGroups, gettext("Delete Services Pool Group"), gettext("Services Pool Group error"))
return
return

View File

@ -240,6 +240,11 @@
exec: gui.calendars.link exec: gui.calendars.link
cleanup: true cleanup: true
} }
{
id: "lnk-spoolsgroup"
exec: gui.sPoolGroups.link
cleanup: true
}
] ]
$.each sidebarLinks, (index, value) -> $.each sidebarLinks, (index, value) ->
gui.doLog "Adding " + value.id gui.doLog "Adding " + value.id

View File

@ -121,6 +121,7 @@
<script type="text/coffeescript" charset="utf-8" src="{% get_static_prefix %}adm/js/gui-d-servicespools.coffee"></script> <script type="text/coffeescript" charset="utf-8" src="{% get_static_prefix %}adm/js/gui-d-servicespools.coffee"></script>
<script type="text/coffeescript" charset="utf-8" src="{% get_static_prefix %}adm/js/gui-d-config.coffee"></script> <script type="text/coffeescript" charset="utf-8" src="{% get_static_prefix %}adm/js/gui-d-config.coffee"></script>
<script type="text/coffeescript" charset="utf-8" src="{% get_static_prefix %}adm/js/gui-d-gallery.coffee"></script> <script type="text/coffeescript" charset="utf-8" src="{% get_static_prefix %}adm/js/gui-d-gallery.coffee"></script>
<script type="text/coffeescript" charset="utf-8" src="{% get_static_prefix %}adm/js/gui-d-servicespoolsgroup.coffee"></script>
<script type="text/coffeescript" charset="utf-8" src="{% get_static_prefix %}adm/js/gui-d-reports.coffee"></script> <script type="text/coffeescript" charset="utf-8" src="{% get_static_prefix %}adm/js/gui-d-reports.coffee"></script>
<script type="text/coffeescript" charset="utf-8" src="{% get_static_prefix %}adm/js/gui-d-calendar.coffee"></script> <script type="text/coffeescript" charset="utf-8" src="{% get_static_prefix %}adm/js/gui-d-calendar.coffee"></script>
<!-- base64 encoding --> <!-- base64 encoding -->

View File

@ -30,6 +30,7 @@
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><img class="icon" src="{{ STATIC_URL }}/adm/img/icons/tools.png"/> <span class="menu-lnk">{% trans 'Tools' %} <b class="caret"></b></span></a> <a href="#" class="dropdown-toggle" data-toggle="dropdown"><img class="icon" src="{{ STATIC_URL }}/adm/img/icons/tools.png"/> <span class="menu-lnk">{% trans 'Tools' %} <b class="caret"></b></span></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a class="lnk-gallery" href="#"><img class="icon" src="{{ STATIC_URL }}/adm/img/icons/gallery.png"/> <span class="menu-lnk">{% trans 'Gallery' %}</span></a></li> <li><a class="lnk-gallery" href="#"><img class="icon" src="{{ STATIC_URL }}/adm/img/icons/gallery.png"/> <span class="menu-lnk">{% trans 'Gallery' %}</span></a></li>
<li><a class="lnk-spoolsgroup" href="#"><img class="icon" src="{{ STATIC_URL }}/adm/img/icons/groups.png"/> <span class="menu-lnk">{% trans 'Services Pool Group' %}</span></a></li>
<li><a class="lnk-reports" href=""><img class="icon" src="{{ STATIC_URL }}/adm/img/icons/reports.png"/> <span class="menu-lnk">{% trans 'Reports' %}</a></span></li> <li><a class="lnk-reports" href=""><img class="icon" src="{{ STATIC_URL }}/adm/img/icons/reports.png"/> <span class="menu-lnk">{% trans 'Reports' %}</a></span></li>
<li><a class="lnk-configuration" href="#"><img class="icon" src="{{ STATIC_URL }}/adm/img/icons/configuration.png"/> <span class="menu-lnk">{% trans 'Configuration' %}</span></a></li> <li><a class="lnk-configuration" href="#"><img class="icon" src="{{ STATIC_URL }}/adm/img/icons/configuration.png"/> <span class="menu-lnk">{% trans 'Configuration' %}</span></a></li>
<li><a class="lnk-clear_cache" href="#"><img class="icon" src="{{ STATIC_URL }}/adm/img/icons/flush-cache.png"/> <span class="menu-lnk">{% trans 'Flush cache' %}</span></a></li> <li><a class="lnk-clear_cache" href="#"><img class="icon" src="{{ STATIC_URL }}/adm/img/icons/flush-cache.png"/> <span class="menu-lnk">{% trans 'Flush cache' %}</span></a></li>

View File

@ -8,7 +8,7 @@
<span class="label label-success tag tagadder" id="adder{{ id }}">{% endverbatim %}{% trans 'Add Tag...' %}{% verbatim %}</span> <span class="label label-success tag tagadder" id="adder{{ id }}">{% endverbatim %}{% trans 'Add Tag...' %}{% verbatim %}</span>
{{/ unless }} {{/ unless }}
<input id="h{{ id }}" type="hidden" data-uds="list" name="{{ name }}" value="{{ value }}" class="{{ css }}" /> <input id="h{{ id }}" type="hidden" data-uds="commaList" name="{{ name }}" value="{{ value }}" class="{{ css }}" />
{% endverbatim %} {% endverbatim %}
{% comment %}<script>/*This is a little trick to make IDE recognize sintax hightlight, will not be show on render :-)*/{% endcomment %} {% comment %}<script>/*This is a little trick to make IDE recognize sintax hightlight, will not be show on render :-)*/{% endcomment %}
@ -44,7 +44,9 @@
// Tagadder never gets destroyed, so we only set the event once // Tagadder never gets destroyed, so we only set the event once
$('#adder{{ id }}').on('click', function(){ $('#adder{{ id }}').on('click', function(){
var text = prompt('Enter new tag'); var text = prompt('Enter new tag');
addTag(text); $.each( text.split(','), function (idx, value) {
addTag(value);
});
}); });
{{/ unless }} {{/ unless }}

View File

@ -0,0 +1,28 @@
{% load i18n html5 static %}
<div class="row">
<div class="col-xs-12">
<h1>{% trans 'UDS Services Pool Groups' %}</h1>
<!-- <ol class="breadcrumb">
<li><a class="lnk-dashboard" href="#">Dashboard</a></li>
<li>{% trans 'Gallery' %}</li>
</ol> -->
</div>
</div><!-- /.row -->
{% if messages %}
<div class="row">
<div class="col-md-offset-2 col-md-8">
{% for message in messages %}
<div class="alert alert-danger alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
{{ message }}
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% verbatim %}
<div class="row">
<div id="{{ sPoolGroups }}" class="col-xs-12"></div>
</div>
{% endverbatim %}