Error: Timezone "gmt+0200" is not recognized - node.js

I've got a problem.
I'm trying to "transfer" some data from one table to each other through *.js file. Everything goes fine, except one thing. This function shows me:
Error: Timezone "gmt+0200" is not recognized
This is my function
async function submitCompletationCG(database, ulogin, idc) {
await connectToSpecificDatabase(database);
const AC_ID = `SELECT * FROM public.cg_actualcompletations WHERE UserLogin = '`+ulogin+`';`;
let AC_IDs = await client.query(AC_ID);
const ACC_ID = `SELECT * FROM public.cg_actualcompletationscondensed WHERE UserLogin = '`+ulogin+`';`;
let ACC_IDs = await client.query(ACC_ID);
const DEPOT = `SELECT * FROM public.cg_actualdepots WHERE UserLogin = '`+ulogin+`';`;
let DEPOTs = await client.query(DEPOT);
let depot_from, depot_to, code_from, code_to;
for(let Depot of DEPOTs.rows) {
depot_from = Depot.depot_from;
depot_to = Depot.depot_to;
code_from = Depot.code_from;
code_to = Depot.code_to;
}
for(let Completation of ACC_IDs.rows) { //Transfer all Completations Condensed
const ACC_Copy = `INSERT INTO public.cg_completationscondensed(
id_c, userlogin, barcode, quantity, adate)
VALUES ('`+idc+`', '`+ulogin+`', '`+Completation.barcode+`', '`+Completation.quantity+`', '`+Completation.adate+`');`;
await client.query(ACC_Copy);
const ACC_Delete = `DELETE FROM public.cg_actualcompletationscondensed
WHERE id = `+Completation.id+`;`;
await client.query(ACC_Delete);
}
for(let Completation of AC_IDs.rows) { //Transfer all Completations
const AC_Copy = `INSERT INTO public.cg_completations(
id_c, userlogin, barcode, quantity, adate)
VALUES ('`+idc+`', '`+ulogin+`', '`+Completation.barcode+`', '`+Completation.quantity+`', '`+Completation.adate+`');`;
await client.query(AC_Copy);
const AC_Delete = `DELETE FROM public.cg_actualcompletations
WHERE id = `+Completation.id+`;`;
await client.query(AC_Delete);
}
const SUB_UArch = `INSERT INTO public.cg_userarch(
userlogin, id_c, depot_from, depot_to, code_from, code_to)
VALUES ('`+ulogin+`', '`+idc+`', '`+depot_from+`', '`+depot_to+`', '`+code_from+`', '`+code_to+`');`;
await client.query(SUB_UArch);
const SUB_DKill = `DELETE FROM public.cg_actualdepots WHERE UserLogin = '`+ulogin+`';`;
await client.query(SUB_DKill);
return true;
}
Sould I set timezone somewhere in angular files? Or it's problem with database? Forgot to say I'm using PostgreSQL. ADate column is type "timestamp without time zone", earlier it was "timestamp with time zone" but I thought it causes the problem and I changed it.
I get this problem in this line:
for(let Completation of ACC_IDs.rows) { //Transfer all Completations Condensed
const ACC_Copy = `INSERT INTO public.cg_completationscondensed(
id_c, userlogin, barcode, quantity, adate)
VALUES ('`+idc+`', '`+ulogin+`', '`+Completation.barcode+`', '`+Completation.quantity+`', '`+Completation.adate+`');`;
await client.query(ACC_Copy);
const ACC_Delete = `DELETE FROM public.cg_actualcompletationscondensed
WHERE id = `+Completation.id+`;`;
await client.query(ACC_Delete);
}
and in next for loop, because there are operation on date too.

I solved this problem. I cannot find answer anywhere on the internet so I do it on my own. I added this two lines at the start of the for loop:
let date = new Date(Completation.adate);
date = date.toLocaleDateString() + " " + date.toLocaleTimeString();
and then changed db query to:
const ACC_Copy = `INSERT INTO public.cg_completationscondensed(
id_c, userlogin, barcode, quantity, adate)
VALUES ('`+idc+`', '`+ulogin+`', '`+Completation.barcode+`', '`+Completation.quantity+`', '`+date+`');`;
and now it works fine, finally!

You are injecting the result of Date() type/value to a query. Converting it ISO string solves my issue.

Related

How to change code to prevent SQL injection in typeorm

I am writing code using nestjs and typeorm.
However, the way I write is vulnerable to SQL injection, so I am changing the code.
//Before
.where(`userId = ${userId}`)
//After
.where(`userId = :userId` , {userId:userId})
I am writing a question because I was changing the code and couldn't find a way to change it for a few cases.
//CASE1
const query1 = `select id, 'normal' as type from user where id = ${userId}`;
const query2 = `select id, 'doctor' as type from doctor where id = ${userId}`;
const finalQuery = await getConnection().query(`select id, type from (${query1} union ${query2}) as f limit ${limit} offset ${offset};`);
//CASE2
...
.addSelect(`CASE WHEN userRole = '${userRole}' THEN ...`, 'userType')
...
//CASE3 -> to find search results in order of accuracy
...
.orderBy(`((LENGTH(user.name) - LENGTH((REPLACE(user.name, '${keyword.replace( / /g, '', )}', '')))) / LENGTH('${keyword.replace(/ /g, '')}'))`,
'ASC')
...
//CASE4
let query = 'xxxx';
let whereQuery = '';
for(const i=0;i<5;i++)
whereQuery += ' or ' + `user.name like '%${keyword}%'`
query.where(whereQuery)
I cannot use parameter in the select function.
In the above case, I am wondering how to change it.
Is it ok to not have to modify the select code?

TypeScript NodeJS application Error: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.ts(7017)

This is time.ts file:
exports.getMinute = (timestamp: number) => {
const milliSecond = timestamp * 1000;
const dateObject = new Date(milliSecond);
const minute = dateObject.toLocaleString('en-us',{minute : "number"});
return minute;
};
exports.getHour = (timestamp: number) => {
const milliSecond = timestamp * 1000;
const dateObject = new Date(milliSecond);
const hour = dateObject.toLocaleString('en-us',{hour : "number"});
return hour;
};
exports.getDay = (timestamp: any) => {
const milliSecond = timestamp ;
const dateObject = new Date(milliSecond);
const day = dateObject.getDate();
return day;
};
exports.getMonth = (timestamp: any) => {
const milliSecond = timestamp ;
const dateObject = new Date(milliSecond);
const month = dateObject.getMonth();
return month;
};
exports.getYear = (timestamp: any) => {
const milliSecond = timestamp ;
const dateObject = new Date(milliSecond);
const year = dateObject.getFullYear();
return year;
};
exports.fullTime = (timestamp: any) => {
let day = this.getDay(timestamp);
const year = this.getYear(timestamp);
let month = this.getMonth(timestamp);
month ++
return `${year}`+'-'+`${month<=9 ? '0'+ month : month }` + '-' + `${day<=9 ? '0'+ day : day }`;
};
I get the following errors:
Element implicitly has an 'any' type because type 'typeof globalThis'
has no index signature.ts(7017)
Element implicitly has an 'any' type because type 'typeof globalThis'
has no index signature.ts(7017)
Element implicitly has an 'any' type because type 'typeof globalThis'
has no index signature.ts(7017)
For these lines of code:
let day = this.getDay(timestamp);
const year = this.getYear(timestamp);
let month = this.getMonth(timestamp);
Also these errors:
Type '"number"' is not assignable to type '"numeric" | "2-digit" |
undefined'.ts(2322)
Type '"number"' is not assignable to type '"numeric" | "2-digit" |
undefined'.ts(2322)
At these lines of the code:
const minute = dateObject.toLocaleString('en-us',{minute : "number"});
const hour = dateObject.toLocaleString('en-us',{hour : "number"});
I don't know what does it mean and how can I fix them?
There are a few things you can do to remove the errors.
exports. is more of a javascript construct, which you usually don't use with typescript. So, I would replace it with export const in all cases in your file, for example:
export const getDay = (timestamp: any) => {
const milliSecond = timestamp;
const dateObject = new Date(milliSecond);
const day = dateObject.getDate();
return day;
};
Regarding usage of this, you usually want to use this when you are located in context of a class, but in your case you have separate functions. So, after changing all export statements, just call the functions directly:
let day = getDay(timestamp);
const year = getYear(timestamp);
let month = getMonth(timestamp);
As for toLocaleString, this is typescript trying to tell you that the value number that you used for minute and hour properties is not a correct value that it supports, and it suggests that you replace it with either numeric, 2-digit, or just not define it (which defaults to undefined). So, statements like this should work:
const minute = dateObject.toLocaleString('en-us', { minute: 'numeric' });
const hour = dateObject.toLocaleString('en-us', { hour: 'numeric' });
IDE usually also gives you hints, for example hovering over a property would tell you what type that property expects. In case of minute it looks like this, which is a union type of 2 string values or undefined. Try hovering over other properties to give you a better idea of what type they expect.
Hope this helps :)

Firebase NodeJS SDK: Query by value on nested object

I have a collection/table that is structured like this:
{
UsedPromos: {
"userid_1": {
"product_1_1": "promo_1_1",
"product_1_2": "promo_1_2",
...
"product_1_n": "promo_1_n",
},
"userid_2": {
"product_2": "promo_2"
},
...
"userid_m": {
...
}
}
}
How can I query an exact match to some "promo_x_y"? I have tried this so far:
const admin = require("firebase-admin");
admin.initializeApp(...);
const ref = admin.database().ref("/UsedPromos");
ref.orderByValue()
.equalTo("promo_x_y")
.once("child_added")
.then((snapshot) => {
console.log(`{key: ${snapshot.key}, value: ${snapshot.val()}}`);
return snapshot
});
But it didn't return anything.
If you are looking for all products that are part of the promotion promo_x_y, you need to adjust your query one level deeper than what you are currently doing.
Currently you are comparing the values of user_1, user_2, and so on to the value "promo_x_y". You get no results, because no entry /UsedPromos/user_1 = "promo_x_y" exists.
/UsedPromosByUser/{user}/{product} = {promo} (your current structure)
To fix this, you will need to search an individual user's list of products. Using the below snippet will log each product that has a value of "promo_x_y".
const admin = require("firebase-admin");
admin.initializeApp(/* ... */);
const ref = admin.database().ref("/UsedPromos");
const userToSearch = "user_1";
ref.child(userToSearch)
.orderByValue()
.equalTo("promo_x_y")
.once("child_added")
.then((snapshot) => {
// snapshot.val() will always be "promo_x_y", so don't bother logging it.
console.log(`${snapshot.key} uses "promo_x_y"`);
return snapshot;
});
Depending on your use case, it may be better to use a "value" event instead.
const admin = require("firebase-admin");
admin.initializeApp(/* ... */);
const ref = admin.database().ref("/UsedPromos");
const userToSearch = "user_1";
ref.child(userToSearch)
.orderByValue()
.equalTo("promo_x_y")
.once("value")
.then((querySnapshot) => {
const productKeys = [];
// productSnapshot.val() will always be "promo_x_y", so don't bother logging it.
querySnapshot.forEach((productSnapshot) => productKeys.push(productSnapshot.key));
console.log(`The following products have a value of "promo_x_y" for user "${userToSearch}": ${productKeys.join(", "}`);
return productKeys;
});
If you are looking to find all products, across all users, that use "promo_x_y", you should create an index in your database instead of using a query.
/UsedPromosByPromo/{promo}/{user}/{product} = true
OR
/UsedPromosByPromo/{promo}/{product}/{user} = true
Instead of using true in the above structure, you could store a timestamp (time of purchase, time promo expires, etc)

Array list with 2 values and doing it to a top 10 list

im working on a Discord bot and have a reputation system with fs (npm package) and saving peoples reps in a file and doing the file name as they discord id
now im working on a top 10 command and would need some help here, i currently have this as code:
let users = [];
let reps = [];
fs.readdirSync('./data/reps/').forEach(obj => {
users.push(obj.replace('.json', ''))
let file = fs.readFileSync(`./data/reps/${obj}`)
let data = JSON.parse(file)
reps.push(data.reps)
})
let top = [...users, ...reps]
top.sort((a,b) => {a - b})
console.log(top)
the files form the users are like this:
{
"users": [
"437762415275278337"
],
"reps": 1
}
users are the current users that can't rep the persion anymore and don't need to use it in the command
i wan to get the top 10 of reps so that i can get the user id and how many reps they have, how could i do it with the code above?
You could try this
const topTen = fs.readdirSync('./data/reps/').map(obj => {
const file = fs.readFileSync(`./data/reps/${obj}`);
const data = JSON.parse(file);
return { ...data, name: obj.replace('.json', '') };
}).sort((a, b) => a.reps - b.reps).slice(0, 10);
console.log(topTen);
I would change how you push the data
const users = [];
fs.readdirSync('./data/reps/').forEach(obj => {
let file = fs.readFileSync(`./data/reps/${obj}`)
let data = JSON.parse(file)
reps.push({ reps: data.reps, id: obj.replace(".json", "") });
})
That way when you sort the array the id goes along with
//define this after the fs.readdirSync.forEach method
const top = users.sort((a,b)=> a.reps-b.reps).slice(0,10);
If you want an array of top ids
const topIds = top.map(e => e.id);
If you want a quick string of it:
const str = top.map(e => `${e.id}: ${e.reps}`).join("\n");
Also you should probably just have one or two json files, one would be the array of user id's and their reps and then the other could be of user id's and who they can't rep anymore

Deleting records on a database

I have a logging command which works perfectly, the only issue is I can not finish the off section of the command. I need it to delete both records (guildid, channel) if the guildid matches.
This is what I have tried.
if (args[0] === 'off') {
message.channel.send('Logging turned off!');
const del = db.prepare('DELETE FROM logging WHERE guildid = ?;');
del.run({
guildid: `${message.guild.id}`
});
return;
Looking at the photo, when the args off is ran, I need it to delete the guildid contents (495602...) and channel contents (<#5290...) if the guildid contents matches with the guild the command was ran in.
Your current answer is the incorrect way to use prepared statement. If you use the way you pose, you open yourself up to SQL injection because you aren't interpreting the value you want to use in the statement as a value, you use it as part of the overall statement and then run the statement without parameters. That means that I could potentially provide a value that might not do exactly what you think it will.
For example the following won't do anything,
const $rowid = "3 OR rowid = 4";
const deleteStatement = db.prepare("DELETE FROM lorem WHERE rowid = $rowid");
deleteStatement.run({$rowid});
deleteStatement.finalize();
But this will delete elements with rowid 3 or 4:
const $rowid = "3 OR rowid = 4";
const deleteStatement = db.prepare(`DELETE FROM lorem WHERE rowid = ${$rowid}`);
deleteStatement.run();
deleteStatement.finalize();
Instead, take a look at the sqlite3 documentation here.
You need to actually paramaterize your prepared statement like the following:
const sqlite3 = require("sqlite3").verbose();
const db = new sqlite3.Database(":memory:");
db.serialize(function() {
// Make the table
db.run("CREATE TABLE lorem (info TEXT)");
// Create some dummy data
const insertStatement = db.prepare("INSERT INTO lorem VALUES (?)");
for (let i = 0; i < 5; i++) {
insertStatement.run(`My Data ${i}`);
}
insertStatement.finalize();
// Delete some data
const deleteStatement = db.prepare("DELETE FROM lorem WHERE rowid = $rowid");
deleteStatement.run({
$rowid: 3
});
deleteStatement.finalize();
// Print elements
db.each("SELECT rowid AS id, info FROM lorem", (err, {id, info}) => console.log(`${id}: ${info}`));
});
db.close();
For anyone in the future looking how to do this, this was the answer.
EDIT: Can't mark as an answer until 2 days lol
if (args[0] === 'off') {
message.channel.send('Logging turned off!');
db.prepare(`DELETE FROM logging WHERE guildid = '${message.guild.id}'`).run();
return;
Late to the better-sqlite3 party:
const del = db.prepare('DELETE FROM logging WHERE guildid = ?');
del.run(message.guild.id)

Resources