I'm trying to save member data as JSON, but it is not working. I'm using discord.js framework.
I have searched Stack Overflow and many other sites, but I can't find a solution.
Here's the code snippet:
const user = message.guild.members.get(message.mentions.users.first().id);
const file = (user.id + ".json");
const content = {
"name": user.username,
"isFlagged": false,
"punishments": 1,
"id": user.id,
"discrim": user.discriminator
};
var B = content.toString();
fs.writeFileIfNotExist(file, B, function(err, existed) {
if (err) {
console.log(err)
} else {
console.log('file created sucessfuly!')
}
});
let points = JSON.parse(fs.readFileSync('./' + user.id + '.json'));
points.isFlagged = false;
points.punishments = points.punishments + 1;
As, CRice notes, calling Object.prototype.toString on an object created from a literal and not shadowing toString with an implementation returning a JSON formatted string, will return the string "[object Object"] which is not what you want.
This is demonstrated by the following snippet:
const content = {
name: 'John Smith',
isFlagged: false,
punishments: 1,
id: 5,
discrim: Symbol()
};
const b = content.toString();
console.log(b);
So first, change your code as follows
const content = {
name: 'John Smith',
isFlagged: false,
punishments: 1,
id: 5,
discrim: Symbol()
};
const b = JSON.stringify(content);
console.log(b);
Lastly, consider rewriting your program to cleanly and consistently leverage asynchronous IO and improve your naming patterns to follow established JavaScript conventions.
const promisify = require('util.promisify');
const fs = require('fs');
const exists = promisify(fs.exists);
const writeFile = promisify(fs.writeFile);
const readFile = promisify(fs.readFile);
const user = message.guild.members.get(message.mentions.users.first().id);
const file = `${user.id}.json`;
const content = {
name: user.username,
isFlagged: false,
punishments: 1,
id: user.id,
discrim: user.discriminator
};
const b = JSON.stringify(content);
(async function () {
try {
await writeFileIfNotExist(file, b);
console.log('file created sucessfuly!')
} catch (e) {
console.error(e);
}
const json = await readFile(`./${user.id}.json`);
const user = JSON.parse(json);
user.isFlagged = false;
user.punishments = user.punishments + 1;
}());
async function writeFileIfNotExists(fileName, data) {
if (await exists(fileName)) {
return;
}
try {
await writeFile(fileName, data);
} catch (e) {
console.error(e);
}
}
Related
So I have a declared constants variable object. i.e:
const objData = {
project: {
name: '',
age: 0,
subProject: {
name: '',
age: 0
}
}
}
And the function that returns the objData:
const dataSchema = () => {
return objData;
}
The flow is, I want to insert data into my table/collection in my database. So that's why I'm using constants to declare schema, and then I just insert with the returned dataSchema.
This is my func to set value into dataSchema:
const mappingData1 = (data) => {
try {
const dataScheme = Object.assign({}, dataSchema())
dataScheme.project.name = data.name;
dataScheme.project.age = data.age;
return dataScheme;
}catch(err){
return err; //return wrapper error here
}
}
const mappingData2 = (data) => {
try {
const dataScheme = Object.assign({}, dataSchema())
dataScheme.project.subProject.name = data.name;
dataScheme.project.subProject.age = data.age;
return dataScheme;
}catch(err){
return err; //return wrapper error here
}
}
Call mappingData schema func, and insert data into db:
//this bellow statement will be called in insertProjectData func, and called in the first time
const data = { name: 'Someone', age: 7 }
const mappedData = await mappingData1(data)
const result = await this.command.insertData(mappedData)
===================================================================================
//this bellow statement will be called in insertSubProjectData func, and called after insertProjectData func
const data = { name: 'Someone', age: 7 }
const mappedData = await mappingData2(data)
const result = await this.command.insertData(mappedData)
The problem is, when the service is running, and insertSubProjectData func is called after insertProjectData func, why project.name and project.age is setted too with the value from insertProjectData func? even though i didn't set project.name and project.age in insertSubProjectData? It's like the original data (objData) is has been modified. I already use Object.assign too, to create a new object
Any idea please? thank you!
You can guarantee a new object by changing your implementation from this:
const objData = {
project: {
name: '',
age: 0,
subProject: {
name: '',
age: 0
}
}
}
// And the function that returns the objData:
const dataSchema = () => {
return objData;
}
To this:
const dataSchema = () => ({
project: {
name: '',
age: 0,
subProject: {
name: '',
age: 0
}
}
})
Then every time you'll have a real new Object. No more issues
I'm trying to call balanceOf() method on a specific Tron contract (TYukBQZ2XXCcRCReAUguyXncCWNY9CEiDQ), but what I get is Failed to execute . If I do not provide the parameters I get Invalid argument count provided - meaning at some level it works for this contract.
What is interesting it works well on contracts other than the ones created with JustSwap Factory contract eg. https://tronscan.io/#/contract/TYukBQZ2XXCcRCReAUguyXncCWNY9CEiDQ/code .
The code includes the standard TRC20 methods - including balanceOf() - I'm stuck and tried all that's possible form my side, but let's just say I'm not fluent in tronweb api.
My code:
export const getDataToken = async (contractAddress, account, account2) => {
try {
const instance = await window.tronWeb.contract(
[
{
constant: true,
inputs: [{ name: "owner", type: "address" }],
name: "balanceOf",
outputs: [{ name: "", type: "uint256" }],
payable: false,
stateMutability: "view",
type: "function"
}
],
contractAddress
);
console.log(instance);
if (instance.balanceOf) {
console.log("dadadad if");
const tokenBalance = await instance.balanceOf(account).call();
const tokenBalance2 = await instance.balanceOf(account2).call();
return {
tokenBalance: (tokenBalance / Math.pow(10, 18)).toString(),
tokenContract: instance,
tokenBalance2: (tokenBalance2 / Math.pow(10, 18)).toString()
};
}
} catch (message) {
console.log("error getData :" + message);
}
};
const { tokenBalance, tokenContract, tokenBalance2 } = getDataToken(
"TYukBQZ2XXCcRCReAUguyXncCWNY9CEiDQ",
"TL4HzzxGMc1LMfs3XCi4yTJikaBVubz5y4",
"TTFp171XD4JdUB33sDq2ydXJyUEEZjNhLD"
);
This function can help (example for getting JustSwap pair price):
async function takePrice(contractAddress, token){
var functionSelector = 'getTokenToTrxInputPrice(uint256)';
var parameter = [
{
type: 'uint256',
value: token
}
]
var options = {};
transaction = await window.tronWeb.transactionBuilder.triggerConstantContract(contractAddress, functionSelector, options, parameter);
return window.tronWeb.BigNumber("0x"+transaction['constant_result'][0]);
}
priceUSDTTRX = window.tronWeb.fromSun(await takePrice(USDTTRX_ADDRESS, "1000000"));
priceSomeTone18TRX = window.tronWeb.fromSun(await takePrice(SomeTone18TRX_ADDRESS, "1"+"0".repeat(18)));
I have good result:
const TronWeb = require("tronweb");
const ethers = require('ethers')
const MAINNET_RPC = "https://api.trongrid.io";
const PLACEHOLDER_PRIVATE_KEY = "YOUR_PRIVATE_KEY";
const HttpProvider = TronWeb.providers.HttpProvider;
const fullNode = new HttpProvider(MAINNET_RPC);
const solidityNode = new HttpProvider(MAINNET_RPC);
const eventServer = new HttpProvider(MAINNET_RPC);
const tronWeb = new TronWeb(fullNode,solidityNode,eventServer,PLACEHOLDER_PRIVATE_KEY);
const startJustSwap = async () => {
try {
const contractTokenExchangeUSDT = 'TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE'; //S-USDT-TRX Token
const parameter = [{type:`uint256`,value: 10000000}];
const tx = await tronWebLocal.transactionBuilder.triggerConstantContract(contractToken, `trxToTokenSwapInput(uint256,uint256)`, {}, parameter);
console.log(tx);
} catch (e) {
console.log(e);
}
};
startJustSwap();
try const tokenBalance = await instance.balanceOf(account).call({ _isConstant: true });
It works for me.
transactionBuilder.triggerConstantContract works too, but mine is simpler
mongo is set up like this in homeController.js
const MongoDB = require("mongodb").MongoClient,
dbURL = "mongodb://localhost:27017",
dbName = "usersdb";
const collectionName = "contacts";
var test = require('assert');
var col;
var usersArray = []; // define an empty array as a placeholder
var gradesArray = [];
MongoDB.connect(dbURL, {
useUnifiedTopology: true,
useNewUrlParser: true,
useCreateIndex: true
},
(error, client) => {
if (error) throw error;
let db = client.db(dbName);
col = db.collection(collectionName, {
safe: false,
useUnifiedTechnology: true
}, (err, r) => {
if (err) {
console.log("Something is wrong in db.collection");
}
});
col.find()
.toArray((error, userData) => {
if (error) throw error;
usersArray = userData; // store all users in the array users[]
//console.log(userData);
});
// console.log(`All users: ${usersArray}`);
});
I have a function in homeController.js that I want to test, it take a name and array of grades, converts the grades, checks if they're valid, and pushes them to the database. The function looks like this and uses the col variable:
router.addUsers = (req, res) => {
console.log("in homeController addUser");
var newUserName = req.body.name;
var newUsergrade = req.body.grade;
var temp = 0;
newUsergrade.forEach(letter => {
letter = letter.toUpperCase();
switch (letter) {
case 'A':
letter = 4.0
break
case 'A-':
letter = 3.7
break
case 'B+':
letter = 3.3
break
case 'B':
letter = 3.0
break
case 'B-':
letter = 2.7
break
case 'C+':
letter = 2.3
break
case 'C':
letter = 2.0
break
case 'C-':
letter = 1.7
break
case 'D+':
letter = 1.3
break
case 'D':
letter = 1.0
break
case 'F':
letter = 0.0
break
}
temp += letter;
});
var valid = false;
if (temp / 4 >= 2.5) {
valid = true;
} else {
vaild = false;
}
col.insertOne({
name: newUserName,
grade: newUsergrade,
isValid: valid
}, function(err, r) {
test.equal(null, err);
test.equal(1, r.insertedCount);
col.find({}).toArray((err, userData) => {
console.log("record found: ", userData);
usersArray = userData;
});
});
Finally, my router.test.js looks like this:
describe("addUsers", () => {
it("should make sure a user can be added to the array", () => {
const fakeReq = {
body: {
name: 'something',
grade: ["a", "b", "a", "a"]
}
},
fakeRes = {
render: () => {}
};
router.addUsers(fakeReq, fakeRes);
// console.log(router.addUsers(fakeReq, fakeRes))
expect(usersArray).to.deep.include({
name: 'something'
});
});
});
I am getting an error saying it cant insertOne of undefined, meaning I need the mongoDB part in my test. How can I incorporate this into my test to test if this function adds one entry?
You are testing a middleware as if it were a standalone function. In this case, you should test the route endpoint. For example:
const request = require("supertest");
const expect = require("chai").expect;
const app = require('../app');
const mongoose = require('mongoose');
const faker = require("faker"); // to generate fake data
const Entity = require('../entities/discount'); // import schema
require('dotenv').config();
describe("GET /Entity/{entityID}", () => {
let body
beforeEach(async () => {
await Entity.deleteMany()
body = {
name: faker.name.title(),
image: faker.image.imageUrl()
}
const entity = new Entity({
_id: new mongoose.Types.ObjectId(),
...body
})
await entity.save()
})
describe("case of success", () => {
it("should work and return status 200 and message ...", async () => {
const res = await request(app)
.get("/entity /" + entityID )
expect(res.status).to.equal(200);
expect(res.body).to.exist
expect(res.body._id).to.exist
expect(res.body).to.have.property("name", body.name);
expect(res.body).to.have.property("image", body.image);
})
})
})
But if you want to test each specific function, you should generate functions that deal with a certain action and test these actions in particular.
I am having some issues with my a particular call in my cloud function that doesn't seem to be resolving correctly.
This is the code that doesn't want to resolve:
console.log('Getting Search Patterns');
let searchPatterns: FirebaseFirestore.QuerySnapshot;
try {
searchPatterns = await admin
.firestore()
.collection('FYP_LOCATIONS')
.get();
} catch (error) {
console.error(error);
}
console.log(`Search Patterns Received: ${searchPatterns}`);
LOG:
As you can see in the log, my function runs up until the console log before the try block, then stops until the function times out. I'm not sure what it is that is causing this issue.
EDIT: I have reformatted my code by separating out each of the different parts in my cloud function into separate functions that I can call; the resulting getSearchTerms() function is as follows:
async function getSearchTerms(): Promise<FirebaseFirestore.DocumentData[]> {
try {
const snapshot = await admin
.firestore()
.collection('FYP_LOCATIONS')
.get();
console.log('Get Returned');
return snapshot.docs.map(doc => doc.data());
} catch (e) {
console.error(e);
return [];
}
}
This still stops at the same point in the function execution, the full function is here, this has been updated to the latest version:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import * as path from 'path';
import * as WordExtractor from 'word-extractor';
import * as textract from 'textract';
import suffixArray from './suffixArray';
// interface Location {
// lid: string;
// location_name: string;
// location_type: string;
// sentimental_value: number;
// }
// interface Context {
// lid: string;
// context_string: string;
// fid: string;
// }
export const processFile = functions.storage.object().onFinalize(async file => {
const serviceAccount = require(__dirname + '/../config/serviceAccount.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://fyp-alex.firebaseio.com',
});
const firestore = admin.firestore();
const fileBucket: string = file.bucket;
const filePath: string = file.name;
const fileDet: string = path.basename(filePath);
const fileNameSplit: string[] = fileDet.split('.');
const fileExt: string = fileNameSplit.pop();
const fileName: string = fileNameSplit.join('.');
const bucket = admin.storage().bucket(fileBucket);
const fileRef = bucket.file(filePath);
const _path: string = `/tmp/${fileName}.${fileExt}`;
console.log(`File path ${filePath}`);
console.log('Getting Download URL');
try {
console.log(`Downloading to: ${_path}`);
await fileRef.download({ destination: _path });
console.log('File Saved');
console.log(`Getting Details: ${_path}`);
const text: string = await getText(_path, fileExt);
console.log(`Processing: ${fileName}`);
console.log('Creating Suffix Array');
const suffix_array = suffixArray(text);
console.log(`Suffix Array Created: ${suffix_array}`);
console.log('Getting Search Patterns');
const searchTerms: FirebaseFirestore.DocumentData[] = await getSearchTerms();
console.log('Search Patterns Received');
const promises = [];
const allContexts: Object[] = [];
for (const searchDoc of searchTerms) {
const searchTerm = searchDoc.location_name.toLowerCase();
console.log(searchTerm);
const matchedIndexes = search(text, searchTerm, suffix_array);
const contexts = createContexts(matchedIndexes, searchDoc, text, fileName);
allContexts.concat(contexts);
}
for (const context of allContexts) {
const p = admin
.firestore()
.collection('FYP_CONTEXTS')
.add(context);
promises.push(p);
}
await Promise.all(promises);
const data = {
processed: 1,
};
return firestore.doc(`FYP_FILES/${fileName}`).update(data);
} catch (e) {
console.error(e);
const data = {
processed: 2,
};
return firestore.doc(`FYP_FILES/${fileName}`).update(data);
}
});
async function getText(_path: string, fileExt: string) {
let text: string = '';
switch (fileExt) {
case 'docx':
case 'doc':
const extractor = new WordExtractor();
const extracted = await extractor.extract(_path);
text = extracted.getBody();
break;
case 'pdf':
break;
case 'txt':
textract.fromFileWithPath(_path, function(extractedError: any, string: string) {
if (extractedError) {
console.error(extractedError);
}
if (string !== null) {
text = string;
}
});
break;
default:
console.log('Unsupported File Type');
}
return text;
}
async function getSearchTerms(): Promise<FirebaseFirestore.DocumentData[]> {
try {
const snapshot = await admin
.firestore()
.collection('FYP_LOCATIONS')
.get();
console.log('Get Returned');
return snapshot.docs.map(doc => doc.data());
} catch (e) {
console.error(e);
return [];
}
}
function createContexts(
matchedIndexes: number[],
searchDoc: FirebaseFirestore.DocumentData,
text: string,
fileName: string
) {
console.log('Creating Contexts');
const contexts = [];
const searchTerm = searchDoc.location_name.toLowerCase();
for (const index of matchedIndexes) {
let left = index - 25;
let right = index + searchTerm.length + 25;
if (left < 0) {
left = 0;
}
if (right > text.length) {
right = text.length;
}
const context = text.substring(left, right);
contexts.push({
lid: searchDoc.lid,
context_string: context,
fid: fileName,
});
}
return contexts;
}
function search(text: string, searchTerm: string, suffix_array: number[]) {
console.log(`Beginning search for: ${searchTerm}`);
let start = 0;
let end = suffix_array.length;
const matchedIndexes: Array<number> = [];
while (start < end) {
const mid: number = (end - 1) / 2;
const index: number = suffix_array[mid];
const finalIndex: number = index + searchTerm.length;
if (finalIndex <= text.length) {
const substring: string = text.substring(index, finalIndex);
const match: number = searchTerm.localeCompare(substring);
if (match === 0) {
console.log(`Match Found at Index: ${index}`);
matchedIndexes.push(index);
} else if (match < 0) {
end = mid;
} else if (match > 0) {
start = mid;
}
console.log(matchedIndexes);
}
}
if (matchedIndexes.length === 0) {
console.log(`No matches found for search term: ${searchTerm}`);
}
return matchedIndexes;
}
Hopefully the full function provides a bit more context.
I have watched Doug's videos through a few times but I am still coming up against this, I did notice that removing the await that seems to be failing (as in removing the promise all together) seemed to cause an earlier await to fail. This is indicative of it being an issue with promises later on in the function but I cannot for the life of me find the issue, I will keep trying but hopefully that provides some useful context.
You aren't letting the function know when the async operations have finished.
I would guess that you want to collect all of the async operations in an array and wait for all of them to finish before letting the function exit.
(Those youtube videos by Doug, mentioned in the comments above are quite good and do a more thorough job of explaining why)
ie.
const requests = [];
const things = [1,2,3];
for (let index = 0; index < things.length; index++) {
const element = things[index];
const promise = firebase.firestore().push(element);
requests.push(promise);
}
return Promise.all(requests);
This is the module that collections and exports async data: scraper.js
const express = require('express')
const cheerio = require('cheerio')
const request = require("tinyreq")
const fs = require('fs')
const _ = require('lodash')
const uuid = require('uuid/v4')
const async = require('async')
const mental_models = {
url: 'https://www.farnamstreetblog.com/mental-models/',
data: {}
}
const decision_making = {
url: 'https://www.farnamstreetblog.com/smart-decisions/',
data: {}
}
const cognitive_bias = {
url: 'https://betterhumans.coach.me/cognitive-bias-cheat-sheet-55a472476b18',
data: {}
}
const DATA_URLS = [mental_models, decision_making, cognitive_bias]
const filterScrape = async (source, params) => {
let filtered_data = {
topics: [],
content: [],
additional_content: []
}
let response = await scrape(source)
try {
let $ = cheerio.load(response)
params.forEach((elem) => {
let headers = ['h1', 'h2', 'h3']
if ($(elem) && headers.includes(elem)) {
let topic = {}
let content = {}
let id = uuid()
topic.id = id
topic.text = $(elem).text()
if ($(elem).closest('p')) {
content.text = $(elem).closest('p').text()
content.id = id
}
filtered_data.topics.push(topic)
filtered_data.content.push(content)
} else if ($(elem) && !headers.includes(elem)) {
let content = {}
let id = uuid()
content.text = $(elem).text()
content.id = id
filtered_data.additional_content.push(content)
} else {
}
})
}
catch (err) {
console.log(err)
}
return filtered_data
}
const scrape = (source) => {
return new Promise((resolve, reject) => {
request(source.url, function (err, body) {
if (err) {
reject(err)
return
}
resolve(body)
})
})
}
const DATA = _.map(DATA_URLS, async (source) => {
let params = ['h1', 'h2', 'h3', 'p']
let new_data = await filterScrape(source, params)
try {
source.data = new_data
}
catch (err) {
console.log(err)
}
})
module.exports = DATA
This is the module that imports the data: neural.js
const brain = require('brain')
const neural_net = new brain.NeuralNetwork()
const DATA = require('./scraper')
console.log(DATA)
Obviously not much going on, I've removed the code since the variable doesn't resolve. When logged it logs a promise but the promise does not resolve. However in the imported module, the promise is logged and then resolves. What gives? Should I import a function that resolves the data?
Of course it would be best to import that function, however it won't change the issue in your code which is here:
const DATA = _.map(DATA_URLS, async (source) => {
Lodash doesn't support async iteration - so you need to have some other method, one would be to use the newest nodejs version (10.x) and make use of async iteration - but that won't use the full power of asynchronous code.
You can also use scramjet - a framework my company is supporting. The code above would take the following form:
const {DataStream} = require("scramjet");
const DATA_URLS = [mental_models, decision_making, cognitive_bias];
module.exports = async () => DataStream.fromArray(DATA_URLS)
.setOptions({maxParallel: 2}) // if you need to limit that at all.
.map(async ({url}) => {
let params = ['h1', 'h2', 'h3', 'p']
let data = await filterScrape(source, params);
return { url, data };
})
.toArray();
The other file would take the following form:
const brain = require('brain')
const neural_net = new brain.NeuralNetwork()
const scraper = require('./scraper')
(async (){
const DATA = await scraper();
console.log(DATA); // or do whatever else you were expecting...
})();