/// <summary> /// Changes a user role within the organisation /// </summary> /// <param name="dbCtx"></param> /// <param name="user"></param> /// <param name="userAccountService"></param> /// <returns></returns> public async Task ChangeOrganisationUserRole <TAccount>(DbContext dbCtx, MapHiveUser user, UserAccountService <TAccount> userAccountService) where TAccount : RelationalUserAccount { //this basically needs to remove all the org roles for a user and add the specified one var ownerRole = await GetOrgOwnerRoleAsync(dbCtx); var adminRole = await GetOrgAdminRoleAsync(dbCtx); var memberRole = await GetOrgMemberRoleAsync(dbCtx); var addRole = memberRole; switch (user.OrganisationRole) { case OrganisationRole.Admin: addRole = adminRole; break; case OrganisationRole.Owner: addRole = ownerRole; break; } user.RemoveLink(ownerRole); user.RemoveLink(adminRole); user.RemoveLink(memberRole); if (user.OrganisationRole.HasValue) { user.AddLink(addRole); } await user.UpdateAsync(dbCtx, userAccountService); }
/// <summary> /// Gets apps visible by a user /// </summary> /// <param name="dbCtx"></param> /// <param name="userId"></param> /// <param name="orgIdentifier"></param> /// <returns></returns> public static async Task <IEnumerable <Application> > GetUserAppsAsync(DbContext dbCtx, Guid?userId, string orgIdentifier = null) { var appCollector = new List <Application>(); //common apps //do not return hive apps! they should not be listed in user apps even though they will usually be common apps var commonApps = await dbCtx.Set <Application>().Where(a => a.IsCommon && !a.IsHive).ToListAsync(); appCollector.AddRange(commonApps); MapHiveUser user = null; if (userId.HasValue) { user = await dbCtx.Set <MapHiveUser>().FirstOrDefaultAsync(u => u.Uuid == userId); } Organisation org = null; if (user != null && !string.IsNullOrEmpty(orgIdentifier)) { org = await dbCtx.Set <Organisation>().FirstOrDefaultAsync(o => o.Slug == orgIdentifier); } //get org apps - the apps that are not public, but assigned to orgs directly if (user != null && org != null) { var orgApps = await org.GetChildrenAsync <Organisation, Application>(dbCtx); foreach (var app in orgApps) { if (!appCollector.Exists(a => a.Uuid == app.Uuid)) { appCollector.Add(app); } } } var outApps = new List <Application>(); foreach (var a in appCollector) { if ( a.IsDefault || //always return the dashboard (a.IsCommon && !a.RequiresAuth) || //and the public apps with no auth (org != null && (await org.GetUserAppAccessCredentials(dbCtx, user, a)).CanUseApp) ) { outApps.Add(a); } } //TODO - more ordering - stuff like special apps that are not public, but assigned to orgs directly, etc. Also, maybe some differentiation between freely accessible apps and the apps with auth. //stuff like home & dashboard always at the beginning and such... return(outApps.OrderByDescending(a => a.IsHome).ThenByDescending(a => a.IsDefault).ThenBy(a => a.Name));; }
/// <summary> /// Gets a full user name based on user data, so pretty much name && surname? name surname : surname || name || email /// </summary> /// <param name="u"></param> /// <returns></returns> public static string GetFullUserName(this MapHiveUser u) { return(!string.IsNullOrEmpty(u.Forename) && !string.IsNullOrEmpty(u.Surname) ? $"{u.Forename} {u.Surname}" : !string.IsNullOrEmpty(u.Forename) ? u.Forename : !string.IsNullOrEmpty(u.Surname) ? u.Surname : u.Email); }
/// <summary> /// Adds a member to an organisation /// </summary> /// <param name="dbCtx"></param> /// <param name="user"></param> /// <param name="userAccountService"></param> /// <param name="role"></param> /// <returns></returns> public async Task AddOrganisationUser <TAccount>(DbContext dbCtx, MapHiveUser user, UserAccountService <TAccount> userAccountService, OrganisationRole role = OrganisationRole.Member) where TAccount : RelationalUserAccount { this.AddLink(user); await this.UpdateAsync(dbCtx); //by default assign a member role to a user var memberRole = await this.GetOrgRoleAsync(dbCtx, role); user.AddLink(memberRole); await user.UpdateAsync(dbCtx, userAccountService); }
/// <summary> /// Returns user application credentials within an organisation /// </summary> /// <param name="dbCtx"></param> /// <param name="user"></param> /// <param name="app"></param> /// <returns></returns> public async Task <OrgUserAppAccessCredentials> GetUserAppAccessCredentials(DbContext dbCtx, MapHiveUser user, Application app) { var output = new OrgUserAppAccessCredentials { Organisation = this, Application = app }; //check if organisation can access and application if not, then good bye if (!await CanUseApp(dbCtx, app)) { return(output); } //check if user is an org owner or org admin output.IsAppAdmin = await IsOrgOwner(dbCtx, user) || await IsOrgAdmin(dbCtx, user); output.CanUseApp = output.IsAppAdmin; //user is not granted app admin access via org owner / admin roles, so need to check if user can access the app as a 'normal' user, so via teams //note: teams can also grant app admin role! if (!output.IsAppAdmin) { var orgTeams = await this.GetChildrenAsync <Organisation, Team>(dbCtx); foreach (var team in orgTeams) { //get team's app link var teamAppLink = await team.GetChildLinkAsync(dbCtx, app); //make sure team grants access to an app if (teamAppLink == null) { continue; } //get team's user link var teamUserLink = await team.GetChildLinkAsync(dbCtx, user); var userCanUseApp = teamUserLink != null; //if a team grants an access to an app for a user we can test if it also test if it is admin access if (userCanUseApp) { //only apply true assignment here so it does not get reset when searching for app admin credentials! output.CanUseApp = userCanUseApp; //extract app access credentials link data var appAccessCredentials = teamAppLink.LinkData.GetByKey(Team.AppAccessCredentialsLinkDataObject); output.IsAppAdmin = appAccessCredentials != null && appAccessCredentials.ContainsKey(Team.AppAdminAccess) && (bool)appAccessCredentials[Team.AppAdminAccess]; } //no point in testing other teams, as full app access is already granted if (output.IsAppAdmin) { break; } } } //if this is a default (dashboard) app a user should ALWAYS BE ABLE TO use it; the default (dashboard) app will take care of handling the context itself if (app.IsDefault) { output.CanUseApp = true; } return(output); }
/// <summary> /// Checks if a user is an organisation admin (user has the org admin role assigned) /// </summary> /// <param name="dbctx"></param> /// <param name="user"></param> /// <returns></returns> public async Task <bool> IsOrgAdmin(DbContext dbctx, MapHiveUser user) { return(await user.HasChildLinkAsync(dbctx, await GetOrgAdminRoleAsync(dbctx))); }
/// <summary> /// Determines if a user is an org member (is assigned to an org) /// </summary> /// <param name="dbctx"></param> /// <param name="user"></param> /// <returns></returns> public async Task <bool> IsOrgMember(DbContext dbctx, MapHiveUser user) { return(await this.HasChildLinkAsync(dbctx, user)); }