diff --git a/README.md b/README.md index 29f9d654..f3dde581 100644 --- a/README.md +++ b/README.md @@ -140,9 +140,9 @@ string emailAddressOrErrorMessage = userResponse.Result.Match( ``` ## ⌛ Progress -![Server & Client - 69 / 291](https://img.shields.io/badge/Server_&_Client-69%20%2F%20291-red?style=for-the-badge) +![Server & Client - 70 / 291](https://img.shields.io/badge/Server_&_Client-70%20%2F%20291-red?style=for-the-badge) -![Server - 25 / 201](https://img.shields.io/badge/Server-25%20%2F%20201-red?style=for-the-badge) +![Server - 26 / 201](https://img.shields.io/badge/Server-26%20%2F%20201-red?style=for-the-badge) ![Client - 44 / 90](https://img.shields.io/badge/Client-44%20%2F%2090-gold?style=for-the-badge) @@ -207,7 +207,7 @@ string emailAddressOrErrorMessage = userResponse.Result.Match( | [Create Phone Verification (Confirmation)](https://appwrite.io/docs/references/1.6.x/client-rest/account#updatePhoneVerification) | ✅ | ❌ | | ### Users -![Account - 14 / 41](https://img.shields.io/badge/Users-14%20%2F%2041-gold?style=for-the-badge) +![Account - 15 / 41](https://img.shields.io/badge/Users-15%20%2F%2041-gold?style=for-the-badge) | Endpoint | Client | Server | |:-:|:-:|:-:| @@ -226,7 +226,7 @@ string emailAddressOrErrorMessage = userResponse.Result.Match( | [Delete User](https://appwrite.io/docs/references/1.6.x/server-rest/users#delete) | ❌ | ✅ | | [Update Email](https://appwrite.io/docs/references/1.6.x/server-rest/users#updateEmail) | ❌ | ✅ | | [Create User JWT](https://appwrite.io/docs/references/1.6.x/server-rest/users#createJWT) | ❌ | ⬛ | -| [Update User Labels](https://appwrite.io/docs/references/1.6.x/server-rest/users#updateLabels) | ❌ | ⬛ | +| [Update User Labels](https://appwrite.io/docs/references/1.6.x/server-rest/users#updateLabels) | ❌ | ✅ | | [List User Logs](https://appwrite.io/docs/references/1.6.x/server-rest/users#listLogs) | ❌ | ⬛ | | [List User Memberships](https://appwrite.io/docs/references/1.6.x/server-rest/users#listMemberships) | ❌ | ⬛ | | [Update MFA](https://appwrite.io/docs/references/1.6.x/server-rest/users#updateMfa) | ❌ | ⬛ | diff --git a/src/PinguApps.Appwrite.Playground/App.cs b/src/PinguApps.Appwrite.Playground/App.cs index ca672181..0b21e143 100644 --- a/src/PinguApps.Appwrite.Playground/App.cs +++ b/src/PinguApps.Appwrite.Playground/App.cs @@ -17,13 +17,13 @@ public App(Client.IAppwriteClient client, Server.Clients.IAppwriteClient server, public async Task Run(string[] args) { - var request = new UpdateEmailRequest() + var request = new UpdateUserLabelsRequest() { UserId = "664aac1a00113f82e620", - Email = "test@example.com" + Labels = ["test", "admin"] }; - var response = await _server.Users.UpdateEmail(request); + var response = await _server.Users.UpdateUserLabels(request); Console.WriteLine(response.Result.Match( result => result.ToString(), diff --git a/src/PinguApps.Appwrite.Server/Clients/IUsersClient.cs b/src/PinguApps.Appwrite.Server/Clients/IUsersClient.cs index 51d4ec46..0e18e25b 100644 --- a/src/PinguApps.Appwrite.Server/Clients/IUsersClient.cs +++ b/src/PinguApps.Appwrite.Server/Clients/IUsersClient.cs @@ -126,7 +126,14 @@ public interface IUsersClient Task> UpdateEmail(UpdateEmailRequest request); [Obsolete("This method hasn't yet been implemented.", true)] Task> CreateUserJwt(CreateUserJwtRequest request); - [Obsolete("This method hasn't yet been implemented.", true)] + + /// + /// Update the user labels by its unique ID. + /// Labels can be used to grant access to resources. While teams are a way for user's to share access to a resource, labels can be defined by the developer to grant access without an invitation. See the Permissions docs for more info + /// Appwrite Docs + /// + /// The request content + /// The user Task> UpdateUserLabels(UpdateUserLabelsRequest request); [Obsolete("This method hasn't yet been implemented.", true)] Task> ListUserLogs(ListUserLogsRequest request); diff --git a/src/PinguApps.Appwrite.Server/Clients/UsersClient.cs b/src/PinguApps.Appwrite.Server/Clients/UsersClient.cs index 13ebe25e..89e11bda 100644 --- a/src/PinguApps.Appwrite.Server/Clients/UsersClient.cs +++ b/src/PinguApps.Appwrite.Server/Clients/UsersClient.cs @@ -268,9 +268,22 @@ public async Task> UpdateEmail(UpdateEmailRequest request) /// public Task> CreateUserJwt(CreateUserJwtRequest request) => throw new NotImplementedException(); - [ExcludeFromCodeCoverage] /// - public Task> UpdateUserLabels(UpdateUserLabelsRequest request) => throw new NotImplementedException(); + public async Task> UpdateUserLabels(UpdateUserLabelsRequest request) + { + try + { + request.Validate(true); + + var result = await _usersApi.UpdateUserLabels(request.UserId, request); + + return result.GetApiResponse(); + } + catch (Exception e) + { + return e.GetExceptionResponse(); + } + } [ExcludeFromCodeCoverage] /// diff --git a/tests/PinguApps.Appwrite.Server.Tests/Clients/Users/UsersClientTests.UpdateUserLabels.cs b/tests/PinguApps.Appwrite.Server.Tests/Clients/Users/UsersClientTests.UpdateUserLabels.cs new file mode 100644 index 00000000..8454c1e3 --- /dev/null +++ b/tests/PinguApps.Appwrite.Server.Tests/Clients/Users/UsersClientTests.UpdateUserLabels.cs @@ -0,0 +1,87 @@ +using System.Net; +using PinguApps.Appwrite.Shared.Requests.Users; +using PinguApps.Appwrite.Shared.Tests; +using PinguApps.Appwrite.Shared.Utils; +using RichardSzalay.MockHttp; + +namespace PinguApps.Appwrite.Server.Tests.Clients.Users; +public partial class UsersClientTests +{ + public static TheoryData UpdateUserLabels_ValidRequestData = + [ + new UpdateUserLabelsRequest + { + UserId = IdUtils.GenerateUniqueId(), + Labels = ["label1", "label2"] + }, + new UpdateUserLabelsRequest + { + UserId = IdUtils.GenerateUniqueId(), + Labels = ["label3", "label4"] + } + ]; + + [Theory] + [MemberData(nameof(UpdateUserLabels_ValidRequestData))] + public async Task UpdateUserLabels_ShouldReturnSuccess_WhenApiCallSucceeds(UpdateUserLabelsRequest request) + { + // Arrange + _mockHttp.Expect(HttpMethod.Put, $"{Constants.Endpoint}/users/{request.UserId}/labels") + .WithJsonContent(request) + .ExpectedHeaders() + .Respond(Constants.AppJson, Constants.UserResponse); + + // Act + var result = await _appwriteClient.Users.UpdateUserLabels(request); + + // Assert + Assert.True(result.Success); + } + + [Fact] + public async Task UpdateUserLabels_ShouldHandleException_WhenApiCallFails() + { + // Arrange + var request = new UpdateUserLabelsRequest + { + UserId = "user123", + Labels = ["label1", "label2"] + }; + + _mockHttp.Expect(HttpMethod.Put, $"{Constants.Endpoint}/users/user123/labels") + .WithJsonContent(request) + .ExpectedHeaders() + .Respond(HttpStatusCode.BadRequest, Constants.AppJson, Constants.AppwriteError); + + // Act + var result = await _appwriteClient.Users.UpdateUserLabels(request); + + // Assert + Assert.True(result.IsError); + Assert.True(result.IsAppwriteError); + } + + [Fact] + public async Task UpdateUserLabels_ShouldReturnErrorResponse_WhenExceptionOccurs() + { + // Arrange + var request = new UpdateUserLabelsRequest + { + UserId = "user123", + Labels = ["label1", "label2"] + }; + + _mockHttp.Expect(HttpMethod.Put, $"{Constants.Endpoint}/users/user123/labels") + .WithJsonContent(request) + .ExpectedHeaders() + .Throw(new HttpRequestException("An error occurred")); + + // Act + var result = await _appwriteClient.Users.UpdateUserLabels(request); + + // Assert + Assert.False(result.Success); + Assert.True(result.IsInternalError); + Assert.Equal("An error occurred", result.Result.AsT2.Message); + } +}