using KTUSAPS.Data.Model; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using System.Linq; using Microsoft.AspNetCore.Mvc.Infrastructure; namespace KTUSAPS.Controllers { [Route("api")] [ApiController] [Produces("application/json")] public class GlueController : ControllerBase { private readonly Data.SAPSDataContext dataContext; private readonly IssuesController issuesController; private readonly PublishedProblemsController publishedProblemsController; private readonly PublishedFeedbacksController publishedFeedbacksController; public GlueController(Data.SAPSDataContext dataContext, IssuesController issuesController, PublishedProblemsController publishedProblemsController, PublishedFeedbacksController publishedFeedbacksController) { this.dataContext = dataContext; this.issuesController = issuesController; this.publishedProblemsController = publishedProblemsController; this.publishedFeedbacksController = publishedFeedbacksController; } [HttpGet("IssueTypes/{typeId}/Issues")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task>> GetIssueTypeIssuesAsync(int typeId) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); return Ok(issueType.Issues); } [HttpPost("IssueTypes/{typeId}/Issues")] [ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task> CreateIssueTypeIssueAsync(int typeId, [FromBody] Issue issueToCreate) { var issueType = await dataContext.IssueTypes.FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); issueToCreate.IssueTypeId = issueType.Id; var createResult = await issuesController.CreateIssueAsync(issueToCreate); if(createResult.Result is CreatedAtActionResult actionResult && actionResult.Value is Issue createdIssue) return CreatedAtAction(nameof(GetIssueTypeIssueAsync), new { typeId = typeId, issueId = createdIssue.Id }, createdIssue); return createResult; } [HttpGet("IssueTypes/{typeId}/Issues/{issueId}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetIssueTypeIssueAsync(int typeId, int issueId) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); var issue = issueType.Issues.FirstOrDefault(i => i.Id == issueId); if (issue == null) return NotFound(); return Ok(issue); } [HttpPatch("IssueTypes/{typeId}/Issues/{issueId}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> UpdateIssueTypeIssueAsync(int typeId, int issueId, [FromBody] Issue issue) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); var dbIssue = issueType.Issues.FirstOrDefault(i => i.Id == issueId); if (dbIssue == null) return NotFound(); return await issuesController.UpdateIssueAsync(dbIssue.Id, issue); } [HttpDelete("IssueTypes/{typeId}/Issues/{issueId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DeleteIssueTypeIssueAsync(int typeId, int issueId) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); var issue = issueType.Issues.FirstOrDefault(i => i.Id == issueId); if (issue == null) return NotFound(); return await issuesController.DeleteIssueAsync(issue.Id); } [HttpGet("IssueTypes/{typeId}/Issues/{issueId}/Problem")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetIssueTypeIssueProblemAsync(int typeId, int issueId) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).ThenInclude(i => i.Problem).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); var issue = issueType.Issues.FirstOrDefault(i => i.Id == issueId); if (issue == null) return NotFound(); if (issue.Problem == null) return NotFound(); return Ok(issue.Problem); } [HttpPost("IssueTypes/{typeId}/Issues/{issueId}/Problem")] [ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status409Conflict)] public async Task> CreateIssueTypeIssueProblemAsync(int typeId, int issueId, [FromBody] PublishedProblem publishedProblem) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).ThenInclude(i => i.Problem).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); var issue = issueType.Issues.FirstOrDefault(i => i.Id == issueId); if (issue == null) return NotFound(); if (issue.Problem != null) return Conflict(); publishedProblem.IssueId = issue.Id; var createResult = await publishedProblemsController.CreatePublishedProblem(publishedProblem); if (createResult.Result is CreatedAtActionResult actionResult && actionResult.Value is PublishedProblem createdProblem) return CreatedAtAction(nameof(GetIssueTypeIssueProblemAsync), new { typeId = typeId, issueId = issue.Id }, createdProblem); return createResult; } [HttpDelete("IssueTypes/{typeId}/Issues/{issueId}/Problem")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DeleteIssueTypeIssueProblemAsync(int typeId, int issueId) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).ThenInclude(i => i.Problem).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); var issue = issueType.Issues.FirstOrDefault(i => i.Id == issueId); if (issue == null) return NotFound(); if (issue.Problem == null) return NotFound(); dataContext.PublishedProblems.Remove(issue.Problem); await dataContext.SaveChangesAsync(); return NoContent(); } [HttpGet("IssueTypes/{typeId}/Issues/{issueId}/Feedback")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetIssueTypeIssueFeedbackAsync(int typeId, int issueId) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).ThenInclude(i => i.Feedback).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); var issue = issueType.Issues.FirstOrDefault(i => i.Id == issueId); if (issue == null) return NotFound(); if (issue.Feedback == null) return NotFound(); return Ok(issue.Feedback); } [HttpPost("IssueTypes/{typeId}/Issues/{issueId}/Feedback")] [ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status409Conflict)] public async Task> CreateIssueTypeIssueFeedbackAsync(int typeId, int issueId, PublishedFeedback publishedFeedback) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).ThenInclude(i => i.Feedback).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); var issue = issueType.Issues.FirstOrDefault(i => i.Id == issueId); if (issue == null) return NotFound(); if (issue.Feedback != null) return Conflict(); publishedFeedback.IssueId = issue.Id; var createResult = await publishedFeedbacksController.PostPublishedFeedback(publishedFeedback); if (createResult.Result is CreatedAtActionResult actionResult && actionResult.Value is PublishedFeedback createdFeedback) return CreatedAtAction(nameof(GetIssueTypeIssueFeedbackAsync), new { typeId = typeId, issueId = issue.Id }, createdFeedback); return createResult; } [HttpDelete("IssueTypes/{typeId}/Issues/{issueId}/Feedback")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DeleteIssueTypeIssueFeedbackAsync(int typeId, int issueId) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).ThenInclude(i => i.Problem).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); var issue = issueType.Issues.FirstOrDefault(i => i.Id == issueId); if (issue == null) return NotFound(); if (issue.Feedback == null) return NotFound(); dataContext.PublishedFeedbacks.Remove(issue.Feedback); await dataContext.SaveChangesAsync(); return NoContent(); } [HttpGet("IssueTypes/{typeId}/Issues/{issueId}/Problem/Votes")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task>> GetIssueTypeIssueProblemVotesAsync(int typeId, int issueId) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).ThenInclude(i => i.Problem).ThenInclude(p => p.Votes).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); var issue = issueType.Issues.FirstOrDefault(i => i.Id == issueId); if (issue == null) return NotFound(); if (issue.Problem == null) return NotFound(); return Ok(issue.Problem.Votes); } [HttpPost("IssueTypes/{typeId}/Issues/{issueId}/Problem/Votes")] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status201Created)] public async Task> CreateIssueTypeIssueProblemVotesAsync(int typeId, int issueId, Vote vote) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).ThenInclude(i => i.Problem).ThenInclude(p => p.Votes).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); var issue = issueType.Issues.FirstOrDefault(i => i.Id == issueId); if (issue == null) return NotFound(); if (issue.Problem == null) return NotFound(); // TODO: Get user id from auth claims if (vote.UserId == default) return BadRequest("Please provide user id"); vote.Problem = issue.Problem; dataContext.Votes.Add(vote); await dataContext.SaveChangesAsync(); return CreatedAtAction(nameof(GetIssueTypeIssueProblemVoteAsync), new { typeId = typeId, issueId = issue.Id, userId = vote.UserId }, vote); } [HttpGet("IssueTypes/{typeId}/Issues/{issueId}/Problem/Votes/{userId}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetIssueTypeIssueProblemVoteAsync(int typeId, int issueId, string userId) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).ThenInclude(i => i.Problem).ThenInclude(p => p.Votes).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); var issue = issueType.Issues.FirstOrDefault(i => i.Id == issueId); if (issue == null) return NotFound(); if (issue.Problem == null) return NotFound(); var vote = issue.Problem.Votes.FirstOrDefault(v => v.UserId == userId); if(vote == default) return NotFound(); return Ok(vote); } [HttpDelete("IssueTypes/{typeId}/Issues/{issueId}/Problem/Votes/{userId}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> DeleteIssueTypeIssueProblemVoteAsync(int typeId, int issueId, string userId) { var issueType = await dataContext.IssueTypes.Include(t => t.Issues).ThenInclude(i => i.Problem).ThenInclude(p => p.Votes).FirstOrDefaultAsync(t => t.Id == typeId); if (issueType == default) return NotFound(); var issue = issueType.Issues.FirstOrDefault(i => i.Id == issueId); if (issue == null) return NotFound(); if (issue.Problem == null) return NotFound(); var vote = issue.Problem.Votes.FirstOrDefault(v => v.UserId == userId); if (vote == default) return NotFound(); dataContext.Votes.Remove(vote); await dataContext.SaveChangesAsync(); return NoContent(); } } }