mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-10-31 13:25:40 +00:00 
			
		
		
		
	Company create (#610)
* API: refactor checkPermission - Rename to checkRole (actually what it is doing) - Permission check will be incoming * Add checkPermission function for API * Create a new company * Bump release notes * Cleanup * Fix
This commit is contained in:
		| @@ -1,3 +1,8 @@ | |||||||
|  | ### 0.18.0 - February 2025 | ||||||
|  | --- | ||||||
|  | - Adds ability to create new companies from the app | ||||||
|  | - Updated translations | ||||||
|  |  | ||||||
| ### 0.17.4 - January 2025 | ### 0.17.4 - January 2025 | ||||||
| --- | --- | ||||||
| - Display responsible owner for orders | - Display responsible owner for orders | ||||||
|   | |||||||
							
								
								
									
										79
									
								
								lib/api.dart
									
									
									
									
									
								
							
							
						
						
									
										79
									
								
								lib/api.dart
									
									
									
									
									
								
							| @@ -237,9 +237,12 @@ class InvenTreeAPI { | |||||||
|  |  | ||||||
|   UserProfile? profile; |   UserProfile? profile; | ||||||
|  |  | ||||||
|   // Available user roles (permissions) are loaded when connecting to the server |   // Available user roles are loaded when connecting to the server | ||||||
|   Map<String, dynamic> roles = {}; |   Map<String, dynamic> roles = {}; | ||||||
|  |  | ||||||
|  |   // Available user permissions are loaded when connecting to the server | ||||||
|  |   Map<String, dynamic> permissions = {}; | ||||||
|  |  | ||||||
|   // Profile authentication token |   // Profile authentication token | ||||||
|   String get token => profile?.token ?? ""; |   String get token => profile?.token ?? ""; | ||||||
|  |  | ||||||
| @@ -701,12 +704,11 @@ class InvenTreeAPI { | |||||||
|  |  | ||||||
|     var data = response.asMap(); |     var data = response.asMap(); | ||||||
|  |  | ||||||
|     if (data.containsKey("roles")) { |     if (!data.containsKey("roles")) { | ||||||
|       // Save a local copy of the user roles |  | ||||||
|       roles = (response.data["roles"] ?? {}) as Map<String, dynamic>; |       roles = {}; | ||||||
|  |       permissions = {}; | ||||||
|  |  | ||||||
|       return true; |  | ||||||
|     } else { |  | ||||||
|       showServerError( |       showServerError( | ||||||
|         apiUrl, |         apiUrl, | ||||||
|         L10().serverError, |         L10().serverError, | ||||||
| @@ -714,6 +716,11 @@ class InvenTreeAPI { | |||||||
|       ); |       ); | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     roles = (data["roles"] ?? {}) as Map<String, dynamic>; | ||||||
|  |     permissions = (data["permissions"] ?? {}) as Map<String, dynamic>; | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Request plugin information from the server |   // Request plugin information from the server | ||||||
| @@ -740,9 +747,9 @@ class InvenTreeAPI { | |||||||
|  |  | ||||||
|   /* |   /* | ||||||
|    * Check if the user has the given role.permission assigned |    * Check if the user has the given role.permission assigned | ||||||
|    * e.g. "part", "change" |    * e.g. "sales_order", "change" | ||||||
|    */ |    */ | ||||||
|   bool checkPermission(String role, String permission) { |   bool checkRole(String role, String permission) { | ||||||
|  |  | ||||||
|     if (!_connected) { |     if (!_connected) { | ||||||
|       return false; |       return false; | ||||||
| @@ -750,17 +757,17 @@ class InvenTreeAPI { | |||||||
|  |  | ||||||
|     // If we do not have enough information, assume permission is allowed |     // If we do not have enough information, assume permission is allowed | ||||||
|     if (roles.isEmpty) { |     if (roles.isEmpty) { | ||||||
|       debug("checkPermission - no roles defined!"); |       debug("checkRole - no roles defined!"); | ||||||
|       return true; |       return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (!roles.containsKey(role)) { |     if (!roles.containsKey(role)) { | ||||||
|       debug("checkPermission - role '$role' not found!"); |       debug("checkRole - role '$role' not found!"); | ||||||
|       return true; |       return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (roles[role] == null) { |     if (roles[role] == null) { | ||||||
|       debug("checkPermission - role '$role' is null!"); |       debug("checkRole - role '$role' is null!"); | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -773,7 +780,7 @@ class InvenTreeAPI { | |||||||
|       } else { |       } else { | ||||||
|         // Unknown error - report it! |         // Unknown error - report it! | ||||||
|         sentryReportError( |         sentryReportError( | ||||||
|           "api.checkPermission", |           "api.checkRole", | ||||||
|           error, stackTrace, |           error, stackTrace, | ||||||
|           context: { |           context: { | ||||||
|             "role": role, |             "role": role, | ||||||
| @@ -788,6 +795,54 @@ class InvenTreeAPI { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    * Check if the user has the particular model permission assigned | ||||||
|  |    * e.g. "company", "add" | ||||||
|  |    */ | ||||||
|  |   bool checkPermission(String model, String permission) { | ||||||
|  |     if (!_connected) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (permissions.isEmpty) { | ||||||
|  |       // Not enough information available - default to True | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!permissions.containsKey(model)) { | ||||||
|  |       debug("checkPermission - model '$model' not found!"); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (permissions[model] == null) { | ||||||
|  |       debug("checkPermission - model '$model' is null!"); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     try { | ||||||
|  |       List<String> perms = List.from(permissions[model] as List<dynamic>); | ||||||
|  |       return perms.contains(permission); | ||||||
|  |     } catch (error, stackTrace) { | ||||||
|  |       if (error is TypeError) { | ||||||
|  |         // Ignore TypeError | ||||||
|  |       } else { | ||||||
|  |         // Unknown error - report it! | ||||||
|  |         sentryReportError( | ||||||
|  |             "api.checkPermission", | ||||||
|  |             error, stackTrace, | ||||||
|  |             context: { | ||||||
|  |               "model": model, | ||||||
|  |               "permission": permission, | ||||||
|  |               "error": error.toString(), | ||||||
|  |             } | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // Unable to determine permission - assume true? | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   // Perform a PATCH request |   // Perform a PATCH request | ||||||
|   Future<APIResponse> patch(String url, {Map<String, dynamic> body = const {}, int? expectedStatusCode}) async { |   Future<APIResponse> patch(String url, {Map<String, dynamic> body = const {}, int? expectedStatusCode}) async { | ||||||
|   | |||||||
| @@ -212,7 +212,7 @@ class InvenTreeModel { | |||||||
|   // Test if the user can "edit" this model |   // Test if the user can "edit" this model | ||||||
|   bool get canEdit { |   bool get canEdit { | ||||||
|     for (String role in rolesRequired) { |     for (String role in rolesRequired) { | ||||||
|       if (InvenTreeAPI().checkPermission(role, "change")) { |       if (InvenTreeAPI().checkRole(role, "change")) { | ||||||
|         return true; |         return true; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -224,7 +224,7 @@ class InvenTreeModel { | |||||||
|   // Test if the user can "create" this model |   // Test if the user can "create" this model | ||||||
|   bool get canCreate { |   bool get canCreate { | ||||||
|     for (String role in rolesRequired) { |     for (String role in rolesRequired) { | ||||||
|       if (InvenTreeAPI().checkPermission(role, "add")) { |       if (InvenTreeAPI().checkRole(role, "add")) { | ||||||
|         return true; |         return true; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -236,7 +236,7 @@ class InvenTreeModel { | |||||||
|   // Test if the user can "delete" this model |   // Test if the user can "delete" this model | ||||||
|   bool get canDelete { |   bool get canDelete { | ||||||
|     for (String role in rolesRequired) { |     for (String role in rolesRequired) { | ||||||
|       if (InvenTreeAPI().checkPermission(role, "delete")) { |       if (InvenTreeAPI().checkRole(role, "delete")) { | ||||||
|         return true; |         return true; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @@ -248,7 +248,7 @@ class InvenTreeModel { | |||||||
|   // Test if the user can "view" this model |   // Test if the user can "view" this model | ||||||
|   bool get canView { |   bool get canView { | ||||||
|     for (String role in rolesRequired) { |     for (String role in rolesRequired) { | ||||||
|       if (InvenTreeAPI().checkPermission(role, "view")) { |       if (InvenTreeAPI().checkRole(role, "view")) { | ||||||
|         return true; |         return true; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -234,6 +234,9 @@ | |||||||
|   "company": "Company", |   "company": "Company", | ||||||
|   "@company": {}, |   "@company": {}, | ||||||
|  |  | ||||||
|  |   "companyAdd": "Add Company", | ||||||
|  |   "@companyAdd": {}, | ||||||
|  |  | ||||||
|   "companyEdit": "Edit Company", |   "companyEdit": "Edit Company", | ||||||
|   "@companyEdit": {}, |   "@companyEdit": {}, | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,7 @@ | |||||||
|  |  | ||||||
| import "package:flutter/material.dart"; | import "package:flutter/material.dart"; | ||||||
|  | import "package:flutter_speed_dial/flutter_speed_dial.dart"; | ||||||
|  | import "package:flutter_tabler_icons/flutter_tabler_icons.dart"; | ||||||
|  |  | ||||||
| import "package:inventree/api.dart"; | import "package:inventree/api.dart"; | ||||||
| import "package:inventree/l10.dart"; | import "package:inventree/l10.dart"; | ||||||
| @@ -35,6 +37,48 @@ class _CompanyListWidgetState extends RefreshableState<CompanyListWidget> { | |||||||
|   @override |   @override | ||||||
|   String getAppBarTitle() => widget.title; |   String getAppBarTitle() => widget.title; | ||||||
|  |  | ||||||
|  |   Future<void> _addCompany(BuildContext context) async { | ||||||
|  |  | ||||||
|  |     InvenTreeCompany().createForm( | ||||||
|  |       context, | ||||||
|  |       L10().companyAdd, | ||||||
|  |       data: widget.filters, | ||||||
|  |       onSuccess: (result) async { | ||||||
|  |         Map<String, dynamic> data = result as Map<String, dynamic>; | ||||||
|  |  | ||||||
|  |         if (data.containsKey("pk")) { | ||||||
|  |           var company = InvenTreeCompany.fromJson(data); | ||||||
|  |  | ||||||
|  |           Navigator.push( | ||||||
|  |             context, | ||||||
|  |             MaterialPageRoute( | ||||||
|  |               builder: (context) => CompanyDetailWidget(company) | ||||||
|  |             ) | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   List<SpeedDialChild> actionButtons(BuildContext context) { | ||||||
|  |     List<SpeedDialChild> actions = []; | ||||||
|  |  | ||||||
|  |     if (InvenTreeAPI().checkPermission("company", "add")) { | ||||||
|  |       actions.add( | ||||||
|  |           SpeedDialChild( | ||||||
|  |               child: Icon(TablerIcons.circle_plus, color: Colors.green), | ||||||
|  |               label: L10().companyAdd, | ||||||
|  |               onTap: () { | ||||||
|  |                 _addCompany(context); | ||||||
|  |               } | ||||||
|  |           ) | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return actions; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget getBody(BuildContext context) { |   Widget getBody(BuildContext context) { | ||||||
|     return PaginatedCompanyList(widget.title, widget.filters); |     return PaginatedCompanyList(widget.title, widget.filters); | ||||||
|   | |||||||
| @@ -183,7 +183,7 @@ class _InvenTreeHomePageState extends State<InvenTreeHomePage> with BaseWidgetPr | |||||||
|     bool allowed = true; |     bool allowed = true; | ||||||
|  |  | ||||||
|     if (role.isNotEmpty || permission.isNotEmpty) { |     if (role.isNotEmpty || permission.isNotEmpty) { | ||||||
|       allowed = InvenTreeAPI().checkPermission(role, permission); |       allowed = InvenTreeAPI().checkRole(role, permission); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return GestureDetector( |     return GestureDetector( | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| name: inventree | name: inventree | ||||||
| description: InvenTree stock management | description: InvenTree stock management | ||||||
|  |  | ||||||
| version: 0.17.4+96 | version: 0.18.0+97 | ||||||
|  |  | ||||||
| environment: | environment: | ||||||
|   sdk: ">=2.19.5 <3.13.0" |   sdk: ">=2.19.5 <3.13.0" | ||||||
|   | |||||||
| @@ -117,10 +117,10 @@ void main() { | |||||||
|       assert(api.roles.isNotEmpty); |       assert(api.roles.isNotEmpty); | ||||||
|  |  | ||||||
|       // Check available permissions |       // Check available permissions | ||||||
|       assert(api.checkPermission("part", "change")); |       assert(api.checkRole("part", "change")); | ||||||
|       assert(api.checkPermission("stock_location", "delete")); |       assert(api.checkRole("stock_location", "delete")); | ||||||
|       assert(!api.checkPermission("part", "weirdpermission")); |       assert(!api.checkRole("part", "weirdpermission")); | ||||||
|       assert(api.checkPermission("blah", "bloo")); |       assert(api.checkRole("blah", "bloo")); | ||||||
|  |  | ||||||
|       debugContains("Received token from server"); |       debugContains("Received token from server"); | ||||||
|       debugContains("showSnackIcon: 'Connected to Server'"); |       debugContains("showSnackIcon: 'Connected to Server'"); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user