|
| 1 | +package httpclient |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "fmt" |
| 6 | +) |
| 7 | + |
| 8 | +const ( |
| 9 | + surveyCollectionPathFormat = "/api/projects/%s/surveys/" |
| 10 | + surveyResourcePathFormat = "/api/projects/%s/surveys/%s/" |
| 11 | +) |
| 12 | + |
| 13 | +type Survey struct { |
| 14 | + ID string `json:"id"` |
| 15 | + Name *string `json:"name,omitempty"` |
| 16 | + Description *string `json:"description,omitempty"` |
| 17 | + Type *string `json:"type,omitempty"` |
| 18 | + Schedule *string `json:"schedule,omitempty"` |
| 19 | + LinkedFlag map[string]interface{} `json:"linked_flag,omitempty"` |
| 20 | + TargetingFlag map[string]interface{} `json:"targeting_flag,omitempty"` |
| 21 | + InternalTargetingFlag map[string]interface{} `json:"internal_targeting_flag,omitempty"` |
| 22 | + Questions []interface{} `json:"questions,omitempty"` |
| 23 | + Conditions interface{} `json:"conditions,omitempty"` |
| 24 | + Appearance interface{} `json:"appearance,omitempty"` |
| 25 | + CreatedAt *string `json:"created_at,omitempty"` |
| 26 | + CreatedBy map[string]interface{} `json:"created_by,omitempty"` |
| 27 | + StartDate *string `json:"start_date,omitempty"` |
| 28 | + EndDate *string `json:"end_date,omitempty"` |
| 29 | + Archived *bool `json:"archived,omitempty"` |
| 30 | + ResponsesLimit *int64 `json:"responses_limit,omitempty"` |
| 31 | + IterationCount *int64 `json:"iteration_count,omitempty"` |
| 32 | + IterationFrequencyDays *int64 `json:"iteration_frequency_days,omitempty"` |
| 33 | + IterationStartDates []interface{} `json:"iteration_start_dates,omitempty"` |
| 34 | + CurrentIteration *int64 `json:"current_iteration,omitempty"` |
| 35 | + CurrentIterationStartDate *string `json:"current_iteration_start_date,omitempty"` |
| 36 | + ResponseSamplingStartDate *string `json:"response_sampling_start_date,omitempty"` |
| 37 | + ResponseSamplingIntervalType *string `json:"response_sampling_interval_type,omitempty"` |
| 38 | + ResponseSamplingInterval *int64 `json:"response_sampling_interval,omitempty"` |
| 39 | + ResponseSamplingLimit *int64 `json:"response_sampling_limit,omitempty"` |
| 40 | + ResponseSamplingDailyLimits interface{} `json:"response_sampling_daily_limits,omitempty"` |
| 41 | + EnablePartialResponses *bool `json:"enable_partial_responses,omitempty"` |
| 42 | + EnableIframeEmbedding *bool `json:"enable_iframe_embedding,omitempty"` |
| 43 | + Translations interface{} `json:"translations,omitempty"` |
| 44 | + FormContent interface{} `json:"form_content,omitempty"` |
| 45 | +} |
| 46 | + |
| 47 | +// SurveyNullableIntegerJSONFields lists the JSON keys whose Go fields drop |
| 48 | +// `omitempty` per the SurveyRequest comment below. Both the resource and |
| 49 | +// httpclient test packages reference this slice so the list lives in one place. |
| 50 | +var SurveyNullableIntegerJSONFields = []string{ |
| 51 | + "linked_flag_id", |
| 52 | + "linked_insight_id", |
| 53 | + "responses_limit", |
| 54 | + "iteration_count", |
| 55 | + "iteration_frequency_days", |
| 56 | + "response_sampling_interval", |
| 57 | + "response_sampling_limit", |
| 58 | +} |
| 59 | + |
| 60 | +// SurveyRequest is the wire format for POST/PUT to the surveys endpoint. |
| 61 | +// |
| 62 | +// Fields marked nullable in the upstream OpenAPI schema (the keys in |
| 63 | +// SurveyNullableIntegerJSONFields above) deliberately omit `,omitempty` so that |
| 64 | +// a nil pointer serialises as JSON `null`. PostHog interprets `null` as "clear |
| 65 | +// this column", which is the semantic users expect when they remove the |
| 66 | +// attribute from their Terraform config. Fields that are not nullable upstream |
| 67 | +// (targeting_flag_id, archived) keep `,omitempty` so an absent value is omitted |
| 68 | +// rather than rejected. |
| 69 | +type SurveyRequest struct { |
| 70 | + Name string `json:"name"` |
| 71 | + Description *string `json:"description,omitempty"` |
| 72 | + Type string `json:"type"` |
| 73 | + Schedule *string `json:"schedule,omitempty"` |
| 74 | + LinkedFlagID *int64 `json:"linked_flag_id"` |
| 75 | + LinkedInsightID *int64 `json:"linked_insight_id"` |
| 76 | + TargetingFlagID *int64 `json:"targeting_flag_id,omitempty"` |
| 77 | + TargetingFlagFilters interface{} `json:"targeting_flag_filters,omitempty"` |
| 78 | + RemoveTargetingFlag *bool `json:"remove_targeting_flag,omitempty"` |
| 79 | + Questions []interface{} `json:"questions"` |
| 80 | + Conditions interface{} `json:"conditions,omitempty"` |
| 81 | + Appearance interface{} `json:"appearance,omitempty"` |
| 82 | + StartDate *string `json:"start_date,omitempty"` |
| 83 | + EndDate *string `json:"end_date,omitempty"` |
| 84 | + Archived *bool `json:"archived,omitempty"` |
| 85 | + ResponsesLimit *int64 `json:"responses_limit"` |
| 86 | + IterationCount *int64 `json:"iteration_count"` |
| 87 | + IterationFrequencyDays *int64 `json:"iteration_frequency_days"` |
| 88 | + ResponseSamplingStartDate *string `json:"response_sampling_start_date,omitempty"` |
| 89 | + ResponseSamplingIntervalType *string `json:"response_sampling_interval_type,omitempty"` |
| 90 | + ResponseSamplingInterval *int64 `json:"response_sampling_interval"` |
| 91 | + ResponseSamplingLimit *int64 `json:"response_sampling_limit"` |
| 92 | + ResponseSamplingDailyLimits interface{} `json:"response_sampling_daily_limits,omitempty"` |
| 93 | + EnablePartialResponses *bool `json:"enable_partial_responses,omitempty"` |
| 94 | + EnableIframeEmbedding *bool `json:"enable_iframe_embedding,omitempty"` |
| 95 | + Translations interface{} `json:"translations,omitempty"` |
| 96 | + CreateInFolder *string `json:"_create_in_folder,omitempty"` |
| 97 | + FormContent interface{} `json:"form_content,omitempty"` |
| 98 | +} |
| 99 | + |
| 100 | +func (c *PosthogClient) CreateSurvey(ctx context.Context, projectID string, input SurveyRequest) (Survey, error) { |
| 101 | + path := fmt.Sprintf(surveyCollectionPathFormat, projectID) |
| 102 | + result, _, err := doPost[Survey](c, ctx, path, input) |
| 103 | + return result, err |
| 104 | +} |
| 105 | + |
| 106 | +func (c *PosthogClient) GetSurvey(ctx context.Context, projectID, id string) (Survey, HTTPStatusCode, error) { |
| 107 | + path := fmt.Sprintf(surveyResourcePathFormat, projectID, id) |
| 108 | + return doGet[Survey](c, ctx, path) |
| 109 | +} |
| 110 | + |
| 111 | +func (c *PosthogClient) UpdateSurvey(ctx context.Context, projectID, id string, input SurveyRequest) (Survey, HTTPStatusCode, error) { |
| 112 | + path := fmt.Sprintf(surveyResourcePathFormat, projectID, id) |
| 113 | + // PostHog's SurveyViewSet.get_serializer_class() routes only POST and PATCH |
| 114 | + // to SurveySerializerCreateUpdateOnly; PUT falls through to SurveySerializer, |
| 115 | + // whose linked_flag_id / linked_insight_id are declared with a dotted source |
| 116 | + // (`source="linked_flag.id"`) and therefore trip DRF's "writable dotted-source |
| 117 | + // fields" AssertionError on update. Use PATCH so the request hits the |
| 118 | + // write-safe serializer path. |
| 119 | + return doPatch[Survey](c, ctx, path, input) |
| 120 | +} |
| 121 | + |
| 122 | +func (c *PosthogClient) DeleteSurvey(ctx context.Context, projectID, id string) (HTTPStatusCode, error) { |
| 123 | + path := fmt.Sprintf(surveyResourcePathFormat, projectID, id) |
| 124 | + return doDelete(c, ctx, path) |
| 125 | +} |
0 commit comments