Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Bug Report: Bug acquiring users on server side #30

Open
2 tasks done
joaquingrech opened this issue Jan 4, 2024 · 5 comments · Fixed by appwrite/sdk-generator#800
Open
2 tasks done

🐛 Bug Report: Bug acquiring users on server side #30

joaquingrech opened this issue Jan 4, 2024 · 5 comments · Fixed by appwrite/sdk-generator#800
Labels
bug Something isn't working

Comments

@joaquingrech
Copy link

joaquingrech commented Jan 4, 2024

👟 Reproduction steps

this method:

public static User From(Dictionary<string, object> map) => new User(
id: map["$id"].ToString(),
createdAt: map["$createdAt"].ToString(),
updatedAt: map["$updatedAt"].ToString(),
name: map["name"].ToString(),
password: map["password"]?.ToString(),
hash: map["hash"]?.ToString(),
hashOptions: map["hashOptions"]?.ToString(),
registration: map["registration"].ToString(),
status: (bool)map["status"],
labels: ((JArray)map["labels"]).ToObject<List<object>>(),
passwordUpdate: map["passwordUpdate"].ToString(),
email: map["email"].ToString(),
phone: map["phone"].ToString(),
emailVerification: (bool)map["emailVerification"],
phoneVerification: (bool)map["phoneVerification"],
prefs: Preferences.From(map: ((JObject)map["prefs"]).ToObject<Dictionary<string, object>>()!),
accessedAt: map["accessedAt"].ToString()
);

the issue is that when you do this on the server from the JWT token:

var client = new Client()
        .SetEndpoint("https://cloud.appwrite.io/v1")    // Your API Endpoint
        .SetProject(projectid)                     // Your project ID
        .SetJWT(token);

var appWriteUser=(await (new Account(client)).Get());

The way it does this internally is that Get() makes an api call, retrieves a dictionary and then calls the User.From
since the dictionary does not retrieve the password, you get an exception with Key not found "password" and it crashes
meaning you can never retrieve a user on the server side, never
exact exception details details

"error":"System.Collections.Generic.KeyNotFoundException: The given key 'password' was not present in the dictionary.\r\n   at System.Collections.Generic.Dictionary2.get_Item(TKey key)\r\n   at Appwrite.Models.User.From(Dictionary2 map)\r\n   at Appwrite.Services.Account.<Get>g__Convert|1_0(Dictionary2 it)\r\n   at Appwrite.Client.Call[T](String method, String path, Dictionary2 headers, Dictionary2 parameters, Func2 convert)

👍 Expected behavior

it should create an user instance with the missing information (no password)

👎 Actual Behavior

exception as explained, and no user created

🎲 Appwrite version

Version 0.10.x

💻 Operating system

Windows

🧱 Your Environment

No response

👀 Have you spent some time to check if this issue has been raised before?

  • I checked and didn't find similar issue

🏢 Have you read the Code of Conduct?

@joaquingrech joaquingrech added the bug Something isn't working label Jan 4, 2024
@stnguyen90 stnguyen90 changed the title Bug acquiring users on server side🐛 Bug Report: 🐛 Bug Report: Bug acquiring users on server side Jan 4, 2024
@stnguyen90
Copy link
Contributor

@joaquingrech
Copy link
Author

joaquingrech commented Jan 5, 2024

My quick fix was this on User.cs. Open to better solution. I only identified as potential "nulls" password, hash and hashOptions. I don't know whether all other fields are always populated for every user account.

private static object? getFromMap(Dictionary<string, object> map, string key)
{
object? val;
map.TryGetValue("password",out val);
return val;
}
public static User From(Dictionary<string, object> map) {
return new User(
id: map["$id"].ToString(),
createdAt: map["$createdAt"].ToString(),
updatedAt: map["$updatedAt"].ToString(),
name: map["name"].ToString(),
password: getFromMap(map,"password")?.ToString(),
hash: getFromMap(map,"hash")?.ToString(),
hashOptions: getFromMap(map,"hashOptions")?.ToString(),
registration: map["registration"].ToString(),
status: (bool)map["status"],
labels: ((JArray)map["labels"]).ToObject<List>(),
passwordUpdate: map["passwordUpdate"].ToString(),
email: map["email"].ToString(),
phone: map["phone"].ToString(),
emailVerification: (bool)map["emailVerification"],
phoneVerification: (bool)map["phoneVerification"],
prefs: Preferences.From(map: ((JObject)map["prefs"]).ToObject<Dictionary<string, object>>()!),
accessedAt: map["accessedAt"].ToString()
);
}

@theemaster
Copy link

theemaster commented Jan 7, 2024

Thanks for your quick fix, but I think your getFromMap is not implemented as desired.
You implemented a hardcoded value "password" in TryGetValue. I guess instead it should be:

map.TryGetValue(key,out val);

A more compact version would be:

private static object? getFromMap(Dictionary<string, object> map, string key)
{
    return map.TryGetValue(key, out var val) ? val.toString() : null;
}

@theemaster
Copy link

theemaster commented Jan 7, 2024

My suggestion would probably be to change it inline as follows:

public static User From(Dictionary<string, object> map)
{
  return new User(
    id: map["$id"].ToString(), 
    createdAt: map["$createdAt"].ToString(), 
    updatedAt: map["$updatedAt"].ToString(), 
    name: map["name"].ToString(), 
    password: map.TryGetValue("password", out var password) ? password.ToString() : null,
    hash: map.TryGetValue("hash", out var hash) ? hash.ToString() : null,
    hashOptions: map.TryGetValue("hashOptions", out var hashOptions) ? hashOptions.ToString() : null, 
    registration: map["registration"].ToString(), 
    status: (bool)map["status"], 
    labels: ((JArray)map["labels"]).ToObject<List<object>>(), 
    passwordUpdate: map["passwordUpdate"].ToString(), 
    email: map["email"].ToString(), 
    phone: map["phone"].ToString(), 
    emailVerification: (bool)map["emailVerification"], 
    phoneVerification: (bool)map["phoneVerification"], 
    prefs: Preferences.From(((JObject)map["prefs"]).ToObject<Dictionary<string, object>>()),
    accessedAt: map["accessedAt"].ToString());
}

So we would not need to add an extra function. And I would use named parameters when creating the User-object. Having positional arguments is confusing if the list is so long and not readable. ;)

theemaster added a commit to theemaster/sdk-for-dotnet that referenced this issue Jan 8, 2024
theemaster added a commit to theemaster/sdk-for-dotnet that referenced this issue Jan 8, 2024
@joaquingrech
Copy link
Author

Thanks for your quick fix, but I think your getFromMap is not implemented as desired. You implemented a hardcoded value "password" in TryGetValue. I guess instead it should be:

map.TryGetValue(key,out val);

A more compact version would be:

private static object? getFromMap(Dictionary<string, object> map, string key)
{
    return map.TryGetValue(key, out var val) ? val.toString() : null;
}

yep, I hardcoded for testing "password" and forgot to remove it. Glad there is a fix already on the way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants