Skip to content

Commit

Permalink
Merge pull request #134 from PinguApps/101-create-email-password-session
Browse files Browse the repository at this point in the history
Implemented create email password session
  • Loading branch information
pingu2k4 authored Aug 11, 2024
2 parents 29b58d5 + d38786a commit 601e2e3
Show file tree
Hide file tree
Showing 9 changed files with 258 additions and 8 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
<!-- ![33 / 288](https://progress-bar.dev/33/?scale=288&suffix=%20/%20288&width=500) -->
![Server & Client - 33 / 288](https://img.shields.io/badge/Server_&_Client-33%20%2F%20288-red?style=for-the-badge)
<!-- ![34 / 288](https://progress-bar.dev/34/?scale=288&suffix=%20/%20288&width=500) -->
![Server & Client - 34 / 288](https://img.shields.io/badge/Server_&_Client-34%20%2F%20288-red?style=for-the-badge)

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

<!-- ![31 / 93](https://progress-bar.dev/31/?scale=93&suffix=%20/%2093&width=300) -->
![Client - 31 / 93](https://img.shields.io/badge/Client-31%20%2F%2093-red?style=for-the-badge)
<!-- ![32 / 93](https://progress-bar.dev/32/?scale=93&suffix=%20/%2093&width=300) -->
![Client - 32 / 93](https://img.shields.io/badge/Client-32%20%2F%2093-red?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
<!-- ![33 / 52](https://progress-bar.dev/33/?scale=52&suffix=%20/%2052&width=120) -->
![Account - 33 / 52](https://img.shields.io/badge/Account-33%20%2F%2052-yellow?style=for-the-badge)
<!-- ![34 / 52](https://progress-bar.dev/34/?scale=52&suffix=%20/%2052&width=120) -->
![Account - 34 / 52](https://img.shields.io/badge/Account-34%20%2F%2052-yellow?style=for-the-badge)

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

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

var result = await _accountApi.CreateEmailPasswordSession(request);

return result.GetApiResponse();
}
catch (Exception e)
{
return e.GetExceptionResponse<Session>();
}
}
}
9 changes: 9 additions & 0 deletions src/PinguApps.Appwrite.Client/Clients/IAccountClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -256,4 +256,13 @@ public interface IAccountClient
/// </summary>
/// <returns>The Session</returns>
Task<AppwriteResult<Session>> CreateAnonymousSession();

/// <summary>
/// <para>Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user.</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>
/// <para><see href="https://appwrite.io/docs/references/1.5.x/client-rest/account#createEmailPasswordSession">Appwrite Docs</see></para>
/// </summary>
/// <param name="request">The request</param>
/// <returns>The Session</returns>
Task<AppwriteResult<Session>> CreateEmailPasswordSession(CreateEmailPasswordSessionRequest 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 @@ -101,4 +101,7 @@ internal interface IAccountApi : IBaseApi

[Post("/account/sessions/anonymous")]
Task<IApiResponse<Session>> CreateAnonymousSession();

[Post("/account/sessions/email")]
Task<IApiResponse<Session>> CreateEmailPasswordSession(CreateEmailPasswordSessionRequest request);
}
6 changes: 5 additions & 1 deletion src/PinguApps.Appwrite.Playground/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ public async Task Run(string[] args)

Console.WriteLine(_client.Session);

var response = await _client.Account.CreateAnonymousSession();
var response = await _client.Account.CreateEmailPasswordSession(new Shared.Requests.CreateEmailPasswordSessionRequest
{
Email = "[email protected]",
Password = "password"
});

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

namespace PinguApps.Appwrite.Shared.Requests;

/// <summary>
/// The request for creating an email password session
/// </summary>
public class CreateEmailPasswordSessionRequest : BaseRequest<CreateEmailPasswordSessionRequest, CreateEmailPasswordSessionRequestValidator>
{
/// <summary>
/// User email
/// </summary>
[JsonPropertyName("email")]
public string Email { get; set; } = string.Empty;

/// <summary>
/// User password. Must be at least 8 chars
/// </summary>
[JsonPropertyName("password")]
public string Password { 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 CreateEmailPasswordSessionRequestValidator : AbstractValidator<CreateEmailPasswordSessionRequest>
{
public CreateEmailPasswordSessionRequestValidator()
{
RuleFor(x => x.Email).NotEmpty().EmailAddress();
RuleFor(x => x.Password).NotEmpty().MinimumLength(8).MaximumLength(256);
}
}
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 CreateEmailPasswordSession_ShouldReturnSuccess_WhenApiCallSucceeds()
{
// Arrange
var request = new CreateEmailPasswordSessionRequest()
{
Email = "[email protected]",
Password = "Password"
};

_mockHttp.Expect(HttpMethod.Post, $"{Constants.Endpoint}/account/sessions/email")
.ExpectedHeaders()
.WithJsonContent(request)
.Respond(Constants.AppJson, Constants.SessionResponse);

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

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

[Fact]
public async Task CreateEmailPasswordSession_ShouldHandleException_WhenApiCallFails()
{
// Arrange
var request = new CreateEmailPasswordSessionRequest()
{
Email = "[email protected]",
Password = "Password"
};

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

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

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

[Fact]
public async Task CreateEmailPasswordSession_ShouldReturnErrorResponse_WhenExceptionOccurs()
{
// Arrange
var request = new CreateEmailPasswordSessionRequest()
{
Email = "[email protected]",
Password = "Password"
};

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

// Act
var result = await _appwriteClient.Account.CreateEmailPasswordSession(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,107 @@
using FluentValidation;
using PinguApps.Appwrite.Shared.Requests;

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

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

[Theory]
[InlineData("[email protected]", "password123")]
[InlineData("[email protected]", "diffPassword")]
public void Properties_CanBeSet(string email, string password)
{
// Arrange
var request = new CreateEmailPasswordSessionRequest();

// Act
request.Email = email;
request.Password = password;

// Assert
Assert.Equal(email, request.Email);
Assert.Equal(password, request.Password);
}

[Theory]
[InlineData("[email protected]", "Password")]
public void IsValid_WithValidData_ReturnsTrue(string email, string password)
{
// Arrange
var request = new CreateEmailPasswordSessionRequest
{
Email = email,
Password = password
};

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

// Assert
Assert.True(isValid);
}

[Theory]
[InlineData(null, "Password")]
[InlineData("", "Password")]
[InlineData("not an email", "Password")]
[InlineData("[email protected]", null)]
[InlineData("[email protected]", "")]
[InlineData("[email protected]", "short")]
[InlineData("[email protected]", "A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. \", \"A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. A much longer string. ")]
public void IsValid_WithInvalidData_ReturnsFalse(string? email, string? password)
{
// Arrange
var request = new CreateEmailPasswordSessionRequest
{
Email = email!,
Password = password!
};

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

// Assert
Assert.False(isValid);
}

[Fact]
public void Validate_WithThrowOnFailuresTrue_ThrowsValidationExceptionOnFailure()
{
// Arrange
var request = new CreateEmailPasswordSessionRequest
{
Email = "not an email",
Password = "short"
};

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

[Fact]
public void Validate_WithThrowOnFailuresFalse_ReturnsInvalidResultOnFailure()
{
// Arrange
var request = new CreateEmailPasswordSessionRequest
{
Email = "not an email",
Password = "short"
};

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

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

0 comments on commit 601e2e3

Please sign in to comment.