用Python和Fauna建立一个预约调度的Telegram机器人

714 阅读9分钟

在靠近用户的地方部署容器

本工程教育(EngEd)计划由科支持。

在全球范围内即时部署容器。Section是经济实惠、简单而强大的。

免费开始吧。

用Python和Fauna构建一个预约调度Telegram机器人

4月16日, 2021

你是否曾经想建立一个Telegram机器人,让你安排或规划你的约会?如果你的答案是肯定的,那么这篇文章就是你所需要的。

你还会使用一个名为FaunaDB的无服务器数据库系统来构建我们的系统,使你的工作变得更加简单。

什么是Fauna?

Fauna是一个客户端无服务器文档数据库,它使用GraphQL和Fauna查询语言(FQL),在无服务器API中支持各种数据类型和关系型数据库。

前提条件

要继续学习本教程,你需要具备以下条件。

安装要求

如果你还没有,请在你的命令行界面上运行下面的命令来安装先决条件。

pip install faunadb telegram python_telegram_bot

设置Fauna数据库

他们的网站上注册,并创建一个新的数据库,名字由你自己选择。这个数据库将存放收藏品、文件和其他与本文相关的数据库元素。

database_dashboard

设置Fauna集合

你需要创建的两个集合是Users 集合和Appointment 集合。请访问这里获取关于创建所需集合的信息。

create_collection

设置Fauna的索引

为了方便访问和滚动数据库中的数据,我们需要创建一个Fauna索引。我们需要为数据库创建三个索引:users_index,appointment_index, 和appointment_today_index

还可以访问这些关于创建索引的说明。

create_index

indexes

将Fauna连接到Python

设置一个Fauna的API密钥

请访问这里,了解如何创建和设置一个API密钥的信息。

new_key

key

创建Telegram机器人

要了解如何创建一个Telegram机器人,请访问这里

用Python为机器人提供动力

创建一个新的Python文件,给它取一个你喜欢的名字。现在你必须将所需的模块导入你的Python文件中。

import telegram
from telegram.ext import Updater
from telegram.ext import CommandHandler
from telegram.ext import MessageHandler, Filters
import pytz
from datetime import datetime, date
from faunadb import query as q
from faunadb.objects import Ref
from faunadb.client import FaunaClient

现在,让我们为你的机器人创建一个调度器和更新器。

telegram_bot_token = "your-telegram-token"
client = FaunaClient(secret="your-fauna-secret-key")
updater = Updater(token=telegram_token, use_context=True)
dispatcher = updater.dispatcher

调度器的功能是处理收到的消息,而更新器则跟踪、监控和读取发送到机器人的消息,并将它们传递给调度器。

现在让我们使用下面的Python代码启动我们的机器人。

def start(update, context):
    chat_id = update.effective_chat.id
    first_name = update["message"]["chat"]["first_name"]
    username = update["message"]["chat"]["username"]
    
    try:
        client.query(q.get(q.match(q.index("users_index"), chat_id)))
        context.bot.send_message(chat_id=chat_id, text="Welcome to Fauna Appointment Scheduler Bot \n\n To schedule an appointment enter /add_appointment \n To list al appointment enter /list_appointments \n To list all appoint,emts you have today enter /list_today_appointments")

    except:
        user = client.query(q.create(q.collection("Users"), {
            "data": {
                "id": chat_id,
                "first_name": first_name,
                "username": username,
                "last_command": "",
                "date": datetime.now(pytz.UTC)
            }
        }))

        context.bot.send_message(chat_id=chat_id, text="Welcome to Fauna Appointment Scheduler Bot, your details have been saved 😊 \n\n To schedule an appointment enter /add_appointment \n To list al appointment enter /list_appointments \n To list all appointments you have today enter /list_today_appointments")

在上面的代码中,你创建了一个叫做start 的函数,然后把updatecontext 作为参数传给了对方。update 是电报用户的数据,是由调度程序自动传递的。context 是由调度程序传递的机器人实例。

然后,你从更新器中收集了chat_idfirst_nameusername ,然后用users_index ,向FQL(Fauna Query Language)客户端发出请求,检查chat_id 的用户是否已经存在于数据库中。

如果该用户存在,你就发送一条欢迎信息。否则,你用提供的信息创建一个用户。接下来,你需要为/start 命令创建一个调度处理程序。Telegram中的命令是任何以/ 开始的文本。

你还可以添加其他的处理程序,如文本处理程序、图像处理程序、重码处理程序,等等。在本教程中,我们将从初始化机器人的命令处理程序开始。

复制并粘贴下面的代码到你的Python文件的末尾,调用调度处理程序,将一个命令处理程序连接到 "start "命令。

start "命令会触发start 方法。更新器检查来自用户的信息。

dispatcher.add_handler(CommandHandler("start", start))
updater.start_polling()

让我们通过运行我们的应用程序。

# python file name is app.py
python app.py

当你的Python应用程序正在运行时,打开你的telegram应用程序并搜索你创建的机器人。

search_bot

打开你的机器人,通过输入/start 命令来启动它。现在你将收到来自机器人的欢迎信息,如下图所示。

start_bot

创建新的约会

现在,我们将使你的Telegram机器人在fauna数据库中创建新的约会。

def add_appointment(update, context):
    chat_id = update.effective_chat.id
    user = client.query(q.get(q.match(q.index("users_index"), chat_id)))
    client.query(q.update(q.ref(q.collection("Users"), user["ref"].id()), {"data": {"last_command": "add_appointment"}}))
    context.bot.send_message(chat_id=chat_id, text="Enter the appointment event you want to add along with its due in this format(mm/dd/yyyy) date separated by a comma 😁")

add_appointment 方法中,你利用chat_id 来查询FQL客户端,使用users_index 索引来检查符合chat_id 的用户数据。

接下来,你更新了用户数据中的last_command 字段,以保存用户发送的add_appointment 命令。然后,你发送了一条消息,要求用户输入约会的名称和它的到期日期,用逗号隔开。

现在你必须创建另一个名为echo 的方法,该方法将收集新约会的名称和到期日期,然后将其保存到数据库中。

def echo(update, context):
    chat_id = update.effective_chat.id
    message = update.message.text
    user = client.query(q.get(q.match(q.index("users_index"), chat_id)))
    last_command = user["data"]["last_command"]
    
    if last_command == "add_appointment":
        events = client.query(q.create(q.collection("Appointments"), {
            "data": {
                "user_id": chat_id,
                "event": message.split(",")[0],
                "completed": False,
                "date_due": message.split(",")[1]
            }
        }))
        
        client.query(q.update(q.ref(q.collection("Users"), user["ref"].id()), {"data": {"last_command": ""}}))
        context.bot.send_message(chat_id=chat_id, text="Successfully added appointment event 👍")

echo 方法中,你利用chat_id 来查询FQL客户端,使用users_index 索引来检查符合chat_id 的用户数据。

接下来,你检查了检索到的数据中的last_command 是否是一个add_appointment 命令。如果是,你查询FQL客户端,使用Appointments 集合中的Faunacreate 方法,用用户信息中提供的信息创建一个约会。

最后,你需要为add_appointment 命令创建一个命令处理器,为echo 方法创建一个消息处理器。消息处理程序过滤消息,并在用户输入消息时触发echo 方法(消息是任何不以/ 开始的文本)。

注意:echo方法只在最后一条命令是add_appointment 命令时才起作用。

dispatcher.add_handler(CommandHandler("add_appointment", add_appointment))
dispatcher.add_handler(MessageHandler(Filters.text, echo))

add_appointment

上市预约

下面的部分将提供列出所有为一个用户保存的约会的功能。

def list_appointments(update, context):
   chat_id = update.effective_chat.id
   event_message = ""
   events = client.query(q.paginate(q.match(q.index("appointment_index"), chat_id)))
   for i in events["data"]:
       event = client.query(q.get(q.ref(q.collection("Appointments"), i.id())))
       if event["data"]["completed"]:
           event_status = "Completed"
          
       else:
           event_status = "Not Completed"
       event_message += "{}\nStatus:{} \nDate Due: {}\nUpdate Link: /update_{}\nDelete Link: /delete_{}\n\n".format(event["data"]["event"], event_status, event["data"]["date_due"], i.id(), i.id())
   if event_message == "":
       event_message = "You don't have any appointments saved, type /add_appointment to schedule one now 😇"
   context.bot.send_message(chat_id=chat_id, text=event_message)

list_appointments 方法中,你保存了用户的chat_id ,并创建了一个名为event_message 的空变量。然后,你利用chat_id ,使用appointments_index 索引查询FQL客户端,以检查与chat_id 匹配的用户数据。

接下来,你循环查看检索到的数据,以检查completed 字段是否被设置为真。如果是这样的话,你就把event_status 设置为 "已完成"。否则,你将其设置为 "未完成"。

然后,你向用户发送了一条信息,其中包含eventstatus 、更新链接和每个预约的删除链接。

更新链接是通过将/update_ 附加到预约的id来创建的,而删除链接是通过将/delete_ 附加到预约的id来创建的。

如果检索到的查询不包含数据,这意味着event_message 是空的。然后,你向用户发送一条消息,说明用户没有保存任何约会。

list_appointment

def list_today_appointments(update, context):
   chat_id = update.effective_chat.id
   event_message = ""
   today = date.today()
   date1=today.strftime("%m/%d/%Y")
   events = client.query(q.paginate(q.match(q.index("appointment_today_index"), chat_id, date1 )))
   for i in events["data"]:
       event = client.query(q.get(q.ref(q.collection("Appointments"), i.id())))
       if event["data"]["completed"]:
           event_status = "Completed"
          
       else:
           event_status = "Not Completed"
       event_message += "{}\nStatus:{} \nDate Due: {}\nUpdate Link: /update_{}\nDelete Link: /delete_{}\n\n".format(event["data"]["event"], event_status, event["data"]["date_due"], i.id(), i.id())
       
   if event_message == "":
       event_message = "You don't have no appointments saved, enter /add_appointment command to schedule one now 😇"
       
   context.bot.send_message(chat_id=chat_id, text=event_message)

list_today_appointments 方法和list_appointments 方法一样,有一个明显的区别,即appointment_today_index 。这个索引只检索date_due 字段与当前日期相匹配的数据。

让我们为这两种方法创建一个命令处理程序。

dispatcher.add_handler(CommandHandler("list_appointments", list_appointments))
dispatcher.add_handler(CommandHandler("list_today_appointments", list_today_appointments))

list_today_appointment

更新约会

现在你将使你的机器人能够更新数据库中的约会。

def update_appointment(update, context):
   chat_id = update.effective_chat.id
   message = update.message.text
   event_id = message.split("_")[1]
   event = client.query(q.get(q.ref(q.collection("Appointments"), event_id)))

   if event["data"]["completed"]:
       new_status = False

   else:
       new_status = True

   client.query(q.update(q.ref(q.collection("Appointments"), event_id), {"data": {"completed": new_status}}))
   context.bot.send_message(chat_id=chat_id, text="Successfully updated appointment status 👌")

update_appointment 方法中,你保存了用户的chat_id 和传递的消息,然后通过删除消息中的update_ 前缀来创建event_id

然后,你利用event_id 来查询FQL客户端,以检查与event_id 匹配的约会。然后,你检查约会的completed 字段是否被设置为True。

如果是这样,你将new_status 变量设置为False。否则,你将new_status 变量设置为True。

最后,你向FQL客户端进行了查询,使用Faunaupdate 方法将completed 字段更新为new_status 变量的值。然后你向用户发送了一条成功的更新信息。

你将update_appointment 方法设置为被一个消息处理程序触发,该处理程序使用regex过滤器来检测更新方法的regex代码。然后,你分割消息以提取约会ID。复制并粘贴下面的代码来创建消息处理程序。

dispatcher.add_handler(MessageHandler(Filters.regex("/update_[0-9]*"), update_appointment))

update_appointment

删除约会

现在你将使你的机器人能够从数据库中删除约会。

def delete_appointment(update, context):
   chat_id = update.effective_chat.id
   message = update.message.text
   event_id = message.split("_")[1]
   client.query(q.delete(q.ref(q.collection("Appointments"), event_id)))
   context.bot.send_message(chat_id=chat_id, text="Successfully deleted appointment👌")

delete_appointment 方法和update_appointment 方法一样。然而,不同的是,在通过查询Appointments 集合来检索约会后,你使用Faunadelete 方法从数据库中删除数据。随后,你发送了一条消息,提醒用户成功删除了约会。

你将delete_appointment 方法设置为被一个消息处理程序触发,该处理程序使用regex过滤器来检测删除方法的regex代码。然后你分割消息以提取约会的ID。复制并粘贴下面的代码来创建消息处理程序。

dispatcher.add_handler(MessageHandler(Filters.regex("/delete_[0-9]*"), update_appointment))

delete_appointment

总结

在这篇文章中,我们用Fauna的无服务器数据库建立了一个约会安排的电报机器人。我们看到了在我们的python应用程序中使用Fauna作为数据库是多么容易。

我们的机器人的源代码可以在Github上找到。

编码愉快!


同行评审的贡献者。Ahmad Mardeni

类似文章

[

How to Create a Reusable React Form component Hero Image

语言

如何创建一个可重复使用的React表单组件

阅读更多

](www.section.io/engineering…

Building a payroll system with next.js Hero Image

语言, Node.js

用Next.js构建一个薪资系统

阅读更多

](www.section.io/engineering…

Creating and Utilizing Decorators in Django example image

架构

在Django中创建和使用装饰器

阅读更多

](www.section.io/engineering…)