diff --git a/KTUSAPS.Data/Model/Issue.cs b/KTUSAPS.Data/Model/Issue.cs index 1376493..932a4f6 100644 --- a/KTUSAPS.Data/Model/Issue.cs +++ b/KTUSAPS.Data/Model/Issue.cs @@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace KTUSAPS.Data.Model @@ -23,9 +24,11 @@ namespace KTUSAPS.Data.Model public string Description { get; set; } public int IssueTypeId { get; set; } + [JsonIgnore] public virtual IssueType IssueType { get; set; } - + [JsonIgnore] public virtual PublishedProblem Problem { get; set; } + [JsonIgnore] public virtual PublishedFeedback Feedback { get; set; } public Issue() diff --git a/KTUSAPS.Data/Model/IssueType.cs b/KTUSAPS.Data/Model/IssueType.cs index 3d25130..1e7c833 100644 --- a/KTUSAPS.Data/Model/IssueType.cs +++ b/KTUSAPS.Data/Model/IssueType.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace KTUSAPS.Data.Model @@ -12,6 +13,7 @@ namespace KTUSAPS.Data.Model public string Name { get; set; } public string NameEn { get; set; } + [JsonIgnore] public virtual HashSet Issues { get; set; } } diff --git a/KTUSAPS.Data/Model/Models.cd b/KTUSAPS.Data/Model/Models.cd index 3569aef..73d961c 100644 --- a/KTUSAPS.Data/Model/Models.cd +++ b/KTUSAPS.Data/Model/Models.cd @@ -7,9 +7,9 @@ Model\Issue.cs + - @@ -57,7 +57,7 @@ - + AAECAAAAAAAAAAAAACAAAAQAAAAAAAAAAAAAAAAAAAA= Model\IssueType.cs @@ -66,5 +66,12 @@ + + + + AAAAAAAEAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAA= + Model\Admin.cs + + \ No newline at end of file diff --git a/KTUSAPS.Data/Model/PublishedFeedback.cs b/KTUSAPS.Data/Model/PublishedFeedback.cs index b68f9f0..8cb9b9e 100644 --- a/KTUSAPS.Data/Model/PublishedFeedback.cs +++ b/KTUSAPS.Data/Model/PublishedFeedback.cs @@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace KTUSAPS.Data.Model @@ -22,6 +23,7 @@ namespace KTUSAPS.Data.Model public DateTime Created { get; set; } public int? IssueId { get; set; } + [JsonIgnore] public virtual Issue Issue { get; set; } public PublishedFeedback() diff --git a/KTUSAPS.Data/Model/PublishedProblem.cs b/KTUSAPS.Data/Model/PublishedProblem.cs index d088ee8..0a07b5d 100644 --- a/KTUSAPS.Data/Model/PublishedProblem.cs +++ b/KTUSAPS.Data/Model/PublishedProblem.cs @@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace KTUSAPS.Data.Model @@ -22,10 +23,13 @@ namespace KTUSAPS.Data.Model public DateTime Created { get; set; } public int? IssueId { get; set; } + [JsonIgnore] public virtual Issue Issue { get; set; } public int? SolutionId { get; set; } + [JsonIgnore] public virtual Solution Solution { get; set; } + [JsonIgnore] public virtual HashSet Votes { get; set; } public PublishedProblem() diff --git a/KTUSAPS.Data/Model/Solution.cs b/KTUSAPS.Data/Model/Solution.cs index fa2f94b..1c9bca0 100644 --- a/KTUSAPS.Data/Model/Solution.cs +++ b/KTUSAPS.Data/Model/Solution.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; namespace KTUSAPS.Data.Model { @@ -13,7 +14,7 @@ namespace KTUSAPS.Data.Model [MaxLength] public string SolutionEn { get; set; } - + [JsonIgnore] public virtual PublishedProblem Problem { get; set; } public DateTime Created { get; set; } diff --git a/KTUSAPS.Data/Model/Vote.cs b/KTUSAPS.Data/Model/Vote.cs index 6882d42..990cc6b 100644 --- a/KTUSAPS.Data/Model/Vote.cs +++ b/KTUSAPS.Data/Model/Vote.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; +using System.Text.Json.Serialization; using System.Threading.Tasks; namespace KTUSAPS.Data.Model @@ -12,6 +13,7 @@ namespace KTUSAPS.Data.Model [MaxLength(64)] public string UserId { get; set; } public int ProblemId { get; set; } + [JsonIgnore] public virtual PublishedProblem Problem { get; set; } } diff --git a/KTUSAPS/AuthorizeCheckOperationFilter.cs b/KTUSAPS/AuthorizeCheckOperationFilter.cs new file mode 100644 index 0000000..dd716b6 --- /dev/null +++ b/KTUSAPS/AuthorizeCheckOperationFilter.cs @@ -0,0 +1,38 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Generic; +using System.Linq; + +namespace KTUSAPS +{ + public class AuthorizeCheckOperationFilter : IOperationFilter + { + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + var hasAuthorize = + context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType().Any() + || context.MethodInfo.GetCustomAttributes(true).OfType().Any(); + + if (hasAuthorize) + { + operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" }); + operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" }); + + operation.Security = new List + { + new OpenApiSecurityRequirement + { + [ + new OpenApiSecurityScheme {Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "msad"} + } + ] = new[] {"email", "openid", "profile"} + } + }; + } + } + } +} diff --git a/KTUSAPS/Controllers/AuthMetadataController.cs b/KTUSAPS/Controllers/AuthMetadataController.cs index d967653..1a4f510 100644 --- a/KTUSAPS/Controllers/AuthMetadataController.cs +++ b/KTUSAPS/Controllers/AuthMetadataController.cs @@ -41,7 +41,6 @@ namespace KTUSAPS.Controllers /// Provided token is correct. /// No valid token provided. [Authorize] - [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status200OK)] [HttpGet("Authed")] public bool IsAuthed() => true; diff --git a/KTUSAPS/Controllers/GlueController.cs b/KTUSAPS/Controllers/GlueController.cs new file mode 100644 index 0000000..321c08f --- /dev/null +++ b/KTUSAPS/Controllers/GlueController.cs @@ -0,0 +1,303 @@ +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(); + } + } +} diff --git a/KTUSAPS/Controllers/IssueTypesController.cs b/KTUSAPS/Controllers/IssueTypesController.cs index 95df773..043060d 100644 --- a/KTUSAPS/Controllers/IssueTypesController.cs +++ b/KTUSAPS/Controllers/IssueTypesController.cs @@ -58,11 +58,11 @@ namespace KTUSAPS.Controllers if (issueType == null) return NotFound(); - return issueType; + return Ok(issueType); } [HttpPatch("{id}")] - [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task UpdateIssueType(int id, IssueType issueType) { @@ -79,7 +79,7 @@ namespace KTUSAPS.Controllers await _context.SaveChangesAsync(); - return NoContent(); + return Ok(eIssueType.Entity); } diff --git a/KTUSAPS/Controllers/IssuesController.cs b/KTUSAPS/Controllers/IssuesController.cs index 9453463..a768166 100644 --- a/KTUSAPS/Controllers/IssuesController.cs +++ b/KTUSAPS/Controllers/IssuesController.cs @@ -77,7 +77,7 @@ namespace KTUSAPS.Controllers nameof(databaseIssue.Publishable) }); await dataContext.SaveChangesAsync(); - return NoContent(); + return Ok(eIssue.Entity); } [HttpDelete("{id}")] diff --git a/KTUSAPS/Controllers/PublishedFeedbacksController.cs b/KTUSAPS/Controllers/PublishedFeedbacksController.cs index 7879a71..743f07a 100644 --- a/KTUSAPS/Controllers/PublishedFeedbacksController.cs +++ b/KTUSAPS/Controllers/PublishedFeedbacksController.cs @@ -61,9 +61,9 @@ namespace KTUSAPS.Controllers } [HttpPatch("{id}")] - [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task UpdatePublishedFeedback(int id, PublishedFeedback publishedFeedback) + public async Task> UpdatePublishedFeedback(int id, PublishedFeedback publishedFeedback) { var databasePublishedFeedback = await _context.PublishedFeedbacks.FindAsync(id); if (databasePublishedFeedback == default) @@ -81,7 +81,7 @@ namespace KTUSAPS.Controllers await _context.SaveChangesAsync(); - return NoContent(); + return Ok(ePublishedFeedback.Entity); } diff --git a/KTUSAPS/Controllers/PublishedProblemsController.cs b/KTUSAPS/Controllers/PublishedProblemsController.cs index 366e863..8fed638 100644 --- a/KTUSAPS/Controllers/PublishedProblemsController.cs +++ b/KTUSAPS/Controllers/PublishedProblemsController.cs @@ -39,7 +39,7 @@ namespace KTUSAPS.Controllers if (publishedProblem.Id != default) return BadRequest("Id has been set on create request, please do not do that, set id to 0 or ommit it."); if (publishedProblem.Issue != null || publishedProblem.Solution != null || publishedProblem.Votes != null) - return BadRequest("Do not privide navigation property values."); + return BadRequest("Do not provide navigation property values."); _context.PublishedProblems.Add(publishedProblem); await _context.SaveChangesAsync(); @@ -61,9 +61,9 @@ namespace KTUSAPS.Controllers } [HttpPatch("{id}")] - [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task UpdatePublishedProblem(int id, PublishedProblem publishedProblem) + public async Task> UpdatePublishedProblem(int id, PublishedProblem publishedProblem) { var databasePublishedProblem = await _context.PublishedProblems.FindAsync(id); if (databasePublishedProblem == default) @@ -82,7 +82,7 @@ namespace KTUSAPS.Controllers await _context.SaveChangesAsync(); - return NoContent(); + return Ok(ePublishedProblem.Entity); } @@ -118,7 +118,7 @@ namespace KTUSAPS.Controllers } [HttpPost("{id}/Votes")] - [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> Vote(int id, Vote vote) diff --git a/KTUSAPS/KTUSAPS.csproj b/KTUSAPS/KTUSAPS.csproj index 2138b67..24264fa 100644 --- a/KTUSAPS/KTUSAPS.csproj +++ b/KTUSAPS/KTUSAPS.csproj @@ -10,20 +10,24 @@ $(DefaultItemExcludes);$(SpaRoot)node_modules\** + + true + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + diff --git a/KTUSAPS/Startup.cs b/KTUSAPS/Startup.cs index c088d22..569c250 100644 --- a/KTUSAPS/Startup.cs +++ b/KTUSAPS/Startup.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; +using System.Collections.Generic; using VueCliMiddleware; namespace KTUSAPS @@ -23,7 +24,10 @@ namespace KTUSAPS // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddControllers(); + services.AddControllers(options => + options.SuppressAsyncSuffixInActionNames = false + ) + .AddControllersAsServices(); services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/dist"; @@ -32,8 +36,9 @@ namespace KTUSAPS services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { + options.MetadataAddress = "https://login.microsoftonline.com/3415f2f7-f5a8-4092-b52a-003aaf844853/v2.0/.well-known/openid-configuration"; options.Audience = Configuration["ClientId"]; - options.Authority = Configuration["Authority"]; + //options.Authority = Configuration["Authority"]; }); services.AddAuthorization((configure) => @@ -47,7 +52,28 @@ namespace KTUSAPS services.AddDbContext((options) => options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString))); services.AddHostedService(); - services.AddSwaggerGen(); + services.AddSwaggerGen(options => + { + options.OperationFilter(); + options.AddSecurityDefinition("msad", new Microsoft.OpenApi.Models.OpenApiSecurityScheme() + { + Type = Microsoft.OpenApi.Models.SecuritySchemeType.OAuth2, + Flows = new Microsoft.OpenApi.Models.OpenApiOAuthFlows() + { + AuthorizationCode = new Microsoft.OpenApi.Models.OpenApiOAuthFlow() + { + AuthorizationUrl = new Uri("https://login.microsoftonline.com/3415f2f7-f5a8-4092-b52a-003aaf844853/oauth2/v2.0/authorize"), + TokenUrl = new Uri("https://login.microsoftonline.com/3415f2f7-f5a8-4092-b52a-003aaf844853/oauth2/v2.0/token"), + Scopes = new Dictionary + { + { "openid", "Access to user's id" }, + { "profile", "Access to user's name" }, + { "email", "Access to email" } + } + } + } + }); + }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. @@ -60,6 +86,10 @@ namespace KTUSAPS app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "API"); + + c.OAuthClientId(Configuration["ClientId"]); + c.OAuthAppName("KTUSA Problemø sistema"); + c.OAuthUsePkce(); }); } diff --git a/KTUSAPS/appsettings.json b/KTUSAPS/appsettings.json index bb80c6b..7710995 100644 --- a/KTUSAPS/appsettings.json +++ b/KTUSAPS/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "Main": "Server=localhost;User=saps;Password=B35eJUmIJxeG0g9yi6ni;Database=saps" + "Main": "Server=localhost;User=saps;Password=FuhcMfapPkGOH8DjPSAw;Database=saps" }, "Logging": { "LogLevel": { @@ -13,4 +13,4 @@ "ClientId": "411a8715-3d63-4a03-9be8-9370d920e36f", "Authority": "https://login.microsoftonline.com/3415f2f7-f5a8-4092-b52a-003aaf844853/v2.0", "Tenant": "3415f2f7-f5a8-4092-b52a-003aaf844853" -} +} \ No newline at end of file