stevekrouse avatar
stevekrouse
docFeedbackForm
HTTP
Val Town Docs Feedback Form & Handler Live form Val Town Docs YouTube tutorial that explains v17 of this val This feedback form was linked on our docs site. This val renders an HTML form, including pre-fills the user's email address if they've submitted the form in the past (via a cookie), and pre-fills the URL by grabbing it out of the query params. It handles form submissions, including parsing the form, saving the data into @stevekrouse.docsFeedback , a private JSON val, and then returns a thank you message, and set's the user's email address as a cookie, to save them some keystrokes the next time they fill out the form. Another val, @stevekrouse.formFeedbackAlert , polls on an interval for new form submissions, and if it finds any, forwards them on a private Val Town discord channel. There are a number of subtleties to the way each of some features are implemented. A user submitted three pieces of feedback in quick succession, so I thought it'd be nice if we remembered user's email addresses after their first form submissions. There are classically two ways to do this, cookies or localstorage. I choose cookies. It requires setting them in the response header and getting them out of the request header. I used a Deno library to parse the cookie but I set it manually because that seemed simpler. You may be wondering about how I'm getting the referrer out of the query params instead of from the HTTP Referrer header. I tried that at first, but it's increasingly difficult to get path data from it due to more restrictive security policies . So instead I decided to include the URL data in a query param. I get it there via this script in my blog's site: function updateFeedback(ref) { let feedback = [...document.getElementsByTagName('a')].find(e => e.innerText == 'Feedback') feedback.setAttribute('href', "https://stevekrouse-docfeedbackform.web.val.run/?ref=" + ref) } setTimeout(() => updateFeedback(document.location.href), 100); navigation.addEventListener('navigate', e => updateFeedback(e.destination.url)); Finally, you may be wondering why I queue up feedback in @stevekrouse.docsFeedback , a private JSON val, and then process it via @stevekrouse.formFeedbackAlert instead of sending it along to Discord directly in this val. I tried that originally but it felt too slow to wait for the API call to Discord before returning the "Thanks for your feedback" message. This is where the context.waitUntil method (that Cloudflare workers and Vercel Edge Functions support) would really come in handy – those allow you to return a Response, and then continue to compute. Currently Val Town requires you to stop all compute with the returning of your Response, so the only way to compute afterwards is to queue it up for another val to take over, and that's what I'm doing here.
Forked from stevekrouse/form
1
stevekrouse avatar
stevekrouse
newThankYouEmailVersion
HTTP
New Stripe Subscription Handler This val handles new subscribers on Stripe: Verifies the signature to make sure it's really from Stripe Filters out only newly created subscriptions Sends a message to our internal Discord channel Sends a thank you to the new subscriber Setup Fork this HTTP val Create a new webhook in Stripe Add your val's HTTP endpoint URL into the Stripe webhook Select customer.subscription.updated as the only event to listen to (more on this below) Add your stripe_sk_customer_readonly to your Val Town Env Variables Add your webhook's signing secret as STRIPE_WEBHOOK_SECRET to you Val Town Env Variables Which Stripe event type to listen to Stripe sends webhooks for many different kinds of events. Relevant for us here are: customer.subscription.created (what we used to listen for) customer.subscription.updated (what we're currently listening for) The issue with customer.subscription.created is that it triggers too early, before the user's payment actually goes through. This is a problem because in early Nov 2024 we started getting credit card fraudsters testing cards using our service. We started getting lots of notifications for new subscriptions that never actually became active. Note: if anyone knows good ways to prevent that sort of behavior at the root, please let me know by commenting on this val! In order to only get notified on a valid subscription, we now subscribe to customer.subscription.updated . This event happens on any subscription change, including renewals and cancellations, so now we have to filter those events to only get new subscriptions, ie where: event.data.previous_attributes.status === 'incomplete' && event.data.object.status === 'active'
Forked from stevekrouse/newStripeSubscriber
1
Next
Updated: October 23, 2023