diff --git a/src/Orchard.Web/Core/Common/Drivers/BodyPartDriver.cs b/src/Orchard.Web/Core/Common/Drivers/BodyPartDriver.cs index c2458a58b9e..064dee05f1e 100644 --- a/src/Orchard.Web/Core/Common/Drivers/BodyPartDriver.cs +++ b/src/Orchard.Web/Core/Common/Drivers/BodyPartDriver.cs @@ -11,6 +11,7 @@ using Orchard.Services; using System.Web.Mvc; using System.Web.Routing; +using Orchard.ContentManagement.Handlers; namespace Orchard.Core.Common.Drivers { public class BodyPartDriver : ContentPartDriver { @@ -75,6 +76,10 @@ protected override void Exporting(BodyPart part, ContentManagement.Handlers.Expo context.Element(part.PartDefinition.Name).SetAttributeValue("Text", part.Text); } + protected override void Cloning(BodyPart originalPart, BodyPart clonePart, CloneContentContext context) { + clonePart.Text = originalPart.Text; + } + private static BodyEditorViewModel BuildEditorViewModel(BodyPart part,RequestContext requestContext) { return new BodyEditorViewModel { BodyPart = part, diff --git a/src/Orchard.Web/Core/Common/Drivers/CommonPartDriver.cs b/src/Orchard.Web/Core/Common/Drivers/CommonPartDriver.cs index 28bdf78c70a..9d63bd3ed16 100644 --- a/src/Orchard.Web/Core/Common/Drivers/CommonPartDriver.cs +++ b/src/Orchard.Web/Core/Common/Drivers/CommonPartDriver.cs @@ -123,5 +123,9 @@ protected override void Exporting(CommonPart part, ExportContentContext context) .SetAttributeValue("ModifiedUtc", XmlConvert.ToString(part.ModifiedUtc.Value, XmlDateTimeSerializationMode.Utc)); } } + + protected override void Cloning(CommonPart originalPart, CommonPart clonePart, CloneContentContext context) { + clonePart.Container = originalPart.Container; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Core/Common/Drivers/TextFieldDriver.cs b/src/Orchard.Web/Core/Common/Drivers/TextFieldDriver.cs index 24b455019a9..70883427f57 100644 --- a/src/Orchard.Web/Core/Common/Drivers/TextFieldDriver.cs +++ b/src/Orchard.Web/Core/Common/Drivers/TextFieldDriver.cs @@ -89,6 +89,10 @@ protected override void Exporting(ContentPart part, TextField field, ExportConte context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Text", field.Value); } + protected override void Cloning(ContentPart part, TextField originalField, TextField cloneField, CloneContentContext context) { + cloneField.Value = originalField.Value; + } + protected override void Describe(DescribeMembersContext context) { context .Member(null, typeof(string), T("Value"), T("The text associated with the field.")) diff --git a/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs b/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs index 39d44e50cf0..82640782448 100644 --- a/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs +++ b/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs @@ -383,26 +383,24 @@ private ActionResult EditPOST(int id, string returnUrl, Action cond } [HttpPost] - public ActionResult Clone(int id, string returnUrl) { - var contentItem = _contentManager.GetLatest(id); + public ActionResult Clone(int id) { + var originalContentItem = _contentManager.GetLatest(id); - if (contentItem == null) - return HttpNotFound(); + if (!Services.Authorizer.Authorize(Permissions.ViewContent, originalContentItem, T("Couldn't open original content"))) + return new HttpUnauthorizedResult(); + + // pass a dummy content to the authorization check to check for "own" variations + var dummyContent = _contentManager.New(originalContentItem.ContentType); - if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("Couldn't clone content"))) + if (!Services.Authorizer.Authorize(Permissions.EditContent, dummyContent, T("Couldn't create clone content"))) return new HttpUnauthorizedResult(); - try { - Services.ContentManager.Clone(contentItem); - } - catch (InvalidOperationException) { - Services.Notifier.Warning(T("Could not clone the content item.")); - return this.RedirectLocal(returnUrl, () => RedirectToAction("List")); - } + var cloneContentItem = _contentManager.Clone(originalContentItem); Services.Notifier.Success(T("Successfully cloned. The clone was saved as a draft.")); - return this.RedirectLocal(returnUrl, () => RedirectToAction("List")); + var adminRouteValues = _contentManager.GetItemMetadata(cloneContentItem).AdminRouteValues; + return RedirectToRoute(adminRouteValues); } [HttpPost] diff --git a/src/Orchard.Web/Core/Contents/Views/Parts.Contents.Clone.SummaryAdmin.cshtml b/src/Orchard.Web/Core/Contents/Views/Parts.Contents.Clone.SummaryAdmin.cshtml index 1894324db8b..aa68112356a 100644 --- a/src/Orchard.Web/Core/Contents/Views/Parts.Contents.Clone.SummaryAdmin.cshtml +++ b/src/Orchard.Web/Core/Contents/Views/Parts.Contents.Clone.SummaryAdmin.cshtml @@ -1,10 +1,9 @@ @using Orchard.ContentManagement @using Orchard.Core.Contents -@using Orchard.Utility.Extensions @{ ContentPart contentPart = Model.ContentPart; } @if (Authorizer.Authorize(Permissions.EditContent, contentPart)) { - @T("Clone") + @T("Clone") @T(" | ") } \ No newline at end of file diff --git a/src/Orchard.Web/Core/Title/Drivers/TitlePartDriver.cs b/src/Orchard.Web/Core/Title/Drivers/TitlePartDriver.cs index 15147e9eed7..a30fe01a8e2 100644 --- a/src/Orchard.Web/Core/Title/Drivers/TitlePartDriver.cs +++ b/src/Orchard.Web/Core/Title/Drivers/TitlePartDriver.cs @@ -52,5 +52,9 @@ protected override void Importing(TitlePart part, ImportContentContext context) protected override void Exporting(TitlePart part, ExportContentContext context) { context.Element(part.PartDefinition.Name).SetAttributeValue("Title", part.Title); } + + protected override void Cloning(TitlePart originalPart, TitlePart clonePart, CloneContentContext context) { + clonePart.Title = originalPart.Title; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Comments/Drivers/CommentsPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Comments/Drivers/CommentsPartDriver.cs index 375ff7b48db..a59a5fb7aea 100644 --- a/src/Orchard.Web/Modules/Orchard.Comments/Drivers/CommentsPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Comments/Drivers/CommentsPartDriver.cs @@ -6,6 +6,7 @@ using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; using System.Collections.Generic; +using Orchard.ContentManagement.Handlers; namespace Orchard.Comments.Drivers { public class CommentsPartDriver : ContentPartDriver { @@ -110,7 +111,7 @@ protected override DriverResult Editor(CommentsPart part, IUpdateModel updater, return Editor(part, shapeHelper); } - protected override void Importing(CommentsPart part, ContentManagement.Handlers.ImportContentContext context) { + protected override void Importing(CommentsPart part, ImportContentContext context) { // Don't do anything if the tag is not specified. if (context.Data.Element(part.PartDefinition.Name) == null) { return; @@ -129,10 +130,16 @@ protected override void Importing(CommentsPart part, ContentManagement.Handlers. ); } - protected override void Exporting(CommentsPart part, ContentManagement.Handlers.ExportContentContext context) { + protected override void Exporting(CommentsPart part, ExportContentContext context) { context.Element(part.PartDefinition.Name).SetAttributeValue("CommentsShown", part.CommentsShown); context.Element(part.PartDefinition.Name).SetAttributeValue("CommentsActive", part.CommentsActive); context.Element(part.PartDefinition.Name).SetAttributeValue("ThreadedComments", part.ThreadedComments); } + + protected override void Cloning(CommentsPart originalPart, CommentsPart clonePart, CloneContentContext context) { + clonePart.CommentsShown = originalPart.CommentsShown; + clonePart.CommentsActive = originalPart.CommentsActive; + // ThreadedComments will be overrided with settings default + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentPickerFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentPickerFieldDriver.cs index ab2c1d60d9f..9f9b092305a 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentPickerFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentPicker/Drivers/ContentPickerFieldDriver.cs @@ -7,6 +7,7 @@ using Orchard.ContentPicker.ViewModels; using Orchard.Localization; using Orchard.Utility.Extensions; +using Orchard.ContentPicker.Fields; namespace Orchard.ContentPicker.Drivers { public class ContentPickerFieldDriver : ContentFieldDriver { @@ -98,6 +99,10 @@ protected override void Exporting(ContentPart part, Fields.ContentPickerField fi } } + protected override void Cloning(ContentPart part, ContentPickerField originalField, ContentPickerField cloneField, CloneContentContext context) { + cloneField.Ids = originalField.Ids; + } + protected override void Describe(DescribeMembersContext context) { context .Member(null, typeof(string), T("Ids"), T("A formatted list of the ids, e.g., {1},{42}")); diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/BooleanFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/BooleanFieldDriver.cs index 683e712e9e6..49a37e1f821 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/BooleanFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/BooleanFieldDriver.cs @@ -70,6 +70,10 @@ protected override void Exporting(ContentPart part, BooleanField field, ExportCo context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Value", field.Value); } + protected override void Cloning(ContentPart part, BooleanField originalField, BooleanField cloneField, CloneContentContext context) { + cloneField.Value = originalField.Value; + } + protected override void Describe(DescribeMembersContext context) { context .Member(null, typeof(Boolean), T("Value"), T("The boolean value of the field.")) diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/DateTimeFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/DateTimeFieldDriver.cs index 4626e1a4e1a..a9dba554efc 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/DateTimeFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/DateTimeFieldDriver.cs @@ -186,6 +186,10 @@ protected override void Exporting(ContentPart part, DateTimeField field, ExportC context.Element(GetPrefix(field, part)).SetAttributeValue("Value", XmlConvert.ToString(value, XmlDateTimeSerializationMode.Utc)); } + protected override void Cloning(ContentPart part, DateTimeField originalField, DateTimeField cloneField, CloneContentContext context) { + cloneField.DateTime = originalField.DateTime; + } + protected override void Describe(DescribeMembersContext context) { context .Member(null, typeof(DateTime), T("Value"), T("The date and time value of the field.")) diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/EnumerationFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/EnumerationFieldDriver.cs index 46082bf7ab4..56a8e856266 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/EnumerationFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/EnumerationFieldDriver.cs @@ -80,6 +80,10 @@ protected override void Exporting(ContentPart part, EnumerationField field, Expo context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Value", field.Value); } + protected override void Cloning(ContentPart part, EnumerationField originalField, EnumerationField cloneField, CloneContentContext context) { + cloneField.Value = originalField.Value; + } + protected override void Describe(DescribeMembersContext context) { context .Member(null, typeof(string), T("Value"), T("The selected values of the field.")) diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/InputFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/InputFieldDriver.cs index b56fdc79da2..55ad803ecae 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/InputFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/InputFieldDriver.cs @@ -67,6 +67,10 @@ protected override void Exporting(ContentPart part, InputField field, ExportCont context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Value", field.Value); } + protected override void Cloning(ContentPart part, InputField originalField, InputField cloneField, CloneContentContext context) { + cloneField.Value = originalField.Value; + } + protected override void Describe(DescribeMembersContext context) { context .Member(null, typeof(string), T("Value"), T("The value of the field.")) diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/LinkFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/LinkFieldDriver.cs index 0cf563921b2..dcba6971ec3 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/LinkFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/LinkFieldDriver.cs @@ -82,6 +82,12 @@ protected override void Exporting(ContentPart part, LinkField field, ExportConte } } + protected override void Cloning(ContentPart part, LinkField originalField, LinkField cloneField, CloneContentContext context) { + cloneField.Text = originalField.Text; + cloneField.Value = originalField.Value; + cloneField.Target = originalField.Target; + } + protected override void Describe(DescribeMembersContext context) { context .Member("Text", typeof(string), T("Text"), T("The text of the link.")) diff --git a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/NumericFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/NumericFieldDriver.cs index 22d1dbeef11..1214081ab20 100644 --- a/src/Orchard.Web/Modules/Orchard.Fields/Drivers/NumericFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Fields/Drivers/NumericFieldDriver.cs @@ -114,6 +114,10 @@ protected override void Exporting(ContentPart part, NumericField field, ExportCo context.Element(field.FieldDefinition.Name + "." + field.Name).SetAttributeValue("Value", field.Value.Value.ToString(CultureInfo.InvariantCulture)); } + protected override void Cloning(ContentPart part, NumericField originalField, NumericField cloneField, CloneContentContext context) { + cloneField.Value = originalField.Value; + } + protected override void Describe(DescribeMembersContext context) { context .Member(null, typeof(decimal), T("Value"), T("The value of the field.")) diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/LayoutPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/LayoutPartDriver.cs index 37c7a7375e4..ee09915c68f 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/LayoutPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/LayoutPartDriver.cs @@ -213,5 +213,10 @@ private string ReadFormattedLayoutData(string formattedLayoutData) var layoutDataString = JsonConvert.SerializeObject(layoutData, Formatting.None); return layoutDataString; } + + protected override void Cloning(LayoutPart originalPart, LayoutPart clonePart, CloneContentContext context) { + clonePart.LayoutData = originalPart.LayoutData; + clonePart.TemplateId = originalPart.TemplateId; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Localization/Controllers/AdminController.cs index 52aa00a3a23..627d1314dbe 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Localization/Controllers/AdminController.cs @@ -1,28 +1,29 @@ -using System; -using System.Web.Mvc; -using Orchard.ContentManagement; -using Orchard.ContentManagement.Aspects; -using Orchard.Core.Contents.Settings; +using Orchard.ContentManagement; +using Orchard.Core.Contents; using Orchard.DisplayManagement; using Orchard.Localization.Models; using Orchard.Localization.Services; -using Orchard.Localization.ViewModels; -using Orchard.Mvc; using Orchard.UI.Notify; +using System; +using System.Web.Mvc; -namespace Orchard.Localization.Controllers { +namespace Orchard.Localization.Controllers +{ [ValidateInput(false)] - public class AdminController : Controller, IUpdateModel { + public class AdminController : Controller { private readonly IContentManager _contentManager; private readonly ILocalizationService _localizationService; + private readonly ICultureManager _cultureManager; public AdminController( IOrchardServices orchardServices, IContentManager contentManager, ILocalizationService localizationService, + ICultureManager cultureManager, IShapeFactory shapeFactory) { _contentManager = contentManager; _localizationService = localizationService; + _cultureManager = cultureManager; T = NullLocalizer.Instance; Services = orchardServices; Shape = shapeFactory; @@ -32,16 +33,20 @@ public AdminController( public Localizer T { get; set; } public IOrchardServices Services { get; set; } + [HttpPost] public ActionResult Translate(int id, string to) { var masterContentItem = _contentManager.Get(id, VersionOptions.Latest); if (masterContentItem == null) return HttpNotFound(); + if (!Services.Authorizer.Authorize(Permissions.ViewContent, masterContentItem, T("Couldn't open original content"))) + return new HttpUnauthorizedResult(); + var masterLocalizationPart = masterContentItem.As(); if (masterLocalizationPart == null) return HttpNotFound(); - // Check is current item stll exists, and redirect. + // Check if current item still exists, and redirect. var existingTranslation = _localizationService.GetLocalizedContentItem(masterContentItem, to); if (existingTranslation != null) { var existingTranslationMetadata = _contentManager.GetItemMetadata(existingTranslation); @@ -50,76 +55,24 @@ public ActionResult Translate(int id, string to) { existingTranslationMetadata.EditorRouteValues); } - var contentItemTranslation = _contentManager.New(masterContentItem.ContentType); - contentItemTranslation.MasterContentItem = masterContentItem; - - var content = _contentManager.BuildEditor(contentItemTranslation); - - return View(content); - } - - [HttpPost, ActionName("Translate")] - [FormValueRequired("submit.Save")] - public ActionResult TranslatePOST(int id) { - return TranslatePOST(id, contentItem => { - if (!contentItem.Has() && !contentItem.TypeDefinition.Settings.GetModel().Draftable) - Services.ContentManager.Publish(contentItem); - }); - } - - [HttpPost, ActionName("Translate")] - [FormValueRequired("submit.Publish")] - public ActionResult TranslateAndPublishPOST(int id) { - return TranslatePOST(id, contentItem => Services.ContentManager.Publish(contentItem)); - } - - public ActionResult TranslatePOST(int id, Action conditionallyPublish) { - var masterContentItem = _contentManager.Get(id, VersionOptions.Latest); - if (masterContentItem == null) - return HttpNotFound(); - - var masterLocalizationPart = masterContentItem.As(); - if (masterLocalizationPart == null) - return HttpNotFound(); - - var model = new EditLocalizationViewModel(); - TryUpdateModel(model, "Localization"); - - var existingTranslation = _localizationService.GetLocalizedContentItem(masterContentItem, model.SelectedCulture); - if (existingTranslation != null) { - var existingTranslationMetadata = _contentManager.GetItemMetadata(existingTranslation); - return RedirectToAction( - Convert.ToString(existingTranslationMetadata.EditorRouteValues["action"]), - existingTranslationMetadata.EditorRouteValues); - } - - var contentItemTranslation = _contentManager - .Create(masterContentItem.ContentType, VersionOptions.Draft, part => { - part.MasterContentItem = masterContentItem; - }); + // pass a dummy content to the authorization check to check for "own" variations + var dummyContent = _contentManager.New(masterContentItem.ContentType); - var content = _contentManager.UpdateEditor(contentItemTranslation, this); + var contentItemTranslation = _contentManager.Clone(masterContentItem); - if (!ModelState.IsValid) { - Services.TransactionManager.Cancel(); + if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItemTranslation, T("Couldn't create translated content"))) + return new HttpUnauthorizedResult(); - return View(content); + var localizationPart = contentItemTranslation.As(); + if(localizationPart != null) { + localizationPart.MasterContentItem = masterContentItem; + localizationPart.Culture = string.IsNullOrWhiteSpace(to) ? null : _cultureManager.GetCultureByName(to); } - conditionallyPublish(contentItemTranslation.ContentItem); - - Services.Notifier.Success(T("Created content item translation.")); - - var metadata = _contentManager.GetItemMetadata(contentItemTranslation); - return RedirectToAction(Convert.ToString(metadata.EditorRouteValues["action"]), metadata.EditorRouteValues); - } - - bool IUpdateModel.TryUpdateModel(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) { - return TryUpdateModel(model, prefix, includeProperties, excludeProperties); - } + Services.Notifier.Success(T("Successfully cloned. The translated content was saved as a draft.")); - void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) { - ModelState.AddModelError(key, errorMessage.ToString()); + var adminRouteValues = _contentManager.GetItemMetadata(contentItemTranslation).AdminRouteValues; + return RedirectToRoute(adminRouteValues); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Drivers/LocalizationPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Localization/Drivers/LocalizationPartDriver.cs index 7709ea93dde..7e8c4e56af2 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Drivers/LocalizationPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Localization/Drivers/LocalizationPartDriver.cs @@ -2,6 +2,7 @@ using System.Linq; using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; +using Orchard.ContentManagement.Handlers; using Orchard.Localization.Models; using Orchard.Localization.Services; using Orchard.Localization.ViewModels; @@ -89,25 +90,23 @@ private static string GetCulture(LocalizationPart part) { private IEnumerable GetDisplayLocalizations(LocalizationPart part, VersionOptions versionOptions) { return _localizationService.GetLocalizations(part.ContentItem, versionOptions) + .Where(c => c.Culture != null) .Select(c => { var localized = c.ContentItem.As(); - if (localized.Culture == null) - localized.Culture = _cultureManager.GetCultureByName(_cultureManager.GetSiteCulture()); return c; }).ToList(); } private IEnumerable GetEditorLocalizations(LocalizationPart part) { return _localizationService.GetLocalizations(part.ContentItem, VersionOptions.Latest) + .Where(c => c.Culture != null) .Select(c => { var localized = c.ContentItem.As(); - if (localized.Culture == null) - localized.Culture = _cultureManager.GetCultureByName(_cultureManager.GetSiteCulture()); return c; }).ToList(); } - protected override void Importing(LocalizationPart part, ContentManagement.Handlers.ImportContentContext context) { + protected override void Importing(LocalizationPart part, ImportContentContext context) { // Don't do anything if the tag is not specified. if (context.Data.Element(part.PartDefinition.Name) == null) { return; @@ -131,7 +130,7 @@ protected override void Importing(LocalizationPart part, ContentManagement.Handl }); } - protected override void Exporting(LocalizationPart part, ContentManagement.Handlers.ExportContentContext context) { + protected override void Exporting(LocalizationPart part, ExportContentContext context) { if (part.MasterContentItem != null) { var masterContentItemIdentity = _contentManager.GetItemMetadata(part.MasterContentItem).Identity; context.Element(part.PartDefinition.Name).SetAttributeValue("MasterContentItem", masterContentItemIdentity.ToString()); @@ -141,5 +140,9 @@ protected override void Exporting(LocalizationPart part, ContentManagement.Handl context.Element(part.PartDefinition.Name).SetAttributeValue("Culture", part.Culture.Culture); } } + + protected override void Cloned(LocalizationPart originalPart, LocalizationPart clonePart, CloneContentContext context) { + clonePart.Culture = originalPart.Culture; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs index bd4baa7651f..67293758bd1 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Localization/Handlers/LocalizationPartHandler.cs @@ -31,7 +31,7 @@ public LocalizationPartHandler(IRepository localizedRepo protected static void PropertySetHandlers(ActivatedContentContext context, LocalizationPart localizationPart) { localizationPart.CultureField.Setter(cultureRecord => { - localizationPart.Record.CultureId = cultureRecord.Id; + localizationPart.Record.CultureId = cultureRecord != null ? cultureRecord.Id : 0; return cultureRecord; }); diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Orchard.Localization.csproj b/src/Orchard.Web/Modules/Orchard.Localization/Orchard.Localization.csproj index 9740059d7a3..dd0cd4c08bc 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Orchard.Localization.csproj +++ b/src/Orchard.Web/Modules/Orchard.Localization/Orchard.Localization.csproj @@ -135,9 +135,6 @@ Designer - - - diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Views/Admin/Translate.cshtml b/src/Orchard.Web/Modules/Orchard.Localization/Views/Admin/Translate.cshtml deleted file mode 100644 index 6728076c5f8..00000000000 --- a/src/Orchard.Web/Modules/Orchard.Localization/Views/Admin/Translate.cshtml +++ /dev/null @@ -1,8 +0,0 @@ -@{ - Layout.Title = T("Translate Content").ToString(); -} - -@using (Html.BeginFormAntiForgeryPost()) { - @Html.ValidationSummary() - @Display(Model) -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Views/EditorTemplates/Parts/Localization.ContentTranslations.Edit.cshtml b/src/Orchard.Web/Modules/Orchard.Localization/Views/EditorTemplates/Parts/Localization.ContentTranslations.Edit.cshtml index f7927c3d105..3f5e0ccb7ff 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Views/EditorTemplates/Parts/Localization.ContentTranslations.Edit.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Localization/Views/EditorTemplates/Parts/Localization.ContentTranslations.Edit.cshtml @@ -6,59 +6,61 @@
- @*Brand new content item*@ - @if (Model.ContentItem.ContentItem.Id == 0) { - if (Model.MasterContentItem == null) { - @T("This is the {0} variation of the content", - BuildSelectedCultureList( - Html.FieldIdFor(m => m.SelectedCulture), - Html.FieldNameFor(m => m.SelectedCulture), - Model.MissingCultures, - Model.SelectedCulture)) + @if (!string.IsNullOrEmpty(Model.SelectedCulture)) + { + @T("This is the {0} variation of the content", + Html.Encode(Model.SelectedCulture)) + + if (Model.ContentLocalizations.Localizations.Any()) + { +
+
@T("Other translations:")
+
+ @Html.UnorderedList(Model.ContentLocalizations.Localizations, (c, i) => + Html.ItemEditLink(c.Culture.Culture, c), "localizations") +
+
} - else { - @T("This is the {0} variation of {1}", + + if (Model.MissingCultures.Any()) + { + var contentItemId = Model.MasterContentItem != null ? Model.MasterContentItem.Id : Model.ContentItem.Id; + +
@Html.ActionLink(T("+ New translation").Text, "Translate", "Admin", new { area = "Orchard.Localization", id = contentItemId }, new { itemprop = "UnsafeUrl" })
+ } + + @Html.Hidden(Html.FieldNameFor(m => m.SelectedCulture), Model.SelectedCulture) + } + else if (Model.MasterContentItem != null) + { + @T("This is the {0} variation of {1}", BuildSelectedCultureList( Html.FieldIdFor(m => m.SelectedCulture), Html.FieldNameFor(m => m.SelectedCulture), Model.MissingCultures, Model.SelectedCulture), Html.ItemEditLink(Model.MasterContentItem)) - } - } - @if (Model.ContentItem.ContentItem.Id > 0) { - if (string.IsNullOrEmpty(Model.SelectedCulture)) { - @T("This content currently has no culture associated to it, please select a culture to associate to this piece of content: {0}", - BuildSelectedCultureList( - Html.FieldIdFor(m => m.SelectedCulture), - Html.FieldNameFor(m => m.SelectedCulture), - Model.MissingCultures, - Model.SelectedCulture)) - } - else { - @T("This is the {0} variation of the content", - Html.Encode(Model.SelectedCulture)) - - if (Model.ContentLocalizations.Localizations.Any()) { -
-
@T("Other translations:")
-
- @Html.UnorderedList(Model.ContentLocalizations.Localizations, (c, i) => - Html.ItemEditLink(c.Culture.Culture, c), "localizations") -
-
- } - - if (Model.MissingCultures.Any()) { - var contentItemId = Model.MasterContentItem != null ? Model.MasterContentItem.Id : Model.ContentItem.Id; - -
@Html.ActionLink(T("+ New translation").Text, "Translate", "Admin", new {area = "Orchard.Localization", id = contentItemId}, null)
- } - - @Html.Hidden(Html.FieldNameFor(m => m.SelectedCulture), Model.SelectedCulture) + if (Model.ContentLocalizations.Localizations.Any()) + { +
+
@T("Other translations:")
+
+ @Html.UnorderedList(Model.ContentLocalizations.Localizations, (c, i) => + Html.ItemEditLink(c.Culture.Culture, c), "localizations") +
+
} } + else + { + @T("This is the {0} variation of the content", + BuildSelectedCultureList( + Html.FieldIdFor(m => m.SelectedCulture), + Html.FieldNameFor(m => m.SelectedCulture), + Model.MissingCultures, + Model.SelectedCulture)) + }
diff --git a/src/Orchard.Web/Modules/Orchard.Localization/Views/Parts/Localization.ContentTranslations.SummaryAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.Localization/Views/Parts/Localization.ContentTranslations.SummaryAdmin.cshtml index 6137c66eba2..5195066f893 100644 --- a/src/Orchard.Web/Modules/Orchard.Localization/Views/Parts/Localization.ContentTranslations.SummaryAdmin.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Localization/Views/Parts/Localization.ContentTranslations.SummaryAdmin.cshtml @@ -16,7 +16,7 @@ var localizationLinks = Html.UnorderedList(localizations, (c, i) => Html.ItemEdi } @if (Model.Culture != null && !((IEnumerable)Model.SiteCultures).All(c => c == Model.Culture || localizations.Any(l => c == l.Culture.Culture))) { -
@Html.ActionLink(T("+ New translation").Text, "Translate", "Admin", new { area = "Orchard.Localization", id = Model.Id }, null)
+
@Html.ActionLink(T("+ New translation").Text, "Translate", "Admin", new { area = "Orchard.Localization", id = Model.Id }, new { itemprop = "UnsafeUrl" })
} } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryPickerFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryPickerFieldDriver.cs index 1d7baa065ff..f2d049bd8c5 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryPickerFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Drivers/MediaLibraryPickerFieldDriver.cs @@ -7,6 +7,7 @@ using Orchard.MediaLibrary.ViewModels; using Orchard.Localization; using Orchard.Utility.Extensions; +using Orchard.MediaLibrary.Fields; namespace Orchard.MediaLibrary.Drivers { public class MediaLibraryPickerFieldDriver : ContentFieldDriver { @@ -95,6 +96,10 @@ protected override void Exporting(ContentPart part, Fields.MediaLibraryPickerFie } } + protected override void Cloning(ContentPart part, MediaLibraryPickerField originalField, MediaLibraryPickerField cloneField, CloneContentContext context) { + cloneField.Ids = originalField.Ids; + } + protected override void Describe(DescribeMembersContext context) { context .Member(null, typeof(string), T("Ids"), T("A formatted list of the ids, e.g., {1},{42}")); diff --git a/src/Orchard.Web/Modules/Orchard.Projections/Drivers/ProjectionPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Projections/Drivers/ProjectionPartDriver.cs index 42d618f6028..91f7ef17487 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/Drivers/ProjectionPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/Drivers/ProjectionPartDriver.cs @@ -341,6 +341,17 @@ protected override void Exporting(ProjectionPart part, ExportContentContext cont } } + protected override void Cloning(ProjectionPart originalPart, ProjectionPart clonePart, CloneContentContext context) { + clonePart.Record.Items = originalPart.Record.Items; + clonePart.Record.ItemsPerPage = originalPart.Record.ItemsPerPage; + clonePart.Record.Skip = originalPart.Record.Skip; + clonePart.Record.PagerSuffix = originalPart.Record.PagerSuffix; + clonePart.Record.MaxItems = originalPart.Record.MaxItems; + clonePart.Record.DisplayPager = originalPart.Record.DisplayPager; + clonePart.Record.QueryPartRecord = originalPart.Record.QueryPartRecord; + clonePart.Record.LayoutRecord = originalPart.Record.LayoutRecord; + } + private class ViewDataContainer : IViewDataContainer { public ViewDataDictionary ViewData { get; set; } } diff --git a/src/Orchard.Web/Modules/Orchard.Tags/Drivers/TagsPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Tags/Drivers/TagsPartDriver.cs index 803e39e0617..ad5681c2745 100644 --- a/src/Orchard.Web/Modules/Orchard.Tags/Drivers/TagsPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Tags/Drivers/TagsPartDriver.cs @@ -89,5 +89,9 @@ protected override void Importing(TagsPart part, ImportContentContext context) { protected override void Exporting(TagsPart part, ExportContentContext context) { context.Element(part.PartDefinition.Name).SetAttributeValue("Tags", String.Join(",", part.CurrentTags)); } + + protected override void Cloning(TagsPart originalPart, TagsPart clonePart, CloneContentContext context) { + clonePart.CurrentTags = originalPart.CurrentTags; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Taxonomies/Drivers/TaxonomyFieldDriver.cs b/src/Orchard.Web/Modules/Orchard.Taxonomies/Drivers/TaxonomyFieldDriver.cs index 00021c08400..1a391a42b78 100644 --- a/src/Orchard.Web/Modules/Orchard.Taxonomies/Drivers/TaxonomyFieldDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Taxonomies/Drivers/TaxonomyFieldDriver.cs @@ -141,6 +141,10 @@ protected override void Importing(ContentPart part, TaxonomyField field, ImportC _taxonomyService.UpdateTerms(part.ContentItem, terms.Select(x => x.As()), field.Name); } + protected override void Cloning(ContentPart part, TaxonomyField originalField, TaxonomyField cloneField, CloneContentContext context) { + _taxonomyService.UpdateTerms(context.CloneContentItem, originalField.Terms, cloneField.Name); + } + private TermPart GetOrCreateTerm(TermEntry entry, int taxonomyId, TaxonomyField field) { var term = default(TermPart); diff --git a/src/Orchard/ContentManagement/DefaultContentManager.cs b/src/Orchard/ContentManagement/DefaultContentManager.cs index fe708846e20..b1a42955a6f 100644 --- a/src/Orchard/ContentManagement/DefaultContentManager.cs +++ b/src/Orchard/ContentManagement/DefaultContentManager.cs @@ -562,26 +562,19 @@ public virtual void Create(ContentItem contentItem, VersionOptions options) { } public virtual ContentItem Clone(ContentItem contentItem) { - // Mostly taken from: http://orchard.codeplex.com/discussions/396664 - var element = Export(contentItem); + var cloneContentItem = New(contentItem.ContentType); + Create(cloneContentItem, VersionOptions.Draft); - // If a handler prevents this element from being exported, it can't be cloned. - if (element == null) { - throw new InvalidOperationException("The content item couldn't be cloned because a handler prevented it from being exported."); + var context = new CloneContentContext(contentItem, cloneContentItem); + foreach (var contentHandler in Handlers) { + contentHandler.Cloning(context); } - var elementId = element.Attribute("Id"); - var copyId = elementId.Value + "-copy"; - elementId.SetValue(copyId); - var status = element.Attribute("Status"); - if (status != null) status.SetValue("Draft"); // So the copy is always a draft. - - var importContentSession = new ImportContentSession(this); - importContentSession.Set(copyId, element.Name.LocalName); - Import(element, importContentSession); - CompleteImport(element, importContentSession); + foreach (var contentHandler in Handlers) { + contentHandler.Cloned(context); + } - return importContentSession.Get(copyId, element.Name.LocalName); + return cloneContentItem; } public virtual ContentItem Restore(ContentItem contentItem, VersionOptions options) { diff --git a/src/Orchard/ContentManagement/Drivers/ContentFieldDriver.cs b/src/Orchard/ContentManagement/Drivers/ContentFieldDriver.cs index 5a10c4aa9ae..9e70cc6fc29 100644 --- a/src/Orchard/ContentManagement/Drivers/ContentFieldDriver.cs +++ b/src/Orchard/ContentManagement/Drivers/ContentFieldDriver.cs @@ -84,6 +84,14 @@ void IContentFieldDriver.Exported(ExportContentContext context) { Process(context.ContentItem, (part, field) => Exported(part, field, context), context.Logger); } + void IContentFieldDriver.Cloning(CloneContentContext context) { + ProcessClone(context.ContentItem, context.CloneContentItem, (part, originalField, cloneField) => Cloning(part, originalField, cloneField, context), context.Logger); + } + + void IContentFieldDriver.Cloned(CloneContentContext context) { + ProcessClone(context.ContentItem, context.CloneContentItem, (part, originalField, cloneField) => Cloned(part, originalField, cloneField, context), context.Logger); + } + void IContentFieldDriver.Describe(DescribeMembersContext context) { Describe(context); } @@ -93,6 +101,12 @@ void Process(ContentItem item, Action effort, ILogger logge occurences.Invoke(pf => effort(pf.part, pf.field), logger); } + void ProcessClone(ContentItem originalItem, ContentItem cloneItem, Action effort, ILogger logger) { + var occurences = originalItem.Parts.SelectMany(part => part.Fields.OfType().Select(field => new { part, field })) + .Join(cloneItem.Parts.SelectMany(part => part.Fields.OfType()), original => original.field.Name, cloneField => cloneField.Name, (original, cloneField) => new { original, cloneField } ); + occurences.Invoke(pf => effort(pf.original.part, pf.original.field, pf.cloneField), logger); + } + DriverResult Process(ContentItem item, Func effort, ILogger logger) { var results = item.Parts .SelectMany(part => part.Fields.OfType().Select(field => new { part, field })) @@ -126,6 +140,8 @@ protected virtual void Imported(ContentPart part, TField field, ImportContentCon protected virtual void ImportCompleted(ContentPart part, TField field, ImportContentContext context) { } protected virtual void Exporting(ContentPart part, TField field, ExportContentContext context) { } protected virtual void Exported(ContentPart part, TField field, ExportContentContext context) { } + protected virtual void Cloning(ContentPart part, TField originalField, TField cloneField, CloneContentContext context) { } + protected virtual void Cloned(ContentPart part, TField originalField, TField cloneField, CloneContentContext context) { } protected virtual void Describe(DescribeMembersContext context) { } diff --git a/src/Orchard/ContentManagement/Drivers/ContentPartDriver.cs b/src/Orchard/ContentManagement/Drivers/ContentPartDriver.cs index 9ffe65b7220..d05328607a0 100644 --- a/src/Orchard/ContentManagement/Drivers/ContentPartDriver.cs +++ b/src/Orchard/ContentManagement/Drivers/ContentPartDriver.cs @@ -106,6 +106,20 @@ void IContentPartDriver.Exported(ExportContentContext context) { Exported(part, context); } + void IContentPartDriver.Cloning(CloneContentContext context) { + var originalPart = context.ContentItem.As(); + var clonePart = context.CloneContentItem.As(); + if (originalPart != null && clonePart != null) + Cloning(originalPart, clonePart, context); + } + + void IContentPartDriver.Cloned(CloneContentContext context) { + var originalPart = context.ContentItem.As(); + var clonePart = context.CloneContentItem.As(); + if (originalPart != null && clonePart != null) + Cloned(originalPart, clonePart, context); + } + protected virtual void GetContentItemMetadata(TContent context, ContentItemMetadata metadata) { } protected virtual DriverResult Display(TContent part, string displayType, dynamic shapeHelper) { return null; } @@ -174,6 +188,10 @@ private static string GetInfosetXmlElementName(TContent part, bool versioned) { return part.PartDefinition.Name + "-" + (versioned ? "VersionInfoset" : "Infoset"); } + protected virtual void Cloning(TContent originalPart, TContent clonePart, CloneContentContext context) { } + + protected virtual void Cloned(TContent originalPart, TContent clonePart, CloneContentContext context) { } + [Obsolete("Provided while transitioning to factory variations")] public ContentShapeResult ContentShape(IShape shape) { return ContentShapeImplementation(shape.Metadata.Type, ctx => shape).Location("Content"); @@ -237,6 +255,5 @@ public IEnumerable GetPartInfo() { return contentPartInfo; } - } } \ No newline at end of file diff --git a/src/Orchard/ContentManagement/Drivers/Coordinators/ContentFieldDriverCoordinator.cs b/src/Orchard/ContentManagement/Drivers/Coordinators/ContentFieldDriverCoordinator.cs index c38b119595c..ba7e3eba99e 100644 --- a/src/Orchard/ContentManagement/Drivers/Coordinators/ContentFieldDriverCoordinator.cs +++ b/src/Orchard/ContentManagement/Drivers/Coordinators/ContentFieldDriverCoordinator.cs @@ -109,5 +109,19 @@ public override void Exported(ExportContentContext context) { contentFieldDriver.Exported(context); } } + + public override void Cloning(CloneContentContext context) { + context.Logger = Logger; + foreach (var contentFieldDriver in _drivers) { + contentFieldDriver.Cloning(context); + } + } + + public override void Cloned(CloneContentContext context) { + context.Logger = Logger; + foreach (var contentFieldDriver in _drivers) { + contentFieldDriver.Cloned(context); + } + } } } \ No newline at end of file diff --git a/src/Orchard/ContentManagement/Drivers/Coordinators/ContentPartDriverCoordinator.cs b/src/Orchard/ContentManagement/Drivers/Coordinators/ContentPartDriverCoordinator.cs index 63bdc4ae088..10efd58ee82 100644 --- a/src/Orchard/ContentManagement/Drivers/Coordinators/ContentPartDriverCoordinator.cs +++ b/src/Orchard/ContentManagement/Drivers/Coordinators/ContentPartDriverCoordinator.cs @@ -95,5 +95,17 @@ public override void Exported(ExportContentContext context) { contentPartDriver.Exported(context); } } + + public override void Cloning(CloneContentContext context) { + foreach (var contentPartDriver in _drivers) { + contentPartDriver.Cloning(context); + } + } + + public override void Cloned(CloneContentContext context) { + foreach (var contentPartDriver in _drivers) { + contentPartDriver.Cloned(context); + } + } } } \ No newline at end of file diff --git a/src/Orchard/ContentManagement/Drivers/IContentFieldDriver.cs b/src/Orchard/ContentManagement/Drivers/IContentFieldDriver.cs index a1b41e9e968..ff144ce3396 100644 --- a/src/Orchard/ContentManagement/Drivers/IContentFieldDriver.cs +++ b/src/Orchard/ContentManagement/Drivers/IContentFieldDriver.cs @@ -12,6 +12,8 @@ public interface IContentFieldDriver : IDependency { void ImportCompleted(ImportContentContext context); void Exporting(ExportContentContext context); void Exported(ExportContentContext context); + void Cloning(CloneContentContext context); + void Cloned(CloneContentContext context); void Describe(DescribeMembersContext context); IEnumerable GetFieldInfo(); void GetContentItemMetadata(GetContentItemMetadataContext context); diff --git a/src/Orchard/ContentManagement/Drivers/IContentPartDriver.cs b/src/Orchard/ContentManagement/Drivers/IContentPartDriver.cs index 531e36c4874..663aa553a13 100644 --- a/src/Orchard/ContentManagement/Drivers/IContentPartDriver.cs +++ b/src/Orchard/ContentManagement/Drivers/IContentPartDriver.cs @@ -12,6 +12,8 @@ public interface IContentPartDriver : IDependency { void ImportCompleted(ImportContentContext context); void Exporting(ExportContentContext context); void Exported(ExportContentContext context); + void Cloning(CloneContentContext context); + void Cloned(CloneContentContext context); IEnumerable GetPartInfo(); void GetContentItemMetadata(GetContentItemMetadataContext context); } diff --git a/src/Orchard/ContentManagement/Handlers/CloneContentContext.cs b/src/Orchard/ContentManagement/Handlers/CloneContentContext.cs index e449f946924..e0603ad8c0e 100644 --- a/src/Orchard/ContentManagement/Handlers/CloneContentContext.cs +++ b/src/Orchard/ContentManagement/Handlers/CloneContentContext.cs @@ -1,6 +1,9 @@ -namespace Orchard.ContentManagement.Handlers { +namespace Orchard.ContentManagement.Handlers { public class CloneContentContext : ContentContextBase { - public CloneContentContext(ContentItem contentItem) : base(contentItem) { + public ContentItem CloneContentItem { get; set; } + public CloneContentContext(ContentItem contentItem, ContentItem cloneContentItem) + :base(contentItem) { + CloneContentItem = cloneContentItem; } } }