Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,11 @@ with an `Origin` header. Native CORS middleware handles `[DisableCors]` endpoint
metadata; it does not authorize browser CMS access. Do not add browser CMS calls,
a permissive CORS policy or a frontend-origin allowlist as a workaround.

Legacy account surface actions are disabled. The old `/api/profile/image-process`
and `/api/newsletter/signup` routes are removed. All member and newsletter writes
now use the private bridge. The legacy account controller type remains only so
historical Razor views compile.

A bounded native-CMS journey passed real login, session, logout, SMTP delivery and
password reset. It used a synthetic member created through the native member
manager in a builtin-member-only database. That runtime lacks the legacy SGF
Expand Down
8 changes: 0 additions & 8 deletions SgfDevs.Tests/DirectoryApiContractTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,4 @@ private static string[] GetContentTypes(ProducesResponseTypeAttribute attribute)
return contentTypes.ToArray();
}

[Fact]
public void ProfileImageEndpoint_RemainsMemberProtected()
{
var method = typeof(DevsApiController).GetMethod(nameof(DevsApiController.UploadProfileImage))!;

Assert.Contains(method.GetCustomAttributes(), attribute =>
attribute.GetType().Name == "UmbracoMemberAuthorizeAttribute");
}
}
2 changes: 2 additions & 0 deletions SgfDevs/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

namespace SGFDevs.Controllers;

// Legacy Razor views still reference this type. Only the private bridge handles member mutations.
[NonController]
[AutoValidateAntiforgeryToken]
public class AccountController : SurfaceController
{
Expand Down
104 changes: 4 additions & 100 deletions SgfDevs/Controllers/DevsApiController.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SGFDevs.Dev;
using Examine;
using SgfDevs.Dev;
using SGFDevs.ViewModels;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Web.Common;
using Umbraco.Cms.Web.Common.Filters;
using Tag = Umbraco.Cms.Web.Common.PublishedModels.Tag;
using Umbraco.Extensions;

Expand All @@ -24,48 +17,22 @@ namespace SGFDevs.Controllers;
[ApiController]
public class DevsApiController : Controller
{
private DirectoryHelper _directoryHelper;
private IMemberService _memberService;
private IExamineManager _examineManager;
private UmbracoHelper _helper;
private IMemberManager _memberManager;
private IMediaService _mediaService;
private MediaFileManager _mediaFileManager;
private IShortStringHelper _shortStringHelper;
private IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider;
private MediaUrlGeneratorCollection _mediaUrlGeneratorCollection;
private NewsletterHelper _newsletterHelper;
private readonly DirectoryHelper _directoryHelper;
private readonly IMemberService _memberService;
private readonly IExamineManager _examineManager;
private readonly MemberConverter _memberConverter;
private readonly MemberTagDisplayService _memberTagDisplayService;


public DevsApiController(
DirectoryHelper directoryHelper,
IMemberService memberService,
IExamineManager examineManager,
UmbracoHelper helper,
IMemberManager memberManager,
IMediaService mediaService,
MediaFileManager mediaFileManager,
IShortStringHelper shortStringHelper,
IContentTypeBaseServiceProvider contentTypeBaseServiceProvider,
MediaUrlGeneratorCollection mediaUrlGeneratorCollection,
NewsletterHelper newsletterHelper,
MemberConverter memberConverter,
MemberTagDisplayService memberTagDisplayService
)
MemberTagDisplayService memberTagDisplayService)
{
_directoryHelper = directoryHelper;
_memberService = memberService;
_examineManager = examineManager;
_helper = helper;
_memberManager = memberManager;
_mediaService = mediaService;
_mediaFileManager = mediaFileManager;
_shortStringHelper = shortStringHelper;
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
_mediaUrlGeneratorCollection = mediaUrlGeneratorCollection;
_newsletterHelper = newsletterHelper;
_memberConverter = memberConverter;
_memberTagDisplayService = memberTagDisplayService;
}
Expand Down Expand Up @@ -148,69 +115,6 @@ public ActionResult<IReadOnlyList<PublicDirectoryMemberDto>> GetSearch(
return Ok(filteredMembers);
}

[Route("api/profile/image-process")]
[UmbracoMemberAuthorize]
public async Task<IActionResult> UploadProfileImage()
{
var currentMember = await _memberManager.GetCurrentMemberAsync();
if (currentMember == null)
{
return Forbid();
}
var member = _memberConverter.FromContent(_memberManager.AsPublishedMember(currentMember));

//var request = HttpContext.Current.Request;
//var request = HttpContext.Request;
var request = Request;

if (request.Form.Files.Count > 0)
{
var file = request.Form.Files[0];

if(file.Length > 0)
{
var filesExtension = System.IO.Path.GetExtension(file.FileName);
var newFileName = member.Username + filesExtension;
var membersMediaFolder = _mediaService.GetRootMedia().FirstOrDefault(x => x.Name.InvariantEquals("Members"));

// Need to explore and see if mediaService.SetMediaFileContent will work to
// update an item if it already exists instead of always creating a new one.
// For now, just create dupes!
// - Myke
var media = _mediaService.CreateMedia(member.Username, membersMediaFolder, Constants.Conventions.MediaTypes.Image);

media.SetValue(
_mediaFileManager,
_mediaUrlGeneratorCollection,
_shortStringHelper,
_contentTypeBaseServiceProvider,
Constants.Conventions.Media.File,
newFileName,
file.OpenReadStream()
);
_mediaService.Save(media);

var imageUdi = new GuidUdi("media", media.Key).ToString();

return Ok(imageUdi);
}
}

return BadRequest();
}

[HttpPost]
[Route("api/newsletter/signup")]
public async Task<IActionResult> NewsletterSignUp([FromForm] string email, [FromForm(Name = "name")] string honeypot)
{
if (string.IsNullOrEmpty(honeypot))
{
await _newsletterHelper.Subscribe(email);
}

return Ok();
}

private PublicDirectoryMemberDto BuildDirectoryResult(IMember umbracoMember)
{
var member = _memberConverter.FromMember(umbracoMember);
Expand Down
Loading