Webhook function does not execute - laravel

I have this code to add user credit to a user when a payment is made
class Webhook extends Controller
{
public function rave(Request $request){
if(Request::input('pay.type') == "credits" and Request::get('price') == 500 ){
$credit = Credit::firstOrCreate(['user_id' => Auth::getUser()->id]);
$credit->increment('amount', 600);
$credit->refresh();
}
}
}
The code works well when i try it as an ajax call attached to a button but it does not execute with a returned webhook response even tho it is returned with a 200 ok when inspected with ngrok.
What might be the reason?

You're not actually returning anything. I'm not sure what kind of response you expect, but try returning something inside if block and see if that nudges you in the right direction.
if ($request->input('pay.type') == 'credits' && $request->input('price') == 500) {
$credit = Credit::firstOrCreate(['user_id' => Auth::user()->id]);
$credit->increment('amount', 600);
$credit->refresh();
return $credit->amount;
}

Related

How To Check If Notification Is Sent Successfully In Laravel

I am unable to find in the documentation of how to handle the notification (what to do if notification is sent successfully or not)
NotificationController
public function AskForLevelUp()
{
$admin = User::where('is_admin', 1)->first();
$sendNotification = Notification::send($admin, new LevelUpNotification(Auth::user()->id));
if ($sendNotification->success()) // **HOW TO DO THIS CORRECTLY**
{
return back()->with('success', 'Your request has been submitted, please wait for admin confirmation.');
}
else
{
return back()->with('failure', 'Something went wrong, your request is not submitted. Please try again later.');
}
}
I've also read that send() has void return value here. Does anyone know how to handle this?

How to send an activity from a bot dialog (c#) trough direct line to a client (angular)

I'm trying to send an event activity from the bot to the client when I'm in a certain dialog, but I just can't get it to work... Any suggestions or code samples I can look at?
Also I already tried to make a back channel and it works but on the bot side as far as I could tell it only works in the message controller.
EDIT*
I'm sorry, for not providing any details, I was in a hurry last week.
So i'm making a bot that will fill a "report" for a user, the bot asks questions, and the user gives the answers. For the first question i have to call a function in my angular app when i'm in the first dialog, that is after the root dialog, that will check the user input and return an "Account" object to the bot if the account exists, if it doesn't then it returns null... (and i know it would be easier to just make an API and connect directly to the bot, but i have to use angular)
I'm using the back channel like so:
botConnection.activity$
.filter( activity => {
// tslint:disable-next-line:max-line-length
return (activity.type === 'message' && activity.from['id'] === 'VisitReportV3' && activity.text === 'Please select an account...') ||
(activity.type === 'message' && activity.from['id'] === 'user' && this.accountFlag)
})
.subscribe(activity => {
if (activity.from['id'] === 'VisitReportV3' && activity.text === 'Please select an account...') {
console.log('"account" received');
this.accountFlag = true;
postAccountInfo();
} else if (activity.from['id'] === 'user' && this.accountFlag) {
console.log('"account" flag recieved');
this.accountFlag = false;
}
});
It's probably completely wrong but i didn't know how else to do it..
tl;dr:
So in short, i need to check if i'm in the first dialog (or the one that asks me for the account) and if I am then wait for the next user input and call the angular function to check the input and see if there are any accounts that match, if not return null if they do return the serialized object to the bot for some more processing... I hope this explains some more.
In your messages controller you are probably only forwarding activities with a type of Message to your dialogs. If you used the default bot template, you probably have something like
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.GetActivityType() == ActivityTypes.Message)
{
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
that you need to change to
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.GetActivityType() == ActivityTypes.Message || activity.GetActivityType() == ActivityTypes.Event)
{
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
That will send both messages and events to your dialogs. Keep in mind though that you need to check for both of them in each of you dialog methods now especially when you are expecting events as the user can type and send a message before your event gets sent.
EDIT
You can't get the dialog name from activity.from['id']. However, in your dialog you can create an Activity reply and set the name to be something else. For example in your dialog,
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
Activity activity = await result as Activity;
Activity reply = activity.CreateReply();
reply.Text = "Please select an account...";
reply.Name = "VisitReportV3";
await context.PostAsync(reply);
}
then in your back channel JavaScript you would change from checking if activity.from['id'] === "VisitReportV3" to activity.name === "VisitReportV3".

Do I need to verify the result for Google Invisible reCaptcha

I am following the instructions on this page
to implement the invisible recaptcha. Everything works great, but how do I know it is working? Is there a way to force a false to test it?
Also, The documentation is not clear on the above page, but some places have additional code to verify the users "response" (it's invisible so i'm not sure what the response is here) - so do I need to add additional back end logic to hit this endpoint with the invisible reCaptcha resulting token and my secret key?
What happens when the user clicks submit on the invisible recaptcha? What is done in the API to return the token? What is the token for? What does the siteverify api then do to determine its a person? Why isnt additional verification needed when the reCAPTCHA V2 (visible click one) is used?
After some testing it looks like you could just do the front end part. The data callback function is not called until google is sure you are a person, if google is not sure then it loads the "select which tiles have a thing in them" reCaptcha to be sure. Once the reCaptcha api is sure that it is a person, the data callback function is fired - at that time you can do further validation to ensure that the token you received during the callback is the one that google actually sent and not a bot trying to fool you by hitting your callback funct - so from there you do server side processing for further validation. Below is an example of a C# ashx handler - and ajax for the validation
function onTestSubmit(token) {
$.ajax({
type: "POST",
url: "testHandler.ashx",
data: { token: token },
success: function (response) {
if (response == "True") {
//do stuff to submit form
}
}
});
}
And the ashx
public class testHandler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/plain";
string token = context.Request.Form["token"];
bool isCaptchaValid = ReCaptcha.Validate(token);
context.Response.Write(isCaptchaValid.ToString());
}
public bool IsReusable {
get {
return false;
}
}
}
public class ReCaptcha
{
private static string URL =
"https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}";
private static string SECRET = "shhhhhhhhhhhhhhSecretTOken";
public bool Success { get; set; }
public List<string> ErrorCodes { get; set; }
public static bool Validate(string encodedResponse)
{
if (string.IsNullOrEmpty(encodedResponse)) return false;
var client = new System.Net.WebClient();
var googleReply = client.DownloadString(string.Format(URL, SECRET, encodedResponse));
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var reCaptcha = serializer.Deserialize<ReCaptcha>(googleReply);
return reCaptcha.Success;
}
}
Yes, you do.
You need to understand that invisible reCaptcha is a process with multiple steps, all of which end up providing a final response regarding the humanity of the user.
In simple words, when the users submits a form (or does whatever it is you are trying to keep bots away from with Invisible reCaptcha) you'll be sending your public sitekey to your backend, which will fire up a verification payload to Google.
In my very basic example, this is the button which the hopefully human visitor clicks to submit a form on my site:
<button type="submit" class="g-recaptcha" data-sitekey="xxxxxxxx_obscured_xxxxxxxx" data-callback="onSubmit">Submit Form</button>
Note how the the button has the data-callback "onSubmit", which upon submission runs this small script:
<script type="text/javascript">
var onSubmit = function(response) {
document.getElementById("simpleForm").submit(); // send response to your backend service
};
</script>
The backend service in my example is a vanilla PHP script intended to process the form input and store it on a database and here comes the tricky part. As part of the POST to the backend, besides the form fields the user filled is the response from the service (and since you may or may not be doing a lot of things on the front-end where the user could manipulate the response before it's posted to your backend, Google's response is not explicit at this point)
On your backend, you'll need to take g-recaptcha-response that came from google and post it to a verification API using your private key (which is not the one on the form) in order to get the human/robot verdict which you can act upon. Here's a simple example written in PHP and hitting the API with cURL:
$recaptcha_response = $_POST["g-recaptcha-response"];
$api_url = 'https://www.google.com/recaptcha/api/siteverify';
$api_secret = 'zzzzzzz_OBSCURED_SECRET_KEY_zzzzzzzzzzz';
$remoteip = '';
$data = array('secret' => $api_secret, 'response' => $recaptcha_response);
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($api_url, false, $context);
$captcha_response = json_decode($result, true);
// at this point I have the definite verdict from google. Should I keep processing the form?.
if ($captcha_response['success'] == true) {
// I heart you, human. Keep going
$captcha_error = 0;
}
else {
// Damn robot, die a slow and painful death
$captcha_error = 1;
}
I make a final decision based on $captcha_error (basically 1 means halt, 0 means keep processing)
If you rely solely on getting the g-recaptcha-response you're having Google do the work and then ignoring the result

How to prevent additional page requests after response sent

I have configured a listener on kernel.request which sets a new response with redirect when the session time has reached a certain value. The listener works fine and redirects to a certain page, on the next request, after the session has ended. But my problem is on the page I have many links and if I press multiple times the same link, the initial request with the redirect is cancelled/stopped and a new request is made with the last link pressed and so it passes my redirect even though the session has ended and is destroyed. So, my question is how to prevent additional requests/link presses after the firs request is made?
Here is my code:
public function onKernelRequestSession(GetResponseEvent $event)
{
$request = $event->getRequest();
$route = $request->get('_route');
$session = $request->getSession();
if ((false === strpos($route, '_wdt')) && ($route != null)) {
$session->start();
$time = time() - $session->getMetadataBag()->getCreated();
if ($route != 'main_route_for_idle_page') {
if (!$session->get("active") && $route == 'main_route_for_site_pages') {
$session->invalidate();
$session->set("active", "1");
} else {
if ($time >= $this->sessionTime) {
$session->clear();
$session->invalidate();
$event->setResponse(new RedirectResponse($this->router->generate('main_route_for_idle_page')));
}
}
} else {
if ($session->get("activ")) {
$session->clear();
$session->invalidate();
}
}
}
}
Thak you.
Idea #1: Simple incremental counter
Each request sends sequence number as param which is being verified as expected at the server.
Server increments the number and sends it back via response
the new number is used in future requests
Basically, if server expects the SEQUENCE number to be 2 and client sends 1 the request is to be rejected.
Idea #2: Unique hash each time
Similar to the idea above, but uses unique hashes to eliminate predictive nature of incremental sequence.
I resolved the issue using JQuery: when a link was pressed I disabled the other ones and so only one request is made from the page:
var isClicked = false;
$(".menu-link").click(function(e) {
if(!isClicked) {
isClicked = true;
} else {
e.preventDefault();
}
});
Thanks.

CI Route Issue Not Getting Variable

I'm having an issue with this route and not sure what my problem is exactly.
My page is located at http://www.kansasoutlawwrestling.com/kowmanager/pmsystem/viewmessage/1 where 1 is the message id.
I set up a route to look like
$route['pmsystem/viewmessage/(:num)'] = 'pmsystem/viewmessage/$1';
and I'm still getting a error message like this
A PHP Error was encountered
Severity: Warning
Message: Missing argument 1 for Pmsystem::viewmessage()
Filename: controllers/pmsystem.php
Line Number: 76
// View A Message
function viewmessage($message_id)
{
//Config Defaults Start
$msgBoxMsgs = array();//msgType = dl, info, warn, note, msg
$cssPageAddons = '';//If you have extra CSS for this view append it here
$jsPageAddons = '<script src='.base_url().'../assets/js/cpanel/personalmessages.js></script><script src='.base_url().'assets/js/mylibs/jwysiwyg/jquery.wysiwyg.js></script>';//If you have extra JS for this view append it here
$metaAddons = '';//Sometimes there is a need for additional Meta Data such in the case of Facebook addon's
$siteTitle = '';//alter only if you need something other than the default for this view.
//Config Defaults Start
//examples of how to use the message box system (css not included).
//$msgBoxMsgs[] = array('msgType' => 'dl', 'theMsg' => 'This is a Blank Message Box...');
/**********************************************************Your Coding Logic Here, Start*/
// Checks to see if a session is active for user and shows corresponding view page
if (!$this->loggedin->chkLoginStatus() === FALSE)
{
if( ! $this->uri->segment(3))
{
redirect('error', 'refresh');
}
}
else
{
redirect('login', 'refresh');
}
$bodyContent = 'viewpm';//which view file
$bodyType = "full";//type of template
/***********************************************************Your Coding Logic Here, End*/
//Double checks if any default variables have been changed, Start.
//If msgBoxMsgs array has anything in it, if so displays it in view, else does nothing.
if(count($msgBoxMsgs) !== 0)
{
$msgBoxes = $this->msgboxes->buildMsgBoxesOutput(array('display' => 'show', 'msgs' =>$msgBoxMsgs));
}
else
{
$msgBoxes = array('display' => 'none');
}
if($siteTitle == '')
{
$siteTitle = $this->metatags->SiteTitle(); //reads
}
//Double checks if any default variables have been changed, End.
$this->data['msgBoxes'] = $msgBoxes;
$this->data['cssPageAddons'] = $cssPageAddons;//if there is any additional CSS to add from above Variable this will send it to the view.
$this->data['jsPageAddons'] = $jsPageAddons;//if there is any addictional JS to add from the above variable this will send it to the view.
$this->data['metaAddons'] = $metaAddons;//if there is any addictional meta data to add from the above variable this will send it to the view.
$this->data['pageMetaTags'] = $this->metatags->MetaTags();//defaults can be changed via models/metatags.php
$this->data['siteTitle'] = $siteTitle;//defaults can be changed via models/metatags.php
$this->data['bodyType'] = $bodyType;
$this->data['bodyContent'] = $bodyContent;
$this->data['user_data'] = $this->users->getUserByUserId($this->session->userdata('user_id'));
$this->data['users'] = $this->loggedin->getUserList();
$this->data['personal_messages'] = array($this->pmmodel->getTotalMessages($this->session->userdata('user_id')), $this->pmmodel->getTotalUnreadMessages($this->session->userdata('user_id')), $this->pmmodel->getLast5Messages($this->session->userdata('user_id')));
$this->data['messages'] = array($this->pmmodel->getInboxMessages($this->session->userdata('user_id')), $this->pmmodel->getSentMessages($this->session->userdata('user_id')));
//$this->data['message_data'] = $this->pmmodel->getPmMessage($this->uri->segment(3));
$this->load->view('cpanel/index', $this->data);
}
UPDATE
// Checks to see if a session is active for user and shows corresponding view page
if (!$this->loggedin->chkLoginStatus() === FALSE)
{
if (!is_numeric($this->uri->segment(3)))
{
$this->data['message_data'] = 'Invalid message id!';
}
else
{
$this->data['message_data'] = $this->pmmodel->getPmMessage($this->uri->segment(3));
}
$bodyContent = 'viewpm';//which view file
}
else
{
redirect('login', 'refresh');
}
$bodyType = "full";//type of template
This route is unnecessary - it doesn't change anything.
$route['pmsystem/viewmessage/(:num)'] = 'pmsystem/viewmessage/$1';
You can remove that route. The problem is here:
function viewmessage($message_id) // no default value means it's required
{
// your code
}
Your controller methods literally accept user input as arguments (whatever's in the address bar). You always have to account for those required arguments not being present in CI controller methods.
function viewmessage($message_id = NULL)
{
if ( ! $message_id) show_404();
// your code
}
This will silence the errors and show a 404 if the required $message_id is not there. Additionally, $this->uri->segment(3) is unnecessary because it should have the same value as $message_id.
I highly discourage redirecting to an error page when you really want a 404, but that's up to you. It sure doesn't help the user realize their mistake when the address is lost after the redirect, and you're sending the wrong HTTP headers by doing so.

Resources