I'm trying to figure out the best way to model/design and then implement a "user" feature in a system.
I am designing an on-line access request system, so our company can use a web-based method for users to request access to various software systems. Since the system is all about the "user", the user is the focal point of the system.
So, a User can request access to a system. Then, the User's Manager will approve/reject the request. After that, the System Owner will approve/reject the request. Then it's the System Admin who approves/rejects, and finally the Security Administrator approves/rejects and adds them to the appropriate Active Directory group so they have access to the target Active Directory-driven application (not this application).
I see all entities that represent a User as a core (set of) class(es) in the system. The User object is straight-forward - just pass their Windows login to Active Directory (AD) via an LDAP query and get their info and load it into an object. In an LDAP query, if there are other Users that report to them (a user's manager is stored in our AD), then this "user" is not only a User in this system but also a Manager. If this User is also in the database as a System Owner, they are also a System Owner.
(Assume a Manager is someone with at least one direct report assigned to them in AD.)
I've considered a single User object, with properties such as IsManager or IsSystemOwner. However, should I construct an object hierarchy where (for example) a Manager class inherits from User? There are quirks with this, because a System Owner could inherit from User or Manager. Not all system owners are managers. However, Managers, System Owners, System Admins, and Security Admins are all Users, because they can be requesting access to some software system where there role in this system is only as a User. Here is an overview of "is a" for all of the user entities:
- A User can request access to some other software system in this system.
- A Manager is a User.
- A System Owner is a User.
- A System Admin is a User.
- A Security Admin is a User (but unlikely to be, due to our organization).
- A Manager may be a System Owner, but not always.
- A System Owner may be a Manager, but not always.
- A System Admin may be a Manager, but not always.
- A System Admin may be a System Owner, but not likely.
- A Security Admin may be a Manager, but not always.
- A Security Admin may be a System Owner, but not likely.
Some additional info:
- I don't anticipate Security Admins to be using the system as a User to request access, but it's always a possibility.
- A Manager may create an access request on behalf of one of their employees (to revoke access to a fired employee, for example)
- All employees in the Windows domain will have access to this site. I assume that I will have some Active Directory groups created for System Admins and Security Admins, as the users in these groups will not be dynamic, rather, users in one team are Sys Admins and users in another team are Security Admins.
- The System Owner is subject to changed and will be stored in the database, along with the option to designate an alternate approver when on vacation, etc.
- I may need a Manager to have an alternate approver, but I didn't plan on storing all users on the domain in the database!
This seems like it's so easy to model on paper, but getting it into good, flexible code is stumping me. All suggestions are welcome.
EDIT: Based on Karl's feedback, I have this prototype model. Does it look solid from an OOP perspective, based on my intended use?
Public Class MyCustomUserObject Public Property LoginID As String Public Property FirstName As String Public Property LastName As String Public Property EmailAddress As String Public Property Roles As List(Of Role) Public Function IsManager() As Boolean ' If List(Of Role) contains an object of type ManagerRole, then True, else False. End Function Public Function IsSystemOwner(systemName As String) As Boolean ' If List(Of Role) contains an object of type SystemOwnerRole with matching name ' in SystemOwnerRole.SoftwareSystems, then True, else False. End Function Public Function IsSystemAdministrator(systemName As String) As Boolean ' If List(Of Role) contains an object of type SystemAdministratorRole with matching name ' in SystemAdministratorRole.SoftwareSystems, then True, else False. End Function Public Function IsSecurityAdministrator() As Boolean Return My.User.IsInRole("My Active Directory group name for Security Admins") End Function End Class Public Class SoftwareSystem Public Property ID As String Public Property Name As String End Class Public MustInherit Class Role Public Property DesignatedApproverLoginID As String End Class Public Class ManagerRole Inherits Role Public Property Subordinates As List(Of AafUser) ' Or this, with a List of login IDs? ' Public Property Subordinates As List(Of String) End Class Public Class SystemOwnerRole Inherits Role Public Property SoftwareSystems As List(Of SoftwareSystem) End Class Public Class SystemAdministratorRole Inherits Role Public Property SoftwareSystems As List(Of SoftwareSystem) End Class Public Class SecurityAdministratorRole Inherits Role ' Explictly a Security Admin for all Software Systems. End Class