diff --git a/README.md b/README.md index 97887725..05a9b5ff 100644 --- a/README.md +++ b/README.md @@ -141,11 +141,11 @@ string emailAddressOrErrorMessage = userResponse.Result.Match( ## ⌛ Progress -![Server & Client - 114 / 318](https://img.shields.io/badge/Server_&_Client-114%20%2F%20318-gold?style=for-the-badge) +![Server & Client - 116 / 318](https://img.shields.io/badge/Server_&_Client-116%20%2F%20318-gold?style=for-the-badge) -![Server - 60 / 225](https://img.shields.io/badge/Server-60%20%2F%20225-red?style=for-the-badge) +![Server - 61 / 225](https://img.shields.io/badge/Server-61%20%2F%20225-red?style=for-the-badge) -![Client - 54 / 93](https://img.shields.io/badge/Client-54%20%2F%2093-gold?style=for-the-badge) +![Client - 55 / 93](https://img.shields.io/badge/Client-55%20%2F%2093-gold?style=for-the-badge) ### 🔑 Key | Icon | Definition | @@ -256,7 +256,7 @@ string emailAddressOrErrorMessage = userResponse.Result.Match( | [Update Phone Verification](https://appwrite.io/docs/references/1.6.x/server-rest/users#updatePhoneVerification) | ❌ | ✅ | ### Teams -![Teams - 14 / 26](https://img.shields.io/badge/Teams-14%20%2F%2026-gold?style=for-the-badge) +![Teams - 16 / 26](https://img.shields.io/badge/Teams-16%20%2F%2026-gold?style=for-the-badge) | Endpoint | Client | Server | |:-:|:-:|:-:| @@ -269,7 +269,7 @@ string emailAddressOrErrorMessage = userResponse.Result.Match( | [Create Team Membership](https://appwrite.io/docs/references/1.6.x/client-rest/teams#createMembership) | ✅ | ✅ | | [Get Team Membership](https://appwrite.io/docs/references/1.6.x/client-rest/teams#getMembership) | ⬛ | ⬛ | | [Update Membership](https://appwrite.io/docs/references/1.6.x/client-rest/teams#updateMembership) | ⬛ | ⬛ | -| [Delete Team Membership](https://appwrite.io/docs/references/1.6.x/client-rest/teams#deleteMembership) | ⬛ | ⬛ | +| [Delete Team Membership](https://appwrite.io/docs/references/1.6.x/client-rest/teams#deleteMembership) | ✅ | ✅ | | [Update Team Membership Status](https://appwrite.io/docs/references/1.6.x/client-rest/teams#updateMembershipStatus) | ⬛ | ⬛ | | [Get Team Memberships](https://appwrite.io/docs/references/1.6.x/client-rest/teams#getPrefs) | ⬛ | ⬛ | | [Update Preferences](https://appwrite.io/docs/references/1.6.x/client-rest/teams#updatePrefs) | ⬛ | ⬛ | diff --git a/src/PinguApps.Appwrite.Client/Clients/ITeamsClient.cs b/src/PinguApps.Appwrite.Client/Clients/ITeamsClient.cs index 88238d12..858ab4c0 100644 --- a/src/PinguApps.Appwrite.Client/Clients/ITeamsClient.cs +++ b/src/PinguApps.Appwrite.Client/Clients/ITeamsClient.cs @@ -71,7 +71,13 @@ public interface ITeamsClient /// The request content /// The membership Task> CreateTeamMembership(CreateTeamMembershipRequest request); - [Obsolete("This method hasn't yet been implemented!")] + + /// + /// This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted. + /// Appwrite Docs + /// + /// The request content + /// 204 success code Task DeleteTeamMembership(DeleteTeamMembershipRequest request); [Obsolete("This method hasn't yet been implemented!")] Task> GetTeamMembership(GetTeamMembershipRequest request); diff --git a/src/PinguApps.Appwrite.Client/Clients/TeamsClient.cs b/src/PinguApps.Appwrite.Client/Clients/TeamsClient.cs index 958fa111..1a09c4a5 100644 --- a/src/PinguApps.Appwrite.Client/Clients/TeamsClient.cs +++ b/src/PinguApps.Appwrite.Client/Clients/TeamsClient.cs @@ -142,9 +142,22 @@ public async Task> CreateTeamMembership(CreateTeamMem } } - [ExcludeFromCodeCoverage] /// - public Task DeleteTeamMembership(DeleteTeamMembershipRequest request) => throw new NotImplementedException(); + public async Task DeleteTeamMembership(DeleteTeamMembershipRequest request) + { + try + { + request.Validate(true); + + var result = await _teamsApi.DeleteTeamMembership(GetCurrentSessionOrThrow(), request.TeamId, request.MembershipId); + + return result.GetApiResponse(); + } + catch (Exception e) + { + return e.GetExceptionResponse(); + } + } [ExcludeFromCodeCoverage] /// diff --git a/src/PinguApps.Appwrite.Playground/App.cs b/src/PinguApps.Appwrite.Playground/App.cs index afbbcfca..7d26ce76 100644 --- a/src/PinguApps.Appwrite.Playground/App.cs +++ b/src/PinguApps.Appwrite.Playground/App.cs @@ -19,12 +19,10 @@ public async Task Run(string[] args) { _client.SetSession(_session); - var request = new CreateTeamMembershipRequest() + var request = new DeleteTeamMembershipRequest() { TeamId = "67142b78001c379958cb", - Email = "pingu@example.com", - Url = "https://localhost:1234/acceptTeamInvite", - Name = "Your Name" + MembershipId = "671448a87af3cd4babc7" }; //var clientResponse = await _client.Teams.CreateTeamMembership(request); @@ -36,7 +34,7 @@ public async Task Run(string[] args) Console.WriteLine("############################################################################"); - var serverResponse = await _server.Teams.CreateTeamMembership(request); + var serverResponse = await _server.Teams.DeleteTeamMembership(request); Console.WriteLine(serverResponse.Result.Match( result => result.ToString(), diff --git a/src/PinguApps.Appwrite.Server/Clients/ITeamsClient.cs b/src/PinguApps.Appwrite.Server/Clients/ITeamsClient.cs index 7474268d..a67fa469 100644 --- a/src/PinguApps.Appwrite.Server/Clients/ITeamsClient.cs +++ b/src/PinguApps.Appwrite.Server/Clients/ITeamsClient.cs @@ -71,7 +71,13 @@ public interface ITeamsClient /// The request content /// The membership Task> CreateTeamMembership(CreateTeamMembershipRequest request); - [Obsolete("This method hasn't yet been implemented!")] + + /// + /// This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted. + /// Appwrite Docs + /// + /// The request content + /// 204 success code Task DeleteTeamMembership(DeleteTeamMembershipRequest request); [Obsolete("This method hasn't yet been implemented!")] Task> GetTeamMembership(GetTeamMembershipRequest request); diff --git a/src/PinguApps.Appwrite.Server/Clients/TeamsClient.cs b/src/PinguApps.Appwrite.Server/Clients/TeamsClient.cs index 80707be9..21542ba9 100644 --- a/src/PinguApps.Appwrite.Server/Clients/TeamsClient.cs +++ b/src/PinguApps.Appwrite.Server/Clients/TeamsClient.cs @@ -142,9 +142,22 @@ public async Task> CreateTeamMembership(CreateTeamMem } } - [ExcludeFromCodeCoverage] /// - public Task DeleteTeamMembership(DeleteTeamMembershipRequest request) => throw new NotImplementedException(); + public async Task DeleteTeamMembership(DeleteTeamMembershipRequest request) + { + try + { + request.Validate(true); + + var result = await _teamsApi.DeleteTeamMembership(request.TeamId, request.MembershipId); + + return result.GetApiResponse(); + } + catch (Exception e) + { + return e.GetExceptionResponse(); + } + } [ExcludeFromCodeCoverage] /// diff --git a/tests/PinguApps.Appwrite.Client.Tests/Clients/Teams/TeamsClientTests.DeleteTeamMembership.cs b/tests/PinguApps.Appwrite.Client.Tests/Clients/Teams/TeamsClientTests.DeleteTeamMembership.cs new file mode 100644 index 00000000..2eeb76dc --- /dev/null +++ b/tests/PinguApps.Appwrite.Client.Tests/Clients/Teams/TeamsClientTests.DeleteTeamMembership.cs @@ -0,0 +1,101 @@ +using System.Net; +using PinguApps.Appwrite.Client.Clients; +using PinguApps.Appwrite.Shared.Requests.Teams; +using PinguApps.Appwrite.Shared.Tests; +using PinguApps.Appwrite.Shared.Utils; +using RichardSzalay.MockHttp; + +namespace PinguApps.Appwrite.Client.Tests.Clients.Teams; +public partial class TeamsClientTests +{ + [Fact] + public async Task DeleteTeamMembership_ShouldReturnSuccess_WhenApiCallSucceeds() + { + // Arrange + var request = new DeleteTeamMembershipRequest + { + TeamId = IdUtils.GenerateUniqueId(), + MembershipId = IdUtils.GenerateUniqueId() + }; + + _mockHttp.Expect(HttpMethod.Delete, $"{TestConstants.Endpoint}/teams/{request.TeamId}/memberships/{request.MembershipId}") + .ExpectedHeaders(true) + .Respond(HttpStatusCode.NoContent); + + _appwriteClient.SetSession(TestConstants.Session); + + // Act + var result = await _appwriteClient.Teams.DeleteTeamMembership(request); + + // Assert + Assert.True(result.Success); + } + + [Fact] + public async Task DeleteTeamMembership_ShouldReturnError_WhenSessionIsNull() + { + // Arrange + var request = new DeleteTeamMembershipRequest + { + TeamId = IdUtils.GenerateUniqueId(), + MembershipId = IdUtils.GenerateUniqueId() + }; + + // Act + var result = await _appwriteClient.Teams.DeleteTeamMembership(request); + + // Assert + Assert.True(result.IsError); + Assert.True(result.IsInternalError); + Assert.Equal(ISessionAware.SessionExceptionMessage, result.Result.AsT2.Message); + } + + [Fact] + public async Task DeleteTeamMembership_ShouldHandleException_WhenApiCallFails() + { + // Arrange + var request = new DeleteTeamMembershipRequest + { + TeamId = IdUtils.GenerateUniqueId(), + MembershipId = IdUtils.GenerateUniqueId() + }; + + _mockHttp.Expect(HttpMethod.Delete, $"{TestConstants.Endpoint}/teams/{request.TeamId}/memberships/{request.MembershipId}") + .ExpectedHeaders(true) + .Respond(HttpStatusCode.BadRequest, TestConstants.AppJson, TestConstants.AppwriteError); + + _appwriteClient.SetSession(TestConstants.Session); + + // Act + var result = await _appwriteClient.Teams.DeleteTeamMembership(request); + + // Assert + Assert.True(result.IsError); + Assert.True(result.IsAppwriteError); + } + + [Fact] + public async Task DeleteTeamMembership_ShouldReturnErrorResponse_WhenExceptionOccurs() + { + // Arrange + var request = new DeleteTeamMembershipRequest + { + TeamId = IdUtils.GenerateUniqueId(), + MembershipId = IdUtils.GenerateUniqueId() + }; + + _mockHttp.Expect(HttpMethod.Delete, $"{TestConstants.Endpoint}/teams/{request.TeamId}/memberships/{request.MembershipId}") + .ExpectedHeaders(true) + .Throw(new HttpRequestException("An error occurred")); + + _appwriteClient.SetSession(TestConstants.Session); + + // Act + var result = await _appwriteClient.Teams.DeleteTeamMembership(request); + + // Assert + Assert.False(result.Success); + Assert.True(result.IsInternalError); + Assert.Equal("An error occurred", result.Result.AsT2.Message); + } +} diff --git a/tests/PinguApps.Appwrite.Server.Tests/Clients/Teams/TeamsClientTests.DeleteTeamMembership.cs b/tests/PinguApps.Appwrite.Server.Tests/Clients/Teams/TeamsClientTests.DeleteTeamMembership.cs new file mode 100644 index 00000000..32bcd21c --- /dev/null +++ b/tests/PinguApps.Appwrite.Server.Tests/Clients/Teams/TeamsClientTests.DeleteTeamMembership.cs @@ -0,0 +1,75 @@ +using System.Net; +using PinguApps.Appwrite.Shared.Requests.Teams; +using PinguApps.Appwrite.Shared.Tests; +using PinguApps.Appwrite.Shared.Utils; +using RichardSzalay.MockHttp; + +namespace PinguApps.Appwrite.Server.Tests.Clients.Teams; +public partial class TeamsClientTests +{ + [Fact] + public async Task DeleteTeamMembership_ShouldReturnSuccess_WhenApiCallSucceeds() + { + // Arrange + var request = new DeleteTeamMembershipRequest + { + TeamId = IdUtils.GenerateUniqueId(), + MembershipId = IdUtils.GenerateUniqueId() + }; + + _mockHttp.Expect(HttpMethod.Delete, $"{TestConstants.Endpoint}/teams/{request.TeamId}/memberships/{request.MembershipId}") + .ExpectedHeaders() + .Respond(HttpStatusCode.NoContent); + + // Act + var result = await _appwriteClient.Teams.DeleteTeamMembership(request); + + // Assert + Assert.True(result.Success); + } + + [Fact] + public async Task DeleteTeamMembership_ShouldHandleException_WhenApiCallFails() + { + // Arrange + var request = new DeleteTeamMembershipRequest + { + TeamId = IdUtils.GenerateUniqueId(), + MembershipId = IdUtils.GenerateUniqueId() + }; + + _mockHttp.Expect(HttpMethod.Delete, $"{TestConstants.Endpoint}/teams/{request.TeamId}/memberships/{request.MembershipId}") + .ExpectedHeaders() + .Respond(HttpStatusCode.BadRequest, TestConstants.AppJson, TestConstants.AppwriteError); + + // Act + var result = await _appwriteClient.Teams.DeleteTeamMembership(request); + + // Assert + Assert.True(result.IsError); + Assert.True(result.IsAppwriteError); + } + + [Fact] + public async Task DeleteTeamMembership_ShouldReturnErrorResponse_WhenExceptionOccurs() + { + // Arrange + var request = new DeleteTeamMembershipRequest + { + TeamId = IdUtils.GenerateUniqueId(), + MembershipId = IdUtils.GenerateUniqueId() + }; + + _mockHttp.Expect(HttpMethod.Delete, $"{TestConstants.Endpoint}/teams/{request.TeamId}/memberships/{request.MembershipId}") + .ExpectedHeaders() + .Throw(new HttpRequestException("An error occurred")); + + // Act + var result = await _appwriteClient.Teams.DeleteTeamMembership(request); + + // Assert + Assert.False(result.Success); + Assert.True(result.IsInternalError); + Assert.Equal("An error occurred", result.Result.AsT2.Message); + } +}