chore: removed everything related to instructions
This commit is contained in:
@@ -1,166 +0,0 @@
|
||||
using GamificationService.Exceptions.Services.Instruction;
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Models.DTO;
|
||||
using GamificationService.Models.Messages.Instructions;
|
||||
using GamificationService.Services.Instructions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace GamificationService.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize(Policy = "User")]
|
||||
public class InstructionController : ControllerBase
|
||||
{
|
||||
private readonly IInstructionService _instructionService;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly ILogger<InstructionController> _logger;
|
||||
|
||||
public InstructionController(IInstructionService instructionService, UserManager<ApplicationUser> userManager, ILogger<InstructionController> logger)
|
||||
{
|
||||
_instructionService = instructionService;
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instruction.
|
||||
/// </summary>
|
||||
/// <param name="model">The instruction model.</param>
|
||||
/// <returns><see cref="InstructionDTO"/> which was created</returns>
|
||||
/// <response code="200">Returns the created instruction</response>
|
||||
[HttpPost]
|
||||
[Authorize(Policy = "Admin")]
|
||||
public async Task<IActionResult> CreateInstruction([FromBody] CreateInstructionRequest model)
|
||||
{
|
||||
var instruction = await _instructionService.CreateInstruction(model);
|
||||
return Ok(instruction);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update an existing instruction.
|
||||
/// </summary>
|
||||
/// <param name="model">The instruction model. Id must match the object which is being updated.</param>
|
||||
/// <returns><see cref="bool"/></returns>
|
||||
/// <response code="200"></response>
|
||||
/// <response code="404">If the instruction is not found</response>
|
||||
[HttpPut]
|
||||
[Authorize(Policy = "Admin")]
|
||||
public async Task<IActionResult> UpdateInstruction([FromBody] UpdateInstructionRequest model)
|
||||
{
|
||||
var instruction = await _instructionService.UpdateInstructionById(model);
|
||||
return Ok(instruction);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete an existing instruction.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the instruction to delete.</param>
|
||||
/// <returns><see cref="bool"/></returns>
|
||||
/// <response code="200"></response>
|
||||
/// <response code="404">If the instruction is not found</response>
|
||||
[HttpDelete]
|
||||
[Authorize(Policy = "Admin")]
|
||||
public async Task<IActionResult> DeleteInstruction(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Ok(await _instructionService.DeleteInstructionById(id));
|
||||
}
|
||||
catch (InstructionNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve all instructions for the authenticated user.
|
||||
/// </summary>
|
||||
/// <returns>A list of <see cref="InstructionDTO"/> for the user.</returns>
|
||||
/// <response code="200">Returns the list of all instructions</response>
|
||||
[HttpGet("all")]
|
||||
public async Task<IActionResult> GetAllInstructions()
|
||||
{
|
||||
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||
|
||||
return Ok(_instructionService.GetAllInstructions(userId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve all completed instructions for the authenticated user.
|
||||
/// </summary>
|
||||
/// <returns>A list of <see cref="InstructionDTO"/> that are completed for the user.</returns>
|
||||
/// <response code="200">Returns the list of completed instructions</response>
|
||||
[HttpGet("completed")]
|
||||
public async Task<IActionResult> GetCompletedInstructions()
|
||||
{
|
||||
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||
|
||||
return Ok(_instructionService.GetCompletedInstructions(userId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve all unfinished instructions for the authenticated user.
|
||||
/// </summary>
|
||||
/// <returns>A list of <see cref="InstructionDTO"/> that are unfinished for the user.</returns>
|
||||
/// <response code="200">Returns the list of unfinished instructions</response>
|
||||
[HttpGet("unfinished")]
|
||||
public async Task<IActionResult> GetUnfinishedInstructions()
|
||||
{
|
||||
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||
|
||||
return Ok(_instructionService.GetUnfinishedInstructions(userId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve instructions by category ID for the authenticated user.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the category to filter instructions.</param>
|
||||
/// <returns>A list of <see cref="InstructionDTO"/> for the specified category.</returns>
|
||||
/// <response code="200">Returns the list of instructions for the specified category</response>
|
||||
/// <response code="404">If the category is not found</response>
|
||||
[HttpGet("category/{id}")]
|
||||
public async Task<IActionResult> GetInstructionsByCategoryId(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||
|
||||
return Ok(_instructionService.GetInstructionsByCategoryId(userId, id));
|
||||
}
|
||||
catch (CategoryNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a specific instruction by its ID for the authenticated user.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the instruction to retrieve.</param>
|
||||
/// <returns><see cref="InstructionDTO"/> for the specified instruction.</returns>
|
||||
/// <response code="200">Returns the instruction with the specified ID</response>
|
||||
/// <response code="404">If the instruction is not found</response>
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> GetInstructionById(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||
|
||||
return Ok(_instructionService.GetInstructionById(userId, id));
|
||||
}
|
||||
catch(InstructionNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,278 +0,0 @@
|
||||
using AutoMapper;
|
||||
using GamificationService.Exceptions.Services.Instruction;
|
||||
using GamificationService.Exceptions.Services.InstructionTest;
|
||||
using GamificationService.Models.BasicResponses;
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Models.DTO;
|
||||
using GamificationService.Services.InstructionTests;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace GamificationService.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize(Policy = "User")]
|
||||
public class InstructionTestController : ControllerBase
|
||||
{
|
||||
private readonly IInstructionTestsService _instructionTestsService;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly ILogger<InstructionTestController> _logger;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public InstructionTestController(IInstructionTestsService instructionTestsService, UserManager<ApplicationUser> userManager, ILogger<InstructionTestController> logger, IMapper mapper)
|
||||
{
|
||||
_instructionTestsService = instructionTestsService;
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an instruction test by its ID.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the instruction test.</param>
|
||||
/// <returns>An <see cref="InstructionTestDTO"/> containing the instruction test DTO if found, or a 404 Not Found if not found.</returns>
|
||||
/// <response code="200">Returns the instruction test DTO</response>
|
||||
/// <response code="404">If the instruction test is not found</response>
|
||||
[HttpGet("{id}")]
|
||||
public IActionResult GetInstructionTestById(long id)
|
||||
{
|
||||
// TODO: verify admin access / user ownership
|
||||
try
|
||||
{
|
||||
var instructionTest = _instructionTestsService.GetInstructionTestById(id);
|
||||
return Ok(_mapper.Map<InstructionTestDTO>(instructionTest));
|
||||
}
|
||||
catch (InstructionTestNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an instruction test by its instruction ID.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the instruction.</param>
|
||||
/// <returns>An <see cref="InstructionTestDTO"/> containing the instruction test DTO if found, or a 404 Not Found if not found.</returns>
|
||||
/// <response code="200">Returns the instruction test DTO</response>
|
||||
/// <response code="404">If the instruction is not found</response>
|
||||
[HttpGet("instruction/{id}")]
|
||||
public IActionResult GetInstructionTestsByInstructionId(long id)
|
||||
{
|
||||
// TODO: verify admin access / user ownership
|
||||
try
|
||||
{
|
||||
var instructionTest = _instructionTestsService.GetInstructionTestsByInstructionId(id);
|
||||
return Ok(_mapper.Map<InstructionTestDTO>(instructionTest));
|
||||
}
|
||||
catch (InstructionTestNotFoundException)
|
||||
{
|
||||
return Ok(new List<InstructionTestDTO>());
|
||||
}
|
||||
catch (InstructionNotFoundException)
|
||||
{
|
||||
return NotFound(new BasicResponse()
|
||||
{
|
||||
Code = 404,
|
||||
Message = "Instruction not found"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all instruction test questions by instruction test ID.
|
||||
/// </summary>
|
||||
/// <param name="instructionTestId">The ID of the instruction test.</param>
|
||||
/// <returns>A list of <see cref="InstructionTestQuestionDTO"/> containing the instruction test questions if found, or a 404 Not Found if not found.</returns>
|
||||
/// <response code="200">Returns the instruction test questions</response>
|
||||
/// <response code="404">If the instruction test questions are not found</response>
|
||||
[HttpGet("{instructionTestId}/questions")]
|
||||
public IActionResult GetInstructionTestQuestionsByInstructionTestId(long instructionTestId)
|
||||
{
|
||||
// TODO: verify admin access / user ownership
|
||||
try
|
||||
{
|
||||
var instructionTestQuestions = _instructionTestsService.GetInstructionTestQuestionsByInstructionTestId(instructionTestId);
|
||||
return Ok(instructionTestQuestions);
|
||||
}
|
||||
catch (InstructionTestNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all instruction test results for authorized user by instruction ID.
|
||||
/// </summary>
|
||||
/// <param name="instructionTestId">The ID of the instruction.</param>
|
||||
/// <returns>A list of <see cref="InstructionTestResultDTO"/> containing the instruction test results if found, or a 404 Not Found if not found.</returns>
|
||||
/// <response code="200">Returns the instruction test results</response>
|
||||
/// <response code="404">If the instruction test results are not found</response>
|
||||
[HttpGet("/{instructionTestId}/results")]
|
||||
public async Task<IActionResult> GetUserInstructionTestResultsByInstructionTestId(long instructionTestId)
|
||||
{
|
||||
// TODO: verify user ownership
|
||||
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||
|
||||
try
|
||||
{
|
||||
var instructionTestResults = _instructionTestsService.GetUserInstructionTestResultsByInstructionTestId(userId, instructionTestId);
|
||||
return Ok(instructionTestResults);
|
||||
}
|
||||
catch (InstructionTestNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all instruction test results for a specific user by instruction test ID (admin access).
|
||||
/// </summary>
|
||||
/// <param name="userId">The ID of the user whose results are being requested.</param>
|
||||
/// <param name="instructionTestId">The ID of the instruction.</param>
|
||||
/// <returns>A list of <see cref="InstructionTestResultDTO"/> containing the instruction test results if found, or a 404 Not Found if not found.</returns>
|
||||
/// <response code="200">Returns the instruction test results</response>
|
||||
/// <response code="404">If the instruction test results are not found</response>
|
||||
/// <response code="403">If the user is not an admin</response>
|
||||
[HttpGet("{instructionTestId}/user/{userId}/results")]
|
||||
[Authorize(Roles = "Admin")]
|
||||
public IActionResult GetInstructionTestResultsForUserByInstructionTestId(long userId, long instructionTestId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var instructionTestResults = _instructionTestsService.GetUserInstructionTestResultsByInstructionTestId(userId, instructionTestId);
|
||||
return Ok(instructionTestResults);
|
||||
}
|
||||
catch (InstructionTestNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all instruction test results for a user by user ID.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the user.</param>
|
||||
/// <returns>A list of <see cref="InstructionTestResultDTO"/> containing the instruction test results if found, or a 404 Not Found if not found.</returns>
|
||||
/// <response code="200">Returns the instruction test results</response>
|
||||
/// <response code="404">If the instruction test results are not found</response>
|
||||
[HttpGet("user/{id}/results")]
|
||||
public IActionResult GetInstructionTestResultsByUserId(long id)
|
||||
{
|
||||
// TODO: verify admin access / user ownership
|
||||
try
|
||||
{
|
||||
var instructionTestResults = _instructionTestsService.GetInstructionTestResultsByUserId(id);
|
||||
return Ok(instructionTestResults);
|
||||
}
|
||||
catch (InstructionTestNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all completed instruction test results for a user by user ID.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the user.</param>
|
||||
/// <returns>A list of <see cref="InstructionTestResultDTO"/> containing the instruction test results if found, or a 404 Not Found if not found.</returns>
|
||||
/// <response code="200">Returns the instruction test results</response>
|
||||
/// <response code="404">If the instruction test results are not found</response>
|
||||
[HttpGet("user/{id}/completed")]
|
||||
public IActionResult GetCompletedInstructionTestsByUserId(long id)
|
||||
{
|
||||
// TODO: verify admin access / user ownership
|
||||
try
|
||||
{
|
||||
var instructionTestResults = _instructionTestsService.GetCompletedInstructionTestsByUserId(id);
|
||||
return Ok(instructionTestResults);
|
||||
}
|
||||
catch (InstructionTestNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instruction test.
|
||||
/// </summary>
|
||||
/// <param name="model">The instruction test model.</param>
|
||||
/// <returns>A <see cref="InstructionTestDTO"/> containing the created instruction test if successful, or a 500 Internal Server Error if not successful.</returns>
|
||||
/// <response code="200">Returns the created instruction test</response>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> CreateInstructionTest([FromBody] InstructionTestCreateDTO model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var instructionTest = await _instructionTestsService.CreateInstructionTest(model);
|
||||
return Ok(instructionTest);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return StatusCode(500, "Failed to create instruction test");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates an existing instruction test.
|
||||
/// </summary>
|
||||
/// <param name="model">The instruction test model.</param>
|
||||
/// <returns>A <see cref="InstructionTestDTO"/> containing the updated instruction test if successful, or a 500 Internal Server Error if not successful.</returns>
|
||||
/// <response code="200">Returns the updated instruction test</response>
|
||||
[HttpPut]
|
||||
[Authorize(Policy = "Admin")]
|
||||
public async Task<IActionResult> UpdateInstructionTest([FromBody] InstructionTestCreateDTO model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var instructionTest = await _instructionTestsService.UpdateInstructionTest(model);
|
||||
return Ok(instructionTest);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return StatusCode(500, "Failed to update instruction test");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes an existing instruction test.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the instruction test to delete.</param>
|
||||
/// <returns>A <see cref="bool"/></returns>
|
||||
/// <response code="200">Returns the deletion status.</response>
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Policy = "Admin")]
|
||||
public async Task<IActionResult> DeleteInstructionTest(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _instructionTestsService.DeleteInstructionTestByIdAsync(id);
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return StatusCode(500, "Failed to delete instruction test");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("submit")]
|
||||
public async Task<IActionResult> SubmitInstructionTest([FromBody] InstructionTestSubmissionDTO model)
|
||||
{
|
||||
// TODO: verify user access
|
||||
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||
|
||||
try
|
||||
{
|
||||
await _instructionTestsService.SubmitInstructionTestAsync(userId, model);
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return StatusCode(500, "Failed to submit instruction test");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,6 @@ public class ApplicationContext : IdentityDbContext<ApplicationUser, Application
|
||||
public DbSet<UserRole> UserRoles { get; set; }
|
||||
public DbSet<RoleRight> RoleRights { get; set; }
|
||||
public DbSet<UserProfile> UserProfiles { get; set; }
|
||||
public DbSet<Instruction> Instructions { get; set; }
|
||||
public DbSet<InstructionCategory> InstructionCategories { get; set; }
|
||||
public DbSet<InstructionParagraph> InstructionParagraphs { get; set; }
|
||||
public DbSet<InstructionTest> InstructionTests { get; set; }
|
||||
public DbSet<InstructionTestQuestion> InstructionTestQuestions { get; set; }
|
||||
public DbSet<InstructionTestResult> InstructionTestResults { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
@@ -34,17 +28,5 @@ public class ApplicationContext : IdentityDbContext<ApplicationUser, Application
|
||||
|
||||
modelBuilder.Entity<RoleRight>()
|
||||
.HasKey(rr => new { rr.RoleId, rr.RightId });
|
||||
|
||||
modelBuilder.Entity<InstructionTest>()
|
||||
.HasMany(itq => itq.Questions);
|
||||
|
||||
modelBuilder.Entity<InstructionTestResult>()
|
||||
.HasOne(itr => itr.InstructionTest);
|
||||
|
||||
modelBuilder.Entity<Instruction>()
|
||||
.HasOne(i => i.Category);
|
||||
|
||||
modelBuilder.Entity<Instruction>()
|
||||
.HasMany(i => i.Paragraphs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,6 @@ public class UnitOfWork : IDisposable
|
||||
private GenericRepository<RefreshToken> _refreshTokenRepository;
|
||||
private GenericRepository<RoleRight> _roleRightRepository;
|
||||
private GenericRepository<UserRole> _userRoleRepository;
|
||||
private GenericRepository<Instruction> _instructionRepository;
|
||||
private GenericRepository<InstructionParagraph> _instructionParagraphRepository;
|
||||
private GenericRepository<InstructionCategory> _instructionCategoryRepository;
|
||||
private GenericRepository<InstructionTest> _instructionTestRepository;
|
||||
private GenericRepository<InstructionTestQuestion> _instructionTestQuestionRepository;
|
||||
private GenericRepository<InstructionTestResult> _instructionTestResultRepository;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -106,83 +100,8 @@ public class UnitOfWork : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public GenericRepository<Instruction> InstructionRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._instructionRepository == null)
|
||||
{
|
||||
this._instructionRepository = new GenericRepository<Instruction>(_context);
|
||||
}
|
||||
return _instructionRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public GenericRepository<InstructionParagraph> InstructionParagraphRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._instructionParagraphRepository == null)
|
||||
{
|
||||
this._instructionParagraphRepository = new GenericRepository<InstructionParagraph>(_context);
|
||||
}
|
||||
return _instructionParagraphRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public GenericRepository<InstructionCategory> InstructionCategoryRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._instructionCategoryRepository == null)
|
||||
{
|
||||
this._instructionCategoryRepository = new GenericRepository<InstructionCategory>(_context);
|
||||
}
|
||||
return _instructionCategoryRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public GenericRepository<InstructionTest> InstructionTestRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._instructionTestRepository == null)
|
||||
{
|
||||
this._instructionTestRepository = new GenericRepository<InstructionTest>(_context);
|
||||
}
|
||||
return _instructionTestRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public GenericRepository<InstructionTestQuestion> InstructionTestQuestionRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._instructionTestQuestionRepository == null)
|
||||
{
|
||||
this._instructionTestQuestionRepository = new GenericRepository<InstructionTestQuestion>(_context);
|
||||
}
|
||||
return _instructionTestQuestionRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public GenericRepository<InstructionTestResult> InstructionTestResultRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._instructionTestResultRepository == null)
|
||||
{
|
||||
this._instructionTestResultRepository = new GenericRepository<InstructionTestResult>(_context);
|
||||
}
|
||||
return _instructionTestResultRepository;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
public bool Save()
|
||||
{
|
||||
return _context.SaveChanges() > 0;
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
namespace GamificationService.Exceptions.Services.Instruction;
|
||||
|
||||
public class CategoryNotFoundException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CategoryNotFoundException"/> class.
|
||||
/// </summary>
|
||||
public CategoryNotFoundException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CategoryNotFoundException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public CategoryNotFoundException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CategoryNotFoundException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public CategoryNotFoundException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.Instruction;
|
||||
|
||||
public class InstructionAccessException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionAccessException"/> class.
|
||||
/// </summary>
|
||||
public InstructionAccessException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionAccessException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public InstructionAccessException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionAccessException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public InstructionAccessException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.Instruction;
|
||||
|
||||
public class InstructionCreationException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionCreationException"/> class.
|
||||
/// </summary>
|
||||
public InstructionCreationException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionCreationException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public InstructionCreationException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionCreationException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public InstructionCreationException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.Instruction;
|
||||
|
||||
public class InstructionDeletionException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionDeletionException"/> class.
|
||||
/// </summary>
|
||||
public InstructionDeletionException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionDeletionException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public InstructionDeletionException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionDeletionException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public InstructionDeletionException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.Instruction;
|
||||
|
||||
public class InstructionNotFoundException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionNotFoundException"/> class.
|
||||
/// </summary>
|
||||
public InstructionNotFoundException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionNotFoundException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public InstructionNotFoundException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionNotFoundException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public InstructionNotFoundException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.Instruction;
|
||||
|
||||
public class InstructionUpdateException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionUpdateException"/> class.
|
||||
/// </summary>
|
||||
public InstructionUpdateException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionUpdateException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public InstructionUpdateException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionUpdateException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public InstructionUpdateException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.InstructionTest;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception that occurs when there is a conflict in instruction test operations.
|
||||
/// </summary>
|
||||
public class InstructionTestConflictException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestConflictException"/> class.
|
||||
/// </summary>
|
||||
public InstructionTestConflictException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestConflictException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public InstructionTestConflictException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestConflictException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public InstructionTestConflictException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.InstructionTest;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception that occurs during the creation of an instruction test.
|
||||
/// </summary>
|
||||
public class InstructionTestCreationException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestCreationException"/> class.
|
||||
/// </summary>
|
||||
public InstructionTestCreationException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestCreationException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public InstructionTestCreationException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestCreationException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public InstructionTestCreationException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.InstructionTest;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception that occurs during the deletion of an instruction test.
|
||||
/// </summary>
|
||||
public class InstructionTestDeletionException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestDeletionException"/> class.
|
||||
/// </summary>
|
||||
public InstructionTestDeletionException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestDeletionException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public InstructionTestDeletionException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestDeletionException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public InstructionTestDeletionException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.InstructionTest;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception that occurs when an instruction test is not found.
|
||||
/// </summary>
|
||||
public class InstructionTestNotFoundException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestNotFoundException"/> class.
|
||||
/// </summary>
|
||||
public InstructionTestNotFoundException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestNotFoundException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public InstructionTestNotFoundException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestNotFoundException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public InstructionTestNotFoundException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.InstructionTest;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception that occurs when an instruction test submission is failed.
|
||||
/// </summary>
|
||||
public class InstructionTestSubmissionException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestSubmissionException"/> class.
|
||||
/// </summary>
|
||||
public InstructionTestSubmissionException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestSubmissionException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public InstructionTestSubmissionException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionTestSubmissionException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public InstructionTestSubmissionException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
@@ -8,12 +8,10 @@ using GamificationService.Logs;
|
||||
using GamificationService.Mapper;
|
||||
using GamificationService.Services.Cookies;
|
||||
using GamificationService.Services.CurrentUsers;
|
||||
using GamificationService.Services.InstructionTests;
|
||||
using GamificationService.Services.JWT;
|
||||
using GamificationService.Services.NotificationService;
|
||||
using GamificationService.Services.Rights;
|
||||
using GamificationService.Services.Roles;
|
||||
using GamificationService.Services.UsersProfile;
|
||||
using GamificationService.Utils;
|
||||
using GamificationService.Utils.Factory;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
@@ -129,8 +127,6 @@ public static class BackendServicesExtensions
|
||||
{
|
||||
public static IServiceCollection AddBackendServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddScoped<IUserProfileService, UserProfileService>();
|
||||
services.AddScoped<IInstructionTestsService, InstructionTestsService>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,123 +47,5 @@ public class MappingProfile : Profile
|
||||
|
||||
#endregion
|
||||
|
||||
#region InstructionParagraphMapping
|
||||
|
||||
CreateMap<InstructionParagraph, InstructionParagraphDTO>()
|
||||
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(x => x.Text, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(x => x.InstructionId, opt => opt.MapFrom(src => src.InstructionId))
|
||||
.ForMember(x => x.Order, opt => opt.MapFrom(src => src.Order))
|
||||
.ForMember(x => x.ImageUrl, opt => opt.MapFrom(src => src.ImageUrl))
|
||||
.ForMember(x => x.VideoUrl, opt => opt.MapFrom(src => src.VideoUrl));
|
||||
|
||||
#endregion
|
||||
|
||||
#region InstructionMapping
|
||||
|
||||
CreateMap<Instruction, InstructionDTO>()
|
||||
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(x => x.Title, opt => opt.MapFrom(src => src.Title))
|
||||
.ForMember(x => x.Description, opt => opt.MapFrom(src => src.Description))
|
||||
.ForMember(x => x.CategoryId, opt => opt.MapFrom(src => src.CategoryId))
|
||||
.ForMember(x => x.AssignDate, opt => opt.MapFrom(src => src.AssignDate))
|
||||
.ForMember(x => x.AssignDate, opt => opt.MapFrom(src => src.DeadlineDate))
|
||||
.ForMember(x => x.IsEnabled, opt => opt.MapFrom(src => src.IsEnabled))
|
||||
.ForMember(x => x.Paragraphs, opt => opt.MapFrom(src => src.Paragraphs));
|
||||
|
||||
#endregion
|
||||
|
||||
#region InstructionCreateMapping
|
||||
|
||||
CreateMap<InstructionCreateDTO, Instruction>()
|
||||
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(x => x.Title, opt => opt.MapFrom(src => src.Title))
|
||||
.ForMember(x => x.Description, opt => opt.MapFrom(src => src.Description))
|
||||
.ForMember(x => x.Paragraphs, opt => opt.MapFrom(src => src.Paragraphs))
|
||||
.ForMember(x => x.CategoryId, opt => opt.MapFrom(src => src.CategoryId))
|
||||
.ForMember(x => x.AssignDate, opt => opt.MapFrom(src => src.AssignDate))
|
||||
.ForMember(x => x.DeadlineDate, opt => opt.MapFrom(src => src.DeadlineDate))
|
||||
.ForMember(x => x.IsEnabled, opt => opt.MapFrom(src => src.IsEnabled));
|
||||
#endregion
|
||||
|
||||
#region InstructionParagraphCreateMapping
|
||||
|
||||
CreateMap<InstructionParagraphCreateDTO, InstructionParagraph>()
|
||||
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(x => x.Text, opt => opt.MapFrom(src => src.Text))
|
||||
.ForMember(x => x.InstructionId, opt => opt.MapFrom(src => src.InstructionId))
|
||||
.ForMember(x => x.Order, opt => opt.MapFrom(src => src.Order))
|
||||
.ForMember(x => x.ImageUrl, opt => opt.MapFrom(src => src.ImageUrl))
|
||||
.ForMember(x => x.VideoUrl, opt => opt.MapFrom(src => src.VideoUrl));
|
||||
|
||||
#endregion
|
||||
|
||||
#region InstructionCategoryMapping
|
||||
|
||||
CreateMap<InstructionCategory, InstructionCategoryDTO>()
|
||||
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(x => x.Title, opt => opt.MapFrom(src => src.Title));
|
||||
|
||||
#endregion
|
||||
|
||||
#region InstructionCategoryCreateMapping
|
||||
|
||||
CreateMap<InstructionCategoryCreateDTO, InstructionCategory>()
|
||||
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(x => x.Title, opt => opt.MapFrom(src => src.Title));
|
||||
|
||||
#endregion
|
||||
|
||||
#region InstructionTestMapping
|
||||
|
||||
CreateMap<InstructionTestCreateDTO, InstructionTest>()
|
||||
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(x => x.Title, opt => opt.MapFrom(src => src.Title))
|
||||
.ForMember(x => x.Questions, opt => opt.MapFrom(src => src.Questions))
|
||||
.ForMember(x => x.ScoreCalcMethod, opt => opt.MapFrom(src => src.ScoreCalcMethod))
|
||||
.ForMember(x => x.MinScore, opt => opt.MapFrom(src => src.MinScore))
|
||||
.ForMember(x => x.MaxAttempts, opt => opt.MapFrom(src => src.MaxAttempts));
|
||||
|
||||
CreateMap<InstructionTest, InstructionTestDTO>()
|
||||
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(x => x.Title, opt => opt.MapFrom(src => src.Title))
|
||||
.ForMember(x => x.ScoreCalcMethod, opt => opt.MapFrom(src => src.ScoreCalcMethod))
|
||||
.ForMember(x => x.MinScore, opt => opt.MapFrom(src => src.MinScore))
|
||||
.ForMember(x => x.MaxAttempts, opt => opt.MapFrom(src => src.MaxAttempts))
|
||||
.ForMember(x => x.Questions, opt => opt.MapFrom(src => src.Questions));
|
||||
|
||||
#endregion
|
||||
|
||||
#region InstructionTestQuestionCreateMapping
|
||||
|
||||
CreateMap<InstructionTestQuestionCreateDTO, InstructionTestQuestion>()
|
||||
.ForMember(x => x.Question, opt => opt.MapFrom(src => src.Question))
|
||||
.ForMember(x => x.Answers, opt => opt.MapFrom(src => src.Answers))
|
||||
.ForMember(x => x.Order, opt => opt.MapFrom(src => src.Order))
|
||||
.ForMember(x => x.IsMultipleAnswer, opt => opt.MapFrom(src => src.IsMultipleAnswer))
|
||||
.ForMember(x => x.CorrectAnswers, opt => opt.MapFrom(src => src.CorrectAnswers));
|
||||
|
||||
#endregion
|
||||
|
||||
#region InstructionTestQuestionMapping
|
||||
|
||||
CreateMap<InstructionTestQuestion, InstructionTestQuestionDTO>()
|
||||
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(x => x.Question, opt => opt.MapFrom(src => src.Question))
|
||||
.ForMember(x => x.Answers, opt => opt.MapFrom(src => src.Answers))
|
||||
.ForMember(x => x.Order, opt => opt.MapFrom(src => src.Order))
|
||||
.ForMember(x => x.IsMultipleAnswer, opt => opt.MapFrom(src => src.IsMultipleAnswer));
|
||||
|
||||
#endregion
|
||||
|
||||
#region InstructionTestResultMapping
|
||||
|
||||
CreateMap<InstructionTestResult, InstructionTestResultDTO>()
|
||||
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(x => x.UserId, opt => opt.MapFrom(src => src.UserId))
|
||||
.ForMember(x => x.InstructionTestId, opt => opt.MapFrom(src => src.InstructionTestId))
|
||||
.ForMember(x => x.Score, opt => opt.MapFrom(src => src.Score));
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class InstructionCategoryCreateDTO
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Title is required")]
|
||||
public string Title { get; set; } = null!;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class InstructionCategoryDTO
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
public string? Title { get; set; } = null!;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class InstructionCreateDTO
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Title is required")]
|
||||
public string Title { get; set; } = null!;
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Paragraphs are required")]
|
||||
public List<InstructionParagraphCreateDTO> Paragraphs { get; set; } = null!;
|
||||
|
||||
[Required(ErrorMessage = "Category id is required")]
|
||||
public long CategoryId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If AssignDate is set, the instruction will be automatically enabled
|
||||
/// when the date is reached. If it's not set, the test will automatically
|
||||
/// obtain the current date as its AssignDate as soon as the instruction
|
||||
/// will be enabled by the IsEnabled parameter.
|
||||
/// </summary>
|
||||
public DateTime? AssignDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When deadline is reached, no more submissions are allowed for this instruction.
|
||||
/// </summary>
|
||||
public DateTime? DeadlineDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disabled instructions cannot be seen by users.
|
||||
/// Tests for such instructions cannot be submitted either.
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; set; } = false;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class InstructionDTO
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
public string? Title { get; set; }
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
public List<InstructionParagraphDTO> Paragraphs { get; set; } = new List<InstructionParagraphDTO>();
|
||||
|
||||
public long? CategoryId { get; set; }
|
||||
|
||||
public DateTime? AssignDate { get; set; }
|
||||
|
||||
public DateTime? DeadlineDate { get; set; }
|
||||
|
||||
public bool IsEnabled { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class InstructionParagraphCreateDTO
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
public long? InstructionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Order defines the order of the paragraphs inside the instruction.
|
||||
/// There must not be two paragraphs with the same order.
|
||||
/// </summary>
|
||||
public int Order { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Text is required")]
|
||||
public string Text { get; set; } = null!;
|
||||
|
||||
public string? ImageUrl { get; set; }
|
||||
|
||||
public string? VideoUrl { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class InstructionParagraphDTO
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
public long? InstructionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Order defines the order of the paragraphs inside the instruction.
|
||||
/// There must not be two paragraphs with the same order.
|
||||
/// </summary>
|
||||
public int Order { get; set; }
|
||||
|
||||
public string? Text { get; set; } = null!;
|
||||
|
||||
public string? ImageUrl { get; set; }
|
||||
|
||||
public string? VideoUrl { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using GamificationService.Utils.Enums;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class InstructionTestCreateDTO
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
public string? Title { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Questions must be specified")]
|
||||
public ICollection<InstructionTestQuestionCreateDTO> Questions { get; set; } = null!;
|
||||
|
||||
public int MaxAttempts { get; set; } = 10;
|
||||
|
||||
[Range(0, 1.0, ErrorMessage = "Minimum score must be between 0.6 and 1.0")]
|
||||
public double MinScore { get; set; } = 0.6;
|
||||
|
||||
public InstructionTestScoreCalcMethod ScoreCalcMethod { get; set; } = InstructionTestScoreCalcMethod.MaxGrade;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using GamificationService.Utils.Enums;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class InstructionTestDTO
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
// Reserved just in case
|
||||
[StringLength(300, ErrorMessage = "Title cannot be longer than 300 characters")]
|
||||
public string? Title { get; set; }
|
||||
|
||||
public int MaxAttempts { get; set; } = 10;
|
||||
|
||||
public double MinScore { get; set; } = 0.6;
|
||||
|
||||
public List<InstructionTestQuestionDTO> Questions { get; set; } = new List<InstructionTestQuestionDTO>();
|
||||
|
||||
public InstructionTestScoreCalcMethod ScoreCalcMethod { get; set; } = InstructionTestScoreCalcMethod.MaxGrade;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class InstructionTestQuestionCreateDTO
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
public bool IsMultipleAnswer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Question will be displayed in the paragraph with the same order number.
|
||||
/// There can be multiple questions attached to the same paragraph.
|
||||
/// </summary>
|
||||
public int Order { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Must have question text")]
|
||||
public string Question { get; set; } = null!;
|
||||
|
||||
[Required(ErrorMessage = "Must have answer options")]
|
||||
public ICollection<string> Answers { get; set; } = null!;
|
||||
|
||||
[Required(ErrorMessage = "Must have correct answers")]
|
||||
public ICollection<int> CorrectAnswers { get; set; } = null!;
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class InstructionTestQuestionDTO
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
public bool IsMultipleAnswer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Question will be displayed in the paragraph with the same order number.
|
||||
/// There can be multiple questions attached to the same paragraph.
|
||||
/// </summary>
|
||||
public int Order { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Must have question text")]
|
||||
public string Question { get; set; } = null!;
|
||||
|
||||
[Required(ErrorMessage = "Must have answer options")]
|
||||
public ICollection<string> Answers { get; set; } = null!;
|
||||
|
||||
public ICollection<int>? CorrectAnswers { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class InstructionTestResultDTO
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
public long? InstructionTestId { get; set; }
|
||||
|
||||
public long? UserId { get; set; }
|
||||
|
||||
public int Score { get; set; }
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class InstructionTestSubmissionDTO
|
||||
{
|
||||
[Required(ErrorMessage = "InstructionTestId is required")]
|
||||
public int InstructionTestId { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Answers must be provided")]
|
||||
public List<List<int>> Answers { get; set; } = null!;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.Database;
|
||||
|
||||
public class Instruction
|
||||
{
|
||||
[Key]
|
||||
public long Id { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Title is required")]
|
||||
public string Title { get; set; } = null!;
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
public long CategoryId { get; set; }
|
||||
[Required(ErrorMessage = "Category must be specified")]
|
||||
public InstructionCategory Category { get; set; } = null!;
|
||||
|
||||
public virtual ICollection<InstructionParagraph> Paragraphs { get; set; }
|
||||
|
||||
public long? InstructionTestId { get; set; }
|
||||
public InstructionTest? InstructionTest { get; set; }
|
||||
|
||||
public DateTime? AssignDate { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public DateTime? DeadlineDate { get; set; }
|
||||
|
||||
public bool IsEnabled { get; set; }
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.Database;
|
||||
|
||||
public class InstructionCategory
|
||||
{
|
||||
[Key]
|
||||
public long Id { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Title is required")]
|
||||
public string Title { get; set; } = null!;
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.Database;
|
||||
|
||||
public class InstructionParagraph
|
||||
{
|
||||
[Key]
|
||||
public long Id { get; set; }
|
||||
|
||||
public long InstructionId { get; set; }
|
||||
[Required(ErrorMessage = "Must be linked to instruction")]
|
||||
|
||||
public int Order { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Paragraph text is required")]
|
||||
public string Text { get; set; } = null!;
|
||||
|
||||
public string? ImageUrl { get; set; }
|
||||
|
||||
public string? VideoUrl { get; set; }
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using GamificationService.Utils.Enums;
|
||||
|
||||
namespace GamificationService.Models.Database;
|
||||
|
||||
public class InstructionTest
|
||||
{
|
||||
[Key]
|
||||
public long Id { get; set; }
|
||||
|
||||
// Reserved just in case
|
||||
[MaxLength(300, ErrorMessage = "Title cannot be longer than 300 characters")]
|
||||
public string? Title { get; set; }
|
||||
|
||||
public virtual ICollection<InstructionTestQuestion> Questions { get; set; }
|
||||
|
||||
public int MaxAttempts { get; set; } = 10;
|
||||
|
||||
public double MinScore { get; set; } = 0.6;
|
||||
|
||||
public InstructionTestScoreCalcMethod ScoreCalcMethod { get; set; } = InstructionTestScoreCalcMethod.MaxGrade;
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.Database;
|
||||
|
||||
public class InstructionTestQuestion
|
||||
{
|
||||
[Key]
|
||||
public long Id { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Must be tied to an instruction test")]
|
||||
public InstructionTest InstructionTest { get; set; } = null!;
|
||||
public long InstructionTestId { get; set; }
|
||||
|
||||
public int Order { get; set; }
|
||||
|
||||
public bool IsMultipleAnswer { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Must have question text")]
|
||||
public string Question { get; set; } = null!;
|
||||
|
||||
[Required(ErrorMessage = "Must have answer options")]
|
||||
public ICollection<string> Answers { get; set; } = null!;
|
||||
|
||||
[Required(ErrorMessage = "Must have correct answer ids")]
|
||||
public ICollection<int> CorrectAnswers { get; set; } = null!;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.Database;
|
||||
|
||||
public class InstructionTestResult
|
||||
{
|
||||
[Key]
|
||||
public long Id { get; set; }
|
||||
|
||||
public long InstructionTestId { get; set; }
|
||||
[Required(ErrorMessage = "Instruction test is required")]
|
||||
public virtual InstructionTest InstructionTest { get; set; } = null!;
|
||||
|
||||
public long UserId { get; set; }
|
||||
[Required(ErrorMessage = "User is required")]
|
||||
public ApplicationUser User { get; set; } = null!;
|
||||
|
||||
[Range(0, 100, ErrorMessage = "Score must be a number from 0 to 100")]
|
||||
public int Score { get; set; }
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace GamificationService.Models.Messages.InstructionTests;
|
||||
|
||||
public class CreateInstructionTestRequest
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace GamificationService.Models.Messages.InstructionTests;
|
||||
|
||||
public class CreateInstructionTestResponse
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace GamificationService.Models.Messages.InstructionTests;
|
||||
|
||||
public class UpdateInstructionTestRequest
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace GamificationService.Models.Messages.InstructionTests;
|
||||
|
||||
public class UpdateInstructionTestResponse
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using GamificationService.Models.DTO;
|
||||
|
||||
namespace GamificationService.Models.Messages.Instructions;
|
||||
|
||||
public class CreateInstructionRequest
|
||||
{
|
||||
[Required(ErrorMessage = "Title is required")]
|
||||
public string Title { get; set; } = null!;
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Paragraphs are required")]
|
||||
public List<InstructionParagraphCreateDTO> Paragraphs { get; set; } = null!;
|
||||
|
||||
[Required(ErrorMessage = "Category id is required")]
|
||||
public long CategoryId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If AssignDate is set, the instruction will be automatically enabled
|
||||
/// when the date is reached. If it's not set, the test will automatically
|
||||
/// obtain the current date as its AssignDate as soon as the instruction
|
||||
/// will be enabled by the IsEnabled parameter.
|
||||
/// </summary>
|
||||
public DateTime? AssignDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When deadline is reached, no more submissions are allowed for this instruction.
|
||||
/// </summary>
|
||||
public DateTime? DeadlineDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disabled instructions cannot be seen by users.
|
||||
/// Tests for such instructions cannot be submitted either.
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; set; } = false;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace GamificationService.Models.Messages.Instructions;
|
||||
|
||||
public class CreateInstructionResponse
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using GamificationService.Models.DTO;
|
||||
|
||||
namespace GamificationService.Models.Messages.Instructions;
|
||||
|
||||
public class UpdateInstructionRequest
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Title is required")]
|
||||
public string Title { get; set; } = null!;
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Paragraphs are required")]
|
||||
public List<InstructionParagraphCreateDTO> Paragraphs { get; set; } = null!;
|
||||
|
||||
[Required(ErrorMessage = "Category id is required")]
|
||||
public long CategoryId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If AssignDate is set, the instruction will be automatically enabled
|
||||
/// when the date is reached. If it's not set, the test will automatically
|
||||
/// obtain the current date as its AssignDate as soon as the instruction
|
||||
/// will be enabled by the IsEnabled parameter.
|
||||
/// </summary>
|
||||
public DateTime? AssignDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When deadline is reached, no more submissions are allowed for this instruction.
|
||||
/// </summary>
|
||||
public DateTime? DeadlineDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Disabled instructions cannot be seen by users.
|
||||
/// Tests for such instructions cannot be submitted either.
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; set; } = false;
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace GamificationService.Models.Messages.Instructions;
|
||||
|
||||
public class UpdateInstructionResponse
|
||||
{
|
||||
|
||||
}
|
||||
@@ -29,12 +29,6 @@ builder.Services.AddLogging();
|
||||
#endregion
|
||||
|
||||
|
||||
#region SMTP
|
||||
|
||||
builder.Services.AddEmail(builder.Configuration);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Database
|
||||
|
||||
builder.Services.AddDatabase(builder.Configuration);
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Models.DTO;
|
||||
|
||||
namespace GamificationService.Services.InstructionTests;
|
||||
|
||||
public interface IInstructionTestsService
|
||||
{
|
||||
public Task<InstructionTest> CreateInstructionTest(InstructionTest instructionTest);
|
||||
public Task<InstructionTestDTO> CreateInstructionTest(InstructionTestCreateDTO instructionTest);
|
||||
public Task<bool> UpdateInstructionTest(InstructionTest instructionTest);
|
||||
public Task<bool> UpdateInstructionTest(InstructionTestCreateDTO instructionTest);
|
||||
public Task<bool> DeleteInstructionTestByIdAsync(long id);
|
||||
|
||||
public Task<InstructionTestResultDTO> SubmitInstructionTestAsync(long userId, InstructionTestSubmissionDTO submission);
|
||||
|
||||
public InstructionTestDTO GetInstructionTestById(long id);
|
||||
public List<InstructionTestDTO> GetInstructionTestsByInstructionId(long instructionId);
|
||||
public List<InstructionTestQuestionDTO> GetInstructionTestQuestionsByInstructionTestId(long instructionTestId);
|
||||
public List<InstructionTestResultDTO> GetUserInstructionTestResultsByInstructionTestId(long userId, long instructionId);
|
||||
public List<InstructionTestResultDTO> GetInstructionTestResultsByUserId(long userId);
|
||||
public List<InstructionTestResultDTO> GetCompletedInstructionTestsByUserId(long userId);
|
||||
}
|
||||
@@ -1,294 +0,0 @@
|
||||
using AutoMapper;
|
||||
using GamificationService.Database.Repositories;
|
||||
using GamificationService.Exceptions.Services.Instruction;
|
||||
using GamificationService.Exceptions.Services.InstructionTest;
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Models.DTO;
|
||||
using GamificationService.Utils.Enums;
|
||||
|
||||
namespace GamificationService.Services.InstructionTests;
|
||||
|
||||
public class InstructionTestsService : IInstructionTestsService
|
||||
{
|
||||
private readonly ILogger<InstructionTestsService> _logger;
|
||||
private readonly UnitOfWork _unitOfWork;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public InstructionTestsService(ILogger<InstructionTestsService> logger, UnitOfWork unitOfWork, IMapper mapper)
|
||||
{
|
||||
_logger = logger;
|
||||
_unitOfWork = unitOfWork;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<InstructionTestDTO> CreateInstructionTest(InstructionTestCreateDTO instructionTest)
|
||||
{
|
||||
return _mapper.Map<InstructionTestDTO>(await CreateInstructionTest(_mapper.Map<InstructionTest>(instructionTest)));
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteInstructionTestByIdAsync(long id)
|
||||
{
|
||||
var instructionTest = _unitOfWork.InstructionTestRepository.GetByID(id);
|
||||
|
||||
if (instructionTest == null)
|
||||
{
|
||||
_logger.LogError("Instruction test with id {Id} not found", id);
|
||||
throw new InstructionTestNotFoundException();
|
||||
}
|
||||
|
||||
// Find all questions
|
||||
var questions = _unitOfWork.InstructionTestQuestionRepository.Get(q => q.InstructionTestId == id);
|
||||
|
||||
// Start transaction
|
||||
await _unitOfWork.BeginTransactionAsync();
|
||||
|
||||
foreach (var question in questions)
|
||||
{
|
||||
_unitOfWork.InstructionTestQuestionRepository.Delete(question);
|
||||
}
|
||||
|
||||
// Delete instruction test
|
||||
_unitOfWork.InstructionTestRepository.Delete(instructionTest);
|
||||
|
||||
if (await _unitOfWork.SaveAsync())
|
||||
{
|
||||
await _unitOfWork.CommitAsync();
|
||||
_logger.LogInformation("Instruction test deleted ({Id})", id);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError("Failed to delete instruction test ({Id})", id);
|
||||
throw new InstructionTestDeletionException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public List<InstructionTestResultDTO> GetCompletedInstructionTestsByUserId(long userId)
|
||||
{
|
||||
var userTestAttempts = _unitOfWork.InstructionTestResultRepository.Get(
|
||||
q => q.UserId == userId).ToList();
|
||||
|
||||
var userInstructionTests = _unitOfWork.InstructionTestRepository.Get(
|
||||
q => userTestAttempts.Any(a => a.InstructionTestId == q.Id)).ToList();
|
||||
|
||||
var conclusiveUserTestResults = new List<InstructionTestResultDTO>();
|
||||
foreach (var instructionTest in userInstructionTests)
|
||||
{
|
||||
var scoreCalcMethod = instructionTest.ScoreCalcMethod;
|
||||
int maxScore = 0;
|
||||
|
||||
if (scoreCalcMethod == InstructionTestScoreCalcMethod.AverageGrade)
|
||||
{
|
||||
maxScore = (int)Math.Round(userTestAttempts.Where(q => q.InstructionTestId == instructionTest.Id).Average(q => q.Score));
|
||||
}
|
||||
else
|
||||
{
|
||||
maxScore = userTestAttempts.Where(q => q.InstructionTestId == instructionTest.Id).Max(q => q.Score);
|
||||
}
|
||||
|
||||
if (maxScore >= instructionTest.MinScore)
|
||||
{
|
||||
conclusiveUserTestResults.Add(_mapper.Map<InstructionTestResultDTO>(userTestAttempts.First(q => q.InstructionTestId == instructionTest.Id)));
|
||||
}
|
||||
}
|
||||
|
||||
return conclusiveUserTestResults;
|
||||
}
|
||||
|
||||
public InstructionTestDTO GetInstructionTestById(long id)
|
||||
{
|
||||
var instructionTest = _unitOfWork.InstructionTestRepository.GetByID(id);
|
||||
if (instructionTest == null)
|
||||
{
|
||||
_logger.LogError("Instruction test with id {Id} not found", id);
|
||||
throw new InstructionTestNotFoundException();
|
||||
}
|
||||
return _mapper.Map<InstructionTestDTO>(instructionTest);
|
||||
}
|
||||
|
||||
public List<InstructionTestQuestionDTO> GetInstructionTestQuestionsByInstructionTestId(long instructionTestId)
|
||||
{
|
||||
var questions = _unitOfWork.InstructionTestQuestionRepository.Get(q => q.InstructionTestId == instructionTestId);
|
||||
return _mapper.Map<List<InstructionTestQuestionDTO>>(questions);
|
||||
}
|
||||
|
||||
public List<InstructionTestResultDTO> GetUserInstructionTestResultsByInstructionTestId(long userId, long instructionTestId)
|
||||
{
|
||||
var userTestResults = _unitOfWork.InstructionTestResultRepository.Get(
|
||||
q => q.UserId == userId && q.InstructionTestId == instructionTestId).ToList();
|
||||
return _mapper.Map<List<InstructionTestResultDTO>>(userTestResults);
|
||||
}
|
||||
|
||||
public List<InstructionTestResultDTO> GetInstructionTestResultsByUserId(long userId)
|
||||
{
|
||||
var userTestResults = _unitOfWork.InstructionTestResultRepository.Get(
|
||||
q => q.UserId == userId).ToList();
|
||||
return _mapper.Map<List<InstructionTestResultDTO>>(userTestResults);
|
||||
}
|
||||
|
||||
public List<InstructionTestDTO> GetInstructionTestsByInstructionId(long instructionId)
|
||||
{
|
||||
var instructionTest = (_unitOfWork.InstructionRepository.GetByID(instructionId)
|
||||
?? throw new InstructionNotFoundException())
|
||||
.InstructionTest ?? throw new InstructionTestNotFoundException();
|
||||
|
||||
return _mapper.Map<List<InstructionTestDTO>>(new List<InstructionTest>() {instructionTest});
|
||||
}
|
||||
|
||||
public async Task<InstructionTestResultDTO> SubmitInstructionTestAsync(long userId, InstructionTestSubmissionDTO submission)
|
||||
{
|
||||
// Retrieve the test and questions
|
||||
var instructionTest = _unitOfWork.InstructionTestRepository.GetByID(submission.InstructionTestId);
|
||||
|
||||
if (instructionTest == null)
|
||||
{
|
||||
_logger.LogError("Instruction test with id {Id} not found", submission.InstructionTestId);
|
||||
throw new InstructionTestNotFoundException();
|
||||
}
|
||||
|
||||
// Check remaining attempts
|
||||
var userTestAttempts = _unitOfWork.InstructionTestResultRepository.Get(
|
||||
q => q.UserId == userId && q.InstructionTestId == submission.InstructionTestId).ToList();
|
||||
|
||||
if (userTestAttempts.Count >= instructionTest.MaxAttempts)
|
||||
{
|
||||
_logger.LogWarning("User {UserId}: denied submission for test {InstructionTestId}: max attempts reached", userId, submission.InstructionTestId);
|
||||
throw new InstructionTestSubmissionException();
|
||||
}
|
||||
|
||||
var questions = _unitOfWork.InstructionTestQuestionRepository.Get(q => q.InstructionTestId == submission.InstructionTestId).ToList();
|
||||
|
||||
// Verify answers amount
|
||||
if (questions.Count != submission.Answers.Count)
|
||||
{
|
||||
_logger.LogWarning("User {UserId}: denied submission for test {InstructionTestId}: wrong number of answers", userId, submission.InstructionTestId);
|
||||
throw new InstructionTestSubmissionException();
|
||||
}
|
||||
|
||||
// Evaluate answers
|
||||
double score = 0;
|
||||
int maxErrorPerQuestion = 1;
|
||||
for (int i = 0; i < questions.Count; i++)
|
||||
{
|
||||
var question = questions[i];
|
||||
|
||||
// User answers for the question without duplicate options
|
||||
var answer = submission.Answers[i].Distinct();
|
||||
|
||||
if (question.IsMultipleAnswer)
|
||||
{
|
||||
int correctUserAnswersCount = 0;
|
||||
int incorrectUserAnswersCount = 0;
|
||||
int correctAnswersCount = question.CorrectAnswers.Count;
|
||||
|
||||
foreach (var option in answer)
|
||||
{
|
||||
if (question.CorrectAnswers.Contains(option))
|
||||
{
|
||||
correctUserAnswersCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
incorrectUserAnswersCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (incorrectUserAnswersCount > maxErrorPerQuestion || correctUserAnswersCount == 0)
|
||||
{
|
||||
// Nothing scored for the question
|
||||
continue;
|
||||
}
|
||||
|
||||
// One question is worth 1 point max
|
||||
double questionScore = correctUserAnswersCount / (double)correctAnswersCount;
|
||||
|
||||
// Add the question score, or half of it if an error is present
|
||||
score += incorrectUserAnswersCount > 0 ? questionScore /= 2 : questionScore;
|
||||
}
|
||||
else
|
||||
{
|
||||
score += question.CorrectAnswers.Contains(answer.First()) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
score = Math.Round(score / questions.Count)*100;
|
||||
|
||||
// Add test result
|
||||
await _unitOfWork.BeginTransactionAsync();
|
||||
|
||||
InstructionTestResult newTestResult = new InstructionTestResult()
|
||||
{
|
||||
UserId = userId,
|
||||
InstructionTestId = submission.InstructionTestId,
|
||||
Score = (int)score
|
||||
};
|
||||
|
||||
_unitOfWork.InstructionTestResultRepository.Insert(newTestResult);
|
||||
|
||||
if (!await _unitOfWork.SaveAsync())
|
||||
{
|
||||
_logger.LogError("Failed to save test result for user {UserId} and test {InstructionTestId}", userId, submission.InstructionTestId);
|
||||
throw new InstructionTestSubmissionException();
|
||||
}
|
||||
|
||||
await _unitOfWork.CommitAsync();
|
||||
return _mapper.Map<InstructionTestResultDTO>(newTestResult);
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateInstructionTest(InstructionTestCreateDTO instructionTest)
|
||||
{
|
||||
return await UpdateInstructionTest(_mapper.Map<InstructionTest>(instructionTest));
|
||||
}
|
||||
|
||||
public async Task<InstructionTest> CreateInstructionTest(InstructionTest instructionTest)
|
||||
{
|
||||
instructionTest.Id = 0;
|
||||
|
||||
await _unitOfWork.BeginTransactionAsync();
|
||||
|
||||
await _unitOfWork.InstructionTestRepository.InsertAsync(instructionTest);
|
||||
|
||||
if (await _unitOfWork.SaveAsync() == false)
|
||||
{
|
||||
_logger.LogError("Failure to create instruction test");
|
||||
throw new InstructionTestCreationException();
|
||||
}
|
||||
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
_logger.LogInformation($"Created instruction test {instructionTest.Id}");
|
||||
return instructionTest;
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateInstructionTest(InstructionTest instructionTest)
|
||||
{
|
||||
var existingInstructionTest = _unitOfWork.InstructionTestRepository.GetByID(instructionTest.Id);
|
||||
if (existingInstructionTest == null)
|
||||
{
|
||||
throw new InstructionTestNotFoundException();
|
||||
}
|
||||
|
||||
await _unitOfWork.BeginTransactionAsync();
|
||||
|
||||
_unitOfWork.InstructionTestQuestionRepository.DeleteRange(existingInstructionTest.Questions);
|
||||
|
||||
if (await _unitOfWork.SaveAsync() == false)
|
||||
{
|
||||
_logger.LogError($"Failure to create existing questions for instruction test {instructionTest.Id} during update");
|
||||
throw new InstructionTestCreationException();
|
||||
}
|
||||
|
||||
_unitOfWork.InstructionTestRepository.Update(instructionTest);
|
||||
|
||||
if (await _unitOfWork.SaveAsync() == false)
|
||||
{
|
||||
_logger.LogError($"Failure to update instruction test {instructionTest.Id}");
|
||||
}
|
||||
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Models.DTO;
|
||||
using GamificationService.Models.Messages.Instructions;
|
||||
|
||||
namespace GamificationService.Services.Instructions;
|
||||
|
||||
public interface IInstructionService
|
||||
{
|
||||
public Task<Instruction> CreateInstruction(Instruction model);
|
||||
public Task<bool> UpdateInstructionById(Instruction model);
|
||||
public Task<bool> DeleteInstructionById(long instructionId);
|
||||
|
||||
public Task<InstructionDTO> CreateInstruction(CreateInstructionRequest model);
|
||||
public Task<bool> UpdateInstructionById(UpdateInstructionRequest model);
|
||||
|
||||
public List<InstructionDTO> GetAllInstructions(long userId);
|
||||
public List<InstructionDTO> GetInstructionsByCategoryId(long userId, long categoryId);
|
||||
public List<InstructionDTO> GetCompletedInstructions(long userId);
|
||||
public List<InstructionDTO> GetUnfinishedInstructions(long userId);
|
||||
public List<InstructionDTO> GetInstructionById(long userId, long instructionId);
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
using AutoMapper;
|
||||
using GamificationService.Database.Repositories;
|
||||
using GamificationService.Exceptions.Services.Instruction;
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Models.DTO;
|
||||
using GamificationService.Models.Messages.Instructions;
|
||||
using GamificationService.Services.InstructionTests;
|
||||
|
||||
namespace GamificationService.Services.Instructions;
|
||||
|
||||
public class InstructionService : IInstructionService
|
||||
{
|
||||
private readonly UnitOfWork _unitOfWork;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly ILogger<InstructionService> _logger;
|
||||
private readonly IInstructionTestsService _instructionTestService;
|
||||
|
||||
public InstructionService(UnitOfWork unitOfWork, IMapper mapper, ILogger<InstructionService> logger, IInstructionTestsService instructionTestService)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_mapper = mapper;
|
||||
_logger = logger;
|
||||
_instructionTestService = instructionTestService;
|
||||
}
|
||||
|
||||
public async Task<Instruction> CreateInstruction(Instruction model)
|
||||
{
|
||||
model.Id = 0;
|
||||
|
||||
await _unitOfWork.BeginTransactionAsync();
|
||||
|
||||
await _unitOfWork.InstructionRepository.InsertAsync(model);
|
||||
|
||||
if(await _unitOfWork.SaveAsync() == false)
|
||||
{
|
||||
_logger.LogError($"Instruction {model.Id} could not be created");
|
||||
throw new InstructionCreationException();
|
||||
}
|
||||
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
_logger.LogInformation($"Instruction {model.Id} created");
|
||||
return model;
|
||||
}
|
||||
|
||||
public async Task<InstructionDTO> CreateInstruction(CreateInstructionRequest model)
|
||||
{
|
||||
Instruction newInstruction = new Instruction()
|
||||
{
|
||||
Title = model.Title,
|
||||
Description = model.Description,
|
||||
CategoryId = model.CategoryId,
|
||||
Paragraphs = _mapper.Map<List<InstructionParagraph>>(model.Paragraphs),
|
||||
AssignDate = model.AssignDate,
|
||||
DeadlineDate = model.DeadlineDate,
|
||||
IsEnabled = model.IsEnabled
|
||||
};
|
||||
|
||||
return _mapper.Map<InstructionDTO>(await CreateInstruction(newInstruction));
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteInstructionById(long instructionId)
|
||||
{
|
||||
Instruction? instruction = _unitOfWork.InstructionRepository.GetByID(instructionId);
|
||||
if (instruction == null)
|
||||
{
|
||||
throw new InstructionNotFoundException();
|
||||
}
|
||||
_unitOfWork.InstructionRepository.Delete(instruction);
|
||||
|
||||
if (await _unitOfWork.SaveAsync() == false)
|
||||
{
|
||||
_logger.LogError($"Instruction {instructionId} could not be deleted");
|
||||
throw new InstructionDeletionException();
|
||||
}
|
||||
|
||||
_logger.LogInformation($"Instruction {instructionId} deleted");
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<InstructionDTO> GetAllInstructions(long userId)
|
||||
{
|
||||
// TODO: select accessible only
|
||||
var instructions = _unitOfWork.InstructionRepository.Get().ToList();
|
||||
return _mapper.Map<List<InstructionDTO>>(instructions);
|
||||
}
|
||||
|
||||
public List<InstructionDTO> GetCompletedInstructions(long userId)
|
||||
{
|
||||
var completedTests = _instructionTestService.GetCompletedInstructionTestsByUserId(userId);
|
||||
var instructions = _unitOfWork.InstructionRepository.Get()
|
||||
.Where(i => completedTests.Any(t => i.InstructionTestId == t.Id));
|
||||
|
||||
return _mapper.Map<List<InstructionDTO>>(instructions);
|
||||
}
|
||||
|
||||
public List<InstructionDTO> GetInstructionById(long userId, long instructionId)
|
||||
{
|
||||
// TODO: select accessible only
|
||||
var instruction = _unitOfWork.InstructionRepository.GetByID(instructionId);
|
||||
return _mapper.Map<List<InstructionDTO>>(instruction);
|
||||
}
|
||||
|
||||
public List<InstructionDTO> GetInstructionsByCategoryId(long userId, long categoryId)
|
||||
{
|
||||
var category = _unitOfWork.InstructionCategoryRepository.GetByID(categoryId);
|
||||
if (category == null)
|
||||
{
|
||||
throw new CategoryNotFoundException();
|
||||
}
|
||||
|
||||
var instructions = _unitOfWork.InstructionRepository.Get().Where(i => i.CategoryId == categoryId);
|
||||
return _mapper.Map<List<InstructionDTO>>(instructions);
|
||||
}
|
||||
|
||||
public List<InstructionDTO> GetUnfinishedInstructions(long userId)
|
||||
{
|
||||
// TODO: only show accessible
|
||||
var completedTests = _instructionTestService.GetCompletedInstructionTestsByUserId(userId);
|
||||
|
||||
var instructions = _unitOfWork.InstructionRepository.Get()
|
||||
.Where(i => !completedTests.Any(t => i.InstructionTestId == t.Id));
|
||||
|
||||
return _mapper.Map<List<InstructionDTO>>(instructions);
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateInstructionById(Instruction model)
|
||||
{
|
||||
var existingInstruction = _unitOfWork.InstructionRepository.GetByID(model.Id);
|
||||
if (existingInstruction == null)
|
||||
{
|
||||
throw new InstructionNotFoundException();
|
||||
}
|
||||
|
||||
await _unitOfWork.BeginTransactionAsync();
|
||||
|
||||
_unitOfWork.InstructionParagraphRepository.DeleteRange(existingInstruction.Paragraphs);
|
||||
|
||||
if (await _unitOfWork.SaveAsync() == false)
|
||||
{
|
||||
_logger.LogError($"Failure to delete older paragraphs for instruction {model.Id} during update");
|
||||
throw new InstructionUpdateException();
|
||||
}
|
||||
|
||||
_unitOfWork.InstructionRepository.Update(model);
|
||||
if (await _unitOfWork.SaveAsync() == false)
|
||||
{
|
||||
_logger.LogError($"Instruction {model.Id} could not be updated");
|
||||
throw new InstructionUpdateException();
|
||||
}
|
||||
_logger.LogInformation($"Instruction {model.Id} updated");
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateInstructionById(UpdateInstructionRequest model)
|
||||
{
|
||||
Instruction? existingInstruction = _unitOfWork.InstructionRepository.GetByID(model.Id);
|
||||
|
||||
if (existingInstruction == null)
|
||||
{
|
||||
throw new InstructionNotFoundException();
|
||||
}
|
||||
|
||||
existingInstruction.Title = model.Title;
|
||||
existingInstruction.Description = model.Description;
|
||||
existingInstruction.CategoryId = model.CategoryId;
|
||||
existingInstruction.Paragraphs = _mapper.Map<List<InstructionParagraph>>(model.Paragraphs);
|
||||
existingInstruction.AssignDate = model.AssignDate;
|
||||
existingInstruction.DeadlineDate = model.DeadlineDate;
|
||||
existingInstruction.IsEnabled = model.IsEnabled;
|
||||
|
||||
return await UpdateInstructionById(_mapper.Map<Instruction>(model));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user