Merge branch 'temp8-I3089' of https://github.com/umbraco/Umbraco-CMS into temp8-I3089

This commit is contained in:
elitsa
2018-10-08 10:23:53 +02:00
201 changed files with 9580 additions and 4378 deletions

View File

@@ -988,14 +988,14 @@ namespace Umbraco.Core.Services.Implement
UnpublishResultType result;
if (culture == "*" || culture == null)
{
Audit(AuditType.UnPublish, "Unpublished by user", userId, content.Id);
Audit(AuditType.Unpublish, "Unpublished by user", userId, content.Id);
result = UnpublishResultType.Success;
}
else
{
Audit(AuditType.UnPublish, $"Culture \"{culture}\" unpublished by user", userId, content.Id);
Audit(AuditType.Unpublish, $"Culture \"{culture}\" unpublished by user", userId, content.Id);
if (!content.Published)
Audit(AuditType.UnPublish, $"Unpublished (culture \"{culture}\" is mandatory) by user", userId, content.Id);
Audit(AuditType.Unpublish, $"Unpublished (culture \"{culture}\" is mandatory) by user", userId, content.Id);
result = content.Published ? UnpublishResultType.SuccessCulture : UnpublishResultType.SuccessMandatoryCulture;
}
scope.Complete();
@@ -1034,7 +1034,7 @@ namespace Umbraco.Core.Services.Implement
var cannotBePublished = publishedCultures.Count == 0; // no published cultures = cannot be published
if (!cannotBePublished)
{
var mandatoryCultures = _languageRepository.GetMany().Where(x => x.Mandatory).Select(x => x.IsoCode);
var mandatoryCultures = _languageRepository.GetMany().Where(x => x.IsMandatory).Select(x => x.IsoCode);
cannotBePublished = mandatoryCultures.Any(x => !publishedCultures.Contains(x, StringComparer.OrdinalIgnoreCase)); // missing mandatory culture = cannot be published
}
@@ -1120,9 +1120,9 @@ namespace Umbraco.Core.Services.Implement
if (unpublishResult.Success) // and succeeded, trigger events
{
// events and audit
scope.Events.Dispatch(UnPublished, this, new PublishEventArgs<IContent>(content, false, false), "UnPublished");
scope.Events.Dispatch(Unpublished, this, new PublishEventArgs<IContent>(content, false, false), "Unpublished");
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(content, TreeChangeTypes.RefreshBranch).ToEventArgs());
Audit(AuditType.UnPublish, "Unpublished by user", userId, content.Id);
Audit(AuditType.Unpublish, "Unpublished by user", userId, content.Id);
scope.Complete();
return new PublishResult(PublishResultType.Success, evtMsgs, content);
}
@@ -1348,10 +1348,10 @@ namespace Umbraco.Core.Services.Implement
scope.WriteLock(Constants.Locks.ContentTree);
// if it's not trashed yet, and published, we should unpublish
// but... UnPublishing event makes no sense (not going to cancel?) and no need to save
// but... Unpublishing event makes no sense (not going to cancel?) and no need to save
// just raise the event
if (content.Trashed == false && content.Published)
scope.Events.Dispatch(UnPublished, this, new PublishEventArgs<IContent>(content, false, false), nameof(UnPublished));
scope.Events.Dispatch(Unpublished, this, new PublishEventArgs<IContent>(content, false, false), nameof(Unpublished));
DeleteLocked(scope, content);
@@ -2098,12 +2098,12 @@ namespace Umbraco.Core.Services.Implement
/// <summary>
/// Occurs before unpublish
/// </summary>
public static event TypedEventHandler<IContentService, PublishEventArgs<IContent>> UnPublishing;
public static event TypedEventHandler<IContentService, PublishEventArgs<IContent>> Unpublishing;
/// <summary>
/// Occurs after unpublish
/// </summary>
public static event TypedEventHandler<IContentService, PublishEventArgs<IContent>> UnPublished;
public static event TypedEventHandler<IContentService, PublishEventArgs<IContent>> Unpublished;
/// <summary>
/// Occurs after change.
@@ -2197,8 +2197,8 @@ namespace Umbraco.Core.Services.Implement
// ensures that a document can be unpublished
internal UnpublishResult StrategyCanUnpublish(IScope scope, IContent content, int userId, EventMessages evtMsgs)
{
// raise UnPublishing event
if (scope.Events.DispatchCancelable(UnPublishing, this, new PublishEventArgs<IContent>(content, evtMsgs)))
// raise Unpublishing event
if (scope.Events.DispatchCancelable(Unpublishing, this, new PublishEventArgs<IContent>(content, evtMsgs)))
{
Logger.Info<ContentService>("Document {ContentName} (id={ContentId}) cannot be unpublished: unpublishing was cancelled.", content.Name, content.Id);
return new UnpublishResult(UnpublishResultType.FailedCancelledByEvent, evtMsgs, content);
@@ -2282,10 +2282,10 @@ namespace Umbraco.Core.Services.Implement
foreach (var content in contents.OrderByDescending(x => x.ParentId))
{
// if it's not trashed yet, and published, we should unpublish
// but... UnPublishing event makes no sense (not going to cancel?) and no need to save
// but... Unpublishing event makes no sense (not going to cancel?) and no need to save
// just raise the event
if (content.Trashed == false && content.Published)
scope.Events.Dispatch(UnPublished, this, new PublishEventArgs<IContent>(content, false, false), nameof(UnPublished));
scope.Events.Dispatch(Unpublished, this, new PublishEventArgs<IContent>(content, false, false), nameof(Unpublished));
// if current content has children, move them to trash
var c = content;

View File

@@ -363,6 +363,16 @@ namespace Umbraco.Core.Services.Implement
// write-lock languages to guard against race conds when dealing with default language
scope.WriteLock(Constants.Locks.Languages);
// look for cycles - within write-lock
if (language.FallbackLanguageId.HasValue)
{
var languages = _languageRepository.GetMany().ToDictionary(x => x.Id, x => x);
if (!languages.ContainsKey(language.FallbackLanguageId.Value))
throw new InvalidOperationException($"Cannot save language {language.IsoCode} with fallback id={language.FallbackLanguageId.Value} which is not a valid language id.");
if (CreatesCycle(language, languages))
throw new InvalidOperationException($"Cannot save language {language.IsoCode} with fallback {languages[language.FallbackLanguageId.Value].IsoCode} as it would create a fallback cycle.");
}
var saveEventArgs = new SaveEventArgs<ILanguage>(language);
if (scope.Events.DispatchCancelable(SavingLanguage, this, saveEventArgs))
{
@@ -380,6 +390,20 @@ namespace Umbraco.Core.Services.Implement
}
}
private bool CreatesCycle(ILanguage language, IDictionary<int, ILanguage> languages)
{
// a new language is not referenced yet, so cannot be part of a cycle
if (!language.HasIdentity) return false;
var id = language.FallbackLanguageId;
while (true) // assuming languages does not already contains a cycle, this must end
{
if (!id.HasValue) return false; // no fallback means no cycle
if (id.Value == language.Id) return true; // back to language = cycle!
id = languages[id.Value].FallbackLanguageId; // else keep chaining
}
}
/// <summary>
/// Deletes a <see cref="ILanguage"/> by removing it (but not its usages) from the db
/// </summary>
@@ -399,8 +423,7 @@ namespace Umbraco.Core.Services.Implement
return;
}
//NOTE: There isn't any constraints in the db, so possible references aren't deleted
// NOTE: Other than the fall-back language, there aren't any other constraints in the db, so possible references aren't deleted
_languageRepository.Delete(language);
deleteEventArgs.CanCancel = false;

View File

@@ -52,6 +52,7 @@ namespace Umbraco.Core.Services.Implement
private readonly IAuditRepository _auditRepository;
private readonly IContentTypeRepository _contentTypeRepository;
private readonly PropertyEditorCollection _propertyEditors;
private static HttpClient _httpClient;
public PackagingService(
ILogger logger,
@@ -1441,7 +1442,6 @@ namespace Umbraco.Core.Services.Implement
/// <returns></returns>
public string FetchPackageFile(Guid packageId, Version umbracoVersion, int userId)
{
using (var httpClient = new HttpClient())
using (var scope = _scopeProvider.CreateScope())
{
//includeHidden = true because we don't care if it's hidden we want to get the file regardless
@@ -1449,7 +1449,11 @@ namespace Umbraco.Core.Services.Implement
byte[] bytes;
try
{
bytes = httpClient.GetByteArrayAsync(url).GetAwaiter().GetResult();
if (_httpClient == null)
{
_httpClient = new HttpClient();
}
bytes = _httpClient.GetByteArrayAsync(url).GetAwaiter().GetResult();
}
catch (HttpRequestException ex)
{

View File

@@ -76,11 +76,11 @@ namespace Umbraco.Core.Services.Implement
// reload - cheap, cached
// default role is single server, but if registrations contain more
// than one active server, then role is master or slave
// than one active server, then role is master or replica
regs = _serverRegistrationRepository.GetMany().ToArray();
// default role is single server, but if registrations contain more
// than one active server, then role is master or slave
// than one active server, then role is master or replica
_currentServerRole = regs.Count(x => x.IsActive) > 1
? (server.IsMaster ? ServerRole.Master : ServerRole.Replica)
: ServerRole.Single;