How to get message after command in Telegram bot sdk Laravel? - laravel

I have some issue with Telegram SDK! As you see in photo below, I ask to enter Some title after user enters /addnotification commmand, here user should enter some title of notification, but I can't get it, because update gives me last message , which was command /addnotification! Please, help if someone knows the answer!
public function handle()
{
$telegram = new Api(Telegram::getAccessToken());
$update = Telegram::getWebhookUpdates();
$chat_id = $update->getMessage()->getChat()->getId();
$text= $update->getMessage()->getText();
$response = $telegram->sendMessage([
'chat_id' => $chat_id,
'text' => 'Пожалуйста введите событие или дело который вы хотели бы добавить.'
]);
// $messageId = $response->getMessageId();
$this->replyWithMessage(['text' => 'Поздравляем! Вы успешно добавили событие!!!']);
$this->replyWithMessage(['text' => 'Название - ' . $text]);
$this->replyWithMessage(['text' => 'Chat Id - ' . $chat_id]);
// $this->replyWithMessage(['text' => $messageId]);
}
}
Here after entering command user should enter some title and I want to get this title(message) , but update gives message which was command!

You are asking the user to input a name for your notification in the same handler - your user has not done any input yet. The library you are using is providing handlers only for commands, you should handle regular messages anywhere else and use some state machine to indicate what input you are waiting from a user or use input syntax like /addnotification *name*. Personally, I could recommend you using this library for Laravel - it's documented better and has more features then irazasyed's one.

Related

What is the correct way to send validation errors back to a Vue component from a Laravel controller?

[I've revised this question a bit to consider another approach. I also apologize if this question seems unduly long. I suppose I'm a bit long-winded but I'm really just trying to be very clear.]
I am fairly new to Laravel, Vue and Vuetify but, after a lot of struggling, I've gotten my CRUD app to work with MySQL, at least as long as I pass my Controller good data. But now I'm struggling with the right way to do error handling.
I use Vuetify to do my front-end error checking and it seems to work very well. I've been able to write validations for every condition I could think of and display a meaningful error message where it is most appropriate to show it. I know I need to do the same validations in my Laravel controller back-end and writing good validations there seems pretty straightforward too. However, I'm having trouble figuring out how to communicate a back-end validation error to my Vue component.
My CRUD app is doing the classic To Do List. One of the fields on my input form for adding a new task is the due date for the new task and one of the edits that should be done on both the front-end and the back-end is that the due date can't be in the past. I've "accidentally" omitted that check on the front-end but have included it on the back-end to be sure the back-end will detect it when I choose a past date as my due date. My Laravel controller detects that as intended and my browser console shows this:
Clearly, the validations in the controller are working and they have correctly detected the problem with the due date. Now, my problem is how to get the relevant information to my Vue component and, when relevant (as it is in this case), how do I display it to my user?
All the examples I could find that were for Laravel apps that use Vue components had them using the then and catch blocks to deal with the Axios response and error information. The other option that occurs to me is to access the error bag generated by the Laravel controller but I can't find any information on how that could be done in a Vue component so it looks like I have to take the Axios approach....
I cannot figure out how to display the relevant information from the Response Payload in my Vue component in the catch block. In every example I've found, the Response is returned to the then block and the Error is returned to the catch block but when there is an error, the then block never gets executed in favour of the catch block. But when the catch block executes, it can't see the Response so it can't show me anything from the Response, like the validation message. All the searching I've done for answers has left me more confused than enlightened since many answers assume the validation errors are going back to a Laravel blade while others are for much older versions of Laravel. (I am running Laravel 8.x.)
I know that not all errors will be user errors. For example, the database could be down, making all access to the database impossible. I also need to note those situations. The user needs to be told something - perhaps "The database is down. Please try again later." - and the admins need to be advised that the database is down. I'm still trying to figure out the best way to do that but am leaning towards ErrorBoundary as the solution.
For the moment, I'll be delighted if someone can explain how to get the information I want from the Response payload when there is a user-fixable error. Some advice on how to handle situations where the error is NOT user-fixable would be even better.
Here is the relevant bit of my Insert logic in the Vue component:
/* We are creating a new item so determine the id for the new item. It should be
one greater than the highest id currently in the array. Every id of an existing
task should always be at least 1. */
console.log(this.name + ".save() - saving a new item");
var highestTaskID = 0; //must be one less than the lowest possible id value
for (let todo of this.todos) {
if (todo.id > highestTaskID) highestTaskID = todo.id;
}
var newTaskID = highestTaskID + 1; /* Calculate the ID of the new task. */
this.editedItem.id = newTaskID;
this.form.id = this.editedItem.id;
this.form.description = this.editedItem.description;
this.form.status = this.editedItem.status;
this.form.priority = this.editedItem.priority;
this.form.due = this.editedItem.due;
let data = new FormData();
data.append('id', this.form.id);
data.append('description', this.form.description);
data.append('status', this.form.status);
data.append('priority', this.form.priority);
data.append('due', this.form.due);
axios.post('/task', data)
.then((res) => {
console.log(this.name + ".save() - response from insert (then): " + res);
this.snackbarMessage = "Created new task";
this.showMessageSnackbar = true;
this.showTable = true; //start showing ToDo table again
this.form.reset();
this.getTasks();
})
.catch((error) => {
console.log(this.name + ".save() - response from insert (catch): " + res);
console.log(this.name + ".save() - error: " + error);
this.snackbarMessage = "Failed to create new task";
this.showMessageSnackbar = true;
this.showTable = true; //start showing ToDo table again
})
This is the store() method in my TaskController:
public function store(Request $request)
{
app('debugbar')->info('TaskController.store() started');
$today = date('Y-m-d');
$this->validate($request, [
'description' => ['required', 'min:5', 'max:191'],
'status' => ['required'],
'priority' => ['required'],
'due' => ['required', 'after-or-equal:' . Date('Y-m-d')]
],
[
'description.required' => 'You must provide a non-blank task description',
'description.min' => 'The task description must contain at least 5 characters',
'description.max' => 'The task description must not exceed 191 characters',
'status.required' => 'You must provide a task status',
'status.in' => 'You must choose a task status from: Pending or Completed',
'priority.required' => 'You must provide a task priority',
'priority.in' => 'You must choose a task priority from: Low, Medium or High',
'due' => 'You must provide a task due date',
'due.after_or_equal' => 'You must provide a due date greater than or equal to today'
]
);
app('debugbar')->info('TaskController.store() validations completed');
Task::create($request->all());
}
Should I be logging any and all errors I detect in the Controller itself, rather than in the Vue component? That might be a lot easier in some respects, although I still have to be able to detect which errors can be passed back to the user for them to handle and when I simply have to tell them to try later because the app isn't working fully yet.
First of all, I'd advise using axios' Response Interceptor which is essentially a callback that gets executed every time a request has been completed so you don't have to do error handling on each and every request.
Create a new file (for example axiosInstance.js)
const axiosInstance = axios.create({
baseURL: 'https://example.com/api',
});
axiosInstance.interceptors.response.use((response) => {
return response;
}, (error) => {
switch(error.response.status) {
case 422:
// Here you will be able to process Laravel Validation Errors.
// You can for example display an error message using your favorite library
console.log("Error Message: " + error.response.data.message);
console.log("Error Object: " + error.response.data.errors);
break;
}
return Promise.reject(error);
}
export default axiosInstance;
As you can see you can access your response by using error.response. This works for catch blocks in simple axios requests aswell.
axios.get('https://example.com/xyz').catch(e => {
console.log(e.response);
});
The above interceptor in my first code block will do special handling for all Laravel Validation Errors since those are returned using HTTP Status 422 (Unprocessable Entity) by default.
To use it, instead of doing axios.get() you can do:
import axiosInstance from './axiosInstance.js';
axiosInstance.get('https://example.com/xyz');
The logic you defined in the catch block of the interceptor will then be executed every time a request that was initiated using axiosInstance. You can also append .catch() again to the request to handle additional logic if a specific requests fails.
To handle additional error types, extend the interceptors switch conditional statement. For example, exceptions like "The database is not available" are returned with status code 500 by Laravel. Usually, a simple message is then available to display to the user by using error.response.data.message.
tl;dr
This is what you could do achieve what you are trying to do using your code:
axios.post('/task', data)
.then((res) => {
console.log(this.name + ".save() - response from insert (then): " + res);
this.snackbarMessage = "Created new task";
this.showMessageSnackbar = true;
this.showTable = true; //start showing ToDo table again
this.form.reset();
this.getTasks();
})
.catch((error) => {
console.log(this.name + ".save() - response from insert (catch): " + error.response);
// Given that your erroneous response contains 'message' (like laravel validation errors do):
console.log(this.name + ".save() - error: " + error.response.data.message);
this.snackbarMessage = "Failed to create new task";
this.showMessageSnackbar = true;
this.showTable = true; //start showing ToDo table again
})

Mailchimp api not sending goodbye email -with https://github.com/drewm/mailchimp-api

when unsubscribing an user I want de default Mailchimp goodbye email to be send.
I'm using the following code
$mailchimp = new MailChimp($apiKey);
$md5 = md5($_POST['email']);
$result = $mailchimp->put("lists/$listId/members/$md5", [
'status' => 'unsubscribed',
'send_goodbye' => true
]);
I have the "Send unsubscribe confirmations to subscribers" check in the relevant list.
It unsubscribes the user but never sends the email.
Any idea why?
I'm using the following php wrapper:
https://github.com/drewm/mailchimp-api
Thanks

How to forward argument for redirect::route->with when hitting an auth filter using Laravel?

I have the following problem:
After a user is created and the user has confirmed her email.
I would like the user to login,
I use the following code to do that:
Redirect::route('login-forward')->with('alert_message', ...)
the alert messages simply states that everything went well, and I would like her to login.
login-forward is protected with an before filter, that runs the actual login form,
When the user then logs in sucesfully, she is brought back to login-forward, whic then puts the user at her personal landing page.
the code for the route 'login-forward is:
Route::get('my-login', array(
'as' => 'login-forward',
'before' => 'auth',
function ()
{
$user = Auth::user();
switch ($user->role)
{
case 'Administrator':
return Redirect::route('admin_dashboard');
case 'FreeUser':
return Redirect::route('cs-dashboard');
default:
return Redirect::route('/');
}}));
the problem is, the ->with('alert_message',...) is not seen by the real login route called by the before filter.
How do I solve this?
The best approach is to let the user logs in automatically when the email is confirmed, if the user confirms the account creation then when you find that user is valid then you may log in that user using something like:
// $user = Get the user object
Auth::login($user);
Also you may use:
Session::put('alert_message', ...);
Redirect::route('login-forward');
Then when the user logs in for the first time, just get the message from Session using:
// Get and show the alert_message
// from session and forget it
#if (Session::has('alert_message'))
{{ Session::pull('alert_message') }}
#endif
So, when you pull the message from the Session to show it, the message will no longer be available in the Session or you may use Session::reflash() to flash the flashed session data for another subsequent request until you get in the page where you want to show the message.
The best choice is - you can make forward to login form without redirect from method of controller for url of personal page.
return Route::dispatch(Request::create('login'))->getOriginalContent();

Facebook losing logged in user with ajax

I am writing a Facebook app and have used the Facebook php SDK so it can be authorized server side. I can see this is working because after authorization when Facebook redirects back to my app, I have the following code in my index.php...
require_once 'facebook.php';
$facebook = new Facebook(array(
'appId' => '111111111111111',
'secret' => '11111111111111111111111111111111',
'cookie' => true
));
// Get User ID
$user = $facebook->getUser();
...and $user returns not null. So far, so good!
I have a link on my app that loads content via ajax when clicked. Here's the JS:
$.post('my_content.php', {
action: 'render'
}, function(res){
if (res.html.length) {
$('.content').html(res.html);
}
},'json');
The problem is, the my_content.php script seems to be losing the fact the user has logged in and authorized the app.
The code I run in the my_content.php script to check whether the user is logged in is the same as in index.php
require_once 'facebook.php';
$facebook = new Facebook(array(
'appId' => '111111111111111',
'secret' => '11111111111111111111111111111111',
'cookie' => true
));
// Get User ID
$user = $facebook->getUser();
This time though $user = $facebook->getUser() returns null.
Is there a way to check if the user is logged in and authorized when running a PHP script with an AJAX call?
Should I store something in a session variable in my index.php script?
EDIT
After even more reading, I'm wondering if I need to retrieve the access token using the JavaScript SDK and pass it to my_content.php. Does anyone know if that's the correct way to do it?
EDIT 2
Turns out the line giving me the problem isn't $user = $facebook->getUser():
It is this one
$user_profile = $facebook->api('/me');
This line fails with the error 'OAuthException: An active access token must be used to query information about the current user.'
Strangely though, if I do this
$access_token = $facebook->getAccessToken();
$user = $facebook->getUser();
echo $access_token;
echo $user;
I do indeed have an access token and a user ID, so it looks like it may well be the bug reported by CBroe - check comments below.

Send SMS from Web (are there some providers for this)?

I'd like to have something like what the app.net site has. You click a button and get the option to send a link to your phone via SMS (or email). What are some options for implementing the sms side of things, and are there services or open source packages that provide this?
Here's a random example from app.net . Click the "Get this App" button to see what I mean.
Something like this would even work for me Send link to Phone Where "saasSMS.com" is some service that handles the whole sms side of things. Ideally could either handle that via a link or via a form post (and it would redirect back to your site on success or something).
What I don't want: A drop down that makes you pick your carrier and some php page that tries to email you #vtext.com or similar. That is just not slick enough.
You can use the ViaNett HTTP API to send SMS messages worldwide without specifying the operator.
As long as your backend supports invoking HTTP requests it will work.
Here is an example written in PHP:
<?php
// Register here to get a username and password:
// http://www.vianett.com/en/free-demonstration-account
if (vianett_sendsms('username', 'password', 'example', '+4412345678', 'Hello world', $error)) {
echo 'Success!';
} else {
echo $error;
}
function vianett_sendsms($username, $password, $from, $to, $msg, &$response=null) {
$url = 'https://smsc.vianett.no/v3/send.ashx';
$data = array(
'user' => $username,
'pass' => $password,
'src' => $from,
'dst' => $to,
'msg' => $msg
);
$qs = http_build_query($data);
$response = file_get_contents($url.'?'.$qs);
return $response == '200|OK';
}
We're getting good results from http://www.twilio.com
For direct SMS, you can try contacting a service provider and make a contract with it. If its for small projects and the server is accessible, you could put a GPRS mobile phone or modem and send with it.

Resources