--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-07-16 19:30:56 -07:00
43 changed files with 512 additions and 100 deletions

View File

@@ -33,7 +33,8 @@ namespace Orchard.Tests.ContentManagement {
typeof(ContentItemVersionRecord),
typeof(GammaRecord),
typeof(DeltaRecord),
typeof(EpsilonRecord));
typeof(EpsilonRecord),
typeof(MegaRecord));
}
[TestFixtureTearDown]
@@ -172,6 +173,23 @@ namespace Orchard.Tests.ContentManagement {
Assert.That(types, Has.Some.With.Property("Name").EqualTo("delta"));
}
[Test]
public void BigStringsShouldNotBeTruncated() {
var megaRepository = _container.Resolve<IRepository<MegaRecord>>();
var mega = new MegaRecord() { BigStuff = new string('x', 20000) };
megaRepository.Create(mega);
_session.Flush();
}
[Test, ExpectedException]
public void StandardStringsShouldNotHaveAStandardSize() {
var megaRepository = _container.Resolve<IRepository<MegaRecord>>();
var mega = new MegaRecord() { SmallStuff = new string('x', 256) };
megaRepository.Create(mega);
_session.Flush();
}
private ContentItemRecord CreateModelRecord(string contentType) {
var contentTypeRepository = _container.Resolve<IRepository<ContentTypeRecord>>();
var contentItemRepository = _container.Resolve<IRepository<ContentItemRecord>>();

View File

@@ -0,0 +1,13 @@
using Orchard.ContentManagement.Records;
using Orchard.Data.Conventions;
namespace Orchard.Tests.ContentManagement.Records {
public class MegaRecord {
public virtual int Id { get; set; }
[StringLengthMax]
public virtual string BigStuff { get; set; }
public virtual string SmallStuff { get; set; }
}
}

View File

@@ -165,7 +165,7 @@ features:
interpreter.Visit(bodyRecord);
Assert.That(sw.ToString().Contains("SchemaBuilder.CreateTable(\"TEST_BodyRecord"));
Assert.That(sw.ToString().Contains(".ContentPartVersionRecord()"));
Assert.That(sw.ToString().Contains(".Column(\"Text\", DbType.String, column => column.WithLength(10000))"));
Assert.That(sw.ToString().Contains(".Column(\"Text\", DbType.String, column => column.Unlimited())"));
Assert.That(sw.ToString().Contains(".Column(\"Format\", DbType.String, column => column.WithLength(42))"));
Assert.That(!sw.ToString().Contains("ContentItemRecord_id"));
}

View File

@@ -172,6 +172,7 @@
<Compile Include="ContentManagement\Handlers\Coordinators\ContentPartDriverCoordinatorTests.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="ContentManagement\Records\MegaRecord.cs" />
<Compile Include="ContentManagement\Records\DeltaRecord.cs">
<SubType>Code</SubType>
</Compile>

View File

@@ -7,7 +7,7 @@ namespace Orchard.Core.Common.DataMigrations {
//CREATE TABLE Common_BodyRecord (Id INTEGER not null, Text TEXT, Format TEXT, ContentItemRecord_id INTEGER, primary key (Id));
SchemaBuilder.CreateTable("BodyRecord", table => table
.ContentPartVersionRecord()
.Column<string>("Text", column => column.WithLength(10000))
.Column<string>("Text", column => column.Unlimited())
.Column<string>("Format")
);

View File

@@ -35,10 +35,7 @@ namespace Orchard.Core.Common.Drivers {
public IOrchardServices Services { get; set; }
protected override DriverResult Display(CommonAspect part, string displayType) {
var model = new CommonMetadataViewModel(part);
return Combined(
ContentPartTemplate(model, "Parts/Common.Metadata").LongestMatch(displayType, "Summary", "SummaryAdmin").Location("metadata", "5"),
ContentPartTemplate(model, "Parts/Common.Publish").LongestMatch(displayType, "Summary", "SummaryAdmin").Location("secondary"));
return ContentPartTemplate(new CommonMetadataViewModel(part), "Parts/Common.Metadata").LongestMatch(displayType, "Summary", "SummaryAdmin").Location("metadata", "5");
}
protected override DriverResult Editor(CommonAspect part) {

View File

@@ -1,5 +1,6 @@
using System.Web.Mvc;
using Orchard.Core.Common.ViewModels;
using Orchard.Core.Contents.ViewModels;
using Orchard.Localization;
using Orchard.Mvc.Html;

View File

@@ -1,5 +1,4 @@
using System;
using Orchard.ContentManagement;
using Orchard.Core.Common.Models;
using Orchard.Security;
@@ -12,7 +11,6 @@ namespace Orchard.Core.Common.ViewModels {
}
public IUser Creator { get { return _commonAspect.Owner; } }
public ContentItem ContentItem { get { return _commonAspect.ContentItem; } }
public DateTime? CreatedUtc { get { return _commonAspect.CreatedUtc; } }
public DateTime? PublishedUtc { get { return _commonAspect.PublishedUtc; } }
@@ -21,22 +19,5 @@ namespace Orchard.Core.Common.ViewModels {
public DateTime? VersionCreatedUtc { get { return _commonAspect.VersionCreatedUtc; } }
public DateTime? VersionPublishedUtc { get { return _commonAspect.VersionPublishedUtc; } }
public DateTime? VersionModifiedUtc { get { return _commonAspect.VersionModifiedUtc; } }
public bool IsPublished {
get { return ContentItem.VersionRecord != null && ContentItem.VersionRecord.Published; }
}
public bool HasDraft {
get {
return (
(ContentItem.VersionRecord != null)
&& ((ContentItem.VersionRecord.Published == false)
|| (ContentItem.VersionRecord.Published && ContentItem.VersionRecord.Latest == false)));
}
}
public bool HasPublished {
get { return IsPublished || ContentItem.ContentManager.Get(ContentItem.Id, VersionOptions.Published) != null; }
}
}
}

View File

@@ -1,12 +0,0 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.Core.Common.ViewModels.CommonMetadataViewModel>" %>
<% // todo: make this all work
if (Model.HasPublished) { %>
<%:Html.ItemDisplayLink(T("View").Text, Model.ContentItem) %><%:T(" | ") %><%
if (Model.HasDraft) { %>
<a href="<%:Html.AntiForgeryTokenGetUrl(Url.Action("Publish", new {id = Model.ContentItem.Id})) %>" title="<%:T("Publish Draft") %>"><%:T("Publish Draft") %></a><%:T(" | ") %><%
} %>
<a href="<%:Html.AntiForgeryTokenGetUrl(Url.Action("Unpublish", new {id = Model.ContentItem.Id})) %>" title="<%:T("Unpublish") %>"><%:T("Unpublish") %></a><%:T(" | ") %><%
}
else { %>
<a href="<%:Html.AntiForgeryTokenGetUrl(Url.Action("Publish", new {id = Model.ContentItem.Id})) %>" title="<%:T("Publish")%>"><%:T("Publish") %></a><%:T(" | ") %><%
} %>

View File

@@ -21,7 +21,7 @@ namespace Orchard.Core.Contents {
var contentTypeDefinitions = _contentDefinitionManager.ListTypeDefinitions().OrderBy(d => d.Name);
builder.Add(T("Content"), "2", menu => {
menu.Add(T("Manage Content"), "1", item => item.Action("List", "Admin", new { area = "Contents" }));
menu.Add(T("Manage Content"), "1", item => item.Action("List", "Admin", new { area = "Contents", id = "" }));
foreach (var contentTypeDefinition in contentTypeDefinitions) {
var ci = _contentManager.New(contentTypeDefinition.Name);
var cim = _contentManager.GetItemMetadata(ci);

View File

@@ -1,13 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web.Mvc;
using System.Web.Routing;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.Records;
using Orchard.Core.Common.Models;
using Orchard.Core.Contents.ViewModels;
using Orchard.Core.PublishLater.Models;
using Orchard.Data;
using Orchard.Localization;
using Orchard.Logging;
@@ -43,6 +45,9 @@ namespace Orchard.Core.Contents.Controllers {
public ILogger Logger { get; set; }
public ActionResult List(ListContentsViewModel model) {
if (model.ContainerId != null && _contentManager.GetLatest((int)model.ContainerId) == null)
return new NotFoundResult();
const int pageSize = 20;
var skip = (Math.Max(model.Page ?? 0, 1) - 1) * pageSize;
@@ -59,6 +64,9 @@ namespace Orchard.Core.Contents.Controllers {
query = query.ForType(model.TypeName);
}
if (model.ContainerId != null)
query = query.Join<CommonRecord>().Where(cr => cr.Container.Id == model.ContainerId);
var contentItems = query.Slice(skip, pageSize);
model.Entries = contentItems.Select(BuildEntry).ToList();
@@ -66,6 +74,50 @@ namespace Orchard.Core.Contents.Controllers {
return View("List", model);
}
[HttpPost, ActionName("List")]
[FormValueRequired("submit.BulkEdit")]
public ActionResult ListPOST(ContentOptions options, IEnumerable<int> itemIds) {
switch (options.BulkAction) {
case ContentsBulkAction.None:
break;
case ContentsBulkAction.PublishNow:
if (!Services.Authorizer.Authorize(Permissions.PublishContent, T("Couldn't publish selected content.")))
return new HttpUnauthorizedResult();
foreach (var item in itemIds.Select(itemId => _contentManager.GetLatest(itemId))) {
_contentManager.Publish(item);
Services.ContentManager.Flush();
}
Services.Notifier.Information(T("Content successfully published."));
break;
case ContentsBulkAction.Unpublish:
if (!Services.Authorizer.Authorize(Permissions.PublishContent, T("Couldn't unpublish selected content.")))
return new HttpUnauthorizedResult();
foreach (var item in itemIds.Select(itemId => _contentManager.GetLatest(itemId))) {
_contentManager.Unpublish(item);
Services.ContentManager.Flush();
}
Services.Notifier.Information(T("Content successfully unpublished."));
break;
case ContentsBulkAction.Remove:
if (!Services.Authorizer.Authorize(Permissions.PublishContent, T("Couldn't delete selected content.")))
return new HttpUnauthorizedResult();
foreach (var item in itemIds.Select(itemId => _contentManager.GetLatest(itemId))) {
_contentManager.Remove(item);
Services.ContentManager.Flush();
}
Services.Notifier.Information(T("Content successfully removed."));
break;
default:
throw new ArgumentOutOfRangeException();
}
// todo: persist filter & order
return RedirectToAction("List");
}
private ListContentsViewModel.Entry BuildEntry(ContentItem contentItem) {
var entry = new ListContentsViewModel.Entry {
ContentItem = contentItem,
@@ -112,24 +164,20 @@ namespace Orchard.Core.Contents.Controllers {
public ActionResult Create(CreateItemViewModel model) {
//todo: need to integrate permissions into generic content management
var contentItem = _contentManager.New(model.Id);
_contentManager.Create(contentItem, VersionOptions.Draft);
model.Content = _contentManager.UpdateEditorModel(contentItem, this);
if (ModelState.IsValid) {
_contentManager.Create(contentItem, VersionOptions.Draft);
model.Content = _contentManager.UpdateEditorModel(contentItem, this);
}
if (!ModelState.IsValid) {
_transactionManager.Cancel();
PrepareEditorViewModel(model.Content);
return View("Create", model);
}
//need to go about this differently - to know when to publish (IPlublishableAspect ?)
if (!contentItem.Has<IPublishingControlAspect>())
if (!contentItem.Has<IPublishingControlAspect>()) {
_contentManager.Publish(contentItem);
_notifier.Information(T("Created content item"));
}
_notifier.Information(T("Created content item"));
return RedirectToAction("Edit", new RouteValueDictionary { { "Id", contentItem.Id } });
}
@@ -182,6 +230,38 @@ namespace Orchard.Core.Contents.Controllers {
return RedirectToAction("List");
}
[HttpPost]
public ActionResult Publish(int id) {
if (!Services.Authorizer.Authorize(Permissions.PublishContent, T("Couldn't publish content")))
return new HttpUnauthorizedResult();
var contentItem = _contentManager.GetLatest(id);
if (contentItem == null)
return new NotFoundResult();
_contentManager.Publish(contentItem);
Services.ContentManager.Flush();
Services.Notifier.Information(T("{0} successfully published.", contentItem.TypeDefinition.DisplayName));
return RedirectToAction("List");
}
[HttpPost]
public ActionResult Unpublish(int id) {
if (!Services.Authorizer.Authorize(Permissions.PublishContent, T("Couldn't unpublish content")))
return new HttpUnauthorizedResult();
var contentItem = _contentManager.GetLatest(id);
if (contentItem == null)
return new NotFoundResult();
_contentManager.Unpublish(contentItem);
Services.ContentManager.Flush();
Services.Notifier.Information(T("{0} successfully unpublished.", contentItem.TypeDefinition.DisplayName));
return RedirectToAction("List");
}
private static void PrepareEditorViewModel(ContentItemViewModel itemViewModel) {
if (string.IsNullOrEmpty(itemViewModel.TemplateName)) {
itemViewModel.TemplateName = "Items/Contents.Item";
@@ -196,4 +276,17 @@ namespace Orchard.Core.Contents.Controllers {
ModelState.AddModelError(key, errorMessage.ToString());
}
}
public class FormValueRequiredAttribute : ActionMethodSelectorAttribute {
private readonly string _submitButtonName;
public FormValueRequiredAttribute(string submitButtonName) {
_submitButtonName = submitButtonName;
}
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
var value = controllerContext.HttpContext.Request.Form[_submitButtonName];
return !string.IsNullOrEmpty(value);
}
}
}

View File

@@ -1,6 +1,7 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Contents.ViewModels;
namespace Orchard.Core.Contents.Drivers {
public class ContentsDriver : ContentItemDriver<ContentPart> {
@@ -11,7 +12,9 @@ namespace Orchard.Core.Contents.Drivers {
}
protected override DriverResult Display(ContentPart part, string displayType) {
return ContentItemTemplate("Items/Contents.Item").LongestMatch(displayType, "Summary", "SummaryAdmin");
return Combined(
ContentItemTemplate("Items/Contents.Item").LongestMatch(displayType, "Summary", "SummaryAdmin"),
ContentPartTemplate(new PublishContentViewModel(part.ContentItem), "Parts/Contents.Publish").LongestMatch(displayType, "Summary", "SummaryAdmin").Location("secondary"));
}
}
}

View File

@@ -0,0 +1,58 @@
using System.Collections.Generic;
using Orchard.Security.Permissions;
namespace Orchard.Core.Contents {
public class Permissions : IPermissionProvider {
public static readonly Permission PublishOthersContent = new Permission { Description = "Publish or unpublish content for others", Name = "PublishOthersContent" };
public static readonly Permission PublishContent = new Permission { Description = "Publish or unpublish content", Name = "PublishContent", ImpliedBy = new[] { PublishOthersContent } };
public static readonly Permission EditOthersContent = new Permission { Description = "Edit content for others", Name = "EditOthersContent", ImpliedBy = new[] { PublishOthersContent } };
public static readonly Permission EditContent = new Permission { Description = "Edit content", Name = "EditContent", ImpliedBy = new[] { EditOthersContent, PublishContent } };
public static readonly Permission DeleteOthersContent = new Permission { Description = "Delete content for others", Name = "DeleteOthersContent" };
public static readonly Permission DeleteContent = new Permission { Description = "Delete content", Name = "DeleteContent", ImpliedBy = new[] { DeleteOthersContent } };
public static readonly Permission MetaListContent = new Permission { ImpliedBy = new[] { EditContent, PublishContent, DeleteContent } };
public string ModuleName {
get {
return "Content";
}
}
public IEnumerable<Permission> GetPermissions() {
return new Permission[] {
EditContent,
EditOthersContent,
PublishContent,
PublishOthersContent,
DeleteContent,
DeleteOthersContent,
};
}
public IEnumerable<PermissionStereotype> GetDefaultStereotypes() {
return new[] {
new PermissionStereotype {
Name = "Administrator",
Permissions = new[] {PublishOthersContent,EditOthersContent,DeleteOthersContent}
},
new PermissionStereotype {
Name = "Editor",
Permissions = new[] {PublishOthersContent,EditOthersContent,DeleteOthersContent}
},
new PermissionStereotype {
Name = "Moderator",
//Permissions = new[] {}
},
new PermissionStereotype {
Name = "Author",
Permissions = new[] {PublishContent,EditContent,DeleteContent}
},
new PermissionStereotype {
Name = "Contributor",
Permissions = new[] {EditContent}
},
};
}
}
}

View File

@@ -0,0 +1,38 @@
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Routing;
using Orchard.Mvc.Routes;
namespace Orchard.Core.Contents {
public class Routes : IRouteProvider {
#region IRouteProvider Members
public void GetRoutes(ICollection<RouteDescriptor> routes) {
foreach (RouteDescriptor routeDescriptor in GetRoutes()) {
routes.Add(routeDescriptor);
}
}
public IEnumerable<RouteDescriptor> GetRoutes() {
return new[] {
new RouteDescriptor {
Priority = 5,
Route = new Route(
"Admin/Contents/List/{id}/InContainer/{containerId}",
new RouteValueDictionary {
{"area", "Contents"},
{"controller", "Admin"},
{"action", "List"}
},
new RouteValueDictionary(),
new RouteValueDictionary {
{"area", "Contents"}
},
new MvcRouteHandler())
}
};
}
#endregion
}
}

View File

@@ -4,16 +4,61 @@ using Orchard.Mvc.ViewModels;
namespace Orchard.Core.Contents.ViewModels {
public class ListContentsViewModel : BaseViewModel {
public ListContentsViewModel() {
Options = new ContentOptions();
}
public string Id { get; set; }
public string TypeName { get { return Id; } }
public int? ContainerId { get; set; }
public string TypeName {
get { return Id; }
}
public string TypeDisplayName { get; set; }
public int? Page { get; set; }
public IList<Entry> Entries { get; set; }
public ContentOptions Options { get; set; }
#region Nested type: Entry
public class Entry {
public ContentItem ContentItem { get; set; }
public ContentItemMetadata ContentItemMetadata { get; set; }
public ContentItemViewModel ViewModel { get; set; }
}
#endregion
}
public class ContentOptions {
public ContentOptions() {
Filter = ContentsFilter.All;
Order = ContentsOrder.Modified;
BulkAction = ContentsBulkAction.None;
}
public ContentsFilter Filter { get; set; }
public ContentsOrder Order { get; set; }
public ContentsBulkAction BulkAction { get; set; }
}
public enum ContentsFilter {
All,
Page,
BlogPost
}
public enum ContentsOrder {
Modified,
Published,
Created,
Title
}
public enum ContentsBulkAction {
None,
PublishNow,
Unpublish,
Remove
}
}

View File

@@ -0,0 +1,28 @@
using Orchard.ContentManagement;
namespace Orchard.Core.Contents.ViewModels {
public class PublishContentViewModel {
public PublishContentViewModel(ContentItem contentItem) {
ContentItem = contentItem;
}
public ContentItem ContentItem { get; private set; }
public bool IsPublished {
get { return ContentItem.VersionRecord != null && ContentItem.VersionRecord.Published; }
}
public bool HasDraft {
get {
return (
(ContentItem.VersionRecord != null)
&& ((ContentItem.VersionRecord.Published == false)
|| (ContentItem.VersionRecord.Published && ContentItem.VersionRecord.Latest == false)));
}
}
public bool HasPublished {
get { return IsPublished || ContentItem.ContentManager.Get(ContentItem.Id, VersionOptions.Published) != null; }
}
}
}

View File

@@ -1,9 +1,40 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.Core.Contents.ViewModels.ListContentsViewModel>" %>
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %>
<h1><%:Html.TitleForPage((string.IsNullOrEmpty(Model.TypeDisplayName) ? T("Manage Content") : T("Manage {0} Content", Model.TypeDisplayName)).ToString())%></h1>
<div class="manage">
<%:Html.ActionLink(!string.IsNullOrEmpty(Model.TypeDisplayName) ? T("Add new {0} content", Model.TypeDisplayName).Text : T("Add new content").Text, "Create", new { }, new { @class = "button primaryAction" })%>
</div>
<%:Html.UnorderedList(
Model.Entries,
(entry, i) => Html.DisplayForItem(entry.ViewModel),
"contentItems") %>
</div><%
using (Html.BeginFormAntiForgeryPost()) { %>
<fieldset class="bulk-actions">
<label for="publishActions"><%:T("Actions:")%></label>
<select id="publishActions" name="<%:Html.NameOf(m => m.Options.BulkAction) %>">
<%:Html.SelectOption(Model.Options.BulkAction, ContentsBulkAction.None, T("Choose action...").ToString())%>
<%:Html.SelectOption(Model.Options.BulkAction, ContentsBulkAction.PublishNow, T("Publish Now").ToString())%>
<%:Html.SelectOption(Model.Options.BulkAction, ContentsBulkAction.Unpublish, T("Unpublish").ToString())%>
<%:Html.SelectOption(Model.Options.BulkAction, ContentsBulkAction.Remove, T("Remove").ToString())%>
</select>
<button type="submit" name="submit.BulkEdit" value="yes"><%:T("Apply") %></button>
</fieldset>
<%-- <fieldset class="bulk-actions">
<label for="filterResults" class="bulk-filter"><%:T("Filter")%></label>
<select id="filterResults" name="<%:Html.NameOf(m => m.Options.Filter) %>">
<%:Html.SelectOption(Model.Options.Filter, ContentsFilter.All, T("All Content").ToString())%>
<%:Html.SelectOption(Model.Options.Filter, ContentsFilter.Page, T("Page").ToString())%>
<%:Html.SelectOption(Model.Options.Filter, ContentsFilter.BlogPost, T("Blog Post").ToString())%>
</select>
<label for="orderResults" class="bulk-order"><%:T("Ordered by")%></label>
<select id="orderResults" name="<%:Html.NameOf(m => m.Options.Order) %>">
<%:Html.SelectOption(Model.Options.Order, ContentsOrder.Created, T("Date Created").ToString())%>
<%:Html.SelectOption(Model.Options.Order, ContentsOrder.Modified, T("Date Modified").ToString())%>
<%:Html.SelectOption(Model.Options.Order, ContentsOrder.Published, T("Date Published").ToString())%>
<%:Html.SelectOption(Model.Options.Order, ContentsOrder.Title, T("Title").ToString())%>
</select>
<button type="submit" name="submit.Filter"><%:T("Apply") %></button>
</fieldset>
--%> <fieldset class="contentItems bulk-items">
<%:Html.UnorderedList(
Model.Entries,
(entry, i) => Html.DisplayForItem(entry.ViewModel),
"")%>
</fieldset><%
} %>

View File

@@ -1,19 +1,16 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<ContentItemViewModel>" %>
<%@ Import Namespace="Orchard.Mvc.ViewModels" %>
<div class="summary">
<div class="summary" itemscope="itemscope" itemid="<%:Model.Item.Id %>" itemtype="http://orchardproject.net/data/ContentItem">
<div class="properties">
<input type="checkbox" value="<%:Model.Item.Id %>" name="itemIds"/>
<h3><%:Html.ItemEditLink(Model.Item) %></h3>
<div class="metadata"><% Html.Zone("metadata"); %></div>
</div>
<div class="related"><%
Html.Zone("secondary"); %>
<%:Html.ItemEditLink(T("Edit").Text, Model.Item) %><%:T(" | ") %><%
using (Html.BeginFormAntiForgeryPost(string.Format("{0}", Url.Action("Remove", new { area = "Contents" })), FormMethod.Post, new {@class = "inline link"})) { %>
<%:Html.Hidden("id", Model.Item.Id, new { id = "" })%>
<button type="submit"><%:T("Remove") %></button><%
} %>
<%:Html.ItemEditLink(T("Edit").Text, Model.Item) %><%:T(" | ") %>
<%:Html.Link(T("Remove").Text, Url.Action("Remove", new { area = "Contents", id = Model.Item.Id }), new { itemprop = "RemoveUrl UnsafeUrl" }) %>
<br /><% Html.Zone("meta"); %>
</div>
<div style="clear:both;"></div>
<% Html.ZonesAny(); %>
<div class="primary"><% Html.ZonesAny(); %></div>
</div>

View File

@@ -0,0 +1,12 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.Core.Contents.ViewModels.PublishContentViewModel>" %>
<% // todo: make this all work
if (Model.HasPublished) { %>
<%:Html.ItemDisplayLink(T("View").Text, Model.ContentItem) %><%:T(" | ") %><%
if (Model.HasDraft) { %>
<%:Html.Link(T("Publish Draft").Text, Url.Action("Publish", new { area = "Contents", id = Model.ContentItem.Id }), new { itemprop = "PublishUrl UnsafeUrl" })%><%:T(" | ") %><%
} %>
<%:Html.Link(T("Unpublish").Text, Url.Action("Unpublish", new { area = "Contents", id = Model.ContentItem.Id }), new { itemprop = "UnpublishUrl UnsafeUrl" })%><%:T(" | ") %><%
}
else { %>
<%:Html.Link(T("Publish").Text, Url.Action("Publish", new { area = "Contents", id = Model.ContentItem.Id }), new { itemprop = "PublishUrl UnsafeUrl" })%><%:T(" | ") %><%
} %>

View File

@@ -1 +1 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.Core.Common.ViewModels.CommonMetadataViewModel>" %>
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.Core.Contents.ViewModels.PublishContentViewModel>" %>

View File

@@ -1,5 +1,5 @@
.content-localization {
margin:1.44em 0 .44em;
margin:1.44em 0 0;
}
.content-localization .content-localizations li,
.content-localization .add-localization {

View File

@@ -77,6 +77,9 @@
<Compile Include="Contents\Controllers\ItemController.cs" />
<Compile Include="Contents\Drivers\ContentsDriver.cs" />
<Compile Include="Contents\Handlers\ContentsHandler.cs" />
<Compile Include="Contents\Permissions.cs" />
<Compile Include="Contents\Routes.cs" />
<Compile Include="Contents\ViewModels\PublishContentViewModel.cs" />
<Compile Include="PublishLater\Drivers\PublishLaterPartDriver.cs" />
<Compile Include="PublishLater\Models\PublishLaterPart.cs" />
<Compile Include="PublishLater\Handlers\PublishLaterPartHandler.cs" />
@@ -228,8 +231,8 @@
<Content Include="Common\Views\DisplayTemplates\Parts\Common.Body.ManageWrapperPre.SummaryAdmin.ascx" />
<Content Include="Common\Views\DisplayTemplates\Parts\Common.Metadata.ascx" />
<Content Include="Common\Views\DisplayTemplates\Parts\Common.Metadata.SummaryAdmin.ascx" />
<Content Include="Common\Views\DisplayTemplates\Parts\Common.Publish.SummaryAdmin.ascx" />
<Content Include="Common\Views\DisplayTemplates\Parts\Common.Publish.ascx" />
<Content Include="Contents\Views\DisplayTemplates\Parts\Contents.Publish.SummaryAdmin.ascx" />
<Content Include="Contents\Views\DisplayTemplates\Parts\Contents.Publish.ascx" />
<Content Include="PublishLater\Views\DisplayTemplates\Parts\PublishLater.Metadata.ascx" />
<Content Include="PublishLater\Views\DisplayTemplates\Parts\PublishLater.Metadata.SummaryAdmin.ascx" />
<Content Include="PublishLater\Views\DisplayTemplates\Parts\PublishLater.SummaryAdmin.ascx" />

View File

@@ -66,7 +66,7 @@ namespace Orchard.Core.Routable.Services {
_contentManager.Query(contentType).Join<RoutableRecord>()
.List()
.Select(i => i.As<IsRoutable>())
.Where(routable => routable.Slug.StartsWith(slug, StringComparison.OrdinalIgnoreCase)) // todo: for some reason the filter doesn't work within the query, even without StringComparison or StartsWith
.Where(routable => routable.Path.Equals(slug, StringComparison.OrdinalIgnoreCase)) // todo: for some reason the filter doesn't work within the query, even without StringComparison or StartsWith
.ToArray();
}
@@ -84,7 +84,7 @@ namespace Orchard.Core.Routable.Services {
return true;
}
var slugsLikeThis = GetSimilarSlugs(part.ContentItem.ContentType, part.Slug);
var slugsLikeThis = GetSimilarSlugs(part.ContentItem.ContentType, part.Path);
// If the part is already a valid content item, don't include it in the list
// of slug to consider for conflict detection

View File

@@ -53,6 +53,7 @@ namespace Orchard.Blogs.Controllers {
if (blogPost.Blog == null)
return new NotFoundResult();
Services.ContentManager.Create(blogPost, VersionOptions.Draft);
model.BlogPost = Services.ContentManager.UpdateEditorModel(blogPost, this);
if (!ModelState.IsValid) {
@@ -60,9 +61,6 @@ namespace Orchard.Blogs.Controllers {
return View(model);
}
Services.ContentManager.Create(model.BlogPost.Item.ContentItem, VersionOptions.Draft);
Services.ContentManager.UpdateEditorModel(blogPost, this);
return Redirect(Url.BlogPostEdit(model.BlogPost.Item));
}

View File

@@ -82,7 +82,6 @@ namespace Orchard.Blogs.Drivers {
}
protected override DriverResult Editor(BlogPost post, IUpdateModel updater) {
updater.TryUpdateModel(post, Prefix, null, null);
return Editor(post);
}
}

View File

@@ -48,8 +48,8 @@ namespace Orchard.Blogs.Extensions {
return urlHelper.Action("Edit", "BlogAdmin", new {blogSlug, area = "Orchard.Blogs"});
}
public static string BlogDelete(this UrlHelper urlHelper, string blogSlug) {
return urlHelper.Action("Delete", "BlogAdmin", new {blogSlug, area = "Orchard.Blogs"});
public static string BlogRemove(this UrlHelper urlHelper, string blogSlug) {
return urlHelper.Action("Remove", "BlogAdmin", new {blogSlug, area = "Orchard.Blogs"});
}
public static string BlogPost(this UrlHelper urlHelper, BlogPost blogPost) {

View File

@@ -7,7 +7,7 @@ if (Model.Entries.Count() > 0) { %>
<div class="actions"><a class="add button primaryAction" href="<%: Url.BlogCreate() %>"><%: T("New Blog") %></a></div>
<%: Html.UnorderedList(Model.Entries, (entry, i) => {
// Add blog post count rendering into "meta" zone
entry.ContentItemViewModel.Zones.AddAction("meta", html => {
entry.ContentItemViewModel.Zones.AddAction("meta:after", html => {
int draftCount = entry.TotalPostCount - entry.ContentItemViewModel.Item.PostCount;
int totalPostCount = entry.TotalPostCount;
@@ -15,7 +15,10 @@ if (Model.Entries.Count() > 0) { %>
if (draftCount > 0){
linkText = linkText + " (" + T.Plural("1 draft", "{0} drafts", draftCount).ToString() + ")";
}
if (entry.ContentItemViewModel.Zones["meta"].Items.Count > 1)
html.ViewContext.Writer.Write(" | ");
html.ViewContext.Writer.Write(html.Link(linkText, Url.BlogForAdmin(entry.ContentItemViewModel.Item.Slug)));
});

View File

@@ -5,11 +5,11 @@
<div class="summary">
<div class="related">
<a href="<%: Url.Blog(Model.Item.Slug) %>" title="<%: T("View") %>"><%: T("View") %></a><%: T(" | ")%>
<a href="<%: Url.BlogForAdmin(Model.Item.Slug) %>" title="<%: T("Edit Posts") %>"><%: T("Edit Posts")%></a><%: T(" | ")%>
<a href="<%: Url.BlogForAdmin(Model.Item.Slug) %>" title="<%: T("List Posts") %>"><%: T("List Posts")%></a><%: T(" | ")%>
<a href="<%: Url.BlogPostCreate(Model.Item) %>" title="<%: T("New Post") %>"><%: T("New Post") %></a><%: T(" | ")%>
<a href="<%: Url.BlogEdit(Model.Item.Slug) %>" title="<%: T("Settings") %>"><%: T("Settings") %></a><%: T(" | ")%>
<a href="<%: Url.BlogEdit(Model.Item.Slug) %>" title="<%: T("Edit") %>"><%: T("Edit")%></a><%: T(" | ")%>
<%-- todo: (heskew) this is waaaaa too verbose. need template helpers for all ibuttons --%>
<% using (Html.BeginFormAntiForgeryPost(Url.BlogDelete(Model.Item.Slug), FormMethod.Post, new { @class = "inline link" })) { %>
<% using (Html.BeginFormAntiForgeryPost(Url.BlogRemove(Model.Item.Slug), FormMethod.Post, new { @class = "inline link" })) { %>
<button type="submit" class="linkButton" title="<%: T("Remove") %>"><%: T("Remove") %></button><%
} %>
</div>

View File

@@ -6,6 +6,7 @@
<%@ Import Namespace="Orchard.Core.Common.Models" %>
<%@ Import Namespace="Orchard.ContentManagement" %>
<%@ Import Namespace="Orchard.Core.Common.ViewModels" %>
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %>
<h2><%: Html.Link(Model.Item.Title, Url.BlogPost(Model.Item)) %></h2>
<div class="meta"><%: Html.PublishedState(new CommonMetadataViewModel(Model.Item.As<CommonAspect>()), T) %> | <%Html.Zone("meta");%></div>
<div class="content"><% Html.Zone("primary", ":manage :metadata");%></div>

View File

@@ -2,4 +2,4 @@
<%@ Import Namespace="Orchard.Mvc.ViewModels"%>
<%@ Import Namespace="Orchard.Blogs.Models"%>
<%: Html.UnorderedList(Model, (bp, i) => Html.DisplayForItem(bp), "blogPosts contentItems") %>
<% if (Model.Count() < 1) { %><div class="info message"><%: T("There are no posts for this blog.") %></div><% } %>
<% if (Model.Count() < 1) { %><div class="info message"><%: T("There are no posts for this blog.") %></div><% } %>

View File

@@ -20,7 +20,7 @@ namespace Orchard.Comments.DataMigrations {
.Column<string>("Email")
.Column<string>("Status")
.Column<DateTime>("CommentDateUtc")
.Column<string>("CommentText", column => column.WithLength(10000))
.Column<string>("CommentText", column => column.Unlimited())
.Column<int>("CommentedOn")
.Column<int>("CommentedOnContainer")
);

View File

@@ -1,4 +1,5 @@
using System.Linq;
using System;
using System.Linq;
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData.Models;
@@ -43,6 +44,14 @@ namespace Orchard.ContentTypes.Controllers {
if (!Services.Authorizer.Authorize(Permissions.CreateContentTypes, T("Not allowed to create a content type.")))
return new HttpUnauthorizedResult();
if(String.IsNullOrWhiteSpace(viewModel.DisplayName)) {
ModelState.AddModelError("DisplayName", T("The Content Type name can't be empty.").ToString());
}
if(_contentDefinitionService.GetTypes().Any(t => t.DisplayName == viewModel.DisplayName)) {
ModelState.AddModelError("DisplayName", T("A type with the same name already exists.").ToString());
}
var typeViewModel = _contentDefinitionService.AddType(viewModel);
if (!ModelState.IsValid) {

View File

@@ -3,10 +3,12 @@ using System.Web.Mvc;
using Orchard.Data.Migration.Generator;
using Orchard.Localization;
using Orchard.Mvc.ViewModels;
using Orchard.UI.Admin;
using Orchard.UI.Notify;
namespace Orchard.DevTools.Controllers {
[ValidateInput(false)]
[Admin]
public class DataMigrationController : Controller {
private readonly ISchemaCommandGenerator _schemaCommandGenerator;

View File

@@ -67,7 +67,12 @@ namespace Orchard.DevTools.Services {
}
if ( createColumn.Length.HasValue ) {
options.Add(string.Format("WithLength({0})", createColumn.Length ));
if ( createColumn.Length == 10000 ) {
options.Add("Unlimited()");
}
else {
options.Add(string.Format("WithLength({0})", createColumn.Length));
}
}
if ( createColumn.Precision > 0 ) {

View File

@@ -69,7 +69,7 @@
// UnsafeUrl links -> form POST
//todo: need some real microdata support eventually (incl. revisiting usage of data-* attributes)
$(function () {
var magicToken = $("input[name=__RequestVerificationToken]");
var magicToken = $("input[name=__RequestVerificationToken]").first();
if (!magicToken) { return; } // no sense in continuing if form POSTS will fail
$("a[itemprop~=UnsafeUrl]").each(function () {
var _this = $(this);

View File

@@ -61,7 +61,7 @@ border:1px solid #8F8F8F;
color:#FFFFFF;
}
fieldset.bulk.actions {
fieldset.bulk-actions {
width:30em;
clear:left;
text-align:left;

View File

@@ -358,7 +358,7 @@ form.inline, form.inline fieldset { /* todo: (heskew) need something other than
form.inline fieldset {
margin:0;
}
fieldset.bulk.actions {
.bulk-actions {
display:inline;
height:auto;
margin:0 1.4em 0 0;
@@ -380,9 +380,12 @@ label.forcheckbox {
display:inline;
line-height:1.8em;
}
fieldset.bulk.actions label, label.sub {
.bulk-actions label, .bulk-items h3, label, label.sub {
display:inline;
}
label.bulk-order {
text-transform:lowercase;
}
label span {
font-weight:normal;
}
@@ -638,7 +641,8 @@ table .button {
-moz-box-shadow:inset 0 1px 3px #878686;
-webkit-box-shadow:inset 0 1px 2px #878686;
clear:both;
margin:1.4em 0;
margin:1em 0;
padding:0;
}
.contentItems li {
border-bottom:1px solid #eaeaea;
@@ -646,6 +650,10 @@ table .button {
overflow:hidden;
padding:0 1.4em .8em;
}
.contentItems.bulk-items li {
padding-bottom:.6em;
padding-left:.6em;
}
#main .contentItems li .actions {
color:#EAE9D9;
height:auto;
@@ -680,6 +688,14 @@ table .button {
.contentItems .metadata ul {
display:inline;
}
.contentItems.bulk-items .metadata, .contentItems.bulk-items .primary {
margin:.6em 0 0 2em;
}
.contentItems.bulk-items .primary {
clear:both;
float:left;
margin-top:0;
}
.contentItems .properties li {
border:0;
float:left;
@@ -697,6 +713,9 @@ table .button {
.contentItems .commentcount {
line-height:2em;
}
#main .contentItems p {
margin:1em 0 0;
}
/* Core Modules

View File

@@ -23,5 +23,14 @@ namespace Orchard.Data.Migration.Schema {
return this;
}
public new AlterColumnCommand WithLength(int? length) {
base.WithLength(length);
return this;
}
public new AlterColumnCommand Unlimited() {
return WithLength(10000);
}
}
}

View File

@@ -37,5 +37,8 @@ namespace Orchard.Data.Migration.Schema {
return this;
}
public ColumnCommand Unlimited() {
return WithLength(10000);
}
}
}

View File

@@ -64,6 +64,10 @@ namespace Orchard.Data.Migration.Schema {
return this;
}
public new CreateColumnCommand Unlimited() {
return WithLength(10000);
}
public new CreateColumnCommand WithType(DbType dbType) {
base.WithType(dbType);
return this;

View File

@@ -1,6 +1,11 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Reflection;
using FluentNHibernate.Cfg.Db;
using NHibernate.Driver;
using NHibernate.SqlTypes;
namespace Orchard.Data.Providers {
public class SqlCeDataServicesProvider : AbstractDataServicesProvider {
@@ -36,6 +41,7 @@ namespace Orchard.Data.Providers {
}
persistence = persistence.ConnectionString(localConnectionString);
persistence = persistence.Driver(typeof(OrchardSqlServerCeDriver).AssemblyQualifiedName);
return persistence;
}
@@ -64,5 +70,35 @@ namespace Orchard.Data.Providers {
engine.GetType().GetMethod("Dispose").Invoke(engine, null);
}
public class OrchardSqlServerCeDriver : SqlServerCeDriver {
private PropertyInfo _dbParamSqlDbTypeProperty;
public override void Configure(IDictionary<string, string> settings) {
base.Configure(settings);
using ( var cmd = CreateCommand() ) {
var dbParam = cmd.CreateParameter();
_dbParamSqlDbTypeProperty = dbParam.GetType().GetProperty("SqlDbType");
}
}
protected override void InitializeParameter(IDbDataParameter dbParam, string name, SqlType sqlType) {
base.InitializeParameter(dbParam, name, sqlType);
if (sqlType.Length <= 4000) {
return;
}
switch(sqlType.DbType) {
case DbType.String:
_dbParamSqlDbTypeProperty.SetValue(dbParam, SqlDbType.NText, null);
break;
case DbType.AnsiString:
_dbParamSqlDbTypeProperty.SetValue(dbParam, SqlDbType.Text, null);
break;
case DbType.Byte:
_dbParamSqlDbTypeProperty.SetValue(dbParam, SqlDbType.Image, null);
break;
}
}
}
}
}

View File

@@ -5,6 +5,7 @@ using System.Linq;
using Orchard.Caching;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.WebSite;
using Orchard.Logging;
using Yaml.Grammar;
namespace Orchard.Environment.Extensions.Folders {
@@ -34,23 +35,38 @@ namespace Orchard.Environment.Extensions.Folders {
_manifestIsOptional = manifestIsOptional;
_cacheManager = cacheManager;
_webSiteFolder = webSiteFolder;
Logger = NullLogger.Instance;
}
ILogger Logger { get; set; }
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
var list = new List<ExtensionDescriptor>();
foreach (var locationPath in _paths) {
var subfolderPaths = _cacheManager.Get(locationPath, ctx => {
var path = locationPath;
var subList = _cacheManager.Get(locationPath, ctx => {
ctx.Monitor(_webSiteFolder.WhenPathChanges(ctx.Key));
return _webSiteFolder.ListDirectories(ctx.Key);
var subfolderPaths = _webSiteFolder.ListDirectories(ctx.Key);
var localList = new List<ExtensionDescriptor>();
foreach ( var subfolderPath in subfolderPaths ) {
var extensionName = Path.GetFileName(subfolderPath.TrimEnd('/', '\\'));
var manifestPath = Path.Combine(subfolderPath, _manifestName);
ctx.Monitor(_webSiteFolder.WhenPathChanges(manifestPath));
try {
var descriptor = GetExtensionDescriptor(path, extensionName, manifestPath);
if ( descriptor != null )
localList.Add(descriptor);
}
catch ( Exception ex ) {
// Ignore invalid module manifests
Logger.Error(ex, "A module could not be loaded. It was ignored.");
}
}
return localList;
});
foreach (var subfolderPath in subfolderPaths) {
var extensionName = Path.GetFileName(subfolderPath.TrimEnd('/', '\\'));
var manifestPath = Path.Combine(subfolderPath, _manifestName);
var descriptor = GetExtensionDescriptor(locationPath, extensionName, manifestPath);
if (descriptor != null)
list.Add(descriptor);
}
list.AddRange(subList);
}
return list;
}

View File

@@ -29,8 +29,9 @@ namespace Orchard.UI.Admin.Notification {
var messageEntries = _notificationManager.GetNotifications().ToList();
baseViewModel.Messages = baseViewModel.Messages == null ? messageEntries : baseViewModel.Messages.Union(messageEntries).ToList();
baseViewModel.Zones.AddRenderPartial("content:before", "Messages", baseViewModel.Messages);
if ( messageEntries.Any() ) {
baseViewModel.Zones.AddRenderPartial("content:before", "Messages", messageEntries);
}
}
public void OnResultExecuted(ResultExecutedContext filterContext) {