/// <summary> /// The Index method is the main method called when the front page of the website is launched. This method: /// 1. authenticates the application /// 2. performs requested actions in response to form submissions /// 3. calls the model to retrieve user data /// 4. calls the view to display user data /// </summary> /// <returns>ActionResult (generally a View).</returns> public ActionResult Index() { string strErrors = string.Empty; // check if we have changed authentication parameters string strFormAction = this.Request["submitButton"]; if (strFormAction == "applicationUpdate") { Org.WhichCred(this.Request["WhichCred"]); StringConstants.ClientId = this.Request["AppId"]; StringConstants.ClientSecret = this.Request["AppSecret"]; StringConstants.AppObjectId = this.Request["AppObjectId"]; StringConstants.Tenant = this.Request["AppTenant"]; } // use ADAL library to connect to AAD tenant using authentication parameters string baseGraphUri = StringConstants.BaseGraphUri + StringConstants.Tenant; GraphQuery graphCall = new GraphQuery(); graphCall.ApiVersion = StringConstants.ApiVersion; graphCall.BaseGraphUri = baseGraphUri; // get token using OAuth Authorization Code AzureADAuthentication aadAuthentication = new AzureADAuthentication(); AuthenticationResult authenticationResult = aadAuthentication.GetAuthenticationResult( StringConstants.Tenant, StringConstants.ClientId, StringConstants.ClientSecret, StringConstants.Resource, StringConstants.AuthenticationEndpoint, ref strErrors); if (authenticationResult != null) { ViewBag.Message = "Authentication succeeded!"; // initialize view data based on default or query string UPN NameValueCollection queryValues = Request.QueryString; string strUpn = queryValues["upn"]; // initialize graph graphCall.aadAuthentication = aadAuthentication; graphCall.aadAuthentication.AadAuthenticationResult = authenticationResult; // configure org and extensions model objects OrgChart.Models.Org org = new OrgChart.Models.Org(graphCall); OrgChart.Models.DirectoryExtensions extensions = new OrgChart.Models.DirectoryExtensions(graphCall); // retrieve template user containing all extensions and add manager UPN ViewBag.ExtensionRegistryUser = extensions.GetExtensionRegistryUser(ref strErrors); ViewBag.ExtensionRegistryUser["managerUserPrincipalName"] = org.GetUsersManager(DirectoryExtensions.GetExtensionRegistryUserUpn()); // setup JObject for setuser by enumerating registry user JObject graphUser = new JObject(); foreach (JProperty property in ViewBag.ExtensionRegistryUser.Properties()) { if (property.Name.StartsWith(DirectoryExtensions.ExtensionPropertyPrefix) || Org.StandardAttributes().Contains(property.Name)) { string value = this.Request[property.Name]; graphUser[property.Name] = (value == string.Empty) ? null : value; } } // strFormAction set at top of Index() to process auth parameter actions, process the rest of the actions here switch (strFormAction) { case "userUpdate": // set display name, manager, job title, trio, skype for given UPN extensions.SetUser(graphUser, ref strErrors); // show the user, unless trio is set, then show the manager strUpn = this.Request["userPrincipalName"]; if ((string)graphUser[DirectoryExtensions.GetExtensionName("trio")] != string.Empty) { strUpn = this.Request["managerUserPrincipalName"]; } break; case "userCreate": // create user with given display name, UPN, and manager, show the new user extensions.CreateUser(graphUser, ref strErrors); strUpn = (string)graphUser["userPrincipalName"]; break; case "userDelete": // delete user with given UPN org.DeleteUser((string)graphUser["userPrincipalName"], ref strErrors); break; case "extensionCreate": { // register the passed extension string strExtension = this.Request["Extension"]; if (extensions.RegisterExtension(strExtension, ref strErrors)) { // set this extension value to "registered" on the "registry" object ViewBag.ExtensionRegistryUser[DirectoryExtensions.GetExtensionName(strExtension)] = "reserved"; JObject returnedUser = extensions.SetUser(ViewBag.ExtensionRegistryUser, ref strErrors); } } break; } // may have changed attributes, extension values, extension registration, or tenant credentials, re-retrieve extension registry user ViewBag.ExtensionRegistryUser = extensions.GetExtensionRegistryUser(ref strErrors); ViewBag.ExtensionRegistryUser["managerUserPrincipalName"] = org.GetUsersManager(DirectoryExtensions.GetExtensionRegistryUserUpn()); // no UPN provided, get the UPN of the first user instead if (strUpn == null) { strUpn = org.GetFirstUpn(); } // initialize the ViewBag if we have a UPN if (strUpn != null) { string strTrio = queryValues["trio"]; bool bTrio = strTrio != null && string.Equals(strTrio, "true", StringComparison.CurrentCultureIgnoreCase); ViewBag.AncestorsAndMainPerson = org.GetAncestorsAndMain(strUpn, bTrio, ref strErrors); ViewBag.DirectsOfDirects = org.GetDirectsOfDirects(strUpn, bTrio, ref strErrors); ViewBag.strErrors = strErrors; } } else { ViewBag.Message = "Authentication Failed!"; } return this.View(); }
/// <summary> /// The Index method is the main method called when the front page of the website is launched. This method: /// 1. authenticates the application /// 2. performs requested actions in response to form submissions /// 3. calls the model to retrieve user data /// 4. calls the view to display user data /// </summary> /// <returns>ActionResult (generally a View).</returns> public ActionResult Index() { string strErrors = string.Empty; // check if we have changed authentication parameters string strFormAction = this.Request["submitButton"]; if (strFormAction == "applicationUpdate") { Org.WhichCred(this.Request["WhichCred"]); StringConstants.ClientId = this.Request["AppId"]; StringConstants.ClientSecret = this.Request["AppSecret"]; StringConstants.AppObjectId = this.Request["AppObjectId"]; StringConstants.Tenant = this.Request["AppTenant"]; } // use ADAL library to connect to AAD tenant using authentication parameters string baseGraphUri = StringConstants.BaseGraphUri + StringConstants.Tenant; GraphQuery graphCall = new GraphQuery(); graphCall.ApiVersion = StringConstants.ApiVersion; graphCall.BaseGraphUri = baseGraphUri; // get token using OAuth Authorization Code AzureADAuthentication aadAuthentication = new AzureADAuthentication(); AuthenticationResult authenticationResult = aadAuthentication.GetAuthenticationResult( StringConstants.Tenant, StringConstants.ClientId, StringConstants.ClientSecret, StringConstants.Resource, StringConstants.AuthenticationEndpoint, ref strErrors); if (authenticationResult != null) { ViewBag.Message = "Authentication succeeded!"; // initialize view data based on default or query string UPN NameValueCollection queryValues = Request.QueryString; string strUpn = queryValues["upn"]; // initialize graph graphCall.aadAuthentication = aadAuthentication; graphCall.aadAuthentication.AadAuthenticationResult = authenticationResult; // configure org and extensions model objects OrgChart.Models.Org org = new OrgChart.Models.Org(graphCall); OrgChart.Models.DirectoryExtensions extensions = new OrgChart.Models.DirectoryExtensions(graphCall); // retrieve template user containing all extensions and add manager UPN ViewBag.ExtensionRegistryUser = extensions.GetExtensionRegistryUser(ref strErrors); ViewBag.ExtensionRegistryUser["managerUserPrincipalName"] = org.GetUsersManager(DirectoryExtensions.GetExtensionRegistryUserUpn()); // setup JObject for setuser by enumerating registry user JObject graphUser = new JObject(); foreach (JProperty property in ViewBag.ExtensionRegistryUser.Properties()) { if (property.Name.StartsWith(DirectoryExtensions.ExtensionPropertyPrefix) || Org.StandardAttributes().Contains(property.Name)) { string value = this.Request[property.Name]; graphUser[property.Name] = (value == string.Empty) ? null : value; } } // strFormAction set at top of Index() to process auth parameter actions, process the rest of the actions here switch (strFormAction) { case "userUpdate": // set display name, manager, job title, trio, skype for given UPN extensions.SetUser(graphUser, ref strErrors); // show the user, unless trio is set, then show the manager strUpn = this.Request["userPrincipalName"]; if ((string)graphUser[DirectoryExtensions.GetExtensionName("trio")] != string.Empty) { strUpn = this.Request["managerUserPrincipalName"]; } break; case "userCreate": // create user with given display name, UPN, and manager, show the new user extensions.CreateUser(graphUser, ref strErrors); strUpn = (string)graphUser["userPrincipalName"]; break; case "userDelete": // delete user with given UPN org.DeleteUser((string)graphUser["userPrincipalName"], ref strErrors); break; case "extensionCreate": { // register the passed extension string strExtension = this.Request["Extension"]; if (extensions.RegisterExtension(strExtension, ref strErrors)) { // set this extension value to "registered" on the "registry" object ViewBag.ExtensionRegistryUser[DirectoryExtensions.GetExtensionName(strExtension)] = "reserved"; JObject returnedUser = extensions.SetUser(ViewBag.ExtensionRegistryUser, ref strErrors); } } break; } // may have changed attributes, extension values, extension registration, or tenant credentials, re-retrieve extension registry user ViewBag.ExtensionRegistryUser = extensions.GetExtensionRegistryUser(ref strErrors); ViewBag.ExtensionRegistryUser["managerUserPrincipalName"] = org.GetUsersManager(DirectoryExtensions.GetExtensionRegistryUserUpn()); // no UPN provided, get the UPN of the first user instead if (strUpn == null) { strUpn = org.GetFirstUpn(); } // initialize the ViewBag if we have a UPN if (strUpn != null) { string strTrio = queryValues["trio"]; bool bTrio = strTrio != null && string.Equals(strTrio, "true", StringComparison.CurrentCultureIgnoreCase); ViewBag.AncestorsAndMainPerson = org.GetAncestorsAndMain(strUpn, bTrio, ref strErrors); ViewBag.DirectsOfDirects = org.GetDirectsOfDirects(strUpn, bTrio, ref strErrors); ViewBag.strErrors = strErrors; } } else { ViewBag.Message = "Authentication Failed!"; } return(this.View()); }
/// <summary> /// get user JSON object (including extension attributes) for object storing extensions registered by this module /// </summary> /// <param name="strErrors">error return value</param> /// <returns>user object</returns> public JObject GetExtensionRegistryUser(ref string strErrors) { string strUpn = DirectoryExtensions.GetExtensionRegistryUserUpn(); return(this.GetUser(strUpn, ref strErrors)); }
/// <summary> /// Initializes a new instance of the <see cref="Org"/> class. /// </summary> /// <param name="gq">initialized graph client object</param> public Org(GraphQuery gq) { this.graphCall = gq; this.extensions = new DirectoryExtensions(gq); }
/// <summary> /// Retrieves chain of command for entity represented by UPN. /// If bTrio is not set, this returns list of single item lists terminating with single item list containing CEO. /// If bTrio is set, this returns list of trio leader lists terminating with single item list containing CEO. /// </summary> /// <param name="strUPN">Main person we are displaying in the org chart.</param> /// <param name="bTrio">Whether we are displaying in trio mode.</param> /// <param name="strErrors">Error return value.</param> /// <returns>list of list of users</returns> public List <List <JObject> > GetAncestorsAndMain(string strUPN, bool bTrio, ref string strErrors) { List <List <JObject> > returnedListOfLists = new List <List <JObject> >(); // preserve original error string strOriginalError = strErrors; // split comma delimited UPN list into UPNs string[] arrayUPN = strUPN.Split(','); for (int idxTrio = 0; idxTrio < arrayUPN.Length; idxTrio++) { // retrieve graph node for this person (or for each trio member) from graph string strMainUPN = arrayUPN[idxTrio]; JObject graphUser = this.extensions.GetUser(strMainUPN, ref strErrors); // TODO: this logic is dependent on trios being properly filled in at each level of hierarchy // enumerate graph users from the main person (or from each trio member) to the root int idxAncestorOrMain = 0; while (graphUser != null) { // create a new AncestorOrMain trio list if processing non-trio member or first member of trio if (idxTrio == 0) { returnedListOfLists.Insert(0, new List <JObject>()); } // get next graph user JObject graphUserParent = this.extensions.GetUsersManager((string)graphUser["userPrincipalName"], ref strErrors); // tag user with manager attribute graphUser["managerUserPrincipalName"] = (graphUserParent != null) ? graphUserParent["userPrincipalName"] : "NO MANAGER"; // insert user at end of the correct AncestorOrMain trio list JToken tokenTrio = null; if (bTrio && graphUser.TryGetValue(DirectoryExtensions.GetExtensionName("trio"), out tokenTrio)) { // trio mode and there is a trio set on this object, add to list each time through returnedListOfLists.ElementAt(returnedListOfLists.Count - idxAncestorOrMain - 1).Add(graphUser); } else if (idxTrio == 0) { // otherwise, this user not part of a trio, just add the first time through returnedListOfLists.ElementAt(returnedListOfLists.Count - idxAncestorOrMain - 1).Add(graphUser); } // detect infinite loop: user is own manager, skip, notify and allow user to fix if ((graphUserParent != null) && ((string)graphUserParent["userPrincipalName"] == (string)graphUser["userPrincipalName"])) { strErrors += (string)graphUser["userPrincipalName"] + " has itself as manager. Please resolve.\n"; break; } // set next graph user graphUser = graphUserParent; // increment the ancestor level idxAncestorOrMain++; } // we know that root doesn't have a manager, restore original error if (graphUser == null) { strErrors = strOriginalError; } } return(returnedListOfLists); }
/// <summary> /// Retrieves subordinates for entity represented by UPN. /// Each direct subordinate is head of a list, with subordinates of that direct as elements of that list. /// </summary> /// <param name="strUPN">Main person we are displaying in the org chart.</param> /// <param name="bTrio">Whether we are displaying in trio mode.</param> /// <param name="strErrors">Error return value.</param> /// <returns>list of list of users</returns> public List <List <JObject> > GetDirectsOfDirects(string strUPN, bool bTrio, ref string strErrors) { List <List <JObject> > returnedListOfLists = new List <List <JObject> >(); // split comma delimited UPN list into UPNs string[] arrayUPN = strUPN.Split(','); // TODO: if in trio mode and only one passed member, do filtered query for rest of trio // TODO: more efficient to do this filtered query for rest of trio in GetAncestorsAndMain // now retrieve direct reports for single person or trio for (int i = 0; i < arrayUPN.Length; i++) { string strMainUPN = arrayUPN[i]; JUsers directs = this.extensions.GetUsersDirectReports(strMainUPN, ref strErrors); if (directs != null && directs.users != null) { foreach (JObject directReport in directs.users) { // add a new list at front of list of lists returnedListOfLists.Insert(0, new List <JObject>()); // tag the direct report with manager attribute directReport["managerUserPrincipalName"] = strMainUPN; // insert the direct report at front of newly inserted list returnedListOfLists.ElementAt(0).Insert(0, directReport); // get direct reports of the direct report (and tag manager state to color code managers among directs) JUsers directsOfDirect = this.extensions.GetUsersDirectReports((string)directReport["userPrincipalName"], ref strErrors); directReport["isManager"] = directsOfDirect.users.Count > 0; foreach (JObject directOfDirect in directsOfDirect.users) { // tag each direct of direct with manager attribute and assume they are not managers (for purposes of coloring) directOfDirect["managerUserPrincipalName"] = (string)directReport["userPrincipalName"]; directOfDirect["isManager"] = false; returnedListOfLists.ElementAt(0).Add(directOfDirect); } } } } // sort the list of lists by trio // http://stackoverflow.com/questions/3309188/c-net-how-to-sort-a-list-t-by-a-property-in-the-object returnedListOfLists.Sort( delegate(List <JObject> x, List <JObject> y) { JToken tokenTrioX = null; bool bxTrio = x.ElementAt(0).TryGetValue(DirectoryExtensions.GetExtensionName("trio"), out tokenTrioX); JToken tokenTrioY = null; bool byTrio = y.ElementAt(0).TryGetValue(DirectoryExtensions.GetExtensionName("trio"), out tokenTrioY); if (!bxTrio && !byTrio) { // if neither has a trio, they are equal return(0); } else if (bxTrio && !byTrio) { // if only one has a trio, that one comes first return(-1); } else if (!bxTrio && byTrio) { // if only one has a trio, that one comes first return(1); } else if (bxTrio && byTrio) { // if both have trios, perform the comparison to determine which one comes first return(((string)tokenTrioX).CompareTo((string)tokenTrioY)); } else { return(0); } }); return(returnedListOfLists); }