📜 ⬆️ ⬇️

Another telegram-bot or implementation of a dating bot

My name is Vlad, by the nature of my activity I am a military man, but I earn money at a business automation company, where I do programming on .net.

Brief background


At the moment of another descent-divergence with my former (next) bride, she let slip that, out of boredom, she was looking for guys to date through a telegram bot, which could send photos and geolocation and you picked people who were nearby. I promised that I would write something similar if we again run away. Yara is for you.
I safely forgot about it, but at the moment of idleness, I scrolled the site with a cupcake on a green background , where I came across a section where people just laid out a post with a photo, briefly wrote about themselves and pointed out contacts.

So the idea to write your bot, which would help people find friends or anyone else.

Task


Create a bot, where everyone who wants to talk, could put a short data about yourself and just wait for him to write.
')


Preparation for work


How to create a bot through BotFather does not know only those who are not interested, so I will not fill the article with unnecessary information.

Storage of "questionnaires"


Initially, I created a project ClassLibrary, which was going to use to work with data.

First you need to decide how to store user data. To do this, we need to "describe" the user.

public class user { [Key] public string tg_id { get; set; }//   public string name { get; set; }//  public string age { get; set; }//  public string country { get; set; }//  public string city { get; set; }// public string gender { get; set; }// public string photo { get; set; }//   public string tg_username { get; set; }// -,           public string tg_chat_id { get; set; }// ,    } 

For storage, a PostgreSQL database was selected, which was deployed on a remote server.
Preset, install EntityFramework, via NuGet. This unrealistically simplifies life in working with the database.

To work requires a package:

NpgSQL.EntityFrameworkCore.PostgreSQL

A migration package is required:

Microsoft.EntityFrameworkCore.Tools

In order not to engage in the routine creation of a table, we simply create the data model itself (our class is higher) and set the connection to the database.

 public DbSet<user> user { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseNpgsql(connectionString); } 

Further we carry out migration.

To do this, in the Package Manager Console execute the following commands:
enable-migrations
Turn on the migration mechanism
Add-migration * *
Create a migration
update-database
We update a DB

Now we will have two tables in the database: Migration history and the user table itself.



After solving the issue of storing data and connecting to the database, you can proceed to writing the bot processor itself.

Bot handler


The telegram itself offers two options for receiving updates: webhook or constantly pull the server, checking for updates. Webhook has a large number of difficulties, so it's easier to just check for updates.

Receive updates processing them


In order not to create a bicycle (it is sometimes useful), it is easier to use a ready-made solution: Telegram.Bot by MrRoundRobin is an excellent, very convenient library for working with Telegram.

Create a new ConsoleApp project in the solution, where we install this package.

 private static readonly TelegramBotClient Bot = new TelegramBotClient(token);//  static void Main(string[] args) { var me = Bot.GetMeAsync().Result;//  ,    (  ,   ) Console.Title = me.Username; //   Bot.OnMessage += BotOnMessageReceived; Bot.OnCallbackQuery += BotOnCallbackQueryReceived; Bot.OnReceiveError += BotOnReceiveError; //   Bot.StartReceiving(Array.Empty<UpdateType>()); Console.WriteLine($"Start listening for @{me.Username}"); Console.ReadLine(); Bot.StopReceiving(); } 

Thus, we started checking for updates and set up our error handlers.
BotOnMessageReceived - the handler for receiving "normal" messages
BotOnCallbackQueryReceived - handler for pressing buttons that appear under the message.

Things are easy, the ability to leave a profile and the ability to scroll through the rest. So you need to send the user two buttons: Registration and Next. The button represents an InlineKeyboardButton object, and all buttons need to be packaged in

 IEnumerable<IEnumerable<InlineKeyboardButton>> 

When you open the bot, it immediately sends a message with the text "/ start", so we need to BotOnMessageReceived process this message and send back our buttons.

 if (message.Text == "/start") { var inlineKeyboard = new InlineKeyboardMarkup(new[] { new [] // first row { InlineKeyboardButton.WithCallbackData("!", "Next"), InlineKeyboardButton.WithCallbackData("", "Registration") } }); Bot.SendTextMessageAsync(message.Chat.Id, "   lovebot! \r\n   - /start\r\n       - /register\r\n     - /stats\r\n     - @hahah2016", replyMarkup: inlineKeyboard); return; } 

check in


To register, you need to remember what the user entered earlier. That is, we need to create a storage bot memory. I simply created a class where I described the logic of filling data.

RegForm.cs
 public class RegForm { public string tg_id { get; set; } public string name { get; set; } public string age { get; set; } public string country { get; set; } public string city { get; set; } public string gender { get; set; } public string photo { get; set; } public string tg_username { get; set; } public string tg_chat_id { get; set; } public int stage; public RegForm(string id, string chat_id, string username) { stage = 1; tg_id = id; tg_username = username; } public (string, int) StageText(string id) { if (stage == 1) return ("  :", stage); if (stage == 2) return (" :", stage); if (stage == 3) return ("  :", stage); if (stage == 4) return ("  :", stage); if (stage == 5) return ("  :", stage); else return ("   :", stage); } public bool SetParam(string param) { if (stage == 1) name = param; if (stage == 2) age = param; if (stage == 3) country = param; if (stage == 4) city = param; if (stage == 5) gender = param; if (stage == 6) photo = param; stage++; return true; } } 

In this class, you can implement data validation, for example, not to miss age as text, etc.

And the memory itself is static Dictionary<string, RegForm> registrations = new Dictionary<string, RegForm>(); , in which we add a new KeyValuePair, when a button is pressed.

For a bot to know how to respond to a click, you need to add to BotOnCallbackQueryReceived

 var message = e.CallbackQuery; if (message.Data == "Registration") { RegForm form = new RegForm(message.From.Id.ToString(), message.Message.Chat.Id.ToString(), message.From.Username);//    registrations.Add(message.From.Id.ToString(), form);//   "",    telegram_id . var t = form.StageText(form.tg_id); // ,   ,     . Bot.SendTextMessageAsync(message.Message.Chat.Id, t.Item1);//  . return; } 

And in the same way, processing the data, you can fill out the form and save the data.
  using (Context db = new Context()) { IMapper mapper = new MapperConfiguration(cfg => cfg.CreateMap<RegForm, User>()).CreateMapper(); if (db.user.Where(x => x.tg_id == message.From.Id.ToString()).Count() != 0) db.user.Update(mapper.Map<RegForm, tgbot_base.classes.user>(u)); else { db.user.Add(mapper.Map<RegForm, tgbot_base.classes.user>(u)); } db.SaveChanges(); } 

If the user already has a profile, then simply update the data.

Saving user photo
 if (message.Type == MessageType.Photo) { string file = Bot.GetFileAsync(message.Photo[message.Photo.Count() - 1].FileId).Result.FilePath; string filepath = message.From.Id + "." + file.Split('.').Last(); using (FileStream fileStream = new FileStream("C:\\images\\" + filepath, FileMode.OpenOrCreate, FileAccess.ReadWrite)) { var st = Bot.DownloadFileAsync(file).Result; st.Position = 0; st.CopyTo(fileStream); } u.SetParam("C:\\images\\" + filepath); } 


Showing other profiles


To do this, you just need to take data from the database and send it to the user.

To do this, we write a simple method that will take data from the database and return it in a convenient format:

 public static User GetRandom() { Stopwatch s = new Stopwatch(); s.Start(); User u; using (Context db = new Context()) { Random r = new Random(); int count = db.user.Count(); if (count > 1) count = count - 1; List<User> users = mapper.Map<List<tgbot_base.classes.user>, List<User>>(db.user.ToList()); u = users.ElementAt(r.Next(0, count)); } Console.WriteLine("[" + DateTime.Now + "] For finding " + s.ElapsedMilliseconds + " ms"); s = null; return u; } 

Next button click handler:

 if (message.Data == "Next") { if (searchForms.Count != 0) { searchForms.Remove(message.From.Id.ToString()); } IMapper mapper = new MapperConfiguration(cfg => cfg.CreateMap<RegForm, User>()).CreateMapper(); User user = BaseWorker.GetRandom(); SendAnket(user, message.Message.Chat.Id.ToString());//,     . return; } 

Conclusion


For all its simplicity, the bot liked the public.

Less than a day, 134 users left their profiles, there are positive feedback. And without much advertising - just one post on the site, which didn’t gain much advantage.

Bots - this is a long forgotten old, which has found a new life. They help to really automate many processes and even search for a couple on the Internet. Bypassing the dating sites monetized.

Thank you for reading to the end.

Good luck, have fun, dont eat yellow snow.

Source: https://habr.com/ru/post/430314/


All Articles