From dcb84d8a9f4dfe7269a59561646fb253225da3a5 Mon Sep 17 00:00:00 2001 From: Ariel Mashraki <7413593+a8m@users.noreply.github.com> Date: Sun, 7 May 2023 17:52:09 +0300 Subject: [PATCH] ent/privacy: move some of the generated privacy helpers to ent/privacy (#3527) --- entc/gen/template/privacy/privacy.tmpl | 62 +++--------- .../customid/ent/privacy/privacy.go | 71 ++++---------- .../edgeschema/ent/privacy/privacy.go | 71 ++++---------- .../privacy/ent/privacy/privacy.go | 71 ++++---------- examples/privacyadmin/ent/privacy/privacy.go | 71 ++++---------- examples/privacytenant/ent/privacy/privacy.go | 71 ++++---------- privacy/privacy.go | 96 ++++++++++++++++++- 7 files changed, 184 insertions(+), 329 deletions(-) diff --git a/entc/gen/template/privacy/privacy.tmpl b/entc/gen/template/privacy/privacy.tmpl index df5c33795..d2196eb96 100644 --- a/entc/gen/template/privacy/privacy.tmpl +++ b/entc/gen/template/privacy/privacy.tmpl @@ -35,9 +35,9 @@ var ( ) {{- range $decision := list "Allow" "Deny" "Skip" }} - // {{ $decision }}f returns an formatted wrapped {{ $decision }} decision. + // {{ $decision }}f returns a formatted wrapped {{ $decision }} decision. func {{ $decision }}f(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, {{ $decision }})...) + return privacy.{{ $decision }}f(format, a...) } {{- end }} @@ -67,6 +67,12 @@ type ( MutationRule = privacy.MutationRule // MutationPolicy combines multiple mutation rules into a single policy. MutationPolicy = privacy.MutationPolicy + // MutationRuleFunc type is an adapter which allows the use of + // ordinary functions as mutation rules. + MutationRuleFunc = privacy.MutationRuleFunc + + // QueryMutationRule is an interface which groups query and mutation rules. + QueryMutationRule = privacy.QueryMutationRule ) // QueryRuleFunc type is an adapter to allow the use of @@ -78,68 +84,24 @@ func (f QueryRuleFunc) EvalQuery(ctx context.Context, q {{ $pkg }}.Query) error return f(ctx, q) } -// MutationRuleFunc type is an adapter which allows the use of -// ordinary functions as mutation rules. -type MutationRuleFunc func(context.Context, {{ $pkg }}.Mutation) error - -// EvalMutation returns f(ctx, m). -func (f MutationRuleFunc) EvalMutation(ctx context.Context, m {{ $pkg }}.Mutation) error { - return f(ctx, m) -} - -// QueryMutationRule is an interface which groups query and mutation rules. -type QueryMutationRule interface { - QueryRule - MutationRule -} - // AlwaysAllowRule returns a rule that returns an allow decision. func AlwaysAllowRule() QueryMutationRule { - return fixedDecision{Allow} + return privacy.AlwaysAllowRule() } // AlwaysDenyRule returns a rule that returns a deny decision. func AlwaysDenyRule() QueryMutationRule { - return fixedDecision{Deny} -} - -type fixedDecision struct { - decision error -} - -func (f fixedDecision) EvalQuery(context.Context, {{ $pkg }}.Query) error { - return f.decision -} - -func (f fixedDecision) EvalMutation(context.Context, {{ $pkg }}.Mutation) error { - return f.decision -} - -type contextDecision struct { - eval func(context.Context) error + return privacy.AlwaysDenyRule() } // ContextQueryMutationRule creates a query/mutation rule from a context eval func. func ContextQueryMutationRule(eval func(context.Context) error) QueryMutationRule { - return contextDecision{eval} -} - -func (c contextDecision) EvalQuery(ctx context.Context, _ {{ $pkg }}.Query) error { - return c.eval(ctx) -} - -func (c contextDecision) EvalMutation(ctx context.Context, _ {{ $pkg }}.Mutation) error { - return c.eval(ctx) + return privacy.ContextQueryMutationRule(eval) } // OnMutationOperation evaluates the given rule only on a given mutation operation. func OnMutationOperation(rule MutationRule, op {{ $pkg }}.Op) MutationRule { - return MutationRuleFunc(func(ctx context.Context, m {{ $pkg }}.Mutation) error { - if m.Op().Is(op) { - return rule.EvalMutation(ctx, m) - } - return Skip - }) + return privacy.OnMutationOperation(rule, op) } // DenyMutationOperationRule returns a rule denying specified mutation operation. diff --git a/entc/integration/customid/ent/privacy/privacy.go b/entc/integration/customid/ent/privacy/privacy.go index e4e852980..b1607c932 100644 --- a/entc/integration/customid/ent/privacy/privacy.go +++ b/entc/integration/customid/ent/privacy/privacy.go @@ -8,7 +8,6 @@ package privacy import ( "context" - "fmt" "entgo.io/ent/entc/integration/customid/ent" "entgo.io/ent/entql" @@ -30,19 +29,19 @@ var ( Skip = privacy.Skip ) -// Allowf returns an formatted wrapped Allow decision. +// Allowf returns a formatted wrapped Allow decision. func Allowf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Allow)...) + return privacy.Allowf(format, a...) } -// Denyf returns an formatted wrapped Deny decision. +// Denyf returns a formatted wrapped Deny decision. func Denyf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Deny)...) + return privacy.Denyf(format, a...) } -// Skipf returns an formatted wrapped Skip decision. +// Skipf returns a formatted wrapped Skip decision. func Skipf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Skip)...) + return privacy.Skipf(format, a...) } // DecisionContext creates a new context from the given parent context with @@ -71,6 +70,12 @@ type ( MutationRule = privacy.MutationRule // MutationPolicy combines multiple mutation rules into a single policy. MutationPolicy = privacy.MutationPolicy + // MutationRuleFunc type is an adapter which allows the use of + // ordinary functions as mutation rules. + MutationRuleFunc = privacy.MutationRuleFunc + + // QueryMutationRule is an interface which groups query and mutation rules. + QueryMutationRule = privacy.QueryMutationRule ) // QueryRuleFunc type is an adapter to allow the use of @@ -82,68 +87,24 @@ func (f QueryRuleFunc) EvalQuery(ctx context.Context, q ent.Query) error { return f(ctx, q) } -// MutationRuleFunc type is an adapter which allows the use of -// ordinary functions as mutation rules. -type MutationRuleFunc func(context.Context, ent.Mutation) error - -// EvalMutation returns f(ctx, m). -func (f MutationRuleFunc) EvalMutation(ctx context.Context, m ent.Mutation) error { - return f(ctx, m) -} - -// QueryMutationRule is an interface which groups query and mutation rules. -type QueryMutationRule interface { - QueryRule - MutationRule -} - // AlwaysAllowRule returns a rule that returns an allow decision. func AlwaysAllowRule() QueryMutationRule { - return fixedDecision{Allow} + return privacy.AlwaysAllowRule() } // AlwaysDenyRule returns a rule that returns a deny decision. func AlwaysDenyRule() QueryMutationRule { - return fixedDecision{Deny} -} - -type fixedDecision struct { - decision error -} - -func (f fixedDecision) EvalQuery(context.Context, ent.Query) error { - return f.decision -} - -func (f fixedDecision) EvalMutation(context.Context, ent.Mutation) error { - return f.decision -} - -type contextDecision struct { - eval func(context.Context) error + return privacy.AlwaysDenyRule() } // ContextQueryMutationRule creates a query/mutation rule from a context eval func. func ContextQueryMutationRule(eval func(context.Context) error) QueryMutationRule { - return contextDecision{eval} -} - -func (c contextDecision) EvalQuery(ctx context.Context, _ ent.Query) error { - return c.eval(ctx) -} - -func (c contextDecision) EvalMutation(ctx context.Context, _ ent.Mutation) error { - return c.eval(ctx) + return privacy.ContextQueryMutationRule(eval) } // OnMutationOperation evaluates the given rule only on a given mutation operation. func OnMutationOperation(rule MutationRule, op ent.Op) MutationRule { - return MutationRuleFunc(func(ctx context.Context, m ent.Mutation) error { - if m.Op().Is(op) { - return rule.EvalMutation(ctx, m) - } - return Skip - }) + return privacy.OnMutationOperation(rule, op) } // DenyMutationOperationRule returns a rule denying specified mutation operation. diff --git a/entc/integration/edgeschema/ent/privacy/privacy.go b/entc/integration/edgeschema/ent/privacy/privacy.go index fc31816d7..9562a8beb 100644 --- a/entc/integration/edgeschema/ent/privacy/privacy.go +++ b/entc/integration/edgeschema/ent/privacy/privacy.go @@ -8,7 +8,6 @@ package privacy import ( "context" - "fmt" "entgo.io/ent/entc/integration/edgeschema/ent" "entgo.io/ent/entql" @@ -30,19 +29,19 @@ var ( Skip = privacy.Skip ) -// Allowf returns an formatted wrapped Allow decision. +// Allowf returns a formatted wrapped Allow decision. func Allowf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Allow)...) + return privacy.Allowf(format, a...) } -// Denyf returns an formatted wrapped Deny decision. +// Denyf returns a formatted wrapped Deny decision. func Denyf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Deny)...) + return privacy.Denyf(format, a...) } -// Skipf returns an formatted wrapped Skip decision. +// Skipf returns a formatted wrapped Skip decision. func Skipf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Skip)...) + return privacy.Skipf(format, a...) } // DecisionContext creates a new context from the given parent context with @@ -71,6 +70,12 @@ type ( MutationRule = privacy.MutationRule // MutationPolicy combines multiple mutation rules into a single policy. MutationPolicy = privacy.MutationPolicy + // MutationRuleFunc type is an adapter which allows the use of + // ordinary functions as mutation rules. + MutationRuleFunc = privacy.MutationRuleFunc + + // QueryMutationRule is an interface which groups query and mutation rules. + QueryMutationRule = privacy.QueryMutationRule ) // QueryRuleFunc type is an adapter to allow the use of @@ -82,68 +87,24 @@ func (f QueryRuleFunc) EvalQuery(ctx context.Context, q ent.Query) error { return f(ctx, q) } -// MutationRuleFunc type is an adapter which allows the use of -// ordinary functions as mutation rules. -type MutationRuleFunc func(context.Context, ent.Mutation) error - -// EvalMutation returns f(ctx, m). -func (f MutationRuleFunc) EvalMutation(ctx context.Context, m ent.Mutation) error { - return f(ctx, m) -} - -// QueryMutationRule is an interface which groups query and mutation rules. -type QueryMutationRule interface { - QueryRule - MutationRule -} - // AlwaysAllowRule returns a rule that returns an allow decision. func AlwaysAllowRule() QueryMutationRule { - return fixedDecision{Allow} + return privacy.AlwaysAllowRule() } // AlwaysDenyRule returns a rule that returns a deny decision. func AlwaysDenyRule() QueryMutationRule { - return fixedDecision{Deny} -} - -type fixedDecision struct { - decision error -} - -func (f fixedDecision) EvalQuery(context.Context, ent.Query) error { - return f.decision -} - -func (f fixedDecision) EvalMutation(context.Context, ent.Mutation) error { - return f.decision -} - -type contextDecision struct { - eval func(context.Context) error + return privacy.AlwaysDenyRule() } // ContextQueryMutationRule creates a query/mutation rule from a context eval func. func ContextQueryMutationRule(eval func(context.Context) error) QueryMutationRule { - return contextDecision{eval} -} - -func (c contextDecision) EvalQuery(ctx context.Context, _ ent.Query) error { - return c.eval(ctx) -} - -func (c contextDecision) EvalMutation(ctx context.Context, _ ent.Mutation) error { - return c.eval(ctx) + return privacy.ContextQueryMutationRule(eval) } // OnMutationOperation evaluates the given rule only on a given mutation operation. func OnMutationOperation(rule MutationRule, op ent.Op) MutationRule { - return MutationRuleFunc(func(ctx context.Context, m ent.Mutation) error { - if m.Op().Is(op) { - return rule.EvalMutation(ctx, m) - } - return Skip - }) + return privacy.OnMutationOperation(rule, op) } // DenyMutationOperationRule returns a rule denying specified mutation operation. diff --git a/entc/integration/privacy/ent/privacy/privacy.go b/entc/integration/privacy/ent/privacy/privacy.go index 38838fc79..3a04ac036 100644 --- a/entc/integration/privacy/ent/privacy/privacy.go +++ b/entc/integration/privacy/ent/privacy/privacy.go @@ -8,7 +8,6 @@ package privacy import ( "context" - "fmt" "entgo.io/ent/entc/integration/privacy/ent" "entgo.io/ent/entql" @@ -30,19 +29,19 @@ var ( Skip = privacy.Skip ) -// Allowf returns an formatted wrapped Allow decision. +// Allowf returns a formatted wrapped Allow decision. func Allowf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Allow)...) + return privacy.Allowf(format, a...) } -// Denyf returns an formatted wrapped Deny decision. +// Denyf returns a formatted wrapped Deny decision. func Denyf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Deny)...) + return privacy.Denyf(format, a...) } -// Skipf returns an formatted wrapped Skip decision. +// Skipf returns a formatted wrapped Skip decision. func Skipf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Skip)...) + return privacy.Skipf(format, a...) } // DecisionContext creates a new context from the given parent context with @@ -71,6 +70,12 @@ type ( MutationRule = privacy.MutationRule // MutationPolicy combines multiple mutation rules into a single policy. MutationPolicy = privacy.MutationPolicy + // MutationRuleFunc type is an adapter which allows the use of + // ordinary functions as mutation rules. + MutationRuleFunc = privacy.MutationRuleFunc + + // QueryMutationRule is an interface which groups query and mutation rules. + QueryMutationRule = privacy.QueryMutationRule ) // QueryRuleFunc type is an adapter to allow the use of @@ -82,68 +87,24 @@ func (f QueryRuleFunc) EvalQuery(ctx context.Context, q ent.Query) error { return f(ctx, q) } -// MutationRuleFunc type is an adapter which allows the use of -// ordinary functions as mutation rules. -type MutationRuleFunc func(context.Context, ent.Mutation) error - -// EvalMutation returns f(ctx, m). -func (f MutationRuleFunc) EvalMutation(ctx context.Context, m ent.Mutation) error { - return f(ctx, m) -} - -// QueryMutationRule is an interface which groups query and mutation rules. -type QueryMutationRule interface { - QueryRule - MutationRule -} - // AlwaysAllowRule returns a rule that returns an allow decision. func AlwaysAllowRule() QueryMutationRule { - return fixedDecision{Allow} + return privacy.AlwaysAllowRule() } // AlwaysDenyRule returns a rule that returns a deny decision. func AlwaysDenyRule() QueryMutationRule { - return fixedDecision{Deny} -} - -type fixedDecision struct { - decision error -} - -func (f fixedDecision) EvalQuery(context.Context, ent.Query) error { - return f.decision -} - -func (f fixedDecision) EvalMutation(context.Context, ent.Mutation) error { - return f.decision -} - -type contextDecision struct { - eval func(context.Context) error + return privacy.AlwaysDenyRule() } // ContextQueryMutationRule creates a query/mutation rule from a context eval func. func ContextQueryMutationRule(eval func(context.Context) error) QueryMutationRule { - return contextDecision{eval} -} - -func (c contextDecision) EvalQuery(ctx context.Context, _ ent.Query) error { - return c.eval(ctx) -} - -func (c contextDecision) EvalMutation(ctx context.Context, _ ent.Mutation) error { - return c.eval(ctx) + return privacy.ContextQueryMutationRule(eval) } // OnMutationOperation evaluates the given rule only on a given mutation operation. func OnMutationOperation(rule MutationRule, op ent.Op) MutationRule { - return MutationRuleFunc(func(ctx context.Context, m ent.Mutation) error { - if m.Op().Is(op) { - return rule.EvalMutation(ctx, m) - } - return Skip - }) + return privacy.OnMutationOperation(rule, op) } // DenyMutationOperationRule returns a rule denying specified mutation operation. diff --git a/examples/privacyadmin/ent/privacy/privacy.go b/examples/privacyadmin/ent/privacy/privacy.go index 47a9d0fe6..d531893b0 100644 --- a/examples/privacyadmin/ent/privacy/privacy.go +++ b/examples/privacyadmin/ent/privacy/privacy.go @@ -8,7 +8,6 @@ package privacy import ( "context" - "fmt" "entgo.io/ent/examples/privacyadmin/ent" @@ -29,19 +28,19 @@ var ( Skip = privacy.Skip ) -// Allowf returns an formatted wrapped Allow decision. +// Allowf returns a formatted wrapped Allow decision. func Allowf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Allow)...) + return privacy.Allowf(format, a...) } -// Denyf returns an formatted wrapped Deny decision. +// Denyf returns a formatted wrapped Deny decision. func Denyf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Deny)...) + return privacy.Denyf(format, a...) } -// Skipf returns an formatted wrapped Skip decision. +// Skipf returns a formatted wrapped Skip decision. func Skipf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Skip)...) + return privacy.Skipf(format, a...) } // DecisionContext creates a new context from the given parent context with @@ -70,6 +69,12 @@ type ( MutationRule = privacy.MutationRule // MutationPolicy combines multiple mutation rules into a single policy. MutationPolicy = privacy.MutationPolicy + // MutationRuleFunc type is an adapter which allows the use of + // ordinary functions as mutation rules. + MutationRuleFunc = privacy.MutationRuleFunc + + // QueryMutationRule is an interface which groups query and mutation rules. + QueryMutationRule = privacy.QueryMutationRule ) // QueryRuleFunc type is an adapter to allow the use of @@ -81,68 +86,24 @@ func (f QueryRuleFunc) EvalQuery(ctx context.Context, q ent.Query) error { return f(ctx, q) } -// MutationRuleFunc type is an adapter which allows the use of -// ordinary functions as mutation rules. -type MutationRuleFunc func(context.Context, ent.Mutation) error - -// EvalMutation returns f(ctx, m). -func (f MutationRuleFunc) EvalMutation(ctx context.Context, m ent.Mutation) error { - return f(ctx, m) -} - -// QueryMutationRule is an interface which groups query and mutation rules. -type QueryMutationRule interface { - QueryRule - MutationRule -} - // AlwaysAllowRule returns a rule that returns an allow decision. func AlwaysAllowRule() QueryMutationRule { - return fixedDecision{Allow} + return privacy.AlwaysAllowRule() } // AlwaysDenyRule returns a rule that returns a deny decision. func AlwaysDenyRule() QueryMutationRule { - return fixedDecision{Deny} -} - -type fixedDecision struct { - decision error -} - -func (f fixedDecision) EvalQuery(context.Context, ent.Query) error { - return f.decision -} - -func (f fixedDecision) EvalMutation(context.Context, ent.Mutation) error { - return f.decision -} - -type contextDecision struct { - eval func(context.Context) error + return privacy.AlwaysDenyRule() } // ContextQueryMutationRule creates a query/mutation rule from a context eval func. func ContextQueryMutationRule(eval func(context.Context) error) QueryMutationRule { - return contextDecision{eval} -} - -func (c contextDecision) EvalQuery(ctx context.Context, _ ent.Query) error { - return c.eval(ctx) -} - -func (c contextDecision) EvalMutation(ctx context.Context, _ ent.Mutation) error { - return c.eval(ctx) + return privacy.ContextQueryMutationRule(eval) } // OnMutationOperation evaluates the given rule only on a given mutation operation. func OnMutationOperation(rule MutationRule, op ent.Op) MutationRule { - return MutationRuleFunc(func(ctx context.Context, m ent.Mutation) error { - if m.Op().Is(op) { - return rule.EvalMutation(ctx, m) - } - return Skip - }) + return privacy.OnMutationOperation(rule, op) } // DenyMutationOperationRule returns a rule denying specified mutation operation. diff --git a/examples/privacytenant/ent/privacy/privacy.go b/examples/privacytenant/ent/privacy/privacy.go index 14ffddc7c..f64e5029e 100644 --- a/examples/privacytenant/ent/privacy/privacy.go +++ b/examples/privacytenant/ent/privacy/privacy.go @@ -8,7 +8,6 @@ package privacy import ( "context" - "fmt" "entgo.io/ent/entql" "entgo.io/ent/examples/privacytenant/ent" @@ -30,19 +29,19 @@ var ( Skip = privacy.Skip ) -// Allowf returns an formatted wrapped Allow decision. +// Allowf returns a formatted wrapped Allow decision. func Allowf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Allow)...) + return privacy.Allowf(format, a...) } -// Denyf returns an formatted wrapped Deny decision. +// Denyf returns a formatted wrapped Deny decision. func Denyf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Deny)...) + return privacy.Denyf(format, a...) } -// Skipf returns an formatted wrapped Skip decision. +// Skipf returns a formatted wrapped Skip decision. func Skipf(format string, a ...any) error { - return fmt.Errorf(format+": %w", append(a, Skip)...) + return privacy.Skipf(format, a...) } // DecisionContext creates a new context from the given parent context with @@ -71,6 +70,12 @@ type ( MutationRule = privacy.MutationRule // MutationPolicy combines multiple mutation rules into a single policy. MutationPolicy = privacy.MutationPolicy + // MutationRuleFunc type is an adapter which allows the use of + // ordinary functions as mutation rules. + MutationRuleFunc = privacy.MutationRuleFunc + + // QueryMutationRule is an interface which groups query and mutation rules. + QueryMutationRule = privacy.QueryMutationRule ) // QueryRuleFunc type is an adapter to allow the use of @@ -82,68 +87,24 @@ func (f QueryRuleFunc) EvalQuery(ctx context.Context, q ent.Query) error { return f(ctx, q) } -// MutationRuleFunc type is an adapter which allows the use of -// ordinary functions as mutation rules. -type MutationRuleFunc func(context.Context, ent.Mutation) error - -// EvalMutation returns f(ctx, m). -func (f MutationRuleFunc) EvalMutation(ctx context.Context, m ent.Mutation) error { - return f(ctx, m) -} - -// QueryMutationRule is an interface which groups query and mutation rules. -type QueryMutationRule interface { - QueryRule - MutationRule -} - // AlwaysAllowRule returns a rule that returns an allow decision. func AlwaysAllowRule() QueryMutationRule { - return fixedDecision{Allow} + return privacy.AlwaysAllowRule() } // AlwaysDenyRule returns a rule that returns a deny decision. func AlwaysDenyRule() QueryMutationRule { - return fixedDecision{Deny} -} - -type fixedDecision struct { - decision error -} - -func (f fixedDecision) EvalQuery(context.Context, ent.Query) error { - return f.decision -} - -func (f fixedDecision) EvalMutation(context.Context, ent.Mutation) error { - return f.decision -} - -type contextDecision struct { - eval func(context.Context) error + return privacy.AlwaysDenyRule() } // ContextQueryMutationRule creates a query/mutation rule from a context eval func. func ContextQueryMutationRule(eval func(context.Context) error) QueryMutationRule { - return contextDecision{eval} -} - -func (c contextDecision) EvalQuery(ctx context.Context, _ ent.Query) error { - return c.eval(ctx) -} - -func (c contextDecision) EvalMutation(ctx context.Context, _ ent.Mutation) error { - return c.eval(ctx) + return privacy.ContextQueryMutationRule(eval) } // OnMutationOperation evaluates the given rule only on a given mutation operation. func OnMutationOperation(rule MutationRule, op ent.Op) MutationRule { - return MutationRuleFunc(func(ctx context.Context, m ent.Mutation) error { - if m.Op().Is(op) { - return rule.EvalMutation(ctx, m) - } - return Skip - }) + return privacy.OnMutationOperation(rule, op) } // DenyMutationOperationRule returns a rule denying specified mutation operation. diff --git a/privacy/privacy.go b/privacy/privacy.go index 6494a5d45..0ae99e5e0 100644 --- a/privacy/privacy.go +++ b/privacy/privacy.go @@ -9,6 +9,7 @@ package privacy import ( "context" "errors" + "fmt" "entgo.io/ent" ) @@ -28,6 +29,36 @@ var ( Skip = errors.New("ent/privacy: skip rule") ) +// Allowf returns a formatted wrapped Allow decision. +func Allowf(format string, a ...any) error { + return fmt.Errorf(format+": %w", append(a, Allow)...) +} + +// Denyf returns a formatted wrapped Deny decision. +func Denyf(format string, a ...any) error { + return fmt.Errorf(format+": %w", append(a, Deny)...) +} + +// Skipf returns a formatted wrapped Skip decision. +func Skipf(format string, a ...any) error { + return fmt.Errorf(format+": %w", append(a, Skip)...) +} + +// AlwaysAllowRule returns a rule that returns an allow decision. +func AlwaysAllowRule() QueryMutationRule { + return fixedDecision{Allow} +} + +// AlwaysDenyRule returns a rule that returns a deny decision. +func AlwaysDenyRule() QueryMutationRule { + return fixedDecision{Deny} +} + +// ContextQueryMutationRule creates a query/mutation rule from a context eval func. +func ContextQueryMutationRule(eval func(context.Context) error) QueryMutationRule { + return contextDecision{eval} +} + type ( // QueryRule defines the interface deciding whether a // query is allowed and optionally modify it. @@ -47,13 +78,46 @@ type ( // MutationPolicy combines multiple mutation rules into a single policy. MutationPolicy []MutationRule - // Policy groups query and mutation policies. - Policy struct { - Query QueryPolicy - Mutation MutationPolicy + // QueryMutationRule is an interface which groups query and mutation rules. + QueryMutationRule interface { + QueryRule + MutationRule } ) +// MutationRuleFunc type is an adapter which allows the use of +// ordinary functions as mutation rules. +type MutationRuleFunc func(context.Context, ent.Mutation) error + +// EvalMutation returns f(ctx, m). +func (f MutationRuleFunc) EvalMutation(ctx context.Context, m ent.Mutation) error { + return f(ctx, m) +} + +// OnMutationOperation evaluates the given rule only on a given mutation operation. +func OnMutationOperation(rule MutationRule, op ent.Op) MutationRule { + return MutationRuleFunc(func(ctx context.Context, m ent.Mutation) error { + if m.Op().Is(op) { + return rule.EvalMutation(ctx, m) + } + return Skip + }) +} + +// DenyMutationOperationRule returns a rule denying specified mutation operation. +func DenyMutationOperationRule(op ent.Op) MutationRule { + rule := MutationRuleFunc(func(_ context.Context, m ent.Mutation) error { + return Denyf("ent/privacy: operation %s is not allowed", m.Op()) + }) + return OnMutationOperation(rule, op) +} + +// Policy groups query and mutation policies. +type Policy struct { + Query QueryPolicy + Mutation MutationPolicy +} + // EvalQuery forwards evaluation to query a policy. func (p Policy) EvalQuery(ctx context.Context, q ent.Query) error { return p.Query.EvalQuery(ctx, q) @@ -160,3 +224,27 @@ func DecisionFromContext(ctx context.Context) (error, bool) { } return decision, ok } + +type fixedDecision struct { + decision error +} + +func (f fixedDecision) EvalQuery(context.Context, ent.Query) error { + return f.decision +} + +func (f fixedDecision) EvalMutation(context.Context, ent.Mutation) error { + return f.decision +} + +type contextDecision struct { + eval func(context.Context) error +} + +func (c contextDecision) EvalQuery(ctx context.Context, _ ent.Query) error { + return c.eval(ctx) +} + +func (c contextDecision) EvalMutation(ctx context.Context, _ ent.Mutation) error { + return c.eval(ctx) +}