How can i use Inlinekeyboard in webhook method telegram Bot ? c# - c#

I use c# and telegram.bot library.
When i use getUpdates method everything is ok but in webhook method not ok
in GetUpdates method when i write below code in OnCallbackQuery event everything is ok and bot get answers
private static void Bot_OnCallbackQuery(object sender,
Telegram.Bot.Args.CallbackQueryEventArgs e)
{
long b;
if (e.CallbackQuery != null && long.TryParse(e.CallbackQuery.Data, out b))//show Post
{
//PostContent
var post = dba.BlogPosts.Find(Convert.ToInt64(e.CallbackQuery.Data));
if (post != null)
{
string removedTag = Regex.Replace(post.Content, "<br>", Environment.NewLine);
removedTag = Regex.Replace(removedTag, "<.*?>", String.Empty);
// HtmlTagsRemover.CleanTagsExceptPbr(postContent.Content);
Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id, removedTag, parseMode: ParseMode.Html);
}
}
else
{
if (e.CallbackQuery != null && e.CallbackQuery.Data.Contains("more_")) // user clicked on MoreButton
{
Post p = new Post();
var posts = p.BlogPostPaging(PostsList, 5, moreCount);
#region InlineKeyboard
var inlineButtons = posts.Select(title => new[]
{InlineKeyboardButton.WithCallbackData(title.Subject, title.BlogPostId.ToString())})
.ToArray();
InlinePostsKeyboard = new InlineKeyboardMarkup(inlineButtons);
#endregion
if (posts.Count>0)
{
Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id, "page: " + moreCount, replyMarkup: InlinePostsKeyboard);// ShowMoreButton
Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id, "see More...", replyMarkup: InlineBtnMoreKeyboard);// MoreButton
moreCount++;
}
else
{
Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id,
"End");
}
}
but when i want use above code in webhook method , bot does not work And no response is received from bot
#region QueryCallBack
var e = update;
long b;
if (e.CallbackQuery != null && long.TryParse(e.CallbackQuery.Data, out b))//show post
{
await Bot.AnswerCallbackQueryAsync(e.CallbackQuery.Id, "test1");
//post Content
var post = _blogPost.EfGetOneBlogPost(b);
if (post != null)
{
var removedTag = Regex.Replace(post.Content, "<br>", Environment.NewLine);
removedTag = Regex.Replace(removedTag, "<.*?>", string.Empty);
await Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id, removedTag, parseMode: ParseMode.Html);
return Ok();
}
}
else
{
if (e.CallbackQuery != null && e.CallbackQuery.Data.Contains("more_")) // user clicked on MoreButton
{
TelegramPostsPaging p = new TelegramPostsPaging();
var posts = p.BlogPostPaging(PostsList, 5, moreCount);
#region InlineKeyboard
var inlineButtons = posts.Select(title => new[]{InlineKeyboardButton.WithCallbackData(title.Subject, title.BlogPostId.ToString())}).ToArray();
InlinePostsKeyboard = new InlineKeyboardMarkup(inlineButtons);
#endregion
if (posts.Count > 0)
{
await Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id, "page: " + moreCount, replyMarkup: InlinePostsKeyboard);// show SeeMore Button
await Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id, "see More...", replyMarkup: InlineBtnMoreKeyboard);// show SeeMore Button
moreCount++;
return Ok();
}
else
{
await Bot.SendTextMessageAsync(e.CallbackQuery.Message.Chat.Id,
"End");
return Ok();
}
}
}
I don't know how to use CallBackQuery in webhook; but in update method i use in OnCallbackQuery event.

How are you getting the update in the webhook? Because the built-in serializer of ASP.NET does not correctly parse the update, you should instead take it as a string and then deserialize it using Newtonsoft.Json

Related

How to detect edited or deleted messages on telegram TLSharp

I am trying to detect which message is edited or deleted on a subscribed channel on telegram with TLSharp library in c#.
1- in a while(true) loop I am getting latest updates.
2- when I delete or edit a message for test, I receive TLUpdateChannelTooLong only.
3- then I use client.GetHistoryAsync function to get channel messages, and check their EditDate.
But I don't know how much should I go deep in history and I can not find deleted message with this code easily.
Is there any solution to find deleted/edited messages easy and safe?
Part of my code:
state = await client.SendRequestAsync<TLState>(new TLRequestGetState());
while (true)
{
await Task.Delay(1000);
var req = new TLRequestGetDifference() { Date = state.Date, Pts = state.Pts, Qts = state.Qts };
TLDifference diff = null;
try
{
diff = await client.SendRequestAsync<TLAbsDifference>(req) as TLDifference;
}
catch (Exception ex)
{
HandleThisException(ex);
}
//--
if (diff != null)
{
state = await client.SendRequestAsync<TLState>(new TLRequestGetState());
foreach (var upd in diff.OtherUpdates.OfType<TLUpdateNewChannelMessage>())
{
var tm = (upd.Message as TLMessage);
if (tm == null) { continue; } // ?
var textMessage = tm.Message;
if (tm.Media != null)
{
if (tm.Media.GetType().ToString() == "TeleSharp.TL.TLMessageMediaPhoto")
{
var tLMessageMediaPhoto = (tm.Media as TLMessageMediaPhoto);
textMessage = tLMessageMediaPhoto.Caption;
}
}
try
{
var from = (tm.ToId as TLPeerChannel).ChannelId;
long replyTo = tm.ReplyToMsgId == null ? 0 : (long)tm.ReplyToMsgId;
await AnalyzeNewMessage( ... );
}
catch (Exception exParsing)
{
HandleThisException(exParsing);
}
}
// Checking Edited/Deleted Messages
foreach(var upLong in diff.OtherUpdates.OfType<TLUpdateChannelTooLong>())
{
TLChannel theChat = null;
foreach(var chat in diff.Chats.OfType<TLChannel>())
{
if(chat.Id == upLong.ChannelId) { theChat = chat; break; }
}
if (theChat != null)
{
var x = await client.GetHistoryAsync(
new TLInputPeerChannel { ChannelId = theChat.Id, AccessHash = (long)theChat.AccessHash },
0,-1,2
); // checking only 2 last messages!
var ChMsgs = x as TLChannelMessages;
foreach (var msg in ChMsgs.Messages.OfType<TLMessage>())
{
if(msg.EditDate != null)
{
var txt = msg.Message;
if (msg.Media != null)
{
if (msg.Media.GetType().ToString() == "TeleSharp.TL.TLMessageMediaPhoto")
{
txt = (msg.Media as TLMessageMediaPhoto).Caption;
}
}
await AnalyzeEditedMessage( ... );
}
}
}
}
}
}

PHAssetChangeRequest Cocoa error -1

I need to save downloaded video to gallery on iPhone, but getting error:
The operation couldnt be completed. (Cocoa error -1/)
Tried also to do this through webClient.DownloadDataAsync(), getting same error. Here is my listing:
public async Task<string> DownloadFile(string fileUri)
{
var tcs = new TaskCompletionSource<string>();
string fileName = fileUri.Split('/').Last();
var documentsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
string videoFileName = System.IO.Path.Combine(documentsDirectory, fileName);
var webClient = new WebClient();
webClient.DownloadFileCompleted += (s, e) =>
{
var authStatus = await PHPhotoLibrary.RequestAuthorizationAsync();
if(authStatus == PHAuthorizationStatus.Authorized){
var fetchOptions = new PHFetchOptions();
var collections = PHAssetCollection.FetchAssetCollections(PHAssetCollectionType.Album, PHAssetCollectionSubtype.Any, fetchOptions);
collection = collections.firstObject as PHAssetCollection;
PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() => {
var assetCreationRequest = PHAssetChangeRequest.FromVideo(NSUrl.FromFileName(videoFileName));
var assetPlaceholder = assetCreationRequest.PlaceholderForCreatedAsset;
var albumChangeRequest = PHAssetCollectionChangeRequest.ChangeRequest(collection);
albumChangeRequest.AddAssets(new PHObject[] { assetPlaceholder });
}, delegate (bool status, NSError error) {
if (status)
{
Console.Write("Video added");
tcs.SetResult("success");
}
});
}
try
{
webClient.DownloadFileAsync(new Uri(fileUri), videoFileName);
}
catch (Exception e)
{
tcs.SetException(e);
}
return await tcs.Task;
}
Any help would be appreciated. Thanks.
(Cocoa error -1/)
Are you sure that you actually have valid data/mp4 from your download?
Are you using SSL (https), otherwise have you applied for an ATS exception in your info.plist?
Check the phone/simulator console output for errors concerning ATS
Note: I typically use NSUrlSession directly to avoid the HttpClient wrapper...
Example using NSUrlSession task:
var videoURL = NSUrl.FromString(urlString);
var videoPath = NSFileManager.DefaultManager.GetUrls(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User)[0];
NSUrlSession.SharedSession.CreateDownloadTask(videoURL, (location, response, createTaskError) =>
{
if (location != null && createTaskError == null)
{
var destinationURL = videoPath.Append(response?.SuggestedFilename ?? videoURL.LastPathComponent, false);
// If file exists, it is already downloaded, but for debugging, delete it...
if (NSFileManager.DefaultManager.FileExists(destinationURL.Path)) NSFileManager.DefaultManager.Remove(destinationURL, out var deleteError);
NSFileManager.DefaultManager.Move(location, destinationURL, out var moveError);
if (moveError == null)
{
PHPhotoLibrary.RequestAuthorization((status) =>
{
if (status.HasFlag(PHAuthorizationStatus.Authorized))
{
PHPhotoLibrary.SharedPhotoLibrary.PerformChanges(() =>
{
PHAssetChangeRequest.FromVideo(destinationURL);
}, (complete, requestError) =>
{
if (!complete && requestError != null)
Console.WriteLine(requestError);
});
}
});
}
else
Console.WriteLine(moveError);
}
else
Console.WriteLine(createTaskError);
}).Resume();
Note: To confirm your code, try using a known valid secure URL source:
https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 via “Video For Everybody” Test Page

error using IAsyncEnumerable<IReadOnlyCollection<IUser>> in discord bot

i have this code line
if (channel.GetUsersAsync().Contains(Program.kami.CurrentUser as IGuildUser))
do something;
it writes an exception which says IAsyncEnumerable> doesnt contain the definition of contains
and i dont know what to do
[Command("join", RunMode=RunMode.Async), Summary("joins voice channel")]
public async Task joinvoice([Remainder, Summary("The text to echo")] string searchP="")
{
IVoiceChannel channel = (CommandHandler.Last as IGuildUser).VoiceChannel;
if (channel == null)
{
await ReplyAsync("u have to be in a channel first");
return;
}
string choice = "";
VideoSearch SearchRisolts = new VideoSearch();
if (searchP != "")
{
if (searchP.Contains("https://"))
choice = searchP;
else
{
List<VideoInformation> video = SearchRisolts.SearchQuery(searchP, 1);
await ReplyAsync("* " + video[0].Title + "\n\n* " + video[1].Title + "\n\n* " + video[2].Title);
//choice = video[int.Parse() - 1].Url;
}
this.Context.Channel.GetMessagesAsync(1).First();
}
IAsyncEnumerable<IReadOnlyCollection<IUser>> x = channel.GetUsersAsync();
if ((await channel.GetUsersAsync()).Contains(Program.kami.CurrentUser as IGuildUser))
var audioClient = await channel.ConnectAsync();
await SendAsync(audioClient,choice);
}
You need to await a GetUserAsync operations
(await channel.GetUsersAsync()).Contains(....)
Be sure that your method is async.

call back query data from inline keyboard

I'm trying to get the data from an inline keyboard, I've searched a lot but unfortunately didn't get my answer and non of codes worked for me. Here's my code please help me
static void Main(string[] args){
InlineKeyboardButton[][] buttons =
new InlineKeyboardButton[][]{
new InlineKeyboardButton[]{newInlineKeyboardButton() { Text = "show Channel", CallbackData = "Data1" }},
new InlineKeyboardButton[]{new InlineKeyboardButton() { Text = "show Website", CallbackData = "Data2" }}};
inlineKeyboardMarkup = new InlineKeyboardMarkup() { InlineKeyboard = buttons };
Task.Run(() => RunBot());
Console.ReadLine();
} // End of main method
public static async Task RunBot(){
while (true){
var u = await bot.MakeRequestAsync(new GetUpdates() { Offset
= offset });
foreach (var update in u)
{
offset = update.UpdateId + 1;
var text = update.Message.Text;
// here I want to get the data like this, but it doesn't work
if (update.ChosenInlineResult != null){
Console.WriteLine("Chosen Inline Result: " +
update.ChosenInlineResult.ToString());
}
switch(text){
case "Something":{
var req = new SendMessage(update.Message.Chat.Id, "راهنما") { ReplyMarkup = inlineKeyboardMarkup };
await bot.MakeRequestAsync(req);
break;
}
}
}
}
}
you must replace this
if (update.ChosenInlineResult != null){
Console.WriteLine("Chosen Inline Result: " +
update.ChosenInlineResult.ToString());
}
with something like This :
if (update.CallbackQuery != null)
{
Console.WriteLine(val.CallbackQuery.Message+"-"+val.CallbackQuery.Data);
}

Multiple forms in Microsoft bot framework

I have two forms. I need to access both the forms based on the user Input.
The forms are as follows
internal static IDialog<JObject> BuildTravelForm()
{
travelstatus = 1;
leaveStatus = 0;
return Chain.From(() => FormDialog.FromForm(TravelForm.BuildForm))
.Do(async (context, order) =>
{
try
{
travelstatus = 0;
var completed = await order;
string source = (string)completed.GetValue("Question1");
string destination = (string)completed.GetValue("Question2");
await context.PostAsync("Your travel request is awaiting approval" + " " + "from" + " " + source + " " + "to" + " " + destination);
}
catch (Exception)
{
await context.PostAsync("Thank you");
}
});
}
The second one goes like this
internal static IDialog<JObject> BuildLeaveForm()
{
leaveStatus = 1;
travelstatus = 0;
return Chain.From(() => FormDialog.FromForm(LeaveForm.BuildForm))
.Do(async (context,order)=>
{
leaveStatus = 0;
var completed = await order;
string startDate = (string)completed.GetValue("Question1");
string endDate = (string)completed.GetValue("Question2");
await context.PostAsync("Your leave is applied" + " " + "from" + " " + startDate + " " + "to" + " " + endDate);
});
}
The controller method is as follows
public async Task<Activity> Post([FromBody]Activity activity)
{
try
{
if (activity.Type == ActivityTypes.Message)
{
if (leaveStatus == 1 && travelstatus==0)
{
//nested if to check intents to follow
await Conversation.SendAsync(activity, BuildLeaveForm);
}
else if(travelstatus == 1 && leaveStatus==0)
{
await Conversation.SendAsync(activity, BuildTravelForm);
}
else
{
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
StateClient stateClient = activity.GetStateClient();
string replyMessage = "";
Luis stluis = await GetEntityFromLUIS(activity.Text);
if (stluis.intents.Count() > 0)
{
Activity reply;
///await Conversation.SendAsync(activity, MakeGreetings);
using (var file = Assembly.GetExecutingAssembly().GetManifestResourceStream("Javis_V2.IntentLibrary.json"))
{
o2 = JObject.Parse(new StreamReader(file).ReadToEnd());
string luisIntent = stluis.intents[0].intent;
if (luisIntent == "LeaveManager")
{
await Conversation.SendAsync(activity, BuildLeaveForm);
}
else if(luisIntent=="TravelManager")
{
await Conversation.SendAsync(activity, BuildTravelForm);
}
else
{
leaveStatus = 0;
travelstatus = 0;
replyMessage = (string)o2.GetValue(luisIntent);
if(replyMessage=="")
{
replyMessage = "Sorry! Not getting you";
}
reply = activity.CreateReply(replyMessage);
await connector.Conversations.ReplyToActivityAsync(reply);
}
}
}
}
}
else
{
HandleSystemMessage(activity);
}
return null;
}
catch (Exception exp)
{
Debug.WriteLine(exp);
return null;
}
}
The problem is that when the first form is completed, and when the second form is triggered through luis intent, the first form pops up. I am looking for something without the use of Dialogs.
Any kind of help is appreciated.
Thanks in advance.
This line is the issue :
if (leaveStatus == 1 && travelstatus==0)
{
//nested if to check intents to follow
await Conversation.SendAsync(activity, BuildLeaveForm);
await connector.Conversations.ReplyToActivityAsync(activity.CreateReply("Thanks"));
}
else if(travelstatus == 1 && leaveStatus==0)
{
await Conversation.SendAsync(activity, BuildTravelForm);
await connector.Conversations.ReplyToActivityAsync(activity.CreateReply("Thanks"));
}
If you see on the above code, the BuildTravelForm or BuildLeaveForm can clearly generate an error and end it without calling the Chain operation Do. If everything executes ok, it will call Do otherwise it will simply skip it. So the best place to reset the status is after the await statement which is ensured to be called after the completion of the dialog.
I will do like this :
if (leaveStatus == 1 && travelstatus==0)
{
//nested if to check intents to follow
await Conversation.SendAsync(activity, BuildLeaveForm);
travelstatus =0; leaveStatus=0;
await connector.Conversations.ReplyToActivityAsync(activity.CreateReply("Thanks"));
}
else if(travelstatus == 1 && leaveStatus==0)
{
await Conversation.SendAsync(activity, BuildTravelForm);
travelstatus =0; leaveStatus=0;
await connector.Conversations.ReplyToActivityAsync(activity.CreateReply("Thanks"));
}
Do check if it works well.

Categories