Skip to content

Commit 7428a1f

Browse files
authored
feat: add contactBooks to sdk, add delete campaign public endpoint (#352)
* feat: add contactBooks to sdk, add delete campaign public endpoint * fix: pr review notes * refactor: pr feedback * feat: bulk delete/create contacts * refactor: rename a few methods for consistency * refactor: update openapi docs based on pr feedback * refactor: update open api docs, based on pr feedback * fix: delete campaign security issue * refactor: delete campaign requires team id (from context) * fix: enums
1 parent 73416dc commit 7428a1f

22 files changed

Lines changed: 1365 additions & 218 deletions
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
openapi: delete /v1/campaigns/{campaignId}
3+
---
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
openapi: post /v1/contactBooks/{contactBookId}/contacts/bulk
3+
---
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
openapi: delete /v1/contactBooks/{contactBookId}/contacts/bulk
3+
---

apps/docs/api-reference/openapi.json

Lines changed: 251 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,6 +1585,163 @@
15851585
}
15861586
}
15871587
},
1588+
"/v1/contactBooks/{contactBookId}/contacts/bulk": {
1589+
"delete": {
1590+
"parameters": [
1591+
{
1592+
"schema": {
1593+
"type": "string",
1594+
"minLength": 3,
1595+
"example": "cuiwqdj74rygf74"
1596+
},
1597+
"required": true,
1598+
"name": "contactBookId",
1599+
"in": "path"
1600+
}
1601+
],
1602+
"requestBody": {
1603+
"required": true,
1604+
"content": {
1605+
"application/json": {
1606+
"schema": {
1607+
"type": "object",
1608+
"properties": {
1609+
"contactIds": {
1610+
"type": "array",
1611+
"items": { "type": "string" },
1612+
"minItems": 1,
1613+
"maxItems": 1000
1614+
}
1615+
},
1616+
"required": ["contactIds"]
1617+
}
1618+
}
1619+
}
1620+
},
1621+
"responses": {
1622+
"200": {
1623+
"description": "Bulk delete contacts from a contact book",
1624+
"content": {
1625+
"application/json": {
1626+
"schema": {
1627+
"type": "object",
1628+
"properties": {
1629+
"success": { "type": "boolean" },
1630+
"count": { "type": "number" }
1631+
},
1632+
"required": ["success", "count"]
1633+
}
1634+
}
1635+
}
1636+
},
1637+
"403": {
1638+
"description": "Forbidden - API key doesn't have access",
1639+
"content": {
1640+
"application/json": {
1641+
"schema": {
1642+
"type": "object",
1643+
"properties": { "error": { "type": "string" } },
1644+
"required": ["error"]
1645+
}
1646+
}
1647+
}
1648+
},
1649+
"404": {
1650+
"description": "Contact book not found",
1651+
"content": {
1652+
"application/json": {
1653+
"schema": {
1654+
"type": "object",
1655+
"properties": { "error": { "type": "string" } },
1656+
"required": ["error"]
1657+
}
1658+
}
1659+
}
1660+
}
1661+
}
1662+
},
1663+
"post": {
1664+
"parameters": [
1665+
{
1666+
"schema": {
1667+
"type": "string",
1668+
"minLength": 3,
1669+
"example": "cuiwqdj74rygf74"
1670+
},
1671+
"required": true,
1672+
"name": "contactBookId",
1673+
"in": "path"
1674+
}
1675+
],
1676+
"requestBody": {
1677+
"required": true,
1678+
"content": {
1679+
"application/json": {
1680+
"schema": {
1681+
"type": "array",
1682+
"items": {
1683+
"type": "object",
1684+
"properties": {
1685+
"email": { "type": "string" },
1686+
"firstName": { "type": "string" },
1687+
"lastName": { "type": "string" },
1688+
"properties": {
1689+
"type": "object",
1690+
"additionalProperties": { "type": "string" }
1691+
},
1692+
"subscribed": { "type": "boolean" }
1693+
},
1694+
"required": ["email"]
1695+
},
1696+
"minItems": 1,
1697+
"maxItems": 1000
1698+
}
1699+
}
1700+
}
1701+
},
1702+
"responses": {
1703+
"200": {
1704+
"description": "Bulk add contacts to a contact book",
1705+
"content": {
1706+
"application/json": {
1707+
"schema": {
1708+
"type": "object",
1709+
"properties": {
1710+
"message": { "type": "string" },
1711+
"count": { "type": "number" }
1712+
},
1713+
"required": ["message", "count"]
1714+
}
1715+
}
1716+
}
1717+
},
1718+
"403": {
1719+
"description": "Forbidden - API key doesn't have access",
1720+
"content": {
1721+
"application/json": {
1722+
"schema": {
1723+
"type": "object",
1724+
"properties": { "error": { "type": "string" } },
1725+
"required": ["error"]
1726+
}
1727+
}
1728+
}
1729+
},
1730+
"404": {
1731+
"description": "Contact book not found",
1732+
"content": {
1733+
"application/json": {
1734+
"schema": {
1735+
"type": "object",
1736+
"properties": { "error": { "type": "string" } },
1737+
"required": ["error"]
1738+
}
1739+
}
1740+
}
1741+
}
1742+
}
1743+
}
1744+
},
15881745
"/v1/contactBooks/{contactBookId}/contacts/{contactId}": {
15891746
"patch": {
15901747
"parameters": [
@@ -1790,10 +1947,9 @@
17901947
"enum": [
17911948
"DRAFT",
17921949
"SCHEDULED",
1793-
"IN_PROGRESS",
1950+
"RUNNING",
17941951
"PAUSED",
1795-
"COMPLETED",
1796-
"CANCELLED"
1952+
"SENT"
17971953
],
17981954
"example": "DRAFT"
17991955
},
@@ -1829,7 +1985,7 @@
18291985
"subject": { "type": "string" },
18301986
"createdAt": { "type": "string", "format": "date-time" },
18311987
"updatedAt": { "type": "string", "format": "date-time" },
1832-
"status": { "type": "string" },
1988+
"status": { "type": "string", "enum": ["DRAFT", "SCHEDULED", "RUNNING", "PAUSED", "SENT"] },
18331989
"scheduledAt": { "type": "string", "nullable": true, "format": "date-time" },
18341990
"total": { "type": "integer" },
18351991
"sent": { "type": "integer" },
@@ -1935,7 +2091,7 @@
19352091
"contactBookId": { "type": "string", "nullable": true },
19362092
"html": { "type": "string", "nullable": true },
19372093
"content": { "type": "string", "nullable": true },
1938-
"status": { "type": "string" },
2094+
"status": { "type": "string", "enum": ["DRAFT", "SCHEDULED", "RUNNING", "PAUSED", "SENT"] },
19392095
"scheduledAt": {
19402096
"type": "string",
19412097
"nullable": true,
@@ -1997,19 +2153,19 @@
19972153
}
19982154
},
19992155
"/v1/campaigns/{campaignId}": {
2156+
"parameters": [
2157+
{
2158+
"schema": {
2159+
"type": "string",
2160+
"minLength": 1,
2161+
"example": "cmp_123"
2162+
},
2163+
"required": true,
2164+
"name": "campaignId",
2165+
"in": "path"
2166+
}
2167+
],
20002168
"get": {
2001-
"parameters": [
2002-
{
2003-
"schema": {
2004-
"type": "string",
2005-
"minLength": 1,
2006-
"example": "cmp_123"
2007-
},
2008-
"required": true,
2009-
"name": "campaignId",
2010-
"in": "path"
2011-
}
2012-
],
20132169
"responses": {
20142170
"200": {
20152171
"description": "Get campaign details",
@@ -2026,7 +2182,84 @@
20262182
"contactBookId": { "type": "string", "nullable": true },
20272183
"html": { "type": "string", "nullable": true },
20282184
"content": { "type": "string", "nullable": true },
2029-
"status": { "type": "string" },
2185+
"status": { "type": "string", "enum": ["DRAFT", "SCHEDULED", "RUNNING", "PAUSED", "SENT"] },
2186+
"scheduledAt": {
2187+
"type": "string",
2188+
"nullable": true,
2189+
"format": "date-time"
2190+
},
2191+
"batchSize": { "type": "integer" },
2192+
"batchWindowMinutes": { "type": "integer" },
2193+
"total": { "type": "integer" },
2194+
"sent": { "type": "integer" },
2195+
"delivered": { "type": "integer" },
2196+
"opened": { "type": "integer" },
2197+
"clicked": { "type": "integer" },
2198+
"unsubscribed": { "type": "integer" },
2199+
"bounced": { "type": "integer" },
2200+
"hardBounced": { "type": "integer" },
2201+
"complained": { "type": "integer" },
2202+
"replyTo": {
2203+
"type": "array",
2204+
"items": { "type": "string" }
2205+
},
2206+
"cc": { "type": "array", "items": { "type": "string" } },
2207+
"bcc": { "type": "array", "items": { "type": "string" } },
2208+
"createdAt": { "type": "string", "format": "date-time" },
2209+
"updatedAt": { "type": "string", "format": "date-time" }
2210+
},
2211+
"required": [
2212+
"id",
2213+
"name",
2214+
"from",
2215+
"subject",
2216+
"previewText",
2217+
"contactBookId",
2218+
"html",
2219+
"content",
2220+
"status",
2221+
"scheduledAt",
2222+
"batchSize",
2223+
"batchWindowMinutes",
2224+
"total",
2225+
"sent",
2226+
"delivered",
2227+
"opened",
2228+
"clicked",
2229+
"unsubscribed",
2230+
"bounced",
2231+
"hardBounced",
2232+
"complained",
2233+
"replyTo",
2234+
"cc",
2235+
"bcc",
2236+
"createdAt",
2237+
"updatedAt"
2238+
]
2239+
}
2240+
}
2241+
}
2242+
}
2243+
}
2244+
},
2245+
"delete": {
2246+
"responses": {
2247+
"200": {
2248+
"description": "Delete campaign",
2249+
"content": {
2250+
"application/json": {
2251+
"schema": {
2252+
"type": "object",
2253+
"properties": {
2254+
"id": { "type": "string" },
2255+
"name": { "type": "string" },
2256+
"from": { "type": "string" },
2257+
"subject": { "type": "string" },
2258+
"previewText": { "type": "string", "nullable": true },
2259+
"contactBookId": { "type": "string", "nullable": true },
2260+
"html": { "type": "string", "nullable": true },
2261+
"content": { "type": "string", "nullable": true },
2262+
"status": { "type": "string", "enum": ["DRAFT", "SCHEDULED", "RUNNING", "PAUSED", "SENT"] },
20302263
"scheduledAt": {
20312264
"type": "string",
20322265
"nullable": true,

apps/docs/docs.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,11 @@
7777
"api-reference/contacts/get-contact",
7878
"api-reference/contacts/get-contacts",
7979
"api-reference/contacts/create-contact",
80+
"api-reference/contacts/bulk-create-contact",
8081
"api-reference/contacts/update-contact",
8182
"api-reference/contacts/upsert-contact",
82-
"api-reference/contacts/delete-contact"
83+
"api-reference/contacts/delete-contact",
84+
"api-reference/contacts/bulk-delete-contacts"
8385
]
8486
},
8587
{
@@ -100,7 +102,8 @@
100102
"api-reference/campaigns/get-campaign",
101103
"api-reference/campaigns/schedule-campaign",
102104
"api-reference/campaigns/pause-campaign",
103-
"api-reference/campaigns/resume-campaign"
105+
"api-reference/campaigns/resume-campaign",
106+
"api-reference/campaigns/delete-campaign"
104107
]
105108
}
106109
]

apps/web/src/server/api/routers/campaign.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ export const campaignRouter = createTRPCRouter({
171171
return campaign;
172172
}),
173173

174-
deleteCampaign: campaignProcedure.mutation(async ({ input }) => {
175-
return await campaignService.deleteCampaign(input.campaignId);
174+
deleteCampaign: campaignProcedure.mutation(async ({ ctx: { team }, input }) => {
175+
return await campaignService.deleteCampaign(input.campaignId, team.id);
176176
}),
177177

178178
getCampaign: campaignProcedure.query(async ({ ctx: { db, team }, input }) => {

0 commit comments

Comments
 (0)