Skip to content

Commit

Permalink
Implement creating a user.
Browse files Browse the repository at this point in the history
  • Loading branch information
DiscoPYF committed Jul 5, 2020
1 parent a01e8bd commit 7f6a27c
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 3 deletions.
4 changes: 2 additions & 2 deletions arangodb-net-standard.Test/ApiClientTestFixtureBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ namespace ArangoDBNetStandardTest
{
public abstract class ApiClientTestFixtureBase : IDisposable, IAsyncLifetime
{
private List<string> _databases = new List<string>();
private List<string> _users = new List<string>();
protected readonly List<string> _databases = new List<string>();
protected readonly List<string> _users = new List<string>();

private readonly List<HttpApiTransport> _transports = new List<HttpApiTransport>();

Expand Down
44 changes: 44 additions & 0 deletions arangodb-net-standard.Test/UserApi/UserApiClientTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using ArangoDBNetStandard;
using ArangoDBNetStandard.UserApi;
using ArangoDBNetStandard.UserApi.Models;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using Xunit;
Expand Down Expand Up @@ -40,5 +42,47 @@ await _userClient.DeleteUserAsync(
Assert.NotNull(ex.ApiError.ErrorMessage);
Assert.Equal(1703, ex.ApiError.ErrorNum); // ERROR_USER_NOT_FOUND
}

[Fact]
public async Task PostUserAsync_ShouldSucceed()
{
PostUserResponse postResponse = await _userClient.PostUserAsync(
new PostUserBody()
{
User = _fixture.UsernameToCreate,
Passwd = "password",
Extra = new Dictionary<string, object>()
{
["somedata"] = "here"
}
});

Assert.False(postResponse.Error);
Assert.Equal(HttpStatusCode.Created, postResponse.Code);
Assert.Equal(_fixture.UsernameToCreate, postResponse.User);
Assert.True(postResponse.Active);
Assert.True(postResponse.Extra.ContainsKey("somedata"));
Assert.Equal("here", postResponse.Extra["somedata"].ToString());
}

[Fact]
public async Task PostUserAsync_ShouldThrow_WhenUserAlreadyExist()
{
var ex = await Assert.ThrowsAsync<ApiErrorException>(async () =>
await _userClient.PostUserAsync(new PostUserBody()
{
User = _fixture.UsernameExisting,
Passwd = "password",
Extra = new Dictionary<string, object>()
{
["somedata"] = "here"
}
}));

Assert.True(ex.ApiError.Error);
Assert.Equal(HttpStatusCode.Conflict, ex.ApiError.Code);
Assert.NotNull(ex.ApiError.ErrorMessage);
Assert.Equal(1702, ex.ApiError.ErrorNum); // ERROR_USER_DUPLICATE
}
}
}
15 changes: 14 additions & 1 deletion arangodb-net-standard.Test/UserApi/UserApiClientTestFixture.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using ArangoDBNetStandard;
using ArangoDBNetStandard.DatabaseApi.Models;
using System;
using System.Threading.Tasks;

namespace ArangoDBNetStandardTest.UserApi
Expand All @@ -13,10 +14,16 @@ public class UserApiClientTestFixture : ApiClientTestFixtureBase

public string UsernameToDelete { get; private set; }

public string UsernameToCreate { get; private set; }

public string UsernameExisting { get; private set; }

public UserApiClientTestFixture()
{
ArangoClient = GetArangoDBClient("_system");
UsernameToDelete = nameof(UserApiClientTestFixture);
UsernameToDelete = nameof(UserApiClientTestFixture) + "Delete";
UsernameToCreate = nameof(UserApiClientTestFixture) + "Post";
UsernameExisting = nameof(UserApiClientTestFixture) + "Existing";
}

public override async Task InitializeAsync()
Expand All @@ -30,8 +37,14 @@ public override async Task InitializeAsync()
new DatabaseUser()
{
Username = UsernameToDelete
},
new DatabaseUser()
{
Username = UsernameExisting
}
});

_users.Add(UsernameToCreate);
}
}
}
5 changes: 5 additions & 0 deletions arangodb-net-standard/ApiClientBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ public ApiClientBase(IApiClientSerialization serialization)
_serialization = serialization;
}

/// <summary>
/// Gets an <see cref="ApiErrorException"/> from the provided error response.
/// </summary>
/// <param name="response">The error response from ArangoDB.</param>
/// <returns></returns>
protected async Task<ApiErrorException> GetApiErrorException(IApiClientResponse response)
{
var stream = await response.Content.ReadAsStreamAsync();
Expand Down
8 changes: 8 additions & 0 deletions arangodb-net-standard/UserApi/IUserApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ namespace ArangoDBNetStandard.UserApi
/// </summary>
public interface IUserApiClient
{
/// <summary>
/// Create a new user. You need server access level Administrate
/// in order to execute this REST call.
/// </summary>
/// <param name="body">The request body containing the user information.</param>
/// <returns></returns>
Task<PostUserResponse> PostUserAsync(PostUserBody body);

Task<DeleteUserResponse> DeleteUserAsync(string username);
}
}
36 changes: 36 additions & 0 deletions arangodb-net-standard/UserApi/Models/PostUserBody.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.Generic;

namespace ArangoDBNetStandard.UserApi.Models
{
/// <summary>
/// Represents a request body to create a user.
/// </summary>
public class PostUserBody
{
/// <summary>
/// The name of the user.
/// </summary>
public string User { get; set; }

/// <summary>
/// The user password.
/// If no password is specified, the empty string will be used.
/// If you pass the special value ARANGODB_DEFAULT_ROOT_PASSWORD,
/// then the password will be set the value stored in the environment variable
/// ARANGODB_DEFAULT_ROOT_PASSWORD.
/// This can be used to pass an instance variable into ArangoDB.
/// </summary>
public string Passwd { get; set; }

/// <summary>
/// An optional flag that specifies whether the user is active.
/// If not specified, this will default to true.
/// </summary>
public bool? Active { get; set; }

/// <summary>
/// Optional object with arbitrary extra data about the user.
/// </summary>
public Dictionary<string, object> Extra { get; set; }
}
}
33 changes: 33 additions & 0 deletions arangodb-net-standard/UserApi/Models/PostUserResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Collections.Generic;
using System.Net;

namespace ArangoDBNetStandard.UserApi.Models
{
public class PostUserResponse
{
/// <summary>
/// The name of the user.
/// </summary>
public string User { get; set; }

/// <summary>
/// Whether the user is active.
/// </summary>
public bool Active { get; set; }

/// <summary>
/// Object with arbitrary extra data about the user.
/// </summary>
public Dictionary<string, object> Extra { get; set; }

/// <summary>
/// Indicates whether an error occurred (false in this case).
/// </summary>
public bool Error { get; set; }

/// <summary>
/// The HTTP status code.
/// </summary>
public HttpStatusCode Code { get; set; }
}
}
21 changes: 21 additions & 0 deletions arangodb-net-standard/UserApi/UserApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,27 @@ public UserApiClient(IApiClientTransport client, IApiClientSerialization seriali
_client = client;
}

/// <summary>
/// Create a new user. You need server access level Administrate
/// in order to execute this REST call.
/// </summary>
/// <exception cref="ApiErrorException">ArangoDB responded with an error.</exception>
/// <param name="body">The request body containing the user information.</param>
/// <returns></returns>
public async Task<PostUserResponse> PostUserAsync(PostUserBody body)
{
var content = GetContent(body, true, true);
using (var response = await _client.PostAsync(_userApiPath, content))
{
if (response.IsSuccessStatusCode)
{
var stream = await response.Content.ReadAsStreamAsync();
return DeserializeJsonFromStream<PostUserResponse>(stream);
}
throw await GetApiErrorException(response);
}
}

/// <summary>
/// Delete a user permanently.
/// You need Administrate for the server access level in order to execute this REST call.
Expand Down

0 comments on commit 7f6a27c

Please sign in to comment.