Date parameters validation using Joi - javascript

I would validate a timestamp passed through query string. This is the routing code:
routing:
router.route('/:userId/:orchardId/:sTime/:eTime')
.get(authorize(LOGGED_USER), validate(getByInterval), controller.getByInterval);
I would validate the eTime parameter to have max value the actual timestamp
validation schema:
getByInterval: {
params: {
userId: Joi.string().regex(/^[0-9]+$/, 'numbers').required(),
orchardId: Joi.string().regex(/^[0-9]+$/, 'numbers').required(),
sTime: Joi.date().timestamp().required(),
eTime: Joi.date().timestamp('unix').max(moment().unix() * 1000),
}
test:
it('should get 200 when data are found', async () => {
const userId = 1;
const orchardId = 1;
const sTime = (moment().unix() * 1000) - 3000;
const eTime = moment().unix() * 1000;
return request(app)
.get(`/v1/data/${userId}/${orchardId}/${sTime}/${eTime}`)
.set('Authorization', `Bearer ${userAccessToken}`)
.expect(httpStatus.OK)
});
I tried in many ways but no one works... I receive this error:
error:
{"code":400,"message":"Validation error","errors":[{"field":"eTime","location":"params","messages":["\"eTime\" must be less than or equal to \"Thu Oct 12 2017 09:49:00 GMT+0200 (CEST)\""],"types":["date.max"]}]}

Related

How can I check if doc in mongodb past a day?

I have an API that gives me a token, that EXPIRES after 24hours.
I want to save it to my tokens collection, and check every time if it past a day, if so generate a new one.
I've installed moment package if its helps.
any suggestions?
My code:
try {
const getTheToken = await TokenModel.findOne({
name: 'theOPToken',
});
// const currentTime = Date.now();
// const previousTime = getTheToken.lastUpdate;
// const oneDay = 86400000; // 24 hours in milliseconds
if (currentTime + oneDay > previousTime) {
//! if so go and generate a new one .
//! and
await TokenModel.findOneAndUpdate(
{
name: 'theOPToken',
},
{
$set: {
accessToken: token,
lastUpdate: Date.now(),
},
}
);
}

Sequelize Validation with condition object

const db = require("../models");
const Meet = db.meet;
checkDuplicateTime = (req, res, next) => {
Meet.findAll({
where: {
tanggal: req.body.date,
waktu: req.body.time
}
}).then(time => {
if(time --- (1000 * 60 * 60) || time +++ (2000 * 60 * 60)) {
res.status(400).send({
message: "Failed! Time already use!!"
});
return;
}
next();
});
});
}
How to inspection data from already in database with condition isBetween before and after time??
in Frontend, I succeed to do it like this :
timedi() {
const timede = this.dateCheck.filter((item) => {
return moment(item.dates).isSame(new Date(this.dates), "day")
}).some((item)=> {
const format = 'hh:mm:ss'
const time = moment(this.time, format) // from input user
const beforeTime = moment(item.time, format).add(-1, 'hours') // from already database
const afterTime = moment(item.time, format).add(2, 'hours'); // from already database
if(time.isBetween(beforeTime, afterTime)) {
console.log('Ignore')
} else {
console.log('Allow')
}
})
},
Hope there is an answer. Thanks.
Source code :
const db = require("../models");
const Meet = db.meet;
checkDuplicateDate = (req, res, next) => {
const dates = req.body.dated;
const times = req.body.timed;
const date = moment(dates).tz('Asia/Jakarta').format('YYYY-MM-DD');
const time = moment(times, [moment.ISO_8601, 'HH:mm']).tz('Asia/Jakarta').format('HH:mm:ss');
const startTime = moment(time, [moment.ISO_8601, 'HH:mm']).add(-2, 'hours').tz('Asia/Jakarta').format('HH:mm:ss');
const beforeTime = moment(time, [moment.ISO_8601, 'HH:mm']).add(2, 'hours').tz('Asia/Jakarta').format('HH:mm:ss');
Meet.findOne({
where: {
tanggal: date,
waktu: {
[Op.between]: [startTime, beforeTime]
}
}
}).then(meet => {
if(meet) {
res.status(400).send({
message: "Failed! Time is booked!!"
})
return
}
next();
});
});
};
I hope in future, this case can help anyone. Thanks.

Axios get request with parameters to filter find certrain createdAt range in mongodb

I've in my react frontend multiple dates in an Array with this format 'MM/YYYY'
Now I want to get my history from MongoDB that's createdAt the time range of one month.
How can i pass my data in this axios get request?
My Frontend
let date = '11/2022'
const getHistory = async () => {
let monthYearStart = dayjs(date, 'MM/YYYY').format('YYYY.MM.01');
let monthYearEnd = dayjs(date, 'MM/YYYY').format('YYYY.MM.32');
const res = await axios.get('/api/monthlyhistory');
setPdfHistory(res.data);
};
getHistory().then(() => {});
My Backend
try {
const history = await History.find({
status: true,
createdAt: {
$gte: dayjs(new Date(monthYearStart, 'YYYY.MM.DD')),
$lt: dayjs(new Date(monthYearEnd, 'YYYY.MM.DD')),
},
});
res.json(history);
} catch (err) {
return res.status(500).json({ msg: err.message });
}
One option would be to pass the dates as query parameters. I would recommend using ISO 8601 format to remove ambiguity use the native Date constructor
Client-side
// Note these are local dates
const monthYearStart = new Date(2022, 10); // month is a zero-based index
const monthYearEnd = new Date(monthYearStart);
monthYearEnd.setMonth(monthYearEnd.getMonth() + 1);
monthYearEnd.setDate(monthYearEnd.getDate() - 1);
const res = await axios.get("/api/monthlyhistory", {
params: {
monthYearStart: monthYearStart.toISOString(),
monthYearEnd: monthYearEnd.toISOString(),
},
});
Server-side
const { monthYearStart, monthYearEnd } = req.query;
const history = await History.find({
status: true,
createdAt: {
$gte: new Date(monthYearStart),
$lt: new Date(monthYearEnd),
},
});

How to get next occurance of an rrule for different timezones

I have an app that allows users to schedule tasks. Users can set a schedule (schedule, an rrule string) as well as a timezone (scheduleTimeZone, a string e.g. Asia/Dubai).
I am trying to write a function (getNextRunAt) that gets the next occurrence of the task at a UTC date and store this in my Postgres DB as a timestamptz field.
I'm struggling to account for DST, lots of the results are an hour or even a day off.
Here's the function (in TypeScript):
import RRule from 'rrule';
import moment from 'moment-timezone';
const getNextRunAt = ({
schedule,
scheduleTimeZone,
}: {
schedule?: string | null;
scheduleTimeZone?: string | null;
}): Date | undefined => {
if (!schedule) {
return undefined;
}
const options = RRule.parseString(schedule);
if (scheduleTimeZone) {
options.tzid = scheduleTimeZone;
}
const dtstart = moment.utc().toDate();
const rule = new RRule({ ...options, dtstart, count: 1 });
const dates = rule.all();
let date = dates[0];
if (scheduleTimeZone && moment(date).tz(scheduleTimeZone).isDST()) {
date = moment(date).subtract(1, 'hour').toDate();
}
return date;
};
export default getNextRunAt;
It works for some dates/times/timezones:
Date.now = jest.fn(() => new Date('2021-03-02 10:24:27.000000Z').getTime());
const nextDate = getNextRunAt({
schedule: 'RRULE:INTERVAL=1;BYDAY=MO,TU,WE,TH,SA,FR,SU;BYMINUTE=0;BYHOUR=9;BYSECOND=0;FREQ=DAILY',
scheduleTimeZone: 'America/Los_Angeles',
});
expect(nextDate).toEqual(new Date('2021-03-02 17:00:00.000000Z'));
// WORKS
But not for others:
Date.now = jest.fn(() => new Date('2021-03-02 10:24:27.000000Z').getTime());
const nextDate = getNextRunAt({
schedule: 'RRULE:INTERVAL=1;BYDAY=MO,TU,WE,TH,SA,FR,SU;BYMINUTE=0;BYHOUR=9;BYSECOND=0;FREQ=DAILY',
scheduleTimeZone: 'America/Los_Angeles',
});
expect(nextDate).toEqual(new Date('2021-03-02 17:00:00.000000Z'));
// DOES NOT WORK
Expected: 2021-03-02T17:00:00.000Z
Received: 2021-03-03T17:00:00.000Z
I think that the last case is wrong with a day. But for others solution might look like:
const getNextRunAt = ({ schedule, scheduleTimeZone }: { schedule?: string | null; scheduleTimeZone?: string | null }): Date | undefined => {
if (!schedule) {
return undefined;
}
const options = RRule.parseString(schedule);
const dtstart = moment();
const rule = new RRule({
...options,
dtstart: dtstart.toDate(),
count: 1,
});
const dates = rule.all();
const date = dates[0];
let mDate = moment.tz(date, scheduleTimeZone);
const offset = Math.abs(mDate.utcOffset()) > 16 ? mDate.utcOffset() / 60 : mDate.utcOffset();
if (!mDate.isDST()) {
mDate = mDate.add(1, 'hours');
}
mDate.add(-offset, 'hour');
return mDate.toDate();};

Why does my JWT expiresIn value change between sending it from the server and receiving it on the front-end?

I set my token expiry date on the server and console.log out the value to check:
However, when I check the value on my React front-end, I get this value:
I don't alter the expiry date in any way but the value is changed dramatically between sending it and receiving it.
Does anyone have any ideas?
Server code
const d = new Date();
console.log(
'current date: ',
moment(d.getTime()).format('YYYY-MM-DD HH:mm:ss')
);
/*const calculatedExpiresIn =
d.getTime() +
60 * 60 * 1000 -
(d.getTime() - d.getMilliseconds()) / 1000;*/
const calculatedExpiresIn = d.getTime() + 60 * 60 * 1000;
console.log(
'calculatedExpiresIn: ',
moment(calculatedExpiresIn).format('YYYY-MM-DD HH:mm:ss')
);
console.log('calculatedExpiresIn: ', calculatedExpiresIn);
const iat = d.getTime();
const user = ok([
{
id: res[0].id,
token: jwt.sign(
{
id: res[0].id,
email: res[0].email,
firstName: res[0].firstName,
surname: res[0].surname,
role: res[0].role,
iat: iat,
},
config.secret,
{
expiresIn: calculatedExpiresIn,
}
),
},
]);
Front-end code
validateSession() {
let token = sessionStorage.getItem('unikey');
const d = new Date();
if (token && token !== undefined) {
let decodedToken = jwtDecode(token);
/*console.log('decodedToken: ', decodedToken);
console.log(
'decodedToken iat date: ',
moment(decodedToken.iat).format('YYYY-MM-DD HH:mm:ss')
);*/
console.log(
'decodedToken expiry date: ',
moment(decodedToken.exp).format('YYYY-MM-DD HH:mm:ss')
);
console.log(
'current date: ',
moment(d.getTime()).format('YYYY-MM-DD HH:mm:ss')
);
console.log('decodedToken expiry date: ', decodedToken.exp);
console.log('current date: ', d.getTime());
console.log('Time difference: ', decodedToken.exp - d.getTime());
if (d > decodedToken.exp) {
console.log('Time is up...');
this.terminateSession();
return false;
}
return true;
} else {
// There is no token so session is automatically invalid
this.terminateSession();
return false;
}
}
Token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NDQsImVtYWlsIjoidGVzdEBlbWFpbC5jb20iLCJmaXJzdE5hbWUiOiJ0ZXN0Iiwic3VybmFtZSI6InVzZXIiLCJyb2xlIjoiYWdlbnQiLCJpYXQiOjE2MTg1NTYyOTE3MzAsImV4cGlyeSI6MTYxODU1OTg5MTczMCwiZXhwIjozMjM3MTE2MTgzNDYwfQ.nUrUFzyyP9POBTklc8ISXamJIz8D9vaUOIdS81_F9FY
The decoded payload is:
{
...
"iat": 1618556291730,
"expiry": 1618559891730,
"exp": 3237116183460
}
There are two things wrong:
The format of the timestamps is wrong, because it's supposed to be in seconds (10 digit number) instead of milliseconds (13 digits) (see NumericDate in RFC7519).
The the expiration time is (aside from the factor 1000) twice as high as expected.
The reason for that is a wrong calculation of the expiresIn parameter in you call to jwt.sign. The parameter is supposed to be a timesspan, e.g. { expiresIn: 60 * 60 } or { expiresIn: "1h" } for one hour, instead of a timestamp.
The sign function will then add the timespan from the parameter to the current time to calculate the correct exp.

Categories

Resources