big ole refactor
This commit is contained in:
47
internal/db/migrations/20250124000001_initial_schema.go
Normal file
47
internal/db/migrations/20250124000001_initial_schema.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.haelnorr.com/h/oslstats/internal/db"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Migrations.MustRegister(
|
||||
// UP: Create initial tables (users, discord_tokens)
|
||||
func(ctx context.Context, conn *bun.DB) error {
|
||||
// Create users table
|
||||
_, err := conn.NewCreateTable().
|
||||
Model((*db.User)(nil)).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create discord_tokens table
|
||||
_, err = conn.NewCreateTable().
|
||||
Model((*db.DiscordToken)(nil)).
|
||||
Exec(ctx)
|
||||
return err
|
||||
},
|
||||
// DOWN: Drop tables in reverse order
|
||||
func(ctx context.Context, conn *bun.DB) error {
|
||||
// Drop discord_tokens first (has foreign key to users)
|
||||
_, err := conn.NewDropTable().
|
||||
Model((*db.DiscordToken)(nil)).
|
||||
IfExists().
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Drop users table
|
||||
_, err = conn.NewDropTable().
|
||||
Model((*db.User)(nil)).
|
||||
IfExists().
|
||||
Exec(ctx)
|
||||
return err
|
||||
},
|
||||
)
|
||||
}
|
||||
34
internal/db/migrations/20260127194815_seasons.go
Normal file
34
internal/db/migrations/20260127194815_seasons.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.haelnorr.com/h/oslstats/internal/db"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Migrations.MustRegister(
|
||||
// UP migration
|
||||
func(ctx context.Context, conn *bun.DB) error {
|
||||
_, err := conn.NewCreateTable().
|
||||
Model((*db.Season)(nil)).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
// DOWN migration
|
||||
func(ctx context.Context, conn *bun.DB) error {
|
||||
_, err := conn.NewDropTable().
|
||||
Model((*db.Season)(nil)).
|
||||
IfExists().
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
}
|
||||
253
internal/db/migrations/20260202231414_add_rbac_system.go
Normal file
253
internal/db/migrations/20260202231414_add_rbac_system.go
Normal file
@@ -0,0 +1,253 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.haelnorr.com/h/oslstats/internal/db"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Migrations.MustRegister(
|
||||
// UP migration
|
||||
func(ctx context.Context, conn *bun.DB) error {
|
||||
conn.RegisterModel((*db.RolePermission)(nil), (*db.UserRole)(nil))
|
||||
// Create permissions table
|
||||
_, err := conn.NewCreateTable().
|
||||
Model((*db.Role)(nil)).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create permissions table
|
||||
_, err = conn.NewCreateTable().
|
||||
Model((*db.Permission)(nil)).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create indexes for permissions
|
||||
_, err = conn.NewCreateIndex().
|
||||
Model((*db.Permission)(nil)).
|
||||
Index("idx_permissions_resource").
|
||||
Column("resource").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.NewCreateIndex().
|
||||
Model((*db.Permission)(nil)).
|
||||
Index("idx_permissions_action").
|
||||
Column("action").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.NewCreateTable().
|
||||
Model((*db.RolePermission)(nil)).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.ExecContext(ctx, `
|
||||
CREATE INDEX idx_role_permissions_role ON role_permissions(role_id)
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.ExecContext(ctx, `
|
||||
CREATE INDEX idx_role_permissions_permission ON role_permissions(permission_id)
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create user_roles table
|
||||
_, err = conn.NewCreateTable().
|
||||
Model((*db.UserRole)(nil)).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create indexes for user_roles
|
||||
_, err = conn.NewCreateIndex().
|
||||
Model((*db.UserRole)(nil)).
|
||||
Index("idx_user_roles_user").
|
||||
Column("user_id").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.NewCreateIndex().
|
||||
Model((*db.UserRole)(nil)).
|
||||
Index("idx_user_roles_role").
|
||||
Column("role_id").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create audit_log table
|
||||
_, err = conn.NewCreateTable().
|
||||
Model((*db.AuditLog)(nil)).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create indexes for audit_log
|
||||
_, err = conn.NewCreateIndex().
|
||||
Model((*db.AuditLog)(nil)).
|
||||
Index("idx_audit_log_user").
|
||||
Column("user_id").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.NewCreateIndex().
|
||||
Model((*db.AuditLog)(nil)).
|
||||
Index("idx_audit_log_action").
|
||||
Column("action").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.NewCreateIndex().
|
||||
Model((*db.AuditLog)(nil)).
|
||||
Index("idx_audit_log_resource").
|
||||
Column("resource_type", "resource_id").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = conn.NewCreateIndex().
|
||||
Model((*db.AuditLog)(nil)).
|
||||
Index("idx_audit_log_created").
|
||||
Column("created_at").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = seedSystemRBAC(ctx, conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
// DOWN migration
|
||||
func(ctx context.Context, dbConn *bun.DB) error {
|
||||
// Drop tables in reverse order
|
||||
// Use raw SQL to avoid relationship resolution issues
|
||||
tables := []string{
|
||||
"audit_log",
|
||||
"user_roles",
|
||||
"role_permissions",
|
||||
"permissions",
|
||||
"roles",
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
_, err := dbConn.ExecContext(ctx, "DROP TABLE IF EXISTS "+table+" CASCADE")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func seedSystemRBAC(ctx context.Context, conn *bun.DB) error {
|
||||
// Seed system roles
|
||||
now := time.Now().Unix()
|
||||
|
||||
adminRole := &db.Role{
|
||||
Name: "admin",
|
||||
DisplayName: "Administrator",
|
||||
Description: "Full system access with all permissions",
|
||||
IsSystem: true,
|
||||
CreatedAt: now,
|
||||
}
|
||||
|
||||
_, err := conn.NewInsert().
|
||||
Model(adminRole).
|
||||
Returning("id").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "dbConn.NewInsert")
|
||||
}
|
||||
|
||||
userRole := &db.Role{
|
||||
Name: "user",
|
||||
DisplayName: "User",
|
||||
Description: "Standard user with basic permissions",
|
||||
IsSystem: true,
|
||||
CreatedAt: now,
|
||||
}
|
||||
|
||||
_, err = conn.NewInsert().
|
||||
Model(userRole).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "dbConn.NewInsert")
|
||||
}
|
||||
|
||||
// Seed system permissions
|
||||
permissionsData := []*db.Permission{
|
||||
{Name: "*", DisplayName: "Wildcard (All Permissions)", Description: "Grants access to all permissions, past, present, and future", Resource: "*", Action: "*", IsSystem: true, CreatedAt: now},
|
||||
{Name: "seasons.create", DisplayName: "Create Seasons", Description: "Create new seasons", Resource: "seasons", Action: "create", IsSystem: true, CreatedAt: now},
|
||||
{Name: "seasons.update", DisplayName: "Update Seasons", Description: "Update existing seasons", Resource: "seasons", Action: "update", IsSystem: true, CreatedAt: now},
|
||||
{Name: "seasons.delete", DisplayName: "Delete Seasons", Description: "Delete seasons", Resource: "seasons", Action: "delete", IsSystem: true, CreatedAt: now},
|
||||
{Name: "users.update", DisplayName: "Update Users", Description: "Update user information", Resource: "users", Action: "update", IsSystem: true, CreatedAt: now},
|
||||
{Name: "users.ban", DisplayName: "Ban Users", Description: "Ban users from the system", Resource: "users", Action: "ban", IsSystem: true, CreatedAt: now},
|
||||
{Name: "users.manage_roles", DisplayName: "Manage User Roles", Description: "Assign and revoke user roles", Resource: "users", Action: "manage_roles", IsSystem: true, CreatedAt: now},
|
||||
}
|
||||
|
||||
_, err = conn.NewInsert().
|
||||
Model(&permissionsData).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "dbConn.NewInsert")
|
||||
}
|
||||
|
||||
// Grant wildcard permission to admin role using Bun
|
||||
// First, get the IDs
|
||||
var wildcardPerm db.Permission
|
||||
err = conn.NewSelect().
|
||||
Model(&wildcardPerm).
|
||||
Where("name = ?", "*").
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Insert role_permission mapping
|
||||
adminRolePerms := &db.RolePermission{
|
||||
RoleID: adminRole.ID,
|
||||
PermissionID: wildcardPerm.ID,
|
||||
}
|
||||
_, err = conn.NewInsert().
|
||||
Model(adminRolePerms).
|
||||
On("CONFLICT (role_id, permission_id) DO NOTHING").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "dbConn.NewInsert")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
67
internal/db/migrations/20260210182212_add_leagues.go
Normal file
67
internal/db/migrations/20260210182212_add_leagues.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/uptrace/bun"
|
||||
|
||||
"git.haelnorr.com/h/oslstats/internal/db"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Migrations.MustRegister(
|
||||
// UP migration
|
||||
func(ctx context.Context, conn *bun.DB) error {
|
||||
// Add slap_version column to seasons table
|
||||
_, err := conn.NewAddColumn().
|
||||
Model((*db.Season)(nil)).
|
||||
ColumnExpr("slap_version VARCHAR NOT NULL DEFAULT 'rebound'").
|
||||
IfNotExists().
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create leagues table
|
||||
_, err = conn.NewCreateTable().
|
||||
Model((*db.League)(nil)).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create season_leagues join table
|
||||
_, err = conn.NewCreateTable().
|
||||
Model((*db.SeasonLeague)(nil)).
|
||||
Exec(ctx)
|
||||
return err
|
||||
},
|
||||
// DOWN migration
|
||||
func(ctx context.Context, conn *bun.DB) error {
|
||||
// Drop season_leagues join table first
|
||||
_, err := conn.NewDropTable().
|
||||
Model((*db.SeasonLeague)(nil)).
|
||||
IfExists().
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Drop leagues table
|
||||
_, err = conn.NewDropTable().
|
||||
Model((*db.League)(nil)).
|
||||
IfExists().
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove slap_version column from seasons table
|
||||
_, err = conn.NewDropColumn().
|
||||
Model((*db.Season)(nil)).
|
||||
ColumnExpr("slap_version").
|
||||
Exec(ctx)
|
||||
return err
|
||||
},
|
||||
)
|
||||
}
|
||||
49
internal/db/migrations/20260211225253_teams.go
Normal file
49
internal/db/migrations/20260211225253_teams.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.haelnorr.com/h/oslstats/internal/db"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Migrations.MustRegister(
|
||||
// UP migration
|
||||
func(ctx context.Context, conn *bun.DB) error {
|
||||
// Add your migration code here
|
||||
_, err := conn.NewCreateTable().
|
||||
Model((*db.Team)(nil)).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = conn.NewCreateTable().
|
||||
Model((*db.TeamParticipation)(nil)).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
// DOWN migration
|
||||
func(ctx context.Context, conn *bun.DB) error {
|
||||
// Add your rollback code here
|
||||
_, err := conn.NewDropTable().
|
||||
Model((*db.TeamParticipation)(nil)).
|
||||
IfExists().
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = conn.NewDropTable().
|
||||
Model((*db.Team)(nil)).
|
||||
IfExists().
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
}
|
||||
44
internal/db/migrations/20260213162216_missing_permissions.go
Normal file
44
internal/db/migrations/20260213162216_missing_permissions.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"git.haelnorr.com/h/oslstats/internal/db"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Migrations.MustRegister(
|
||||
// UP migration
|
||||
func(ctx context.Context, conn *bun.DB) error {
|
||||
// Add your migration code here
|
||||
now := time.Now().Unix()
|
||||
permissionsData := []*db.Permission{
|
||||
{Name: "seasons.add_league", DisplayName: "Add Leagues to Season", Description: "Assign an existing league to Seasons", Resource: "seasons", Action: "add_league", IsSystem: true, CreatedAt: now},
|
||||
{Name: "seasons.remove_league", DisplayName: "Remove Leagues from a Season", Description: "Remove an assigned league league from Seasons", Resource: "seasons", Action: "remove_league", IsSystem: true, CreatedAt: now},
|
||||
{Name: "leagues.create", DisplayName: "Create Leagues", Description: "Create new leagues", Resource: "leagues", Action: "create", IsSystem: true, CreatedAt: now},
|
||||
{Name: "leagues.update", DisplayName: "Update Leagues", Description: "Update existing leagues", Resource: "leagues", Action: "update", IsSystem: true, CreatedAt: now},
|
||||
{Name: "leagues.delete", DisplayName: "Delete Leagues", Description: "Delete leagues", Resource: "leagues", Action: "delete", IsSystem: true, CreatedAt: now},
|
||||
{Name: "teams.create", DisplayName: "Create Teams", Description: "Create new teams", Resource: "teams", Action: "create", IsSystem: true, CreatedAt: now},
|
||||
{Name: "teams.update", DisplayName: "Update Teams", Description: "Update existing teams", Resource: "teams", Action: "update", IsSystem: true, CreatedAt: now},
|
||||
{Name: "teams.delete", DisplayName: "Delete Teams", Description: "Delete teams", Resource: "teams", Action: "delete", IsSystem: true, CreatedAt: now},
|
||||
{Name: "teams.add_to_league", DisplayName: "Add Teams to League", Description: "Add an existing team to a league/season", Resource: "teams", Action: "add_to_league", IsSystem: true, CreatedAt: now},
|
||||
}
|
||||
|
||||
_, err := conn.NewInsert().
|
||||
Model(&permissionsData).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "dbConn.NewInsert")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
// DOWN migration
|
||||
func(ctx context.Context, dbConn *bun.DB) error {
|
||||
// Add your rollback code here
|
||||
return nil
|
||||
},
|
||||
)
|
||||
}
|
||||
9
internal/db/migrations/migrations.go
Normal file
9
internal/db/migrations/migrations.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// Package migrations defines the database migrations to apply when using the migrate tags
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
// Migrations is the collection of all database migrations
|
||||
var Migrations = migrate.NewMigrations()
|
||||
Reference in New Issue
Block a user