New backoffice: Add new codefile controllers and services (#14157)

* Add scaffolding

* Entities not Entitys

* Remove unececary obsoleted constructor

* Implement create script

* Return a simplified ScriptFile instead of IScript

That file abstraction seems way too bloated, containing a lot of stuff that's not relevant for files, such as IDs and keys.

* Use IScript instead of custom return model

* Add validation when creating script

* Add Get script endpoint

* Add response types

* Add Delete

* Throw if user key not found

* Remove unused maapper

* Add update endpoint

* Add Get by path

* Add create folder endpoint

* Don't pass performingUserId to folder creation

* Remove update folder

* Add delete folder endpoint

* Use specific ScriptFolderOperationStatus instead of ScriptOperationStatus

* Add OperationStatusResult

* Check folder for invalid name

* Check name for invalid characters

* Add partial view snippet endpoint

* Start working on CreatePartialView

* Add create partial view endpoint

* Retrieve key from audit method

* Add operation status results

* Add Get endpoint

* Return 201 when creating

* Add update partial view endpoint

* Add delete endpoint

* Add response types

* Add folder base implementation

* Add folder endpoints

* User property for allowed file extensions

* Rename async method to async

* Break snippet into endpoint in two

* Make content non-nullable

* Remove IService

* Add get by path

* Add viewmodels

* Add create and update models

* Add create stylesheet

* Add update endpoint

* Rename StylesheetControllerBase to StylesheetControllerBase

* Add stylesheet delete

* Rename controller bases

* Add stylesheet folders

* Add status results

* Add response types to folders

* Add richtext rules endpoints

* Add Get all endpoint

* Add get rules by path endpoint

* Aling validates so they're not async

These are private methods, so there's no reason to make them preemptively async

* Add template obsoletions to interface

* Add stream methods

This is evidently used by deploy 🤷

* Obsolete stylesheet operations

* Add get and getall across all services

* Obsolete script operations

* Obsolete old partial view methods

* Add some method docs

* Add compatibility suppression

* Update OpenApi.json

* Rename action

* formatting

* Fix import

* add expression body

* Invert if

* Move base on own line

* Rename file

* Rename to all

* Change to stylesheet instead of script

* Add Umbraco.Code.MapAll to map definitions

* Add comment about auditing

* use publish cancelable async

* use expression body

* formatting

* fix to use pattern matching

---------

Co-authored-by: Zeegaan <nge@umbraco.dk>
This commit is contained in:
Mole
2023-04-26 13:47:47 +02:00
committed by GitHub
parent 17fef47450
commit b411452f79
122 changed files with 4381 additions and 34 deletions

View File

@@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.DataType;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;

View File

@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.PartialView;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.PartialView;
public class ByPathPartialViewController : PartialViewControllerBase
{
private readonly IPartialViewService _partialViewService;
private readonly IUmbracoMapper _mapper;
public ByPathPartialViewController(
IPartialViewService partialViewService,
IUmbracoMapper mapper)
{
_partialViewService = partialViewService;
_mapper = mapper;
}
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PartialViewResponseModel), StatusCodes.Status200OK)]
public async Task<IActionResult> ByPath(string path)
{
IPartialView? partialView = await _partialViewService.GetAsync(path);
return partialView is null
? NotFound()
: Ok(_mapper.Map<PartialViewResponseModel>(partialView));
}
}

View File

@@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.PartialView;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.PartialView;
public class CreatePartialViewController : PartialViewControllerBase
{
private readonly IUmbracoMapper _umbracoMapper;
private readonly IPartialViewService _partialViewService;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
public CreatePartialViewController(
IUmbracoMapper umbracoMapper,
IPartialViewService partialViewService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
{
_umbracoMapper = umbracoMapper;
_partialViewService = partialViewService;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
}
[HttpPost]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status201Created)]
public async Task<IActionResult> Create(CreatePartialViewRequestModel createRequestModel)
{
PartialViewCreateModel createModel = _umbracoMapper.Map<PartialViewCreateModel>(createRequestModel)!;
Attempt<IPartialView?, PartialViewOperationStatus> createAttempt = await _partialViewService.CreateAsync(createModel, CurrentUserKey(_backOfficeSecurityAccessor));
return createAttempt.Success
? CreatedAtAction<ByPathPartialViewController>(controller => nameof(controller.ByPath), new { path = createAttempt.Result!.Path })
: PartialViewOperationStatusResult(createAttempt.Status);
}
}

View File

@@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.PartialView;
public class DeletePartialViewController : PartialViewControllerBase
{
private readonly IPartialViewService _partialViewService;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
public DeletePartialViewController(
IPartialViewService partialViewService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
{
_partialViewService = partialViewService;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
}
[HttpDelete]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> Delete(string path)
{
PartialViewOperationStatus operationStatus = await _partialViewService.DeleteAsync(path, CurrentUserKey(_backOfficeSecurityAccessor));
return operationStatus is PartialViewOperationStatus.Success
? Ok()
: PartialViewOperationStatusResult(operationStatus);
}
}

View File

@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.PartialView.Folder;
public class ByPathPartialViewFolderController : PartialViewFolderControllerBase
{
public ByPathPartialViewFolderController(IUmbracoMapper mapper, IPartialViewFolderService partialViewFolderService) : base(mapper, partialViewFolderService)
{
}
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public Task<IActionResult> ByPath(string path) => GetFolderAsync(path);
}

View File

@@ -0,0 +1,22 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.Folder;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.PartialView.Folder;
public class CreatePartialViewFolderController : PartialViewFolderControllerBase
{
public CreatePartialViewFolderController(
IUmbracoMapper mapper,
IPartialViewFolderService partialViewFolderService)
: base(mapper, partialViewFolderService)
{
}
[HttpPost]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public Task<IActionResult> Create(CreatePathFolderRequestModel model) => CreateAsync(model);
}

View File

@@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.PartialView.Folder;
public class DeletePartialViewFolderController : PartialViewFolderControllerBase
{
public DeletePartialViewFolderController(
IUmbracoMapper mapper,
IPartialViewFolderService partialViewFolderService)
: base(mapper, partialViewFolderService)
{
}
[HttpDelete]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public Task<IActionResult> Delete(string path) => DeleteAsync(path);
}

View File

@@ -0,0 +1,63 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.Builders;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.PartialView.Folder;
[ApiVersion("1.0")]
[ApiController]
[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.PartialView}/folder")]
[ApiExplorerSettings(GroupName = "Partial View")]
public class PartialViewFolderControllerBase : PathFolderManagementControllerBase<PartialViewFolderOperationStatus>
{
private readonly IPartialViewFolderService _partialViewFolderService;
public PartialViewFolderControllerBase(
IUmbracoMapper mapper,
IPartialViewFolderService partialViewFolderService)
: base(mapper)
{
_partialViewFolderService = partialViewFolderService;
}
protected override Task<PathContainer?> GetContainerAsync(string path) => _partialViewFolderService.GetAsync(path);
protected override Task<Attempt<PathContainer?, PartialViewFolderOperationStatus>> CreateContainerAsync(
PathContainer container) =>
_partialViewFolderService.CreateAsync(container);
protected override Task<Attempt<PartialViewFolderOperationStatus>> DeleteContainerAsync(string path) =>
_partialViewFolderService.DeleteAsync(path);
protected override IActionResult OperationStatusResult(PartialViewFolderOperationStatus status) =>
status switch
{
PartialViewFolderOperationStatus.AlreadyExists => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Folder already exists")
.WithDetail("The folder already exists")
.Build()),
PartialViewFolderOperationStatus.NotEmpty => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Not empty")
.WithDetail("The folder is not empty and can therefore not be deleted.")
.Build()),
PartialViewFolderOperationStatus.NotFound => NotFound(new ProblemDetailsBuilder()
.WithTitle("Not found")
.WithDetail("The specified folder was not found.")
.Build()),
PartialViewFolderOperationStatus.ParentNotFound => NotFound(new ProblemDetailsBuilder()
.WithTitle("Parent not found")
.WithDetail("The parent folder was not found.")
.Build()),
PartialViewFolderOperationStatus.InvalidName => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Invalid name")
.WithDetail("The name specified is not a valid name.")
.Build()),
_ => StatusCode(StatusCodes.Status500InternalServerError, "Unknown partial view folder operation status")
};
}

View File

@@ -0,0 +1,46 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.Builders;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.PartialView;
[ApiVersion("1.0")]
[ApiController]
[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.PartialView}")]
[ApiExplorerSettings(GroupName = "Partial View")]
public class PartialViewControllerBase : ManagementApiControllerBase
{
protected IActionResult PartialViewOperationStatusResult(PartialViewOperationStatus status) =>
status switch
{
PartialViewOperationStatus.Success => Ok(),
PartialViewOperationStatus.AlreadyExists => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Partial view already exists")
.WithDetail("A partial view with the same path already exists")
.Build()),
PartialViewOperationStatus.InvalidFileExtension => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Invalid file extension")
.WithDetail("The file extension is not valid for a partial view.")
.Build()),
PartialViewOperationStatus.ParentNotFound => NotFound(new ProblemDetailsBuilder()
.WithTitle("Parent not found")
.WithDetail("The parent folder was not found.")
.Build()),
PartialViewOperationStatus.PathTooLong => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Path too long")
.WithDetail("The file path is too long.")
.Build()),
PartialViewOperationStatus.InvalidName => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Invalid name")
.WithDetail("The partial view name is invalid.")
.Build()),
PartialViewOperationStatus.NotFound => NotFound(new ProblemDetailsBuilder()
.WithTitle("Partial view not found")
.WithDetail("The partial view was not found.")
.Build()),
_ => StatusCode(StatusCodes.Status500InternalServerError, "Unknown partial view operation status")
};
}

View File

@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.PartialView.Snippets;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Snippets;
namespace Umbraco.Cms.Api.Management.Controllers.PartialView.Snippet;
public class ByNameController : PartialViewControllerBase
{
private readonly IPartialViewService _partialViewService;
private readonly IUmbracoMapper _umbracoMapper;
public ByNameController(IPartialViewService partialViewService, IUmbracoMapper umbracoMapper)
{
_partialViewService = partialViewService;
_umbracoMapper = umbracoMapper;
}
[HttpGet("snippet/{name}")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PartialViewSnippetResponseModel), StatusCodes.Status200OK)]
public async Task<IActionResult> GetByName(string name)
{
PartialViewSnippet? snippet = await _partialViewService.GetSnippetByNameAsync(name);
if (snippet is null)
{
return NotFound();
}
PartialViewSnippetResponseModel? viewModel = _umbracoMapper.Map<PartialViewSnippetResponseModel>(snippet);
return Ok(viewModel);
}
}

View File

@@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
using Umbraco.Cms.Api.Management.ViewModels.PartialView.Snippets;
using Umbraco.Cms.Core.Services;
using Umbraco.New.Cms.Core.Models;
namespace Umbraco.Cms.Api.Management.Controllers.PartialView.Snippet;
public class GetAllController : PartialViewControllerBase
{
private readonly IPartialViewService _partialViewService;
public GetAllController(IPartialViewService partialViewService) => _partialViewService = partialViewService;
[HttpGet("snippet")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<SnippetItemResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetAll(int skip = 0, int take = 100)
{
PagedModel<string> snippets = await _partialViewService.GetSnippetNamesAsync(skip, take);
var pageViewModel = new PagedViewModel<SnippetItemResponseModel>
{
Total = snippets.Total,
Items = snippets.Items.Select(x => new SnippetItemResponseModel(x)),
};
return Ok(pageViewModel);
}
}

View File

@@ -0,0 +1,41 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.PartialView;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.PartialView;
public class UpdatePartialViewController : PartialViewControllerBase
{
private readonly IPartialViewService _partialViewService;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
private readonly IUmbracoMapper _mapper;
public UpdatePartialViewController(
IPartialViewService partialViewService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
IUmbracoMapper mapper)
{
_partialViewService = partialViewService;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
_mapper = mapper;
}
[HttpPut]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> Update(UpdatePartialViewRequestModel updateViewModel)
{
PartialViewUpdateModel updateModel = _mapper.Map<PartialViewUpdateModel>(updateViewModel)!;
Attempt<IPartialView?, PartialViewOperationStatus> updateAttempt = await _partialViewService.UpdateAsync(updateModel, CurrentUserKey(_backOfficeSecurityAccessor));
return updateAttempt.Success
? Ok()
: PartialViewOperationStatusResult(updateAttempt.Status);
}
}

View File

@@ -0,0 +1,60 @@
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.Folder;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Api.Management.Controllers;
public abstract class PathFolderManagementControllerBase<TStatus> : ManagementApiControllerBase
where TStatus : Enum
{
protected readonly IUmbracoMapper Mapper;
protected PathFolderManagementControllerBase(
IUmbracoMapper mapper) =>
Mapper = mapper;
protected async Task<IActionResult> GetFolderAsync(string path)
{
PathContainer? container = await GetContainerAsync(path);
if (container == null)
{
return NotFound();
}
PathFolderResponseModel? viewModel = Mapper.Map<PathFolderResponseModel>(container);
return Ok(viewModel);
}
protected async Task<IActionResult> CreateAsync(CreatePathFolderRequestModel requestModel)
{
PathContainer folderModel = Mapper.Map<PathContainer>(requestModel)!;
Attempt<PathContainer?, TStatus> attempt = await CreateContainerAsync(folderModel);
if (attempt.Success is false)
{
return OperationStatusResult(attempt.Status);
}
PathFolderResponseModel? viewModel = Mapper.Map<PathFolderResponseModel>(attempt.Result);
return Ok(viewModel);
}
protected async Task<IActionResult> DeleteAsync(string path)
{
Attempt<TStatus> attempt = await DeleteContainerAsync(path);
return attempt.Success
? Ok()
: OperationStatusResult(attempt.Result!);
}
protected abstract Task<PathContainer?> GetContainerAsync(string path);
protected abstract Task<Attempt<PathContainer?, TStatus>> CreateContainerAsync(PathContainer container);
protected abstract Task<Attempt<TStatus>> DeleteContainerAsync(string path);
protected abstract IActionResult OperationStatusResult(TStatus status);
}

View File

@@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.Script;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.Script;
public class ByPathScriptController : ScriptControllerBase
{
private readonly IScriptService _scriptService;
private readonly IUmbracoMapper _mapper;
public ByPathScriptController(
IScriptService scriptService,
IUmbracoMapper mapper)
{
_scriptService = scriptService;
_mapper = mapper;
}
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(ScriptResponseModel), StatusCodes.Status200OK)]
public async Task<IActionResult> ByPath(string path)
{
IScript? script = await _scriptService.GetAsync(path);
return script is null
? NotFound()
: Ok(_mapper.Map<ScriptResponseModel>(script));
}
}

View File

@@ -0,0 +1,44 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.Script;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.Script;
public class CreateScriptController : ScriptControllerBase
{
private readonly IScriptService _scriptService;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
private readonly IUmbracoMapper _umbracoMapper;
public CreateScriptController(
IScriptService scriptService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
IUmbracoMapper umbracoMapper)
{
_scriptService = scriptService;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
_umbracoMapper = umbracoMapper;
}
[HttpPost]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status201Created)]
public async Task<IActionResult> Create(CreateScriptRequestModel requestModel)
{
Guid currentUserKey = CurrentUserKey(_backOfficeSecurityAccessor);
ScriptCreateModel createModel = _umbracoMapper.Map<ScriptCreateModel>(requestModel)!;
Attempt<IScript?, ScriptOperationStatus> createAttempt = await _scriptService.CreateAsync(createModel, currentUserKey);
return createAttempt.Success
? CreatedAtAction<ByPathScriptController>(controller => nameof(controller.ByPath), new { path = createAttempt.Result!.Path })
: ScriptOperationStatusResult(createAttempt.Status);
}
}

View File

@@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.Script;
public class DeleteScriptController : ScriptControllerBase
{
private readonly IScriptService _scriptService;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
public DeleteScriptController(
IScriptService scriptService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
{
_scriptService = scriptService;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
}
[HttpDelete]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> Delete(string path)
{
ScriptOperationStatus operationStatus = await _scriptService.DeleteAsync(path, CurrentUserKey(_backOfficeSecurityAccessor));
return operationStatus is ScriptOperationStatus.Success
? Ok()
: ScriptOperationStatusResult(operationStatus);
}
}

View File

@@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.Script.Folder;
public class ByPathScriptFolderController : ScriptFolderControllerBase
{
public ByPathScriptFolderController(
IUmbracoMapper mapper,
IScriptFolderService scriptFolderService)
: base(mapper, scriptFolderService)
{
}
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public Task<IActionResult> ByPath(string path) => GetFolderAsync(path);
}

View File

@@ -0,0 +1,22 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.Folder;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.Script.Folder;
public class CreateScriptFolderController : ScriptFolderControllerBase
{
public CreateScriptFolderController(
IUmbracoMapper mapper,
IScriptFolderService scriptFolderService)
: base(mapper, scriptFolderService)
{
}
[HttpPost]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public Task<IActionResult> Create(CreatePathFolderRequestModel model) => CreateAsync(model);
}

View File

@@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.Script.Folder;
public class DeleteScriptFolderController : ScriptFolderControllerBase
{
public DeleteScriptFolderController(IUmbracoMapper mapper, IScriptFolderService scriptFolderService)
: base(mapper, scriptFolderService)
{
}
[HttpDelete]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public Task<IActionResult> Delete(string path) => DeleteAsync(path);
}

View File

@@ -0,0 +1,63 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.Builders;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.Script.Folder;
[ApiVersion("1.0")]
[ApiController]
[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.Script}/folder")]
[ApiExplorerSettings(GroupName = "Script")]
public class ScriptFolderControllerBase : PathFolderManagementControllerBase<ScriptFolderOperationStatus>
{
private readonly IScriptFolderService _scriptFolderService;
public ScriptFolderControllerBase(
IUmbracoMapper mapper,
IScriptFolderService scriptFolderService)
: base(mapper)
{
_scriptFolderService = scriptFolderService;
}
protected override Task<PathContainer?> GetContainerAsync(string path)
=> _scriptFolderService.GetAsync(path);
protected override Task<Attempt<PathContainer?, ScriptFolderOperationStatus>> CreateContainerAsync(PathContainer container)
=> _scriptFolderService.CreateAsync(container);
protected override Task<Attempt<ScriptFolderOperationStatus>> DeleteContainerAsync(string path) =>
_scriptFolderService.DeleteAsync(path);
protected override IActionResult OperationStatusResult(ScriptFolderOperationStatus status) =>
status switch
{
ScriptFolderOperationStatus.AlreadyExists => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Folder already exists")
.WithDetail("The folder already exists")
.Build()),
ScriptFolderOperationStatus.NotEmpty => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Not empty")
.WithDetail("The folder is not empty and can therefore not be deleted.")
.Build()),
ScriptFolderOperationStatus.NotFound => NotFound(new ProblemDetailsBuilder()
.WithTitle("Not found")
.WithDetail("The specified folder was not found.")
.Build()),
ScriptFolderOperationStatus.ParentNotFound => NotFound(new ProblemDetailsBuilder()
.WithTitle("Parent not found")
.WithDetail("The parent folder was not found.")
.Build()),
ScriptFolderOperationStatus.InvalidName => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Invalid name")
.WithDetail("The name specified is not a valid name.")
.Build()),
_ => StatusCode(StatusCodes.Status500InternalServerError, "Unknown script folder operation status")
};
}

View File

@@ -0,0 +1,50 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.Builders;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.Script;
[ApiVersion("1.0")]
[ApiController]
[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.Script}")]
[ApiExplorerSettings(GroupName = nameof(Constants.UdiEntityType.Script))]
public class ScriptControllerBase : ManagementApiControllerBase
{
protected IActionResult ScriptOperationStatusResult(ScriptOperationStatus status) =>
status switch
{
ScriptOperationStatus.Success => Ok(),
ScriptOperationStatus.AlreadyExists => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Script already exists")
.WithDetail("A script with the same path already exists")
.Build()),
ScriptOperationStatus.CancelledByNotification => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Cancelled by notification")
.WithDetail("A script notification handler prevented the script operation.")
.Build()),
ScriptOperationStatus.InvalidFileExtension => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Invalid file extension")
.WithDetail("The file extension is not valid for a script.")
.Build()),
ScriptOperationStatus.ParentNotFound => NotFound(new ProblemDetailsBuilder()
.WithTitle("Parent not found")
.WithDetail("The parent folder was not found.")
.Build()),
ScriptOperationStatus.PathTooLong => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Path too long")
.WithDetail("The file path is too long.")
.Build()),
ScriptOperationStatus.NotFound => NotFound(new ProblemDetailsBuilder()
.WithTitle("Script not found")
.WithDetail("The script was not found.")
.Build()),
ScriptOperationStatus.InvalidName => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Invalid name")
.WithDetail("The script name is invalid.")
.Build()),
_ => StatusCode(StatusCodes.Status500InternalServerError, "Unknown script operation status")
};
}

View File

@@ -0,0 +1,41 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.Script;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.Script;
public class UpdateScriptController : ScriptControllerBase
{
private readonly IScriptService _scriptService;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
private readonly IUmbracoMapper _umbracoMapper;
public UpdateScriptController(
IScriptService scriptService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
IUmbracoMapper umbracoMapper)
{
_scriptService = scriptService;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
_umbracoMapper = umbracoMapper;
}
[HttpPut]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> Update(UpdateScriptRequestModel updateViewModel)
{
ScriptUpdateModel? updateModel = _umbracoMapper.Map<ScriptUpdateModel>(updateViewModel);
Attempt<IScript?, ScriptOperationStatus> updateAttempt = await _scriptService.UpdateAsync(updateModel!, CurrentUserKey(_backOfficeSecurityAccessor));
return updateAttempt.Success
? Ok()
: ScriptOperationStatusResult(updateAttempt.Status);
}
}

View File

@@ -0,0 +1,35 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
using Umbraco.Cms.Api.Management.ViewModels.Stylesheet;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.Stylesheet;
public class AllStylesheetController : StylesheetControllerBase
{
private readonly IStylesheetService _stylesheetService;
private readonly IUmbracoMapper _umbracoMapper;
public AllStylesheetController(
IStylesheetService stylesheetService,
IUmbracoMapper umbracoMapper)
{
_stylesheetService = stylesheetService;
_umbracoMapper = umbracoMapper;
}
[HttpGet("all")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<StylesheetOverviewResponseModel>), StatusCodes.Status200OK)]
public async Task<IActionResult> All(int skip = 0, int take = 100)
{
IStylesheet[] stylesheets = (await _stylesheetService.GetAllAsync()).ToArray();
List<StylesheetOverviewResponseModel> viewModels = _umbracoMapper.MapEnumerable<IStylesheet, StylesheetOverviewResponseModel>(stylesheets.Skip(skip).Take(take));
return Ok(new PagedViewModel<StylesheetOverviewResponseModel> { Items = viewModels, Total = stylesheets.Length });
}
}

View File

@@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.Stylesheet;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.Stylesheet;
public class ByPathStylesheetController : StylesheetControllerBase
{
private readonly IStylesheetService _stylesheetService;
private readonly IUmbracoMapper _umbracoMapper;
public ByPathStylesheetController(
IStylesheetService stylesheetService,
IUmbracoMapper umbracoMapper)
{
_stylesheetService = stylesheetService;
_umbracoMapper = umbracoMapper;
}
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(StylesheetResponseModel), StatusCodes.Status200OK)]
public async Task<IActionResult> ByPath(string path)
{
IStylesheet? stylesheet = await _stylesheetService.GetAsync(path);
if (stylesheet is null)
{
return NotFound();
}
StylesheetResponseModel? viewModel = _umbracoMapper.Map<StylesheetResponseModel>(stylesheet);
return Ok(viewModel);
}
}

View File

@@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.Stylesheet;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.Stylesheet;
public class CreateStylesheetController : StylesheetControllerBase
{
private readonly IStylesheetService _stylesheetService;
private readonly IUmbracoMapper _umbracoMapper;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
public CreateStylesheetController(
IStylesheetService stylesheetService,
IUmbracoMapper umbracoMapper,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
{
_stylesheetService = stylesheetService;
_umbracoMapper = umbracoMapper;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
}
[HttpPost]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status201Created)]
public async Task<IActionResult> Create(CreateStylesheetRequestModel requestModel)
{
StylesheetCreateModel createModel = _umbracoMapper.Map<StylesheetCreateModel>(requestModel)!;
Attempt<IStylesheet?, StylesheetOperationStatus> createAttempt = await _stylesheetService.CreateAsync(createModel, CurrentUserKey(_backOfficeSecurityAccessor));
return createAttempt.Success
? CreatedAtAction<ByPathStylesheetController>(controller => nameof(controller.ByPath), new { path = createAttempt.Result!.Path })
: StylesheetOperationStatusResult(createAttempt.Status);
}
}

View File

@@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.Stylesheet;
public class DeleteStylesheetController : StylesheetControllerBase
{
private readonly IStylesheetService _stylesheetService;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
public DeleteStylesheetController(
IStylesheetService stylesheetService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
{
_stylesheetService = stylesheetService;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
}
[HttpDelete]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> Delete(string path)
{
StylesheetOperationStatus operationStatus = await _stylesheetService.DeleteAsync(path, CurrentUserKey(_backOfficeSecurityAccessor));
return operationStatus is StylesheetOperationStatus.Success
? Ok()
: StylesheetOperationStatusResult(operationStatus);
}
}

View File

@@ -0,0 +1,38 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.RichTextStylesheet;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings.Css;
namespace Umbraco.Cms.Api.Management.Controllers.Stylesheet;
public class ExtractRichTextRulesController : StylesheetControllerBase
{
private readonly IRichTextStylesheetService _richTextStylesheetService;
private readonly IUmbracoMapper _umbracoMapper;
public ExtractRichTextRulesController(
IRichTextStylesheetService richTextStylesheetService,
IUmbracoMapper umbracoMapper)
{
_richTextStylesheetService = richTextStylesheetService;
_umbracoMapper = umbracoMapper;
}
[HttpPost("rich-text/extract-rules")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(ExtractRichTextStylesheetRulesResponseModel), StatusCodes.Status200OK)]
public async Task<IActionResult> ExtractRichTextRules(ExtractRichTextStylesheetRulesRequestModel requestModel)
{
RichTextStylesheetData? model = _umbracoMapper.Map<RichTextStylesheetData>(requestModel);
IEnumerable<StylesheetRule> rules = await _richTextStylesheetService.ExtractRichTextRules(model!);
return Ok(new ExtractRichTextStylesheetRulesResponseModel
{
Rules = _umbracoMapper.MapEnumerable<StylesheetRule, RichTextRuleViewModel>(rules),
});
}
}

View File

@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.Stylesheet.Folder;
public class ByPathStylesheetFolderController : StylesheetFolderControllerBase
{
public ByPathStylesheetFolderController(IUmbracoMapper mapper, IStylesheetFolderService stylesheetFolderService) : base(mapper, stylesheetFolderService)
{
}
[HttpGet]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public Task<IActionResult> ByPath(string path) => GetFolderAsync(path);
}

View File

@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.Folder;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.Stylesheet.Folder;
public class CreateStylesheetFolderController : StylesheetFolderControllerBase
{
public CreateStylesheetFolderController(IUmbracoMapper mapper, IStylesheetFolderService stylesheetFolderService) : base(mapper, stylesheetFolderService)
{
}
[HttpPost]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public Task<IActionResult> Create(CreatePathFolderRequestModel model) => CreateAsync(model);
}

View File

@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.Stylesheet.Folder;
public class DeleteStylesheetFolderController : StylesheetFolderControllerBase
{
public DeleteStylesheetFolderController(IUmbracoMapper mapper, IStylesheetFolderService stylesheetFolderService) : base(mapper, stylesheetFolderService)
{
}
[HttpDelete]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public Task<IActionResult> Delete(string path) => DeleteAsync(path);
}

View File

@@ -0,0 +1,62 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.Builders;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.Stylesheet.Folder;
[ApiVersion("1.0")]
[ApiController]
[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.Stylesheet}/folder")]
[ApiExplorerSettings(GroupName = "Stylesheet")]
public class StylesheetFolderControllerBase : PathFolderManagementControllerBase<StylesheetFolderOperationStatus>
{
private readonly IStylesheetFolderService _stylesheetFolderService;
public StylesheetFolderControllerBase(
IUmbracoMapper mapper,
IStylesheetFolderService stylesheetFolderService)
: base(mapper)
{
_stylesheetFolderService = stylesheetFolderService;
}
protected override Task<PathContainer?> GetContainerAsync(string path) => _stylesheetFolderService.GetAsync(path);
protected override Task<Attempt<PathContainer?, StylesheetFolderOperationStatus>> CreateContainerAsync(PathContainer container)
=> _stylesheetFolderService.CreateAsync(container);
protected override Task<Attempt<StylesheetFolderOperationStatus>> DeleteContainerAsync(string path)
=> _stylesheetFolderService.DeleteAsync(path);
protected override IActionResult OperationStatusResult(StylesheetFolderOperationStatus status) =>
status switch
{
StylesheetFolderOperationStatus.AlreadyExists => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Folder already exists")
.WithDetail("The folder already exists")
.Build()),
StylesheetFolderOperationStatus.NotEmpty => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Not empty")
.WithDetail("The folder is not empty and can therefore not be deleted.")
.Build()),
StylesheetFolderOperationStatus.NotFound => NotFound(new ProblemDetailsBuilder()
.WithTitle("Not found")
.WithDetail("The specified folder was not found.")
.Build()),
StylesheetFolderOperationStatus.ParentNotFound => NotFound(new ProblemDetailsBuilder()
.WithTitle("Parent not found")
.WithDetail("The parent folder was not found.")
.Build()),
StylesheetFolderOperationStatus.InvalidName => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Invalid name")
.WithDetail("The name specified is not a valid name.")
.Build()),
_ => StatusCode(StatusCodes.Status500InternalServerError, "Unknown stylesheet folder operation status")
};
}

View File

@@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.RichTextStylesheet;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
using StylesheetRule = Umbraco.Cms.Core.Strings.Css.StylesheetRule;
namespace Umbraco.Cms.Api.Management.Controllers.Stylesheet;
public class GetRichTextRulesByPath : StylesheetControllerBase
{
private readonly IRichTextStylesheetService _richTextStylesheetService;
private readonly IUmbracoMapper _umbracoMapper;
public GetRichTextRulesByPath(
IRichTextStylesheetService richTextStylesheetService,
IUmbracoMapper umbracoMapper)
{
_richTextStylesheetService = richTextStylesheetService;
_umbracoMapper = umbracoMapper;
}
[HttpGet("rich-text/rules")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(RichTextStylesheetRulesResponseModel), StatusCodes.Status200OK)]
public async Task<IActionResult> GetByPath(string path)
{
Attempt<IEnumerable<StylesheetRule>, StylesheetOperationStatus> rulesAttempt = await _richTextStylesheetService.GetRulesByPathAsync(path);
if (rulesAttempt.Success is false)
{
return StylesheetOperationStatusResult(rulesAttempt.Status);
}
return Ok(new RichTextStylesheetRulesResponseModel
{
Rules = _umbracoMapper.MapEnumerable<StylesheetRule, RichTextRuleViewModel>(rulesAttempt.Result)
});
}
}

View File

@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.RichTextStylesheet;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.Stylesheet;
public class InterpolateRichTextRulesController : StylesheetControllerBase
{
private readonly IRichTextStylesheetService _richTextStylesheetService;
private readonly IUmbracoMapper _umbracoMapper;
public InterpolateRichTextRulesController(
IRichTextStylesheetService richTextStylesheetService,
IUmbracoMapper umbracoMapper)
{
_richTextStylesheetService = richTextStylesheetService;
_umbracoMapper = umbracoMapper;
}
[HttpPost("rich-text/interpolate-rules")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(InterpolateRichTextStylesheetResponseModel), StatusCodes.Status200OK)]
public async Task<IActionResult> InterpolateRichTextRules(InterpolateRichTextStylesheetRequestModel requestModel)
{
RichTextStylesheetData? model = _umbracoMapper.Map<RichTextStylesheetData>(requestModel);
var content = await _richTextStylesheetService.InterpolateRichTextRules(model!);
return Ok(new InterpolateRichTextStylesheetResponseModel
{
Content = content,
});
}
}

View File

@@ -0,0 +1,50 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Common.Builders;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.Stylesheet;
[ApiVersion("1.0")]
[ApiController]
[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.Stylesheet}")]
[ApiExplorerSettings(GroupName = "Stylesheet")]
public class StylesheetControllerBase : ManagementApiControllerBase
{
protected IActionResult StylesheetOperationStatusResult(StylesheetOperationStatus status) =>
status switch
{
StylesheetOperationStatus.Success => Ok(),
StylesheetOperationStatus.AlreadyExists => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Stylesheet already exists")
.WithDetail("A stylesheet with the same path already exists")
.Build()),
StylesheetOperationStatus.CancelledByNotification => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Cancelled by notification")
.WithDetail("A stylesheet notification handler prevented the stylesheet operation.")
.Build()),
StylesheetOperationStatus.InvalidFileExtension => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Invalid file extension")
.WithDetail("The file extension is not valid for a stylesheet.")
.Build()),
StylesheetOperationStatus.ParentNotFound => NotFound(new ProblemDetailsBuilder()
.WithTitle("Parent not found")
.WithDetail("The parent folder was not found.")
.Build()),
StylesheetOperationStatus.PathTooLong => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Path too long")
.WithDetail("The file path is too long.")
.Build()),
StylesheetOperationStatus.NotFound => NotFound(new ProblemDetailsBuilder()
.WithTitle("Stylesheet not found")
.WithDetail("The stylesheet was not found.")
.Build()),
StylesheetOperationStatus.InvalidName => BadRequest(new ProblemDetailsBuilder()
.WithTitle("Invalid name")
.WithDetail("The stylesheet name is invalid.")
.Build()),
_ => StatusCode(StatusCodes.Status500InternalServerError, "Unknown script operation status"),
};
}

View File

@@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.Stylesheet;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Api.Management.Controllers.Stylesheet;
public class UpdateStylesheetController : StylesheetControllerBase
{
private readonly IStylesheetService _stylesheetService;
private readonly IUmbracoMapper _umbracoMapper;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
public UpdateStylesheetController(
IStylesheetService stylesheetService,
IUmbracoMapper umbracoMapper,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
{
_stylesheetService = stylesheetService;
_umbracoMapper = umbracoMapper;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
}
[HttpPut]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> Update(UpdateStylesheetRequestModel requestModel)
{
StylesheetUpdateModel updateModel = _umbracoMapper.Map<StylesheetUpdateModel>(requestModel)!;
Attempt<IStylesheet?, StylesheetOperationStatus> updateAttempt = await _stylesheetService.UpdateAsync(updateModel, CurrentUserKey(_backOfficeSecurityAccessor));
return updateAttempt.Success
? Ok()
: StylesheetOperationStatusResult(updateAttempt.Status);
}
}

View File

@@ -8,7 +8,7 @@ namespace Umbraco.Cms.Api.Management.DependencyInjection;
internal static class EntityBuilderExtensions
{
internal static IUmbracoBuilder AddEntitys(this IUmbracoBuilder builder)
internal static IUmbracoBuilder AddEntities(this IUmbracoBuilder builder)
{
builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>()
.Add<ItemTypeMapDefinition>();

View File

@@ -0,0 +1,16 @@
using Umbraco.Cms.Api.Management.Mapping.PartialView;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Mapping;
namespace Umbraco.Cms.Api.Management.DependencyInjection;
internal static class PartialViewBuilderExtensions
{
internal static IUmbracoBuilder AddPartialViews(this IUmbracoBuilder builder)
{
builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>()
.Add<PartialViewViewModelsMapDefinition>();
return builder;
}
}

View File

@@ -0,0 +1,16 @@
using Umbraco.Cms.Api.Management.Mapping.Folder;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Mapping;
namespace Umbraco.Cms.Api.Management.DependencyInjection;
public static class PathFolderBuilderExtensions
{
internal static IUmbracoBuilder AddPathFolders(this IUmbracoBuilder builder)
{
builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>()
.Add<PathFolderViewModelMapDefinition>();
return builder;
}
}

View File

@@ -0,0 +1,16 @@
using Umbraco.Cms.Api.Management.Mapping.Script;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Mapping;
namespace Umbraco.Cms.Api.Management.DependencyInjection;
internal static class ScriptBuilderExtensions
{
internal static IUmbracoBuilder AddScripts(this IUmbracoBuilder builder)
{
builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>()
.Add<ScriptViewModelsMapDefinition>();
return builder;
}
}

View File

@@ -0,0 +1,16 @@
using Umbraco.Cms.Api.Management.Mapping.Stylesheet;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Mapping;
namespace Umbraco.Cms.Api.Management.DependencyInjection;
internal static class StylesheetBuilderExtensions
{
internal static IUmbracoBuilder AddStylesheets(this IUmbracoBuilder builder)
{
builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>()
.Add<StylesheetViewModelsMapDefinition>();
return builder;
}
}

View File

@@ -46,7 +46,11 @@ public class ManagementApiComposer : IComposer
.AddUsers()
.AddUserGroups()
.AddPackages()
.AddEntitys()
.AddEntities()
.AddPathFolders()
.AddScripts()
.AddPartialViews()
.AddStylesheets()
.AddBackOfficeAuthentication();
services

View File

@@ -0,0 +1,28 @@
using Umbraco.Cms.Api.Management.ViewModels.Folder;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Api.Management.Mapping.Folder;
public class PathFolderViewModelMapDefinition : IMapDefinition
{
public void DefineMaps(IUmbracoMapper mapper)
{
mapper.Define<PathContainer, PathFolderResponseModel>((_, _) => new PathFolderResponseModel(), Map);
mapper.Define<CreatePathFolderRequestModel, PathContainer>((_, _) => new PathContainer { Name = string.Empty }, Map);
}
// Umbraco.Code.MapAll
private void Map(CreatePathFolderRequestModel source, PathContainer target, MapperContext context)
{
target.Name = source.Name;
target.ParentPath = source.ParentPath;
}
// Umbraco.Code.MapAll
private void Map(PathContainer source, PathFolderResponseModel target, MapperContext context)
{
target.Name = source.Name;
target.ParentPath = source.ParentPath;
}
}

View File

@@ -0,0 +1,49 @@
using Umbraco.Cms.Api.Management.ViewModels.PartialView;
using Umbraco.Cms.Api.Management.ViewModels.PartialView.Snippets;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Snippets;
namespace Umbraco.Cms.Api.Management.Mapping.PartialView;
public class PartialViewViewModelsMapDefinition : IMapDefinition
{
public void DefineMaps(IUmbracoMapper mapper)
{
mapper.Define<PartialViewSnippet, PartialViewSnippetResponseModel>((_, _) => new PartialViewSnippetResponseModel { Name = string.Empty, Content = string.Empty }, Map);
mapper.Define<IPartialView, PartialViewResponseModel>((_, _) => new PartialViewResponseModel { Name = string.Empty, Path = string.Empty, Content = string.Empty }, Map);
mapper.Define<CreatePartialViewRequestModel, PartialViewCreateModel>((_, _) => new PartialViewCreateModel { Name = string.Empty }, Map);
mapper.Define<UpdatePartialViewRequestModel, PartialViewUpdateModel>((_, _) => new PartialViewUpdateModel { Content = string.Empty, ExistingPath = string.Empty, Name = string.Empty }, Map);
}
// Umbraco.Code.MapAll
private void Map(UpdatePartialViewRequestModel source, PartialViewUpdateModel target, MapperContext context)
{
target.Name = source.Name;
target.Content = source.Content;
target.ExistingPath = source.ExistingPath;
}
// Umbraco.Code.MapAll
private void Map(IPartialView source, PartialViewResponseModel target, MapperContext context)
{
target.Name = source.Name ?? string.Empty;
target.Content = source.Content ?? string.Empty;
target.Path = source.Path;
}
// Umbraco.Code.MapAll
private void Map(CreatePartialViewRequestModel source, PartialViewCreateModel target, MapperContext context)
{
target.Name = source.Name;
target.Content = source.Content;
target.ParentPath = source.ParentPath;
}
// Umbraco.Code.MapAll
private void Map(PartialViewSnippet source, PartialViewSnippetResponseModel target, MapperContext context)
{
target.Name = source.Name;
target.Content = source.Content;
}
}

View File

@@ -0,0 +1,39 @@
using Umbraco.Cms.Api.Management.ViewModels.Script;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Api.Management.Mapping.Script;
public class ScriptViewModelsMapDefinition : IMapDefinition
{
public void DefineMaps(IUmbracoMapper mapper)
{
mapper.Define<CreateScriptRequestModel, ScriptCreateModel>((_, _) => new ScriptCreateModel { Name = string.Empty }, Map);
mapper.Define<UpdateScriptRequestModel, ScriptUpdateModel>((_, _) => new ScriptUpdateModel { Name = string.Empty, Content = string.Empty, ExistingPath = string.Empty }, Map);
mapper.Define<IScript, ScriptResponseModel>((_, _) => new ScriptResponseModel { Name = string.Empty, Content = string.Empty }, Map);
}
// Umbraco.Code.MapAll
private void Map(UpdateScriptRequestModel source, ScriptUpdateModel target, MapperContext context)
{
target.Name = source.Name;
target.Content = source.Content;
target.ExistingPath = source.ExistingPath;
}
// Umbraco.Code.MapAll
private void Map(IScript source, ScriptResponseModel target, MapperContext context)
{
target.Name = source.Name ?? string.Empty;
target.Content = source.Content ?? string.Empty;
target.Path = source.Path;
}
// Umbraco.Code.MapAll
private void Map(CreateScriptRequestModel source, ScriptCreateModel target, MapperContext context)
{
target.Name = source.Name;
target.ParentPath = source.ParentPath;
target.Content = source.Content;
}
}

View File

@@ -0,0 +1,74 @@
using Umbraco.Cms.Api.Management.ViewModels.RichTextStylesheet;
using Umbraco.Cms.Api.Management.ViewModels.Stylesheet;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Strings.Css;
namespace Umbraco.Cms.Api.Management.Mapping.Stylesheet;
public class StylesheetViewModelsMapDefinition : IMapDefinition
{
public void DefineMaps(IUmbracoMapper mapper)
{
mapper.Define<IStylesheet, StylesheetResponseModel>((_, _) => new StylesheetResponseModel { Content = string.Empty, Name = string.Empty, Path = string.Empty }, Map);
mapper.Define<CreateStylesheetRequestModel, StylesheetCreateModel>((_, _) => new StylesheetCreateModel { Name = string.Empty }, Map);
mapper.Define<UpdateStylesheetRequestModel, StylesheetUpdateModel>((_, _) => new StylesheetUpdateModel { Content = string.Empty, Name = string.Empty, ExistingPath = string.Empty }, Map);
mapper.Define<InterpolateRichTextStylesheetRequestModel, RichTextStylesheetData>((_, _) => new RichTextStylesheetData(), Map);
mapper.Define<ExtractRichTextStylesheetRulesRequestModel, RichTextStylesheetData>((_, _) => new RichTextStylesheetData(), Map);
mapper.Define<StylesheetRule, RichTextRuleViewModel>((_, _) => new RichTextRuleViewModel { Name = string.Empty, Selector = string.Empty, Styles = string.Empty }, Map);
mapper.Define<IStylesheet, StylesheetOverviewResponseModel>((_, _) => new StylesheetOverviewResponseModel{ Name = string.Empty, Path = string.Empty }, Map);
}
// Umbraco.Code.MapAll
private void Map(IStylesheet source, StylesheetOverviewResponseModel target, MapperContext context)
{
target.Name = source.Alias;
target.Path = source.Path;
}
// Umbraco.Code.MapAll
private void Map(StylesheetRule source, RichTextRuleViewModel target, MapperContext context)
{
target.Name = source.Name;
target.Selector = source.Selector;
target.Styles = source.Styles;
}
// Umbraco.Code.MapAll -Rules
private void Map(ExtractRichTextStylesheetRulesRequestModel source, RichTextStylesheetData target, MapperContext context)
=> target.Content = source.Content;
// Umbraco.Code.MapAll
private void Map(InterpolateRichTextStylesheetRequestModel source, RichTextStylesheetData target, MapperContext context)
{
target.Content = source.Content;
target.Rules = source.Rules?.Select(x => new StylesheetRule
{
Name = x.Name, Selector = x.Selector, Styles = x.Styles,
}).ToArray() ?? Array.Empty<StylesheetRule>();
}
// Umbraco.Code.MapAll
private void Map(UpdateStylesheetRequestModel source, StylesheetUpdateModel target, MapperContext context)
{
target.Content = source.Content;
target.Name = source.Name;
target.ExistingPath = source.ExistingPath;
}
// Umbraco.Code.MapAll
private void Map(CreateStylesheetRequestModel source, StylesheetCreateModel target, MapperContext context)
{
target.Content = source.Content;
target.Name = source.Name;
target.ParentPath = source.ParentPath;
}
// Umbraco.Code.MapAll
private void Map(IStylesheet source, StylesheetResponseModel target, MapperContext context)
{
target.Name = source.Name ?? string.Empty;
target.Content = source.Content ?? string.Empty;
target.Path = source.Path;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Api.Management.ViewModels.Folder;
public class CreatePathFolderRequestModel : PathFolderModelBase
{
public string? ParentPath { get; set; }
}

View File

@@ -0,0 +1,5 @@
namespace Umbraco.Cms.Api.Management.ViewModels.Folder;
public class PathFolderModelBase : FolderModelBase
{
}

View File

@@ -0,0 +1,11 @@
namespace Umbraco.Cms.Api.Management.ViewModels.Folder;
public class PathFolderResponseModel : FolderModelBase
{
public string? ParentPath { get; set; }
public string Path =>
string.IsNullOrEmpty(ParentPath)
? Name
: System.IO.Path.Combine(ParentPath, Name);
}

View File

@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Api.Management.ViewModels.Item;
public class SnippetItemResponseModel
{
public required string Name { get; set; }
}

View File

@@ -0,0 +1,8 @@
using Umbraco.Cms.Api.Management.ViewModels.TextFiles;
namespace Umbraco.Cms.Api.Management.ViewModels.PartialView;
public class CreatePartialViewRequestModel : CreateTextFileViewModelBase
{
}

View File

@@ -0,0 +1,7 @@
using Umbraco.Cms.Api.Management.ViewModels.TextFiles;
namespace Umbraco.Cms.Api.Management.ViewModels.PartialView;
public class PartialViewResponseModel : TextFileResponseModelBase
{
}

View File

@@ -0,0 +1,8 @@
namespace Umbraco.Cms.Api.Management.ViewModels.PartialView.Snippets;
public class PartialViewSnippetResponseModel
{
public required string Name { get; set; }
public required string Content { get; set; }
}

View File

@@ -0,0 +1,19 @@
using System.Diagnostics.CodeAnalysis;
namespace Umbraco.Cms.Api.Management.ViewModels.PartialView.Snippets;
public class SnippetItemResponseModel
{
public SnippetItemResponseModel()
{
}
[SetsRequiredMembers]
public SnippetItemResponseModel(string name)
{
Name = name;
}
public required string Name { get; set; }
}

View File

@@ -0,0 +1,7 @@
using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Api.Management.ViewModels.PartialView;
public class UpdatePartialViewRequestModel : TextFileUpdateModel
{
}

View File

@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Api.Management.ViewModels.RichTextStylesheet;
public class ExtractRichTextStylesheetRulesRequestModel
{
public required string Content { get; set; }
}

View File

@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Api.Management.ViewModels.RichTextStylesheet;
public class ExtractRichTextStylesheetRulesResponseModel : RichTextStylesheetRulesResponseModel
{
}

View File

@@ -0,0 +1,8 @@
namespace Umbraco.Cms.Api.Management.ViewModels.RichTextStylesheet;
public class InterpolateRichTextStylesheetRequestModel
{
public string? Content { get; set; }
public IEnumerable<RichTextRuleViewModel>? Rules { get; set; }
}

View File

@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Api.Management.ViewModels.RichTextStylesheet;
public class InterpolateRichTextStylesheetResponseModel
{
public required string Content { get; set; }
}

View File

@@ -0,0 +1,10 @@
namespace Umbraco.Cms.Api.Management.ViewModels.RichTextStylesheet;
public class RichTextRuleViewModel
{
public required string Name { get; set; }
public required string Selector { get; set; }
public required string Styles { get; set; }
}

View File

@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Api.Management.ViewModels.RichTextStylesheet;
public class RichTextStylesheetRulesResponseModel
{
public required IEnumerable<RichTextRuleViewModel> Rules { get; set; } = Enumerable.Empty<RichTextRuleViewModel>();
}

View File

@@ -0,0 +1,8 @@
using Umbraco.Cms.Api.Management.ViewModels.TextFiles;
namespace Umbraco.Cms.Api.Management.ViewModels.Script;
public class CreateScriptRequestModel : CreateTextFileViewModelBase
{
}

View File

@@ -0,0 +1,7 @@
using Umbraco.Cms.Api.Management.ViewModels.TextFiles;
namespace Umbraco.Cms.Api.Management.ViewModels.Script;
public class ScriptResponseModel : TextFileResponseModelBase
{
}

View File

@@ -0,0 +1,7 @@
using Umbraco.Cms.Api.Management.ViewModels.TextFiles;
namespace Umbraco.Cms.Api.Management.ViewModels.Script;
public class ScriptViewModelBase : TextFileViewModelBase
{
}

View File

@@ -0,0 +1,7 @@
using Umbraco.Cms.Api.Management.ViewModels.TextFiles;
namespace Umbraco.Cms.Api.Management.ViewModels.Script;
public class UpdateScriptRequestModel : UpdateTextFileViewModelBase
{
}

View File

@@ -0,0 +1,8 @@
using Umbraco.Cms.Api.Management.ViewModels.TextFiles;
namespace Umbraco.Cms.Api.Management.ViewModels.Stylesheet;
public class CreateStylesheetRequestModel : CreateTextFileViewModelBase
{
}

View File

@@ -0,0 +1,8 @@
namespace Umbraco.Cms.Api.Management.ViewModels.Stylesheet;
public class StylesheetOverviewResponseModel
{
public required string Name { get; set; }
public required string Path { get; set; }
}

View File

@@ -0,0 +1,7 @@
using Umbraco.Cms.Api.Management.ViewModels.TextFiles;
namespace Umbraco.Cms.Api.Management.ViewModels.Stylesheet;
public class StylesheetResponseModel : TextFileResponseModelBase
{
}

View File

@@ -0,0 +1,7 @@
using Umbraco.Cms.Api.Management.ViewModels.TextFiles;
namespace Umbraco.Cms.Api.Management.ViewModels.Stylesheet;
public class UpdateStylesheetRequestModel : UpdateTextFileViewModelBase
{
}

View File

@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Api.Management.ViewModels.TextFiles;
public class CreateTextFileViewModelBase : TextFileViewModelBase
{
public string? ParentPath { get; set; }
}

View File

@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Api.Management.ViewModels.TextFiles;
public class TextFileResponseModelBase : TextFileViewModelBase
{
public string Path { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,8 @@
namespace Umbraco.Cms.Api.Management.ViewModels.TextFiles;
public class TextFileViewModelBase
{
public required string Name { get; set; }
public required string Content { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace Umbraco.Cms.Api.Management.ViewModels.TextFiles;
public class UpdateTextFileViewModelBase : TextFileViewModelBase
{
public required string ExistingPath { get; set; }
}

View File

@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/en-us/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
@@ -918,6 +917,20 @@
<Right>lib/net7.0/Umbraco.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Umbraco.Cms.Core.Persistence.Repositories.IFileWithFoldersRepository.FolderExists(System.String)</Target>
<Left>lib/net7.0/Umbraco.Core.dll</Left>
<Right>lib/net7.0/Umbraco.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Umbraco.Cms.Core.Persistence.Repositories.IFileWithFoldersRepository.FolderHasContent(System.String)</Target>
<Left>lib/net7.0/Umbraco.Core.dll</Left>
<Right>lib/net7.0/Umbraco.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0006</DiagnosticId>
<Target>M:Umbraco.Cms.Core.Persistence.Repositories.IPropertyTypeUsageRepository.ContentTypeExistAsync(System.Guid)</Target>

View File

@@ -306,6 +306,13 @@ namespace Umbraco.Cms.Core.DependencyInjection
Services.AddUnique<IMediaTypeService, MediaTypeService>();
Services.AddUnique<IFileService, FileService>();
Services.AddUnique<ITemplateService, TemplateService>();
Services.AddUnique<IScriptService, ScriptService>();
Services.AddUnique<IStylesheetService, StylesheetService>();
Services.AddUnique<IStylesheetFolderService, StylesheetFolderService>();
Services.AddUnique<IRichTextStylesheetService, RichTextStylesheetService>();
Services.AddUnique<IPartialViewService, PartialViewService>();
Services.AddUnique<IScriptFolderService, ScriptFolderService>();
Services.AddUnique<IPartialViewFolderService, PartialViewFolderService>();
Services.AddUnique<ITemporaryFileService, TemporaryFileService>();
Services.AddUnique<ITemplateContentParserService, TemplateContentParserService>();
Services.AddUnique<IEntityService, EntityService>();

View File

@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Core.Models;
public class PartialViewCreateModel : TextFileCreateModel
{
}

View File

@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Core.Models;
public class PartialViewUpdateModel : TextFileUpdateModel
{
}

View File

@@ -0,0 +1,25 @@
namespace Umbraco.Cms.Core.Models;
/// <summary>
/// A container using a path as its identity.
/// </summary>
public class PathContainer
{
/// <summary>
/// The name of the container
/// </summary>
public required string Name { get; set; }
/// <summary>
/// The path to the parent of the container
/// </summary>
public string? ParentPath { get; set; }
/// <summary>
/// The path of the container.
/// </summary>
public string Path =>
string.IsNullOrEmpty(ParentPath)
? Name
: System.IO.Path.Combine(ParentPath, Name);
}

View File

@@ -0,0 +1,10 @@
using Umbraco.Cms.Core.Strings.Css;
namespace Umbraco.Cms.Core.Models;
public class RichTextStylesheetData
{
public string? Content { get; set; }
public StylesheetRule[] Rules { get; set; } = Array.Empty<StylesheetRule>();
}

View File

@@ -0,0 +1,5 @@
namespace Umbraco.Cms.Core.Models;
public class ScriptCreateModel : TextFileCreateModel
{
}

View File

@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Core.Models;
public class ScriptUpdateModel : TextFileUpdateModel
{
}

View File

@@ -0,0 +1,5 @@
namespace Umbraco.Cms.Core.Models;
public class StylesheetCreateModel : TextFileCreateModel
{
}

View File

@@ -0,0 +1,5 @@
namespace Umbraco.Cms.Core.Models;
public class StylesheetUpdateModel : TextFileUpdateModel
{
}

View File

@@ -0,0 +1,15 @@
namespace Umbraco.Cms.Core.Models;
public class TextFileCreateModel
{
public required string Name { get; set; }
public string? ParentPath { get; set; }
public string? Content { get; set; }
public string FilePath =>
ParentPath is null
? Name
: Path.Combine(ParentPath, Name);
}

View File

@@ -0,0 +1,19 @@
namespace Umbraco.Cms.Core.Models;
public class TextFileUpdateModel
{
/// <summary>
/// The new name of the file.
/// </summary>
public required string Name { get; set; }
/// <summary>
/// The new content of the file.
/// </summary>
public required string Content { get; set; }
/// <summary>
/// The path of the file to update.
/// </summary>
public required string ExistingPath { get; set; }
}

View File

@@ -5,4 +5,8 @@ public interface IFileWithFoldersRepository
void AddFolder(string folderPath);
void DeleteFolder(string folderPath);
bool FolderExists(string folderPath);
bool FolderHasContent(string folderPath);
}

View File

@@ -101,6 +101,7 @@ public class FileService : RepositoryService, IFileService
#region Stylesheets
/// <inheritdoc />
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
public IEnumerable<IStylesheet> GetStylesheets(params string[] paths)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
@@ -113,6 +114,7 @@ public class FileService : RepositoryService, IFileService
_auditRepository.Save(new AuditItem(objectId, type, userId, entityType));
/// <inheritdoc />
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
public IStylesheet? GetStylesheet(string? path)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
@@ -122,6 +124,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
public void SaveStylesheet(IStylesheet? stylesheet, int? userId = null)
{
if (stylesheet is null)
@@ -150,6 +153,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
public void DeleteStylesheet(string path, int? userId)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
@@ -181,6 +185,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
public void CreateStyleSheetFolder(string folderPath)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
@@ -191,6 +196,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IStylesheetFolderService for stylesheet folder operations - will be removed in Umbraco 15")]
public void DeleteStyleSheetFolder(string folderPath)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
@@ -201,6 +207,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
public Stream GetStylesheetFileContentStream(string filepath)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
@@ -210,6 +217,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
public void SetStylesheetFileContent(string filepath, Stream content)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
@@ -220,6 +228,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
public long GetStylesheetFileSize(string filepath)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
@@ -233,6 +242,7 @@ public class FileService : RepositoryService, IFileService
#region Scripts
/// <inheritdoc />
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
public IEnumerable<IScript> GetScripts(params string[] names)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
@@ -242,6 +252,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
public IScript? GetScript(string? name)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
@@ -251,6 +262,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
public void SaveScript(IScript? script, int? userId)
{
if (userId is null)
@@ -283,6 +295,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
public void DeleteScript(string path, int? userId = null)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
@@ -313,6 +326,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IScriptFolderService for script folder operations - will be removed in Umbraco 15")]
public void CreateScriptFolder(string folderPath)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
@@ -323,6 +337,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IScriptFolderService for script folder operations - will be removed in Umbraco 15")]
public void DeleteScriptFolder(string folderPath)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
@@ -333,6 +348,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
public Stream GetScriptFileContentStream(string filepath)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
@@ -342,6 +358,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
public void SetScriptFileContent(string filepath, Stream content)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
@@ -352,6 +369,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
public long GetScriptFileSize(string filepath)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
@@ -571,6 +589,7 @@ public class FileService : RepositoryService, IFileService
#region Partial Views
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
public IEnumerable<string> GetPartialViewSnippetNames(params string[] filterNames)
{
var snippetProvider =
@@ -590,6 +609,7 @@ public class FileService : RepositoryService, IFileService
return empty.Union(files.Except(empty)).WhereNotNull();
}
[Obsolete("Please use IPartialViewFolderService for partial view folder operations - will be removed in Umbraco 15")]
public void DeletePartialViewFolder(string folderPath)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
@@ -608,6 +628,7 @@ public class FileService : RepositoryService, IFileService
}
}
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
public IEnumerable<IPartialView> GetPartialViews(params string[] names)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
@@ -616,6 +637,7 @@ public class FileService : RepositoryService, IFileService
}
}
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
public IPartialView? GetPartialView(string path)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
@@ -632,12 +654,14 @@ public class FileService : RepositoryService, IFileService
}
}
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
public Attempt<IPartialView?> CreatePartialView(IPartialView partialView, string? snippetName = null, int? userId = Constants.Security.SuperUserId) =>
CreatePartialViewMacro(partialView, PartialViewType.PartialView, snippetName, userId);
public Attempt<IPartialView?> CreatePartialViewMacro(IPartialView partialView, string? snippetName = null, int? userId = Constants.Security.SuperUserId) =>
CreatePartialViewMacro(partialView, PartialViewType.PartialViewMacro, snippetName, userId);
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
public bool DeletePartialView(string path, int? userId = null) =>
DeletePartialViewMacro(path, PartialViewType.PartialView, userId);
@@ -719,6 +743,7 @@ public class FileService : RepositoryService, IFileService
public bool DeletePartialViewMacro(string path, int? userId = null) =>
DeletePartialViewMacro(path, PartialViewType.PartialViewMacro, userId);
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
public Attempt<IPartialView?> SavePartialView(IPartialView partialView, int? userId = null) =>
SavePartialView(partialView, PartialViewType.PartialView, userId);
@@ -757,6 +782,7 @@ public class FileService : RepositoryService, IFileService
public Attempt<IPartialView?> SavePartialViewMacro(IPartialView partialView, int? userId = null) =>
SavePartialView(partialView, PartialViewType.PartialViewMacro, userId);
[Obsolete("Please use IPartialViewFolderService for partial view folder operations - will be removed in Umbraco 15")]
public void CreatePartialViewFolder(string folderPath)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
@@ -772,6 +798,7 @@ public class FileService : RepositoryService, IFileService
return headerMatch.Replace(contents, string.Empty);
}
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
private Attempt<IPartialView?> SavePartialView(IPartialView partialView, PartialViewType partialViewType, int? userId = null)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
@@ -823,6 +850,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
public Stream GetPartialViewFileContentStream(string filepath)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
@@ -845,6 +873,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
public void SetPartialViewFileContent(string filepath, Stream content)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
@@ -855,6 +884,7 @@ public class FileService : RepositoryService, IFileService
}
/// <inheritdoc />
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
public long GetPartialViewFileSize(string filepath)
{
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))

View File

@@ -0,0 +1,77 @@
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.Services;
public abstract class FileServiceBase<TRepository, TEntity> : RepositoryService, IBasicFileService<TEntity>
where TRepository : IFileRepository, IReadRepository<string, TEntity>
where TEntity : IFile
{
public TRepository Repository { get; }
public FileServiceBase(
ICoreScopeProvider provider,
ILoggerFactory loggerFactory,
IEventMessagesFactory eventMessagesFactory,
TRepository repository)
: base(provider, loggerFactory, eventMessagesFactory)
{
Repository = repository;
}
protected abstract string[] AllowedFileExtensions { get; }
protected virtual bool HasValidFileExtension(string fileName)
=> AllowedFileExtensions.Contains(Path.GetExtension(fileName));
protected virtual bool HasValidFileName(string fileName)
{
if (fileName.ContainsAny(Path.GetInvalidFileNameChars()))
{
return false;
}
return true;
}
/// <inheritdoc />
public Task<TEntity?> GetAsync(string path)
{
using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true);
return Task.FromResult(Repository.Get(path));
}
/// <inheritdoc />
public Task<IEnumerable<TEntity>> GetAllAsync(params string[] paths)
{
using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true);
return Task.FromResult(Repository.GetMany(paths));
}
/// <inheritdoc />
public Task<Stream> GetContentStreamAsync(string path)
{
using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true);
return Task.FromResult(Repository.GetFileContentStream(path));
}
/// <inheritdoc />
public Task SetContentStreamAsync(string path, Stream content)
{
using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true);
Repository.SetFileContent(path, content);
return Task.CompletedTask;
}
/// <inheritdoc />
public Task<long> GetFileSizeAsync(string path)
{
using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true);
return Task.FromResult(Repository.GetFileSize(path));
}
}

View File

@@ -0,0 +1,41 @@
using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Core.Services;
public interface IBasicFileService<TEntity> where TEntity : IFile
{
/// <summary>
/// Gets <see cref="TEntity"/> by path.
/// </summary>
/// <param name="path">The path to get <see cref="TEntity"/> from.</param>
/// <returns><see cref="TEntity"/>, or null if not found</returns>
Task<TEntity?> GetAsync(string path);
/// <summary>
/// Gets all <see cref="TEntity"/> by path, or all if no paths are specified.
/// </summary>
/// <param name="paths">Optional paths of <see cref="TEntity"/> to get.</param>
/// <returns>IEnumerable of <see cref="TEntity"/></returns>
Task<IEnumerable<TEntity>> GetAllAsync(params string[] paths);
/// <summary>
/// Get the content of a file as a stream.
/// </summary>
/// <param name="path">The path to the file.</param>
/// <returns>A stream containing the contents of the file.</returns>
Task<Stream> GetContentStreamAsync(string path);
/// <summary>
/// Set the content of a file from a stream.
/// </summary>
/// <param name="path">The path to the file.</param>
/// <param name="content">The desired content of the file as a stream.</param>
Task SetContentStreamAsync(string path, Stream content);
/// <summary>
///
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
Task<long> GetFileSizeAsync(string path);
}

View File

@@ -11,10 +11,12 @@ public interface IFileService : IService
[Obsolete("Please use SnippetCollection.GetPartialViewSnippetNames() or SnippetCollection.GetPartialViewMacroSnippetNames() instead. Scheduled for removal in V12.")]
IEnumerable<string> GetPartialViewSnippetNames(params string[] filterNames);
[Obsolete("Please use IPartialViewFolderService for partial view folder operations - will be removed in Umbraco 15")]
void CreatePartialViewFolder(string folderPath);
void CreatePartialViewMacroFolder(string folderPath);
[Obsolete("Please use IPartialViewFolderService for partial view folder operations - will be removed in Umbraco 15")]
void DeletePartialViewFolder(string folderPath);
void DeletePartialViewMacroFolder(string folderPath);
@@ -23,20 +25,25 @@ public interface IFileService : IService
/// Gets a list of all <see cref="IPartialView" /> objects
/// </summary>
/// <returns>An enumerable list of <see cref="IPartialView" /> objects</returns>
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
IEnumerable<IPartialView> GetPartialViews(params string[] names);
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
IPartialView? GetPartialView(string path);
IPartialView? GetPartialViewMacro(string path);
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
Attempt<IPartialView?> CreatePartialView(IPartialView partialView, string? snippetName = null, int? userId = Constants.Security.SuperUserId);
Attempt<IPartialView?> CreatePartialViewMacro(IPartialView partialView, string? snippetName = null, int? userId = Constants.Security.SuperUserId);
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
bool DeletePartialView(string path, int? userId = null);
bool DeletePartialViewMacro(string path, int? userId = null);
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
Attempt<IPartialView?> SavePartialView(IPartialView partialView, int? userId = null);
Attempt<IPartialView?> SavePartialViewMacro(IPartialView partialView, int? userId = null);
@@ -46,6 +53,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="filepath">The filesystem path to the partial view.</param>
/// <returns>The content of the partial view.</returns>
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
Stream GetPartialViewFileContentStream(string filepath);
/// <summary>
@@ -53,6 +61,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="filepath">The filesystem path to the partial view.</param>
/// <param name="content">The content of the partial view.</param>
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
void SetPartialViewFileContent(string filepath, Stream content);
/// <summary>
@@ -60,6 +69,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="filepath">The filesystem path to the partial view.</param>
/// <returns>The size of the partial view.</returns>
[Obsolete("Please use IPartialViewService for partial view operations - will be removed in Umbraco 15")]
long GetPartialViewFileSize(string filepath);
/// <summary>
@@ -87,6 +97,7 @@ public interface IFileService : IService
/// Gets a list of all <see cref="IStylesheet" /> objects
/// </summary>
/// <returns>An enumerable list of <see cref="IStylesheet" /> objects</returns>
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
IEnumerable<IStylesheet> GetStylesheets(params string[] paths);
/// <summary>
@@ -94,6 +105,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="path">Path of the stylesheet incl. extension</param>
/// <returns>A <see cref="IStylesheet" /> object</returns>
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
IStylesheet? GetStylesheet(string? path);
/// <summary>
@@ -101,6 +113,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="stylesheet"><see cref="IStylesheet" /> to save</param>
/// <param name="userId">Optional id of the user saving the stylesheet</param>
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
void SaveStylesheet(IStylesheet? stylesheet, int? userId = null);
/// <summary>
@@ -108,6 +121,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="path">Name incl. extension of the Stylesheet to delete</param>
/// <param name="userId">Optional id of the user deleting the stylesheet</param>
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
void DeleteStylesheet(string path, int? userId = null);
/// <summary>
@@ -115,12 +129,14 @@ public interface IFileService : IService
/// </summary>
/// <param name="folderPath"></param>
/// <returns></returns>
[Obsolete("Please use IStylesheetFolderService for stylesheet folder operations - will be removed in Umbraco 15")]
void CreateStyleSheetFolder(string folderPath);
/// <summary>
/// Deletes a folder for style sheets
/// </summary>
/// <param name="folderPath"></param>
[Obsolete("Please use IStylesheetFolderService for stylesheet folder operations - will be removed in Umbraco 15")]
void DeleteStyleSheetFolder(string folderPath);
/// <summary>
@@ -128,6 +144,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="filepath">The filesystem path to the stylesheet.</param>
/// <returns>The content of the stylesheet.</returns>
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
Stream GetStylesheetFileContentStream(string filepath);
/// <summary>
@@ -135,6 +152,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="filepath">The filesystem path to the stylesheet.</param>
/// <param name="content">The content of the stylesheet.</param>
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
void SetStylesheetFileContent(string filepath, Stream content);
/// <summary>
@@ -142,12 +160,14 @@ public interface IFileService : IService
/// </summary>
/// <param name="filepath">The filesystem path to the stylesheet.</param>
/// <returns>The size of the stylesheet.</returns>
[Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")]
long GetStylesheetFileSize(string filepath);
/// <summary>
/// Gets a list of all <see cref="IScript" /> objects
/// </summary>
/// <returns>An enumerable list of <see cref="IScript" /> objects</returns>
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
IEnumerable<IScript> GetScripts(params string[] names);
/// <summary>
@@ -155,6 +175,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="name">Name of the script incl. extension</param>
/// <returns>A <see cref="IScript" /> object</returns>
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
IScript? GetScript(string? name);
/// <summary>
@@ -162,6 +183,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="script"><see cref="IScript" /> to save</param>
/// <param name="userId">Optional id of the user saving the script</param>
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
void SaveScript(IScript? script, int? userId = Constants.Security.SuperUserId);
/// <summary>
@@ -169,6 +191,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="path">Name incl. extension of the Script to delete</param>
/// <param name="userId">Optional id of the user deleting the script</param>
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
void DeleteScript(string path, int? userId = null);
/// <summary>
@@ -176,12 +199,14 @@ public interface IFileService : IService
/// </summary>
/// <param name="folderPath"></param>
/// <returns></returns>
[Obsolete("Please use IScriptFolderService for script folder operations - will be removed in Umbraco 15")]
void CreateScriptFolder(string folderPath);
/// <summary>
/// Deletes a folder for scripts
/// </summary>
/// <param name="folderPath"></param>
[Obsolete("Please use IScriptFolderService for script folder operations - will be removed in Umbraco 15")]
void DeleteScriptFolder(string folderPath);
/// <summary>
@@ -189,6 +214,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="filepath">The filesystem path to the script.</param>
/// <returns>The content of the script file.</returns>
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
Stream GetScriptFileContentStream(string filepath);
/// <summary>
@@ -196,6 +222,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="filepath">The filesystem path to the script.</param>
/// <param name="content">The content of the script file.</param>
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
void SetScriptFileContent(string filepath, Stream content);
/// <summary>
@@ -203,18 +230,21 @@ public interface IFileService : IService
/// </summary>
/// <param name="filepath">The filesystem path to the script file.</param>
/// <returns>The size of the script file.</returns>
[Obsolete("Please use IScriptService for script operations - will be removed in Umbraco 15")]
long GetScriptFileSize(string filepath);
/// <summary>
/// Gets a list of all <see cref="ITemplate" /> objects
/// </summary>
/// <returns>An enumerable list of <see cref="ITemplate" /> objects</returns>
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
IEnumerable<ITemplate> GetTemplates(params string[] aliases);
/// <summary>
/// Gets a list of all <see cref="ITemplate" /> objects
/// </summary>
/// <returns>An enumerable list of <see cref="ITemplate" /> objects</returns>
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
IEnumerable<ITemplate> GetTemplates(int masterTemplateId);
/// <summary>
@@ -222,6 +252,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="alias">The alias of the template.</param>
/// <returns>The <see cref="ITemplate" /> object matching the alias, or null.</returns>
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
ITemplate? GetTemplate(string? alias);
/// <summary>
@@ -229,6 +260,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="id">The identifier of the template.</param>
/// <returns>The <see cref="ITemplate" /> object matching the identifier, or null.</returns>
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
ITemplate? GetTemplate(int id);
/// <summary>
@@ -236,6 +268,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="id">The guid identifier of the template.</param>
/// <returns>The <see cref="ITemplate" /> object matching the identifier, or null.</returns>
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
ITemplate? GetTemplate(Guid id);
/// <summary>
@@ -243,6 +276,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="masterTemplateId"></param>
/// <returns></returns>
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
IEnumerable<ITemplate> GetTemplateDescendants(int masterTemplateId);
/// <summary>
@@ -250,6 +284,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="template"><see cref="ITemplate" /> to save</param>
/// <param name="userId">Optional id of the user saving the template</param>
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
void SaveTemplate(ITemplate template, int userId = Constants.Security.SuperUserId);
/// <summary>
@@ -261,11 +296,13 @@ public interface IFileService : IService
/// <returns>
/// The template created
/// </returns>
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
Attempt<OperationResult<OperationResultType, ITemplate>?> CreateTemplateForContentType(
string contentTypeAlias,
string? contentTypeName,
int userId = Constants.Security.SuperUserId);
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
ITemplate CreateTemplateWithIdentity(string? name, string? alias, string? content, ITemplate? masterTemplate = null, int userId = Constants.Security.SuperUserId);
/// <summary>
@@ -273,6 +310,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="alias">Alias of the <see cref="ITemplate" /> to delete</param>
/// <param name="userId">Optional id of the user deleting the template</param>
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
void DeleteTemplate(string alias, int userId = Constants.Security.SuperUserId);
/// <summary>
@@ -280,6 +318,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="templates">List of <see cref="Template" /> to save</param>
/// <param name="userId">Optional id of the user</param>
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
void SaveTemplate(IEnumerable<ITemplate> templates, int userId = Constants.Security.SuperUserId);
/// <summary>
@@ -287,6 +326,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="filepath">The filesystem path to the template.</param>
/// <returns>The content of the template.</returns>
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
Stream GetTemplateFileContentStream(string filepath);
/// <summary>
@@ -294,6 +334,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="filepath">The filesystem path to the template.</param>
/// <param name="content">The content of the template.</param>
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
void SetTemplateFileContent(string filepath, Stream content);
/// <summary>
@@ -301,6 +342,7 @@ public interface IFileService : IService
/// </summary>
/// <param name="filepath">The filesystem path to the template.</param>
/// <returns>The size of the template.</returns>
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
long GetTemplateFileSize(string filepath);
/// <summary>

View File

@@ -0,0 +1,8 @@
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Core.Services;
public interface IPartialViewFolderService : IPathFolderService<PartialViewFolderOperationStatus>
{
}

View File

@@ -0,0 +1,49 @@
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.New.Cms.Core.Models;
using PartialViewSnippet = Umbraco.Cms.Core.Snippets.PartialViewSnippet;
namespace Umbraco.Cms.Core.Services;
public interface IPartialViewService : IBasicFileService<IPartialView>
{
/// <summary>
/// Deletes a partial view.
/// </summary>
/// <param name="path">The path of the partial view to delete.</param>
/// <param name="performingUserKey">The key of the user performing the operation.</param>
/// <returns>An operation status.</returns>
Task<PartialViewOperationStatus> DeleteAsync(string path, Guid performingUserKey);
/// <summary>
/// Gets the name of all the available partial view snippets.
/// </summary>
/// <param name="skip">Amount to skip.</param>
/// <param name="take">Amount to take.</param>
/// <returns></returns>
Task<PagedModel<string>> GetSnippetNamesAsync(int skip, int take);
/// <summary>
/// Gets a partial view snippet by name, returns null if not found.
/// </summary>
/// <param name="name">The name of the snippet to get.</param>
/// <returns>The partial view snippet, null if not found.</returns>
Task<PartialViewSnippet?> GetSnippetByNameAsync(string name);
/// <summary>
/// Creates a new partial view.
/// </summary>
/// <param name="createModel"><see cref="PartialViewCreateModel"/> containing the information about the partial view being created.</param>
/// <param name="performingUserKey">The key of the user performing the operation.</param>
/// <returns>An attempt indicating if the operation was a success as well as a more detailed <see cref="PartialViewOperationStatus"/>.</returns>
Task<Attempt<IPartialView?, PartialViewOperationStatus>> CreateAsync(PartialViewCreateModel createModel, Guid performingUserKey);
/// <summary>
/// Updates an existing partial view.
/// </summary>
/// <param name="updateModel">A <see cref="PartialViewUpdateModel"/> with the changes.</param>
/// <param name="performingUserKey">The key of the user performing the operation.</param>
/// <returns>An attempt indicating if the operation was a success as well as a more detailed <see cref="PartialViewOperationStatus"/>.</returns>
Task<Attempt<IPartialView?, PartialViewOperationStatus>> UpdateAsync(PartialViewUpdateModel updateModel, Guid performingUserKey);
}

View File

@@ -0,0 +1,12 @@
using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Core.Services;
public interface IPathFolderService<TStatus> where TStatus : Enum
{
Task<PathContainer?> GetAsync(string path);
Task<Attempt<PathContainer?, TStatus>> CreateAsync(PathContainer container);
Task<Attempt<TStatus?>> DeleteAsync(string path);
}

View File

@@ -0,0 +1,14 @@
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Cms.Core.Strings.Css;
namespace Umbraco.Cms.Core.Services;
public interface IRichTextStylesheetService
{
Task<string> InterpolateRichTextRules(RichTextStylesheetData data);
Task<IEnumerable<StylesheetRule>> ExtractRichTextRules(RichTextStylesheetData data);
Task<Attempt<IEnumerable<StylesheetRule>, StylesheetOperationStatus>> GetRulesByPathAsync(string path);
}

View File

@@ -0,0 +1,8 @@
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Core.Services;
public interface IScriptFolderService : IPathFolderService<ScriptFolderOperationStatus>
{
}

View File

@@ -0,0 +1,31 @@
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Core.Services;
public interface IScriptService : IBasicFileService<IScript>
{
/// <summary>
/// Creates a new script.
/// </summary>
/// <param name="createModel"><see cref="ScriptCreateModel"/> containing the information about the script being created.</param>
/// <param name="performingUserKey">The key of the user performing the operation.</param>
/// <returns>An attempt indicating if the operation was a success as well as a more detailed <see cref="ScriptOperationStatus"/>.</returns>
Task<Attempt<IScript?, ScriptOperationStatus>> CreateAsync(ScriptCreateModel createModel, Guid performingUserKey);
/// <summary>
/// Updates an existing script.
/// </summary>
/// <param name="updateModel">A <see cref="ScriptUpdateModel"/> with the changes.</param>
/// <param name="performingUserKey">The key of the user performing the operation.</param>
/// <returns>An attempt indicating if the operation was a success as well as a more detailed <see cref="ScriptOperationStatus"/>.</returns>
Task<Attempt<IScript?, ScriptOperationStatus>> UpdateAsync(ScriptUpdateModel updateModel, Guid performingUserKey);
/// <summary>
/// Deletes a Script.
/// </summary>
/// <param name="path">The path of the script to delete.</param>
/// <param name="performingUserKey">The key of the user performing the operation.</param>
/// <returns>An operation status.</returns>
Task<ScriptOperationStatus> DeleteAsync(string path, Guid performingUserKey);
}

View File

@@ -0,0 +1,8 @@
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Core.Services;
public interface IStylesheetFolderService : IPathFolderService<StylesheetFolderOperationStatus>
{
}

View File

@@ -0,0 +1,31 @@
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Core.Services;
public interface IStylesheetService : IBasicFileService<IStylesheet>
{
/// <summary>
/// Creates a new stylesheet.
/// </summary>
/// <param name="createModel"><see cref="StylesheetCreateModel"/> containing the information about the stylesheet being created.</param>
/// <param name="performingUserKey">The key of the user performing the operation.</param>
/// <returns>An attempt indicating if the operation was a success as well as a more detailed <see cref="StylesheetOperationStatus"/>.</returns>
Task<Attempt<IStylesheet?, StylesheetOperationStatus>> CreateAsync(StylesheetCreateModel createModel, Guid performingUserKey);
/// <summary>
/// Updates an existing stylesheet.
/// </summary>
/// <param name="updateModel">A <see cref="StylesheetUpdateModel"/> with the changes.</param>
/// <param name="performingUserKey">The key of the user performing the operation.</param>
/// <returns>An attempt indicating if the operation was a success as well as a more detailed <see cref="StylesheetOperationStatus"/>.</returns>
Task<Attempt<IStylesheet?, StylesheetOperationStatus>> UpdateAsync(StylesheetUpdateModel updateModel, Guid performingUserKey);
/// <summary>
/// Deletes a stylesheet.
/// </summary>
/// <param name="path">The path of the stylesheet to delete.</param>
/// <param name="performingUserKey">The key of the user performing the operation.</param>
/// <returns>An operation status.</returns>
Task<StylesheetOperationStatus> DeleteAsync(string path, Guid performingUserKey);
}

View File

@@ -0,0 +1,11 @@
namespace Umbraco.Cms.Core.Services.OperationStatus;
public enum PartialViewFolderOperationStatus
{
Success,
AlreadyExists,
NotFound,
NotEmpty,
ParentNotFound,
InvalidName,
}

View File

@@ -0,0 +1,13 @@
namespace Umbraco.Cms.Core.Services.OperationStatus;
public enum PartialViewOperationStatus
{
Success,
AlreadyExists,
ParentNotFound,
InvalidName,
InvalidFileExtension,
PathTooLong,
CancelledByNotification,
NotFound
}

Some files were not shown because too many files have changed in this diff Show More