最後一天,我們來為Button增加對應的功能,目前有的按鈕有兩種,一種是[進入資料夾],一種是[設為上傳路徑]。
那我們就先從[進入資料夾]開始,我們要製作進入子資料夾之後呈現的畫面,我們寫一個 ListSelectedFolderCarousel
,跟昨天的 ListFolderCarousel
很像,差別在我們透過floderID去取得內容d.ListFolderByID(folderID)
,還有我們在Carousel的最前面會插入顯示自己當前的目錄還有檔案的bubble。
這樣如果當前目錄裡面沒有其他子資料夾要展開的話,至少還有一個bubble顯示,並且能設定他為上傳路徑。
// internal\app\service\drive\drive_service.go
func (dr *GoogleDriveService) ListSelectedFolderCarousel(ctx context.Context, lineID string, folderID string) (*domainDrive.FolderCarousel, error) {
dToken, err := dr.driveServiceDynamodb.GetGoogleOAuthToken(lineID)
if err != nil {
log.Println(err)
return nil, err
}
tok := oauth2.Token{
AccessToken: dToken.AccessToken,
TokenType: dToken.TokenType,
RefreshToken: dToken.RefreshToken,
Expiry: dToken.Expiry,
}
d, err := dr.driveServiceGoogleOA.NewGoogleDrive(ctx, &tok)
if err != nil {
log.Println(err)
return nil, err
}
var params domainDrive.NewFolderCarouselParam
// 當前目錄下的自己,才能看到資料夾下的檔案
folderList, err := d.ListFolderByID(folderID)
if err != nil {
log.Println(err)
return nil, err
}
currentPath, err := d.FindFolderPathByID(folderID)
if err != nil {
log.Println(err)
return nil, err
}
currentFile, err := d.ListFilesByID(folderID)
if err != nil {
log.Println(err)
return nil, err
}
segments := strings.Split(currentPath, "/")
currentName := segments[len(segments)-2]
params.BubbleParams = append(params.BubbleParams, domainDrive.NewFolderBubbleParam{
Type: "打開資料夾",
Name: currentName,
Path: currentPath,
ID: folderID,
InsideFolderM: folderList,
FileM: currentFile,
})
for folderID, name := range folderList {
path, err := d.FindFolderPathByID(folderID)
if err != nil {
log.Println(err)
return nil, err
}
insideFolderM, err := d.ListFolderByID(folderID)
if err != nil {
log.Println(err)
return nil, err
}
fileM, err := d.ListFilesByID(folderID)
if err != nil {
log.Println(err)
return nil, err
}
param := domainDrive.NewFolderBubbleParam{
Type: "子資料夾",
Name: name,
Path: path,
ID: folderID,
InsideFolderM: insideFolderM,
FileM: fileM,
}
params.BubbleParams = append(params.BubbleParams, param)
}
carousel := domainDrive.NewFolderCarousel(params)
return &carousel, err
}
接著是[設為上傳路徑]的按鈕,我們寫上SetUploadPath
,把輸入的folderID
代到dToken.Info
的"upload_folder_id"
裡面,然後再更新回Dynamodb。
// internal\app\service\drive\drive_service.go
func (dr *GoogleDriveService) SetUploadPath(ctx context.Context, lineID string, folderID string) error {
dToken, err := dr.driveServiceDynamodb.GetGoogleOAuthToken(lineID)
if err != nil {
log.Println(err)
return err
}
dToken.PK = lineID
dToken.Info = map[string]interface{}{
"upload_folder_id": folderID,
}
_, err = dr.driveServiceDynamodb.TxUpdateGoogleOAuthToken(dToken)
if err != nil {
log.Println(err)
return err
}
return nil
}
這樣兩個按鈕需要的service就完成了,但是寫了設定上傳路徑之後,我想有時候也會想看一下當前的上傳路徑在哪裡,所以我們順手寫上GetUploadPath
,來從Dynamodb取得folderID,再透過FindFolderPathByID
去查詢上傳的路徑。
// internal\app\service\drive\drive_service.go
func (dr *GoogleDriveService) GetUploadPath(ctx context.Context, lineID string) (string, error) {
dToken, err := dr.driveServiceDynamodb.GetGoogleOAuthToken(lineID)
if err != nil {
log.Println(err)
return "", err
}
folderID := dToken.Info["upload_folder_id"]
tok := oauth2.Token{
AccessToken: dToken.AccessToken,
TokenType: dToken.TokenType,
RefreshToken: dToken.RefreshToken,
Expiry: dToken.Expiry,
}
d, err := dr.driveServiceGoogleOA.NewGoogleDrive(ctx, &tok)
if err != nil {
log.Println(err)
return "", err
}
path, err := d.FindFolderPathByID(folderID.(string))
if err != nil {
log.Println(err)
return "", err
}
return path, nil
}
接著我們在callback處理message.Text
的地方先多加一條判斷來調用GetUploadPath
。
// internal\router\api\v1\callback.go
if message.Text == "[上傳路徑]" {
lineID := event.Source.UserID
path, err := app.DriveService.GetUploadPath(ctx, lineID)
if err != nil {
log.Println(err)
return
}
if _, err = app.LineBotClient.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(path)).Do(); err != nil {
log.Println(err)
}
return
}
再來,我們在最上面loop events的地方,來處理Button的Postback。當按鈕被按下的時候就會觸發Postback,我們透過event.Postback.Data
可以取得我們當初在按鈕裡面的data埋下的資訊("action=setFolder&folderID=XXX"
),並透過url.ParseQuery
將data解析出來,我們再根據action
代的是setFolder還是openFolder來呼叫對應的service來操作,這樣就沒問題哩。
// internal\router\api\v1\callback.go
for _, event := range events {
// Handle Button Postback
if event.Type == linebot.EventTypePostback {
// 如果是 Postback 事件,取得 postback 資料
postbackData := event.Postback.Data
log.Printf("Postback data: %s", postbackData)
// 解析 postback 資料
values, err := url.ParseQuery(postbackData)
if err != nil {
log.Printf("Error parsing postback data: %v", err)
return
}
// 取得特定參數的值,setFolder || openFolder
action := values.Get("action")
folderID := values.Get("folderID")
lineID := event.Source.UserID
// 在這裡可以根據 action 和 FolderID 做相應的處理
log.Printf("Action: %s, FolderID: %s", action, folderID)
if action == "openFolder" {
res, err := app.DriveService.ListSelectedFolderCarousel(ctx, lineID, folderID)
if err != nil {
log.Println(err)
return
}
if _, err := app.LineBotClient.ReplyMessage(
event.ReplyToken,
linebot.NewFlexMessage("打開資料夾", res.CarouselContainer),
).Do(); err != nil {
log.Println(err)
return
}
}
if action == "setFolder" {
err := app.DriveService.SetUploadPath(ctx, lineID, folderID)
if err != nil {
log.Println(err)
return
}
if _, err = app.LineBotClient.ReplyMessage(event.ReplyToken, linebot.NewTextMessage("成功設定上傳路徑")).Do(); err != nil {
log.Println(err)
}
return
}
}
if event.Type == linebot.EventTypeMessage {
...
最後,為了操作方便,我們進到LineOA(不是Line developers),到圖文選單的地方
我們選好自己想要的版型之後,可以上傳自己做的圖片當背景,依照他給定的A,B,C…區塊設定動作,我們類型選擇回傳文字,內容用[]
包起來,這樣在按下圖片區塊的時候,我們就可以讓使用者傳送對應的文字訊息了。
在手機上的效果會像這樣
最後的最後,我們走一遍流程再來測試一次。
列出我的雲端硬碟
進入子資料夾
設為上傳路徑&上傳檔案
確認上傳路徑
對照GoogleDrive
終於完賽了~ 謝謝有看過我其中任何一篇文章的每一個人,可能目前還有些地方沒有寫得很好,有時間應該會整理整理再放上來,真的是參與過才懂那種連續30天,每天都要擠出時間寫code+寫文章的感覺,真的沒有一開始想像的容易XDD,不過好在還是成功完賽了,再次感謝各位!!