Skip to content

Commit

Permalink
Merge pull request #11 from cowienduckie/dev
Browse files Browse the repository at this point in the history
feat: add interaction endpoints with Kanban board
  • Loading branch information
cowienduckie authored Nov 20, 2023
2 parents 5a58784 + 649005f commit 9cf6381
Show file tree
Hide file tree
Showing 45 changed files with 2,751 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

namespace GraphQl.CustomFilters;

public class EqualAndContainStringFilter : StringOperationFilterInputType
public class EqualOrContainStringFilter : StringOperationFilterInputType
{
protected override void Configure(IFilterInputTypeDescriptor descriptor)
{
descriptor.Operation(DefaultFilterOperations.Equals).Type<NonNullType<StringType>>();
descriptor.Operation(DefaultFilterOperations.Contains).Type<NonNullType<StringType>>();
descriptor.Operation(DefaultFilterOperations.Equals).Type<StringType>();
descriptor.Operation(DefaultFilterOperations.Contains).Type<StringType>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ protected override void Configure(IFilterInputTypeDescriptor<ActivityLogDto> des
{
descriptor.BindFieldsExplicitly();

descriptor.Field(t => t.Username).Type<EqualAndContainStringFilter>();
descriptor.Field(t => t.Username).Type<EqualOrContainStringFilter>();
descriptor.Field(t => t.Action).Type<EqualStringFilter>();
}
}
1 change: 0 additions & 1 deletion src/PersonalData/PersonalData.Api/Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.IdentityModel.Tokens.Jwt;
using Configuration.MassTransit;
using Configuration.OpenTelemetry;
using Configuration.OpenTelemetry.Behaviors;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ protected override void Configure(
{
descriptor.BindFieldsExplicitly();

descriptor.Field(t => t.FirstName).Type<EqualAndContainStringFilter>();
descriptor.Field(t => t.LastName).Type<EqualAndContainStringFilter>();
descriptor.Field(t => t.FirstName).Type<EqualOrContainStringFilter>();
descriptor.Field(t => t.LastName).Type<EqualOrContainStringFilter>();
descriptor.Field(t => t.UserStatus).Type<EqualIntFilter>();
}
}
6 changes: 5 additions & 1 deletion src/Portal/Portal.Api/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,11 @@ private static IServiceCollection AddCustomDbContext(this IServiceCollection ser

services.AddDbContext<PortalContext>(options =>
{
options.UseNpgsql(connString, opt => { opt.EnableRetryOnFailure(3); });
options.UseNpgsql(connString, o =>
{
o.EnableRetryOnFailure(3);
o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
});

options.EnableDetailedErrors();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Portal.Boundaries.GraphQL.Dtos.Sections;
using Portal.Boundaries.GraphQL.Dtos.Tasks;
using Portal.Domain;

namespace Portal.Boundaries.GraphQL.Dtos.Projects;

public class KanbanProjectDto
{
public string Id { get; set; } = default!;
public string Name { get; set; } = default!;
public string? Notes { get; set; }
public string Color { get; set; } = default!;
public DateTime? DueDate { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime? LastModifiedOn { get; set; }

public IReadOnlyDictionary<string, object> Tasks { get; set; } = default!;
public IReadOnlyDictionary<string, object> Columns { get; set; } = default!;

public List<string> ColumnOrder { get; set; } = default!;
}

public static partial class DtoConverter
{
public static KanbanProjectDto ToKanbanProjectDto(this Project project)
{
var columnOrder = project.Sections
.OrderBy(s => s.OrderIndex)
.Select(s => s.Id.ToString())
.ToList();

var tasks = project.Tasks
.Select(t => t.ToKanbanTaskDto())
.ToDictionary(t => t.Id, t => t as object);

var columns = project.Sections
.Select(s => s.ToKanbanSectionDto())
.ToDictionary(s => s.Id, t => t as object);

return new KanbanProjectDto
{
Id = project.Id.ToString(),
Name = project.Name,
Notes = project.Notes,
Color = project.Color,
DueDate = project.DueDate,
CreatedOn = project.CreatedOn,
LastModifiedOn = project.LastModifiedOn,

Tasks = tasks,
Columns = columns,

ColumnOrder = columnOrder
};
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Portal.Domain;

namespace Portal.Boundaries.GraphQL.Dtos;
namespace Portal.Boundaries.GraphQL.Dtos.Projects;

public class SimplifiedProjectDto
{
Expand All @@ -11,7 +11,7 @@ public class SimplifiedProjectDto
public DateTime? LastModifiedOn { get; set; }
}

public static class Converter
public static partial class DtoConverter
{
public static SimplifiedProjectDto ToSimplifiedProjectDto(this Project project)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Portal.Domain;

namespace Portal.Boundaries.GraphQL.Dtos.Sections;

public class KanbanSectionDto
{
public string Id { get; set; } = default!;
public string Name { get; set; } = default!;
public List<string> TaskIds { get; set; } = default!;
}

public static class DtoConverter
{
public static KanbanSectionDto ToKanbanSectionDto(this Section section)
{
var taskIds = section.Tasks.Select(t => t.Id.ToString()).ToList();

return new KanbanSectionDto
{
Id = section.Id.ToString(),
Name = section.Name,
TaskIds = taskIds
};
}
}
46 changes: 46 additions & 0 deletions src/Portal/Portal/Boundaries/GraphQL/Dtos/Tasks/KanbanTaskDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Task = Portal.Domain.Task;

namespace Portal.Boundaries.GraphQL.Dtos.Tasks;

public class KanbanTaskDto
{
public string Id { get; set; } = default!;
public string Name { get; set; } = default!;
public string? Notes { get; set; }

public bool IsCompleted { get; set; }
public DateTime? CompletedOn { get; set; }
public string? CompletedBy { get; set; }

public DateTime? StartOn { get; set; }
public DateTime? DueOn { get; set; }

public bool Liked { get; set; }
public int LikesCount { get; set; }

public string? Assignee { get; set; }

public string Column { get; set; } = default!;
}

public static class DtoConverter
{
public static KanbanTaskDto ToKanbanTaskDto(this Task task)
{
return new KanbanTaskDto
{
Id = task.Id.ToString(),
Name = task.Name,
Notes = task.Notes,
IsCompleted = task.Completed,
CompletedOn = task.CompletedOn,
CompletedBy = task.CompletedBy.ToString(),
StartOn = task.StartOn,
DueOn = task.DueOn,
Liked = task.Liked,
LikesCount = task.LikesCount,
Assignee = task.AssigneeId.ToString(),
Column = task.SectionId.ToString()
};
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using GraphQl.CustomFilters;
using HotChocolate.Data.Filters;
using Portal.Boundaries.GraphQL.Dtos;
using Portal.Boundaries.GraphQL.Dtos.Projects;

namespace Portal.Boundaries.GraphQL.Filters;

Expand All @@ -11,7 +11,7 @@ protected override void Configure(
{
descriptor.BindFieldsExplicitly();

descriptor.Field(t => t.Id).Type<EqualAndContainStringFilter>();
descriptor.Field(t => t.Name).Type<EqualAndContainStringFilter>();
descriptor.Field(t => t.Id).Type<EqualOrContainStringFilter>();
descriptor.Field(t => t.Name).Type<EqualOrContainStringFilter>();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using HotChocolate.Types;
using Portal.UseCases.Mutations;

namespace Portal.Boundaries.GraphQL.InputTypes;

public class UpdateKanbanProjectInputType : InputObjectType<UpdateKanbanProjectCommand>
{
protected override void Configure(IInputObjectTypeDescriptor<UpdateKanbanProjectCommand> descriptor)
{
descriptor.Field(x => x.Tasks).Type<AnyType>();
}
}
26 changes: 21 additions & 5 deletions src/Portal/Portal/Boundaries/GraphQL/Mutation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using HotChocolate;
using HotChocolate.Authorization;
using MediatR;
using Portal.Boundaries.GraphQL.InputTypes;
using Portal.Boundaries.GraphQL.ResponseTypes;
using Portal.UseCases.Mutations;
using Portal.UseCases.Responses;
Expand All @@ -14,12 +13,29 @@ namespace Portal.Boundaries.GraphQL;
public class Mutation
{
[GraphQLType(typeof(CreateProjectResponseType))]
[Authorize(AuthorizationPolicy.ADMIN_ACCESS)]
[Authorize(AuthorizationPolicy.ADMIN_MEMBER_ACCESS)]
public async Task<CreateProjectResponse> CreateProject(
[GraphQLType(typeof(CreateProjectInputType))]
CreateProjectCommand createProjectInput,
CreateProjectCommand input,
[Service] ISender mediator)
{
return await mediator.Send(createProjectInput);
return await mediator.Send(input);
}

[GraphQLType(typeof(UpdateKanbanProjectResponseType))]
[Authorize(AuthorizationPolicy.ADMIN_MEMBER_ACCESS)]
public async Task<UpdateKanbanProjectResponse> UpdateKanbanProject(
UpdateKanbanProjectCommand input,
[Service] ISender mediator)
{
return await mediator.Send(input);
}

[GraphQLType(typeof(CreateTaskResponseType))]
[Authorize(AuthorizationPolicy.ADMIN_MEMBER_ACCESS)]
public async Task<CreateTaskResponse> CreateTask(
CreateTaskCommand input,
[Service] ISender mediator)
{
return await mediator.Send(input);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using HotChocolate.Types;
using Portal.Boundaries.GraphQL.Dtos.Projects;

namespace Portal.Boundaries.GraphQL.ObjectTypes;

public class KanbanProjectType : ObjectType<KanbanProjectDto>
{
protected override void Configure(IObjectTypeDescriptor<KanbanProjectDto> descriptor)
{
descriptor.Field(x => x.Tasks).Type<AnyType>();
descriptor.Field(x => x.Columns).Type<AnyType>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using HotChocolate.Types;
using Portal.Boundaries.GraphQL.Dtos.Sections;

namespace Portal.Boundaries.GraphQL.ObjectTypes;

public class KanbanSectionType : ObjectType<KanbanSectionDto>
{
protected override void Configure(IObjectTypeDescriptor<KanbanSectionDto> descriptor)
{
}
}
11 changes: 11 additions & 0 deletions src/Portal/Portal/Boundaries/GraphQL/ObjectTypes/KanbanTaskType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using HotChocolate.Types;
using Portal.Boundaries.GraphQL.Dtos.Tasks;

namespace Portal.Boundaries.GraphQL.ObjectTypes;

public class KanbanTaskType : ObjectType<KanbanTaskDto>
{
protected override void Configure(IObjectTypeDescriptor<KanbanTaskDto> descriptor)
{
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using HotChocolate.Types;
using Portal.Boundaries.GraphQL.Dtos;
using Portal.Boundaries.GraphQL.Dtos.Projects;

namespace Portal.Boundaries.GraphQL.ObjectTypes;

Expand Down
12 changes: 11 additions & 1 deletion src/Portal/Portal/Boundaries/GraphQL/Query.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using HotChocolate.Data;
using HotChocolate.Types;
using MediatR;
using Portal.Boundaries.GraphQL.Dtos;
using Portal.Boundaries.GraphQL.Dtos.Projects;
using Portal.Boundaries.GraphQL.Filters;
using Portal.Boundaries.GraphQL.ObjectTypes;
using Portal.UseCases.Queries;
Expand All @@ -30,4 +30,14 @@ public async Task<IQueryable<SimplifiedProjectDto>> GetProjects([Service] ISende
{
return await mediator.Send(new GetProjectsQuery());
}

[GraphQLName("KanbanProject")]
[GraphQLType(typeof(KanbanProjectType))]
[Authorize(AuthorizationPolicy.ADMIN_MEMBER_ACCESS)]
public async Task<KanbanProjectDto?> GetKanbanProjectById(
GetKanbanProjectByIdQuery input,
[Service] ISender mediator)
{
return await mediator.Send(input);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using HotChocolate.Types;
using Portal.UseCases.Responses;

namespace Portal.Boundaries.GraphQL.ResponseTypes;

public class CreateTaskResponseType : ObjectType<CreateTaskResponse>
{
protected override void Configure(IObjectTypeDescriptor<CreateTaskResponse> descriptor)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using HotChocolate.Types;
using Portal.UseCases.Responses;

namespace Portal.Boundaries.GraphQL.ResponseTypes;

public class UpdateKanbanProjectResponseType : ObjectType<UpdateKanbanProjectResponse>
{
protected override void Configure(IObjectTypeDescriptor<UpdateKanbanProjectResponse> descriptor)
{
}
}
Loading

0 comments on commit 9cf6381

Please sign in to comment.