Skip to content

Commit

Permalink
Merge pull request #169 from PinguApps/83-delete-identity
Browse files Browse the repository at this point in the history
Implemented delete identity
  • Loading branch information
pingu2k4 authored Sep 23, 2024
2 parents b5b6e5d + 66ed06b commit be164c4
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 10 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,14 @@ string emailAddressOrErrorMessage = userResponse.Result.Match(
```

## ⌛ Progress
<!-- ![48 / 291](https://progress-bar.dev/48/?scale=291&suffix=%20/%20288&width=500) -->
![Server & Client - 48 / 291](https://img.shields.io/badge/Server_&_Client-48%20%2F%20291-red?style=for-the-badge)
<!-- ![49 / 291](https://progress-bar.dev/49/?scale=291&suffix=%20/%20288&width=500) -->
![Server & Client - 49 / 291](https://img.shields.io/badge/Server_&_Client-49%20%2F%20291-red?style=for-the-badge)

<!-- ![9 / 201](https://progress-bar.dev/9/?scale=195&suffix=%20/%20201&width=300) -->
![Server - 9 / 201](https://img.shields.io/badge/Server-9%20%2F%20201-red?style=for-the-badge)

<!-- ![39 / 93](https://progress-bar.dev/39/?scale=93&suffix=%20/%2093&width=300) -->
![Client - 39 / 90](https://img.shields.io/badge/Client-39%20%2F%2090-gold?style=for-the-badge)
<!-- ![40 / 93](https://progress-bar.dev/40/?scale=93&suffix=%20/%2093&width=300) -->
![Client - 40 / 90](https://img.shields.io/badge/Client-40%20%2F%2090-gold?style=for-the-badge)

### 🔑 Key
| Icon | Definition |
Expand All @@ -155,16 +155,16 @@ string emailAddressOrErrorMessage = userResponse.Result.Match(
|| There is currently no intention to implement the endpoint for the given SDK type (client or server) |

### Account
<!-- ![48 / 55](https://progress-bar.dev/48/?scale=55&suffix=%20/%2052&width=120) -->
![Account - 48 / 55](https://img.shields.io/badge/Account-48%20%2F%2055-forestgreen?style=for-the-badge)
<!-- ![49 / 55](https://progress-bar.dev/49/?scale=55&suffix=%20/%2052&width=120) -->
![Account - 49 / 55](https://img.shields.io/badge/Account-49%20%2F%2055-forestgreen?style=for-the-badge)

| Endpoint | Client | Server | Notes |
|:-:|:-:|:-:|:-:|
| [Get Account](https://appwrite.io/docs/references/1.6.x/client-rest/account#get) ||| |
| [Create Account](https://appwrite.io/docs/references/1.6.x/client-rest/account#create) ||| |
| [Update Email](https://appwrite.io/docs/references/1.6.x/client-rest/account#updateEmail) ||| |
| [List Identities](https://appwrite.io/docs/references/1.6.x/client-rest/account#listIdentities) ||| |
| [Delete Identity](https://appwrite.io/docs/references/1.6.x/client-rest/account#deleteIdentity) | || |
| [Delete Identity](https://appwrite.io/docs/references/1.6.x/client-rest/account#deleteIdentity) | || |
| [Create JWT](https://appwrite.io/docs/references/1.6.x/client-rest/account#createJWT) ||| |
| [List Logs](https://appwrite.io/docs/references/1.6.x/client-rest/account#listLogs) ||| |
| [Update MFA](https://appwrite.io/docs/references/1.6.x/client-rest/account#updateMFA) ||| |
Expand Down
17 changes: 17 additions & 0 deletions src/PinguApps.Appwrite.Client/Clients/AccountClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -680,4 +680,21 @@ public async Task<AppwriteResult<IdentitiesList>> ListIdentities(List<Query>? qu
return e.GetExceptionResponse<IdentitiesList>();
}
}

/// <inheritdoc/>
public async Task<AppwriteResult> DeleteIdentity(DeleteIdentityRequest request)
{
try
{
request.Validate(true);

var result = await _accountApi.DeleteIdentity(GetCurrentSessionOrThrow(), request.IdentityId);

return result.GetApiResponse();
}
catch (Exception e)
{
return e.GetExceptionResponse();
}
}
}
7 changes: 7 additions & 0 deletions src/PinguApps.Appwrite.Client/Clients/IAccountClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,11 @@ public interface IAccountClient
/// <param name="queries">Array of query strings generated using the Query class provided by the SDK. <see href="https://appwrite.io/docs/queries">Learn more about queries</see>. Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: <c>userId</c>, <c>provider</c>, <c>providerUid</c>, <c>providerEmail</c>, <c>providerAccessTokenExpiry</c></param>
/// <returns>The Identities List</returns>
Task<AppwriteResult<IdentitiesList>> ListIdentities(List<Query>? queries = null);

/// <summary>
/// Delete an identity by its unique ID
/// </summary>
/// <param name="request">The request content</param>
/// <returns>code 204 ofr success</returns>
Task<AppwriteResult> DeleteIdentity(DeleteIdentityRequest request);
}
3 changes: 3 additions & 0 deletions src/PinguApps.Appwrite.Client/Internals/IAccountApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,7 @@ internal interface IAccountApi : IBaseApi
[Get("/account/identities")]
[QueryUriFormat(System.UriFormat.Unescaped)]
Task<IApiResponse<IdentitiesList>> ListIdentities([Header("x-appwrite-session")] string session, [Query(CollectionFormat.Multi), AliasAs("queries[]")] IEnumerable<string> queries);

[Delete("/account/identities/{identityId}")]
Task<IApiResponse> DeleteIdentity([Header("x-appwrite-session")] string session, string identityId);
}
6 changes: 5 additions & 1 deletion src/PinguApps.Appwrite.Playground/App.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.Extensions.Configuration;
using PinguApps.Appwrite.Client;
using PinguApps.Appwrite.Server.Servers;
using PinguApps.Appwrite.Shared.Requests;

namespace PinguApps.Appwrite.Playground;
internal class App
Expand All @@ -20,7 +21,10 @@ public async Task Run(string[] args)
{
_client.SetSession(_session);

var response = await _client.Account.ListIdentities();
var response = await _client.Account.DeleteIdentity(new DeleteIdentityRequest
{
IdentityId = "my identity id"
});

Console.WriteLine(response.Result.Match(
account => account.ToString(),
Expand Down
16 changes: 16 additions & 0 deletions src/PinguApps.Appwrite.Shared/Requests/DeleteIdentityRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Text.Json.Serialization;
using PinguApps.Appwrite.Shared.Requests.Validators;

namespace PinguApps.Appwrite.Shared.Requests;

/// <summary>
/// The request for deleting an identity
/// </summary>
public class DeleteIdentityRequest : BaseRequest<DeleteIdentityRequest, DeleteIdentityRequestValidator>
{
/// <summary>
/// Identity ID
/// </summary>
[JsonPropertyName("identityId")]
public string IdentityId { get; set; } = string.Empty;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using FluentValidation;

namespace PinguApps.Appwrite.Shared.Requests.Validators;
public class DeleteIdentityRequestValidator : AbstractValidator<DeleteIdentityRequest>
{
public DeleteIdentityRequestValidator()
{
RuleFor(request => request.IdentityId)
.NotEmpty().WithMessage("Identity ID must not be empty.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using System.Net;
using PinguApps.Appwrite.Client.Clients;
using PinguApps.Appwrite.Shared.Requests;
using PinguApps.Appwrite.Shared.Tests;
using RichardSzalay.MockHttp;

namespace PinguApps.Appwrite.Client.Tests.Clients.Account;
public partial class AccountClientTests
{
[Fact]
public async Task DeleteIdentity_ShouldReturnSuccess_WhenApiCallSucceeds()
{
// Arrange
var request = new DeleteIdentityRequest { IdentityId = "validIdentityId" };

_mockHttp.Expect(HttpMethod.Delete, $"{Constants.Endpoint}/account/identities/{request.IdentityId}")
.ExpectedHeaders(true)
.Respond(HttpStatusCode.NoContent);

_appwriteClient.SetSession(Constants.Session);

// Act
var result = await _appwriteClient.Account.DeleteIdentity(request);

// Assert
Assert.True(result.Success);
}

[Fact]
public async Task DeleteIdentity_ShouldHitDifferentEndpoint_WhenNewIdentityIdIsUsed()
{
// Arrange
var identityId = "myIdentityId";
var request = new DeleteIdentityRequest { IdentityId = identityId };
var requestUri = $"{Constants.Endpoint}/account/identities/{identityId}";
var mockRequest = _mockHttp.Expect(HttpMethod.Delete, requestUri)
.ExpectedHeaders(true)
.Respond(HttpStatusCode.NoContent);

_appwriteClient.SetSession(Constants.Session);

// Act
var result = await _appwriteClient.Account.DeleteIdentity(request);

// Assert
_mockHttp.VerifyNoOutstandingExpectation();
var matches = _mockHttp.GetMatchCount(mockRequest);
Assert.Equal(1, matches);
}

[Fact]
public async Task DeleteIdentity_ShouldReturnError_WhenSessionIsNull()
{
// Arrange
var request = new DeleteIdentityRequest { IdentityId = "validIdentityId" };

// Act
var result = await _appwriteClient.Account.DeleteIdentity(request);

// Assert
Assert.True(result.IsError);
Assert.True(result.IsInternalError);
Assert.Equal(ISessionAware.SessionExceptionMessage, result.Result.AsT2.Message);
}

[Fact]
public async Task DeleteIdentity_ShouldHandleException_WhenApiCallFails()
{
// Arrange
var request = new DeleteIdentityRequest { IdentityId = "validIdentityId" };

_mockHttp.Expect(HttpMethod.Delete, $"{Constants.Endpoint}/account/identities/{request.IdentityId}")
.ExpectedHeaders(true)
.Respond(HttpStatusCode.BadRequest, Constants.AppJson, Constants.AppwriteError);

_appwriteClient.SetSession(Constants.Session);

// Act
var result = await _appwriteClient.Account.DeleteIdentity(request);

// Assert
Assert.True(result.IsError);
Assert.True(result.IsAppwriteError);
}

[Fact]
public async Task DeleteIdentity_ShouldReturnErrorResponse_WhenExceptionOccurs()
{
// Arrange
var request = new DeleteIdentityRequest { IdentityId = "validIdentityId" };

_mockHttp.Expect(HttpMethod.Delete, $"{Constants.Endpoint}/account/identities/{request.IdentityId}")
.ExpectedHeaders(true)
.Throw(new HttpRequestException("An error occurred"));

_appwriteClient.SetSession(Constants.Session);

// Act
var result = await _appwriteClient.Account.DeleteIdentity(request);

// Assert
Assert.False(result.Success);
Assert.True(result.IsInternalError);
Assert.Equal("An error occurred", result.Result.AsT2.Message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public async Task DeleteSession_ShouldReturnSuccess_WhenApiCallSucceeds()

_mockHttp.Expect(HttpMethod.Delete, $"{Constants.Endpoint}/account/sessions/current")
.ExpectedHeaders(true)
.Respond(Constants.AppJson, Constants.MfaTypeResponse);
.Respond(HttpStatusCode.NoContent);

_appwriteClient.SetSession(Constants.Session);

Expand All @@ -38,7 +38,7 @@ public async Task DeleteSession_ShouldHitDifferentEndpoint_WhenNewTypeIsUsed()
var requestUri = $"{Constants.Endpoint}/account/sessions/{sessionId}";
var mockRequest = _mockHttp.Expect(HttpMethod.Delete, requestUri)
.ExpectedHeaders(true)
.Respond(Constants.AppJson, Constants.MfaTypeResponse);
.Respond(HttpStatusCode.NoContent);

_appwriteClient.SetSession(Constants.Session);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using FluentValidation;
using PinguApps.Appwrite.Shared.Requests;

namespace PinguApps.Appwrite.Shared.Tests.Requests;
public class DeleteIdentityRequestTests
{
[Fact]
public void Constructor_InitializesWithExpectedValues()
{
// Arrange & Act
var request = new DeleteIdentityRequest();

// Assert
Assert.Equal(string.Empty, request.IdentityId);
}

[Theory]
[InlineData("A string")]
public void Properties_CanBeSet(string identityId)
{
// Arrange
var request = new DeleteIdentityRequest();

// Act
request.IdentityId = identityId;

// Assert
Assert.Equal(identityId, request.IdentityId);
}

[Fact]
public void IsValid_WithValidInputs_ReturnsTrue()
{
// Arrange
var request = new DeleteIdentityRequest
{
IdentityId = "validIdentityId"
};

// Act
var isValid = request.IsValid();

// Assert
Assert.True(isValid);
}

[Theory]
[InlineData("")]
[InlineData(null)]
public void IsValid_WithInvalidInputs_ReturnsFalse(string? identityId)
{
// Arrange
var request = new DeleteIdentityRequest
{
IdentityId = identityId!
};

// Act
var isValid = request.IsValid();

// Assert
Assert.False(isValid);
}

[Fact]
public void Validate_WithThrowOnFailuresTrue_ThrowsValidationExceptionOnFailure()
{
// Arrange
var request = new DeleteIdentityRequest
{
IdentityId = ""
};

// Assert
Assert.Throws<ValidationException>(() => request.Validate(true));
}

[Fact]
public void Validate_WithThrowOnFailuresFalse_ReturnsInvalidResultOnFailure()
{
// Arrange
var request = new DeleteIdentityRequest
{
IdentityId = ""
};

// Act
var result = request.Validate(false);

// Assert
Assert.False(result.IsValid);
}
}

0 comments on commit be164c4

Please sign in to comment.