Skip to content

Commit

Permalink
Better error logging in Google import (#703)
Browse files Browse the repository at this point in the history
  • Loading branch information
ten-sis authored May 1, 2020
1 parent 0fd622d commit ba75fed
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 53 deletions.
41 changes: 17 additions & 24 deletions app/helpers/GoogleTakeOutAutoImport.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { mergeJSONWithLocalData } from '../helpers/GoogleData';

export class NoRecentLocationsError extends Error {}
export class InvalidFileExtensionError extends Error {}
export class EmptyFilePathError extends Error {}

const ZIP_EXT_CHECK_REGEX = /\.zip$/;
let progress;
Expand Down Expand Up @@ -49,6 +50,9 @@ export function getFilenamesForLatest2Months(rootPath, now) {
// Imports any Takeout location data
// Currently works for Google Takeout Location data
export async function importTakeoutData(filePath) {
if (!filePath) {
throw new EmptyFilePathError();
}
let unifiedPath = filePath;

if (Platform.OS === 'ios') {
Expand Down Expand Up @@ -93,30 +97,19 @@ export async function importTakeoutData(filePath) {
if (isExist) {
console.log('[INFO] File exists:', `file://${filepath}`);

const contents = await RNFS.readFile(`file://${filepath}`).catch(
err => {
console.log(
`[INFO] Caught error on opening "file://${filepath}"`,
err,
);
console.log(
`[INFO] Attempting to open file "file://${filepath}" again`,
err,
);

/**
* IMPORTANT!!!
* A temporary hack around URI generation bug in react-native-fs on android.
* An exception is thrown as `file://` is not in the file URI:
* "Error: ENOENT: No content provider:
* /data/user/0/edu.mit.privatekit/cache/Takeout-2020-04-12T15:48:54.295Z/Takeout/Location History/Semantic Location History/2020/2020_APRIL.json,
* open '/data/user/0/edu.mit.privatekit/cache/Takeout-2020-04-12T15:48:54.295Z/Takeout/Location History/Semantic Location History/2020/2020_APRIL.json'
* "
* @see https://github.com/itinance/react-native-fs/blob/master/android/src/main/java/com/rnfs/RNFSManager.java#L110
*/
return RNFS.readFile(`file://file://${filepath}`);
},
);
const contents = await RNFS.readFile(`file://${filepath}`).catch(() => {
/**
* IMPORTANT!!!
* A temporary hack around URI generation bug in react-native-fs on android.
* An exception is thrown as `file://` is not in the file URI:
* "Error: ENOENT: No content provider:
* /data/user/0/edu.mit.privatekit/cache/Takeout-2020-04-12T15:48:54.295Z/Takeout/Location History/Semantic Location History/2020/2020_APRIL.json,
* open '/data/user/0/edu.mit.privatekit/cache/Takeout-2020-04-12T15:48:54.295Z/Takeout/Location History/Semantic Location History/2020/2020_APRIL.json'
* "
* @see https://github.com/itinance/react-native-fs/blob/master/android/src/main/java/com/rnfs/RNFSManager.java#L110
*/
return RNFS.readFile(`file://file://${filepath}`);
});

newLocations = [
...newLocations,
Expand Down
10 changes: 8 additions & 2 deletions app/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@
"button_text": "Import past locations",
"google": {
"disclaimer": "Safe Paths has no affiliation with Google and never shares your data.",
"instructions_detailed": "Visit Google Takeout and export your Location History using the following settings: \n1. Delivery method: \"Add to Drive\" \n2. Frequency: \"Export once\" \n3. File type & size: \".zip\" and \"1GB\"\n4. Google sends an email when the export is ready \n5. Return here to import locations. Import options:\n- Import from Google Drive\n- Download from browser, then import from local phone files. Make sure to be on WiFi network as files can be big.",
"instructions_detailed": "Visit Google Takeout and export your Location History using the following settings: \n1. Delivery method: \"Add to Drive\" \n2. Frequency: \"Export once\" \n3. File type & size: \".zip\" and \"1GB\"\n4. Google sends an email when the export is ready \n5. Return here to import locations from Google Drive",
"instructions_first": "Adding location data from Google will give you a head start on building your recent locations.",
"instructions_second": "Before you can import, you must first \"Take out\" your location data from Google.",
"title": "Google Maps",
"visit_button_text": "Visit Google Takeout"
"visit_button_text": "Visit Google Takeout",
"already_imported":"Provided Takeout file has already been imported.",
"no_recent_locations": "Takeout doesn't have any recent locations.",
"invalid_file_format": "Provided file format is not supported. \nSupported formats: \".zip\".",
"file_open_error": "Could not open the file. \nPlease, make sure the file is opened from Google Drive"
},
"success":"Recent locations has been successfully imported!",
"error":"Something went wrong while importing your data.",
"subtitle": "To see if you encountered someone with COVID-19 prior to downloading this app, you can import your personal location history.",
"title": "Import Locations"
},
Expand Down
51 changes: 27 additions & 24 deletions app/views/Import.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import {
View,
} from 'react-native';

import languages from './../locales/languages';
import NavigationBarWrapper from '../components/NavigationBarWrapper';
import { Typography } from '../components/Typography';
import colors from '../constants/colors';
import fontFamily from '../constants/fonts';
import { pickFile } from '../helpers/General';
import {
EmptyFilePathError,
InvalidFileExtensionError,
NoRecentLocationsError,
importTakeoutData,
Expand All @@ -33,41 +33,44 @@ const ImportScreen = props => {
const {
navigation: { goBack },
} = props;
const [importResults, setImportResults] = useState(makeImportResults());

const [importResults, _setImportResults] = useState(makeImportResults());
const setImportResults = (...args) =>
_setImportResults(makeImportResults(...args));
async function importPickFile() {
try {
// reset info message
setImportResults(makeImportResults());
setImportResults();

const filePath = await pickFile();
if (filePath) {
const newLocations = await importTakeoutData(filePath);
if (newLocations.length) {
setImportResults(makeImportResults('label.import_success'));
} else {
setImportResults(makeImportResults('label.import_already_imported'));
}

const newLocations = await importTakeoutData(filePath);

if (newLocations.length) {
setImportResults(t('import.success'));
} else {
setImportResults(t('import.google.already_imported'));
}
} catch (err) {
if (err instanceof NoRecentLocationsError) {
setImportResults(
makeImportResults('label.import_no_recent_locations', true),
);
setImportResults(t('import.google.no_recent_locations'), true);
} else if (err instanceof InvalidFileExtensionError) {
setImportResults(
makeImportResults('label.import_invalid_file_format', true),
);
setImportResults(t('import.google.invalid_file_format'), true);
} else if (err instanceof EmptyFilePathError) {
/**
* If the imported file is opened from other than Google Drive folder,
* filepath is returned as null. Leaving a message to ensure import file
* is located on Google Drive.
*/
setImportResults(t('import.google.file_open_error'), true);
} else {
setImportResults(makeImportResults('label.import_error', true));
console.log('[ERROR] Failed to import locations', err);
setImportResults(t('import.error'), true);
}
}
}

return (
<NavigationBarWrapper
title={languages.t('import.title')}
onBackPress={goBack}>
<NavigationBarWrapper title={t('import.title')} onBackPress={goBack}>
<ScrollView style={styles.main}>
<View style={styles.subHeaderTitle}>
<Typography style={styles.sectionDescription}>
Expand All @@ -90,15 +93,15 @@ const ImportScreen = props => {
}
style={styles.buttonTouchable}>
<Typography style={styles.buttonText}>
{languages.t('import.google.visit_button_text')}
{t('import.google.visit_button_text')}
</Typography>
</TouchableOpacity>
<TouchableOpacity
testID='google-takeout-import-btn'
onPress={importPickFile}
style={styles.buttonTouchable}>
<Typography style={styles.buttonText}>
{languages.t('import.title')}
{t('import.title')}
</Typography>
</TouchableOpacity>

Expand All @@ -108,7 +111,7 @@ const ImportScreen = props => {
...styles.importResults,
...(importResults?.error ? styles.importResultsError : {}),
}}>
{languages.t(importResults.label)}
{importResults.label}
</Typography>
) : null}
</View>
Expand Down
4 changes: 1 addition & 3 deletions app/views/__tests__/__snapshots__/Import.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,7 @@ Array [
2. Frequency: "Export once"
3. File type & size: ".zip" and "1GB"
4. Google sends an email when the export is ready
5. Return here to import locations. Import options:
- Import from Google Drive
- Download from browser, then import from local phone files. Make sure to be on WiFi network as files can be big.
5. Return here to import locations from Google Drive
</Text>
<View
accessible={true}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"i18n:extract": "i18next",
"i18n:pull": "./app/locales/pull.sh",
"test": "jest --config=./jest/config.js",
"test:watch": "jest --config=./jest/config.js --watch",
"update-snapshots": "jest --config=./jest/config.js --updateSnapshot",
"test:dev_setup": "bats __tests__/dev_setup.test.bats"
},
Expand Down

0 comments on commit ba75fed

Please sign in to comment.