I'm trying to create a new user and adding it to an already existing ParseRole, but i'm getting the ParseException: object not found for update after performing await parseRole.SaveAsync();.
I checked in the Parse website and both the Role and User are saved (the ids returned by c# code are correct), but the Role hasn't that user.
[TestMethod]
public async Task CanCreateCustomer()
{
var customer = ParseObject.Create<ApplicationUser>();
customer.FirstName = GetRandom.FirstName();
customer.LastName = GetRandom.LastName();
customer.Password = "123";
customer.Username = customer.GetUserName();
Assert.IsNull(customer.ObjectId);
await customer.SignUpAsync();
Assert.IsNotNull(customer.ObjectId);
var parseRole = await ParseRole.Query.Where(x => x.Name == Roles.CustomerRole).FirstAsync();
parseRole.Users.Add(customer);
await parseRole.SaveAsync();
}
The problem was I didn't set the ACL for my roles to allow write access to the logged user (or public, in case of my unit test)
Related
My exception says that user = null but I don't understand why? UserId is passed in the debugger
private async Task ReactionAdd(Cacheable<IUserMessage, ulong> cache, ISocketMessageChannel socketMessageChannel, SocketReaction reaction)
{
if (reaction.MessageId == 771361839917170748)
{
var emote = Emote.Parse("<:NepSmug:740928682310500412>").ToString();
if (reaction.Emote.ToString() == emote)
{
var sockettextChannel = socketMessageChannel as SocketTextChannel;
ulong roleid = 741342300499738715;
var role = sockettextChannel.Guild.GetRole(roleid);
var user = sockettextChannel.Guild.GetUser(reaction.UserId);
await user.AddRoleAsync(role);
}
}
}
The user is null might caused by recent change on the Discrod API refer to this. The changes caused the Guild.User info is not downloaded properly.
First thing to check is if the User is assigned on Context.Guild or not (You can also verify if the user in your Discord server is equal on the Context.Guild.Users).
Second you need to enable this feature on your Discord Bot
The title suggests it. Is there any way for the bot to detect when a user joined the guild and automatically grant that user a specific role? I want to automatically grant every user the "member" role, how can I achieve this? I am not at all experienced with C#.
I have tried this, with no success:
public async Task auto_role(SocketGuildUser user)
{
await user.AddRoleAsync((Context.Guild.Roles.FirstOrDefault(x => x.Name == "Member")));
}
If you wish to add a role to any newly joined guild member, you should not be touching the command system at all since, well, it's not a command!
What you do want to do is hook something like the UserJoined event, which is fired whenever a new user joins a guild.
So, for example, you may want to do something like this:
public class MemberAssignmentService
{
private readonly ulong _roleId;
public MemberAssignmentService(DiscordSocketClient client, ulong roleId)
{
// Hook the evnet
client.UserJoined += AssignMemberAsync;
// Note that we are using role identifier here instead
// of name like your original solution; this is because
// a role name check could easily be circumvented by a new role
// with the exact name.
_roleId = roleId;
}
private async Task AssignMemberAsync(SocketGuildUser guildUser)
{
var guild = guildUser.Guild;
// Check if the desired role exist within this guild.
// If not, we simply bail out of the handler.
var role = guild.GetRole(_roleId);
if (role == null) return;
// Check if the bot user has sufficient permission
if (!guild.CurrentUser.GuildPermissions.Has(GuildPermissions.ManageRoles)) return;
// Finally, we call AddRoleAsync
await guildUser.AddRoleAsync(role);
}
}
I want to give a Discord client a role in a ReactionAdded event. Why does not this work?
public static async Task AddedReactEvent(Cacheable<IUserMessage, ulong> message, ISocketMessageChannel channel, SocketReaction reaction)
{
if (channel.Id == 504031332612046881)
{
if (reaction.Emote.Name == "PS4")
{
var context = new CommandContext(_client, message.Value);
var role = context.Guild.Roles.FirstOrDefault(x => x.Name == "PS4");
Console.WriteLine(role.Color.ToString());
await (reaction.User.Value as IGuildUser).AddRoleAsync(role);
}
}
}
It clearly seems to be a NullReferenceException. This could be because your var role could be null. You can find it out if you use breakpoints and run the debugger.
Also your method of getting the role though the channel through the _client seems inappropriate. Why bother to create a new commandContext just get the role from Cacheable channel.
var role = ((ITextChannel) channel).Guild.Roles.FirstOrDefault(x => x.Name == "PS4");
This ought to get you the role. Also if it is your private server you are coding for dont bother to use the role name thing. Instead use the role id something like
var role = ((ITextChannel) channel).Guild.GetRole(437634977941684226);
You can get the role id by mentioning the role and placing a \ before it (escaping it).
Like
\#bot
becomes
<#&437634977941684226>
and 437634977941684226 is your roleID
var client = ActiveDirectoryClientFactory.GetActiveDirectoryClient(_connector);
client.Context.MergeOption = MergeOption.AppendOnly;
_withOwnedDevices = await client.Users.Expand(d => d.OwnedDevices).ExecuteAsync();
_withMemberOf = await client.Users.Expand(d => d.MemberOf).ExecuteAsync();
When running the above code I do get OwnedDevices but MemberOf comes back empty all the time.
var client = ActiveDirectoryClientFactory.GetActiveDirectoryClient(_connector);
_withOwners = await client.Devices.Expand(d => d.RegisteredOwners).ExecuteAsync();
_withUsers = await client.Devices.Expand(d => d.RegisteredUsers).ExecuteAsync();
_withMemberOf = await client.Devices.Expand(d => d.MemberOf).ExecuteAsync();
Similiarly running the above nets RegisteredOwners and RegisteredUsers but nothing on the MemberOf collection.
var client = ActiveDirectoryClientFactory.GetActiveDirectoryClient(_connector);
var matches = await client.Users.Where(u => u.Mail == email).Expand(u => u.MemberOf).ExecuteAsync();
This nets a list of matches, one, and the MemberOf collection has results. Querying the same Active Directory in all cases.
The problem seems to be related to the need for the special MergeOption. Without AppendOnly or NoTracking I get an exception when making the second of two calls with different Expand options. I do a similar thing with devices and do not have to set the MergeOption at all and the context merges the objects no problem so both expanded collections are shown on the entity. In the case of users if you try the same thing the ActiveDirectoryClient throws a "The context is already tracking a different entity with the same resource Uri." In testing with Devices that problem only creeps in when trying to do an expand on MemberOf, can do multiple calls to expand other collections but once I try with MemberOf you get the tracking exception.
I tested below code:
ActiveDirectoryClient client = AuthenticationHelper.GetActiveDirectoryClient();
client.Context.MergeOption = MergeOption.AppendOnly;
var _withMemberOf = await client.Users.Expand(d => d.MemberOf).ExecuteAsync();
Above code will return page Collection of the users. Max number of users in current page is 100.Each user has a MemberOf property which shows the groups and roles memberships of the user .Blow is a screenshot when debug in vs:
Please check whether the user you successfully get MemberOf collection via :
var client = ActiveDirectoryClientFactory.GetActiveDirectoryClient(_connector);
var matches = await client.Users.Where(u => u.Mail == email).Expand(u => u.MemberOf).ExecuteAsync();
is included in the CurrentPage collections , you could use below code to get the next page collection of users to check that :
client.Context.MergeOption = MergeOption.AppendOnly;
IPagedCollection<IUser> pagedCollection = await client.Users.Expand(d => d.MemberOf).ExecuteAsync();
if (pagedCollection != null)
{
do
{
//loop the users and get the memberof information
pagedCollection = await pagedCollection.GetNextPageAsync();
} while (pagedCollection != null);
}
I have a serivce that fetches a list of users from a legacy system and synchronises my AspNet Identity database. I’ve a problem when updating a user’s email address with UserManager.SetEmail(string userId, string email) and the validation fails. The user object in the UserStore retains the value of the invalid email address. I stop processing that user and skip to the next user in my list. Later when my service finds a new user to create, I use UserManager.Create(ApplicationUser user) and the database is updated with all outstanding changes including the invalid email address of the existing user.
Is there a way to stop the invalid email address being persisted? Is this a bug or am I just not using it correctly? Should I just manually take a backup of every object before any update and revert all values if the IdentityResult has an error?
//get LegacyUsers
foreach (AppUser appUser in LegacyUsers){
var user = UserManager.FindByName(appUser.userName);
if (user != null){
If (!user.Email.Equals(appUser.Email)){
var result = UserManager.setEmail(user.Id, appUser.Email)
if (!result.Succeeded){
//user object still has new value of email despite error, but not yet persisted to DB.
Log.Error(…);
continue;
}
}
}
else
{
ApplicationUser newUser = new ApplicationUser{
UserName = appUser.userName,
//etc
}
var result = UserManager.Create(newUser); //DB updates first user with new email aswell as inserting this new user
if (!result.Succeeded){
Log.Error(…);
continue;
}
}
}
I'm using version 2.2.1.40403 of Microsoft.AspNet.Identity.Core and Microsoft.AspNet.Identity.EntityFramework
This is happening because EF keeps track of models and updates all of the modified objects when SaveChanges() method is called by UserManager.Create() method. You could easily detach the user which has invalid email from the DbContext like this:
// first get DbContext from the Owin.
var context = HttpContext.GetOwinContext().Get<ApplicationDbContext>();
foreach (AppUser appUser in LegacyUsers){
var user = UserManager.FindByName(appUser.userName);
if (user != null){
If (!user.Email.Equals(appUser.Email)){
var result = UserManager.setEmail(user.Id, appUser.Email)
if (!result.Succeeded){
Log.Error(…);
// detach the user then proceed to the next one
context.Entry(user).State = EntityState.Detached;
continue;
}
}
}
else{
// rest of the code
}
}