Skip to content

Commit

Permalink
Make Separate Get Methods for Subentities (#47)
Browse files Browse the repository at this point in the history
* Add `EnrollmentDate` property to`StudentGroup`

* Introduce `StudentGroupViewDto`

* Add `IAssigningService.GetAssigningEntitiesPageAsync<TViewDto>`

* Implement `GetAssigningEntitiesPageAsync`

* Extend integration tests for assigning endpoints

* Fix tests

* Implement GET methods for assigned entities

* Enhance fake data generation for `StudentGroup`
  • Loading branch information
romandykyi authored Nov 26, 2023
1 parent 8f5655c commit 179335f
Show file tree
Hide file tree
Showing 18 changed files with 1,104 additions and 14 deletions.
5 changes: 5 additions & 0 deletions Core/Dtos/University/StudentGroupViewDto.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using EUniversity.Core.Dtos.Users;

namespace EUniversity.Core.Dtos.University;

public record StudentGroupViewDto(StudentPreviewDto Student, DateTimeOffset EnrollmentDate);
5 changes: 5 additions & 0 deletions Core/Models/University/StudentGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ public class StudentGroup : IEntity<int>
[Key]
public int Id { get; set; }

/// <summary>
/// Date when student was added to the group.
/// </summary>
public DateTimeOffset EnrollmentDate { get; set; }

/// <summary>
/// Foreign key of the associated student.
/// </summary>
Expand Down
17 changes: 16 additions & 1 deletion Core/Services/IAssigningService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Linq.Expressions;
using EUniversity.Core.Filters;
using EUniversity.Core.Pagination;
using System.Linq.Expressions;

namespace EUniversity.Core.Services;

Expand All @@ -25,6 +27,19 @@ public interface IAssigningService<TAssigningEntity, TId1, TId2>
/// </returns>
public Expression<Func<TAssigningEntity, bool>> AssigningEntityPredicate(TId1 id1, TId2 id2);

/// <summary>
/// Retrieves a page with assigning entities DTOs asynchronously.
/// </summary>
/// <param name="id1">ID of the entity for which assigned entities should be returned.</param>
/// <param name="properties"><see cref="PaginationProperties"/> object specifying pagination parameters.</param>
/// <param name="filter">An optional filter to apply.</param>
/// <returns>
/// A task that represents the asynchronous operation, containing
/// the page with assigning entities DTOs asynchronously.
/// </returns>
/// <typeparam name="TViewDto">A type of the DTO to which entities will be mapped.</typeparam>
public Task<Page<TViewDto>> GetAssigningEntitiesPageAsync<TViewDto>(TId1 id1, PaginationProperties properties, IFilter<TAssigningEntity>? filter = null);

/// <summary>
/// Adds the first entity to the second based on their IDs.
/// </summary>
Expand Down
32 changes: 32 additions & 0 deletions EUniversity/Controllers/University/GroupsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using EUniversity.Core.Policy;
using EUniversity.Core.Services;
using EUniversity.Core.Services.University;
using EUniversity.Infrastructure.Services.University;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
Expand Down Expand Up @@ -141,6 +142,37 @@ public async Task<IActionResult> DeleteGroupAsync([FromRoute] int id)
return result ? NoContent() : NotFound();
}

/// <summary>
/// Gets a page with all students that are part of the group with the given ID.
/// </summary>
/// <remarks>
/// If there is no items in the requested page, then empty page will be returned.
/// </remarks>
/// <response code="200">Returns requested page with students that are part of the group.</response>
/// <response code="400">Bad request</response>
/// <response code="401">Unauthorized user call</response>
/// <response code="404">Group does not exist</response>
[HttpGet]
[Route("{groupId:int}/students")]
[Authorize(Policies.Default)]
[ProducesResponseType(typeof(Page<StudentGroupViewDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetStudentsInGroupAsync(
[FromRoute] int groupId,
[FromQuery] PaginationProperties properties)
{
if (!await _existenceChecker.ExistsAsync<Group, int>(groupId))
{
return NotFound(
CustomResponses.NotFound("The group with the specified ID does not exist.",
HttpContext));
}
return Ok(await _studentGroupsService
.GetAssigningEntitiesPageAsync<StudentGroupViewDto>(groupId, properties));
}

/// <summary>
/// Adds a student to a group.
/// </summary>
Expand Down
31 changes: 31 additions & 0 deletions EUniversity/Controllers/University/SemestersController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SharpGrip.FluentValidation.AutoValidation.Mvc.Attributes;
using System.Text.RegularExpressions;

namespace EUniversity.Controllers.University;

Expand Down Expand Up @@ -141,6 +142,36 @@ public async Task<IActionResult> DeleteSemesterAsync([FromRoute] int id)
return result ? NoContent() : NotFound();
}

/// <summary>
/// Gets a page with all students related to the semester with the given ID.
/// </summary>
/// <remarks>
/// If there is no items in the requested page, then empty page will be returned.
/// </remarks>
/// <response code="200">Returns requested page with students related to the semester.</response>
/// <response code="400">Bad request</response>
/// <response code="401">Unauthorized user call</response>
[HttpGet]
[Route("{semesterId:int}/students")]
[Authorize(Policies.Default)]
[ProducesResponseType(typeof(Page<StudentSemesterViewDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetStudentsInSemesterAsync(
[FromRoute] int semesterId,
[FromQuery] PaginationProperties properties)
{
if (!await _existenceChecker.ExistsAsync<Semester, int>(semesterId))
{
return NotFound(
CustomResponses.NotFound("The semester with the specified ID does not exist.",
HttpContext));
}
return Ok(await _studentSemestersService
.GetAssigningEntitiesPageAsync<StudentSemesterViewDto>(semesterId, properties));
}

/// <summary>
/// Adds a student to a semester.
/// </summary>
Expand Down
Loading

0 comments on commit 179335f

Please sign in to comment.