Can a Queue be rescheduled in OctoberCMS - php

Task:
I am creating a way that a frontend user can send a message and schedule a time for it to be delivered. To accomplish this, I am storing the message info in database tables and then Setting a queue to fire a send function at the appropriate time.
Question:
If the user changes their mind about the time to send the message after this code is executed, is there a way to remove this from the queue and then re add it to fire at a different time?
Example
$data = ['message_id' => $this->messageModel->id];
$queue = Queue::later($this->send_at, 'KurtJensen\Twilio\Classes\SendQueue', $data);
// ==== Everything works great up to this point =======
// Don't know if this will work
// Can I get a queue identifier here?
$this->messageModel->queue_id = $queue->id;
$this->messageModel->save();
Then later to change time:
$this->messageModel= Message::find($id);
$q_id = $this->messageModel->queue_id;
// ==== I doubt this would work or if canceling a queue is possible =======
Queue::cancel($q_id);
$queue = Queue::later($new_time, 'KurtJensen\Twilio\Classes\SendQueue', $data);
$this->messageModel->queue_id = $queue->id;
$this->messageModel->save();

Related

How to remove all requests from Telegram Bot database (getUpdates)

hello my bot continue sending message to me.
my code is:
while(true)
{
header('Content-Type: text/html; charset=utf-8');
$token= "MY-TOKEN";
$url= "https://api.telegram.org/bot".$token."/getUpdates";
$update = file_get_contents($url);
$arrayUpdate= json_decode($update, true);
foreach ($arrayUpdate['result'] as $key) {
$chat_id = $key['message']['from']['id'];
$command = $key['message']['text'];
}
if($command == "/start"){
$text= "starting...";
$url= "https://api.telegram.org/bot".$token."/sendMessage?chat_id=".$chat_id."&text=".$text;
file_get_contents($url);
}
}
my bot send me message infinity i want my bot to send me message when i use it then stop and wait for next request.
Your problem is that you put your code that checks for updates in a infinite while loop. So you get infinite messages. To fix that:
Manage "offsets" of updates. Every update has a unique id number called update_id. Every time an update gets received, its update_id equals update_id of the last messages + 1 (Every time an update arrives, its update_id gets increased by one). You can ask bot api to get only updates that has a update_id bigger than or equal what you specify, by passing offset when executing getUpdates:
This is one example, using GET:
api.telegram.org/bot<TOKEN>/getUpdates?offset=<UPDATE_ID>
Save the update_id of the last message you received. Add it by 1. Next time when you ask for updates via getUpdates, pass this new update_id as offset as shown above (or via POST). And api will bring you the next message received. Also, when you use offset to get new messages, old messages get deleted. They can't be obtained using getUpdates.
Process only the last message you receive, not all of them. Currently, you are processing all messages received in one request. But this way you would process old message more than once. So just process the last one and let the api delete the last message for you in each request.
Messages saved in getUpdates queue will eventually get empty as every old message gets deleted in each request. Don't forget to take care about such situation.
More info about getUpdates: API Documentation

How to structure tests for processes that occur over time?

What is the approach for constructing tests of code that don't have an outcome in the immediate sense?
Let's say we have a very simple (yet quite rude) process:
User signs up to site
Two days pass
Send reminder email
Update some database fields
Ten days pass
Send "c'ya" email
Delete account
I can write tests for each set of sub tasks (email is sent, database is updated, etc). However how do I write well structured tests, that read something like:
"Two days after registration, reminder email should be sent"
"Ten days after registration, account is deleted"
Although I am using PHP and PHPUnit, I feel the question may/may not be language agnostic.
Based on implementation of your event mechanics. Like, when some event listener somewhere in your code receives event user:reminder with user id, then you need just:
1) Test reminder-send script by sending that event manually:
$eventBus->init();
$eventBus->attachListener($reminderListener);
$eventBus->fire(new ReminderEvent($user->id));
$this->expect(...); // reminder must be `sent`
2) Test generation of event when time had passed:
$time = now();
$delay = ...;
$emitter = new RemindEventEmitter($user->id, $time + $delay)
$eventBus->addEmitter($emitter);
$eventBus->setCurrentTime($time); // when we just registered emitter...
$eventBus->run();
$this->expectNot(...); // ... that event _must not_ be fired
$eventBus->setCurrentTime($time + $delay); // manually skip $delay time ...
$eventBus->run();
$this->expect(...); // test that event _must_ be fired
And that event-spawning/dispatching thing ($eventBus in my example) must relay on mockable/replacable time-getter:
// in production code
$eventBus->setCurrentTime(now());
// elsewhere in tests
$eventBus->setCurrentTime(<point in time you want to test against>);

Salesforce callout using PHP

Apologies, since I may not know the terminologies for the salesforce API. I just started programming a connector to interact with salesforce and I am stuck.
I have a requirement, where each time a new entry is added to the Leads section, I will have to retrieve a couple of fields (Firstname and Product Code) and pass it to a different software that makes use of PHP.
<?php
require "conf/config_cleverbridge_connector.inc.php";
require "include/lc_connector.inc.php";
// Start of Main program
// Read basic parameters
if ($LC_Username === "")
{
$LC_Username = readParam("USER");
}
if ($LC_Password === "")
{
$LC_Password = readParam("PASSWORD");
}
$orderID = "";
$customerID = substr(readParam("PURCHASE_ID"), 0, 10);
$comment = readParam("EMAIL")."-".readParam("PURCHASE_ID");
// Create product array
$products = array();
$itemID = readParam("INTERNAL_PRODUCT_ID");
$quantity = 1;
if (!ONCE_PER_PURCHASED_QUANTITY)
{
$quantity = readParam("QUANTITY");
}
// Add product to the product array
$products[] = array (
"itemIdentification" => $itemID,
"quantity" => $quantity,
);
// Create the order
$order = array(
"orderIdentification" => $orderID,
"customerIdentification" => $customerID,
"comment" => $comment,
"product" => $products,
);
// Calling webservice
$ticket = doOrder($LC_Username, $LC_Password, $order);
if ($ticket)
{
Header("HTTP/1.1 200 Ok");
Header("Content-Type: text/plain");
print TICKET_URL.$result->order->ticketIdentification;
exit;
}
else
{
$error = "No result from WSConnector_doOrder";
trigger_error($error, E_USER_WARNING);
printError(500, "Internal Error.");
exit;
}
// End of Main program
?>
Now this is the code that I got and have to work with. And this is hosted on a different remote server.
I am very very new to salesforce and I am not really sure how to trigger calling this php file over a remote site.
The basic idea is:
1. New entry in Lead is created.
2. Immediately 2 fields (custID and prodID) are sent to this PHP file I have pasted above (some of the variables are different)
3. This does its processing and sends 2 fields back to salesforce.
Any help or guidance is appreciated. Even links to read up on is okay as I am completely clueless.
PS: I have another example where it makes use of JSON Messages if that may make any difference.
Thanks
I'll repost the links from my comment :)
https://salesforce.stackexchange.com/questions/23977/is-it-possible-to-get-the-record-id
Web hook in salesforce?
If your PHP endpoint is visible on the open web (not a part of some intranet or just your own localhost) then simplest thing to do would be to send an Outbound Message from Salesforce. No coding required, just some XML document you'll have to parse on the PHP side. Plus it will automatically attempt to resend the messages if the host is unreachable...
If your app can't be accessed from SF servers then I think your PHP app will have to be the "actor". Querying SF every X minutes for new Leads or maybe subscribing to Streaming API... This will mean you'd have to store credentials to SF on your PHP app and remember to either change the password periodically or set on the "integration user"'s profile the "password never expires" checkbox.
So you're getting the notification, you generate your tickets, time to send them back. Will you want to pretend the update of Lead was done by the person that created it or will you want to see "last modified by: Integration User"? Outbound message can contain session id which you can use to act as the person who initiated the action (created the lead and fired the workflow) - at least until they log out or the session timeouts.
For message back you can use SOAP or REST salesforce apis - read the docs to figure out how to send an update command (and if you want to make it clear it was done by special user associated with this PHP app - how to log in to the APIs). I think the user's profile must have "API enabled" ticked before you could reuse somebody's session so maybe it's better to have a dedicated account for integrations like that...
Another thing to keep in mind if it'd be outbound messages is to ignore the messages sent from sandboxes so if somebody makes a test environment you will not call your "production" database of tickets. You can also remember to modify the outbound message and remote site setting every time a sandbox is made so you'll have "prod talking to prod, test talking to test". I know you can include user's session id in the OM - so maybe you can also add organization's id (for production it'll stay the same, every new sandbox will have new id).
The problem with this approach is that it might not scale. If 1000 leads is inserted in one batch (for example with Data Loader) - you'll get spammed with 1000 outbound messages. Your server must be able to handle such load... but it will also mean you're using 1 API request to send every single update back. You can check the limit of API requests in Setup -> Company Information. Developer Edition will have this limit very low, sandboxes are better, production is best (it also depends how many user licenses have you bought). That's why I've asked about some batching them up.
More coding but also more reliable would be to ask SF for changes every X minutes (Streaming API? Normal query? check the "web hook" answer) and send an update of all these records in one go. SELECT Id, Name FROM Lead WHERE Ticket__c = null (note there's nothing about AND LastModifiedDate >= :lastTimeIChecked)...

Prevent PHP from sending multiple emails when running parallel instances

This is more of a logic question than language question, though the approach might vary depending on the language. In this instance I'm using Actionscript and PHP.
I have a flash graphic that is getting data stored in a mysql database served from a PHP script. This part is working fine. It cycles through database entries every time it is fired.
The graphic is not on a website, but is being used at 5 locations, set to load and run at regular intervals (all 5 locations fire at the same time, or at least within <500ms of each-other). This is real-time info, so time is of the essence, currently the script loads and parses at all 5 locations between 30ms-300ms (depending on the distance from the server)
I was originally having a pagination problem, where each of the 5 locations would pull a different database entry since i was moving to the next entry every time the script runs. I solved this by setting the script to only move to the next entry after a certain amount of time passed, solving the problem.
However, I also need the script to send an email every time it displays a new entry, I only want it to send one email. I've attempted to solve this by adding a "has been emailed" boolean to the database. But, since all the scripts run at the same time, this rarely works (it does sometimes). Most of the time I get 5 emails sent. The timeliness of sending this email doesn't have to be as fast as the graphic gets info from the script, 5-10 second delay is fine.
I've been trying to come up with a solution for this. Currently I'm thinking of spawning a python script through PHP, that has a random delay (between 2 and 5 seconds) hopefully alleviating the problem. However, I'm not quite sure how to run exec() command from php without the script waiting for the command to finish. Or, is there a better way to accomplish this?
UPDATE: here is my current logic (relevant code only):
//get the top "unread" information from the database
$query="SELECT * FROM database WHERE Read = '0' ORDER BY Entry ASC LIMIT 1";
//DATA
$emailed = $row["emailed"];
$Entry = $row["databaseEntryID"];
if($emailed == 0)
{
**CODE TO SEND EMAIL**
$EmailSent="UPDATE database SET emailed = '1' WHERE databaseEntryID = '$Entry'";
$mysqli->query($EmailSent);
}
Thanks!
You need to use some kind of locking. E.g. database locking
function send_email_sync($message)
{
sql_query("UPDATE email_table SET email_sent=1 WHERE email_sent=0");
$result = FALSE;
if(number_of_affacted_rows() == 1) {
send_email_now($message);
$result = TRUE;
}
return $result;
}
The functions sql_query and number_of_affected_rows need to be adapted to your particular database.
Old answer:
Use file-based locking: (only works if the script only runs on a single server)
function send_email_sync($message)
{
$fd = fopen(__FILE__, "r");
if(!$fd) {
die("something bad happened in ".__FILE__.":".__LINE__);
}
$result = FALSE;
if(flock($fd, LOCK_EX | LOCK_NB)) {
if(!email_has_already_been_sent()) {
actually_send_email($message);
mark_email_as_sent();
$result = TRUE; //email has been sent
}
flock($fd, LOCK_UN);
}
fclose($fd);
return $result;
}
You will need to lock the row in your database by using a transaction.
psuedo code:
Start transaction
select row .. for update
update row
commit
if (mysqli_affected_rows ( $connection )) >1
send_email();

Maintaining counter value in PHP

I'm working on a system where an android app needs to send periodic updates to a server to say it is running okay. If 4 checks pass and an update hasn't been sent, a text message needs to be sent. I want to use a counter in the PHP file that checks how many 'checks' have passed without an update. However every time the android application contacts the server the counter is reset and never increases. I have it working but I don't want the message to be sent until the counter is 4. Does anyone have any suggestions on how to retain the value of the counter when the file is 'reopened'. Thanks.
<?php
//...
// check the value sent from the android application
if(isset($_REQUEST['alert'])){
echo "alert";
// everything is ok, reset the counter
$counter = 0;
}
else echo "no alert";
// increase the counter
$counter++;
if($counter >= 4) {
while($row = mysql_fetch_array($result)) {
$phNum = $row['mobile'];
}
// an update has not been sent in 4 attempts, send a text message
send_sms($phNum);
}
//...
?>
Perhaps you could:
Use SharedPreferences in Android App which would keep count of checks? then send it to server to say all 4 checks were passed?
PHP script is executed from beginning every time you visit website, another method would be to use sessions but that will get a bit messy, and another way: when request is called, it would send your data + device ID (unique ID to each device), then it would add number of checks into database and keep track of checks for each device, that would slow down your execution time by not that much.
But as I said already, Shared Preferences would work.
If your android app is properly sending and storing cookies you can use the php $_SESSION or $_CCOKIE variable for persistent data.

Categories