1/**
2 * API utilities service
3 *
4 * @module app/common/services/api-utils
5 * @exports APIUtils
6 * @name APIUtils
7 */
8
9window.angular && (function(angular) {
10  'use strict';
11  angular.module('app.common.services').factory('APIUtils', [
12    '$http', 'Constants', '$q', 'dataService',
13    function($http, Constants, $q, DataService) {
14      var getScaledValue = function(value, scale) {
15        scale = scale + '';
16        scale = parseInt(scale, 10);
17        var power = Math.abs(parseInt(scale, 10));
18
19        if (scale > 0) {
20          value = value * Math.pow(10, power);
21        } else if (scale < 0) {
22          value = value / Math.pow(10, power);
23        }
24        return value;
25      };
26      var SERVICE = {
27        API_CREDENTIALS: Constants.API_CREDENTIALS,
28        API_RESPONSE: Constants.API_RESPONSE,
29        CHASSIS_POWER_STATE: Constants.CHASSIS_POWER_STATE,
30        HOST_STATE_TEXT: Constants.HOST_STATE,
31        HOST_STATE: Constants.HOST_STATE,
32        LED_STATE: Constants.LED_STATE,
33        LED_STATE_TEXT: Constants.LED_STATE_TEXT,
34        HOST_SESSION_STORAGE_KEY: Constants.API_CREDENTIALS.host_storage_key,
35        getChassisState: function() {
36          var deferred = $q.defer();
37          $http({
38            method: 'GET',
39            url: DataService.getHost() +
40                '/xyz/openbmc_project/state/chassis0/attr/CurrentPowerState',
41            headers: {
42              'Accept': 'application/json',
43              'Content-Type': 'application/json'
44            },
45            withCredentials: true
46          })
47              .then(
48                  function(response) {
49                    var json = JSON.stringify(response.data);
50                    var content = JSON.parse(json);
51                    deferred.resolve(content.data);
52                  },
53                  function(error) {
54                    console.log(error);
55                    deferred.reject(error);
56                  });
57          return deferred.promise;
58        },
59        getHostState: function() {
60          var deferred = $q.defer();
61          $http({
62            method: 'GET',
63            url: DataService.getHost() +
64                '/xyz/openbmc_project/state/host0/attr/CurrentHostState',
65            headers: {
66              'Accept': 'application/json',
67              'Content-Type': 'application/json'
68            },
69            withCredentials: true
70          })
71              .then(
72                  function(response) {
73                    var json = JSON.stringify(response.data);
74                    var content = JSON.parse(json);
75                    deferred.resolve(content.data);
76                  },
77                  function(error) {
78                    console.log(error);
79                    deferred.reject(error);
80                  });
81          return deferred.promise;
82        },
83        getNetworkInfo: function() {
84          var deferred = $q.defer();
85          $http({
86            method: 'GET',
87            url: DataService.getHost() +
88                '/xyz/openbmc_project/network/enumerate',
89            headers: {
90              'Accept': 'application/json',
91              'Content-Type': 'application/json'
92            },
93            withCredentials: true
94          })
95              .then(
96                  function(response) {
97                    var json = JSON.stringify(response.data);
98                    var content = JSON.parse(json);
99                    var hostname = '';
100                    var macAddress = '';
101
102                    function parseNetworkData(content) {
103                      var data = {
104                        interface_ids: [],
105                        interfaces: {},
106                        ip_addresses: {ipv4: [], ipv6: []},
107                      };
108                      var interfaceId = '', keyParts = [], interfaceHash = '',
109                          interfaceType = '';
110                      for (var key in content.data) {
111                        if (key.match(/network\/eth\d+$/ig)) {
112                          interfaceId = key.split('/').pop();
113                          if (data.interface_ids.indexOf(interfaceId) == -1) {
114                            data.interface_ids.push(interfaceId);
115                            data.interfaces[interfaceId] = {
116                              interfaceIname: '',
117                              DomainName: '',
118                              MACAddress: '',
119                              Nameservers: [],
120                              DHCPEnabled: 0,
121                              ipv4: {ids: [], values: []},
122                              ipv6: {ids: [], values: []}
123                            };
124                            data.interfaces[interfaceId].MACAddress =
125                                content.data[key].MACAddress;
126                            data.interfaces[interfaceId].DomainName =
127                                content.data[key].DomainName.join(' ');
128                            data.interfaces[interfaceId].Nameservers =
129                                content.data[key].Nameservers;
130                            data.interfaces[interfaceId].DHCPEnabled =
131                                content.data[key].DHCPEnabled;
132                          }
133                        } else if (
134                            key.match(
135                                /network\/eth\d+\/ipv[4|6]\/[a-z0-9]+$/ig)) {
136                          keyParts = key.split('/');
137                          interfaceHash = keyParts.pop();
138                          interfaceType = keyParts.pop();
139                          interfaceId = keyParts.pop();
140
141                          if (data.interfaces[interfaceId][interfaceType]
142                                  .ids.indexOf(interfaceHash) == -1) {
143                            data.interfaces[interfaceId][interfaceType]
144                                .ids.push(interfaceHash);
145                            data.interfaces[interfaceId][interfaceType]
146                                .values.push(content.data[key]);
147                            data.ip_addresses[interfaceType].push(
148                                content.data[key]['Address']);
149                          }
150                        }
151                      }
152                      return data;
153                    }
154
155                    if (content.data.hasOwnProperty(
156                            '/xyz/openbmc_project/network/config') &&
157                        content.data['/xyz/openbmc_project/network/config']
158                            .hasOwnProperty('HostName')) {
159                      hostname =
160                          content.data['/xyz/openbmc_project/network/config']
161                              .HostName;
162                    }
163
164                    if (content.data.hasOwnProperty(
165                            '/xyz/openbmc_project/network/eth0') &&
166                        content.data['/xyz/openbmc_project/network/eth0']
167                            .hasOwnProperty('MACAddress')) {
168                      macAddress =
169                          content.data['/xyz/openbmc_project/network/eth0']
170                              .MACAddress;
171                    }
172
173                    deferred.resolve({
174                      data: content.data,
175                      hostname: hostname,
176                      mac_address: macAddress,
177                      formatted_data: parseNetworkData(content)
178                    });
179                  },
180                  function(error) {
181                    console.log(error);
182                    deferred.reject(error);
183                  });
184          return deferred.promise;
185        },
186        setMACAddress: function(interface_name, mac_address) {
187          return $http({
188                   method: 'PUT',
189                   url: DataService.getHost() +
190                       '/xyz/openbmc_project/network/' + interface_name +
191                       '/attr/MACAddress',
192                   headers: {
193                     'Accept': 'application/json',
194                     'Content-Type': 'application/json'
195                   },
196                   withCredentials: true,
197                   data: JSON.stringify({'data': mac_address})
198                 })
199              .then(function(response) {
200                return response.data;
201              });
202        },
203        getLEDState: function() {
204          var deferred = $q.defer();
205          $http({
206            method: 'GET',
207            url: DataService.getHost() +
208                '/xyz/openbmc_project/led/groups/enclosure_identify',
209            headers: {
210              'Accept': 'application/json',
211              'Content-Type': 'application/json'
212            },
213            withCredentials: true
214          })
215              .then(
216                  function(response) {
217                    var json = JSON.stringify(response.data);
218                    var content = JSON.parse(json);
219                    deferred.resolve(content.data.Asserted);
220                  },
221                  function(error) {
222                    console.log(error);
223                    deferred.reject(error);
224                  });
225          return deferred.promise;
226        },
227        login: function(username, password, callback) {
228          $http({
229            method: 'POST',
230            url: DataService.getHost() + '/login',
231            headers: {
232              'Accept': 'application/json',
233              'Content-Type': 'application/json'
234            },
235            withCredentials: true,
236            data: JSON.stringify({'data': [username, password]})
237          })
238              .then(
239                  function(response) {
240                    if (callback) {
241                      callback(response.data);
242                    }
243                  },
244                  function(error) {
245                    if (callback) {
246                      if (error && error.status && error.status == 'error') {
247                        callback(error);
248                      } else {
249                        callback(error, true);
250                      }
251                    }
252                    console.log(error);
253                  });
254        },
255        testPassword: function(username, password) {
256          // Calls /login without the current session to verify the given
257          // password is correct ignore the interceptor logout on a bad password
258          return $http({
259                   method: 'POST',
260                   url: DataService.getHost() + '/login',
261                   headers: {
262                     'Accept': 'application/json',
263                     'Content-Type': 'application/json'
264                   },
265                   withCredentials: false,
266                   data: JSON.stringify({'data': [username, password]})
267                 })
268              .then(function(response) {
269                return response.data;
270              });
271        },
272        logout: function(callback) {
273          $http({
274            method: 'POST',
275            url: DataService.getHost() + '/logout',
276            headers: {
277              'Accept': 'application/json',
278              'Content-Type': 'application/json'
279            },
280            withCredentials: true,
281            data: JSON.stringify({'data': []})
282          })
283              .then(
284                  function(response) {
285                    if (callback) {
286                      callback(response.data);
287                    }
288                  },
289                  function(error) {
290                    if (callback) {
291                      callback(null, error);
292                    }
293                    console.log(error);
294                  });
295        },
296        changePassword: function(user, newPassword) {
297          var deferred = $q.defer();
298          $http({
299            method: 'POST',
300            url: DataService.getHost() + '/xyz/openbmc_project/user/' + user +
301                '/action/SetPassword',
302            headers: {
303              'Accept': 'application/json',
304              'Content-Type': 'application/json'
305            },
306            withCredentials: true,
307            data: JSON.stringify({'data': [newPassword]}),
308            responseType: 'arraybuffer'
309          })
310              .then(
311                  function(response, status, headers) {
312                    deferred.resolve(
313                        {data: response, status: status, headers: headers});
314                  },
315                  function(error) {
316                    console.log(error);
317                    deferred.reject(error);
318                  });
319          return deferred.promise;
320        },
321        chassisPowerOn: function(callback) {
322          $http({
323            method: 'POST',
324            url: DataService.getHost() + '/xyz/openbmc_project/state/host0',
325            headers: {
326              'Accept': 'application/json',
327              'Content-Type': 'application/json'
328            },
329            withCredentials: true,
330            data: JSON.stringify({'data': []})
331          })
332              .then(
333                  function(response) {
334                    var json = JSON.stringify(response.data);
335                    var content = JSON.parse(json);
336                    if (callback) {
337                      return callback(content.data.CurrentPowerState);
338                    }
339                  },
340                  function(error) {
341                    if (callback) {
342                      callback(error);
343                    } else {
344                      console.log(error);
345                    }
346                  });
347        },
348        chassisPowerOff: function() {
349          var deferred = $q.defer();
350          $http({
351            method: 'PUT',
352            url: DataService.getHost() +
353                '/xyz/openbmc_project/state/chassis0/attr/RequestedPowerTransition',
354            headers: {
355              'Accept': 'application/json',
356              'Content-Type': 'application/json'
357            },
358            withCredentials: true,
359            data: JSON.stringify(
360                {'data': 'xyz.openbmc_project.State.Chassis.Transition.Off'})
361          })
362              .then(
363                  function(response) {
364                    var json = JSON.stringify(response.data);
365                    var content = JSON.parse(json);
366                    deferred.resolve(content.status);
367                  },
368                  function(error) {
369                    console.log(error);
370                    deferred.reject(error);
371                  });
372          return deferred.promise;
373        },
374        setLEDState: function(state, callback) {
375          $http({
376            method: 'PUT',
377            url: DataService.getHost() +
378                '/xyz/openbmc_project/led/groups/enclosure_identify/attr/Asserted',
379            headers: {
380              'Accept': 'application/json',
381              'Content-Type': 'application/json'
382            },
383            withCredentials: true,
384            data: JSON.stringify({'data': state})
385          })
386              .then(
387                  function(response) {
388                    var json = JSON.stringify(response.data);
389                    var content = JSON.parse(json);
390                    if (callback) {
391                      return callback(content.status);
392                    }
393                  },
394                  function(error) {
395                    if (callback) {
396                      callback(error);
397                    } else {
398                      console.log(error);
399                    }
400                  });
401        },
402        bmcReboot: function(callback) {
403          $http({
404            method: 'PUT',
405            url: DataService.getHost() +
406                '/xyz/openbmc_project/state/bmc0/attr/RequestedBmcTransition',
407            headers: {
408              'Accept': 'application/json',
409              'Content-Type': 'application/json'
410            },
411            withCredentials: true,
412            data: JSON.stringify(
413                {'data': 'xyz.openbmc_project.State.BMC.Transition.Reboot'})
414          })
415              .then(
416                  function(response) {
417                    var json = JSON.stringify(response.data);
418                    var content = JSON.parse(json);
419                    if (callback) {
420                      return callback(content.status);
421                    }
422                  },
423                  function(error) {
424                    if (callback) {
425                      callback(error);
426                    } else {
427                      console.log(error);
428                    }
429                  });
430        },
431        hostPowerOn: function() {
432          var deferred = $q.defer();
433          $http({
434            method: 'PUT',
435            url: DataService.getHost() +
436                '/xyz/openbmc_project/state/host0/attr/RequestedHostTransition',
437            headers: {
438              'Accept': 'application/json',
439              'Content-Type': 'application/json'
440            },
441            withCredentials: true,
442            data: JSON.stringify(
443                {'data': 'xyz.openbmc_project.State.Host.Transition.On'})
444          })
445              .then(
446                  function(response) {
447                    var json = JSON.stringify(response.data);
448                    var content = JSON.parse(json);
449                    deferred.resolve(content.status);
450                  },
451                  function(error) {
452                    console.log(error);
453                    deferred.reject(error);
454                  });
455          return deferred.promise;
456        },
457        hostPowerOff: function() {
458          var deferred = $q.defer();
459          $http({
460            method: 'PUT',
461            url: DataService.getHost() +
462                '/xyz/openbmc_project/state/host0/attr/RequestedHostTransition',
463            headers: {
464              'Accept': 'application/json',
465              'Content-Type': 'application/json'
466            },
467            withCredentials: true,
468            data: JSON.stringify(
469                {'data': 'xyz.openbmc_project.State.Host.Transition.Off'})
470          })
471              .then(
472                  function(response) {
473                    var json = JSON.stringify(response.data);
474                    var content = JSON.parse(json);
475                    deferred.resolve(content.status);
476                  },
477                  function(error) {
478                    console.log(error);
479                    deferred.reject(error);
480                  });
481          return deferred.promise;
482        },
483        hostReboot: function() {
484          var deferred = $q.defer();
485          $http({
486            method: 'PUT',
487            url: DataService.getHost() +
488                '/xyz/openbmc_project/state/host0/attr/RequestedHostTransition',
489            headers: {
490              'Accept': 'application/json',
491              'Content-Type': 'application/json'
492            },
493            withCredentials: true,
494            data: JSON.stringify(
495                {'data': 'xyz.openbmc_project.State.Host.Transition.Reboot'})
496          })
497              .then(
498                  function(response) {
499                    var json = JSON.stringify(response.data);
500                    var content = JSON.parse(json);
501                    deferred.resolve(content.status);
502                  },
503                  function(error) {
504                    console.log(error);
505                    deferred.reject(error);
506                  });
507
508          return deferred.promise;
509        },
510        hostShutdown: function(callback) {
511          $http({
512            method: 'POST',
513            url: DataService.getHost() + '/xyz/openbmc_project/state/host0',
514            headers: {
515              'Accept': 'application/json',
516              'Content-Type': 'application/json'
517            },
518            withCredentials: true,
519            data: JSON.stringify({'data': []})
520          })
521              .then(
522                  function(response) {
523                    var json = JSON.stringify(response.data);
524                    var content = JSON.parse(json);
525                    if (callback) {
526                      return callback(content);
527                    }
528                  },
529                  function(error) {
530                    if (callback) {
531                      callback(error);
532                    } else {
533                      console.log(error);
534                    }
535                  });
536        },
537        getLogs: function() {
538          var deferred = $q.defer();
539          $http({
540            method: 'GET',
541            url: DataService.getHost() +
542                '/xyz/openbmc_project/logging/enumerate',
543            headers: {
544              'Accept': 'application/json',
545              'Content-Type': 'application/json'
546            },
547            withCredentials: true
548          })
549              .then(
550                  function(response) {
551                    var json = JSON.stringify(response.data);
552                    var content = JSON.parse(json);
553                    var dataClone = JSON.parse(JSON.stringify(content.data));
554                    var data = [];
555                    var severityCode = '';
556                    var priority = '';
557                    var health = '';
558                    var relatedItems = [];
559
560                    for (var key in content.data) {
561                      if (content.data.hasOwnProperty(key) &&
562                          content.data[key].hasOwnProperty('Id')) {
563                        var severityFlags = {
564                          low: false,
565                          medium: false,
566                          high: false
567                        };
568                        var healthFlags = {
569                          critical: false,
570                          warning: false,
571                          good: false
572                        };
573                        severityCode =
574                            content.data[key].Severity.split('.').pop();
575                        priority =
576                            Constants.SEVERITY_TO_PRIORITY_MAP[severityCode];
577                        severityFlags[priority.toLowerCase()] = true;
578                        health = Constants.SEVERITY_TO_HEALTH_MAP[severityCode];
579                        healthFlags[health.toLowerCase()] = true;
580                        relatedItems = [];
581                        content.data[key].associations.forEach(function(item) {
582                          relatedItems.push(item[2]);
583                        });
584
585                        data.push(Object.assign(
586                            {
587                              path: key,
588                              copied: false,
589                              priority: priority,
590                              severity_code: severityCode,
591                              severity_flags: severityFlags,
592                              health_flags: healthFlags,
593                              additional_data:
594                                  content.data[key].AdditionalData.join('\n'),
595                              type: content.data[key].Message,
596                              selected: false,
597                              search_text:
598                                  ('#' + content.data[key].Id + ' ' +
599                                   severityCode + ' ' +
600                                   content.data[key].Severity + ' ' +
601                                   content.data[key].AdditionalData.join(' '))
602                                      .toLowerCase(),
603                              meta: false,
604                              confirm: false,
605                              related_items: relatedItems,
606                              data: {key: key, value: content.data[key]}
607                            },
608                            content.data[key]));
609                      }
610                    }
611                    deferred.resolve({data: data, original: dataClone});
612                  },
613                  function(error) {
614                    console.log(error);
615                    deferred.reject(error);
616                  });
617
618          return deferred.promise;
619        },
620        getAllSensorStatus: function(callback) {
621          $http({
622            method: 'GET',
623            url: DataService.getHost() +
624                '/xyz/openbmc_project/sensors/enumerate',
625            headers: {
626              'Accept': 'application/json',
627              'Content-Type': 'application/json'
628            },
629            withCredentials: true
630          })
631              .then(
632                  function(response) {
633                    var json = JSON.stringify(response.data);
634                    var content = JSON.parse(json);
635                    var dataClone = JSON.parse(JSON.stringify(content.data));
636                    var sensorData = [];
637                    var severity = {};
638                    var title = '';
639                    var tempKeyParts = [];
640                    var order = 0;
641                    var customOrder = 0;
642
643                    function getSensorStatus(reading) {
644                      var severityFlags = {
645                        critical: false,
646                        warning: false,
647                        normal: false
648                      },
649                          severityText = '', order = 0;
650
651                      if (reading.hasOwnProperty('CriticalLow') &&
652                          reading.Value < reading.CriticalLow) {
653                        severityFlags.critical = true;
654                        severityText = 'critical';
655                        order = 2;
656                      } else if (
657                          reading.hasOwnProperty('CriticalHigh') &&
658                          reading.Value > reading.CriticalHigh) {
659                        severityFlags.critical = true;
660                        severityText = 'critical';
661                        order = 2;
662                      } else if (
663                          reading.hasOwnProperty('CriticalLow') &&
664                          reading.hasOwnProperty('WarningLow') &&
665                          reading.Value >= reading.CriticalLow &&
666                          reading.Value <= reading.WarningLow) {
667                        severityFlags.warning = true;
668                        severityText = 'warning';
669                        order = 1;
670                      } else if (
671                          reading.hasOwnProperty('WarningHigh') &&
672                          reading.hasOwnProperty('CriticalHigh') &&
673                          reading.Value >= reading.WarningHigh &&
674                          reading.Value <= reading.CriticalHigh) {
675                        severityFlags.warning = true;
676                        severityText = 'warning';
677                        order = 1;
678                      } else {
679                        severityFlags.normal = true;
680                        severityText = 'normal';
681                      }
682                      return {
683                        flags: severityFlags,
684                        severityText: severityText,
685                        order: order
686                      };
687                    }
688
689                    for (var key in content.data) {
690                      if (content.data.hasOwnProperty(key) &&
691                          content.data[key].hasOwnProperty('Unit')) {
692                        severity = getSensorStatus(content.data[key]);
693
694                        if (!content.data[key].hasOwnProperty('CriticalLow')) {
695                          content.data[key].CriticalLow = '--';
696                          content.data[key].CriticalHigh = '--';
697                        }
698
699                        if (!content.data[key].hasOwnProperty('WarningLow')) {
700                          content.data[key].WarningLow = '--';
701                          content.data[key].WarningHigh = '--';
702                        }
703
704                        tempKeyParts = key.split('/');
705                        title = tempKeyParts.pop();
706                        title = tempKeyParts.pop() + '_' + title;
707                        title = title.split('_')
708                                    .map(function(item) {
709                                      return item.toLowerCase()
710                                                 .charAt(0)
711                                                 .toUpperCase() +
712                                          item.slice(1);
713                                    })
714                                    .reduce(function(prev, el) {
715                                      return prev + ' ' + el;
716                                    });
717
718                        content.data[key].Value = getScaledValue(
719                            content.data[key].Value, content.data[key].Scale);
720                        content.data[key].CriticalLow = getScaledValue(
721                            content.data[key].CriticalLow,
722                            content.data[key].Scale);
723                        content.data[key].CriticalHigh = getScaledValue(
724                            content.data[key].CriticalHigh,
725                            content.data[key].Scale);
726                        content.data[key].WarningLow = getScaledValue(
727                            content.data[key].WarningLow,
728                            content.data[key].Scale);
729                        content.data[key].WarningHigh = getScaledValue(
730                            content.data[key].WarningHigh,
731                            content.data[key].Scale);
732                        if (Constants.SENSOR_SORT_ORDER.indexOf(
733                                content.data[key].Unit) > -1) {
734                          customOrder = Constants.SENSOR_SORT_ORDER.indexOf(
735                              content.data[key].Unit);
736                        } else {
737                          customOrder = Constants.SENSOR_SORT_ORDER_DEFAULT;
738                        }
739
740                        sensorData.push(Object.assign(
741                            {
742                              path: key,
743                              selected: false,
744                              confirm: false,
745                              copied: false,
746                              title: title,
747                              unit:
748                                  Constants
749                                      .SENSOR_UNIT_MAP[content.data[key].Unit],
750                              severity_flags: severity.flags,
751                              status: severity.severityText,
752                              order: severity.order,
753                              custom_order: customOrder,
754                              search_text:
755                                  (title + ' ' + content.data[key].Value + ' ' +
756                                   Constants.SENSOR_UNIT_MAP[content.data[key]
757                                                                 .Unit] +
758                                   ' ' + severity.severityText + ' ' +
759                                   content.data[key].CriticalLow + ' ' +
760                                   content.data[key].CriticalHigh + ' ' +
761                                   content.data[key].WarningLow + ' ' +
762                                   content.data[key].WarningHigh + ' ')
763                                      .toLowerCase(),
764                              original_data:
765                                  {key: key, value: content.data[key]}
766                            },
767                            content.data[key]));
768                      }
769                    }
770
771                    callback(sensorData, dataClone);
772                  },
773                  function(error) {
774                    console.log(error);
775                  });
776        },
777        getActivation: function(imageId) {
778          return $http({
779                   method: 'GET',
780                   url: DataService.getHost() +
781                       '/xyz/openbmc_project/software/' + imageId +
782                       '/attr/Activation',
783                   headers: {
784                     'Accept': 'application/json',
785                     'Content-Type': 'application/json'
786                   },
787                   withCredentials: true
788                 })
789              .then(function(response) {
790                return response.data;
791              });
792        },
793        getFirmwares: function() {
794          var deferred = $q.defer();
795          $http({
796            method: 'GET',
797            url: DataService.getHost() +
798                '/xyz/openbmc_project/software/enumerate',
799            headers: {
800              'Accept': 'application/json',
801              'Content-Type': 'application/json'
802            },
803            withCredentials: true
804          })
805              .then(
806                  function(response) {
807                    var json = JSON.stringify(response.data);
808                    var content = JSON.parse(json);
809                    var data = [];
810                    var activationStatus = '';
811                    var isExtended = false;
812                    var bmcActiveVersion = '';
813                    var hostActiveVersion = '';
814                    var imageType = '';
815                    var extendedVersions = [];
816                    var functionalImages = [];
817
818                    function getFormatedExtendedVersions(extendedVersion) {
819                      var versions = [];
820                      extendedVersion = extendedVersion.split(',');
821
822                      extendedVersion.forEach(function(item) {
823                        var parts = item.split('-');
824                        var numberIndex = 0;
825                        for (var i = 0; i < parts.length; i++) {
826                          if (/[0-9]/.test(parts[i])) {
827                            numberIndex = i;
828                            break;
829                          }
830                        }
831                        var titlePart = parts.splice(0, numberIndex);
832                        titlePart = titlePart.join('');
833                        titlePart = titlePart[0].toUpperCase() +
834                            titlePart.substr(1, titlePart.length);
835                        var versionPart = parts.join('-');
836                        versions.push({title: titlePart, version: versionPart});
837                      });
838
839                      return versions;
840                    }
841
842                    // Get the list of functional images so we can compare
843                    // later if an image is functional
844                    if (content.data[Constants.FIRMWARE.FUNCTIONAL_OBJPATH]) {
845                      functionalImages =
846                          content.data[Constants.FIRMWARE.FUNCTIONAL_OBJPATH]
847                              .endpoints;
848                    }
849                    for (var key in content.data) {
850                      if (content.data.hasOwnProperty(key) &&
851                          content.data[key].hasOwnProperty('Version')) {
852                        // If the image is "Functional" use that for the
853                        // activation status, else use the value of "Activation"
854                        // github.com/openbmc/phosphor-dbus-interfaces/blob/master/xyz/openbmc_project/Software/Activation.interface.yaml
855                        activationStatus =
856                            content.data[key].Activation.split('.').pop();
857                        if (functionalImages.includes(key)) {
858                          activationStatus = 'Functional';
859                        }
860
861                        imageType = content.data[key].Purpose.split('.').pop();
862                        isExtended = content.data[key].hasOwnProperty(
863                                         'ExtendedVersion') &&
864                            content.data[key].ExtendedVersion != '';
865                        if (isExtended) {
866                          extendedVersions = getFormatedExtendedVersions(
867                              content.data[key].ExtendedVersion);
868                        }
869                        data.push(Object.assign(
870                            {
871                              path: key,
872                              activationStatus: activationStatus,
873                              imageId: key.split('/').pop(),
874                              imageType: imageType,
875                              isExtended: isExtended,
876                              extended:
877                                  {show: false, versions: extendedVersions},
878                              data: {key: key, value: content.data[key]}
879                            },
880                            content.data[key]));
881
882                        if (activationStatus == 'Functional' &&
883                            imageType == 'BMC') {
884                          bmcActiveVersion = content.data[key].Version;
885                        }
886
887                        if (activationStatus == 'Functional' &&
888                            imageType == 'Host') {
889                          hostActiveVersion = content.data[key].Version;
890                        }
891                      }
892                    }
893
894                    deferred.resolve({
895                      data: data,
896                      bmcActiveVersion: bmcActiveVersion,
897                      hostActiveVersion: hostActiveVersion
898                    });
899                  },
900                  function(error) {
901                    console.log(error);
902                    deferred.reject(error);
903                  });
904
905          return deferred.promise;
906        },
907        changePriority: function(imageId, priority) {
908          var deferred = $q.defer();
909          $http({
910            method: 'PUT',
911            url: DataService.getHost() + '/xyz/openbmc_project/software/' +
912                imageId + '/attr/Priority',
913            headers: {
914              'Accept': 'application/json',
915              'Content-Type': 'application/json'
916            },
917            withCredentials: true,
918            data: JSON.stringify({'data': priority})
919          })
920              .then(
921                  function(response) {
922                    var json = JSON.stringify(response.data);
923                    var content = JSON.parse(json);
924                    deferred.resolve(content);
925                  },
926                  function(error) {
927                    console.log(error);
928                    deferred.reject(error);
929                  });
930
931          return deferred.promise;
932        },
933        deleteImage: function(imageId) {
934          var deferred = $q.defer();
935          $http({
936            method: 'POST',
937            url: DataService.getHost() + '/xyz/openbmc_project/software/' +
938                imageId + '/action/Delete',
939            headers: {
940              'Accept': 'application/json',
941              'Content-Type': 'application/json'
942            },
943            withCredentials: true,
944            data: JSON.stringify({'data': []})
945          })
946              .then(
947                  function(response) {
948                    var json = JSON.stringify(response.data);
949                    var content = JSON.parse(json);
950                    deferred.resolve(content);
951                  },
952                  function(error) {
953                    console.log(error);
954                    deferred.reject(error);
955                  });
956
957          return deferred.promise;
958        },
959        activateImage: function(imageId) {
960          var deferred = $q.defer();
961          $http({
962            method: 'PUT',
963            url: DataService.getHost() + '/xyz/openbmc_project/software/' +
964                imageId + '/attr/RequestedActivation',
965            headers: {
966              'Accept': 'application/json',
967              'Content-Type': 'application/json'
968            },
969            withCredentials: true,
970            data:
971                JSON.stringify({'data': Constants.FIRMWARE.ACTIVATE_FIRMWARE})
972          })
973              .then(
974                  function(response) {
975                    var json = JSON.stringify(response.data);
976                    var content = JSON.parse(json);
977                    deferred.resolve(content);
978                  },
979                  function(error) {
980                    console.log(error);
981                    deferred.reject(error);
982                  });
983
984          return deferred.promise;
985        },
986        uploadImage: function(file) {
987          return $http({
988                   method: 'POST',
989                   timeout: 5 * 60 * 1000,
990                   url: DataService.getHost() + '/upload/image',
991                   headers: {'Content-Type': 'application/octet-stream'},
992                   withCredentials: true,
993                   data: file
994                 })
995              .then(function(response) {
996                return response.data;
997              });
998        },
999        downloadImage: function(host, filename) {
1000          return $http({
1001                   method: 'POST',
1002                   url: DataService.getHost() +
1003                       '/xyz/openbmc_project/software/action/DownloadViaTFTP',
1004                   headers: {
1005                     'Accept': 'application/json',
1006                     'Content-Type': 'application/json'
1007                   },
1008                   withCredentials: true,
1009                   data: JSON.stringify({'data': [filename, host]}),
1010                   responseType: 'arraybuffer'
1011                 })
1012              .then(function(response) {
1013                return response.data;
1014              });
1015        },
1016        getBMCEthernetInfo: function() {
1017          var deferred = $q.defer();
1018          $http({
1019            method: 'GET',
1020            url: DataService.getHost() +
1021                '/xyz/openbmc_project/inventory/system/chassis/motherboard/boxelder/bmc/ethernet',
1022            headers: {
1023              'Accept': 'application/json',
1024              'Content-Type': 'application/json'
1025            },
1026            withCredentials: true
1027          })
1028              .then(
1029                  function(response) {
1030                    var json = JSON.stringify(response.data);
1031                    var content = JSON.parse(json);
1032                    deferred.resolve(content.data);
1033                  },
1034                  function(error) {
1035                    console.log(error);
1036                    deferred.reject(error);
1037                  });
1038
1039          return deferred.promise;
1040        },
1041        getBMCInfo: function(callback) {
1042          var deferred = $q.defer();
1043          $http({
1044            method: 'GET',
1045            url: DataService.getHost() +
1046                '/xyz/openbmc_project/inventory/system/chassis/motherboard/boxelder/bmc',
1047            headers: {
1048              'Accept': 'application/json',
1049              'Content-Type': 'application/json'
1050            },
1051            withCredentials: true
1052          })
1053              .then(
1054                  function(response) {
1055                    var json = JSON.stringify(response.data);
1056                    var content = JSON.parse(json);
1057                    deferred.resolve(content.data);
1058                  },
1059                  function(error) {
1060                    console.log(error);
1061                    deferred.reject(error);
1062                  });
1063          return deferred.promise;
1064        },
1065        getServerInfo: function() {
1066          // TODO: openbmc/openbmc#3117 Need a way via REST to get
1067          // interfaces so we can get the system object(s) by the looking
1068          // for the system interface.
1069          return $http({
1070                   method: 'GET',
1071                   url: DataService.getHost() +
1072                       '/xyz/openbmc_project/inventory/system',
1073                   headers: {
1074                     'Accept': 'application/json',
1075                     'Content-Type': 'application/json'
1076                   },
1077                   withCredentials: true
1078                 })
1079              .then(function(response) {
1080                return response.data;
1081              });
1082        },
1083        getBMCTime: function() {
1084          return $http({
1085                   method: 'GET',
1086                   url: DataService.getHost() + '/xyz/openbmc_project/time/bmc',
1087                   headers: {
1088                     'Accept': 'application/json',
1089                     'Content-Type': 'application/json'
1090                   },
1091                   withCredentials: true
1092                 })
1093              .then(function(response) {
1094                return response.data;
1095              });
1096        },
1097        getHardwares: function(callback) {
1098          $http({
1099            method: 'GET',
1100            url: DataService.getHost() +
1101                '/xyz/openbmc_project/inventory/enumerate',
1102            headers: {
1103              'Accept': 'application/json',
1104              'Content-Type': 'application/json'
1105            },
1106            withCredentials: true
1107          }).then(function(response) {
1108            var json = JSON.stringify(response.data);
1109            var content = JSON.parse(json);
1110            var hardwareData = [];
1111            var keyIndexMap = {};
1112            var title = '';
1113            var data = [];
1114            var searchText = '';
1115            var componentIndex = -1;
1116            var tempParts = [];
1117
1118            function isSubComponent(key) {
1119              for (var i = 0; i < Constants.HARDWARE.parent_components.length;
1120                   i++) {
1121                if (key.split(Constants.HARDWARE.parent_components[i]).length ==
1122                    2)
1123                  return true;
1124              }
1125
1126              return false;
1127            }
1128
1129            function titlelize(title) {
1130              title = title.replace(/([A-Z0-9]+)/g, ' $1').replace(/^\s+/, '');
1131              for (var i = 0; i < Constants.HARDWARE.uppercase_titles.length;
1132                   i++) {
1133                if (title.toLowerCase().indexOf(
1134                        (Constants.HARDWARE.uppercase_titles[i] + ' ')) > -1) {
1135                  return title.toUpperCase();
1136                }
1137              }
1138
1139              return title;
1140            }
1141
1142            function camelcaseToLabel(obj) {
1143              var transformed = [], label = '', value = '';
1144              for (var key in obj) {
1145                label = key.replace(/([A-Z0-9]+)/g, ' $1').replace(/^\s+/, '');
1146                if (obj[key] !== '') {
1147                  value = obj[key];
1148                  if (value == 1 || value == 0) {
1149                    value = (value == 1) ? 'Yes' : 'No';
1150                  }
1151                  transformed.push({key: label, value: value});
1152                }
1153              }
1154
1155              return transformed;
1156            }
1157
1158            function getSearchText(data) {
1159              var searchText = '';
1160              for (var i = 0; i < data.length; i++) {
1161                searchText += ' ' + data[i].key + ' ' + data[i].value;
1162              }
1163
1164              return searchText;
1165            }
1166
1167            for (var key in content.data) {
1168              if (content.data.hasOwnProperty(key) &&
1169                  key.indexOf(Constants.HARDWARE.component_key_filter) == 0) {
1170                data = camelcaseToLabel(content.data[key]);
1171                searchText = getSearchText(data);
1172                title = key.split('/').pop();
1173
1174                title = titlelize(title);
1175
1176                if (!isSubComponent(key)) {
1177                  hardwareData.push(Object.assign(
1178                      {
1179                        path: key,
1180                        title: title,
1181                        selected: false,
1182                        expanded: false,
1183                        search_text: title.toLowerCase() + ' ' +
1184                            searchText.toLowerCase(),
1185                        sub_components: [],
1186                        original_data: {key: key, value: content.data[key]}
1187                      },
1188                      {items: data}));
1189
1190                  keyIndexMap[key] = hardwareData.length - 1;
1191                } else {
1192                  var tempParts = key.split('/');
1193                  tempParts.pop();
1194                  tempParts = tempParts.join('/');
1195                  componentIndex = keyIndexMap[tempParts];
1196                  data = content.data[key];
1197                  data.title = title;
1198                  hardwareData[componentIndex].sub_components.push(data);
1199                  hardwareData[componentIndex].search_text +=
1200                      ' ' + title.toLowerCase();
1201
1202                  // Sort the subcomponents alphanumeric so they are displayed
1203                  // on the inventory page in order (e.g. core 0, core 1, core
1204                  // 2, ... core 12, core 13)
1205                  hardwareData[componentIndex].sub_components.sort(function(
1206                      a, b) {
1207                    return a.title.localeCompare(
1208                        b.title, 'en', {numeric: true});
1209                  });
1210                }
1211              }
1212            }
1213
1214            if (callback) {
1215              callback(hardwareData, content.data);
1216            } else {
1217              return {data: hardwareData, original_data: content.data};
1218            }
1219          });
1220        },
1221        deleteLogs: function(logs) {
1222          var defer = $q.defer();
1223          var promises = [];
1224
1225          function finished() {
1226            defer.resolve();
1227          }
1228
1229          logs.forEach(function(item) {
1230            promises.push($http({
1231              method: 'POST',
1232              url: DataService.getHost() +
1233                  '/xyz/openbmc_project/logging/entry/' + item.Id +
1234                  '/action/Delete',
1235              headers: {
1236                'Accept': 'application/json',
1237                'Content-Type': 'application/json'
1238              },
1239              withCredentials: true,
1240              data: JSON.stringify({'data': []})
1241            }));
1242          });
1243
1244          $q.all(promises).then(finished);
1245
1246          return defer.promise;
1247        },
1248        resolveLogs: function(logs) {
1249          var defer = $q.defer();
1250          var promises = [];
1251
1252          function finished() {
1253            defer.resolve();
1254          }
1255
1256          logs.forEach(function(item) {
1257            promises.push($http({
1258              method: 'PUT',
1259              url: DataService.getHost() +
1260                  '/xyz/openbmc_project/logging/entry/' + item.Id +
1261                  '/attr/Resolved',
1262              headers: {
1263                'Accept': 'application/json',
1264                'Content-Type': 'application/json'
1265              },
1266              withCredentials: true,
1267              data: JSON.stringify({'data': '1'})
1268            }));
1269          });
1270
1271          $q.all(promises).then(finished);
1272
1273          return defer.promise;
1274        },
1275        getPowerConsumption: function() {
1276          return $http({
1277                   method: 'GET',
1278                   url: DataService.getHost() +
1279                       '/xyz/openbmc_project/sensors/power/total_power',
1280                   headers: {
1281                     'Accept': 'application/json',
1282                     'Content-Type': 'application/json'
1283                   },
1284                   withCredentials: true
1285                 })
1286              .then(
1287                  function(response) {
1288                    var json = JSON.stringify(response.data);
1289                    var content = JSON.parse(json);
1290
1291                    return getScaledValue(
1292                               content.data.Value, content.data.Scale) +
1293                        ' ' +
1294                        Constants.POWER_CONSUMPTION_TEXT[content.data.Unit];
1295                  },
1296                  function(error) {
1297                    if ('Not Found' == error.statusText) {
1298                      return Constants.POWER_CONSUMPTION_TEXT.notavailable;
1299                    } else {
1300                      throw error;
1301                    }
1302                  });
1303        },
1304        getPowerCap: function() {
1305          return $http({
1306                   method: 'GET',
1307                   url: DataService.getHost() +
1308                       '/xyz/openbmc_project/control/host0/power_cap',
1309                   headers: {
1310                     'Accept': 'application/json',
1311                     'Content-Type': 'application/json'
1312                   },
1313                   withCredentials: true
1314                 })
1315              .then(function(response) {
1316                var json = JSON.stringify(response.data);
1317                var content = JSON.parse(json);
1318
1319                return (false == content.data.PowerCapEnable) ?
1320                    Constants.POWER_CAP_TEXT.disabled :
1321                    content.data.PowerCap + ' ' + Constants.POWER_CAP_TEXT.unit;
1322              });
1323        },
1324        setHostname: function(hostname) {
1325          return $http({
1326                   method: 'PUT',
1327                   url: DataService.getHost() +
1328                       '/xyz/openbmc_project/network/config/attr/HostName',
1329                   headers: {
1330                     'Accept': 'application/json',
1331                     'Content-Type': 'application/json'
1332                   },
1333                   withCredentials: true,
1334                   data: JSON.stringify({'data': hostname})
1335                 })
1336              .then(function(response) {
1337                return response.data;
1338              });
1339        },
1340      };
1341      return SERVICE;
1342    }
1343  ]);
1344
1345})(window.angular);
1346