iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 5
1

建立 LINE Notify 服務

第一步先到 LINE Notify 管力登入服務去建立一個服務

接著按下登入服務

把該填的填一填,要注意的是 Callback Url 這邊先暫時先打 localhost:5500,等頁面上傳後再回來改 domain


建立完成之後就到剛剛填的信箱去收信點下網址並啟動服務

這樣第一步就建立完成嚕!

動工

接著上次的透過上次的專案並使用 flask_restful 來改造成 Restful 格式的專案(後面開發會比較輕鬆)
因為我們會讓前端呼叫,CORS 設定成*比較輕鬆,若是有要設定跨域問題的在這邊設定哦 ?
加入套件到 requirements.txt

flask==1.0.2
Flask-RESTful==0.3.6
Flask-Cors==3.0.6
requests==2.22.0

透過使用 flask_restful 幫忙轉發並管理路由
將 api.py 改為以下的 code

from flask import Flask
from flask_restful import Api
from flask_cors import CORS
from controller.notify_controller import NotifyController

app = Flask(__name__)
CORS(app, resources={r"*": {"origins": "*", "supports_credentials": True}})
api = Api(app)

api.add_resource(NotifyController, '/notify')

if __name__ == '__main__':
    app.run(debug=True)

這邊我使用 Postgresql,並在專案底下建立一個 lib/ 的資料夾,裡頭放著名為 db.py (這裡還是要記得建立 init.py 哦!)
這邊只簡單建立 Context Manager 讓連線可以被我呼叫。
db.py:

import psycopg2
import psycopg2.extras

class Database():
    conns = []
    def __enter__(self):
        return self

    def connect(self):
        conn = psycopg2.connect(
            database=PG_DB,
            user=PG_USER,
            password=PG_PWD,
            host=PG_HOST,
            port=PG_PORT
        )
        self.conns.append(conn)
        return conn

    def __exit__(self, type, value, traceback):
        for conn in self.conns:
            conn.close()
        self.conns.clear()

新增一下資料夾名為 controller,建立 init.py & notify_controller.py,這邊搭配 with 做資源管理器,
DB 部分則見黎一個 notify 表,然後一個 token 的欄位。

在這個 class 類別下方法只要輸入 def get/post/put/patch/delete 的函式就可以對應 CRUD 的功能了!

notify_controller.py code is:

from flask_restful import Resource, reqparse
import requests
import json
from lib.db import Database
import psycopg2.extras

class NotifyController(Resource):
    def post(self):
        parser = reqparse.RequestParser()
        parser.add_argument('code', required=True, help='code can not be blank!')
        args = parser.parse_args()
        code = args['code']
        client = {'grant_type': 'authorization_code', 'code': code, 'redirect_uri': 'YOUR_REDIRECT_URI',
                  'client_id': 'YOUR_CLIENT_ID', 'client_secret': 'YOUR_CLIENT_SECRET'}
        r = requests.post(
            'https://notify-bot.line.me/oauth/token', data=client)
        req = json.loads(r.text)
        if req['status'] == 200:
            token = req['access_token']
            # Here is use PostgreSQL, you can change your love db
            with Database() as db:
                with db.connect() as conn:
                    with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
                        cur.execute(
                            f"INSERT INTO notify(token) VALUES ('{token}')")
            return {'access_token': req['access_token']}, 200
        else:
            return {'message': r.text}, 200

以下這三個要設定成你的當時輸入的字串

  • YOUR_REDIRECT_URI
  • YOUR_CLIENT_ID
  • YOUR_CLIENT_SECRET

若不清楚 Client_id & Client_secret 的話就回到 Notify 頁面並點選剛剛建立的服務就能看到 token 了

建立一個 views/ 的資料夾,並建立兩個檔案

  • notify_index.html

    這邊需要修改 client_id 以及 redirect_uri
    這個檔案主要功能是讓使用者有個可以按按鈕觸發的地方,當然這只是個範例,實際上線可能就會直接 call API 導向 LINE Notify 頁面等等

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Link Notify</title>
  </head>
  <body>
    <button onclick="Auth();">點選這裡連結到LineNotify</button>

    <script>
      function Auth() {
        var URL = "https://notify-bot.line.me/oauth/authorize?";
        URL += "response_type=code";
        URL += "&client_id=YOUR_CLIENT_ID";
        URL += "&redirect_uri=YOUR_REDIRECT_URI";
        URL += "&scope=notify";
        URL += "&state=nostate";
        window.location.href = URL;
      }
    </script>
  </body>
</html>
  • notify_confirm.html

    修改 ajax 裡的 url,將網址換成之前部署的網址,若忘了可以在部署一次 sls deploy
    當導回來的時候透過 ajax 來呼叫 serverless api 讓後端發 requests 給https://notify-bot.line.me/oauth/token來獲取access_token

因為這個路由有 CORS 的問題,若透過瀏覽器來的話會出錯,這邊則是讓後端去處理

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>message check</title>
  </head>
  <body>
    verify messate:
    <div class="message"></div>
  </body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>

  <script>
    var urlParams = new URLSearchParams(window.location.search);
    var notify_code = urlParams.get("code");
    var state = urlParams.get("state");
    $(function() {
      $.ajax({
        url: "https://SLS_URI.execute-api.us-east-2.amazonaws.com/dev/notify",
        type: "POST",
        dataType: "json",
        data: { code: notify_code },
        success: function(response) {
          console.log(response);
          $(".message").text(response["access_token"]);
        },
        error: function(xhr) {
          console.log(xhr);
          alert("Ajax request 發生錯誤");
        }
      });
    });
  </script>
</html>

接著就是測試程式碼是不是正常的,把這兩個檔案丟到 S3 上面


把 object url 複製到 LINE Notify 上的 callback url 欄位,這樣就可以實機測試了 ?

接著按下 index page 的按鈕應該就會看到連動成功(進資料庫應該也會被 insert 一筆)

到了這邊如果沒問題真的是恭喜你,我踩了好多坑 Orz

參考

資源管理器
flask CORS
CORS


上一篇
Day 4 - 認識與使用 S3 容器
下一篇
Day 6 - 建立一個使用 Query string 來幫忙發送的 LINE Notify
系列文
一步步帶你了解 AWS & LINE API 並使用 Serverless 介接的各種應用30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
timchen0607
iT邦新手 5 級 ‧ 2020-04-11 09:44:26

你好 請教下
就算我已經連動過 進去Index是不是還是一樣要再連動一次才行?

NiJia iT邦新手 5 級 ‧ 2020-04-15 09:37:48 檢舉

如果有存在 DB 就不用喔!

NiJia iT邦新手 5 級 ‧ 2020-04-15 09:39:52 檢舉

另外這份 code 可以參考我之後改寫的,因為當時對 flask 還不是很熟 XD
https://github.com/louis70109/flask-line-notify

我要留言

立即登入留言