Skip to content

Commit

Permalink
add exportDB / ImportDB
Browse files Browse the repository at this point in the history
  • Loading branch information
AlphaStyle committed Jan 11, 2018
1 parent 5b7f5f0 commit 13083c1
Show file tree
Hide file tree
Showing 5 changed files with 299 additions and 4 deletions.
72 changes: 72 additions & 0 deletions app/components/settings/General.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,53 @@ import PropTypes from 'prop-types';
// Custom Libs
import _withFadeInAnimation from '../shared/hoc/_withFadeInAnimation';

import { exportDB, importDB } from '../../helpers/pouchDB.js';
const openDialog = require('../../renderers/dialog');
const ipc = require('electron').ipcRenderer;

// Component
class General extends Component {
constructor(props) {
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
this.selectExportPath = this.selectExportPath.bind(this);
this.selectImportPath = this.selectImportPath.bind(this);
this.exportDBs = this.exportDBs.bind(this);
this.importDBs = this.importDBs.bind(this);
}

componentWillMount() {
this.setState(this.props.general);
}

componentDidMount() {
ipc.on('no-access-directory', (event, message) => {
openDialog({
type: 'warning',
title: 'No Access Permission',
message: `${message}. Please choose a different directory!`,
});
});

ipc.on('confirmed-export-path', (event, path) => {
this.setState({ exportPath: path }, () => {
this.props.updateSettings('appSettings', this.state);
});
});

ipc.on('confirmed-import-path', (event, path) => {
this.setState({ importPath: path }, () => {
this.props.updateSettings('appSettings', this.state);
});
});
}

componentWillUnmount() {
ipc.removeAllListeners('no-access-directory');
ipc.removeAllListeners('confirmed-export-path');
ipc.removeAllListeners('confirmed-import-path');
}

handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
Expand All @@ -25,6 +61,28 @@ class General extends Component {
});
}

selectExportPath() {
ipc.send('select-export-path');
}

selectImportPath() {
ipc.send('select-import-path');
}

exportDBs() {
this.selectExportPath();
ipc.on('confirmed-export-path', (event, path) => {
exportDB(path);
});
}

importDBs() {
this.selectImportPath();
ipc.on('confirmed-import-path', (event, path) => {
importDB(path);
});
}

render() {
return (
<div>
Expand Down Expand Up @@ -56,6 +114,20 @@ class General extends Component {
</label>
</div>
</div>

<div className="row">
<div className="col-md-12">
<div className="pageItem">
<label className="itemLabel">Export / Import</label>
<button onClick={this.exportDBs} className="button">
Export
</button>
<button onClick={this.importDBs} className="button">
Import
</button>
</div>
</div>
</div>
</div>
</div>
);
Expand Down
122 changes: 121 additions & 1 deletion app/helpers/pouchDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ const PouchDB = require('pouchdb-browser');
const contactsDB = new PouchDB('contacts');
const invoicesDB = new PouchDB('invoices');

// Used for ExportDB and ImportDB
const fs = require('fs');
const MemoryStream = require('memorystream');
const replicationStream = require('pouchdb-replication-stream');

// CSV to JSON and JSON to CSV
const csvjson = require('csvjson');

PouchDB.plugin(replicationStream.plugin);
PouchDB.adapter('writableStream', replicationStream.adapters.writableStream);

// Utility
import { omit } from 'lodash';

Expand Down Expand Up @@ -79,6 +90,115 @@ runMigration(
}
);

// Export PouchDBs
const exportDB = path => {
// create the export file
const file = fs.createWriteStream(path);

// Store PouchDB in memory before dumping to file
const invoicesStream = new MemoryStream();
const contactsStream = new MemoryStream();

// Temporary objects before merged into one
let invoicesStreamObject = {};
let contactsStreamObject = {};

// Invoice MemoryStream
invoicesStream.on('data', chunk => {
const j = JSON.parse(chunk.toString());
if (j.docs) {
invoicesStreamObject = j;
}
});

invoicesStream.on('end', () => {
finished();
});

// Contact MemoryStream
contactsStream.on('data', chunk => {
const j = JSON.parse(chunk.toString());
if (j.docs) {
contactsStreamObject = j;
}
});

contactsStream.on('end', () => {
finished();
});

// Dump contacts to memoryStream
contactsDB.dump(contactsStream).then(res => {
// TODO: error handling
if (res.ok !== true) {
console.log('Dump Failed');
}
});

// Dump invoices to memoryStream
invoicesDB.dump(invoicesStream).then(res => {
// TODO: error handling
if (res.ok !== true) {
console.log('Dump Failed');
}
});

// TODO: Improve this!
let done = 0;
const finished = () => {
done += 1;
if (done === 2) {
writeStreamToCSV();
}
};

// Merge and save memory stored PouchDB content to CSV file
const writeStreamToCSV = () => {
const streamObject = {
invoices: invoicesStreamObject,
'contacts:': contactsStreamObject,
};

const options = {
delimiter: ',',
wrap: false,
headers: 'full',
objectDenote: '.',
arrayDenote: '[]',
};

console.log('object', streamObject);

file.write(csvjson.toCSV(streamObject, options));
cleanup();
};

// Close and reset for next export
const cleanup = () => {
invoicesStreamObject = {};
contactsStreamObject = {};
file.close();
done = 0;
};
};

// Import PouchDB from CSV file
const importDB = path => {
// Read the CSV file
const data = fs.readFileSync(path, 'utf8');

if (data) {
const options = {
delimiter: ',',
quote: '"',
};

// TODO: This does not output the correct JSON as of now!
const j = csvjson.toSchemaObject(data);
console.log(j);
}
};

// Set DB via dbName
const setDB = dbName =>
new Promise((resolve, reject) => {
Expand Down Expand Up @@ -157,4 +277,4 @@ const updateDoc = (dbName, docId, updatedDoc) =>
.catch(err => reject(err));
});

export { getAllDocs, deleteDoc, saveDoc, updateDoc };
export { getAllDocs, deleteDoc, saveDoc, updateDoc, exportDB, importDB };
48 changes: 48 additions & 0 deletions main/select-export-directory.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Node Libs
const fs = require('fs');
const nodePath = require('path');

// Electron Libs
const ipc = require('electron').ipcMain;
Expand All @@ -24,3 +25,50 @@ ipc.on('select-export-directory', event => {
}
});
});

ipc.on('select-export-path', event => {
const window = BrowserWindow.fromWebContents(event.sender);
dialog.showSaveDialog(
window,
{ filters: [{ name: 'CSV', extensions: ['csv'] }] },
path => {
if (path) {
// Get the directory to check whether
// you have write permission or not
const dir = nodePath.parse(path).dir;

fs.access(dir, fs.constants.W_OK, err => {
if (err) {
event.sender.send('no-access-directory', err.message);
} else {
appConfig.set('exportPath', path);
event.sender.send('confirmed-export-path', path);
}
});
}
}
);
});

ipc.on('select-import-path', event => {
const window = BrowserWindow.fromWebContents(event.sender);
dialog.showOpenDialog(
window,
{
filters: [{ name: 'CSV', extensions: ['csv'] }],
properties: ['openFile'],
},
path => {
if (path) {
fs.access(path[0], fs.constants.R_OK, err => {
if (err) {
event.sender.send('no-access-directory', err.message);
} else {
appConfig.set('importPath', path[0]);
event.sender.send('confirmed-import-path', path[0]);
}
});
}
}
);
});
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"lint-staged": "lint-staged"
},
"dependencies": {
"csvjson": "^5.0.0",
"date-fns": "^1.28.5",
"dotenv": "^4.0.0",
"electron-is-dev": "^0.3.0",
Expand All @@ -36,8 +37,10 @@
"glob": "^7.1.2",
"is-svg": "^2.1.0",
"jimp": "^0.2.28",
"memorystream": "^0.3.1",
"moment": "^2.20.1",
"pouchdb-browser": "6.2.0",
"pouchdb-replication-stream": "^1.2.9",
"react": "^16.2.0",
"react-addons-shallow-compare": "^15.6.2",
"react-beautiful-dnd": "^2.4.1",
Expand Down
Loading

0 comments on commit 13083c1

Please sign in to comment.