diff --git a/src/Orchard.Web/Core/Shapes/CoreShapes.cs b/src/Orchard.Web/Core/Shapes/CoreShapes.cs index 98722594c..c9b6d5aa6 100644 --- a/src/Orchard.Web/Core/Shapes/CoreShapes.cs +++ b/src/Orchard.Web/Core/Shapes/CoreShapes.cs @@ -283,7 +283,7 @@ namespace Orchard.Core.Shapes { [Shape] public void ContentZone(dynamic Display, dynamic Shape, TextWriter Output) { var unordered = ((IEnumerable)Shape).ToArray(); - var tabbed = unordered.GroupBy(x => (string)x.Metadata.Tab); + var tabbed = unordered.GroupBy(x => (string)x.Metadata.Tab ?? ""); if (tabbed.Count() > 1) { foreach (var tab in tabbed) { diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Commands/BlogWidgetCommands.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Commands/BlogWidgetCommands.cs new file mode 100644 index 000000000..af390fd45 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Commands/BlogWidgetCommands.cs @@ -0,0 +1,165 @@ +using System; +using System.Linq; +using Orchard.Blogs.Models; +using Orchard.Blogs.Services; +using Orchard.Commands; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Aspects; +using Orchard.Core.Common.Models; +using Orchard.Security; +using Orchard.Settings; +using Orchard.Widgets.Models; +using Orchard.Widgets.Services; + +namespace Orchard.Blogs.Commands { + public class BlogWidgetCommands : DefaultOrchardCommandHandler { + private readonly IWidgetsService _widgetsService; + private readonly IBlogService _blogService; + private readonly ISiteService _siteService; + private readonly IMembershipService _membershipService; + private readonly IContentManager _contentManager; + + private BlogPart blog; + + public BlogWidgetCommands( + IWidgetsService widgetsService, + IBlogService blogService, + ISiteService siteService, + IMembershipService membershipService, + IContentManager contentManager) { + _widgetsService = widgetsService; + _blogService = blogService; + _siteService = siteService; + _membershipService = membershipService; + _contentManager = contentManager; + + RenderTitle = true; + } + + [OrchardSwitch] + public string Title { get; set; } + + [OrchardSwitch] + public string Name { get; set; } + + [OrchardSwitch] + public bool RenderTitle { get; set; } + + [OrchardSwitch] + public string Zone { get; set; } + + [OrchardSwitch] + public string Position { get; set; } + + [OrchardSwitch] + public string Layer { get; set; } + + [OrchardSwitch] + public string Identity { get; set; } + + [OrchardSwitch] + public string Owner { get; set; } + + [OrchardSwitch] + public string BlogPath { get; set; } + + [OrchardSwitch] + public int BlogId { get; set; } + + [OrchardSwitch] + public string Count { get; set; } + + [CommandName("blog widget create recentblogposts")] + [CommandHelp("blog widget create recentblogposts /Title: /Name:<name> /Zone:<zone> /Position:<position> /Layer:<layer> (/BlogId:<id> | /BlogPath:<path>) [/Identity:<identity>] [/RenderTitle:true|false] [/Owner:<owner>] [/Count:<count>]\r\n\t" + "Creates a new widget")] + [OrchardSwitches("Title,Name,Zone,Position,Layer,BlogId,BlogPath,Identity,Owner,RenderTitle,Count")] + public void CreateRecentBlogPostsWidget() { + var type = "RecentBlogPosts"; + + var widget = CreateStandardWidget(type); + if (widget == null) { + return; + } + + widget.As<RecentBlogPostsPart>().BlogId = blog.Id; + + // Setting count to 0 means all posts. It's an optional parameter and defaults to 5. + if (!string.IsNullOrWhiteSpace(Count)) { + int CountAsNumber = 0; + if (Int32.TryParse(Count, out CountAsNumber)) { + widget.As<RecentBlogPostsPart>().Count = CountAsNumber; + } + } + + _contentManager.Publish(widget.ContentItem); + Context.Output.WriteLine(T("{0} widget created successfully.", type).Text); + } + + [CommandName("blog widget create blogarchives")] + [CommandHelp("blog widget create blogarchives /Title:<title> /Name:<name> /Zone:<zone> /Position:<position> /Layer:<layer> (/BlogId:<id> | /BlogPath:<path>) [/Identity:<identity>] [/RenderTitle:true|false] [/Owner:<owner>]\r\n\t" + "Creates a new widget")] + [OrchardSwitches("Title,Name,Zone,Position,Layer,BlogId,BlogPath,Identity,Owner,RenderTitle")] + public void CreateBlogArchivesWidget() { + var type = "BlogArchives"; + + var widget = CreateStandardWidget(type); + if (widget == null) { + return; + } + + widget.As<BlogArchivesPart>().BlogId = blog.Id; + + _contentManager.Publish(widget.ContentItem); + Context.Output.WriteLine(T("{0} widget created successfully.", type).Text); + } + + private WidgetPart CreateStandardWidget(string type) { + var widgetTypeNames = _widgetsService.GetWidgetTypeNames().ToList(); + if (!widgetTypeNames.Contains(type)) { + Context.Output.WriteLine(T("Creating widget failed: type {0} was not found. Supported widget types are: {1}.", + type, + string.Join(" ", widgetTypeNames))); + return null; + } + + var layer = GetLayer(Layer); + if (layer == null) { + Context.Output.WriteLine(T("Creating {0} widget failed: layer {1} was not found.", type, Layer)); + return null; + } + + blog = GetBlog(BlogId, BlogPath); + if (blog == null) { + Context.Output.WriteLine(T("Creating {0} widget failed: blog was not found.", type)); + return null; + } + + var widget = _widgetsService.CreateWidget(layer.ContentItem.Id, type, T(Title).Text, Position, Zone); + + if (!String.IsNullOrWhiteSpace(Name)) { + widget.Name = Name.Trim(); + } + + widget.RenderTitle = RenderTitle; + + if (String.IsNullOrEmpty(Owner)) { + Owner = _siteService.GetSiteSettings().SuperUser; + } + var owner = _membershipService.GetUser(Owner); + widget.As<ICommonPart>().Owner = owner; + + if (widget.Has<IdentityPart>() && !String.IsNullOrEmpty(Identity)) { + widget.As<IdentityPart>().Identifier = Identity; + } + + return widget; + } + + private LayerPart GetLayer(string layer) { + var layers = _widgetsService.GetLayers(); + return layers.FirstOrDefault(layerPart => String.Equals(layerPart.Name, layer, StringComparison.OrdinalIgnoreCase)); + } + + private BlogPart GetBlog(int blogId, string blogPath) { + return _contentManager.Get<BlogPart>(blogId) ?? _blogService.Get(blogPath); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj b/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj index 25f36dc12..d4b202396 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Orchard.Blogs.csproj @@ -93,6 +93,7 @@ </ItemGroup> <ItemGroup> <Compile Include="AdminMenu.cs" /> + <Compile Include="Commands\BlogWidgetCommands.cs" /> <Compile Include="Controllers\RemoteBlogPublishingController.cs" /> <Compile Include="Drivers\BlogArchivesPartDriver.cs" /> <Compile Include="Drivers\RemoteBlogPublishingDriver.cs" /> diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogService.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogService.cs index ed3a16a34..b431dabca 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogService.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Services/BlogService.cs @@ -17,7 +17,7 @@ namespace Orchard.Blogs.Services { private readonly ShellSettings _shellSettings; private readonly IShellDescriptorManager _shellDescriptorManager; private readonly HashSet<int> _processedBlogParts = new HashSet<int>(); - IPathResolutionService _pathResolutionService; + private readonly IPathResolutionService _pathResolutionService; public BlogService( IContentManager contentManager, diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Services/RoleService.cs b/src/Orchard.Web/Modules/Orchard.Roles/Services/RoleService.cs index a7c3ce0f7..3240669e0 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Services/RoleService.cs +++ b/src/Orchard.Web/Modules/Orchard.Roles/Services/RoleService.cs @@ -46,7 +46,7 @@ namespace Orchard.Roles.Services { public IEnumerable<RoleRecord> GetRoles() { var roles = from role in _roleRepository.Table select role; - return roles.ToList(); + return roles; } public RoleRecord GetRole(int id) { diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Recipes/blog.recipe.xml b/src/Orchard.Web/Modules/Orchard.Setup/Recipes/blog.recipe.xml index 49e8befb6..e5a5d69ed 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Recipes/blog.recipe.xml +++ b/src/Orchard.Web/Modules/Orchard.Setup/Recipes/blog.recipe.xml @@ -56,13 +56,13 @@ layer create Anonymous /LayerRule:"not authenticated" /Description:"The widgets in this layer are displayed when the user is anonymous" layer create Disabled /LayerRule:"false" /Description:"The widgets in this layer are never displayed" layer create TheHomepage /LayerRule:"url '~/'" /Description:"The widgets in this layer are displayed on the home page" - widget create RecentBlogPosts /Title:"Recent Blog Posts" /Zone:"AsideSecond" /Position:"5" /Layer:"TheHomepage" /Identity:"RecentBlogPosts1" - widget create BlogArchives /Title:"Blog Archives" /Zone:"AsideSecond" /Position:"6" /Layer:"TheHomepage" /Identity:"BlogArchives1" - widget create TagCloud /Title:"Blog Post Tags" /Zone:"AsideSecond" /Position:"7" /Layer:"TheHomepage" /Identity:"TagCloud1" + blog create /Title:"Blog" /Homepage:true /Description:"This is your Orchard Blog." + blog widget create RecentBlogPosts /Title:"Recent Blog Posts" /Zone:"AsideSecond" /Position:"5" /Layer:"TheHomepage" /Identity:"RecentBlogPosts1" /BlogPath:"" + blog widget create BlogArchives /Title:"Blog Archives" /Zone:"AsideSecond" /Position:"60" /Layer:"TheHomepage" /Identity:"BlogArchives1" /BlogPath:"" + tags widget create TagCloud /Title:"Blog Post Tags" /Zone:"AsideSecond" /Position:"70" /Layer:"TheHomepage" /Identity:"TagCloud1" /Slug:"/" site setting set baseurl theme activate "The Theme Machine" menu create /MenuName:"Main Menu" - blog create /Title:"Blog" /Homepage:true /Description:"This is your Orchard Blog." menuitem create /MenuPosition:"0" /MenuText:"Home" /Url:"~/" /MenuName:"Main Menu" widget create MenuWidget /Title:"Main Menu" /RenderTitle:false /Zone:"Navigation" /Position:"1" /Layer:"Default" /Identity:"MenuWidget1" /MenuName:"Main Menu" </Command> diff --git a/src/Orchard.Web/Modules/Orchard.Tags/Commands/TagsWidgetCommands.cs b/src/Orchard.Web/Modules/Orchard.Tags/Commands/TagsWidgetCommands.cs new file mode 100644 index 000000000..0e9b79662 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Tags/Commands/TagsWidgetCommands.cs @@ -0,0 +1,116 @@ +using System; +using System.Linq; +using Orchard.Commands; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Aspects; +using Orchard.Core.Common.Models; +using Orchard.Security; +using Orchard.Settings; +using Orchard.Tags.Models; +using Orchard.Widgets.Models; +using Orchard.Widgets.Services; + +namespace Orchard.Tags.Commands { + public class TagWidgetCommands : DefaultOrchardCommandHandler { + private readonly IWidgetsService _widgetsService; + private readonly ISiteService _siteService; + private readonly IMembershipService _membershipService; + private readonly IContentManager _contentManager; + + public TagWidgetCommands( + IWidgetsService widgetsService, + ISiteService siteService, + IMembershipService membershipService, + IContentManager contentManager) { + _widgetsService = widgetsService; + _siteService = siteService; + _membershipService = membershipService; + _contentManager = contentManager; + + RenderTitle = true; + } + + [OrchardSwitch] + public string Title { get; set; } + + [OrchardSwitch] + public string Name { get; set; } + + [OrchardSwitch] + public bool RenderTitle { get; set; } + + [OrchardSwitch] + public string Zone { get; set; } + + [OrchardSwitch] + public string Position { get; set; } + + [OrchardSwitch] + public string Layer { get; set; } + + [OrchardSwitch] + public string Identity { get; set; } + + [OrchardSwitch] + public string Owner { get; set; } + + [OrchardSwitch] + public string Slug { get; set; } + + [OrchardSwitch] + public string Buckets { get; set; } + + [CommandName("tags widget create tagcloud")] + [CommandHelp("tags widget create tagcloud /Title:<title> /Name:<name> /Zone:<zone> /Position:<position> /Layer:<layer> [/Identity:<identity>] [/RenderTitle:true|false] [/Owner:<owner>] [/Slug:<slug>] [/Buckets:<number>]\r\n\t" + "Creates a new widget")] + [OrchardSwitches("Title,Name,Zone,Position,Layer,Buckets,Identity,Owner,RenderTitle,Slug")] + public void CreateTagsCloudWidget() { + var type = "TagCloud"; + + var layer = GetLayer(Layer); + if (layer == null) { + Context.Output.WriteLine(T("Creating {0} widget failed: layer {1} was not found.", type, Layer)); + return; + } + + var widget = _widgetsService.CreateWidget(layer.ContentItem.Id, type, T(Title).Text, Position, Zone); + + if (!String.IsNullOrWhiteSpace(Name)) { + widget.Name = Name.Trim(); + } + + widget.RenderTitle = RenderTitle; + + if (String.IsNullOrEmpty(Owner)) { + Owner = _siteService.GetSiteSettings().SuperUser; + } + var owner = _membershipService.GetUser(Owner); + widget.As<ICommonPart>().Owner = owner; + + if (widget.Has<IdentityPart>() && !String.IsNullOrEmpty(Identity)) { + widget.As<IdentityPart>().Identifier = Identity; + } + + if (widget == null) { + return; + } + + widget.As<TagCloudPart>().Slug = Slug; + + // It's an optional parameter and defaults to 5. + if (!string.IsNullOrWhiteSpace(Buckets)) { + int BucketsAsNumber = 0; + if (Int32.TryParse(Buckets, out BucketsAsNumber)) { + widget.As<TagCloudPart>().Buckets = BucketsAsNumber; + } + } + + _contentManager.Publish(widget.ContentItem); + Context.Output.WriteLine(T("{0} widget created successfully.", type).Text); + } + + private LayerPart GetLayer(string layer) { + var layers = _widgetsService.GetLayers(); + return layers.FirstOrDefault(layerPart => String.Equals(layerPart.Name, layer, StringComparison.OrdinalIgnoreCase)); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Tags/Orchard.Tags.csproj b/src/Orchard.Web/Modules/Orchard.Tags/Orchard.Tags.csproj index 77aef27b5..c78f9ef38 100644 --- a/src/Orchard.Web/Modules/Orchard.Tags/Orchard.Tags.csproj +++ b/src/Orchard.Web/Modules/Orchard.Tags/Orchard.Tags.csproj @@ -99,6 +99,7 @@ </ItemGroup> <ItemGroup> <Compile Include="AdminMenu.cs" /> + <Compile Include="Commands\TagsWidgetCommands.cs" /> <Compile Include="Controllers\AdminController.cs" /> <Compile Include="Drivers\TagCloudDriver.cs" /> <Compile Include="Feeds\TagFeedQuery.cs" /> @@ -195,6 +196,7 @@ <ItemGroup> <Content Include="packages.config" /> </ItemGroup> + <ItemGroup /> <PropertyGroup> <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> diff --git a/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.cshtml index fef515c51..5cac51030 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.cshtml @@ -87,10 +87,14 @@ } </td> <td> - @Display(New.DateTimeRelative(dateTimeUtc: entry.User.CreatedUtc)) + @if (entry.User.CreatedUtc != null) { + @Display(New.DateTimeRelative(dateTimeUtc: entry.User.CreatedUtc)) + } </td> <td> - @Display(New.DateTimeRelative(dateTimeUtc: entry.User.LastLoginUtc)) + @if (entry.User.LastLoginUtc != null) { + @Display(New.DateTimeRelative(dateTimeUtc: entry.User.LastLoginUtc)) + } </td> </tr> userIndex++; diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Filters/WidgetFilter.cs b/src/Orchard.Web/Modules/Orchard.Widgets/Filters/WidgetFilter.cs index 7535cf1a7..20b570714 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Filters/WidgetFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Filters/WidgetFilter.cs @@ -59,7 +59,7 @@ namespace Orchard.Widgets.Filters { foreach (var widgetPart in widgetParts) { var commonPart = widgetPart.As<ICommonPart>(); if (commonPart == null || commonPart.Container == null) { - Logger.Warning("The widget '{0}' is has no assigned layer or the layer does not exist.", widgetPart.Title); + Logger.Warning("The widget '{0}' has no assigned layer or the layer does not exist.", widgetPart.Title); continue; }