So im very new to fullstack and been working on a little vanilla js project to make a website that calls a server I run that calls chess.com api, for example retrieving all elo ratings is:
https://api.chess.com/pub/player/${username}/stats
So I made a backend call in node-js:
const fetch = require('node-fetch');
exports.getChessManStats = () => {
return (req, res) => {
res.set('Access-Control-Allow-Origin', '*');
const username = req.param('username');
console.log(req.param('username'));
fetch(`https://api.chess.com/pub/player/${username}/stats`)
.then(res2 => res2.json() )
.then(chessManData => {
res.json({
daily: chessManData.chess_daily.last.rating,
rapid: chessManData.chess_rapid.last.rating,
blitz: chessManData.chess_blitz.last.rating,
bullet: chessManData.chess_bullet.last.rating,
})
})
.catch(err => console.log(err));
}
};
the code then runs with express on the main.js with:
const app = express();
app.get('/getRating',chessManController.getChessManStats());
obviously later down the line I called app.listen(3000) .
So then at the frontend I made a button that calls this function :
const makeUserStats = () => {
const username = document.getElementById('username').value;//id=username is type input
document.getElementById('rating').innerHTML = `Searching`; //making the rating div into 'searching'
console.log(`http://localhost:3000/getRating?username=${username}`)//just seeing the sting I send
fetch(`http://localhost:3000/getRating?username=${username}`)
.then(rating => {
document.getElementsByClassName('statButton').disabled = true;//disabling buttons until the data arrives
console.log('got json');
return rating.json();
})
.catch(err => console.log(err))//looking for errors
.then((userRating => {
window.userRating = userRating;//saving the stats globaly to use in other buttons
window.user = username;
}))
.then(() => {
document.getElementsByClassName('statButton').disabled = false;//enabling the buttons again
document.getElementById('rating').innerHTML = `${window.user} rating is:`;
})
}
and now when I press the button it works with some usernames and with some dont.
YoniRamot (mine) works, hikaru (pro player) works, atomicstew (friend) doesnt work, idobl (friend) doesnt work. and the wierd part is it does'nt catch any errors, just waiting for answer that it never gets.
but if you go the the api they all exist:
https://api.chess.com/pub/player/yoniramot/stats -- mine
https://api.chess.com/pub/player/hikaru/stats --proplayer
https://api.chess.com/pub/player/atomicstew/stats --friend
https://api.chess.com/pub/player/idobl/stats --friend
the console of the backend shows:
atomicstew
TypeError: Cannot read property 'last' of undefined
at C:\Users\Yonatan\Desktop\coding\training\intermediateChess\backend\controllers\chessStats.js:12:45
at processTicksAndRejections (internal/process/task_queues.js:93:5)
meaning that the backend gets the username but does'nt find it in the api for some reason.
please help my mind is blowing at this point.
-edit 1-
So I added a console log before sending the res with the data, and it printed:
atomicstew
{
chess_rapid: {
last: { rating: 1228, date: 1612114999, rd: 28 },
best: {
rating: 1265,
date: 1611786478,
game: 'https://www.chess.com/live/game/6380128206'
},
record: { win: 233, loss: 202, draw: 19 }
},
chess_blitz: {
last: { rating: 902, date: 1611928398, rd: 50 },
best: {
rating: 1010,
date: 1609882454,
game: 'https://www.chess.com/live/game/6297568401'
},
record: { win: 26, loss: 24, draw: 4 }
},
fide: 0,
tactics: {
highest: { rating: 1659, date: 1609635730 },
lowest: { rating: 387, date: 1608148134 }
},
lessons: {},
puzzle_rush: {}
}
TypeError: Cannot read property 'last' of undefined
at C:\Users\Yonatan\Desktop\coding\training\intermediateChess\backend\controllers\chessStats.js:13:45
at processTicksAndRejections (internal/process/task_queues.js:93:5)
and the references I am calling are right there, so I am still stuck.
-edit 2-
I noe realized that if a player didnt play a certain game mode than the api doesnt hold that values. any ideas how to save the data as 0 or null if there is no data neatly?
Issue is in following block of code where you are trying to access last field on different properties in response:
res.json({
daily: chessManData.chess_daily.last.rating,
rapid: chessManData.chess_rapid.last.rating,
blitz: chessManData.chess_blitz.last.rating,
bullet: chessManData.chess_bullet.last.rating,
})
I had quick look at response for following API and it does not have chess_daily and chess_bullet properties.
https://api.chess.com/pub/player/atomicstew/stats
Since you are trying to access chessManData.chess_daily.last.rating and chess_daily is not present in chessManData, you are getting exception for .last.
In order to fix it, you can replace above block by following:
res.json({
daily: chessManData.chess_daily && chessManData.chess_daily.last ? chessManData.chess_daily.last.rating : null, // replace null with appropriate default value for rating
rapid: chessManData.chess_rapid && chessManData.chess_rapid.last ? chessManData.chess_rapid.last.rating : null,
blitz: chessManData.chess_blitz && chessManData.chess_blitz.last ? chessManData.chess_blitz.last.rating : null,
bullet: chessManData.chess_bullet && chessManData.chess_bullet.last ? chessManData.chess_bullet.last.rating : null,
})
Related
Semi-new developer building a project using the MERN stack.
The app has two models, one for Users and one for Tournaments. Tournament model has an attribute called participants which is an array.
I wrote an Express backend route so that a User can register for Tournaments.participants[].
This looks like:
router.post('/:id', (req, res) => {
Tournament.findById(req.params.id)
.then(tournament => {
tournament.participants.push(req.body);
return tournament.save();
})
.then(savedTournament => res.json(savedTournament))
.catch(err => res.json(err));
});
However, a User can just keep clicking Sign Up and I'd have a bunch of duplicate users, so I'm trying to write a conditional that will disable Sign Up if the user is already in Tournament.participants[].
I tried writing a conditional inside the Express route using Array.includes(req.body) but couldn't hack it.
Looked something like
Tournament.findById(req.params.id)
.then(tournament => {
if (tournament.participants.includes(req.body) {
return res.status(400).json({ msg: "This user already signed up for this tournament" });
} else {
tournament.participants.push(req.body);
return tournament.save();
}
})
.then(savedTournament => res.json(savedTournament))
.catch(err => res.json(err));
I tried different variations as well, like if (tournament.participants.includes(!req.body)) then push(req.body), etc.
And I also tried just rendering a different button if the participants.includes(user) but I believe this should be done on the backend anyway.. I'm open to suggestions.
Can anyone help me out?
In general, you can't use the native comparison operators with objects, includes included:
const foo = { id: 1 };
const bar = [{ id: 1 }];
console.log(bar.includes(foo)); // outputs `false`
You should use some kind of item id in order to check if its already exists:
function isIdIncluded(arr, id) {
return arr.some(x => x.id === id)
}
const foo = { id: 1 };
const bar = [{ id: 1 }];
console.log(isIdIncluded(bar, 1)); // outputs `true`
I assume you are keeping the users's _id in the participants array, and your tournament schema is similar to this:
const tournamentSchema = new mongoose.Schema({
name: String,
participants: Array,
});
Now if you send a request with this body:
{
"user": "5e97255a342f395774f30162" //the user id who wants to participate
}
You can use this code (I just changed the req.body to req.body.user)
Tournament.findById(req.params.id)
.then((tournament) => {
if (tournament.participants.includes(req.body.user)) {
return res.status(400).json({ msg: "This user already signed up for this tournament" });
} else {
tournament.participants.push(req.body.user);
return tournament.save();
}
})
.then((savedTournament) => res.json(savedTournament))
.catch((err) => res.status(500).json(err));
Now when a user first time participates a tournament, the document will be like this:
{
"participants": [
"5e97255a342f395774f30162"
],
"_id": "5e97255a342f395774f30161",
"name": "Chess Tournament"
}
And when the same user tries, the response will be like this with a 400 status code.
{
"msg": "This user already signed up for this tournament"
}
Also please note that, the user id shouldn't be send in the request body, but it must be the user's id who is logged in.
I might just be missing something simple, but I've never had this error before and I don't think I edited it enough to cause this problem since it was last functional. The code block below keeps giving me this error at the top of the file:
(node:17592) UnhandledPromiseRejectionWarning: TypeError: client.catch is not a function
I have specified client = new Discord.Client();
The other issue I am having is that I am trying to get the role that is being made by the bot to be the name of the two players/users (challenger vs target format) after the target has accepted the challenge posed by the challenger. It just makes a role named "new role" instead. Any help with either of these problems?
if (message.channel.id === '541736552582086656') return challenged.send("Do you accept the challenge? Please reply with 'accept' or 'deny'.")
.then((newmsg) => {
newmsg.channel.awaitMessages(response => response.content, {
max: 1,
time: 150000,
errors: ['time'],
}).then((collected) => {
// Grabs the first (and only) message from the collection.
const reply = collected.first();
if (reply.content === 'accept'){
reply.channel.send(`You have ***accepted *** the challenge from ${challenger}. Please wait while your battlefield is made...`);
message.author.send(`${target} has accepted your challenge! Please wait while the channel is made for your brawl...`)
var server = message.guild;
var permsName = `${target} vs ${challenger}`;
var name = `${target} vs ${challenger}`;
message.guild.createRole({
data: {
name: permsName,
hoist: true,
color: "#00fffa",
permissions: [] }
}).then(role => {
target.addRole(data, permsName)
challenger.addRole(role, permsName)
// client.catch error occurring below
.catch(error => client.catch(error))
}).catch(error => client.catch(error)).then(
server.createChannel(name, "text")).then(
(channel) => {
channel.setParent("542070913177485323")
})
} else if (reply.content === 'deny') {
reply.channel.send("You have ***denied *** the challenge.")
} else {
reply.channel.send("Your response wasn't valid.");
}
})
})
}
module.exports.help = {
name: "challenge"
}
I have tried looking up the problem and I don't see anything that has helped so far with either issue. They might be related since the catch is after the add role part? Thanks in advance for the help!
Curious if there's a template you copied for this bot? The Discord.Client object does not have any catch method, so calling client.catch() is not going to work.
To clarify, this is fine:
challenger.addRole(role, permsName)
.catch(error => /* do something with this error */);
What can you do with the error? You could print it to console, I suppose:
challenger.addRole(role, permsName)
.catch(error => console.error(error));
But you can't call client.catch(error), because that's not a real method - you can check out the docs for the Client object here.
Regarding the role name, you just have a small error: you don't want to wrap your options object in { data: }, your options object is the data. Just pass them in directly, like so:
message.guild.createRole({
name: permsName,
hoist: true,
color: "#00fffa",
permissions: []
}).then(role => {
Hope that helps!
I'm using React v 16.3.2 and am building an app to communicate orders with a DB on Firebase, also using axios 0.18.0.
I'm expecting that once I hit a certain button (continue) it will create this spinner effect on the screen as it loads, so I have the following code:
purchaseContinueHandler = () => {
this.setState = ({loading: true});
const order = {
ingredients: this.state.ingredients,
price: this.state.totalPrice,
customer: {
name: 'Name',
address: {
street: 'teststreet 1',
zipCode: '86753',
country: 'U.S.'
},
email: 'example#example.com'
},
deliveryMethod: 'fastest'
}
axios.post('/orders.json', order)
.then(response => { this.setState( { loading: false } );
})
.catch(error => {
this.setState( { loading: false } ); //**<--This is where i get the error**
});
}
I run it and hit Continue on the app and get the error:
Unhandled Rejection (TypeError): _this.setState is not a function
and it points to the line listed above.
Ran into this documentation and tried to implement the solution that worked for him (create a constructor() and bind this to this) but that didn't work.
I was reading that this was no longer automatically added to the function but not sure what to do with that information, I'm pretty new to React still.
Any advice?
You are assigning an object to setState in the first line of code, so when you try to call it later it no longer is a function...
this.setState = ({loading: true});
should be
this.setState({loading: true})
The setState is a function, you change it to an JavaScript Object, I guess it's a tiny mistake, you have to write:
this.setState({loading: true})
Use it not change it to other things.
I am trying to update a Stripe account to add an external account token to be charged later as shown in the example here.
var stripe = require("stripe")("sk_test_xxxxxxxxxxxxx"),
knex = require("knex")(config);
router.post("/paymentcardinfo",middleware.isLoggedIn,function(req,res){
knex("users.stripe").select("stripe_id_key")
.then((stripeID) => {
stripeID = stripeID[0].stripe_id_key;
console.log("My Stripe ID: "stripeID);
console.log("stripeID var type:", typeof stripeID);
stripe.accounts.update({
stripeID,
external_account: req.body.stripeToken,
}, function(err,acct) {
if(err){
console.log(err);
} else {
console.log("SUCCESS ********",acct);
// asynchronously called
}})
})
.catch((e) => {
console.log(e);
res.redirect("/paymentcardinfo")
});
});
Which returns the following
My Stripe ID: acct_xxxxxxxxxxxxx
stripeID var type: string
[Error: Stripe: "id" must be a string, but got: object (on API request to `POST /accounts/{id}`)]
where acct_xxxxxxxxxxx is the user's stored account ID. Based on the first console.log value, it would appear that stripeID is a string and not an object, which makes me unsure of how to proceed with this error.
Although the documentation specifies
stripe.accounts.update({
{CONNECTED_STRIPE_ACCOUNT_ID},
metadata: {internal_id: 42},
}).then(function(acct) {
// asynchronously called
});`
The following worked for me
stripe.accounts.update(
CONNECTED_STRIPE_ACCOUNT_ID,
{
metadata: {internal_id:42},
}
).then((account) => {
// response to successful action
I have the following code in my Model.js file.
Model.observe('loaded', (ctx, next) => {
const {
data,
options: {
user
}
} = ctx;
const owner = (user && data && user.uid === data.userId) || false;
console.log(
`${data.id}: loaded - access by ${user && user.name}, owner:${owner}`
);
if (!owner) {
delete data.testProp1;
}
console.log('returning: ', ctx.data);
next();
});
When I make a request, I see the following log output (server logs):
f3f9ffd6-14dc-42e5-94ba-503aa3426faa: loaded - access by User1, owner:false
returning:
{
testProp2: true,
id: 'f3f9ffd6-14dc-42e5-94ba-503aa3426faa',
userId: 'sfeywkKSuBTlf0DwE4ZOFd8RX5E3'
}
But then in the actual response the browser receives I actually get:
{
testProp1: true,
testProp2: true,
id: 'f3f9ffd6-14dc-42e5-94ba-503aa3426faa',
userId: 'sfeywkKSuBTlf0DwE4ZOFd8RX5E3'
}
Is there something in the documentation I am missing? Deleting the property is exactly what it shows in the Loopback docs here. Also, I actually see the modified data as the data property on the ctx object before calling next(). Anyone run into this issue or know some caveat to the docs that isn't explicitly stated?