From af99ce522a08ccec779f4651ca55e8c2f92f8f44 Mon Sep 17 00:00:00 2001 From: Pascal Noisette Date: Sat, 5 Mar 2022 11:44:47 +0100 Subject: [PATCH] Add an option to easily change the backend server, fix #131 --- README.md | 6 +++++ src/background.js | 6 ++++- src/containers/OptionsUI.jsx | 52 ++++++++++++++++++++++++++++++++++++ src/reducers/options_ui.js | 40 +++++++++++++++++++++++++++ src/sagas/options_ui.js | 9 +++++++ src/utils/api.js | 42 ++++++++++++++++++++++++++--- 6 files changed, 151 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3210d9a..0adb84b 100755 --- a/README.md +++ b/README.md @@ -60,3 +60,9 @@ you can import/export with json file. you can cutomize shortcut and other settings fron icon-menu. - whether or not confirm before delete + +### Sync + +To sync your notes in the cloud (and share them across several browsers automatically) you will need to register and login from the menu. + +This setup can be customized from icon-menu: icon-menu where you can specify a custom url. The url must point to a running backend instance. You can learn how to self host one using the [dedicated project](https://github.com/kumabook/stickynotes-backend/). \ No newline at end of file diff --git a/src/background.js b/src/background.js index 1f8e7da..9333c31 100644 --- a/src/background.js +++ b/src/background.js @@ -234,7 +234,7 @@ function handlePopupMessage(msg) { break; } case 'reset-password': - browser.tabs.create({ url: api.resetPasswordUrl }); + browser.tabs.create({ url: api.getResetPasswordUrl() }); break; default: break; @@ -348,6 +348,10 @@ function handleOptionsUIMessage(msg) { }))); break; } + case 'updated-server-url': { + browser.storage.local.get().then(payload => api.setOnPremiseUrl(payload)); + break; + } default: break; } diff --git a/src/containers/OptionsUI.jsx b/src/containers/OptionsUI.jsx index caeb34b..f7e7ba7 100644 --- a/src/containers/OptionsUI.jsx +++ b/src/containers/OptionsUI.jsx @@ -1,4 +1,5 @@ /* global confirm: false */ +/* global chrome */ import React from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; @@ -21,6 +22,43 @@ class OptionsUI extends React.Component { ); } + renderSetOnPremise() { + return ( +
+

On Premise

+ { + this.props.hasCustomBaseUrl = e.target.checked; + this.props.handleUseCustomerBackupServer(this.props); + }} + /> + Use a custom backend server + {this.props.hasCustomBaseUrl && ['BASE_URL', 'CLIENT_ID', 'CLIENT_SECRET'].map((key)=>
+ { + this.props[key] = e.target.value; + this.props.handleUseCustomerBackupServer(this.props); + }} + /> +  {key} +
)} + {this.props.hasCustomBaseUrl && this.props.BASE_URL && this.props.BASE_URL != "" && ( +
+
You can get a client id and a client secret here
+ {chrome.permissions.request({origins: [this.props['BASE_URL']]})}} /> Allow the web-extension to backup data on this domain +
+ )} +
+ ); + } + renderFiles() { return (
@@ -43,6 +81,7 @@ class OptionsUI extends React.Component {
{this.renderFiles()} {this.renderCanMoveFocusByTab()} + {this.renderSetOnPremise()}
); } @@ -54,6 +93,11 @@ OptionsUI.propTypes = { handleInputFiles: PropTypes.func.isRequired, handleCanMoveFocusByTabChange: PropTypes.func.isRequired, canMoveFocusByTab: PropTypes.bool.isRequired, + handleUseCustomerBackupServer: PropTypes.func.isRequired, + hasCustomBaseUrl: PropTypes.func.isRequired, + BASE_URL: PropTypes.string, + CLIENT_ID: PropTypes.string, + CLIENT_SECRET: PropTypes.string, }; OptionsUI.defaultProps = { @@ -62,6 +106,10 @@ OptionsUI.defaultProps = { function mapStateToProps(state) { return { canMoveFocusByTab: state.canMoveFocusByTab, + hasCustomBaseUrl: state.hasCustomBaseUrl, + BASE_URL: state.BASE_URL, + CLIENT_ID: state.CLIENT_ID, + CLIENT_SECRET: state.CLIENT_SECRET, }; } @@ -90,6 +138,10 @@ function mapDispatchToProps(dispatch) { type: 'UPDATE_CAN_MOVE_FOCUS_BY_TAB', payload, }), + handleUseCustomerBackupServer: payload => dispatch({ + type: 'UPDATE_USE_CUSTOM_BACKUP_SERVER', + payload, + }), }; } diff --git a/src/reducers/options_ui.js b/src/reducers/options_ui.js index a5c9e77..137c448 100644 --- a/src/reducers/options_ui.js +++ b/src/reducers/options_ui.js @@ -9,9 +9,49 @@ const canMoveFocusByTab = (state = true, action) => { } }; +const hasCustomBaseUrl = (state = false, action) => { + switch (action.type) { + case 'UPDATE_USE_CUSTOM_BACKUP_SERVER': + return action.payload.hasCustomBaseUrl; + default: + return state; + } +}; + +const BASE_URL = (state = "", action) => { + switch (action.type) { + case 'UPDATE_USE_CUSTOM_BACKUP_SERVER': + return action.payload.BASE_URL; + default: + return state; + } +}; + +const CLIENT_ID = (state = "", action) => { + switch (action.type) { + case 'UPDATE_USE_CUSTOM_BACKUP_SERVER': + return action.payload.CLIENT_ID; + default: + return state; + } +}; + +const CLIENT_SECRET = (state = "", action) => { + switch (action.type) { + case 'UPDATE_USE_CUSTOM_BACKUP_SERVER': + return action.payload.CLIENT_SECRET; + default: + return state; + } +}; + const rootReducer = combineReducers({ canMoveFocusByTab, + hasCustomBaseUrl, + BASE_URL, + CLIENT_ID, + CLIENT_SECRET, }); export default rootReducer; diff --git a/src/sagas/options_ui.js b/src/sagas/options_ui.js index a0d4656..c8d8e3d 100644 --- a/src/sagas/options_ui.js +++ b/src/sagas/options_ui.js @@ -94,6 +94,14 @@ function* watchCanMoveFocusByTab() { }); } +function* watchUseCustomerBackupServer() { + yield takeEvery('UPDATE_USE_CUSTOM_BACKUP_SERVER', function* update() { + const { BASE_URL, CLIENT_ID, CLIENT_SECRET, hasCustomBaseUrl } = yield select(state => state); + yield browser.storage.local.set({ BASE_URL, CLIENT_ID, CLIENT_SECRET, hasCustomBaseUrl }); + port.postMessage({ type: 'updated-server-url', portName }); + }); +} + export default function* root() { yield [ @@ -101,5 +109,6 @@ export default function* root() { fork(watchImport), fork(watchExport), fork(watchCanMoveFocusByTab), + fork(watchUseCustomerBackupServer), ]; } diff --git a/src/utils/api.js b/src/utils/api.js index 5408155..8d890a6 100644 --- a/src/utils/api.js +++ b/src/utils/api.js @@ -2,7 +2,40 @@ import browser from 'webextension-polyfill'; import logger from './logger'; -const { BASE_URL, CLIENT_ID, CLIENT_SECRET } = process.env; +let { BASE_URL, CLIENT_ID, CLIENT_SECRET } = process.env; + +browser.storage.local.get('hasCustomBaseUrl').then((hasCustomBaseUrl) => { + if (hasCustomBaseUrl) { + ['BASE_URL', 'CLIENT_ID', 'CLIENT_SECRET'].forEach(key=>browser.storage.local.get(key).then((v) => { + if (v && v[key]) { + if (key=='BASE_URL') + BASE_URL = v[key]; + if (key=='CLIENT_ID') + CLIENT_ID = v[key]; + if (key=='CLIENT_SECRET') + CLIENT_SECRET = v[key]; + } + })); + } +}); + + +function setOnPremiseUrl(payload) { + let server = {}; + ['BASE_URL', 'CLIENT_ID', 'CLIENT_SECRET'].forEach(key=>{ + if (!payload.hasCustomBaseUrl || typeof(payload[key]) == "undefined" || payload[key] == "") { + server[key] = process.env[key]; + } else { + server[key] = payload[key]; + } + }); + ({ BASE_URL, CLIENT_ID, CLIENT_SECRET } = server); +} + + +function getResetPasswordUrl() { + return `${BASE_URL}/password_resets/new`; +} function getAccessToken() { return browser.storage.local.get('accessToken').then((v) => { @@ -84,6 +117,9 @@ function sendRequest(method, url, params) { logger.trace(JSON.stringify(params)); return fetch(u, { method, headers, body }) + .catch(function(e) { + return {ok: false, status: e.code, exception: e} + }) .then((response) => { logger.trace(response); if (response.ok) { @@ -158,6 +194,6 @@ export default { isLoggedIn, getUser, setUser, - signUpUrl: `${BASE_URL}/users/new`, - resetPasswordUrl: `${BASE_URL}/password_resets/new`, + getResetPasswordUrl, + setOnPremiseUrl, };