I have a project where I have a database (db.xml) with next structure:
<TVGuide xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="./schema.xsd">
<Shows>
<Show>
<ShowId>1</ShowId>
<Name>Game of Thrones</Name>
<Genre>Fantasy, Drama, Adventure</Genre>
<IMDBRating>9.3</IMDBRating>
<Seasons>8</Seasons>
<Awards>
<Award>
<Title>Outstanding Drama Series </Title>
<Year>2015, 2016, 2018 </Year>
</Award>
<Award>
<Title>Best Television Series - Drama </Title>
<Year>2018</Year>
</Award>
</Awards>
<Cast>
<Actor>
<Name>Peter Dinklage</Name>
<Role>Tyrion Lannister</Role>
<DOB>June 11, 1969</DOB>
<Nationality>American</Nationality>
<PlayedCharacterRole>Main</PlayedCharacterRole>
</Actor>
<Actor>
<Name>Emilia Clarke</Name>
<Role>Daenerys Targaryen</Role>
<DOB>October 23, 1986</DOB>
<Nationality>British</Nationality>
<PlayedCharacterRole>Main</PlayedCharacterRole>
</Actor>
<Actor>
<Name>Kit Harington</Name>
<Role>Jon Snow</Role>
<DOB>December 26, 1986</DOB>
<Nationality>British</Nationality>
<PlayedCharacterRole>Main</PlayedCharacterRole>
</Actor>
</Cast>
<Creators>
<Creator>
<Name>David Benioff</Name>
<Role>Executive Producer, Writer</Role>
</Creator>
<Creator>
<Name>D. B. Weiss</Name>
<Role>Executive Producer, Writer</Role>
</Creator>
</Creators>
</Show>
<Show>
<ShowId>2</ShowId>
<Name>Breaking Bad</Name>
<Genre>Crime, Drama, Thriller</Genre>
<IMDBRating>9.5</IMDBRating>
<Seasons>5</Seasons>
<Awards/>
<Cast/>
<Creators/>
</Show>
...
XML is validated by XSD schema I created (schema.xsd).
in index.ts I'm instantiating the server, and create the routes:
import * as fs from "fs";
import * as path from "path";
import { DOMParser, XMLSerializer } from "xmldom";
import bodyParser from "body-parser";
import { exec } from "child_process";
import express from "express";
import morgan from "morgan";
import { validateXMLWithXSD } from "./validateXML";
const filePath = path.join(__dirname, "./assets/db.xml");
const schemaPath = path.join(__dirname, "./assets/schema.xsd");
const app = express();
const port = 8000;
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
app.use(morgan("tiny"));
app.use((req, res, next) => {
console.log("Time:", Date.now());
next();
});
app.get("/shows", (req, res) => {
const filePathShows = path.join(__dirname, "./assets/show.xsl");
const filePathDB = path.join(__dirname, "./assets/db.xml");
const filePathGenerated = path.join(__dirname, "./results/shows.html");
console.log(filePathShows);
exec(
`xsltproc ${filePathShows} ${filePathDB} > ${filePathGenerated}`,
(err, stdout, stderr) => {
if (err) {
console.error(err);
res.status(500).send(err);
return;
}
res.sendFile(filePathGenerated);
}
);
});
// create a new show in the database
app.post("/shows", async (req, res) => {
const { newShow } = req.body;
// read the existing XML database
fs.readFile(filePath, async (err, data) => {
if (err) {
res.send(err);
} else {
// parse the XML data
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(data.toString(), "text/xml");
const newShowElement = xmlDoc.createElement("Show");
const ShowIdElement = xmlDoc.createElement("ShowId");
const ShowIdText = xmlDoc.createTextNode(newShow.ShowId);
ShowIdElement.appendChild(ShowIdText);
newShowElement.appendChild(ShowIdElement);
const NameElement = xmlDoc.createElement("Name");
const NameText = xmlDoc.createTextNode(newShow.Name);
NameElement.appendChild(NameText);
newShowElement.appendChild(NameElement);
const GenreElement = xmlDoc.createElement("Genre");
const GenreText = xmlDoc.createTextNode(newShow.Genre);
GenreElement.appendChild(GenreText);
newShowElement.appendChild(GenreElement);
const IMDBRatingElement = xmlDoc.createElement("IMDBRating");
const IMDBRatingText = xmlDoc.createTextNode(newShow.IMDBRating);
IMDBRatingElement.appendChild(IMDBRatingText);
newShowElement.appendChild(IMDBRatingElement);
const SeasonsElement = xmlDoc.createElement("Seasons");
const SeasonsText = xmlDoc.createTextNode(newShow.Seasons);
SeasonsElement.appendChild(SeasonsText);
newShowElement.appendChild(SeasonsElement);
const AwardsElement = xmlDoc.createElement("Awards");
const awards = newShow.Awards;
if (awards.length > 0) {
awards.forEach((award: any) => {
const AwardElement = xmlDoc.createElement("Award");
const TitleElement = xmlDoc.createElement("Title");
const TitleText = xmlDoc.createTextNode(award.Title);
TitleElement.appendChild(TitleText);
AwardElement.appendChild(TitleElement);
const YearElement = xmlDoc.createElement("Year");
const YearText = xmlDoc.createTextNode(award.Year);
YearElement.appendChild(YearText);
AwardElement.appendChild(YearElement);
AwardsElement.appendChild(AwardElement);
});
}
newShowElement.appendChild(AwardsElement);
const CastElement = xmlDoc.createElement("Cast");
const actors = newShow.Cast;
if (actors.length > 0) {
actors.forEach((actor: any) => {
const ActorElement = xmlDoc.createElement("Actor");
const NameElement = xmlDoc.createElement("Name");
const NameText = xmlDoc.createTextNode(actor.Name);
NameElement.appendChild(NameText);
ActorElement.appendChild(NameElement);
const RoleElement = xmlDoc.createElement("Role");
const RoleText = xmlDoc.createTextNode(actor.Role);
RoleElement.appendChild(RoleText);
ActorElement.appendChild(RoleElement);
const DOBElement = xmlDoc.createElement("DOB");
const DOBText = xmlDoc.createTextNode(actor.DOB);
DOBElement.appendChild(DOBText);
ActorElement.appendChild(DOBElement);
const NationalityElement = xmlDoc.createElement("Nationality");
const NationalityText = xmlDoc.createTextNode(actor.Nationality);
NationalityElement.appendChild(NationalityText);
ActorElement.appendChild(NationalityElement);
const PlayedCharacterRoleElement = xmlDoc.createElement(
"PlayedCharacterRole"
);
const PlayedCharacterRoleText = xmlDoc.createTextNode(
actor.PlayedCharacterRole
);
PlayedCharacterRoleElement.appendChild(PlayedCharacterRoleText);
ActorElement.appendChild(PlayedCharacterRoleElement);
CastElement.appendChild(ActorElement);
});
}
newShowElement.appendChild(CastElement);
const Creators = newShow.Creators;
const CreatorsElement = xmlDoc.createElement("Creators");
if (Creators.length > 0) {
Creators.forEach((Creator: any) => {
const CreatorElement = xmlDoc.createElement("Creator");
const NameElement = xmlDoc.createElement("Name");
const NameText = xmlDoc.createTextNode(Creator.Name);
NameElement.appendChild(NameText);
CreatorElement.appendChild(NameElement);
const RoleElement = xmlDoc.createElement("Role");
const RoleText = xmlDoc.createTextNode(Creator.Role);
RoleElement.appendChild(RoleText);
CreatorElement.appendChild(RoleElement);
CreatorsElement.appendChild(CreatorElement);
});
}
newShowElement.appendChild(CreatorsElement);
// add the new show to the database
xmlDoc.getElementsByTagName("Shows")[0].appendChild(newShowElement);
// write the new XML database
const serializer = new XMLSerializer();
const xmlString = serializer.serializeToString(xmlDoc);
// validate schema
try {
await validateXMLWithXSD(xmlString, schemaPath);
} catch (error) {
console.error(error);
res.status(500).send(error);
return;
}
fs.writeFile(filePath, xmlString, (err) => {
if (err) {
console.error(err);
} else {
res.send("New Show added to database :)");
}
});
}
});
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
on /shows I'm creating a table with all the shows from the show.xsl, that gest necessary data from db.xml and generates valid html that is stored in /results/shows.html
What I want to do now is to add the possibility to update existing data, via a PUT method. This is my progress so far, but I'm not sure how to handle complex elements like <Awards>, <Cast>, <Creators> that contain multiple children.
// create an update request what will update a show based on the ShowId
app.put("/shows/:ShowId", (req, res) => {
const { ShowId } = req.params;
const updatedShow = req.body;
// read the existing XML database
fs.readFile(filePath, async (err, data) => {
if (err) {
res.send(err);
} else {
// parse the XML data
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(data.toString(), "text/xml");
const showElements = xmlDoc.getElementsByTagName("Show");
for (let i = 0; i < showElements.length; i++) {
const show = showElements[i];
const ShowIdElement = show.getElementsByTagName("ShowId")[0];
const ShowIdText = ShowIdElement.childNodes[0];
if (ShowIdText.nodeValue === ShowId) {
// update the show
const NameElement = show.getElementsByTagName("Name")[0];
const NameText = NameElement.childNodes[0];
NameText.nodeValue = updatedShow.Name;
const GenreElement = show.getElementsByTagName("Genre")[0];
const GenreText = GenreElement.childNodes[0];
GenreText.nodeValue = updatedShow.Genre;
const IMDBRatingElement = show.getElementsByTagName("IMDBRating")[0];
const IMDBRatingText = IMDBRatingElement.childNodes[0];
IMDBRatingText.nodeValue = updatedShow.IMDBRating;
const SeasonsElement = show.getElementsByTagName("Seasons")[0];
const SeasonsText = SeasonsElement.childNodes[0];
SeasonsText.nodeValue = updatedShow.Seasons;
// get the awards element and remove all the awards from it and then add the new awards
const AwardsElement = show.getElementsByTagName("Awards")[0];
while (AwardsElement.firstChild) {
AwardsElement.removeChild(AwardsElement.firstChild);
}
const Awards = updatedShow.Awards;
if (Awards && Awards.length > 0) {
Awards.forEach((award: any) => {
const AwardElement = xmlDoc.createElement("Award");
const AwardText = xmlDoc.createTextNode(award);
AwardElement.appendChild(AwardText);
AwardsElement.appendChild(AwardElement);
});
}
//get the cast element and remove all the actors from it and then add the new actors
const CastElement = show.getElementsByTagName("Cast")[0];
while (CastElement.firstChild) {
CastElement.removeChild(CastElement.firstChild);
}
const Cast = updatedShow.Cast;
if (Cast && Cast.length > 0) {
Cast.forEach((actor: any) => {
const ActorElement = xmlDoc.createElement("Actor");
const NameElement = xmlDoc.createElement("Name");
const NameText = xmlDoc.createTextNode(actor.Name);
NameElement.appendChild(NameText);
ActorElement.appendChild(NameElement);
const RoleElement = xmlDoc.createElement("Role");
const RoleText = xmlDoc.createTextNode(actor.Role);
RoleElement.appendChild(RoleText);
ActorElement.appendChild(RoleElement);
const DOBElement = xmlDoc.createElement("DOB");
const DOBText = xmlDoc.createTextNode(actor.DOB);
DOBElement.appendChild(DOBText);
ActorElement.appendChild(DOBElement);
const PlayedCharacterRoleElement = xmlDoc.createElement(
"PlayedCharacterRole"
);
const PlayedCharacterRoleText = xmlDoc.createTextNode(
actor.PlayedCharacterRole
);
PlayedCharacterRoleElement.appendChild(PlayedCharacterRoleText);
ActorElement.appendChild(PlayedCharacterRoleElement);
CastElement.appendChild(ActorElement);
});
}
//get the creators element and remove all the creators from it and then add the new creators
const CreatorsElement = show.getElementsByTagName("Creators")[0];
while (CreatorsElement.firstChild) {
CreatorsElement.removeChild(CreatorsElement.firstChild);
}
const Creators = updatedShow.Creators;
if (Creators && Creators.length > 0) {
Creators.forEach((creator: any) => {
const CreatorElement = xmlDoc.createElement("Creator");
const NameElement = xmlDoc.createElement("Name");
const NameText = xmlDoc.createTextNode(creator.Name);
NameElement.appendChild(NameText);
CreatorElement.appendChild(NameElement);
const RoleElement = xmlDoc.createElement("Role");
const RoleText = xmlDoc.createTextNode(creator.Role);
RoleElement.appendChild(RoleText);
CreatorElement.appendChild(RoleElement);
CreatorsElement.appendChild(CreatorElement);
});
}
}
const dbFilePath = path.join(__dirname, "./assets/db.xml");
const serializedXml = new XMLSerializer().serializeToString(xmlDoc);
try {
await validateXMLWithXSD(serializedXml, schemaPath);
} catch (error) {
console.error(error);
res.status(500).send(error);
return;
}
fs.writeFile(dbFilePath, serializedXml, (writeErr) => {
if (writeErr) {
console.error(writeErr);
} else {
res.send("Show updated successfully!");
}
});
}
}
});
});
I was thinking that I could erase their children and create new one, with the data provided, but I'm getting this error:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
when sending this object in Postman:
{
"updatedShow": {
"Name": "new Friends222",
"Genre": "new Comedy",
"IMDBRating": "8.9",
"Seasons": "10",
"Awards": [
{
"Title": "new yolo ",
"Year": "2022"
}
],
"Cast": [
{
"Name": "new Jennifer Aniston",
"Role": "Rachel Green",
"DOB": "February 11, 1969",
"Nationality": "American",
"PlayedCharacterRole": "Main"
},
{
"Name": "new Courteney Cox",
"Role": "Monica Geller",
"DOB": "June 15, 1964",
"Nationality": "American",
"PlayedCharacterRole": "Main"
}
],
"Creators": [
{
"Name": "new Creator1",
"Role": "Director, pussy boy"
},
{
"Name": "new Creator2",
"Role": "Dick girl"
}
]
}
}
So my question is how to update an existing <Show> data, in Postman, by ShowId ?
Related
i wanted to add something to my son file but when I try to add it just override my son file can someone help me with this
const fs = require('fs')
const chalk = require('chalk')
const getNotes = function(){
return 'Your notes....'
}
// add note function
const addNote = function (title, body) {
const notes = loadNotes()
const duplicateNotes = notes.filter(function (note) {
return note.title === title
})
if (duplicateNotes.length === 0) {
notes.push({
title: title,
body: body
})
saveNotes(notes)
console.log(chalk.green.inverse('New note added!'))
} else {
console.log(chalk.red.inverse('Note title taken!'))
}
}
const saveNotes = function(notes){
const dataJSON = JSON.stringify(notes)
fs.writeFileSync('notes.json', dataJSON)
}
const loadNotes = function(){
try{
const dataBuffer = fs.readFileSync(notes.json)
const dataJSON = dataBuffer.toString();
return JSON.parse(dataJSON)
}catch (e){
return []
}
}
module.exports = {
getNotes: getNotes,
addNote: addNote,
}
when I run node app.js add --title="list" --body="apple" and then i add another different title and body it just override the --title="list" --body="apple why is that happening ?
It seems you just forgot the quotes:
const dataBuffer = fs.readFileSync(notes.json)
should be
const dataBuffer = fs.readFileSync('notes.json')
I have this api which works fine when running locally. But, once it is deployed to Heroku i get a error 503 which is because it tries to target localhost on Heroku's server and not the user's localhost. Is there a way to make this target the user's localhost instead?
The frontend is React. Here's the code in React that fetches this api every 5sec.
axiosFunc = () => {
const { user } = this.props.auth;
console.log(user);
axios.get(`api/avaya/${user.id}`).then((res) => console.log(res));
};
timer = (time) => {
const date = new Date(time);
return `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
};
componentDidMount() {
this.axiosFunc();
this.interval = setInterval(this.axiosFunc, 5000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
and this is the API on the backend with express
const router = require("express").Router();
const xml2js = require("xml2js");
const Avaya = require("../../models/Avaya");
const User = require("../../models/User");
router.route("/:id").get(async (req, res) => {
const user = await User.findById(req.params.id);
const axios = require("axios");
axios({
method: "post",
baseURL: `http://127.0.0.1:60000/onexagent/api/registerclient?name=${user.username}`,
timeout: 2000,
})
.then((reg) => {
xml2js
.parseStringPromise(reg.data, { mergeAttrs: true })
.then((result) => {
if (result.RegisterClientResponse.ResponseCode[0] === "0") {
const clientId = result.RegisterClientResponse.ClientId[0];
user.avayaClientId = clientId;
user.save();
}
const clientId = user.avayaClientId;
axios({
method: "post",
url: `http://127.0.0.1:60000/onexagent/api/nextnotification?clientid=${clientId}`,
}).then((notification) => {
xml2js
.parseStringPromise(notification.data, { mergeAttrs: true })
.then((result) => {
const notifType = [];
const notifDetails = [];
for (let i in result.NextNotificationResponse) {
notifType.push(i);
}
const arranged = {
NotificationType: notifType[1],
ResponseCode:
result.NextNotificationResponse[notifType[0]][0],
};
for (let i in result.NextNotificationResponse[
notifType[1]
][0]) {
notifDetails.push(i);
}
for (let i = 0; i < notifDetails.length; i++) {
arranged[[notifDetails[i]][0]] =
result.NextNotificationResponse[notifType[1]][0][
notifDetails[i]
][0];
}
for (let i in arranged) {
if ("Outbound" in arranged) {
arranged.CallType = "Outbound";
} else if ("Inbound" in arranged)
arranged.CallType = "Inbound";
else {
arranged.CallType = " ";
}
}
if (
arranged.NotificationType === "VoiceInteractionCreated" ||
arranged.NotificationType === "VoiceInteractionMissed" ||
arranged.NotificationType === "VoiceInteractionTerminated"
) {
const newLogs = new Avaya({
notification: arranged,
});
newLogs.owner = user;
newLogs.save();
user.avayaNotifications.push(newLogs),
user
.save()
.then((logs) => res.json(logs))
.catch((err) => res.status(400).json("Error: " + err));
} else {
res.send("Nothing to record");
}
});
});
});
})
.catch((err) => res.status(503).json(err));
});
router.route("/history/:username").get(async (req, res) => {
const user = await User.findOne({ username: [`${req.params.username}`] });
Avaya.find({ owner: [`${await user.id}`] }).then((user) => res.json(user));
});
module.exports = router;
EDIT: I was able to fix thanks to #Molda
using fetch instead of axios doesn't result in cors error.
New frontend code
getLogs = async () => {
const { user } = this.props.auth;
const reg = await fetch(
`http://127.0.0.1:60000/onexagent/api/registerclient?name=${user.id}`
);
let regData = await reg.text();
let regxml = new XMLParser().parseFromString(regData);
if (regxml.attributes.ResponseCode === "0") {
axios.post(`/api/avaya/register/${user.id}`, regxml);
console.log(regxml.attributes.ResponseCode);
}
let resp = await fetch(`/api/avaya/getid/${user.id}`);
let clientId = await resp.text();
let logs = await fetch(
`http://127.0.0.1:60000/onexagent/api/nextnotification?clientid=${clientId}`
);
let data = await logs.text();
var xml = new XMLParser().parseFromString(data);
axios.post(`/api/avaya/getlogs/${user.id}`, xml);
};
timer = (time) => {
const date = new Date(time);
return `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
};
componentDidMount() {
this.getLogs();
this.interval = setInterval(this.getLogs, 5000);
}
New backend code:
const router = require("express").Router();
const Avaya = require("../../models/Avaya");
const User = require("../../models/User");
router.route("/register/:id").post(async (req, res) => {
const user = await User.findById(req.params.id);
const clientId = req.body.attributes.ClientId;
user.avayaClientId = clientId;
user.save();
});
router.route("/getid/:id").get(async (req, res) => {
const user = await User.findById(req.params.id);
res.send(user.avayaClientId);
});
router.route("/getlogs/:id").post(async (req, res) => {
const user = await User.findById(req.params.id);
const arranged = {
NotificationType: req.body.children[0].name,
ResponseCode: req.body.attributes.ResponseCode,
CallType: " ",
};
for (let i in req.body.children[0].attributes) {
if (i === "Outbound") {
arranged.CallType = "Outbound";
}
if (i === "Inbound") {
arranged.CallType = "Inbound";
}
arranged[i] = req.body.children[0].attributes[i];
}
console.log(arranged);
if (
arranged.NotificationType === "VoiceInteractionCreated" ||
arranged.NotificationType === "VoiceInteractionMissed" ||
arranged.NotificationType === "VoiceInteractionTerminated"
) {
const newLogs = new Avaya({
notification: arranged,
});
newLogs.owner = user;
newLogs.save();
user.avayaNotifications.push(newLogs),
user
.save()
.then((logs) => res.json(logs))
.catch((err) => res.status(400).json("Error: " + err));
} else {
res.send("Nothing to record");
}
});
router.route("/history/:username").get(async (req, res) => {
const user = await User.findOne({ username: [`${req.params.username}`] });
Avaya.find({ owner: [`${await user.id}`] }).then((user) => res.json(user));
});
module.exports = router;
I really don't get the part of (requesting with Axios in API)
Is this a third party API ?
But I suggest you to use (.env) which is a file in your root folder contains the development config like base URLs, expire tokens, API keys ... etc
and when you upload to Heroku you have to make a (.env) in Heroku app and but your config
Let's take an example
in my development mode, my .env looks like
app_url = localhost:4000
port = 4000
db = development_api
db_username = root
db_password =
db_engine = mysql2
in my production mode, my .env looks like
app_url = http://appsomething.heroku.com
port = 80
db = production_api
db_username = root
db_password = 3210LDWAK#AALKQ
db_engine = mysql2
and read more about how to use .ENV
Without using ThunderCore Hub or any Web3 wallet which supports Thunder Token, how could I programmatically send transactions or transfer Thunder Tokens?
To send a transaction on Thundercore, set these fields in the transaction:
set chainId with from net_version() (eth.net.getId())
set nonce with the value of eth_getTransactionCount() (eth.getTransactionCount)
set gas price from eth_gasPrice() (getGasPrice)
set gas limit from eth_estimateGas (eth.estimateGas)
See the submitTx method in the following code:
transfer.js
const fs = require('fs');
const path = require('path');
const Accounts = require('web3-eth-accounts');
const Eth = require('web3-eth');
const Web3 = require('web3');
const BN = Web3.utils.BN;
const pretty = require('./pretty');
const erc20Abi = require('./ERC20.abi.json');
const web3Provider = () => {
return Eth.giveProvider || 'https://mainnet-rpc.thundercore.com';
}
const signTx = async (fromAccount, tx) => {
const signedTx = await fromAccount.signTransaction(tx)
return signedTx.rawTransaction // hex string
}
class ChainHelper {
constructor(eth, chainId, fromAccount) {
this.eth = eth;
this.chainId = chainId;
this.fromAccount = fromAccount;
this.fromAddress = fromAccount.address;
}
async submitTx(toAddress, value, txData) {
const eth = this.eth;
const promiseResults = await Promise.all([
eth.getTransactionCount(this.fromAccount.address),
eth.getGasPrice(),
]);
const nonce = promiseResults[0];
const gasPrice = promiseResults[1];
const fromAddress = this.fromAddress;
const tx = {
'gasLimit': 0,
'chainId': this.chainId,
'gasPrice': gasPrice,
'nonce': nonce,
'from': fromAddress,
'to': toAddress,
'value': value,
'data': txData,
}
const gasMultiple = new BN(1.0);
tx.gasLimit = '0x' + (new BN(await eth.estimateGas(tx))).mul(gasMultiple).toString(16);
console.log('tx:', pretty.format(tx));
const rawTxStr = await signTx(this.fromAccount, tx);
return eth.sendSignedTransaction(rawTxStr);
}
async transferToken (contractAddress, toAddress, value) {
const eth = this.eth;
const contractAbi = erc20Abi;
const contract = new eth.Contract(contractAbi, contractAddress);
const txData = contract.methods.transfer(toAddress, value).encodeABI();
return this.submitTx(contractAddress, 0, txData);
}
}
const create = async (privateKey) => {
const accounts = new Accounts();
if (!privateKey.startsWith('0x')) {
privateKey = '0x' + privateKey;
}
const account = accounts.privateKeyToAccount(privateKey);
const eth = new Eth(web3Provider());
const networkId = await eth.net.getId();
return new ChainHelper(eth, networkId, account);
}
const readKeys = () => {
const privateKeys = fs.readFileSync(path.join(__dirname, '..', '.private-keys'),
{encoding: 'ascii'}).split('\n').filter(x => x.length > 0);
return privateKeys;
}
module.exports = {
create: create,
readKeys: readKeys,
};
testTransfer.js
const fs = require('fs');
const path = require('path');
const ChainHelper = require('../src/transfer.js');
const toAddress = '0x6f0d809e0fa6650460324f26df239bde6c004ecf';
describe('transfer', () => {
it('transfer TT', async() => {
const privateKey = ChainHelper.readKeys()[0]
const c = await ChainHelper.create(privateKey);
c.submitTx(toAddress, 1, '');
});
it('tokenTransfer', async() => {
const privateKey = ChainHelper.readKeys()[0]
const c = await ChainHelper.create(privateKey);
/* Token.issue() */
const jsonBuf = fs.readFileSync(path.join(__dirname, '..', 'build', 'contracts', 'Token.json'));
const contractData = JSON.parse(jsonBuf);
const contractAbi = contractData['abi'];
const contractAddress = contractData['networks'][c.chainId]['address'];
const contract = new c.eth.Contract(contractAbi, contractAddress);
const toAddress = c.fromAddress;
const tokenAmount = 2;
let txData = contract.methods.issue(tokenAmount, c.fromAddress).encodeABI();
let r = await c.submitTx(toAddress, 0, txData);
console.log('Token.issue receipt:', r);
/* Token.transfer() */
r = await c.transferToken(contractAddress, toAddress, tokenAmount)
console.log('Token.transfer receipt:', r);
});
});
The code above targets the command line or server-side node.js, to send transactions from a browser replace signTx and eth.sendSignedTransaction with web3.eth.sendTransaction
The complete example is in the transfer branch of this field-support repo.
Path 1 - Match_Creator/cricket/matchList;
Path 2 - Match_Creator/cricket/completedMatchList;
I have a collection called matchList (Path 1) In which i am having a doc called c434108.
Now I want to move this doc(c434108) to Path 2;
/* eslint-disable promise/catch-or-return */
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const { db } = require("./db/index");
const createCompletedMatchListDoc = (request, response) => {
completedMatchDocsData();
};
function completedMatchDocsData() {
createNewCompletedMatchDocs()
}
function getOldCompletedMatchDocs(){
var completedMatchesRef = db
.collection("Match_Creator")
.doc("cricket")
.collection("matchList");
var completedMatchDocData;
var completedMatchDataArr = [];
return new Promise(resolve => {
let query = completedMatchesRef
.where("status", "==", "live")
.get()
.then(snapshot => {
// eslint-disable-next-line promise/always-return
if (snapshot.empty) {
console.log("No matching documents.");
return;
}
snapshot.forEach(doc => {
completedMatchDocData = doc.data();
completedMatchDataArr.push(completedMatchDocData);
resolve(completedMatchDataArr);
});
console.log("sarang", completedMatchDataArr[2]);
})
.catch(err => {
console.log("Error getting documents", err);
});
});
}
const createNewCompletedMatchDocs = (async(change, context) => {
let completedMatchData = await getOldCompletedMatchDocs();
console.log('aman', completedMatchData[1]);
const newValue = change.after.data();
const previousValue = change.before.data();
const st1 =newValue.status;
const st2 = previousValue.status;
console.log('I am a log entry' + st1 + ' ' + st2);
var data = completedMatchData[0];
return db.collection('Match_Creator').doc('cricket').collection('completedMatchList').add(data)
.catch(error => {
console.log('Error writting document: ' + error);
return false;
});
})
module.exports = createCompletedMatchListDoc;
And After copy this doc(c434108) i want to delete this doc(c434108) from path 1.
And My index.js file is:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const storeMatchData = require("./liveScoring");
const createCompletedMatchListDoc = require("./completedMatchList");
var http = require("https");
module.exports = {
liveScoring: functions.https.onRequest(storeMatchData),
createCompletedMatchListDoc: functions.https.onRequest(
createCompletedMatchListDoc
)
};
I am able to solve my problem.
This is my completeMatchList.js file
/* eslint-disable promise/catch-or-return */
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const { db } = require("./db/index");
const createCompletedMatchListDoc = (request, response) => {
completedMatchDocsData();
};
function completedMatchDocsData() {
setNewCompletedMatchDocs()
}
function getOldCompletedMatchDocs(){
var completedMatchesRef = db
.collection("Match_Creator")
.doc("cricket")
.collection("matchList");
var completedMatchDocData;
var completedMatchDataArr = [];
return new Promise(resolve => {
let query = completedMatchesRef
.where("status", "==", "live")
.get()
.then(snapshot => {
// eslint-disable-next-line promise/always-return
if (snapshot.empty) {
console.log("No matching documents.");
return;
}
snapshot.forEach(doc => {
// completedMatchDocData = doc.data();
completedMatchDocData = {
docId: "",
docData: ""
}
completedMatchDocData.docId = doc.id;
completedMatchDocData.docData = doc.data();
completedMatchDataArr.push(completedMatchDocData);
resolve(completedMatchDataArr); // Here i am getting the data and pushing it in array
});
console.log("sarang", completedMatchDataArr);
})
.catch(err => {
console.log("Error getting documents", err);
});
});
}
const setNewCompletedMatchDocs = (async () => {
let getCompletedMatchData = await getOldCompletedMatchDocs();
// console.log("balram", getCompletedMatchData[0].docId);
let newCompletedMatchDocRef = db.collection("Match_Creator").doc("cricket").collection("completedMatchList").doc(getCompletedMatchData[0].docId);
return newCompletedMatchDocRef.set(getCompletedMatchData[0].docData); //set/copy the data to new path.
})
This is my main index.js file
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const storeMatchData = require("./liveScoring");
const createCompletedMatchListDoc = require("./completedMatchList");
const { db } = require("./db/index");
var http = require("https");
module.exports = {
liveScoring: functions.https.onRequest(storeMatchData),
createCompletedMatchListDoc: functions.https.onRequest(
createCompletedMatchListDoc
)
};
Now after copy document data to a new path i will delete the previous document. For deleting the document i have not written the function.
I'm not seeing anything that would allow you to move a document between collections(someone correct me if I'm wrong). You have to copy from the old collection to the new one and then remove the old one.
This is another post on StackOverflow that is running into this same issue and someone provided Java code on how to implement it.
EDIT: Updated link.
Hope this helps.
i don't know if the questions is very clear, but probably looking at the code you'll understand.
i'm trying to see if the next() function was called on my router.
But everytime i use the debugger, i watch that the next i passed as a stub to my router don't get on my router as a stub, looks like it get lost on the way. If i extract the callback from the router and exports it separately, it works just fine. But i didn't want to separate things and export them.
const express = require('express');
const mostReadRouter = express.Router();
const mostReadBackEnd = require('../services/most-read-back-end');
const translateMostReadList = require('../services/most-read-service');
mostReadRouter.get('/', (req, res, next) => {
let mostReadUrl = req.query.most_read_url;
if (!mostReadUrl) {
logger.error('param most_read_url is required');
res.status(400).send('param most_read_url is required');
return;
}
let sendSucces = mostRead => {
logger.info(`sending most read list for url: ${mostReadUrl}`);
res.json(mostRead);
};
let sendError = error => {
if (isNotFoundError(error)) {
next();
} else {
next(error);
}
};
mostReadBackEnd
.getMostReadList(mostReadUrl)
.then(translateMostReadList, sendError)
.then(sendSucces, sendError)
.catch(sendError);
});
module.exports = mostReadRouter;
const chai = require('chai');
const {expect} = chai;
chai.use(require('sinon-chai'));
const sinon = require('sinon');
const sandbox = sinon.createSandbox();
const proxyQuire = require('proxyquire');
const statusStub = sandbox.stub();
const sendStub = sandbox.stub();
const getMostReadListStub = sandbox.stub();
const translateStub = sandbox.stub();
const jsonStub = sandbox.stub();
const thenStub = sandbox.stub();
process.env.CONFIGURATOR_API = 'xpto';
const router = proxyQuire('../../app/routes/most-read-router', {
'../services/most-read-back-end': {
getMostReadList: getMostReadListStub
},
'../services/most-read-service': {
translate: translateStub
}
});
describe('MostReadRouter', () => {
afterEach(() => sandbox.reset());
describe('#get(request,response,next)', () => {
it.only('should call next() when getMostReadList does not work` ', async () => {
getMostReadListStub.rejects(new Error('the error'));
let req = {
method: 'GET',
url: '/',
query: {
most_read_url: 'http://beatiful_url.com'
}
};
let res = {
json: jsonStub
};
let next = sandbox.stub();
await router(req, res, next);
expect(next).to.be.calledOnce;
});
})
});