diff --git a/images/elements/thank-you.jpg b/images/elements/thank-you.jpg new file mode 100644 index 00000000..75ae85c1 Binary files /dev/null and b/images/elements/thank-you.jpg differ diff --git a/pages/paypal/paypal.go b/pages/paypal/paypal.go index 94adce8e..d2a1b7e4 100644 --- a/pages/paypal/paypal.go +++ b/pages/paypal/paypal.go @@ -5,11 +5,18 @@ import ( "github.com/aerogo/aero" "github.com/animenotifier/arn" + "github.com/animenotifier/notify.moe/utils" "github.com/logpacker/PayPal-Go-SDK" ) // CreatePayment ... func CreatePayment(ctx *aero.Context) string { + user := utils.GetUser(ctx) + + if user == nil { + return ctx.Error(http.StatusUnauthorized, "Not logged in", nil) + } + c, err := arn.PayPal() if err != nil { @@ -56,9 +63,9 @@ func CreatePayment(ctx *aero.Context) string { Transactions: []paypalsdk.Transaction{paypalsdk.Transaction{ Amount: &paypalsdk.Amount{ Currency: "USD", - Total: "7.00", + Total: "10.00", }, - Description: "Pro Account", + Description: "Top Up Balance", }}, RedirectURLs: &paypalsdk.RedirectURLs{ ReturnURL: "https://" + ctx.App.Config.Domain + "/paypal/success", diff --git a/pages/paypal/success.go b/pages/paypal/success.go index 35512c4d..954531db 100644 --- a/pages/paypal/success.go +++ b/pages/paypal/success.go @@ -1,17 +1,33 @@ package paypal import ( + "errors" "net/http" + "strconv" "github.com/aerogo/aero" "github.com/animenotifier/arn" + "github.com/animenotifier/notify.moe/components" + "github.com/animenotifier/notify.moe/utils" ) +const adminID = "4J6qpK1ve" + // Success ... func Success(ctx *aero.Context) string { + user := utils.GetUser(ctx) + + if user == nil { + return ctx.Error(http.StatusUnauthorized, "Not logged in", nil) + } + paymentID := ctx.Query("paymentId") - // token := ctx.Query("token") - // payerID := ctx.Query("PayerID") + token := ctx.Query("token") + payerID := ctx.Query("PayerID") + + if paymentID == "" || payerID == "" || token == "" { + return ctx.Error(http.StatusBadRequest, "Invalid parameters", errors.New("paymentId, token and PayerID are required")) + } c, err := arn.PayPal() @@ -19,19 +35,63 @@ func Success(ctx *aero.Context) string { return ctx.Error(http.StatusInternalServerError, "Could not initiate PayPal client", err) } - _, err = c.GetAccessToken() + c.SetAccessToken(token) + execute, err := c.ExecuteApprovedPayment(paymentID, payerID) if err != nil { - return ctx.Error(http.StatusInternalServerError, "Could not get PayPal access token", err) + return ctx.Error(http.StatusInternalServerError, "Error executing PayPal payment", err) } - payment, err := c.GetPayment(paymentID) + if execute.State != "approved" { + return ctx.Error(http.StatusInternalServerError, "PayPal payment has not been approved", err) + } + + sdkPayment, err := c.GetPayment(paymentID) if err != nil { return ctx.Error(http.StatusInternalServerError, "Could not retrieve payment information", err) } - arn.PrettyPrint(payment) + arn.PrettyPrint(sdkPayment) - return ctx.HTML("success") + transaction := sdkPayment.Transactions[0] + + payment := &arn.PayPalPayment{ + ID: paymentID, + PayerID: payerID, + UserID: user.ID, + Method: sdkPayment.Payer.PaymentMethod, + Amount: transaction.Amount.Total, + Currency: transaction.Amount.Currency, + Created: arn.DateTimeUTC(), + } + + err = payment.Save() + + if err != nil { + return ctx.Error(http.StatusInternalServerError, "Could not save payment in the database", err) + } + + // Increase user's balance + user.Balance += payment.AnimeDollar() + + // Save in DB + err = user.Save() + + if err != nil { + return ctx.Error(http.StatusInternalServerError, "Could not save new balance", err) + } + + // Notify admin + go func() { + admin, _ := arn.GetUser(adminID) + admin.SendNotification(&arn.Notification{ + Title: user.Nick + " bought " + strconv.Itoa(payment.AnimeDollar()) + " AD", + Message: user.Nick + " paid " + payment.Amount + " " + payment.Currency + " making his new balance " + strconv.Itoa(user.Balance), + Icon: user.LargeAvatar(), + Link: "https://" + ctx.App.Config.Domain + "/api/paypalpayment/" + payment.ID, + }) + }() + + return ctx.HTML(components.PayPalSuccess(payment)) } diff --git a/pages/paypal/success.pixy b/pages/paypal/success.pixy new file mode 100644 index 00000000..ee13b1d4 --- /dev/null +++ b/pages/paypal/success.pixy @@ -0,0 +1,10 @@ +component PayPalSuccess(payment *arn.PayPalPayment) + h1 Thank you for your support! + + .new-payment.mountable + span + + .new-payment-amount.count-up= payment.AnimeDollar() + span.new-payment-currency AD + + p.mountable + img.new-payment-thank-you-image(src="/images/elements/thank-you.jpg", alt="Thank you!") \ No newline at end of file diff --git a/pages/paypal/success.scarlet b/pages/paypal/success.scarlet new file mode 100644 index 00000000..ebb83b08 --- /dev/null +++ b/pages/paypal/success.scarlet @@ -0,0 +1,12 @@ +.new-payment + horizontal + margin 2rem auto + font-size 4rem + color green + +.new-payment-currency + margin-left 1rem + margin-bottom content-padding + +.new-payment-thank-you-image + width 683px \ No newline at end of file diff --git a/pages/settings/settings.go b/pages/settings/settings.go index 761cc9a5..a7a03e0a 100644 --- a/pages/settings/settings.go +++ b/pages/settings/settings.go @@ -13,7 +13,7 @@ func Get(ctx *aero.Context) string { user := utils.GetUser(ctx) if user == nil { - return ctx.Error(http.StatusForbidden, "Not logged in", nil) + return ctx.Error(http.StatusUnauthorized, "Not logged in", nil) } return utils.AllowEmbed(ctx, ctx.HTML(components.Settings(user))) diff --git a/scripts/AnimeNotifier.ts b/scripts/AnimeNotifier.ts index 4d551d09..759772c5 100644 --- a/scripts/AnimeNotifier.ts +++ b/scripts/AnimeNotifier.ts @@ -121,7 +121,8 @@ export class AnimeNotifier { Promise.resolve().then(() => this.displayLocalDates()), Promise.resolve().then(() => this.setSelectBoxValue()), Promise.resolve().then(() => this.assignActions()), - Promise.resolve().then(() => this.updatePushUI()) + Promise.resolve().then(() => this.updatePushUI()), + Promise.resolve().then(() => this.countUp()) ]) // Apply page title @@ -214,6 +215,32 @@ export class AnimeNotifier { } } + countUp() { + for(let element of findAll("count-up")) { + let final = parseInt(element.innerText) + let duration = 2000.0 + let start = Date.now() + + element.innerText = "0" + + let callback = () => { + let progress = (Date.now() - start) / duration + + if(progress > 1) { + progress = 1 + } + + element.innerText = String(Math.round(progress * final)) + + if(progress < 1) { + window.requestAnimationFrame(callback) + } + } + + window.requestAnimationFrame(callback) + } + } + pushAnalytics() { if(!this.user) { return diff --git a/sw/service-worker.ts b/sw/service-worker.ts index a528e0b7..2f843de4 100644 --- a/sw/service-worker.ts +++ b/sw/service-worker.ts @@ -94,7 +94,7 @@ self.addEventListener("message", (evt: any) => { self.addEventListener("fetch", async (evt: FetchEvent) => { let request = evt.request as Request let isAuth = request.url.includes("/auth/") || request.url.includes("/logout") - let ignoreCache = request.url.includes("/api/") || request.url.includes("chrome-extension") + let ignoreCache = request.url.includes("/api/") || request.url.includes("/paypal/") || request.url.includes("chrome-extension") // Delete existing cache on authentication if(isAuth) {