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 }