- Replace manual IP logging with the `withRequestLogAttrs` helper in authentication handlers. - Add user activity logging for API documentation and login page views. - Clean up log calls to use variadic expansion of request attributes.
182 lines
5.7 KiB
Go
182 lines
5.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"warpbox.dev/backend/libs/services"
|
|
"warpbox.dev/backend/libs/web"
|
|
)
|
|
|
|
type homeData struct {
|
|
MaxUploadSize string
|
|
LimitSummary string
|
|
Collections []collectionView
|
|
IsAdmin bool
|
|
AnonymousOpen bool
|
|
ExpiryOptions []expiryOption
|
|
DefaultExpiryMinutes int
|
|
}
|
|
|
|
type expiryOption struct {
|
|
Minutes int
|
|
Label string
|
|
}
|
|
|
|
func (a *App) Home(w http.ResponseWriter, r *http.Request) {
|
|
currentUser := a.currentPublicUser(r)
|
|
var collections []collectionView
|
|
var isAdmin bool
|
|
var user services.User
|
|
var loggedIn bool
|
|
if current, ok := a.currentUser(r); ok {
|
|
user = current
|
|
loggedIn = true
|
|
isAdmin = user.Role == services.UserRoleAdmin
|
|
userCollections, err := a.authService.ListCollections(user.ID)
|
|
if err == nil {
|
|
collections = make([]collectionView, 0, len(userCollections))
|
|
for _, collection := range userCollections {
|
|
collections = append(collections, collectionView{ID: collection.ID, Name: collection.Name})
|
|
}
|
|
}
|
|
}
|
|
settings, err := a.settingsService.UploadPolicy()
|
|
if err != nil {
|
|
http.Error(w, "unable to load upload policy", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
actor := "anonymous"
|
|
if loggedIn {
|
|
actor = "user"
|
|
}
|
|
a.logger.Info("upload page viewed", withRequestLogAttrs(r,
|
|
"source", "page",
|
|
"severity", "user_activity",
|
|
"code", 2500,
|
|
"actor", actor,
|
|
"user_id", user.ID,
|
|
)...)
|
|
maxUploadSize, limitSummary := a.homeUploadPolicyLabels(settings, user, loggedIn, isAdmin)
|
|
expiryOptions, defaultExpiry := a.homeExpiryOptions(settings, user, loggedIn, isAdmin)
|
|
a.renderPage(w, r, http.StatusOK, "home.html", web.PageData{
|
|
Title: "Upload your files",
|
|
Description: "Upload and share files through a self-hosted Warpbox instance.",
|
|
CurrentUser: currentUser,
|
|
Data: homeData{
|
|
MaxUploadSize: maxUploadSize,
|
|
LimitSummary: limitSummary,
|
|
Collections: collections,
|
|
IsAdmin: isAdmin,
|
|
AnonymousOpen: settings.AnonymousUploadsEnabled,
|
|
ExpiryOptions: expiryOptions,
|
|
DefaultExpiryMinutes: defaultExpiry,
|
|
},
|
|
})
|
|
}
|
|
|
|
// homeExpiryOptions builds the expiry ladder offered on the upload form, capped to
|
|
// the viewer's effective maximum retention. Admins have no cap (the dropdown is
|
|
// still capped at 365 days for sanity; the API accepts any value for admins).
|
|
func (a *App) homeExpiryOptions(settings services.UploadPolicySettings, user services.User, loggedIn, isAdmin bool) ([]expiryOption, int) {
|
|
maxDays := settings.AnonymousMaxDays
|
|
unlimited := false
|
|
switch {
|
|
case isAdmin:
|
|
unlimited = true
|
|
case loggedIn:
|
|
maxDays = a.settingsService.EffectivePolicyForUser(settings, user).MaxDays
|
|
// A negative per-user MaxDays override means unlimited retention.
|
|
if maxDays < 0 {
|
|
unlimited = true
|
|
}
|
|
}
|
|
return buildExpiryOptions(maxDays, unlimited)
|
|
}
|
|
|
|
func buildExpiryOptions(maxDays int, unlimited bool) ([]expiryOption, int) {
|
|
ladder := []int{60, 720, 1440, 2880, 4320, 7200, 10080, 14400, 20160, 43200, 86400, 129600, 259200, 525600}
|
|
|
|
capMinutes := maxDays * 24 * 60
|
|
if unlimited || capMinutes <= 0 {
|
|
capMinutes = 525600
|
|
}
|
|
|
|
options := make([]expiryOption, 0, len(ladder)+1)
|
|
seen := make(map[int]bool)
|
|
for _, minutes := range ladder {
|
|
if minutes > capMinutes {
|
|
break
|
|
}
|
|
options = append(options, expiryOption{Minutes: minutes, Label: expiryLabel(minutes)})
|
|
seen[minutes] = true
|
|
}
|
|
// Always offer the exact cap as a final choice (e.g. a 15-day limit).
|
|
if !unlimited && !seen[capMinutes] {
|
|
options = append(options, expiryOption{Minutes: capMinutes, Label: expiryLabel(capMinutes)})
|
|
}
|
|
if len(options) == 0 {
|
|
options = append(options, expiryOption{Minutes: capMinutes, Label: expiryLabel(capMinutes)})
|
|
}
|
|
// Unlimited uploaders can pick "never expires" (sentinel -1) after the ladder.
|
|
if unlimited {
|
|
options = append(options, expiryOption{Minutes: -1, Label: "Unlimited (never expires)"})
|
|
}
|
|
|
|
// Default to 24h when available, otherwise the smallest option offered.
|
|
defaultMinutes := options[0].Minutes
|
|
if seen[1440] {
|
|
defaultMinutes = 1440
|
|
}
|
|
return options, defaultMinutes
|
|
}
|
|
|
|
func expiryLabel(minutes int) string {
|
|
switch {
|
|
case minutes < 60:
|
|
return strconv.Itoa(minutes) + " minutes"
|
|
case minutes < 1440:
|
|
hours := minutes / 60
|
|
if hours == 1 {
|
|
return "1 hour"
|
|
}
|
|
return strconv.Itoa(hours) + " hours"
|
|
case minutes == 1440:
|
|
return "24 hours"
|
|
default:
|
|
days := minutes / 1440
|
|
if days == 1 {
|
|
return "1 day"
|
|
}
|
|
return strconv.Itoa(days) + " days"
|
|
}
|
|
}
|
|
|
|
func (a *App) homeUploadPolicyLabels(settings services.UploadPolicySettings, user services.User, loggedIn, isAdmin bool) (string, string) {
|
|
if isAdmin {
|
|
return "No file size limit", "Admin uploads bypass storage and daily caps."
|
|
}
|
|
if !loggedIn {
|
|
if !settings.AnonymousUploadsEnabled {
|
|
return "Anonymous uploads disabled", "Sign in to upload files."
|
|
}
|
|
return services.FormatMegabytesLabel(settings.AnonymousMaxUploadMB), "Daily anonymous cap: " + services.FormatMegabytesLabel(settings.AnonymousDailyUploadMB) + " per IP · " + strconv.Itoa(settings.AnonymousMaxDays) + " day max."
|
|
}
|
|
policy := a.settingsService.EffectivePolicyForUser(settings, user)
|
|
maxUpload := a.uploadService.MaxUploadSizeLabel()
|
|
if policy.MaxUploadMB < 0 {
|
|
maxUpload = "unlimited"
|
|
} else if policy.MaxUploadMB > 0 {
|
|
maxUpload = services.FormatMegabytesLabel(policy.MaxUploadMB)
|
|
}
|
|
quota := "unlimited"
|
|
if policy.StorageQuotaSet {
|
|
quota = services.FormatMegabytesLabel(policy.StorageQuotaMB)
|
|
}
|
|
expiryLimit := strconv.Itoa(policy.MaxDays) + " day max."
|
|
if policy.MaxDays < 0 {
|
|
expiryLimit = "no expiry limit."
|
|
}
|
|
return maxUpload, "Daily cap: " + services.FormatMegabytesLabel(policy.DailyUploadMB) + " · Storage quota: " + quota + " · " + expiryLimit
|
|
}
|