Skip to content

Commit

Permalink
feat(Groups): add creatorNameIdentifier and createDate parameters to …
Browse files Browse the repository at this point in the history
…group model (#181)

Co-authored-by: Lilian Delouvy <[email protected]>
  • Loading branch information
lilian-delouvy and lilian-delouvy-axa authored Mar 22, 2022
1 parent f92980e commit 0a9621b
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 76 deletions.
8 changes: 5 additions & 3 deletions docker/initBase.sql
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ BEGIN
CREATE TABLE [sch_ECOTAG].[T_Group](
[GRP_Id] uniqueidentifier NOT NULL DEFAULT newid(),
[GRP_Name] [varchar](16) NOT NULL,
[GRP_CreatorNameIdentifier] [varchar](32) NOT NULL,
[GRP_CreateDate] BIGINT NOT NULL,
CONSTRAINT [PK_T_Group] UNIQUE([GRP_Id]),
CONSTRAINT [PK_T_Group_Name] UNIQUE([GRP_Name]),
)
Expand Down Expand Up @@ -186,9 +188,9 @@ INSERT INTO [sch_ECOTAG].[T_User]([USR_Id],[USR_Email],[USR_Subject]) VALUES (@f
INSERT INTO [sch_ECOTAG].[T_User]([USR_Id],[USR_Email],[USR_Subject]) VALUES (@secondUserId,"[email protected]","S222222")
INSERT INTO [sch_ECOTAG].[T_User]([USR_Id],[USR_Email],[USR_Subject]) VALUES (@thirdUserId,"[email protected]","S333333")

INSERT INTO [sch_ECOTAG].[T_Group]([GRP_Id],[GRP_Name]) VALUES (@firstGroupId, "firstgroup")
INSERT INTO [sch_ECOTAG].[T_Group]([GRP_Id],[GRP_Name]) VALUES (@secondGroupId, "secondgroup")
INSERT INTO [sch_ECOTAG].[T_Group]([GRP_Id],[GRP_Name]) VALUES (@thirdGroupId, "thirdgroup")
INSERT INTO [sch_ECOTAG].[T_Group]([GRP_Id],[GRP_Name],[GRP_CREATORNAMEIDENTIFIER],[GRP_CREATEDATE]) VALUES (@firstGroupId, "firstgroup", "S111111", 637831187822285511)
INSERT INTO [sch_ECOTAG].[T_Group]([GRP_Id],[GRP_Name],[GRP_CREATORNAMEIDENTIFIER],[GRP_CREATEDATE]) VALUES (@secondGroupId, "secondgroup", "S111111", 637831187625235412)
INSERT INTO [sch_ECOTAG].[T_Group]([GRP_Id],[GRP_Name],[GRP_CREATORNAMEIDENTIFIER],[GRP_CREATEDATE]) VALUES (@thirdGroupId, "thirdgroup", "S222222", 637831187822285511)

INSERT INTO [sch_ECOTAG].[T_GroupUsers]([GPU_Id],[GRP_Id],[USR_Id]) VALUES (newid(), @firstGroupId, @firstUserId)
INSERT INTO [sch_ECOTAG].[T_GroupUsers]([GPU_Id],[GRP_Id],[USR_Id]) VALUES (newid(), @firstGroupId, @secondUserId)
Expand Down
34 changes: 32 additions & 2 deletions src/Ml.Cli.WebApp/Server/Groups/Cmd/CreateGroupCmd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,46 @@
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Ml.Cli.WebApp.Server.Groups.Database.Group;
using Ml.Cli.WebApp.Server.Groups.Database.Users;

namespace Ml.Cli.WebApp.Server.Groups.Cmd;

public record GroupInput
{
[MaxLength(16)]
[MinLength(3)]
[RegularExpression(@"^[a-zA-Z0-9-_]*$")]
public string Name { get; set; }

public List<string> UserIds { get; set; }
}

public record CreateGroupInput
{
[MaxLength(16)]
[MinLength(3)]
[RegularExpression(@"^[a-zA-Z0-9-_]*$")]
public string Name { get; set; }

[MaxLength(32)]
[MinLength(1)]
public string CreatorNameIdentifier { get; set; }

public List<string> UserIds { get; set; }
}

public class CreateGroupCmd
{
public const string InvalidModel = "InvalidModel";
public const string UserNotFound = "UserNotFound";

private readonly IGroupsRepository _groupsRepository;
private readonly IUsersRepository _usersRepository;

public CreateGroupCmd(IGroupsRepository groupsRepository)
public CreateGroupCmd(IGroupsRepository groupsRepository, IUsersRepository usersRepository)
{
_groupsRepository = groupsRepository;
_usersRepository = usersRepository;
}

public async Task<ResultWithError<string, ErrorResult>> ExecuteAsync(CreateGroupInput createGroupInput)
Expand All @@ -39,8 +58,19 @@ public async Task<ResultWithError<string, ErrorResult>> ExecuteAsync(CreateGroup
};
return commandResult;
}

var user = await _usersRepository.GetUserBySubjectAsync(createGroupInput.CreatorNameIdentifier);
if (user == null)
{
commandResult.Error = new ErrorResult
{
Key = UserNotFound,
Error = null
};
return commandResult;
}

var result = await _groupsRepository.CreateGroupAsync(createGroupInput.Name.ToLower());
var result = await _groupsRepository.CreateGroupAsync(createGroupInput);
if (!result.IsSuccess)
{
commandResult.Error = result.Error;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ public class GroupDataModel
{
public string Id { get; set; }
public string Name { get; set; }

public long CreateDate { get; set; }
public IList<string> UserIds { get; set; }
}
11 changes: 10 additions & 1 deletion src/Ml.Cli.WebApp/Server/Groups/Database/Group/GroupModel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
Expand All @@ -18,5 +19,13 @@ public class GroupModel
[MinLength(3)]
public string Name { get; set; }

[Column("GRP_CreatorNameIdentifier")]
[MaxLength(32)]
[MinLength(1)]
public string CreatorNameIdentifier { get; set; }

[Column("GRP_CreateDate")]
public long CreateDate { get; set; }

public List<GroupUsersModel> GroupUsers { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Ml.Cli.WebApp.Server.Groups.Cmd;
using Ml.Cli.WebApp.Server.Groups.Database.GroupUsers;

namespace Ml.Cli.WebApp.Server.Groups.Database.Group;
Expand Down Expand Up @@ -61,12 +61,14 @@ public async Task<GroupDataModel> GetGroupByNameAsync(string name)
return group?.ToGroupDataModel();
}

public async Task<ResultWithError<string, ErrorResult>> CreateGroupAsync(string groupName)
public async Task<ResultWithError<string, ErrorResult>> CreateGroupAsync(CreateGroupInput group)
{
var commandResult = new ResultWithError<string, ErrorResult>();
var groupModel = new GroupModel
{
Name = groupName
Name = group.Name.ToLower(),
CreatorNameIdentifier = group.CreatorNameIdentifier,
CreateDate = DateTime.Now.Ticks
};
var result = _groupsContext.Groups.AddIfNotExists(groupModel, group => group.Name == groupModel.Name);
if (result == null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Ml.Cli.WebApp.Server.Groups.Cmd;

namespace Ml.Cli.WebApp.Server.Groups.Database.Group;

public interface IGroupsRepository
{
Task<List<GroupDataModel>> GetAllGroupsAsync(bool? mine, IList<string> groupIds);

Task<ResultWithError<string, ErrorResult>> CreateGroupAsync(string groupName);
Task<ResultWithError<string, ErrorResult>> CreateGroupAsync(CreateGroupInput group);

Task<GroupDataModel> GetGroupAsync(string id);

Expand Down
10 changes: 8 additions & 2 deletions src/Ml.Cli.WebApp/Server/Groups/GroupsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,15 @@ public async Task<ActionResult<GroupDataModel>> GetGroup([FromServices]GetGroupC
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize(Roles = Roles.DataAdministateur)]
public async Task<ActionResult<string>> Create([FromServices]CreateGroupCmd createGroupCmd, CreateGroupInput createGroupInput)
public async Task<ActionResult<string>> Create([FromServices]CreateGroupCmd createGroupCmd, GroupInput groupInput)
{
var commandResult = await createGroupCmd.ExecuteAsync(createGroupInput);
var nameIdentifier = User.Identity.GetSubject();
var commandResult = await createGroupCmd.ExecuteAsync(new CreateGroupInput()
{
Name = groupInput.Name,
UserIds = groupInput.UserIds,
CreatorNameIdentifier = nameIdentifier
});
if (!commandResult.IsSuccess)
{
return BadRequest(commandResult.Error);
Expand Down
114 changes: 114 additions & 0 deletions tests/Ml.Cli.WebApp.Tests/Server/Groups/CreateGroupShould.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using Ml.Cli.WebApp.Server;
using Ml.Cli.WebApp.Server.Database.Users;
using Ml.Cli.WebApp.Server.Groups;
using Ml.Cli.WebApp.Server.Groups.Cmd;
using Ml.Cli.WebApp.Server.Groups.Database;
using Ml.Cli.WebApp.Server.Groups.Database.Group;
using Ml.Cli.WebApp.Server.Oidc;
using Xunit;

namespace Ml.Cli.WebApp.Tests.Server.Groups;

public class CreateGroupShould

{
public static GroupContext GetInMemoryGroupContext()
{
var builder = new DbContextOptionsBuilder<GroupContext>();
var databaseName = Guid.NewGuid().ToString();
builder.UseInMemoryDatabase(databaseName);

var options = builder.Options;
var groupContext = new GroupContext(options);
groupContext.Database.EnsureCreated();
groupContext.Database.EnsureCreatedAsync();
return groupContext;
}

[Theory]
[InlineData("newGroup", "s666666")]
public async Task CreateGroup(string name, string nameIdentifier)
{
var result = await InitMockAndExecuteAsync(name, nameIdentifier);

var resultOk = result.Result as CreatedResult;
Assert.NotNull(resultOk);
var resultValue = resultOk.Value as string;
Assert.NotNull(resultValue);
}

[Theory]
[InlineData("a", "s666666", CreateGroupCmd.InvalidModel)]
[InlineData("too_long_group_name", "s666666", CreateGroupCmd.InvalidModel)]
[InlineData("abd$", "s666666", CreateGroupCmd.InvalidModel)]
[InlineData("abcdef(", "s666666", CreateGroupCmd.InvalidModel)]
[InlineData("group1", "s666666", GroupsRepository.AlreadyTakenName)]
[InlineData("newGroup", "s111111", CreateGroupCmd.UserNotFound)]
public async Task ReturnError_WhenCreateGroup(string name, string nameIdentifier, string errorKey)
{
var result = await InitMockAndExecuteAsync(name, nameIdentifier);

var resultWithError = result.Result as BadRequestObjectResult;
Assert.NotNull(resultWithError);
var resultWithErrorValue = resultWithError.Value as ErrorResult;
Assert.Equal(errorKey, resultWithErrorValue?.Key);
}

private static async Task<ActionResult<string>> InitMockAndExecuteAsync(string name, string nameIdentifier)
{
var (groupsRepository, usersRepository, groupsController, context) = await InitMockAsync(nameIdentifier);

groupsController.ControllerContext = new ControllerContext
{
HttpContext = context
};
var createGroupCmd = new CreateGroupCmd(groupsRepository, usersRepository);
var result = await groupsController.Create(createGroupCmd, new GroupInput()
{
Name = name,
UserIds = new List<string>()
});
return result;
}

public static async Task<(GroupsRepository groupsRepository, UsersRepository usersRepository, GroupsController groupsController, DefaultHttpContext context)> InitMockAsync(
string nameIdentifier)
{
var groupContext = GetInMemoryGroupContext();

var group1 = new GroupModel() { Name = "group1" };
var group2 = new GroupModel() { Name = "group2" };
groupContext.Add(group1);
groupContext.Add(group2);
await groupContext.SaveChangesAsync();

var user1 = new UserModel { Email = "[email protected]", Subject = "s666666" };
var user2 = new UserModel { Email = "[email protected]", Subject = "s666667" };
groupContext.Users.Add(user1);
groupContext.Users.Add(user2);
await groupContext.SaveChangesAsync();

var memoryCache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
var usersRepository = new UsersRepository(groupContext, memoryCache);
var groupsRepository = new GroupsRepository(groupContext, null);
var groupsController = new GroupsController();

var context = new DefaultHttpContext()
{
User = new ClaimsPrincipal(new ClaimsIdentity(new[]
{
new Claim(IdentityExtensions.EcotagClaimTypes.NameIdentifier, nameIdentifier)
}))
};
return (groupsRepository, usersRepository, groupsController, context);
}
}
63 changes: 0 additions & 63 deletions tests/Ml.Cli.WebApp.Tests/Server/Groups/GroupsControllerShould.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,69 +50,6 @@ private static Mock<IServiceProvider> GetMockedServiceProvider(GroupContext grou
return serviceProvider;
}

public class CreateGroupTests
{
private static async Task<GroupContext> GetGroupContext(List<string> groupNamesArray)
{
var groupContext = GetInMemoryGroupContext();
if (groupNamesArray != null)
groupNamesArray.ForEach(current =>
groupContext.Groups.Add(new GroupModel { Id = Guid.NewGuid(), Name = current })
);
await groupContext.SaveChangesAsync();
return groupContext;
}

[Theory]
[InlineData("[]", "abc")]
[InlineData("[]", "abcdefgh")]
[InlineData("[]", "Abcd-dad")]
[InlineData("[]", "abdd_O")]
public async Task Should_Create_New_Group(string groupNamesInDatabase, string newGroupName)
{
var groupNamesArray = JsonConvert.DeserializeObject<List<string>>(groupNamesInDatabase);
var groupContext = await GetGroupContext(groupNamesArray);
var newGroup = new CreateGroupInput
{
Name = newGroupName
};
var serviceProvider = GetMockedServiceProvider(groupContext);
var repository = new GroupsRepository(groupContext, serviceProvider.Object);
var groupsController = new GroupsController();
var createGroupCmd = new CreateGroupCmd(repository);
var result = await groupsController.Create(createGroupCmd, newGroup);
var resultCreated = result.Result as CreatedResult;
Assert.NotNull(resultCreated);
}

[Theory]
[InlineData("[\"abcd\"]", "abcD", GroupsRepository.AlreadyTakenName)]
[InlineData("[]", "ab", CreateGroupCmd.InvalidModel)]
[InlineData("[]", "daizidosqdhuzqijodzqoazdjskqldz", CreateGroupCmd.InvalidModel)]
[InlineData("[]", "abd$", CreateGroupCmd.InvalidModel)]
[InlineData("[]", "abcdefghzoiqsdzqosqodz^", CreateGroupCmd.InvalidModel)]
[InlineData("[]", "P$", CreateGroupCmd.InvalidModel)]
[InlineData("[]", "zqdsqd(", CreateGroupCmd.InvalidModel)]
public async Task Should_Return_Error_On_New_Group_Creation(string groupNamesInDatabase, string groupName, string errorType)
{
var groupNamesArray = JsonConvert.DeserializeObject<List<string>>(groupNamesInDatabase);
var groupContext = await GetGroupContext(groupNamesArray);
var newGroup = new CreateGroupInput
{
Name = groupName
};
var serviceProvider = GetMockedServiceProvider(groupContext);
var repository = new GroupsRepository(groupContext, serviceProvider.Object);
var groupsController = new GroupsController();
var createGroupCmd = new CreateGroupCmd(repository);
var result = await groupsController.Create(createGroupCmd, newGroup);
var resultWithError = result.Result as BadRequestObjectResult;
Assert.NotNull(resultWithError);
var resultWithErrorValue = resultWithError.Value as ErrorResult;
Assert.Equal(errorType, resultWithErrorValue?.Key);
}
}

[Theory]
[InlineData("[\"firstGroupName\",\"secondGroupName\"]", "s666666")]
[InlineData("[]", "s666667")]
Expand Down

0 comments on commit 0a9621b

Please sign in to comment.