parent
28a2c991a2
commit
a8a9141ede
@ -1,13 +0,0 @@ |
||||
package features_fakepay |
||||
|
||||
import ( |
||||
"github.com/gofiber/fiber/v2" |
||||
) |
||||
|
||||
func PostApiPay(c *fiber.Ctx) error { |
||||
return c.Redirect("/fakepay/complete") |
||||
} |
||||
|
||||
func SetupApi(app *fiber.App) { |
||||
app.Post("/api/fakepay/pay", PostApiPay) |
||||
} |
||||
@ -1,9 +0,0 @@ |
||||
package features_fakepay |
||||
|
||||
import ( |
||||
// "MY/webapp/data"
|
||||
// _ "github.com/mattn/go-sqlite3"
|
||||
// sq "github.com/Masterminds/squirrel"
|
||||
) |
||||
|
||||
|
||||
@ -1,10 +0,0 @@ |
||||
package features_fakepay |
||||
|
||||
import ( |
||||
"github.com/gofiber/fiber/v2" |
||||
) |
||||
|
||||
func Setup(app *fiber.App) { |
||||
SetupApi(app) |
||||
SetupViews(app) |
||||
} |
||||
@ -1,11 +0,0 @@ |
||||
package features_fakepay |
||||
|
||||
import ( |
||||
"github.com/gofiber/fiber/v2" |
||||
. "MY/webapp/common" |
||||
) |
||||
|
||||
func SetupViews(app *fiber.App) { |
||||
err := ConfigViews(app, "views/fakepay") |
||||
if err != nil { panic(err) } |
||||
} |
||||
@ -1,78 +0,0 @@ |
||||
package features_paypal |
||||
|
||||
import ( |
||||
"github.com/gofiber/fiber/v2" |
||||
"github.com/plutov/paypal/v4" |
||||
"os" |
||||
"context" |
||||
. "MY/webapp/common" |
||||
config "MY/webapp/config" |
||||
"fmt" |
||||
) |
||||
|
||||
func CreatePaypal() (*paypal.Client, error) { |
||||
return paypal.NewClient( |
||||
config.Settings.Paypal.ClientID, |
||||
config.Settings.Paypal.SecretID, |
||||
config.Settings.Paypal.URL) // or paypal.APIBaseLive
|
||||
} |
||||
|
||||
func PostApiOrder(c *fiber.Ctx) error { |
||||
pay, err := CreatePaypal() |
||||
|
||||
if err != nil { return IfErrNil(err, c) } |
||||
|
||||
pay.SetLog(os.Stdout) |
||||
|
||||
units := []paypal.PurchaseUnitRequest{ |
||||
{ |
||||
ReferenceID: "myinternalid1", |
||||
Amount: &paypal.PurchaseUnitAmount{ |
||||
Currency: "USD", |
||||
Value: "10.99", |
||||
}, |
||||
Description: "Product description", |
||||
Items: []paypal.Item{ |
||||
{ |
||||
Name: "Learn Go the Hard Way", |
||||
UnitAmount: &paypal.Money{ |
||||
Currency: "USD", |
||||
Value: "10.99", |
||||
}, |
||||
Quantity: "1", |
||||
}, |
||||
}, |
||||
}, |
||||
} |
||||
|
||||
source := &paypal.PaymentSource{} |
||||
appCtx := &paypal.ApplicationContext{} |
||||
|
||||
order, err := pay.CreateOrder(context.TODO(), paypal.OrderIntentCapture, units, source, appCtx) |
||||
|
||||
fmt.Println("ORDER", order) |
||||
|
||||
return c.JSON(order) |
||||
} |
||||
|
||||
func PostApiOrderCapture(c *fiber.Ctx) error { |
||||
orderID := c.Params("orderID") |
||||
|
||||
fmt.Println("POST ORDER CAPTURE", orderID) |
||||
pay, err := CreatePaypal() |
||||
if err != nil { return IfErrNil(err, c) } |
||||
|
||||
capture, err := pay.CaptureOrder(context.TODO(), orderID, paypal.CaptureOrderRequest{}) |
||||
if err != nil { return IfErrNil(err, c) } |
||||
|
||||
fmt.Println("CAPTURE", capture) |
||||
|
||||
return c.JSON(fiber.Map{"status": "ok"}) |
||||
} |
||||
|
||||
func SetupApi(app *fiber.App) { |
||||
app.Post("/api/paypal/order", PostApiOrder) |
||||
app.Post("/api/paypal/order/:orderID/capture", PostApiOrderCapture) |
||||
} |
||||
|
||||
|
||||
@ -1,160 +0,0 @@ |
||||
import express from "express"; |
||||
import "dotenv/config"; |
||||
import { |
||||
ApiError, |
||||
CheckoutPaymentIntent, |
||||
Client, |
||||
Environment, |
||||
LogLevel, |
||||
OrdersController, |
||||
PaymentsController, |
||||
PaypalExperienceLandingPage, |
||||
PaypalExperienceUserAction, |
||||
ShippingPreference, |
||||
} from "@paypal/paypal-server-sdk"; |
||||
import bodyParser from "body-parser"; |
||||
|
||||
const app = express(); |
||||
app.use(bodyParser.json()); |
||||
|
||||
const { |
||||
PAYPAL_CLIENT_ID, |
||||
PAYPAL_CLIENT_SECRET, |
||||
PORT = 8080, |
||||
} = process.env; |
||||
|
||||
const client = new Client({ |
||||
clientCredentialsAuthCredentials: { |
||||
oAuthClientId: PAYPAL_CLIENT_ID, |
||||
oAuthClientSecret: PAYPAL_CLIENT_SECRET, |
||||
}, |
||||
timeout: 0, |
||||
environment: Environment.Sandbox, |
||||
logging: { |
||||
logLevel: LogLevel.Info, |
||||
logRequest: { logBody: true }, |
||||
logResponse: { logHeaders: true }, |
||||
}, |
||||
}); |
||||
|
||||
const ordersController = new OrdersController(client); |
||||
const paymentsController = new PaymentsController(client); |
||||
|
||||
|
||||
/** |
||||
* Create an order to start the transaction. |
||||
* @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
|
||||
*/ |
||||
const createOrder = async (cart) => { |
||||
const collect = { |
||||
body: { |
||||
intent: "CAPTURE", |
||||
purchaseUnits: [ |
||||
{ |
||||
amount: { |
||||
currencyCode: "USD", |
||||
value: "100", |
||||
breakdown: { |
||||
itemTotal: { |
||||
currencyCode: "USD", |
||||
value: "100", |
||||
}, |
||||
}, |
||||
}, |
||||
// lookup item details in `cart` from database
|
||||
items: [ |
||||
{ |
||||
name: "T-Shirt", |
||||
unitAmount: { |
||||
currencyCode: "USD", |
||||
value: "100", |
||||
}, |
||||
quantity: "1", |
||||
description: "Super Fresh Shirt", |
||||
sku: "sku01", |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}, |
||||
prefer: "return=minimal", |
||||
}; |
||||
|
||||
|
||||
try { |
||||
const { body, ...httpResponse } = await ordersController.createOrder( |
||||
collect |
||||
); |
||||
// Get more response info...
|
||||
// const { statusCode, headers } = httpResponse;
|
||||
return { |
||||
jsonResponse: JSON.parse(body), |
||||
httpStatusCode: httpResponse.statusCode, |
||||
}; |
||||
} catch (error) { |
||||
if (error instanceof ApiError) { |
||||
// const { statusCode, headers } = error;
|
||||
throw new Error(error.message); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
// createOrder route
|
||||
app.post("/api/orders", async (req, res) => { |
||||
try { |
||||
// use the cart information passed from the front-end to calculate the order amount detals
|
||||
const { cart } = req.body; |
||||
const { jsonResponse, httpStatusCode } = await createOrder(cart); |
||||
res.status(httpStatusCode).json(jsonResponse); |
||||
} catch (error) { |
||||
console.error("Failed to create order:", error); |
||||
res.status(500).json({ error: "Failed to create order." }); |
||||
} |
||||
}); |
||||
|
||||
|
||||
/** |
||||
* Capture payment for the created order to complete the transaction. |
||||
* @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture
|
||||
*/ |
||||
const captureOrder = async (orderID) => { |
||||
const collect = { |
||||
id: orderID, |
||||
prefer: "return=minimal", |
||||
}; |
||||
|
||||
try { |
||||
const { body, ...httpResponse } = await ordersController.captureOrder( |
||||
collect |
||||
); |
||||
// Get more response info...
|
||||
// const { statusCode, headers } = httpResponse;
|
||||
return { |
||||
jsonResponse: JSON.parse(body), |
||||
httpStatusCode: httpResponse.statusCode, |
||||
}; |
||||
} catch (error) { |
||||
if (error instanceof ApiError) { |
||||
// const { statusCode, headers } = error;
|
||||
throw new Error(error.message); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
// captureOrder route
|
||||
app.post("/api/orders/:orderID/capture", async (req, res) => { |
||||
try { |
||||
const { orderID } = req.params; |
||||
const { jsonResponse, httpStatusCode } = await captureOrder(orderID); |
||||
res.status(httpStatusCode).json(jsonResponse); |
||||
} catch (error) { |
||||
console.error("Failed to create order:", error); |
||||
res.status(500).json({ error: "Failed to capture order." }); |
||||
} |
||||
}); |
||||
|
||||
|
||||
app.listen(PORT, () => { |
||||
console.log(`Node server listening at http://localhost:${PORT}/`); |
||||
}); |
||||
|
||||
@ -1,9 +0,0 @@ |
||||
package features_paypal |
||||
|
||||
import ( |
||||
// "MY/webapp/data"
|
||||
// _ "github.com/mattn/go-sqlite3"
|
||||
// sq "github.com/Masterminds/squirrel"
|
||||
) |
||||
|
||||
|
||||
@ -1,10 +0,0 @@ |
||||
package features_paypal |
||||
|
||||
import ( |
||||
"github.com/gofiber/fiber/v2" |
||||
) |
||||
|
||||
func Setup(app *fiber.App) { |
||||
SetupApi(app) |
||||
SetupViews(app) |
||||
} |
||||
@ -1,11 +0,0 @@ |
||||
package features_paypal |
||||
|
||||
import ( |
||||
"github.com/gofiber/fiber/v2" |
||||
. "MY/webapp/common" |
||||
) |
||||
|
||||
func SetupViews(app *fiber.App) { |
||||
err := ConfigViews(app, "views/paypal") |
||||
if err != nil { panic(err) } |
||||
} |
||||
@ -1,31 +0,0 @@ |
||||
package features_shopping |
||||
|
||||
import ( |
||||
"github.com/gofiber/fiber/v2" |
||||
"MY/webapp/data" |
||||
_ "github.com/mattn/go-sqlite3" |
||||
sq "github.com/Masterminds/squirrel" |
||||
"fmt" |
||||
) |
||||
|
||||
func GetApiProducts(c *fiber.Ctx) error { |
||||
sql, args, err := sq.Select("*").From("Product").ToSql() |
||||
|
||||
fmt.Println("SQL:", sql, args, err) |
||||
|
||||
return data.SelectJson[data.Product](c, err, sql, args...) |
||||
} |
||||
|
||||
func GetApiCart(c *fiber.Ctx) error { |
||||
return c.JSON(fiber.Map{}) |
||||
} |
||||
|
||||
func GetApiCartRemove(c *fiber.Ctx) error { |
||||
return c.Redirect("/shopping/checkout") |
||||
} |
||||
|
||||
func SetupApi(app *fiber.App) { |
||||
app.Get("/api/shopping/products", GetApiProducts) |
||||
app.Get("/api/shopping/cart", GetApiCart) |
||||
app.Get("/api/shopping/cart/remove/:item_id", GetApiCartRemove) |
||||
} |
||||
@ -1,9 +0,0 @@ |
||||
package features_shopping |
||||
|
||||
import ( |
||||
// "MY/webapp/data"
|
||||
// _ "github.com/mattn/go-sqlite3"
|
||||
// sq "github.com/Masterminds/squirrel"
|
||||
) |
||||
|
||||
|
||||
@ -1,10 +0,0 @@ |
||||
package features_shopping |
||||
|
||||
import ( |
||||
"github.com/gofiber/fiber/v2" |
||||
) |
||||
|
||||
func Setup(app *fiber.App) { |
||||
SetupApi(app) |
||||
SetupViews(app) |
||||
} |
||||
@ -1,11 +0,0 @@ |
||||
package features_shopping |
||||
|
||||
import ( |
||||
"github.com/gofiber/fiber/v2" |
||||
. "MY/webapp/common" |
||||
) |
||||
|
||||
func SetupViews(app *fiber.App) { |
||||
err := ConfigViews(app, "views/shopping") |
||||
if err != nil { panic(err) } |
||||
} |
||||
@ -1,9 +1,44 @@ |
||||
package features_survey |
||||
|
||||
import ( |
||||
// "MY/webapp/data"
|
||||
"MY/webapp/data" |
||||
// _ "github.com/mattn/go-sqlite3"
|
||||
// sq "github.com/Masterminds/squirrel"
|
||||
) |
||||
|
||||
|
||||
func QueryData() data.Survey { |
||||
return data.Survey{ |
||||
Title: "Sample Survey", |
||||
Description: "The description.", |
||||
CreatedOn: "01/20/26", |
||||
Respondents: 200, |
||||
State: "Finished", |
||||
Questions: []data.Question{ |
||||
{ |
||||
Id: 1, |
||||
Question: "Do you like HTML?", |
||||
Answer: true, |
||||
// TODO: just for prototyping, needs to be a better model
|
||||
Result: 20, |
||||
}, |
||||
{ |
||||
Id: 2, |
||||
Question: "Do you like CSS?", |
||||
Answer: false, |
||||
Result: 11, |
||||
}, |
||||
{ |
||||
Id: 3, |
||||
Question: "Do you like JavaScript?", |
||||
Answer: true, |
||||
Result: 43, |
||||
}, |
||||
{ |
||||
Id: 4, |
||||
Question: "Are you a programmer?", |
||||
Answer: true, |
||||
Result: 28, |
||||
}, |
||||
}, |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,21 @@ |
||||
-- +goose Up |
||||
-- +goose StatementBegin |
||||
CREATE TABLE question ( |
||||
id INTEGER PRIMARY KEY, |
||||
question TEXT UNIQUE NOT NULL, |
||||
result INTEGER DEFAULT 0); |
||||
|
||||
CREATE TABLE survey ( |
||||
id INTEGER PRIMARY KEY, |
||||
title TEXT UNIQUE NOT NULL, |
||||
description TEXT UNIQUE NOT NULL, |
||||
created_on DATETIME DEFAULT CURRENT_TIMESTAMP, |
||||
respondents INTEGER DEFAULT 0, |
||||
active BOOLEAN INTEGER DEFAULT false); |
||||
-- +goose StatementEnd |
||||
|
||||
-- +goose Down |
||||
-- +goose StatementBegin |
||||
DROP TABLE IF EXISTS question; |
||||
DROP TABLE IF EXISTS survey; |
||||
-- +goose StatementEnd |
||||
Loading…
Reference in new issue