2
0
Files
gitcaddy-server/routers/web/repo/setting/subscriptions.go
logikonline d1f20f6b46
All checks were successful
Build and Release / Create Release (push) Successful in 0s
Build and Release / Unit Tests (push) Successful in 3m10s
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 5m13s
Build and Release / Lint (push) Successful in 5m25s
Build and Release / Build Binaries (amd64, linux, linux-latest) (push) Successful in 3m13s
Build and Release / Build Binaries (amd64, windows, windows-latest) (push) Successful in 8h5m42s
Build and Release / Build Binaries (amd64, darwin, macos) (push) Successful in 7m30s
Build and Release / Build Binaries (arm64, darwin, macos) (push) Successful in 7m55s
Build and Release / Build Binary (linux/arm64) (push) Successful in 7m36s
feat(ci): add repository subscription monetization system
Implement complete subscription monetization system for repositories with Stripe and PayPal integration. Includes:
- Database models and migrations for monetization settings, subscription products, and user subscriptions
- Payment provider abstraction layer with Stripe and PayPal implementations
- Admin UI for configuring payment providers and viewing subscriptions
- Repository settings UI for managing subscription products and tiers
- Subscription checkout flow and webhook handlers for payment events
- Access control to gate repository code behind active subscriptions
2026-01-31 13:37:07 -05:00

147 lines
4.5 KiB
Go

// Copyright 2026 MarketAlly. All rights reserved.
// SPDX-License-Identifier: MIT
package setting
import (
"net/http"
monetize_model "code.gitcaddy.com/server/v3/models/monetize"
repo_model "code.gitcaddy.com/server/v3/models/repo"
"code.gitcaddy.com/server/v3/modules/templates"
"code.gitcaddy.com/server/v3/modules/web"
"code.gitcaddy.com/server/v3/services/context"
"code.gitcaddy.com/server/v3/services/forms"
)
const tplSubscriptions templates.TplName = "repo/settings/subscriptions"
// SubscriptionsGeneral shows the subscriptions enable/disable toggle.
func SubscriptionsGeneral(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.settings.subscriptions")
ctx.Data["PageIsSettingsSubscriptions"] = true
ctx.Data["PageIsSettingsSubscriptionsGeneral"] = true
ctx.Data["PageType"] = "general"
ctx.Data["SubscriptionsEnabled"] = ctx.Repo.Repository.SubscriptionsEnabled
ctx.HTML(http.StatusOK, tplSubscriptions)
}
// SubscriptionsGeneralPost toggles the subscriptions enabled flag.
func SubscriptionsGeneralPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.settings.subscriptions")
ctx.Data["PageIsSettingsSubscriptions"] = true
ctx.Data["PageIsSettingsSubscriptionsGeneral"] = true
ctx.Data["PageType"] = "general"
enabled := ctx.FormBool("subscriptions_enabled")
ctx.Repo.Repository.SubscriptionsEnabled = enabled
if err := repo_model.UpdateRepositoryColsWithAutoTime(ctx, ctx.Repo.Repository, "subscriptions_enabled"); err != nil {
ctx.ServerError("UpdateRepositoryCols", err)
return
}
ctx.Flash.Success(ctx.Tr("repo.settings.subscriptions.saved"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/subscriptions")
}
// SubscriptionsProducts shows the product list and create form.
func SubscriptionsProducts(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.settings.subscriptions.products")
ctx.Data["PageIsSettingsSubscriptions"] = true
ctx.Data["PageIsSettingsSubscriptionsProducts"] = true
ctx.Data["PageType"] = "products"
products, err := monetize_model.GetProductsByRepoID(ctx, ctx.Repo.Repository.ID)
if err != nil {
ctx.ServerError("GetProductsByRepoID", err)
return
}
ctx.Data["Products"] = products
ctx.HTML(http.StatusOK, tplSubscriptions)
}
// SubscriptionsProductsPost creates or updates a product.
func SubscriptionsProductsPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.settings.subscriptions.products")
ctx.Data["PageIsSettingsSubscriptions"] = true
ctx.Data["PageIsSettingsSubscriptionsProducts"] = true
ctx.Data["PageType"] = "products"
form := web.GetForm(ctx).(*forms.SubscriptionProductForm)
p := &monetize_model.RepoSubscriptionProduct{
RepoID: ctx.Repo.Repository.ID,
Name: form.Name,
Type: monetize_model.ProductType(form.Type),
PriceCents: form.PriceCents,
Currency: form.Currency,
IsActive: form.IsActive,
}
editID := ctx.FormInt64("id")
if editID > 0 {
p.ID = editID
if err := monetize_model.UpdateProduct(ctx, p); err != nil {
ctx.ServerError("UpdateProduct", err)
return
}
} else {
if err := monetize_model.CreateProduct(ctx, p); err != nil {
ctx.ServerError("CreateProduct", err)
return
}
}
ctx.Flash.Success(ctx.Tr("repo.settings.subscriptions.product_saved"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/subscriptions/products")
}
// SubscriptionsProductDelete deletes a product.
func SubscriptionsProductDelete(ctx *context.Context) {
id := ctx.FormInt64("id")
if id > 0 {
if err := monetize_model.DeleteProduct(ctx, id); err != nil {
ctx.ServerError("DeleteProduct", err)
return
}
}
ctx.Flash.Success(ctx.Tr("repo.settings.subscriptions.product_deleted"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/subscriptions/products")
}
// SubscriptionsClients shows the subscriber list for this repo.
func SubscriptionsClients(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.settings.subscriptions.clients")
ctx.Data["PageIsSettingsSubscriptions"] = true
ctx.Data["PageIsSettingsSubscriptionsClients"] = true
ctx.Data["PageType"] = "clients"
page := ctx.FormInt("page")
if page <= 0 {
page = 1
}
pageSize := 20
subs, count, err := monetize_model.GetSubscriptionsByRepoID(ctx, ctx.Repo.Repository.ID, page, pageSize)
if err != nil {
ctx.ServerError("GetSubscriptionsByRepoID", err)
return
}
for _, sub := range subs {
_ = sub.LoadUser(ctx)
_ = sub.LoadProduct(ctx)
}
ctx.Data["Subscriptions"] = subs
ctx.Data["Total"] = count
pager := context.NewPagination(int(count), pageSize, page, 5)
pager.AddParamFromRequest(ctx.Req)
ctx.Data["Page"] = pager
ctx.HTML(http.StatusOK, tplSubscriptions)
}