package usecase import ( errs "backend/pkg/library/errors" "bytes" "context" "encoding/json" "io" "net/http" "net/url" "backend/pkg/member/domain/usecase" ) // 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.SvcThirdPartyErrorL( use.Logger, []errs.LogField{ {Key: "uri", Val: uri}, {Key: "headers", Val: headers}, {Key: "body", Val: body}, {Key: "result", Val: result}, {Key: "method", Val: http.MethodPost}, }, "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.SvcThirdPartyErrorL( use.Logger, []errs.LogField{ {Key: "uri", Val: uri}, {Key: "headers", Val: headers}, {Key: "result", Val: result}, {Key: "method", Val: http.MethodGet}, }, "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.SvcThirdPartyErrorL( use.Logger, []errs.LogField{ {Key: "req", Val: req}, {Key: "result", Val: result}, {Key: "method", Val: http.MethodGet}, }, "failed to create request") } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return errs.SvcThirdPartyError("unexpected status code: " + http.StatusText(resp.StatusCode)) } body, err := io.ReadAll(resp.Body) if err != nil { return errs.SvcThirdPartyError("failed to read response body") } if err := json.Unmarshal(body, result); err != nil { return errs.SvcThirdPartyError("failed to parse response body") } return nil }