This commit is contained in:
2020-01-22 19:13:18 +00:00
parent e78b54b040
commit 0d1988a20e
16 changed files with 127 additions and 136 deletions

View File

@@ -126,7 +126,7 @@ https://en.wikipedia.org/wiki/Non-functional_requirement
- REST best practices
- Excellent reference guide here: https://github.com/Microsoft/api-guidelines/blob/vNext/Guidelines.md
- URLS: A good api url: https://api.ayanova.com/v1.0/client/22
- URLS: A good api url: https://api.ayanova.com/v1.0/customer/22
- Keep length under 2000 characters for maximum client compatibility
- concurrency (The ETag response-header field provides the current value of the entity tag for the requested variant. Used with If-Match, If-None-Match and If-Range to implement optimistic concurrency control.)
- JSON property names SHOULD be camelCased.
@@ -135,11 +135,11 @@ https://en.wikipedia.org/wiki/Non-functional_requirement
This object MUST contain name/value pairs with the names "code" and "message," and it MAY contain name/value pairs with the names "target," "details" and "innererror."
eg: error:{code=1200,message="blah"} error:{code=1200,message="blah",target="eg property name", details="details for programmer", innererror:}
- Versioning: this is an area I need to treat carefully, there are tools to make it easier:
- I will use URL Path segment versioning, i.e. api/v1.0/client/22
- I will use URL Path segment versioning, i.e. api/v1.0/customer/22
- https://www.hanselman.com/blog/ASPNETCoreRESTfulWebAPIVersioningMadeEasy.aspx
- https://github.com/Microsoft/aspnet-api-versioning/wiki
- https://github.com/Microsoft/aspnet-api-versioning/tree/master/samples/aspnetcore/SwaggerSample
- Push notifications (I.e. on a client record being created or a workorder updated or...?)
- Push notifications (I.e. on a customer record being created or a workorder updated or...?)
- If so there is a segment in the rest doc from microsoft that goes over it in detail
- API THROTTLING / RATE LIMITING
- https://github.com/stefanprodan/AspNetCoreRateLimit

View File

@@ -10,6 +10,10 @@ ROLES set general accessibility to change or delete or read objects, however Bus
**DELETE RIGHTS***
If you can modify an object you can delete an object unless business rules say otherwise
**SEE NAME / PICKLISTS ***
- Not sure if correct but for now assuming anyone can read the name of any object and that the UI will exclude them by biz rule if they aren't supposed to see something
- this does mean a subcontractor could use the api to fetch a list of customers outside of the client though...hmmm..
**LIMITED ROLES / BUSINESS RULES LIMITATIONS **
(formerly self owned)
@@ -17,7 +21,7 @@ In some cases business rules may further restrict what a user can do.
For example a SubContractorLimited has the change right to a workorder, but in fact the workorder itself has business rules that limit that drastically down to almost nothing but a single area entry in labor
=-=-=-=- HOW TO HANDLE EDIT OWN PLANNING =-=-=-=-=-
- EditOwn is really not about editown it's about supporting a user who is not supposed to see any data other than the bare minimum in order to fill out workorders
- EditOwn IS DEPRECATED FROM ORIGINAL PLAN is really not about editown it's about supporting a user who is not supposed to see any data other than the bare minimum in order to fill out workorders
- Make it a business rule(s) instead in the areas of workorders and anything specific
- Get rid of edit own rights code entirely

View File

@@ -20,7 +20,8 @@ UPDATE SPEC DOCS with new format and names etc or at least remove nonsense as ne
UPDATE MANUAL API REGARDING LISTS
CLIENT / TEST ROLE NAME CHANGE
- "client" now "customer"
CLIENT PROJECT CUSTOM FIELDS CHANGE
@@ -43,6 +44,12 @@ DO CLIENT STUFF NOW COME BACK TO THIS STUFF LATER
TODO: the license being logged breaks the format of the log file because it has line breaks etc, so instead, maybe log out as a single line (remove breaks)
- Or maybe don't log it at all, what's the point? People can just edit it, maybe the DBID is the only really useful thing so we can match it for support to the customer
- or just log the ID number or a more succint version
\
TODO: Need route to gather all object role rights in a format useful to display in UI so that a biz manager can see at a glance the rights for different roles to objects
- This way it's dynamic and picked up from the code itself which is always the source of truth so no need to put in the manual
- Would likely want to display multiple ways: for a specific object or role or selected user maybe too in the user info form ("effective roles")
- Move this over to client once the backend supports it
*** BEFORE NEXT UPDATE TO DEVOPS SERVER:::::::
TODO: 2019-06-07 10:47:57.8894|WARN|Microsoft.AspNetCore.Cors.Infrastructure.CorsService|The CORS protocol does not allow specifying a wildcard (any) origin and credentials at the same time.
@@ -58,6 +65,7 @@ TODO: DO I NOT HAVE AN ERASE DB ROUTE?
TODO: API RATE LIMITING / THROTTLING
- Return code 429
- Going to need rate limiting to save people from themselves
- Have this link from solutions.txt about this: https://github.com/stefanprodan/AspNetCoreRateLimit
- All the big api's have hourly limits on requests and also limits on total data throughput per hour
- (minute as well which actually makes more sense since it means they would only be down for a minute if they exceed it) too
- Find out what others do

View File

@@ -81,7 +81,7 @@ namespace AyaNova.Api.Controllers
LocaleKeysToFetch.Add("UserTypesAdministrator");
LocaleKeysToFetch.Add("UserTypesSchedulable");
LocaleKeysToFetch.Add("UserTypesNonSchedulable");
LocaleKeysToFetch.Add("UserTypesClient");
LocaleKeysToFetch.Add("UserTypesCustomer");
LocaleKeysToFetch.Add("UserTypesHeadOffice");
LocaleKeysToFetch.Add("UserTypesSubContractor");
var LT = LocaleBiz.GetSubsetStatic(LocaleKeysToFetch, LocaleId).Result;
@@ -89,7 +89,7 @@ namespace AyaNova.Api.Controllers
ReturnList.Add(new NameIdItem() { Name = LT["UserTypesAdministrator"], Id = (long)UserType.Administrator });
ReturnList.Add(new NameIdItem() { Name = LT["UserTypesSchedulable"], Id = (long)UserType.Schedulable });
ReturnList.Add(new NameIdItem() { Name = LT["UserTypesNonSchedulable"], Id = (long)UserType.NonSchedulable });
ReturnList.Add(new NameIdItem() { Name = LT["UserTypesClient"], Id = (long)UserType.Client });
ReturnList.Add(new NameIdItem() { Name = LT["UserTypesCustomer"], Id = (long)UserType.Customer });
ReturnList.Add(new NameIdItem() { Name = LT["UserTypesHeadOffice"], Id = (long)UserType.HeadOffice });
ReturnList.Add(new NameIdItem() { Name = LT["UserTypesSubContractor"], Id = (long)UserType.Subcontractor });
}
@@ -110,8 +110,8 @@ namespace AyaNova.Api.Controllers
LocaleKeysToFetch.Add("AuthorizationRoleTechFull");
LocaleKeysToFetch.Add("AuthorizationRoleSubContractorLimited");
LocaleKeysToFetch.Add("AuthorizationRoleSubContractorFull");
LocaleKeysToFetch.Add("AuthorizationRoleClientLimited");
LocaleKeysToFetch.Add("AuthorizationRoleClientFull");
LocaleKeysToFetch.Add("AuthorizationRoleCustomerLimited");
LocaleKeysToFetch.Add("AuthorizationRoleCustomerFull");
LocaleKeysToFetch.Add("AuthorizationRoleOpsAdminLimited");
LocaleKeysToFetch.Add("AuthorizationRoleOpsAdminFull");
LocaleKeysToFetch.Add("AuthorizationRoleSalesLimited");
@@ -131,8 +131,8 @@ namespace AyaNova.Api.Controllers
ReturnList.Add(new NameIdItem() { Name = LT["AuthorizationRoleTechFull"], Id = (long)AuthorizationRoles.TechFull });
ReturnList.Add(new NameIdItem() { Name = LT["AuthorizationRoleSubContractorLimited"], Id = (long)AuthorizationRoles.SubContractorLimited });
ReturnList.Add(new NameIdItem() { Name = LT["AuthorizationRoleSubContractorFull"], Id = (long)AuthorizationRoles.SubContractorFull });
ReturnList.Add(new NameIdItem() { Name = LT["AuthorizationRoleClientLimited"], Id = (long)AuthorizationRoles.ClientLimited });
ReturnList.Add(new NameIdItem() { Name = LT["AuthorizationRoleClientFull"], Id = (long)AuthorizationRoles.ClientFull });
ReturnList.Add(new NameIdItem() { Name = LT["AuthorizationRoleCustomerLimited"], Id = (long)AuthorizationRoles.CustomerLimited });
ReturnList.Add(new NameIdItem() { Name = LT["AuthorizationRoleCustomerFull"], Id = (long)AuthorizationRoles.CustomerFull });
ReturnList.Add(new NameIdItem() { Name = LT["AuthorizationRoleOpsAdminLimited"], Id = (long)AuthorizationRoles.OpsAdminLimited });
ReturnList.Add(new NameIdItem() { Name = LT["AuthorizationRoleOpsAdminFull"], Id = (long)AuthorizationRoles.OpsAdminFull });
ReturnList.Add(new NameIdItem() { Name = LT["AuthorizationRoleSalesLimited"], Id = (long)AuthorizationRoles.SalesLimited });

View File

@@ -165,7 +165,7 @@ namespace AyaNova.Api.Controllers
//Instantiate the business object handler
DataListFilterBiz biz = DataListFilterBiz.GetBiz(ct, HttpContext);
//If a user has change roles, or editOwnRoles then they can create, true is passed for isOwner since they are creating so by definition the owner
//check roles
if (!Authorized.HasCreateRole(HttpContext.Items, biz.BizType))
return StatusCode(403, new ApiNotAuthorizedResponse());

View File

@@ -17,6 +17,8 @@ namespace AyaNova.DataList
AuthorizationRoles FullListAllowedRoles { get; set; }
//allowed roles to access mini list templated fields
//generally this will be *any* because most forms will need to allow this for picklists such as usernames etc
// but this is a safety valve for sensitive lists like financial reports where there is just no need for untrusted roles to see it
AuthorizationRoles MiniListAllowedRoles { get; set; }

View File

@@ -26,6 +26,7 @@ namespace AyaNova.DataList
{
LtKey = "WidgetName",
FieldKey = "widgetname",
AyaObjectType = (int)AyaType.Widget,
UiFieldDataType = (int)AyaUiFieldDataType.Text,
SqlIdColumnName = "awidget.id",
SqlValueColumnName = "awidget.name"

View File

@@ -18,7 +18,7 @@ namespace AyaNova.DataList
ListKey = nameof(TestWidgetUserEmailDataList);
SQLFrom = "from awidget left outer join auser on (awidget.userid=auser.id) left outer join auseroptions on (auser.id=auseroptions.userid)";
FullListAllowedRoles = AuthorizationRoles.AllInternalStaff;//anyone but clients and subcontractors (just for test)
MiniListAllowedRoles = AuthorizationRoles.All;//anyone (so can select on forms)
MiniListAllowedRoles = AuthorizationRoles.AllExceptCustomers;//anyone but clients who shouldn't see users email addresses (so can select on forms)
DefaultListObjectType = AyaType.Widget;
DefaultDataListDisplayTemplate = @"
{

View File

@@ -11,117 +11,91 @@ namespace AyaNova.DataList
SQLFrom = "from auser";
FullListAllowedRoles = AuthorizationRoles.AllInternalStaff;//anyone but clients and subcontractors (just for test)
MiniListAllowedRoles = AuthorizationRoles.All;//anyone (so can select on forms)
DefaultListObjectType = AyaType.Widget;
DefaultListObjectType = AyaType.User;
DefaultDataListDisplayTemplate = @"
{
""full"":[""widgetname"",""widgetserial"",""widgetdollaramount"",""widgetroles"",""widgetstartdate"",""widgetactive"",""username""],
""mini"":[""widgetname"",""widgetserial""]
""full"":[""username"",""useremployeenumber"",""useractive"",""usernotes"",""userroles""],
""mini"":[""username""]
}
";
//NOTE: Due to the join, all the sql id and name fields that can conflict with the joined (in this case User) table need to be specified completely
FieldDefinitions = new List<AyaDataListFieldDefinition>();
FieldDefinitions.Add(new AyaDataListFieldDefinition { FieldKey = "df", AyaObjectType = (int)AyaType.Widget, SqlIdColumnName = "awidget.id" });
FieldDefinitions.Add(new AyaDataListFieldDefinition { FieldKey = "df", AyaObjectType = (int)AyaType.User, SqlIdColumnName = "auser.id" });
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "WidgetName",
FieldKey = "widgetname",
UiFieldDataType = (int)AyaUiFieldDataType.Text,
SqlIdColumnName = "awidget.id",
SqlValueColumnName = "awidget.name"
});
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "WidgetSerial",
FieldKey = "widgetserial",
UiFieldDataType = (int)AyaUiFieldDataType.Integer,
SqlValueColumnName = "awidget.serial"
});
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "WidgetDollarAmount",
FieldKey = "widgetdollaramount",
UiFieldDataType = (int)AyaUiFieldDataType.Currency,
SqlValueColumnName = "awidget.dollaramount"
});
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "WidgetCount",
FieldKey = "widgetcount",
UiFieldDataType = (int)AyaUiFieldDataType.Integer,
SqlValueColumnName = "awidget.count"
});
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "WidgetRoles",
FieldKey = "widgetroles",
UiFieldDataType = (int)AyaUiFieldDataType.Enum,
EnumType = typeof(AuthorizationRoles).ToString(),
SqlValueColumnName = "awidget.roles"
});
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "WidgetStartDate",
FieldKey = "widgetstartdate",
UiFieldDataType = (int)AyaUiFieldDataType.DateTime,
SqlValueColumnName = "awidget.startdate"
});
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "WidgetEndDate",
FieldKey = "widgetenddate",
UiFieldDataType = (int)AyaUiFieldDataType.DateTime,
SqlValueColumnName = "awidget.enddate"
});
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "WidgetNotes",
FieldKey = "widgetnotes",
UiFieldDataType = (int)AyaUiFieldDataType.Text,
SqlValueColumnName = "awidget.notes"
});
//FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "User", FieldKey = "userid", UiFieldDataType = (int)AyaUiFieldDataType.Text, AyaObjectType = (int)AyaType.User });
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
FieldKey = "username",
LtKey = "User",
UiFieldDataType = (int)AyaUiFieldDataType.Text,
FieldKey = "username",
AyaObjectType = (int)AyaType.User,
UiFieldDataType = (int)AyaUiFieldDataType.Text,
SqlIdColumnName = "auser.id",
SqlValueColumnName = "auser.name"
});
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "Active",
FieldKey = "widgetactive",
FieldKey = "useractive",
UiFieldDataType = (int)AyaUiFieldDataType.Bool,
SqlValueColumnName = "awidget.active"
});
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "Tags",
FieldKey = "widgettags",
UiFieldDataType = (int)AyaUiFieldDataType.Tags,
SqlValueColumnName = "awidget.tags"
SqlValueColumnName = "auser.active"
});
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom1", FieldKey = "widgetcustom1", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom2", FieldKey = "widgetcustom2", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom3", FieldKey = "widgetcustom3", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom4", FieldKey = "widgetcustom4", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom5", FieldKey = "widgetcustom5", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom6", FieldKey = "widgetcustom6", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom7", FieldKey = "widgetcustom7", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom8", FieldKey = "widgetcustom8", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom9", FieldKey = "widgetcustom9", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom10", FieldKey = "widgetcustom10", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom11", FieldKey = "widgetcustom11", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom12", FieldKey = "widgetcustom12", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom13", FieldKey = "widgetcustom13", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom14", FieldKey = "widgetcustom14", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom15", FieldKey = "widgetcustom15", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom16", FieldKey = "widgetcustom16", IsCustomField = true });
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "AuthorizationRoles",
FieldKey = "userroles",
UiFieldDataType = (int)AyaUiFieldDataType.Enum,
EnumType = typeof(AuthorizationRoles).ToString(),
SqlValueColumnName = "auser.roles"
});
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "UserUserType",
FieldKey = "usertype",
UiFieldDataType = (int)AyaUiFieldDataType.Enum,
EnumType = typeof(UserType).ToString(),
SqlValueColumnName = "auser.usertype"
});
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "UserEmployeeNumber",
FieldKey = "useremployeenumber",
UiFieldDataType = (int)AyaUiFieldDataType.Text,
SqlValueColumnName = "auser.employeenumber"
});
FieldDefinitions.Add(new AyaDataListFieldDefinition
{
LtKey = "UserNotes",
FieldKey = "usernotes",
UiFieldDataType = (int)AyaUiFieldDataType.Text,
SqlValueColumnName = "auser.notes"
});
// //-------------------------
//NOT SURE ABOUT CUSTOM FIELDS
//NEED TO COME BACK TO THIS ONCE CLIENT IS CONSUMING THESE LISTS
//WIDGETLIST has custom fields so good test before doing here
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom1", FieldKey = "widgetcustom1", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom2", FieldKey = "widgetcustom2", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom3", FieldKey = "widgetcustom3", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom4", FieldKey = "widgetcustom4", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom5", FieldKey = "widgetcustom5", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom6", FieldKey = "widgetcustom6", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom7", FieldKey = "widgetcustom7", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom8", FieldKey = "widgetcustom8", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom9", FieldKey = "widgetcustom9", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom10", FieldKey = "widgetcustom10", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom11", FieldKey = "widgetcustom11", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom12", FieldKey = "widgetcustom12", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom13", FieldKey = "widgetcustom13", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom14", FieldKey = "widgetcustom14", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom15", FieldKey = "widgetcustom15", IsCustomField = true });
// FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetCustom16", FieldKey = "widgetcustom16", IsCustomField = true });
}
}//eoc
}//eons

View File

@@ -37,9 +37,9 @@ namespace AyaNova.Biz
///<summary>SubContractorFull</summary>
SubContractorFull = 1024,
///<summary>ClientLimited</summary>
ClientLimited = 2048,
CustomerLimited = 2048,
///<summary>ClientFull</summary>
ClientFull = 4096,
CustomerFull = 4096,
///<summary>OpsAdminLimited</summary>
OpsAdminLimited = 8192,
///<summary>OpsAdminFull</summary>
@@ -53,11 +53,16 @@ namespace AyaNova.Biz
///<summary>Anyone of any role</summary>
All = BizAdminLimited | BizAdminFull | DispatchLimited | DispatchFull | InventoryLimited |
InventoryFull | AccountingFull | TechLimited | TechFull | SubContractorLimited |
SubContractorFull | ClientLimited | ClientFull | OpsAdminLimited | OpsAdminFull | SalesFull | SalesLimited,
SubContractorFull | CustomerLimited | CustomerFull | OpsAdminLimited | OpsAdminFull | SalesFull | SalesLimited,
///<summary>Anyone inside company</summary>
AllInternalStaff = BizAdminLimited | BizAdminFull | DispatchLimited | DispatchFull | InventoryLimited |
InventoryFull | AccountingFull | TechLimited | TechFull | OpsAdminLimited | OpsAdminFull | SalesFull | SalesLimited
InventoryFull | AccountingFull | TechLimited | TechFull | OpsAdminLimited | OpsAdminFull | SalesFull | SalesLimited,
///<summary>Anyone except customers</summary>
AllExceptCustomers = BizAdminLimited | BizAdminFull | DispatchLimited | DispatchFull | InventoryLimited |
InventoryFull | AccountingFull | TechLimited | TechFull | SubContractorLimited |
SubContractorFull | OpsAdminLimited | OpsAdminFull | SalesFull | SalesLimited
}//end AuthorizationRoles
//, 65536, 131072, 262144, 524288, 1,048,576

View File

@@ -16,17 +16,15 @@ namespace AyaNova.Biz
static BizRoles()
{
//TODO: change this entire block to work off a fragment of JSON that can be shared with the Client side project as well
//Add all object roles here
//NOTE: do not need to add change roles to read roles, Authorized.cs takes care of that automatically
//by assuming if you can change you can read
//HOW THIS WORKS / WHATS EXPECTED
//Change = CREATE, RETRIEVE, UPDATE, DELETE - Full rights
//EditOwn = special subset of CHANGE: You can create and if it's one you created then you have rights to edit it or delete, but you can't edit ones others have created
//Change = CREATE, RETRIEVE, UPDATE, DELETE - Full rights
//ReadFullRecord = You can read *all* the fields of the record, but can't modify it. Change is automatically checked for so only add different roles from change
//PICKLIST NOTE: this does not control getting a list of names for selection which is role independent because it's required for so much indirectly
//MINI / PICKLIST NOTE: roles do not control getting a list of names for selection which is role independent because it's required for so much indirectly
//DELETE = There is no specific delete right for now though it's checked for by routes in Authorized.cs in case we want to add it in future as a separate right from create.
#region All roles initialization
@@ -178,8 +176,7 @@ namespace AyaNova.Biz
System.Diagnostics.Debugger.Log(1, "JSONFRAGMENTFORCLIENT", "BizRoles.cs -> biz-role-rights.js Client roles JSON fragment:");
System.Diagnostics.Debugger.Log(1, "JSONFRAGMENTFORCLIENT", json);
//ONGOING VALIDATION TO CATCH MISMATCH WHEN NEW ROLES ADDED (wont' catch changes to existing unfortunately)
// var lastRoles = "{\r\n \"User\": {\r\n \"Change\": 2,\r\n \"EditOwn\": 0,\r\n \"ReadFullRecord\": 1\r\n },\r\n \"UserOptions\": {\r\n \"Change\": 2,\r\n \"EditOwn\": 0,\r\n \"ReadFullRecord\": 1\r\n },\r\n \"Widget\": {\r\n \"Change\": 34,\r\n \"EditOwn\": 256,\r\n \"ReadFullRecord\": 17\r\n },\r\n \"ServerState\": {\r\n \"Change\": 16384,\r\n \"EditOwn\": 0,\r\n \"ReadFullRecord\": 32767\r\n },\r\n \"License\": {\r\n \"Change\": 16386,\r\n \"EditOwn\": 0,\r\n \"ReadFullRecord\": 8193\r\n },\r\n \"LogFile\": {\r\n \"Change\": 0,\r\n \"EditOwn\": 0,\r\n \"ReadFullRecord\": 24576\r\n },\r\n \"JobOperations\": {\r\n \"Change\": 16384,\r\n \"EditOwn\": 0,\r\n \"ReadFullRecord\": 8195\r\n },\r\n \"AyaNova7Import\": {\r\n \"Change\": 16384,\r\n \"EditOwn\": 0,\r\n \"ReadFullRecord\": 0\r\n },\r\n \"Metrics\": {\r\n \"Change\": 0,\r\n \"EditOwn\": 0,\r\n \"ReadFullRecord\": 24576\r\n },\r\n \"Locale\": {\r\n \"Change\": 16386,\r\n \"EditOwn\": 0,\r\n \"ReadFullRecord\": 32767\r\n },\r\n \"DataFilter\": {\r\n \"Change\": 2,\r\n \"EditOwn\": 32767,\r\n \"ReadFullRecord\": 32767\r\n },\r\n \"FormCustom\": {\r\n \"Change\": 2,\r\n \"EditOwn\": 0,\r\n \"ReadFullRecord\": 32767\r\n }\r\n}";
//ONGOING VALIDATION TO CATCH MISMATCH WHEN NEW ROLES ADDED (wont' catch changes to existing unfortunately)
var lastRoles = "{\"User\":{\"Change\":2,\"ReadFullRecord\":1},\"UserOptions\":{\"Change\":2,\"ReadFullRecord\":1},\"Widget\":{\"Change\":34,\"ReadFullRecord\":17},\"ServerState\":{\"Change\":16384,\"ReadFullRecord\":32767},\"License\":{\"Change\":16386,\"ReadFullRecord\":8193},\"LogFile\":{\"Change\":0,\"ReadFullRecord\":24576},\"JobOperations\":{\"Change\":16384,\"ReadFullRecord\":8195},\"AyaNova7Import\":{\"Change\":16384,\"ReadFullRecord\":0},\"Metrics\":{\"Change\":0,\"ReadFullRecord\":24576},\"Locale\":{\"Change\":16386,\"ReadFullRecord\":32767},\"DataFilter\":{\"Change\":2,\"ReadFullRecord\":32767},\"FormCustom\":{\"Change\":2,\"ReadFullRecord\":32767}}";
Dictionary<AyaType, BizRoleSet> lastRolesDeserialized = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<AyaType, BizRoleSet>>(lastRoles);

View File

@@ -479,12 +479,12 @@ namespace AyaNova.Biz
AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "UserType");
}
//Validate client type user
if (!SeedOrImportRelaxedRulesMode && proposedObj.UserType == UserType.Client)
//Validate customer type user
if (!SeedOrImportRelaxedRulesMode && proposedObj.UserType == UserType.Customer)
{
if (proposedObj.ClientId == null || proposedObj.ClientId == 0)
if (proposedObj.CustomerId == null || proposedObj.CustomerId == 0)
{
AddError(ApiErrorCode.VALIDATION_REQUIRED, "ClientId");
AddError(ApiErrorCode.VALIDATION_REQUIRED, "CustomerId");
}
else
{
@@ -594,7 +594,7 @@ namespace AyaNova.Biz
UserType = o.UserType,
EmployeeNumber = o.EmployeeNumber,
Notes = o.Notes,
ClientId = o.ClientId,
CustomerId = o.CustomerId,
HeadOfficeId = o.HeadOfficeId,
SubVendorId = o.SubVendorId
};

View File

@@ -9,7 +9,7 @@ namespace AyaNova.Biz
Administrator = 1,
Schedulable = 2,
NonSchedulable = 3,
Client = 4,
Customer = 4,
HeadOffice = 5,
Utility = 6,
Subcontractor = 7

View File

@@ -32,7 +32,7 @@ namespace AyaNova.Models
[MaxLength(255)]
public string EmployeeNumber { get; set; }
public string Notes { get; set; }
public long? ClientId { get; set; }
public long? CustomerId { get; set; }
public long? HeadOfficeId { get; set; }
public long? SubVendorId { get; set; }
public string CustomFields { get; set; }

View File

@@ -169,7 +169,7 @@ namespace AyaNova.Util
//Add user table
exec("CREATE TABLE auser (id BIGSERIAL PRIMARY KEY, active bool not null, name varchar(255) not null, " +
"login text not null, password text not null, salt text not null, roles integer not null, localeid bigint not null REFERENCES alocale (id), " +
"dlkey text, dlkeyexpire timestamp, usertype integer not null, employeenumber varchar(255), notes text, clientid bigint, " +
"dlkey text, dlkeyexpire timestamp, usertype integer not null, employeenumber varchar(255), notes text, customerid bigint, " +
"headofficeid bigint, subvendorid bigint, customfields text, tags varchar(255) ARRAY)");
//Index for name fetching

View File

@@ -205,11 +205,11 @@ namespace AyaNova.Util
//1 accountant / bookkeeper
GenSeedUser(log, 1, AuthorizationRoles.AccountingFull | AuthorizationRoles.BizAdminLimited, UserType.NonSchedulable, timeZoneOffset);
//10 full on client users
GenSeedUser(log, 10, AuthorizationRoles.ClientLimited, UserType.Client, timeZoneOffset);
//10 full on customer users
GenSeedUser(log, 10, AuthorizationRoles.CustomerLimited, UserType.Customer, timeZoneOffset);
//10 limited client users
GenSeedUser(log, 10, AuthorizationRoles.ClientLimited, UserType.Client, timeZoneOffset);
//10 limited customer users
GenSeedUser(log, 10, AuthorizationRoles.CustomerLimited, UserType.Customer, timeZoneOffset);
//PERF
watch.Stop();
LogStatus(JobId, LogJob, log, $"{SeededUserCount} Users seeded in {watch.ElapsedMilliseconds} ms");
@@ -280,11 +280,11 @@ namespace AyaNova.Util
//5 accountant / bookkeeper
GenSeedUser(log, 5, AuthorizationRoles.AccountingFull | AuthorizationRoles.BizAdminLimited, UserType.NonSchedulable, timeZoneOffset);
//100 full on client users
GenSeedUser(log, 20, AuthorizationRoles.ClientFull, UserType.Client, timeZoneOffset);
//100 full on customer users
GenSeedUser(log, 20, AuthorizationRoles.CustomerFull, UserType.Customer, timeZoneOffset);
//100 limited client users
GenSeedUser(log, 20, AuthorizationRoles.ClientLimited, UserType.Client, timeZoneOffset);
//100 limited customer users
GenSeedUser(log, 20, AuthorizationRoles.CustomerLimited, UserType.Customer, timeZoneOffset);
//PERF
watch.Stop();
@@ -356,11 +356,11 @@ namespace AyaNova.Util
//accountant / bookkeeper
GenSeedUser(log, 20, AuthorizationRoles.AccountingFull | AuthorizationRoles.BizAdminLimited, UserType.NonSchedulable, timeZoneOffset);
//full on client users
GenSeedUser(log, 200, AuthorizationRoles.ClientFull, UserType.Client, timeZoneOffset);
//full on customer users
GenSeedUser(log, 200, AuthorizationRoles.CustomerFull, UserType.Customer, timeZoneOffset);
//limited client users
GenSeedUser(log, 50, AuthorizationRoles.ClientLimited, UserType.Client, timeZoneOffset);
//limited customer users
GenSeedUser(log, 50, AuthorizationRoles.CustomerLimited, UserType.Customer, timeZoneOffset);
//PERF
watch.Stop();
@@ -444,8 +444,8 @@ namespace AyaNova.Util
GenSeedUser(log, 1, AuthorizationRoles.SubContractorLimited, UserType.Subcontractor, timeZoneOffset, "SubContractorLimited", "SubContractorLimited");
GenSeedUser(log, 1, AuthorizationRoles.SubContractorFull, UserType.Subcontractor, timeZoneOffset, "SubContractorFull", "SubContractorFull");
GenSeedUser(log, 1, AuthorizationRoles.ClientLimited, UserType.Client, timeZoneOffset, "ClientLimited", "ClientLimited");
GenSeedUser(log, 1, AuthorizationRoles.ClientFull, UserType.Client, timeZoneOffset, "ClientFull", "ClientFull");
GenSeedUser(log, 1, AuthorizationRoles.CustomerLimited, UserType.Customer, timeZoneOffset, "CustomerLimited", "CustomerLimited");
GenSeedUser(log, 1, AuthorizationRoles.CustomerFull, UserType.Customer, timeZoneOffset, "CustomerFull", "CustomerFull");
GenSeedUser(log, 1, AuthorizationRoles.OpsAdminLimited, UserType.NonSchedulable, timeZoneOffset, "OpsAdminLimited", "OpsAdminLimited");
GenSeedUser(log, 1, AuthorizationRoles.OpsAdminFull, UserType.NonSchedulable, timeZoneOffset, "OpsAdminFull", "OpsAdminFull");