app-cloudep-member-server/pkg/usecase/verify_line.go

129 lines
3.4 KiB
Go
Raw Permalink Normal View History

2024-12-30 03:58:14 +00:00
package usecase
import (
"app-cloudep-member-server/pkg/domain"
"app-cloudep-member-server/pkg/domain/usecase"
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"net/url"
"code.30cm.net/digimon/library-go/errs"
"code.30cm.net/digimon/library-go/errs/code"
)
// LineCodeToAccessToken 透過 Line 授權碼換取 Access Token
func (use *MemberUseCase) LineCodeToAccessToken(ctx context.Context, code string) (usecase.LineAccessTokenResponse, error) {
data := url.Values{
"grant_type": {"authorization_code"},
"code": {code},
"redirect_uri": {use.Config.LineAuth.RedirectURI},
"client_id": {use.Config.LineAuth.ClientID},
"client_secret": {use.Config.LineAuth.ClientSecret},
}
uri := "https://api.line.me/oauth2/v2.1/token"
headers := map[string]string{
"Content-Type": "application/x-www-form-urlencoded",
}
var tokenResponse usecase.LineAccessTokenResponse
if err := use.doPost(ctx, uri, headers, data.Encode(), &tokenResponse); err != nil {
return usecase.LineAccessTokenResponse{}, err
}
return tokenResponse, nil
}
// LineGetProfileByAccessToken 使用 Access Token 獲取 Line 用戶資料
func (use *MemberUseCase) LineGetProfileByAccessToken(ctx context.Context, accessToken string) (*usecase.LineUserProfile, error) {
uri := "https://api.line.me/v2/profile"
headers := map[string]string{
"Authorization": "Bearer " + accessToken,
}
var profile usecase.LineUserProfile
if err := use.doGet(ctx, uri, headers, &profile); err != nil {
return nil, err
}
return &profile, nil
}
// doPost 發送 POST 請求並解析返回數據
func (use *MemberUseCase) doPost(ctx context.Context, uri string, headers map[string]string, body string, result interface{}) error {
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, bytes.NewBufferString(body))
if err != nil {
return errs.ThirdPartyError(
code.CloudEPMember,
domain.FailedToVerifyLine,
"failed to create request",
)
}
for key, value := range headers {
req.Header.Set(key, value)
}
return use.doRequest(req, result)
}
// doGet 發送 GET 請求並解析返回數據
func (use *MemberUseCase) doGet(ctx context.Context, uri string, headers map[string]string, result interface{}) error {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return errs.ThirdPartyError(
code.CloudEPMember,
domain.FailedToVerifyLine,
"failed to create request",
)
}
for key, value := range headers {
req.Header.Set(key, value)
}
return use.doRequest(req, result)
}
// doRequest 發送 HTTP 請求並處理響應
func (use *MemberUseCase) doRequest(req *http.Request, result interface{}) error {
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return errs.ThirdPartyError(
code.CloudEPMember,
domain.FailedToVerifyLine,
"failed to send request",
)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return errs.ThirdPartyError(
code.CloudEPMember,
domain.FailedToVerifyLine,
"unexpected status code: "+http.StatusText(resp.StatusCode),
)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return errs.ThirdPartyError(
code.CloudEPMember,
domain.FailedToVerifyLine,
"failed to read response body",
)
}
if err := json.Unmarshal(body, result); err != nil {
return errs.ThirdPartyError(
code.CloudEPMember,
domain.FailedToVerifyLine,
"failed to parse response body",
)
}
return nil
}