package db import ( "context" "database/sql" "git.haelnorr.com/h/oslstats/internal/permissions" "github.com/pkg/errors" "github.com/uptrace/bun" ) type Permission struct { bun.BaseModel `bun:"table:permissions,alias:p"` ID int `bun:"id,pk,autoincrement"` Name permissions.Permission `bun:"name,unique,notnull"` DisplayName string `bun:"display_name,notnull"` Description string `bun:"description"` Resource string `bun:"resource,notnull"` Action string `bun:"action,notnull"` IsSystem bool `bun:"is_system,default:false"` CreatedAt int64 `bun:"created_at,notnull"` } // GetPermissionByName queries the database for a permission matching the given name // Returns nil, nil if no permission is found func GetPermissionByName(ctx context.Context, tx bun.Tx, name permissions.Permission) (*Permission, error) { if name == "" { return nil, errors.New("name cannot be empty") } perm := new(Permission) err := tx.NewSelect(). Model(perm). Where("name = ?", name). Limit(1). Scan(ctx) if err != nil && err != sql.ErrNoRows { return nil, errors.Wrap(err, "tx.NewSelect") } return perm, nil } // GetPermissionByID queries the database for a permission matching the given ID // Returns nil, nil if no permission is found func GetPermissionByID(ctx context.Context, tx bun.Tx, id int) (*Permission, error) { if id <= 0 { return nil, errors.New("id must be positive") } perm := new(Permission) err := tx.NewSelect(). Model(perm). Where("id = ?", id). Limit(1). Scan(ctx) if err != nil && err != sql.ErrNoRows { return nil, errors.Wrap(err, "tx.NewSelect") } return perm, nil } // GetPermissionsByResource queries for all permissions for a given resource func GetPermissionsByResource(ctx context.Context, tx bun.Tx, resource string) ([]*Permission, error) { if resource == "" { return nil, errors.New("resource cannot be empty") } var perms []*Permission err := tx.NewSelect(). Model(&perms). Where("resource = ?", resource). Order("action ASC"). Scan(ctx) if err != nil && err != sql.ErrNoRows { return nil, errors.Wrap(err, "tx.NewSelect") } return perms, nil } // GetPermissionsByIDs queries for permissions matching the given IDs func GetPermissionsByIDs(ctx context.Context, tx bun.Tx, ids []int) ([]*Permission, error) { if len(ids) == 0 { return []*Permission{}, nil } var perms []*Permission err := tx.NewSelect(). Model(&perms). Where("id IN (?)", bun.In(ids)). Scan(ctx) if err != nil && err != sql.ErrNoRows { return nil, errors.Wrap(err, "tx.NewSelect") } return perms, nil } // ListAllPermissions returns all permissions func ListAllPermissions(ctx context.Context, tx bun.Tx) ([]*Permission, error) { var perms []*Permission err := tx.NewSelect(). Model(&perms). Order("resource ASC", "action ASC"). Scan(ctx) if err != nil && err != sql.ErrNoRows { return nil, errors.Wrap(err, "tx.NewSelect") } return perms, nil } // CreatePermission creates a new permission func CreatePermission(ctx context.Context, tx bun.Tx, perm *Permission) error { if perm == nil { return errors.New("permission cannot be nil") } _, err := tx.NewInsert(). Model(perm). Exec(ctx) if err != nil { return errors.Wrap(err, "tx.NewInsert") } return nil } // DeletePermission deletes a permission (checks IsSystem protection) func DeletePermission(ctx context.Context, tx bun.Tx, id int) error { if id <= 0 { return errors.New("id must be positive") } // Check if permission is system permission perm, err := GetPermissionByID(ctx, tx, id) if err != nil { return errors.Wrap(err, "GetPermissionByID") } if perm == nil { return errors.New("permission not found") } if perm.IsSystem { return errors.New("cannot delete system permission") } _, err = tx.NewDelete(). Model((*Permission)(nil)). Where("id = ?", id). Exec(ctx) if err != nil { return errors.Wrap(err, "tx.NewDelete") } return nil }