diff --git a/charts/lfx-v2-meeting-service/Chart.yaml b/charts/lfx-v2-meeting-service/Chart.yaml index 847b285..f2c9c51 100644 --- a/charts/lfx-v2-meeting-service/Chart.yaml +++ b/charts/lfx-v2-meeting-service/Chart.yaml @@ -5,5 +5,5 @@ apiVersion: v2 name: lfx-v2-meeting-service description: LFX Platform V2 Meeting Service chart type: application -version: 0.6.3 +version: 0.6.4 appVersion: "latest" diff --git a/internal/infrastructure/proxy/client.go b/internal/infrastructure/proxy/client.go index b18dff1..1581313 100644 --- a/internal/infrastructure/proxy/client.go +++ b/internal/infrastructure/proxy/client.go @@ -9,8 +9,10 @@ import ( "encoding/json" "fmt" "io" + "log/slog" "net/http" "net/url" + "strings" "time" "github.com/auth0/go-auth0/authentication" @@ -86,6 +88,9 @@ func NewClient(config Config) *Client { panic("ITX_CLIENT_PRIVATE_KEY is required but not set") } + // Strip trailing slash from base URL to prevent double slashes in URL construction + config.BaseURL = strings.TrimRight(config.BaseURL, "/") + // Create Auth0 authentication client with private key assertion (JWT) // The private key should be in PEM format (raw, not base64-encoded) authConfig, err := authentication.New( @@ -118,6 +123,30 @@ func NewClient(config Config) *Client { } } +// logRequest logs the outgoing HTTP request for debugging +func (c *Client) logRequest(ctx context.Context, method, url string, body []byte) { + slog.DebugContext(ctx, "ITX API Request", + "method", method, + "url", url, + "body", string(body), + ) +} + +// logResponse logs the incoming HTTP response for debugging +func (c *Client) logResponse(ctx context.Context, statusCode int, body []byte) { + if statusCode < 200 || statusCode >= 300 { + slog.ErrorContext(ctx, "ITX API Response Error", + "status_code", statusCode, + "body", string(body), + ) + } else { + slog.DebugContext(ctx, "ITX API Response", + "status_code", statusCode, + "body", string(body), + ) + } +} + // CreateZoomMeeting creates a new Zoom meeting in ITX func (c *Client) CreateZoomMeeting(ctx context.Context, req *itx.CreateZoomMeetingRequest) (*itx.ZoomMeetingResponse, error) { // Marshal request @@ -138,6 +167,9 @@ func (c *Client) CreateZoomMeeting(ctx context.Context, req *itx.CreateZoomMeeti httpReq.Header.Set("Accept", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPost, url, body) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -153,6 +185,9 @@ func (c *Client) CreateZoomMeeting(ctx context.Context, req *itx.CreateZoomMeeti return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -180,6 +215,9 @@ func (c *Client) GetZoomMeeting(ctx context.Context, meetingID string) (*itx.Zoo httpReq.Header.Set("Accept", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodGet, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -195,6 +233,9 @@ func (c *Client) GetZoomMeeting(ctx context.Context, meetingID string) (*itx.Zoo return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -221,6 +262,9 @@ func (c *Client) DeleteZoomMeeting(ctx context.Context, meetingID string) error // Set headers (Authorization automatically added by OAuth2 transport) httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodDelete, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -236,6 +280,9 @@ func (c *Client) DeleteZoomMeeting(ctx context.Context, meetingID string) error return domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return c.mapHTTPError(resp.StatusCode, respBody) @@ -263,6 +310,9 @@ func (c *Client) UpdateZoomMeeting(ctx context.Context, meetingID string, req *i httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPut, url, body) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -278,6 +328,9 @@ func (c *Client) UpdateZoomMeeting(ctx context.Context, meetingID string, req *i return domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return c.mapHTTPError(resp.StatusCode, respBody) @@ -299,6 +352,9 @@ func (c *Client) GetMeetingCount(ctx context.Context, projectID string) (*itx.Me httpReq.Header.Set("Accept", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodGet, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -314,6 +370,9 @@ func (c *Client) GetMeetingCount(ctx context.Context, projectID string) (*itx.Me return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -365,6 +424,9 @@ func (c *Client) GetMeetingJoinLink(ctx context.Context, req *itx.GetJoinLinkReq httpReq.Header.Set("Accept", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodGet, queryURL, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -380,6 +442,9 @@ func (c *Client) GetMeetingJoinLink(ctx context.Context, req *itx.GetJoinLinkReq return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -414,6 +479,9 @@ func (c *Client) CreateRegistrant(ctx context.Context, meetingID string, req *it httpReq.Header.Set("Accept", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPost, url, body) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -429,6 +497,9 @@ func (c *Client) CreateRegistrant(ctx context.Context, meetingID string, req *it return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -456,6 +527,9 @@ func (c *Client) GetRegistrant(ctx context.Context, meetingID, registrantID stri httpReq.Header.Set("Accept", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodGet, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -471,6 +545,9 @@ func (c *Client) GetRegistrant(ctx context.Context, meetingID, registrantID stri return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -504,6 +581,9 @@ func (c *Client) UpdateRegistrant(ctx context.Context, meetingID, registrantID s httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPut, url, body) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -519,6 +599,9 @@ func (c *Client) UpdateRegistrant(ctx context.Context, meetingID, registrantID s return domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return c.mapHTTPError(resp.StatusCode, respBody) @@ -539,6 +622,9 @@ func (c *Client) DeleteRegistrant(ctx context.Context, meetingID, registrantID s // Set headers (Authorization automatically added by OAuth2 transport) httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodDelete, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -554,6 +640,9 @@ func (c *Client) DeleteRegistrant(ctx context.Context, meetingID, registrantID s return domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return c.mapHTTPError(resp.StatusCode, respBody) @@ -575,6 +664,9 @@ func (c *Client) GetRegistrantICS(ctx context.Context, meetingID, registrantID s httpReq.Header.Set("Accept", "text/calendar") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodGet, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -590,6 +682,9 @@ func (c *Client) GetRegistrantICS(ctx context.Context, meetingID, registrantID s return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -613,6 +708,9 @@ func (c *Client) ResendRegistrantInvitation(ctx context.Context, meetingID, regi // Set headers (Authorization automatically added by OAuth2 transport) httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPost, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -628,6 +726,9 @@ func (c *Client) ResendRegistrantInvitation(ctx context.Context, meetingID, regi return domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return c.mapHTTPError(resp.StatusCode, respBody) @@ -660,6 +761,9 @@ func (c *Client) ResendMeetingInvitations(ctx context.Context, meetingID string, httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPost, url, body) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -675,6 +779,9 @@ func (c *Client) ResendMeetingInvitations(ctx context.Context, meetingID string, return domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return c.mapHTTPError(resp.StatusCode, respBody) @@ -695,6 +802,9 @@ func (c *Client) RegisterCommitteeMembers(ctx context.Context, meetingID string) // Set headers (Authorization automatically added by OAuth2 transport) httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPost, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -710,6 +820,9 @@ func (c *Client) RegisterCommitteeMembers(ctx context.Context, meetingID string) return domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return c.mapHTTPError(resp.StatusCode, respBody) @@ -737,6 +850,9 @@ func (c *Client) UpdateOccurrence(ctx context.Context, meetingID, occurrenceID s httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPut, url, body) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -752,6 +868,9 @@ func (c *Client) UpdateOccurrence(ctx context.Context, meetingID, occurrenceID s return domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return c.mapHTTPError(resp.StatusCode, respBody) @@ -772,6 +891,9 @@ func (c *Client) DeleteOccurrence(ctx context.Context, meetingID, occurrenceID s // Set headers (Authorization automatically added by OAuth2 transport) httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodDelete, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -787,6 +909,9 @@ func (c *Client) DeleteOccurrence(ctx context.Context, meetingID, occurrenceID s return domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return c.mapHTTPError(resp.StatusCode, respBody) @@ -815,6 +940,9 @@ func (c *Client) CreatePastMeeting(ctx context.Context, req *itx.CreatePastMeeti httpReq.Header.Set("Accept", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPost, url, body) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -830,6 +958,9 @@ func (c *Client) CreatePastMeeting(ctx context.Context, req *itx.CreatePastMeeti return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -857,6 +988,9 @@ func (c *Client) GetPastMeeting(ctx context.Context, pastMeetingID string) (*itx httpReq.Header.Set("Accept", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodGet, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -872,6 +1006,9 @@ func (c *Client) GetPastMeeting(ctx context.Context, pastMeetingID string) (*itx return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -907,6 +1044,9 @@ func (c *Client) UpdatePastMeeting(ctx context.Context, pastMeetingID string, re httpReq.Header.Set("Accept", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPut, url, body) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -922,6 +1062,9 @@ func (c *Client) UpdatePastMeeting(ctx context.Context, pastMeetingID string, re return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -944,6 +1087,8 @@ func (c *Client) DeletePastMeeting(ctx context.Context, pastMeetingID string) er // Set headers (Authorization automatically added by OAuth2 transport) httpReq.Header.Set("x-scope", "manage:zoom") + c.logRequest(ctx, http.MethodDelete, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -959,6 +1104,9 @@ func (c *Client) DeletePastMeeting(ctx context.Context, pastMeetingID string) er return domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return c.mapHTTPError(resp.StatusCode, respBody) @@ -980,6 +1128,9 @@ func (c *Client) GetPastMeetingSummary(ctx context.Context, pastMeetingID, summa httpReq.Header.Set("Accept", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodGet, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -995,6 +1146,9 @@ func (c *Client) GetPastMeetingSummary(ctx context.Context, pastMeetingID, summa return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -1029,6 +1183,9 @@ func (c *Client) UpdatePastMeetingSummary(ctx context.Context, pastMeetingID, su httpReq.Header.Set("Accept", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPut, url, body) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -1044,6 +1201,9 @@ func (c *Client) UpdatePastMeetingSummary(ctx context.Context, pastMeetingID, su return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -1107,6 +1267,9 @@ func (c *Client) CreateInvitee(ctx context.Context, pastMeetingID string, req *i httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPost, url, bodyBytes) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -1122,6 +1285,8 @@ func (c *Client) CreateInvitee(ctx context.Context, pastMeetingID string, req *i return nil, domain.NewInternalError("failed to read response", err) } + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -1156,6 +1321,9 @@ func (c *Client) UpdateInvitee(ctx context.Context, pastMeetingID, inviteeID str httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPut, url, bodyBytes) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -1171,6 +1339,8 @@ func (c *Client) UpdateInvitee(ctx context.Context, pastMeetingID, inviteeID str return nil, domain.NewInternalError("failed to read response", err) } + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -1193,6 +1363,9 @@ func (c *Client) DeleteInvitee(ctx context.Context, pastMeetingID, inviteeID str // Set headers httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodDelete, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -1208,6 +1381,9 @@ func (c *Client) DeleteInvitee(ctx context.Context, pastMeetingID, inviteeID str return domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return c.mapHTTPError(resp.StatusCode, respBody) @@ -1236,6 +1412,9 @@ func (c *Client) CreateAttendee(ctx context.Context, pastMeetingID string, req * httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPost, url, bodyBytes) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -1251,6 +1430,9 @@ func (c *Client) CreateAttendee(ctx context.Context, pastMeetingID string, req * return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -1285,6 +1467,9 @@ func (c *Client) UpdateAttendee(ctx context.Context, pastMeetingID, attendeeID s httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodPut, url, bodyBytes) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -1300,6 +1485,9 @@ func (c *Client) UpdateAttendee(ctx context.Context, pastMeetingID, attendeeID s return nil, domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return nil, c.mapHTTPError(resp.StatusCode, respBody) @@ -1322,6 +1510,9 @@ func (c *Client) DeleteAttendee(ctx context.Context, pastMeetingID, attendeeID s // Set headers httpReq.Header.Set("x-scope", "manage:zoom") + // Log request + c.logRequest(ctx, http.MethodDelete, url, nil) + // Execute request resp, err := c.httpClient.Do(httpReq) if err != nil { @@ -1337,6 +1528,9 @@ func (c *Client) DeleteAttendee(ctx context.Context, pastMeetingID, attendeeID s return domain.NewInternalError("failed to read response", err) } + // Log response + c.logResponse(ctx, resp.StatusCode, respBody) + // Handle non-2xx status codes if resp.StatusCode < 200 || resp.StatusCode >= 300 { return c.mapHTTPError(resp.StatusCode, respBody)