everybody loves a refactor

This commit is contained in:
2026-02-15 12:27:36 +11:00
parent 2944443143
commit c5f6fe6098
44 changed files with 278 additions and 234 deletions

View File

@@ -185,12 +185,12 @@ func AdminAuditLogDetail(s *hws.Server, conn *db.DB) http.Handler {
var err error
log, err = db.GetAuditLogByID(ctx, tx, id)
if err != nil {
if db.IsBadRequest(err) {
throw.NotFound(s, w, r, r.URL.Path)
return false, nil
}
return false, errors.Wrap(err, "db.GetAuditLogByID")
}
if log == nil {
throw.NotFound(s, w, r, r.URL.Path)
return false, nil
}
return true, nil
}); !ok {
return

View File

@@ -31,12 +31,12 @@ func AdminPreviewRoleStart(s *hws.Server, conn *db.DB, ssl bool) http.Handler {
var err error
role, err = db.GetRoleByID(ctx, tx, roleID)
if err != nil {
if db.IsBadRequest(err) {
throw.NotFound(s, w, r, "Role not found")
return false, nil
}
return false, errors.Wrap(err, "db.GetRoleByID")
}
if role == nil {
throw.NotFound(s, w, r, "Role not found")
return false, nil
}
// Cannot preview admin role
if role.Name == roles.Admin {
throw.BadRequest(s, w, r, "Cannot preview admin role", nil)

View File

@@ -9,6 +9,7 @@ import (
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/respond"
"git.haelnorr.com/h/oslstats/internal/roles"
"git.haelnorr.com/h/oslstats/internal/validation"
adminview "git.haelnorr.com/h/oslstats/internal/view/adminview"
@@ -108,7 +109,7 @@ func AdminRoleManage(s *hws.Server, conn *db.DB) http.Handler {
roleIDStr := r.PathValue("id")
roleID, err := strconv.Atoi(roleIDStr)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
respond.BadRequest(w, err)
return
}
@@ -117,11 +118,12 @@ func AdminRoleManage(s *hws.Server, conn *db.DB) http.Handler {
var err error
role, err = db.GetRoleByID(ctx, tx, roleID)
if err != nil {
if db.IsBadRequest(err) {
respond.NotFound(w, err)
return false, nil
}
return false, errors.Wrap(err, "db.GetRoleByID")
}
if role == nil {
return false, errors.New("role not found")
}
return true, nil
}); !ok {
return
@@ -146,11 +148,12 @@ func AdminRoleDeleteConfirm(s *hws.Server, conn *db.DB) http.Handler {
var err error
role, err = db.GetRoleByID(ctx, tx, roleID)
if err != nil {
if db.IsBadRequest(err) {
respond.NotFound(w, err)
return false, nil
}
return false, errors.Wrap(err, "db.GetRoleByID")
}
if role == nil {
return false, errors.New("role not found")
}
return true, nil
}); !ok {
return
@@ -166,7 +169,7 @@ func AdminRoleDelete(s *hws.Server, conn *db.DB) http.Handler {
roleIDStr := r.PathValue("id")
roleID, err := strconv.Atoi(roleIDStr)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
respond.BadRequest(w, err)
return
}
@@ -180,11 +183,12 @@ func AdminRoleDelete(s *hws.Server, conn *db.DB) http.Handler {
// First check if role exists and get its details
role, err := db.GetRoleByID(ctx, tx, roleID)
if err != nil {
if db.IsBadRequest(err) {
respond.NotFound(w, err)
return false, nil
}
return false, errors.Wrap(err, "db.GetRoleByID")
}
if role == nil {
return false, errors.New("role not found")
}
// Check if it's a system role
if role.IsSystem {
@@ -194,6 +198,10 @@ func AdminRoleDelete(s *hws.Server, conn *db.DB) http.Handler {
// Delete the role with audit logging
err = db.DeleteRole(ctx, tx, roleID, db.NewAudit(r, nil))
if err != nil {
if db.IsBadRequest(err) {
respond.NotFound(w, err)
return false, nil
}
return false, errors.Wrap(err, "db.DeleteRole")
}
@@ -218,7 +226,7 @@ func AdminRolePermissionsModal(s *hws.Server, conn *db.DB) http.Handler {
roleIDStr := r.PathValue("id")
roleID, err := strconv.Atoi(roleIDStr)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
respond.BadRequest(w, err)
return
}
@@ -232,11 +240,12 @@ func AdminRolePermissionsModal(s *hws.Server, conn *db.DB) http.Handler {
var err error
role, err = db.GetRoleByID(ctx, tx, roleID)
if err != nil {
if db.IsBadRequest(err) {
respond.NotFound(w, err)
return false, nil
}
return false, errors.Wrap(err, "db.GetRoleByID")
}
if role == nil {
return false, errors.New("role not found")
}
// Load all permissions
allPermissions, err = db.ListAllPermissions(ctx, tx)
@@ -281,7 +290,7 @@ func AdminRolePermissionsUpdate(s *hws.Server, conn *db.DB) http.Handler {
roleIDStr := r.PathValue("id")
roleID, err := strconv.Atoi(roleIDStr)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
respond.BadRequest(w, err)
return
}
@@ -305,12 +314,12 @@ func AdminRolePermissionsUpdate(s *hws.Server, conn *db.DB) http.Handler {
if ok := conn.WithWriteTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
role, err := db.GetRoleByID(ctx, tx, roleID)
if err != nil {
if db.IsBadRequest(err) {
respond.NotFound(w, err)
return false, nil
}
return false, errors.Wrap(err, "db.GetRoleByID")
}
if role == nil {
w.WriteHeader(http.StatusBadRequest)
return false, nil
}
err = role.UpdatePermissions(ctx, tx, permissionIDs, db.NewAudit(r, nil))
if err != nil {
return false, errors.Wrap(err, "role.UpdatePermissions")

View File

@@ -42,9 +42,6 @@ func ensureUserHasAdminRole(ctx context.Context, tx bun.Tx, user *db.User) error
if err != nil {
return errors.Wrap(err, "db.GetRoleByName")
}
if adminRole == nil {
return errors.New("admin role not found in database")
}
// Grant admin role
err = db.AssignRole(ctx, tx, user.ID, adminRole.ID, nil)

View File

@@ -158,7 +158,7 @@ func login(
}
user, err := db.GetUserByDiscordID(ctx, tx, discorduser.ID)
if err != nil {
if err != nil && !db.IsBadRequest(err) {
return nil, errors.Wrap(err, "db.GetUserByDiscordID")
}
var redirect string

View File

@@ -2,10 +2,12 @@ package handlers
import (
"context"
"fmt"
"net/http"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/respond"
"git.haelnorr.com/h/oslstats/internal/validation"
"github.com/pkg/errors"
"github.com/uptrace/bun"
@@ -22,12 +24,12 @@ func IsUnique(
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
getter, err := validation.ParseForm(r)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
respond.BadRequest(w, err)
return
}
value := getter.String(field).TrimSpace().Required().Value
if !getter.Validate() {
w.WriteHeader(http.StatusBadRequest)
respond.BadRequest(w, err)
return
}
unique := false
@@ -41,9 +43,10 @@ func IsUnique(
return
}
if unique {
w.WriteHeader(http.StatusOK)
respond.OK(w)
} else {
w.WriteHeader(http.StatusConflict)
err := fmt.Errorf("'%s' is not unique for field '%s'", value, field)
respond.Conflict(w, err)
}
})
}

View File

@@ -11,6 +11,7 @@ import (
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/notify"
"git.haelnorr.com/h/oslstats/internal/respond"
"git.haelnorr.com/h/oslstats/internal/validation"
leaguesview "git.haelnorr.com/h/oslstats/internal/view/leaguesview"
)
@@ -78,8 +79,7 @@ func NewLeagueSubmit(
notify.Warn(s, w, r, "Duplicate Short Name", "This short name is already taken.", nil)
return
}
w.Header().Set("HX-Redirect", fmt.Sprintf("/leagues/%s", league.ShortName))
w.WriteHeader(http.StatusOK)
respond.HXRedirect(w, "/leagues/%s", league.ShortName)
notify.SuccessWithDelay(s, w, r, "League Created", fmt.Sprintf("Successfully created league: %s", name), nil)
})
}

View File

@@ -12,6 +12,7 @@ import (
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/discord"
"git.haelnorr.com/h/oslstats/internal/notify"
"git.haelnorr.com/h/oslstats/internal/respond"
"git.haelnorr.com/h/oslstats/internal/store"
"git.haelnorr.com/h/oslstats/internal/throw"
"git.haelnorr.com/h/oslstats/pkg/oauth"
@@ -34,10 +35,10 @@ func Login(
if r.Method == "POST" {
if err != nil {
notify.ServiceUnavailable(s, w, r, "Login currently unavailable", err)
w.WriteHeader(http.StatusOK)
respond.OK(w)
return
}
w.Header().Set("HX-Redirect", "/login")
respond.HXRedirect(w, "/login")
return
}

View File

@@ -8,6 +8,7 @@ import (
"git.haelnorr.com/h/golib/hwsauth"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/discord"
"git.haelnorr.com/h/oslstats/internal/respond"
"git.haelnorr.com/h/oslstats/internal/throw"
"github.com/pkg/errors"
"github.com/uptrace/bun"
@@ -22,11 +23,6 @@ func Logout(
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
user := db.CurrentUser(r.Context())
if user == nil {
// JIC - should be impossible to get here if route is protected by LoginReq
w.Header().Set("HX-Redirect", "/")
return
}
if ok := conn.WithWriteTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
token, err := user.DeleteDiscordTokens(ctx, tx)
if err != nil {
@@ -48,7 +44,7 @@ func Logout(
}); !ok {
return
}
w.Header().Set("HX-Redirect", "/")
respond.HXRedirect(w, "/")
},
)
}

View File

@@ -12,6 +12,7 @@ import (
"git.haelnorr.com/h/oslstats/internal/config"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/respond"
"git.haelnorr.com/h/oslstats/internal/store"
"git.haelnorr.com/h/oslstats/internal/throw"
authview "git.haelnorr.com/h/oslstats/internal/view/authview"
@@ -82,7 +83,7 @@ func Register(
return
}
if !unique {
w.WriteHeader(http.StatusConflict)
respond.Conflict(w, errors.New("username is taken"))
} else {
err = auth.Login(w, r, user, true)
if err != nil {
@@ -90,7 +91,7 @@ func Register(
return
}
pageFrom := cookies.CheckPageFrom(w, r)
w.Header().Set("HX-Redirect", pageFrom)
respond.HXRedirect(w, "%s", pageFrom)
}
},
)

View File

@@ -25,11 +25,12 @@ func SeasonPage(
var err error
season, err = db.GetSeason(ctx, tx, seasonStr)
if err != nil {
if db.IsBadRequest(err) {
throw.NotFound(s, w, r, r.URL.Path)
return false, nil
}
return false, errors.Wrap(err, "db.GetSeason")
}
if season == nil {
return true, nil
}
leaguesWithTeams, err = season.MapTeamsToLeagues(ctx, tx)
if err != nil {
@@ -40,10 +41,6 @@ func SeasonPage(
}); !ok {
return
}
if season == nil {
throw.NotFound(s, w, r, r.URL.Path)
return
}
renderSafely(seasonsview.DetailPage(season, leaguesWithTeams), s, r, w)
})
}

View File

@@ -8,6 +8,7 @@ import (
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/notify"
"git.haelnorr.com/h/oslstats/internal/respond"
"git.haelnorr.com/h/oslstats/internal/throw"
"git.haelnorr.com/h/oslstats/internal/validation"
"git.haelnorr.com/h/oslstats/internal/view/seasonsview"
@@ -28,6 +29,10 @@ func SeasonEditPage(
var err error
season, err = db.GetSeason(ctx, tx, seasonStr)
if err != nil {
if db.IsBadRequest(err) {
throw.NotFound(s, w, r, r.URL.Path)
return false, nil
}
return false, errors.Wrap(err, "db.GetSeason")
}
allLeagues, err = db.GetLeagues(ctx, tx)
@@ -38,10 +43,6 @@ func SeasonEditPage(
}); !ok {
return
}
if season == nil {
throw.NotFound(s, w, r, r.URL.Path)
return
}
renderSafely(seasonsview.EditPage(season, allLeagues), s, r, w)
})
}
@@ -79,11 +80,12 @@ func SeasonEditSubmit(
var err error
season, err = db.GetSeason(ctx, tx, seasonStr)
if err != nil {
if db.IsBadRequest(err) {
respond.NotFound(w, err)
return false, nil
}
return false, errors.Wrap(err, "db.GetSeason")
}
if season == nil {
return false, errors.New("season does not exist")
}
err = season.Update(ctx, tx, version, start, end, finalsStart, finalsEnd, db.NewAudit(r, nil))
if err != nil {
return false, errors.Wrap(err, "season.Update")
@@ -93,13 +95,7 @@ func SeasonEditSubmit(
return
}
if season == nil {
throw.NotFound(s, w, r, r.URL.Path)
return
}
w.Header().Set("HX-Redirect", fmt.Sprintf("/seasons/%s", season.ShortName))
w.WriteHeader(http.StatusOK)
respond.HXRedirect(w, "/seasons/%s", season.ShortName)
notify.SuccessWithDelay(s, w, r, "Season Updated", fmt.Sprintf("Successfully updated season: %s", season.Name), nil)
})
}

View File

@@ -38,6 +38,10 @@ func SeasonLeagueAddTeam(
var err error
team, season, league, err = db.NewTeamParticipation(ctx, tx, seasonStr, leagueStr, teamID, db.NewAudit(r, nil))
if err != nil {
if db.IsBadRequest(err) {
w.WriteHeader(http.StatusBadRequest)
return false, nil
}
return false, errors.Wrap(err, "db.NewTeamParticipation")
}
return true, nil

View File

@@ -22,12 +22,15 @@ func SeasonLeaguePage(
leagueStr := r.PathValue("league_short_name")
var season *db.Season
var league *db.League
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
season, league, _, err = db.GetSeasonLeague(ctx, tx, seasonStr, leagueStr)
season, _, _, err = db.GetSeasonLeague(ctx, tx, seasonStr, leagueStr)
if err != nil {
if db.IsBadRequest(err) {
throw.NotFound(s, w, r, r.URL.Path)
return false, nil
}
return false, errors.Wrap(err, "db.GetSeasonLeague")
}
return true, nil
@@ -35,11 +38,6 @@ func SeasonLeaguePage(
return
}
if season == nil || league == nil {
throw.NotFound(s, w, r, r.URL.Path)
return
}
defaultTab := season.GetDefaultTab()
redirectURL := fmt.Sprintf(
"/seasons/%s/leagues/%s/%s",

View File

@@ -7,7 +7,7 @@ import (
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/throw"
seasonsview "git.haelnorr.com/h/oslstats/internal/view/seasonsview"
"git.haelnorr.com/h/oslstats/internal/view/seasonsview"
"github.com/pkg/errors"
"github.com/uptrace/bun"
)
@@ -28,6 +28,10 @@ func SeasonLeagueFinalsPage(
var err error
season, league, _, err = db.GetSeasonLeague(ctx, tx, seasonStr, leagueStr)
if err != nil {
if db.IsBadRequest(err) {
throw.NotFound(s, w, r, r.URL.Path)
return false, nil
}
return false, errors.Wrap(err, "db.GetSeasonLeague")
}
return true, nil
@@ -35,11 +39,6 @@ func SeasonLeagueFinalsPage(
return
}
if season == nil || league == nil {
throw.NotFound(s, w, r, r.URL.Path)
return
}
if r.Method == "GET" {
renderSafely(seasonsview.SeasonLeagueFinalsPage(season, league), s, r, w)
} else {

View File

@@ -28,6 +28,10 @@ func SeasonLeagueFixturesPage(
var err error
season, league, _, err = db.GetSeasonLeague(ctx, tx, seasonStr, leagueStr)
if err != nil {
if db.IsBadRequest(err) {
throw.NotFound(s, w, r, r.URL.Path)
return false, nil
}
return false, errors.Wrap(err, "db.GetSeasonLeague")
}
return true, nil
@@ -35,11 +39,6 @@ func SeasonLeagueFixturesPage(
return
}
if season == nil || league == nil {
throw.NotFound(s, w, r, r.URL.Path)
return
}
if r.Method == "GET" {
renderSafely(seasonsview.SeasonLeagueFixturesPage(season, league), s, r, w)
} else {

View File

@@ -28,6 +28,10 @@ func SeasonLeagueStatsPage(
var err error
season, league, _, err = db.GetSeasonLeague(ctx, tx, seasonStr, leagueStr)
if err != nil {
if db.IsBadRequest(err) {
throw.NotFound(s, w, r, r.URL.Path)
return false, nil
}
return false, errors.Wrap(err, "db.GetSeasonLeague")
}
return true, nil
@@ -35,11 +39,6 @@ func SeasonLeagueStatsPage(
return
}
if season == nil || league == nil {
throw.NotFound(s, w, r, r.URL.Path)
return
}
if r.Method == "GET" {
renderSafely(seasonsview.SeasonLeagueStatsPage(season, league), s, r, w)
} else {

View File

@@ -28,18 +28,16 @@ func SeasonLeagueTablePage(
var err error
season, league, _, err = db.GetSeasonLeague(ctx, tx, seasonStr, leagueStr)
if err != nil {
if db.IsBadRequest(err) {
throw.NotFound(s, w, r, r.URL.Path)
return false, nil
}
return false, errors.Wrap(err, "db.GetSeasonLeague")
}
return true, nil
}); !ok {
return
}
if season == nil || league == nil {
throw.NotFound(s, w, r, r.URL.Path)
return
}
if r.Method == "GET" {
renderSafely(seasonsview.SeasonLeagueTablePage(season, league), s, r, w)
} else {

View File

@@ -30,6 +30,10 @@ func SeasonLeagueTeamsPage(
var err error
season, league, teams, err = db.GetSeasonLeague(ctx, tx, seasonStr, leagueStr)
if err != nil {
if db.IsBadRequest(err) {
throw.NotFound(s, w, r, r.URL.Path)
return false, nil
}
return false, errors.Wrap(err, "db.GetSeasonLeague")
}
@@ -46,11 +50,6 @@ func SeasonLeagueTeamsPage(
return
}
if season == nil || league == nil {
throw.NotFound(s, w, r, r.URL.Path)
return
}
if r.Method == "GET" {
renderSafely(seasonsview.SeasonLeagueTeamsPage(season, league, teams, available), s, r, w)
} else {

View File

@@ -10,6 +10,7 @@ import (
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/notify"
"git.haelnorr.com/h/oslstats/internal/respond"
"git.haelnorr.com/h/oslstats/internal/view/seasonsview"
)
@@ -26,6 +27,10 @@ func SeasonAddLeague(
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
err := db.NewSeasonLeague(ctx, tx, seasonStr, leagueStr, db.NewAudit(r, nil))
if err != nil {
if db.IsBadRequest(err) {
respond.BadRequest(w, err)
return false, nil
}
return false, errors.Wrap(err, "db.NewSeasonLeague")
}
@@ -64,13 +69,17 @@ func SeasonRemoveLeague(
var err error
season, err = db.GetSeason(ctx, tx, seasonStr)
if err != nil {
if db.IsBadRequest(err) {
respond.NotFound(w, err)
return false, nil
}
return false, errors.Wrap(err, "db.GetSeason")
}
if season == nil {
return false, errors.New("season not found")
}
err = season.RemoveLeague(ctx, tx, leagueStr, db.NewAudit(r, nil))
if err != nil {
if db.IsBadRequest(err) {
respond.BadRequest(w, err)
}
return false, errors.Wrap(err, "season.RemoveLeague")
}

View File

@@ -8,6 +8,7 @@ import (
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/notify"
"git.haelnorr.com/h/oslstats/internal/respond"
"git.haelnorr.com/h/oslstats/internal/validation"
seasonsview "git.haelnorr.com/h/oslstats/internal/view/seasonsview"
"git.haelnorr.com/h/timefmt"
@@ -83,8 +84,7 @@ func NewSeasonSubmit(
notify.Warn(s, w, r, "Duplicate Short Name", "This short name is already taken.", nil)
return
}
w.Header().Set("HX-Redirect", fmt.Sprintf("/seasons/%s", season.ShortName))
w.WriteHeader(http.StatusOK)
respond.HXRedirect(w, "/seasons/%s", season.ShortName)
notify.SuccessWithDelay(s, w, r, "Season Created", fmt.Sprintf("Successfully created season: %s", name), nil)
})
}

View File

@@ -2,10 +2,9 @@ package handlers
import (
"net/http"
"path/filepath"
"strings"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/oslstats/internal/respond"
"git.haelnorr.com/h/oslstats/internal/throw"
)
@@ -23,41 +22,8 @@ func StaticFS(staticFS *http.FileSystem, server *hws.Server) http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
// Explicitly set Content-Type for CSS files
if strings.HasSuffix(r.URL.Path, ".css") {
w.Header().Set("Content-Type", "text/css; charset=utf-8")
} else if strings.HasSuffix(r.URL.Path, ".js") {
w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
} else if strings.HasSuffix(r.URL.Path, ".ico") {
w.Header().Set("Content-Type", "image/x-icon")
} else {
// Let Go detect the content type for other files
ext := filepath.Ext(r.URL.Path)
if contentType := mimeTypes[ext]; contentType != "" {
w.Header().Set("Content-Type", contentType)
}
}
respond.ContentType(w, r)
fs.ServeHTTP(w, r)
},
)
}
// Common MIME types for static files
var mimeTypes = map[string]string{
".html": "text/html; charset=utf-8",
".css": "text/css; charset=utf-8",
".js": "application/javascript; charset=utf-8",
".json": "application/json; charset=utf-8",
".xml": "application/xml; charset=utf-8",
".png": "image/png",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".gif": "image/gif",
".svg": "image/svg+xml",
".ico": "image/x-icon",
".webp": "image/webp",
".woff": "font/woff",
".woff2": "font/woff2",
".ttf": "font/ttf",
".eot": "application/vnd.ms-fontobject",
}

View File

@@ -6,6 +6,7 @@ import (
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/respond"
"git.haelnorr.com/h/oslstats/internal/validation"
"github.com/pkg/errors"
"github.com/uptrace/bun"
@@ -20,7 +21,7 @@ func IsTeamShortNamesUnique(
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
getter, err := validation.ParseForm(r)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
respond.BadRequest(w, err)
return
}
@@ -28,12 +29,12 @@ func IsTeamShortNamesUnique(
altShortName := getter.String("alt_short_name").TrimSpace().ToUpper().MaxLength(3).Value
if shortName == "" || altShortName == "" {
w.WriteHeader(http.StatusOK)
respond.OK(w)
return
}
if shortName == altShortName {
w.WriteHeader(http.StatusConflict)
respond.Conflict(w, errors.New("short names cannot be the same"))
return
}
@@ -49,9 +50,9 @@ func IsTeamShortNamesUnique(
}
if isUnique {
w.WriteHeader(http.StatusOK)
respond.OK(w)
} else {
w.WriteHeader(http.StatusConflict)
respond.Conflict(w, errors.New("short name combination is taken"))
}
})
}

View File

@@ -32,31 +32,10 @@ func TeamsPage(
}); !ok {
return
}
renderSafely(teamsview.ListPage(teams), s, r, w)
})
}
// TeamsList renders just the teams list, for use with POST requests and HTMX
func TeamsList(
s *hws.Server,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pageOpts, ok := db.GetPageOpts(s, w, r)
if !ok {
return
}
var teams *db.List[db.Team]
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
teams, err = db.ListTeams(ctx, tx, pageOpts)
if err != nil {
return false, errors.Wrap(err, "db.ListTeams")
}
return true, nil
}); !ok {
return
}
renderSafely(teamsview.TeamsList(teams), s, r, w)
if r.Method == "GET" {
renderSafely(teamsview.ListPage(teams), s, r, w)
} else {
renderSafely(teamsview.TeamsList(teams), s, r, w)
}
})
}

View File

@@ -11,6 +11,7 @@ import (
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/notify"
"git.haelnorr.com/h/oslstats/internal/respond"
"git.haelnorr.com/h/oslstats/internal/validation"
teamsview "git.haelnorr.com/h/oslstats/internal/view/teamsview"
)
@@ -88,8 +89,7 @@ func NewTeamSubmit(
notify.Warn(s, w, r, "Duplicate Short Names", "This combination of short names is already taken.", nil)
return
}
w.Header().Set("HX-Redirect", "/teams")
w.WriteHeader(http.StatusOK)
respond.HXRedirect(w, "teams")
notify.SuccessWithDelay(s, w, r, "Team Created", fmt.Sprintf("Successfully created team: %s", name), nil)
})
}