Showing
4 changed files
with
108 additions
and
50 deletions
... | ... | @@ -238,23 +238,23 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) |
238 | 238 | function success() { |
239 | 239 | deferred.resolve(response.data); |
240 | 240 | }, |
241 | - function fail() { | |
242 | - deferred.reject(); | |
241 | + function fail(response) { | |
242 | + deferred.reject(response); | |
243 | 243 | } |
244 | 244 | ) |
245 | 245 | } else { |
246 | 246 | deferred.resolve(response.data); |
247 | 247 | } |
248 | - }, function fail() { | |
249 | - deferred.reject(); | |
248 | + }, function fail(response) { | |
249 | + deferred.reject(response); | |
250 | 250 | }); |
251 | 251 | } else if (deleteEntityAttributesPromise) { |
252 | 252 | deleteEntityAttributesPromise.then( |
253 | 253 | function success() { |
254 | 254 | deferred.resolve(); |
255 | 255 | }, |
256 | - function fail() { | |
257 | - deferred.reject(); | |
256 | + function fail(response) { | |
257 | + deferred.reject(response); | |
258 | 258 | } |
259 | 259 | ) |
260 | 260 | } else { |
... | ... | @@ -277,7 +277,7 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) |
277 | 277 | } |
278 | 278 | var deleteEntityTimeseriesPromise; |
279 | 279 | if (deleteTimeseries.length) { |
280 | - deleteEntityTimeseriesPromise = deleteEntityTimeseries(entityType, entityId, deleteTimeseries); | |
280 | + deleteEntityTimeseriesPromise = deleteEntityTimeseries(entityType, entityId, deleteTimeseries, config); | |
281 | 281 | } |
282 | 282 | if (Object.keys(timeseriesData).length) { |
283 | 283 | var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/' + timeseriesScope; |
... | ... | @@ -287,23 +287,23 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) |
287 | 287 | function success() { |
288 | 288 | deferred.resolve(response.data); |
289 | 289 | }, |
290 | - function fail() { | |
291 | - deferred.reject(); | |
290 | + function fail(response) { | |
291 | + deferred.reject(response); | |
292 | 292 | } |
293 | 293 | ) |
294 | 294 | } else { |
295 | 295 | deferred.resolve(response.data); |
296 | 296 | } |
297 | - }, function fail() { | |
298 | - deferred.reject(); | |
297 | + }, function fail(response) { | |
298 | + deferred.reject(response); | |
299 | 299 | }); |
300 | 300 | } else if (deleteEntityTimeseriesPromise) { |
301 | 301 | deleteEntityTimeseriesPromise.then( |
302 | 302 | function success() { |
303 | 303 | deferred.resolve(); |
304 | 304 | }, |
305 | - function fail() { | |
306 | - deferred.reject(); | |
305 | + function fail(response) { | |
306 | + deferred.reject(response); | |
307 | 307 | } |
308 | 308 | ) |
309 | 309 | } else { |
... | ... | @@ -312,7 +312,8 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) |
312 | 312 | return deferred.promise; |
313 | 313 | } |
314 | 314 | |
315 | - function deleteEntityAttributes(entityType, entityId, attributeScope, attributes) { | |
315 | + function deleteEntityAttributes(entityType, entityId, attributeScope, attributes, config) { | |
316 | + config = config || {}; | |
316 | 317 | var deferred = $q.defer(); |
317 | 318 | var keys = ''; |
318 | 319 | for (var i = 0; i < attributes.length; i++) { |
... | ... | @@ -322,15 +323,16 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) |
322 | 323 | keys += attributes[i].key; |
323 | 324 | } |
324 | 325 | var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/' + attributeScope + '?keys=' + keys; |
325 | - $http.delete(url).then(function success() { | |
326 | + $http.delete(url, config).then(function success() { | |
326 | 327 | deferred.resolve(); |
327 | - }, function fail() { | |
328 | - deferred.reject(); | |
328 | + }, function fail(response) { | |
329 | + deferred.reject(response); | |
329 | 330 | }); |
330 | 331 | return deferred.promise; |
331 | 332 | } |
332 | 333 | |
333 | - function deleteEntityTimeseries(entityType, entityId, timeseries) { | |
334 | + function deleteEntityTimeseries(entityType, entityId, timeseries, config) { | |
335 | + config = config || {}; | |
334 | 336 | var deferred = $q.defer(); |
335 | 337 | var keys = ''; |
336 | 338 | for (var i = 0; i < timeseries.length; i++) { |
... | ... | @@ -340,10 +342,10 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) |
340 | 342 | keys += timeseries[i].key; |
341 | 343 | } |
342 | 344 | var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/timeseries/delete' + '?keys=' + keys; |
343 | - $http.delete(url).then(function success() { | |
345 | + $http.delete(url, config).then(function success() { | |
344 | 346 | deferred.resolve(); |
345 | - }, function fail() { | |
346 | - deferred.reject(); | |
347 | + }, function fail(response) { | |
348 | + deferred.reject(response); | |
347 | 349 | }); |
348 | 350 | return deferred.promise; |
349 | 351 | } | ... | ... |
... | ... | @@ -20,7 +20,7 @@ export default angular.module('thingsboard.api.device', [thingsboardTypes]) |
20 | 20 | .name; |
21 | 21 | |
22 | 22 | /*@ngInject*/ |
23 | -function DeviceService($http, $q, $window, userService, attributeService, customerService, types) { | |
23 | +function DeviceService($http, $q, $window, userService, attributeService, customerService, types, $timeout) { | |
24 | 24 | |
25 | 25 | var service = { |
26 | 26 | assignDeviceToCustomer: assignDeviceToCustomer, |
... | ... | @@ -167,25 +167,45 @@ function DeviceService($http, $q, $window, userService, attributeService, custom |
167 | 167 | var url = '/api/device'; |
168 | 168 | $http.post(url, device, config).then(function success(response) { |
169 | 169 | deferred.resolve(response.data); |
170 | - }, function fail() { | |
171 | - deferred.reject(); | |
170 | + }, function fail(response) { | |
171 | + deferred.reject(response); | |
172 | + }); | |
173 | + return deferred.promise; | |
174 | + } | |
175 | + | |
176 | + function resendRequest(callback){ | |
177 | + const deferred = $q.defer(); | |
178 | + let request = callback(); | |
179 | + request.then(function success(response) { | |
180 | + deferred.resolve(response); | |
181 | + }, function fail(response) { | |
182 | + if (response.status === 429) { | |
183 | + $timeout(function () { | |
184 | + request = callback(); | |
185 | + }, 1000 + Math.random() * 10000); | |
186 | + } else { | |
187 | + deferred.reject(response); | |
188 | + } | |
172 | 189 | }); |
173 | 190 | return deferred.promise; |
174 | 191 | } |
175 | 192 | |
176 | 193 | function saveDeviceRelarion(deviceId, deviceRelation, config) { |
177 | - var deferred = $q.defer(); | |
178 | - var attributesType = Object.keys(types.attributesScope); | |
179 | - var allPromise = []; | |
180 | - var promise = ""; | |
181 | - for (var i = 0; i < attributesType.length; i++) { | |
194 | + const deferred = $q.defer(); | |
195 | + let attributesType = Object.keys(types.attributesScope); | |
196 | + let allPromise = []; | |
197 | + let promise = ""; | |
198 | + for (let i = 0; i < attributesType.length; i++) { | |
182 | 199 | if (deviceRelation.attributes[attributesType[i]] && deviceRelation.attributes[attributesType[i]].length !== 0) { |
183 | - promise = attributeService.saveEntityAttributes(types.entityType.device, deviceId, types.attributesScope[attributesType[i]].value, deviceRelation.attributes[attributesType[i]], config).then(function success() {}); | |
200 | + promise = resendRequest(function () { | |
201 | + return attributeService.saveEntityAttributes(types.entityType.device, deviceId, types.attributesScope[attributesType[i]].value, deviceRelation.attributes[attributesType[i]], config); | |
202 | + }); | |
184 | 203 | allPromise.push(promise); |
185 | 204 | } |
186 | 205 | } |
187 | 206 | if (deviceRelation.timeseries.length !== 0) { |
188 | - promise = attributeService.saveEntityTimeseries(types.entityType.device, deviceId, "time", deviceRelation.timeseries, config).then(function success() { | |
207 | + promise = resendRequest(function () { | |
208 | + return attributeService.saveEntityTimeseries(types.entityType.device, deviceId, "time", deviceRelation.timeseries, config); | |
189 | 209 | }); |
190 | 210 | allPromise.push(promise); |
191 | 211 | } |
... | ... | @@ -197,26 +217,41 @@ function DeviceService($http, $q, $window, userService, attributeService, custom |
197 | 217 | |
198 | 218 | function saveDeviceParameters(deviceParameters, update, config) { |
199 | 219 | config = config || {}; |
200 | - var deferred = $q.defer(); | |
201 | - var newDevice = { | |
220 | + const deferred = $q.defer(); | |
221 | + let statisticalInfo = { | |
222 | + create: {}, | |
223 | + update: {}, | |
224 | + error: {} | |
225 | + }; | |
226 | + let newDevice = { | |
202 | 227 | name: deviceParameters.name, |
203 | 228 | type: deviceParameters.type |
204 | 229 | }; |
205 | - saveDevice(newDevice, config).then(function success(response) { | |
230 | + resendRequest(function () { | |
231 | + return saveDevice(newDevice, config); | |
232 | + }).then(function success(response) { | |
233 | + statisticalInfo.create.device = 1; | |
206 | 234 | saveDeviceRelarion(response.id.id, deviceParameters, config).then(function success() { |
207 | - deferred.resolve(); | |
235 | + deferred.resolve(statisticalInfo); | |
208 | 236 | }); |
209 | - }, function fail() { | |
237 | + }, function fail(response) { | |
238 | + console.log(response); // eslint-disable-line | |
210 | 239 | if (update) { |
211 | - findByName(deviceParameters.name, config).then(function success(response) { | |
240 | + resendRequest(function () { | |
241 | + return findByName(deviceParameters.name, config); | |
242 | + }).then(function success(response) { | |
243 | + statisticalInfo.update.device = 1; | |
212 | 244 | saveDeviceRelarion(response.id.id, deviceParameters, config).then(function success() { |
213 | - deferred.resolve(); | |
245 | + deferred.resolve(statisticalInfo); | |
214 | 246 | }); |
247 | + }, function fail() { | |
248 | + statisticalInfo.error.device = newDevice; | |
249 | + deferred.resolve(statisticalInfo); | |
215 | 250 | }); |
216 | 251 | } else { |
217 | - deferred.resolve(); | |
252 | + statisticalInfo.error.device = newDevice; | |
253 | + deferred.resolve(statisticalInfo); | |
218 | 254 | } |
219 | - console.log("error"); // eslint-disable-line | |
220 | 255 | }); |
221 | 256 | return deferred.promise; |
222 | 257 | } |
... | ... | @@ -374,8 +409,8 @@ function DeviceService($http, $q, $window, userService, attributeService, custom |
374 | 409 | var url = '/api/tenant/devices?deviceName=' + deviceName; |
375 | 410 | $http.get(url, config).then(function success(response) { |
376 | 411 | deferred.resolve(response.data); |
377 | - }, function fail() { | |
378 | - deferred.reject(); | |
412 | + }, function fail(response) { | |
413 | + deferred.reject(response); | |
379 | 414 | }); |
380 | 415 | return deferred.promise; |
381 | 416 | } | ... | ... |
... | ... | @@ -27,13 +27,15 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo |
27 | 27 | |
28 | 28 | vm.addDevices = addDevices; |
29 | 29 | vm.importParams = { |
30 | - isUpdate: true | |
30 | + isUpdate: true, | |
31 | + isHeader: true | |
31 | 32 | }; |
32 | 33 | |
33 | 34 | vm.importTitle = importTitle; |
34 | 35 | vm.importFileLabel = importFileLabel; |
35 | 36 | |
36 | 37 | vm.columnsParam = []; |
38 | + vm.parseData = []; | |
37 | 39 | |
38 | 40 | vm.entityType = types.entityType.device; |
39 | 41 | vm.columnTypes = {}; |
... | ... | @@ -108,17 +110,26 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo |
108 | 110 | } |
109 | 111 | |
110 | 112 | function parseCSVData(importData) { |
113 | + var columnParam = {}; | |
111 | 114 | var config = { |
112 | 115 | delim: vm.importParams.delim, |
113 | 116 | header: vm.importParams.isHeader |
114 | 117 | }; |
115 | 118 | parseData = importExport.convertCSVToJson(importData, config); |
116 | 119 | for (var i = 0; i < parseData.headers.length; i++) { |
117 | - var columnParam = { | |
118 | - type: types.entityGroup.columnType.serverAttribute.value, | |
119 | - key: vm.importParams.isHeader ? parseData.headers[i] : "", | |
120 | - sampleData: parseData.rows[0][i] | |
121 | - }; | |
120 | + if (vm.importParams.isHeader && parseData.headers[i].search(/^(name|type)$/im) === 0) { | |
121 | + columnParam = { | |
122 | + type: types.entityGroup.columnType.entityField.value, | |
123 | + key: parseData.headers[i].toLowerCase(), | |
124 | + sampleData: parseData.rows[0][i] | |
125 | + }; | |
126 | + } else { | |
127 | + columnParam = { | |
128 | + type: types.entityGroup.columnType.serverAttribute.value, | |
129 | + key: vm.importParams.isHeader ? parseData.headers[i] : "", | |
130 | + sampleData: parseData.rows[0][i] | |
131 | + }; | |
132 | + } | |
122 | 133 | vm.columnsParam.push(columnParam); |
123 | 134 | } |
124 | 135 | } |
... | ... | @@ -132,6 +143,8 @@ export default function ImportDialogCsvController($scope, $mdDialog, toast, impo |
132 | 143 | // ["Device 3", "test", "test", false, 125], |
133 | 144 | // ["Device 4", "test", "test", false, 126], |
134 | 145 | // ["Device 5", "test", "test", false, 127]]}; |
146 | + arrayParam = vm.columnsParam; | |
147 | + data = parseData; | |
135 | 148 | var arrayData = []; |
136 | 149 | var config = { |
137 | 150 | ignoreErrors: true | ... | ... |
... | ... | @@ -810,7 +810,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, |
810 | 810 | return parseFloat(str.replace(',', '.')); |
811 | 811 | } |
812 | 812 | if (str.search(/^(true|false)$/im) === 0) { |
813 | - return str.toLowerCase() === 'true'; | |
813 | + return str === 'true'; | |
814 | 814 | } |
815 | 815 | if (str === "") { |
816 | 816 | return null; |
... | ... | @@ -822,12 +822,16 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, |
822 | 822 | config = config || {}; |
823 | 823 | const delim = config.delim || ","; |
824 | 824 | const header = config.header || false; |
825 | + let result = {}; | |
825 | 826 | |
826 | 827 | let csvlines = csvdata.split(/[\r\n]+/); |
827 | 828 | let csvheaders = splitCSV(csvlines[0], delim); |
829 | + if (csvheaders.length < 2) { | |
830 | + toast.showError('A file should contain at least two columns'); | |
831 | + return -1; | |
832 | + } | |
828 | 833 | let csvrows = header ? csvlines.slice(1, csvlines.length) : csvlines; |
829 | 834 | |
830 | - let result = {}; | |
831 | 835 | result.headers = csvheaders; |
832 | 836 | result.rows = []; |
833 | 837 | |
... | ... | @@ -839,6 +843,10 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document, |
839 | 843 | break; |
840 | 844 | |
841 | 845 | let rowitems = splitCSV(row, delim); |
846 | + if (rowitems.length !== result.headers.length) { | |
847 | + toast.showError('Invalid file format. Row:' + (header ? result.rows.length + 2: result.rows.length + 1)); | |
848 | + return -1; | |
849 | + } | |
842 | 850 | for (let i = 0; i < rowitems.length; i++) { |
843 | 851 | rowitems[i] = parseStringToFormatJS(rowitems[i]); |
844 | 852 | } | ... | ... |