big ole refactor

This commit is contained in:
2026-02-14 19:48:59 +11:00
parent 0fc3bb0c94
commit 4a2396bca8
66 changed files with 989 additions and 1114 deletions

View File

@@ -17,10 +17,10 @@ import (
)
// AdminAuditLogsPage renders the full admin dashboard page with audit logs section (GET request)
func AdminAuditLogsPage(s *hws.Server, conn *bun.DB) http.Handler {
func AdminAuditLogsPage(s *hws.Server, conn *db.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pageOpts := pageOptsFromQuery(s, w, r)
if pageOpts == nil {
pageOpts, ok := db.GetPageOpts(s, w, r)
if !ok {
return
}
@@ -29,7 +29,7 @@ func AdminAuditLogsPage(s *hws.Server, conn *bun.DB) http.Handler {
var actions []string
var resourceTypes []string
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
// Get filters from query
@@ -73,10 +73,10 @@ func AdminAuditLogsPage(s *hws.Server, conn *bun.DB) http.Handler {
}
// AdminAuditLogsList shows the full audit logs list with filters (POST request for HTMX)
func AdminAuditLogsList(s *hws.Server, conn *bun.DB) http.Handler {
func AdminAuditLogsList(s *hws.Server, conn *db.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pageOpts := pageOptsFromForm(s, w, r)
if pageOpts == nil {
pageOpts, ok := db.GetPageOpts(s, w, r)
if !ok {
return
}
@@ -85,7 +85,7 @@ func AdminAuditLogsList(s *hws.Server, conn *bun.DB) http.Handler {
var actions []string
var resourceTypes []string
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
// Get filters from form
@@ -129,16 +129,16 @@ func AdminAuditLogsList(s *hws.Server, conn *bun.DB) http.Handler {
}
// AdminAuditLogsFilter returns only the results container (table + pagination) for HTMX updates
func AdminAuditLogsFilter(s *hws.Server, conn *bun.DB) http.Handler {
func AdminAuditLogsFilter(s *hws.Server, conn *db.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pageOpts := pageOptsFromForm(s, w, r)
if pageOpts == nil {
pageOpts, ok := db.GetPageOpts(s, w, r)
if !ok {
return
}
var logs *db.List[db.AuditLog]
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
// Get filters from form
@@ -164,7 +164,7 @@ func AdminAuditLogsFilter(s *hws.Server, conn *bun.DB) http.Handler {
}
// AdminAuditLogDetail shows details for a single audit log entry
func AdminAuditLogDetail(s *hws.Server, conn *bun.DB) http.Handler {
func AdminAuditLogDetail(s *hws.Server, conn *db.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Get ID from path
idStr := r.PathValue("id")
@@ -181,7 +181,7 @@ func AdminAuditLogDetail(s *hws.Server, conn *bun.DB) http.Handler {
var log *db.AuditLog
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
log, err = db.GetAuditLogByID(ctx, tx, id)
if err != nil {

View File

@@ -12,10 +12,10 @@ import (
)
// AdminDashboard renders the full admin dashboard page (defaults to users section)
func AdminDashboard(s *hws.Server, conn *bun.DB) http.Handler {
func AdminDashboard(s *hws.Server, conn *db.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var users *db.List[db.User]
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
users, err = db.GetUsersWithRoles(ctx, tx, nil)
if err != nil {

View File

@@ -1,25 +0,0 @@
package handlers
import (
"net/http"
"git.haelnorr.com/h/golib/hws"
adminview "git.haelnorr.com/h/oslstats/internal/view/adminview"
"github.com/uptrace/bun"
)
// AdminPermissionsPage renders the full admin dashboard page with permissions section
func AdminPermissionsPage(s *hws.Server, conn *bun.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// TODO: Load permissions from database
renderSafely(adminview.PermissionsPage(), s, r, w)
})
}
// AdminPermissionsList shows all permissions (HTMX content replacement)
func AdminPermissionsList(s *hws.Server, conn *bun.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// TODO: Load permissions from database
renderSafely(adminview.PermissionsList(), s, r, w)
})
}

View File

@@ -6,7 +6,6 @@ import (
"strconv"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/oslstats/internal/config"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/rbac"
"git.haelnorr.com/h/oslstats/internal/roles"
@@ -16,7 +15,7 @@ import (
)
// AdminPreviewRoleStart starts preview mode for a specific role
func AdminPreviewRoleStart(s *hws.Server, conn *bun.DB, cfg *config.Config) http.Handler {
func AdminPreviewRoleStart(s *hws.Server, conn *db.DB, ssl bool) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Get role ID from URL
roleIDStr := r.PathValue("id")
@@ -28,7 +27,7 @@ func AdminPreviewRoleStart(s *hws.Server, conn *bun.DB, cfg *config.Config) http
// Verify role exists and is not admin
var role *db.Role
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
role, err = db.GetRoleByID(ctx, tx, roleID)
if err != nil {
@@ -49,7 +48,7 @@ func AdminPreviewRoleStart(s *hws.Server, conn *bun.DB, cfg *config.Config) http
}
// Set preview role cookie
rbac.SetPreviewRoleCookie(w, roleID, cfg.HWSAuth.SSL)
rbac.SetPreviewRoleCookie(w, roleID, ssl)
// Redirect to home page
http.Redirect(w, r, "/", http.StatusSeeOther)

View File

@@ -8,10 +8,8 @@ import (
"time"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/oslstats/internal/auditlog"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/roles"
"git.haelnorr.com/h/oslstats/internal/throw"
"git.haelnorr.com/h/oslstats/internal/validation"
adminview "git.haelnorr.com/h/oslstats/internal/view/adminview"
"github.com/pkg/errors"
@@ -19,20 +17,15 @@ import (
)
// AdminRoles renders the full admin dashboard page with roles section
func AdminRoles(s *hws.Server, conn *bun.DB) http.Handler {
func AdminRoles(s *hws.Server, conn *db.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var pageOpts *db.PageOpts
if r.Method == "GET" {
pageOpts = pageOptsFromQuery(s, w, r)
} else {
pageOpts = pageOptsFromForm(s, w, r)
}
if pageOpts == nil {
pageOpts, ok := db.GetPageOpts(s, w, r)
if !ok {
return
}
var rolesList *db.List[db.Role]
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
rolesList, err = db.GetRoles(ctx, tx, pageOpts)
if err != nil {
@@ -59,7 +52,7 @@ func AdminRoleCreateForm(s *hws.Server) http.Handler {
}
// AdminRoleCreate creates a new role
func AdminRoleCreate(s *hws.Server, conn *bun.DB, audit *auditlog.Logger) http.Handler {
func AdminRoleCreate(s *hws.Server, conn *db.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
getter, ok := validation.ParseFormOrNotify(s, w, r)
if !ok {
@@ -74,14 +67,14 @@ func AdminRoleCreate(s *hws.Server, conn *bun.DB, audit *auditlog.Logger) http.H
return
}
pageOpts := pageOptsFromForm(s, w, r)
if pageOpts == nil {
pageOpts, ok := db.GetPageOpts(s, w, r)
if !ok {
return
}
var rolesList *db.List[db.Role]
var newRole *db.Role
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
newRole = &db.Role{
Name: roles.Role(name),
DisplayName: displayName,
@@ -90,9 +83,9 @@ func AdminRoleCreate(s *hws.Server, conn *bun.DB, audit *auditlog.Logger) http.H
CreatedAt: time.Now().Unix(),
}
err := db.Insert(tx, newRole).WithAudit(r, audit.Callback()).Exec(ctx)
err := db.CreateRole(ctx, tx, newRole, db.NewAudit(r, nil))
if err != nil {
return false, errors.Wrap(err, "db.Insert")
return false, errors.Wrap(err, "db.CreateRole")
}
rolesList, err = db.GetRoles(ctx, tx, pageOpts)
@@ -110,7 +103,7 @@ func AdminRoleCreate(s *hws.Server, conn *bun.DB, audit *auditlog.Logger) http.H
}
// AdminRoleManage shows the role management modal with details and actions
func AdminRoleManage(s *hws.Server, conn *bun.DB) http.Handler {
func AdminRoleManage(s *hws.Server, conn *db.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
roleIDStr := r.PathValue("id")
roleID, err := strconv.Atoi(roleIDStr)
@@ -120,7 +113,7 @@ func AdminRoleManage(s *hws.Server, conn *bun.DB) http.Handler {
}
var role *db.Role
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
role, err = db.GetRoleByID(ctx, tx, roleID)
if err != nil {
@@ -139,7 +132,7 @@ func AdminRoleManage(s *hws.Server, conn *bun.DB) http.Handler {
}
// AdminRoleDeleteConfirm shows the delete confirmation dialog
func AdminRoleDeleteConfirm(s *hws.Server, conn *bun.DB) http.Handler {
func AdminRoleDeleteConfirm(s *hws.Server, conn *db.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
roleIDStr := r.PathValue("id")
roleID, err := strconv.Atoi(roleIDStr)
@@ -149,7 +142,7 @@ func AdminRoleDeleteConfirm(s *hws.Server, conn *bun.DB) http.Handler {
}
var role *db.Role
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
role, err = db.GetRoleByID(ctx, tx, roleID)
if err != nil {
@@ -168,7 +161,7 @@ func AdminRoleDeleteConfirm(s *hws.Server, conn *bun.DB) http.Handler {
}
// AdminRoleDelete deletes a role
func AdminRoleDelete(s *hws.Server, conn *bun.DB, audit *auditlog.Logger) http.Handler {
func AdminRoleDelete(s *hws.Server, conn *db.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
roleIDStr := r.PathValue("id")
roleID, err := strconv.Atoi(roleIDStr)
@@ -177,13 +170,13 @@ func AdminRoleDelete(s *hws.Server, conn *bun.DB, audit *auditlog.Logger) http.H
return
}
pageOpts := pageOptsFromForm(s, w, r)
if pageOpts == nil {
pageOpts, ok := db.GetPageOpts(s, w, r)
if !ok {
return
}
var rolesList *db.List[db.Role]
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
// First check if role exists and get its details
role, err := db.GetRoleByID(ctx, tx, roleID)
if err != nil {
@@ -199,9 +192,9 @@ func AdminRoleDelete(s *hws.Server, conn *bun.DB, audit *auditlog.Logger) http.H
}
// Delete the role with audit logging
err = db.DeleteByID[db.Role](tx, roleID).WithAudit(r, audit.Callback()).Delete(ctx)
err = db.DeleteRole(ctx, tx, roleID, db.NewAudit(r, nil))
if err != nil {
return false, errors.Wrap(err, "db.DeleteByID")
return false, errors.Wrap(err, "db.DeleteRole")
}
// Reload roles
@@ -220,7 +213,7 @@ func AdminRoleDelete(s *hws.Server, conn *bun.DB, audit *auditlog.Logger) http.H
}
// AdminRolePermissionsModal shows the permissions management modal for a role
func AdminRolePermissionsModal(s *hws.Server, conn *bun.DB) http.Handler {
func AdminRolePermissionsModal(s *hws.Server, conn *db.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
roleIDStr := r.PathValue("id")
roleID, err := strconv.Atoi(roleIDStr)
@@ -234,12 +227,12 @@ func AdminRolePermissionsModal(s *hws.Server, conn *bun.DB) http.Handler {
var groupedPerms []adminview.PermissionsByResource
var rolePermIDs map[int]bool
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
// Load role with permissions
var err error
role, err = db.GetRoleWithPermissions(ctx, tx, roleID)
role, err = db.GetRoleByID(ctx, tx, roleID)
if err != nil {
return false, errors.Wrap(err, "db.GetRoleWithPermissions")
return false, errors.Wrap(err, "db.GetRoleByID")
}
if role == nil {
return false, errors.New("role not found")
@@ -283,7 +276,7 @@ func AdminRolePermissionsModal(s *hws.Server, conn *bun.DB) http.Handler {
}
// AdminRolePermissionsUpdate updates the permissions for a role
func AdminRolePermissionsUpdate(s *hws.Server, conn *bun.DB, audit *auditlog.Logger) http.Handler {
func AdminRolePermissionsUpdate(s *hws.Server, conn *db.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
roleIDStr := r.PathValue("id")
roleID, err := strconv.Atoi(roleIDStr)
@@ -291,7 +284,6 @@ func AdminRolePermissionsUpdate(s *hws.Server, conn *bun.DB, audit *auditlog.Log
w.WriteHeader(http.StatusBadRequest)
return
}
user := db.CurrentUser(r.Context())
getter, ok := validation.ParseFormOrNotify(s, w, r)
if !ok {
@@ -304,80 +296,24 @@ func AdminRolePermissionsUpdate(s *hws.Server, conn *bun.DB, audit *auditlog.Log
return
}
selectedPermIDs := make(map[int]bool)
for _, id := range permissionIDs {
selectedPermIDs[id] = true
}
pageOpts := pageOptsFromForm(s, w, r)
if pageOpts == nil {
pageOpts, ok := db.GetPageOpts(s, w, r)
if !ok {
return
}
var rolesList *db.List[db.Role]
if ok := db.WithWriteTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
// Get role with current permissions
role, err := db.GetRoleWithPermissions(ctx, tx, roleID)
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 {
return false, errors.Wrap(err, "db.GetRoleWithPermissions")
return false, errors.Wrap(err, "db.GetRoleByID")
}
if role == nil {
throw.NotFound(s, w, r, "Role not found")
w.WriteHeader(http.StatusBadRequest)
return false, nil
}
// Get all permissions to know what exists
allPermissions, err := db.ListAllPermissions(ctx, tx)
err = role.UpdatePermissions(ctx, tx, permissionIDs, db.NewAudit(r, nil))
if err != nil {
return false, errors.Wrap(err, "db.ListAllPermissions")
}
// Build map of current permissions
currentPermIDs := make(map[int]bool)
for _, perm := range role.Permissions {
currentPermIDs[perm.ID] = true
}
var addedPerms []string
var removedPerms []string
// Determine what to add and remove
for _, perm := range allPermissions {
hasNow := currentPermIDs[perm.ID]
shouldHave := selectedPermIDs[perm.ID]
if shouldHave && !hasNow {
// Add permission
err := db.AddPermissionToRole(ctx, tx, roleID, perm.ID)
if err != nil {
return false, errors.Wrap(err, "db.AddPermissionToRole")
}
addedPerms = append(addedPerms, string(perm.Name))
} else if !shouldHave && hasNow {
// Remove permission
err := db.RemovePermissionFromRole(ctx, tx, roleID, perm.ID)
if err != nil {
return false, errors.Wrap(err, "db.RemovePermissionFromRole")
}
removedPerms = append(removedPerms, string(perm.Name))
}
}
// Log the permission changes
if len(addedPerms) > 0 || len(removedPerms) > 0 {
details := map[string]any{
"role_name": string(role.Name),
}
if len(addedPerms) > 0 {
details["added_permissions"] = addedPerms
}
if len(removedPerms) > 0 {
details["removed_permissions"] = removedPerms
}
err = audit.LogSuccess(ctx, tx, user, "update", "role_permissions", roleID, details, r)
if err != nil {
return false, errors.Wrap(err, "audit.LogSuccess")
}
return false, errors.Wrap(err, "role.UpdatePermissions")
}
// Reload roles

View File

@@ -12,20 +12,15 @@ import (
)
// AdminUsersPage renders the full admin dashboard page with users section
func AdminUsersPage(s *hws.Server, conn *bun.DB) http.Handler {
func AdminUsersPage(s *hws.Server, conn *db.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var pageOpts *db.PageOpts
if r.Method == "GET" {
pageOpts = pageOptsFromQuery(s, w, r)
} else {
pageOpts = pageOptsFromForm(s, w, r)
}
if pageOpts == nil {
pageOpts, ok := db.GetPageOpts(s, w, r)
if !ok {
return
}
var users *db.List[db.User]
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
users, err = db.GetUsersWithRoles(ctx, tx, pageOpts)
if err != nil {

View File

@@ -47,7 +47,7 @@ func ensureUserHasAdminRole(ctx context.Context, tx bun.Tx, user *db.User) error
}
// Grant admin role
err = db.AssignRole(ctx, tx, user.ID, adminRole.ID)
err = db.AssignRole(ctx, tx, user.ID, adminRole.ID, nil)
if err != nil {
return errors.Wrap(err, "db.AssignRole")
}

View File

@@ -22,7 +22,7 @@ import (
func Callback(
s *hws.Server,
auth *hwsauth.Authenticator[*db.User, bun.Tx],
conn *bun.DB,
conn *db.DB,
cfg *config.Config,
store *store.Store,
discordAPI *discord.APIClient,
@@ -70,7 +70,7 @@ func Callback(
switch data {
case "login":
var redirect func()
if ok := db.WithWriteTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithWriteTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
redirect, err = login(ctx, auth, tx, cfg, w, r, code, store, discordAPI)
if err != nil {
throw.InternalServiceError(s, w, r, "OAuth login failed", err)

View File

@@ -15,7 +15,7 @@ import (
// Returns 200 OK if unique, 409 Conflict if not unique
func IsUnique(
s *hws.Server,
conn *bun.DB,
conn *db.DB,
model any,
field string,
) http.Handler {
@@ -31,7 +31,7 @@ func IsUnique(
return
}
unique := false
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
unique, err = db.IsUnique(ctx, tx, model, field, value)
if err != nil {
return false, errors.Wrap(err, "db.IsUnique")

View File

@@ -14,11 +14,11 @@ import (
func LeaguesList(
s *hws.Server,
conn *bun.DB,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var leagues []*db.League
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
leagues, err = db.GetLeagues(ctx, tx)
if err != nil {

View File

@@ -9,7 +9,6 @@ import (
"github.com/pkg/errors"
"github.com/uptrace/bun"
"git.haelnorr.com/h/oslstats/internal/auditlog"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/notify"
"git.haelnorr.com/h/oslstats/internal/validation"
@@ -18,20 +17,15 @@ import (
func NewLeague(
s *hws.Server,
conn *bun.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
renderSafely(leaguesview.NewPage(), s, r, w)
return
}
renderSafely(leaguesview.NewPage(), s, r, w)
})
}
func NewLeagueSubmit(
s *hws.Server,
conn *bun.DB,
audit *auditlog.Logger,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
getter, ok := validation.ParseFormOrNotify(s, w, r)
@@ -53,7 +47,7 @@ func NewLeagueSubmit(
nameUnique := false
shortNameUnique := false
var league *db.League
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
nameUnique, err = db.IsUnique(ctx, tx, (*db.League)(nil), "name", name)
if err != nil {
@@ -66,14 +60,9 @@ func NewLeagueSubmit(
if !nameUnique || !shortNameUnique {
return true, nil
}
league = &db.League{
Name: name,
ShortName: shortname,
Description: description,
}
err = db.Insert(tx, league).WithAudit(r, audit.Callback()).Exec(ctx)
league, err = db.NewLeague(ctx, tx, name, shortname, description, db.NewAudit(r, nil))
if err != nil {
return false, errors.Wrap(err, "db.Insert")
return false, errors.Wrap(err, "db.NewLeague")
}
return true, nil
}); !ok {

View File

@@ -7,9 +7,9 @@ import (
"git.haelnorr.com/h/golib/cookies"
"git.haelnorr.com/h/golib/hws"
"github.com/pkg/errors"
"github.com/uptrace/bun"
"git.haelnorr.com/h/oslstats/internal/config"
"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/store"
@@ -19,7 +19,7 @@ import (
func Login(
s *hws.Server,
conn *bun.DB,
conn *db.DB,
cfg *config.Config,
st *store.Store,
discordAPI *discord.APIClient,

View File

@@ -16,7 +16,7 @@ import (
func Logout(
s *hws.Server,
auth *hwsauth.Authenticator[*db.User, bun.Tx],
conn *bun.DB,
conn *db.DB,
discordAPI *discord.APIClient,
) http.Handler {
return http.HandlerFunc(
@@ -27,7 +27,7 @@ func Logout(
w.Header().Set("HX-Redirect", "/")
return
}
if ok := db.WithWriteTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
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 {
return false, errors.Wrap(err, "user.DeleteDiscordTokens")

View File

@@ -1,45 +0,0 @@
package handlers
import (
"net/http"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/validation"
"github.com/uptrace/bun"
)
// pageOptsFromForm calls r.ParseForm and gets the pageOpts from the formdata.
// It renders a Bad Request error page on fail
// PageOpts will be nil on fail
func pageOptsFromForm(s *hws.Server, w http.ResponseWriter, r *http.Request) *db.PageOpts {
getter, ok := validation.ParseFormOrError(s, w, r)
if !ok {
return nil
}
return getPageOpts(s, w, r, getter)
}
// pageOptsFromQuery gets the pageOpts from the request query and renders a Bad Request error page on fail
// PageOpts will be nil on fail
func pageOptsFromQuery(s *hws.Server, w http.ResponseWriter, r *http.Request) *db.PageOpts {
return getPageOpts(s, w, r, validation.NewQueryGetter(r))
}
func getPageOpts(s *hws.Server, w http.ResponseWriter, r *http.Request, g validation.Getter) *db.PageOpts {
page := g.Int("page").Optional().Min(1).Value
perPage := g.Int("per_page").Optional().Min(1).Max(100).Value
order := g.String("order").TrimSpace().ToUpper().Optional().AllowedValues([]string{"ASC", "DESC"}).Value
orderBy := g.String("order_by").TrimSpace().Optional().ToLower().Value
valid := g.ValidateAndError(s, w, r)
if !valid {
return nil
}
pageOpts := &db.PageOpts{
Page: page,
PerPage: perPage,
Order: bun.Order(order),
OrderBy: orderBy,
}
return pageOpts
}

View File

@@ -20,7 +20,7 @@ import (
func Register(
s *hws.Server,
auth *hwsauth.Authenticator[*db.User, bun.Tx],
conn *bun.DB,
conn *db.DB,
cfg *config.Config,
store *store.Store,
) http.Handler {
@@ -55,7 +55,7 @@ func Register(
username := r.FormValue("username")
unique := false
var user *db.User
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
unique, err = db.IsUnique(ctx, tx, (*db.User)(nil), "username", username)
if err != nil {
return false, errors.Wrap(err, "db.IsUsernameUnique")
@@ -63,7 +63,7 @@ func Register(
if !unique {
return true, nil
}
user, err = db.CreateUser(ctx, tx, username, details.DiscordUser)
user, err = db.CreateUser(ctx, tx, username, details.DiscordUser, db.NewAudit(r, nil))
if err != nil {
return false, errors.Wrap(err, "db.CreateUser")
}

View File

@@ -14,14 +14,14 @@ import (
func SeasonPage(
s *hws.Server,
conn *bun.DB,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
seasonStr := r.PathValue("season_short_name")
var season *db.Season
var leaguesWithTeams []db.LeagueWithTeams
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
season, err = db.GetSeason(ctx, tx, seasonStr)
if err != nil {

View File

@@ -6,7 +6,6 @@ import (
"net/http"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/oslstats/internal/auditlog"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/notify"
"git.haelnorr.com/h/oslstats/internal/throw"
@@ -19,13 +18,13 @@ import (
func SeasonEditPage(
s *hws.Server,
conn *bun.DB,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
seasonStr := r.PathValue("season_short_name")
var season *db.Season
var allLeagues []*db.League
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
season, err = db.GetSeason(ctx, tx, seasonStr)
if err != nil {
@@ -49,8 +48,7 @@ func SeasonEditPage(
func SeasonEditSubmit(
s *hws.Server,
conn *bun.DB,
audit *auditlog.Logger,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
seasonStr := r.PathValue("season_short_name")
@@ -77,7 +75,7 @@ func SeasonEditSubmit(
}
var season *db.Season
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
season, err = db.GetSeason(ctx, tx, seasonStr)
if err != nil {
@@ -86,12 +84,9 @@ func SeasonEditSubmit(
if season == nil {
return false, errors.New("season does not exist")
}
season.Update(version, start, end, finalsStart, finalsEnd)
err = db.Update(tx, season).WherePK().
Column("slap_version", "start_date", "end_date", "finals_start_date", "finals_end_date").
WithAudit(r, audit.Callback()).Exec(ctx)
err = season.Update(ctx, tx, version, start, end, finalsStart, finalsEnd, db.NewAudit(r, nil))
if err != nil {
return false, errors.Wrap(err, "db.Update")
return false, errors.Wrap(err, "season.Update")
}
return true, nil
}); !ok {

View File

@@ -6,7 +6,6 @@ import (
"net/http"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/oslstats/internal/auditlog"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/notify"
"git.haelnorr.com/h/oslstats/internal/validation"
@@ -16,8 +15,7 @@ import (
func SeasonLeagueAddTeam(
s *hws.Server,
conn *bun.DB,
audit *auditlog.Logger,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
seasonStr := r.PathValue("season_short_name")
@@ -36,73 +34,12 @@ func SeasonLeagueAddTeam(
var league *db.League
var team *db.Team
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
// Get season
season, err = db.GetSeason(ctx, tx, seasonStr)
team, season, league, err = db.NewTeamParticipation(ctx, tx, seasonStr, leagueStr, teamID, db.NewAudit(r, nil))
if err != nil {
return false, errors.Wrap(err, "db.GetSeason")
return false, errors.Wrap(err, "db.NewTeamParticipation")
}
if season == nil {
notify.Warn(s, w, r, "Not Found", "Season not found.", nil)
return false, nil
}
// Get league
league, err = db.GetLeague(ctx, tx, leagueStr)
if err != nil {
return false, errors.Wrap(err, "db.GetLeague")
}
if league == nil {
notify.Warn(s, w, r, "Not Found", "League not found.", nil)
return false, nil
}
if !season.HasLeague(league.ID) {
notify.Warn(s, w, r, "Invalid League", "This league is not associated with this season.", nil)
return false, nil
}
// Get team
team, err = db.GetTeam(ctx, tx, teamID)
if err != nil {
return false, errors.Wrap(err, "db.GetTeam")
}
if team == nil {
notify.Warn(s, w, r, "Not Found", "Team not found.", nil)
return false, nil
}
// Check if team is already in this season (in any league)
var tpCount int
tpCount, err = tx.NewSelect().
Model((*db.TeamParticipation)(nil)).
Where("season_id = ? AND team_id = ?", season.ID, team.ID).
Count(ctx)
if err != nil {
return false, errors.Wrap(err, "tx.NewSelect")
}
if tpCount > 0 {
notify.Warn(s, w, r, "Already In Season", fmt.Sprintf(
"Team '%s' is already participating in this season.",
team.Name,
), nil)
return false, nil
}
// Add team to league
participation := &db.TeamParticipation{
SeasonID: season.ID,
LeagueID: league.ID,
TeamID: team.ID,
}
err = db.Insert(tx, participation).WithAudit(r, audit.Callback()).Exec(ctx)
if err != nil {
return false, errors.Wrap(err, "db.Insert")
}
return true, nil
}); !ok {
return

View File

@@ -14,7 +14,7 @@ import (
func SeasonLeaguePage(
s *hws.Server,
conn *bun.DB,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
seasonStr := r.PathValue("season_short_name")
@@ -25,7 +25,7 @@ func SeasonLeaguePage(
var teams []*db.Team
var allTeams []*db.Team
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
season, league, teams, err = db.GetSeasonLeague(ctx, tx, seasonStr, leagueStr)
if err != nil {

View File

@@ -8,7 +8,6 @@ import (
"github.com/pkg/errors"
"github.com/uptrace/bun"
"git.haelnorr.com/h/oslstats/internal/auditlog"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/notify"
"git.haelnorr.com/h/oslstats/internal/view/seasonsview"
@@ -16,8 +15,7 @@ import (
func SeasonAddLeague(
s *hws.Server,
conn *bun.DB,
audit *auditlog.Logger,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
seasonStr := r.PathValue("season_short_name")
@@ -25,32 +23,10 @@ func SeasonAddLeague(
var season *db.Season
var allLeagues []*db.League
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
season, err = db.GetSeason(ctx, tx, seasonStr)
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 {
return false, errors.Wrap(err, "db.GetSeason")
}
if season == nil {
return false, errors.New("season not found")
}
league, err := db.GetLeague(ctx, tx, leagueStr)
if err != nil {
return false, errors.Wrap(err, "db.GetLeague")
}
if league == nil {
return false, errors.New("league not found")
}
// Create the many-to-many relationship
seasonLeague := &db.SeasonLeague{
SeasonID: season.ID,
LeagueID: league.ID,
}
err = db.Insert(tx, seasonLeague).WithAudit(r, audit.Callback()).Exec(ctx)
if err != nil {
return false, errors.Wrap(err, "db.Insert")
return false, errors.Wrap(err, "db.NewSeasonLeague")
}
// Reload season with updated leagues
@@ -76,8 +52,7 @@ func SeasonAddLeague(
func SeasonRemoveLeague(
s *hws.Server,
conn *bun.DB,
audit *auditlog.Logger,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
seasonStr := r.PathValue("season_short_name")
@@ -85,7 +60,7 @@ func SeasonRemoveLeague(
var season *db.Season
var allLeagues []*db.League
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
season, err = db.GetSeason(ctx, tx, seasonStr)
if err != nil {
@@ -94,22 +69,9 @@ func SeasonRemoveLeague(
if season == nil {
return false, errors.New("season not found")
}
league, err := db.GetLeague(ctx, tx, leagueStr)
err = season.RemoveLeague(ctx, tx, leagueStr, db.NewAudit(r, nil))
if err != nil {
return false, errors.Wrap(err, "db.GetLeague")
}
if league == nil {
return false, errors.New("league not found")
}
// Delete the many-to-many relationship
err = db.DeleteItem[db.SeasonLeague](tx).
Where("season_id = ? AND league_id = ?", season.ID, league.ID).
WithAudit(r, audit.Callback()).
Delete(ctx)
if err != nil {
return false, errors.Wrap(err, "db.DeleteItem")
return false, errors.Wrap(err, "season.RemoveLeague")
}
// Reload season with updated leagues

View File

@@ -11,18 +11,18 @@ import (
"github.com/uptrace/bun"
)
// SeasonsPage renders the full page with the seasons list, for use with GET requests
// SeasonsPage renders the season list. On GET it returns the full page, otherwise it just returns the list
func SeasonsPage(
s *hws.Server,
conn *bun.DB,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pageOpts := pageOptsFromQuery(s, w, r)
if pageOpts == nil {
pageOpts, ok := db.GetPageOpts(s, w, r)
if !ok {
return
}
var seasons *db.List[db.Season]
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
seasons, err = db.ListSeasons(ctx, tx, pageOpts)
if err != nil {
@@ -32,31 +32,10 @@ func SeasonsPage(
}); !ok {
return
}
renderSafely(seasonsview.ListPage(seasons), s, r, w)
})
}
// SeasonsList renders just the seasons list, for use with POST requests and HTMX
func SeasonsList(
s *hws.Server,
conn *bun.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pageOpts := pageOptsFromForm(s, w, r)
if pageOpts == nil {
return
}
var seasons *db.List[db.Season]
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
seasons, err = db.ListSeasons(ctx, tx, pageOpts)
if err != nil {
return false, errors.Wrap(err, "db.ListSeasons")
}
return true, nil
}); !ok {
return
}
renderSafely(seasonsview.SeasonsList(seasons), s, r, w)
if r.Method == "GET" {
renderSafely(seasonsview.ListPage(seasons), s, r, w)
} else {
renderSafely(seasonsview.SeasonsList(seasons), s, r, w)
}
})
}

View File

@@ -6,7 +6,6 @@ import (
"net/http"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/oslstats/internal/auditlog"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/notify"
"git.haelnorr.com/h/oslstats/internal/validation"
@@ -18,20 +17,15 @@ import (
func NewSeason(
s *hws.Server,
conn *bun.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
renderSafely(seasonsview.NewPage(), s, r, w)
return
}
renderSafely(seasonsview.NewPage(), s, r, w)
})
}
func NewSeasonSubmit(
s *hws.Server,
conn *bun.DB,
audit *auditlog.Logger,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
getter, ok := validation.ParseFormOrNotify(s, w, r)
@@ -58,7 +52,7 @@ func NewSeasonSubmit(
nameUnique := false
shortNameUnique := false
var season *db.Season
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
nameUnique, err = db.IsUnique(ctx, tx, (*db.Season)(nil), "name", name)
if err != nil {
@@ -71,10 +65,9 @@ func NewSeasonSubmit(
if !nameUnique || !shortNameUnique {
return true, nil
}
season = db.NewSeason(name, version, shortname, start)
err = db.Insert(tx, season).WithAudit(r, audit.Callback()).Exec(ctx)
season, err = db.NewSeason(ctx, tx, name, version, shortname, start, db.NewAudit(r, nil))
if err != nil {
return false, errors.Wrap(err, "db.Insert")
return false, errors.Wrap(err, "db.NewSeason")
}
return true, nil
}); !ok {

View File

@@ -15,7 +15,7 @@ import (
// and also validates that they are different from each other
func IsTeamShortNamesUnique(
s *hws.Server,
conn *bun.DB,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
getter, err := validation.ParseForm(r)
@@ -38,7 +38,7 @@ func IsTeamShortNamesUnique(
}
var isUnique bool
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithReadTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
isUnique, err = db.TeamShortNamesUnique(ctx, tx, shortName, altShortName)
if err != nil {
return false, errors.Wrap(err, "db.TeamShortNamesUnique")

View File

@@ -14,15 +14,15 @@ import (
// TeamsPage renders the full page with the teams list, for use with GET requests
func TeamsPage(
s *hws.Server,
conn *bun.DB,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pageOpts := pageOptsFromQuery(s, w, r)
if pageOpts == nil {
pageOpts, ok := db.GetPageOpts(s, w, r)
if !ok {
return
}
var teams *db.List[db.Team]
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
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 {
@@ -39,15 +39,15 @@ func TeamsPage(
// TeamsList renders just the teams list, for use with POST requests and HTMX
func TeamsList(
s *hws.Server,
conn *bun.DB,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pageOpts := pageOptsFromForm(s, w, r)
if pageOpts == nil {
pageOpts, ok := db.GetPageOpts(s, w, r)
if !ok {
return
}
var teams *db.List[db.Team]
if ok := db.WithReadTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
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 {

View File

@@ -9,7 +9,6 @@ import (
"github.com/pkg/errors"
"github.com/uptrace/bun"
"git.haelnorr.com/h/oslstats/internal/auditlog"
"git.haelnorr.com/h/oslstats/internal/db"
"git.haelnorr.com/h/oslstats/internal/notify"
"git.haelnorr.com/h/oslstats/internal/validation"
@@ -18,7 +17,6 @@ import (
func NewTeamPage(
s *hws.Server,
conn *bun.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
renderSafely(teamsview.NewPage(), s, r, w)
@@ -27,8 +25,7 @@ func NewTeamPage(
func NewTeamSubmit(
s *hws.Server,
conn *bun.DB,
audit *auditlog.Logger,
conn *db.DB,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
getter, ok := validation.ParseFormOrNotify(s, w, r)
@@ -38,10 +35,10 @@ func NewTeamSubmit(
name := getter.String("name").
TrimSpace().Required().
MaxLength(25).MinLength(3).Value
shortname := getter.String("short_name").
shortName := getter.String("short_name").
TrimSpace().Required().
MaxLength(3).MinLength(3).Value
altShortname := getter.String("alt_short_name").
altShortName := getter.String("alt_short_name").
TrimSpace().Required().
MaxLength(3).MinLength(3).Value
color := getter.String("color").
@@ -51,22 +48,21 @@ func NewTeamSubmit(
}
// Check that short names are different
if shortname == altShortname {
if shortName == altShortName {
notify.Warn(s, w, r, "Invalid Short Names", "Short name and alternative short name must be different.", nil)
return
}
nameUnique := false
shortNameComboUnique := false
var team *db.Team
if ok := db.WithNotifyTx(s, w, r, conn, func(ctx context.Context, tx bun.Tx) (bool, error) {
if ok := conn.WithNotifyTx(s, w, r, func(ctx context.Context, tx bun.Tx) (bool, error) {
var err error
nameUnique, err = db.IsUnique(ctx, tx, (*db.Team)(nil), "name", name)
if err != nil {
return false, errors.Wrap(err, "db.IsTeamNameUnique")
}
shortNameComboUnique, err = db.TeamShortNamesUnique(ctx, tx, shortname, altShortname)
shortNameComboUnique, err = db.TeamShortNamesUnique(ctx, tx, shortName, altShortName)
if err != nil {
return false, errors.Wrap(err, "db.TeamShortNamesUnique")
}
@@ -74,15 +70,9 @@ func NewTeamSubmit(
if !nameUnique || !shortNameComboUnique {
return true, nil
}
team = &db.Team{
Name: name,
ShortName: shortname,
AltShortName: altShortname,
Color: color,
}
err = db.Insert(tx, team).WithAudit(r, audit.Callback()).Exec(ctx)
_, err = db.NewTeam(ctx, tx, name, shortName, altShortName, color, db.NewAudit(r, nil))
if err != nil {
return false, errors.Wrap(err, "db.Insert")
return false, errors.Wrap(err, "db.NewTeam")
}
return true, nil
}); !ok {