From 72fa8bf09358a7f5a488898054977b318566fa4b Mon Sep 17 00:00:00 2001 From: Andrei Hancu Date: Tue, 4 Aug 2020 17:57:33 +0300 Subject: [PATCH 1/5] addAccount route + component --- app/components/AddAccount.vue | 225 +++++++++++++++++++++++++++++ app/components/AppSettingsView.vue | 31 +++- app/routes/index.js | 2 + 3 files changed, 255 insertions(+), 3 deletions(-) create mode 100644 app/components/AddAccount.vue diff --git a/app/components/AddAccount.vue b/app/components/AddAccount.vue new file mode 100644 index 000000000..c2c857729 --- /dev/null +++ b/app/components/AddAccount.vue @@ -0,0 +1,225 @@ + + + + + diff --git a/app/components/AppSettingsView.vue b/app/components/AppSettingsView.vue index 4ebd4cf92..b3441f9a3 100644 --- a/app/components/AppSettingsView.vue +++ b/app/components/AppSettingsView.vue @@ -4,8 +4,22 @@ + + + + + + + + + + - + + @@ -26,7 +40,6 @@ import routes from "../routes"; import ScreenHeader from "./ScreenHeader"; import ScreenFooter from "./ScreenFooter"; -import { hexStringToByteWiseString } from "../utilities"; import { Build } from "../config"; export default { @@ -34,8 +47,14 @@ export default { return { loggedIn: this.$portalInterface.isLoggedIn(), versions: Build, + currentUser: this.$portalInterface._currentUser }; }, + computed: { + accounts() { + return this.$store.state.portal.accounts; + }, + }, components: { ScreenHeader, ScreenFooter, @@ -56,6 +75,10 @@ export default { goToLogin() { this.$navigateTo(routes.login); }, + + addAccount() { + this.$navigateTo(routes.addAccount); + } }, }; @@ -64,6 +87,8 @@ export default { // Start custom common variables @import "../app-variables"; // End custom common variables - +.v-middle { + vertical-align: middle; +} // Custom styles diff --git a/app/routes/index.js b/app/routes/index.js index c35b00606..bd04814f6 100644 --- a/app/routes/index.js +++ b/app/routes/index.js @@ -24,6 +24,7 @@ import DeployNotes from "../components/deploy/DeployNotesView"; import DeployReview from "../components/deploy/DeployReviewView"; import { Route, RouteState } from "./navigate"; +import AddAccount from "~/components/AddAccount"; const routes = { appSettings: new Route(AppSettings, {}), @@ -36,6 +37,7 @@ const routes = { deployReview: new Route(DeployReview, {}), developerMenu: new Route(DeveloperMenu, { developer: true }), login: new Route(Login, { login: true }), + addAccount: new Route(AddAccount, {}), module: new Route(Module, {}), assembleStation: new Route(AssembleStation, {}), stations: new Route(StationListView, { listing: true }), From a4b20a289ed3aac20e29257aad7e26f32ebc21df Mon Sep 17 00:00:00 2001 From: Andrei Hancu Date: Tue, 4 Aug 2020 17:58:17 +0300 Subject: [PATCH 2/5] sqlite migration for accounts --- .../20200731_093924_add_accounts_table.js | 15 +++++++++++++++ app/migrations/index.js | 1 + 2 files changed, 16 insertions(+) create mode 100644 app/migrations/20200731_093924_add_accounts_table.js diff --git a/app/migrations/20200731_093924_add_accounts_table.js b/app/migrations/20200731_093924_add_accounts_table.js new file mode 100644 index 000000000..f382715a1 --- /dev/null +++ b/app/migrations/20200731_093924_add_accounts_table.js @@ -0,0 +1,15 @@ +import Migration from "./Migration"; + +export class AddAccounts_20200731_093924 extends Migration { + up(db) { + return db.batch([ + `CREATE TABLE IF NOT EXISTS accounts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT, + email TEXT, + portal_id TEXT, + token TEXT + )`, + ]); + } +} diff --git a/app/migrations/index.js b/app/migrations/index.js index b5c1dc3d1..de60948d6 100644 --- a/app/migrations/index.js +++ b/app/migrations/index.js @@ -8,3 +8,4 @@ export * from "./20200624_193105_add_sensor_trend.js"; export * from "./20200708_162023_add_notes_table.js"; export * from "./20200715_075044_add_module_flags.js"; export * from "./20200723_093924_add_portal_updated_time.js"; +export * from "./20200731_093924_add_accounts_table.js"; From 0a81b64c50324fab8345cf9b9793d50c63a07b88 Mon Sep 17 00:00:00 2001 From: Andrei Hancu Date: Tue, 4 Aug 2020 17:59:30 +0300 Subject: [PATCH 3/5] add account to portal store --- app/store/actions.ts | 3 +++ app/store/modules/portal.ts | 47 ++++++++++++++++++++++++++++++++++++- app/store/mutations.ts | 3 +++ app/store/row-types.ts | 8 +++++++ 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/app/store/actions.ts b/app/store/actions.ts index 1f4f97572..d274e7400 100644 --- a/app/store/actions.ts +++ b/app/store/actions.ts @@ -57,3 +57,6 @@ export const SAVE_NOTES = "SAVE_NOTES"; // Portal export const UPDATE_PORTAL = "UPDATE_PORTAL"; +export const LOAD_ACCOUNTS = "LOAD_ACCOUNTS"; +export const UPDATE_ACCOUNT = "UPDATE_ACCOUNT"; +export const LOGOUT_ACCOUNTS = "LOGOUT_ACCOUNTS"; diff --git a/app/store/modules/portal.ts b/app/store/modules/portal.ts index a3b97aaae..5ab265ff1 100644 --- a/app/store/modules/portal.ts +++ b/app/store/modules/portal.ts @@ -1,12 +1,16 @@ import Vue from "../../wrappers/vue"; import * as ActionTypes from "../actions"; import * as MutationTypes from "../mutations"; +import {ServiceRef, Services} from "./utilities"; +import {AccountsTableRow} from "../row-types"; export class PortalState { authenticated: boolean = false; + services: ServiceRef = new ServiceRef(); + accounts: any; } -type ActionParameters = { commit: any }; +type ActionParameters = { commit: any; dispatch: any; state: any }; const getters = {}; @@ -14,21 +18,62 @@ const actions = { [ActionTypes.INITIALIZE]: ({ commit }: ActionParameters) => { // }, + [ActionTypes.LOAD]: ({ commit, dispatch, state }: ActionParameters) => { + // + dispatch(ActionTypes.LOAD_ACCOUNTS); + }, [ActionTypes.UPDATE_PORTAL]: ({ commit }: ActionParameters) => { // }, + [ActionTypes.LOAD_ACCOUNTS]: ({ commit, dispatch, state }: ActionParameters) => { + return state.services + .db() + .getAllAccounts() + .then((accounts) => { + commit(MutationTypes.LOAD_ACCOUNTS, accounts) + }) + .catch((e) => console.log('ActionTypes.LOAD_ACCOUNTS', e)) + }, + [ActionTypes.UPDATE_ACCOUNT]: ({ commit, dispatch, state }: ActionParameters, account) => { + return state.services + .db() + .addOrUpdateAccounts(account) + .then((all) => { + dispatch(ActionTypes.LOAD_ACCOUNTS); + }) + .catch((e) => console.log('ActionTypes.UPDATE_ACCOUNT', e)) + }, + [ActionTypes.LOGOUT_ACCOUNTS]: ({ commit, dispatch, state }: ActionParameters) => { + return state.services + .db() + .deleteAllAccounts() + .then((all) => { + commit(MutationTypes.LOGOUT_ACCOUNTS); + dispatch(ActionTypes.LOAD_ACCOUNTS); + }) + .catch((e) => console.log('ActionTypes.LOGOUT_ACCOUNTS', e)) + }, }; const mutations = { [MutationTypes.RESET]: (state: PortalState, error: string) => { Object.assign(state, new PortalState()); }, + [MutationTypes.SERVICES]: (state: PortalState, services: () => Services) => { + Vue.set(state, "services", new ServiceRef(services)); + }, [MutationTypes.LOGIN]: (state: PortalState, token: string) => { Vue.set(state, "authenticated", true); }, [MutationTypes.LOGOUT]: (state: PortalState) => { Vue.set(state, "authenticated", false); }, + [MutationTypes.LOGOUT_ACCOUNTS]: (state: PortalState) => { + Vue.set(state, "accounts", []); + }, + [MutationTypes.LOAD_ACCOUNTS]: (state: PortalState, accounts: AccountsTableRow) => { + Vue.set(state, 'accounts', accounts); + }, }; const state = () => new PortalState(); diff --git a/app/store/mutations.ts b/app/store/mutations.ts index 7fa0b54fa..c97867688 100644 --- a/app/store/mutations.ts +++ b/app/store/mutations.ts @@ -23,6 +23,9 @@ export const TRANSFER_CLOSE = "TRANSFER_CLOSE"; export const LOGIN = "LOGIN"; export const LOGOUT = "LOGOUT"; +export const LOAD_ACCOUNTS = "LOAD_ACCOUNTS"; +export const UPDATE_ACCOUNT = "UPDATE_ACCOUNT"; +export const LOGOUT_ACCOUNTS = "LOGOUT_ACCOUNTS"; export const STATION_QUERIED = "STATION_QUERIED"; export const STATION_ACTIVITY = "STATION_ACTIVITY"; diff --git a/app/store/row-types.ts b/app/store/row-types.ts index b4ad93d42..35ffa3ccd 100644 --- a/app/store/row-types.ts +++ b/app/store/row-types.ts @@ -75,3 +75,11 @@ export interface NotesTableRow { notes: string; notesObject: object | null; } + +export interface AccountsTableRow { + id: number; + name: string; + email: string; + portalId: string; + token: string; +} From eba51e25b5d6282cd36d00e2ea27b14287a0f9b1 Mon Sep 17 00:00:00 2001 From: Andrei Hancu Date: Tue, 4 Aug 2020 17:59:49 +0300 Subject: [PATCH 4/5] add accounts translation --- app/i18n/en.js | 5 ++++- app/i18n/es.js | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/i18n/en.js b/app/i18n/en.js index 0e0f7dbd3..39db82eae 100644 --- a/app/i18n/en.js +++ b/app/i18n/en.js @@ -407,5 +407,8 @@ module.exports = { daysHrsMin: "days hrs min", hrsMinSec: "hrs min sec", downloadFirmware: "Download Firmware", - upgradeFirmware: "Upgrade Firmware" + upgradeFirmware: "Upgrade Firmware", + addAccount: "Add Account", + logOutAll: "Log Out All Accounts", + accounts: "Accounts" }; diff --git a/app/i18n/es.js b/app/i18n/es.js index 71a1ef516..d9b95c911 100644 --- a/app/i18n/es.js +++ b/app/i18n/es.js @@ -407,5 +407,8 @@ module.exports = { daysHrsMin: "días hrs min", hrsMinSec: "hrs min seg", downloadFirmware: "Descargar Firmware", - upgradeFirmware: "Actualización de Firmware" + upgradeFirmware: "Actualización de Firmware", + addAccount: "Add Account", + logOutAll: "Log Out All Accounts", + accounts: "Accounts" }; From 5a9acde20c321a76359b616d2c9c0a6684f7f027 Mon Sep 17 00:00:00 2001 From: Andrei Hancu Date: Tue, 4 Aug 2020 18:43:06 +0300 Subject: [PATCH 5/5] db interface changes --- app/services/db-interface.ts | 32 +++++++++++++++++++++++++++++++- app/services/portal-interface.ts | 12 ++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/app/services/db-interface.ts b/app/services/db-interface.ts index 8c05d0690..56cfb879c 100644 --- a/app/services/db-interface.ts +++ b/app/services/db-interface.ts @@ -2,7 +2,7 @@ import _ from "lodash"; import Config from "../config"; import { sqliteToJs } from "../utilities"; import { Download, FileTypeUtils } from "../store/types"; -import { DownloadTableRow, NotesTableRow } from "../store/row-types"; +import {AccountsTableRow, DownloadTableRow, NotesTableRow} from "../store/row-types"; const log = Config.logger("DbInterface"); @@ -869,4 +869,34 @@ export default class DatabaseInterface { ) .catch((err) => Promise.reject(new Error(`error fetching notes: ${err}`))); } + + public getAllAccounts(): Promise { + return this.getDatabase() + .then((db) => db.query("SELECT * FROM accounts")) + .then((rows) => sqliteToJs(rows)) + .then((rows) => { + return rows; + }) + .catch((err) => Promise.reject(new Error(`error fetching accounts: ${err}`))); + } + + public addOrUpdateAccounts(account: any): Promise { + return this.getDatabase() + .then((db) => + db.query(`SELECT id FROM accounts WHERE portal_id = ?`, [account.portalId]).then((maybeId) => { + console.log('maybeId', maybeId); + if (maybeId.length == 0) { + return db.execute(`INSERT INTO accounts (name, email, portal_id, token) VALUES (?, ?, ?, ?)`, [account.name, account.email, account.portalId, account.token]); + } + const values = [account.name, account.email, account.portalId, account.token, maybeId[0].id]; + return db.execute(`UPDATE accounts SET name = ?, email = ?, portal_id = ?, token = ? WHERE id = ?`, values); + }) + ) + .catch((err) => Promise.reject(new Error(`error fetching accounts: ${err}`))); + } + + public deleteAllAccounts(): Promise { + return this.getDatabase() + .then((db) => db.query("DELETE FROM accounts")) + } } diff --git a/app/services/portal-interface.ts b/app/services/portal-interface.ts index 023d60da1..0139af618 100644 --- a/app/services/portal-interface.ts +++ b/app/services/portal-interface.ts @@ -4,6 +4,7 @@ import AppSettings from "../wrappers/app-settings"; import { Download, FileTypeUtils } from "../store/types"; import { AuthenticationError } from "../lib/errors"; import Config from "../config"; +import * as ActionTypes from "../store/actions"; type ProgressFunc = (total: number, copied: number, info: object) => void; @@ -18,6 +19,7 @@ export default class PortalInterface { _dbInterface: any; _fs: any; _conservify: any; + _store: any; _currentUser: any; _appSettings: any; @@ -26,6 +28,7 @@ export default class PortalInterface { this._dbInterface = services.Database(); this._fs = services.FileSystem(); this._conservify = services.Conservify(); + this._store = services.Store(); this._currentUser = {}; this._appSettings = new AppSettings(); } @@ -40,7 +43,7 @@ export default class PortalInterface { }); } - private storeCurrentUser(refreshed) { + private storeCurrentUser(refreshed, accessToken) { return this.query({ refreshed: refreshed || false, authenticated: true, @@ -49,6 +52,10 @@ export default class PortalInterface { }).then((data) => { this._currentUser.name = data.name; this._currentUser.portalId = data.id; + this._currentUser.email = data.email; + this._currentUser.token = accessToken; + this._store.dispatch(ActionTypes.UPDATE_ACCOUNT, {...this._currentUser}); + return data; }); } @@ -88,6 +95,7 @@ export default class PortalInterface { public logout() { this._appSettings.remove("accessToken"); + this._store.dispatch(ActionTypes.LOGOUT_ACCOUNTS); return Promise.resolve(true); } @@ -241,7 +249,7 @@ export default class PortalInterface { // Headers should always be lower case, bug otherwise. const accessToken = response.headers.authorization; this._appSettings.setString("accessToken", accessToken); - return this.storeCurrentUser(true).then(() => { + return this.storeCurrentUser(true, accessToken).then(() => { return { token: accessToken, };