mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-27 21:16:48 +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:
parent
0c5944a8a0
commit
1a3f48f48c
@ -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'");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user