Custom keyboard in TelegramBot using MS Bot Framework - telegram

As far as i know, i can youse Actions (http://blog.botframework.com/2016/05/13/BotFramework.buttons/) to create inline keyboards in Telegram and other messages.
But what about Custom Keyboards (https://core.telegram.org/bots#keyboards)? How can i add them using Bot Framework?
I read about ChannelData (http://docs.botframework.com/connector/custom-channeldata/#custom-telegram-messages), but i didnt get, how can i pass JSON to CreateReplyMessage method.

Use CreateReplyMessage to create a Message object:
var replyMessage = incomingMessage.CreateReplyMessage("Yo, I heard you.");
Then set the ChannelData
replyMessage.ChannelData = {custom Telegram JSON}

For Bot Framework v4:
{
var reply = context.Context.Activity.CreateReply(messageText);
if (BotDialogHelpers.ExtractMessengerFromDialogContext(context) == BotDialogHelpers.Messengers.Telegram)
{
GenerateReplyMarkupForTelegram(reply);
}
await context.Context.SendActivityAsync(reply, token);
}
/// <summary>
/// https://learn.microsoft.com/en-us/azure/bot-service/dotnet/bot-builder-dotnet-channeldata?view=azure-bot-service-3.0
/// https://core.telegram.org/bots/api#message sendMessage reply_markup
/// </summary>
private void GenerateReplyMarkupForTelegram(IActivity reply)
{
var replyMarkup = new
{
reply_markup = new
{
remove_keyboard = true,
}
};
var channelData = new
{
method = "sendMessage",
parameters = replyMarkup,
};
reply.ChannelData = JObject.FromObject(channelData);
}

Related

The request was missing an Authentication Key. Please, refer to section "Authentication" with IHttpClientFactory

I'm trying to send an HTTP request from .NET Core 3.1 REST API to another API but below Exception keep appeared Although I'm already added the Authentication Key :
The request was missing an Authentication Key. Please, refer to section "Authentication"
here is my code :
public class AppService
{
private readonly IHttpClientFactory _clientFactory;
string key = "key=llllll ......";
string webAPIKey = "......";
string Id = "......";
public AppService(IHttpClientFactory clientFactory) {
_clientFactory = clientFactory;
}
public async Task<string> sendBroadCastNotification()
{
Data _data = new Data();
_data.title = "test data Ttile";
_data.detail = "test data detail";
Notification _notification = new Notification();
_notification.title = "test notification Ttile";
_notification.body = "test notification body";
MyNotification NotifcationData = new MyNotification {
data=_data,
notification=_notification,
to= "/topics/all"
};
try {
var client = _clientFactory.CreateClient();
client.DefaultRequestHeaders.Add("project_id", Id );
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", key);
StringContent bodyOfRequest = new StringContent(System.Text.Json.JsonSerializer.Serialize(NotifcationData ), Encoding.UTF8, "application/json");
using var httpResponse =
await client.PostAsync("https://.......", bodyOfRequest);
var result = httpResponse.Content.ReadAsStringAsync().Result;
return result;
}
catch (Exception ex)
{
throw new System.ArgumentException(ex.Message.ToString(), "original");
}
//return null;
}
}
I found the answer here in this link:
I add the key by using the below line:
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", key);
the below way that I was trying to add the authorization header wasn't understandable as an authorization header :
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", key);

Xamarin forms UWP: how can I save an jpg from ImageSource?

I can save a picture in iOS and Android but I can't find a way to save an image in UWP. Any ideas?
Thank you in advance.
I can't find a way to save an image in UWP
No, we can't extract the image data from an Xamarin ImageSource object.
There is StreamImagesourceHandler class implementation in UWP, see here
public sealed class StreamImageSourceHandler : IImageSourceHandler
{
public async Task<Windows.UI.Xaml.Media.ImageSource> LoadImageAsync(ImageSource imagesource, CancellationToken cancellationToken = new CancellationToken())
{
BitmapImage bitmapimage = null;
//Omitted
return bitmapimage;
}
}
So we need to extract data from BitmapImage.
Actually the BitmapImage class is inherited from ImageSource class, while we can't extract the image data from ImageSource, for the reason, please see these two questions:
Convert ImageSource to WriteableBitmap in Metro Windows 8
How save BitmapImage WinRT
The solution here is to use different way for Windows Runtime(W/WP8.1 & UWP) app, extracting image data from System.IO.Stream class is supported in UWP.
We can use DependencyService to access native platform features, firstly, create an interface in PCL:
public interface ISaveImage
{
void SavePictureToDisk(ImageSource imgSrc, string Id, bool OverwriteIfExist = false);
void SavePictureToDiskWINRT(System.IO.Stream imgStream, string Id, bool OverwriteIfExist = false);
}
In the code behind of Xamarin page:
var memoryStream = new MemoryStream(Convert.FromBase64String("iVBOxxxxxxxxxxMVEX/uQOAuwPzUxxxxxxxxxxxx="));
ImageSource imgsource = ImageSource.FromStream(() => memoryStream);
if (Device.OS == TargetPlatform.Windows|| Device.OS == TargetPlatform.WinPhone)
DependencyService.Get<ISaveImage>().SavePictureToDiskWINRT(memoryStream, "1");
else
DependencyService.Get<ISaveImage>().SavePictureToDisk(imgsource, "1");
Implement the interface in UWP platform:
using Xamarin.Forms;
using WorkingWithImages.WinUniversal;
using System.IO;
using System;
using Windows.Storage.Streams;
[assembly: Xamarin.Forms.Dependency(typeof(SaveImageImplementation))]
namespace WorkingWithImages.WinUniversal
{
public class SaveImageImplementation : ISaveImage
{
public SaveImageImplementation() { }
public void SavePictureToDisk(ImageSource imgSrc, string Id, bool OverwriteIfExist = false)
{
throw new NotImplementedException();
}
public async void SavePictureToDiskWINRT(Stream imgStream, string Id, bool OverwriteIfExist = false)
{
var inStream = imgStream.AsRandomAccessStream();
var fileBytes = new byte[inStream.Size];
using (DataReader reader = new DataReader(inStream))
{
await reader.LoadAsync((uint)inStream.Size);
reader.ReadBytes(fileBytes);
}
var file = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFileAsync(Id+".jpg", Windows.Storage.CreationCollisionOption.ReplaceExisting);
using (var fs = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite))
{
var outStream = fs.GetOutputStreamAt(0);
var dataWriter = new DataWriter(outStream);
dataWriter.WriteBytes(fileBytes);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
await outStream.FlushAsync();
outStream.Dispose();
fs.Dispose();
}
}
}
}
Please check my completed demo in here
About UWP File storage guidance, please see Create, write, and read a file
maybe someone needs a solution for iOS and Android (below). Meanwhile I'm waiting an idea for UWP.
iOS
/// <summary>
/// Saves the picture to disk.
/// </summary>
/// <returns>The picture to disk.</returns>
/// <param name="imgSrc">Image source.</param>
/// <param name="id">Identifier.</param>
/// <param name="overwriteIfExist">if set to <c>true</c> overwrite if exist.</param>
/// <returns>The picture to disk.</returns>
public async void SaveImage(ImageSource imgSrc, string id, bool overwriteIfExist = false)
{
var renderer = new StreamImagesourceHandler();
var photo = await renderer.LoadImageAsync(imgSrc);
string jpgFilename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), id + ".jpg");
if (File.Exists(jpgFilename))
{
File.Delete(jpgFilename);
}
NSData imgData = photo.AsJPEG();
NSError err;
if (imgData.Save(jpgFilename, false, out err))
{
Console.WriteLine("saved as " + jpgFilename);
}
else
{
Console.WriteLine("NOT saved as " + jpgFilename
+ " because" + err.LocalizedDescription);
}
}
Good to know, when iOS saves an image as jpg, the image header says png.
Android
/// <summary>
/// Saves the picture to disk.
/// </summary>
/// <param name="imgSrc">Image source.</param>
/// <param name="id">The image identifier.</param>
/// <param name="overwriteIfExist">if set to <c>true</c> overwrite if exist.</param>
/// <returns>The picture to disk.</returns>
public async void SaveImage(ImageSource imgSrc, string id,
bool overwriteIfExist = false)
{
var renderer = new StreamImagesourceHandler();
var photo = await renderer.LoadImageAsync(imgSrc, Forms.Context);
string jpgFilename = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), id + ".jpg");
if (File.Exists(jpgFilename))
{
File.Delete(jpgFilename);
}
using (FileStream fs = new FileStream(jpgFilename, FileMode.OpenOrCreate))
{
photo.Compress(Bitmap.CompressFormat.Jpeg, 100, fs);
}
}

How can I get channel messages from telegram channels with TLSharp?

How can I get channel messages from telegram channels with TLSharp?
The following links haven't helped me:
How can I get messages from a Telegram channel with the Telegram API
How to obtain all messages from my channel in telegram?
You can use this code
public async Task GatherChannelHistory(string channelName, int offset = 0, int maxId = -1, int limit = 50)
{
_resultMessages.Clear();
await _client.ConnectAsync();
var dialogs = (TLDialogsSlice)await _client.GetUserDialogsAsync();
var chat = dialogs.Chats.ToList()
.OfType<TLChannel>()
.FirstOrDefault(c => c.Title == channelName);
if (chat.AccessHash != null)
{
var tlAbsMessages =
await _client.GetHistoryAsync(
new TLInputPeerChannel {ChannelId= chat.Id, AccessHash = chat.AccessHash.Value}, offset,
maxId, limit);
var tlChannelMessages = (TLChannelMessages) tlAbsMessages;
for (var index = 0; index < tlChannelMessages.Messages.Count-1; index++)
{
var tlAbsMessage = tlChannelMessages.Messages.ToList()[index];
var message = (TLMessage) tlAbsMessage;
//Now you have the message and you can do what you need with it
//the code below is an example of messages classification
if (message.media == null)
{
_resultMessages.Add(new ChannelMessage()
{
Id = message.id,
ChannelId = chat.id,
Content = message.message,
Type = EnChannelMessage.Message,
Views = message.views,
});
}
else
{
switch (message.media.GetType().ToString())
{
case "TeleSharp.TL.TLMessageMediaPhoto":
var tLMessageMediaPhoto = (TLMessageMediaPhoto)message.media;
_resultMessages.Add(new ChannelMessage()
{
Id = message.id,
ChannelId = chat.id,
Content = tLMessageMediaPhoto.caption,
Type = EnChannelMessage.MediaPhoto,
Views = message.views ?? 0,
});
break;
case "TeleSharp.TL.TLMessageMediaDocument":
var tLMessageMediaDocument = (TLMessageMediaDocument)message.media;
_resultMessages.Add(new ChannelMessage()
{
Id = message.id,
ChannelId = chat.id,
Content = tLMessageMediaDocument.caption,
Type = EnChannelMessage.MediaDocument,
Views = message.views ?? 0,
});
break;
case "TeleSharp.TL.TLMessageMediaWebPage":
var tLMessageMediaWebPage = (TLMessageMediaWebPage)message.media;
string url = string.Empty;
if (tLMessageMediaWebPage.webpage.GetType().ToString() != "TeleSharp.TL.TLWebPageEmpty")
{
var webPage = (TLWebPage) tLMessageMediaWebPage.webpage;
url = webPage.url;
}
_resultMessages.Add(new ChannelMessage
{
Id = message.id,
ChannelId = chat.id,
Content = message.message + #" : " + url,
Type = EnChannelMessage.WebPage,
Views = message.views ?? 0,
});
break;
}
}
}
}
}
To get channel messages you simply need to be receiving channel updates.
As at TL-schema-52 you could request:
channels.getDialogs#a9d3d249 offset:int limit:int = messages.Dialogs;
however this has been dropped in TL-schema-53.
I'm guessing you can try one of the other channel.* functions,
I have not tried yet on TL-schema-53
What version of the TL-schema is your TLSharp using?
You could simply implement the relevant functions if they are not yet implemented in your TLSharp version
Not sure if this works 100% without missing any messages, but this is what I have used in one of my projects:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TeleSharp.TL;
using TeleSharp.TL.Channels;
using TeleSharp.TL.Messages;
using TLSharp.Core;
using TLSharp.Core.Utils;
namespace NewsArchive.Telegram
{
/// <summary>
/// Created to be used as a workaround of ref/out since they cannot be used in an async method => GetMessagesInternal
/// </summary>
public class RequestOffset
{
/// <summary>
/// Value of the offset
/// </summary>
public int Id { get; set; }
}
public class TelegramNewsClient
{
#region Properties
private TelegramClient _client;
private int _apiId;
private string _apiHash;
private static readonly int RESULT_MAX = 100;
#endregion
/// <summary>
/// Ctor
/// </summary>
/// <param name="apiId"></param>
/// <param name="apiHash"></param>
public TelegramNewsClient(int apiId, string apiHash)
{
_apiId = apiId;
_apiHash = apiHash;
_client = new TelegramClient(_apiId, _apiHash);
_client.ConnectAsync().Wait();
}
/// <summary>
/// Authenticates the user with the phone number
/// </summary>
/// <param name="phone"></param>
/// <returns></returns>
public async Task Authenticate(string phone)
{
var hash = await _client.SendCodeRequestAsync(phone);
var code = "<code_from_telegram>"; // you can change code in debugger
var user = await _client.MakeAuthAsync(phone, hash, code);
}
/// <summary>
/// Gets all messages from a channel
/// </summary>
/// <param name="channelName"></param>
/// <returns></returns>
public async Task<IEnumerable<TLMessage>> GetChannelMessages(string channelName)
{
var messages = new List<TLMessage>();
var channel = await GetChannel(channelName);
if(channel == null)
throw new Exception($"The channel {channelName} was not found!");
var offset = new RequestOffset(){Id = 1};
var internalMessages = new List<TLMessage>();
internalMessages = await GetMessagesInternal(channel.Id, channel.AccessHash.Value, offset);
messages = messages.Concat(internalMessages)
.OrderBy(m => m.Id)
.ToList();
while (internalMessages.Count > 0)
{
/*When you reach the last message, the API will keep returning the same last message over and over again,
that's why we stop making requests and return the result*/
if ((internalMessages.Count == 1 && internalMessages.First().Id == messages.Max(m => m.Id)))
break;
internalMessages = await GetMessagesInternal(channel.Id, channel.AccessHash.Value, offset);
messages = messages.Concat(internalMessages)
.OrderBy(m =>m.Id)
.ToList();
/*if you make too many requests you will be locked out of the API*/
await Task.Delay(TimeSpan.FromSeconds(1));
}
return messages;
}
private async Task<List<TLMessage>> GetMessagesInternal(int channelId, long accessHash, RequestOffset offset)
{
/*Refer to https://core.telegram.org/api/offsets for more info on how to use the offsets.
Here we basically get the last RESULT_MAX (100 in this case) messages newer than the offset.Id aka offsetId*/
var history = await _client.GetHistoryAsync(new TLInputPeerChannel
{
ChannelId = channelId,
AccessHash = accessHash
}, offset.Id, 0, -RESULT_MAX, RESULT_MAX, 0, 0) as TLChannelMessages;
/*Some messages are service messages with no useful content, and if cast to TLMessage it will throw an exception*/
var messages = history.Messages
.Where(m => m is TLMessage)
.Cast<TLMessage>()
.ToList();
/*Get the ID of the last message so it can be used in the next API call*/
offset.Id = messages.Max(m => m.Id);
return messages;
}
private async Task<TLChannel> GetChannel(string channelName)
{
var offset = new RequestOffset() { Id = RESULT_MAX };
var channels = (await _client.GetUserDialogsAsync(0, offset.Id, null, RESULT_MAX) as TLDialogs)
?.Chats
?.Cast<TLChannel>()
?.ToList();
var channel = channels?.FirstOrDefault(c => c.Username.Equals(channelName, StringComparison.OrdinalIgnoreCase));
offset.Id += RESULT_MAX - 1;
while (channels.Count > 0 && channel == null)
{
channels = (await _client.GetUserDialogsAsync(0, offset.Id, null, RESULT_MAX) as TLDialogs)
?.Chats
?.Cast<TLChannel>()
?.ToList();
channel = channels?.FirstOrDefault(c => c.Username.Equals(channelName, StringComparison.OrdinalIgnoreCase));
offset.Id += RESULT_MAX - 1;
/*if you make too many requests you will be locked out of the API*/
await Task.Delay(TimeSpan.FromSeconds(1));
}
return channel;
}
}
}

Post data with free-jqgrid, what are the code in client and Web API side?

I am using ASP.NET MVC 6 Web API. In the View I use free-jqgrid.
Let's borrow Oleg's free jqgrid data to demonstrate my purpose. We already have the table shown.
Next I am going to add new Vendor. Please notify that there is primary key id(identity column) in the database. We don't want it displaying in the screen.
In VendorRespository.cs, I add the new Vendor as
public void AddVendor(Vendor item)
{
using (VendorDataContext dataContext = new VendorDataContext())
{
dataContext.Database.Connection.ConnectionString = DBUtility.GetSharedConnectionString(
"http://centralized.admin.test.com");
var newVendor = dataContext.Vendors.Create();
newVendor.Company = item.Company;
newVendor.ContactName = item.ContactName;
newVendor.ContactPhone = item.ContactName;
newVendor.UserName = item.UserName;
newVendor.UserKey = item.UserKey;
newVendor.Active = item.Active;
newVendor.FacilityId =item.FacilityId;
newVendor.ClientID = item.ClientID;
dataContext.SaveChanges();
}
}
My questions:
Not sure the script like?
<script>
API_URL = "/VendorManagement/";
function updateDialog(action) {
return {
url: API_URL
, closeAfterAdd: true
, closeAfterEdit: true
, afterShowForm: function (formId) { }
, modal: true
, onclickSubmit: function (params) {
var list = $("#jqgrid");
var selectedRow = list.getGridParam("selrow");
rowData = list.getRowData(selectedRow);
params.url += rowData.Id;
params.mtype = action;
}
, width: "300"
};
}
jQuery("#jqgrid").jqGrid('navGrid',
{ add: true, edit: true, del: true },
updateDialog('PUT'),
updateDialog('POST'),
updateDialog('DELETE')
);
In the controller, not sure what is the code?
// POST
public HttpResponseMessage PostVendor(Vendor item)
{
_vendorRespository.AddVendor(item);
var response = Request.CreateResponse<Vendor>(HttpStatusCode.Created, item);
string uri = Url.Link("DefaultApi", new { id = item.Id });
response.Headers.Location = new Uri(uri);
return response;
}
My code has many compiling errors such as
'HttpRequest' does not contain a definition for 'CreateResponse' and the best extension method overload 'HttpRequestMessageExtensions.CreateResponse(HttpRequestMessage, HttpStatusCode, Vendor)' requires a receiver of type 'HttpRequestMessage'
Please help me to get rid of the error and inappropriate code.
EDIT:
I borrowed the code snippet from here.
I need add the code such as
[Microsoft.AspNet.Mvc.HttpGet]
public dynamic GetVendorById(int pkey)
{
return null;
}
And
// POST
[System.Web.Http.HttpPost]
public HttpResponseMessage PostVendor(Vendor item)
{
_vendorRespository.AddVendor(item);
var response = Request.CreateResponse<Vendor>(HttpStatusCode.Created, item);
string uri = Url.Link("/VendorManagement/GetVendorById", new { id = item.pkey });
response.Headers.Location = new Uri(uri);
return response;
}

Adding subscribers to a list using Mailchimp's API v3 using .net

I am trying add a subscriber to a list but I'm struggling to implement it without any example code.
can anybody help me with the example?
Inspired by this video:
MailChimp.NET Tutorial: Create, Edit And Delete List Members - here my test code to add a subscriber to a 'given list'.
The subscriber will receive an email asking to confirm the subscription. After that confirmation the new subscriber
will be listed in mailchimp campaign list.
(used version mailchimp.net wrapper v:3 with newtonsoft.json version 10.0.3) - this worked for me.
private static readonly IMailChimpManager Manager = new MailChimpManager(ApiKey);
public async Task AddSubscriberToCampaignList(string emailAddress, string listName, string fname, string lname)
{
try
{
var listsAwaitable = Manager.Lists.GetAllAsync().ConfigureAwait(false);
var list = listsAwaitable.GetAwaiter().GetResult().FirstOrDefault(l =>
l.Name.Equals(listName, StringComparison.CurrentCultureIgnoreCase));
if (list != null)
{
//the subscriber
var member = new Member
{
EmailAddress = emailAddress,
StatusIfNew = Status.Pending,
EmailType = "html",
TimestampSignup = DateTime.UtcNow.ToString("s"),
};
if (fname != null && lname != null)
{
var subscriberName = new Dictionary<string, object>
{
{"FNAME", fname},
{"LNAME", lname}
};
member.MergeFields = subscriberName;
}
string campaignListKey = list.Id;
await Manager.Members.AddOrUpdateAsync(campaignListKey, member);
}
}
catch (MailChimpException e)
{
throw;
}

Resources