feat(payments): edit the rewarded-ads config from the admin catalog page
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 12s
CI / integration (pull_request) Successful in 24s
CI / ui (pull_request) Has been skipped
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 1s
CI / deploy (pull_request) Successful in 1m57s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 12s
CI / integration (pull_request) Successful in 24s
CI / ui (pull_request) Has been skipped
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 1s
CI / deploy (pull_request) Successful in 1m57s
The "watch for chips" rewarded payout and its per-day / per-hour caps live in the shared payments.config row and had no admin surface — they could only be changed by SQL, contrary to D32 (the rewarded rate is meant to be admin-configurable). Add a "Rewarded ads" form on the /_gm/catalog page: RewardConfig / SetRewardConfig on the service (non-negative validated), a setRewardConfig store writer (the singleton config row), the consoleSetReward handler + POST /_gm/catalog/reward route, and the form pre-filled from the current config. No migration — the columns already exist. The reward rate is a config value, not a sellable catalog atom (so a "no-ads forever" style product is still out of scope by D32/D33). Test: an integration test sets the config, checks the page pre-fill, and refuses a negative value.
This commit is contained in:
@@ -46,13 +46,32 @@ func (s *Server) consoleCatalog(c *gin.Context) {
|
||||
// Order the list like the public offer: sales (chip packs) first, then the chip-exchange values,
|
||||
// grouped and price-sorted the same way, so the console mirrors what a buyer sees.
|
||||
payments.SortAdminCatalog(products)
|
||||
view := adminconsole.CatalogView{ShowAll: showAll}
|
||||
payout, daily, hourly, err := s.payments.RewardConfig(c.Request.Context())
|
||||
if err != nil {
|
||||
s.consoleError(c, err)
|
||||
return
|
||||
}
|
||||
view := adminconsole.CatalogView{ShowAll: showAll, RewardPayout: payout, RewardDailyCap: daily, RewardHourlyCap: hourly}
|
||||
for _, p := range products {
|
||||
view.Products = append(view.Products, catalogRow(p))
|
||||
}
|
||||
s.renderConsole(c, "catalog", "catalog", "Catalog", view)
|
||||
}
|
||||
|
||||
// consoleSetReward updates the rewarded-video config (chips per view plus the per-day and per-hour
|
||||
// caps) from the catalog page's rewarded-ads form. A blank field reads as 0; a negative value is
|
||||
// refused by the service.
|
||||
func (s *Server) consoleSetReward(c *gin.Context) {
|
||||
payout, _ := strconv.Atoi(strings.TrimSpace(c.PostForm("reward_payout")))
|
||||
daily, _ := strconv.Atoi(strings.TrimSpace(c.PostForm("reward_daily")))
|
||||
hourly, _ := strconv.Atoi(strings.TrimSpace(c.PostForm("reward_hourly")))
|
||||
if err := s.payments.SetRewardConfig(c.Request.Context(), payout, daily, hourly); err != nil {
|
||||
s.renderConsoleMessage(c, "Update failed", err.Error(), catalogBack)
|
||||
return
|
||||
}
|
||||
s.renderConsoleMessage(c, "Saved", "the rewarded-ads config was updated", catalogBack)
|
||||
}
|
||||
|
||||
// catalogRow projects a product into its list row.
|
||||
func catalogRow(p payments.AdminProduct) adminconsole.ProductRow {
|
||||
row := adminconsole.ProductRow{ID: p.ID.String(), Title: p.Title, Active: p.Active, Transacted: p.Transacted}
|
||||
|
||||
Reference in New Issue
Block a user