New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Members and member types in the Management API #15662
Conversation
# Conflicts: # src/Umbraco.Cms.Api.Management/OpenApi.json
Seems like I can't determine the member ID from the outside. Even when I provide one, it is just ignored |
…ypes' into v14/feature/members-and-member-types
You're absolutely right @bergmania ... the "regular" document/media creation is not reused for members, so the handling of explicit IDs during content creation is not applied here. I have created a fix 😄 |
When I create a member, I have to consider a Also, when I try to create a member with an id that already exists i just get: {
"type": "Error",
"title": "Unknown error. Please see the log for more details.",
"status": 500,
"operationStatus": "Unknown"
} The message in the log is as expected:
|
src/Umbraco.Cms.Api.Management/Controllers/Member/UpdateMemberController.cs
Show resolved
Hide resolved
@@ -745,7 +749,7 @@ public bool Exists(string username) | |||
public void SetLastLogin(string username, DateTime date) => throw new NotImplementedException(); | |||
|
|||
/// <inheritdoc /> | |||
public void Save(IMember member) | |||
public Attempt<OperationResult?> Save(IMember member, int userId = Constants.Security.SuperUserId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is the pattern often, but I do not like a default value to be the super admin. For new methods I think we should avoid having the default value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm definitively not a fan of the pattern either, but the method signature originates from IContentServiceBase<IMember>
, which is a requirement for using the generic content handling that powers the document and media APIs too. The userId
parameter is defined as optional and with the super user default value in the interface (see source), so we can't really do much about it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it could work just to have public Attempt<OperationResult?> Save(IMember member, int userId)
?
Also able to get this error 500 when saving a member type {
"type": "Error",
"title": "The property something cannot have variations of CultureAndSegment with the content type variations of Nothing",
"status": 500,
"detail": " at Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement.ContentTypeRepositoryBase`1.ValidateVariations(IContentTypeComposition entity) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs:line 709\n at Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement.ContentTypeRepositoryBase`1.PersistNewBaseContentType(IContentTypeComposition entity) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs:line 172\n at Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement.MemberTypeRepository.PersistNewItem(IMemberType entity) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs:line 157\n at Umbraco.Cms.Core.Cache.FullDataSetRepositoryCachePolicy`2.Create(TEntity entity, Action`1 persistNew) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Infrastructure/Cache/FullDataSetRepositoryCachePolicy.cs:line 48\n at Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement.EntityRepositoryBase`2.Save(TEntity entity) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepositoryBase.cs:line 116\n at Umbraco.Cms.Core.Services.ContentTypeServiceBase`2.Save(TItem item, Int32 userId) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs:line 539\n at Umbraco.Cms.Core.Services.ContentTypeServiceBase`2.SaveAsync(TItem item, Guid performingUserKey) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs:line 499\n at Umbraco.Cms.Core.Services.ContentTypeEditing.MemberTypeEditingService.CreateAsync(MemberTypeCreateModel model, Guid userKey) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Core/Services/ContentTypeEditing/MemberTypeEditingService.cs:line 27\n at Umbraco.Cms.Api.Management.Controllers.MemberType.CreateMemberTypeController.Create(CreateMemberTypeRequestModel requestModel) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Cms.Api.Management/Controllers/MemberType/CreateMemberTypeController.cs:line 40\n at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()\n--- End of stack trace from previous location ---\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()\n--- End of stack trace from previous location ---\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)\n at Umbraco.Cms.Web.Common.Middleware.BasicAuthenticationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Web.Website/Middleware/BasicAuthenticationMiddleware.cs:line 62\n at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.InterfaceMiddlewareBinder.<>c__DisplayClass2_0.<<CreateMiddleware>b__0>d.MoveNext()\n--- End of stack trace from previous location ---\n at Umbraco.Cms.Web.BackOffice.Middleware.BackOfficeExternalLoginProviderErrorMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Web.BackOffice/Middleware/BackOfficeExternalLoginProviderErrorMiddleware.cs:line 50\n at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.InterfaceMiddlewareBinder.<>c__DisplayClass2_0.<<CreateMiddleware>b__0>d.MoveNext()\n--- End of stack trace from previous location ---\n at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)\n at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)\n at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)\n at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)\n at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)\n at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)\n at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)\n at StackExchange.Profiling.MiniProfilerMiddleware.Invoke(HttpContext context) in C:\\projects\\dotnet\\src\\MiniProfiler.AspNetCore\\MiniProfilerMiddleware.cs:line 112\n at Umbraco.Cms.Web.Common.Middleware.UmbracoRequestMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs:line 139\n at Umbraco.Cms.Web.Common.Middleware.UmbracoRequestMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs:line 145\n at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.InterfaceMiddlewareBinder.<>c__DisplayClass2_0.<<CreateMiddleware>b__0>d.MoveNext()\n--- End of stack trace from previous location ---\n at Umbraco.Cms.Web.Common.Middleware.PreviewAuthenticationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Web.Common/Middleware/PreviewAuthenticationMiddleware.cs:line 82\n at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.InterfaceMiddlewareBinder.<>c__DisplayClass2_0.<<CreateMiddleware>b__0>d.MoveNext()\n--- End of stack trace from previous location ---\n at Umbraco.Cms.Web.Common.Middleware.UmbracoRequestLoggingMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) in /Users/bjarkeberg/RiderProjects/Umbraco-CMS-V14/src/Umbraco.Web.Common/Middleware/UmbracoRequestLoggingMiddleware.cs:line 42\n at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.InterfaceMiddlewareBinder.<>c__DisplayClass2_0.<<CreateMiddleware>b__0>d.MoveNext()\n--- End of stack trace from previous location ---\n at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext httpContext, Boolean retry)\n at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddlewareImpl.<Invoke>g__Awaited|10_0(ExceptionHandlerMiddlewareImpl middleware, HttpContext context, Task task)",
"instance": "InvalidOperationException"
} |
"Parent" for members and "Folder" for member types have been removed from the member API (whilst retained in the document and media APIs). Good catch 👍 As for creating entities using existing IDs, this is a problem across the all content APIs. I have added an explicit task to handle this. The member type save validation error is caused by attempting variance for a member type. This is also a problem for media. I have added another task to handle this 😄 |
Prerequisites
Description
This PR adds member type and member editing to the Management API. The feature set mimics what is possible in the current back-office, which is a subset of document and media capabilities.
Limitations
Sensitive properties are not handled by the API as a whole. This is yet to be added, so sensitive member data are treated as any other data at this point in time.
Authorization needs to be added. See FIXME in
MemberControllerBase
. A separate task will be created to amend this.Testing this PR
Using Swagger it should be possible to perform all member and member type operations that are possible in the current back-office.
Members
Note that the member models have a fair few required properties that are not part of documents and media (e.g. username, email, password, ...).
Member types