Skip to content
This repository has been archived by the owner on Jan 4, 2024. It is now read-only.

Commit

Permalink
Merge pull request #128 from friendsofagape/auto_backup
Browse files Browse the repository at this point in the history
Auto backup
  • Loading branch information
joelthe1 authored Mar 16, 2020
2 parents 9b6ffff + e0984b2 commit 6979263
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 10 deletions.
66 changes: 56 additions & 10 deletions src/components/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -47,7 +48,8 @@ class SettingsModal extends React.Component {
langCodeValue: "",
langCode: "",
langVersion: "",
folderPath: ""
folderPath: "",
backupFrequency: ""
},
refSetting: {
bibleName: "",
Expand Down Expand Up @@ -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 = () => {
Expand Down Expand Up @@ -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;
Expand All @@ -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) => {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1057,7 +1071,7 @@ class SettingsModal extends React.Component {
}
</FormattedMessage>
</div>
<div style={{"display": "flex"}} className="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<div style={{"display": "flex", padding: "20px 0 0 0"}} className="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<label
style={{"marginTop": "-24px", "fontSize": "14px"}}
className="mdl-textfield__label"
Expand All @@ -1083,6 +1097,38 @@ class SettingsModal extends React.Component {
/>
</RadioButtonGroup>
</div>
<div style={{"display": "flex"}} className="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<label
style={{"marginTop": "-24px", "fontSize": "14px"}}
className="mdl-textfield__label"
id="label-autobackup"
>
<FormattedMessage id="label-auto-backup" />
</label>
<RadioButtonGroup
valueSelected={backupFrequency}
name="autobackup"
style={{display: "flex", marginBottom:"6%", marginTop: "8px"}}
onChange={(event, value) => this.onChangeBackupSetting(value)}
>
<RadioButton
value="none"
label={<FormattedMessage id="label-none" />}
style={{width: "70%"}}
/>
<RadioButton
value="daily"
label={<FormattedMessage id="label-daily" />}
style={{width: "70%", marginLeft: "25px"}}
/>
<RadioButton
value="weekly"
label={<FormattedMessage id="label-weekly" />}
style={{width: "70%", marginLeft: "25px"}}
/>
</RadioButtonGroup>
</div>

<FormattedMessage id="btn-save" >
{ (message)=>
<RaisedButton
Expand Down
4 changes: 4 additions & 0 deletions src/translations/ar.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export default {
"label-pwd" : "كلمه السر",
"label-credentials": "شهاداته",
"label-no-project" : "لا توجد مشاريع لإظهارها.",
"label-auto-backup": "لصناعة السيارات في النسخ الاحتياطي",
"label-none": "لا يوجد",
"label-daily": "اليومي",
"label-weekly": "أسبوعي",
"placeholder-search-text" : "البحث عن النص",
"placeholder-replace-text" : "إستبدال",
"placeholder-path-to-destination" : "مسار إلى مجلد الوجهة",
Expand Down
4 changes: 4 additions & 0 deletions src/translations/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ export default {
"label-incomplete-verses" : "Possible Incomplete Verses",
"label-multiple-spaces" : "Verses with Multiple Spaces",
"label-statistic-heading": "Statistics for the Book of",
"label-auto-backup": "Auto-backup",
"label-none": "None",
"label-daily": "Daily",
"label-weekly": "Weekly",
"export-html": "HTML",
"export-usfm": "USFM",
"export-html-1-column": "1-Column HTML",
Expand Down
4 changes: 4 additions & 0 deletions src/translations/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export default {
"label-unjoin-this-verse": "Desunir este verso",
"label-join-to-preceding-verse": "Únete al verso anterior",
"label-joint-with-the-preceding-verse(s)" : "----- Conjunta con los versos anteriores -----",
"label-auto-backup": "copia de seguridad automática",
"label-none": "Ninguno",
"label-daily": "Diario",
"label-weekly": "Semanal",
"placeholder-search-text" : "Buscar texto",
"placeholder-replace-text" : "Reemplazo",
"placeholder-path-to-destination" : "Ruta a la carpeta de destino",
Expand Down
4 changes: 4 additions & 0 deletions src/translations/hi.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export default {
"label-unjoin-this-verse": "आयत को अलग करें",
"label-join-to-preceding-verse": "पिछले आयत से जोड़े",
"label-joint-with-the-preceding-verse(s)" : "----- पिछले आयत(तों) के साथ जोड़े -----",
"label-auto-backup": "ऑटो बैकअप",
"label-none": "नहीं",
"label-daily": "दैनिक",
"label-weekly": "साप्ताहिक",
"placeholder-search-text" : "विषय ढूंढें",
"placeholder-replace-text" : "प्रतिस्थापन",
"placeholder-path-to-destination" : "लक्षित फोल्डर की ओर मार्ग",
Expand Down
4 changes: 4 additions & 0 deletions src/translations/pt.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export default {
"label-unjoin-this-verse": "Desunir este verso",
"label-join-to-preceding-verse": "Junte-se ao verso anterior",
"label-joint-with-the-preceding-verse(s)" : "----- Juntar-se ao (s) versículo (s) -----",
"label-auto-backup": "backup automático",
"label-none": "Nenhum",
"label-daily": "Diariamente",
"label-weekly": "Semanal",
"placeholder-search-text" : "Buscar Texto",
"placeholder-replace-text" : "Substituição",
"placeholder-path-to-destination" : "Localização da pasta de destino",
Expand Down
178 changes: 178 additions & 0 deletions src/util/auto_export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import AutographaStore from "../components/AutographaStore";
const path = require("path");
const fs = require("fs");
const constants = require("../util/constants");
const db = require(`${__dirname}/data-provider`).targetDb();

export const initializeBackUp = async () => {
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;
}

0 comments on commit 6979263

Please sign in to comment.