using System;
using System.Collections.Generic;
using System.Net;
using System.Linq;
using System.Net.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web.BackOffice.Filters;
using Umbraco.Web.Common.Attributes;
using Umbraco.Web.Common.Exceptions;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Security;
using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.BackOffice.Controllers
{
///
///
/// The API controller used for editing dictionary items
///
///
/// The security for this controller is defined to allow full CRUD access to dictionary if the user has access to either:
/// Dictionary
///
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
[UmbracoTreeAuthorize(Constants.Trees.Dictionary)]
public class DictionaryController : BackOfficeNotificationsController
{
private readonly ILogger _logger;
private readonly ILocalizationService _localizationService;
private readonly IWebSecurity _webSecurity;
private readonly IGlobalSettings _globalSettings;
private readonly ILocalizedTextService _localizedTextService;
private readonly UmbracoMapper _umbracoMapper;
public DictionaryController(
ILogger logger,
ILocalizationService localizationService,
IWebSecurity webSecurity,
IGlobalSettings globalSettings,
ILocalizedTextService localizedTextService,
UmbracoMapper umbracoMapper
)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService));
_webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity));
_globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings));
_localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService));
_umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper));
}
///
/// Deletes a data type with a given ID
///
///
///
[HttpDelete]
[HttpPost]
public IActionResult DeleteById(int id)
{
var foundDictionary = _localizationService.GetDictionaryItemById(id);
if (foundDictionary == null)
return NotFound();
var foundDictionaryDescendants = _localizationService.GetDictionaryItemDescendants(foundDictionary.Key);
foreach (var dictionaryItem in foundDictionaryDescendants)
{
_localizationService.Delete(dictionaryItem, _webSecurity.CurrentUser.Id);
}
_localizationService.Delete(foundDictionary, _webSecurity.CurrentUser.Id);
return Ok();
}
///
/// Creates a new dictionary item
///
///
/// The parent id.
///
///
/// The key.
///
///
/// The .
///
[HttpPost]
public ActionResult Create(int parentId, string key)
{
if (string.IsNullOrEmpty(key))
throw HttpResponseException.CreateNotificationValidationErrorResponse("Key can not be empty."); // TODO: translate
if (_localizationService.DictionaryItemExists(key))
{
var message = _localizedTextService.Localize(
"dictionaryItem/changeKeyError",
_webSecurity.CurrentUser.GetUserCulture(_localizedTextService, _globalSettings),
new Dictionary { { "0", key } });
throw HttpResponseException.CreateNotificationValidationErrorResponse(message);
}
try
{
Guid? parentGuid = null;
if (parentId > 0)
parentGuid = _localizationService.GetDictionaryItemById(parentId).Key;
var item = _localizationService.CreateDictionaryItemWithIdentity(
key,
parentGuid,
string.Empty);
return item.Id;
}
catch (Exception ex)
{
_logger.Error(GetType(), ex, "Error creating dictionary with {Name} under {ParentId}", key, parentId);
throw HttpResponseException.CreateNotificationValidationErrorResponse("Error creating dictionary item");
}
}
///
/// Gets a dictionary item by id
///
///
/// The id.
///
///
/// The .
///
///
/// Returns a not found response when dictionary item does not exist
///
public ActionResult GetById(int id)
{
var dictionary = _localizationService.GetDictionaryItemById(id);
if (dictionary == null)
return NotFound();
return _umbracoMapper.Map(dictionary);
}
///
/// Saves a dictionary item
///
///
/// The dictionary.
///
///
/// The .
///
public DictionaryDisplay PostSave(DictionarySave dictionary)
{
var dictionaryItem =
_localizationService.GetDictionaryItemById(int.Parse(dictionary.Id.ToString()));
if (dictionaryItem == null)
throw HttpResponseException.CreateNotificationValidationErrorResponse("Dictionary item does not exist");
var userCulture = _webSecurity.CurrentUser.GetUserCulture(_localizedTextService, _globalSettings);
if (dictionary.NameIsDirty)
{
// if the name (key) has changed, we need to check if the new key does not exist
var dictionaryByKey = _localizationService.GetDictionaryItemByKey(dictionary.Name);
if (dictionaryByKey != null && dictionaryItem.Id != dictionaryByKey.Id)
{
var message = _localizedTextService.Localize(
"dictionaryItem/changeKeyError",
userCulture,
new Dictionary { { "0", dictionary.Name } });
ModelState.AddModelError("Name", message);
throw HttpResponseException.CreateValidationErrorResponse(ModelState);
}
dictionaryItem.ItemKey = dictionary.Name;
}
foreach (var translation in dictionary.Translations)
{
_localizationService.AddOrUpdateDictionaryValue(dictionaryItem,
_localizationService.GetLanguageById(translation.LanguageId), translation.Translation);
}
try
{
_localizationService.Save(dictionaryItem);
var model = _umbracoMapper.Map(dictionaryItem);
model.Notifications.Add(new BackOfficeNotification(
_localizedTextService.Localize("speechBubbles/dictionaryItemSaved", userCulture), string.Empty,
NotificationStyle.Success));
return model;
}
catch (Exception ex)
{
_logger.Error(GetType(), ex, "Error saving dictionary with {Name} under {ParentId}", dictionary.Name, dictionary.ParentId);
throw HttpResponseException.CreateNotificationValidationErrorResponse("Something went wrong saving dictionary");
}
}
///
/// Retrieves a list with all dictionary items
///
///
/// The .
///
public IEnumerable GetList()
{
var list = new List();
const int level = 0;
foreach (var dictionaryItem in _localizationService.GetRootDictionaryItems().OrderBy(ItemSort()))
{
var item = _umbracoMapper.Map(dictionaryItem);
item.Level = 0;
list.Add(item);
GetChildItemsForList(dictionaryItem, level + 1, list);
}
return list;
}
///
/// Get child items for list.
///
///
/// The dictionary item.
///
///
/// The level.
///
///
/// The list.
///
private void GetChildItemsForList(IDictionaryItem dictionaryItem, int level, ICollection list)
{
foreach (var childItem in _localizationService.GetDictionaryItemChildren(dictionaryItem.Key).OrderBy(ItemSort()))
{
var item = _umbracoMapper.Map(childItem);
item.Level = level;
list.Add(item);
GetChildItemsForList(childItem, level + 1, list);
}
}
private static Func ItemSort() => item => item.ItemKey;
}
}