Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Redis

Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

บางครั้งก็เป็นการดีที่สุดที่จะสร้างการเตือนความจำสำหรับงานประจำปีของคุณเพื่อที่คุณจะได้ไม่ลืมและพลาดวันพิเศษเหล่านั้น

หากคุณและทีม/เพื่อนของคุณใช้ Slack คุณควรทำให้การเตือนเหล่านี้เป็นอัตโนมัติผ่าน slackbots

ในขณะที่ทำเช่นนั้น หากคุณต้องการให้ slackbot ของคุณมีการบำรุงรักษาต่ำ อาจเป็นการดีที่สุดที่จะใช้เทคโนโลยีไร้เซิร์ฟเวอร์สำหรับการโต้ตอบกับแหล่งที่มาพร้อมกัน และยังช่วยให้สามารถปรับขนาดในแนวนอนได้อีกด้วย

เรากำลังสร้างอะไร

เรากำลังสร้าง ตัวเตือนเหตุการณ์ Slackbot โดยใช้ Python, AWS Chalice, AWS Lambda และ API Gateway สำหรับการโฮสต์ ซึ่งจะช่วยให้ผู้ใช้:

  • ตั้งค่าวันเกิดสำหรับผู้ใช้
  • กำหนดวันครบรอบสำหรับผู้ใช้
  • ตั้งค่าเหตุการณ์ที่กำหนดเองสำหรับผู้ใช้หรือช่องทางทั่วไป

เมื่อตั้งค่ากิจกรรมแล้ว:

  • เตือนผู้คนว่ามีงานกิจกรรมใดที่กำลังจะเกิดขึ้น ยกเว้นผู้ที่อยู่ตรงกลางของกิจกรรม (บุคคลที่ถูกกล่าวถึงขณะตั้งค่ากิจกรรม)
  • โพสต์ในช่องทั่วไปเมื่อถึงวันครบรอบกิจกรรม โดยกล่าวถึงบุคคลที่อยู่ตรงกลางของกิจกรรม (หรือทุกคนในช่อง)

คำสั่ง

ชุด

  • /event set birthday <YYYY-MM-DD> <user>

    ตั้งค่าวันเกิดของผู้ใช้

    Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

  • /event set anniversary <YYYY-MM-DD> <user>

    กำหนดวันครบรอบสำหรับผู้ใช้ เมื่อพวกเขาเริ่มทำงานที่นั่น

    Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

  • /event set custom <YYYY-MM-DD> <user> <any kind of message with whitespaces>

    ตั้งค่าการเตือนความจำที่กำหนดเองโดยใช้ข้อความที่ให้มา

    Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

รับทั้งหมด

  • /event get-all :

    แสดงเหตุการณ์ทั้งหมดที่ตั้งไว้

    Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

  • /event get-all birthday :

    แสดงวันเกิดทั้งหมดที่ตั้งค่าไว้

    Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

  • /event get-all anniversary :

    แสดงวันครบรอบทั้งหมดที่ตั้งไว้

    Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

  • /event get-all custom :

    แสดงเหตุการณ์ที่กำหนดเองทั้งหมดที่ตั้งค่าไว้

    Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

รับ

  • /event get birthday <user> :

    แสดงรายละเอียดวันเกิดของผู้ใช้

    Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

  • /event get anniversary <user> :

    แสดงรายละเอียดวันครบรอบสำหรับผู้ใช้ เมื่อพวกเขาเริ่มทำงานที่นั่น

    Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

  • /event get custom <event_name>(can be found with get-all) :

    แสดงรายละเอียดกิจกรรมที่กำหนดเองโดยใช้ข้อความที่ให้มา

    Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

ลบ

  • /event remove birthday <user> :

    ลบวันเกิดของผู้ใช้

    Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

  • /event remove anniversary <user> :

    ลบวันครบรอบสำหรับผู้ใช้เมื่อพวกเขาเริ่มทำงานที่นั่น

    Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

  • /event remove custom <event_name>(can be found with get-all) :

    ลบเหตุการณ์ที่กำหนดเองโดยใช้ข้อความที่ให้มา

    Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

การแจ้งเตือนตามกำหนดเวลา

  • เตือนช่องทั่วไป

    เมื่อถึงเวลา slackbot จะส่งข้อความเตือนไปยังช่องที่ระบุ Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

  • ข้อความส่วนตัวจากบอท

    เมื่อถึงเวลาแล้ว slackbot จะส่งข้อความเตือนความจำส่วนตัว Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

ดังนั้น เครื่องมือนี้จึงสามารถใช้ติดตามวันที่พิเศษสำหรับสมาชิกในทีมได้ วิธีนี้จะช่วยรักษาความสัมพันธ์และการสื่อสารระหว่างกันในลักษณะที่ดี

เริ่มต้นใช้งาน

เตรียมฐานข้อมูล

เราสามารถสร้างฐานข้อมูล Redis ของเราบน Upstash Console สังเกต UPSTASH_REDIS_REST_URL และ UPSTASH_REDIS_REST_TOKEN เนื่องจากจะเป็นตัวแปรสภาพแวดล้อมสำหรับ AWS

การกำหนดค่าข้อมูลรับรอง AWS

(นำมาจาก Official Chalice Repo คุณสามารถดูข้อมูลเพิ่มเติมได้ที่นั่น)

$ mkdir ~/.aws
$ cat >> ~/.aws/config
[default]
aws_access_key_id=YOUR_ACCESS_KEY_HERE
aws_secret_access_key=YOUR_SECRET_ACCESS_KEY
region=YOUR_REGION (such as us-west-2, us-west-1, etc)

อนุสัญญาบางข้อ

  • ทั้งหมด .py ไฟล์ภายนอก app.py ควรวางไว้ใต้ chalicelib ไดเร็กทอรี ไม่เช่นนั้นคำสั่งนำเข้าอาจทำให้เกิดปัญหาได้
  • ควรกำหนดค่าตัวแปรสภาพแวดล้อมทั้งหมดใน config.json ไฟล์ภายใน .chalice ไดเรกทอรี
    • ในรูปแบบ json โดยมีคีย์:"environment_variables"

การพัฒนาที่มาของโครงการ

  • ก่อนอื่น เนื่องจากเราใช้ AWS Chalice , เพื่อติดตั้ง chalice:

    pip install chalice

ริเริ่มโครงการ Chalice

chalice new-project <project_name> Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis จากนั้น cd ลงในโฟลเดอร์โครงการ โปรเจ็กต์มาพร้อมเทมเพลตแล้ว

เรียกใช้:chalice local เพื่อดูว่าโครงการได้ผลหรือไม่

app.py

ไฟล์หลักสำหรับโครงสร้างโครงการโดยรวมและเพื่อจัดการคำขอ Slack

ด้วยเหตุนี้ เราจึงสร้างโครงสร้างโครงการและจุดสิ้นสุดของเรา เราตัดสินใจว่าจะจัดการกิจกรรมอย่างไร จะกำหนดเวลาอะไรสำหรับการเตือนความจำให้ทำงาน

from chalice import Chalice, Cron, Rate
import os
import random
from datetime import date
from chalicelib.utils import responseToDict, postToChannel, diffWithTodayFromString, allSlackUsers, sendDm, validateRequest, convertToCorrectMention
from chalicelib.upstash import setHandler, getAllHandler, getEvent, getAllKeys, removeEvent

app = Chalice(app_name='birthday-slackbot')
NOTIFY_TIME_LIMIT = int(os.getenv("NOTIFY_TIME_LIMIT"))


# Sample route for get requests.
@app.route('/', methods=["GET"])
def something():
    return {
        "Hello": "World"
        }

# Configuring POST request endpoint.
# Command is parsed and handled/directed to handler
@app.route('/', methods=["POST"], content_types=["application/x-www-form-urlencoded"])
def index():

    # Parse the body for ease of use
    r = responseToDict(app.current_request.raw_body)
    headers = app.current_request.headers

    # Check validity of the request.
    if not validateRequest(headers, r):
        return {"Status": "Validation failed."}


    commandArray = r['text'].split()
    command = commandArray.pop(0)

    try:
        if command == "set":
            setHandler(commandArray)
            return {
            'response_type': "ephemeral",
            'text': "Set the event."
            }

        elif command == "get":
            eventType = commandArray[0]
            eventName = eventType + "-" + commandArray[1]
            resultDict = getEvent(eventName)
            return {
            'response_type': "ephemeral",
            'text': "`{}` Details:\n\n Date: {}\nRemaining: {} days!".format(eventName, resultDict[0], resultDict[1])
            }

        elif command == "get-all":

            stringResult = getAllHandler(commandArray)
            return {
            'response_type': "ephemeral",
            'text': "{}".format(stringResult)
            }

        elif command == "remove":
            eventName = "{}-{}".format(commandArray[0], commandArray[1])
            removeEvent(eventName)
            return {
            'response_type': "ephemeral",
            'text': "Removed the event."
            }
        else:
            return {
            'response_type': "ephemeral",
            'text': "Wrong usage of the command."
            }
    except:
        print("some stuff")
        return {
            'response_type': "ephemeral",
            'text': "Some problem occured. Please check your command."
        }


# Run at 10:00 am (UTC) every day.
@app.schedule(Cron(0, 10, '*', '*', '?', '*'))
def periodicCheck(event):
    allKeys = getAllKeys()
    for key in allKeys:
        handleEvent(key)


# Generic event is parsed and directed to relevant handlers.
def handleEvent(eventName):
    eventSplitted = eventName.split('-')

    eventType = eventSplitted[0]

    # discard @ or ! as a first character
    personName = eventSplitted[1][1:]
    personMention = convertToCorrectMention(personName)

    eventDict = getEvent(eventName)
    remainingDays = eventDict[1]
    totalTime = eventDict[2]


    if eventType == "birthday":
        birthdayHandler(personMention, personName, remainingDays)

    elif eventType == "anniversary":
        anniversaryHandler(personMention, personName, remainingDays, totalTime)

    elif eventType == "custom":
        eventMessage = "Not specified"
        if len(eventSplitted) == 3:
            eventMessage = eventSplitted[2]
        customHandler(eventMessage, personMention, personName, remainingDays)

# Handles birthday events.
def birthdayHandler(personMention, personName, remainingDays):
    if remainingDays == 0:
        sendRandomBirthdayToChannel('general', personMention)
    if remainingDays <= NOTIFY_TIME_LIMIT:
        dmEveryoneExcept("{} day(s) until {}'s birthday!".format(remainingDays, personMention), personName)

# Handles anniversary events.
def anniversaryHandler(personMention, personName, remainingDays, totalTime):
    if remainingDays == 0:
        sendRandomAnniversaryToChannel('general', personMention, totalTime)
    if remainingDays <= NOTIFY_TIME_LIMIT:
        dmEveryoneExcept("{} day(s) until {}'s anniversary! It will be {} year(s) since they joined!".format(remainingDays, personMention, totalTime), personName)

# Handles custom events.
def customHandler(eventMessage, personMention, personName, remainingDays):
    if remainingDays == 0:
        postToChannel('general', "`{}` is here {}!".format(eventMessage, personMention))
    elif remainingDays <= NOTIFY_TIME_LIMIT:
        dmEveryoneExcept("{} day(s) until {} `{}`!".format(remainingDays, personMention, eventMessage), personName)


# Sends private message to everyone except for the person given.
def dmEveryoneExcept(message, person):
    usersAndIds = allSlackUsers()
    for user in usersAndIds:
        if user[0] != person:
            sendDm(user[1], message)


# Sends randomly chosen birthday message to specified channel.
def sendRandomBirthdayToChannel(channel, personMention):
    messageList = [
        "Happy Birthday {}! Wishing you the best!".format(personMention),
        "Happy Birthday {}! Wishing you a happy age!".format(personMention),
        "Happy Birthday {}! Wishing you a healthy, happy life!".format(personMention),
    ]
    message = random.choice(messageList)
    return postToChannel('general', message)

# Sends randomly chosen anniversary message to specified channel.
def sendRandomAnniversaryToChannel(channel, personMention, totalTime):
    messageList = [
        "Today is the anniversary of {} joining! It has been {} years since they joined!".format(personMention, totalTime - 1),
        "Celebrating the anniversary of {} joining! It has been {} years!".format(personMention, totalTime - 1),
        "Congratulating {} for entering {}(th) year here!".format(personMention, totalTime),
    ]
    message = random.choice(messageList)
    return postToChannel('general', message)


# We want to run our event handlers when the project is deployed/redeployed.
allKeys = getAllKeys()
for key in allKeys:
    handleEvent(key)

chalicelib/utils.py

ไฟล์หลักสำหรับฟังก์ชั่นผู้ช่วยและสิ่งที่เป็นนามธรรม

เราจะใช้ไฟล์นี้เป็นหลักสำหรับนามธรรม ดังนั้นซอร์สโค้ดของเราจะไม่เกะกะและจะรักษาความสามารถในการอ่านได้

from urllib import request
import urllib
from urllib.parse import parse_qsl
import json
import os
import hmac
import hashlib
from datetime import date


SLACK_BOT_TOKEN = os.getenv("SLACK_BOT_TOKEN")
SLACK_SIGNING_SECRET = os.getenv("SLACK_SIGNING_SECRET")

# Returns real name of the slack user.
def getRealName(slackUsers, username):
    for user in slackUsers:
        if user[0] == username:
            return user[2]
    return "Nameless"

# Returns all slack users in the workspace.
def allSlackUsers():
    resultDict = sendPostRequest("https://slack.com/api/users.list", SLACK_BOT_TOKEN)
    members = resultDict['members']

    userMembers = []
    for member in members:
        if not member['deleted'] and not member['is_bot']:
            userMembers.append([member['name'], member['id'], member['real_name']])

    return userMembers

# Returns the id of the given channel.
def channelNameToId(channelName) :
    resultDict = sendPostRequest("https://slack.com/api/conversations.list", SLACK_BOT_TOKEN)
    for channel in resultDict['channels']:
        if (channel['name'] == channelName):
            return channel['id']
    return None

# Posts to given slack channelId with given message.
def postToSlack(channelId, messageText):
    data = {
        "channel": channelId,
        "text": messageText
    }
    data = json.dumps(data)
    data = str(data)
    data = data.encode('utf-8')
    resultDict = sendPostRequest("https://slack.com/api/chat.postMessage", SLACK_BOT_TOKEN, data)
    return resultDict

# Posts to a slack channel.
def postToChannel(channel, messageText):
    channelId = channelNameToId(channel)
    return postToSlack(channelId, messageText)

# Sends a private message to a user with userId.
def sendDm(userId, messageText):
    return postToSlack(userId, messageText)

# Sends generic post request and returns the result.
def sendPostRequest(requestURL, bearerToken, data={}):
    req = request.Request(requestURL, method="POST", data=data)
    req.add_header("Authorization", "Bearer {}".format(bearerToken))
    req.add_header("Content-Type", "application/json; charset=utf-8")

    r = request.urlopen(req)
    resultDict = json.loads(r.read().decode())
    return resultDict

# Parses and converts the res to dict.
def responseToDict(res):
    return dict(parse_qsl(res.decode()))


# Dates are given as: YYYY-MM-DD
# Returns difference between current day and the anniversary.
def diffWithTodayFromString(dateString):
    now = date.today()
    currentYear = now.year

    dateTokens = dateString.split("-")
    month = int(dateTokens[1])
    day = int(dateTokens[2])

    if now > date(currentYear, month, day):
        return (date((currentYear + 1), month, day) - now).days
    return (date(currentYear, month, day) - now).days


# Dates are given as: YYYY-MM-DD
# Calculates the total time that has passed until current date.
def totalTimefromString(dateString):
    now = date.today()

    dateTokens = dateString.split("-")
    year = int(dateTokens[0])
    month = int(dateTokens[1])
    day = int(dateTokens[2])

    then = date(year, month, day)

    years = now.year - then.year
    return years + 1

# Validate requests coming to endpoint.
# Hashes request body with timestamp and signing secret.
# Then, compares that hash with slack signature.
def validateRequest(header, body):

    bodyAsString = urllib.parse.urlencode(body)

    timestamp = header['x-slack-request-timestamp']
    slackSignature = header['x-slack-signature']
    baseString = "v0:{}:{}".format(timestamp, bodyAsString)

    h =  hmac.new(SLACK_SIGNING_SECRET.encode(), baseString.encode(), hashlib.sha256)
    hashResult = h.hexdigest()
    mySignature = "v0=" + hashResult

    return mySignature == slackSignature

# Converts given name to mention string.
def convertToCorrectMention(name):
    if name == "channel" or name == "here" or name == "everyone":
        return "<!{}>".format(name)
    else:
        return "<@{}>".format(name)

chalicelib/upstash.py

ไฟล์หลักสำหรับฟังก์ชันที่เกี่ยวข้องโดยตรงกับฐานข้อมูล

ที่นี่ เราจะจัดการกับการเรียกฐานข้อมูลของเรา เราจะดึงข้อมูลจากฐานข้อมูล ตั้งค่าคู่คีย์-ค่า ฯลฯ ไฟล์นี้ยังช่วยให้เราสรุปรายละเอียดระดับต่ำจาก app.py , เพิ่มความสามารถในการอ่านและโมดูลาร์

ข้อดีของ Upstash Redis Database คือรองรับการเรียก RESTFUL API ด้วยวิธีนี้ คุณจะสามารถเข้าถึงฐานข้อมูลของคุณโดยไม่จำเป็นต้องสร้างและปิดการเชื่อมต่ออยู่ตลอดเวลา ซึ่งเป็นวิธีที่เหมาะสำหรับแอปพลิเคชันแบบไร้เซิร์ฟเวอร์

from chalicelib.utils import sendPostRequest, getRealName, allSlackUsers, diffWithTodayFromString, totalTimefromString
import os

UPSTASH_REST_URL = os.getenv("UPSTASH_REST_URL")
UPSTASH_TOKEN = os.getenv("UPSTASH_TOKEN")

# Posts to Upstash Rest Url with parameters given.
def postToUpstash(parameters):
    requestURL = UPSTASH_REST_URL
    for parameter in parameters:
        requestURL += ("/" + parameter)

    resultDict = sendPostRequest(requestURL, UPSTASH_TOKEN)
    return resultDict['result']


# Sets key-value pair for the event with given parameters.
def setEvent(parameterArray):

    postQueryParameters = ['SET']

    for parameter in parameterArray:
        parameter = parameter.split()
        for subparameter in parameter:
            postQueryParameters.append(subparameter)

    resultDict = postToUpstash(postQueryParameters)

    return resultDict


# Returns event details from the event given.
def getEvent(eventName):
    postQueryParameters = ['GET', eventName]
    date = postToUpstash(postQueryParameters)

    timeDiff = diffWithTodayFromString(date)
    totalTime = totalTimefromString(date)
    mergedDict = [date, timeDiff, totalTime]
    return mergedDict

# Fetches all keys (events) from the database
def getAllKeys():
    return postToUpstash(['KEYS', '*'])

# Deletes given event from the database.
def removeEvent(eventName):
    postQueryParameters = ['DEL', eventName]
    resultDict = postToUpstash(postQueryParameters)
    return resultDict


# Handles set request by parsing and configuring setEvent function parameters.
def setHandler(commandArray):
    eventType = commandArray.pop(0)
    date = commandArray.pop(0)
    user = commandArray.pop(0)

    if eventType == "birthday":
        listName = "birthday-" + user
        return setEvent( [listName, date] )

    elif eventType == "anniversary":
        listName = "anniversary-" + user
        return setEvent( [listName, date] )

    elif eventType == "custom":
        message = ""
        for string in commandArray:
            message += string + "_"

        listName = "custom-" + user + "-" + message
        user = commandArray[1]
        return setEvent( [listName, date] )
    else:
        return

# Handles get-all requests.
def getAllHandler(commandArray):
    filterParameter = None
    if len(commandArray) == 1:
        filterParameter = commandArray[0]

    allKeys = getAllKeys()
    birthdays = []
    anniversaries = []
    customs = []

    slackUsers = allSlackUsers()

    stringResult = "\n"
    for key in allKeys:
        if key[0] == 'b':
            birthdays.append(key)
        elif key[0] == 'a':
            anniversaries.append(key)
        elif key[0] == 'c':
            customs.append(key)

    if filterParameter is None or filterParameter == "birthday":
        stringResult += "Birthdays:\n"
        for bday in birthdays:
            tag = bday.split('-')[1]
            username = tag[1:]
            realName = getRealName(slackUsers, username)
            details = getEvent(bday)

            stringResult += "`{}` ({}): {} - `{} days` remaining!\n".format(tag, realName, details[0], details[1])

    if filterParameter is None or filterParameter == "anniversary":
        stringResult += "\nAnniversaries:\n"
        for ann in anniversaries:
            tag = ann.split('-')[1]
            username = tag[1:]
            realName = getRealName(slackUsers, username)
            details = getEvent(ann)

            stringResult += "`{}` ({}): {} - `{} days` remaining!\n".format(tag, realName, details[0], details[1])

    if filterParameter is None or filterParameter == "custom":
        stringResult += "\nCustom Reminders:\n"
        for cstm in customs:
            splitted = cstm.split('-')
            username = splitted[2]
            realName = getRealName(slackUsers, username)
            details = getEvent(cstm)

            stringResult += "`{}-{}` ({}): {}\n".format(splitted[1], splitted[2], getRealName(slackUsers, username), details[0])

    return stringResult

.chalice/config.json

ไฟล์สำหรับกำหนดค่าโปรเจ็กต์บน AWS

ที่นี่ เรากำหนดรายละเอียดโครงการของเรา เช่น ตัวแปรสภาพแวดล้อมและขั้นตอนการปรับใช้ สำหรับสิ่งนี้ เราจะกำหนดค่าตัวแปรสภาพแวดล้อมโดยการเพิ่ม:

{
  "environment_variables": {
    "UPSTASH_REST_URL": <UPSTASH_REDIS_REST_URL>,
    "UPSTASH_TOKEN": <UPSTASH_REDIS_REST_TOKEN>,
    "SLACK_BOT_TOKEN": <SLACK_BOT_TOKEN>,
    "SLACK_SIGNING_SECRET": <SLACK_SIGNING_SECRET>,
    "NOTIFY_TIME_LIMIT": "<amount of days before getting notifications for events>"
    }
}

เสร็จแล้ว

โครงสร้างโฟลเดอร์

โครงสร้างโฟลเดอร์ของคุณควรมีลักษณะดังนี้:

<project_name>:
    app.py

    chalicelib:
        utils.py
        upstash.py
        <Some other default files generated by chalice>

    .chalice:
        config.json
        <Some other default files generated by chalice>

เรียกใช้ในเครื่อง

Chalice เปิดใช้งานการปรับใช้ในพื้นที่ ซึ่งทำให้กระบวนการพัฒนารวดเร็วมาก

เรียกใช้:chalice local Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

หากคุณไม่มีที่อยู่ IP แบบคงที่ คุณควรใช้บริการช่องสัญญาณเช่น ngrok เพื่อให้คุณสามารถแสดงปลายทางของคุณไปยัง Slack:

./ngrok http 8000 -> อุโมงค์โลคัลโฮสต์ของคุณ:8000 Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

กำหนดค่า Slack

1. ไปที่หน้าแอป Slack API:

  • สร้างแอปใหม่
    • ตั้งแต่เริ่มต้น
    • ตั้งชื่อแอปและเลือกพื้นที่ทำงาน
  • ไปที่ Oauth &Permissions
    • เพิ่มขอบเขตต่อไปนี้
      • channels:read
      • แชท:เขียน
      • chat:write.public
      • คำสั่ง
      • groups:read
      • ผู้ใช้:อ่าน
    • ติดตั้งแอปลงพื้นที่ทำงาน
      • ข้อมูลพื้นฐาน --> ติดตั้งแอปของคุณ --> ติดตั้งไปยังพื้นที่ทำงาน
  1. สังเกตตัวแปร (สิ่งเหล่านี้จะเป็นตัวแปร env สำหรับการปรับใช้ AWS) :
    • SLACK_SIGNING_SECRET :
      • ไปที่ข้อมูลพื้นฐาน
        • ข้อมูลประจำตัวของแอป --> ข้อมูลลับในการลงชื่อ
    • SLACK_BOT_TOKEN :
      • ไปที่ OAuth &สิทธิ์
        • โทเค็น OAuth ของผู้ใช้บ็อต

3. ไปที่หน้าแอป Slack API และเลือกแอปที่เกี่ยวข้อง:

หลังจากการปรับใช้ คุณสามารถใช้ REST_API_URL หรือ ngrok_domain เป็น <domain> .

  1. ไปที่หน้าแอป Slack API และเลือกแอปที่เกี่ยวข้อง:
  • ไปที่คำสั่ง Slash:
    • สร้างคำสั่งใหม่:
      • Command :event
      • ขอ URL :<domain>
      • กำหนดค่าส่วนที่เหลือตามที่คุณต้องการ
  • หลังจากการเปลี่ยนแปลงเหล่านี้ Slack อาจต้องติดตั้งแอปใหม่อีกครั้ง

ยินดีด้วย!

ตอนนี้คุณมี Slackbot แบบไร้เซิร์ฟเวอร์ที่ใช้งานได้! ปรับแต่งได้ตามต้องการ

หลังจากที่คุณพอใจกับการโฮสต์และผลลัพธ์ในท้องถิ่นแล้ว เพียง:

  • chalice deploy สำหรับการปรับใช้ขั้นสุดท้ายบน AWS Lambda และ API Gateway Slackbot วันเกิดแบบไร้เซิร์ฟเวอร์พร้อม AWS Chalice และ Upstash Redis

ตอนนี้คุณสามารถใช้ REST_API_URL ที่ AWS Chalice จัดหาให้ในการกำหนดค่า Slack ได้แล้ว

สำหรับโครงการที่สมบูรณ์ คุณสามารถไปที่ Github Repo ได้