diff options
32 files changed, 830 insertions, 495 deletions
diff --git a/src/org/traccar/Context.java b/src/org/traccar/Context.java index ca45a34d6..dcab28a9c 100644 --- a/src/org/traccar/Context.java +++ b/src/org/traccar/Context.java @@ -15,8 +15,11 @@ */ package org.traccar; +import java.io.FileInputStream; +import java.util.Properties; import org.traccar.database.DataCache; import org.traccar.database.DataManager; +import org.traccar.database.PermissionsManager; import org.traccar.geocode.GisgraphyReverseGeocoder; import org.traccar.geocode.GoogleReverseGeocoder; import org.traccar.geocode.NominatimReverseGeocoder; @@ -24,10 +27,6 @@ import org.traccar.geocode.ReverseGeocoder; import org.traccar.helper.Log; import org.traccar.http.WebServer; -import java.io.FileInputStream; -import java.util.Properties; -import org.traccar.database.PermissionsManager; - public class Context { private static Properties properties; @@ -92,7 +91,9 @@ public class Context { dataManager = new DataManager(properties); dataCache = new DataCache(dataManager); - permissionsManager = new PermissionsManager(); + if (Boolean.valueOf(properties.getProperty("http.new"))) { + permissionsManager = new PermissionsManager(); + } if (Boolean.parseBoolean(properties.getProperty("geocoder.enable"))) { String type = properties.getProperty("geocoder.type"); diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java index 3a34be2d7..5e921c0ea 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -22,7 +22,6 @@ import java.net.URLClassLoader; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; @@ -307,28 +306,27 @@ public class DataManager { admin.setName("admin"); admin.setEmail("admin"); admin.setPassword("admin"); + admin.setAdmin(true); addUser(admin); + + Device device = new Device(); + device.setName("test1"); + device.setUniqueId("123456789012345"); + addDevice(device); + linkDevice(admin.getId(), device.getId()); } - public long login(String email, String password) throws SQLException { - - Connection connection = dataSource.getConnection(); - try { - PreparedStatement statement = connection.prepareStatement( - "SELECT id FROM user WHERE email = ? AND " + - "password = CAST(HASH('SHA256', STRINGTOUTF8(?), 1000) AS VARCHAR);"); - try { - statement.setString(1, email); - statement.setString(2, password); - - ResultSet result = statement.executeQuery(); - result.next(); - return result.getLong("id"); - } finally { - statement.close(); - } - } finally { - connection.close(); + public User login(String email, String password) throws SQLException { + Collection<User> result = QueryBuilder.create(dataSource, + "SELECT * FROM user WHERE email = :email AND " + + "password = CAST(HASH('SHA256', STRINGTOUTF8(:password), 1000) AS VARCHAR);") + .setString("email", email) + .setString("password", password) + .executeQuery(new User()); + if (!result.isEmpty()) { + return result.iterator().next(); + } else { + return null; } } diff --git a/src/org/traccar/http/AsyncServlet.java b/src/org/traccar/http/AsyncServlet.java index f00257f80..2bc6ff7a1 100644 --- a/src/org/traccar/http/AsyncServlet.java +++ b/src/org/traccar/http/AsyncServlet.java @@ -182,7 +182,7 @@ public class AsyncServlet extends HttpServlet { context.setTimeout(ASYNC_TIMEOUT); HttpServletRequest req = (HttpServletRequest) context.getRequest(); - long userId = (Long) req.getSession().getAttribute(MainServlet.USER_ID); + long userId = (Long) req.getSession().getAttribute(MainServlet.USER_KEY); synchronized (asyncSessions) { diff --git a/src/org/traccar/http/BaseServlet.java b/src/org/traccar/http/BaseServlet.java index 9249b33d8..122dbe70b 100644 --- a/src/org/traccar/http/BaseServlet.java +++ b/src/org/traccar/http/BaseServlet.java @@ -26,10 +26,11 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.traccar.model.User; public abstract class BaseServlet extends HttpServlet { - public static final String USER_ID = "userId"; + public static final String USER_KEY = "user"; @Override protected final void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { @@ -46,16 +47,16 @@ public abstract class BaseServlet extends HttpServlet { protected abstract boolean handle(String command, HttpServletRequest req, HttpServletResponse resp) throws Exception; public long getUserId(HttpSession session) { - Long userId = (Long) session.getAttribute(USER_ID); - if (userId == null) { + User user = (User) session.getAttribute(USER_KEY); + if (user == null) { throw new AccessControlException("User is not logged in"); } - return userId; + return user.getId(); } - public void sendResponse(Writer writer) throws IOException { + public void sendResponse(Writer writer, boolean success) throws IOException { JsonObjectBuilder result = Json.createObjectBuilder(); - result.add("success", true); + result.add("success", success); writer.write(result.build().toString()); } diff --git a/src/org/traccar/http/DeviceServlet.java b/src/org/traccar/http/DeviceServlet.java index a06ea5368..1387c2a13 100644 --- a/src/org/traccar/http/DeviceServlet.java +++ b/src/org/traccar/http/DeviceServlet.java @@ -47,19 +47,19 @@ public class DeviceServlet extends BaseServlet { Device device = JsonConverter.objectFromJson(req.getReader(), new Device()); Context.getDataManager().addDevice(device); Context.getDataManager().linkDevice(getUserId(req.getSession()), device.getId()); - sendResponse(resp.getWriter()); + sendResponse(resp.getWriter(), JsonConverter.objectToJson(device)); } private void update(HttpServletRequest req, HttpServletResponse resp) throws Exception { Context.getDataManager().updateDevice(JsonConverter.objectFromJson( req.getReader(), new Device())); - sendResponse(resp.getWriter()); + sendResponse(resp.getWriter(), true); } private void remove(HttpServletRequest req, HttpServletResponse resp) throws Exception { Context.getDataManager().removeDevice(JsonConverter.objectFromJson( req.getReader(), new Device())); - sendResponse(resp.getWriter()); + sendResponse(resp.getWriter(), true); } } diff --git a/src/org/traccar/http/JsonConverter.java b/src/org/traccar/http/JsonConverter.java index 0802fb9ea..f7c5a5622 100644 --- a/src/org/traccar/http/JsonConverter.java +++ b/src/org/traccar/http/JsonConverter.java @@ -29,6 +29,7 @@ import javax.json.JsonArray; import javax.json.JsonArrayBuilder; import javax.json.JsonObject; import javax.json.JsonObjectBuilder; +import javax.json.JsonValue; import org.traccar.model.Factory; public class JsonConverter { @@ -57,7 +58,9 @@ public class JsonConverter { } else if (parameterType.equals(int.class)) { method.invoke(object, json.getJsonNumber(name).intValue()); } else if (parameterType.equals(long.class)) { - method.invoke(object, json.getJsonNumber(name).longValue()); + if (json.get(name).getValueType() == JsonValue.ValueType.NUMBER) { + method.invoke(object, json.getJsonNumber(name).longValue()); + } } else if (parameterType.equals(double.class)) { method.invoke(object, json.getJsonNumber(name).doubleValue()); } else if (parameterType.equals(String.class)) { diff --git a/src/org/traccar/http/MainServlet.java b/src/org/traccar/http/MainServlet.java index 036c472f8..18430f0c3 100644 --- a/src/org/traccar/http/MainServlet.java +++ b/src/org/traccar/http/MainServlet.java @@ -41,24 +41,34 @@ public class MainServlet extends BaseServlet { } private void session(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - resp.getWriter().println("{ success: true, session: " + (req.getSession().getAttribute(USER_ID) != null) + " }"); + User user = (User) req.getSession().getAttribute(USER_KEY); + if (user != null) { + sendResponse(resp.getWriter(), JsonConverter.objectToJson(user)); + } else { + sendResponse(resp.getWriter(), false); + } } private void login(HttpServletRequest req, HttpServletResponse resp) throws Exception { - req.getSession().setAttribute(USER_ID, Context.getDataManager().login( - req.getParameter("email"), req.getParameter("password"))); - sendResponse(resp.getWriter()); + User user = Context.getDataManager().login( + req.getParameter("email"), req.getParameter("password")); + if (user != null) { + req.getSession().setAttribute(USER_KEY, user); + sendResponse(resp.getWriter(), JsonConverter.objectToJson(user)); + } else { + sendResponse(resp.getWriter(), false); + } } private void logout(HttpServletRequest req, HttpServletResponse resp) throws Exception { - req.getSession().removeAttribute(USER_ID); - sendResponse(resp.getWriter()); + req.getSession().removeAttribute(USER_KEY); + sendResponse(resp.getWriter(), true); } private void register(HttpServletRequest req, HttpServletResponse resp) throws Exception { User user = JsonConverter.objectFromJson(req.getReader(), new User()); Context.getDataManager().addUser(user); - sendResponse(resp.getWriter()); + sendResponse(resp.getWriter(), true); } } diff --git a/web/Application.js b/web/Application.js deleted file mode 100644 index 85826e6a5..000000000 --- a/web/Application.js +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -Ext.Loader.setConfig({ - disableCaching: false -}); - -Ext.Loader.loadScript({ - - url: function() { - var urlParams = document.URL.split("?"); - var params = Ext.urlDecode(urlParams[urlParams.length - 1]); - - if (!params.lang) { - return "Strings.js"; - } else { - return "Strings-" + params.lang + ".js"; - } - }(), - - onLoad: function() { - - Ext.application({ - name: 'Traccar', - requires: [ - 'Styles', - 'Login', - 'MainView' - ], - - launch: function() { - Ext.Ajax.request({ - url: '/api/session', - success: function(response) { - var result = Ext.decode(response.responseText); - if (result.success && result.session) { - Ext.create('MainView', { renderTo: document.body }); - } else { - Ext.create('Login').show(); - } - }, - failure: function() { - alert(error); - } - }) - } - }); - } -}); diff --git a/web/DeviceDialog.js b/web/DeviceDialog.js deleted file mode 100644 index e0016d790..000000000 --- a/web/DeviceDialog.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -Ext.define('DeviceForm', { - extend: 'Ext.form.Panel', - xtype: 'device-form', - - defaultType: 'textfield', - bodyPadding: Styles.panel_padding, - - defaults: { anchor: '100%' }, - - url: '/api/device/add', - jsonSubmit: true, - - items: [{ - allowBlank: false, - fieldLabel: Strings.device_name, - name: 'name' - }, { - allowBlank: false, - fieldLabel: Strings.device_identifier, - name: 'uniqueId' - }], - - buttons: [{ - text: Strings.dialog_create, - handler: function() { - var win = this.up('window'); - var form = this.up('form').getForm(); - if (form.isValid()) { - form.submit({ - success: function() { - win.close(); - win.onUpdate(); - }, - failure: function() { - win.close(); - } - }); - } - } - }, { - text: Strings.dialog_cancel, - handler: function() { - this.up('window').close(); - } - }] -}); - -Ext.define('DeviceDialog', { - extend: 'Ext.window.Window', - - modal: true, - - title: Strings.device_dialog, - - items: [{ xtype: 'device-form' }] -}); diff --git a/web/DeviceView.js b/web/DeviceView.js deleted file mode 100644 index 80e75cb2c..000000000 --- a/web/DeviceView.js +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -Ext.define('DeviceView', { - extend: 'Ext.grid.Panel', - requires: [ 'DeviceDialog' ], - xtype: 'device-view', - - title: Strings.device_title, - - tbar: [{ - text:'Add', - handler: function() { - var panel = this.up('panel'); - Ext.create('DeviceDialog', { - onUpdate: function() { - panel.store.reload(); - } - }).show(); - } - }, { - text:'Edit' - }, { - text:'Remove', - handler: function() { - Ext.Msg.show({ - title: Strings.device_dialog, - message: 'Remove device?', - buttons: Ext.Msg.YESNO, - buttonText: { - yes: Strings.dialog_delete, - no: Strings.dialog_cancel - }, - fn: function(btn) { - if (btn === 'yes') { - console.log('Yes pressed'); - } else if (btn === 'no') { - console.log('No pressed'); - } - } - }); - } - }, { - xtype: 'tbfill' - }, { - text:'Settings' - }, { - text:'Logout', - handler: function() { - Ext.Ajax.request({ - url: '/api/logout', - success: function() { - window.location.reload(); - } - }); - } - }], - - store: { - proxy: { - type: 'ajax', - url: '/api/device/get', - reader: { - type: 'json', - rootProperty: 'data' - } - }, - autoLoad: true, - - fields:[ - 'id', - 'name', - 'uniqueId', - 'positionId', - 'dataId' - ] - }, - - columns: [ - { text: Strings.device_name, dataIndex: 'name', flex: 1 }, - { text: Strings.device_identifier, dataIndex: 'uniqueId', flex: 1 } - ] -}); diff --git a/web/Login.js b/web/Login.js deleted file mode 100644 index cdc312bf8..000000000 --- a/web/Login.js +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -Ext.define('LoginForm', { - extend: 'Ext.form.Panel', - xtype: 'login-form', - - defaultType: 'textfield', - bodyPadding: Styles.panel_padding, - - defaults: { anchor: '100%' }, - - url: '/api/login', - - items: [{ - allowBlank: false, - fieldLabel: Strings.login_email, - name: 'email' - }, { - allowBlank: false, - fieldLabel: Strings.login_password, - name: 'password', - inputType: 'password' - }], - - buttons: [{ - text: Strings.login_register, - handler: function() { - Ext.create('RegisterDialog').show(); - } - }, { - text: Strings.login_login, - handler: function() { - this.up('window').submit(); - } - }], - - listeners: { - afterRender: function(){ - this.keyNav = Ext.create('Ext.util.KeyNav', this.el, { - enter: function() { - this.up('window').submit(); - }, - scope: this - }); - } - } -}); - -Ext.define('Login', { - extend: 'Ext.window.Window', - requires: [ - 'MainView', - 'RegisterDialog' - ], - - title: Strings.login_title, - closable: false, - resizable: false, - - items: [{ xtype: 'login-form' }], - - submit: function() { - var win = this; - var form = this.down('form').getForm(); - if (form.isValid()) { - form.submit({ - success: function() { - win.close(); - Ext.create('MainView', { renderTo: document.body }); - }, - failure: function() { - Ext.Msg.alert(Strings.login_title, Strings.login_failed); - } - }); - } - } -}); diff --git a/web/RegisterDialog.js b/web/RegisterDialog.js deleted file mode 100644 index c69026ea6..000000000 --- a/web/RegisterDialog.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -Ext.define('RegisterForm', { - extend: 'Ext.form.Panel', - xtype: 'register-form', - - defaultType: 'textfield', - bodyPadding: Styles.panel_padding, - - defaults: { anchor: '100%' }, - - url: '/api/register', - jsonSubmit: true, - - items: [{ - allowBlank: false, - fieldLabel: Strings.login_name, - name: 'name' - }, { - allowBlank: false, - fieldLabel: Strings.login_email, - name: 'email', - vtype: 'email' - }, { - allowBlank: false, - fieldLabel: Strings.login_password, - name: 'password', - inputType: 'password' - }], - - buttons: [{ - text: Strings.dialog_create, - handler: function() { - var win = this.up('window'); - var form = this.up('form').getForm(); - if (form.isValid()) { - form.submit({ - success: function() { - win.close(); - }, - failure: function() { - // error - } - }); - } - } - - }, { - text: Strings.dialog_cancel, - handler: function() { - this.up('window').close(); - } - }] -}); - -Ext.define('RegisterDialog', { - extend: 'Ext.window.Window', - - title: Strings.login_register, - resizable: false, - - items: [{ xtype: 'register-form' }] -}); diff --git a/web/Styles.js b/web/app.js index bbfd099c6..9599373a6 100644 --- a/web/Styles.js +++ b/web/app.js @@ -14,16 +14,11 @@ * limitations under the License. */ -Ext.define('Styles', { - singleton: true, - - panel_padding: 10, - - device_width: 350, - - report_height: 250, +Ext.Loader.setConfig({ + disableCaching: false +}); - map_center: [ -0.1275, 51.507222 ], - map_zoom: 6, - map_max_zoom: 16 +Ext.application({ + name: 'Traccar', + extend: 'Traccar.Application' }); diff --git a/web/Strings-ru.js b/web/app/Application.js index 73b3a329f..dfb972c06 100644 --- a/web/Strings-ru.js +++ b/web/app/Application.js @@ -1,4 +1,4 @@ -/* +/* * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,19 +14,25 @@ * limitations under the License. */ -Ext.define('Strings', { - singleton: true, +Ext.define('Traccar.Application', { + extend: 'Ext.app.Application', + name: 'Traccar', - login_title: 'Логин', - login_user: 'Пользователь', - login_password: 'Пароль', - login_register: 'Регистрация', - login_login: 'Вход', - login_failed: 'Неправильный логин или пароль.', + requires: [ + 'Traccar.Resources', + 'Traccar.ErrorManager' + ], + + models: [ + 'User', + 'Device' + ], + + stores: [ + 'Devices' + ], - device_title: 'Устройства', - device_name: 'Название', - device_identifier: 'Идентификатор', - - map_title: 'Карта' + controllers: [ + 'Root' + ] }); diff --git a/web/app/ErrorManager.js b/web/app/ErrorManager.js new file mode 100644 index 000000000..341432e7b --- /dev/null +++ b/web/app/ErrorManager.js @@ -0,0 +1,39 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Ext.define('Traccar.ErrorManager', { + singleton: true, + + check: function(success, response) { + if (success) { + var result = Ext.decode(response.responseText); + if (result.success || result.error === undefined) { + return true; + } else { + Ext.Msg.alert(strings.error_title, result.error); + return false; + } + } else { + Ext.Msg.alert(strings.error_title, response.statusText); + return false; + } + }, + + error: function(message) { + Ext.Msg.alert(strings.error_title, message); + } + +}); diff --git a/web/app/LoginManager.js b/web/app/LoginManager.js new file mode 100644 index 000000000..89df7684f --- /dev/null +++ b/web/app/LoginManager.js @@ -0,0 +1,73 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Ext.define('Traccar.LoginManager', { + singleton: true, + + session: function(options) { + Ext.Ajax.request({ + scope: this, + url: '/api/session', + callback: this.onSessionReturn, + original: options + }); + }, + + onSessionReturn: function(options, success, response) { + options = options.original; + if (Traccar.ErrorManager.check(success, response)) { + var result = Ext.decode(response.responseText); + if (result.success) { + this.user = result.data; + } + Ext.callback(options.callback, options.scope, [result.success]); + } + }, + + login: function(options) { + Ext.Ajax.request({ + scope: this, + url: '/api/login', + params: options.data, + callback: this.onLoginReturn, + original: options + }); + }, + + onLoginReturn: function(options, success, response) { + options = options.original; + if (Traccar.ErrorManager.check(success, response)) { + var result = Ext.decode(response.responseText); + if (result.success) { + this.user = result.data; + } + Ext.callback(options.callback, options.scope, [result.success]); + } + }, + + logout: function() { + Ext.Ajax.request({ + scope: this, + url: '/api/logout', + callback: this.onLogoutReturn + }); + }, + + onLogoutReturn: function() { + window.location.reload(); + } + +}); diff --git a/web/Strings.js b/web/app/Resources.js index 33ec25c49..400174c0e 100644 --- a/web/Strings.js +++ b/web/app/Resources.js @@ -14,28 +14,47 @@ * limitations under the License. */ -Ext.define('Strings', { - singleton: true, - +var strings = { + shared_loading: 'Loading...', + + error_title: 'Error', + error_unknown: 'Unknown error', + login_title: 'Login', login_name: 'Name', login_email: 'Email', login_password: 'Password', login_register: 'Register', login_login: 'Login', - login_failed: 'Incorrect email address or password.', + login_failed: 'Incorrect email address or password', + login_created: 'New user has been registered', device_dialog: 'Device', device_title: 'Devices', device_name: 'Name', device_identifier: 'Identifier', + device_remove: 'Remove device?', report_title: 'Reports', - - dialog_create: 'Create', - dialog_update: 'Update', + + dialog_save: 'Save', dialog_delete: 'Delete', dialog_cancel: 'Cancel', map_title: 'Map' +}; + +var styles = { + panel_padding: 10, + + device_width: 350, + + report_height: 250, + + map_center: [ -0.1275, 51.507222 ], + map_zoom: 6, + map_max_zoom: 16 +}; + +Ext.define('Traccar.Resources', { }); diff --git a/web/app/controller/Root.js b/web/app/controller/Root.js new file mode 100644 index 000000000..f999cf462 --- /dev/null +++ b/web/app/controller/Root.js @@ -0,0 +1,57 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Ext.define('Traccar.controller.Root', { + extend: 'Ext.app.Controller', + + requires: [ + 'Traccar.LoginManager', + 'Traccar.view.login.Login', + 'Traccar.view.main.Main' + ], + + onLaunch: function () { + Traccar.LoginManager.session({ + scope: this, + callback: 'onSession' + }); + }, + + onSession: function(success) { + if (success) { + this.loadApp(); + } else { + this.login = Ext.create('Traccar.view.login.Login', { + listeners: { + scope: this, + login: 'onLogin' + } + }); + this.login.show(); + } + }, + + onLogin: function() { + this.login.close(); + this.loadApp(); + }, + + loadApp: function() { + Ext.getStore('Devices').load(); + Ext.create('Traccar.view.main.Main'); + } + +}); diff --git a/web/app/model/Device.js b/web/app/model/Device.js new file mode 100644 index 000000000..77dfa0f05 --- /dev/null +++ b/web/app/model/Device.js @@ -0,0 +1,26 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Ext.define('Traccar.model.Device', { + extend: 'Ext.data.Model', + identifier: 'negative', + + fields: [ + { name: 'id', type: 'int' }, + { name: 'name', type: 'string' }, + { name: 'uniqueId', type: 'string' } + ] +}); diff --git a/web/app/model/User.js b/web/app/model/User.js new file mode 100644 index 000000000..68f7cafb4 --- /dev/null +++ b/web/app/model/User.js @@ -0,0 +1,28 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Ext.define('Traccar.model.User', { + extend: 'Ext.data.Model', + identifier: 'negative', + + fields: [ + { name: 'id', type: 'int' }, + { name: 'name', type: 'string' }, + { name: 'unqiueId', type: 'string' }, + { name: 'password', type: 'string' }, + { name: 'admin', type: 'boolean' } + ] +}); diff --git a/web/app/store/Devices.js b/web/app/store/Devices.js new file mode 100644 index 000000000..2b1af192f --- /dev/null +++ b/web/app/store/Devices.js @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Ext.define('Traccar.store.Devices', { + extend: 'Ext.data.Store', + model: 'Traccar.model.Device', + + proxy: { + type: 'ajax', + api: { + create : '/api/device/add', + read : '/api/device/get', + update : '/api/device/update', + destroy : '/api/device/remove' + }, + reader: { + type: 'json', + rootProperty: 'data' + }, + writer: { + type: 'json', + writeAllFields: true + } + } +}); diff --git a/web/app/view/device/Device.js b/web/app/view/device/Device.js new file mode 100644 index 000000000..4dfa13c44 --- /dev/null +++ b/web/app/view/device/Device.js @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Ext.define('Traccar.view.device.Device', { + extend: 'Ext.grid.Panel', + xtype: 'device-view', + + requires: [ + 'Traccar.view.device.DeviceController' + ], + + controller: 'device', + + title: strings.device_title, + selType: 'rowmodel', + + tbar: [{ + text:'Add', + handler: 'onAddClick', + reference: 'deviceAddButton' + }, { + text:'Edit', + disabled: true, + handler: 'onEditClick', + reference: 'deviceEditButton' + }, { + text:'Remove', + disabled: true, + handler: 'onRemoveClick', + reference: 'deviceRemoveButton' + }, { + xtype: 'tbfill' + }, { + text:'Settings' + }, { + text:'Logout', + handler: 'onLogoutClick' + }], + + store: 'Devices', + + listeners: { + selectionchange: 'onSelectionChange' + }, + + columns: [ + { text: strings.device_name, dataIndex: 'name', flex: 1 }, + { text: strings.device_identifier, dataIndex: 'uniqueId', flex: 1 } + ] + +}); diff --git a/web/app/view/device/DeviceController.js b/web/app/view/device/DeviceController.js new file mode 100644 index 000000000..460ba3f9a --- /dev/null +++ b/web/app/view/device/DeviceController.js @@ -0,0 +1,90 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Ext.define('Traccar.view.device.DeviceController', { + extend: 'Ext.app.ViewController', + alias: 'controller.device', + + requires: [ + 'Traccar.view.device.DeviceDialog' + ], + + onLogoutClick: function() { + Traccar.LoginManager.logout(); + }, + + onAddClick: function() { + var device = Ext.create('Traccar.model.Device'); + var dialog = Ext.create('Traccar.view.device.DeviceDialog'); + dialog.down('form').loadRecord(device); + dialog.show(); + }, + + onEditClick: function() { + var device = this.getView().getSelectionModel().getSelection()[0]; + var dialog = Ext.create('Traccar.view.device.DeviceDialog'); + dialog.down('form').loadRecord(device); + dialog.show(); + }, + + onRemoveClick: function() { + var device = this.getView().getSelectionModel().getSelection()[0]; + Ext.Msg.show({ + title: strings.device_dialog, + message: strings.device_remove, + buttons: Ext.Msg.YESNO, + buttonText: { + yes: strings.dialog_delete, + no: strings.dialog_cancel + }, + fn: function(btn) { + if (btn === 'yes') { + var store = Ext.getStore('Devices'); + store.remove(device); + store.sync(); + } + } + }); + }, + + onSelectionChange: function(selected) { + var disabled = selected.length > 0; + this.lookupReference('deviceEditButton').setDisabled(disabled); + this.lookupReference('deviceRemoveButton').setDisabled(disabled); + }, + + onSaveClick: function(button) { + var dialog = button.up('window').down('form'); + dialog.updateRecord(); + var store = Ext.getStore('Devices'); + var device = dialog.getRecord(); + if (device.phantom) { + store.add(device); + } + store.sync({ + failure: function(batch) { + store.rejectChanges(); // TODO + Traccar.ErrorManager.check(true, batch.exceptions[0].getResponse()); + } + }); + button.up('window').close(); + }, + + onCancelClick: function(button) { + button.up('window').close(); + } + +}); diff --git a/web/app/view/device/DeviceDialog.js b/web/app/view/device/DeviceDialog.js new file mode 100644 index 000000000..5e41d1ff4 --- /dev/null +++ b/web/app/view/device/DeviceDialog.js @@ -0,0 +1,51 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Ext.define('Traccar.view.device.DeviceDialog', { + extend: 'Ext.window.Window', + xtype: 'device-dialog', + + controller: 'device', + + bodyPadding: styles.panel_padding, + title: strings.device_dialog, + resizable: false, + modal: true, + + items: { + xtype: 'form', + items: [{ + xtype: 'textfield', + name: 'name', + fieldLabel: strings.device_name, + allowBlank: false + }, { + xtype: 'textfield', + name: 'uniqueId', + fieldLabel: strings.device_identifier, + allowBlank: false + }] + }, + + buttons: [{ + text: strings.dialog_save, + handler: 'onSaveClick' + }, { + text: strings.dialog_cancel, + handler: 'onCancelClick' + }] + +}); diff --git a/web/app/view/login/Login.js b/web/app/view/login/Login.js new file mode 100644 index 000000000..3e23c4838 --- /dev/null +++ b/web/app/view/login/Login.js @@ -0,0 +1,66 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Ext.define('Traccar.view.login.Login', { + extend: 'Ext.window.Window', + + requires: [ + 'Traccar.view.login.LoginController' + ], + + controller: 'login', + + bodyPadding: styles.panel_padding, + title: strings.login_title, + closable: false, + resizable: false, + modal: true, + + items: { + xtype: 'form', + reference: 'form', + + items: [{ + xtype: 'textfield', + name: 'email', + fieldLabel: strings.login_email, + allowBlank: false, + enableKeyEvents: true, + listeners: { + specialKey: 'onSpecialKey' + } + }, { + xtype: 'textfield', + name: 'password', + fieldLabel: strings.login_password, + inputType: 'password', + allowBlank: false, + enableKeyEvents: true, + listeners: { + specialKey: 'onSpecialKey' + } + }] + }, + + buttons: [{ + text: strings.login_register, + handler: 'onRegisterClick' + }, { + text: strings.login_login, + handler: 'onLoginClick' + }] + +}); diff --git a/web/app/view/login/LoginController.js b/web/app/view/login/LoginController.js new file mode 100644 index 000000000..a88fffc09 --- /dev/null +++ b/web/app/view/login/LoginController.js @@ -0,0 +1,61 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Ext.define('Traccar.view.login.LoginController', { + extend: 'Ext.app.ViewController', + alias: 'controller.login', + + requires: [ + 'Traccar.view.login.Register' + ], + + onSpecialKey: function(field, e) { + if (e.getKey() === e.ENTER) { + this.doLogin(); + } + }, + + onLoginClick: function() { + this.doLogin(); + }, + + doLogin: function() { + var form = this.lookupReference('form'); + if (form.isValid()) { + Ext.getBody().mask(strings.shared_loading); + + Traccar.LoginManager.login({ + data: form.getValues(), + scope: this, + callback: 'onLoginReturn' + }); + } + }, + + onLoginReturn: function(success) { + Ext.getBody().unmask(); + if (success) { + this.fireViewEvent('login'); + } else { + Traccar.ErrorManager.error(strings.login_failed); + } + }, + + onRegisterClick: function() { + Ext.create('Traccar.view.login.Register').show(); + } + +}); diff --git a/web/app/view/login/Register.js b/web/app/view/login/Register.js new file mode 100644 index 000000000..b6b570efe --- /dev/null +++ b/web/app/view/login/Register.js @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Ext.define('Traccar.view.login.Register', { + extend: 'Ext.window.Window', + + requires: [ + 'Traccar.view.login.RegisterController' + ], + + controller: 'register', + + bodyPadding: styles.panel_padding, + title: strings.login_register, + resizable: false, + modal: true, + + items: { + xtype: 'form', + reference: 'form', + jsonSubmit: true, + + items: [{ + xtype: 'textfield', + name: 'name', + fieldLabel: strings.login_name, + allowBlank: false + }, { + xtype: 'textfield', + name: 'email', + fieldLabel: strings.login_email, + vtype: 'email', + allowBlank: false + }, { + xtype: 'textfield', + name: 'password', + fieldLabel: strings.login_password, + inputType: 'password', + allowBlank: false + }] + }, + + buttons: [{ + text: strings.dialog_save, + handler: 'onCreateClick' + }, { + text: strings.dialog_cancel, + handler: 'closeView' + }] + +}); diff --git a/web/app/view/login/RegisterController.js b/web/app/view/login/RegisterController.js new file mode 100644 index 000000000..e690b56e8 --- /dev/null +++ b/web/app/view/login/RegisterController.js @@ -0,0 +1,40 @@ +/* + * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Ext.define('Traccar.view.login.RegisterController', { + extend: 'Ext.app.ViewController', + alias: 'controller.register', + + onCreateClick: function() { + var form = this.lookupReference('form'); + if (form.isValid()) { + Ext.Ajax.request({ + scope: this, + url: '/api/register', + jsonData: form.getValues(), + callback: this.onCreateReturn + }); + } + }, + + onCreateReturn: function(options, success, response) { + if (Traccar.ErrorManager.check(success, response)) { + this.closeView(); + Ext.toast(strings.login_created); + } + } + +}); diff --git a/web/MainView.js b/web/app/view/main/Main.js index f6c9a5842..d6a350785 100644 --- a/web/MainView.js +++ b/web/app/view/main/Main.js @@ -14,13 +14,13 @@ * limitations under the License. */ -Ext.define('MainView', { +Ext.define('Traccar.view.main.Main', { extend: 'Ext.container.Viewport', requires: [ - 'DeviceView', - 'MapView', - 'ReportView' + 'Traccar.view.device.Device', + 'Traccar.view.report.Report', + 'Traccar.view.map.Map' ], layout: 'border', @@ -33,15 +33,16 @@ Ext.define('MainView', { items: [{ region:'west', xtype: 'device-view', - width: Styles.device_width + width: styles.device_width }, { region: 'south', xtype: 'report-view', header: false, - height: Styles.report_height + height: styles.report_height }, { region: 'center', xtype: 'map-view', collapsible: false }] + }); diff --git a/web/MapView.js b/web/app/view/map/Map.js index 5c20dba9d..b63d87c9f 100644 --- a/web/MapView.js +++ b/web/app/view/map/Map.js @@ -14,14 +14,14 @@ * limitations under the License. */ -Ext.define('MapView', { +Ext.define('Traccar.view.map.Map', { extend: 'Ext.form.Panel', xtype: 'map-view', - title: Strings.map_title, + title: strings.map_title, layout: 'fit', - update: function() { + /*update: function() { Ext.Ajax.request({ scope: this, url: '/api/async', @@ -42,33 +42,33 @@ Ext.define('MapView', { // error } }); - }, + },*/ listeners: { afterrender: function() { - var bindKey = 'AseEs0DLJhLlTNoxbNXu7DGsnnH4UoWuGue7-irwKkE3fffaClwc9q_Mr6AyHY8F'; + /*var bindKey = 'AseEs0DLJhLlTNoxbNXu7DGsnnH4UoWuGue7-irwKkE3fffaClwc9q_Mr6AyHY8F'; var layer = new ol.layer.Tile({ source: new ol.source.BingMaps({ key: bindKey, imagerySet: 'Road' })}); - /*var layer = new ol.layer.Tile({ source: new ol.source.BingMaps({ + var layer = new ol.layer.Tile({ source: new ol.source.BingMaps({ key: bindKey, imagerySet: 'Aerial' - })}); + })});*/ var layer = new ol.layer.Tile({ source: new ol.source.OSM({ - })});*/ + })}); this.vectorSource = new ol.source.Vector({}); var vectorLayer = new ol.layer.Vector({ source: this.vectorSource }); var view = new ol.View({ - center: ol.proj.transform(Styles.map_center, 'EPSG:4326', 'EPSG:3857'), - zoom: Styles.map_zoom, - maxZoom: Styles.map_max_zoom + center: ol.proj.transform(styles.map_center, 'EPSG:4326', 'EPSG:3857'), + zoom: styles.map_zoom, + maxZoom: styles.map_max_zoom }); this.map = new ol.Map({ @@ -77,11 +77,12 @@ Ext.define('MapView', { view: view }); - this.update(); + //this.update(); }, resize: function() { this.map.updateSize(); } } + }); diff --git a/web/ReportView.js b/web/app/view/report/Report.js index fbaedf175..29fa6248a 100644 --- a/web/ReportView.js +++ b/web/app/view/report/Report.js @@ -14,11 +14,11 @@ * limitations under the License. */ -Ext.define('ReportView', { +Ext.define('Traccar.view.report.Report', { extend: 'Ext.grid.Panel', xtype: 'report-view', - title: Strings.report_title, + title: strings.report_title, tbar: [{ text:'Do Something' @@ -28,4 +28,5 @@ Ext.define('ReportView', { { text: "Column1", dataIndex: 'c1', flex: 1 }, { text: "Column2", dataIndex: 'c2', flex: 1 } ] + }); diff --git a/web/index.html b/web/index.html index 26ac37ae9..71077abe5 100644 --- a/web/index.html +++ b/web/index.html @@ -4,10 +4,10 @@ <title>Traccar</title> <link rel="stylesheet" type="text/css" href="//cdn.sencha.com/ext/gpl/5.1.0/build/packages/ext-theme-neptune/build/resources/ext-theme-neptune-all.css"> <link rel="stylesheet" type="text/css" href="//openlayers.org/en/v3.4.0/css/ol.css"> -<script type="text/javascript" src="//cdn.sencha.com/ext/gpl/5.1.0/build/ext-all.js"></script> +<script type="text/javascript" src="//cdn.sencha.com/ext/gpl/5.1.0/build/ext-all-debug.js"></script> <script type="text/javascript" src="//cdn.sencha.com/ext/gpl/5.1.0/build/packages/ext-theme-neptune/build/ext-theme-neptune.js"></script> <script type="text/javascript" src="//openlayers.org/en/v3.4.0/build/ol.js"></script> -<script type ="text/javascript" src="Application.js"></script> +<script type ="text/javascript" src="app.js"></script> </head> <body> </body> |