fix+cleanup publishing with variants
This commit is contained in:
@@ -51,23 +51,20 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to return the cultures that have been flagged for unpublishing
|
||||
/// Gets the cultures that have been flagged for unpublishing.
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>Gets cultures for which content.UnpublishCulture() has been invoked.</remarks>
|
||||
internal static IReadOnlyList<string> GetCulturesUnpublishing(this IContent content)
|
||||
{
|
||||
if (!content.ContentType.VariesByCulture() && !content.IsPropertyDirty("PublishCultureInfos") && !content.Published)
|
||||
// fixme/review - assuming it's || here not && ?
|
||||
if (!content.Published || !content.ContentType.VariesByCulture() || !content.IsPropertyDirty("PublishCultureInfos"))
|
||||
return Array.Empty<string>();
|
||||
|
||||
var culturesChanging = content.CultureInfos.Where(x => x.Value.IsDirty()).Select(x => x.Key);
|
||||
|
||||
var result = new List<string>();
|
||||
foreach (var culture in culturesChanging)
|
||||
if (!content.IsCulturePublished(culture) && content.WasCulturePublished(culture))
|
||||
result.Add(culture);
|
||||
|
||||
return result;
|
||||
return culturesChanging
|
||||
.Where(x => !content.IsCulturePublished(x) && // is not published anymore
|
||||
content.WasCulturePublished(x)) // but was published before
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -20,8 +20,6 @@ namespace Umbraco.Core.Models
|
||||
private ContentScheduleCollection _schedule;
|
||||
private bool _published;
|
||||
private PublishedState _publishedState;
|
||||
private DateTime? _releaseDate;
|
||||
private DateTime? _expireDate;
|
||||
private ContentCultureInfosCollection _publishInfos;
|
||||
private ContentCultureInfosCollection _publishInfosOrig;
|
||||
private HashSet<string> _editedCultures;
|
||||
@@ -102,7 +100,7 @@ namespace Umbraco.Core.Models
|
||||
_schedule = new ContentScheduleCollection();
|
||||
_schedule.CollectionChanged += ScheduleCollectionChanged;
|
||||
}
|
||||
return _schedule ?? (_schedule = new ContentScheduleCollection());
|
||||
return _schedule;
|
||||
}
|
||||
set
|
||||
{
|
||||
@@ -301,7 +299,8 @@ namespace Umbraco.Core.Models
|
||||
_publishInfos.Remove(culture);
|
||||
|
||||
//we need to set the culture name to be dirty so we know it's being modified
|
||||
//fixme is there a better way to do this, not as far as i know.
|
||||
//fixme is there a better way to do this, not as far as i know.
|
||||
// fixme why do we need this?
|
||||
SetCultureName(GetCultureName(culture), culture);
|
||||
|
||||
if (_publishInfos.Count == 0) _publishInfos = null;
|
||||
|
||||
@@ -3,14 +3,16 @@ using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Model for scheduled content
|
||||
/// Represents a scheduled action for a document.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class ContentSchedule : IDeepCloneable
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContentSchedule"/> class.
|
||||
/// </summary>
|
||||
public ContentSchedule(int id, string culture, DateTime date, ContentScheduleChange change)
|
||||
{
|
||||
Id = id;
|
||||
@@ -20,32 +22,46 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The unique Id of the schedule item
|
||||
/// Gets the unique identifier of the document targeted by the scheduled action.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The culture for the schedule item
|
||||
/// Gets the culture of the scheduled action.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// string.Empty represents invariant culture
|
||||
/// string.Empty represents the invariant culture.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
public string Culture { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The date for the schedule
|
||||
/// Gets the date of the scheduled action.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public DateTime Date { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The action to take for the schedule
|
||||
/// Gets the action to take.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public ContentScheduleChange Change { get; }
|
||||
|
||||
// fixme/review - must implement Equals?
|
||||
// fixing ContentScheduleCollection.Equals which was broken, breaks content Can_Deep_Clone test
|
||||
// because SequenceEqual on the inner sorted lists fails, because it ends up doing reference-equal
|
||||
// on each content schedule - so we *have* to implement Equals for us too?
|
||||
public override bool Equals(object obj)
|
||||
=> obj is ContentSchedule other && Equals(other);
|
||||
|
||||
public bool Equals(ContentSchedule other)
|
||||
{
|
||||
// don't compare Ids, two ContentSchedule are equal if they are for the same change
|
||||
// for the same culture, on the same date - and the collection deals w/duplicates
|
||||
return Culture.InvariantEquals(other.Culture) && Date == other.Date && Change == other.Change;
|
||||
}
|
||||
|
||||
public object DeepClone()
|
||||
{
|
||||
return new ContentSchedule(Id, Culture, Date, Change);
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
// fixme/review - should this be named DocumentScheduleAction?
|
||||
// fixme/review - should values be Release and Expire not Start and Stop?
|
||||
|
||||
/// <summary>
|
||||
/// The scheduled change types of scheduled content
|
||||
/// Defines scheduled actions for documents.
|
||||
/// </summary>
|
||||
public enum ContentScheduleChange
|
||||
{
|
||||
/// <summary>
|
||||
/// Release the document.
|
||||
/// </summary>
|
||||
Start,
|
||||
|
||||
/// <summary>
|
||||
/// Expire the document.
|
||||
/// </summary>
|
||||
End
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
changes = new SortedList<DateTime, ContentSchedule>();
|
||||
_schedule[culture] = changes;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Below will throw if there are duplicate dates added, should validate/return bool?
|
||||
// but the bool won't indicate which date was in error, maybe have 2 diff methods to schedule start/end?
|
||||
@@ -78,7 +78,7 @@ namespace Umbraco.Core.Models
|
||||
changes.Add(releaseDate.Value, entry);
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, entry));
|
||||
}
|
||||
|
||||
|
||||
if (expireDate.HasValue)
|
||||
{
|
||||
var entry = new ContentSchedule(0, culture, expireDate.Value, ContentScheduleChange.End);
|
||||
@@ -102,7 +102,7 @@ namespace Umbraco.Core.Models
|
||||
if (s.Count == 0)
|
||||
_schedule.Remove(change.Culture);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,9 +135,9 @@ namespace Umbraco.Core.Models
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, ofChange.Value));
|
||||
if (s.Count == 0)
|
||||
_schedule.Remove(culture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,41 +193,27 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (!(obj is ContentScheduleCollection c))
|
||||
return false;
|
||||
return Equals(c);
|
||||
}
|
||||
=> obj is ContentScheduleCollection other && Equals(other);
|
||||
|
||||
public bool Equals(ContentScheduleCollection other)
|
||||
{
|
||||
var thisSched = this._schedule;
|
||||
if (other == null) return false;
|
||||
|
||||
var thisSched = _schedule;
|
||||
var thatSched = other._schedule;
|
||||
|
||||
var equal = false;
|
||||
if (thisSched.Count == thatSched.Count)
|
||||
if (thisSched.Count != thatSched.Count)
|
||||
return false;
|
||||
|
||||
// fixme/review - code was returning false *if* thatList.SequenceEqual(thisList) and not the opposite?
|
||||
foreach (var (culture, thisList) in thisSched)
|
||||
{
|
||||
equal = true;
|
||||
foreach (var pair in thisSched)
|
||||
{
|
||||
if (thatSched.TryGetValue(pair.Key, out var val))
|
||||
{
|
||||
if (val.SequenceEqual(pair.Value))
|
||||
{
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Require key be present.
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if culture is missing, or actions differ, false
|
||||
if (!thatSched.TryGetValue(culture, out var thatList) || !thatList.SequenceEqual(thisList))
|
||||
return false;
|
||||
}
|
||||
return equal;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,20 +4,42 @@ using System.Runtime.Serialization;
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum for the various statuses a Content object can have
|
||||
/// Describes the states of a document, with regard to (schedule) publishing.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract]
|
||||
public enum ContentStatus
|
||||
{
|
||||
// typical flow:
|
||||
// Unpublished (add release date)-> AwaitingRelease (release)-> Published (expire)-> Expired
|
||||
|
||||
/// <summary>
|
||||
/// The document is not trashed, and not published.
|
||||
/// </summary>
|
||||
[EnumMember]
|
||||
Unpublished,
|
||||
|
||||
/// <summary>
|
||||
/// The document is published.
|
||||
/// </summary>
|
||||
[EnumMember]
|
||||
Published,
|
||||
|
||||
/// <summary>
|
||||
/// The document is not trashed, not published, after being unpublished by a scheduled action.
|
||||
/// </summary>
|
||||
[EnumMember]
|
||||
Expired,
|
||||
|
||||
/// <summary>
|
||||
/// The document is trashed.
|
||||
/// </summary>
|
||||
[EnumMember]
|
||||
Trashed,
|
||||
|
||||
/// <summary>
|
||||
/// The document is not trashed, not published, and pending publication by a scheduled action.
|
||||
/// </summary>
|
||||
[EnumMember]
|
||||
AwaitingRelease
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
@@ -48,7 +51,58 @@ namespace Umbraco.Core.Models
|
||||
[DataMember]
|
||||
public string CultureName
|
||||
{
|
||||
get => _cultureName ?? CultureInfo.GetCultureInfo(IsoCode).DisplayName;
|
||||
// CultureInfo.DisplayName is the name in the installed .NET language
|
||||
// .NativeName is the name in culture info's language
|
||||
// .EnglishName is the name in English
|
||||
//
|
||||
// there is no easy way to get the name in a specified culture (which would need to be installed on the server)
|
||||
// this works:
|
||||
// var rm = new ResourceManager("mscorlib", typeof(int).Assembly);
|
||||
// var name = rm.GetString("Globalization.ci_" + culture.Name, displayCulture);
|
||||
// but can we rely on it?
|
||||
//
|
||||
// and... DisplayName is captured and cached in culture infos returned by GetCultureInfo(), using
|
||||
// the value for the current thread culture at the moment it is first retrieved - whereas creating
|
||||
// a new CultureInfo() creates a new instance, which _then_ can get DisplayName again in a different
|
||||
// culture
|
||||
//
|
||||
// I assume that, on a site, all language names should be in the SAME language, in DB,
|
||||
// and that would be the umbracoDefaultUILanguage (app setting) - BUT if by accident
|
||||
// ANY culture has been retrieved with another current thread culture - it's now corrupt
|
||||
//
|
||||
// so, the logic below ensures that the name always end up being the correct name
|
||||
// see also LanguageController.GetAllCultures which is doing the same
|
||||
//
|
||||
// fixme/review - stop saving language names in database?
|
||||
// all this, including the ugly settings injection, because se store language names in db,
|
||||
// otherwise it would be ok to simply return new CultureInfo(IsoCode).DisplayName to get the name
|
||||
// in whatever culture is current - could we ... not do it?
|
||||
//
|
||||
// but then, some tests that compare audit strings (for culture names) would need to be fixed
|
||||
|
||||
get
|
||||
{
|
||||
if (_cultureName != null) return _cultureName;
|
||||
|
||||
// capture
|
||||
var threadUiCulture = Thread.CurrentThread.CurrentUICulture;
|
||||
|
||||
try
|
||||
{
|
||||
var globalSettings = (IGlobalSettings) Composing.Current.Container.GetInstance(typeof(IGlobalSettings));
|
||||
var defaultUiCulture = CultureInfo.GetCultureInfo(globalSettings.DefaultUILanguage);
|
||||
Thread.CurrentThread.CurrentUICulture = defaultUiCulture;
|
||||
|
||||
// get name - new-ing an instance to get proper display name
|
||||
return new CultureInfo(IsoCode).DisplayName;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// restore
|
||||
Thread.CurrentThread.CurrentUICulture = threadUiCulture;
|
||||
}
|
||||
}
|
||||
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _cultureName, Ps.Value.CultureNameSelector);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using NPoco;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Dtos
|
||||
@@ -55,6 +54,5 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
[ResultColumn]
|
||||
[Reference(ReferenceType.OneToOne)]
|
||||
public DocumentVersionDto PublishedVersionDto { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,20 +175,15 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
public static IEnumerable<ContentScheduleDto> BuildScheduleDto(IContent entity, ILanguageRepository languageRepository)
|
||||
{
|
||||
var schedule = new List<ContentScheduleDto>();
|
||||
foreach(var s in entity.ContentSchedule.FullSchedule)
|
||||
{
|
||||
schedule.Add(new ContentScheduleDto
|
||||
return entity.ContentSchedule.FullSchedule.Select(x =>
|
||||
new ContentScheduleDto
|
||||
{
|
||||
Action = s.Change.ToString(),
|
||||
Date = s.Date,
|
||||
Action = x.Change.ToString(),
|
||||
Date = x.Date,
|
||||
NodeId = entity.Id,
|
||||
LanguageId = languageRepository.GetIdByIsoCode(s.Culture, false),
|
||||
Id = s.Id
|
||||
LanguageId = languageRepository.GetIdByIsoCode(x.Culture, false),
|
||||
Id = x.Id
|
||||
});
|
||||
}
|
||||
|
||||
return schedule;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -83,11 +83,16 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
var translator = new SqlTranslator<IContent>(sqlClause, query);
|
||||
var sql = translator.Translate();
|
||||
|
||||
AddGetByQueryOrderBy(sql);
|
||||
|
||||
return MapDtosToContent(Database.Fetch<DocumentDto>(sql));
|
||||
}
|
||||
|
||||
private void AddGetByQueryOrderBy(Sql<ISqlContext> sql)
|
||||
{
|
||||
sql // fixme why - this should be Path
|
||||
.OrderBy<NodeDto>(x => x.Level)
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
|
||||
return MapDtosToContent(Database.Fetch<DocumentDto>(sql));
|
||||
}
|
||||
|
||||
protected override Sql<ISqlContext> GetBaseQuery(QueryType queryType)
|
||||
@@ -321,7 +326,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
var contentVersionDto = dto.DocumentVersionDto.ContentVersionDto;
|
||||
contentVersionDto.NodeId = nodeDto.NodeId;
|
||||
contentVersionDto.Current = !publishing;
|
||||
contentVersionDto.Text = content.Name; //fixme is this requried? isn't this mapped in the ContentBaseFactory?
|
||||
Database.Insert(contentVersionDto);
|
||||
content.VersionId = contentVersionDto.Id;
|
||||
|
||||
@@ -367,11 +371,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
Database.Insert(dto);
|
||||
|
||||
//insert the schedule
|
||||
var scheduleDto = ContentBaseFactory.BuildScheduleDto(content, LanguageRepository);
|
||||
foreach (var c in scheduleDto)
|
||||
var scheduleDtos = ContentBaseFactory.BuildScheduleDto(content, LanguageRepository);
|
||||
foreach (var scheduleDto in scheduleDtos)
|
||||
{
|
||||
c.NodeId = nodeDto.NodeId;
|
||||
Database.Insert(c);
|
||||
scheduleDto.NodeId = nodeDto.NodeId;
|
||||
Database.Insert(scheduleDto);
|
||||
}
|
||||
|
||||
// persist the variations
|
||||
@@ -502,7 +506,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
documentVersionDto.Published = true; // now published
|
||||
contentVersionDto.Current = false; // no more current
|
||||
contentVersionDto.Text = content.Name;
|
||||
}
|
||||
Database.Update(contentVersionDto);
|
||||
Database.Update(documentVersionDto);
|
||||
@@ -596,22 +599,22 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (content.IsPropertyDirty("ContentSchedule"))
|
||||
{
|
||||
//update the schedule, get the existing one so we know what to update
|
||||
var dtoSchedule = ContentBaseFactory.BuildScheduleDto(content, LanguageRepository);
|
||||
var existingSched = Database.Fetch<int>(Sql()
|
||||
.Select<ContentScheduleDto>(x => x.Id)
|
||||
.From<ContentScheduleDto>()
|
||||
.Where<ContentScheduleDto>(x => x.NodeId == content.Id));
|
||||
var scheduleDtos = ContentBaseFactory.BuildScheduleDto(content, LanguageRepository).ToList();
|
||||
|
||||
//remove any that no longer exist
|
||||
var schedToRemove = existingSched.Except(dtoSchedule.Select(x => x.Id));
|
||||
foreach (var c in schedToRemove)
|
||||
Database.DeleteWhere<ContentScheduleDto>("id = @id", new { id = c });
|
||||
var ids = scheduleDtos.Where(x => x.Id > 0).Select(x => x.Id).Distinct();
|
||||
Database.Execute(Sql()
|
||||
.Delete<ContentScheduleDto>()
|
||||
.Where<ContentScheduleDto>(x => x.NodeId == content.Id)
|
||||
.WhereNotIn<ContentScheduleDto>(x => x.Id, ids));
|
||||
|
||||
//add/update the rest
|
||||
foreach (var c in dtoSchedule)
|
||||
foreach (var scheduleDto in scheduleDtos)
|
||||
{
|
||||
if (c.Id == 0)
|
||||
Database.Insert(c);
|
||||
if (scheduleDto.Id == 0)
|
||||
Database.Insert(scheduleDto);
|
||||
else
|
||||
Database.Update(c);
|
||||
Database.Update(scheduleDto);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,47 +910,41 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IContent> GetContentForRelease(DateTime date)
|
||||
{
|
||||
var sqlSchedule = Sql()
|
||||
.Select<ContentScheduleDto>(x => x.NodeId)
|
||||
.From<ContentScheduleDto>()
|
||||
.Where<ContentScheduleDto>(x =>
|
||||
x.Action == ContentScheduleChange.Start.ToString()
|
||||
&& x.Date <= date);
|
||||
var action = ContentScheduleChange.Start.ToString();
|
||||
|
||||
//fixme - If we don't cast to IEnumerable<T> or do a ToArray, the Expression Visitor will FAIL!
|
||||
// in the ExpressionVisitorBase.VisitMethodCall where the switch checks for "Contains" for some reason
|
||||
// the 'special case' that redirects to `SqlIn` fails because the m.Arguments.Count is only ONE instead of TWO,
|
||||
// no time to investigate right now.
|
||||
// fixed here: https://github.com/umbraco/Umbraco-CMS/pull/3516/files so when that's merged we don't need the AsEnumerable() thing
|
||||
var scheduledIds = Database.Fetch<int>(sqlSchedule);
|
||||
if (scheduledIds.Count == 0) return Enumerable.Empty<IContent>();
|
||||
var e = scheduledIds.AsEnumerable();
|
||||
// fixme/review - code would blow if more than 2000 items
|
||||
// fixme/review - isn't this simpler?
|
||||
var sql = GetBaseQuery(QueryType.Many)
|
||||
.WhereIn<NodeDto>(x => x.NodeId, Sql()
|
||||
.Select<ContentScheduleDto>(x => x.NodeId)
|
||||
.From<ContentScheduleDto>()
|
||||
.Where<ContentScheduleDto>(x => x.Action == action && x.Date <= date));
|
||||
|
||||
var query = Query<IContent>().Where(x => x.Published == false && e.Contains(x.Id));
|
||||
return Get(query);
|
||||
sql.Where<NodeDto>(x => !x.Trashed); // fixme/review - shouldn't we exclude trashed nodes?
|
||||
sql.Where<DocumentDto>(x => !x.Published);
|
||||
|
||||
AddGetByQueryOrderBy(sql);
|
||||
|
||||
return MapDtosToContent(Database.Fetch<DocumentDto>(sql));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IContent> GetContentForExpiration(DateTime date)
|
||||
{
|
||||
var sqlSchedule = Sql()
|
||||
.Select<ContentScheduleDto>(x => x.NodeId)
|
||||
.From<ContentScheduleDto>()
|
||||
.Where<ContentScheduleDto>(x =>
|
||||
x.Action == ContentScheduleChange.End.ToString()
|
||||
&& x.Date <= date);
|
||||
var action = ContentScheduleChange.End.ToString();
|
||||
|
||||
//fixme - If we don't cast to IEnumerable<T> or do a ToArray, the Expression Visitor will FAIL!
|
||||
// in the ExpressionVisitorBase.VisitMethodCall where the switch checks for "Contains" for some reason
|
||||
// the 'special case' that redirects to `SqlIn` fails because the m.Arguments.Count is only ONE instead of TWO,
|
||||
// no time to investigate right now.
|
||||
// fixed here: https://github.com/umbraco/Umbraco-CMS/pull/3516/files so when that's merged we don't need the AsEnumerable() thing
|
||||
var scheduledIds = Database.Fetch<int>(sqlSchedule);
|
||||
if (scheduledIds.Count == 0) return Enumerable.Empty<IContent>();
|
||||
var e = scheduledIds.AsEnumerable();
|
||||
// fixme/review - see as above
|
||||
var sql = GetBaseQuery(QueryType.Many)
|
||||
.WhereIn<NodeDto>(x => x.NodeId, Sql()
|
||||
.Select<ContentScheduleDto>(x => x.NodeId)
|
||||
.From<ContentScheduleDto>()
|
||||
.Where<ContentScheduleDto>(x => x.Action == action && x.Date <= date));
|
||||
|
||||
var query = Query<IContent>().Where(x => x.Published && e.Contains(x.Id));
|
||||
return Get(query);
|
||||
sql.Where<DocumentDto>(x => x.Published);
|
||||
|
||||
AddGetByQueryOrderBy(sql);
|
||||
|
||||
return MapDtosToContent(Database.Fetch<DocumentDto>(sql));
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1160,23 +1157,27 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
private IDictionary<int, ContentScheduleCollection> GetContentSchedule(params int[] contentIds)
|
||||
{
|
||||
var result = new Dictionary<int, ContentScheduleCollection>();
|
||||
foreach(var ids in contentIds.InGroupsOf(2000))
|
||||
{
|
||||
var sql = Sql().Select<ContentScheduleDto>().From<ContentScheduleDto>().Where<ContentScheduleDto>(x => ids.Contains(x.NodeId));
|
||||
var scheduleDto = Database.Fetch<ContentScheduleDto>(sql);
|
||||
|
||||
foreach (var dto in scheduleDto)
|
||||
{
|
||||
var schedule = new ContentScheduleCollection();
|
||||
schedule.Add(new ContentSchedule(dto.Id,
|
||||
LanguageRepository.GetIsoCodeById(dto.LanguageId) ?? string.Empty,
|
||||
dto.Date,
|
||||
dto.Action == ContentScheduleChange.Start.ToString()
|
||||
? ContentScheduleChange.Start
|
||||
: ContentScheduleChange.End));
|
||||
result[dto.NodeId] = schedule;
|
||||
}
|
||||
var scheduleDtos = Database.FetchByGroups<ContentScheduleDto, int>(contentIds, 2000, batch => Sql()
|
||||
.Select<ContentScheduleDto>()
|
||||
.From<ContentScheduleDto>()
|
||||
.WhereIn<ContentScheduleDto>(x => x.NodeId, batch));
|
||||
|
||||
foreach (var scheduleDto in scheduleDtos)
|
||||
{
|
||||
// fixme/review - code was adding a new collection on each dto?
|
||||
|
||||
if (!result.TryGetValue(scheduleDto.NodeId, out var col))
|
||||
col = result[scheduleDto.NodeId] = new ContentScheduleCollection();
|
||||
|
||||
col.Add(new ContentSchedule(scheduleDto.Id,
|
||||
LanguageRepository.GetIsoCodeById(scheduleDto.LanguageId) ?? string.Empty,
|
||||
scheduleDto.Date,
|
||||
scheduleDto.Action == ContentScheduleChange.Start.ToString()
|
||||
? ContentScheduleChange.Start
|
||||
: ContentScheduleChange.End));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
// fast way of getting an id for an isoCode - avoiding cloning
|
||||
// _codeIdMap is rebuilt whenever PerformGetAll runs
|
||||
public int? GetIdByIsoCode(string isoCode, bool throwOnNotFound)
|
||||
public int? GetIdByIsoCode(string isoCode, bool throwOnNotFound = true)
|
||||
{
|
||||
if (isoCode == null) return null;
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
|
||||
namespace Umbraco.Core.Publishing
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to perform scheduled publishing/unpublishing
|
||||
/// </summary>
|
||||
internal class ScheduledPublisher
|
||||
{
|
||||
private readonly IContentService _contentService;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IUserService _userService;
|
||||
|
||||
public ScheduledPublisher(IContentService contentService, ILogger logger, IUserService userService)
|
||||
{
|
||||
_contentService = contentService;
|
||||
_logger = logger;
|
||||
_userService = userService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes scheduled operations
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Returns the number of items successfully completed
|
||||
/// </returns>
|
||||
public int CheckPendingAndProcess()
|
||||
{
|
||||
var results = _contentService.PerformScheduledPublish(DateTime.Now);
|
||||
return results.Count(x => x.Success);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,7 +132,7 @@ namespace Umbraco.Core.Services
|
||||
IEnumerable<IContent> GetRootContent();
|
||||
|
||||
/// <summary>
|
||||
/// Gets documents with an expiration date greater then today.
|
||||
/// Gets documents having an expiration date before (lower than, or equal to) a specified date.
|
||||
/// </summary>
|
||||
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
|
||||
/// <remarks>
|
||||
@@ -142,7 +142,7 @@ namespace Umbraco.Core.Services
|
||||
IEnumerable<IContent> GetContentForExpiration(DateTime date);
|
||||
|
||||
/// <summary>
|
||||
/// Gets documents with a release date greater then today.
|
||||
/// Gets documents having a release date before (lower than, or equal to) a specified date.
|
||||
/// </summary>
|
||||
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
|
||||
/// <remarks>
|
||||
@@ -362,23 +362,7 @@ namespace Umbraco.Core.Services
|
||||
/// </remarks>
|
||||
PublishResult SavePublishing(IContent content, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/*
|
||||
fixme - document this better + test
|
||||
If the item being published is Invariant and it has Variant descendants and
|
||||
we are NOT forcing publishing of anything not published - the result will be that the Variant cultures that are
|
||||
already published (but may contain a draft) are published. Any cultures that don't have a published version are not published
|
||||
fixme: now, if publishing '*' then all cultures
|
||||
If the item being published is Invariant and it has Variant descendants and
|
||||
we ARE forcing publishing of anything not published - the result will be that all Variant cultures are
|
||||
published regardless of whether they don't have any current published versions
|
||||
|
||||
If the item being published is Variant and it has Invariant descendants and
|
||||
we are NOT forcing publishing of anything not published - the result will be that all Invariant documents are
|
||||
published that already have a published versions, regardless of what cultures are selected to be published
|
||||
If the item being published is Variant and it has Invariant descendants and
|
||||
we ARE forcing publishing of anything not published - the result will be that all Invariant documents are
|
||||
published regardless of whether they have a published version or not and regardless of what cultures are selected to be published
|
||||
*/
|
||||
// fixme/review - should SaveAndPublishBranch always publish the root document of the branch, even when !force?
|
||||
|
||||
/// <summary>
|
||||
/// Saves and publishes a document branch.
|
||||
@@ -392,7 +376,7 @@ namespace Umbraco.Core.Services
|
||||
/// than one culture, see the other overloads of this method.</para>
|
||||
/// <para>The <paramref name="force"/> parameter determines which documents are published. When <c>false</c>,
|
||||
/// only those documents that are already published, are republished. When <c>true</c>, all documents are
|
||||
/// published.</para>
|
||||
/// published. The root of the branch is always published, regardless of <paramref name="force"/>.</para>
|
||||
/// </remarks>
|
||||
IEnumerable<PublishResult> SaveAndPublishBranch(IContent content, bool force, string culture = "*", int userId = 0);
|
||||
|
||||
@@ -406,7 +390,7 @@ namespace Umbraco.Core.Services
|
||||
/// <remarks>
|
||||
/// <para>The <paramref name="force"/> parameter determines which documents are published. When <c>false</c>,
|
||||
/// only those documents that are already published, are republished. When <c>true</c>, all documents are
|
||||
/// published.</para>
|
||||
/// published. The root of the branch is always published, regardless of <paramref name="force"/>.</para>
|
||||
/// </remarks>
|
||||
IEnumerable<PublishResult> SaveAndPublishBranch(IContent content, bool force, string[] cultures, int userId = 0);
|
||||
|
||||
@@ -421,7 +405,7 @@ namespace Umbraco.Core.Services
|
||||
/// <remarks>
|
||||
/// <para>The <paramref name="force"/> parameter determines which documents are published. When <c>false</c>,
|
||||
/// only those documents that are already published, are republished. When <c>true</c>, all documents are
|
||||
/// published.</para>
|
||||
/// published. The root of the branch is always published, regardless of <paramref name="force"/>.</para>
|
||||
/// <para>The <paramref name="editing"/> parameter is a function which determines whether a document has
|
||||
/// changes to publish (else there is no need to publish it). If one wants to publish only a selection of
|
||||
/// cultures, one may want to check that only properties for these cultures have changed. Otherwise, other
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.IO;
|
||||
@@ -942,9 +940,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
|
||||
// finally, "save publishing"
|
||||
// what happens next depends on whether the content can be published or not
|
||||
var saved = SavePublishing(content, userId);
|
||||
return saved;
|
||||
return SavePublishing(content, userId);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -970,6 +966,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
((Content)content).PublishedState = PublishedState.Publishing;
|
||||
|
||||
// state here is either Publishing or Unpublishing
|
||||
// (even though, Publishing to unpublish a culture may end up unpublishing everything)
|
||||
var publishing = content.PublishedState == PublishedState.Publishing;
|
||||
var unpublishing = content.PublishedState == PublishedState.Unpublishing;
|
||||
|
||||
@@ -1014,11 +1011,11 @@ namespace Umbraco.Core.Services.Implement
|
||||
unpublishing = content.Published; // if not published yet, nothing to do
|
||||
|
||||
// we may end up in a state where we won't publish nor unpublish
|
||||
// keep going, though, as we want to save anways
|
||||
// keep going, though, as we want to save anyways
|
||||
}
|
||||
|
||||
//fixme - casting
|
||||
((Content)content).Published = content.Published; // reset published state = save unchanged
|
||||
((Content)content).Published = content.Published; // reset published state = save unchanged - fixme doh?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1026,7 +1023,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
var newest = GetById(content.Id); // ensure we have the newest version - in scope
|
||||
if (content.VersionId != newest.VersionId) // but use the original object if it's already the newest version
|
||||
content = newest;
|
||||
content = newest; // fixme confusing should just die here - else we'll miss some changes
|
||||
|
||||
if (content.Published)
|
||||
{
|
||||
@@ -1269,18 +1266,20 @@ namespace Umbraco.Core.Services.Implement
|
||||
// should not trigger a publish).
|
||||
HashSet<string> ShouldPublish(IContent c)
|
||||
{
|
||||
var isRoot = c.Id == content.Id;
|
||||
|
||||
if (c.ContentType.VariesByCulture())
|
||||
{
|
||||
// variant content type
|
||||
// add culture if edited, and already published or forced
|
||||
if (c.IsCultureEdited(culture) && (c.IsCulturePublished(culture) || force))
|
||||
if (c.IsCultureEdited(culture) && (c.IsCulturePublished(culture) || force || isRoot))
|
||||
return new HashSet<string> { culture.ToLowerInvariant() };
|
||||
}
|
||||
else
|
||||
{
|
||||
// invariant content type
|
||||
// add "*" if edited, and already published or forced
|
||||
if (c.Edited && (c.Published || force))
|
||||
if (c.Edited && (c.Published || force || isRoot))
|
||||
return new HashSet<string> { "*" };
|
||||
}
|
||||
|
||||
@@ -1314,6 +1313,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
HashSet<string> ShouldPublish(IContent c)
|
||||
{
|
||||
var culturesToPublish = new HashSet<string>();
|
||||
var isRoot = c.Id == content.Id;
|
||||
|
||||
if (c.ContentType.VariesByCulture())
|
||||
{
|
||||
@@ -1321,7 +1321,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
// add cultures which are edited, and already published or forced
|
||||
foreach (var culture in cultures)
|
||||
{
|
||||
if (c.IsCultureEdited(culture) && (c.IsCulturePublished(culture) || force))
|
||||
if (c.IsCultureEdited(culture) && (c.IsCulturePublished(culture) || force || isRoot))
|
||||
culturesToPublish.Add(culture.ToLowerInvariant());
|
||||
}
|
||||
}
|
||||
@@ -1329,7 +1329,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
// invariant content type
|
||||
// add "*" if edited, and already published or forced
|
||||
if (c.Edited && (c.Published || force))
|
||||
if (c.Edited && (c.Published || force || isRoot))
|
||||
culturesToPublish.Add("*");
|
||||
}
|
||||
|
||||
@@ -1425,7 +1425,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
// publishValues: a function publishing values (using the appropriate PublishCulture calls)
|
||||
private PublishResult SaveAndPublishBranchOne(IScope scope, IContent document,
|
||||
Func<IContent, HashSet<string>> shouldPublish, Func<IContent, HashSet<string>, bool> publishCultures,
|
||||
bool checkPath,
|
||||
bool isRoot,
|
||||
ICollection<IContent> publishedDocuments,
|
||||
EventMessages evtMsgs, int userId)
|
||||
{
|
||||
@@ -1442,8 +1442,28 @@ namespace Umbraco.Core.Services.Implement
|
||||
if (publishCultures != null && !publishCultures(document, culturesToPublish))
|
||||
return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, document);
|
||||
|
||||
return SavePublishingInternal(scope, document, userId);
|
||||
// fixme - this is totally kinda wrong
|
||||
|
||||
var culturesPublishing = document.ContentType.VariesByCulture()
|
||||
? document.PublishCultureInfos.Where(x => x.Value.IsDirty()).Select(x => x.Key).ToList()
|
||||
: null;
|
||||
var result = StrategyCanPublish(scope, document, userId, /*checkPath:*/ isRoot, culturesPublishing, Array.Empty<string>(), evtMsgs);
|
||||
if (!result.Success)
|
||||
return result;
|
||||
result = StrategyPublish(scope, document, userId, culturesPublishing, Array.Empty<string>(), evtMsgs);
|
||||
if (!result.Success)
|
||||
throw new Exception("panic");
|
||||
if (document.HasIdentity == false)
|
||||
document.CreatorId = userId;
|
||||
document.WriterId = userId;
|
||||
_documentRepository.Save(document);
|
||||
publishedDocuments.Add(document);
|
||||
// fixme - but then, we have all the audit thing to run
|
||||
// so... it would be better to re-run the internal thing?
|
||||
return result;
|
||||
|
||||
// we want _some part_ of it but not all of it
|
||||
return SavePublishingInternal(scope, document, userId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1969,7 +1989,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
Audit(AuditType.SendToPublish, content.WriterId, content.Id);
|
||||
}
|
||||
|
||||
// fixme here, on only on success?
|
||||
// fixme here, on only on success?
|
||||
scope.Complete();
|
||||
|
||||
return saveResult.Success;
|
||||
@@ -2312,7 +2332,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
|
||||
var variesByCulture = content.ContentType.VariesByCulture();
|
||||
|
||||
|
||||
//First check if mandatory languages fails, if this fails it will mean anything that the published flag on the document will
|
||||
// be changed to Unpublished and any culture currently published will not be visible.
|
||||
if (variesByCulture)
|
||||
@@ -2322,7 +2342,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
// missing mandatory culture = cannot be published
|
||||
var mandatoryCultures = _languageRepository.GetMany().Where(x => x.IsMandatory).Select(x => x.IsoCode);
|
||||
var mandatoryMissing = mandatoryCultures.Any(x => !content.PublishedCultures.Contains(x, StringComparer.OrdinalIgnoreCase));
|
||||
var mandatoryMissing = mandatoryCultures.Any(x => !content.PublishedCultures.Contains(x, StringComparer.OrdinalIgnoreCase));
|
||||
if (mandatoryMissing)
|
||||
return new PublishResult(PublishResultType.FailedPublishMandatoryCultureMissing, evtMsgs, content);
|
||||
|
||||
@@ -2454,7 +2474,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpublishes a document
|
||||
/// Unpublishes a document
|
||||
/// </summary>
|
||||
/// <param name="scope"></param>
|
||||
/// <param name="content"></param>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// A value indicating the result of publishing a content item.
|
||||
/// A value indicating the result of publishing or unpublishing a document.
|
||||
/// </summary>
|
||||
public enum PublishResultType : byte
|
||||
{
|
||||
@@ -10,15 +9,19 @@
|
||||
// every failure codes as >128 - see OperationResult and OperationResultType for details.
|
||||
|
||||
#region Success - Publish
|
||||
|
||||
/// <summary>
|
||||
/// The publishing was successful.
|
||||
/// The document was successfully published.
|
||||
/// </summary>
|
||||
SuccessPublish = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The specified document culture was successfully published.
|
||||
/// </summary>
|
||||
SuccessPublishCulture = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The item was already published.
|
||||
/// The document was already published.
|
||||
/// </summary>
|
||||
SuccessPublishAlready = 2,
|
||||
|
||||
@@ -27,22 +30,22 @@
|
||||
#region Success - Unpublish
|
||||
|
||||
/// <summary>
|
||||
/// The unpublishing was successful.
|
||||
/// The document was successfully unpublished.
|
||||
/// </summary>
|
||||
SuccessUnpublish = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The item was already unpublished.
|
||||
/// The document was already unpublished.
|
||||
/// </summary>
|
||||
SuccessUnpublishAlready = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The specified variant was unpublished, the content item itself remains published.
|
||||
/// The specified document culture was unpublished, the document item itself remains published.
|
||||
/// </summary>
|
||||
SuccessUnpublishCulture = 5,
|
||||
|
||||
/// <summary>
|
||||
/// The specified variant was a mandatory culture therefore it was unpublished and the content item itself is unpublished
|
||||
/// The specified document culture was unpublished, and was a mandatory culture, therefore the document itself was unpublished.
|
||||
/// </summary>
|
||||
SuccessUnpublishMandatoryCulture = 6,
|
||||
|
||||
@@ -51,13 +54,12 @@
|
||||
#region Success - Mixed
|
||||
|
||||
/// <summary>
|
||||
/// A variant content item has a culture published and another culture unpublished in the same operation
|
||||
/// Specified document cultures were successfully published and unpublished (in the same operation).
|
||||
/// </summary>
|
||||
SuccessMixedCulture = 7,
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Failed - Publish
|
||||
|
||||
/// <summary>
|
||||
@@ -67,36 +69,36 @@
|
||||
FailedPublish = 128,
|
||||
|
||||
/// <summary>
|
||||
/// The content could not be published because it's ancestor path isn't published.
|
||||
/// The document could not be published because its ancestor path is not published.
|
||||
/// </summary>
|
||||
FailedPublishPathNotPublished = FailedPublish | 1,
|
||||
|
||||
/// <summary>
|
||||
/// The content item was scheduled to be un-published and it has expired so we cannot force it to be
|
||||
/// The document has expired so we cannot force it to be
|
||||
/// published again as part of a bulk publish operation.
|
||||
/// </summary>
|
||||
FailedPublishHasExpired = FailedPublish | 2,
|
||||
|
||||
/// <summary>
|
||||
/// The content item is scheduled to be released in the future and therefore we cannot force it to
|
||||
/// The document is scheduled to be released in the future and therefore we cannot force it to
|
||||
/// be published during a bulk publish operation.
|
||||
/// </summary>
|
||||
FailedPublishAwaitingRelease = FailedPublish | 3,
|
||||
|
||||
/// <summary>
|
||||
/// A culture on the content item was scheduled to be un-published and it has expired so we cannot force it to be
|
||||
/// A document culture has expired so we cannot force it to be
|
||||
/// published again as part of a bulk publish operation.
|
||||
/// </summary>
|
||||
FailedPublishCultureHasExpired = FailedPublish | 4,
|
||||
|
||||
/// <summary>
|
||||
/// A culture on the content item is scheduled to be released in the future and therefore we cannot force it to
|
||||
/// A document culture is scheduled to be released in the future and therefore we cannot force it to
|
||||
/// be published during a bulk publish operation.
|
||||
/// </summary>
|
||||
FailedPublishCultureAwaitingRelease = FailedPublish | 5,
|
||||
|
||||
/// <summary>
|
||||
/// The content item could not be published because it is in the trash.
|
||||
/// The document could not be published because it is in the trash.
|
||||
/// </summary>
|
||||
FailedPublishIsTrashed = FailedPublish | 6,
|
||||
|
||||
@@ -106,17 +108,17 @@
|
||||
FailedPublishCancelledByEvent = FailedPublish | 7,
|
||||
|
||||
/// <summary>
|
||||
/// The content item could not be published because it contains invalid data (has not passed validation requirements).
|
||||
/// The document could not be published because it contains invalid data (has not passed validation requirements).
|
||||
/// </summary>
|
||||
FailedPublishContentInvalid = FailedPublish | 8,
|
||||
|
||||
/// <summary>
|
||||
/// Cannot publish a document that has no publishing flags or values
|
||||
/// The document cannot be published because it has no publishing flags or values.
|
||||
/// </summary>
|
||||
FailedPublishNothingToPublish = FailedPublish | 9, // in ContentService.StrategyCanPublish - fixme weird
|
||||
|
||||
/// <summary>
|
||||
/// Some mandatory cultures are missing.
|
||||
/// The document could not be published because some mandatory cultures are missing.
|
||||
/// </summary>
|
||||
FailedPublishMandatoryCultureMissing = FailedPublish | 10, // in ContentService.SavePublishing
|
||||
|
||||
@@ -125,7 +127,7 @@
|
||||
#region Failed - Unpublish
|
||||
|
||||
/// <summary>
|
||||
/// Unpublish failed
|
||||
/// The document could not be unpublished.
|
||||
/// </summary>
|
||||
FailedUnpublish = FailedPublish | 11, // in ContentService.SavePublishing
|
||||
|
||||
@@ -135,6 +137,5 @@
|
||||
FailedUnpublishCancelledByEvent = FailedPublish | 12,
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1268,7 +1268,6 @@
|
||||
<Compile Include="PropertyEditors\ValueConverters\TinyMceValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\UploadPropertyConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\YesNoValueConverter.cs" />
|
||||
<Compile Include="Publishing\ScheduledPublisher.cs" />
|
||||
<Compile Include="ReflectionUtilities.cs" />
|
||||
<Compile Include="RenderingEngine.cs" />
|
||||
<Compile Include="RuntimeLevel.cs" />
|
||||
|
||||
@@ -37,13 +37,13 @@ namespace Umbraco.Tests.Services
|
||||
// ii2 !published !edited
|
||||
|
||||
// !force = publishes those that are actually published, and have changes
|
||||
// here: nothing
|
||||
// here: root (root is always published)
|
||||
|
||||
var r = SaveAndPublishInvariantBranch(iRoot, false, method).ToArray();
|
||||
AssertPublishResults(r, x => x.Content.Name,
|
||||
"iroot", "ii1", "ii2");
|
||||
AssertPublishResults(r, x => x.Result,
|
||||
PublishResultType.SuccessPublishAlready,
|
||||
PublishResultType.SuccessPublish,
|
||||
PublishResultType.SuccessPublishAlready,
|
||||
PublishResultType.SuccessPublishAlready);
|
||||
|
||||
@@ -220,8 +220,8 @@ namespace Umbraco.Tests.Services
|
||||
AssertPublishResults(r, x => x.Content.Name,
|
||||
"vroot.de", "iv1.de", "iv2.de");
|
||||
AssertPublishResults(r, x => x.Result,
|
||||
PublishResultType.SuccessPublish,
|
||||
PublishResultType.SuccessPublish,
|
||||
PublishResultType.SuccessPublishCulture,
|
||||
PublishResultType.SuccessPublishCulture,
|
||||
PublishResultType.SuccessPublishAlready);
|
||||
|
||||
// reload - SaveAndPublishBranch has modified other instances
|
||||
@@ -291,7 +291,7 @@ namespace Umbraco.Tests.Services
|
||||
AssertPublishResults(r, x => x.Result,
|
||||
PublishResultType.SuccessPublishAlready,
|
||||
PublishResultType.SuccessPublish,
|
||||
PublishResultType.SuccessPublish);
|
||||
PublishResultType.SuccessPublishCulture);
|
||||
|
||||
// reload - SaveAndPublishBranch has modified other instances
|
||||
Reload(ref ii1);
|
||||
|
||||
@@ -351,10 +351,11 @@ namespace Umbraco.Tests.Services
|
||||
|
||||
content.ContentSchedule.Add(null, DateTime.Now.AddHours(2));
|
||||
contentService.Save(content, Constants.Security.SuperUserId);
|
||||
Assert.AreEqual(1, content.ContentSchedule.FullSchedule.Count);
|
||||
|
||||
content = contentService.GetById(content.Id);
|
||||
var sched = content.ContentSchedule.FullSchedule;
|
||||
Assert.AreEqual(1, sched.Count());
|
||||
Assert.AreEqual(1, sched.Count);
|
||||
Assert.AreEqual(1, sched.Count(x => x.Culture == string.Empty));
|
||||
content.ContentSchedule.Clear(ContentScheduleChange.End);
|
||||
contentService.Save(content, Constants.Security.SuperUserId);
|
||||
@@ -363,7 +364,7 @@ namespace Umbraco.Tests.Services
|
||||
// Assert
|
||||
content = contentService.GetById(content.Id);
|
||||
sched = content.ContentSchedule.FullSchedule;
|
||||
Assert.AreEqual(0, sched.Count());
|
||||
Assert.AreEqual(0, sched.Count);
|
||||
Assert.IsTrue(contentService.SaveAndPublish(content).Success);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Web.Http;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
@@ -28,10 +29,14 @@ namespace Umbraco.Web.Editors
|
||||
[HttpGet]
|
||||
public IDictionary<string, string> GetAllCultures()
|
||||
{
|
||||
return
|
||||
CultureInfo.GetCultures(CultureTypes.AllCultures)
|
||||
.Where(x => !x.Name.IsNullOrWhiteSpace())
|
||||
.OrderBy(x => x.DisplayName).ToDictionary(x => x.Name, x => x.DisplayName);
|
||||
// get cultures - new-ing instances to get proper display name,
|
||||
// in the current culture, and not the cached one
|
||||
// (see notes in Language class about culture info names)
|
||||
return CultureInfo.GetCultures(CultureTypes.AllCultures)
|
||||
.Where(x => !x.Name.IsNullOrWhiteSpace())
|
||||
.Select(x => new CultureInfo(x.Name)) // important!
|
||||
.OrderBy(x => x.DisplayName)
|
||||
.ToDictionary(x => x.Name, x => x.DisplayName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Publishing;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Sync;
|
||||
|
||||
@@ -12,16 +11,14 @@ namespace Umbraco.Web.Scheduling
|
||||
private readonly IRuntimeState _runtime;
|
||||
private readonly IContentService _contentService;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IUserService _userService;
|
||||
|
||||
public ScheduledPublishing(IBackgroundTaskRunner<RecurringTaskBase> runner, int delayMilliseconds, int periodMilliseconds,
|
||||
IRuntimeState runtime, IContentService contentService, ILogger logger, IUserService userService)
|
||||
IRuntimeState runtime, IContentService contentService, ILogger logger)
|
||||
: base(runner, delayMilliseconds, periodMilliseconds)
|
||||
{
|
||||
_runtime = runtime;
|
||||
_contentService = contentService;
|
||||
_logger = logger;
|
||||
_userService = userService;
|
||||
}
|
||||
|
||||
public override bool PerformRun()
|
||||
@@ -58,9 +55,8 @@ namespace Umbraco.Web.Scheduling
|
||||
// run
|
||||
// fixme context & events during scheduled publishing?
|
||||
// in v7 we create an UmbracoContext and an HttpContext, and cache instructions
|
||||
// are batched, and we have to explicitely flush them, how is it going to work here?
|
||||
var publisher = new ScheduledPublisher(_contentService, _logger, _userService);
|
||||
var count = publisher.CheckPendingAndProcess();
|
||||
// are batched, and we have to explicitly flush them, how is it going to work here?
|
||||
_contentService.PerformScheduledPublish(DateTime.Now);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace Umbraco.Web.Scheduling
|
||||
{
|
||||
private IRuntimeState _runtime;
|
||||
private IContentService _contentService;
|
||||
private IUserService _userService;
|
||||
private IAuditService _auditService;
|
||||
private ILogger _logger;
|
||||
private ProfilingLogger _proflog;
|
||||
@@ -45,13 +44,12 @@ namespace Umbraco.Web.Scheduling
|
||||
private IBackgroundTask[] _tasks;
|
||||
|
||||
public void Initialize(IRuntimeState runtime,
|
||||
IContentService contentService, IAuditService auditService, IUserService userService,
|
||||
IContentService contentService, IAuditService auditService,
|
||||
HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications,
|
||||
IScopeProvider scopeProvider, ILogger logger, ProfilingLogger proflog)
|
||||
{
|
||||
_runtime = runtime;
|
||||
_contentService = contentService;
|
||||
_userService = userService;
|
||||
_auditService = auditService;
|
||||
_scopeProvider = scopeProvider;
|
||||
_logger = logger;
|
||||
@@ -118,7 +116,7 @@ namespace Umbraco.Web.Scheduling
|
||||
{
|
||||
// scheduled publishing/unpublishing
|
||||
// install on all, will only run on non-replica servers
|
||||
var task = new ScheduledPublishing(_publishingRunner, 60000, 60000, _runtime, _contentService, _logger, _userService);
|
||||
var task = new ScheduledPublishing(_publishingRunner, 60000, 60000, _runtime, _contentService, _logger);
|
||||
_publishingRunner.TryAdd(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue"><data><IncludeFilters /><ExcludeFilters /></data></s:String>
|
||||
<s:String x:Key="/Default/FilterSettingsManager/AttributeFilterXml/@EntryValue"><data /></s:String>
|
||||
<s:String x:Key="/Default/PatternsAndTemplates/StructuralSearch/Pattern/=2DA32DA040A7D74599ABE288C7224CF0/Comment/@EntryValue">Disposable construction</s:String>
|
||||
<s:String x:Key="/Default/PatternsAndTemplates/StructuralSearch/Pattern/=2DA32DA040A7D74599ABE288C7224CF0/Severity/@EntryValue">HINT</s:String>
|
||||
<s:Boolean x:Key="/Default/PatternsAndTemplates/StructuralSearch/Pattern/=37A0B37A0ABAA34AA5CB32A93653C4FE/@KeyIndexDefined">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp71</s:String></wpf:ResourceDictionary>
|
||||
</wpf:ResourceDictionary>
|
||||
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp71</s:String>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=unpublish/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=unpublishing/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
|
||||
Reference in New Issue
Block a user