4cecoder / pay2post

fullstack app with paywall that you have to pay to make a single post so it better be important!
MIT License
1 stars 0 forks source link

Implement Payment Before Posting is Allowed (Stripe Payment Processing) #3

Closed 4cecoder closed 3 months ago

4cecoder commented 3 months ago

Description

Implement a payment processing system using Stripe to ensure users must pay before they can create a post. This feature will enforce the paywall functionality of the "pay2post" app, ensuring that all posts are paid for before being published.

Steps

  1. Set Up Stripe Account

    • Create a Stripe account and obtain API keys.
    • Add the Stripe keys to your environment variables or configuration file.
  2. Install Stripe Package

    • Install the Stripe package for Go:
      go get github.com/stripe/stripe-go/v72
  3. Update Database Model

    • Add a Paid field to the Post model to track payment status:
      type Post struct {
       gorm.Model
       UserID  uint
       Content string
       Paid    bool
      }
  4. Create Payment Endpoint

    • Add an endpoint to handle payment processing with Stripe:

      func paymentHandler(c *gin.Context) {
       var input struct {
           Token string `json:"token"`
           PostID uint  `json:"post_id"`
       }
      
       if err := c.ShouldBindJSON(&input); err != nil {
           c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
           return
       }
      
       // Set your secret key. Remember to switch to your live secret key in production!
       // See your keys here: https://dashboard.stripe.com/apikeys
       stripe.Key = "sk_test_YOUR_SECRET_KEY"
      
       params := &stripe.ChargeParams{
           Amount:   stripe.Int64(500), // Amount in cents
           Currency: stripe.String(string(stripe.CurrencyUSD)),
           Description: stripe.String("Pay2Post charge"),
       }
       params.SetSource(input.Token)
      
       _, err := charge.New(params)
      
       if err != nil {
           c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
           return
       }
      
       // Mark the post as paid
       var post models.Post
       if err := db.First(&post, input.PostID).Error; err != nil {
           c.JSON(http.StatusNotFound, gin.H{"error": "Post not found"})
           return
       }
      
       post.Paid = true
       db.Save(&post)
      
       c.JSON(http.StatusOK, gin.H{"message": "Payment successful and post updated"})
      }
  5. Update Post Creation Logic

    • Ensure that posts can only be created if they are paid for:

      func createPost(c *gin.Context) {
       var post models.Post
       if err := c.ShouldBindJSON(&post); err != nil {
           c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
           return
       }
      
       post.Paid = false // Initially set as unpaid
      
       db.Create(&post)
       c.JSON(http.StatusOK, post)
      }
  6. Frontend Integration with HTMX

    • Update the frontend to include payment processing with Stripe before submitting a post:

      <!-- templates/post.html -->
      <!DOCTYPE html>
      <html>
      <head>
       <title>Create Post</title>
       <script src="https://js.stripe.com/v3/"></script>
       <script src="https://unpkg.com/htmx.org@1.3.3"></script>
      </head>
      <body>
       <h1>Create a Post</h1>
       <form id="post-form" hx-post="/posts" hx-trigger="submit" hx-target="#message" onsubmit="handlePayment(event)">
           <textarea name="content" placeholder="Your post content..."></textarea>
           <button type="submit">Create Post</button>
       </form>
       <div id="message"></div>
      
       <script>
           function handlePayment(event) {
               event.preventDefault();
               var stripe = Stripe('pk_test_YOUR_PUBLIC_KEY');
      
               stripe.createToken('bank_account').then(function(result) {
                   if (result.error) {
                       // Inform the user if there was an error
                       var errorElement = document.getElementById('message');
                       errorElement.textContent = result.error.message;
                   } else {
                       // Send the token to your server
                       fetch('/pay', {
                           method: 'POST',
                           headers: {
                               'Content-Type': 'application/json'
                           },
                           body: JSON.stringify({
                               token: result.token.id,
                               post_id: postID // Replace with the actual post ID
                           })
                       }).then(function(response) {
                           return response.json();
                       }).then(function(data) {
                           var messageElement = document.getElementById('message');
                           if (data.error) {
                               messageElement.textContent = data.error;
                           } else {
                               messageElement.textContent = 'Payment successful and post updated';
                           }
                       });
                   }
               });
           }
       </script>
      </body>
      </html>

This issue covers the implementation of payment processing using Stripe to enforce the paywall functionality before a user can create a post. It includes setting up the Stripe account, creating necessary endpoints, updating the post creation logic, and integrating the frontend with HTMX for seamless user experience.