1010 lines
31 KiB
TypeScript
1010 lines
31 KiB
TypeScript
import type { ApiSettings, CampaignListItem, DeltaDeletedItem } from "../types";
|
|
import { apiDownload, apiFetch } from "./client";
|
|
import { campaignJobsQueryParams, type CampaignJobsQueryParameters } from "../features/campaigns/utils/jobListQuery";
|
|
export { fetchResourceAccessExplanation } from "@govoplan/core-webui";
|
|
export type {
|
|
AccessDecisionProvenanceItem,
|
|
ResourceAccessExplanationUser as AccessExplanationUser,
|
|
ResourceAccessExplanationResponse
|
|
} from "@govoplan/core-webui";
|
|
|
|
export type CampaignListResponse =
|
|
CampaignListItem[] |
|
|
{
|
|
campaigns?: CampaignListItem[];
|
|
items?: CampaignListItem[];
|
|
results?: CampaignListItem[];
|
|
};
|
|
|
|
|
|
|
|
export type CampaignShare = {
|
|
id: string;
|
|
campaign_id: string;
|
|
target_type: "user" | "group";
|
|
target_id: string;
|
|
permission: "read" | "write";
|
|
revoked_at?: string | null;
|
|
};
|
|
|
|
export type CampaignShareTarget = {id: string;name: string;secondary?: string | null;};
|
|
export type CampaignShareTargets = {users: CampaignShareTarget[];groups: CampaignShareTarget[];};
|
|
|
|
export type CampaignUpdatePayload = {
|
|
external_id?: string | null;
|
|
name?: string | null;
|
|
status?: string | null;
|
|
description?: string | null;
|
|
};
|
|
|
|
export type CampaignCreateMinimalPayload = {
|
|
external_id?: string;
|
|
name?: string;
|
|
description?: string | null;
|
|
current_flow?: string;
|
|
current_step?: string;
|
|
};
|
|
|
|
export type CampaignCreateResponse = {
|
|
campaign: CampaignListItem & {
|
|
current_version_id?: string | null;
|
|
};
|
|
version: CampaignVersionListItem;
|
|
};
|
|
|
|
export type CampaignVersionListItem = {
|
|
id: string;
|
|
campaign_id: string;
|
|
version_number: number;
|
|
schema_version?: string;
|
|
source_filename?: string | null;
|
|
source_base_path?: string | null;
|
|
workflow_state?: string;
|
|
current_flow?: string;
|
|
current_step?: string | null;
|
|
is_complete?: boolean;
|
|
editor_state?: Record<string, unknown>;
|
|
autosaved_at?: string | null;
|
|
published_at?: string | null;
|
|
locked_at?: string | null;
|
|
locked_by_user_id?: string | null;
|
|
user_lock_state?: "temporary" | "permanent" | null;
|
|
user_locked_at?: string | null;
|
|
user_locked_by_user_id?: string | null;
|
|
created_at?: string;
|
|
updated_at?: string;
|
|
validation_summary?: Record<string, unknown> | null;
|
|
build_summary?: Record<string, unknown> | null;
|
|
execution_snapshot_hash?: string | null;
|
|
execution_snapshot_at?: string | null;
|
|
};
|
|
|
|
export type CampaignVersionDetail = CampaignVersionListItem & {
|
|
raw_json: Record<string, unknown>;
|
|
campaign_json?: Record<string, unknown>;
|
|
mail_profile_migration_required?: boolean;
|
|
};
|
|
|
|
export type CampaignWorkspaceResponse = {
|
|
campaign: CampaignListItem | null;
|
|
versions: CampaignVersionListItem[];
|
|
current_version: CampaignVersionDetail | null;
|
|
summary: CampaignSummary | null;
|
|
selected_version_id?: string | null;
|
|
};
|
|
|
|
export type CampaignDeltaResponse = {
|
|
campaigns: CampaignListItem[];
|
|
deleted: DeltaDeletedItem[];
|
|
watermark?: string | null;
|
|
has_more: boolean;
|
|
full: boolean;
|
|
};
|
|
|
|
export type CampaignWorkspaceDeltaResponse = CampaignWorkspaceResponse & {
|
|
deleted: DeltaDeletedItem[];
|
|
watermark?: string | null;
|
|
has_more: boolean;
|
|
full: boolean;
|
|
};
|
|
|
|
export type CampaignWorkspaceQuery = {
|
|
versionId?: string | null;
|
|
includeCurrentVersion?: boolean;
|
|
includeSummary?: boolean;
|
|
includeVersions?: boolean;
|
|
since?: string | null;
|
|
limit?: number;
|
|
};
|
|
|
|
export type RecipientImportColumnKind = "ignore" | "id" | "active" | "name" | "from" | "to" | "cc" | "bcc" | "reply_to" | "field" | "new_field" | "attachment_pattern";
|
|
|
|
export type RecipientImportColumnMappingProfileItem = {
|
|
columnIndex: number;
|
|
kind: RecipientImportColumnKind;
|
|
fieldName?: string | null;
|
|
newFieldName?: string | null;
|
|
};
|
|
|
|
export type RecipientImportMappingProfile = {
|
|
id: string;
|
|
name: string;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
columnCount: number;
|
|
headers: string[];
|
|
normalizedHeaders: string[];
|
|
orderedHeaderFingerprint: string;
|
|
unorderedHeaderFingerprint: string;
|
|
delimiter: "," | ";" | "\t";
|
|
headerRows: number;
|
|
quoted: boolean;
|
|
valueSeparators: string;
|
|
mappings: RecipientImportColumnMappingProfileItem[];
|
|
};
|
|
|
|
export type RecipientImportMappingProfilePayload = Omit<RecipientImportMappingProfile, "id" | "createdAt" | "updatedAt">;
|
|
|
|
export type RecipientImportMappingProfileListResponse = {
|
|
profiles: RecipientImportMappingProfile[];
|
|
};
|
|
|
|
export type CampaignAddressLookupCandidate = {
|
|
contact_id: string;
|
|
address_book_id: string;
|
|
display_name: string;
|
|
email?: string | null;
|
|
email_label?: string | null;
|
|
organization?: string | null;
|
|
role_title?: string | null;
|
|
tags: string[];
|
|
source_kind: string;
|
|
source_ref?: string | null;
|
|
source_revision?: string | null;
|
|
provenance: Record<string, unknown>;
|
|
};
|
|
|
|
export type CampaignAddressLookupResponse = {
|
|
available: boolean;
|
|
candidates: CampaignAddressLookupCandidate[];
|
|
};
|
|
|
|
export type CampaignRecipientAddressSource = {
|
|
source_id: string;
|
|
source_label: string;
|
|
source_kind: string;
|
|
source_revision: string;
|
|
recipient_count: number;
|
|
provenance: Record<string, unknown>;
|
|
};
|
|
|
|
export type CampaignRecipientAddressSourcesResponse = {
|
|
available: boolean;
|
|
sources: CampaignRecipientAddressSource[];
|
|
};
|
|
|
|
export type CampaignRecipientSnapshotItem = {
|
|
contact_id: string;
|
|
display_name: string;
|
|
email: string;
|
|
email_label?: string | null;
|
|
fields: Record<string, unknown>;
|
|
provenance: Record<string, unknown>;
|
|
};
|
|
|
|
export type CampaignRecipientAddressSourceSnapshot = {
|
|
source_id: string;
|
|
source_label: string;
|
|
source_kind: string;
|
|
source_revision: string;
|
|
generated_at: string;
|
|
recipients: CampaignRecipientSnapshotItem[];
|
|
provenance: Record<string, unknown>;
|
|
};
|
|
|
|
export type CampaignVersionUpdatePayload = {
|
|
campaign_json?: Record<string, unknown> | null;
|
|
current_flow?: string | null;
|
|
current_step?: string | null;
|
|
workflow_state?: string | null;
|
|
is_complete?: boolean | null;
|
|
editor_state?: Record<string, unknown> | null;
|
|
source_filename?: string | null;
|
|
source_base_path?: string | null;
|
|
migrate_legacy_mail_settings?: boolean;
|
|
};
|
|
|
|
export type CampaignPartialValidationPayload = {
|
|
campaign_json?: Record<string, unknown> | null;
|
|
section?: string | null;
|
|
};
|
|
|
|
export type CampaignPartialValidationResponse = {
|
|
ok: boolean;
|
|
section?: string | null;
|
|
error_count: number;
|
|
warning_count: number;
|
|
info_count: number;
|
|
issues: Record<string, unknown>[];
|
|
};
|
|
|
|
export type CampaignSummary = {
|
|
generated_at?: string;
|
|
selected_version_id?: string | null;
|
|
campaign?: CampaignListItem;
|
|
current_version?: {
|
|
id: string;
|
|
version_number?: number;
|
|
schema_version?: string;
|
|
source_filename?: string | null;
|
|
created_at?: string | null;
|
|
validation_summary?: Record<string, unknown> | null;
|
|
build_summary?: Record<string, unknown> | null;
|
|
} | null;
|
|
cards?: {
|
|
jobs_total?: number;
|
|
inactive?: number;
|
|
queueable?: number;
|
|
needs_attention?: number;
|
|
sent?: number;
|
|
smtp_accepted?: number;
|
|
failed?: number;
|
|
outcome_unknown?: number;
|
|
not_attempted?: number;
|
|
queued_or_active?: number;
|
|
cancelled?: number;
|
|
partially_completed?: boolean;
|
|
imap_appended?: number;
|
|
imap_failed?: number;
|
|
};
|
|
status_counts?: Record<string, Record<string, number>>;
|
|
issues?: Record<string, unknown>;
|
|
attachments?: Record<string, unknown>;
|
|
attempts?: Record<string, unknown>;
|
|
delivery?: Record<string, unknown>;
|
|
recent_failures?: Record<string, unknown>[];
|
|
};
|
|
|
|
export type CampaignQueuePayload = {
|
|
version_id?: string | null;
|
|
include_warnings?: boolean;
|
|
enqueue_celery?: boolean;
|
|
dry_run?: boolean;
|
|
};
|
|
|
|
export type CampaignDeliveryOptions = {
|
|
campaign_id: string;
|
|
version_id: string;
|
|
worker_queue_available: boolean;
|
|
synchronous_send: {
|
|
allowed?: boolean;
|
|
reason?: string | null;
|
|
message?: string | null;
|
|
eligible_recipient_job_count?: number;
|
|
policy?: {
|
|
max_recipient_jobs?: number;
|
|
source?: string;
|
|
deployment_max_recipient_jobs?: number;
|
|
tenant_max_recipient_jobs?: number | null;
|
|
};
|
|
};
|
|
};
|
|
|
|
export type CampaignSendNowPayload = {
|
|
version_id?: string | null;
|
|
include_warnings?: boolean;
|
|
check_files?: boolean;
|
|
validate_before_send?: boolean;
|
|
build_before_send?: boolean;
|
|
dry_run?: boolean;
|
|
use_rate_limit?: boolean;
|
|
enqueue_imap_task?: boolean;
|
|
};
|
|
|
|
export type CampaignAppendSentPayload = {
|
|
dry_run?: boolean;
|
|
enqueue_celery?: boolean;
|
|
run_inline?: boolean;
|
|
};
|
|
|
|
|
|
export type CampaignAttachmentPreviewFile = {
|
|
id: string;
|
|
version_id?: string;
|
|
blob_id?: string;
|
|
display_path: string;
|
|
filename: string;
|
|
owner_type: string;
|
|
owner_id: string;
|
|
checksum_sha256?: string;
|
|
size_bytes?: number;
|
|
content_type?: string | null;
|
|
linked_to_campaign?: boolean;
|
|
share?: Record<string, unknown> | null;
|
|
};
|
|
|
|
export type CampaignAttachmentPreviewRule = {
|
|
source: "global" | "entry";
|
|
entry_index: number;
|
|
entry_id?: string | null;
|
|
index: number;
|
|
attachment_id?: string | null;
|
|
label?: string | null;
|
|
required: boolean;
|
|
pattern: string;
|
|
base_path_name?: string | null;
|
|
base_path?: string | null;
|
|
status: "ok" | "missing" | "ambiguous";
|
|
behavior?: string | null;
|
|
zip_included?: boolean;
|
|
zip_mode?: "inherit" | "include" | "exclude";
|
|
zip_archive_id?: string | null;
|
|
zip_filename?: string | null;
|
|
matches: CampaignAttachmentPreviewFile[];
|
|
match_count: number;
|
|
linked_match_count?: number;
|
|
unlinked_match_count?: number;
|
|
issues: Record<string, unknown>[];
|
|
};
|
|
|
|
export type CampaignAttachmentPreviewResponse = {
|
|
campaign_id: string;
|
|
version_id: string;
|
|
shared_file_count: number;
|
|
candidate_file_count?: number;
|
|
matched_file_count?: number;
|
|
linked_file_count?: number;
|
|
unlinked_file_count?: number;
|
|
rules: CampaignAttachmentPreviewRule[];
|
|
linkable_files?: CampaignAttachmentPreviewFile[];
|
|
unused_shared_files: CampaignAttachmentPreviewFile[];
|
|
};
|
|
|
|
export type CampaignAttachmentPreviewPayload = {
|
|
include_unmatched?: boolean;
|
|
include_unlinked_candidates?: boolean;
|
|
campaign_json?: Record<string, unknown>;
|
|
};
|
|
|
|
export type CampaignAttachmentLinkMatchesPayload = {
|
|
campaign_json?: Record<string, unknown> | null;
|
|
dry_run?: boolean;
|
|
};
|
|
|
|
export type CampaignAttachmentLinkMatchesResponse = {
|
|
campaign_id: string;
|
|
version_id: string;
|
|
matched_file_count: number;
|
|
already_linked_file_count: number;
|
|
linked_file_count: number;
|
|
dry_run?: boolean;
|
|
linked_files: CampaignAttachmentPreviewFile[];
|
|
linkable_files: CampaignAttachmentPreviewFile[];
|
|
};
|
|
|
|
export type CampaignMockSendPayload = {
|
|
version_id?: string | null;
|
|
send?: boolean;
|
|
include_warnings?: boolean;
|
|
include_needs_review?: boolean;
|
|
append_sent?: boolean;
|
|
clear_mailbox?: boolean;
|
|
check_files?: boolean;
|
|
};
|
|
|
|
export type CampaignReviewStatePayload = {
|
|
inspection_complete: boolean;
|
|
reviewed_message_keys: string[];
|
|
};
|
|
|
|
export type CampaignSendJobPayload = {
|
|
include_warnings?: boolean;
|
|
dry_run?: boolean;
|
|
use_rate_limit?: boolean;
|
|
enqueue_imap_task?: boolean;
|
|
};
|
|
|
|
|
|
export type CampaignJobsQuery = Omit<CampaignJobsQueryParameters, "since" | "limit">;
|
|
|
|
export type CampaignJobsResponse = {
|
|
jobs: Record<string, unknown>[];
|
|
page: number;
|
|
page_size: number;
|
|
total: number;
|
|
total_unfiltered: number;
|
|
pages: number;
|
|
cursor?: string | null;
|
|
next_cursor?: string | null;
|
|
counts: Record<string, Record<string, number>>;
|
|
filtered_counts: Record<string, Record<string, number>>;
|
|
review: {
|
|
inspection_complete?: boolean;
|
|
blocking_count?: number;
|
|
required_count?: number;
|
|
reviewed_required_count?: number;
|
|
bulk_acceptable_count?: number;
|
|
};
|
|
};
|
|
|
|
export type CampaignJobsDeltaResponse = CampaignJobsResponse & {
|
|
deleted: DeltaDeletedItem[];
|
|
watermark?: string | null;
|
|
has_more: boolean;
|
|
full: boolean;
|
|
};
|
|
|
|
export type CampaignJobDetailResponse = {
|
|
job: Record<string, unknown>;
|
|
attempts: {
|
|
smtp?: Record<string, unknown>[];
|
|
imap?: Record<string, unknown>[];
|
|
};
|
|
};
|
|
|
|
export type CampaignReportEmailPayload = {
|
|
to: string[];
|
|
version_id?: string;
|
|
include_jobs?: boolean;
|
|
attach_jobs_csv?: boolean;
|
|
attach_report_json?: boolean;
|
|
dry_run?: boolean;
|
|
};
|
|
|
|
export async function listCampaigns(settings: ApiSettings): Promise<CampaignListItem[]> {
|
|
const response = await apiFetch<CampaignListResponse>(settings, "/api/v1/campaigns");
|
|
|
|
if (Array.isArray(response)) {
|
|
return response;
|
|
}
|
|
|
|
return response.campaigns ?? response.items ?? response.results ?? [];
|
|
}
|
|
|
|
export async function listCampaignsDelta(
|
|
settings: ApiSettings,
|
|
options: {since?: string | null;limit?: number;} = {})
|
|
: Promise<CampaignDeltaResponse> {
|
|
const params = new URLSearchParams();
|
|
if (options.since) params.set("since", options.since);
|
|
if (options.limit) params.set("limit", String(options.limit));
|
|
const suffix = params.size > 0 ? `?${params.toString()}` : "";
|
|
return apiFetch<CampaignDeltaResponse>(settings, `/api/v1/campaigns/delta${suffix}`);
|
|
}
|
|
|
|
export async function listRecipientImportMappingProfiles(settings: ApiSettings): Promise<RecipientImportMappingProfile[]> {
|
|
const response = await apiFetch<RecipientImportMappingProfileListResponse>(settings, "/api/v1/campaigns/recipient-import/mapping-profiles");
|
|
return response.profiles ?? [];
|
|
}
|
|
|
|
export async function createRecipientImportMappingProfile(
|
|
settings: ApiSettings,
|
|
payload: RecipientImportMappingProfilePayload)
|
|
: Promise<RecipientImportMappingProfile> {
|
|
return apiFetch<RecipientImportMappingProfile>(settings, "/api/v1/campaigns/recipient-import/mapping-profiles", {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function updateRecipientImportMappingProfile(
|
|
settings: ApiSettings,
|
|
profileId: string,
|
|
payload: RecipientImportMappingProfilePayload)
|
|
: Promise<RecipientImportMappingProfile> {
|
|
return apiFetch<RecipientImportMappingProfile>(settings, `/api/v1/campaigns/recipient-import/mapping-profiles/${encodeURIComponent(profileId)}`, {
|
|
method: "PUT",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function deleteRecipientImportMappingProfile(settings: ApiSettings, profileId: string): Promise<void> {
|
|
await apiFetch<void>(settings, `/api/v1/campaigns/recipient-import/mapping-profiles/${encodeURIComponent(profileId)}`, { method: "DELETE" });
|
|
}
|
|
|
|
export async function lookupCampaignAddresses(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
query: string,
|
|
limit = 25)
|
|
: Promise<CampaignAddressLookupResponse> {
|
|
const params = new URLSearchParams({ query, limit: String(limit) });
|
|
return apiFetch<CampaignAddressLookupResponse>(settings, `/api/v1/campaigns/${campaignId}/address-lookup?${params.toString()}`);
|
|
}
|
|
|
|
export async function listCampaignRecipientAddressSources(
|
|
settings: ApiSettings,
|
|
campaignId: string)
|
|
: Promise<CampaignRecipientAddressSourcesResponse> {
|
|
return apiFetch<CampaignRecipientAddressSourcesResponse>(settings, `/api/v1/campaigns/${campaignId}/recipient-address-sources`);
|
|
}
|
|
|
|
export async function snapshotCampaignRecipientAddressSource(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
sourceId: string)
|
|
: Promise<CampaignRecipientAddressSourceSnapshot> {
|
|
return apiFetch<CampaignRecipientAddressSourceSnapshot>(settings, `/api/v1/campaigns/${campaignId}/recipient-address-sources/snapshot`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ source_id: sourceId })
|
|
});
|
|
}
|
|
|
|
export async function getCampaign(settings: ApiSettings, campaignId: string): Promise<CampaignListItem> {
|
|
return apiFetch<CampaignListItem>(settings, `/api/v1/campaigns/${campaignId}`);
|
|
}
|
|
|
|
export async function updateCampaignMetadata(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
payload: CampaignUpdatePayload)
|
|
: Promise<CampaignListItem> {
|
|
return apiFetch<CampaignListItem>(settings, `/api/v1/campaigns/${campaignId}`, {
|
|
method: "PUT",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function createNewCampaign(
|
|
settings: ApiSettings,
|
|
overrides: CampaignCreateMinimalPayload = {})
|
|
: Promise<CampaignCreateResponse> {
|
|
const now = new Date();
|
|
const stamp = now.toISOString().slice(0, 19).replace(/[-:T]/g, "");
|
|
const payload = {
|
|
external_id: overrides.external_id ?? `new-campaign-${stamp}`,
|
|
name: overrides.name ?? "i18n:govoplan-campaign.new_campaign.1f0d021c",
|
|
description: overrides.description ?? "",
|
|
current_flow: overrides.current_flow ?? "create",
|
|
current_step: overrides.current_step ?? "basics"
|
|
};
|
|
|
|
return apiFetch<CampaignCreateResponse>(settings, "/api/v1/campaigns/new", {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function getCampaignSchema(settings: ApiSettings): Promise<unknown> {
|
|
return apiFetch(settings, "/api/v1/schemas/campaign");
|
|
}
|
|
|
|
export async function getCampaignSchemaUi(settings: ApiSettings): Promise<unknown> {
|
|
return apiFetch(settings, "/api/v1/schemas/campaign/ui");
|
|
}
|
|
|
|
export async function getCampaignWorkspace(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
options: CampaignWorkspaceQuery = {})
|
|
: Promise<CampaignWorkspaceResponse> {
|
|
const params = new URLSearchParams();
|
|
if (options.versionId) params.set("version_id", options.versionId);
|
|
if (options.includeCurrentVersion !== undefined) params.set("include_current_version", String(options.includeCurrentVersion));
|
|
if (options.includeSummary !== undefined) params.set("include_summary", String(options.includeSummary));
|
|
if (options.includeVersions !== undefined) params.set("include_versions", String(options.includeVersions));
|
|
const suffix = params.size > 0 ? `?${params.toString()}` : "";
|
|
return apiFetch<CampaignWorkspaceResponse>(settings, `/api/v1/campaigns/${campaignId}/workspace${suffix}`);
|
|
}
|
|
|
|
export async function getCampaignWorkspaceDelta(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
options: CampaignWorkspaceQuery = {})
|
|
: Promise<CampaignWorkspaceDeltaResponse> {
|
|
const params = new URLSearchParams();
|
|
if (options.versionId) params.set("version_id", options.versionId);
|
|
if (options.includeCurrentVersion !== undefined) params.set("include_current_version", String(options.includeCurrentVersion));
|
|
if (options.includeSummary !== undefined) params.set("include_summary", String(options.includeSummary));
|
|
if (options.includeVersions !== undefined) params.set("include_versions", String(options.includeVersions));
|
|
if (options.since) params.set("since", options.since);
|
|
if (options.limit) params.set("limit", String(options.limit));
|
|
const suffix = params.size > 0 ? `?${params.toString()}` : "";
|
|
return apiFetch<CampaignWorkspaceDeltaResponse>(settings, `/api/v1/campaigns/${campaignId}/workspace/delta${suffix}`);
|
|
}
|
|
|
|
export async function listCampaignVersions(
|
|
settings: ApiSettings,
|
|
campaignId: string)
|
|
: Promise<CampaignVersionListItem[]> {
|
|
return apiFetch<CampaignVersionListItem[]>(settings, `/api/v1/campaigns/${campaignId}/versions`);
|
|
}
|
|
|
|
export async function getCampaignVersion(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string)
|
|
: Promise<CampaignVersionDetail> {
|
|
return apiFetch<CampaignVersionDetail>(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}`);
|
|
}
|
|
|
|
export async function unlockCampaignVersionValidation(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string)
|
|
: Promise<CampaignVersionDetail> {
|
|
return apiFetch<CampaignVersionDetail>(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/unlock-validation`, {
|
|
method: "POST"
|
|
});
|
|
}
|
|
|
|
export async function lockCampaignVersionTemporarily(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string)
|
|
: Promise<CampaignVersionDetail> {
|
|
return apiFetch<CampaignVersionDetail>(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/lock-temporarily`, {
|
|
method: "POST"
|
|
});
|
|
}
|
|
|
|
export async function unlockCampaignVersionUserLock(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string)
|
|
: Promise<CampaignVersionDetail> {
|
|
return apiFetch<CampaignVersionDetail>(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/unlock-user-lock`, {
|
|
method: "POST"
|
|
});
|
|
}
|
|
|
|
export async function lockCampaignVersionPermanently(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string)
|
|
: Promise<CampaignVersionDetail> {
|
|
return apiFetch<CampaignVersionDetail>(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/lock-permanently`, {
|
|
method: "POST"
|
|
});
|
|
}
|
|
|
|
export async function updateCampaignVersion(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string,
|
|
payload: CampaignVersionUpdatePayload)
|
|
: Promise<CampaignVersionDetail> {
|
|
return apiFetch<CampaignVersionDetail>(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}`, {
|
|
method: "PUT",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function forkCampaignVersion(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string,
|
|
payload: CampaignVersionUpdatePayload = {})
|
|
: Promise<CampaignCreateResponse> {
|
|
return apiFetch<CampaignCreateResponse>(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/fork`, {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function autosaveCampaignVersion(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string,
|
|
payload: CampaignVersionUpdatePayload)
|
|
: Promise<CampaignVersionDetail> {
|
|
return apiFetch<CampaignVersionDetail>(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/autosave`, {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function setCampaignVersionStep(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string,
|
|
currentStep: string,
|
|
currentFlow?: string | null)
|
|
: Promise<CampaignVersionDetail> {
|
|
return apiFetch<CampaignVersionDetail>(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/set-step`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ current_flow: currentFlow, current_step: currentStep })
|
|
});
|
|
}
|
|
|
|
export async function validatePartial(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string,
|
|
payload: CampaignPartialValidationPayload = {})
|
|
: Promise<CampaignPartialValidationResponse> {
|
|
return apiFetch<CampaignPartialValidationResponse>(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/validate-partial`, {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function publishCampaignVersion(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string)
|
|
: Promise<CampaignVersionDetail> {
|
|
return apiFetch<CampaignVersionDetail>(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/publish`, {
|
|
method: "POST"
|
|
});
|
|
}
|
|
|
|
export async function validateVersion(
|
|
settings: ApiSettings,
|
|
versionId: string,
|
|
checkFiles = false,
|
|
linkUnsharedMatches = false)
|
|
: Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/versions/${versionId}/validate`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ check_files: checkFiles, link_unshared_matches: linkUnsharedMatches })
|
|
});
|
|
}
|
|
|
|
export async function buildVersion(
|
|
settings: ApiSettings,
|
|
versionId: string,
|
|
writeEml = true)
|
|
: Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/versions/${versionId}/build`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ write_eml: writeEml })
|
|
});
|
|
}
|
|
|
|
|
|
export function previewCampaignAttachments(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string,
|
|
payload: CampaignAttachmentPreviewPayload = {})
|
|
: Promise<CampaignAttachmentPreviewResponse> {
|
|
return apiFetch<CampaignAttachmentPreviewResponse>(
|
|
settings,
|
|
`/api/v1/campaigns/${campaignId}/versions/${versionId}/attachments/preview`,
|
|
{ method: "POST", body: JSON.stringify(payload) }
|
|
);
|
|
}
|
|
|
|
export function linkCampaignAttachmentMatches(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string,
|
|
payload: CampaignAttachmentLinkMatchesPayload = {})
|
|
: Promise<CampaignAttachmentLinkMatchesResponse> {
|
|
return apiFetch<CampaignAttachmentLinkMatchesResponse>(
|
|
settings,
|
|
`/api/v1/campaigns/${campaignId}/versions/${versionId}/attachments/link-matches`,
|
|
{ method: "POST", body: JSON.stringify(payload) }
|
|
);
|
|
}
|
|
|
|
export async function getCampaignSummary(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId?: string)
|
|
: Promise<CampaignSummary> {
|
|
const suffix = versionId ? `?version_id=${encodeURIComponent(versionId)}` : "";
|
|
return apiFetch<CampaignSummary>(settings, `/api/v1/campaigns/${campaignId}/summary${suffix}`);
|
|
}
|
|
|
|
export async function getCampaignJobs(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
options: CampaignJobsQuery = {})
|
|
: Promise<CampaignJobsResponse> {
|
|
const params = campaignJobsQueryParams(options);
|
|
const suffix = params.size > 0 ? `?${params.toString()}` : "";
|
|
return apiFetch<CampaignJobsResponse>(settings, `/api/v1/campaigns/${campaignId}/jobs${suffix}`);
|
|
}
|
|
|
|
export async function getCampaignJobsDelta(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
options: CampaignJobsQuery & {since?: string | null;limit?: number;} = {})
|
|
: Promise<CampaignJobsDeltaResponse> {
|
|
const params = campaignJobsQueryParams(options);
|
|
const suffix = params.size > 0 ? `?${params.toString()}` : "";
|
|
return apiFetch<CampaignJobsDeltaResponse>(settings, `/api/v1/campaigns/${campaignId}/jobs/delta${suffix}`);
|
|
}
|
|
|
|
export async function getCampaignJobDetail(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
jobId: string)
|
|
: Promise<CampaignJobDetailResponse> {
|
|
return apiFetch<CampaignJobDetailResponse>(settings, `/api/v1/campaigns/${campaignId}/jobs/${jobId}`);
|
|
}
|
|
|
|
export async function getCampaignReport(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId?: string)
|
|
: Promise<CampaignSummary> {
|
|
const params = new URLSearchParams({ include_jobs: "false" });
|
|
if (versionId) params.set("version_id", versionId);
|
|
return apiFetch<CampaignSummary>(settings, `/api/v1/campaigns/${campaignId}/report?${params.toString()}`);
|
|
}
|
|
|
|
export async function downloadCampaignJobsCsv(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId?: string)
|
|
: Promise<void> {
|
|
const suffix = versionId ? `?version_id=${encodeURIComponent(versionId)}` : "";
|
|
await apiDownload(
|
|
settings,
|
|
`/api/v1/campaigns/${campaignId}/report/jobs.csv${suffix}`,
|
|
`campaign-${campaignId}${versionId ? `-${versionId}` : ""}-jobs.csv`
|
|
);
|
|
}
|
|
|
|
export async function emailCampaignReport(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
payload: CampaignReportEmailPayload)
|
|
: Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/${campaignId}/report/email`, {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function retryCampaignJobs(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
payload: Record<string, unknown> = {})
|
|
: Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/${campaignId}/jobs/retry`, {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function sendUnattemptedCampaignJobs(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
payload: Record<string, unknown> = {})
|
|
: Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/${campaignId}/jobs/send-unattempted`, {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function sendCampaignJob(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
jobId: string,
|
|
payload: CampaignSendJobPayload = {})
|
|
: Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/${campaignId}/jobs/${jobId}/send`, {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function resolveCampaignJobOutcome(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
jobId: string,
|
|
decision: "smtp_accepted" | "not_sent" | "imap_appended" | "imap_not_appended",
|
|
note?: string)
|
|
: Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/${campaignId}/jobs/${jobId}/resolve-outcome`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ decision, note: note || null })
|
|
});
|
|
}
|
|
|
|
export async function updateCampaignReviewState(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId: string,
|
|
payload: CampaignReviewStatePayload)
|
|
: Promise<CampaignVersionDetail> {
|
|
return apiFetch<CampaignVersionDetail>(settings, `/api/v1/campaigns/${campaignId}/versions/${versionId}/review-state`, {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function queueCampaign(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
payload: CampaignQueuePayload = {})
|
|
: Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/${campaignId}/queue`, {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function getCampaignDeliveryOptions(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
versionId?: string | null)
|
|
: Promise<CampaignDeliveryOptions> {
|
|
const query = versionId ? `?version_id=${encodeURIComponent(versionId)}` : "";
|
|
return apiFetch<CampaignDeliveryOptions>(settings, `/api/v1/campaigns/${campaignId}/delivery-options${query}`);
|
|
}
|
|
|
|
export async function sendCampaignNow(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
payload: CampaignSendNowPayload = {})
|
|
: Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/${campaignId}/send-now`, {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
|
|
export async function mockSendCampaign(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
payload: CampaignMockSendPayload = {})
|
|
: Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/${campaignId}/mock-send`, {
|
|
method: "POST",
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function pauseCampaign(settings: ApiSettings, campaignId: string): Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/${campaignId}/pause`, { method: "POST" });
|
|
}
|
|
|
|
export async function resumeCampaign(settings: ApiSettings, campaignId: string): Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/${campaignId}/resume`, { method: "POST" });
|
|
}
|
|
|
|
export async function cancelCampaign(settings: ApiSettings, campaignId: string): Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/${campaignId}/cancel`, { method: "POST" });
|
|
}
|
|
|
|
export async function appendSent(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
payload: CampaignAppendSentPayload = {})
|
|
: Promise<Record<string, unknown>> {
|
|
return apiFetch<Record<string, unknown>>(settings, `/api/v1/campaigns/${campaignId}/append-sent`, {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
dry_run: payload.dry_run ?? false,
|
|
enqueue_celery: payload.enqueue_celery ?? true,
|
|
run_inline: payload.run_inline ?? false
|
|
})
|
|
});
|
|
}
|
|
|
|
export async function getCampaignShareTargets(settings: ApiSettings, campaignId: string): Promise<CampaignShareTargets> {
|
|
return apiFetch<CampaignShareTargets>(settings, `/api/v1/campaigns/${campaignId}/share-targets`);
|
|
}
|
|
|
|
export async function getCampaignShares(settings: ApiSettings, campaignId: string): Promise<CampaignShare[]> {
|
|
const response = await apiFetch<{shares: CampaignShare[];}>(settings, `/api/v1/campaigns/${campaignId}/shares`);
|
|
return response.shares;
|
|
}
|
|
|
|
export async function updateCampaignOwner(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
payload: {owner_user_id?: string | null;owner_group_id?: string | null;})
|
|
: Promise<CampaignListItem> {
|
|
return apiFetch<CampaignListItem>(settings, `/api/v1/campaigns/${campaignId}/owner`, { method: "PUT", body: JSON.stringify(payload) });
|
|
}
|
|
|
|
export async function upsertCampaignShare(
|
|
settings: ApiSettings,
|
|
campaignId: string,
|
|
payload: {target_type: "user" | "group";target_id: string;permission: "read" | "write";})
|
|
: Promise<CampaignShare> {
|
|
return apiFetch<CampaignShare>(settings, `/api/v1/campaigns/${campaignId}/shares`, { method: "POST", body: JSON.stringify(payload) });
|
|
}
|
|
|
|
export async function revokeCampaignShare(settings: ApiSettings, campaignId: string, shareId: string): Promise<void> {
|
|
await apiFetch<void>(settings, `/api/v1/campaigns/${campaignId}/shares/${shareId}`, { method: "DELETE" });
|
|
}
|