2022-06-17 10:21:01 +02:00
using System.Xml ;
2021-09-14 22:13:39 +02:00
using System.Globalization ;
2022-04-04 17:14:03 +02:00
using System.Net.Mime ;
using System.Text ;
2021-01-29 10:30:28 +01:00
using Microsoft.AspNetCore.Authorization ;
2020-06-03 17:17:30 +02:00
using Microsoft.AspNetCore.Mvc ;
2020-09-21 09:27:54 +02:00
using Microsoft.Extensions.Logging ;
2021-01-29 10:30:28 +01:00
using Microsoft.Extensions.Options ;
2021-02-18 11:06:02 +01:00
using Umbraco.Cms.Core ;
using Umbraco.Cms.Core.Configuration.Models ;
using Umbraco.Cms.Core.Mapping ;
using Umbraco.Cms.Core.Models ;
using Umbraco.Cms.Core.Models.ContentEditing ;
2022-06-17 10:21:01 +02:00
using Umbraco.Cms.Core.Hosting ;
2021-02-18 11:06:02 +01:00
using Umbraco.Cms.Core.Security ;
using Umbraco.Cms.Core.Services ;
using Umbraco.Cms.Web.Common.Attributes ;
using Umbraco.Cms.Web.Common.Authorization ;
2021-01-13 11:39:44 +01:00
using Umbraco.Extensions ;
2022-06-17 10:21:01 +02:00
using Umbraco.Cms.Infrastructure.Packaging ;
using System.Xml.Linq ;
using Microsoft.AspNetCore.Http ;
2022-07-13 13:33:42 +02:00
using Microsoft.Extensions.DependencyInjection ;
using Umbraco.Cms.Web.Common.DependencyInjection ;
2018-06-13 15:17:31 +02:00
2022-06-20 08:37:17 +02:00
namespace Umbraco.Cms.Web.BackOffice.Controllers ;
/// <inheritdoc />
/// <summary>
/// The API controller used for editing dictionary items
/// </summary>
/// <remarks>
/// The security for this controller is defined to allow full CRUD access to dictionary if the user has access to
/// either:
/// Dictionary
/// </remarks>
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
[Authorize(Policy = AuthorizationPolicies.TreeAccessDictionary)]
[ParameterSwapControllerActionSelector(nameof(GetById), "id", typeof(int), typeof(Guid), typeof(Udi))]
public class DictionaryController : BackOfficeNotificationsController
2018-06-13 20:19:18 +02:00
{
2022-06-20 08:37:17 +02:00
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor ;
private readonly GlobalSettings _globalSettings ;
private readonly ILocalizationService _localizationService ;
private readonly ILocalizedTextService _localizedTextService ;
private readonly ILogger < DictionaryController > _logger ;
private readonly IUmbracoMapper _umbracoMapper ;
2022-07-11 15:22:33 +02:00
private readonly IEntityXmlSerializer _serializer ;
private readonly IHostingEnvironment _hostingEnvironment ;
private readonly PackageDataInstallation _packageDataInstallation ;
2020-06-03 17:17:30 +02:00
2022-06-20 08:37:17 +02:00
public DictionaryController (
ILogger < DictionaryController > logger ,
ILocalizationService localizationService ,
IBackOfficeSecurityAccessor backofficeSecurityAccessor ,
IOptionsSnapshot < GlobalSettings > globalSettings ,
ILocalizedTextService localizedTextService ,
2022-07-11 15:22:33 +02:00
IUmbracoMapper umbracoMapper ,
IEntityXmlSerializer serializer ,
IHostingEnvironment hostingEnvironment ,
PackageDataInstallation packageDataInstallation )
2022-06-20 08:37:17 +02:00
{
_logger = logger ? ? throw new ArgumentNullException ( nameof ( logger ) ) ;
_localizationService = localizationService ? ? throw new ArgumentNullException ( nameof ( localizationService ) ) ;
2022-07-13 13:33:42 +02:00
_backofficeSecurityAccessor = backofficeSecurityAccessor ? ? throw new ArgumentNullException ( nameof ( backofficeSecurityAccessor ) ) ;
2022-06-20 08:37:17 +02:00
_globalSettings = globalSettings . Value ? ? throw new ArgumentNullException ( nameof ( globalSettings ) ) ;
_localizedTextService = localizedTextService ? ? throw new ArgumentNullException ( nameof ( localizedTextService ) ) ;
_umbracoMapper = umbracoMapper ? ? throw new ArgumentNullException ( nameof ( umbracoMapper ) ) ;
2022-07-11 15:22:33 +02:00
_serializer = serializer ? ? throw new ArgumentNullException ( nameof ( serializer ) ) ;
_hostingEnvironment = hostingEnvironment ? ? throw new ArgumentNullException ( nameof ( hostingEnvironment ) ) ;
_packageDataInstallation = packageDataInstallation ? ? throw new ArgumentNullException ( nameof ( packageDataInstallation ) ) ;
2022-06-20 08:37:17 +02:00
}
2022-07-13 13:33:42 +02:00
[Obsolete("Please use ctor that also takes an IEntityXmlSerializer, IHostingEnvironment & PackageDataInstallation instead, scheduled for removal in v12")]
public DictionaryController (
ILogger < DictionaryController > logger ,
ILocalizationService localizationService ,
IBackOfficeSecurityAccessor backofficeSecurityAccessor ,
IOptionsSnapshot < GlobalSettings > globalSettings ,
ILocalizedTextService localizedTextService ,
IUmbracoMapper umbracoMapper )
: this (
logger ,
localizationService ,
backofficeSecurityAccessor ,
globalSettings ,
localizedTextService ,
umbracoMapper ,
StaticServiceProvider . Instance . GetRequiredService < IEntityXmlSerializer > ( ) ,
StaticServiceProvider . Instance . GetRequiredService < IHostingEnvironment > ( ) ,
StaticServiceProvider . Instance . GetRequiredService < PackageDataInstallation > ( ) )
{
}
2018-06-13 20:19:18 +02:00
/// <summary>
2022-06-20 08:37:17 +02:00
/// Deletes a data type with a given ID
2018-06-13 20:19:18 +02:00
/// </summary>
2022-06-20 08:37:17 +02:00
/// <param name="id"></param>
/// <returns>
/// <see cref="HttpResponseMessage" />
/// </returns>
[HttpDelete]
[HttpPost]
public IActionResult DeleteById ( int id )
2018-06-13 20:19:18 +02:00
{
2022-06-20 08:37:17 +02:00
IDictionaryItem ? foundDictionary = _localizationService . GetDictionaryItemById ( id ) ;
2019-02-01 15:24:07 +11:00
2022-06-20 08:37:17 +02:00
if ( foundDictionary = = null )
2018-06-13 20:19:18 +02:00
{
2022-06-20 08:37:17 +02:00
return NotFound ( ) ;
2019-02-01 15:24:07 +11:00
}
2018-06-13 15:17:31 +02:00
2022-06-20 08:37:17 +02:00
IEnumerable < IDictionaryItem > foundDictionaryDescendants =
_localizationService . GetDictionaryItemDescendants ( foundDictionary . Key ) ;
2019-02-14 12:40:45 +01:00
2022-06-20 08:37:17 +02:00
foreach ( IDictionaryItem dictionaryItem in foundDictionaryDescendants )
{
_localizationService . Delete ( dictionaryItem , _backofficeSecurityAccessor . BackOfficeSecurity ? . CurrentUser ? . Id ? ? - 1 ) ;
}
2019-06-01 13:07:16 +02:00
2022-06-20 08:37:17 +02:00
_localizationService . Delete ( foundDictionary , _backofficeSecurityAccessor . BackOfficeSecurity ? . CurrentUser ? . Id ? ? - 1 ) ;
2019-06-01 13:07:16 +02:00
2022-06-20 08:37:17 +02:00
return Ok ( ) ;
}
2019-06-01 13:07:16 +02:00
2022-06-20 08:37:17 +02:00
/// <summary>
/// Creates a new dictionary item
/// </summary>
/// <param name="parentId">
/// The parent id.
/// </param>
/// <param name="key">
/// The key.
/// </param>
/// <returns>
/// The <see cref="HttpResponseMessage" />.
/// </returns>
[HttpPost]
public ActionResult < int > Create ( int parentId , string key )
{
if ( string . IsNullOrEmpty ( key ) )
{
return ValidationProblem ( "Key can not be empty." ) ; // TODO: translate
}
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
if ( _localizationService . DictionaryItemExists ( key ) )
{
var message = _localizedTextService . Localize (
"dictionaryItem" ,
"changeKeyError" ,
_backofficeSecurityAccessor . BackOfficeSecurity ? . CurrentUser ? . GetUserCulture ( _localizedTextService , _globalSettings ) ,
new Dictionary < string , string? >
{
{ "0" , key }
} ) ;
return ValidationProblem ( message ) ;
2018-06-13 20:19:18 +02:00
}
2022-06-20 08:37:17 +02:00
try
2018-06-13 20:19:18 +02:00
{
2022-06-20 08:37:17 +02:00
Guid ? parentGuid = null ;
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
if ( parentId > 0 )
2018-06-13 20:19:18 +02:00
{
2022-06-20 08:37:17 +02:00
parentGuid = _localizationService . GetDictionaryItemById ( parentId ) ? . Key ;
2018-06-13 20:19:18 +02:00
}
2022-06-20 08:37:17 +02:00
IDictionaryItem item = _localizationService . CreateDictionaryItemWithIdentity (
key ,
parentGuid ,
string . Empty ) ;
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
return item . Id ;
2018-06-13 20:19:18 +02:00
}
2022-06-20 08:37:17 +02:00
catch ( Exception ex )
2018-06-13 20:19:18 +02:00
{
2022-06-20 08:37:17 +02:00
_logger . LogError ( ex , "Error creating dictionary with {Name} under {ParentId}" , key , parentId ) ;
return ValidationProblem ( "Error creating dictionary item" ) ;
}
}
2020-08-26 08:05:15 +02:00
2022-06-20 08:37:17 +02:00
/// <summary>
/// Gets a dictionary item by id
/// </summary>
/// <param name="id">
/// The id.
/// </param>
/// <returns>
/// The <see cref="DictionaryDisplay" />. Returns a not found response when dictionary item does not exist
/// </returns>
public ActionResult < DictionaryDisplay ? > GetById ( int id )
{
IDictionaryItem ? dictionary = _localizationService . GetDictionaryItemById ( id ) ;
if ( dictionary = = null )
{
return NotFound ( ) ;
2020-08-26 08:05:15 +02:00
}
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
return _umbracoMapper . Map < IDictionaryItem , DictionaryDisplay > ( dictionary ) ;
}
/// <summary>
/// Gets a dictionary item by guid
/// </summary>
/// <param name="id">
/// The id.
/// </param>
/// <returns>
/// The <see cref="DictionaryDisplay" />. Returns a not found response when dictionary item does not exist
/// </returns>
public ActionResult < DictionaryDisplay ? > GetById ( Guid id )
{
IDictionaryItem ? dictionary = _localizationService . GetDictionaryItemById ( id ) ;
if ( dictionary = = null )
2020-08-26 08:05:15 +02:00
{
2022-06-20 08:37:17 +02:00
return NotFound ( ) ;
}
return _umbracoMapper . Map < IDictionaryItem , DictionaryDisplay > ( dictionary ) ;
}
2020-08-26 08:05:15 +02:00
2022-06-20 08:37:17 +02:00
/// <summary>
/// Gets a dictionary item by udi
/// </summary>
/// <param name="id">
/// The id.
/// </param>
/// <returns>
/// The <see cref="DictionaryDisplay" />. Returns a not found response when dictionary item does not exist
/// </returns>
public ActionResult < DictionaryDisplay ? > GetById ( Udi id )
{
var guidUdi = id as GuidUdi ;
if ( guidUdi = = null )
{
return NotFound ( ) ;
2020-08-26 08:05:15 +02:00
}
2022-06-20 08:37:17 +02:00
IDictionaryItem ? dictionary = _localizationService . GetDictionaryItemById ( guidUdi . Guid ) ;
if ( dictionary = = null )
2020-08-26 08:05:15 +02:00
{
2022-06-20 08:37:17 +02:00
return NotFound ( ) ;
}
2020-08-26 08:05:15 +02:00
2022-06-20 08:37:17 +02:00
return _umbracoMapper . Map < IDictionaryItem , DictionaryDisplay > ( dictionary ) ;
}
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
/// <summary>
/// Changes the structure for dictionary items
/// </summary>
/// <param name="move"></param>
/// <returns></returns>
public IActionResult ? PostMove ( MoveOrCopy move )
{
IDictionaryItem ? dictionaryItem = _localizationService . GetDictionaryItemById ( move . Id ) ;
if ( dictionaryItem = = null )
{
return ValidationProblem ( _localizedTextService . Localize ( "dictionary" , "itemDoesNotExists" ) ) ;
2018-06-13 20:19:18 +02:00
}
2022-06-20 08:37:17 +02:00
IDictionaryItem ? parent = _localizationService . GetDictionaryItemById ( move . ParentId ) ;
if ( parent = = null )
2022-04-04 17:14:03 +02:00
{
2022-06-20 08:37:17 +02:00
if ( move . ParentId = = Constants . System . Root )
2022-04-04 17:14:03 +02:00
{
2022-06-20 08:37:17 +02:00
dictionaryItem . ParentId = null ;
2022-04-04 17:14:03 +02:00
}
else
{
2022-06-20 08:37:17 +02:00
return ValidationProblem ( _localizedTextService . Localize ( "dictionary" , "parentDoesNotExists" ) ) ;
2022-04-04 17:14:03 +02:00
}
2022-06-20 08:37:17 +02:00
}
else
{
dictionaryItem . ParentId = parent . Key ;
if ( dictionaryItem . Key = = parent . ParentId )
{
return ValidationProblem ( _localizedTextService . Localize ( "moveOrCopy" , "notAllowedByPath" ) ) ;
2022-04-04 17:14:03 +02:00
}
2022-06-20 08:37:17 +02:00
}
2022-04-21 11:20:12 +02:00
2022-06-20 08:37:17 +02:00
_localizationService . Save ( dictionaryItem ) ;
2022-04-04 17:14:03 +02:00
2022-06-20 08:37:17 +02:00
DictionaryDisplay ? model = _umbracoMapper . Map < IDictionaryItem , DictionaryDisplay > ( dictionaryItem ) ;
2022-04-04 17:14:03 +02:00
2022-06-20 08:37:17 +02:00
return Content ( model ! . Path , MediaTypeNames . Text . Plain , Encoding . UTF8 ) ;
}
2022-04-04 17:14:03 +02:00
2022-06-20 08:37:17 +02:00
/// <summary>
/// Saves a dictionary item
/// </summary>
/// <param name="dictionary">
/// The dictionary.
/// </param>
/// <returns>
/// The <see cref="DictionaryDisplay" />.
/// </returns>
public ActionResult < DictionaryDisplay ? > PostSave ( DictionarySave dictionary )
{
IDictionaryItem ? dictionaryItem = dictionary . Id is null
? null
: _localizationService . GetDictionaryItemById ( int . Parse ( dictionary . Id . ToString ( ) ! , CultureInfo . InvariantCulture ) ) ;
2022-04-04 17:14:03 +02:00
2022-06-20 08:37:17 +02:00
if ( dictionaryItem = = null )
2018-06-13 20:19:18 +02:00
{
2022-06-20 08:37:17 +02:00
return ValidationProblem ( "Dictionary item does not exist" ) ;
}
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
CultureInfo ? userCulture =
_backofficeSecurityAccessor . BackOfficeSecurity ? . CurrentUser ? . GetUserCulture ( _localizedTextService , _globalSettings ) ;
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
if ( dictionary . NameIsDirty )
{
// if the name (key) has changed, we need to check if the new key does not exist
IDictionaryItem ? dictionaryByKey = _localizationService . GetDictionaryItemByKey ( dictionary . Name ! ) ;
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
if ( dictionaryByKey ! = null & & dictionaryItem . Id ! = dictionaryByKey . Id )
2018-06-13 15:17:31 +02:00
{
2022-06-20 08:37:17 +02:00
var message = _localizedTextService . Localize (
"dictionaryItem" ,
"changeKeyError" ,
userCulture ,
new Dictionary < string , string? > { { "0" , dictionary . Name } } ) ;
ModelState . AddModelError ( "Name" , message ) ;
return ValidationProblem ( ModelState ) ;
}
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
dictionaryItem . ItemKey = dictionary . Name ! ;
}
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
foreach ( DictionaryTranslationSave translation in dictionary . Translations )
{
_localizationService . AddOrUpdateDictionaryValue ( dictionaryItem , _localizationService . GetLanguageById ( translation . LanguageId ) , translation . Translation ) ;
}
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
try
{
_localizationService . Save ( dictionaryItem ) ;
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
DictionaryDisplay ? model = _umbracoMapper . Map < IDictionaryItem , DictionaryDisplay > ( dictionaryItem ) ;
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
model ? . Notifications . Add ( new BackOfficeNotification (
_localizedTextService . Localize ( "speechBubbles" , "dictionaryItemSaved" , userCulture ) , string . Empty , NotificationStyle . Success ) ) ;
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
return model ;
}
catch ( Exception ex )
{
_logger . LogError ( ex , "Error saving dictionary with {Name} under {ParentId}" , dictionary . Name , dictionary . ParentId ) ;
return ValidationProblem ( "Something went wrong saving dictionary" ) ;
}
}
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
/// <summary>
/// Retrieves a list with all dictionary items
/// </summary>
/// <returns>
/// The <see cref="IEnumerable{T}" />.
/// </returns>
public IEnumerable < DictionaryOverviewDisplay > GetList ( )
{
IDictionaryItem [ ] items = _localizationService . GetDictionaryItemDescendants ( null ) . ToArray ( ) ;
var list = new List < DictionaryOverviewDisplay > ( items . Length ) ;
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
// recursive method to build a tree structure from the flat structure returned above
void BuildTree ( int level = 0 , Guid ? parentId = null )
{
IDictionaryItem [ ] children = items . Where ( t = > t . ParentId = = parentId ) . ToArray ( ) ;
if ( children . Any ( ) = = false )
2018-06-13 15:17:31 +02:00
{
2022-06-20 08:37:17 +02:00
return ;
2018-06-13 15:17:31 +02:00
}
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
foreach ( IDictionaryItem child in children . OrderBy ( ItemSort ( ) ) )
2018-06-13 20:19:18 +02:00
{
2022-06-20 08:37:17 +02:00
DictionaryOverviewDisplay ? display =
_umbracoMapper . Map < IDictionaryItem , DictionaryOverviewDisplay > ( child ) ;
if ( display is not null )
2020-08-26 08:05:15 +02:00
{
2022-06-20 08:37:17 +02:00
display . Level = level ;
list . Add ( display ) ;
2020-08-26 08:05:15 +02:00
}
2022-06-20 08:37:17 +02:00
BuildTree ( level + 1 , child . Key ) ;
2018-06-13 20:19:18 +02:00
}
2022-06-20 08:37:17 +02:00
}
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
BuildTree ( ) ;
2020-08-26 08:05:15 +02:00
2022-06-20 08:37:17 +02:00
return list ;
}
2018-06-13 20:19:18 +02:00
2022-06-20 08:37:17 +02:00
/// <summary>
/// Get child items for list.
/// </summary>
/// <param name="dictionaryItem">
/// The dictionary item.
/// </param>
/// <param name="level">
/// The level.
/// </param>
/// <param name="list">
/// The list.
/// </param>
private void GetChildItemsForList ( IDictionaryItem dictionaryItem , int level , ICollection < DictionaryOverviewDisplay > list )
{
foreach ( IDictionaryItem childItem in _localizationService . GetDictionaryItemChildren ( dictionaryItem . Key )
? . OrderBy ( ItemSort ( ) ) ? ? Enumerable . Empty < IDictionaryItem > ( ) )
2018-06-13 20:19:18 +02:00
{
2022-06-20 08:37:17 +02:00
DictionaryOverviewDisplay ? item = _umbracoMapper . Map < IDictionaryItem , DictionaryOverviewDisplay > ( childItem ) ;
if ( item is not null )
2018-06-13 20:19:18 +02:00
{
2022-06-20 08:37:17 +02:00
item . Level = level ;
list . Add ( item ) ;
2018-06-13 20:19:18 +02:00
}
2018-11-06 15:56:30 +01:00
2022-06-20 08:37:17 +02:00
GetChildItemsForList ( childItem , level + 1 , list ) ;
2018-06-13 20:19:18 +02:00
}
}
2018-11-06 15:56:30 +01:00
2022-07-11 15:22:33 +02:00
public IActionResult ExportDictionary ( int id , bool includeChildren = false )
{
IDictionaryItem ? dictionaryItem = _localizationService . GetDictionaryItemById ( id ) ;
if ( dictionaryItem = = null )
2022-06-17 10:21:01 +02:00
{
2022-07-11 15:22:33 +02:00
throw new NullReferenceException ( "No dictionary item found with id " + id ) ;
}
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
XElement xml = _serializer . Serialize ( dictionaryItem , includeChildren ) ;
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
var fileName = $"{dictionaryItem.ItemKey}.udt" ;
// Set custom header so umbRequestHelper.downloadFile can save the correct filename
HttpContext . Response . Headers . Add ( "x-filename" , fileName ) ;
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
return File ( Encoding . UTF8 . GetBytes ( xml . ToDataString ( ) ) , MediaTypeNames . Application . Octet , fileName ) ;
}
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
public IActionResult ImportDictionary ( string file , int parentId )
{
if ( string . IsNullOrWhiteSpace ( file ) )
2022-06-17 10:21:01 +02:00
{
2022-07-11 15:22:33 +02:00
return NotFound ( ) ;
}
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
var filePath = Path . Combine ( _hostingEnvironment . MapPathContentRoot ( Constants . SystemDirectories . Data ) , file ) ;
if ( ! System . IO . File . Exists ( filePath ) )
{
return NotFound ( ) ;
}
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
var xd = new XmlDocument { XmlResolver = null } ;
xd . Load ( filePath ) ;
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
var userId = _backofficeSecurityAccessor . BackOfficeSecurity ? . GetUserId ( ) . Result ? ? 0 ;
var element = XElement . Parse ( xd . InnerXml ) ;
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
IDictionaryItem ? parentDictionaryItem = _localizationService . GetDictionaryItemById ( parentId ) ;
IEnumerable < IDictionaryItem > dictionaryItems = _packageDataInstallation
. ImportDictionaryItem ( element , userId , parentDictionaryItem ? . Key ) ;
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
// Try to clean up the temporary file.
try
{
System . IO . File . Delete ( filePath ) ;
2022-06-17 10:21:01 +02:00
}
2022-07-11 15:22:33 +02:00
catch ( Exception ex )
2022-06-17 10:21:01 +02:00
{
2022-07-11 15:22:33 +02:00
_logger . LogError ( ex , "Error cleaning up temporary udt file in {File}" , filePath ) ;
}
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
var model = _umbracoMapper . Map < IDictionaryItem , DictionaryDisplay > ( dictionaryItems . FirstOrDefault ( ) ) ;
return Content ( model ! . Path , MediaTypeNames . Text . Plain , Encoding . UTF8 ) ;
}
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
public ActionResult < DictionaryImportModel > Upload ( IFormFile file )
{
if ( file = = null )
{
return ValidationProblem (
_localizedTextService . Localize ( "media" , "failedFileUpload" ) ,
_localizedTextService . Localize ( "speechBubbles" , "fileErrorNotFound" ) ) ;
}
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
var fileName = file . FileName . Trim ( Constants . CharArrays . DoubleQuote ) ;
var ext = fileName . Substring ( fileName . LastIndexOf ( '.' ) + 1 ) . ToLower ( ) ;
var root = _hostingEnvironment . MapPathContentRoot ( Constants . SystemDirectories . TempFileUploads ) ;
var tempPath = Path . Combine ( root , fileName ) ;
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
if ( ! Path . GetFullPath ( tempPath ) . StartsWith ( Path . GetFullPath ( root ) ) )
{
return ValidationProblem (
_localizedTextService . Localize ( "media" , "failedFileUpload" ) ,
_localizedTextService . Localize ( "media" , "invalidFileName" ) ) ;
}
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
if ( ! ext . InvariantEquals ( "udt" ) )
{
return ValidationProblem (
_localizedTextService . Localize ( "media" , "failedFileUpload" ) ,
_localizedTextService . Localize ( "media" , "disallowedFileType" ) ) ;
}
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
using ( FileStream stream = System . IO . File . Create ( tempPath ) )
{
file . CopyToAsync ( stream ) . GetAwaiter ( ) . GetResult ( ) ;
}
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
var xd = new XmlDocument { XmlResolver = null } ;
xd . Load ( tempPath ) ;
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
if ( xd . DocumentElement = = null )
{
return ValidationProblem (
_localizedTextService . Localize ( "media" , "failedFileUpload" ) ,
_localizedTextService . Localize ( "speechBubbles" , "fileErrorNotFound" ) ) ;
}
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
var model = new DictionaryImportModel ( )
{
TempFileName = tempPath ,
DictionaryItems = new List < DictionaryPreviewImportModel > ( ) ,
} ;
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
var level = 1 ;
var currentParent = string . Empty ;
foreach ( XmlNode dictionaryItem in xd . GetElementsByTagName ( "DictionaryItem" ) )
{
var name = dictionaryItem . Attributes ? . GetNamedItem ( "Name" ) ? . Value ? ? string . Empty ;
var parentKey = dictionaryItem ? . ParentNode ? . Attributes ? . GetNamedItem ( "Key" ) ? . Value ? ? string . Empty ;
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
if ( parentKey ! = currentParent | | level = = 1 )
{
level + = 1 ;
currentParent = parentKey ;
2022-06-17 10:21:01 +02:00
}
2022-07-11 14:07:08 +02:00
2022-07-11 15:22:33 +02:00
model . DictionaryItems . Add ( new DictionaryPreviewImportModel ( ) { Level = level , Name = name } ) ;
}
2022-06-17 10:21:01 +02:00
2022-07-11 15:22:33 +02:00
if ( ! model . DictionaryItems . Any ( ) )
{
return ValidationProblem (
_localizedTextService . Localize ( "media" , "failedFileUpload" ) ,
_localizedTextService . Localize ( "dictionary" , "noItemsInFile" ) ) ;
2022-06-17 10:21:01 +02:00
}
2022-07-11 15:22:33 +02:00
return model ;
}
2022-06-20 08:37:17 +02:00
private static Func < IDictionaryItem , string > ItemSort ( ) = > item = > item . ItemKey ;
2018-06-13 20:19:18 +02:00
}