/* * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ Ext.define('Traccar.controller.Root', { extend: 'Ext.app.Controller', alias: 'controller.root', requires: [ 'Traccar.view.dialog.Login', 'Traccar.view.Main', 'Traccar.view.MainMobile', 'Traccar.model.Position' ], init: function () { var i, data, attribute, chartTypesStore, maintenanceTypesStore; chartTypesStore = Ext.getStore('ReportChartTypes'); maintenanceTypesStore = Ext.getStore('MaintenanceTypes'); Ext.state.Manager.setProvider(new Ext.state.CookieProvider()); data = Ext.getStore('PositionAttributes').getData().items; for (i = 0; i < data.length; i++) { attribute = data[i]; Traccar.model.Position.addFields([{ name: 'attribute.' + attribute.get('key'), attributeKey: attribute.get('key'), calculate: this.calculateAttribute, persist: false }]); if (attribute.get('valueType') === 'number') { chartTypesStore.add({ key: 'attribute.' + attribute.get('key'), name: attribute.get('name') }); maintenanceTypesStore.add(attribute); } } }, calculateAttribute: function (data) { var value = data.attributes[this.attributeKey]; if (value !== undefined) { return Traccar.AttributeFormatter.getAttributeConverter(this.attributeKey)(value); } return value; }, onLaunch: function () { Ext.Ajax.request({ scope: this, url: 'api/server', callback: this.onServerReturn }); }, showAnnouncement: function (announcement) { var maxWidth = Ext.getBody().getViewSize().width - 2 * Traccar.Style.normalPadding; if (maxWidth > Traccar.Style.windowWidth) { maxWidth = Traccar.Style.windowWidth; } Ext.Msg.show({ msg: announcement, buttons: Ext.Msg.OK, closable: false, modal: false, maxWidth: maxWidth }).alignTo(Ext.getBody(), 't-t', [0, Traccar.Style.normalPadding]); }, onServerReturn: function (options, success, response) { var announcement, token, parameters = {}; if (success) { Traccar.app.setServer(Ext.decode(response.responseText)); announcement = Traccar.app.getServer().get('announcement'); if (announcement) { this.showAnnouncement(announcement); } token = Ext.Object.fromQueryString(window.location.search).token; if (token) { parameters.token = token; } Ext.Ajax.request({ scope: this, url: 'api/session', method: 'GET', params: parameters, callback: this.onSessionReturn }); } else { Traccar.app.showError(response); } }, onSessionReturn: function (options, success, response) { var passwordReset, dialog; Ext.get('spinner').setVisible(false); if (success) { Traccar.app.setUser(Ext.decode(response.responseText)); this.loadApp(); } else { this.login = Ext.create('widget.login', { listeners: { scope: this, login: this.onLogin } }); this.login.show(); passwordReset = Ext.Object.fromQueryString(window.location.search).passwordReset; if (passwordReset) { dialog = Ext.Msg.prompt(Strings.loginReset, Strings.userPassword, function (btn, text) { dialog.textField.inputEl.dom.type = 'text'; if (btn === 'ok') { Ext.Ajax.request({ scope: this, method: 'POST', url: 'api/password/update', params: { token: passwordReset, password: text }, callback: function (options, success, response) { if (success) { Traccar.app.showToast(Strings.loginUpdateSuccess); this.removeUrlParameter('passwordReset'); } else { Traccar.app.showError(response.responseText); } } }); } }, this); dialog.textField.inputEl.dom.type = 'password'; } } }, onLogin: function () { this.login.close(); this.loadApp(); }, loadApp: function () { var updateView, attributionView, eventId; if (window.webkit && window.webkit.messageHandlers.appInterface) { window.webkit.messageHandlers.appInterface.postMessage('login'); } if (window.appInterface) { window.appInterface.postMessage('login'); } Ext.getStore('Groups').load(); Ext.getStore('Drivers').load(); Ext.getStore('Geofences').load(); Ext.getStore('Calendars').load(); Ext.getStore('Maintenances').load(); Ext.getStore('ComputedAttributes').load(); Ext.getStore('AllCommandTypes').load(); Ext.getStore('Commands').load(); Ext.getStore('AllNotificationTypes').load({ callback: function (records, operation, success) { var store = Ext.getStore('ReportEventTypes'); if (success) { store.add({ type: Traccar.store.ReportEventTypes.allEvents, name: Strings.eventAll }); store.loadData(records, true); } } }); Ext.getStore('AllNotificators').load(); Ext.getStore('Notifications').load(); Ext.getStore('ServerAttributes').loadData(Ext.getStore('CommonDeviceAttributes').getData().items, true); Ext.getStore('ServerAttributes').loadData(Ext.getStore('CommonUserAttributes').getData().items, true); Ext.getStore('UserAttributes').loadData(Ext.getStore('CommonUserAttributes').getData().items, true); Ext.getStore('DeviceAttributes').loadData(Ext.getStore('CommonDeviceAttributes').getData().items, true); Ext.getStore('GroupAttributes').loadData(Ext.getStore('CommonDeviceAttributes').getData().items, true); Ext.getStore('Devices').load({ scope: this, callback: function () { this.asyncUpdate(true); } }); updateView = Ext.get('update'); if (updateView) { updateView.remove(); } attributionView = Ext.get('attribution'); if (attributionView) { attributionView.remove(); } if (Traccar.app.isMobile()) { Ext.create('widget.mainMobile'); } else { Ext.create('widget.main'); } eventId = Ext.Object.fromQueryString(window.location.search).eventId; if (eventId) { this.fireEvent('showsingleevent', eventId); this.removeUrlParameter('eventId'); } }, beep: function () { if (!this.beepSound) { this.beepSound = new Audio('beep.wav'); } this.beepSound.play(); }, soundPressed: function () { var soundButton = Ext.getCmp('soundButton'); return soundButton && soundButton.pressed; }, removeUrlParameter: function (param) { var params = Ext.Object.fromQueryString(window.location.search); delete params[param]; if (Ext.Object.isEmpty(params)) { window.history.pushState(null, null, window.location.pathname); } else { window.history.pushState(null, null, window.location.pathname + '?' + Ext.Object.toQueryString(params)); } }, asyncUpdate: function (first) { var self = this, protocol, pathname, socket; protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; pathname = window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/') + 1); socket = new WebSocket(protocol + '//' + window.location.host + pathname + 'api/socket'); socket.onclose = function () { Ext.Ajax.request({ url: 'api/devices', success: function (response) { self.updateDevices(Ext.decode(response.responseText)); }, failure: function (response) { if (response.status === 401) { window.location.reload(); } } }); Ext.Ajax.request({ url: 'api/positions', headers: { Accept: 'application/json' }, success: function (response) { self.updatePositions(Ext.decode(response.responseText)); } }); setTimeout(function () { self.asyncUpdate(false); }, Traccar.Style.reconnectTimeout); }; socket.onmessage = function (event) { var data = Ext.decode(event.data); if (data.devices) { self.updateDevices(data.devices); } if (data.positions) { self.updatePositions(data.positions, first); first = false; } if (data.events) { self.updateEvents(data.events); } }; }, updateDevices: function (array) { var i, store, entity; store = Ext.getStore('Devices'); for (i = 0; i < array.length; i++) { entity = store.getById(array[i].id); if (entity) { entity.set({ status: array[i].status, lastUpdate: array[i].lastUpdate, geofenceIds: array[i].geofenceIds }, { dirty: false }); } } }, updatePositions: function (array, first) { var i, store, entity, deviceId, device; store = Ext.getStore('LatestPositions'); for (i = 0; i < array.length; i++) { entity = store.findRecord('deviceId', array[i].deviceId, 0, false, false, true); if (entity) { entity.set(array[i]); } else { store.add(Ext.create('Traccar.model.Position', array[i])); } if (Ext.getStore('Events').findRecord('positionId', array[i].id, 0, false, false, true)) { Ext.getStore('EventPositions').add(Ext.create('Traccar.model.Position', array[i])); } } if (first) { deviceId = Ext.Object.fromQueryString(window.location.search).deviceId; if (deviceId) { device = Ext.getStore('VisibleDevices').findRecord('id', deviceId, 0, false, true, true); if (device) { this.fireEvent('selectdevice', device, true); } } if (!device) { this.zoomToAllDevices(); } } }, updateEvents: function (array) { var i, store, device; store = Ext.getStore('Events'); for (i = 0; i < array.length; i++) { store.insert(0, array[i]); device = Ext.getStore('Devices').getById(array[i].deviceId); if (device) { if (this.soundPressed()) { this.beep(); } Traccar.app.showToast(array[i].text, device.get('name')); } else { Traccar.app.showToast(array[i].text); } } }, zoomToAllDevices: function () { var lat, lon, zoom; lat = Traccar.app.getPreference('latitude', 0); lon = Traccar.app.getPreference('longitude', 0); zoom = Traccar.app.getPreference('zoom', 0); if (lat === 0 && lon === 0 && zoom === 0) { this.fireEvent('zoomtoalldevices'); } } });