Skip to content

Commit a3f1528

Browse files
refactor(policy): refactor policy management to use Role model
- Replaced Policy references with Role in PolicyManager and RoleEvaluator classes. - Updated related methods and properties to reflect the change from policies to roles. - Introduced a new Role model to encapsulate role-based access control logic. - Adjusted integration and unit tests to validate the new role-based structure.
1 parent d9b9879 commit a3f1528

File tree

7 files changed

+267
-269
lines changed

7 files changed

+267
-269
lines changed

lib/src/core/policy_manager.dart

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import 'package:flutter_policy_engine/src/core/interfaces/i_policy_evaluator.dar
33
import 'package:flutter_policy_engine/src/core/interfaces/i_policy_storage.dart';
44
import 'package:flutter_policy_engine/src/core/memory_policy_storage.dart';
55
import 'package:flutter_policy_engine/src/core/role_evaluator.dart';
6-
import 'package:flutter_policy_engine/src/models/policy.dart';
6+
import 'package:flutter_policy_engine/src/models/role.dart';
77
import 'package:flutter_policy_engine/src/utils/json_handler.dart';
88
import 'package:flutter_policy_engine/src/utils/log_handler.dart';
99

@@ -40,7 +40,7 @@ class PolicyManager extends ChangeNotifier {
4040
IPolicyEvaluator? _evaluator;
4141

4242
/// Internal cache of loaded policies, keyed by policy identifier.
43-
Map<String, Policy> _policies = {};
43+
Map<String, Role> _roles = {};
4444

4545
/// Indicates whether the policy manager has been initialized with policy data.
4646
bool _isInitialized = false;
@@ -54,15 +54,15 @@ class PolicyManager extends ChangeNotifier {
5454
///
5555
/// The returned map cannot be modified directly. Use [initialize] to update
5656
/// the policy collection.
57-
Map<String, Policy> get policies => Map.unmodifiable(_policies);
57+
Map<String, Role> get roles => Map.unmodifiable(_roles);
5858

5959
/// Initializes the policy manager with policy data from JSON.
6060
///
6161
/// Parses the provided [jsonPolicies] and loads them into the internal cache.
6262
/// This method should be called before using any policy-related functionality.
6363
///
6464
/// [jsonPolicies] should be a map where keys are policy identifiers and values
65-
/// are JSON representations of [Policy] objects.
65+
/// are JSON representations of [Role] objects.
6666
///
6767
/// Throws:
6868
/// - [JsonParseException] if policy parsing fails completely
@@ -118,30 +118,30 @@ class PolicyManager extends ChangeNotifier {
118118
}
119119

120120
// Create the policy and add to valid policies
121-
final policy = Policy(
122-
roleName: key,
121+
final role = Role(
122+
name: key,
123123
allowedContent: value.cast<String>(),
124124
);
125-
validPolicies[key] = policy.toJson();
125+
validPolicies[key] = role.toJson();
126126
}
127127

128-
_policies = JsonHandler.parseMap(
128+
_roles = JsonHandler.parseMap(
129129
validPolicies,
130-
(json) => Policy.fromJson(json),
130+
(json) => Role.fromJson(json),
131131
context: 'policy_manager',
132132
allowPartialSuccess: true,
133133
);
134134

135135
// Only create evaluator if we have at least some policies
136-
if (_policies.isNotEmpty) {
137-
_evaluator = RoleEvaluator(_policies);
138-
await _storage.savePolicies(_policies);
136+
if (_roles.isNotEmpty) {
137+
_evaluator = RoleEvaluator(_roles);
138+
await _storage.savePolicies(_roles);
139139
_isInitialized = true;
140140

141141
LogHandler.info(
142142
'Policy manager initialized successfully',
143143
context: {
144-
'loaded_policies': _policies.length,
144+
'loaded_policies': _roles.length,
145145
'total_policies': jsonPolicies.length,
146146
},
147147
operation: 'policy_manager_initialized',

lib/src/core/role_evaluator.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'package:flutter_policy_engine/src/core/interfaces/i_policy_evaluator.dart';
2-
import 'package:flutter_policy_engine/src/models/policy.dart';
2+
import 'package:flutter_policy_engine/src/models/role.dart';
33
import 'package:meta/meta.dart';
44

55
/// A policy evaluator that determines access permissions based on role-based policies.
@@ -8,7 +8,7 @@ import 'package:meta/meta.dart';
88
/// role-based access control functionality. It evaluates whether content is
99
/// allowed for a specific role by checking against predefined policies.
1010
///
11-
/// Each role is associated with a [Policy] that defines the rules for content
11+
/// Each role is associated with a [Role] that defines the rules for content
1212
/// evaluation. If no policy exists for a given role, access is denied by default.
1313
///
1414
/// Example usage:
@@ -25,7 +25,7 @@ class RoleEvaluator implements IPolicyEvaluator {
2525
/// Creates a new [RoleEvaluator] with the specified policies.
2626
///
2727
/// The [policies] parameter should contain a mapping of role names to their
28-
/// corresponding [Policy] objects. Each policy defines the rules for content
28+
/// corresponding [Role] objects. Each policy defines the rules for content
2929
/// evaluation for that specific role.
3030
///
3131
/// Throws an [ArgumentError] if [policies] is null.
@@ -35,8 +35,8 @@ class RoleEvaluator implements IPolicyEvaluator {
3535
///
3636
/// This map contains all available policies that can be evaluated by this
3737
/// evaluator. The key is the role name and the value is the corresponding
38-
/// [Policy] object.
39-
final Map<String, Policy> _policies;
38+
/// [Role] object.
39+
final Map<String, Role> _policies;
4040

4141
/// Evaluates whether the specified content is allowed for the given role.
4242
///
@@ -45,11 +45,11 @@ class RoleEvaluator implements IPolicyEvaluator {
4545
///
4646
/// Returns `true` if:
4747
/// - A policy exists for the [roleName]
48-
/// - The policy's [Policy.isContentAllowed] method returns `true` for the [content]
48+
/// - The policy's [Role.isContentAllowed] method returns `true` for the [content]
4949
///
5050
/// Returns `false` if:
5151
/// - No policy exists for the [roleName]
52-
/// - The policy's [Policy.isContentAllowed] method returns `false` for the [content]
52+
/// - The policy's [Role.isContentAllowed] method returns `false` for the [content]
5353
///
5454
/// Parameters:
5555
/// - [roleName]: The name of the role to evaluate permissions for

lib/src/models/policy.dart renamed to lib/src/models/role.dart

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,25 @@ import 'package:collection/collection.dart';
1717
/// );
1818
/// ```
1919
@immutable
20-
class Policy {
20+
class Role {
2121
/// Creates a new policy with the specified role name and allowed content.
2222
///
23-
/// The [roleName] identifies the role this policy applies to.
23+
/// The [name] identifies the role this policy applies to.
2424
/// The [allowedContent] list contains the content types or actions that are
2525
/// permitted for this role. The [metadata] provides additional configuration
2626
/// options and defaults to an empty map if not specified.
2727
///
28-
/// Throws an [ArgumentError] if [roleName] is empty or [allowedContent] is null.
29-
const Policy({
30-
required this.roleName,
28+
/// Throws an [ArgumentError] if [name] is empty or [allowedContent] is null.
29+
const Role({
30+
required this.name,
3131
required this.allowedContent,
3232
this.metadata = const {},
3333
});
3434

3535
/// The name of the role this policy applies to.
3636
///
3737
/// This should be a unique identifier for the role within your application.
38-
final String roleName;
38+
final String name;
3939

4040
/// List of content types or actions that are allowed for this role.
4141
///
@@ -52,7 +52,7 @@ class Policy {
5252

5353
/// Creates a copy of this policy with the given fields replaced by new values.
5454
///
55-
/// Returns a new [Policy] instance with the same values as this one,
55+
/// Returns a new [Role] instance with the same values as this one,
5656
/// except for the fields that are explicitly provided in the parameters.
5757
///
5858
/// Example:
@@ -62,13 +62,13 @@ class Policy {
6262
/// metadata: {'priority': 'low'},
6363
/// );
6464
/// ```
65-
Policy copyWith({
66-
String? roleName,
65+
Role copyWith({
66+
String? name,
6767
List<String>? allowedContent,
6868
Map<String, dynamic>? metadata,
6969
}) =>
70-
Policy(
71-
roleName: roleName ?? this.roleName,
70+
Role(
71+
name: name ?? this.name,
7272
allowedContent: allowedContent ?? this.allowedContent,
7373
metadata: metadata ?? this.metadata,
7474
);
@@ -88,15 +88,15 @@ class Policy {
8888

8989
/// Compares this policy with another object for equality.
9090
///
91-
/// Two policies are considered equal if they have the same [roleName] and
91+
/// Two policies are considered equal if they have the same [name] and
9292
/// the same [allowedContent] (regardless of order). The [metadata] is not
9393
/// considered in the equality comparison.
9494
@override
9595
bool operator ==(Object other) {
9696
if (identical(this, other)) return true;
97-
if (other is! Policy) return false;
97+
if (other is! Role) return false;
9898

99-
if (roleName != other.roleName) return false;
99+
if (name != other.name) return false;
100100
if (allowedContent.length != other.allowedContent.length) return false;
101101

102102
// Sort both lists to ensure order-independent comparison (same as hashCode)
@@ -108,22 +108,22 @@ class Policy {
108108

109109
/// Returns the hash code for this policy.
110110
///
111-
/// The hash code is based on the [roleName] and [allowedContent] fields.
111+
/// The hash code is based on the [name] and [allowedContent] fields.
112112
/// The allowedContent is sorted to ensure consistent hash codes regardless of order.
113113
@override
114114
int get hashCode {
115115
final sortedContent = List<String>.from(allowedContent)..sort();
116-
return Object.hash(roleName, const ListEquality().hash(sortedContent));
116+
return Object.hash(name, const ListEquality().hash(sortedContent));
117117
}
118118

119119
/// Returns a string representation of this policy.
120120
///
121121
/// The string includes the role name, allowed content, and metadata.
122122
@override
123123
String toString() =>
124-
'Policy(roleName: $roleName, allowedContent: $allowedContent, metadata: $metadata)';
124+
'Policy(roleName: $name, allowedContent: $allowedContent, metadata: $metadata)';
125125

126-
/// Creates a [Policy] instance from a JSON map.
126+
/// Creates a [Role] instance from a JSON map.
127127
///
128128
/// The JSON map should contain:
129129
/// - `roleName`: A string representing the role name
@@ -141,12 +141,12 @@ class Policy {
141141
/// };
142142
/// final policy = Policy.fromJson(json);
143143
/// ```
144-
factory Policy.fromJson(Map<String, dynamic> json) {
145-
final roleName = json['roleName'];
144+
factory Role.fromJson(Map<String, dynamic> json) {
145+
final name = json['roleName'];
146146
final allowedContent = json['allowedContent'];
147147
final metadata = json['metadata'];
148148

149-
if (roleName == null || roleName is! String) {
149+
if (name == null || name is! String) {
150150
throw ArgumentError('roleName must be a non-null string');
151151
}
152152
if (allowedContent == null || allowedContent is! List) {
@@ -156,8 +156,8 @@ class Policy {
156156
throw ArgumentError('All allowedContent items must be strings');
157157
}
158158

159-
return Policy(
160-
roleName: roleName,
159+
return Role(
160+
name: name,
161161
allowedContent: allowedContent.cast<String>(),
162162
metadata:
163163
metadata is Map<String, dynamic> ? metadata : <String, dynamic>{},
@@ -179,7 +179,7 @@ class Policy {
179179
/// // }
180180
/// ```
181181
Map<String, dynamic> toJson() => {
182-
'roleName': roleName,
182+
'roleName': name,
183183
'allowedContent': allowedContent,
184184
'metadata': metadata,
185185
};

0 commit comments

Comments
 (0)