Save different data for same user on different Guilds - discord

I set up a stats command as follows
[Command("Stats")]
public async Task StatsOther(SocketUser socketUser = null)
{
if (socketUser == null)
{
socketUser = Context.User;
}
var account = UserAccounts.GetAccount(socketUser);
await Context.Channel.SendMessageAsync($"Hey {socketUser.Mention}, You have {account.Size} long sandwhiches and {account.XP} XP.");
}
And the class UserAccounts searches if there exists in our database a socketUser with the ID property. Now say the same user in on different guild I need to store different data for him but the socketUser.ID will be the same no matter the guild. So when the user tries to use stats command he will see the same data irrespective of the guild he is in right now.
Here is where UserAccounts.GetAccount leads and does its thing,
public static UserAccount GetAccountFromID(ulong ID)
{
var result = from a in accounts
where a.ID == ID
select a;
var FoundAccount = result.FirstOrDefault();
if (FoundAccount == null)
{
FoundAccount = CreateUserAccount(ID);
}
return FoundAccount;
}
Clearly the linq query is checking for IDs and they happen to be the same for a user no matter the guild.
I tried using SocketGuildUser but sadly a socketGuildUser.ID is also independent of the guild. So I am unable to store different data for the same user from different guilds. Using the latest beta available.
How can I achieve this.

You could make use of a Dictionary implemented for each user. Where each user have its own Dictionary<GuildID, Data>.
And on the SQL side (if you are using SQL), you could have a new table, where it has a foreign key constrain on the User ID, and has a Guild ID too.
(The foreign key constrain on userID might not be needed if none of the user's stats is shared between all guilds; Aka you just have a SQL-table which you can do a SELECT stuff FROM tableName WHERE userID = ? AND guildID = ?)

Related

I want to use server's ID followed by if-else blocks for assigning different roles in multiple servers when users join

Following is the code using which I cannot have control for assigning different roles across multiple servers:
async def on_member_join(member):
role = discord.utils.get(member.guild.roles, name='Role Name')
await member.add_roles(role)
^This code is working fine, however I want to add one more stage which would match server ID using 'if-else' and if the server is correct, then assigning roles should take place individually...
I don't know certain attributes/methods for doing this I want to implement Something like this:
if serverID = = (ID)
role = discord.utils.get(member.guild.roles, name='Role Name')
await member.add_roles(role)
Thank you for the help.
There is a Member.guild you can use that to get the guild.id
async def on_member_join(member):
if member.guild.id == 123:
#code

LDAP query for deleted users

The normal way to query a directory for users is (&(objectClass=user)(objectCategory=person)). The normal way to query for deleted objects is to add (isDeleted=TRUE).
However, the objectCategory attribute does not exist on tombstone objects, so a query for (&(objectClass=user)(objectCategory=person)(isDeleted=TRUE)) will get you nothing.
If you remove the (objectCategory=person) part, you'll get computers too, as they inherit from user.
Is it possible to retrieve only deleted users?
If not, is it possible to tell from the returned tombstone object if it's a user or not?
Try an LDAP filter like:
(&(isDeleted=TRUE)(userAccountControl:1.2.840.113556.1.4.803:=512))
This should retrieve most deleted user type entries.
python3 code
import ldap
from ldap.controls.simple import ValueLessRequestControl
...
base =
scope = ldap.SCOPE_SUBTREE
filterstr = '(&(objectClass=user)(isDeleted=TRUE))'
attrlist =
result_set = []
ct = ldap.controls.simple.ValueLessRequestControl('1.2.840.113556.1.4.417', True)
result_id = l.search_ext(base, scope, filterstr, attrlist, serverctrls=[ct, ])
for i in range(0, 100):
result_type, result_data = l.result(result_id, 0)
if result_type == ldap.RES_SEARCH_ENTRY:
result_set.append(result_data)
else:
break
...

Delete trigger for audit table

I'm working on a web application that executes CRUD operations on some table in a SQL Server database. There will be a logged user in the application executing these operations.
(By the way, I'm using Entity Framework)
Let's say table is
MyTable
MyTableId
SomeColumn
LastModifiedUserId
LastModifiedDate
And I a have an audit table like
MyTableHistory
MyTableHistoryId
MyTableId
SomeColumn
ActionType --ins/upd/del
ActionUserId
ActioDate
And I'm using triggers to insert data on the audit table.
Inserts and updates are easy by consulting the Inserted and Updated tables to find the userid who modified the record.
But what about deletes? Any idea how I might get that info?
There is no such thing as updated table. The two pseudo tables available in DML triggers are inserted and deleted. In the case of insert table deleted is empty, in the case of delete table inserted is empty, in the case of update both tables are populated.
You can create three separate triggers for each action (to distinguish ActionType) or try to combine all in one trigger.
Note: take into account multiple row actions.
Assuming you are using EF to add the information about which user is updating records, the easiest way to capture that information is to have EF perform a 2-step process (UPDATE, DELETE) on the data you wish to delete. You will then need to interpret the two audit rows as part of the same operation.
There is a much more involved solution that "might" work, but I have not tested it. There is more information available below if you wish to explore it.
Blog describing the solution
Stack Overflow post of someone trying it
Another option altogether is to abandon trigger auditing (which is problematic for this very reason) and use Entity Framework instead. Below is an example of how one might accomplish this by overriding the SaveChanges method:
public virtual IEnumerable<System.Data.Entity.Infrastructure.DbEntityEntry> ChangedEntries()
{
return ChangeTracker.Entries().Where(x =>
x.State == EntityState.Added ||
x.State == EntityState.Deleted ||
x.State == EntityState.Modified);
}
public virtual int SaveChanges(string userName)
{
var changes = ChangedEntries();
foreach (var entry in changes)
{
var eventType = entry.State == EntityState.Added ? "A" : entry.State == EntityState.Deleted ? "D" : "U";
var entityType = ObjectContext.GetObjectType(entry.Entity.GetType()).Name;
var oldValues = entry.State == EntityState.Added ? null : JsonConvert.SerializeObject(entry.OriginalValues.ToObject());
var newValues = entry.State == EntityState.Deleted ? null : JsonConvert.SerializeObject(entry.CurrentValues.ToObject());
oldValues = oldValues?.Substring(0, Math.Min(oldValues.Length, 4000));
newValues = newValues?.Substring(0, Math.Min(newValues.Length, 4000));
AuditItems.Add(
new AuditItem
{
EventTime = DateTime.Now,
UserName = userName,
EntityType = entityType,
EventType = eventType,
OldValues = oldValues,
NewValues = newValues
}
);
}
return base.SaveChanges();
}

How can I assigned roles automatically in webmatrix

I want to assigned new registered users automatically the role of Member in Database.
WebMatrix sample Starter Site app - Account\Register.cshtml
Tested and it works.
// Check if user already exists
var user = db.QuerySingle("SELECT Email FROM UserProfile WHERE LOWER(Email) = LOWER(#0)", email);
if (user == null) {
// Insert email into the profile table
db.Execute("INSERT INTO UserProfile (Email) VALUES (#0)", email);
//Roles have already been added to webpages_Roles table
//Logic to determine role for e-mail (user) being added for the first time
if (email == "John#gmail.com") {
var userName=email;
var roleName="Administrator";
Roles.AddUserToRole(userName, roleName);
}
else if (email == "Greg#gmail.com") {
var userName=email;
var roleName="Guest";
Roles.AddUserToRole(userName, roleName);
}
else {
//All others are assigned the role of Member
var username=email;
var roleName="Member";
Roles.AddUserToRole(userName, roleName);
}
In your register code, which in the sample WebMatrix app is found in the file Account\Register.cshtml, there's if statements that first determine that the information being submitted is valid and then that the email doesn't exist in your database. Within those if statements, if the user is successfully created, then you can add code like:
// boy, is this a hack, Member = RoleID 8
db.Execute("INSERT INTO webpages_UsersInRoles (UserId, RoleID) VALUES( #0, 8 )", UserID);
Now I used 8 as an example. Look in your webpages_Roles table. This has a list of RoleNames and their RoleID. If you've already created the Member role, it will be in this table. Use the corresponding RoleID instead of the 8 that I used.

Check for existence or catch exception?

I want to update a record if the record exists or insert a new one if it doesn't.
What would be the best approach?
Do a Select Count() and if comes back zero then insert, if one then query the record, modify and update,
or should I just try to query the record and catch any system.queryexception?
This is all done in Apex, not from REST or the JS API.
Adding to what's already been said here, you want to use FOR UPDATE in these cases to avoid what superfell is referring to. So,
Account theAccount;
Account[] accounts = [SELECT Id FROM Account WHERE Name = 'TEST' LIMIT 1 FOR UPDATE];
if(accounts.size() == 1)
theAccount = accounts[0];
else
theAccount = new Account();
// Make modifications to theAccount, which is either:
// 1. A record-locked account that was selected OR
// 2. A new account that was just created with new Account()
upsert theAccount;
You should use the upsert call if at all possible, the select then insert/update approach is problematic once you get into the realm of concurrent calls unless you goto the trouble of correctly locking a parent row as part of the select call.
I would try it with a list and isEmpty() function:
List<Account> a = [select id from account where name = 'blaahhhh' Limit 1];
if(a.isEmpty()){
System.debug('#### do insert');
}
else{
System.debug('#### do update');
}

Resources