Skip to content

Commit

Permalink
Merge pull request #293 from PinguApps/289-update-push-target
Browse files Browse the repository at this point in the history
Implemented update push target
  • Loading branch information
pingu2k4 authored Oct 13, 2024
2 parents ed3108b + 558645b commit 8d14738
Show file tree
Hide file tree
Showing 9 changed files with 305 additions and 10 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,11 @@ string emailAddressOrErrorMessage = userResponse.Result.Match(

## ⌛ Progress
<!-- `red` for first third, `gold` for second third, `forestgreen` for final third, `blue` for 100% -->
![Server & Client - 98 / 295](https://img.shields.io/badge/Server_&_Client-98%20%2F%20295-red?style=for-the-badge)
![Server & Client - 99 / 295](https://img.shields.io/badge/Server_&_Client-99%20%2F%20295-gold?style=for-the-badge)

![Server - 53 / 202](https://img.shields.io/badge/Server-53%20%2F%20202-red?style=for-the-badge)

![Client - 45 / 93](https://img.shields.io/badge/Client-45%20%2F%2093-gold?style=for-the-badge)
![Client - 46 / 93](https://img.shields.io/badge/Client-46%20%2F%2093-gold?style=for-the-badge)

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

### Account
![Account - 56 / 58](https://img.shields.io/badge/Account-56%20%2F%2058-forestgreen?style=for-the-badge)
![Account - 57 / 58](https://img.shields.io/badge/Account-57%20%2F%2058-forestgreen?style=for-the-badge)

| Endpoint | Client | Server |
|:-:|:-:|:-:|
Expand Down Expand Up @@ -196,7 +196,7 @@ string emailAddressOrErrorMessage = userResponse.Result.Match(
| [Delete Session](https://appwrite.io/docs/references/1.6.x/client-rest/account#deleteSession) |||
| [Update Status](https://appwrite.io/docs/references/1.6.x/client-rest/account#updateStatus) |||
| [Create Push Target](https://appwrite.io/docs/references/1.6.x/client-rest/account#createPushTarget) |||
| [Update Push Target](https://appwrite.io/docs/references/1.6.x/client-rest/account#updatePushTarget) | ||
| [Update Push Target](https://appwrite.io/docs/references/1.6.x/client-rest/account#updatePushTarget) | ||
| [Delete Push Target](https://appwrite.io/docs/references/1.6.x/client-rest/account#deletePushTarget) |||
| [Create Email Token (OTP)](https://appwrite.io/docs/references/1.6.x/client-rest/account#createEmailToken) |||
| [Create Magic URL Token](https://appwrite.io/docs/references/1.6.x/client-rest/account#createMagicURLToken) |||
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 @@ -669,6 +669,23 @@ public async Task<AppwriteResult<Target>> CreatePushTarget(CreatePushTargetReque
}
}

/// <inheritdoc/>
public async Task<AppwriteResult<Target>> UpdatePushTarget(UpdatePushTargetRequest request)
{
try
{
request.Validate(true);

var result = await _accountApi.UpdatePushTarget(GetCurrentSessionOrThrow(), request.TargetId, request);

return result.GetApiResponse();
}
catch (Exception e)
{
return e.GetExceptionResponse<Target>();
}
}

/// <inheritdoc/>
public async Task<AppwriteResult<Token>> CreateMagicUrlToken(CreateMagicUrlTokenRequest request)
{
Expand Down
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 @@ -312,6 +312,13 @@ public interface IAccountClient
/// <returns>The target</returns>
Task<AppwriteResult<Target>> CreatePushTarget(CreatePushTargetRequest request);

/// <summary>
/// <para><see href="https://appwrite.io/docs/references/1.6.x/client-rest/account#updatePushTarget">Appwrite Docs</see></para>
/// </summary>
/// <param name="request">The request content</param>
/// <returns>The target</returns>
Task<AppwriteResult<Target>> UpdatePushTarget(UpdatePushTargetRequest request);

/// <summary>
/// <para>Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the <see cref="CreateSession(CreateSessionRequest)"/> endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. If you are on a mobile device you can leave the URL parameter empty, so that the login completion will be handled by your Appwrite instance by default.</para>
/// <para>A user is limited to 10 active sessions at a time by default. <see href="https://appwrite.io/docs/authentication-security#limits">Learn more about session limits</see>.</para>
Expand Down
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 @@ -121,6 +121,9 @@ internal interface IAccountApi : IBaseApi
[Post("/account/targets/push")]
Task<IApiResponse<Target>> CreatePushTarget([Header("x-appwrite-session")] string session, CreatePushTargetRequest request);

[Put("/account/targets/{targetId}/push")]
Task<IApiResponse<Target>> UpdatePushTarget([Header("x-appwrite-session")] string session, string targetId, UpdatePushTargetRequest request);

[Post("/account/tokens/magic-url")]
Task<IApiResponse<Token>> CreateMagicUrlToken(CreateMagicUrlTokenRequest request);

Expand Down
10 changes: 4 additions & 6 deletions src/PinguApps.Appwrite.Playground/App.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Microsoft.Extensions.Configuration;
using PinguApps.Appwrite.Shared.Requests.Account;
using PinguApps.Appwrite.Shared.Utils;

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

var request = new CreatePushTargetRequest()
var request = new UpdatePushTargetRequest()
{
TargetId = IdUtils.GenerateUniqueId(),
Identifier = "token",
ProviderId = "abcdef"
TargetId = "670be3330025c0f23b93",
Identifier = "token"
};

var response = await _client.Account.CreatePushTarget(request);
var response = await _client.Account.UpdatePushTarget(request);

Console.WriteLine(response.Result.Match(
result => result.ToString(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Text.Json.Serialization;
using PinguApps.Appwrite.Shared.Attributes;
using PinguApps.Appwrite.Shared.Requests.Account.Validators;

namespace PinguApps.Appwrite.Shared.Requests.Account;
public class UpdatePushTargetRequest : BaseRequest<UpdatePushTargetRequest, UpdatePushTargetRequestValidator>
{
/// <summary>
/// Target ID.
/// </summary>
[JsonPropertyName("targetId")]
[SdkExclude]
public string TargetId { get; set; } = string.Empty;

/// <summary>
/// The target identifier (token, email, phone etc.)
/// </summary>
[JsonPropertyName("identifier")]
public string Identifier { get; set; } = string.Empty;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using FluentValidation;

namespace PinguApps.Appwrite.Shared.Requests.Account.Validators;
public class UpdatePushTargetRequestValidator : AbstractValidator<UpdatePushTargetRequest>
{
public UpdatePushTargetRequestValidator()
{
RuleFor(x => x.TargetId)
.NotEmpty().WithMessage("TargetId is required.");

RuleFor(x => x.Identifier)
.NotEmpty().WithMessage("Identifier is required.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System.Net;
using PinguApps.Appwrite.Client.Clients;
using PinguApps.Appwrite.Shared.Requests.Account;
using PinguApps.Appwrite.Shared.Tests;
using PinguApps.Appwrite.Shared.Utils;
using RichardSzalay.MockHttp;

namespace PinguApps.Appwrite.Client.Tests.Clients.Account;
public partial class AccountClientTests
{
[Fact]
public async Task UpdatePushTarget_ShouldReturnSuccess_WhenApiCallSucceeds()
{
// Arrange
var request = new UpdatePushTargetRequest
{
TargetId = IdUtils.GenerateUniqueId(),
Identifier = "token"
};

_mockHttp.Expect(HttpMethod.Put, $"{TestConstants.Endpoint}/account/targets/{request.TargetId}/push")
.ExpectedHeaders()
.WithJsonContent(request, _jsonSerializerOptions)
.Respond(TestConstants.AppJson, TestConstants.TargetResponse);

_appwriteClient.SetSession(TestConstants.Session);

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

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

[Fact]
public async Task UpdatePushTarget_ShouldReturnError_WhenSessionIsNull()
{
// Arrange
var request = new UpdatePushTargetRequest
{
TargetId = IdUtils.GenerateUniqueId(),
Identifier = "token"
};

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

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

[Fact]
public async Task UpdatePushTarget_ShouldHandleException_WhenApiCallFails()
{
// Arrange
var request = new UpdatePushTargetRequest
{
TargetId = IdUtils.GenerateUniqueId(),
Identifier = "token"
};

_mockHttp.Expect(HttpMethod.Put, $"{TestConstants.Endpoint}/account/targets/{request.TargetId}/push")
.ExpectedHeaders()
.WithJsonContent(request, _jsonSerializerOptions)
.Respond(HttpStatusCode.BadRequest, TestConstants.AppJson, TestConstants.AppwriteError);

_appwriteClient.SetSession(TestConstants.Session);

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

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

[Fact]
public async Task UpdatePushTarget_ShouldReturnErrorResponse_WhenExceptionOccurs()
{
// Arrange
var request = new UpdatePushTargetRequest
{
TargetId = IdUtils.GenerateUniqueId(),
Identifier = "token"
};

_mockHttp.Expect(HttpMethod.Put, $"{TestConstants.Endpoint}/account/targets/{request.TargetId}/push")
.ExpectedHeaders()
.WithJsonContent(request, _jsonSerializerOptions)
.Throw(new HttpRequestException("An error occurred"));

_appwriteClient.SetSession(TestConstants.Session);

// Act
var result = await _appwriteClient.Account.UpdatePushTarget(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
@@ -0,0 +1,132 @@
using FluentValidation;
using PinguApps.Appwrite.Shared.Requests.Account;
using PinguApps.Appwrite.Shared.Utils;

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

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

[Fact]
public void Properties_CanBeSet()
{
var targetId = IdUtils.GenerateUniqueId();
var identifier = "email";

// Arrange
var request = new UpdatePushTargetRequest();

// Act
request.TargetId = targetId;
request.Identifier = identifier;

// Assert
Assert.Equal(targetId, request.TargetId);
Assert.Equal(identifier, request.Identifier);
}

public static TheoryData<UpdatePushTargetRequest> ValidRequestsData = new()
{
new UpdatePushTargetRequest
{
TargetId = IdUtils.GenerateUniqueId(),
Identifier = "token"
},
new UpdatePushTargetRequest
{
TargetId = IdUtils.GenerateUniqueId(),
Identifier = "email"
},
new UpdatePushTargetRequest
{
TargetId = IdUtils.GenerateUniqueId(),
Identifier = "phone"
}
};

[Theory]
[MemberData(nameof(ValidRequestsData))]
public void IsValid_WithValidData_ReturnsTrue(UpdatePushTargetRequest request)
{
// Act
var isValid = request.IsValid();

// Assert
Assert.True(isValid);
}

public static TheoryData<UpdatePushTargetRequest> InvalidRequestsData = new()
{
new UpdatePushTargetRequest
{
TargetId = "",
Identifier = "token"
},
new UpdatePushTargetRequest
{
TargetId = null!,
Identifier = "token"
},
new UpdatePushTargetRequest
{
TargetId = IdUtils.GenerateUniqueId(),
Identifier = ""
},
new UpdatePushTargetRequest
{
TargetId = IdUtils.GenerateUniqueId(),
Identifier = null!
}
};

[Theory]
[MemberData(nameof(InvalidRequestsData))]
public void IsValid_WithInvalidData_ReturnsFalse(UpdatePushTargetRequest request)
{
// Act
var isValid = request.IsValid();

// Assert
Assert.False(isValid);
}

[Fact]
public void Validate_WithThrowOnFailuresTrue_ThrowsValidationExceptionOnFailure()
{
// Arrange
var request = new UpdatePushTargetRequest
{
TargetId = "",
Identifier = ""
};

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

[Fact]
public void Validate_WithThrowOnFailuresFalse_ReturnsInvalidResultOnFailure()
{
// Arrange
var request = new UpdatePushTargetRequest
{
TargetId = "",
Identifier = ""
};

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

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

0 comments on commit 8d14738

Please sign in to comment.