Role Management Demo
Dynamic role creation, updating, and removal demonstration
Role Management Demo
This advanced example demonstrates the dynamic role management capabilities of the Flutter Policy Engine. The demo shows how to create, update, and remove roles at runtime, providing a comprehensive testing environment for policy management operations.
🎯 Demo Overview
The Role Management Demo provides:
- Dynamic Role Creation: Add new roles with custom permissions
- Role Updates: Modify existing role permissions
- Role Removal: Delete roles from the system
- Real-time Testing: Test policy changes immediately
- Interactive UI: User-friendly forms for role management
- Status Feedback: Clear feedback for all operations
📱 Complete Demo Code
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_policy_engine/flutter_policy_engine.dart';
class RoleManagementDemo extends StatefulWidget {
const RoleManagementDemo({super.key});
@override
State<RoleManagementDemo> createState() => _RoleManagementDemoState();
}
class _RoleManagementDemoState extends State<RoleManagementDemo> {
late PolicyManager policyManager;
bool _isInitialized = false;
String _selectedRole = 'guest';
// Form controllers for role management
final TextEditingController _roleNameController = TextEditingController();
final TextEditingController _permissionsController = TextEditingController();
// Status messages
String _statusMessage = '';
bool _isSuccess = true;
@override
void initState() {
super.initState();
_initializePolicyManager();
}
@override
void dispose() {
_roleNameController.dispose();
_permissionsController.dispose();
super.dispose();
}
Future<void> _initializePolicyManager() async {
policyManager = PolicyManager();
final policies = {
"admin": ["LoginPage", "Dashboard", "UserManagement", "Settings"],
"user": ["LoginPage", "Dashboard"],
"guest": ["LoginPage"]
};
try {
await policyManager.initialize(policies);
setState(() {
_isInitialized = true;
_selectedRole = 'guest';
});
} catch (e) {
log(e.toString());
setState(() {
_isInitialized = false;
_statusMessage = 'Failed to initialize: $e';
_isSuccess = false;
});
}
}
void _showStatus(String message, bool isSuccess) {
setState(() {
_statusMessage = message;
_isSuccess = isSuccess;
});
// Clear status after 3 seconds
Future.delayed(const Duration(seconds: 3), () {
if (mounted) {
setState(() {
_statusMessage = '';
});
}
});
}
Future<void> _addRole() async {
final roleName = _roleNameController.text.trim();
final permissionsText = _permissionsController.text.trim();
if (roleName.isEmpty) {
_showStatus('Role name cannot be empty', false);
return;
}
try {
final permissions = permissionsText.isEmpty
? <String>[]
: permissionsText.split(',').map((e) => e.trim()).toList();
final role = Role(name: roleName, allowedContent: permissions);
await policyManager.addRole(role);
_showStatus('Role "$roleName" added successfully', true);
_roleNameController.clear();
_permissionsController.clear();
// Update selected role if it's the new one
setState(() {
_selectedRole = roleName;
});
} catch (e) {
_showStatus('Failed to add role: $e', false);
}
}
Future<void> _updateRole() async {
final roleName = _roleNameController.text.trim();
final permissionsText = _permissionsController.text.trim();
if (roleName.isEmpty) {
_showStatus('Role name cannot be empty', false);
return;
}
try {
final permissions = permissionsText.isEmpty
? <String>[]
: permissionsText.split(',').map((e) => e.trim()).toList();
final role = Role(name: roleName, allowedContent: permissions);
await policyManager.updateRole(role);
_showStatus('Role "$roleName" updated successfully', true);
_roleNameController.clear();
_permissionsController.clear();
} catch (e) {
_showStatus('Failed to update role: $e', false);
}
}
Future<void> _removeRole() async {
final roleName = _roleNameController.text.trim();
if (roleName.isEmpty) {
_showStatus('Role name cannot be empty', false);
return;
}
try {
await policyManager.removeRole(roleName);
_showStatus('Role "$roleName" removed successfully', true);
_roleNameController.clear();
_permissionsController.clear();
// Reset selected role if it was removed
if (_selectedRole == roleName) {
setState(() {
_selectedRole = 'guest';
});
}
} catch (e) {
_showStatus('Failed to remove role: $e', false);
}
}
void _selectRole(String roleName) {
setState(() {
_selectedRole = roleName;
_roleNameController.text = roleName;
// Get current permissions for the role
final role = policyManager.getRole(roleName);
if (role != null) {
_permissionsController.text = role.allowedContent.join(', ');
}
});
}
@override
Widget build(BuildContext context) {
if (!_isInitialized) {
return Scaffold(
appBar: AppBar(
title: const Text('Role Management Demo'),
),
body: const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
SizedBox(height: 16),
Text('Loading policies...'),
],
),
),
);
}
return PolicyProvider(
policyManager: policyManager,
child: Scaffold(
appBar: AppBar(
title: const Text('Role Management Demo'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Status message
if (_statusMessage.isNotEmpty)
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: _isSuccess ? Colors.green[100] : Colors.red[100],
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: _isSuccess ? Colors.green : Colors.red,
),
),
child: Text(
_statusMessage,
style: TextStyle(
color: _isSuccess ? Colors.green[800] : Colors.red[800],
),
),
),
// Current roles section
_buildCurrentRolesSection(),
const SizedBox(height: 32),
// Role management forms
_buildRoleManagementForms(),
const SizedBox(height: 32),
// Policy testing section
_buildPolicyTestingSection(),
],
),
),
),
);
}
Widget _buildCurrentRolesSection() {
final roles = policyManager.getAllRoles();
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Current Roles',
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: roles.map((role) {
final isSelected = _selectedRole == role.name;
return GestureDetector(
onTap: () => _selectRole(role.name),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
decoration: BoxDecoration(
color: isSelected ? Colors.blue : Colors.grey[200],
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: isSelected ? Colors.blue : Colors.grey[300]!,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
role.name,
style: TextStyle(
color: isSelected ? Colors.white : Colors.black,
fontWeight: FontWeight.bold,
),
),
if (role.allowedContent.isNotEmpty)
Text(
'Permissions: ${role.allowedContent.join(', ')}',
style: TextStyle(
color: isSelected ? Colors.white70 : Colors.grey[600],
fontSize: 12,
),
),
],
),
),
);
}).toList(),
),
],
),
),
);
}
Widget _buildRoleManagementForms() {
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Role Management',
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 16),
// Role name input
TextField(
controller: _roleNameController,
decoration: const InputDecoration(
labelText: 'Role Name',
hintText: 'Enter role name (e.g., moderator)',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
// Permissions input
TextField(
controller: _permissionsController,
decoration: const InputDecoration(
labelText: 'Permissions',
hintText: 'Enter permissions separated by commas (e.g., LoginPage, Dashboard, Settings)',
border: OutlineInputBorder(),
),
maxLines: 2,
),
const SizedBox(height: 24),
// Action buttons
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: _addRole,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
),
child: const Text('Add Role'),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton(
onPressed: _updateRole,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange,
foregroundColor: Colors.white,
),
child: const Text('Update Role'),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton(
onPressed: _removeRole,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
),
child: const Text('Remove Role'),
),
),
],
),
],
),
),
);
}
Widget _buildPolicyTestingSection() {
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Policy Testing',
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 8),
Text(
'Selected Role: $_selectedRole',
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(height: 16),
// Policy widgets for testing
_buildPolicyTest('LoginPage', 'Login Page'),
_buildPolicyTest('Dashboard', 'Dashboard'),
_buildPolicyTest('UserManagement', 'User Management'),
_buildPolicyTest('Settings', 'Settings'),
],
),
),
);
}
Widget _buildPolicyTest(String content, String displayName) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('$displayName:'),
const SizedBox(height: 4),
PolicyWidget(
role: _selectedRole,
content: content,
fallback: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.red[100],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.red),
),
child: Text('Access denied for $displayName'),
),
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.green[100],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.green),
),
child: Text('Access granted to $displayName'),
),
),
],
),
);
}
}
Add Role
Future<void> _addRole() async {
final roleName = _roleNameController.text.trim();
final permissionsText = _permissionsController.text.trim();
final permissions = permissionsText.split(',').map((e) => e.trim()).toList();
final role = Role(name: roleName, allowedContent: permissions);
await policyManager.addRole(role);
}
Update Role
Future<void> _updateRole() async {
final roleName = _roleNameController.text.trim();
final permissionsText = _permissionsController.text.trim();
final permissions = permissionsText.split(',').map((e) => e.trim()).toList();
final role = Role(name: roleName, allowedContent: permissions);
await policyManager.updateRole(role);
}
Remove Role
Future<void> _removeRole() async {
final roleName = _roleNameController.text.trim();
await policyManager.removeRole(roleName);
}
2. Interactive Role Selection
void _selectRole(String roleName) {
setState(() {
_selectedRole = roleName;
_roleNameController.text = roleName;
// Get current permissions for the role
final role = policyManager.getRole(roleName);
if (role != null) {
_permissionsController.text = role.allowedContent.join(', ');
}
});
}
3. Status Feedback System
void _showStatus(String message, bool isSuccess) {
setState(() {
_statusMessage = message;
_isSuccess = isSuccess;
});
// Clear status after 3 seconds
Future.delayed(const Duration(seconds: 3), () {
if (mounted) {
setState(() {
_statusMessage = '';
});
}
});
}
Adding a New Role
- Enter Role Name: Type a new role name (e.g., "moderator")
- Enter Permissions: Add comma-separated permissions (e.g., "LoginPage, Dashboard, UserManagement")
- Click "Add Role": The new role appears in the Current Roles section
- Test the Role: Select the new role to test its permissions
Updating an Existing Role
- Select a Role: Click on an existing role in the Current Roles section
- Modify Permissions: Update the permissions in the text field
- Click "Update Role": The role's permissions are updated
- Test Changes: Verify the changes in the Policy Testing section
Removing a Role
- Enter Role Name: Type the name of the role to remove
- Click "Remove Role": The role is deleted from the system
- Verify Removal: The role no longer appears in Current Roles
Scenario 1: Create Moderator Role
- Role Name: moderator
- Permissions: LoginPage, Dashboard, UserManagement
- Expected Result: Access to login, dashboard, and user management, but not settings
Scenario 2: Update User Role
- Original: LoginPage, Dashboard
- Updated: LoginPage, Dashboard, Settings
- Expected Result: User role now has access to settings
Scenario 3: Remove Guest Role
- Action: Remove guest role
- Expected Result: Guest role disappears, cannot be selected
🔍 Key Learning Points
- Dynamic Operations: Roles can be created, updated, and removed at runtime
- Real-time Updates: Policy changes take effect immediately
- Error Handling: Comprehensive error handling with user feedback
- Form Validation: Input validation prevents invalid operations
- State Management: Proper state management for UI updates
- User Experience: Intuitive interface with clear visual feedback