Needs more testing, but permission delegation seems to work right now.

This commit is contained in:
Adolfo Gómez García 2015-03-05 15:20:46 +01:00
parent 6387629e7e
commit 2435f589b9
24 changed files with 663 additions and 539 deletions

View File

@ -37,11 +37,13 @@ from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _, activate
from django.conf import settings
from uds.REST.handlers import Handler, HandlerError, AccessDenied, NotFound, RequestError, ResponseError
from uds.REST.handlers import Handler, HandlerError, AccessDenied, NotFound, RequestError, ResponseError, NotSupportedError
import time
import logging
import six
logger = logging.getLogger(__name__)
__all__ = [str(v) for v in ['Handler', 'Dispatcher']]
@ -142,18 +144,20 @@ class Dispatcher(View):
response[k] = val
return response
except RequestError as e:
return http.HttpResponseBadRequest(unicode(e))
return http.HttpResponseBadRequest(six.text_type(e))
except ResponseError as e:
return http.HttpResponseServerError(unicode(e))
return http.HttpResponseServerError(six.text_type(e))
except NotSupportedError as e:
return http.HttpResponseBadRequest(six.text_type(e))
except AccessDenied as e:
return http.HttpResponseForbidden(unicode(e))
return http.HttpResponseForbidden(six.text_type(e))
except NotFound as e:
return http.HttpResponseNotFound(unicode(e))
return http.HttpResponseNotFound(six.text_type(e))
except HandlerError as e:
return http.HttpResponseBadRequest(unicode(e))
return http.HttpResponseBadRequest(six.text_type(e))
except Exception as e:
logger.exception('Error processing request')
return http.HttpResponseServerError(unicode(e))
return http.HttpResponseServerError(six.text_type(e))
@staticmethod
def registerSubclasses(classes):

View File

@ -82,6 +82,13 @@ class ResponseError(HandlerError):
pass
class NotSupportedError(HandlerError):
'''
Some elements do not support some operations (as searching over an authenticator that does not supports it)
'''
pass
class Handler(object):
'''
REST requests handler base class
@ -110,6 +117,7 @@ class Handler(object):
self._kwargs = kwargs
self._headers = {}
self._authToken = None
self._user = None
if self.authenticated: # Only retrieve auth related data on authenticated handlers
try:
self._authToken = self._request.META.get(AUTH_TOKEN_HEADER, '')
@ -129,6 +137,8 @@ class Handler(object):
if self.needs_staff and not self.getValue('staff_member'):
raise AccessDenied()
self._user = self.getUser()
def headers(self):
'''
Returns the headers of the REST request (all)
@ -253,6 +263,7 @@ class Handler(object):
'''
If user is staff member, returns his Associated user on auth
'''
logger.debug('REST : {}'.format(self._session))
authId = self.getValue('auth')
username = self.getValue('username')
# Maybe it's root user??

View File

@ -39,6 +39,7 @@ from uds.core import auths
from users_groups import Users, Groups
from uds.REST import NotFound
from uds.REST.model import ModelHandler
from uds.core.util import permissions
import logging
@ -93,10 +94,12 @@ class Authenticators(ModelHandler):
'small_name': auth.small_name,
'users_count': auth.users.count(),
'type': type_.type(),
'permission': permissions.getEffectivePermission(self._user, auth)
}
# Custom "search" method
def search(self, item):
self.ensureAccess(item, permissions.PERMISSION_READ)
try:
type_ = self._params['type']
if type_ not in ('user', 'group'):
@ -108,7 +111,7 @@ class Authenticators(ModelHandler):
canDoSearch = type_ == 'user' and (auth.searchUsers != auths.Authenticator.searchUsers) or (auth.searchGroups != auths.Authenticator.searchGroups)
if canDoSearch is False:
self.invalidRequestException()
self.notSupported()
if type_ == 'user':
return auth.searchUsers(term)
@ -121,6 +124,8 @@ class Authenticators(ModelHandler):
from uds.core.Environment import Environment
authType = auths.factory().lookup(type_)
self.ensureAccess(authType, permissions.PERMISSION_MANAGEMENT, root=True)
dct = self._params.copy()
dct['_request'] = self._request
res = authType.test(Environment.getTempEnv(), dct)

View File

@ -35,6 +35,7 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _, ugettext
from uds.models import Network
from uds.core.util import net
from uds.core.util import permissions
from uds.core.ui.UserInterface import gui
from uds.REST.model import ModelHandler, SaveException
@ -89,4 +90,5 @@ class Networks(ModelHandler):
'name': item.name,
'net_string': item.net_string,
'networks_count': item.transports.count(),
'permission': permissions.getEffectivePermission(self._user, item)
}

View File

@ -33,8 +33,8 @@
from __future__ import unicode_literals
from django.utils.translation import ugettext, ugettext_lazy as _
from django.conf import settings
from uds.models import OSManager
from uds.core.util import permissions
from uds.REST import NotFound, RequestError
from uds.core.osmanagers import factory
@ -59,8 +59,7 @@ class OsManagers(ModelHandler):
{'deployed_count': {'title': _('Used by'), 'type': 'numeric', 'width': '8em'}}
]
@staticmethod
def osmToDict(osm):
def osmToDict(self, osm):
type_ = osm.getType()
return {
'id': osm.uuid,
@ -68,10 +67,11 @@ class OsManagers(ModelHandler):
'deployed_count': osm.deployedServices.count(),
'type': type_.type(),
'comments': osm.comments,
'permission': permissions.getEffectivePermission(self._user, osm)
}
def item_as_dict(self, item):
return OsManagers.osmToDict(item)
return self.osmToDict(item)
def checkDelete(self, item):
if item.deployedServices.count() > 0:

View File

@ -38,7 +38,7 @@ from uds.REST import Handler
from uds.REST import RequestError
from uds.core.util import permissions
from uds.models import Provider, Service, Authenticator, OSManager, Transport, Network, ServicesPool
from uds.models import Provider, Service, Authenticator, OSManager, Transport, Network, ServicePool
from uds.models import User, Group
import six
@ -64,7 +64,7 @@ class Permissions(Handler):
'osmanagers': OSManager,
'transports': Transport,
'networks': Network,
'servicespools': ServicesPool
'servicespools': ServicePool
}.get(arg, None)
if cls is None:
@ -84,16 +84,17 @@ class Permissions(Handler):
entity = perm.user
res.append({
'id': perm.uuid,
'type': kind,
'auth': entity.manager.uuid,
'auth_name': entity.manager.name,
'id': entity.uuid,
'name': entity.name,
'entity_id': entity.uuid,
'entity_name': entity.name,
'perm': perm.permission,
'perm_name': perm.permission_as_string
})
return sorted(res, key=lambda v: v['auth_name'] + v['name'])
return sorted(res, key=lambda v: v['auth_name'] + v['entity_name'])
def get(self):
'''
@ -115,28 +116,36 @@ class Permissions(Handler):
'''
Processes post requests
'''
if len(self._args) != 4:
raise RequestError('Invalid request')
logger.debug('Put args: {}'.format(self._args))
perm = {
'0': permissions.PERMISSION_NONE,
'1': permissions.PERMISSION_READ,
'2': permissions.PERMISSION_ALL
}.get(self._params.get('perm', '0'), permissions.PERMISSION_NONE)
la = len(self._args)
cls = Permissions.getClass(self._args[0])
if la == 5 and self._args[3] == 'add':
perm = {
'0': permissions.PERMISSION_NONE,
'1': permissions.PERMISSION_READ,
'2': permissions.PERMISSION_MANAGEMENT,
'3': permissions.PERMISSION_ALL
}.get(self._params.get('perm', '0'), permissions.PERMISSION_NONE)
obj = cls.objects.get(uuid=self._args[1])
cls = Permissions.getClass(self._args[0])
if self._args[2] == 'users':
user = User.objects.get(uuid=self._args[3])
permissions.addUserPermission(user, obj, perm)
elif self._args[2] == 'groups':
group = Group.objects.get(uuid=self._args[3])
permissions.addGroupPermission(group, obj, perm)
obj = cls.objects.get(uuid=self._args[1])
if self._args[2] == 'users':
user = User.objects.get(uuid=self._args[4])
permissions.addUserPermission(user, obj, perm)
elif self._args[2] == 'groups':
group = Group.objects.get(uuid=self._args[4])
permissions.addGroupPermission(group, obj, perm)
else:
raise RequestError('Ivalid request')
return Permissions.permsToDict(permissions.getPermissions(obj))
elif la == 1 and self._args[0] == 'revoke':
items = self._params.get('items', [])
for permId in items:
permissions.revokePermissionById(permId)
return {}
else:
raise RequestError('Ivalid request')
return Permissions.permsToDict(permissions.getPermissions(obj))
raise RequestError('Invalid request')

View File

@ -36,6 +36,7 @@ from django.utils.translation import ugettext, ugettext_lazy as _
from uds.models import Provider, Service, UserService
from uds.REST.methods.services import Services as DetailServices
from uds.core import services
from uds.core.util import permissions
from uds.REST import NotFound, RequestError
from uds.REST.model import ModelHandler
@ -87,6 +88,7 @@ class Providers(ModelHandler):
'offers': offers,
'type': type_.type(),
'comments': provider.comments,
'permission': permissions.getEffectivePermission(self._user, provider)
}
def checkDelete(self, item):
@ -110,7 +112,9 @@ class Providers(ModelHandler):
'''
for s in Service.objects.all():
try:
yield DetailServices.serviceToDict(s, True)
perm = permissions.getEffectivePermission(self._user, s)
if perm >= permissions.PERMISSION_READ:
yield DetailServices.serviceToDict(s, perm, True)
except Exception:
logger.exception('Passed service cause type is unknown')
@ -119,7 +123,9 @@ class Providers(ModelHandler):
Custom method that returns a service by its uuid, no matter who's his daddy
'''
try:
return DetailServices.serviceToDict(Service.objects.get(uuid=self._args[1]), True)
service = Service.objects.get(uuid=self._args[1])
perm = self.ensureAccess(service, permissions.PERMISSION_READ) # Ensures that we can read this item
return DetailServices.serviceToDict(service, perm, True)
except Exception:
raise RequestError(ugettext('Service not found'))
@ -128,6 +134,7 @@ class Providers(ModelHandler):
Custom method that swaps maintenance mode state for a provider
:param item:
'''
self.ensureAccess(item, permissions.PERMISSION_MANAGEMENT)
item.maintenance_mode = not item.maintenance_mode
item.save()
return self.item_as_dict(item)
@ -137,6 +144,9 @@ class Providers(ModelHandler):
logger.debug('Type: {}'.format(type_))
spType = services.factory().lookup(type_)
self.ensureAccess(spType, permissions.PERMISSION_MANAGEMENT, root=True)
logger.debug('spType: {}'.format(spType))
res = spType.test(Environment.getTempEnv(), self._params)
if res[0]:

View File

@ -39,6 +39,7 @@ from uds.models import Service, UserService
from uds.core.services import Service as coreService
from uds.core.util import log
from uds.core.util import permissions
from uds.core.Environment import Environment
from uds.REST.model import DetailHandler
from uds.REST import NotFound, ResponseError, RequestError
@ -55,7 +56,22 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
'''
@staticmethod
def serviceToDict(item, full=False):
def serviceInfo(item):
info = item.getType()
return {
'icon': info.icon().replace('\n', ''),
'needs_publication': info.publicationType is not None,
'max_deployed': info.maxDeployed,
'uses_cache': info.usesCache,
'uses_cache_l2': info.usesCache_L2,
'cache_tooltip': _(info.cacheTooltip),
'cache_tooltip_l2': _(info.cacheTooltip_L2),
'needs_manager': info.needsManager,
'must_assign_manually': info.mustAssignManually,
}
@staticmethod
def serviceToDict(item, perm, full=False):
'''
Convert a service db item to a dict for a rest response
:param item: Service item (db)
@ -70,31 +86,22 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
'deployed_services_count': item.deployedServices.count(),
'user_services_count': UserService.objects.filter(deployed_service__service=item).count(),
'maintenance_mode': item.provider.maintenance_mode,
'permission': perm
}
if full:
info = item.getType()
retVal['info'] = {
'icon': info.icon().replace('\n', ''),
'needs_publication': info.publicationType is not None,
'max_deployed': info.maxDeployed,
'uses_cache': info.usesCache,
'uses_cache_l2': info.usesCache_L2,
'cache_tooltip': _(info.cacheTooltip),
'cache_tooltip_l2': _(info.cacheTooltip_L2),
'needs_manager': info.needsManager,
'must_assign_manually': info.mustAssignManually,
}
retVal['info'] = Services.serviceInfo(item)
return retVal
def getItems(self, parent, item):
# Extract provider
# Check what kind of access do we have to parent provider
perm = permissions.getEffectivePermission(self._user, parent)
try:
if item is None:
return [Services.serviceToDict(k) for k in parent.services.all()]
return [Services.serviceToDict(k, perm) for k in parent.services.all()]
else:
k = parent.services.get(uuid=item)
val = Services.serviceToDict(k)
val = Services.serviceToDict(k, perm, full=True)
return self.fillIntanceFields(k, val)
except Exception:
logger.exception('itemId {}'.format(item))

View File

@ -37,10 +37,12 @@ from uds.models import DeployedService, OSManager, Service, Image
from uds.core.ui.images import DEFAULT_THUMB_BASE64
from uds.core.util.State import State
from uds.core.util import log
from uds.core.util import permissions
from uds.REST.model import ModelHandler
from uds.REST import RequestError, ResponseError
from uds.core.ui.UserInterface import gui
from uds.REST.methods.user_services import AssignedService, CachedService, Groups, Transports, Publications
from .user_services import AssignedService, CachedService, Groups, Transports, Publications
from .services import Services
import logging
@ -80,6 +82,7 @@ class ServicesPools(ModelHandler):
val = {
'id': item.uuid,
'name': item.name,
'parent': item.service.name,
'comments': item.comments,
'state': item.state if item.service.provider.maintenance_mode is False else State.MAINTENANCE,
'thumb': item.image.thumb64 if item.image is not None else DEFAULT_THUMB_BASE64,
@ -93,6 +96,8 @@ class ServicesPools(ModelHandler):
'user_services_count': item.userServices.count(),
'restrained': item.isRestrained(),
'show_transports': item.show_transports,
'permission': permissions.getEffectivePermission(self._user, item),
'info': Services.serviceInfo(item.service)
}
if item.osmanager is not None:

View File

@ -35,6 +35,7 @@ from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _, ugettext
from uds.models import Transport, Network
from uds.core.transports import factory
from uds.core.util import permissions
from uds.REST.model import ModelHandler
@ -93,6 +94,7 @@ class Transports(ModelHandler):
'networks': [{'id': n.id} for n in item.networks.all()],
'deployed_count': item.deployedServices.count(),
'type': type_.type(),
'permission': permissions.getEffectivePermission(self._user, item)
}
def afterSave(self, item):

View File

@ -33,13 +33,14 @@
from __future__ import unicode_literals
from uds.REST.handlers import NotFound, RequestError, ResponseError
from uds.REST.handlers import NotFound, RequestError, ResponseError, AccessDenied, NotSupportedError
from django.utils.translation import ugettext as _
from django.db import IntegrityError
from uds.core.ui.UserInterface import gui as uiGui
from uds.REST.handlers import Handler, HandlerError
from uds.core.util import log
from uds.core.util import permissions
import fnmatch
import re
@ -50,7 +51,7 @@ import logging
logger = logging.getLogger(__name__)
__updated__ = '2015-02-16'
__updated__ = '2015-03-05'
# a few constants
@ -150,6 +151,12 @@ class BaseModelHandler(Handler):
return gui
def ensureAccess(self, obj, permission, root=False):
perm = permissions.getEffectivePermission(self._user, obj, root)
if perm < permission:
self.accessDenied()
return perm
def typeInfo(self, type_): # pylint: disable=no-self-use
'''
Returns info about the type
@ -233,6 +240,12 @@ class BaseModelHandler(Handler):
message = _('Item not found') if message is None else None
raise NotFound('{} {}: {}'.format(message, self.__class__, self._args))
def accessDenied(self, message=None):
raise AccessDenied(message or _('Access denied'))
def notSupported(self, message=None):
raise NotSupportedError(message or _('Operation not supported'))
# Success methods
def success(self):
'''
@ -284,6 +297,7 @@ class DetailHandler(BaseModelHandler): # pylint: disable=abstract-class-not-use
self._params = params
self._args = args
self._kwargs = kwargs
self._user = kwargs.get('user', None)
def __checkCustom(self, check, parent, arg=None):
'''
@ -312,6 +326,7 @@ class DetailHandler(BaseModelHandler): # pylint: disable=abstract-class-not-use
nArgs = len(self._args)
parent = self._kwargs['parent']
if nArgs == 0:
return self.getItems(parent, None)
@ -578,6 +593,7 @@ class ModelHandler(BaseModelHandler):
# log related
def getLogs(self, item):
self.ensureAccess(item, permissions.PERMISSION_READ)
logger.debug('Default getLogs invoked')
return log.getLogs(item)
@ -656,14 +672,26 @@ class ModelHandler(BaseModelHandler):
return data
# Helper to process detail
# Details can be managed (writen) by any user that has MANAGEMENT permission over parent
def processDetail(self):
logger.debug('Processing detail {0}'.format(self._path))
logger.debug('Processing detail {} for user {}'.format(self._path, self._user))
try:
item = self.model.objects.filter(uuid=self._args[0])[0]
# If we do not have access to parent to, at least, read...
if self._operation in ('put', 'post', 'delete'):
requiredPermission = permissions.PERMISSION_MANAGEMENT
else:
requiredPermission = permissions.PERMISSION_READ
if permissions.checkPermissions(self._user, item, requiredPermission) is False:
logger.debug('Permission for user {} does not comply with {}'.format(self._user, requiredPermission))
self.accessDenied()
detailCls = self.detail[self._args[1]]
args = list(self._args[2:])
path = self._path + '/'.join(args[:2])
detail = detailCls(self, path, self._params, *args, parent=item)
detail = detailCls(self, path, self._params, *args, parent=item, user=self._user)
method = getattr(detail, self._operation)
except KeyError:
self.invalidMethodException()
@ -672,10 +700,17 @@ class ModelHandler(BaseModelHandler):
return method()
def getItems(self, *args, **kwargs):
def getItems(self, overview=True, *args, **kwargs):
for item in self.model.objects.filter(*args, **kwargs):
try:
yield self.item_as_dict_overview(item)
if permissions.checkPermissions(self._user, item, permissions.PERMISSION_READ) is False:
continue
if overview:
yield self.item_as_dict_overview(item)
else:
res = self.item_as_dict(item)
self.fillIntanceFields(item, res)
yield res
except Exception: # maybe an exception is thrown to skip an item
# logger.exception('Exception getting item from {0}'.format(self.model))
pass
@ -693,15 +728,7 @@ class ModelHandler(BaseModelHandler):
nArgs = len(self._args)
if nArgs == 0:
result = []
for val in self.model.objects.all():
try:
res = self.item_as_dict(val)
self.fillIntanceFields(val, res)
result.append(res)
except Exception: # maybe an exception is thrown to skip an item
pass
return result
return list(self.getItems(overview=False))
# if has custom methods, look for if this request matches any of them
for cm in self.custom_methods:
@ -735,6 +762,9 @@ class ModelHandler(BaseModelHandler):
# get item ID
try:
val = self.model.objects.get(uuid=self._args[0].lower())
self.ensureAccess(val, permissions.PERMISSION_READ)
res = self.item_as_dict(val)
self.fillIntanceFields(val, res)
return res
@ -793,6 +823,9 @@ class ModelHandler(BaseModelHandler):
if len(self._args) > 1: # Detail?
return self.processDetail()
self.ensureAccess(self.model(), permissions.PERMISSION_ALL, root=True) # Must have write permissions to create, modify, etc..
try:
# Extract fields
args = self.readFieldsFromParams(self.save_fields)
@ -854,6 +887,9 @@ class ModelHandler(BaseModelHandler):
if len(self._args) != 1:
raise RequestError('Delete need one and only one argument')
self.ensureAccess(self.model(), permissions.PERMISSION_ALL, root=True) # Must have write permissions to delete
try:
item = self.model.objects.get(uuid=self._args[0].lower())
self.checkDelete(item)

View File

@ -32,7 +32,7 @@
'''
from __future__ import unicode_literals
__updated__ = '2015-03-01'
__updated__ = '2015-03-05'
from uds.models import Provider, Service, OSManager, Transport, Network, ServicePool, UserService, Authenticator, User, Group, StatsCounters, StatsEvents
import logging

View File

@ -32,7 +32,7 @@
'''
from __future__ import unicode_literals
__updated__ = '2015-03-04'
__updated__ = '2015-03-05'
from uds.models import Permissions
from uds.core.util import ot
@ -43,6 +43,7 @@ logger = logging.getLogger(__name__)
PERMISSION_ALL = Permissions.PERMISSION_ALL
PERMISSION_READ = Permissions.PERMISSION_READ
PERMISSION_MANAGEMENT = Permissions.PERMISSION_MANAGEMENT
PERMISSION_NONE = Permissions.PERMISSION_NONE
@ -54,6 +55,19 @@ def getPermissions(obj):
return list(Permissions.enumeratePermissions(object_type=ot.getObjectType(obj), object_id=obj.pk))
def getEffectivePermission(user, obj, root=False):
if user.is_admin is True:
return PERMISSION_ALL
if user.staff_member is False:
return PERMISSION_NONE
if root is False:
return Permissions.getPermissions(user=user, groups=user.groups.all(), object_type=ot.getObjectType(obj), object_id=obj.pk)
else:
return Permissions.getPermissions(user=user, groups=user.groups.all(), object_type=ot.getObjectType(obj))
def addUserPermission(user, obj, permission=PERMISSION_READ):
# Some permissions added to some object types needs at least READ_PERMISSION on parent
Permissions.addPermission(user=user, object_type=ot.getObjectType(obj), object_id=obj.pk, permission=permission)
@ -63,15 +77,16 @@ def addGroupPermission(group, obj, permission=PERMISSION_READ):
Permissions.addPermission(group=group, object_type=ot.getObjectType(obj), object_id=obj.pk, permission=permission)
def checkPermissions(user, obj, permission=PERMISSION_ALL):
if user.is_admin is True:
return True
if user.is_staff is False:
return False
return Permissions.getPermissions(user=user, groups=user.groups.all(), object_type=ot.getObjectType(obj), object_id=obj.pk) >= permission
def checkPermissions(user, obj, permission=PERMISSION_ALL, root=False):
return getEffectivePermission(user, obj, root) >= permission
def getPermissionName(perm):
return Permissions.permissionAsString(perm)
def revokePermissionById(permId):
try:
return Permissions.objects.get(uuid=permId).delete()
except Exception:
return None

View File

@ -33,7 +33,7 @@
from __future__ import unicode_literals
__updated__ = '2015-03-04'
__updated__ = '2015-03-05'
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext as _
@ -58,8 +58,9 @@ class Permissions(UUIDModel):
# pylint: disable=model-missing-unicode
# Allowed permissions
PERMISSION_NONE = 0
PERMISSION_READ = 16
PERMISSION_ALL = 32
PERMISSION_READ = 32
PERMISSION_MANAGEMENT = 64
PERMISSION_ALL = 96
created = models.DateTimeField(db_index=True)
ends = models.DateTimeField(db_index=True, null=True, blank=True, default=None) # Future "permisions ends at this moment", not assigned right now
@ -77,6 +78,7 @@ class Permissions(UUIDModel):
return {
Permissions.PERMISSION_NONE: _('None'),
Permissions.PERMISSION_READ: _('Read'),
Permissions.PERMISSION_MANAGEMENT: _('Management'),
Permissions.PERMISSION_ALL: _('All')
}.get(perm, _('None'))

View File

@ -6,6 +6,13 @@ api = @api
api.debug = on
api.permissions = {
NONE: 0
READ: 32
MANAGEMENT: 64
ALL: 96
}
api.doLog = (args...) ->
if api.debug
try
@ -267,6 +274,12 @@ class BasicModelRest
return
permission: () ->
if api.config.admin is true
return api.permissions.ALL
return api.permissions.NONE
getPermissions: (id, success_fnc, fail_fnc) ->
path = "permissions/" + @path + '/' + id
@_requestPath path,
@ -275,17 +288,17 @@ class BasicModelRest
fail: fail_fnc
addPermission: (id, type, itemId, perm, success_fnc, fail_fnc) ->
path = "permissions/" + @path + '/' + id + '/' + type + '/' + itemId
path = "permissions/" + @path + '/' + id + '/' + type + '/add/' + itemId
data =
perm: perm
api.putJson path, data,
success: success_fnc
fail: fail_fnc
revokePermissions: (id, type, itemIds, success_fnc, fail_fnc)->
path = "permissions/revoke/" + @path + '/' + id + '/' + type
revokePermissions: (itemIds, success_fnc, fail_fnc)->
path = "permissions/revoke"
data =
ids: itemIds
items: itemIds
api.putJson path, data,
success: success_fnc
fail: fail_fnc
@ -337,13 +350,15 @@ class DetailModelRestApi extends BasicModelRest
model
].join("/")
@moptions = options
permission: () ->
if @moptions.permission? then @moptions.permission else api.permissions.ALL
create: (data, success_fnc, fail_fnc) ->
@put data,
success: success_fnc
fail: fail_fnc
save: (data, success_fnc, fail_fnc) ->
@put data,
id: data.id

View File

@ -125,6 +125,7 @@ gui.authenticators.link = (event) ->
"edit"
"delete"
"xls"
"permissions"
]
onRowDeselect: ->
clearDetails()
@ -141,8 +142,8 @@ gui.authenticators.link = (event) ->
id = selected[0].id
type = gui.authenticators.types[selected[0].type]
gui.doLog "Type", type
user = new GuiElement(api.authenticators.detail(id, "users"), "users")
group = new GuiElement(api.authenticators.detail(id, "groups"), "groups")
user = new GuiElement(api.authenticators.detail(id, "users", { permission: selected[0].permission }), "users")
group = new GuiElement(api.authenticators.detail(id, "groups", { permission: selected[0].permission }), "groups")
grpTable = group.table(
container: "groups-placeholder"
rowSelect: "single"

View File

@ -19,6 +19,7 @@ gui.connectivity.link = (event) ->
"edit"
"delete"
"xls"
"permissions"
]
onNew: gui.methods.typedNew(gui.connectivity.transports, gettext("New transport"), gettext("Transport creation error"))
onEdit: gui.methods.typedEdit(gui.connectivity.transports, gettext("Edit transport"), gettext("Transport saving error"))
@ -32,6 +33,7 @@ gui.connectivity.link = (event) ->
"edit"
"delete"
"xls"
"permissions"
]
onNew: gui.methods.typedNew(gui.connectivity.networks, gettext("New network"), gettext("Network creation error"))
onEdit: gui.methods.typedEdit(gui.connectivity.networks, gettext("Edit network"), gettext("Network saving error"))

View File

@ -17,6 +17,7 @@ gui.osmanagers.link = (event) ->
"edit"
"delete"
"xls"
"permissions"
]
onNew: gui.methods.typedNew(gui.osmanagers, gettext("New OSManager"), gettext("OSManager creation error"))
onEdit: gui.methods.typedEdit(gui.osmanagers, gettext("Edit OSManager"), gettext("OSManager saving error"))

View File

@ -54,6 +54,8 @@ gui.providers.link = (event) ->
return
tableId = gui.providers.table(
getPermission: (selected) ->
gui.doLog "Selected", selected
container: "providers-placeholder"
rowSelect: "single"
onCheck: (check, items) -> # Check if item can be deleted
@ -84,9 +86,9 @@ gui.providers.link = (event) ->
clearDetails()
$("#detail-placeholder").removeClass "hidden"
id = selected[0].id
# Giving the name compossed with type, will ensure that only styles will be reattached once
services = new GuiElement(api.providers.detail(id, "services"), "services-" + selected[0].type)
services = new GuiElement(api.providers.detail(id, "services", { permission: selected[0].permission }), "services-" + selected[0].type)
tmpLogTable = undefined
servicesTable = services.table(
container: "services-placeholder"
@ -120,7 +122,6 @@ gui.providers.link = (event) ->
"edit"
"delete"
"xls"
"permissions"
]
onEdit: gui.methods.typedEdit(services, gettext("Edit service"), gettext("Service creation error"))
onNew: gui.methods.typedNew(services, gettext("New service"), gettext("Service saving error"))
@ -141,6 +142,7 @@ gui.providers.link = (event) ->
"new"
"edit"
{
permission: api.permissions.MANAGEMENT
text: gettext("Maintenance")
css: "disabled"
click: (val, value, btn, tbl, refreshFnc) ->

View File

@ -79,243 +79,114 @@ gui.servicesPools.link = (event) ->
return
return
# Fills up the list of available services
api.providers.allServices (services) ->
availableServices = {}
$.each services, (undefined_, service) ->
availableServices[service.id] = service
api.templates.get "services_pool", (tmpl) ->
gui.appendToWorkspace api.templates.evaluate(tmpl,
deployed_services: "deployed-services-placeholder"
assigned_services: "assigned-services-placeholder"
cache: "cache-placeholder"
groups: "groups-placeholder"
transports: "transports-placeholder"
publications: "publications-placeholder"
logs: "logs-placeholder"
)
gui.setLinksEvents()
# Append tabs click events
$(".bottom_tabs").on "click", (event) ->
gui.doLog event.target
setTimeout (->
$($(event.target).attr("href") + " span.fa-refresh").click()
return
), 10
return
gui.doLog "Available services", availableServices
api.templates.get "services_pool", (tmpl) ->
gui.appendToWorkspace api.templates.evaluate(tmpl,
deployed_services: "deployed-services-placeholder"
assigned_services: "assigned-services-placeholder"
cache: "cache-placeholder"
groups: "groups-placeholder"
transports: "transports-placeholder"
publications: "publications-placeholder"
logs: "logs-placeholder"
)
gui.setLinksEvents()
# Append tabs click events
$(".bottom_tabs").on "click", (event) ->
gui.doLog event.target
setTimeout (->
$($(event.target).attr("href") + " span.fa-refresh").click()
return
), 10
#
# * Services pools part
#
servicesPoolsTable = gui.servicesPools.table(
container: "deployed-services-placeholder"
rowSelect: "single"
buttons: [
"new"
"edit"
"delete"
"xls"
"permissions"
]
onRowDeselect: ->
clearDetails()
return
#
# * Services pools part
#
servicesPoolsTable = gui.servicesPools.table(
container: "deployed-services-placeholder"
rowSelect: "single"
buttons: [
"new"
"edit"
"delete"
"xls"
]
onRowDeselect: ->
clearDetails()
onRowSelect: (selected) ->
servPool = selected[0]
gui.doLog "Selected services pool", servPool
clearDetails()
service = null
try
info = servPool.info
catch e
gui.doLog "Exception on rowSelect", e
gui.notify "Service pool " + gettext("error"), "danger"
return
onRowSelect: (selected) ->
servPool = selected[0]
gui.doLog "Selected services pool", servPool
clearDetails()
service = null
try
service = availableServices[servPool.service_id]
catch e
gui.doLog "Exception on rowSelect", e
gui.notify "Service pool " + gettext("error"), "danger"
return
if service?
$("#detail-placeholder").removeClass "hidden"
else
$("#detail-placeholder").addClass "hidden"
return
$("#detail-placeholder").removeClass "hidden"
#
# * Cache Part
#
cachedItems = null
# If service does not supports cache, do not show it
# Shows/hides cache
if info.uses_cache or info.uses_cache_l2
$("#cache-placeholder_tab").removeClass "hidden"
cachedItems = new GuiElement(api.servicesPools.detail(servPool.id, "cache", { permission: servPool.permission }), "cache")
#
# * Cache Part
#
cachedItems = null
# If service does not supports cache, do not show it
# Shows/hides cache
if service.info.uses_cache or service.info.uses_cache_l2
$("#cache-placeholder_tab").removeClass "hidden"
cachedItems = new GuiElement(api.servicesPools.detail(servPool.id, "cache"), "cache")
# Cached items table
prevCacheLogTbl = null
cachedItemsTable = cachedItems.table(
container: "cache-placeholder_tbl"
buttons: [
"delete"
"xls"
]
rowSelect: "single"
onData: (data) ->
fillState data
return
onRowSelect: (selected) ->
gui.do
cached = selected[0]
if prevCacheLogTbl
$tbl = $(prevCacheLogTbl).dataTable()
$tbl.fnClearTable()
$tbl.fnDestroy()
prevCacheLogTbl = cachedItems.logTable(cached.id,
container: "cache-placeholder_log"
)
return
onDelete: gui.methods.del(cachedItems, gettext("Remove Cache element"), gettext("Deletion error"))
)
prevTables.push cachedItemsTable
else
$("#cache-placeholder_tab").addClass "hidden"
#
# * Groups part
#
groups = null
# Shows/hides groups
if service.info.must_assign_manually is false
$("#groups-placeholder_tab").removeClass "hidden"
groups = new GuiElement(api.servicesPools.detail(servPool.id, "groups"), "groups")
# Groups items table
groupsTable = groups.table(
container: "groups-placeholder"
rowSelect: "single"
buttons: [
"new"
"delete"
"xls"
]
onNew: (value, table, refreshFnc) ->
api.templates.get "pool_add_group", (tmpl) ->
api.authenticators.overview (data) ->
# Sorts groups, expression means that "if a > b returns 1, if b > a returns -1, else returns 0"
modalId = gui.launchModal(gettext("Add group"), api.templates.evaluate(tmpl,
auths: data
))
$(modalId + " #id_auth_select").on "change", (event) ->
auth = $(modalId + " #id_auth_select").val()
api.authenticators.detail(auth, "groups").overview (data) ->
$select = $(modalId + " #id_group_select")
$select.empty()
# Sorts groups, expression means that "if a > b returns 1, if b > a returns -1, else returns 0"
$.each data, (undefined_, value) ->
$select.append "<option value=\"" + value.id + "\">" + value.name + "</option>"
return
# Refresh selectpicker if item is such
$select.selectpicker "refresh" if $select.hasClass("selectpicker")
return
return
$(modalId + " .button-accept").on "click", (event) ->
auth = $(modalId + " #id_auth_select").val()
group = $(modalId + " #id_group_select").val()
if auth is -1 or group is -1
gui.notify gettext("You must provide authenticator and group"), "danger"
else # Save & close modal
groups.rest.create
id: group
, (data) ->
$(modalId).modal "hide"
refreshFnc()
return
return
# Makes form "beautyfull" :-)
gui.tools.applyCustoms modalId
return
return
return
onDelete: gui.methods.del(groups, gettext("Remove group"), gettext("Group removal error"))
onData: (data) ->
$.each data, (undefined_, value) ->
value.group_name = "<b>" + value.auth_name + "</b>\\" + value.name
return
return
)
prevTables.push groupsTable
else
$("#groups-placeholder_tab").addClass "hidden"
#
# * Assigned services part
#
prevAssignedLogTbl = null
assignedServices = new GuiElement(api.servicesPools.detail(servPool.id, "services"), "services")
assignedServicesTable = assignedServices.table(
container: "assigned-services-placeholder_tbl"
# Cached items table
prevCacheLogTbl = null
cachedItemsTable = cachedItems.table(
container: "cache-placeholder_tbl"
buttons: [
"delete"
"xls"
]
rowSelect: "single"
buttons: (if service.info.must_assign_manually then [
"new"
"delete"
"xls"
] else [
"delete"
"xls"
])
onData: (data) ->
fillState data
$.each data, (index, value) ->
if value.in_use is true
value.in_use = gettext('Yes')
else
value.in_use = gettext('No')
return
onRowSelect: (selected) ->
service = selected[0]
if prevAssignedLogTbl
$tbl = $(prevAssignedLogTbl).dataTable()
gui.do
cached = selected[0]
if prevCacheLogTbl
$tbl = $(prevCacheLogTbl).dataTable()
$tbl.fnClearTable()
$tbl.fnDestroy()
prevAssignedLogTbl = assignedServices.logTable(service.id,
container: "assigned-services-placeholder_log"
prevCacheLogTbl = cachedItems.logTable(cached.id,
container: "cache-placeholder_log"
)
return
onDelete: gui.methods.del(assignedServices, gettext("Remove Assigned service"), gettext("Deletion error"))
onDelete: gui.methods.del(cachedItems, gettext("Remove Cache element"), gettext("Deletion error"))
)
prevTables.push cachedItemsTable
else
$("#cache-placeholder_tab").addClass "hidden"
#
# * Groups part
#
groups = null
# Shows/hides groups
if info.must_assign_manually is false
$("#groups-placeholder_tab").removeClass "hidden"
groups = new GuiElement(api.servicesPools.detail(servPool.id, "groups", { permission: servPool.permission }), "groups")
# Log of assigned services (right under assigned services)
prevTables.push assignedServicesTable
#
# * Transports part
#
transports = new GuiElement(api.servicesPools.detail(servPool.id, "transports"), "transports")
# Transports items table
transportsTable = transports.table(
container: "transports-placeholder"
# Groups items table
groupsTable = groups.table(
container: "groups-placeholder"
rowSelect: "single"
buttons: [
"new"
@ -323,18 +194,38 @@ gui.servicesPools.link = (event) ->
"xls"
]
onNew: (value, table, refreshFnc) ->
api.templates.get "pool_add_transport", (tmpl) ->
api.transports.overview (data) ->
modalId = gui.launchModal(gettext("Add transport"), api.templates.evaluate(tmpl,
transports: data
api.templates.get "pool_add_group", (tmpl) ->
api.authenticators.overview (data) ->
# Sorts groups, expression means that "if a > b returns 1, if b > a returns -1, else returns 0"
modalId = gui.launchModal(gettext("Add group"), api.templates.evaluate(tmpl,
auths: data
))
$(modalId + " #id_auth_select").on "change", (event) ->
auth = $(modalId + " #id_auth_select").val()
api.authenticators.detail(auth, "groups").overview (data) ->
$select = $(modalId + " #id_group_select")
$select.empty()
# Sorts groups, expression means that "if a > b returns 1, if b > a returns -1, else returns 0"
$.each data, (undefined_, value) ->
$select.append "<option value=\"" + value.id + "\">" + value.name + "</option>"
return
# Refresh selectpicker if item is such
$select.selectpicker "refresh" if $select.hasClass("selectpicker")
return
return
$(modalId + " .button-accept").on "click", (event) ->
transport = $(modalId + " #id_transport_select").val()
if transport is -1
gui.notify gettext("You must provide a transport"), "danger"
auth = $(modalId + " #id_auth_select").val()
group = $(modalId + " #id_group_select").val()
if auth is -1 or group is -1
gui.notify gettext("You must provide authenticator and group"), "danger"
else # Save & close modal
transports.rest.create
id: transport
groups.rest.create
id: group
, (data) ->
$(modalId).modal "hide"
refreshFnc()
@ -351,142 +242,232 @@ gui.servicesPools.link = (event) ->
return
onDelete: gui.methods.del(transports, gettext("Remove transport"), gettext("Transport removal error"))
onDelete: gui.methods.del(groups, gettext("Remove group"), gettext("Group removal error"))
onData: (data) ->
$.each data, (undefined_, value) ->
style = "display:inline-block; background: url(data:image/png;base64," + value.type.icon + "); ; background-size: 16px 16px; background-repeat: no-repeat; width: 16px; height: 16px; vertical-align: middle;"
value.trans_type = value.type.name
value.name = "<span style=\"" + style + "\"></span> " + value.name
value.group_name = "<b>" + value.auth_name + "</b>\\" + value.name
return
return
)
prevTables.push transportsTable
#
# * Publications part
#
publications = null
if service.info.needs_publication
$("#publications-placeholder_tab").removeClass "hidden"
pubApi = api.servicesPools.detail(servPool.id, "publications")
publications = new GuiElement(pubApi, "publications")
# Publications table
publicationsTable = publications.table(
container: "publications-placeholder"
rowSelect: "single"
buttons: [
"new"
{
text: gettext("Cancel")
css: "disabled"
click: (val, value, btn, tbl, refreshFnc) ->
gui.promptModal gettext("Publish"), gettext("Cancel publication"),
onYes: ->
pubApi.invoke val.id + "/cancel", ->
refreshFnc()
return
return
return
select: (val, value, btn, tbl, refreshFnc) ->
unless val
$(btn).removeClass("btn3d-warning").addClass "disabled"
return
if val.state == 'K'
$(btn).empty().append(gettext("Force Cancel"))
else
$(btn).empty().append(gettext("Cancel"))
# Waiting for publication, Preparing or running
gui.doLog "State: ", val.state
$(btn).removeClass("disabled").addClass "btn3d-warning" if [
"P"
"W"
"L"
"K"
].indexOf(val.state) != -1
return
}
"xls"
]
onNew: (action, tbl, refreshFnc) ->
gui.promptModal gettext("Publish"), gettext("Launch new publication?"),
onYes: ->
pubApi.invoke "publish", (->
refreshFnc()
return
), gui.failRequestModalFnc(gettext("Failed creating publication"))
return
return
)
prevTables.push publicationsTable
else
$("#publications-placeholder_tab").addClass "hidden"
#
# * Log table
#
logTable = gui.servicesPools.logTable(servPool.id,
container: "logs-placeholder"
)
prevTables.push logTable
return
prevTables.push groupsTable
else
$("#groups-placeholder_tab").addClass "hidden"
# Pre-process data received to add "icon" to deployed service
onData: (data) ->
gui.doLog "onData", data
$.each data, (index, value) ->
gui.doLog value.thumb
try
service = availableServices[value.service_id]
if not service?
value.parent = gettext("undefined")
return
style = "display:inline-block; background: url(data:image/png;base64," + value.thumb + "); background-size: 16px 16px; background-repeat: no-repeat; width: 16px; height: 16px; vertical-align: middle;"
gui.doLog style
if value.restrained
value.name = "<span class=\"fa fa-exclamation text-danger\"></span> " + value.name
value.state = gettext("Restrained")
value.name = "<span style=\"" + style + "\"></span> " + value.name
value.parent = service.name
catch e
value.name = "<span class=\"fa fa-asterisk text-alert\"></span> " + value.name
value.parent = gettext("unknown (needs reload)")
#
# * Assigned services part
#
prevAssignedLogTbl = null
assignedServices = new GuiElement(api.servicesPools.detail(servPool.id, "services", { permission: servPool.permission }), "services")
assignedServicesTable = assignedServices.table(
container: "assigned-services-placeholder_tbl"
rowSelect: "single"
buttons: (if info.must_assign_manually then [
"new"
"delete"
"xls"
] else [
"delete"
"xls"
])
onData: (data) ->
fillState data
$.each data, (index, value) ->
if value.in_use is true
value.in_use = gettext('Yes')
else
value.in_use = gettext('No')
return
onRowSelect: (selected) ->
svr = selected[0]
if prevAssignedLogTbl
$tbl = $(prevAssignedLogTbl).dataTable()
$tbl.fnClearTable()
$tbl.fnDestroy()
prevAssignedLogTbl = assignedServices.logTable(svr.id,
container: "assigned-services-placeholder_log"
)
return
onDelete: gui.methods.del(assignedServices, gettext("Remove Assigned service"), gettext("Deletion error"))
)
# Log of assigned services (right under assigned services)
prevTables.push assignedServicesTable
#
# * Transports part
#
transports = new GuiElement(api.servicesPools.detail(servPool.id, "transports", { permission: servPool.permission }), "transports")
# Transports items table
transportsTable = transports.table(
container: "transports-placeholder"
rowSelect: "single"
buttons: [
"new"
"delete"
"xls"
]
onNew: (value, table, refreshFnc) ->
api.templates.get "pool_add_transport", (tmpl) ->
api.transports.overview (data) ->
modalId = gui.launchModal(gettext("Add transport"), api.templates.evaluate(tmpl,
transports: data
))
$(modalId + " .button-accept").on "click", (event) ->
transport = $(modalId + " #id_transport_select").val()
if transport is -1
gui.notify gettext("You must provide a transport"), "danger"
else # Save & close modal
transports.rest.create
id: transport
, (data) ->
$(modalId).modal "hide"
refreshFnc()
return
return
# Makes form "beautyfull" :-)
gui.tools.applyCustoms modalId
return
return
return
onDelete: gui.methods.del(transports, gettext("Remove transport"), gettext("Transport removal error"))
onData: (data) ->
$.each data, (undefined_, value) ->
style = "display:inline-block; background: url(data:image/png;base64," + value.type.icon + "); ; background-size: 16px 16px; background-repeat: no-repeat; width: 16px; height: 16px; vertical-align: middle;"
value.trans_type = value.type.name
value.name = "<span style=\"" + style + "\"></span> " + value.name
return
return
)
prevTables.push transportsTable
#
# * Publications part
#
publications = null
if info.needs_publication
$("#publications-placeholder_tab").removeClass "hidden"
pubApi = api.servicesPools.detail(servPool.id, "publications")
publications = new GuiElement(pubApi, "publications", { permission: servPool.permission })
# Publications table
publicationsTable = publications.table(
container: "publications-placeholder"
rowSelect: "single"
buttons: [
"new"
{
text: gettext("Cancel")
css: "disabled"
click: (val, value, btn, tbl, refreshFnc) ->
gui.promptModal gettext("Publish"), gettext("Cancel publication"),
onYes: ->
pubApi.invoke val.id + "/cancel", ->
refreshFnc()
return
return
return
select: (val, value, btn, tbl, refreshFnc) ->
unless val
$(btn).removeClass("btn3d-warning").addClass "disabled"
return
if val.state == 'K'
$(btn).empty().append(gettext("Force Cancel"))
else
$(btn).empty().append(gettext("Cancel"))
# Waiting for publication, Preparing or running
gui.doLog "State: ", val.state
$(btn).removeClass("disabled").addClass "btn3d-warning" if [
"P"
"W"
"L"
"K"
].indexOf(val.state) != -1
return
}
"xls"
]
onNew: (action, tbl, refreshFnc) ->
gui.promptModal gettext("Publish"), gettext("Launch new publication?"),
onYes: ->
pubApi.invoke "publish", (->
refreshFnc()
return
), gui.failRequestModalFnc(gettext("Failed creating publication"))
return
return
)
prevTables.push publicationsTable
else
$("#publications-placeholder_tab").addClass "hidden"
#
# * Log table
#
logTable = gui.servicesPools.logTable(servPool.id,
container: "logs-placeholder"
)
prevTables.push logTable
return
# Pre-process data received to add "icon" to deployed service
onData: (data) ->
gui.doLog "onData", data
$.each data, (index, value) ->
gui.doLog value.thumb
try
style = "display:inline-block; background: url(data:image/png;base64," + value.thumb + "); background-size: 16px 16px; background-repeat: no-repeat; width: 16px; height: 16px; vertical-align: middle;"
gui.doLog style
if value.restrained
value.name = "<span class=\"fa fa-exclamation text-danger\"></span> " + value.name
value.state = gettext("Restrained")
value.name = "<span style=\"" + style + "\"></span> " + value.name
catch e
value.name = "<span class=\"fa fa-asterisk text-alert\"></span> " + value.name
return
onNew: gui.methods.typedNew(gui.servicesPools, gettext("New service pool"), "Service pool " + gettext("creation error"),
guiProcessor: (guiDef) -> # Create has "save on publish" field
gui.doLog guiDef
newDef = [].concat(guiDef).concat([
name: "publish_on_save"
value: true
gui:
label: gettext("Publish on creation")
tooltip: gettext("If selected, will initiate the publication inmediatly after creation")
type: "checkbox"
order: 150
defvalue: true
])
gui.doLog newDef
newDef
return
preprocessor: preFnc
)
onEdit: gui.methods.typedEdit(gui.servicesPools, gettext("Edit") + " service pool", "Service pool " + gettext("saving error"))
onDelete: gui.methods.del(gui.servicesPools, gettext("Delete") + " service pool", "Service pool " + gettext("deletion error"))
onNew: gui.methods.typedNew(gui.servicesPools, gettext("New service pool"), "Service pool " + gettext("creation error"),
guiProcessor: (guiDef) -> # Create has "save on publish" field
gui.doLog guiDef
newDef = [].concat(guiDef).concat([
name: "publish_on_save"
value: true
gui:
label: gettext("Publish on creation")
tooltip: gettext("If selected, will initiate the publication inmediatly after creation")
type: "checkbox"
order: 150
defvalue: true
])
gui.doLog newDef
newDef
preprocessor: preFnc
)
return
onEdit: gui.methods.typedEdit(gui.servicesPools, gettext("Edit") + " service pool", "Service pool " + gettext("saving error"))
onDelete: gui.methods.del(gui.servicesPools, gettext("Delete") + " service pool", "Service pool " + gettext("deletion error"))
)
return
return

View File

@ -276,52 +276,56 @@
$.each tblParams.buttons, (index, value) -> # Iterate through button definition
btn = null
switch value
when "new"
if Object.keys(self.types).length isnt 0
menuId = gui.genRamdonId("dd-")
ordered = []
$.each self.types, (k, v) ->
ordered.push
type: k
css: v.css
name: v.name
description: v.description
if self.rest.permission() >= api.permissions.MANAGEMENT
if Object.keys(self.types).length isnt 0
menuId = gui.genRamdonId("dd-")
ordered = []
$.each self.types, (k, v) ->
ordered.push
type: k
css: v.css
name: v.name
description: v.description
return
return
ordered = ordered.sort((a, b) ->
a.name.localeCompare b.name
)
btn =
sExtends: "div"
sButtonText: api.templates.evaluate("tmpl_comp_dropdown",
label: gui.config.dataTableButtons["new"].text
css: gui.config.dataTableButtons["new"].css
id: menuId
tableId: tableId
columns: columns
menu: ordered
ordered = ordered.sort((a, b) ->
a.name.localeCompare b.name
)
else
btn =
sExtends: "div"
sButtonText: api.templates.evaluate("tmpl_comp_dropdown",
label: gui.config.dataTableButtons["new"].text
css: gui.config.dataTableButtons["new"].css
id: menuId
tableId: tableId
columns: columns
menu: ordered
)
else
btn =
sExtends: "text"
sButtonText: gui.config.dataTableButtons["new"].text
sButtonClass: gui.config.dataTableButtons["new"].css
fnClick: clickHandlerFor(tblParams.onNew, "new", true)
when "edit"
if self.rest.permission() >= api.permissions.MANAGEMENT
btn =
sExtends: "text"
sButtonText: gui.config.dataTableButtons["new"].text
sButtonClass: gui.config.dataTableButtons["new"].css
fnClick: clickHandlerFor(tblParams.onNew, "new", true)
when "edit"
btn =
sExtends: "text"
sButtonText: gui.config.dataTableButtons.edit.text
fnSelect: editSelected
fnClick: clickHandlerFor(tblParams.onEdit, "edit")
sButtonClass: gui.config.dataTableButtons.edit.css
sButtonText: gui.config.dataTableButtons.edit.text
fnSelect: editSelected
fnClick: clickHandlerFor(tblParams.onEdit, "edit")
sButtonClass: gui.config.dataTableButtons.edit.css
when "delete"
btn =
sExtends: "text"
sButtonText: gui.config.dataTableButtons["delete"].text
fnSelect: deleteSelected
fnClick: clickHandlerFor(tblParams.onDelete, "delete")
sButtonClass: gui.config.dataTableButtons["delete"].css
if self.rest.permission() >= api.permissions.MANAGEMENT
btn =
sExtends: "text"
sButtonText: gui.config.dataTableButtons["delete"].text
fnSelect: deleteSelected
fnClick: clickHandlerFor(tblParams.onDelete, "delete")
sButtonClass: gui.config.dataTableButtons["delete"].css
when "refresh"
btn =
sExtends: "text"
@ -329,7 +333,7 @@
fnClick: refreshFnc
sButtonClass: gui.config.dataTableButtons.refresh.css
when "permissions"
if api.config.admin
if self.rest.permission() == api.permissions.ALL
btn =
sExtends: "text"
sButtonText: gui.config.dataTableButtons.permissions.text
@ -346,33 +350,35 @@
# End export to excell
sButtonClass: gui.config.dataTableButtons.xls.css
else # Custom button, this has to be
try
css = ((if value.css then value.css + " " else "")) + gui.config.dataTableButtons.custom.css
btn =
sExtends: "text"
sButtonText: value.text
sButtonClass: css
perm = if value.permission? then value.permission else api.permissions.NONE
if self.rest.permission() >= perm
try
css = ((if value.css then value.css + " " else "")) + gui.config.dataTableButtons.custom.css
btn =
sExtends: "text"
sButtonText: value.text
sButtonClass: css
if value.click
btn.fnClick = (btn) ->
tbl = $("#" + tableId).dataTable()
val = @fnGetSelectedData()[0]
setTimeout (->
value.click val, value, btn, tbl, refreshFnc
if value.click
btn.fnClick = (btn) ->
tbl = $("#" + tableId).dataTable()
val = @fnGetSelectedData()[0]
setTimeout (->
value.click val, value, btn, tbl, refreshFnc
return
), 0
return
), 0
return
if value.select
btn.fnSelect = (btn) ->
tbl = $("#" + tableId).dataTable()
val = @fnGetSelectedData()[0]
setTimeout (->
value.select val, value, btn, tbl, refreshFnc
if value.select
btn.fnSelect = (btn) ->
tbl = $("#" + tableId).dataTable()
val = @fnGetSelectedData()[0]
setTimeout (->
value.select val, value, btn, tbl, refreshFnc
return
), 0
return
), 0
return
catch e
gui.doLog "Button", value, e
catch e
gui.doLog "Button", value, e
btns.push btn if btn
return

View File

@ -1,4 +1,18 @@
gui.permissions = (val, rest, tbl, refreshFnc) ->
baseId = gui.genRamdonId('perms-')
fillSelect = (perms, forUser) ->
$select = $('#' + baseId + (if forUser then '_user_select' else '_group_select'))
$select.empty()
padRight = (str, len)->
numPads = len - str.length
if (numPads > 0) then str + Array(numPads+1).join('&nbsp;') else str
for item in perms
if (forUser is true and item.type is 'user') or (forUser is false and item.type is 'group')
$select.append('<option value="' + item.id + '">' + padRight(item.auth_name + '\\' + item.entity_name, 28) + '&nbsp;| ' + item.perm_name)
addModal = (forUser) ->
if forUser
@ -39,14 +53,18 @@ gui.permissions = (val, rest, tbl, refreshFnc) ->
if auth is -1 or item is -1
gui.notify gettext("You must provide authenticator and") + " " + label, "danger"
else # Save & close modal
rest.addPermission val.id, items, item, perm
$(modalId).modal "hide"
rest.addPermission val.id, items, item, perm, (
(perms) ->
$(modalId).modal "hide"
fillSelect perms, forUser
)
return
# Makes form "beautyfull" :-)
gui.tools.applyCustoms modalId
return
delModal = (forUser, selectedItems) ->
if forUser
label = gettext('User')
@ -64,30 +82,19 @@ gui.permissions = (val, rest, tbl, refreshFnc) ->
gui.doLog modalId
$(modalId + ' .button-revoke').on('click', () ->
rest.revokePermissions val.id, items, toDel
$(modalId).modal "hide"
rest.revokePermissions toDel, (
(perms) ->
$(modalId).modal "hide"
for v in selectedItems
$(v).remove()
)
)
fillSelect = (baseId, perms, forUser) ->
$select = $('#' + baseId + (if forUser then '_user_select' else '_group_select'))
$select.empty()
padRight = (str, len)->
numPads = len - str.length
if (numPads > 0) then str + Array(numPads+1).join('&nbsp;') else str
for item in perms
if (forUser is true and item.type is 'user') or (forUser is false and item.type is 'group')
$select.append('<option value="' + item.id + '">' + padRight(item.auth_name + '\\' + item.name, 28) + '&nbsp;| ' + item.perm_name)
api.templates.get "permissions", (tmpl) ->
rest.getPermissions val.id, (perms) ->
id = gui.genRamdonId('perms-')
content = api.templates.evaluate(tmpl,
id: id
id: baseId
perms: perms
)
modalId = gui.launchModal gettext("Permissions for") + " " + val.name, content,
@ -95,31 +102,31 @@ gui.permissions = (val, rest, tbl, refreshFnc) ->
closeButton: '<button type="button" class="btn btn-default" data-dismiss="modal">Ok</button>'
# Fills user select
fillSelect id, perms, true
fillSelect id, perms, false
fillSelect perms, true
fillSelect perms, false
$('#' + id + '_user_del').on('click', () ->
$select = $('#' + id + '_user_select')
$('#' + baseId + '_user_del').on('click', () ->
$select = $('#' + baseId + '_user_select')
selected = $select.find(":selected")
return if selected.length is 0
delModal true, selected
)
$('#' + id + '_user_add').on('click', () ->
$('#' + baseId + '_user_add').on('click', () ->
addModal yes
)
$('#' + id + '_group_del').on('click', () ->
$select = $('#' + id + '_group_select')
$('#' + baseId + '_group_del').on('click', () ->
$select = $('#' + baseId + '_group_select')
selected = $select.find(":selected")
return if selected.length is 0
delModal false, selected
)
$('#' + id + '_group_add').on('click', () ->
$('#' + baseId + '_group_add').on('click', () ->
addModal no
)

View File

@ -5,7 +5,7 @@
<div class="col-md-6 column">
<div class="form-group">
<label for="{{ id }}_select">{% endverbatim %}{% trans 'Users' %}{% verbatim %}</label>
<select class="form-control" multiple size="8" id="{{ id }}_user_select" style='font-family: "Courier New"'>
<select class="form-control" multiple size="12" id="{{ id }}_user_select" style='font-family: "Courier New"'>
</select>
</div>
<div class="form-group">
@ -20,7 +20,7 @@
<div class="col-md-6 column">
<div class="form-group">
<label for="{{ id }}_select">{% endverbatim %}{% trans 'Groups' %}{% verbatim %}</label>
<select class="form-control" multiple size="8" id="{{ id }}_group_select" style='font-family: "Courier New"'>
<select class="form-control" multiple size="12" id="{{ id }}_group_select" style='font-family: "Courier New"'>
</select>
</div>
<div class="form-group">

View File

@ -25,8 +25,9 @@
<label for="id_perm_select" class="col-sm-2 control-label">{% endverbatim %}{% trans 'Permission' %}{% verbatim %}</label>
<div class="col-sm-10">
<select id="id_perm_select" name="group" class="selectpicker show-menu-arrow show-tick modal_field_data" data-style="btn-default" data-width="100%">
<option value="1">Read only</option>
<option value="2">All Access</option>
<option value="1">{% endverbatim %}{% trans 'Read only' %}{% verbatim %}</option>
<option value="2">{% endverbatim %}{% trans 'Management Access' %}{% verbatim %}</option>
<option value="2">{% endverbatim %}{% trans 'Full Access' %}{% verbatim %}</option>
</select>
</div>
</div>