diff --git a/docs/8.0/ayanova/docs/adm-users.md b/docs/8.0/ayanova/docs/adm-users.md index 139b0ad7..a73adaad 100644 --- a/docs/8.0/ayanova/docs/adm-users.md +++ b/docs/8.0/ayanova/docs/adm-users.md @@ -1,9 +1,101 @@ # ADM-USERS Placeholder +[UNDER CONSTRUCTION PRE-RELEASE] -## LOGIN NAME -We recommend using the users Email address as their login name +This form is used to create and edit Users and control their access to AyaNova. -## User Settings -This section is a duplicate of the [User settings](home-user-settings.md) form. +## Do not share User accounts +Every User of AyaNova **must** have their own account. AyaNova does _not_ support multiple simultaneous logins with the same User account; a fresh login automatically revokes prior logins so logging in as a User that is already logged in will kick out that first User. + +For security purposes it is important that each User have their own account so that it's easy to keep track of who did what when and where in case issues arise. Also it makes it easier to revoke access when a User is no longer allowed to access AyaNova. + +## Menu options + +### Direct notification + +Send a direct Notification message to this User. This differs from a Memo in that it will trigger an alert for them (the bell icon at the top of the AyaNova user interface) and is useful when you have an urgent message to send. + +### Send password reset email + +Initiate a password reset process for this User. + +When a user forgets their password or a new User has just been created and you want them to set their own password to get started, use this link to send the User a temporary access link to AyaNova so they can set their password and login name themselves. + +Note that it requires the User to have a valid email address set in the settings tab. + +### Scheduled Users + +If this User is a scheduleable type, this menu option is a shortcut to the work order item scheduled users data table filtered to show only _this_ User's records. + +### Labors + +If this User is a scheduleable type, this menu option is a shortcut to the work order item labor data table filtered to show only _this_ User's records. + +## User tab + +### Name + +This is the only required field. Enter the User name here, we recommend `Firstname Lastname` format however as long as it's unique you can enter anything you wish here to identify Users in all areas of the AyaNova user interface. + +### Employee number + +Optional field designated for employee number. + +### Authorization roles + +This is where you grant access to the different areas of AyaNova for this User. [AyaNova roles](ay-biz-admin-roles.md) are broadly defined by the business roles that User must perform so in most cases you would grant roles based on the User's actual job roles. It is better to grant less access initially and add as required. + +### User type + +#### Service user + +This type of User consumes an AyaNova license, is scheduleable for service and is appropriate for any staff User that peforms service and needs to have their service tracked. + +#### Non-Service user + +This type of User does _not_ consume an AyaNova license, is not scheduleable for service and is appropriate for any staff User that isn't directly performing service for the company that needs to be tracked. All users of AyaNova should have their own login account, two or more Users are not able to be logged in at the same time under the same User account. + +#### Subcontractor + +This type of User consumes an AyaNova license, is scheduleable for service and is appropriate for any non-staff contracted User that peforms service under contract and needs to have their service tracked. This type of User has far more limited rights than a Service User and is generally restricted in what data they can view in AyaNova to only that which is required for them to do their job. + +### New login name / New password + +Set or reset the User's login name and password here. Note that the User can also change their own login credentials in their User settings so it's often the case that a temporary set of credentials is set here by the administrator and then the User themselves will use this to login and immediately change their login and password. + +If this value is changed while a User is actively logged in, it doesn't take effect until the *next* time they login. + +### Last login +This read only field shows the last time this User logged in for security purposes. + +### Active + +The active field controls whether a User is enabled in AyaNova. Inactive Users can not log in and their name is not offered in selection lists for new records by default. + +#### Revoking access + +Only active Users can login. If a User is set to inactive their authentication token is immediately revoked and even if they are currently logged in they will be logged out the moment they attempt any operation in AyaNova that needs to connect with the server or when the web application attempts to connect behind the scenes to check for notifications as it periodically does. + +This means the moment a User is deactivated and saved they are effectively locked out of AyaNova. + +#### Scheduleable type Users + +Scheduleable Users only consume a license when they are set to Active. De-activating them is a way to free up a license and also preserve the history of their work in AyaNova. +Scheduleable Users only appear in the schedule form if they are Active, de-activating a User means their work order scheduled items will not be displayed in the Service -> Schedule form so be sure to re-assign any open scheduled work order items for them to another Active User to ensure it doesn't get lost. You can not see their work order items in the graphical schedule form but you can still see them in the Work order data tables so click through to the Scheduled Users list, filter by the inactive Tech to confirm and re-assign any unfinished work still under their name. + +### Notes +This optional field is for the Use of the AyaNova administrator and is not displayed to the User themselves. It can be used for any purpose required. + +### Tags + +Tags for Users are optional but connected to many areas of AyaNova when it comes to filtering data and the notification system in particular. + +If the User is a scheduleable type, the tags entered here can be used as a filter in the schedule calendar to filter in or out data by tagged Users. This is useful in a large busy shop when there are just too many items to display in the graphical schedule and so tags are created to group scheduleable Users in some way that is most appropriate for the dispatcher / scheduler staff. + +In addition some notifications can be filtered by tag as required. + + +## User settings tab + +This section is a duplicate of the [User settings](home-user-settings.md) form. This tab can be used to set up Users in advance and is also mirrored for the User themselves to make adjustments including changing their own password and login. diff --git a/server/AyaNova/biz/UserBiz.cs b/server/AyaNova/biz/UserBiz.cs index 46ec6952..d1fbdeb4 100644 --- a/server/AyaNova/biz/UserBiz.cs +++ b/server/AyaNova/biz/UserBiz.cs @@ -297,56 +297,6 @@ namespace AyaNova.Biz } } - // //////////////////////////////////////////////////////////////////////////////////////////////// - // //DUPLICATE - // // - // internal async Task DuplicateAsync(long id) - // { - // User dbObject = await GetAsync(id, false); - - // if (dbObject == null) - // { - // AddError(ApiErrorCode.NOT_FOUND, "id"); - // return null; - // } - - // //Also used for Contacts (customer type user or ho type user) - // //by users with no User right but with Customer rights so need to double check here - // if ( - // (dbObject.IsOutsideUser && !Authorized.HasCreateRole(CurrentUserRoles, AyaType.Customer)) || - // (!dbObject.IsOutsideUser && !Authorized.HasCreateRole(CurrentUserRoles, AyaType.User)) - // ) - // { - // AddError(ApiErrorCode.NOT_AUTHORIZED); - // return null; - // } - - // User newObject = new User(); - // CopyObject.Copy(dbObject, newObject, "Id, Salt, Login, Password, CurrentAuthToken, DlKey, DlKeyExpire, Wiki, Serial"); - // string newUniqueName = string.Empty; - // bool NotUnique = true; - // long l = 1; - // do - // { - // newUniqueName = Util.StringUtil.UniqueNameBuilder(dbObject.Name, l++, 255); - // NotUnique = await ct.User.AnyAsync(z => z.Name == newUniqueName); - // } while (NotUnique); - // newObject.Name = newUniqueName; - // newObject.Id = 0; - // newObject.Concurrency = 0; - // newObject.Salt = Hasher.GenerateSalt(); - // newObject.Password = Hasher.GenerateSalt(); - // newObject.Login = Hasher.GenerateSalt(); - // newObject.UserOptions = new UserOptions(); - // newObject.UserOptions.TranslationId = ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID; - // await ct.User.AddAsync(newObject); - // await ct.SaveChangesAsync(); - // await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct); - // await SearchIndexAsync(newObject, true); - // await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null); - // await HandlePotentialNotificationEvent(AyaEvent.Created, newObject); - // return newObject; - // } //////////////////////////////////////////////////////////////////////////////////////////////// /// GET @@ -388,86 +338,6 @@ namespace AyaNova.Biz } - // //////////////////////////////////////////////////////////////////////////////////////////////// - // //UPDATE - // // - // internal async Task PutAsync(User putObject) - // { - // //todo: update to use the new PUT methodology - // var dbObject = await GetAsync(putObject.Id, false); - // if (dbObject == null) - // { - // AddError(ApiErrorCode.NOT_FOUND, "id"); - // return null; - // } - // //Also used for Contacts (customer type user or ho type user) - // //by users with no User right but with Customer rights so need to double check here - // if ( - // (dbObject.IsOutsideUser && !Authorized.HasModifyRole(CurrentUserRoles, AyaType.Customer)) || - // (!dbObject.IsOutsideUser && !Authorized.HasModifyRole(CurrentUserRoles, AyaType.User)) - // ) - // { - // AddError(ApiErrorCode.NOT_AUTHORIZED); - // return null; - // } - - - // User SnapshotOfOriginalDBObj = new User(); - // CopyObject.Copy(dbObject, SnapshotOfOriginalDBObj); - // CopyObject.Copy(putObject, dbObject, "Id, Salt, CurrentAuthToken, LoginKey, DlKey, DlKeyExpire"); - // dbObject.Tags = TagBiz.NormalizeTags(dbObject.Tags); - // dbObject.CustomFields = JsonUtil.CompactJson(dbObject.CustomFields); - - // //NOTE: It's valid to call this without intending to change login or password (null values) - // //Is the user updating the password? - // if (!string.IsNullOrWhiteSpace(putObject.Password)) - // { - // //YES password is being updated: - // dbObject.Password = Hasher.hash(SnapshotOfOriginalDBObj.Salt, putObject.Password); - // } - // else - // { - // //No, use the snapshot password value - // dbObject.Password = SnapshotOfOriginalDBObj.Password; - // dbObject.Salt = SnapshotOfOriginalDBObj.Salt; - // } - // //Updating login? - // if (!string.IsNullOrWhiteSpace(putObject.Login)) - // { - // //YES Login is being updated: - // dbObject.Login = putObject.Login; - // } - // else - // { - // //No, use the original value - // dbObject.Login = SnapshotOfOriginalDBObj.Login; - // } - - - // ct.Entry(dbObject).OriginalValues["Concurrency"] = putObject.Concurrency; - // await ValidateAsync(dbObject, SnapshotOfOriginalDBObj); - // if (HasErrors) return null; - // try - // { - // await ct.SaveChangesAsync(); - // } - // catch (DbUpdateConcurrencyException) - // { - // if (!await ExistsAsync(putObject.Id)) - // AddError(ApiErrorCode.NOT_FOUND); - // else - // AddError(ApiErrorCode.CONCURRENCY_CONFLICT); - // return null; - // } - // await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, BizType, AyaEvent.Modified), ct); - // await SearchIndexAsync(dbObject, false); - // await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, dbObject.Tags, SnapshotOfOriginalDBObj.Tags); - // await HandlePotentialNotificationEvent(AyaEvent.Modified, dbObject, SnapshotOfOriginalDBObj); - - - // return dbObject; - // } - //////////////////////////////////////////////////////////////////////////////////////////////// //UPDATE @@ -528,6 +398,13 @@ namespace AyaNova.Biz putObject.Login = dbObject.Login; } + //DE-ACTIVATING USER? + if (putObject.Active == false && dbObject.Active == true) + { + //yes, deactivating, so revoke their auth token + putObject.CurrentAuthToken = Hasher.GenerateSalt();//new random token that will definitely not work + } + await ValidateAsync(putObject, dbObject); if (HasErrors) return null; ct.Replace(dbObject, putObject);