From a6867dd3873043e430c99adaa8993d33f494a3a7 Mon Sep 17 00:00:00 2001 From: Oscar Martinez Date: Wed, 3 Jun 2020 21:53:48 -0500 Subject: [PATCH 1/9] Fixing api crash --- .envSample | 0 divisaTraceback.js | 49 ++++++++++++++---------- interfaz.js | 93 +++++++++++++++++++++++++--------------------- 3 files changed, 79 insertions(+), 63 deletions(-) create mode 100644 .envSample diff --git a/.envSample b/.envSample new file mode 100644 index 0000000..e69de29 diff --git a/divisaTraceback.js b/divisaTraceback.js index ea1a615..a2b452c 100644 --- a/divisaTraceback.js +++ b/divisaTraceback.js @@ -1,61 +1,54 @@ -const request = require('request-promise'); - -require('dotenv').config() +let moment = require('moment'); +require('dotenv').config(); // Source: https://apiv2.bitcoinaverage.com/ const divisaTraceback = async(timestamp, divisa, amount) => { let crypto = ['BTC', 'ETH', 'LTC'] let normal = ['USD', 'GBP', 'CNY', 'EUR']; - let opt = { method: 'GET', json: true }; - let cryptoHeaders = { - 'X-Testing': 'testing', - 'x-ba-key': process.env.APIKEY - } try { if((Date.now() - 7776000000) <= (timestamp * 1000)) { if(crypto.includes(divisa) || normal.includes(divisa)) { - if(amount > 0) { - opt.headers = cryptoHeaders; + if(amount >= 0) { let divisaTraceback = {}; + let resolution = await getResolution(timestamp); if(crypto.includes(divisa)) { divisaTraceback[crypto.splice(crypto.indexOf(divisa), 1)[0]] = Number(amount); - Object.assign(divisaTraceback, await requestIteration(normal, divisa, true, timestamp, amount)); - Object.assign(divisaTraceback, await requestIteration(crypto, 'USD', false, timestamp, divisaTraceback['USD'])); + Object.assign(divisaTraceback, await requestIteration(normal, divisa, true, timestamp, amount, resolution)); + Object.assign(divisaTraceback, await requestIteration(crypto, 'USD', false, timestamp, divisaTraceback['USD'], resolution)); } else { divisaTraceback[normal.splice(normal.indexOf(divisa), 1)[0]] = Number(amount); - Object.assign(divisaTraceback, await requestIteration(crypto, divisa, false, timestamp, amount)); - Object.assign(divisaTraceback, await requestIteration(normal, 'BTC', true, timestamp, divisaTraceback['BTC'])); + Object.assign(divisaTraceback, await requestIteration(crypto, divisa, false, timestamp, amount, resolution)); + Object.assign(divisaTraceback, await requestIteration(normal, 'BTC', true, timestamp, divisaTraceback['BTC'], resolution)); } return(divisaTraceback); - } else return('The amount must be greater that 0'); + } else return('The amount must be 1 or higher'); } else return('Currency target invalid'); } else return('Date out of range') } catch(e) { - return(e); + throw 'error'; } }; -const requestIteration = async(set, divisa, flag, timestamp, amount) => { +const requestIteration = async(set, divisa, flag, timestamp, amount, resolution) => { let opt = { method: 'GET', json: true, headers: { - 'X-Testing': 'testing', 'x-ba-key': process.env.APIKEY } }; let res = {}; for (element in set) { if(flag) { - opt.uri = `https://apiv2.bitcoinaverage.com/indices/global/history/${divisa}${set[element]}?at=${timestamp}&resolution=hour`; + opt.uri = `https://apiv2.bitcoinaverage.com/indices/global/history/${divisa}${set[element]}?at=${timestamp}&resolution=${resolution}`; let { average } = await request(opt); res[set[element]] = average * amount; } else { - opt.uri = `https://apiv2.bitcoinaverage.com/indices/global/history/${set[element]}${divisa}?at=${timestamp}&resolution=hour`; + opt.uri = `https://apiv2.bitcoinaverage.com/indices/global/history/${set[element]}${divisa}?at=${timestamp}&resolution=${resolution}`; let { average } = await request(opt); res[set[element]] = amount / average; } @@ -63,4 +56,20 @@ const requestIteration = async(set, divisa, flag, timestamp, amount) => { return res; }; +const getResolution = async(timestamp) => { + let resolution = 'day'; + let momentTime = moment(timestamp); + if(process.env.API_MODE == 'dev') { + if(momentTime >= moment().subtract(2, 'hours')) resolution = 'minute'; + else if(momentTime >= moment().subtract(10, 'days')) resolution = 'hour'; + + } else if(process.env.API_MODE == 'startup' || process.env.API_MODE == 'grow') { + if(momentTime >= moment().subtract(24, 'hours')) resolution = 'minute'; + else if(momentTime >= moment().subtract(31, 'days')) resolution = 'hour'; + + } else throw new Error('Bad config'); + + return resolution; +} + module.exports = divisaTraceback; \ No newline at end of file diff --git a/interfaz.js b/interfaz.js index 60a5a28..8e43eeb 100644 --- a/interfaz.js +++ b/interfaz.js @@ -91,7 +91,7 @@ const main = async () => { } while (true) { await init(); - console.clear(); + //console.clear(); console.log('Select one to modify the field.\n'); let carbonCreditMenu = await generateData(carbonCredit, 0); let { insertMenu } = await inquirer.prompt([{ @@ -111,42 +111,47 @@ const main = async () => { }]); if (insertMenu == 'Insert current register') { if (await validateInsertion(carbonCredit)) { - carbonCredit.conversionPrice = await divisaTraceback( - moment.utc(carbonCredit.cancelDate + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(), - carbonCredit.cancelPrice.divisa, - carbonCredit.cancelPrice.qty - ); - showData(carbonCredit, 0); - serialNoPart=carbonCredit.SerialNo.split('-'); - serialFloor=serialNoPart[7]; - serialTop=serialNoPart[8]; - var totalCC = 1+parseInt(serialTop)-parseInt(serialFloor); - let { input } = await inquirer.prompt([{ - type: 'input', - name: 'input', - message: 'Data is correct, you will insert '+ String(totalCC) +" carbon credits y | n:", - }]); - if (input == 'y') { - carbonCredit.issueDate = moment(carbonCredit.issueDate + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); - carbonCredit.cancelDate = moment(carbonCredit.cancelDate + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); - carbonCredit.ccVintageStart = moment(carbonCredit.ccVintageStart + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); - carbonCredit.ccVintageEnd = moment(carbonCredit.ccVintageEnd + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); - carbonCredit.CCID = await hashSortCoerce.hash(carbonCredit); - const hash = await db.put(carbonCredit); - console.log(`Successful insertion, CCID: ${carbonCredit.CCID}, hash: ${hash}.`); - for(var i=parseInt(serialFloor)+1; i<=serialTop; i++){ - var tempCarbonCredit = {...carbonCredit}; - tempCarbonCredit.SerialNo= await asyncCCSerialNo(serialNoPart,i) - tempCarbonCredit.CCID = await hashSortCoerce.hash(tempCarbonCredit); - const hash = await db.put(tempCarbonCredit); - console.log(`Successful insertion, CCID: ${tempCarbonCredit.CCID}, hash: ${hash}.`); - } - console.log(`Inserted ${totalCC} carbon credits.`); - break; - } else { - console.clear(); - console.log('Insertion aborted'); - break; + try{ + carbonCredit.conversionPrice = await divisaTraceback( + moment.utc(carbonCredit.cancelDate + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(), + carbonCredit.cancelPrice.divisa, + carbonCredit.cancelPrice.qty + ); + if(carbonCredit.conversionPrice === 'error') throw new Error('Error at getting currencies price.'); + showData(carbonCredit, 0); + serialNoPart=carbonCredit.SerialNo.split('-'); + serialFloor=serialNoPart[7]; + serialTop=serialNoPart[8]; + var totalCC = 1+parseInt(serialTop)-parseInt(serialFloor); + let { input } = await inquirer.prompt([{ + type: 'input', + name: 'input', + message: 'Data is correct, you will insert '+ String(totalCC) +" carbon credits y | n:", + }]); + if (input == 'y') { + carbonCredit.issueDate = moment(carbonCredit.issueDate + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); + carbonCredit.cancelDate = moment(carbonCredit.cancelDate + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); + carbonCredit.ccVintageStart = moment(carbonCredit.ccVintageStart + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); + carbonCredit.ccVintageEnd = moment(carbonCredit.ccVintageEnd + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); + carbonCredit.CCID = await hashSortCoerce.hash(carbonCredit); + const hash = await db.put(carbonCredit); + console.log(`Successful insertion, CCID: ${carbonCredit.CCID}, hash: ${hash}.`); + for(var i=parseInt(serialFloor)+1; i<=serialTop; i++){ + var tempCarbonCredit = {...carbonCredit}; + tempCarbonCredit.SerialNo= await asyncCCSerialNo(serialNoPart,i) + tempCarbonCredit.CCID = await hashSortCoerce.hash(tempCarbonCredit); + const hash = await db.put(tempCarbonCredit); + console.log(`Successful insertion, CCID: ${tempCarbonCredit.CCID}, hash: ${hash}.`); + } + console.log(`Inserted ${totalCC} carbon credits.`); + break; + } else { + console.clear(); + console.log('Insertion aborted'); + break; + } + } catch(e) { + console.log(e.message); } } else { @@ -182,12 +187,14 @@ const main = async () => { if (input == '') console.log('Input mustn\'t be empty'); else if (insertMenu == 'issueDate' || insertMenu == 'cancelDate' || insertMenu == 'ccVintageStart' || insertMenu == 'ccVintageEnd') { const date = moment.utc(input + ' +0000', 'DD-MM-YYYY HH:mm'); - if (date.isValid() && insertMenu == 'cancelDate' && moment() >= date && date >= moment().subtract(10, 'days')) { - carbonCredit[insertMenu] = date.format('DD-MM-YYYY HH:mm Z'); - } - else if (date.isValid() && insertMenu != 'cancelDate' && moment() >= date) { - carbonCredit[insertMenu] = date.format('DD-MM-YYYY HH:mm Z'); - } else console.log(' Date must follow next syntax: dd-mm-yyyy hh-mm and cancel date must be 10 days old at most'); + if(date.isValid() && moment() >= date) { + if(insertMenu != 'cancelDate') carbonCredit[insertMenu] = date.format('DD-MM-YYYY HH:mm Z'); + else if((date >= moment().subtract(3, 'months') && process.env.API_MODE == 'dev') || + (date >= moment().subtract(1, 'year') && process.env.API_MODE == 'startup') || + (date >= moment().subtract(7, 'year') && process.env.API_MODE == 'grow')) { + carbonCredit[insertMenu] = date.format('DD-MM-YYYY HH:mm Z'); + } else console.error(' Date is too old to get pricing data'); + } else console.error(' Date must follow next syntax: dd-mm-yyyy hh-mm and can\'t be in the future'); } else if (insertMenu == 'qty') { if (parseFloat(input)) carbonCredit.cancelPrice[insertMenu] = input; From 9fe97b99cb6d7ea0d78adfffac9e66c705ea1a10 Mon Sep 17 00:00:00 2001 From: "David E. Perez Negron Rocha" Date: Tue, 9 Jun 2020 00:23:53 -0500 Subject: [PATCH 2/9] Adding receipts pinner and downloader script --- .gitignore | 3 ++- receipts.sh | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100755 receipts.sh diff --git a/.gitignore b/.gitignore index 41ece8f..486ea91 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /node_modules /orbitdb +/receipts package-lock.json -.env \ No newline at end of file +.env diff --git a/receipts.sh b/receipts.sh new file mode 100755 index 0000000..195ff6a --- /dev/null +++ b/receipts.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +./connectNodes.sh + +# Receipts and Files to PIN +FilesHashList=("QmYw6JTNABDDfXvc3U2BfURjF5Zzx9eG3N43wJqHc4upDL" ) # \ + #"" \ + #"" \) +echo "" +echo "IPFS PIN DECA's Carbon Credits Receipts?:" + +read -p "Enter Y for Yes, N for No:" choice +case "$choice" in + Y | y) echo "Pinning Receipts by IPFS hash"; + for val in ${FilesHashList[*]}; do + /usr/local/bin/ipfs pin add $val + done + ;; + N | n) ;; + + *) echo "no option selected";; +esac + +receiptsRoute=./receipts +echo "" +echo "IPFS GET(Download) DECA's Carbon Credits Receipts?:" + +read -p "Enter Y for Yes, N for No:" choice +case "$choice" in + Y | y) echo "Getting Receipts by IPFS hash"; + echo "Default receipts file is ./receipts..." + mkdir $receiptsRoute + for val in ${FilesHashList[*]}; do + /usr/local/bin/ipfs get $val -o $receiptsRoute + done + ;; + N | n) ;; + + *) echo "no option selected";; +esac + +echo "Bye ;) $USERNAME" From 50a77fdeb0c815ca2f30707d9f14f3891ffa242f Mon Sep 17 00:00:00 2001 From: Oscar Martinez Date: Thu, 11 Jun 2020 17:47:59 -0500 Subject: [PATCH 3/9] Feature finished --- .envSample | 3 +++ divisaTraceback.js | 67 +++++++++++++++++++++------------------------- interfaz.js | 19 ++++++------- 3 files changed, 43 insertions(+), 46 deletions(-) diff --git a/.envSample b/.envSample index e69de29..993b684 100644 --- a/.envSample +++ b/.envSample @@ -0,0 +1,3 @@ +APIKEY= +API_MODE= +# Available modes: dev, startup, grow \ No newline at end of file diff --git a/divisaTraceback.js b/divisaTraceback.js index a2b452c..2fa2b09 100644 --- a/divisaTraceback.js +++ b/divisaTraceback.js @@ -1,4 +1,5 @@ -let moment = require('moment'); +const moment = require('moment'); +const request = require('request-promise'); require('dotenv').config(); // Source: https://apiv2.bitcoinaverage.com/ @@ -6,33 +7,27 @@ require('dotenv').config(); const divisaTraceback = async(timestamp, divisa, amount) => { let crypto = ['BTC', 'ETH', 'LTC'] let normal = ['USD', 'GBP', 'CNY', 'EUR']; - try { - if((Date.now() - 7776000000) <= (timestamp * 1000)) { - if(crypto.includes(divisa) || normal.includes(divisa)) { - if(amount >= 0) { - let divisaTraceback = {}; - let resolution = await getResolution(timestamp); + if(amount > 0) { + let divisaTraceback = {}; + let resolution = await getResolution(timestamp); + if(crypto.includes(divisa)) { + divisaTraceback[crypto.splice(crypto.indexOf(divisa), 1)[0]] = Number(amount); + Object.assign(divisaTraceback, await requestIteration(normal, divisa, true, timestamp, amount, resolution)); + Object.assign(divisaTraceback, await requestIteration(crypto, 'USD', false, timestamp, divisaTraceback['USD'], resolution)); + } + else if (normal.includes(divisa)) { + divisaTraceback[normal.splice(normal.indexOf(divisa), 1)[0]] = Number(amount); + Object.assign(divisaTraceback, await requestIteration(crypto, divisa, false, timestamp, amount, resolution)); + Object.assign(divisaTraceback, await requestIteration(normal, 'BTC', true, timestamp, divisaTraceback['BTC'], resolution)); + } else throw new Error('Currency target invalid'); - if(crypto.includes(divisa)) { - divisaTraceback[crypto.splice(crypto.indexOf(divisa), 1)[0]] = Number(amount); - Object.assign(divisaTraceback, await requestIteration(normal, divisa, true, timestamp, amount, resolution)); - Object.assign(divisaTraceback, await requestIteration(crypto, 'USD', false, timestamp, divisaTraceback['USD'], resolution)); - } - else { - divisaTraceback[normal.splice(normal.indexOf(divisa), 1)[0]] = Number(amount); - Object.assign(divisaTraceback, await requestIteration(crypto, divisa, false, timestamp, amount, resolution)); - Object.assign(divisaTraceback, await requestIteration(normal, 'BTC', true, timestamp, divisaTraceback['BTC'], resolution)); - } - return(divisaTraceback); - } else return('The amount must be 1 or higher'); - } else return('Currency target invalid'); - } else return('Date out of range') - } catch(e) { - throw 'error'; - } + console.log(` Resolution: ${resolution}`); + return(divisaTraceback); + } else throw new Error('The amount must be 0 or higher'); }; const requestIteration = async(set, divisa, flag, timestamp, amount, resolution) => { + timestamp = timestamp.format('X'); let opt = { method: 'GET', json: true, @@ -44,12 +39,14 @@ const requestIteration = async(set, divisa, flag, timestamp, amount, resolution) for (element in set) { if(flag) { opt.uri = `https://apiv2.bitcoinaverage.com/indices/global/history/${divisa}${set[element]}?at=${timestamp}&resolution=${resolution}`; - let { average } = await request(opt); + let { average, time } = await request(opt); + if(res.time === undefined) res.time = moment.utc(time, 'YYYY-MM-DD HH:mm:ss').format('DD-MM-YYYY HH:mm Z'); res[set[element]] = average * amount; } else { opt.uri = `https://apiv2.bitcoinaverage.com/indices/global/history/${set[element]}${divisa}?at=${timestamp}&resolution=${resolution}`; - let { average } = await request(opt); + let { average, time } = await request(opt); + if(res.time === undefined) res.time = moment.utc(time, 'YYYY-MM-DD HH:mm:ss').format('DD-MM-YYYY HH:mm Z'); res[set[element]] = amount / average; } } @@ -58,17 +55,13 @@ const requestIteration = async(set, divisa, flag, timestamp, amount, resolution) const getResolution = async(timestamp) => { let resolution = 'day'; - let momentTime = moment(timestamp); - if(process.env.API_MODE == 'dev') { - if(momentTime >= moment().subtract(2, 'hours')) resolution = 'minute'; - else if(momentTime >= moment().subtract(10, 'days')) resolution = 'hour'; - - } else if(process.env.API_MODE == 'startup' || process.env.API_MODE == 'grow') { - if(momentTime >= moment().subtract(24, 'hours')) resolution = 'minute'; - else if(momentTime >= moment().subtract(31, 'days')) resolution = 'hour'; - - } else throw new Error('Bad config'); - + if(process.env.APIMODE == 'dev') { + if(timestamp >= moment.utc().subtract(2, 'hours')) resolution = 'minute'; + else if(timestamp >= moment().subtract(10, 'days')) resolution = 'hour'; + } else if(process.env.APIMODE == 'startup' || process.env.APIMODE == 'grow') { + if(timestamp >= moment.utc().subtract(24, 'hours')) resolution = 'minute'; + else if(timestamp >= moment.utc().subtract(31, 'days')) resolution = 'hour'; + } else throw new Error('Bad config at .env file'); return resolution; } diff --git a/interfaz.js b/interfaz.js index 8e43eeb..b4ff2c8 100644 --- a/interfaz.js +++ b/interfaz.js @@ -91,7 +91,7 @@ const main = async () => { } while (true) { await init(); - //console.clear(); + console.clear(); console.log('Select one to modify the field.\n'); let carbonCreditMenu = await generateData(carbonCredit, 0); let { insertMenu } = await inquirer.prompt([{ @@ -113,7 +113,7 @@ const main = async () => { if (await validateInsertion(carbonCredit)) { try{ carbonCredit.conversionPrice = await divisaTraceback( - moment.utc(carbonCredit.cancelDate + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(), + moment.utc(carbonCredit.cancelDate, 'DD-MM-YYYY HH:mm Z'), carbonCredit.cancelPrice.divisa, carbonCredit.cancelPrice.qty ); @@ -148,10 +148,10 @@ const main = async () => { } else { console.clear(); console.log('Insertion aborted'); - break; + continue; } } catch(e) { - console.log(e.message); + console.log(`Error at divisaTraceback: ${e.message}`); } } else { @@ -187,11 +187,12 @@ const main = async () => { if (input == '') console.log('Input mustn\'t be empty'); else if (insertMenu == 'issueDate' || insertMenu == 'cancelDate' || insertMenu == 'ccVintageStart' || insertMenu == 'ccVintageEnd') { const date = moment.utc(input + ' +0000', 'DD-MM-YYYY HH:mm'); - if(date.isValid() && moment() >= date) { + console.log(date); + if(date.isValid() && moment.utc() >= date) { if(insertMenu != 'cancelDate') carbonCredit[insertMenu] = date.format('DD-MM-YYYY HH:mm Z'); - else if((date >= moment().subtract(3, 'months') && process.env.API_MODE == 'dev') || - (date >= moment().subtract(1, 'year') && process.env.API_MODE == 'startup') || - (date >= moment().subtract(7, 'year') && process.env.API_MODE == 'grow')) { + else if((date >= moment.utc().subtract(3, 'months') && process.env.APIMODE == 'dev') || + (date >= moment.utc().subtract(1, 'year') && process.env.APIMODE == 'startup') || + (date >= moment.utc().subtract(7, 'year') && process.env.APIMODE == 'grow')) { carbonCredit[insertMenu] = date.format('DD-MM-YYYY HH:mm Z'); } else console.error(' Date is too old to get pricing data'); } else console.error(' Date must follow next syntax: dd-mm-yyyy hh-mm and can\'t be in the future'); @@ -529,7 +530,7 @@ const generateData = async (data, n) => { menu.push({ name: element, disabled: ' ' }); menu = menu.concat(await generateData(data[element], n + 1)); } else { - let space = ' '.repeat(20 - element.length); + let space = ' '.repeat(25 - element.length); space = space.substring(0, space.length - tab.length); menu.push(`${tab}${element}${space}${data[element]}`); } From e70994e89d58c2195ca47b8c69ec8de296e3278c Mon Sep 17 00:00:00 2001 From: "David E. Perez Negron Rocha" Date: Fri, 12 Jun 2020 00:26:29 -0500 Subject: [PATCH 4/9] Fix for a diferent directories for Proyect Receipts, so that Receipts is for DECAs Distributed Database --- .gitignore | 1 + receipts.sh | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 486ea91..9499476 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /node_modules /orbitdb /receipts +/proyectsReceipts package-lock.json .env diff --git a/receipts.sh b/receipts.sh index 195ff6a..63c16f2 100755 --- a/receipts.sh +++ b/receipts.sh @@ -21,7 +21,7 @@ case "$choice" in *) echo "no option selected";; esac -receiptsRoute=./receipts +receiptsRoute=./proyectsReceipts echo "" echo "IPFS GET(Download) DECA's Carbon Credits Receipts?:" @@ -40,3 +40,4 @@ case "$choice" in esac echo "Bye ;) $USERNAME" + From ea4518052391c36bdc7b9e51dc400bda04f2a6c2 Mon Sep 17 00:00:00 2001 From: "David E. Perez Negron Rocha" Date: Fri, 12 Jun 2020 16:30:25 -0500 Subject: [PATCH 5/9] Adding official DECA OrbitDB Database --- index.js | 4 ++-- interfaz.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index eb18fc2..55a0817 100644 --- a/index.js +++ b/index.js @@ -3,7 +3,7 @@ const IpfsClient = require('ipfs-http-client'); const OrbitDB = require('orbit-db'); //Instance of ipfs locally in ipfs daemon const node = IpfsClient('http://localhost:5001'); -const addressDB = 'decaCCDB'; +const addressDB = '/orbitdb/zdpuAykPJ4qtBg2toS2vxr5eaPfGEBJmvGerM7V7x8qn5c8hW/decaCCDB'; //Async function to replicate or create a doc database async function createReplicate() { @@ -39,4 +39,4 @@ async function createReplicate() { } //Call the async function -createReplicate(); \ No newline at end of file +createReplicate(); diff --git a/interfaz.js b/interfaz.js index b4ff2c8..53c2a14 100644 --- a/interfaz.js +++ b/interfaz.js @@ -6,7 +6,7 @@ let moment = require('moment'); let hasher = require('node-object-hash') const fs = require('fs'); -const addressDB = 'decaCCDB'; +const addressDB = '/orbitdb/zdpuAykPJ4qtBg2toS2vxr5eaPfGEBJmvGerM7V7x8qn5c8hW/decaCCDB'; //A instance of ipfs locally in ipfs daemon const ipfs = IpfsClient('http://localhost:5001'); From 6d3d537d0dad5f7668e066334108bd3eb363038b Mon Sep 17 00:00:00 2001 From: Oscar Martinez Date: Fri, 12 Jun 2020 17:10:54 -0500 Subject: [PATCH 6/9] Feature finished --- divisaTraceback.js | 2 - interfaz.js | 98 +++++++++++++++++++++++++++++++++------------- 2 files changed, 71 insertions(+), 29 deletions(-) diff --git a/divisaTraceback.js b/divisaTraceback.js index 2fa2b09..f21c7db 100644 --- a/divisaTraceback.js +++ b/divisaTraceback.js @@ -40,13 +40,11 @@ const requestIteration = async(set, divisa, flag, timestamp, amount, resolution) if(flag) { opt.uri = `https://apiv2.bitcoinaverage.com/indices/global/history/${divisa}${set[element]}?at=${timestamp}&resolution=${resolution}`; let { average, time } = await request(opt); - if(res.time === undefined) res.time = moment.utc(time, 'YYYY-MM-DD HH:mm:ss').format('DD-MM-YYYY HH:mm Z'); res[set[element]] = average * amount; } else { opt.uri = `https://apiv2.bitcoinaverage.com/indices/global/history/${set[element]}${divisa}?at=${timestamp}&resolution=${resolution}`; let { average, time } = await request(opt); - if(res.time === undefined) res.time = moment.utc(time, 'YYYY-MM-DD HH:mm:ss').format('DD-MM-YYYY HH:mm Z'); res[set[element]] = amount / average; } } diff --git a/interfaz.js b/interfaz.js index b4ff2c8..31f82b1 100644 --- a/interfaz.js +++ b/interfaz.js @@ -5,6 +5,7 @@ let inquirer = require('inquirer'); let moment = require('moment'); let hasher = require('node-object-hash') const fs = require('fs'); +const path = require('path'); const addressDB = 'decaCCDB'; @@ -17,6 +18,9 @@ const hashSortCoerce = hasher({ sort: true, coerce: true }); //Function to start application const main = async () => { + if (!fs.existsSync('./receipts')){ + fs.mkdirSync('./receipts'); + } const orbitdb = await OrbitDB.createInstance(ipfs) const db = await orbitdb.docs(addressDB, { indexBy: 'CCID' }); await db.load(); @@ -36,8 +40,10 @@ const main = async () => { }]); if (mainMenu == 'Show carbon credit records') { let data = db.get(''); + console.log(` ${data.length} records found`); while (true) { - let { showMenu } = await inquirer.prompt([{ + const fileName = moment.utc().format(); + let { showMenu } = await inquirer.prompt({ type: 'list', name: 'showMenu', message: 'Select an option', @@ -45,24 +51,33 @@ const main = async () => { 'Show in terminal', 'Save as JSON', 'Save as CSV', + 'Save as TXT', 'Back to main menu' ] - }]); + }); if (showMenu == 'Show in terminal') { for (element in data) { showData(data[element], 0); console.log('-------------------------------------\n'); } } else if (showMenu == 'Save as JSON') { - fs.writeFileSync(`/tmp/${moment().format()}.json`, JSON.stringify(data)); - console.log(`File saved in /tmp/${moment().format()}.json`); + fs.writeFileSync(path.resolve('receipts', `${fileName}.json`), JSON.stringify(data)); + console.log(`File saved in ${path.resolve('receipts', fileName + '.json')}`); } else if (showMenu == 'Save as CSV') { - let csv = ''; - for (element in data) csv += await JSONToCSV(data[element]); - fs.writeFileSync(`/tmp/${moment().format()}.csv`, csv); - console.log(`File saved in /tmp/${moment().format()}.csv`); - } - else if (showMenu == 'Back to main menu') { + let csv = await JSONToCSV(data); + fs.writeFileSync(path.resolve('receipts', `${fileName}.csv`), csv); + console.log(`File saved in ${path.resolve('receipts', fileName + '.csv')}`); + } else if (showMenu == 'Save as TXT') { + let stream = fs.createWriteStream(path.resolve('receipts', `${fileName}.txt`)); + let result = await elemInsert(data); + stream.once('open', function (fd) { + for (let i = 0; i < result.length; i++) { + stream.write(result[i] + '\n'); + } + stream.end(); + }); + console.log(`File saved in ${path.resolve('receipts', fileName + '.txt')}`); + } else if (showMenu == 'Back to main menu') { break; } } @@ -91,7 +106,7 @@ const main = async () => { } while (true) { await init(); - console.clear(); + //console.clear(); console.log('Select one to modify the field.\n'); let carbonCreditMenu = await generateData(carbonCredit, 0); let { insertMenu } = await inquirer.prompt([{ @@ -122,7 +137,7 @@ const main = async () => { serialNoPart=carbonCredit.SerialNo.split('-'); serialFloor=serialNoPart[7]; serialTop=serialNoPart[8]; - var totalCC = 1+parseInt(serialTop)-parseInt(serialFloor); + let totalCC = 1+parseInt(serialTop)-parseInt(serialFloor); let { input } = await inquirer.prompt([{ type: 'input', name: 'input', @@ -132,18 +147,25 @@ const main = async () => { carbonCredit.issueDate = moment(carbonCredit.issueDate + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); carbonCredit.cancelDate = moment(carbonCredit.cancelDate + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); carbonCredit.ccVintageStart = moment(carbonCredit.ccVintageStart + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); - carbonCredit.ccVintageEnd = moment(carbonCredit.ccVintageEnd + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); - carbonCredit.CCID = await hashSortCoerce.hash(carbonCredit); - const hash = await db.put(carbonCredit); - console.log(`Successful insertion, CCID: ${carbonCredit.CCID}, hash: ${hash}.`); - for(var i=parseInt(serialFloor)+1; i<=serialTop; i++){ - var tempCarbonCredit = {...carbonCredit}; - tempCarbonCredit.SerialNo= await asyncCCSerialNo(serialNoPart,i) + carbonCredit.ccVintageEnd = moment(carbonCredit.ccVintageEnd + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); + const fileName = moment().format(); + let stream = fs.createWriteStream(path.resolve('receipts', fileName + '.txt')); + stream.once('open', async function (fd) { + carbonCredit.CCID = await hashSortCoerce.hash(carbonCredit); + const hash = await db.put(carbonCredit); + stream.write('CCID: ' + carbonCredit.CCID + ' SerialNo: ' + carbonCredit.SerialNo + '\n'); + for (let i = parseInt(serialFloor) + 1; i <= serialTop; i++) { + let tempCarbonCredit = { + ...carbonCredit + }; + tempCarbonCredit.SerialNo = await asyncCCSerialNo(serialNoPart, i) tempCarbonCredit.CCID = await hashSortCoerce.hash(tempCarbonCredit); const hash = await db.put(tempCarbonCredit); - console.log(`Successful insertion, CCID: ${tempCarbonCredit.CCID}, hash: ${hash}.`); - } + } + stream.end(); + }); console.log(`Inserted ${totalCC} carbon credits.`); + console.log(`Receipts saved in ${path.resolve('receipts', fileName + '.txt')}`); break; } else { console.clear(); @@ -522,6 +544,14 @@ const elemSearch = async (objectSearch) => { return elems; } +const elemInsert = async (objectShow) => { + let elems = []; + for (let key in objectShow) { + elems.push('CCID: ' + objectShow[key]['CCID'] + ' SerialNumber: ' + objectShow[key]['SerialNo']); + } + return elems; +} + const generateData = async (data, n) => { let menu = []; let tab = ' '.repeat(n); @@ -583,14 +613,28 @@ const showErrorData = async (data) => { //Parse json to csv const JSONToCSV = async (data, n) => { - let csv = ''; - for (element in data) { - if (typeof (data[element]) == 'object') { - validateInsertion(data[element]); + let csv; + for (element in data[0]) { + console.log(typeof(data[0][element])); + console.log(data[0][element]); + if (typeof data[0][element] == 'object') { + console.log('Entro aqui') + for(subelement in data[0][element]) csv += `${element} - ${subelement}, `; } - else csv += `${data[element]}, ` + else csv += `${element}, `; + } + csv = csv.slice(0, -2); + csv += '\n'; + for(record in data) { + for (element in data[record]) { + if (typeof data[record][element] == 'object') { + for(subelement in data[0][element]) csv += `${data[record][element][subelement]}, `; + } + else csv += `${data[record][element]}, `; + } + csv = csv.slice(0, -2); + csv += '\n'; } - if (n == 0) csv += '\n'; return csv; } From f5c2fd70f05da4c26c54d35856c7737c2836b93f Mon Sep 17 00:00:00 2001 From: p1r0 Date: Sat, 13 Jun 2020 02:11:52 +0000 Subject: [PATCH 7/9] Update README.md, fixed carbon credit structure and Pinning section --- README.md | 91 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index b0936a6..59e6c95 100644 --- a/README.md +++ b/README.md @@ -15,39 +15,40 @@ DECA's Carbon Credits OrbitDB Code and configs, everything you need for setting ## Carbon Credit Structure ```sh -{ /* CC - Carbon credits Unix Time is date and time based in the UTC 0 example for the first carbon credit that is 1365209 */ - SerialNo: 'GS1-1-MX-GS2441-16-2018-17438-328-328', - CCAddress: 'https://registry.goldstandard.org/credit-blocks/details/107995', //Address GS Registry - issueDate: 1552953600, // CC creation UnixTime - cancelDate: 1587214800, // CC cancelation cancelation UnixTime - ccVintageStart: 1514764800, // CC what year it was created in UnixTime - ccVintageEnd: 1514764800, // CC what year it was created in UnixTime - ccCategory: 'Energy Efficiency - Domestic', // CC category agricultural - ccMeasurement: 'VER(TCO2e)', //CC Measurement - ccStandard: 'GS', // CC standard Woodland Carbon Credit - countryCode: 'MX' // Country code - ccProjectID: 'GS2441', // CC project ID in the original backlog is it unique? - ccID: 17438-328-328, - CCAdquisitionRecipt: 'QmWWQSuPMS6aXCbZKpEjPHPUZN2NjB3YrhJTHsV4X3vb2t', //Recipt of CC in IPFS - cancelPrice: { - qty: 19.50, - divisa : 'USD'}, - conversionPrice:{ - USD: 19.50, - EUR: 17.93, - CNY: 137.93, - BTC: 0.0027, - LTC: 0.45, - ETH: 0.11, - }, - cancelRemaks: 'Cancel by account 1067262', -} - +[ + { + //CCID: unique Carbon Credit Hash in DECAs registry (used as receipt and control) + CCID: 'a67178fa3cb20e49f748050871f4f10784693bde1b9ec805740ff9c63b93860d', + SerialNo: 'GS1-1-MX-GS2441-16-2018-17438-328-328', + ccAddress: 'https://registry.goldstandard.org/credit-blocks/details/107995', //Address GS Registry + issueDate: 1552953600, // CC creation UnixTime + cancelDate: 1587168000, // CC cancelation cancelation UnixTime + ccCategory: 'Energy Efficiency - Domestic', // CC category agricultural + ccStandard: 'GS', // CC standard GoldStandard Carbon Credit + cancelPrice: { qty: '19.5', divisa: 'USD' }, + ccProjectID: 'GS2441', // CC project ID in the original backlog + countryCode: 'MX', // Country code + cancelRemaks: 'Cancel by account 1067262', + ccVintageEnd: 1546214400, // CC what end date it was created in UnixTime + ccMeasurement: 'VER(TCO2e)', //CC Measurement + ccVintageStart: 1514764800, // CC what date year it was created in UnixTime + conversionPrice: { + BTC: 0.0027239430402556876, + CNY: 137.92740063195478, + ETH: 0.10952545708624091, + EUR: 17.93351483640976, + GBP: 15.588145399888809, + LTC: 0.45310691929120134, + USD: 19.5 + }, + CCAdquisitionRecipt: 'QmYw6JTNABDDfXvc3U2BfURjF5Zzx9eG3N43wJqHc4upDL' //Recipt of CC in IPFS + } +] ``` ## Requirements @@ -281,3 +282,37 @@ WantedBy=multi-user.target ``` **NOTE: service must be set as active (running), if not please verify the preview steps** +# IPFS pin projects receipts + +**You can help us by pinning DECA's project receipts into IPFS which will give deeper trust to DECA.** + +We have a script in order to pin (replicate into your node) the projects receipts that DECA got, so that +any one can have a proof that we bought this receipts as public information. Also you can store a copy of this receipts which will be added by IPFS hash into this script. + +> run the IPFS pin script + +```sh + $ /receipts.sh +connect Qmd4Cv2fNwixP6cabEnTVFkF57GUGD6VBEcDhUkqHPG4X9 success +connect QmfBASmqe3Az9AUjCxx3dtomSmbZEiJCsXusPxznjNnjU5 success +connect QmQBAsbA49q7QrKhetJpbo5gKxQQiL6sxVXCep5skmuHsq success +connect QmZL1otpiCzWMEJTHXbQ5Hb4aFE7TKLjAuuBAAet1WAgtD success + +IPFS PIN DECA's Carbon Credits Receipts?: +Enter Y for Yes, N for No:Y +Pinning Receipts by IPFS hash +pinned QmYw6JTNABDDfXvc3U2BfURjF5Zzx9eG3N43wJqHc4upDL recursively + +IPFS GET(Download) DECA's Carbon Credits Receipts?: +Enter Y for Yes, N for No:Y +Getting Receipts by IPFS hash +Default receipts file is ./receipts... +Saving file(s) to ./proyectsReceipts + 135.34 KiB / 135.34 KiB [======================================================================================================================================] 100.00% 0s +Bye ;) + +$ ls proyectsReceipts +QmYw6JTNABDDfXvc3U2BfURjF5Zzx9eG3N43wJqHc4upDL +``` + +As you can see in the above example we pin the receipt by running " ./receipts.sh ", also we Download this receipt with should be allocated in the directory projects Receipts. From 902f2eb42860cf4fbf3a326d1945aff22b813542 Mon Sep 17 00:00:00 2001 From: Oscar Martinez Date: Mon, 15 Jun 2020 20:02:19 -0500 Subject: [PATCH 8/9] Fix date validation in startup and grow api plans --- .gitignore | 1 + interfaz.js | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 9499476..770c2df 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /proyectsReceipts package-lock.json .env +.directory diff --git a/interfaz.js b/interfaz.js index 33ff1d4..3f767eb 100644 --- a/interfaz.js +++ b/interfaz.js @@ -7,7 +7,7 @@ let hasher = require('node-object-hash') const fs = require('fs'); const path = require('path'); -const addressDB = '/orbitdb/zdpuAykPJ4qtBg2toS2vxr5eaPfGEBJmvGerM7V7x8qn5c8hW/decaCCDB'; +const addressDB = 'decaCCDB'; //A instance of ipfs locally in ipfs daemon const ipfs = IpfsClient('http://localhost:5001'); @@ -213,8 +213,8 @@ const main = async () => { if(date.isValid() && moment.utc() >= date) { if(insertMenu != 'cancelDate') carbonCredit[insertMenu] = date.format('DD-MM-YYYY HH:mm Z'); else if((date >= moment.utc().subtract(3, 'months') && process.env.APIMODE == 'dev') || - (date >= moment.utc().subtract(1, 'year') && process.env.APIMODE == 'startup') || - (date >= moment.utc().subtract(7, 'year') && process.env.APIMODE == 'grow')) { + (date >= moment.utc().subtract(1, 'years') && process.env.APIMODE == 'startup') || + (date >= moment.utc().subtract(7, 'years') && process.env.APIMODE == 'grow')) { carbonCredit[insertMenu] = date.format('DD-MM-YYYY HH:mm Z'); } else console.error(' Date is too old to get pricing data'); } else console.error(' Date must follow next syntax: dd-mm-yyyy hh-mm and can\'t be in the future'); From 8aed24d2efe4b50dac78f6d80fd8f6d932a991b9 Mon Sep 17 00:00:00 2001 From: Oscar Martinez Date: Tue, 16 Jun 2020 23:05:07 -0500 Subject: [PATCH 9/9] Feature finished --- .envSample | 2 +- interfaz.js | 77 ++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/.envSample b/.envSample index 993b684..ab62bc9 100644 --- a/.envSample +++ b/.envSample @@ -1,3 +1,3 @@ APIKEY= -API_MODE= +APIMODE= # Available modes: dev, startup, grow \ No newline at end of file diff --git a/interfaz.js b/interfaz.js index 3f767eb..92b0c72 100644 --- a/interfaz.js +++ b/interfaz.js @@ -57,7 +57,7 @@ const main = async () => { }); if (showMenu == 'Show in terminal') { for (element in data) { - showData(data[element], 0); + showData(data[element]); console.log('-------------------------------------\n'); } } else if (showMenu == 'Save as JSON') { @@ -133,7 +133,7 @@ const main = async () => { carbonCredit.cancelPrice.qty ); if(carbonCredit.conversionPrice === 'error') throw new Error('Error at getting currencies price.'); - showData(carbonCredit, 0); + showData(carbonCredit); serialNoPart=carbonCredit.SerialNo.split('-'); serialFloor=serialNoPart[7]; serialTop=serialNoPart[8]; @@ -148,12 +148,12 @@ const main = async () => { carbonCredit.cancelDate = moment(carbonCredit.cancelDate + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); carbonCredit.ccVintageStart = moment(carbonCredit.ccVintageStart + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); carbonCredit.ccVintageEnd = moment(carbonCredit.ccVintageEnd + ' +0000', 'DD-MM-YYYY HH:mm Z').unix(); - const fileName = moment().format(); + const fileName = moment.utc().format(); let stream = fs.createWriteStream(path.resolve('receipts', fileName + '.txt')); stream.once('open', async function (fd) { carbonCredit.CCID = await hashSortCoerce.hash(carbonCredit); const hash = await db.put(carbonCredit); - stream.write('CCID: ' + carbonCredit.CCID + ' SerialNo: ' + carbonCredit.SerialNo + '\n'); + stream.write(`CCID: ${carbonCredit.CCID} SerialNo: ${carbonCredit.SerialNo} \n`); for (let i = parseInt(serialFloor) + 1; i <= serialTop; i++) { let tempCarbonCredit = { ...carbonCredit @@ -161,6 +161,7 @@ const main = async () => { tempCarbonCredit.SerialNo = await asyncCCSerialNo(serialNoPart, i) tempCarbonCredit.CCID = await hashSortCoerce.hash(tempCarbonCredit); const hash = await db.put(tempCarbonCredit); + stream.write(`CCID: ${tempCarbonCredit.CCID} SerialNo: ${tempCarbonCredit.SerialNo} \n`); } stream.end(); }); @@ -234,11 +235,13 @@ const main = async () => { else if (mainMenu == 'Search carbon credits') { let { searchMenu } = await inquirer.prompt([{ type: 'list', + pageSize: 24, name: 'searchMenu', message: 'Search carbon credit by:', choices: [ 'Category', 'CCID', + 'SerialNo', 'Standard', 'Project Id', 'Vintage Date', @@ -267,8 +270,12 @@ const main = async () => { message: 'Select CCID', choices: choicesSearch }]).then(answer => { - console.log(db.get(answer.CCID)) - }) + let query = db.get(answer.CCID); + for (element in query) { + showData(query[element]); + console.log('-------------------------------------\n'); + } + }); } else { console.clear(); console.log("No registries found") @@ -278,6 +285,28 @@ const main = async () => { console.log('Search canceled'); } } + else if (searchMenu == 'SerialNo') { + let { input } = await inquirer.prompt([{ + type: 'input', + name: 'input', + message: 'SerialNo: ', + }]); + let { confirm } = await inquirer.prompt([{ + type: 'input', + name: 'confirm', + message: 'Confirm y | n: ', + }]); + if (confirm == 'y') { + const data = db.query((doc) => doc.SerialNo == input); + for (element in data) { + showData(data[element]); + console.log('-------------------------------------\n'); + } + } else { + console.clear(); + console.log('Search canceled'); + } + } else if (searchMenu == 'CCID') { let { input } = await inquirer.prompt([{ type: 'input', @@ -290,7 +319,8 @@ const main = async () => { message: 'Confirm y | n: ', }]); if (confirm == 'y') { - console.log(db.get(input)) + showData(db.get(input)[0]); + console.log('-------------------------------------\n'); } else { console.clear(); console.log('Search canceled'); @@ -317,7 +347,11 @@ const main = async () => { message: 'Select CCID', choices: choicesSearch }]).then(answer => { - console.log(db.get(answer.CCID)) + let query = db.get(answer.CCID); + for (element in query) { + showData(query[element]); + console.log('-------------------------------------\n'); + } }) } else { console.clear(); @@ -349,7 +383,11 @@ const main = async () => { message: 'Select CCID', choices: choicesSearch }]).then(answer => { - console.log(db.get(answer.CCID)) + let query = db.get(answer.CCID); + for (element in query) { + showData(query[element]); + console.log('-------------------------------------\n'); + } }) } else { console.clear(); @@ -363,6 +401,7 @@ const main = async () => { else if (searchMenu == 'Vintage Date') { let { vintageMenu } = await inquirer.prompt([{ type: 'list', + pageSize: 24, name: 'vintageMenu', message: 'Search carbon credit by:', choices: [ @@ -394,7 +433,11 @@ const main = async () => { message: 'Select CCID', choices: choicesSearch }]).then(answer => { - console.log(db.get(answer.CCID)) + let query = db.get(answer.CCID); + for (element in query) { + showData(query[element]); + console.log('-------------------------------------\n'); + } }) } else { console.clear(); @@ -427,7 +470,11 @@ const main = async () => { message: 'Select CCID', choices: choicesSearch }]).then(answer => { - console.log(db.get(answer.CCID)) + let query = db.get(answer.CCID); + for (element in query) { + showData(query[element]); + console.log('-------------------------------------\n'); + } }) } else { console.clear(); @@ -463,7 +510,11 @@ const main = async () => { message: 'Select CCID', choices: choicesSearch }]).then(answer => { - console.log(db.get(answer.CCID)) + let query = db.get(answer.CCID); + for (element in query) { + showData(query[element]); + console.log('-------------------------------------\n'); + } }) } else { console.clear(); @@ -574,7 +625,7 @@ const asyncCCSerialNo = async (serialNoPart, index) => { } //Show carbon credit data -const showData = async (data, n) => { +const showData = async (data, n = 0) => { for (element in data) { for (let i = 0; i < n; i++) process.stdout.write('\t'); if (typeof (data[element]) == 'object') {