From 974be113568498f1b9f4b4c20b60c9a6625f2c2e Mon Sep 17 00:00:00 2001 From: deeptirawat1510 Date: Mon, 20 Nov 2023 17:48:58 +0530 Subject: [PATCH] #1191 | Deepthi M, Deepti R, Implemented the functionality to configure the server url. --- Makefile | 8 ++ makefiles/androidDevice.mk | 1 + .../openchs-android/config/env/no_env.json | 4 + packages/openchs-android/src/App.js | 3 +- packages/openchs-android/src/Avni.js | 4 +- .../src/ServerUrlConfiguration.js | 133 ++++++++++++++++++ .../src/service/SettingsService.js | 10 +- 7 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 packages/openchs-android/config/env/no_env.json create mode 100644 packages/openchs-android/src/ServerUrlConfiguration.js diff --git a/Makefile b/Makefile index ece58dab2..49eb08abd 100644 --- a/Makefile +++ b/Makefile @@ -132,6 +132,7 @@ as_prerelease_dev: ; $(call _create_config,prerelease_dev) as_perf: ; $(call _create_config,perf) as_prod: ; $(call _create_config,prod) as_prod_dev: ; $(call _create_config,prod_dev) +as_no_env: ; $(call _create_config,no_env) release_clean: ## If you get dex errors rm -rf packages/openchs-android/android/app/build @@ -197,6 +198,13 @@ release_prod_universal_without_clean: release_prod_universal: enableSeparateBuildPerCPUArchitecture=false make release_prod +release_no_env: as_no_env release + +release_no_env_universal_without_clean: + enableSeparateBuildPerCPUArchitecture=false make release_no_env + +release_no_env_universal: renew_env release_no_env_universal_without_clean + release_staging_without_clean: as_staging enableSeparateBuildPerCPUArchitecture=false make release diff --git a/makefiles/androidDevice.mk b/makefiles/androidDevice.mk index 4e0952a25..0668f1721 100644 --- a/makefiles/androidDevice.mk +++ b/makefiles/androidDevice.mk @@ -65,6 +65,7 @@ run_app_prerelease: as_prerelease _run_app run_app_prerelease_dev: as_prerelease_dev _run_app run_app_prod: as_prod _run_app run_app_prod_dev: as_prod_dev _run_app +run_app_no_env: as_no_env _run_app stop_app: adb shell am force-stop ${app_android_package_name} diff --git a/packages/openchs-android/config/env/no_env.json b/packages/openchs-android/config/env/no_env.json new file mode 100644 index 000000000..7d6ac6461 --- /dev/null +++ b/packages/openchs-android/config/env/no_env.json @@ -0,0 +1,4 @@ +{ + "allowServerURLConfig": true, + "ENV": "prod" +} \ No newline at end of file diff --git a/packages/openchs-android/src/App.js b/packages/openchs-android/src/App.js index 0b537549c..b4fd750a9 100644 --- a/packages/openchs-android/src/App.js +++ b/packages/openchs-android/src/App.js @@ -13,6 +13,7 @@ import AppStore from "./store/AppStore"; import RealmFactory from "./framework/db/RealmFactory"; import General from "./utility/General"; import EnvironmentConfig from "./framework/EnvironmentConfig"; +import Config from './framework/Config'; const {TamperCheckModule} = NativeModules; @@ -49,7 +50,7 @@ class App extends Component { const clipboardString = `${this.state.error.message}\nStacktrace:${this.state.stacktrace}`; General.logError("App", `renderError: ${clipboardString}`); - if (EnvironmentConfig.inNonDevMode()) { + if (EnvironmentConfig.inNonDevMode() && !Config.allowServerURLConfig) { Alert.alert("App will restart now", this.state.error.message, [ { diff --git a/packages/openchs-android/src/Avni.js b/packages/openchs-android/src/Avni.js index def676934..714293712 100644 --- a/packages/openchs-android/src/Avni.js +++ b/packages/openchs-android/src/Avni.js @@ -3,6 +3,7 @@ import {StatusBar, StyleSheet, View} from 'react-native'; import Colors from "./views/primitives/Colors"; import { LogBox } from 'react-native'; import General from "./utility/General"; +import Config from './framework/Config'; export default class Avni extends Component { static styles = StyleSheet.create({ @@ -18,10 +19,11 @@ export default class Avni extends Component { LogBox.ignoreAllLogs(); General.logDebug("Avni", "=====================>>>>>>>Rendering main app component"); const App = require('./App').default; + const ServerUrlConfiguration = require('./ServerUrlConfiguration').default; return ( - + {Config.allowServerURLConfig ? : } ); } diff --git a/packages/openchs-android/src/ServerUrlConfiguration.js b/packages/openchs-android/src/ServerUrlConfiguration.js new file mode 100644 index 000000000..09c41be45 --- /dev/null +++ b/packages/openchs-android/src/ServerUrlConfiguration.js @@ -0,0 +1,133 @@ +import React, { Component } from 'react'; +import { Image, Text, View, TextInput, TouchableOpacity } from 'react-native'; +import Colors from './views/primitives/Colors'; +const App = require('./App').default; +import AsyncStorage from '@react-native-async-storage/async-storage'; +import { getJSON } from './framework/http/requests'; + +class ServerUrlConfiguration extends Component { + constructor(props) { + super(props); + this.state = { + serverUrl: '', + isValidUrl: true, + isURLInitialised: false, + isLoading: false, + isVerifying: false, + }; + } + + async componentDidMount() { + this.setState({ isLoading: true }); + if (!_.isNil(await AsyncStorage.getItem('serverUrl'))) { + this.setState({ + isURLInitialised: true + }) + } + this.setState({ isLoading: false }); + } + + isUrlValid = async (url) => { + const urlRegex = /^(https?:\/\/)?(?!www\.)[a-zA-Z0-9.-]+\.[a-zA-Z]{2,5}(:[0-9]{1,5})?(\/.*)?$/; + const ipRegex = /^(https?:\/\/)?(\d{1,3}\.){3}\d{1,3}:\d{1,5}$/; + if (urlRegex.test(url) || ipRegex.test(url)) { + return getJSON(url + "/idp-details", true).then((idpDetails) => { + return true; + }).catch((error) => { + return false; + }); + } + else { + return false; + } + + }; + + handleUrlChange = (text) => { + this.setState({ serverUrl: text, isValidUrl: true }); + }; + + handleSubmit = async () => { + this.setState({ isVerifying: true }); + const lowerCaseUrl = this.state.serverUrl.replace(/^https/i, 'https'); + if (await this.isUrlValid(lowerCaseUrl)) { + this.storeServerUrl(lowerCaseUrl); + this.setState({ isURLInitialised: true }); + } else { + this.setState({ isValidUrl: false }); + } + this.setState({ isVerifying: false }); + }; + + storeServerUrl = async (url) => { + try { + await AsyncStorage.setItem('serverUrl', url); + console.log('Server URL stored successfully'); + } catch (error) { + console.error('Error storing server URL:', error); + } + }; + + renderURLConfigView = () => { + return ( + + + + + + {!this.state.isValidUrl && ( + Please enter a valid server URL. + )} + + {this.state.isVerifying && Validating URL....} + + { + this.handleSubmit(); + }} + style={{ + marginTop: 20, + backgroundColor: this.state.serverUrl && this.state.isValidUrl && !this.state.isVerifying ? "#009973" : "gray", + paddingVertical: 10, + borderRadius: 5, + alignItems: 'center', + }} + disabled={!this.state.serverUrl || !this.state.isValidUrl || this.state.isVerifying} + > + Submit + + + ) + } + + renderTextView = (text) => { + return ( + + {text} + ); + } + + render() { + if (this.state.isLoading) { + return this.renderTextView("Loading..."); + } + if (this.state.isURLInitialised && !this.state.isLoading) { + return + } + if (!this.state.isURLInitialised && !this.state.isLoading) { + return this.renderURLConfigView(); + } + } +} + +export default ServerUrlConfiguration; \ No newline at end of file diff --git a/packages/openchs-android/src/service/SettingsService.js b/packages/openchs-android/src/service/SettingsService.js index 54eed7959..cc9e726a8 100644 --- a/packages/openchs-android/src/service/SettingsService.js +++ b/packages/openchs-android/src/service/SettingsService.js @@ -7,6 +7,8 @@ import {ModelGeneral, Settings, LocaleMapping, OrganisationConfig} from 'openchs import Config from '../framework/Config'; import _ from 'lodash'; import EnvironmentConfig from "../framework/EnvironmentConfig"; +import AsyncStorage from '@react-native-async-storage/async-storage'; +import RNRestart from 'react-native-restart'; @Service("settingsService") class SettingsService extends BaseService { @@ -16,7 +18,8 @@ class SettingsService extends BaseService { super(db, beanStore); } - init() { + async init() { + let url = Config.allowServerURLConfig ? await AsyncStorage.getItem('serverUrl') : Config.SERVER_URL; const dbInScope = this.db; General.logDebug("SettingsService", `Config.ENV: ${Config.ENV}`); this.db.write(() => { @@ -28,9 +31,12 @@ class SettingsService extends BaseService { settings.password = ""; settings.logLevel = InitialSettings.logLevel; settings.pageSize = InitialSettings.pageSize; - settings.serverURL = Config.SERVER_URL; + settings.serverURL = url; settings.poolId = ""; settings.clientId = Config.CLIENT_ID || ""; + if (Config.allowServerURLConfig){ + RNRestart.Restart(); + } } if (EnvironmentConfig.isDevMode()) {