Skip to content

Commit

Permalink
merge upstream, resolve conflicts, verify tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Abby Wheelis committed Nov 2, 2023
2 parents 9c700df + e8075b0 commit ee4b390
Show file tree
Hide file tree
Showing 20 changed files with 253 additions and 260 deletions.
40 changes: 34 additions & 6 deletions www/__mocks__/cordovaMocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export const mockFile = () => {
"applicationStorageDirectory" : "../path/to/app/storage/directory"};
}

//for consent document
const _storage = {};

export const mockBEMUserCache = () => {
const _cache = {};
const messages = [];
Expand Down Expand Up @@ -98,19 +101,44 @@ export const mockBEMUserCache = () => {
// this was mocked specifically for enketoHelper's use, could be expanded if needed
const fakeSurveyConfig = fakeConfig;

if(key == "config/app_ui_config"){
if (key == "config/app_ui_config") {
return new Promise<any>((rs, rj) =>
setTimeout(() => {
rs(fakeSurveyConfig);
}, 100)
);
setTimeout(() => {
rs(fakeSurveyConfig);
}, 100)
);
}
else {
return null;
return new Promise<any[]>((rs, rj) =>
setTimeout(() => {
rs(_storage[key]);
}, 100)
);
}
},
isEmptyDoc: (doc) => {
if (doc == undefined) { return true }
let string = doc.toString();
if (string.length == 0) {
return true;
} else {
return false;
}
}
}
window['cordova'] ||= {};
window['cordova'].plugins ||= {};
window['cordova'].plugins.BEMUserCache = mockBEMUserCache;
}

export const mockBEMDataCollection = () => {
const mockBEMDataCollection = {
markConsented: (consentDoc) => {
setTimeout(() => {
_storage['config/consent'] = consentDoc;
}, 100)
}
}
window['cordova'] ||= {};
window['cordova'].plugins.BEMDataCollection = mockBEMDataCollection;
}
24 changes: 24 additions & 0 deletions www/__tests__/startprefs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { markConsented, isConsented, readConsentState, getConsentDocument } from '../js/splash/startprefs';

import { mockBEMUserCache, mockBEMDataCollection } from "../__mocks__/cordovaMocks";
import { mockLogger } from "../__mocks__/globalMocks";

mockBEMUserCache();
mockBEMDataCollection();
mockLogger();

global.fetch = (url: string) => new Promise((rs, rj) => {
setTimeout(() => rs({
json: () => new Promise((rs, rj) => {
let myJSON = { "emSensorDataCollectionProtocol": { "protocol_id": "2014-04-6267", "approval_date": "2016-07-14" } };
setTimeout(() => rs(myJSON), 100);
})
}));
}) as any;

it('checks state of consent before and after marking consent', async () => {
expect(await readConsentState().then(isConsented)).toBeFalsy();
let marked = await markConsented();
expect(await readConsentState().then(isConsented)).toBeTruthy();
expect(await getConsentDocument()).toEqual({"approval_date": "2016-07-14", "protocol_id": "2014-04-6267"});
});
6 changes: 4 additions & 2 deletions www/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@
"confirm": "Confirm",
"user-data-erased": "User data erased.",
"consent-not-found": "Consent for data collection not found, consent now?",
"no-consent-logout": "Consent for data collection not found, please save your opcode, log out, and log back in with the same opcode. Note that you won't get any personalized stats until you do!",
"no-consent-message": "OK! Note that you won't get any personalized stats until you do!",
"consent-found": "Consent found!",
"consented-to": "Consented to protocol {{protocol_id}}, {{approval_date}}",
"consented-to": "Consented to protocol last updated on {{approval_date}}",
"consented-ok": "OK",
"qrcode": "My OPcode",
"qrcode-share-title": "You can save your OPcode to login easily in the future!"
Expand Down Expand Up @@ -154,9 +155,10 @@
"scootershare": "Scooter share",
"drove_alone": "Gas Car Drove Alone",
"shared_ride": "Gas Car Shared Ride",
"hybrid_drove_alone": "Hybrid Drove Alone",
"hybrid_shared_ride": "Hybrid Shared Ride",
"e_car_drove_alone": "E-Car Drove Alone",
"e_car_shared_ride": "E-Car Shared Ride",
"moped": "Moped",
"taxi": "Taxi / Uber / Lyft",
"bus": "Bus",
"train": "Train",
Expand Down
1 change: 0 additions & 1 deletion www/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import 'leaflet/dist/leaflet.css';

import './js/ngApp.js';
import './js/splash/referral.js';
import './js/splash/startprefs.js';
import './js/splash/pushnotify.js';
import './js/splash/storedevicesettings.js';
import './js/splash/localnotify.js';
Expand Down
2 changes: 0 additions & 2 deletions www/js/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ const App = () => {
const { colors } = useTheme();
const { t } = useTranslation();

const StartPrefs = getAngularService('StartPrefs');

const routes = useMemo(() => {
const showMetrics = appConfig?.survey_info?.['trip-labels'] == 'MULTILABEL';
return showMetrics ? defaultRoutes(t) : defaultRoutes(t).filter(r => r.key != 'metrics');
Expand Down
22 changes: 10 additions & 12 deletions www/js/control/ProfileSettings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import { AppContext } from "../App";
import { shareQR } from "../components/QrCode";
import { storageClear } from "../plugin/storage";
import { getAppVersion } from "../plugin/clientStats";
import { getConsentDocument } from "../splash/startprefs";
import { logDebug } from "../plugin/logger";

//any pure functions can go outside
const ProfileSettings = () => {
Expand All @@ -39,7 +41,6 @@ const ProfileSettings = () => {
const EmailHelper = getAngularService('EmailHelper');
const NotificationScheduler = getAngularService('NotificationScheduler');
const ControlHelper = getAngularService('ControlHelper');
const StartPrefs = getAngularService('StartPrefs');

//functions that come directly from an Angular service
const editCollectionConfig = () => setEditCollectionVis(true);
Expand Down Expand Up @@ -314,8 +315,9 @@ const ProfileSettings = () => {

//in ProfileSettings in DevZone (above two functions are helpers)
async function checkConsent() {
StartPrefs.getConsentDocument().then(function(resultDoc){
getConsentDocument().then(function(resultDoc){
setConsentDoc(resultDoc);
logDebug("In profile settings, consent doc found", resultDoc);
if (resultDoc == null) {
setNoConsentVis(true);
} else {
Expand Down Expand Up @@ -482,17 +484,13 @@ const ProfileSettings = () => {
onDismiss={()=>setNoConsentVis(false)}
style={settingStyles.dialog(colors.elevation.level3)}>
<Dialog.Title>{t('general-settings.consent-not-found')}</Dialog.Title>
<Dialog.Content>
<Text variant="">{t('general-settings.no-consent-logout')}</Text>
</Dialog.Content>
<Dialog.Actions>
<Button onPress={()=>{
setNoConsentVis(false);
setNoConsentMessageVis(true)}}>
{t('general-settings.cancel')}
</Button>
<Button onPress={()=>{
setNoConsentVis(false);
// $state.go("root.reconsent"); //don't know how to do this yet
}}>
{t('general-settings.confirm')}
setNoConsentVis(false); }}>
{t('general-settings.consented-ok')}
</Button>
</Dialog.Actions>
</Dialog>
Expand All @@ -503,7 +501,7 @@ const ProfileSettings = () => {
<Dialog visible={consentVis}
onDismiss={()=>setConsentVis(false)}
style={settingStyles.dialog(colors.elevation.level3)}>
<Dialog.Title>{t('general-settings.consented-to', {protocol_id: consentDoc.protocol_id, approval_date: consentDoc.approval_date})}</Dialog.Title>
<Dialog.Title>{t('general-settings.consented-to', {approval_date: consentDoc.approval_date})}</Dialog.Title>
<Dialog.Actions>
<Button onPress={()=>{
setConsentDoc({});
Expand Down
8 changes: 4 additions & 4 deletions www/js/controllers.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import angular from 'angular';
import { addStatError, addStatReading, statKeys } from './plugin/clientStats';
import { getPendingOnboardingState } from './onboarding/onboardingHelper';

angular.module('emission.controllers', ['emission.splash.startprefs',
'emission.splash.pushnotify',
angular.module('emission.controllers', ['emission.splash.pushnotify',
'emission.splash.storedevicesettings',
'emission.splash.localnotify',
'emission.splash.remotenotify'])
Expand All @@ -14,7 +14,7 @@ angular.module('emission.controllers', ['emission.splash.startprefs',
.controller('DashCtrl', function($scope) {})

.controller('SplashCtrl', function($scope, $state, $interval, $rootScope,
StartPrefs, PushNotify, StoreDeviceSettings,
PushNotify, StoreDeviceSettings,
LocalNotify, RemoteNotify) {
console.log('SplashCtrl invoked');
// alert("attach debugger!");
Expand Down Expand Up @@ -49,7 +49,7 @@ angular.module('emission.controllers', ['emission.splash.startprefs',
'root.main.metrics']
if (isInList(toState.name, personalTabs)) {
// toState is in the personalTabs list
StartPrefs.getPendingOnboardingState().then(function(result) {
getPendingOnboardingState().then(function(result) {
if (result != null) {
event.preventDefault();
$state.go(result);
Expand Down
2 changes: 1 addition & 1 deletion www/js/onboarding/ProtocolPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { View, ScrollView } from 'react-native';
import { Button, Surface } from 'react-native-paper';
import { resetDataAndRefresh } from '../config/dynamicConfig';
import { AppContext } from '../App';
import { getAngularService } from '../angular-react-helper';
import PrivacyPolicy from './PrivacyPolicy';
import { onboardingStyles } from './OnboardingStack';
import { markConsented } from '../splash/startprefs';
import { setProtocolDone } from './onboardingHelper';

const ProtocolPage = () => {
Expand Down
21 changes: 11 additions & 10 deletions www/js/onboarding/SaveQrPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { preloadDemoSurveyResponse } from "./SurveyPage";
import { storageSet } from "../plugin/storage";
import { registerUser } from "../commHelper";
import { resetDataAndRefresh } from "../config/dynamicConfig";
import { markConsented } from "../splash/startprefs";
import i18next from "i18next";

const SaveQrPage = ({ }) => {
Expand All @@ -22,16 +23,16 @@ const SaveQrPage = ({ }) => {

useEffect(() => {
if (overallStatus == true && !registerUserDone) {
const StartPrefs = getAngularService('StartPrefs');
StartPrefs.markConsented().then((response) => {
logDebug('permissions done, going to log in');
login(onboardingState.opcode).then((response) => {
logDebug('login done, refreshing onboarding state');
setRegisterUserDone(true);
preloadDemoSurveyResponse();
refreshOnboardingState();
});
});
logDebug('permissions done, going to log in');
markConsented()
.then(login(onboardingState.opcode)
.then((response) => {
logDebug('login done, refreshing onboarding state');
setRegisterUserDone(true);
preloadDemoSurveyResponse();
refreshOnboardingState();
})
);
} else {
logDebug('permissions not done, waiting');
}
Expand Down
18 changes: 13 additions & 5 deletions www/js/onboarding/onboardingHelper.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { DateTime } from "luxon";
import { getAngularService } from "../angular-react-helper";
import { getConfig, resetDataAndRefresh } from "../config/dynamicConfig";
import { storageGet, storageSet } from "../plugin/storage";
import { logDebug } from "../plugin/logger";
import { readConsentState, isConsented } from "../splash/startprefs";
import { getAngularService } from "../angular-react-helper";

export const INTRO_DONE_KEY = 'intro_done';

Expand Down Expand Up @@ -61,15 +62,22 @@ export function getPendingOnboardingState(): Promise<OnboardingState> {
};

async function readConsented() {
const StartPrefs = getAngularService('StartPrefs');
return StartPrefs.readConsentState().then(StartPrefs.isConsented) as Promise<boolean>;
return readConsentState().then(isConsented) as Promise<boolean>;
}

async function readIntroDone() {
export async function readIntroDone() {
return storageGet(INTRO_DONE_KEY).then((read_val) => !!read_val) as Promise<boolean>;
}

export async function markIntroDone() {
const currDateTime = DateTime.now().toISO();
return storageSet(INTRO_DONE_KEY, currDateTime);
return storageSet(INTRO_DONE_KEY, currDateTime)
.then(() => {
//handle "on intro" events
logDebug("intro done, calling registerPush and storeDeviceSettings");
const PushNotify = getAngularService("PushNotify");
const StoreSeviceSettings = getAngularService("StoreDeviceSettings");
PushNotify.registerPush();
StoreSeviceSettings.storeDeviceSettings();
});
}
7 changes: 6 additions & 1 deletion www/js/plugin/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ const unmungeValue = (key, retData) => {
}

const localStorageSet = (key: string, value: {[k: string]: any}) => {
localStorage.setItem(key, JSON.stringify(value));
//checking for a value to prevent storing undefined
//case where local was null and native was undefined stored "undefined"
//see discussion: https://github.com/e-mission/e-mission-phone/pull/1072#discussion_r1373753945
if (value) {
localStorage.setItem(key, JSON.stringify(value));
}
}

const localStorageGet = (key: string) => {
Expand Down
1 change: 0 additions & 1 deletion www/js/splash/localnotify.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import angular from 'angular';

angular.module('emission.splash.localnotify', ['emission.plugin.logger',
'emission.splash.startprefs',
'ionic-toast'])
.factory('LocalNotify', function($window, $ionicPlatform, $ionicPopup,
$state, $rootScope, ionicToast, Logger) {
Expand Down
28 changes: 9 additions & 19 deletions www/js/splash/pushnotify.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
//naming of this file can be a little confusing - "pushnotifysettings" for rewritten file
//https://github.com/e-mission/e-mission-phone/pull/1072#discussion_r1375360832


/*
* This module deals with the interaction with the push plugin, the redirection
* of silent push notifications and the re-parsing of iOS pushes. It then
Expand All @@ -15,12 +19,12 @@

import angular from 'angular';
import { updateUser } from '../commHelper';
import { readConsentState, isConsented } from './startprefs';

angular.module('emission.splash.pushnotify', ['emission.plugin.logger',
'emission.services',
'emission.splash.startprefs'])
'emission.services'])
.factory('PushNotify', function($window, $state, $rootScope, $ionicPlatform,
$ionicPopup, Logger, StartPrefs) {
$ionicPopup, Logger) {

var pushnotify = {};
var push = null;
Expand Down Expand Up @@ -159,8 +163,8 @@ angular.module('emission.splash.pushnotify', ['emission.plugin.logger',

$ionicPlatform.ready().then(function() {
pushnotify.datacollect = $window.cordova.plugins.BEMDataCollection;
StartPrefs.readConsentState()
.then(StartPrefs.isConsented)
readConsentState()
.then(isConsented)
.then(function(consentState) {
if (consentState == true) {
pushnotify.registerPush();
Expand All @@ -172,19 +176,5 @@ angular.module('emission.splash.pushnotify', ['emission.plugin.logger',
Logger.log("pushnotify startup done");
});

$rootScope.$on(StartPrefs.CONSENTED_EVENT, function(event, data) {
console.log("got consented event "+JSON.stringify(event.name)
+" with data "+ JSON.stringify(data));
if (StartPrefs.isIntroDone()) {
console.log("intro is done -> reconsent situation, we already have a token -> register");
pushnotify.registerPush();
}
});

$rootScope.$on(StartPrefs.INTRO_DONE_EVENT, function(event, data) {
console.log("intro is done -> original consent situation, we should have a token by now -> register");
pushnotify.registerPush();
});

return pushnotify;
});
6 changes: 4 additions & 2 deletions www/js/splash/remotenotify.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//naming of this module can be confusing "remotenotifyhandler" for rewritten file
//https://github.com/e-mission/e-mission-phone/pull/1072#discussion_r1375360832

/*
* This module deals with handling specific push messages that open web pages
* or popups. It does not interface with the push plugin directly. Instead, it
Expand All @@ -15,8 +18,7 @@
import angular from 'angular';
import { addStatEvent, statKeys } from '../plugin/clientStats';

angular.module('emission.splash.remotenotify', ['emission.plugin.logger',
'emission.splash.startprefs'])
angular.module('emission.splash.remotenotify', ['emission.plugin.logger'])

.factory('RemoteNotify', function($http, $window, $ionicPopup, $rootScope, Logger) {

Expand Down
Loading

0 comments on commit ee4b390

Please sign in to comment.