Skip to content

Commit

Permalink
Honor the PublishOwnContent permission when using the content API (#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeAlhayek authored Nov 1, 2022
1 parent c5adad4 commit 27cee7c
Showing 1 changed file with 50 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using System;
using System.Linq;
using System.Net;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
using Newtonsoft.Json.Linq;
using OrchardCore.ContentManagement;
using OrchardCore.ContentManagement.Handlers;
using OrchardCore.ContentManagement.Metadata;

namespace OrchardCore.Contents.Controllers
Expand All @@ -16,7 +18,7 @@ namespace OrchardCore.Contents.Controllers
[Authorize(AuthenticationSchemes = "Api"), IgnoreAntiforgeryToken, AllowAnonymous]
public class ApiController : Controller
{
private static readonly JsonMergeSettings UpdateJsonMergeSettings = new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Replace };
private static readonly JsonMergeSettings UpdateJsonMergeSettings = new() { MergeArrayHandling = MergeArrayHandling.Replace };

private readonly IContentManager _contentManager;
private readonly IContentDefinitionManager _contentDefinitionManager;
Expand Down Expand Up @@ -99,39 +101,40 @@ public async Task<IActionResult> Post(ContentItem model, bool draft = false)

if (contentItem == null)
{
if (!await _authorizationService.AuthorizeAsync(User, CommonPermissions.PublishContent))
if (String.IsNullOrEmpty(model?.ContentType) || _contentDefinitionManager.GetTypeDefinition(model.ContentType) == null)
{
return this.ChallengeOrForbid("Api");
return BadRequest();
}

if (_contentDefinitionManager.GetTypeDefinition(model.ContentType) == null)
contentItem = await _contentManager.NewAsync(model.ContentType);
contentItem.Owner = User.FindFirstValue(ClaimTypes.NameIdentifier);

if (!await _authorizationService.AuthorizeAsync(User, CommonPermissions.PublishContent, contentItem))
{
return BadRequest();
return this.ChallengeOrForbid("Api");
}

var newContentItem = await _contentManager.NewAsync(model.ContentType);
newContentItem.Merge(model);
contentItem.Merge(model);

var result = await _contentManager.UpdateValidateAndCreateAsync(newContentItem, VersionOptions.Draft);
var result = await _contentManager.UpdateValidateAndCreateAsync(contentItem, VersionOptions.Draft);

if (!result.Succeeded)
{
return Problem(
title: S["One or more validation errors occurred."],
detail: string.Join(',', result.Errors),
statusCode: (int)HttpStatusCode.BadRequest);
// Add the validation results to the ModelState to present the errors as part of the response.
AddValidationErrorsToModelState(result);
}

// We check the model state after calling all handlers because they trigger WF content events so, even they are not
// intended to add model errors (only drivers), a WF content task may be executed inline and add some model errors.
else if (!ModelState.IsValid)
if (!ModelState.IsValid)
{
return Problem(
title: S["One or more validation errors occurred."],
detail: String.Join(", ", ModelState.Values.SelectMany(x => x.Errors.Select(x => x.ErrorMessage))),
statusCode: (int)HttpStatusCode.BadRequest);
return ValidationProblem(new ValidationProblemDetails(ModelState)
{
Title = S["One or more validation errors occurred."],
Detail = String.Join(", ", ModelState.Values.SelectMany(x => x.Errors.Select(x => x.ErrorMessage))),
Status = (int)HttpStatusCode.BadRequest,
});
}

contentItem = newContentItem;
}
else
{
Expand All @@ -147,19 +150,20 @@ public async Task<IActionResult> Post(ContentItem model, bool draft = false)

if (!result.Succeeded)
{
return Problem(
title: S["One or more validation errors occurred."],
detail: string.Join(',', result.Errors),
statusCode: (int)HttpStatusCode.BadRequest);
// Add the validation results to the ModelState to present the errors as part of the response.
AddValidationErrorsToModelState(result);
}

// We check the model state after calling all handlers because they trigger WF content events so, even they are not
// intended to add model errors (only drivers), a WF content task may be executed inline and add some model errors.
else if (!ModelState.IsValid)
if (!ModelState.IsValid)
{
return Problem(
title: S["One or more validation errors occurred."],
detail: String.Join(", ", ModelState.Values.SelectMany(x => x.Errors.Select(x => x.ErrorMessage))),
statusCode: (int)HttpStatusCode.BadRequest);
return ValidationProblem(new ValidationProblemDetails(ModelState)
{
Title = S["One or more validation errors occurred."],
Detail = String.Join(", ", ModelState.Values.SelectMany(x => x.Errors.Select(x => x.ErrorMessage))),
Status = (int)HttpStatusCode.BadRequest,
});
}
}

Expand All @@ -174,5 +178,23 @@ public async Task<IActionResult> Post(ContentItem model, bool draft = false)

return Ok(contentItem);
}

private void AddValidationErrorsToModelState(ContentValidateResult result)
{
foreach (var error in result.Errors)
{
if (error.MemberNames != null && error.MemberNames.Any())
{
foreach (var memberName in error.MemberNames)
{
ModelState.AddModelError(memberName, error.ErrorMessage);
}
}
else
{
ModelState.AddModelError(String.Empty, error.ErrorMessage);
}
}
}
}
}

0 comments on commit 27cee7c

Please sign in to comment.