package db import ( "context" "git.haelnorr.com/h/oslstats/internal/roles" "github.com/pkg/errors" "github.com/uptrace/bun" ) type UserRole struct { UserID int `bun:",pk"` User *User `bun:"rel:belongs-to,join:user_id=id"` RoleID int `bun:",pk"` Role *Role `bun:"rel:belongs-to,join:role_id=id"` } // AssignRole grants a role to a user func AssignRole(ctx context.Context, tx bun.Tx, userID, roleID int) error { if userID <= 0 { return errors.New("userID must be positive") } if roleID <= 0 { return errors.New("roleID must be positive") } userRole := &UserRole{ UserID: userID, RoleID: roleID, } err := Insert(tx, userRole). ConflictNothing("user_id", "role_id").Exec(ctx) if err != nil { return errors.Wrap(err, "db.Insert") } return nil } // RevokeRole removes a role from a user func RevokeRole(ctx context.Context, tx bun.Tx, userID, roleID int) error { if userID <= 0 { return errors.New("userID must be positive") } if roleID <= 0 { return errors.New("roleID must be positive") } err := DeleteItem[UserRole](tx). Where("user_id = ?", userID). Where("role_id = ?", roleID). Delete(ctx) if err != nil { return errors.Wrap(err, "tx.NewDelete") } return nil } // HasRole checks if a user has a specific role func HasRole(ctx context.Context, tx bun.Tx, userID int, roleName roles.Role) (bool, error) { if userID <= 0 { return false, errors.New("userID must be positive") } if roleName == "" { return false, errors.New("roleName cannot be empty") } user, err := GetByID[User](tx, userID). Relation("Roles").GetFirst(ctx) if err != nil { return false, errors.Wrap(err, "GetByID") } if user == nil { return false, nil } for _, role := range user.Roles { if role.Name == roleName { return true, nil } } return false, nil }