@stacksjs/defaults 0.74.1 → 0.74.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/Actions/Dashboard/Marketing/AbandonedCartCampaignAction.ts +51 -0
- package/app/Actions/Dashboard/Marketing/AbandonedCartIndexAction.ts +85 -0
- package/app/Actions/Dashboard/Marketing/abandoned-cart-records.test.ts +316 -0
- package/app/Actions/Dashboard/Marketing/abandoned-cart-records.ts +429 -0
- package/app/Models/AnalyticsEvent.ts +5 -0
- package/app/Models/Content/Menu.ts +5 -1
- package/app/Models/Content/MenuItem.ts +6 -1
- package/app/Models/Content/Page.ts +5 -1
- package/app/Models/Content/Post.ts +5 -1
- package/app/Models/Content/Redirect.ts +5 -1
- package/app/Models/EmailIdempotency.ts +5 -0
- package/app/Models/EmailList.ts +6 -0
- package/app/Models/EmailSuppression.ts +5 -0
- package/app/Models/EmailWebhookEvent.ts +5 -0
- package/app/Models/Forms/Form.ts +5 -1
- package/app/Models/Forms/FormField.ts +6 -1
- package/app/Models/MailPreference.ts +5 -0
- package/app/Models/Request.ts +5 -0
- package/app/Models/SiteDomain.ts +5 -1
- package/app/Models/Tag.ts +6 -0
- package/app/Models/Team.ts +6 -1
- package/app/Models/User.ts +6 -1
- package/app/Models/commerce/Auction.ts +6 -0
- package/app/Models/commerce/AuctionItem.ts +6 -0
- package/app/Models/commerce/Cart.ts +6 -1
- package/app/Models/commerce/CartItem.ts +6 -1
- package/app/Models/commerce/Category.ts +6 -0
- package/app/Models/commerce/Coupon.ts +6 -0
- package/app/Models/commerce/DeliveryRoute.ts +6 -1
- package/app/Models/commerce/DeliveryStop.ts +6 -1
- package/app/Models/commerce/GiftCard.ts +6 -1
- package/app/Models/commerce/LicenseKey.ts +6 -1
- package/app/Models/commerce/LoyaltyReward.ts +6 -0
- package/app/Models/commerce/Manufacturer.ts +6 -0
- package/app/Models/commerce/Order.ts +6 -1
- package/app/Models/commerce/Payment.ts +6 -1
- package/app/Models/commerce/PrintDevice.ts +6 -0
- package/app/Models/commerce/Product.ts +6 -0
- package/app/Models/commerce/ProductUnit.ts +6 -0
- package/app/Models/commerce/ProductVariant.ts +6 -0
- package/app/Models/commerce/Review.ts +6 -1
- package/app/Models/commerce/ShippingMethod.ts +6 -0
- package/app/Models/commerce/ShippingRate.ts +6 -0
- package/app/Models/commerce/ShippingZone.ts +6 -0
- package/app/Models/commerce/TaxRate.ts +6 -0
- package/app/Models/commerce/Transaction.ts +6 -1
- package/app/Models/commerce/WaitlistProduct.ts +6 -1
- package/app/Models/commerce/WaitlistRestaurant.ts +6 -1
- package/app/Models/realtime/Websocket.ts +5 -0
- package/ide/vscode/package.json +1 -1
- package/package.json +2 -2
- package/project/storage/framework/tsconfig.app.json +4 -1
- package/resources/components/Dashboard/Marketing/AbandonedCartsDashboard.stx +240 -0
- package/resources/components/Dashboard/Marketing/AbandonedCartsTable.stx +96 -0
- package/resources/components/Dashboard/Marketing/RecoveryCampaignDialog.stx +145 -0
- package/resources/functions/dashboard/sidebar.ts +1 -0
- package/resources/views/cms/blocks/form.stx +92 -1
- package/routes/dashboard-api.ts +5 -0
- package/routes/forms.ts +46 -0
- package/views/dashboard/marketing/abandoned-carts/index.stx +10 -0
package/routes/forms.ts
CHANGED
|
@@ -35,6 +35,52 @@ route.get('/api/forms/{uuid}', async (request: any) => {
|
|
|
35
35
|
return response.json(publicDefinition(form))
|
|
36
36
|
}).rateLimit(60, 'minute')
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* File uploads for a form's `file` fields.
|
|
40
|
+
*
|
|
41
|
+
* Proxied through the server rather than presigned, because this is where the
|
|
42
|
+
* ceilings in `config/forms.ts` can actually be applied: a presigned policy can
|
|
43
|
+
* express a size cap but not a real type check (S3 sees only the Content-Type
|
|
44
|
+
* the client declared), and a proxied upload works on a local disk too. A
|
|
45
|
+
* public form is not a bulk-upload surface. stacksjs/stacks#2406.
|
|
46
|
+
*
|
|
47
|
+
* The stored path is returned for the submit step, which checks it sits under
|
|
48
|
+
* this form's prefix before accepting it.
|
|
49
|
+
*/
|
|
50
|
+
route.post('/api/forms/{uuid}/uploads', async (request: any) => {
|
|
51
|
+
const { checkUpload, fileFieldNamed, formUploadPrefix, loadFormByUuid, resolveUploadLimits } = await import('@stacksjs/forms')
|
|
52
|
+
|
|
53
|
+
const form = await loadFormByUuid(String(request.params?.uuid ?? request.param?.('uuid') ?? ''), await siteIdForRequest(request))
|
|
54
|
+
if (!form || form.status === 'draft')
|
|
55
|
+
return response.notFound('Form not found')
|
|
56
|
+
|
|
57
|
+
// Same gate the submit endpoint applies: a closed form does not take files
|
|
58
|
+
// either, and accepting them would leave orphans nothing ever references.
|
|
59
|
+
if (form.status !== 'active')
|
|
60
|
+
return response.json({ message: 'This form is not accepting responses.' }, { status: 409 })
|
|
61
|
+
|
|
62
|
+
const field = fileFieldNamed(form, request.get?.('field') ?? request.input?.('field'))
|
|
63
|
+
if (!field)
|
|
64
|
+
return response.json({ message: 'Unknown upload field.' }, { status: 422 })
|
|
65
|
+
|
|
66
|
+
const file = request.file?.('file')
|
|
67
|
+
if (!file)
|
|
68
|
+
return response.json({ message: `${field.label} is required.` }, { status: 422 })
|
|
69
|
+
|
|
70
|
+
const limits = resolveUploadLimits(field)
|
|
71
|
+
const rejection = checkUpload(field, { name: file.name, size: file.size }, limits)
|
|
72
|
+
if (rejection)
|
|
73
|
+
return response.json({ message: rejection.message }, { status: rejection.status })
|
|
74
|
+
|
|
75
|
+
const { Storage } = await import('@stacksjs/storage')
|
|
76
|
+
const stored = await Storage.put(file, {
|
|
77
|
+
...(limits.disk ? { disk: limits.disk } : {}),
|
|
78
|
+
dir: formUploadPrefix(form),
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
return response.json({ path: stored.path }, { status: 201 })
|
|
82
|
+
}).rateLimit(20, 'minute')
|
|
83
|
+
|
|
38
84
|
route.post('/api/forms/{uuid}/submissions', async (request: any) => {
|
|
39
85
|
const { dispatchSubmissionNotifications, loadFormByUuid, submitForm } = await import('@stacksjs/forms')
|
|
40
86
|
|