Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dashboard for submitted papers #16

Merged
merged 4 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using PaperBoy.ContentStore.Domain;
using PaperBoy.ContentStore.Domain.Commands;

namespace PaperBoy.ContentStore.Application.CommandHandlers;

/// <summary>
/// Handler for approving a paper.
/// </summary>
/// <param name="paperRepository">The repository for accessing paper data.</param>
public class ApprovePaperCommandHandler(IPaperRepository paperRepository)
{
/// <summary>
/// Executes the command to approve a paper.
/// </summary>
/// <param name="command">The command containing the paper ID.</param>
/// <exception cref="PaperNotFoundException">Thrown when the paper with the specified ID is not found.</exception>
public async Task ExecuteAsync(ApprovePaperCommand command)
{
var paper = await paperRepository.GetByIdAsync(command.PaperId);

if (paper == null)
{
throw new PaperNotFoundException($"Paper with id {command.PaperId} not found.");
}

paper.Approve(command);

await paperRepository.SaveAsync(paper);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using PaperBoy.ContentStore.Domain;
using PaperBoy.ContentStore.Shared;

namespace PaperBoy.ContentStore.Application.Projections;

public interface IPaperInfoRepository
{
Task<PaperInfo?> GetByIdAsync(Guid id);
Task<PagedResult<PaperInfo>> GetAllAsync(int page, int pageSize);
}
Task<PagedResult<PaperInfo>> GetPendingAsync(int page, int pageSize);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public PaperInfoProjection()
Project<PageSummaryGeneratedEvent>(OnPageSummaryGenerated);
Project<SummaryGeneratedEvent>(OnPaperSummarized);
Project<ScoreGeneratedEvent>(OnPaperScored);
Project<PaperDeclinedEvent>(OnPaperDeclined);
Project<PaperApprovedEvent>(OnPaperApproved);
}

private void OnPaperScored(ScoreGeneratedEvent @event, IDocumentOperations operations)
Expand Down Expand Up @@ -56,4 +58,22 @@ private void OnPaperImported(PaperImportedEvent @event, IDocumentOperations oper

operations.Insert(paperInfo);
}
}

private void OnPaperDeclined(PaperDeclinedEvent @event, IDocumentOperations operations)
{
var paperInfo = operations.Load<PaperInfo>(@event.PaperId)!;

paperInfo.Status = Domain.PaperStatus.Declined;

operations.Update(paperInfo);
}

private void OnPaperApproved(PaperApprovedEvent @event, IDocumentOperations operations)
{
var paperInfo = operations.Load<PaperInfo>(@event.PaperId)!;

paperInfo.Status = Domain.PaperStatus.Approved;

operations.Update(paperInfo);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace PaperBoy.ContentStore.Domain.Commands;

public record ApprovePaperCommand(Guid PaperId);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace PaperBoy.ContentStore.Domain.Events;

public record PaperApprovedEvent(Guid PaperId);
20 changes: 18 additions & 2 deletions apps/contentstore/PaperBoy.ContentStore/Domain/Paper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,15 @@ public void Decline(DeclinePaperCommand cmd)
EmitDomainEvent(new PaperDeclinedEvent(cmd.PaperId));
}

/// <summary>
/// Approves the paper because it is suitable for the audience.
/// </summary>
/// <param name="cmd">Command data to use for approving the paper.</param>
public void Approve(ApprovePaperCommand cmd)
{
EmitDomainEvent(new PaperApprovedEvent(cmd.PaperId));
}

protected override bool TryApplyDomainEvent(object domainEvent)
{
switch (domainEvent)
Expand All @@ -159,6 +168,9 @@ protected override bool TryApplyDomainEvent(object domainEvent)
case PaperDeclinedEvent paperDeclinedEvent:
Apply(paperDeclinedEvent);
break;
case PaperApprovedEvent paperApprovedEvent:
Apply(paperApprovedEvent);
break;
}

return true;
Expand Down Expand Up @@ -214,5 +226,9 @@ private void Apply(PaperImportedEvent paperImportedEvent)
Version++;
}


}
private void Apply(PaperApprovedEvent paperApprovedEvent)
{
Status = PaperStatus.Approved;
Version++;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Marten;
using PaperBoy.ContentStore.Application.Projections;
using PaperBoy.ContentStore.Domain;
using PaperBoy.ContentStore.Shared;

namespace PaperBoy.ContentStore.Infrastructure;

Expand All @@ -9,13 +11,31 @@ public async Task<PagedResult<PaperInfo>> GetAllAsync(int page, int pageSize)
{
var session = store.LightweightSession();
var count = await session.Query<PaperInfo>().CountAsync();
var results = await session.Query<PaperInfo>().OrderBy(x => x.DateCreated).Skip(page * pageSize).Take(pageSize).ToListAsync();

var results = await session.Query<PaperInfo>()
.OrderBy(x => x.DateCreated)
.Skip(page * pageSize)
.Take(pageSize)
.ToListAsync();

return new PagedResult<PaperInfo>(results, page, pageSize, count);
}

public Task<PaperInfo?> GetByIdAsync(Guid id)
public async Task<PagedResult<PaperInfo>> GetPendingAsync(int page, int pageSize)
{
throw new NotImplementedException();
var session = store.LightweightSession();
var count = await session.Query<PaperInfo>().CountAsync();

var results = await session.Query<PaperInfo>()
.Where(x =>
x.Status == PaperStatus.Imported ||
x.Status == PaperStatus.Summarized ||
x.Status == PaperStatus.Scored)
.OrderBy(x => x.DateCreated)
.Skip(page * pageSize)
.Take(pageSize)
.ToListAsync();

return new PagedResult<PaperInfo>(results, page, pageSize, count);
}
}
85 changes: 56 additions & 29 deletions apps/contentstore/PaperBoy.ContentStore/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using PaperBoy.ContentStore.Domain.Commands;
using PaperBoy.ContentStore.Infrastructure;
using PaperBoy.ContentStore.Requests;
using PaperBoy.ContentStore.Responses;
using Weasel.Core;

var builder = WebApplication.CreateBuilder(args);
Expand All @@ -33,6 +32,7 @@
builder.Services.AddScoped<SubmitPageSummaryCommandHandler>();
builder.Services.AddScoped<SubmitDescriptionCommandHandler>();
builder.Services.AddScoped<DeclinePaperCommandHandler>();
builder.Services.AddScoped<ApprovePaperCommandHandler>();

var app = builder.Build();

Expand All @@ -45,21 +45,22 @@
return Results.Accepted();
});

app.MapPut("/papers/{paperId}/summary", async (Guid paperId, SubmitPaperSummaryRequest request, SubmitSummaryCommandHandler commandHandler) =>
{
try
app.MapPut("/papers/{paperId}/summary",
async (Guid paperId, SubmitPaperSummaryRequest request, SubmitSummaryCommandHandler commandHandler) =>
{
var updateSummaryCommand = new SubmitSummaryCommand(paperId, request.Summary);
try
{
var updateSummaryCommand = new SubmitSummaryCommand(paperId, request.Summary);

await commandHandler.ExecuteAsync(updateSummaryCommand);
await commandHandler.ExecuteAsync(updateSummaryCommand);

return Results.Accepted();
}
catch (PaperNotFoundException)
{
return Results.NotFound();
}
});
return Results.Accepted();
}
catch (PaperNotFoundException)
{
return Results.NotFound();
}
});

app.MapPut("/papers/{paperId}/pages/{pageNumber}/summary", async (Guid paperId, int pageNumber,
SubmitPageSummaryRequest request, SubmitPageSummaryCommandHandler commandHandler) =>
Expand All @@ -78,13 +79,31 @@
}
});

app.MapPut("/papers/{paperId}/score", async (Guid paperId, SubmitPaperScoreRequest request, SubmitScoreCommandHandler commandHandler) =>
app.MapPut("/papers/{paperId}/score",
async (Guid paperId, SubmitPaperScoreRequest request, SubmitScoreCommandHandler commandHandler) =>
{
try
{
var submitScoreCommand = new SubmitScoreCommand(paperId, request.Score, request.Explanation);

await commandHandler.ExecuteAsync(submitScoreCommand);

return Results.Accepted();
}
catch (PaperNotFoundException)
{
return Results.NotFound();
}
});

app.MapPut("/papers/{paperId}/description", async (Guid paperId, SubmitPaperDescriptionRequest request,
SubmitDescriptionCommandHandler commandHandler) =>
{
try
{
var submitScoreCommand = new SubmitScoreCommand(paperId, request.Score, request.Explanation);
var submitDescriptionCommand = new SubmitDescriptionCommand(paperId, request.Description);

await commandHandler.ExecuteAsync(submitScoreCommand);
await commandHandler.ExecuteAsync(submitDescriptionCommand);

return Results.Accepted();
}
Expand All @@ -94,14 +113,11 @@
}
});

app.MapPut("/papers/{paperId}/description", async (Guid paperId, SubmitPaperDescriptionRequest request, SubmitDescriptionCommandHandler commandHandler) =>
app.MapPost("/papers/{paperId}/decline", async (Guid paperId, DeclinePaperCommandHandler commandHandler) =>
{
try
{
var submitDescriptionCommand = new SubmitDescriptionCommand(paperId, request.Description);

await commandHandler.ExecuteAsync(submitDescriptionCommand);

await commandHandler.ExecuteAsync(new DeclinePaperCommand(paperId));
return Results.Accepted();
}
catch (PaperNotFoundException)
Expand All @@ -110,11 +126,11 @@
}
});

app.MapPost("/papers/{paperId}/decline", async (Guid paperId, DeclinePaperCommandHandler commandHandler) =>
app.MapPost("/papers/{paperId}/approve", async (Guid paperId, ApprovePaperCommandHandler commandHandler) =>
{
try
{
await commandHandler.ExecuteAsync(new DeclinePaperCommand(paperId));
await commandHandler.ExecuteAsync(new ApprovePaperCommand(paperId));
return Results.Accepted();
}
catch (PaperNotFoundException)
Expand Down Expand Up @@ -147,12 +163,23 @@
return Results.Ok(paper);
});

app.MapGet("/papers", async (IPaperInfoRepository paperInfoRepository, [FromQuery] int page = 0) =>
{
var papers = await paperInfoRepository.GetAllAsync(page, 20);
return Results.Ok(papers);
});
app.MapGet("/papers/all",
async (IPaperInfoRepository paperInfoRepository, [FromQuery] int page = 0) =>
{
var papers = await paperInfoRepository.GetAllAsync(page, 20);

return Results.Ok(papers);
});

app.MapGet("/papers/pending",
async (IPaperInfoRepository paperInfoRepository, [FromQuery] int page = 0) =>
{
var papers = await paperInfoRepository.GetPendingAsync(page, 20);

return Results.Ok(papers);
});


app.MapDefaultEndpoints();

app.Run();
app.Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using PaperBoy.ContentStore.Application.Projections;

namespace PaperBoy.ContentStore.Responses;

/// <summary>
/// Represents the response for retrieving a list of papers with pagination.
/// </summary>
/// <param name="Items">The list of papers.</param>
/// <param name="Page">The current page number.</param>
/// <param name="PageSize">The number of items per page.</param>
/// <param name="TotalCount">The total number of items.</param>
public record GetPapersResponse(IEnumerable<PaperInfo> Items, int Page, int PageSize, int TotalCount);
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace PaperBoy.ContentStore.Application.Projections;
namespace PaperBoy.ContentStore.Shared;

public record PagedResult<T>(IEnumerable<T> Items, int Page, int PageSize, int TotalCount);
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Dapr.Client;

namespace PaperBoy.Dashboard.Clients.ContentStore;

public interface IContentStoreClient
{
Task<PagedResult<PaperInfo>> GetPendingPapersAsync(PaperStatus[] statuses, int pageIndex);
}

public class ContentStoreClient(DaprClient daprClient) : IContentStoreClient
{
public async Task<PagedResult<PaperInfo>> GetPendingPapersAsync(PaperStatus[] statuses, int pageIndex)
{
var statusFilter = string.Join(",", statuses.Select(x => x.ToString()));

return await daprClient.InvokeMethodAsync<PagedResult<PaperInfo>>(HttpMethod.Get, "contentstore",
"/papers/pending");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace PaperBoy.Dashboard.Clients.ContentStore;

public record PagedResult<T>(IEnumerable<T> Items, int Page, int PageSize, int TotalCount)
{
public bool HasPreviousPage => Page > 0;
public bool HasNextPage => (Page + 1) * PageSize < TotalCount;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace PaperBoy.Dashboard.Clients.ContentStore
{
public class PaperInfo
{
public Guid Id { get; set; }
public string Title { get; set; } = default!;
public SubmitterInformation Submitter { get; set; } = default!;
public string Url { get; set; } = default!;
public PaperStatus Status { get; set; } = default!;
public int SectionsSummarized { get; set; }
public int TotalSections { get; set; }
}

public class SubmitterInformation
{
public string Name { get; set; } = default!;
public string EmailAddress { get; set; } = default!;
}

public enum PaperStatus
{
Imported,
Summarized,
Scored,
Approved,
Declined,
ReadyForPublication
}
}
Loading
Loading