Clean up
This commit is contained in:
@@ -1,38 +0,0 @@
|
|||||||
using KTUSAPS.Data;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace KTUSAPS.Auth
|
|
||||||
{
|
|
||||||
public class AdminAuthorizationHandler : AuthorizationHandler<AdminRequirement>
|
|
||||||
{
|
|
||||||
private readonly IServiceProvider serviceProvider;
|
|
||||||
public AdminAuthorizationHandler(IServiceProvider serviceProvider)
|
|
||||||
{
|
|
||||||
this.serviceProvider = serviceProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async override Task HandleRequirementAsync(AuthorizationHandlerContext context, AdminRequirement requirement)
|
|
||||||
{
|
|
||||||
var idclaim = context.User.Claims.Where(c => c.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier").FirstOrDefault();
|
|
||||||
if(idclaim == default)
|
|
||||||
{
|
|
||||||
context.Fail();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
using var scope = serviceProvider.CreateScope();
|
|
||||||
var dataContext = scope.ServiceProvider.GetRequiredService<SAPSDataContext>();
|
|
||||||
var admin = await dataContext.Admins.Where(a => a.UserId == idclaim.Value).FirstOrDefaultAsync();
|
|
||||||
if (admin != default)
|
|
||||||
{
|
|
||||||
context.Succeed(requirement);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
context.Fail();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
8
KTUSAPS/Auth/MyIssueRequirement.cs
Normal file
8
KTUSAPS/Auth/MyIssueRequirement.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
|
namespace KTUSAPS.Auth
|
||||||
|
{
|
||||||
|
public class MyIssueRequirement : IAuthorizationRequirement
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
117
KTUSAPS/Auth/SaPsAuthorizationHandler.cs
Normal file
117
KTUSAPS/Auth/SaPsAuthorizationHandler.cs
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
using KTUSAPS.Data;
|
||||||
|
using KTUSAPS.Data.Model;
|
||||||
|
using KTUSAPS.Extensions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace KTUSAPS.Auth
|
||||||
|
{
|
||||||
|
public class SaPsAuthorizationHandler : IAuthorizationHandler
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider serviceProvider;
|
||||||
|
public SaPsAuthorizationHandler(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
this.serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task HandleAsync(AuthorizationHandlerContext context)
|
||||||
|
{
|
||||||
|
var cache = new AuthProcessingCache(context.User, serviceProvider);
|
||||||
|
foreach (var requirement in context.Requirements)
|
||||||
|
{
|
||||||
|
if (requirement is AdminRequirement adminRequirement)
|
||||||
|
await HandleRequirementAsync(context, adminRequirement, cache);
|
||||||
|
if (requirement is MyIssueRequirement myIssueRequirement)
|
||||||
|
await HandleRequirementAsync(context, myIssueRequirement, cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleRequirementAsync(AuthorizationHandlerContext context, MyIssueRequirement myIssueRequirement, AuthProcessingCache cache)
|
||||||
|
{
|
||||||
|
if(context.Resource is not Issue issue)
|
||||||
|
throw new Exception($"'{nameof(MyIssueRequirement)}' must be issued with resource of type '{nameof(Issue)}'");
|
||||||
|
|
||||||
|
if(issue.UserID == context.User.GetUserId())
|
||||||
|
{
|
||||||
|
context.Succeed(myIssueRequirement);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(await cache.DetermineIsAdminAsync())
|
||||||
|
{
|
||||||
|
context.Succeed(myIssueRequirement);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleRequirementAsync(AuthorizationHandlerContext context, AdminRequirement adminRequirement, AuthProcessingCache cache)
|
||||||
|
{
|
||||||
|
if(await cache.DetermineIsAdminAsync())
|
||||||
|
{
|
||||||
|
context.Succeed(adminRequirement);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.Fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class AuthProcessingCache
|
||||||
|
{
|
||||||
|
private readonly ClaimsPrincipal _user;
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
private bool? isAdmin;
|
||||||
|
public bool IsAdmin => determineIsAdminCached();
|
||||||
|
|
||||||
|
public AuthProcessingCache(ClaimsPrincipal user, IServiceProvider serviceProvider) {
|
||||||
|
_user = user;
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool determineIsAdminCached()
|
||||||
|
{
|
||||||
|
if (isAdmin == null)
|
||||||
|
isAdmin = determineIsAdmin();
|
||||||
|
return isAdmin.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool determineIsAdmin()
|
||||||
|
{
|
||||||
|
var objectId = _user.GetObjectId();
|
||||||
|
if (objectId == default)
|
||||||
|
return false;
|
||||||
|
using var scope = _serviceProvider.CreateScope();
|
||||||
|
var dataContext = scope.ServiceProvider.GetRequiredService<SAPSDataContext>();
|
||||||
|
var admin = dataContext.Admins.Where(a => a.UserId == objectId).FirstOrDefault();
|
||||||
|
if (admin != default)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ValueTask<bool> determineIsAdminAsync()
|
||||||
|
{
|
||||||
|
var idclaim = _user.Claims.Where(c => c.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier").FirstOrDefault();
|
||||||
|
if (idclaim == default)
|
||||||
|
return false;
|
||||||
|
using var scope = _serviceProvider.CreateScope();
|
||||||
|
var dataContext = scope.ServiceProvider.GetRequiredService<SAPSDataContext>();
|
||||||
|
var admin = await dataContext.Admins.Where(a => a.UserId == idclaim.Value).FirstOrDefaultAsync();
|
||||||
|
if (admin != default)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<bool> DetermineIsAdminAsync()
|
||||||
|
{
|
||||||
|
if (isAdmin == null)
|
||||||
|
isAdmin = await determineIsAdminAsync();
|
||||||
|
return isAdmin.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -47,9 +47,9 @@
|
|||||||
>Pateiktos problemos</router-link
|
>Pateiktos problemos</router-link
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
<!-- <li class="nav-item">
|
<li v-if="$root.isLocal" class="nav-item">
|
||||||
<a href="/swagger" class="nav-link">Swagger UI</a>
|
<a href="/swagger" class="nav-link">Swagger UI</a>
|
||||||
</li> -->
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="navbar-nav">
|
<div class="navbar-nav">
|
||||||
<template v-if="$store.state.msalAuth.isLoggedIn">
|
<template v-if="$store.state.msalAuth.isLoggedIn">
|
||||||
|
@@ -1,303 +0,0 @@
|
|||||||
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<ActionResult<IEnumerable<Issue>>> 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<ActionResult<Issue>> 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<ActionResult<Issue>> 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<ActionResult<Issue>> 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<IActionResult> 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<ActionResult<PublishedProblem>> 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<ActionResult<PublishedProblem>> 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<IActionResult> 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<ActionResult<PublishedProblem>> 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<ActionResult<PublishedFeedback>> 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<IActionResult> 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<ActionResult<IEnumerable<Vote>>> 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<ActionResult<Vote>> 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<ActionResult<Vote>> 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<ActionResult<Vote>> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,9 +1,12 @@
|
|||||||
using KTUSAPS.Data.Model;
|
using KTUSAPS.Auth;
|
||||||
|
using KTUSAPS.Data.Model;
|
||||||
using KTUSAPS.Extensions;
|
using KTUSAPS.Extensions;
|
||||||
|
using KTUSAPS.Models;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -15,19 +18,29 @@ namespace KTUSAPS.Controllers
|
|||||||
public class IssuesController : ControllerBase
|
public class IssuesController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly Data.SAPSDataContext dataContext;
|
private readonly Data.SAPSDataContext dataContext;
|
||||||
|
private readonly IAuthorizationService _authorizationService;
|
||||||
|
|
||||||
public IssuesController(Data.SAPSDataContext dataContext)
|
public IssuesController(Data.SAPSDataContext dataContext, IAuthorizationService authorizationService)
|
||||||
{
|
{
|
||||||
this.dataContext = dataContext;
|
this.dataContext = dataContext;
|
||||||
|
_authorizationService = authorizationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[Authorize("admin")]
|
[Authorize]
|
||||||
public async Task<ActionResult<IEnumerable<Issue>>> GetIssues()
|
public async Task<ActionResult<IEnumerable<Issue>>> GetIssues([FromQuery] RequestScope requestScope = RequestScope.All)
|
||||||
{
|
{
|
||||||
|
if (requestScope == RequestScope.All)
|
||||||
|
{
|
||||||
|
var authorizationResult = await _authorizationService.AuthorizeAsync(User, "admin");
|
||||||
|
if (!authorizationResult.Succeeded)
|
||||||
|
return Forbid();
|
||||||
return await dataContext.Issues.ToListAsync();
|
return await dataContext.Issues.ToListAsync();
|
||||||
|
} else if (requestScope == RequestScope.My)
|
||||||
|
return await dataContext.Issues.Where(i => i.UserID == User.GetUserId()).ToListAsync();
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
@@ -59,13 +72,17 @@ namespace KTUSAPS.Controllers
|
|||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[Authorize("admin")]
|
[Authorize]
|
||||||
public ActionResult<Issue> GetIssue(int id)
|
public async Task<ActionResult<Issue>> GetIssue(int id)
|
||||||
{
|
{
|
||||||
var issue = dataContext.Issues.AsQueryable().Where(i => i.Id == id).FirstOrDefault();
|
var issue = dataContext.Issues.AsQueryable().Where(i => i.Id == id).FirstOrDefault();
|
||||||
if(issue == default)
|
if(issue == default)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
|
var authorizationResult = await _authorizationService.AuthorizeAsync(User, issue, new MyIssueRequirement());
|
||||||
|
if(authorizationResult.Succeeded)
|
||||||
return Ok(issue);
|
return Ok(issue);
|
||||||
|
return Forbid();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPatch("{id}")]
|
[HttpPatch("{id}")]
|
||||||
|
8
KTUSAPS/Models/RequestScope.cs
Normal file
8
KTUSAPS/Models/RequestScope.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace KTUSAPS.Models
|
||||||
|
{
|
||||||
|
public enum RequestScope
|
||||||
|
{
|
||||||
|
All,
|
||||||
|
My,
|
||||||
|
}
|
||||||
|
}
|
@@ -45,21 +45,19 @@ namespace KTUSAPS
|
|||||||
|
|
||||||
services.AddAuthorization((configure) =>
|
services.AddAuthorization((configure) =>
|
||||||
{
|
{
|
||||||
var adminPolicy = new Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder()
|
configure.DefaultPolicy = new AuthorizationPolicyBuilder()
|
||||||
.RequireAuthenticatedUser()
|
.RequireAuthenticatedUser()
|
||||||
|
.Build();
|
||||||
|
configure.AddPolicy("admin", new AuthorizationPolicyBuilder(configure.DefaultPolicy)
|
||||||
.AddRequirements(new AdminRequirement())
|
.AddRequirements(new AdminRequirement())
|
||||||
.Build();
|
.Build());
|
||||||
configure.AddPolicy("admin", adminPolicy);
|
|
||||||
configure.DefaultPolicy = new Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder()
|
|
||||||
.RequireAuthenticatedUser()
|
|
||||||
.Build();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var connectionString = Configuration.GetConnectionString("Main");
|
var connectionString = Configuration.GetConnectionString("Main");
|
||||||
services.AddDbContext<Data.SAPSDataContext>((options) => options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)));
|
services.AddDbContext<Data.SAPSDataContext>((options) => options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)));
|
||||||
services.AddHostedService<DatabaseInitializationService>();
|
services.AddHostedService<DatabaseInitializationService>();
|
||||||
|
|
||||||
services.AddSingleton<IAuthorizationHandler, AdminAuthorizationHandler>();
|
services.AddSingleton<IAuthorizationHandler, SaPsAuthorizationHandler>();
|
||||||
|
|
||||||
services.AddSwaggerGen(options =>
|
services.AddSwaggerGen(options =>
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user