feature/adding ticket creation in Zendesk integration#557
feature/adding ticket creation in Zendesk integration#557lukasz-hycom merged 61 commits intomainfrom
Conversation
… feature/creating-zendesk-tickets
…tachment to use httpClient
…using specific exceptions
… and multipart/form-data
… feature/adding-createTicket-form
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
WalkthroughAdds end-to-end Zendesk ticket creation (attachments, custom-field mapping), SurveyJS → tickets submission path, makes ticket.type optional across models/UI, updates CMS mappers/mocks to Zendesk fields, expands Zendesk env config, and enforces changeset checks in CI. Changes
Sequence DiagramsequenceDiagram
actor User
participant SurveyUI as SurveyJS Form
participant API as SurveyJS Controller
participant Mapper as mapSurveyToTicket
participant Service as SurveyJS Service
participant TicketsSvc as Zendesk TicketService
participant Zendesk as Zendesk API
User->>SurveyUI: submit survey
SurveyUI->>API: POST /surveys/submit
API->>Mapper: mapSurveyToTicket(payload)
Mapper-->>API: PostTicketBody
API->>Service: submitSurvey(body, auth)
Service->>Service: validate & route to 'tickets'
Service->>TicketsSvc: createTicket(mappedData, auth)
TicketsSvc->>TicketsSvc: find or create requester
TicketsSvc->>Zendesk: upload attachments (parallel)
TicketsSvc->>Zendesk: create ticket with custom fields
Zendesk-->>TicketsSvc: ticket created
TicketsSvc-->>Service: success
Service-->>API: success response
API-->>User: 200 OK
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/modules/surveyjs/src/api-harmonization/surveyjs.module.ts (1)
6-32: Fix missing@Optional()on Tickets.Service injection.Line 28 of
surveyjs.service.tsinjectsTickets.Serviceas a required dependency without@Optional(), but the provider is only registered whenconfig.integrations.tickets?.serviceexists (lines 19–24 ofsurveyjs.module.ts). When the tickets integration is disabled, Nest will fail during bootstrap because it cannot resolve this required dependency. Add@Optional()to theticketsServiceparameter or provide a fallback implementation.
🤖 Fix all issues with AI agents
In `@packages/framework/src/modules/tickets/tickets.request.ts`:
- Around line 9-21: TicketAttachmentInput currently exposes content as a Node
Buffer which breaks browser SDK JSON serialization; change
TicketAttachmentInput.content to a base64 string (e.g., content: string) and
update any code that constructs PostTicketBody so attachments provide
base64-encoded content, or alternatively implement a serializer/SDK interceptor
in sdk.ts that converts Buffer → base64 before calling createTicket/ofetch; also
audit and update all createTicket call sites to always supply topic on
PostTicketBody to avoid 4xx validation errors, and if you must keep Buffer in
server-only APIs, document the need for a Buffer polyfill (e.g., npm buffer) for
browser consumers.
In
`@packages/integrations/contentful-cms/src/modules/cms/mappers/cms.page.mapper.ts`:
- Around line 224-229: getAllPages and getAlternativePages are missing the new
create-ticket page constants even though mapMockPage now maps '/create-ticket'
variants; update both functions to include PAGE_CREATE_TICKET_EN,
PAGE_CREATE_TICKET_DE, and PAGE_CREATE_TICKET_PL in their returned lists (and
any locale-alternative mapping arrays) so the create-ticket routes appear in
page listings and locale switching logic referenced by mapMockPage.
In `@packages/integrations/mocked/src/modules/cms/mappers/cms.page.mapper.ts`:
- Around line 245-250: getAllPages and getAlternativePages are missing the
create-ticket page constants even though mapPage handles '/create-ticket'
(PAGE_CREATE_TICKET_EN, PAGE_CREATE_TICKET_DE, PAGE_CREATE_TICKET_PL); update
both functions to include these three constants in their returned lists so
listing and locale switching work for the create-ticket routes, ensuring you add
PAGE_CREATE_TICKET_EN/DE/PL to the same arrays/enum usages where other page
constants are listed.
In `@packages/integrations/zendesk/src/modules/tickets/zendesk-ticket.service.ts`:
- Around line 407-416: The upload URL is duplicating /api/v2 because
this.baseUrl already contains the API suffix; update the uploadAttachment method
to build the uploadUrl without re-adding /api/v2 (use this.baseUrl +
'/uploads?filename=...' or otherwise normalize/remove trailing/leading slashes)
so the final URL is .../api/v2/uploads only once; ensure
encodeURIComponent(filename) is still used and preserve the existing
Authorization and Content-Type headers in uploadAttachment.
- Around line 255-289: The current enrichment pipeline (fetchTicketComments ->
fetchUser -> mapTicketToModel) can throw in the catchError and cause the whole
operation to fail after the ticket is created; change it to be best‑effort by
catching enrichment errors and returning the created ticket instead of
rethrowing: inside the observable chain around
fetchTicketComments/firstValueFrom(fetchUser)/mapTicketToModel and in the
catchError block, replace the throwError with code that logs the enrichment
error (or records it) and returns of(mapTicketToModel(createdTicket, comments)
or simply of(createdTicket) as a safe fallback; also ensure individual author
fetch failures are tolerated (filter undefined authors already exists) so the
overall flow always emits the createdTicket model even when enrichment fails.
- Around line 376-394: The current findZendeskUserByEmail silently swallows
API/network errors by returning of(undefined) in the catchError, which must
instead propagate real failures while still returning undefined for "no user
found" cases; update the catchError after the map to rethrow the original error
(use throwError(() => err) or equivalent) so searchUsers errors bubble up, and
keep the existing map logic that returns undefined when users array has no exact
match—refer to the findZendeskUserByEmail function and its catchError/map around
the searchUsers call.
In `@packages/modules/surveyjs/src/api-harmonization/surveyjs.service.ts`:
- Around line 181-188: The code currently builds ticketData
(Tickets.Request.PostTicketBody) by defaulting required fields title,
description, and topic to empty strings from surveyData which can create
invalid/low-quality tickets; update the logic around the ticket creation (where
ticketData is constructed) to validate that surveyData.title,
surveyData.description, and surveyData.topic are present and non-empty before
constructing/posting the ticket (e.g., return or throw a validation error if any
required field is missing), remove the empty-string fallbacks, and ensure any
callers of the function handling survey submissions (the code that uses
ticketData) properly handle the validation error so tickets are only created
when required fields are provided.
In `@packages/modules/surveyjs/src/frontend/Survey.tsx`:
- Around line 110-172: handleSubmit closes over the initial state.model (null)
so file field detection using state.model fails; fix by making handleSubmit
accept the current survey model as an explicit parameter (e.g.,
handleSubmit(data, model)) and use that model instead of reading state.model
inside handleSubmit (referencing state.model, handleSubmit, startTransition);
then update the completion/callback that invokes handleSubmit (the survey
onComplete/submit handler) to pass the up-to-date state.model into handleSubmit
so fileFieldNames detection uses the live model and multipart submission is used
when files exist.
In `@packages/modules/surveyjs/src/sdk/surveyjs.ts`:
- Around line 32-99: The multipart branch of submitSurvey serializes every field
with String(value), which corrupts arrays/objects; update submitSurvey (handling
inside the 'surveyPayload' branch and the else branch where Object.entries are
appended) to detect non-primitive values (e.g., Array.isArray(value) || (typeof
value === 'object' && value !== null)) and use JSON.stringify(value) for those,
while leaving strings, numbers and booleans appended as-is; keep file appends
for 'attachments' unchanged and keep headers logic and sdk.makeRequest usage
intact; also ensure this matches how mapSurveyJsRequest expects JSON-stringified
fields on the backend.
🧹 Nitpick comments (1)
packages/modules/surveyjs/src/api-harmonization/surveyjs.service.ts (1)
92-105: Multipart submissions to non-ticket destinations will fail.If a multipart submission is made to a survey that doesn't have
'tickets'insubmitDestination, the code falls through to line 103 which checks for'surveyPayload' in payload. This check will fail for multipart form data, throwing aBadRequestException.Consider adding explicit handling or a clearer error message for this case:
Suggested improvement
// For multipart submissions with files going to tickets - handle directly if (isMultipartSubmission && survey.submitDestination.includes('tickets')) { return this.handleMultipartTicketSubmission( payload as Record<string, string>, files, authorization, ); } + // Multipart submissions are only supported for ticket destinations + if (isMultipartSubmission) { + throw new BadRequestException('File uploads are only supported for ticket submissions'); + } + // For JSON submissions - validate payload format if (!('surveyPayload' in payload)) { throw new BadRequestException('Invalid payload format for JSON submission'); }
…/o2sdev/openselfservice into feature/adding-createTicket-form
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In
`@packages/integrations/contentful-cms/src/modules/cms/mappers/blocks/cms.ticket-details.mapper.ts`:
- Around line 35-77: Add localized mappings for the preferredContactMethod enum
wherever other field mappings exist (same blocks that contain inquiryType,
productCategory, maintenanceType) so raw Zendesk enum keys won't be shown to
users; update the preferredContactMethod entries in each language block's
mapping object (the same object that contains
inquiryType/productCategory/maintenanceType) and in the fieldMapping that
references properties.preferredContactMethod, providing human-readable localized
strings for each enum value (e.g., email/phone/whatsapp/other or your project's
enum keys) across all language sections mentioned.
In
`@packages/integrations/mocked/src/modules/cms/mappers/blocks/cms.ticket-details.mapper.ts`:
- Around line 35-77: The mapper cms.ticket-details.mapper.ts is missing
localized field mappings for the preferredContactMethod property, so the UI will
show raw enum values; update the fieldMapping (or add a new mapping object
alongside inquiryType/productCategory/etc.) to include localized labels for each
possible preferredContactMethod value (e.g., PHONE, EMAIL, SMS or whatever enum
keys exist) for the locale in this file, using the same pattern as
status/inquiryType/productCategory, or if preferredContactMethod is free-text,
add a comment on the preferredContactMethod entry in properties to indicate it's
free-text and leave out fieldMapping.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/integrations/zendesk/src/modules/tickets/zendesk-ticket.mapper.ts`:
- Around line 51-62: The code builds consentFieldIds and contactFormId using
Number(...) but only filters null, so NaN values slip through; update the
construction of consentFieldIds to convert env vars and filter out non-finite
numbers (e.g., use Number(...) and .filter((id): id is number =>
Number.isFinite(id))) and change contactFormId to produce undefined for invalid
or NaN values (e.g., const contactFormId =
Number(process.env.ZENDESK_CONTACT_FORM_ID); const contactFormIdValid =
Number.isFinite(contactFormId) ? contactFormId : undefined) and then use
contactFormIdValid in isContactUsForm (ticket.ticket_form_id ===
contactFormIdValid) so bogus env strings no longer cause mismatches.
…yjs' for mock surveys
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@apps/docs/docs/integrations/forms/surveyjs/features.md`:
- Around line 158-165: Update the earlier "Form Submission" section to mention
ticket destinations alongside the SurveyJS backend: reference the
submitDestination configuration and note that submitDestination can include
'tickets' to route submissions into the framework's Tickets service (e.g.,
Zendesk), and list required fields description (string) and ticketFormId
(number) for ticket submissions so the two sections align with the SurveyJS
module's ticket-support behavior.
In
`@apps/docs/docs/main-components/harmonization-app/normalized-data-model/core-model-tickets.md`:
- Around line 119-125: Update the parameter table in core-model-tickets.md to
call out integration-specific required fields: keep 'description' and 'type'
marked optional in the core model but add a clear note (adjacent to the table or
as a footnote) stating that certain integrations (e.g., Zendesk, SurveyJS)
require these fields; reference the exact parameter names 'description' and
'type' and, optionally, list affected integrations to prevent confusion for
implementers.
🧹 Nitpick comments (2)
apps/docs/docs/integrations/tickets/zendesk/features.md (1)
186-228: Clarify user-facing error semantics.
Consider describing the failure as HTTP 400 rather than the framework exception class name to keep the docs API-centric.💡 Suggested wording tweak
- **Important**: If the `type` doesn't match any configured form ID, the ticket creation will fail with a `BadRequestException`. This ensures that all tickets are properly categorized. + **Important**: If the `type` doesn't match any configured form ID, ticket creation fails with HTTP 400 (bad request). This ensures that all tickets are properly categorized.apps/docs/docs/integrations/tickets/zendesk/usage.md (1)
152-207: Clarify request vs. responsetypesemantics.
The request uses a numeric form ID, but the example response shows a normalized stringtype. Add a short note to avoid confusion.📝 Suggested addition
**Example Response:** + +> Note: The response `type` is the normalized ticket type, not the numeric form ID provided in the request. ```json {
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @.changeset/cuddly-teams-flash.md:
- Line 15: The changeset summary sentence is incomplete; update the final clause
in .changeset/cuddly-teams-flash.md to finish the thought and be specific about
which CMS mapper mocks were changed (e.g., "Updated mapper mocks in cms:
[name-of-cms]-mapper and [other-cms]-mapper" or similar), ensuring the sentence
reads as a complete, grammatically correct release note and lists the exact
mapper names updated.
… feature/adding-createTicket-form
What does this PR do?
Key Changes
Summary by CodeRabbit
New Features
Enhancements
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.