Align template API with dictionary API (#13714)
* Align the template services and API with the dictionary ones (use attempt pattern) * A little controller clean-up * Mimic old file service behavior, make unit tests happy * Align CreateForContentTypeAsync return value with the rest of the TemplateService API * Scaffold endpoint should no longer feature master templates * Update the OpenAPI JSON
This commit is contained in:
@@ -24,7 +24,7 @@ public class ByKeyTemplateController : TemplateControllerBase
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<TemplateViewModel>> ByKey(Guid key)
|
||||
{
|
||||
ITemplate? template = await _templateService.GetTemplateAsync(key);
|
||||
ITemplate? template = await _templateService.GetAsync(key);
|
||||
return template == null
|
||||
? NotFound()
|
||||
: Ok(_umbracoMapper.Map<TemplateViewModel>(template));
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Template;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Template;
|
||||
|
||||
@@ -12,32 +13,30 @@ public class CreateTemplateController : TemplateControllerBase
|
||||
{
|
||||
private readonly ITemplateService _templateService;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
private readonly ITemplateContentParserService _templateContentParserService;
|
||||
|
||||
public CreateTemplateController(
|
||||
ITemplateService templateService,
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
|
||||
ITemplateContentParserService templateContentParserService)
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
|
||||
{
|
||||
_templateService = templateService;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
_templateContentParserService = templateContentParserService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> Create(TemplateCreateModel createModel)
|
||||
public async Task<IActionResult> Create(TemplateCreateModel createModel)
|
||||
{
|
||||
ITemplate? template = await _templateService.CreateTemplateWithIdentityAsync(
|
||||
Attempt<ITemplate, TemplateOperationStatus> result = await _templateService.CreateAsync(
|
||||
createModel.Name,
|
||||
createModel.Alias,
|
||||
createModel.Content,
|
||||
CurrentUserId(_backOfficeSecurityAccessor));
|
||||
|
||||
return template == null
|
||||
? NotFound()
|
||||
: CreatedAtAction<ByKeyTemplateController>(controller => nameof(controller.ByKey), template.Key);
|
||||
return result.Success
|
||||
? CreatedAtAction<ByKeyTemplateController>(controller => nameof(controller.ByKey), result.Result.Key)
|
||||
: TemplateOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core;
|
||||
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.Template;
|
||||
|
||||
@@ -19,9 +22,13 @@ public class DeleteTemplateController : TemplateControllerBase
|
||||
[HttpDelete("{key:guid}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> Delete(Guid key)
|
||||
=> await _templateService.DeleteTemplateAsync(key, CurrentUserId(_backOfficeSecurityAccessor))
|
||||
public async Task<IActionResult> Delete(Guid key)
|
||||
{
|
||||
Attempt<ITemplate?, TemplateOperationStatus> result = await _templateService.DeleteAsync(key, CurrentUserId(_backOfficeSecurityAccessor));
|
||||
return result.Success
|
||||
? Ok()
|
||||
: NotFound();
|
||||
: TemplateOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@ public class ScaffoldTemplateController : TemplateControllerBase
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(TemplateScaffoldViewModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<TemplateScaffoldViewModel>> Scaffold(string? masterTemplateAlias = null)
|
||||
public async Task<ActionResult<TemplateScaffoldViewModel>> Scaffold()
|
||||
{
|
||||
var scaffoldViewModel = new TemplateScaffoldViewModel
|
||||
{
|
||||
Content = _defaultViewContentProvider.GetDefaultFileContent(masterTemplateAlias)
|
||||
Content = _defaultViewContentProvider.GetDefaultFileContent()
|
||||
};
|
||||
|
||||
return await Task.FromResult(Ok(scaffoldViewModel));
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
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.Template;
|
||||
|
||||
@@ -10,4 +13,18 @@ namespace Umbraco.Cms.Api.Management.Controllers.Template;
|
||||
[ApiVersion("1.0")]
|
||||
public class TemplateControllerBase : ManagementApiControllerBase
|
||||
{
|
||||
protected IActionResult TemplateOperationStatusResult(TemplateOperationStatus status) =>
|
||||
status switch
|
||||
{
|
||||
TemplateOperationStatus.TemplateNotFound => NotFound("The template could not be found"),
|
||||
TemplateOperationStatus.InvalidAlias => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Invalid alias")
|
||||
.WithDetail("The template alias is not valid.")
|
||||
.Build()),
|
||||
TemplateOperationStatus.CancelledByNotification => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Cancelled by notification")
|
||||
.WithDetail("A notification handler prevented the template operation.")
|
||||
.Build()),
|
||||
_ => StatusCode(StatusCodes.Status500InternalServerError, "Unknown template operation status")
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Template;
|
||||
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.Template;
|
||||
|
||||
@@ -27,18 +29,22 @@ public class UpdateTemplateController : TemplateControllerBase
|
||||
[HttpPut("{key:guid}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult> Update(Guid key, TemplateUpdateModel updateModel)
|
||||
public async Task<IActionResult> Update(Guid key, TemplateUpdateModel updateModel)
|
||||
{
|
||||
ITemplate? template = await _templateService.GetTemplateAsync(key);
|
||||
ITemplate? template = await _templateService.GetAsync(key);
|
||||
if (template == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
template = _umbracoMapper.Map(updateModel, template);
|
||||
await _templateService.SaveTemplateAsync(template, CurrentUserId(_backOfficeSecurityAccessor));
|
||||
|
||||
return Ok();
|
||||
Attempt<ITemplate, TemplateOperationStatus> result = await _templateService.UpdateAsync(template, CurrentUserId(_backOfficeSecurityAccessor));
|
||||
|
||||
return result.Success ?
|
||||
Ok()
|
||||
: TemplateOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4337,6 +4337,16 @@
|
||||
"201": {
|
||||
"description": "Created"
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
@@ -4410,6 +4420,16 @@
|
||||
"200": {
|
||||
"description": "Success"
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
@@ -4451,6 +4471,16 @@
|
||||
"200": {
|
||||
"description": "Success"
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
@@ -4519,15 +4549,6 @@
|
||||
"Template"
|
||||
],
|
||||
"operationId": "GetTemplateScaffold",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "masterTemplateAlias",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
|
||||
@@ -11,6 +11,7 @@ using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Extensions;
|
||||
using File = System.IO.File;
|
||||
@@ -32,7 +33,7 @@ public class FileService : RepositoryService, IFileService
|
||||
private readonly IScriptRepository _scriptRepository;
|
||||
private readonly IStylesheetRepository _stylesheetRepository;
|
||||
private readonly ITemplateService _templateService;
|
||||
private readonly IShortStringHelper _shortStringHelper;
|
||||
private readonly ITemplateRepository _templateRepository;
|
||||
|
||||
[Obsolete("Use other ctor - will be removed in Umbraco 15")]
|
||||
public FileService(
|
||||
@@ -77,9 +78,9 @@ public class FileService : RepositoryService, IFileService
|
||||
IAuditRepository auditRepository,
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
ITemplateService templateService,
|
||||
ITemplateRepository templateRepository,
|
||||
// unused dependencies but the DI forces us to have them, otherwise we'll get an "ambiguous constructor"
|
||||
// exception (and [ActivatorUtilitiesConstructor] doesn't work here either)
|
||||
ITemplateRepository templateRepository,
|
||||
IShortStringHelper shortStringHelper,
|
||||
IOptions<GlobalSettings> globalSettings)
|
||||
: base(uowProvider, loggerFactory, eventMessagesFactory)
|
||||
@@ -91,7 +92,7 @@ public class FileService : RepositoryService, IFileService
|
||||
_auditRepository = auditRepository;
|
||||
_hostingEnvironment = hostingEnvironment;
|
||||
_templateService = templateService;
|
||||
_shortStringHelper = shortStringHelper;
|
||||
_templateRepository = templateRepository;
|
||||
}
|
||||
|
||||
#region Stylesheets
|
||||
@@ -372,7 +373,21 @@ public class FileService : RepositoryService, IFileService
|
||||
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
|
||||
public Attempt<OperationResult<OperationResultType, ITemplate>?> CreateTemplateForContentType(
|
||||
string contentTypeAlias, string? contentTypeName, int userId = Constants.Security.SuperUserId)
|
||||
=> _templateService.CreateTemplateForContentTypeAsync(contentTypeAlias, contentTypeName, userId).GetAwaiter().GetResult();
|
||||
{
|
||||
// mimic old service behavior
|
||||
if (contentTypeAlias.Length > 255)
|
||||
{
|
||||
throw new InvalidOperationException("Name cannot be more than 255 characters in length.");
|
||||
}
|
||||
|
||||
Attempt<ITemplate, TemplateOperationStatus> result = _templateService.CreateForContentTypeAsync(contentTypeAlias, contentTypeName, userId).GetAwaiter().GetResult();
|
||||
|
||||
// mimic old service behavior
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
return result.Success
|
||||
? OperationResult.Attempt.Succeed(OperationResultType.Success, eventMessages, result.Result)
|
||||
: OperationResult.Attempt.Succeed(OperationResultType.Failed, eventMessages, result.Result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new template, setting the content if a view exists in the filesystem
|
||||
@@ -390,8 +405,18 @@ public class FileService : RepositoryService, IFileService
|
||||
string? content,
|
||||
ITemplate? masterTemplate = null,
|
||||
int userId = Constants.Security.SuperUserId)
|
||||
=> _templateService.CreateTemplateWithIdentityAsync(name, alias, content, userId).GetAwaiter().GetResult()
|
||||
?? new Template(_shortStringHelper, name, alias);
|
||||
{
|
||||
// mimic old service behavior
|
||||
ArgumentException.ThrowIfNullOrEmpty(name);
|
||||
ArgumentException.ThrowIfNullOrEmpty(alias);
|
||||
if (name.Length > 255)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(name), "Name cannot be more than 255 characters in length.");
|
||||
}
|
||||
|
||||
Attempt<ITemplate, TemplateOperationStatus> result = _templateService.CreateAsync(name, alias, content, userId).GetAwaiter().GetResult();
|
||||
return result.Result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all <see cref="ITemplate" /> objects
|
||||
@@ -399,7 +424,7 @@ public class FileService : RepositoryService, IFileService
|
||||
/// <returns>An enumerable list of <see cref="ITemplate" /> objects</returns>
|
||||
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
|
||||
public IEnumerable<ITemplate> GetTemplates(params string[] aliases)
|
||||
=> _templateService.GetTemplatesAsync(aliases).GetAwaiter().GetResult();
|
||||
=> _templateService.GetAllAsync(aliases).GetAwaiter().GetResult();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all <see cref="ITemplate" /> objects
|
||||
@@ -407,7 +432,7 @@ public class FileService : RepositoryService, IFileService
|
||||
/// <returns>An enumerable list of <see cref="ITemplate" /> objects</returns>
|
||||
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
|
||||
public IEnumerable<ITemplate> GetTemplates(int masterTemplateId)
|
||||
=> _templateService.GetTemplatesAsync(masterTemplateId).GetAwaiter().GetResult();
|
||||
=> _templateService.GetChildrenAsync(masterTemplateId).GetAwaiter().GetResult();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ITemplate" /> object by its alias.
|
||||
@@ -416,7 +441,7 @@ public class FileService : RepositoryService, IFileService
|
||||
/// <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")]
|
||||
public ITemplate? GetTemplate(string? alias)
|
||||
=> _templateService.GetTemplateAsync(alias).GetAwaiter().GetResult();
|
||||
=> _templateService.GetAsync(alias).GetAwaiter().GetResult();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ITemplate" /> object by its identifier.
|
||||
@@ -425,7 +450,7 @@ public class FileService : RepositoryService, IFileService
|
||||
/// <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")]
|
||||
public ITemplate? GetTemplate(int id)
|
||||
=> _templateService.GetTemplateAsync(id).GetAwaiter().GetResult();
|
||||
=> _templateService.GetAsync(id).GetAwaiter().GetResult();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ITemplate" /> object by its guid identifier.
|
||||
@@ -434,7 +459,7 @@ public class FileService : RepositoryService, IFileService
|
||||
/// <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")]
|
||||
public ITemplate? GetTemplate(Guid id)
|
||||
=> _templateService.GetTemplateAsync(id).GetAwaiter().GetResult();
|
||||
=> _templateService.GetAsync(id).GetAwaiter().GetResult();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the template descendants
|
||||
@@ -443,7 +468,7 @@ public class FileService : RepositoryService, IFileService
|
||||
/// <returns></returns>
|
||||
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
|
||||
public IEnumerable<ITemplate> GetTemplateDescendants(int masterTemplateId)
|
||||
=> _templateService.GetTemplateDescendantsAsync(masterTemplateId).GetAwaiter().GetResult();
|
||||
=> _templateService.GetDescendantsAsync(masterTemplateId).GetAwaiter().GetResult();
|
||||
|
||||
/// <summary>
|
||||
/// Saves a <see cref="Template" />
|
||||
@@ -452,16 +477,62 @@ public class FileService : RepositoryService, IFileService
|
||||
/// <param name="userId"></param>
|
||||
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
|
||||
public void SaveTemplate(ITemplate template, int userId = Constants.Security.SuperUserId)
|
||||
=> _templateService.SaveTemplateAsync(template, userId).GetAwaiter().GetResult();
|
||||
{
|
||||
// mimic old service behavior
|
||||
if (template == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(template));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(template.Name) || template.Name.Length > 255)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Name cannot be null, empty, contain only white-space characters or be more than 255 characters in length.");
|
||||
}
|
||||
|
||||
if (template.Id > 0)
|
||||
{
|
||||
_templateService.UpdateAsync(template, userId).GetAwaiter().GetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_templateService.CreateAsync(template, userId).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a collection of <see cref="Template" /> objects
|
||||
/// </summary>
|
||||
/// <param name="templates">List of <see cref="Template" /> to save</param>
|
||||
/// <param name="userId">Optional id of the user</param>
|
||||
// FIXME: we need to re-implement PackageDataInstallation.ImportTemplates so it imports templates in the correct order
|
||||
// instead of relying on being able to save invalid templates (child templates whose master has yet to be created)
|
||||
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
|
||||
public void SaveTemplate(IEnumerable<ITemplate> templates, int userId = Constants.Security.SuperUserId)
|
||||
=> _templateService.SaveTemplateAsync(templates, userId).GetAwaiter().GetResult();
|
||||
{
|
||||
ITemplate[] templatesA = templates.ToArray();
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
|
||||
{
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
var savingNotification = new TemplateSavingNotification(templatesA, eventMessages);
|
||||
if (scope.Notifications.PublishCancelable(savingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (ITemplate template in templatesA)
|
||||
{
|
||||
_templateRepository.Save(template);
|
||||
}
|
||||
|
||||
scope.Notifications.Publish(
|
||||
new TemplateSavedNotification(templatesA, eventMessages).WithStateFrom(savingNotification));
|
||||
|
||||
Audit(AuditType.Save, userId, -1, UmbracoObjectTypes.Template.GetName());
|
||||
scope.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a template by its alias
|
||||
@@ -470,22 +541,22 @@ public class FileService : RepositoryService, IFileService
|
||||
/// <param name="userId"></param>
|
||||
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
|
||||
public void DeleteTemplate(string alias, int userId = Constants.Security.SuperUserId)
|
||||
=> _templateService.DeleteTemplateAsync(alias, userId).GetAwaiter().GetResult();
|
||||
=> _templateService.DeleteAsync(alias, userId).GetAwaiter().GetResult();
|
||||
|
||||
/// <inheritdoc />
|
||||
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
|
||||
public Stream GetTemplateFileContentStream(string filepath)
|
||||
=> _templateService.GetTemplateFileContentStreamAsync(filepath).GetAwaiter().GetResult();
|
||||
=> _templateService.GetFileContentStreamAsync(filepath).GetAwaiter().GetResult();
|
||||
|
||||
/// <inheritdoc />
|
||||
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
|
||||
public void SetTemplateFileContent(string filepath, Stream content)
|
||||
=> _templateService.SetTemplateFileContentAsync(filepath, content).GetAwaiter().GetResult();
|
||||
=> _templateService.SetFileContentAsync(filepath, content).GetAwaiter().GetResult();
|
||||
|
||||
/// <inheritdoc />
|
||||
[Obsolete("Please use ITemplateService for template operations - will be removed in Umbraco 15")]
|
||||
public long GetTemplateFileSize(string filepath)
|
||||
=> _templateService.GetTemplateFileSizeAsync(filepath).GetAwaiter().GetResult();
|
||||
=> _templateService.GetFileSizeAsync(filepath).GetAwaiter().GetResult();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -8,49 +9,49 @@ public interface ITemplateService : IService
|
||||
/// Gets a list of all <see cref="ITemplate" /> objects
|
||||
/// </summary>
|
||||
/// <returns>An enumerable list of <see cref="ITemplate" /> objects</returns>
|
||||
Task<IEnumerable<ITemplate>> GetTemplatesAsync(params string[] aliases);
|
||||
Task<IEnumerable<ITemplate>> GetAllAsync(params string[] aliases);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all <see cref="ITemplate" /> objects
|
||||
/// </summary>
|
||||
/// <returns>An enumerable list of <see cref="ITemplate" /> objects</returns>
|
||||
Task<IEnumerable<ITemplate>> GetTemplatesAsync(int masterTemplateId);
|
||||
Task<IEnumerable<ITemplate>> GetChildrenAsync(int masterTemplateId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ITemplate" /> object by its alias.
|
||||
/// </summary>
|
||||
/// <param name="alias">The alias of the template.</param>
|
||||
/// <returns>The <see cref="ITemplate" /> object matching the alias, or null.</returns>
|
||||
Task<ITemplate?> GetTemplateAsync(string? alias);
|
||||
Task<ITemplate?> GetAsync(string? alias);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ITemplate" /> object by its identifier.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier of the template.</param>
|
||||
/// <returns>The <see cref="ITemplate" /> object matching the identifier, or null.</returns>
|
||||
Task<ITemplate?> GetTemplateAsync(int id);
|
||||
Task<ITemplate?> GetAsync(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="ITemplate" /> object by its guid identifier.
|
||||
/// </summary>
|
||||
/// <param name="id">The guid identifier of the template.</param>
|
||||
/// <returns>The <see cref="ITemplate" /> object matching the identifier, or null.</returns>
|
||||
Task<ITemplate?> GetTemplateAsync(Guid id);
|
||||
Task<ITemplate?> GetAsync(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the template descendants
|
||||
/// </summary>
|
||||
/// <param name="masterTemplateId"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<ITemplate>> GetTemplateDescendantsAsync(int masterTemplateId);
|
||||
Task<IEnumerable<ITemplate>> GetDescendantsAsync(int masterTemplateId);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a <see cref="ITemplate" />
|
||||
/// Updates a <see cref="ITemplate" />
|
||||
/// </summary>
|
||||
/// <param name="template"><see cref="ITemplate" /> to save</param>
|
||||
/// <param name="template"><see cref="ITemplate" /> to update</param>
|
||||
/// <param name="userId">Optional id of the user saving the template</param>
|
||||
/// <returns>True if the template was saved, false otherwise.</returns>
|
||||
Task<bool> SaveTemplateAsync(ITemplate template, int userId = Constants.Security.SuperUserId);
|
||||
/// <returns></returns>
|
||||
Task<Attempt<ITemplate, TemplateOperationStatus>> UpdateAsync(ITemplate template, int userId = Constants.Security.SuperUserId);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a template for a content type
|
||||
@@ -61,12 +62,28 @@ public interface ITemplateService : IService
|
||||
/// <returns>
|
||||
/// The template created
|
||||
/// </returns>
|
||||
Task<Attempt<OperationResult<OperationResultType, ITemplate>?>> CreateTemplateForContentTypeAsync(
|
||||
Task<Attempt<ITemplate, TemplateOperationStatus>> CreateForContentTypeAsync(
|
||||
string contentTypeAlias,
|
||||
string? contentTypeName,
|
||||
int userId = Constants.Security.SuperUserId);
|
||||
|
||||
Task<ITemplate?> CreateTemplateWithIdentityAsync(string? name, string? alias, string? content, int userId = Constants.Security.SuperUserId);
|
||||
/// <summary>
|
||||
/// Creates a new template
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the new template</param>
|
||||
/// <param name="alias">Alias of the template</param>
|
||||
/// <param name="content">View content for the new template</param>
|
||||
/// <param name="userId">Optional id of the user creating the template</param>
|
||||
/// <returns></returns>
|
||||
Task<Attempt<ITemplate, TemplateOperationStatus>> CreateAsync(string name, string alias, string? content, int userId = Constants.Security.SuperUserId);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new template
|
||||
/// </summary>
|
||||
/// <param name="template">The new template</param>
|
||||
/// <param name="userId">Optional id of the user creating the template</param>
|
||||
/// <returns></returns>
|
||||
Task<Attempt<ITemplate, TemplateOperationStatus>> CreateAsync(ITemplate template, int userId = Constants.Security.SuperUserId);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a template by its alias
|
||||
@@ -74,7 +91,7 @@ public interface ITemplateService : IService
|
||||
/// <param name="alias">Alias of the <see cref="ITemplate" /> to delete</param>
|
||||
/// <param name="userId">Optional id of the user deleting the template</param>
|
||||
/// <returns>True if the template was deleted, false otherwise</returns>
|
||||
Task<bool> DeleteTemplateAsync(string alias, int userId = Constants.Security.SuperUserId);
|
||||
Task<Attempt<ITemplate?, TemplateOperationStatus>> DeleteAsync(string alias, int userId = Constants.Security.SuperUserId);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a template by its key
|
||||
@@ -82,34 +99,26 @@ public interface ITemplateService : IService
|
||||
/// <param name="key">Key of the <see cref="ITemplate" /> to delete</param>
|
||||
/// <param name="userId">Optional id of the user deleting the template</param>
|
||||
/// <returns>True if the template was deleted, false otherwise</returns>
|
||||
Task<bool> DeleteTemplateAsync(Guid key, int userId = Constants.Security.SuperUserId);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a collection of <see cref="Template" /> objects
|
||||
/// </summary>
|
||||
/// <param name="templates">List of <see cref="Template" /> to save</param>
|
||||
/// <param name="userId">Optional id of the user</param>
|
||||
/// <returns>True if the templates were saved, false otherwise</returns>
|
||||
Task<bool> SaveTemplateAsync(IEnumerable<ITemplate> templates, int userId = Constants.Security.SuperUserId);
|
||||
Task<Attempt<ITemplate?, TemplateOperationStatus>> DeleteAsync(Guid key, int userId = Constants.Security.SuperUserId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content of a template as a stream.
|
||||
/// </summary>
|
||||
/// <param name="filepath">The filesystem path to the template.</param>
|
||||
/// <returns>The content of the template.</returns>
|
||||
Task<Stream> GetTemplateFileContentStreamAsync(string filepath);
|
||||
Task<Stream> GetFileContentStreamAsync(string filepath);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the content of a template.
|
||||
/// </summary>
|
||||
/// <param name="filepath">The filesystem path to the template.</param>
|
||||
/// <param name="content">The content of the template.</param>
|
||||
Task SetTemplateFileContentAsync(string filepath, Stream content);
|
||||
Task SetFileContentAsync(string filepath, Stream content);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of a template.
|
||||
/// </summary>
|
||||
/// <param name="filepath">The filesystem path to the template.</param>
|
||||
/// <returns>The size of the template.</returns>
|
||||
Task<long> GetTemplateFileSizeAsync(string filepath);
|
||||
Task<long> GetFileSizeAsync(string filepath);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
public enum TemplateOperationStatus
|
||||
{
|
||||
Success,
|
||||
CancelledByNotification,
|
||||
InvalidAlias,
|
||||
TemplateNotFound,
|
||||
MasterTemplateNotFound
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.Persistence.Querying;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
@@ -34,10 +35,10 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Attempt<OperationResult<OperationResultType, ITemplate>?>> CreateTemplateForContentTypeAsync(
|
||||
public async Task<Attempt<ITemplate, TemplateOperationStatus>> CreateForContentTypeAsync(
|
||||
string contentTypeAlias, string? contentTypeName, int userId = Constants.Security.SuperUserId)
|
||||
{
|
||||
var template = new Template(_shortStringHelper, contentTypeName,
|
||||
ITemplate template = new Template(_shortStringHelper, contentTypeName,
|
||||
|
||||
// NOTE: We are NOT passing in the content type alias here, we want to use it's name since we don't
|
||||
// want to save template file names as camelCase, the Template ctor will clean the alias as
|
||||
@@ -45,13 +46,13 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
// This fixes: http://issues.umbraco.org/issue/U4-7953
|
||||
contentTypeName);
|
||||
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
|
||||
if (contentTypeAlias != null && contentTypeAlias.Length > 255)
|
||||
if (IsValidAlias(template.Alias) == false)
|
||||
{
|
||||
throw new InvalidOperationException("Name cannot be more than 255 characters in length.");
|
||||
return Attempt.FailWithStatus(TemplateOperationStatus.InvalidAlias, template);
|
||||
}
|
||||
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
|
||||
// check that the template hasn't been created on disk before creating the content type
|
||||
// if it exists, set the new template content to the existing file content
|
||||
var content = GetViewContent(contentTypeAlias);
|
||||
@@ -66,56 +67,46 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
if (scope.Notifications.PublishCancelable(savingEvent))
|
||||
{
|
||||
scope.Complete();
|
||||
return OperationResult.Attempt.Fail<OperationResultType, ITemplate>(
|
||||
OperationResultType.FailedCancelledByEvent, eventMessages, template);
|
||||
return Attempt.FailWithStatus(TemplateOperationStatus.CancelledByNotification, template);
|
||||
}
|
||||
|
||||
_templateRepository.Save(template);
|
||||
scope.Notifications.Publish(
|
||||
new TemplateSavedNotification(template, eventMessages).WithStateFrom(savingEvent));
|
||||
|
||||
Audit(AuditType.Save, userId, template.Id, UmbracoObjectTypes.Template.GetName());
|
||||
Audit(AuditType.New, userId, template.Id, UmbracoObjectTypes.Template.GetName());
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
return await Task.FromResult(OperationResult.Attempt.Succeed<OperationResultType, ITemplate>(
|
||||
OperationResultType.Success,
|
||||
eventMessages,
|
||||
template));
|
||||
return await Task.FromResult(Attempt.SucceedWithStatus(TemplateOperationStatus.Success, template));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ITemplate?> CreateTemplateWithIdentityAsync(
|
||||
string? name,
|
||||
string? alias,
|
||||
public async Task<Attempt<ITemplate, TemplateOperationStatus>> CreateAsync(
|
||||
string name,
|
||||
string alias,
|
||||
string? content,
|
||||
int userId = Constants.Security.SuperUserId)
|
||||
=> await CreateAsync(new Template(_shortStringHelper, name, alias) { Content = content }, userId);
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Attempt<ITemplate, TemplateOperationStatus>> CreateAsync(ITemplate template, int userId = Constants.Security.SuperUserId)
|
||||
{
|
||||
if (name == null)
|
||||
try
|
||||
{
|
||||
throw new ArgumentNullException(nameof(name));
|
||||
// file might already be on disk, if so grab the content to avoid overwriting
|
||||
template.Content = GetViewContent(template.Alias) ?? template.Content;
|
||||
return await SaveAsync(template, AuditType.New, userId);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
catch (PathTooLongException ex)
|
||||
{
|
||||
throw new ArgumentException("Name cannot be empty or contain only white-space characters", nameof(name));
|
||||
LoggerFactory.CreateLogger<TemplateService>().LogError(ex, "The template path was too long. Consider making the template alias shorter.");
|
||||
return Attempt.FailWithStatus(TemplateOperationStatus.InvalidAlias, template);
|
||||
}
|
||||
|
||||
if (name.Length > 255)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(name), "Name cannot be more than 255 characters in length.");
|
||||
}
|
||||
|
||||
// file might already be on disk, if so grab the content to avoid overwriting
|
||||
var template = new Template(_shortStringHelper, name, alias) { Content = GetViewContent(alias) ?? content };
|
||||
|
||||
return await SaveTemplateAsync(template, userId)
|
||||
? template
|
||||
: null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<ITemplate>> GetTemplatesAsync(params string[] aliases)
|
||||
public async Task<IEnumerable<ITemplate>> GetAllAsync(params string[] aliases)
|
||||
{
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
|
||||
{
|
||||
@@ -124,7 +115,7 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<ITemplate>> GetTemplatesAsync(int masterTemplateId)
|
||||
public async Task<IEnumerable<ITemplate>> GetChildrenAsync(int masterTemplateId)
|
||||
{
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
|
||||
{
|
||||
@@ -133,7 +124,7 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ITemplate?> GetTemplateAsync(string? alias)
|
||||
public async Task<ITemplate?> GetAsync(string? alias)
|
||||
{
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
|
||||
{
|
||||
@@ -142,7 +133,7 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ITemplate?> GetTemplateAsync(int id)
|
||||
public async Task<ITemplate?> GetAsync(int id)
|
||||
{
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
|
||||
{
|
||||
@@ -151,7 +142,7 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ITemplate?> GetTemplateAsync(Guid id)
|
||||
public async Task<ITemplate?> GetAsync(Guid id)
|
||||
{
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
|
||||
{
|
||||
@@ -161,7 +152,7 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<ITemplate>> GetTemplateDescendantsAsync(int masterTemplateId)
|
||||
public async Task<IEnumerable<ITemplate>> GetDescendantsAsync(int masterTemplateId)
|
||||
{
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
|
||||
{
|
||||
@@ -170,22 +161,42 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> SaveTemplateAsync(ITemplate template, int userId = Constants.Security.SuperUserId)
|
||||
{
|
||||
if (template == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(template));
|
||||
}
|
||||
public async Task<Attempt<ITemplate, TemplateOperationStatus>> UpdateAsync(ITemplate template, int userId = Constants.Security.SuperUserId)
|
||||
=> await SaveAsync(
|
||||
template,
|
||||
AuditType.Save,
|
||||
userId,
|
||||
// fail the attempt if the template does not exist within the scope
|
||||
() => _templateRepository.Exists(template.Id)
|
||||
? TemplateOperationStatus.Success
|
||||
: TemplateOperationStatus.TemplateNotFound);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(template.Name) || template.Name.Length > 255)
|
||||
private async Task<Attempt<ITemplate, TemplateOperationStatus>> SaveAsync(ITemplate template, AuditType auditType, int userId = Constants.Security.SuperUserId, Func<TemplateOperationStatus>? scopeValidator = null)
|
||||
{
|
||||
if (IsValidAlias(template.Alias) == false)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Name cannot be null, empty, contain only white-space characters or be more than 255 characters in length.");
|
||||
return Attempt.FailWithStatus(TemplateOperationStatus.InvalidAlias, template);
|
||||
}
|
||||
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
|
||||
{
|
||||
ITemplate? masterTemplate = await GetMasterTemplate(template.Content);
|
||||
TemplateOperationStatus scopeValidatorStatus = scopeValidator?.Invoke() ?? TemplateOperationStatus.Success;
|
||||
if (scopeValidatorStatus != TemplateOperationStatus.Success)
|
||||
{
|
||||
return Attempt.FailWithStatus(scopeValidatorStatus, template);
|
||||
}
|
||||
|
||||
var masterTemplateAlias = _templateContentParserService.MasterTemplateAlias(template.Content);
|
||||
ITemplate? masterTemplate = masterTemplateAlias.IsNullOrWhiteSpace()
|
||||
? null
|
||||
: await GetAsync(masterTemplateAlias);
|
||||
|
||||
// fail if the template content specifies a master template but said template does not exist
|
||||
if (masterTemplateAlias.IsNullOrWhiteSpace() == false && masterTemplate == null)
|
||||
{
|
||||
return Attempt.FailWithStatus(TemplateOperationStatus.MasterTemplateNotFound, template);
|
||||
}
|
||||
|
||||
await SetMasterTemplateAsync(template, masterTemplate);
|
||||
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
@@ -193,7 +204,7 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
if (scope.Notifications.PublishCancelable(savingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return false;
|
||||
return Attempt.FailWithStatus(TemplateOperationStatus.CancelledByNotification, template);
|
||||
}
|
||||
|
||||
_templateRepository.Save(template);
|
||||
@@ -201,50 +212,22 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
scope.Notifications.Publish(
|
||||
new TemplateSavedNotification(template, eventMessages).WithStateFrom(savingNotification));
|
||||
|
||||
Audit(AuditType.Save, userId, template.Id, UmbracoObjectTypes.Template.GetName());
|
||||
Audit(auditType, userId, template.Id, UmbracoObjectTypes.Template.GetName());
|
||||
scope.Complete();
|
||||
return true;
|
||||
return Attempt.SucceedWithStatus(TemplateOperationStatus.Success, template);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> SaveTemplateAsync(IEnumerable<ITemplate> templates, int userId = Constants.Security.SuperUserId)
|
||||
{
|
||||
ITemplate[] templatesA = templates.ToArray();
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
|
||||
{
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
var savingNotification = new TemplateSavingNotification(templatesA, eventMessages);
|
||||
if (scope.Notifications.PublishCancelable(savingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (ITemplate template in templatesA)
|
||||
{
|
||||
_templateRepository.Save(template);
|
||||
}
|
||||
|
||||
scope.Notifications.Publish(
|
||||
new TemplateSavedNotification(templatesA, eventMessages).WithStateFrom(savingNotification));
|
||||
|
||||
Audit(AuditType.Save, userId, -1, UmbracoObjectTypes.Template.GetName());
|
||||
scope.Complete();
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
public async Task<Attempt<ITemplate?, TemplateOperationStatus>> DeleteAsync(string alias, int userId = Constants.Security.SuperUserId)
|
||||
=> await DeleteAsync(() => Task.FromResult(_templateRepository.Get(alias)), userId);
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> DeleteTemplateAsync(string alias, int userId = Constants.Security.SuperUserId)
|
||||
=> await DeleteTemplateAsync(() => Task.FromResult(_templateRepository.Get(alias)), userId);
|
||||
public async Task<Attempt<ITemplate?, TemplateOperationStatus>> DeleteAsync(Guid key, int userId = Constants.Security.SuperUserId)
|
||||
=> await DeleteAsync(async () => await GetAsync(key), userId);
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> DeleteTemplateAsync(Guid key, int userId = Constants.Security.SuperUserId)
|
||||
=> await DeleteTemplateAsync(async () => await GetTemplateAsync(key), userId);
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Stream> GetTemplateFileContentStreamAsync(string filepath)
|
||||
public async Task<Stream> GetFileContentStreamAsync(string filepath)
|
||||
{
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
|
||||
{
|
||||
@@ -253,7 +236,7 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task SetTemplateFileContentAsync(string filepath, Stream content)
|
||||
public async Task SetFileContentAsync(string filepath, Stream content)
|
||||
{
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
|
||||
{
|
||||
@@ -264,7 +247,7 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<long> GetTemplateFileSizeAsync(string filepath)
|
||||
public async Task<long> GetFileSizeAsync(string filepath)
|
||||
{
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
|
||||
{
|
||||
@@ -272,21 +255,6 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ITemplate?> GetMasterTemplate(string? content)
|
||||
{
|
||||
var masterTemplateAlias = _templateContentParserService.MasterTemplateAlias(content);
|
||||
ITemplate? masterTemplate = masterTemplateAlias.IsNullOrWhiteSpace()
|
||||
? null
|
||||
: await GetTemplateAsync(masterTemplateAlias);
|
||||
|
||||
if (masterTemplateAlias.IsNullOrWhiteSpace() == false && masterTemplate == null)
|
||||
{
|
||||
throw new ArgumentException($"Could not find master template with alias: {masterTemplateAlias}", content);
|
||||
}
|
||||
|
||||
return masterTemplate;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
private async Task SetMasterTemplateAsync(ITemplate template, ITemplate? masterTemplate)
|
||||
{
|
||||
@@ -308,7 +276,7 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
//After updating the master - ensure we update the path property if it has any children already assigned
|
||||
if (template.Id > 0)
|
||||
{
|
||||
IEnumerable<ITemplate> templateHasChildren = await GetTemplateDescendantsAsync(template.Id);
|
||||
IEnumerable<ITemplate> templateHasChildren = await GetDescendantsAsync(template.Id);
|
||||
|
||||
foreach (ITemplate childTemplate in templateHasChildren)
|
||||
{
|
||||
@@ -331,7 +299,7 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
childTemplate.Path = masterTemplate.Path + "," + template.Id + "," + childTemplatePath;
|
||||
|
||||
//Save the children with the updated path
|
||||
await SaveTemplateAsync(childTemplate);
|
||||
await UpdateAsync(childTemplate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,7 +334,7 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
private void Audit(AuditType type, int userId, int objectId, string? entityType) =>
|
||||
_auditRepository.Save(new AuditItem(objectId, type, userId, entityType));
|
||||
|
||||
private async Task<bool> DeleteTemplateAsync(Func<Task<ITemplate?>> getTemplate, int userId)
|
||||
private async Task<Attempt<ITemplate?, TemplateOperationStatus>> DeleteAsync(Func<Task<ITemplate?>> getTemplate, int userId)
|
||||
{
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
|
||||
{
|
||||
@@ -374,7 +342,7 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
if (template == null)
|
||||
{
|
||||
scope.Complete();
|
||||
return true;
|
||||
return Attempt.FailWithStatus<ITemplate?, TemplateOperationStatus>(TemplateOperationStatus.TemplateNotFound, null);
|
||||
}
|
||||
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
@@ -382,7 +350,7 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
if (scope.Notifications.PublishCancelable(deletingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return false;
|
||||
return Attempt.FailWithStatus<ITemplate?, TemplateOperationStatus>(TemplateOperationStatus.CancelledByNotification, template);
|
||||
}
|
||||
|
||||
_templateRepository.Delete(template);
|
||||
@@ -392,7 +360,10 @@ public class TemplateService : RepositoryService, ITemplateService
|
||||
|
||||
Audit(AuditType.Delete, userId, template.Id, UmbracoObjectTypes.Template.GetName());
|
||||
scope.Complete();
|
||||
return await Task.FromResult(true);
|
||||
return Attempt.SucceedWithStatus<ITemplate?, TemplateOperationStatus>(TemplateOperationStatus.Success, template);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsValidAlias(string alias)
|
||||
=> alias.IsNullOrWhiteSpace() == false && alias.Length <= 255;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
@@ -61,7 +62,7 @@ public class TemplateController : BackOfficeNotificationsController
|
||||
/// <returns></returns>
|
||||
public TemplateDisplay? GetByAlias(string alias)
|
||||
{
|
||||
ITemplate? template = _templateService.GetTemplateAsync(alias).GetAwaiter().GetResult();
|
||||
ITemplate? template = _templateService.GetAsync(alias).GetAwaiter().GetResult();
|
||||
return template == null ? null : _umbracoMapper.Map<ITemplate, TemplateDisplay>(template);
|
||||
}
|
||||
|
||||
@@ -69,7 +70,7 @@ public class TemplateController : BackOfficeNotificationsController
|
||||
/// Get all templates
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<EntityBasic>? GetAll() => _templateService.GetTemplatesAsync().GetAwaiter().GetResult()
|
||||
public IEnumerable<EntityBasic>? GetAll() => _templateService.GetAllAsync().GetAwaiter().GetResult()
|
||||
?.Select(_umbracoMapper.Map<ITemplate, EntityBasic>).WhereNotNull();
|
||||
|
||||
/// <summary>
|
||||
@@ -79,7 +80,7 @@ public class TemplateController : BackOfficeNotificationsController
|
||||
/// <returns></returns>
|
||||
public ActionResult<TemplateDisplay?> GetById(int id)
|
||||
{
|
||||
ITemplate? template = _templateService.GetTemplateAsync(id).GetAwaiter().GetResult();
|
||||
ITemplate? template = _templateService.GetAsync(id).GetAwaiter().GetResult();
|
||||
if (template == null)
|
||||
{
|
||||
return NotFound();
|
||||
@@ -96,7 +97,7 @@ public class TemplateController : BackOfficeNotificationsController
|
||||
/// <returns></returns>
|
||||
public ActionResult<TemplateDisplay?> GetById(Guid id)
|
||||
{
|
||||
ITemplate? template = _templateService.GetTemplateAsync(id).GetAwaiter().GetResult();
|
||||
ITemplate? template = _templateService.GetAsync(id).GetAwaiter().GetResult();
|
||||
if (template == null)
|
||||
{
|
||||
return NotFound();
|
||||
@@ -118,7 +119,7 @@ public class TemplateController : BackOfficeNotificationsController
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
ITemplate? template = _templateService.GetTemplateAsync(guidUdi.Guid).GetAwaiter().GetResult();
|
||||
ITemplate? template = _templateService.GetAsync(guidUdi.Guid).GetAwaiter().GetResult();
|
||||
if (template == null)
|
||||
{
|
||||
return NotFound();
|
||||
@@ -136,13 +137,13 @@ public class TemplateController : BackOfficeNotificationsController
|
||||
[HttpPost]
|
||||
public IActionResult DeleteById(int id)
|
||||
{
|
||||
ITemplate? template = _templateService.GetTemplateAsync(id).GetAwaiter().GetResult();
|
||||
ITemplate? template = _templateService.GetAsync(id).GetAwaiter().GetResult();
|
||||
if (template == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
_templateService.DeleteTemplateAsync(template.Alias).GetAwaiter().GetResult();
|
||||
_templateService.DeleteAsync(template.Alias).GetAwaiter().GetResult();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@@ -156,7 +157,7 @@ public class TemplateController : BackOfficeNotificationsController
|
||||
|
||||
if (id > 0)
|
||||
{
|
||||
ITemplate? master = _templateService.GetTemplateAsync(id).GetAwaiter().GetResult();
|
||||
ITemplate? master = _templateService.GetAsync(id).GetAwaiter().GetResult();
|
||||
if (master != null)
|
||||
{
|
||||
dt.SetMasterTemplate(master);
|
||||
@@ -190,7 +191,7 @@ public class TemplateController : BackOfficeNotificationsController
|
||||
if (display.Id > 0)
|
||||
{
|
||||
// update
|
||||
ITemplate? template = _templateService.GetTemplateAsync(display.Id).GetAwaiter().GetResult();
|
||||
ITemplate? template = _templateService.GetAsync(display.Id).GetAwaiter().GetResult();
|
||||
if (template == null)
|
||||
{
|
||||
return NotFound();
|
||||
@@ -200,11 +201,11 @@ public class TemplateController : BackOfficeNotificationsController
|
||||
|
||||
_umbracoMapper.Map(display, template);
|
||||
|
||||
_templateService.SaveTemplateAsync(template).GetAwaiter().GetResult();
|
||||
_templateService.UpdateAsync(template).GetAwaiter().GetResult();
|
||||
|
||||
if (changeAlias)
|
||||
{
|
||||
template = _templateService.GetTemplateAsync(template.Id).GetAwaiter().GetResult();
|
||||
template = _templateService.GetAsync(template.Id).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
_umbracoMapper.Map(template, display);
|
||||
@@ -215,7 +216,7 @@ public class TemplateController : BackOfficeNotificationsController
|
||||
ITemplate? master = null;
|
||||
if (string.IsNullOrEmpty(display.MasterTemplateAlias) == false)
|
||||
{
|
||||
master = _templateService.GetTemplateAsync(display.MasterTemplateAlias).GetAwaiter().GetResult();
|
||||
master = _templateService.GetAsync(display.MasterTemplateAlias).GetAwaiter().GetResult();
|
||||
if (master == null)
|
||||
{
|
||||
return NotFound();
|
||||
@@ -224,14 +225,14 @@ public class TemplateController : BackOfficeNotificationsController
|
||||
|
||||
// we need to pass the template name as alias to keep the template file casing consistent with templates created with content
|
||||
// - see comment in FileService.CreateTemplateForContentType for additional details
|
||||
ITemplate? template =
|
||||
_templateService.CreateTemplateWithIdentityAsync(display.Name, display.Name, display.Content).GetAwaiter().GetResult();
|
||||
if (template == null)
|
||||
Attempt<ITemplate, TemplateOperationStatus> result =
|
||||
_templateService.CreateAsync(display.Name!, display.Name!, display.Content).GetAwaiter().GetResult();
|
||||
if (result.Success == false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
_umbracoMapper.Map(template, display);
|
||||
_umbracoMapper.Map(result.Result, display);
|
||||
}
|
||||
|
||||
return display;
|
||||
|
||||
@@ -197,4 +197,14 @@ public abstract class UmbracoIntegrationTest : UmbracoIntegrationTestBase
|
||||
configBuilder.AddConfiguration(GlobalSetupTeardown.TestConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
protected void DeleteAllTemplateViewFiles()
|
||||
{
|
||||
var fileSystems = GetRequiredService<FileSystems>();
|
||||
var viewFileSystem = fileSystems.MvcViewsFileSystem!;
|
||||
foreach (var file in viewFileSystem.GetFiles(string.Empty).ToArray())
|
||||
{
|
||||
viewFileSystem.DeleteFile(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,12 @@ public class PackageDataInstallationTests : UmbracoIntegrationTestWithContent
|
||||
|
||||
private IMediaTypeService MediaTypeService => GetRequiredService<IMediaTypeService>();
|
||||
|
||||
public override void CreateTestData()
|
||||
{
|
||||
DeleteAllTemplateViewFiles();
|
||||
base.CreateTestData();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Import_uBlogsy_ContentTypes_And_Verify_Structure()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Tests.Common.Testing;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class TemplateServiceTests : UmbracoIntegrationTest
|
||||
{
|
||||
private ITemplateService TemplateService => GetRequiredService<ITemplateService>();
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => DeleteAllTemplateViewFiles();
|
||||
|
||||
[Test]
|
||||
public async Task Can_Create_Template_Then_Assign_Child()
|
||||
{
|
||||
Attempt<ITemplate, TemplateOperationStatus> result = await TemplateService.CreateAsync("Child", "child", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(TemplateOperationStatus.Success, result.Status);
|
||||
var child = result.Result;
|
||||
|
||||
result = await TemplateService.CreateAsync("Parent", "parent", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(TemplateOperationStatus.Success, result.Status);
|
||||
var parent = result.Result;
|
||||
|
||||
child.Content = "Layout = \"Parent.cshtml\";";
|
||||
result = await TemplateService.UpdateAsync(child);
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(TemplateOperationStatus.Success, result.Status);
|
||||
|
||||
child = await TemplateService.GetAsync(child.Key);
|
||||
Assert.NotNull(child);
|
||||
|
||||
Assert.AreEqual(parent.Alias, child.MasterTemplateAlias);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Create_Template_With_Child_Then_Unassign()
|
||||
{
|
||||
Attempt<ITemplate, TemplateOperationStatus> result = await TemplateService.CreateAsync("Parent", "parent", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
var parent = result.Result;
|
||||
|
||||
result = await TemplateService.CreateAsync("Child", "child", "Layout = \"Parent.cshtml\";");
|
||||
Assert.IsTrue(result.Success);
|
||||
var child = result.Result;
|
||||
|
||||
child = await TemplateService.GetAsync(child.Key);
|
||||
Assert.NotNull(child);
|
||||
Assert.AreEqual("parent", child.MasterTemplateAlias);
|
||||
|
||||
child.Content = "test";
|
||||
result = await TemplateService.UpdateAsync(child);
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
child = await TemplateService.GetAsync(child.Key);
|
||||
Assert.NotNull(child);
|
||||
Assert.AreEqual(null, child.MasterTemplateAlias);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Create_Template_With_Child_Then_Reassign()
|
||||
{
|
||||
Attempt<ITemplate, TemplateOperationStatus> result = await TemplateService.CreateAsync("Parent", "parent", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
result = await TemplateService.CreateAsync("Parent2", "parent2", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
result = await TemplateService.CreateAsync("Child", "child", "Layout = \"Parent.cshtml\";");
|
||||
Assert.IsTrue(result.Success);
|
||||
var child = result.Result;
|
||||
|
||||
child = await TemplateService.GetAsync(child.Key);
|
||||
Assert.NotNull(child);
|
||||
Assert.AreEqual("parent", child.MasterTemplateAlias);
|
||||
|
||||
child.Content = "Layout = \"Parent2.cshtml\";";
|
||||
result = await TemplateService.UpdateAsync(child);
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
child = await TemplateService.GetAsync(child.Key);
|
||||
Assert.NotNull(child);
|
||||
Assert.AreEqual("parent2", child.MasterTemplateAlias);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Child_Template_Paths_Are_Updated_When_Reassigning_Master()
|
||||
{
|
||||
Attempt<ITemplate, TemplateOperationStatus> result = await TemplateService.CreateAsync("Parent", "parent", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
var parent = result.Result;
|
||||
|
||||
result = await TemplateService.CreateAsync("Parent2", "parent2", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
var parent2 = result.Result;
|
||||
|
||||
result = await TemplateService.CreateAsync("Child", "child", "Layout = \"Parent.cshtml\";");
|
||||
Assert.IsTrue(result.Success);
|
||||
var child = result.Result;
|
||||
|
||||
result = await TemplateService.CreateAsync("Child1", "child1", "Layout = \"Child.cshtml\";");
|
||||
Assert.IsTrue(result.Success);
|
||||
var childOfChild1 = result.Result;
|
||||
|
||||
result = await TemplateService.CreateAsync("Child2", "child2", "Layout = \"Child.cshtml\";");
|
||||
Assert.IsTrue(result.Success);
|
||||
var childOfChild2 = result.Result;
|
||||
|
||||
Assert.AreEqual($"child", childOfChild1.MasterTemplateAlias);
|
||||
Assert.AreEqual($"{parent.Path},{child.Id},{childOfChild1.Id}", childOfChild1.Path);
|
||||
Assert.AreEqual($"child", childOfChild2.MasterTemplateAlias);
|
||||
Assert.AreEqual($"{parent.Path},{child.Id},{childOfChild2.Id}", childOfChild2.Path);
|
||||
|
||||
child.Content = "Layout = \"Parent2.cshtml\";";
|
||||
result = await TemplateService.UpdateAsync(child);
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
childOfChild1 = await TemplateService.GetAsync(childOfChild1.Key);
|
||||
Assert.NotNull(childOfChild1);
|
||||
|
||||
childOfChild2 = await TemplateService.GetAsync(childOfChild2.Key);
|
||||
Assert.NotNull(childOfChild2);
|
||||
|
||||
Assert.AreEqual($"child", childOfChild1.MasterTemplateAlias);
|
||||
Assert.AreEqual($"{parent2.Path},{child.Id},{childOfChild1.Id}", childOfChild1.Path);
|
||||
Assert.AreEqual($"child", childOfChild2.MasterTemplateAlias);
|
||||
Assert.AreEqual($"{parent2.Path},{child.Id},{childOfChild2.Id}", childOfChild2.Path);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Query_Template_Children()
|
||||
{
|
||||
Attempt<ITemplate, TemplateOperationStatus> result = await TemplateService.CreateAsync("Parent", "parent", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
var parent = result.Result;
|
||||
|
||||
result = await TemplateService.CreateAsync("Child1", "child1", "Layout = \"Parent.cshtml\";");
|
||||
Assert.IsTrue(result.Success);
|
||||
var child1 = result.Result;
|
||||
|
||||
result = await TemplateService.CreateAsync("Child2", "child2", "Layout = \"Parent.cshtml\";");
|
||||
Assert.IsTrue(result.Success);
|
||||
var child2 = result.Result;
|
||||
|
||||
var children = await TemplateService.GetChildrenAsync(parent.Id);
|
||||
|
||||
Assert.AreEqual(2, children.Count());
|
||||
Assert.NotNull(children.FirstOrDefault(t => t.Id == child1.Id));
|
||||
Assert.NotNull(children.FirstOrDefault(t => t.Id == child2.Id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Update_Template()
|
||||
{
|
||||
var result = await TemplateService.CreateAsync("Parent", "parent", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
var parent = result.Result;
|
||||
parent.Name = "Parent Updated";
|
||||
|
||||
result = await TemplateService.UpdateAsync(parent);
|
||||
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
parent = await TemplateService.GetAsync(parent.Key);
|
||||
Assert.IsNotNull(parent);
|
||||
Assert.AreEqual("Parent Updated", parent.Name);
|
||||
Assert.AreEqual("parent", parent.Alias);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Delete_Template()
|
||||
{
|
||||
var result = await TemplateService.CreateAsync("Parent", "parent", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
var parent = result.Result;
|
||||
|
||||
result = await TemplateService.DeleteAsync(parent.Key);
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
parent = await TemplateService.GetAsync(parent.Key);
|
||||
Assert.IsNull(parent);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Deleting_Master_Template_Also_Deletes_Children()
|
||||
{
|
||||
Attempt<ITemplate, TemplateOperationStatus> result = await TemplateService.CreateAsync("Parent", "parent", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
var parent = result.Result;
|
||||
|
||||
result = await TemplateService.CreateAsync("Child", "child", "Layout = \"Parent.cshtml\";");
|
||||
Assert.IsTrue(result.Success);
|
||||
var child = result.Result;
|
||||
Assert.AreEqual("parent", child.MasterTemplateAlias);
|
||||
|
||||
result = await TemplateService.DeleteAsync(parent.Key);
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
child = await TemplateService.GetAsync(child.Key);
|
||||
Assert.Null(child);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Update_Non_Existing_Template()
|
||||
{
|
||||
var result = await TemplateService.CreateAsync("Parent", "parent", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
var parent = result.Result;
|
||||
|
||||
result = await TemplateService.DeleteAsync("parent");
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
parent.Name = "Parent Updated";
|
||||
|
||||
result = await TemplateService.UpdateAsync(parent);
|
||||
Assert.IsFalse(result.Success);
|
||||
Assert.AreEqual(TemplateOperationStatus.TemplateNotFound, result.Status);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Create_Child_Template_Without_Master_Template()
|
||||
{
|
||||
var result = await TemplateService.CreateAsync("Child", "child", "Layout = \"Parent.cshtml\";");
|
||||
Assert.IsFalse(result.Success);
|
||||
Assert.AreEqual(TemplateOperationStatus.MasterTemplateNotFound, result.Status);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Update_Child_Template_Without_Master_Template()
|
||||
{
|
||||
var result = await TemplateService.CreateAsync("Child", "child", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
var child = result.Result;
|
||||
child.Content = "Layout = \"Parent.cshtml\";";
|
||||
|
||||
result = await TemplateService.UpdateAsync(child);
|
||||
Assert.IsFalse(result.Success);
|
||||
Assert.AreEqual(TemplateOperationStatus.MasterTemplateNotFound, result.Status);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Create_Template_With_Invalid_Alias()
|
||||
{
|
||||
var invalidAlias = new string('a', 256);
|
||||
var result = await TemplateService.CreateAsync("Child", invalidAlias, "test");
|
||||
Assert.IsFalse(result.Success);
|
||||
Assert.AreEqual(TemplateOperationStatus.InvalidAlias, result.Status);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Update_Template_With_Invalid_Alias()
|
||||
{
|
||||
var result = await TemplateService.CreateAsync("Child", "child", "test");
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
var child = result.Result;
|
||||
var invalidAlias = new string('a', 256);
|
||||
child.Alias = invalidAlias;
|
||||
|
||||
result = await TemplateService.UpdateAsync(child);
|
||||
Assert.IsFalse(result.Success);
|
||||
Assert.AreEqual(TemplateOperationStatus.InvalidAlias, result.Status);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user