How do I restrict hours of operation in a rest-based API function? - amazon-web-services

I have an API integration for our web store running on AWS Lambda to return live delivery quotes based on customer address, and then create the delivery order to a third party delivery as a service provider when the invoice is completed (paid).
I was able to add a time restriction for Monday-Saturday but Sunday has different hours and is not working. Here is the relevant code:
'use strict'
/**
* This function is use to generate qoutes to client 1st warehouse
*/
exports.handler = function (event, context, callback) {
console.log('-------------------EVENT OBJECT--------------------------')
// console.log(event.body.shipping_address)
console.log(event)
try {
const app = require('./app')
const EventEmitter = require('events').EventEmitter
const _bus = new EventEmitter()
let date = new Date()
if (date.getDay() == 0) {
if (!(date.getHours() >= 17 && date.getHours() <= 22) || !(date.getHours() < 3)) {
callback(null, {
message: 'The store is closed'
})
}
} else {
if (date.getHours() >= 3 && date.getHours() <= 15) {
callback(null, {
message: 'The store is closed'
})
}
}
let _shipmentReturn = []
let _shipmentReturnError = []
}
catch(e) {
}
}

Be very careful when using NOT logic.
Your 'normal' days have the store closed from 3am to 4pm. (Yes, 4pm. That's because you only check hours, so 3:59pm is still an 'hour' of 3, so it would be closed.)
On Sunday, the store is closed from midnight to 4:59pm, and also 10pm to midnight.
Take a look at this line:
if (!(date.getHours() >= 17 && date.getHours() <= 22) || !(date.getHours() < 3)) {
Let's pick a time of 2am. It equates to:
if (!(FALSE) || !(TRUE))
This equals TRUE, so the store is closed.
Same for 4am: if (!(FALSE) || !(FALSE)) also equals TRUE
You possibly want an AND rather than an OR in those logic statements.
I would also recommend that you convert the UTC times into your "local" times, which would make it easier for you to write the logic. This will avoid errors where UTC Sunday does not actually align to your 'local' Sunday. For example, if you are UTC-6, then 2am UTC Sunday is not Sunday in your timezone.

Related

Alarm Manager stops trigger PendingIntent after few moments

I try to create reminder app. My aim is to trigger notification every hour. I have used Alarm Manager to achieve it. Everything works correctly for first 2-3 hours. After that time notifications stop being deliveried. If I reopen app I get missing notification imediatelly.
Alarm Manager:
val intent = Intent(context, AlarmReceiver::class.java).apply {
action = context.getString(R.string.alarm_pending_action)
}
val alarmIntent = PendingIntent.getBroadcast(context, 0, intent, FLAG_UPDATE_CURRENT)
val datetimeToAlarm = Calendar.getInstance()
.apply {
set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
datetimeToAlarm.timeInMillis,
60 * 60 * 1000,
alarmIntent
)
AlarmReceiver:
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != null) {
if (intent.action!!.equals(context.getString(R.string.alarm_pending_action), ignoreCase = true)) {
NotificationHelper.createNotification(context)
}
}
}
AndroidManifest
<receiver android:name=".alert.AlarmReceiver"/>
Thank you for your help
I solved my problem. Solution is to replace setRepeating by setAlarmClock and it works well.

Google Datastore Pagination

I am trying to use the cursor to implement pagination but when I try to use the endCursor that is returned after my first query (queries 10 records), it gives me an error "invalid encoding". By the way I have a total of 16 records. I am expecting that on my next query, it will give me the last 6 records
Here's my code:
router.get("/scan/history/query", async (req: Request, resp: Response) => {
const userId = resp.locals.user && resp.locals.user.sub
const pageCursor = req.query.cursor
if (userId) {
let mainQuery = dataStoreClient.createQuery(process.env.GOOGLE_DATASTORE_KIND_SCAN_RESULTS)
.filter("userId", QUERY_FILTER_OPERATORS.EQUAL, userId)
.filter("isDeletedDocument", QUERY_FILTER_OPERATORS.EQUAL, false)
.select(["__key__", "scanDate", "scanKeyword", "scanFilter",
"hasRecord", "scanThreatStatus", "scanDuration",
"scanType", "scanStatus", "domainName"])
.order("scanDate", { descending: true })
.limit(10)
if (pageCursor) {
mainQuery = mainQuery.start(pageCursor)
}
const results = await mainQuery.run()
const entities = results[0]
const info = results[1]
const hasNextPage = info.moreResults !== "NO_MORE_RESULTS"
const pageResult = new PageResult(entities, info.endCursor, hasNextPage)
return HttpResult.Ok(resp, pageResult)
}
return HttpResult.UriNotFound(resp)
})
UPDATE:
I tried this with thousands of records and my limit is still 10. It works perfectly for like 2 or 3 queries but when I tried to query for the fourth time, it throws me an error "invalid encoding"
I know this is old, but in case anyone else comes across this issue (as I just did), I was able to resolve it by encoding the cursor value using encodeURIComponent(). It looks like the cursor value occasionally contains a + character, which causes issues when not escaped in the URL

Quartz.net daily jobs keeps getting executed every minute

I have the code below. I would expect it to run daily at 17:00 if the config setting was not set otherwise the config setting will be used. So far no issue, the variable is set correctly. However: Instead of daily the job gets executed every minute and I cant figure out why. Is the scheduler not set up correctly?
TimeSpan timeOfExecution;
if (!TimeSpan.TryParse(ConfigurationManager.AppSettings["TimeOfExecution"], out timeOfExecution))
{
timeOfExecution = new TimeSpan(17, 0, 0);
}
var job = JobBuilder.Create<DailyReportJob>()
.WithIdentity("DailyReportJob")
.Build();
var trigger = TriggerBuilder.Create()
.WithIdentity("DailyReportTrigger")
.WithDailyTimeIntervalSchedule(s => s.OnEveryDay().StartingDailyAt(new TimeOfDay(timeOfExecution.Hours, timeOfExecution.Minutes)))
.Build();
Scheduler.ScheduleJob(job, trigger);
Scheduler.ListenerManager.AddJobListener(AutofacJobListener);
Scheduler.Start();
The default time for this trigger is every minute, since you haven't specified otherwise.
You can check all the intervals using this code:
var dt = trigger.GetNextFireTimeUtc();
for (int i = 0; i < 10; i++)
{
if (dt == null)
break;
Console.WriteLine(dt.Value.ToLocalTime());
dt = trigger.GetFireTimeAfter(dt);
}
If you want to schedule your job to run once a day at 5pm, you can change your code adding a 24 hour interval:
var trigger = TriggerBuilder.Create()
.WithIdentity("DailyReportTrigger")
.WithDailyTimeIntervalSchedule(s => s.OnEveryDay().StartingDailyAt(new TimeOfDay(timeOfExecution.Hours, timeOfExecution.Minutes)))
.WithIntervalInHours(24)
.Build();

ColdFusion - Get next scheduled task due to run

This thread was useful in finding out the next run-time for a scheduled task.
How do I find out the next run time for a Scheduled Task?
But, is there also a way to simply get the next scheduled task due to run?
If I can get the date and name of the next task due to run, I can plug that date into a jQuery countdown timer, which will display a countdown to the next scheduled task, something like:
TaskABC due to run in:
12 03 20
hrs min sec
. This is for an admin interface in case you're wondering how geeky can people get:-)
EDIT
I had the same thought as Bill. But was curious if there was another way.
I poked around and apparently the internal Scheduler class maintains a list of upcoming tasks. The list is private, but you can use the same reflection technique to access it. Interestingly the list also includes system tasks like the mail spooler, session/application trackers, watchers, etecetera. So you must iterate through it until you find a "scheduled task" ie CronTabEntry
Below is a very lightly tested function that seems to do the trick in CF9. (Note, includes the CreateTimeStruct function from http://www.cflib.org).
Rules:
Returns a structure containing the name and time remaining until the next task. If no tasks were found, result.task is an empty string.
Excludes paused tasks
Usage:
result = new TaskUtil().getNextTask();
WriteDump(result);
CFC
component {
public struct function getNextTask() {
// get list of upcoming tasks from factory (UNDOCUMENTED)
local.scheduler = createObject("java", "coldfusion.server.ServiceFactory").getSchedulerService();
local.taskField = local.scheduler.getClass().getDeclaredField("_tasks");
local.taskField.setAccessible( true );
local.taskList = local.taskField.get(local.scheduler);
// taskList contains system jobs too, so we must iterate
// through the tasks to find the next "scheduled task"
local.nextTask = "";
local.tasks = local.taskList.iterator();
while ( local.tasks.hasNext() ) {
local.currTask = local.tasks.next();
local.className = local.currTask.getRunnable().getClass().name;
// exit as soon as we find a scheduled task that is NOT paused
if (local.className eq "coldfusion.scheduling.CronTabEntry"
&& !local.currTask.getRunnable().paused) {
local.nextTask = local.currTask;
break;
}
}
// if we found a task, calculate how many days, hours, etcetera
// until its next run time
local.details = { task="", remaining={} };
if ( isObject(local.nextTask) ) {
local.secondsToGo = (local.nextTask.getWhen() - now().getTime()) / 1000;
local.details.task = local.nextTask.getRunnable().task;
local.details.remaining = createTimeStruct(local.secondsToGo);
local.details.nextDate = dateAdd("s", local.nextTask.getWhen() / 1000
, "January 1 1970 00:00:00" );
}
return local.details;
}
/**
* Abbreviated version of CreateTimeStruct by Dave Pomerance
* See http://www.cflib.org/index.cfm?event=page.udfbyid&udfid=421
*
* #param timespan The timespan to convert.
* #return Returns a structure.
* #author Dave Pomerance
* #version 1, January 7, 2002
*/
public struct function CreateTimeStruct(required numeric timespan) {
var timestruct = StructNew();
var mask = "s";
// only 4 allowed values for mask - if not one of those, return blank struct
if (ListFind("d,h,m,s", mask)) {
// compute seconds
if (mask eq "s") {
timestruct.s = (timespan mod 60) + (timespan - Int(timespan));
timespan = int(timespan/60);
mask = "m";
} else timestruct.s = 0;
// compute minutes
if (mask eq "m") {
timestruct.m = timespan mod 60;
timespan = int(timespan/60);
mask = "h";
} else timestruct.m = 0;
// compute hours, days
if (mask eq "h") {
timestruct.h = timespan mod 24;
timestruct.d = int(timespan/24);
} else {
timestruct.h = 0;
timestruct.d = timespan;
}
}
return timestruct;
}
}
My first thought is to iterate Leigh's getNextRunTime(string taskName) function over the collection of tasks. You can get an array of structs containing the details of all scheduled tasks using taskArray = createobject("java","coldfusion.server.ServiceFactory").getCronService().listAll();
The key in the struct containing the task name is "task". So you can extract all the task names as an array for example, run Leigh's function on each element and determine which one will run next.

Replicating Google Analytics DateRange picker

I need to replicate the Google Analytics date picker (plus a few new options). Can anyone tell me how to highlight all the cells on a calendar between two dates. My basic JavaScript is OK but I think I'm getting a bit out of my depth.
I'm using JQuery 1.5.1 and JQuery UI 1.8.14.
In needed to replicate Google Analytics date picker as well. I know you were asking just about highlighting cells, but if someone else would prefer complete solution, you can see my answer from another question: jquery google analytics datepicker
Here's a solution using the built-in 'onSelect' event (jsFiddle):
$(document).ready(function() {
'use strict';
var range = {
'start': null,
'stop': null
};
$('#picker').datepicker({
'onSelect': function(dateText, inst) {
var d, ds, i, sel, $this = $(this);
if (range.start === null || range.stop === null) {
if (range.start === null) {
range.start = new Date(dateText);
} else {
range.stop = new Date(dateText);
}
}
if (range.start !== null && range.stop !== null) {
if ($this.find('td').hasClass('selected')) {
//clear selected range
$this.children().removeClass('selected');
range.start = new Date(dateText);
range.stop = null;
//call internal method '_updateDatepicker'.
inst.inline = true;
} else {
//prevent internal method '_updateDatepicker' from being called.
inst.inline = false;
if (range.start > range.stop) {
d = range.stop;
range.stop = range.start;
range.start = d;
}
sel = (range.start.toString() === range.stop.toString()) ? 0 : (new Date(range.stop - range.start)).getDate();
for (i = 0; i <= sel; i += 1) {
ds = (range.start.getMonth() + 1).toString() + '/' + (range.start.getDate() + i).toString() + '/' + (range.start.getFullYear()).toString();
d = new Date(ds);
$this.find('td a').filter(function(index) {
return $(this).text() === d.getDate().toString();
}).parents('td').addClass('selected');
}
}
}
}
});
});
I became desperate and came up with a solution on my own. It wasn't pretty but I'll detail it.
I was able to construct a div that had the text boxes, buttons and the datepicker that looked like the Google Analytics control but I couldn't make the datepicker work properly. Eventually, I came up with the idea of creating a toggle variable that kept track of which date you were selecting (start date or end date). Using that variable in a custom onSelect event handler worked well but I still couldn't figure out how to get the cells between dates to highlight.
It took a while, but I slowly came to the realization that I couldn't do it with the datepicker as it existed out of the box. Once I figured that out, I was able to come up with a solution.
My solution was to add a new event call afterSelect. This is code that would run after all the internal adjustments and formatting were complete. I then wrote a function that, given a cell in the datepicker calendar, would return the date that it represented. I identified the calendar date cells by using jQuery to find all the elements that had the "ui-state-default" class. Once I had the date function and a list of all the calendar cells, I just needed to iterate over all of them and, if the date was in the correct range, add a new class to the parent.
It was extremely tedious but I was able to make it work.