diff --git a/src/components/Settings.js b/src/components/Settings.js index d9ccf71..2ce4e06 100644 --- a/src/components/Settings.js +++ b/src/components/Settings.js @@ -19,6 +19,7 @@ import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary"; import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails"; import Typography from "@material-ui/core/Typography"; import ExpandMoreIcon from "@material-ui/icons/ExpandMore"; +import * as auto_export from "../util/auto_export"; const numberFormat = require("../util/getNumberFormat") const { dialog, getCurrentWindow } = require('electron').remote; @@ -47,7 +48,8 @@ class SettingsModal extends React.Component { langCodeValue: "", langCode: "", langVersion: "", - folderPath: "" + folderPath: "", + backupFrequency: "" }, refSetting: { bibleName: "", @@ -116,10 +118,14 @@ class SettingsModal extends React.Component { settingData.langCode = doc.targetLang; settingData.langCodeValue = doc.targetLang; settingData.langVersion = doc.targetVersion; - settingData.folderPath = doc.targetPath; - }, (err) => { + settingData.folderPath = doc.targetPath; + settingData.backupFrequency = (doc.backupFrequency) === undefined ? "daily" : doc.backupFrequency; + if (settingData.langCodeValue && settingData.langVersion && settingData.backupFrequency !== "none") { + auto_export.initializeBackUp(); + } + }, (err) => { // console.log(err); - }); + }); } loadReference = () => { @@ -241,14 +247,15 @@ class SettingsModal extends React.Component { saveSetting = () => { if (this.target_setting() === false) return; - const currentTrans = AutographaStore.currentTrans; - const {langCode, langVersion, folderPath} = this.state.settingData; + const currentTrans = AutographaStore.currentTrans; + const {langCode, langVersion, folderPath, backupFrequency} = this.state.settingData; const settingData = { _id: 'targetBible', targetLang: langCode.toLowerCase(), targetVersion: langVersion, targetPath: folderPath, - langScript: AutographaStore.scriptDirection.toUpperCase() + langScript: AutographaStore.scriptDirection.toUpperCase(), + backupFrequency: backupFrequency } db.get('targetBible').then((doc) => { settingData._rev = doc._rev; @@ -261,7 +268,11 @@ class SettingsModal extends React.Component { }, (err) => { swal(currentTrans["dynamic-msg-trans-data"], currentTrans["dynamic-msg-went-wrong"], "success"); }); - }); + }); + + if (langCode && langVersion && backupFrequency !== "none") { + auto_export.initializeBackUp(); + } } openFileDialogSettingData = (event) => { @@ -752,6 +763,9 @@ class SettingsModal extends React.Component { onChangeScriptDir = (value) => { AutographaStore.scriptDirection = value; + } + onChangeBackupSetting = (value) => { + this.setState({ settingData: { ...this.state.settingData, backupFrequency: value} }); } onChangeRefScriptDir = (value) => { AutographaStore.refScriptDirection = value; @@ -945,7 +959,7 @@ class SettingsModal extends React.Component { let closeSetting = () => AutographaStore.showModalSettings = false const { show } = this.props; - const { langCodeValue, langVersion, folderPath } = this.state.settingData; + const { langCodeValue, langVersion, folderPath, backupFrequency } = this.state.settingData; const { bibleName, refVersion, refLangCode, refFolderPath } = this.state.refSetting; const listCode = this.state._listArray; @@ -1057,7 +1071,7 @@ class SettingsModal extends React.Component { } -
+
+
+ + this.onChangeBackupSetting(value)} + > + } + style={{width: "70%"}} + /> + } + style={{width: "70%", marginLeft: "25px"}} + /> + } + style={{width: "70%", marginLeft: "25px"}} + /> + +
+ { (message)=> { + try { + // Initial Backup call + backUp(); + const delay = 60000 * 60; // 60 minutes/1 hour + setInterval(async () => { + backUp(); + }, delay); + } catch(e) { + console.log(e); + } +} + +async function backUp() { + let targetLangDoc = await db.get('targetBible'); + const outputPath = targetLangDoc.targetPath; + const directory = path.join(Array.isArray(outputPath) ? outputPath[0] : outputPath,"auto-backup"); + const nameElements = [ + targetLangDoc && targetLangDoc.targetLang, + targetLangDoc && targetLangDoc.targetVersion + ].filter(Boolean); + const foldername = nameElements.join("_"); + const dirPath = path.join(directory, foldername); + if (!fs.existsSync(dirPath)){ + fs.mkdirSync(dirPath, { recursive: true }); + } + await fs.readdir(dirPath, (err, folders) => { + if (folders.length >= 1) { + let folderName = (folders[(folders.length)-1]).split('_'); + var d = new Date(); + let timeStamp = [ d && getTimeStamp(d) ].filter(Boolean); + let currentTime = timeStamp[0].split('_'); + let days = calculateDays(currentTime,folderName); + if (days >= 1 && (targetLangDoc.backupFrequency).toLowerCase() === "daily") { + buildFilePath(new Date(), dirPath); + folderHandling (folders, dirPath); + } else if (days >= 7 && (targetLangDoc.backupFrequency).toLowerCase() === "weekly") { + buildFilePath(new Date(), dirPath); + folderHandling (folders, dirPath); + } else { + return null; + } + + } else { + buildFilePath(new Date(), dirPath); + } + }); +} + +async function exportAllBooks(dir) { + let doc = await db.get('targetBible'); + constants.bookCodeList.forEach(async(value, index) => { + let book={}; + book.bookNumber = (index+1).toString(); + book.bookName = AutographaStore.editBookNamesMode ? AutographaStore.translatedBookNames[index] : constants.booksList[index]; + book.bookCode = value; + book.outputPath = doc.targetPath; + await toUsfm(book, dir); + }) +} + +export const toUsfm = async (book, dir) => { + const usfmDoc = await toUsfmDoc(book, false); + const filename = (book.bookCode) + '.usfm'; + const filePath = path.join(dir, filename); + writeUsfm(usfmDoc, filePath); +}; + +async function toUsfmDoc(book, returnNullForEmptyBook=false) { + try { + const usfmContent = []; + var isEmpty = true; + usfmContent.push('\\id ' + book.bookCode); + usfmContent.push('\\mt ' + book.bookName); + const doc = await db.get(book.bookNumber); + for (const chapter of doc.chapters) { + usfmContent.push('\n\\c ' + chapter.chapter); + usfmContent.push('\\p'); + let i = 0; + let verseNumber; + let verses; + for (const verse of chapter.verses) { + i = i + 1; + if (i < (chapter.verses).length && chapter.verses[i].joint_verse) { + // Finding out the join verses and get their verse number(s) + verseNumber = chapter.verses[i].joint_verse + "-" + chapter.verses[i].verse_number; + verses = chapter.verses[(chapter.verses[i].joint_verse)-1].verse; + continue; + } else { + if (verseNumber) { + // Push join verse number (1-3) and content. + let newVerse = addMtag(verses); + usfmContent.push('\\v ' + verseNumber + ' ' + newVerse); + verseNumber = undefined; + verses = undefined; + } else { + // Push verse number and content. + let newVerse = addMtag(verse.verse); + usfmContent.push('\\v ' + verse.verse_number + ' ' + newVerse); + } + isEmpty = isEmpty && !verse.verse; + } + } + } + return (returnNullForEmptyBook && isEmpty) + ? null + : usfmContent.join('\n'); + } catch(err) { + console.log(err); + } +} + +function addMtag(verses) { + let newVerse = verses; + if(verses.indexOf('\n') !== -1 ){ + newVerse = verses.trim().replace(new RegExp(/[\n\r]/, 'gu'), '\n\\m ') + verses = newVerse + } + return newVerse; +} + +async function buildFilePath(date, dirPath) { + const dateElement = [ date && getTimeStamp(date) ].filter(Boolean); + const dir = path.join(dirPath, dateElement[0]); + if (!fs.existsSync(dir)){ + fs.mkdirSync(dir, { recursive: true }); + } + exportAllBooks(dir); +} + +function folderHandling (folders, dirPath) { + if (folders.length >= 5) { + var files = fs.readdirSync(path.join(dirPath, folders[0])); + files.forEach(file => { + fs.unlinkSync(path.join(dirPath, folders[0], file)); + }); + fs.rmdir(path.join(dirPath, folders[0]), function(err, result) { + if(err) console.log('error', err); + }); + } +} + +function writeUsfm(usfmDoc, filePath) { + if (usfmDoc && filePath) { + fs.writeFileSync(filePath, usfmDoc, 'utf8', function(err, result) { + if(err) console.log('error', err); + }); + } +} + +function getTimeStamp(date) { + var months = ["January","February","March","April","May","June","July","August","September","October","November","December"]; + var year = date.getFullYear(), + month = ((date.getMonth() + 1) < 10 ? '0' : '') + (date.getMonth() + 1), + day = (date.getDate() < 10 ? '0' : '') + date.getDate(), + hour = (date.getHours() < 10 ? '0' : '') + date.getHours(), + minute = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(), + second = (date.getSeconds() < 10 ? '0' : '') + date.getSeconds(); + + return (months[parseInt(month)-1] + " " + day + "-" + year.toString() + "_" + hour + ":" + minute + ":" + second).toString(); +} + +function calculateDays(currDate, preDate) + { + var currTime = new Date(currDate[0] + " " + currDate[1]); + var preTime = new Date(preDate[0] + " " + preDate[1]); + var difference = Math.abs(currTime.getTime() - preTime.getTime()) / 1000; + // var hour = Math.floor(difference / 3600) % 24; + // var minutes = Math.floor(difference / 60) % 60; + var days = Math.floor(difference / 86400); + return days; + }