diff --git a/server/src/uds/REST/mixins.py b/server/src/uds/REST/mixins.py index a484abda5..a97335831 100644 --- a/server/src/uds/REST/mixins.py +++ b/server/src/uds/REST/mixins.py @@ -34,6 +34,7 @@ from __future__ import unicode_literals from handlers import NotFound, RequestError from django.utils.translation import ugettext as _ +from django.db import IntegrityError import logging @@ -66,8 +67,14 @@ class ModelHandlerMixin(object): detail = None # Dictionary containing detail routing model = None save_fields = [] - + def __fillIntanceFields(self, item, res): + if hasattr(item, 'getInstance'): + for key, value in item.getInstance().valuesDict().iteritems(): + value = {"true":True, "false":False}.get(value, value) + logger.debug('{0} = {1}'.format(key, value)) + res[key] = value + def item_as_dict(self, item): pass @@ -96,9 +103,7 @@ class ModelHandlerMixin(object): result = [] for val in self.model.objects.all(): res = self.item_as_dict(val) - if hasattr(val, 'getInstance'): - for key, value in val.getInstance().valuesDict().iteritems(): - res[key] = value + self.__fillIntanceFields(val, res) result.append(res) return result @@ -109,14 +114,11 @@ class ModelHandlerMixin(object): if self.detail is not None and len(self._args) > 1: return self.processDetail() - try: val = self.model.objects.get(pk=self._args[0]) res = self.item_as_dict(val) - if hasattr(val, 'getInstance'): - for key, value in val.getInstance().valuesDict().iteritems(): - res[key] = value - return res + self.__fillIntanceFields(val, res) + return res except: raise NotFound('item not found') @@ -129,46 +131,49 @@ class ModelHandlerMixin(object): del self._params[key] except KeyError as e: raise RequestError('needed parameter not found in data {0}'.format(unicode(e))) - - if len(args) == 0: # create new - isNew = False - try: - item = self.model.objects.create(**args); - res = self.item_as_dict(item) - except: # Duplicate key probably - raise RequestError('Element already exists (duplicate key error)') - - elif len(args) == 1: - try: - item = self.model.objects.get(pk=self._args[0]); - # Update "general" values - item.update(**args) - res = self.item_as_dict(item) - except: - raise RequestError('Element {0} do not exists anymore'.format(self._args[0])) - else: - raise RequestError('incorrect invocation to PUT') try: - isNew = True - if self._params.has_key('data_type'): # Needs to store instance - item.data_type = self._params['data_type'] - item.data = item.getInstance(self._params).serialize() - - for key, value in item.getInstance().valuesDict().iteritems(): - res[key] = value - - item.save() + if len(self._args) == 0: # create new + item = self.model.objects.create(**args); + elif len(self._args) == 1: + # We have to take care with this case, update will efectively update records on db + item = self.model.objects.get(pk=self._args[0]); + item.__dict__.update(args) # Update fields from args + else: + raise Exception() # Incorrect invocation + except self.model.DoesNotExist: + raise NotFound('Element do not exists') + except IntegrityError: # Duplicate key probably + raise RequestError('Element already exists (duplicate key error)') except Exception as e: - item.delete() # Remove pre-saved element - raise RequestError(unicode(e)) + raise RequestError('incorrect invocation to PUT') + + # Store associated object if needed + if self._params.has_key('data_type'): # Needs to store instance + item.data_type = self._params['data_type'] + item.data = item.getInstance(self._params).serialize() + + res = self.item_as_dict(item) + self.__fillIntanceFields(item, res) + + item.save() + return res def delete(self): logger.debug('method DELETE for {0}, {1}'.format(self.__class__.__name__, self._args)) if len(self._args) != 1: - raise RequestError('Delete need an argument') + raise RequestError('Delete need one and only one argument') + try: + item = self.model.objects.get(pk=self._args[0]); + item.delete() + except self.model.DoesNotExist: + raise NotFound('Element do not exists') + except Exception as e: + logger.exception('delete') + raise RequestError('incorrect invocation to DELETE') + return 'deleted' class ModelTypeHandlerMixin(object): diff --git a/server/src/uds/static/adm/js/api.js b/server/src/uds/static/adm/js/api.js index 90c1b8048..4287b7024 100644 --- a/server/src/uds/static/adm/js/api.js +++ b/server/src/uds/static/adm/js/api.js @@ -96,7 +96,35 @@ request.setRequestHeader(api.config.auth_header, api.config.token); }, }); - }; + }; // End putJson + + + api.deleteJson = function(path, options) { + options = options || {}; + var success_fnc = options.success || function(){}; + var fail_fnc = options.fail || api.defaultFail; + + var url = api.url_for(path); + api.doLog('Ajax DELETE Json for "' + url + '"'); + $.ajax({ + url : url, + type : "DELETE", + dataType : "json", + success: function(data) { + api.doLog('Success on DELETE "' + url + '".'); + api.doLog('Received ', data); + success_fnc(data); + }, + error: function(jqXHR, textStatus, errorThrown) { + api.doLog('Error on DELETE "' + url + '". ', textStatus, ', ', errorThrown); + fail_fnc(jqXHR, textStatus, errorThrown); + }, + beforeSend : function(request) { + request.setRequestHeader(api.config.auth_header, api.config.token); + }, + }); + }; // End putJson + // Public attributes api.debug = true; @@ -142,6 +170,7 @@ function BasicModelRest(path, options) { this.path = path; this.getPath = options.getPath || path; this.putPath = options.putPath || path; + this.delPath = options.delPath || path; this.typesPath = options.typesPath || (path + '/types'); this.tableInfoPath = options.tableInfoPath || (path + '/tableinfo'); this.cache = api.cache('bmr'+path); @@ -254,6 +283,20 @@ BasicModelRest.prototype = { }); }, + // -------------- + // Delete + // -------------- + del: function(id, success_fnc, fail_fnc) { + "use strict"; + + var path = this.delPath + '/' + id; + + api.deleteJson(path, { + success: success_fnc, + fail: fail_fnc + }); + }, + // -------------- // Types methods // -------------- diff --git a/server/src/uds/static/adm/js/gui-definition.js b/server/src/uds/static/adm/js/gui-definition.js index 8ae2d813b..5e7cfe263 100644 --- a/server/src/uds/static/adm/js/gui-definition.js +++ b/server/src/uds/static/adm/js/gui-definition.js @@ -139,15 +139,22 @@ gui.connectivity.link = function(event) { })); gui.connectivity.transports.table({ - rowSelect : 'multi', + rowSelect : 'single', container : 'transports-placeholder', buttons : [ 'new', 'edit', 'delete', 'xls' ], - onEdit: function(value, event, table) { + onEdit: function(value, event, table, refreshFnc) { gui.connectivity.transports.rest.gui(value.type, function(itemGui){ gui.connectivity.transports.rest.item(value.id, function(item) { - var form = gui.fields(itemGui, item); - gui.launchModalForm(gettext('Edit transport')+' '+value.name,form, function(form_selector) { - var fields = gui.fields.read(form_selector); + var form = gui.form.fromFields(itemGui, item); + gui.launchModalForm(gettext('Edit transport')+' '+value.name,form, function(form_selector, closeFnc) { + var fields = gui.form.read(form_selector); + fields.data_type = value.type; + fields.nets_positive = false; + gui.connectivity.transports.rest.save(fields, function(data) { // Success on put + closeFnc(); + refreshFnc(); + }, gui.failRequestModalFnc(gettext('Error creating transport')) // Fail on put, show modal message + ); return false; }); }); @@ -155,9 +162,9 @@ gui.connectivity.link = function(event) { }, onNew: function(type, table, refreshFnc) { gui.connectivity.transports.rest.gui(type, function(itemGui) { - var form = gui.fields(itemGui); + var form = gui.form.fromFields(itemGui); gui.launchModalForm(gettext('New transport'), form, function(form_selector, closeFnc) { - var fields = gui.fields.read(form_selector); + var fields = gui.form.read(form_selector); // Append "own" fields, in this case data_type fields.data_type = type; fields.nets_positive = false; @@ -169,6 +176,13 @@ gui.connectivity.link = function(event) { }); }); }, + onDelete: function(value, event, table, refreshFnc) { + // TODO: Add confirmation to deletion + gui.connectivity.transports.rest.del(value.id, function(){ + refreshFnc(); + }, gui.failRequestModalFnc(gettext('Error removing transport')) + ); + }, }); gui.connectivity.networks.table({ rowSelect : 'multi', diff --git a/server/src/uds/static/adm/js/gui-element.js b/server/src/uds/static/adm/js/gui-element.js index 72ea9e1f1..6645b20d9 100644 --- a/server/src/uds/static/adm/js/gui-element.js +++ b/server/src/uds/static/adm/js/gui-element.js @@ -19,12 +19,12 @@ GuiElement.prototype = { init : function() { "use strict"; gui.doLog('Initializing ' + this.name); - var $this = this; + var self = this; this.rest.types(function(data) { var styles = ''; $.each(data, function(index, value) { - var className = $this.name + '-' + value.type; - $this.types[value.type] = { + var className = self.name + '-' + value.type; + self.types[value.type] = { css : className, name : value.name || '', description : value.description || '' @@ -78,7 +78,7 @@ GuiElement.prototype = { options = options || {}; gui.doLog('Composing table for ' + this.name); var tableId = this.name + '-table'; - var $this = this; // Store this for child functions + var self = this; // Store this for child functions // --------------- // Cells renderers @@ -101,7 +101,7 @@ GuiElement.prototype = { // Icon renderer, based on type (created on init methods in styles) var renderTypeIcon = function(data, type, value){ if( type == 'display' ) { - var css = $this.types[value.type].css; + var css = self.types[value.type].css; return ' ' + renderEmptyCell(data); } else { return renderEmptyCell(data); @@ -185,7 +185,7 @@ GuiElement.prototype = { columns: columns, })).appendTo('head'); - $this.rest.overview(function(data) { // Gets "overview" data for table (table contents, but resume form) + self.rest.overview(function(data) { // Gets "overview" data for table (table contents, but resume form) var table = gui.table(title, tableId); if (options.container === undefined) { gui.appendToWorkspace('