fixed relationship issues

This commit is contained in:
2026-02-05 00:10:10 +11:00
parent 20308fe35c
commit 4c31c24069
22 changed files with 236 additions and 254 deletions

View File

@@ -2,7 +2,6 @@ package db
import (
"context"
"time"
"git.haelnorr.com/h/oslstats/internal/roles"
"github.com/pkg/errors"
@@ -10,42 +9,14 @@ import (
)
type UserRole struct {
bun.BaseModel `bun:"table:user_roles,alias:ur"`
ID int `bun:"id,pk,autoincrement"`
UserID int `bun:"user_id,notnull"`
RoleID int `bun:"role_id,notnull"`
GrantedBy *int `bun:"granted_by"`
GrantedAt int64 `bun:"granted_at,notnull"` // TODO: default now
ExpiresAt *int64 `bun:"expires_at"`
// Relations
User *User `bun:"rel:belongs-to,join:user_id=id"`
Role *Role `bun:"rel:belongs-to,join:role_id=id"`
}
// GetUserRoles loads all roles for a given user
func GetUserRoles(ctx context.Context, tx bun.Tx, userID int) ([]*Role, error) {
if userID <= 0 {
return nil, errors.New("userID must be positive")
}
var roles []*Role
err := tx.NewSelect().
Model(&roles).
// TODO: why are we joining? can we do relation?
Join("JOIN user_roles AS ur ON ur.role_id = r.id").
Where("ur.user_id = ?", userID).
Where("ur.expires_at IS NULL OR ur.expires_at > ?", time.Now().Unix()).
Scan(ctx)
if err != nil {
return nil, errors.Wrap(err, "tx.NewSelect")
}
return roles, nil
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, grantedBy *int) error {
func AssignRole(ctx context.Context, tx bun.Tx, userID, roleID int) error {
if userID <= 0 {
return errors.New("userID must be positive")
}
@@ -53,16 +24,16 @@ func AssignRole(ctx context.Context, tx bun.Tx, userID, roleID int, grantedBy *i
return errors.New("roleID must be positive")
}
now := time.Now().Unix()
// TODO: use proper m2m table instead of raw SQL
_, err := tx.ExecContext(ctx, `
INSERT INTO user_roles (user_id, role_id, granted_by, granted_at)
VALUES ($1, $2, $3, $4)
ON CONFLICT (user_id, role_id) DO NOTHING
`, userID, roleID, grantedBy, now)
userRole := &UserRole{
UserID: userID,
RoleID: roleID,
}
_, err := tx.NewInsert().
Model(userRole).
On("CONFLICT (user_id, role_id) DO NOTHING").
Exec(ctx)
if err != nil {
return errors.Wrap(err, "tx.ExecContext")
return errors.Wrap(err, "tx.NewInsert")
}
return nil
@@ -77,13 +48,13 @@ func RevokeRole(ctx context.Context, tx bun.Tx, userID, roleID int) error {
return errors.New("roleID must be positive")
}
// TODO: use proper m2m table instead of raw sql
_, err := tx.ExecContext(ctx, `
DELETE FROM user_roles
WHERE user_id = $1 AND role_id = $2
`, userID, roleID)
_, err := tx.NewDelete().
Model((*UserRole)(nil)).
Where("user_id = ?", userID).
Where("role_id = ?", roleID).
Exec(ctx)
if err != nil {
return errors.Wrap(err, "tx.ExecContext")
return errors.Wrap(err, "tx.NewDelete")
}
return nil
@@ -97,18 +68,19 @@ func HasRole(ctx context.Context, tx bun.Tx, userID int, roleName roles.Role) (b
if roleName == "" {
return false, errors.New("roleName cannot be empty")
}
// TODO: use proper m2m table instead of TableExpr and Join?
count, err := tx.NewSelect().
TableExpr("user_roles AS ur").
Join("JOIN roles AS r ON r.id = ur.role_id").
Where("ur.user_id = ?", userID).
Where("r.name = ?", roleName).
Where("ur.expires_at IS NULL OR ur.expires_at > ?", time.Now().Unix()).
Count(ctx)
user := new(User)
err := tx.NewSelect().
Model(user).
Relation("Roles").
Where("u.id = ? ", userID).
Scan(ctx)
if err != nil {
return false, errors.Wrap(err, "tx.NewSelect")
}
return count > 0, nil
for _, role := range user.Roles {
if role.Name == roleName {
return true, nil
}
}
return false, nil
}