Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions chart/gameshelf/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ metadata:
data:
port: "8080"
site-name: {{ .Values.siteName | quote }}
site-color: {{ .Values.siteColor | default "#3B82F6" | quote }}
custom-branding-enabled: {{ .Values.customBrandingEnabled | quote }}
10 changes: 10 additions & 0 deletions chart/gameshelf/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ spec:
secretKeyRef:
name: {{ include "gameshelf.fullname" . }}
key: admin-secret
- name: SITE_COLOR
valueFrom:
configMapKeyRef:
name: {{ include "gameshelf.fullname" . }}
key: site-color
- name: CUSTOM_BRANDING_ENABLED
valueFrom:
configMapKeyRef:
name: {{ include "gameshelf.fullname" . }}
key: custom-branding-enabled
- name: SDK_SERVICE_URL
value: "http://replicated:3000"
livenessProbe:
Expand Down
2 changes: 2 additions & 0 deletions chart/gameshelf/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ resources:

siteName: "GameShelf"
adminSecret: "changeme" # REQUIRED — set a strong secret, e.g. --set adminSecret=... or in a values override
siteColor: "#3B82F6"
customBrandingEnabled: "false"

# --- Embedded PostgreSQL (Bitnami subchart) ---
postgresql:
Expand Down
2 changes: 2 additions & 0 deletions helmchart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ spec:
integrationLicenseID: repl{{ LicenseFieldValue `licenseID` }}
adminSecret: repl{{ ConfigOption `admin_secret`}}
siteName: repl{{ ConfigOption `site_name`}}
siteColor: repl{{ ConfigOption `site_color`}}
customBrandingEnabled: repl{{ LicenseFieldValue `custom_branding_enabled` }}
builder:
image:
tag: latest
8 changes: 8 additions & 0 deletions internal/api/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ func (s *Server) toggleGameHandler(w http.ResponseWriter, r *http.Request) {

// POST /admin/branding — update site branding
func (s *Server) updateBrandingHandler(w http.ResponseWriter, r *http.Request) {
if !s.cfg.CustomBrandingEnabled {
http.Error(w, "Custom branding requires an upgraded license", http.StatusForbidden)
return
}
if err := r.ParseForm(); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
Expand Down Expand Up @@ -141,6 +145,10 @@ func (s *Server) logoHandler(w http.ResponseWriter, r *http.Request) {

// POST /admin/logo — upload a new logo image
func (s *Server) uploadLogoHandler(w http.ResponseWriter, r *http.Request) {
if !s.cfg.CustomBrandingEnabled {
http.Error(w, "Custom branding requires an upgraded license", http.StatusForbidden)
return
}
r.Body = http.MaxBytesReader(w, r.Body, 2<<20) // 2MB
if err := r.ParseMultipartForm(2 << 20); err != nil {
http.Error(w, "file too large (max 2MB)", http.StatusBadRequest)
Expand Down
7 changes: 5 additions & 2 deletions internal/api/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ type PageData struct {
DBScores []db.Score
AllGames []db.Game
Site *db.Site
IdentitySecretMasked string // shown (masked) on admin panel
IdentitySecretMasked string // shown (masked) on admin panel
CustomBrandingEnabled bool // true when custom_branding_enabled license field is "true"
}

// pageBase fills the branding fields from the DB and SDK banner state.
Expand All @@ -43,7 +44,7 @@ func (s *Server) pageBase(r *http.Request) PageData {
if err != nil || site == nil {
data = PageData{
SiteName: s.cfg.SiteName,
PrimaryColor: "#3B82F6",
PrimaryColor: s.cfg.SiteColor,
SecondaryColor: "#1E40AF",
BackgroundColor: "#F9FAFB",
FontFamily: "system",
Expand All @@ -60,6 +61,8 @@ func (s *Server) pageBase(r *http.Request) PageData {
}
}

data.CustomBrandingEnabled = s.cfg.CustomBrandingEnabled

// Populate SDK banners (fail-open: errors are logged and ignored)
if s.sdk.Available() {
expiresAt, err := s.sdk.GetExpiresAt(r.Context())
Expand Down
18 changes: 13 additions & 5 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ type Config struct {
Port string
SiteName string
IdentitySecret string // optional; auto-generated and stored in DB if empty
SDKServiceURL string // URL of Replicated SDK sidecar, e.g. http://localhost:3000
LocalDev bool // LOCAL_DEV=true bypasses SDK gates when SDK_SERVICE_URL is unset
SDKServiceURL string // URL of Replicated SDK sidecar, e.g. http://localhost:3000
LocalDev bool // LOCAL_DEV=true bypasses SDK gates when SDK_SERVICE_URL is unset
SiteColor string // default primary color (hex), overridden by DB branding settings
CustomBrandingEnabled bool // set by LicenseFieldValue custom_branding_enabled via KOTS
}

func Load() Config {
Expand All @@ -22,6 +24,10 @@ func Load() Config {
if siteName == "" {
siteName = "GameShelf"
}
siteColor := os.Getenv("SITE_COLOR")
if siteColor == "" {
siteColor = "#3B82F6"
}
adminSecret := os.Getenv("ADMIN_SECRET")
if adminSecret == "" {
adminSecret = "changeme"
Expand All @@ -32,8 +38,10 @@ func Load() Config {
AdminSecret: adminSecret,
Port: port,
SiteName: siteName,
IdentitySecret: os.Getenv("IDENTITY_SECRET"),
SDKServiceURL: os.Getenv("SDK_SERVICE_URL"),
LocalDev: os.Getenv("LOCAL_DEV") == "true",
IdentitySecret: os.Getenv("IDENTITY_SECRET"),
SDKServiceURL: os.Getenv("SDK_SERVICE_URL"),
LocalDev: os.Getenv("LOCAL_DEV") == "true",
SiteColor: siteColor,
CustomBrandingEnabled: os.Getenv("CUSTOM_BRANDING_ENABLED") == "true",
}
}
13 changes: 13 additions & 0 deletions kots-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,16 @@ spec:
type: text
default: "GameShelf"
help_text: "The name displayed in the browser title and header."
- name: branding
title: Branding
when: '{{repl LicenseFieldValue "custom_branding_enabled" | eq "true"}}'
items:
- name: site_color
title: Primary Color
type: text
default: "#3B82F6"
help_text: "Primary color for the GameShelf UI (hex format, e.g. #3B82F6). Requires the Custom Branding license entitlement."
validation:
regex:
pattern: '^#[0-9A-Fa-f]{6}$'
message: "Must be a valid hex color code (e.g. #3B82F6)"
2 changes: 2 additions & 0 deletions templates/admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
{{ define "content" }}
<h1 class="text-3xl font-extrabold text-gray-900 mb-8">Admin Panel</h1>

{{ if .CustomBrandingEnabled }}
<!-- Branding Section -->
<section class="bg-white rounded-2xl shadow-sm border border-gray-100 p-6 mb-6">
<h2 class="text-lg font-bold text-gray-900 mb-4">Site Branding</h2>
Expand Down Expand Up @@ -83,6 +84,7 @@ <h2 class="text-lg font-bold text-gray-900 mb-4">Logo</h2>
</button>
</form>
</section>
{{ end }}

<!-- Identity Section -->
<section class="bg-white rounded-2xl shadow-sm border border-gray-100 p-6 mb-6">
Expand Down
Loading