Skip to content

Commit

Permalink
Merge pull request #166 from PinguApps/102-update-magic-url-session
Browse files Browse the repository at this point in the history
Implemented update magic url session
  • Loading branch information
pingu2k4 authored Sep 22, 2024
2 parents 93476f6 + f701fe0 commit 222af46
Show file tree
Hide file tree
Showing 13 changed files with 378 additions and 14 deletions.
18 changes: 9 additions & 9 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
<!-- ![42 / 290](https://progress-bar.dev/42/?scale=290&suffix=%20/%20288&width=500) -->
![Server & Client - 42 / 290](https://img.shields.io/badge/Server_&_Client-42%20%2F%20290-red?style=for-the-badge)
<!-- ![44 / 290](https://progress-bar.dev/44/?scale=290&suffix=%20/%20288&width=500) -->
![Server & Client - 44 / 290](https://img.shields.io/badge/Server_&_Client-44%20%2F%20290-red?style=for-the-badge)

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

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

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

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

| Endpoint | Client | Server | Notes |
|:-:|:-:|:-:|:-:|
Expand Down Expand Up @@ -188,7 +188,7 @@ string emailAddressOrErrorMessage = userResponse.Result.Match(
| [Delete Sessions](https://appwrite.io/docs/references/1.6.x/client-rest/account#deleteSessions) ||| |
| [Create Anonymous Session](https://appwrite.io/docs/references/1.6.x/client-rest/account#createAnonymousSession) ||| |
| [Create Email Password Session](https://appwrite.io/docs/references/1.6.x/client-rest/account#createEmailPasswordSession) ||| |
| [Update Magic URL Session](https://appwrite.io/docs/references/1.6.x/client-rest/account#updateMagicURLSession) | | | |
| [Update Magic URL Session](https://appwrite.io/docs/references/1.6.x/client-rest/account#updateMagicURLSession) | | | |
| [Create OAuth2 Session](https://appwrite.io/docs/references/1.6.x/client-rest/account#createOAuth2Session) ||| |
| [Update Phone Session](https://appwrite.io/docs/references/1.6.x/client-rest/account#updatePhoneSession) ||| |
| [Create Session](https://appwrite.io/docs/references/1.6.x/client-rest/account#createSession) ||| |
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 @@ -629,4 +629,21 @@ public async Task<AppwriteResult<Token>> CreateMagicUrlToken(CreateMagicUrlToken
return e.GetExceptionResponse<Token>();
}
}

/// <inheritdoc/>
public async Task<AppwriteResult<Session>> UpdateMagicUrlSession(UpdateMagicUrlSessionRequest request)
{
try
{
request.Validate(true);

var result = await _accountApi.UpdateMagicUrlSession(request);

return result.GetApiResponse();
}
catch (Exception e)
{
return e.GetExceptionResponse<Session>();
}
}
}
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 @@ -299,4 +299,11 @@ public interface IAccountClient
/// <param name="request">The request content</param>
/// <returns>The token</returns>
Task<AppwriteResult<Token>> CreateMagicUrlToken(CreateMagicUrlTokenRequest request);

/// <summary>
/// Use this endpoint to create a session from token. Provide the <see cref="UpdateMagicUrlSessionRequest.UserId"/> and <see cref="UpdateMagicUrlSessionRequest.Secret"/> parameters from the successful response of authentication flows initiated by token creation. For example, magic URL and phone login.
/// </summary>
/// <param name="request">The request content</param>
/// <returns>The session</returns>
Task<AppwriteResult<Session>> UpdateMagicUrlSession(UpdateMagicUrlSessionRequest 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 @@ -113,4 +113,7 @@ internal interface IAccountApi : IBaseApi

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

[Put("/account/sessions/magic-url")]
Task<IApiResponse<Session>> UpdateMagicUrlSession(UpdateMagicUrlSessionRequest request);
}
23 changes: 18 additions & 5 deletions src/PinguApps.Appwrite.Playground/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,30 @@ public async Task Run(string[] args)
{
//_client.SetSession(_session);

var response = await _server.Account.CreateMagicUrlToken(new CreateMagicUrlTokenRequest
//var response = await _server.Account.CreateMagicUrlToken(new CreateMagicUrlTokenRequest
//{
// UserId = "",
// Email = "[email protected]",
// Url = "https://localhost:1234/magic",
// Phrase = true
//});

var response = await _server.Account.UpdateMagicUrlSession(new UpdateMagicUrlSessionRequest
{
UserId = "664aac1a00113f82e620",
Email = "[email protected]",
Url = "https://localhost:1234/magic",
Phrase = true
UserId = "",
Secret = ""
});

Console.WriteLine(response.Result.Match(
account => account.ToString(),
appwriteError => appwriteError.Message,
internalERror => internalERror.Message));

var res2 = await _server.Account.CreateAnonymousSession();

Console.WriteLine(res2.Result.Match(
account => account.ToString(),
appwriteError => appwriteError.Message,
internalERror => internalERror.Message));
}
}
3 changes: 3 additions & 0 deletions src/PinguApps.Appwrite.Server/Internals/IAccountApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ internal interface IAccountApi : IBaseApi

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

[Put("/account/sessions/magic-url")]
Task<IApiResponse<Session>> UpdateMagicUrlSession(UpdateMagicUrlSessionRequest request);
}
17 changes: 17 additions & 0 deletions src/PinguApps.Appwrite.Server/Servers/AccountServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,21 @@ public async Task<AppwriteResult<Token>> CreateMagicUrlToken(CreateMagicUrlToken
return e.GetExceptionResponse<Token>();
}
}

/// <inheritdoc/>
public async Task<AppwriteResult<Session>> UpdateMagicUrlSession(UpdateMagicUrlSessionRequest request)
{
try
{
request.Validate(true);

var result = await _accountApi.UpdateMagicUrlSession(request);

return result.GetApiResponse();
}
catch (Exception e)
{
return e.GetExceptionResponse<Session>();
}
}
}
7 changes: 7 additions & 0 deletions src/PinguApps.Appwrite.Server/Servers/IAccountServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,11 @@ public interface IAccountServer
/// <param name="request">The request content</param>
/// <returns>The token</returns>
Task<AppwriteResult<Token>> CreateMagicUrlToken(CreateMagicUrlTokenRequest request);

/// <summary>
/// Use this endpoint to create a session from token. Provide the <see cref="UpdateMagicUrlSessionRequest.UserId"/> and <see cref="UpdateMagicUrlSessionRequest.Secret"/> parameters from the successful response of authentication flows initiated by token creation. For example, magic URL and phone login.
/// </summary>
/// <param name="request">The request content</param>
/// <returns>The session</returns>
Task<AppwriteResult<Session>> UpdateMagicUrlSession(UpdateMagicUrlSessionRequest request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Text.Json.Serialization;
using PinguApps.Appwrite.Shared.Requests.Validators;

namespace PinguApps.Appwrite.Shared.Requests;
public class UpdateMagicUrlSessionRequest : BaseRequest<UpdateMagicUrlSessionRequest, UpdateMagicUrlSessionRequestValidator>
{
/// <summary>
/// User ID. Choose a custom ID or generate a random ID with <see cref="Utils.IdUtils.GenerateUniqueId(int)"/>. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.
/// </summary>
[JsonPropertyName("userId")]
public string UserId { get; set; } = string.Empty;

/// <summary>
/// Valid verification token.
/// </summary>
[JsonPropertyName("secret")]
public string Secret { get; set; } = string.Empty;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using FluentValidation;

namespace PinguApps.Appwrite.Shared.Requests.Validators;
public class UpdateMagicUrlSessionRequestValidator : AbstractValidator<UpdateMagicUrlSessionRequest>
{
public UpdateMagicUrlSessionRequestValidator()
{
RuleFor(x => x.UserId)
.NotEmpty().WithMessage("UserId is required.")
.Matches("^[a-zA-Z0-9][a-zA-Z0-9._-]{0,35}$").WithMessage("UserId can only contain a-z, A-Z, 0-9, period, hyphen, and underscore, and can't start with a special char. Max length is 36 chars.");

RuleFor(x => x.Secret)
.NotEmpty().WithMessage("Secret is required.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Net;
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 UpdateMagicUrlSession_ShouldReturnSuccess_WhenApiCallSucceeds()
{
// Arrange
var request = new UpdateMagicUrlSessionRequest()
{
UserId = "user123",
Secret = "validSecret"
};

_mockHttp.Expect(HttpMethod.Put, $"{Constants.Endpoint}/account/sessions/magic-url")
.ExpectedHeaders()
.WithJsonContent(request)
.Respond(Constants.AppJson, Constants.SessionResponse);

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

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

[Fact]
public async Task UpdateMagicUrlSession_ShouldHandleException_WhenApiCallFails()
{
// Arrange
var request = new UpdateMagicUrlSessionRequest()
{
UserId = "user123",
Secret = "validSecret"
};

_mockHttp.Expect(HttpMethod.Put, $"{Constants.Endpoint}/account/sessions/magic-url")
.ExpectedHeaders()
.WithJsonContent(request)
.Respond(HttpStatusCode.BadRequest, Constants.AppJson, Constants.AppwriteError);

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

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

[Fact]
public async Task UpdateMagicUrlSession_ShouldReturnErrorResponse_WhenExceptionOccurs()
{
// Arrange
var request = new UpdateMagicUrlSessionRequest()
{
UserId = "user123",
Secret = "validSecret"
};

_mockHttp.Expect(HttpMethod.Put, $"{Constants.Endpoint}/account/sessions/magic-url")
.ExpectedHeaders()
.WithJsonContent(request)
.Throw(new HttpRequestException("An error occurred"));

// Act
var result = await _appwriteClient.Account.UpdateMagicUrlSession(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,77 @@
using System.Net;
using PinguApps.Appwrite.Shared.Requests;
using PinguApps.Appwrite.Shared.Tests;
using RichardSzalay.MockHttp;

namespace PinguApps.Appwrite.Server.Tests.Servers.Account;
public partial class AccountServerTests
{
[Fact]
public async Task UpdateMagicUrlSession_ShouldReturnSuccess_WhenApiCallSucceeds()
{
// Arrange
var request = new UpdateMagicUrlSessionRequest()
{
UserId = "user123",
Secret = "validSecret"
};

_mockHttp.Expect(HttpMethod.Put, $"{Constants.Endpoint}/account/sessions/magic-url")
.ExpectedHeaders()
.WithJsonContent(request)
.Respond(Constants.AppJson, Constants.SessionResponse);

// Act
var result = await _appwriteServer.Account.UpdateMagicUrlSession(request);

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

[Fact]
public async Task UpdateMagicUrlSession_ShouldHandleException_WhenApiCallFails()
{
// Arrange
var request = new UpdateMagicUrlSessionRequest()
{
UserId = "user123",
Secret = "validSecret"
};

_mockHttp.Expect(HttpMethod.Put, $"{Constants.Endpoint}/account/sessions/magic-url")
.ExpectedHeaders()
.WithJsonContent(request)
.Respond(HttpStatusCode.BadRequest, Constants.AppJson, Constants.AppwriteError);

// Act
var result = await _appwriteServer.Account.UpdateMagicUrlSession(request);

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

[Fact]
public async Task UpdateMagicUrlSession_ShouldReturnErrorResponse_WhenExceptionOccurs()
{
// Arrange
var request = new UpdateMagicUrlSessionRequest()
{
UserId = "user123",
Secret = "validSecret"
};

_mockHttp.Expect(HttpMethod.Put, $"{Constants.Endpoint}/account/sessions/magic-url")
.ExpectedHeaders()
.WithJsonContent(request)
.Throw(new HttpRequestException("An error occurred"));

// Act
var result = await _appwriteServer.Account.UpdateMagicUrlSession(request);

// Assert
Assert.False(result.Success);
Assert.True(result.IsInternalError);
Assert.Equal("An error occurred", result.Result.AsT2.Message);
}
}
Loading

0 comments on commit 222af46

Please sign in to comment.