129 lines
3.4 KiB
Go
129 lines
3.4 KiB
Go
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
|
|
}
|