From b53f2e6a36fb180e4038229edd8edc92e4de96b1 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Mon, 7 Feb 2011 14:17:48 -0800 Subject: [PATCH] #17282 - Gallery modules improvements --HG-- branch : dev --- .../Orchard.Tests.Modules.csproj | 1 - .../Services/PackagingServicesTests.cs | 146 ------------------ .../Content/Images/stars.png | Bin 0 -> 564 bytes .../Controllers/GalleryController.cs | 137 +++++++++++----- .../PackagingServicesController.cs | 22 +-- .../Orchard.Packaging.csproj | 3 +- .../Services/IPackagingServices.cs | 13 -- .../Services/IPackagingSourceManager.cs | 8 +- .../Services/PackagingEntry.cs | 1 + .../Services/PackagingServices.cs | 39 ----- .../Services/PackagingSourceManager.cs | 57 ++++--- .../Styles/orchard-packaging-admin.css | 15 ++ .../PackagingExtensionsViewModel.cs | 13 ++ .../Views/Gallery/Modules.cshtml | 123 +++++++++------ .../Views/Gallery/Themes.cshtml | 135 +++++++++------- 15 files changed, 343 insertions(+), 370 deletions(-) delete mode 100644 src/Orchard.Tests.Modules/Packaging/Services/PackagingServicesTests.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Packaging/Content/Images/stars.png delete mode 100644 src/Orchard.Web/Modules/Orchard.Packaging/Services/IPackagingServices.cs delete mode 100644 src/Orchard.Web/Modules/Orchard.Packaging/Services/PackagingServices.cs diff --git a/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj b/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj index f750841f4..fee652874 100644 --- a/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj +++ b/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj @@ -143,7 +143,6 @@ - diff --git a/src/Orchard.Tests.Modules/Packaging/Services/PackagingServicesTests.cs b/src/Orchard.Tests.Modules/Packaging/Services/PackagingServicesTests.cs deleted file mode 100644 index 6c362a134..000000000 --- a/src/Orchard.Tests.Modules/Packaging/Services/PackagingServicesTests.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Xml.Linq; -using Autofac; -using Moq; -using NUnit.Framework; -using Orchard.Caching; -using Orchard.ContentManagement; -using Orchard.ContentManagement.Handlers; -using Orchard.ContentManagement.MetaData; -using Orchard.ContentManagement.MetaData.Models; -using Orchard.ContentManagement.MetaData.Services; -using Orchard.ContentManagement.Records; -using Orchard.Core.Settings.Handlers; -using Orchard.Core.Settings.Metadata; -using Orchard.Core.Settings.Models; -using Orchard.Core.Settings.Services; -using Orchard.Data; -using Orchard.DisplayManagement; -using Orchard.DisplayManagement.Descriptors; -using Orchard.DisplayManagement.Implementation; -using Orchard.Environment; -using Orchard.Environment.Configuration; -using Orchard.Environment.Extensions; -using Orchard.Localization; -using Orchard.Packaging.Services; -using Orchard.Security; -using Orchard.Security.Permissions; -using Orchard.Security.Providers; -using Orchard.Settings; -using Orchard.Tests.Modules.Users; -using Orchard.Tests.Stubs; -using Orchard.UI.Notify; -using Orchard.Users.Handlers; -using Orchard.Users.Models; -using Orchard.Users.Services; - -namespace Orchard.Tests.Modules.Packaging.Services { - public class PackagingServicesTests : DatabaseEnabledTestsBase { - private Mock _authorizer; - private Mock _workContext; - private IUser _currentUser; - - public override void Register(ContainerBuilder builder) { - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType(typeof(SettingsFormatter)) - .As(typeof(IMapper)) - .As(typeof(IMapper)); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As().InstancePerDependency(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - - builder.RegisterInstance(new Mock().Object); - builder.RegisterInstance(new Mock().Object); - builder.RegisterType().As(); - builder.RegisterType().As(); - - builder.RegisterType().As(); - builder.RegisterInstance(ShellSettingsUtility.CreateEncryptionEnabled()); - - _authorizer = new Mock(); - builder.RegisterInstance(_authorizer.Object); - - _workContext = new Mock(); - _workContext.Setup(w => w.GetState(It.Is(s => s == "CurrentSite"))).Returns(() => _container.Resolve().GetSiteSettings()); - _workContext.Setup(w => w.GetState(It.Is(s => s == "CurrentUser"))).Returns(() => _currentUser); - - var _workContextAccessor = new Mock(); - _workContextAccessor.Setup(w => w.GetContext()).Returns(_workContext.Object); - builder.RegisterInstance(_workContextAccessor.Object).As(); - } - - protected override IEnumerable DatabaseTypes { - get { - return new[] { typeof(UserPartRecord), - typeof(SiteSettingsPartRecord), - typeof(RegistrationSettingsPartRecord), - typeof(ContentTypeRecord), - typeof(ContentItemRecord), - typeof(ContentItemVersionRecord), - }; - } - } - - [Test] - public void CanManagePackagesTest() { - const string superUsername = "admin"; - const string regularUsername = "user1"; - - IPackagingServices packagingServices = _container.Resolve(); - IOrchardServices orchardServices = _container.Resolve(); - ShellSettings shellSettings = _container.Resolve(); - shellSettings.Name = ShellSettings.DefaultName; - - IUser regularUser = CreateUser(regularUsername); - IUser superUser = CreateUser(superUsername); - - orchardServices.WorkContext.CurrentSite.As().SuperUser = superUsername; - _currentUser = regularUser; - _session.Flush(); - - // Setup authorizer to return false - _authorizer.Setup(x => x.Authorize(It.IsAny(), It.IsAny())).Returns(false); - - // Test regular user without permission explicit assigned and which is not the default admin - Assert.That(packagingServices.CanManagePackages(), Is.False); - - // Test regular user with permission explicit assigned and which is not the default admin - _authorizer.Setup(x => x.Authorize(It.IsAny(), It.IsAny())).Returns(true); - Assert.That(packagingServices.CanManagePackages(), Is.True); - - // Test super user that even without permission explicit assigned should be able to manage packages - _authorizer.Setup(x => x.Authorize(It.IsAny(), It.IsAny())).Returns(false); - Assert.That(packagingServices.CanManagePackages(), Is.False); - _currentUser = superUser; - Assert.That(packagingServices.CanManagePackages(), Is.True); - - // Test with super user from another tenant site - shellSettings.Name = "tenantsite2"; - _session.Flush(); - - Assert.That(packagingServices.CanManagePackages(), Is.False); - } - - private IUser CreateUser(string username) { - var manager = _container.Resolve(); - - UserPart userPart = manager.New("User"); - userPart.Record = new UserPartRecord { UserName = username, NormalizedUserName = username, Email = string.Format("{0}@orcharproject.com", username) }; - manager.Create(userPart.ContentItem); - - return userPart; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Content/Images/stars.png b/src/Orchard.Web/Modules/Orchard.Packaging/Content/Images/stars.png new file mode 100644 index 0000000000000000000000000000000000000000..cf2d4b30e82c852639da04b08f5ef9e849f4f815 GIT binary patch literal 564 zcmV-40?Yl0P)N2bPDNB8 zb~7$DE;i7Ety%y80kKI$K~y+Tm6K_5fRj;OC=9_MM-T;oL+wC@3fsU><&hLaeEYWc<*s6vW*0H{NPF0nw z)w!t2@+_FCX0X2NZ|Hn;^Ba6IcK2*y-O<1*7L}?t(DkVUyFpzCx^8RTZlLE{wSmr; zCts3s(Z2i43Hue{`MbKRXj|JeuWok1*+PX{Hj9?+@no(Pwhf?AyKI4ex0`sCy&etF zh=vH_E7b4nY*)ga=n@iNW4~J!^{6^PNL7h%Iga*FkNQ*{CaMzOL6+kR^~Euoi&J>f zIl(@{#PSVmMEC*W@)@1g8@$y7+t!>Pz|4;zgoUs~7pwuH)Uw25!jG&M2w_=GA?q3I z8wT@3D*6Z)Cxp)k_E>q#_XM8^y|Ug}hTtbc!l{GAau-oR zRBh0*aavZ@DGcHAbN`oe-m _packagingSourceManager.GetModuleList(source).ToArray()); - } - - public ActionResult Themes(int? sourceId) { - return ListExtensions(sourceId, DefaultExtensionTypes.Theme, "Themes", source => _packagingSourceManager.GetThemeList(source).ToArray()); - } - - protected ActionResult ListExtensions(int? sourceId, string extensionType, string returnView, Func getList) { - if (!_packagingServices.CanManagePackages()) + public ActionResult Modules(PackagingExtensionsOptions options, PagerParameters pagerParameters) { + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to list Modules"))) return new HttpUnauthorizedResult(); - var selectedSource = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault(); + var pager = new Pager(Services.WorkContext.CurrentSite, pagerParameters); + return ListExtensions(options, DefaultExtensionTypes.Module, pager); + } + + public ActionResult Themes(PackagingExtensionsOptions options, PagerParameters pagerParameters) { + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to list Themes"))) + return new HttpUnauthorizedResult(); + + var pager = new Pager(Services.WorkContext.CurrentSite, pagerParameters); + return ListExtensions(options, DefaultExtensionTypes.Theme, pager); + } + + protected ActionResult ListExtensions(PackagingExtensionsOptions options, string packageType, Pager pager) { + var selectedSource = _packagingSourceManager.GetSources().Where(s => s.Id == options.SourceId).FirstOrDefault(); var sources = selectedSource != null ? new[] { selectedSource } @@ -139,26 +144,86 @@ namespace Orchard.Packaging.Controllers { ; IEnumerable extensions = null; + int totalCount = 0; foreach (var source in sources) { try { - var sourceExtensions = getList(source); + var sourceExtensions = _packagingSourceManager.GetExtensionList( + source, + packages => { + packages = packages.Where(p => p.PackageType == packageType); + + switch (options.Order) { + case PackagingExtensionsOrder.Downloads: + packages = packages.OrderByDescending(p => p.DownloadCount).ThenBy(p => p.Title); + break; + case PackagingExtensionsOrder.Ratings: + packages = packages.OrderByDescending(p => p.Rating).ThenBy(p => p.Title); + break; + case PackagingExtensionsOrder.Alphanumeric: + packages = packages.OrderBy(p => p.Title); + break; + } + + if(pager.PageSize != 0) { + packages = packages.Skip((pager.Page - 1)*pager.PageSize).Take(pager.PageSize); + } + + return packages; + } + ).ToArray(); + + // count packages separately to prevent loading everything just to count + totalCount += _packagingSourceManager.GetExtensionCount( + source, + packages => packages.Where(p => p.PackageType == packageType) + ); + extensions = extensions == null ? sourceExtensions : extensions.Concat(sourceExtensions); + + // apply another paging rule in case there were multiple sources + if (sources.Count() > 1) { + switch (options.Order) { + case PackagingExtensionsOrder.Downloads: + extensions = extensions.OrderByDescending(p => p.DownloadCount).ThenBy(p => p.Title); + break; + case PackagingExtensionsOrder.Ratings: + extensions = extensions.OrderByDescending(p => p.Rating).ThenBy(p => p.Title); + break; + case PackagingExtensionsOrder.Alphanumeric: + extensions = extensions.OrderBy(p => p.Title); + break; + } + + if (pager.PageSize != 0) { + extensions = extensions.Take(pager.PageSize); + } + } } catch (Exception ex) { Logger.Error(ex, "Error loading extensions from gallery source '{0}'. {1}.", source.FeedTitle, ex.Message); - _notifier.Error(T("Error loading extensions from gallery source '{0}'. {1}.", source.FeedTitle, ex.Message)); + Services.Notifier.Error(T("Error loading extensions from gallery source '{0}'. {1}.", source.FeedTitle, ex.Message)); } } - return View(returnView, new PackagingExtensionsViewModel { - Extensions = extensions ?? new PackagingEntry[] { }, + extensions = extensions ?? new PackagingEntry[0]; + var pagerShape = Services.New.Pager(pager).TotalItemCount(totalCount); + + // maintain previous route data when generating page links + var routeData = new RouteData(); + routeData.Values.Add("Options.Order", options.Order); + pagerShape.RouteData(routeData); + + return View(packageType == DefaultExtensionTypes.Theme ? "Themes" : "Modules", new PackagingExtensionsViewModel { + Extensions = extensions, Sources = _packagingSourceManager.GetSources().OrderBy(s => s.FeedTitle), - SelectedSource = selectedSource + SelectedSource = selectedSource, + Pager = pagerShape, + Options = options }); } public ActionResult Install(string packageId, string version, int sourceId, string redirectTo) { - if (!_packagingServices.CanManagePackages()) + if (_shellSettings.Name != ShellSettings.DefaultName || !Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to add sources"))) return new HttpUnauthorizedResult(); var source = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault(); @@ -171,16 +236,16 @@ namespace Orchard.Packaging.Controllers { _packageManager.Install(packageId, version, source.FeedUrl, HostingEnvironment.MapPath("~/")); if (packageId.StartsWith(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Theme))) { - _notifier.Information(T("The theme has been successfully installed. It can be enabled in the \"Themes\" page accessible from the menu.")); + Services.Notifier.Information(T("The theme has been successfully installed. It can be enabled in the \"Themes\" page accessible from the menu.")); } else if (packageId.StartsWith(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Module))) { - _notifier.Information(T("The module has been successfully installed. Its features can be enabled in the \"Configuration | Features\" page accessible from the menu.")); + Services.Notifier.Information(T("The module has been successfully installed. Its features can be enabled in the \"Configuration | Features\" page accessible from the menu.")); } } catch (Exception exception) { - _notifier.Error(T("Package installation failed.")); + Services.Notifier.Error(T("Package installation failed.")); for (Exception scan = exception; scan != null; scan = scan.InnerException) { - _notifier.Error(T("{0}", scan.Message)); + Services.Notifier.Error(T("{0}", scan.Message)); } } diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Controllers/PackagingServicesController.cs b/src/Orchard.Web/Modules/Orchard.Packaging/Controllers/PackagingServicesController.cs index 859cfda8a..dda7a74f8 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Controllers/PackagingServicesController.cs +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Controllers/PackagingServicesController.cs @@ -4,12 +4,14 @@ using System.Web; using System.Web.Hosting; using System.Web.Mvc; using NuGet; +using Orchard.Environment.Configuration; using Orchard.Environment.Extensions; using Orchard.Environment.Extensions.Models; using Orchard.FileSystems.AppData; using Orchard.Localization; using Orchard.Mvc.Extensions; using Orchard.Packaging.Services; +using Orchard.Security; using Orchard.Themes; using Orchard.UI.Admin; using Orchard.UI.Notify; @@ -21,19 +23,19 @@ namespace Orchard.Packaging.Controllers { [Themed, Admin] public class PackagingServicesController : Controller { - private readonly IPackagingServices _packagingServices; + private readonly ShellSettings _shellSettings; private readonly IPackageManager _packageManager; private readonly IAppDataFolderRoot _appDataFolderRoot; private readonly INotifier _notifier; public PackagingServicesController( - IPackagingServices packagingServices, + ShellSettings shellSettings, IPackageManager packageManager, INotifier notifier, IAppDataFolderRoot appDataFolderRoot, IOrchardServices services) { - _packagingServices = packagingServices; + _shellSettings = shellSettings; _packageManager = packageManager; _notifier = notifier; _appDataFolderRoot = appDataFolderRoot; @@ -46,7 +48,7 @@ namespace Orchard.Packaging.Controllers { public IOrchardServices Services { get; set; } public ActionResult AddTheme(string returnUrl) { - if (!_packagingServices.CanManagePackages()) + if (_shellSettings.Name != ShellSettings.DefaultName || !Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to add themes"))) return new HttpUnauthorizedResult(); return View(); @@ -54,7 +56,7 @@ namespace Orchard.Packaging.Controllers { [HttpPost, ActionName("AddTheme")] public ActionResult AddThemePOST(string returnUrl) { - if (!_packagingServices.CanManagePackages()) + if (_shellSettings.Name != ShellSettings.DefaultName || !Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to add themes"))) return new HttpUnauthorizedResult(); return InstallPackage(returnUrl, Request.RawUrl); @@ -62,14 +64,14 @@ namespace Orchard.Packaging.Controllers { [HttpPost, ActionName("RemoveTheme")] public ActionResult RemoveThemePOST(string themeId, string returnUrl, string retryUrl) { - if (!_packagingServices.CanManagePackages()) + if (_shellSettings.Name != ShellSettings.DefaultName || !Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to remove themes"))) return new HttpUnauthorizedResult(); return UninstallPackage(PackageBuilder.BuildPackageId(themeId, DefaultExtensionTypes.Theme), returnUrl, retryUrl); } public ActionResult AddModule(string returnUrl) { - if (!_packagingServices.CanManagePackages()) + if (_shellSettings.Name != ShellSettings.DefaultName || !Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to add modules"))) return new HttpUnauthorizedResult(); return View(); @@ -77,14 +79,14 @@ namespace Orchard.Packaging.Controllers { [HttpPost, ActionName("AddModule")] public ActionResult AddModulePOST(string returnUrl) { - if (!_packagingServices.CanManagePackages()) + if (_shellSettings.Name != ShellSettings.DefaultName || !Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to add modules"))) return new HttpUnauthorizedResult(); return InstallPackage(returnUrl, Request.RawUrl); } public ActionResult InstallPackage(string returnUrl, string retryUrl) { - if (!_packagingServices.CanManagePackages()) + if (_shellSettings.Name != ShellSettings.DefaultName || !Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to install packages"))) return new HttpUnauthorizedResult(); try { @@ -117,7 +119,7 @@ namespace Orchard.Packaging.Controllers { } public ActionResult UninstallPackage(string id, string returnUrl, string retryUrl) { - if (!_packagingServices.CanManagePackages()) + if (_shellSettings.Name != ShellSettings.DefaultName || !Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to uninstall packages"))) return new HttpUnauthorizedResult(); try { diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Orchard.Packaging.csproj b/src/Orchard.Web/Modules/Orchard.Packaging/Orchard.Packaging.csproj index bbba625a2..8cdee0e16 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Orchard.Packaging.csproj +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Orchard.Packaging.csproj @@ -77,7 +77,6 @@ - @@ -85,7 +84,6 @@ - @@ -96,6 +94,7 @@ + DataServiceClientGenerator diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Services/IPackagingServices.cs b/src/Orchard.Web/Modules/Orchard.Packaging/Services/IPackagingServices.cs deleted file mode 100644 index e2e915cb5..000000000 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Services/IPackagingServices.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Orchard.Packaging.Services { - /// - /// Provides generic packaging related methods. - /// - public interface IPackagingServices : IDependency { - - /// - /// Verifies if the current user is allowed to manage packages. The super user of the default tenant site is always allowed. - /// - /// True if the allowed; false otherwise. - bool CanManagePackages(); - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Services/IPackagingSourceManager.cs b/src/Orchard.Web/Modules/Orchard.Packaging/Services/IPackagingSourceManager.cs index a794cd0d4..4df2d2653 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Services/IPackagingSourceManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Services/IPackagingSourceManager.cs @@ -1,4 +1,8 @@ +using System; using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using Orchard.Packaging.GalleryServer; using Orchard.Packaging.Models; namespace Orchard.Packaging.Services { @@ -7,7 +11,7 @@ namespace Orchard.Packaging.Services { void AddSource(string feedTitle, string feedUrl); void RemoveSource(int id); - IEnumerable GetModuleList(PackagingSource packagingSource = null); - IEnumerable GetThemeList(PackagingSource packagingSource = null); + IEnumerable GetExtensionList(PackagingSource packagingSource = null, Func, IQueryable> query = null); + int GetExtensionCount(PackagingSource packagingSource = null, Func, IQueryable> query = null); } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackagingEntry.cs b/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackagingEntry.cs index 3db78265e..aa5258fe4 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackagingEntry.cs +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackagingEntry.cs @@ -17,5 +17,6 @@ namespace Orchard.Packaging.Services { public string IconUrl { get; set; } public double Rating { get; set; } public int RatingsCount { get; set; } + public int DownloadCount { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackagingServices.cs b/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackagingServices.cs deleted file mode 100644 index eae39c50e..000000000 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackagingServices.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Orchard.Environment; -using Orchard.Environment.Configuration; -using Orchard.Localization; - -namespace Orchard.Packaging.Services { - /// - /// Provides generic packaging related methods. - /// - public class PackagingServices : IPackagingServices { - private readonly IOrchardServices _orchardServices; - private readonly ShellSettings _shellSettings; - - public PackagingServices(IOrchardServices orchardServices, - ShellSettings shellSettings) { - _orchardServices = orchardServices; - _shellSettings = shellSettings; - - T = NullLocalizer.Instance; - } - - public Localizer T { get; set; } - - /// - /// Verifies if the current user is allowed to manage packages. The super user of the default tenant site is always allowed. - /// - /// True if the allowed; False otherwise. - public bool CanManagePackages() { - // Check if super user for default tenant site - if (_shellSettings.Name == ShellSettings.DefaultName - && _orchardServices.WorkContext.CurrentUser.UserName == _orchardServices.WorkContext.CurrentSite.SuperUser) { - - return true; - } - - // Check if it has permission explicitly assigned - return _orchardServices.Authorizer.Authorize(Permissions.ManagePackages, T("Not authorized to manage packages.")); - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackagingSourceManager.cs b/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackagingSourceManager.cs index 15ebd5f3a..bd8218c5b 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackagingSourceManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackagingSourceManager.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using Orchard.Data; using Orchard.Environment.Extensions; -using Orchard.Environment.Extensions.Models; using Orchard.Localization; using Orchard.Packaging.GalleryServer; using Orchard.Packaging.Models; @@ -42,30 +42,42 @@ namespace Orchard.Packaging.Services { } } - public IEnumerable GetModuleList(PackagingSource packagingSource = null) { - return GetExtensionList(DefaultExtensionTypes.Module, packagingSource); - } - public IEnumerable GetThemeList(PackagingSource packagingSource = null) { - return GetExtensionList(DefaultExtensionTypes.Theme, packagingSource); - } - - private IEnumerable GetExtensionList(string filter = null, PackagingSource packagingSource = null) { + public IEnumerable GetExtensionList(PackagingSource packagingSource = null, Func, IQueryable> query = null) { return (packagingSource == null ? GetSources() : new[] {packagingSource}) .SelectMany( source => { - GalleryFeedContext galleryFeedContext = new GalleryFeedContext(new Uri(source.FeedUrl)); - return galleryFeedContext.Packages - .Where(p => p.PackageType == filter) - .ToList() - .Select(p => { - PublishedScreenshot firstScreenshot = galleryFeedContext.Screenshots - .Where(s => s.PublishedPackageId == p.Id && s.PublishedPackageVersion == p.Version) - .ToList() - .FirstOrDefault(); - return CreatePackageEntry(p, firstScreenshot, packagingSource, galleryFeedContext.GetReadStreamUri(p)); - }); + var galleryFeedContext = new GalleryFeedContext(new Uri(source.FeedUrl)); + IQueryable packages = galleryFeedContext.Packages; + + if (query != null) { + packages = query(packages); + } + + return packages.ToList().Select( + p => { + PublishedScreenshot firstScreenshot = galleryFeedContext.Screenshots + .Where(s => s.PublishedPackageId == p.Id && s.PublishedPackageVersion == p.Version) + .ToList() + .FirstOrDefault(); + return CreatePackageEntry(p, firstScreenshot, packagingSource, galleryFeedContext.GetReadStreamUri(p)); + }); } - ).ToArray(); + ); + } + + public int GetExtensionCount(PackagingSource packagingSource = null, Func, IQueryable> query = null) { + return (packagingSource == null ? GetSources() : new[] { packagingSource }) + .Sum( source => { + var galleryFeedContext = new GalleryFeedContext(new Uri(source.FeedUrl)); + IQueryable packages = galleryFeedContext.Packages; + + if (query != null) { + packages = query(packages); + } + + return packages.Count(); + } + ); } private static PackagingEntry CreatePackageEntry(PublishedPackage package, PublishedScreenshot screenshot, PackagingSource source, Uri downloadUri) { @@ -91,7 +103,8 @@ namespace Orchard.Packaging.Services { IconUrl = iconUrl, FirstScreenshot = firstScreenshot, Rating = package.Rating, - RatingsCount = package.RatingsCount + RatingsCount = package.RatingsCount, + DownloadCount = package.DownloadCount }; } diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Styles/orchard-packaging-admin.css b/src/Orchard.Web/Modules/Orchard.Packaging/Styles/orchard-packaging-admin.css index 68ad245ef..cb15f2877 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Styles/orchard-packaging-admin.css +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Styles/orchard-packaging-admin.css @@ -46,4 +46,19 @@ .screenshotThumbnail .thumbnail { width: 171px; height: 128px; +} + +.ratings { + background:url(../Content/Images/stars.png) repeat-x; + position: relative; + height: 14px; + width: 75px; + display: block; + float: left; + clear: both; +} +.score { + background: url(../Content/Images/stars.png) repeat-x 0 -14px; + position: absolute; + width: 45px; } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/ViewModels/PackagingExtensionsViewModel.cs b/src/Orchard.Web/Modules/Orchard.Packaging/ViewModels/PackagingExtensionsViewModel.cs index a4d764d3f..3e366e279 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/ViewModels/PackagingExtensionsViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Packaging/ViewModels/PackagingExtensionsViewModel.cs @@ -7,5 +7,18 @@ namespace Orchard.Packaging.ViewModels { public IEnumerable Extensions { get; set; } public IEnumerable Sources { get; set; } public PackagingSource SelectedSource { get; set; } + public PackagingExtensionsOptions Options { get; set; } + public dynamic Pager { get; set; } + } + + public class PackagingExtensionsOptions { + public int? SourceId { get; set; } + public PackagingExtensionsOrder Order { get; set; } + } + + public enum PackagingExtensionsOrder { + Downloads, + Ratings, + Alphanumeric } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Views/Gallery/Modules.cshtml b/src/Orchard.Web/Modules/Orchard.Packaging/Views/Gallery/Modules.cshtml index 612f24f1e..07e33c90a 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Views/Gallery/Modules.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Views/Gallery/Modules.cshtml @@ -1,7 +1,17 @@ @model Orchard.Packaging.ViewModels.PackagingExtensionsViewModel +@using Orchard.Packaging.ViewModels; @using System.Linq; -@{ Style.Require("PackagingAdmin"); } +@{ + Style.Require("PackagingAdmin"); + + var pageSizes = new List() { 10, 50, 100 }; + var defaultPageSize = WorkContext.CurrentSite.PageSize; + if(!pageSizes.Contains(defaultPageSize)) { + pageSizes.Add(defaultPageSize); + } + +}

@Html.TitleForPage(T("Browse Gallery - Modules").Text)

@@ -14,56 +24,77 @@ @Html.SelectOption(source.Id, Model.SelectedSource != null && Model.SelectedSource.Id == source.Id, source.FeedTitle) } + +
+ + + + +
-} -@if (Model.Extensions.Count() > 0) { -
    - @foreach (var item in Model.Extensions) { -
  • - @{ - string iconUrl = @item.IconUrl; - if (string.IsNullOrWhiteSpace(iconUrl)) { - iconUrl = Href("../../Content/Images/ModuleDefaultIcon.png"); - } - } + if (Model.Extensions.Count() > 0) { +
      + @foreach (var item in Model.Extensions) { +
    • + @{ + string iconUrl = @item.IconUrl; + if (string.IsNullOrWhiteSpace(iconUrl)) { + iconUrl = Href("../../Content/Images/ModuleDefaultIcon.png"); + } + } -
      -
      -
      - @if (!string.IsNullOrWhiteSpace(item.GalleryDetailsUrl)) { - -

      @item.Title - @T("Version: {0}", item.Version)

      -
      - } else { -

      @item.Title - @T("Version: {0}", item.Version)

      - } -
      +
      +
      +
      + @if (!string.IsNullOrWhiteSpace(item.GalleryDetailsUrl)) { + +

      @item.Title - @T("Version: {0}", item.Version)

      +
      + } else { +

      @item.Title - @T("Version: {0}", item.Version)

      + } +
      - +
      +
       
      +
      -
      -

      @(item.Description == null ? T("(No description").Text : item.Description)

      -
        -
      • @T("Last Updated: {0}", DateTime.Now.ToLocalTime())
      • -
      •  | @T("Author: {0}", !string.IsNullOrEmpty(item.Authors) ? item.Authors : T("Unknown").ToString())
      • -
      •  | @T("Rating: {0}", item.Rating)
      • -
      •  | @T("Ratings Count: {0}", item.RatingsCount)
      • -
      •  | @T("Website: ") - @if (!string.IsNullOrEmpty(item.ProjectUrl)) { @item.ProjectUrl } else { @T("Unknown").ToString() } -
      • -
      -
      -
      + -
      - module -
      -
      -
    • } -
    +
    +

    @(item.Description == null ? T("(No description").Text : item.Description)

    +
      +
    • @T("Last Updated: {0}", DateTime.Now.ToLocalTime())
    • +
    •  | @T("Author: {0}", !string.IsNullOrEmpty(item.Authors) ? item.Authors : T("Unknown").ToString())
    • +
    •  | @T("Downloads: {0}", item.DownloadCount)
    • +
    •  | @T("Website: ") + @if (!string.IsNullOrEmpty(item.ProjectUrl)) { @item.ProjectUrl } else { @T("Unknown").ToString() } +
    • +
    +
    + + +
    + module +
    + +
  • } +
+ } + + @Display(Model.Pager) } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Views/Gallery/Themes.cshtml b/src/Orchard.Web/Modules/Orchard.Packaging/Views/Gallery/Themes.cshtml index 313d972e9..20de75839 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Views/Gallery/Themes.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Views/Gallery/Themes.cshtml @@ -1,7 +1,17 @@ @model Orchard.Packaging.ViewModels.PackagingExtensionsViewModel +@using Orchard.Packaging.ViewModels; @using System.Linq; -@{ Style.Require("PackagingAdmin"); } +@{ + Style.Require("PackagingAdmin"); + + var pageSizes = new List() { 10, 50, 100 }; + var defaultPageSize = WorkContext.CurrentSite.PageSize; + if(!pageSizes.Contains(defaultPageSize)) { + pageSizes.Add(defaultPageSize); + } + +}

@Html.TitleForPage(T("Browse Gallery - Themes").Text)

@@ -14,63 +24,82 @@ @Html.SelectOption(source.Id, Model.SelectedSource != null && Model.SelectedSource.Id == source.Id, source.FeedTitle) } + +
+ + + + +
-} -@if (Model.Extensions.Count() > 0) { -
    - @foreach (var item in Model.Extensions) { -
  • - @{ - string extensionClass = "iconThumbnail"; - string iconUrl = @item.IconUrl; - if (!string.IsNullOrWhiteSpace(@item.FirstScreenshot)) { - iconUrl = @item.FirstScreenshot; - extensionClass = "screenshotThumbnail"; - } - else if (string.IsNullOrWhiteSpace(iconUrl)) { - iconUrl = Href("../../Content/Images/imagePlaceholder.png"); - extensionClass = "screenshotThumbnail"; - } - } + if (Model.Extensions.Count() > 0) { +
      + @foreach (var item in Model.Extensions) { +
    • + @{ + string extensionClass = "iconThumbnail"; + string iconUrl = @item.IconUrl; + if (!string.IsNullOrWhiteSpace(@item.FirstScreenshot)) { + iconUrl = @item.FirstScreenshot; + extensionClass = "screenshotThumbnail"; + } + else if (string.IsNullOrWhiteSpace(iconUrl)) { + iconUrl = Href("../../Content/Images/imagePlaceholder.png"); + extensionClass = "screenshotThumbnail"; + } + } -
      -
      -
      - @if (!string.IsNullOrWhiteSpace(item.GalleryDetailsUrl)) { - -

      @item.Title - @T("Version: {0}", item.Version)

      -
      - } else { -

      @item.Title - @T("Version: {0}", item.Version)

      - } -
      +
      +
      +
      + @if (!string.IsNullOrWhiteSpace(item.GalleryDetailsUrl)) { + +

      @item.Title - @T("Version: {0}", item.Version)

      +
      + } else { +

      @item.Title - @T("Version: {0}", item.Version)

      + } +
      - +
      +
       
      +
      -
      -

      @(item.Description == null ? T("(No description").Text : item.Description)

      -
        -
      • @T("Last Updated: {0}", DateTime.Now.ToLocalTime())
      • -
      •  | @T("Author: {0}", !string.IsNullOrEmpty(item.Authors) ? item.Authors : T("Unknown").ToString())
      • -
      •  | @T("Rating: {0}", item.Rating)
      • -
      •  | @T("Ratings Count: {0}", item.RatingsCount)
      • -
      •  | @T("Website: ") - @if(!string.IsNullOrEmpty(item.ProjectUrl)) { @item.ProjectUrl } - else { @T("Unknown").ToString() } -
      • -
      -
      -
      + -
      - theme -
      -
      -
    • } -
    +
    +

    @(item.Description == null ? T("(No description").Text : item.Description)

    +
      +
    • @T("Last Updated: {0}", DateTime.Now.ToLocalTime())
    • +
    •  | @T("Author: {0}", !string.IsNullOrEmpty(item.Authors) ? item.Authors : T("Unknown").ToString())
    • +
    •  | @T("Downloads: {0}", item.DownloadCount)
    • +
    •  | @T("Website: ") + @if(!string.IsNullOrEmpty(item.ProjectUrl)) { @item.ProjectUrl } + else { @T("Unknown").ToString() } +
    • +
    +
    + + +
    + theme +
    + +
  • } +
+ } } \ No newline at end of file