protected virtual void OnPlayerDisconnected(SteamPlayer player) { var user = GetUser(player); if (user == null) { return; } if (user.Session is UnturnedUserSession session) { session.OnSessionEnd(); } AsyncHelper.RunSync(async() => { var disconnectedEvent = new UserDisconnectedEvent(user); await m_EventBus.EmitAsync(m_Runtime, this, disconnectedEvent); m_UnturnedUsers.Remove(user); var userData = await m_UserDataStore.GetUserDataAsync(user.Id, user.Type); if (userData == null) { return; } userData.LastSeen = DateTime.Now; await m_UserDataStore.SaveUserDataAsync(userData); }); }
public override Task <decimal> GetBalanceAsync(string ownerId, string ownerType) { var tcs = new TaskCompletionSource <decimal>(); m_EconomyDispatcher.Enqueue(async() => { tcs.SetResult(await m_UserDataStore.GetUserDataAsync <decimal?>(ownerId, ownerType, TableName) ?? DefaultBalance); }); return(tcs.Task); }
private void UpdateLastSeen(string id, string type) { UniTask.RunOnThreadPool(async() => { var userData = await m_UserDataStore.GetUserDataAsync(id, type); if (userData == null) { return; } userData.LastSeen = DateTime.Now; await m_UserDataStore.SetUserDataAsync(userData); }).Forget(); }
public async Task SeedUserDataAsync(string actorId, string actorType, string displayName, Dictionary <string, object> data = null) { var userData = await m_UserDataStore.GetUserDataAsync(actorId, actorType); if (userData != null) { return; // no seeding } var autoAssignRoles = new HashSet <string>(await m_PermissionRoleStore.GetAutoAssignedRolesAsync(actorId, actorType)); userData = new UserData { Data = data ?? new Dictionary <string, object>(), Id = actorId, Type = actorType, LastSeen = DateTime.Now, FirstSeen = DateTime.Now, Permissions = new HashSet <string>(), Roles = autoAssignRoles, LastDisplayName = displayName }; await m_UserDataStore.SaveUserDataAsync(userData); }
public async Task <PermissionRoleData?> GetOrderedPermissionRoleData(string id, string type) { PermissionRoleData?result = null; var data = await m_UserDataStore.GetUserDataAsync(id, type); if (data?.Roles != null) { foreach (var roleId in data.Roles) { var role = await m_PermissionRolesDataStore.GetRoleAsync(roleId); if (role == null) { continue; } if ((result?.Priority ?? int.MinValue) < role.Priority) { result = role; } } } return(result); }
private async void SaveDeathLocation(PlayerLife sender, EDeathCause cause, ELimb limb, CSteamID instigator) { var userData = await m_UserDataStore.GetUserDataAsync(sender.player.channel.owner.playerID.steamID.ToString(), "player"); userData.Data["deathLocation"] = sender.transform.position.ToSerializableVector3(); await m_UserDataStore.SetUserDataAsync(userData); }
public async Task <IUser?> FindUserAsync(string userType, string searchString, UserSearchMode searchMode) { if (searchMode != UserSearchMode.FindById && searchMode != UserSearchMode.FindByNameOrId) { return(null); } var data = await m_UserDataStore.GetUserDataAsync(searchString, userType); if (data == null) { return(null); } return(new OfflineUser(this, m_UserDataStore, data)); }
public async Task SeedUserDataAsync(string actorId, string actorType, string?displayName, Dictionary <string, object?>?data = null) { if (string.IsNullOrEmpty(actorId)) { throw new ArgumentException(nameof(actorId)); } if (string.IsNullOrEmpty(actorType)) { throw new ArgumentException(nameof(actorType)); } var userData = await m_UserDataStore.GetUserDataAsync(actorId, actorType); if (userData != null) { return; // no seeding } var autoAssignRoles = new HashSet <string>(await m_PermissionRoleStore.GetAutoAssignedRolesAsync(actorId, actorType)); userData = new UserData { Data = data ?? new Dictionary <string, object?>(), Id = actorId, Type = actorType, LastSeen = DateTime.Now, FirstSeen = DateTime.Now, Permissions = new HashSet <string>(), Roles = autoAssignRoles, LastDisplayName = displayName }; await m_UserDataStore.SetUserDataAsync(userData); }
protected override async UniTask OnExecuteAsync() { if (Context.Parameters.Length != 0) { throw new CommandWrongUsageException(Context); } UnturnedUser uPlayer = (UnturnedUser)Context.Actor; var userData = await m_UserDataStore.GetUserDataAsync(uPlayer.Id, uPlayer.Type); if (!userData.Data.ContainsKey("deathLocation")) { throw new UserFriendlyException(m_StringLocalizer["back:none"]); } var backLocation = SerializableVector3.Deserialize(userData.Data["deathLocation"]); if (backLocation == null) { throw new UserFriendlyException(m_StringLocalizer["back:none"]); } await uPlayer.Player.Player.TeleportToLocationAsync(backLocation.ToUnityVector3()); await PrintAsync(m_StringLocalizer["back:success"]); }
public async Task SavePersistentDataAsync <T>(string key, T data) { var userData = await m_UserDataStore.GetUserDataAsync(Id, Type); userData.Data ??= new Dictionary <string, object>(); if (userData.Data.ContainsKey(key)) { userData.Data[key] = data; } else { userData.Data.Add(key, data); } await m_UserDataStore.SaveUserDataAsync(userData); }
private async Task SalaryTimer(string salaryId) { while (_salaries.Contains(salaryId)) { var salary = _configuration.GetSection("Salaries").Get <List <Salary> >().FirstOrDefault(x => x.RoleId == salaryId); if (salary != null) { foreach (var player in await _userManager.GetUsersAsync(KnownActorTypes.Player)) { if (player.Session == null) { continue; } var playerData = await _userDataStore.GetUserDataAsync(player.Id, KnownActorTypes.Player); if (playerData !.Roles !.Contains(salary !.RoleId !)) { await _economyProvider.Value.UpdateBalanceAsync(player.Id, KnownActorTypes.Player, salary.Payment, "Salary"); await player.PrintMessageAsync(_stringLocalizer["SalaryPayment", new { Money = salary.Payment, RoleId = salary.RoleId }], Color.Green); } } await Task.Delay(TimeSpan.FromSeconds(salary.Timer)); } else { if (_salaries.Contains(salaryId)) { _salaries.Remove(salaryId); } } } }
public override async Task <bool> CheckAsync(ICommandContext context, IServiceProvider services, CancellationToken cancellationToken = default) { IUserDataStore userDataStore = services.GetRequiredService <IUserDataStore>(); // check if user is bot admin UserData userData = await userDataStore.GetUserDataAsync(context.Message.SenderID.Value, cancellationToken).ConfigureAwait(false); return(userData.IsBotAdmin); }
protected async Task <HashSet <string> > GetPermissionsAsync(IPermissionActor actor, bool inherit = true) //order by descending priority { var permissions = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase); var user = await m_UserDataStore.GetUserDataAsync(actor.Id, actor.Type); if (user?.Permissions != null) { permissions.UnionWith(user.Permissions); } foreach (var role in (await m_PermissionRoleStore.GetRolesAsync(actor, inherit)).OrderByDescending(gp => gp.Priority)) { permissions.UnionWith(((PermissionRole)role).Permissions); } return(permissions); }
protected override async Task OnExecuteAsync() { if (Context.Parameters.Length != 3) { throw new CommandWrongUsageException(Context); } IPermissionActor target; string permission; string actorType = Context.Parameters[0].ToLower(); string targetName = Context.Parameters[1]; string permissionToUpdate = Context.Parameters[2]; switch (actorType) { case "g": case "group": permission = "Manage.Groups." + targetName; target = await m_PermissionGroupStore.GetGroupAsync(targetName); if (target == null) { await Context.Actor.PrintMessageAsync($"Group \"{targetName}\" was not found.", Color.Red); return; } break; case "p": case "player": permission = "Manage.Players"; var id = await Context.Parameters.GetAsync <string>(1); var user = await m_UserDataStore.GetUserDataAsync(actorType, id); if (user == null) { // todo: localizable throw new UserFriendlyException($"User not found: {id}"); } target = (UserDataPermissionActor)user; break; default: throw new CommandWrongUsageException(Context); } if (await CheckPermissionAsync(permission) != PermissionGrantResult.Grant) { throw new NotEnoughPermissionException(Context, permission); } await ExecuteUpdateAsync(target, permissionToUpdate); }
protected virtual void OnPendingPlayerConnected(ValidateAuthTicketResponse_t callback, ref bool isvalid, ref string explanation) { var isvalid_ = isvalid; var explanation_ = explanation; AsyncHelper.RunSync(async() => { if (!isvalid_) { return; } var steamPending = Provider.pending.First(d => d.playerID.steamID == callback.m_SteamID); var pendingUser = new UnturnedPendingUser(steamPending); await m_DataSeeder.SeedUserDataAsync(pendingUser.Id, pendingUser.Type, pendingUser.DisplayName); var userData = await m_UserDataStore.GetUserDataAsync(pendingUser.Type, pendingUser.Id); userData.LastSeen = DateTime.Now; userData.LastDisplayName = pendingUser.DisplayName; await m_UserDataStore.SaveUserDataAsync(userData); pendingUser.PersistentData = userData.Data; m_PendingUsers.Add(pendingUser); var userConnectingEvent = new UserConnectingEvent(pendingUser); await m_EventBus.EmitAsync(m_Runtime, this, userConnectingEvent); if (!string.IsNullOrEmpty(userConnectingEvent.RejectionReason)) { isvalid_ = false; explanation_ = userConnectingEvent.RejectionReason; } if (userConnectingEvent.IsCancelled) { isvalid_ = false; } }); isvalid = isvalid_; explanation = explanation_; }
private async Task <T> GetConfigAsync <T>(ChatMessage message, CancellationToken cancellationToken = default) where T : class, ITargetConfig { if (message.IsGroupMessage) { return(await _groupConfigStore.GetGroupConfigAsync(message.RecipientID, cancellationToken).ConfigureAwait(false) as T); } else { return(await _userDataStore.GetUserDataAsync(message.SenderID.Value, cancellationToken).ConfigureAwait(false) as T); } }
public async Task SavePersistentDataAsync <T>(string key, T?data) { if (string.IsNullOrEmpty(key)) { throw new ArgumentException(nameof(key)); } var userData = await m_UserDataStore.GetUserDataAsync(Id, Type) ?? new UserData(); userData.Data ??= new Dictionary <string, object?>(); if (userData.Data.ContainsKey(key)) { userData.Data[key] = data; } else { userData.Data.Add(key, data); } await m_UserDataStore.SetUserDataAsync(userData); }
protected override async UniTask OnExecuteAsync() { if (Context.Parameters.Length > 1) { throw new CommandWrongUsageException(Context); } if (Context.Parameters.Length == 0 && Context.Actor.Type != KnownActorTypes.Player) { throw new CommandWrongUsageException(Context); } if (Context.Parameters.Length == 1 && await CheckPermissionAsync("others") == PermissionGrantResult.Deny) { throw new NotEnoughPermissionException(Context, "others"); } UnturnedUser uPlayer = Context.Parameters.Length == 0 ? (UnturnedUser)Context.Actor : await Context.Parameters.GetAsync <UnturnedUser>(0); if (uPlayer == null) { throw new UserFriendlyException(m_StringLocalizer["commands:failed_player", new { Player = Context.Parameters[0] }]); } UserData userData = await m_UserDataStore.GetUserDataAsync(uPlayer.Id, uPlayer.Type); if (!userData.Data.ContainsKey("homes")) { throw new UserFriendlyException(m_StringLocalizer["home:no_home"]); } var homes = (Dictionary <object, object>)userData.Data["homes"]; if (homes.Count == 0) { throw new UserFriendlyException(m_StringLocalizer["home:no_home"]); } var stringBuilder = new StringBuilder(); foreach (var pair in homes) { stringBuilder.Append($"{pair.Key}, "); } stringBuilder.Remove(stringBuilder.Length - 2, 2); await uPlayer.PrintMessageAsync(m_StringLocalizer["home:list", new { User = uPlayer.DisplayName, Homes = stringBuilder.ToString() }]); }
private async Task <UserData> GetOrCreateUserData(CommandContext context, CancellationToken cancellationToken = default) { try { UserData result = await _userDataStore.GetUserDataAsync(context.Message.SenderID.Value, cancellationToken).ConfigureAwait(false); return(result ?? new UserData(context.Message.SenderID.Value)); } catch { await context.ReplyTextAsync("/alert Failed retrieving user data from the database.", cancellationToken).ConfigureAwait(false); throw; } }
protected override async UniTask OnExecuteAsync() { if (Context.Parameters.Length < 1 || Context.Parameters.Length > 2) { throw new CommandWrongUsageException(Context); } if (Context.Parameters.Length == 1 && Context.Actor.Type != KnownActorTypes.Player) { throw new CommandWrongUsageException(Context); } if (Context.Parameters.Length == 2 && await CheckPermissionAsync("others") == PermissionGrantResult.Deny) { throw new NotEnoughPermissionException(Context, "others"); } var uPlayer = Context.Parameters.Length == 1 ? (UnturnedUser)Context.Actor : await Context.Parameters.GetAsync <UnturnedUser>(0); if (uPlayer == null) { throw new UserFriendlyException(m_StringLocalizer["commands:failed_player", new { Player = Context.Parameters[0] }]); } UserData userData = await m_UserDataStore.GetUserDataAsync(uPlayer.Id, uPlayer.Type); if (!userData.Data.ContainsKey("homes")) { throw new UserFriendlyException(m_StringLocalizer["home:no_home"]); } var homes = (Dictionary <object, object>)userData.Data["homes"]; string homeName = Context.Parameters[0]; if (!homes.ContainsKey(homeName)) { throw new UserFriendlyException(m_StringLocalizer["home:invalid_home", new { Home = homeName }]); } homes.Remove(homeName); userData.Data["homes"] = homes; await m_UserDataStore.SetUserDataAsync(userData); await uPlayer.PrintMessageAsync(m_StringLocalizer["home:delete", new { Home = homeName }]); }
private async Task <bool> IsQueueOwnerOrBotAdmin(IdQueue queue, uint userID, CancellationToken cancellationToken = default) { // check if this is owner's queue if (queue.OwnerID != null && queue.OwnerID.Value == userID) { return(true); } // if not, check if bot admin UserData user = await _userDataStore.GetUserDataAsync(userID, cancellationToken).ConfigureAwait(false); if (user.IsBotAdmin) { return(true); } // if checks failed, is not owner or admin return(false); }
public async Task HandleEventAsync(object sender, UnturnedPlayerDeathEvent @event) { await UniTask.SwitchToMainThread(); var id = @event.Player.EntityInstanceId; var position = @event.Player.Transform.Position.ToSerializableVector(); UniTask.RunOnThreadPool(async() => { var userData = await m_UserDataStore.GetUserDataAsync(id, KnownActorTypes.Player); if (userData == null) { var displayName = @event.Player.SteamPlayer.playerID.characterName; await m_UserDataSeeder.SeedUserDataAsync(id, KnownActorTypes.Player, displayName, new() { { "deathLocation", position } }); return; } userData.Data["deathLocation"] = position; await m_UserDataStore.SetUserDataAsync(userData); }).Forget(); }
protected override async UniTask OnExecuteAsync() { if (Context.Parameters.Length > 1) { throw new CommandWrongUsageException(Context); } UnturnedUser uPlayer = (UnturnedUser)Context.Actor; bool bed = Context.Parameters.Length == 0; string homeName = Context.Parameters.Length == 1 ? Context.Parameters[0] : ""; SerializableVector3 home = null; // If user is teleporting to a home, query the datastore for the Vector3 location if (!bed) { UserData userData = await m_UserDataStore.GetUserDataAsync(uPlayer.Id, uPlayer.Type); if (!userData.Data.ContainsKey("homes")) { throw new UserFriendlyException(m_StringLocalizer["home:no_home"]); } var homes = (Dictionary <object, object>)userData.Data["homes"]; if (!homes.ContainsKey(homeName)) { throw new UserFriendlyException(m_StringLocalizer["home:invalid_home", new { Home = homeName }]); } home = SerializableVector3.Deserialize(homes[homeName]); if (home == null) { throw new UserFriendlyException(m_StringLocalizer["home:invalid_home", new { Home = homeName }]); } } // Here we will delay the teleportation whether it be to a bed or home int delay = m_Configuration.GetValue <int>("teleportation:delay"); bool cancelOnMove = m_Configuration.GetValue <bool>("teleportation:cancelOnMove"); bool cancelOnDamage = m_Configuration.GetValue <bool>("teleportation:cancelOnDamage"); await uPlayer.PrintMessageAsync(m_StringLocalizer["home:success", new { Home = homeName, Time = delay }]); bool success = await m_TeleportService.TeleportAsync(uPlayer, new TeleportOptions(m_PluginAccessor.Instance, delay, cancelOnMove, cancelOnDamage)); if (!success) { throw new UserFriendlyException(m_StringLocalizer["teleport:canceled"]); } // Bed-specific teleportation if (bed) { await UniTask.SwitchToMainThread(); if (!uPlayer.Player.Player.teleportToBed()) { throw new UserFriendlyException(m_StringLocalizer["home:no_bed"]); } return; } if (!await uPlayer.Player.Player.TeleportToLocationAsync(home.ToUnityVector3())) { throw new UserFriendlyException(m_StringLocalizer["home:failure", new { Home = homeName }]); } }
protected override async UniTask OnExecuteAsync() { if (Context.Parameters.Length > 1) { throw new CommandWrongUsageException(Context); } UnturnedUser uPlayer = (UnturnedUser)Context.Actor; UserData userData = await m_UserDataStore.GetUserDataAsync(uPlayer.Id, uPlayer.Type); if (!userData.Data.ContainsKey("homes")) { userData.Data.Add("homes", new Dictionary <string, SerializableVector3>()); } var homes = (Dictionary <object, object>)userData.Data["homes"]; int amountOfHomes = homes.Count; // If this is the user's first home, or they have permission to make infinite homes, then skip the check if (amountOfHomes != 0 && await CheckPermissionAsync("infinite") == PermissionGrantResult.Deny) { bool any = false; for (int i = amountOfHomes; i < 11; i++) { // No logic unless it finds a permission with a number to limit homes if (await CheckPermissionAsync(i.ToString()) == PermissionGrantResult.Deny) { continue; } any = true; if (i > amountOfHomes) { break; } throw new UserFriendlyException(m_StringLocalizer["home:too_many"]); } // If there is no permission, only allow 1 home if (!any) { throw new UserFriendlyException(m_StringLocalizer["home:too_many"]); } } if (Context.Parameters.Length == 0) { homes["home"] = uPlayer.Player.Player.transform.position.ToSerializableVector(); userData.Data["homes"] = homes; await m_UserDataStore.SetUserDataAsync(userData); await uPlayer.PrintMessageAsync(m_StringLocalizer["home:set", new { Home = "home" }]); } else { string home = Context.Parameters[0]; homes[home] = uPlayer.Player.Player.transform.position.ToSerializableVector(); userData.Data["homes"] = homes; await m_UserDataStore.SetUserDataAsync(userData); await uPlayer.PrintMessageAsync(m_StringLocalizer["home:set", new { Home = home }]); } }
public override Task <decimal> GetBalanceAsync(string ownerId, string ownerType) { return(m_Dispatcher.EnqueueV2(async() => await m_UserDataStore.GetUserDataAsync <decimal?>(ownerId, ownerType, TableName) ?? DefaultBalance)); }
public virtual async Task <IReadOnlyCollection <IPermissionRole> > GetRolesAsync(IPermissionActor actor, bool inherit = true) { if (actor == null) { throw new ArgumentNullException(nameof(actor)); } var roles = new List <IPermissionRole>(); var roleIds = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase); if (actor is IPermissionRole role) { roles.Add(role); roleIds.Add(role.Id); if (!inherit) { return(roles); } // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator foreach (var parentRoleId in role.Parents) { if (string.IsNullOrEmpty(parentRoleId)) { continue; } if (roleIds.Contains(parentRoleId)) { continue; } var parentRole = await GetRoleAsync(parentRoleId); if (parentRole == null) { continue; } roles.Add(parentRole); roleIds.Add(parentRoleId); } return(roles); } var userData = await m_UserDataStore.GetUserDataAsync(actor.Id, actor.Type); if (userData?.Roles == null) { return(GetAutoAssignRoles().ToList()); } // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator foreach (var roleId in userData.Roles) { if (string.IsNullOrEmpty(roleId)) { continue; } if (roleIds.Contains(roleId)) { continue; } var userRole = await GetRoleAsync(roleId); if (userRole == null) { continue; } roles.Add(userRole); roleIds.Add(roleId); if (!inherit) { continue; } // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator foreach (var parentRoleId in userRole.Parents) { if (string.IsNullOrEmpty(parentRoleId)) { continue; } if (roleIds.Contains(parentRoleId)) { continue; } var parentRole = await GetRoleAsync(parentRoleId); if (parentRole == null) { continue; } roles.Add(parentRole); roleIds.Add(parentRoleId); } } return(roles); }
protected override async Task OnExecuteAsync() { if (Context.Parameters.Length != 3) { throw new CommandWrongUsageException(Context); } IPermissionActor target; var actorType = Context.Parameters[0].ToLower(); var permission = "permissions.manage." + actorType; var targetName = Context.Parameters[1]; var permissionToUpdate = Context.Parameters[2]; switch (actorType) { case "r": case "role": permission = "permissions.manage.roles." + targetName; target = await m_PermissionRoleStore.GetRoleAsync(targetName); // todo: register on startup instead of here so it can get written to a help file m_PermissionRegistry.RegisterPermission(Context.CommandRegistration.Component, permission, description: $"Manage role: {targetName}"); if (target == null) { await Context.Actor.PrintMessageAsync($"Role \"{targetName}\" was not found.", Color.Red); return; } break; case "p": case "player": permission = "permissions.manage.players"; actorType = KnownActorTypes.Player; goto default; default: var idOrName = await Context.Parameters.GetAsync <string>(1); var user = await m_UserManager.FindUserAsync(actorType, idOrName, UserSearchMode.NameOrId); m_PermissionRegistry.RegisterPermission(Context.CommandRegistration.Component, permission, description: $"Manage actor: {actorType}"); if (user == null) { // todo: make localizable throw new UserFriendlyException($"Player not found: {idOrName}"); } var userData = await m_UserDataStore.GetUserDataAsync(user.Id, actorType); target = (UserDataPermissionActor)userData; break; } // we call m_PermissionChecker from here so the permission will become OpenMod.Core.manage.players instead of if (await m_PermissionChecker.CheckPermissionAsync(Context.Actor, permission) != PermissionGrantResult.Grant) { throw new NotEnoughPermissionException(Context, permission); } await ExecuteUpdateAsync(target, permissionToUpdate); }
public virtual async Task <IReadOnlyCollection <IPermissionGroup> > GetGroupsAsync(IPermissionActor actor, bool inherit = true) { var groups = new List <IPermissionGroup>(); var groupsIds = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase); if (actor is IPermissionGroup group) { groups.Add(group); groupsIds.Add(group.Id); if (!inherit) { return(groups); } // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator foreach (var parentGroupId in group.Parents) { if (groupsIds.Contains(parentGroupId)) { continue; } var parentGroup = await GetGroupAsync(parentGroupId); if (parentGroup == null) { continue; } groups.Add(parentGroup); groupsIds.Add(parentGroupId); } return(groups); } var userData = await m_UserDataStore.GetUserDataAsync(actor.Id, actor.Type); // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator foreach (var groupId in userData.Groups) { if (groupsIds.Contains(groupId)) //prevent add group that was already by parent for example { continue; } var userGroup = await GetGroupAsync(groupId); if (userGroup == null) { continue; } groups.Add(userGroup); groupsIds.Add(groupId); if (!inherit) { continue; } // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator foreach (var parentGroupId in userGroup.Parents) { if (groupsIds.Contains(parentGroupId)) { continue; } var parentGroup = await GetGroupAsync(parentGroupId); if (parentGroup == null) { continue; } groups.Add(parentGroup); groupsIds.Add(parentGroupId); } } return(groups); }
public virtual async Task <IReadOnlyCollection <IPermissionRole> > GetRolesAsync(IPermissionActor actor, bool inherit = true) { var roles = new List <IPermissionRole>(); var roleIds = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase); if (actor is IPermissionRole role) { roles.Add(role); roleIds.Add(role.Id); if (!inherit) { return(roles); } // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator foreach (var parentRoleId in role.Parents) { if (roleIds.Contains(parentRoleId)) { continue; } var parentRole = await GetRoleAsync(parentRoleId); if (parentRole == null) { continue; } roles.Add(parentRole); roleIds.Add(parentRoleId); } return(roles); } var userData = await m_UserDataStore.GetUserDataAsync(actor.Id, actor.Type); // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator foreach (var roleId in userData.Roles) { if (roleIds.Contains(roleId)) //prevent add roles that was already by parent for example { continue; } var userRole = await GetRoleAsync(roleId); if (userRole == null) { continue; } roles.Add(userRole); roleIds.Add(roleId); if (!inherit) { continue; } // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator foreach (var parentRoleId in userRole.Parents) { if (roleIds.Contains(parentRoleId)) { continue; } var parentRole = await GetRoleAsync(parentRoleId); if (parentRole == null) { continue; } roles.Add(parentRole); roleIds.Add(parentRoleId); } } return(roles); }