--HG--
branch : 1.x
This commit is contained in:
Renaud Paquay
2011-01-07 23:52:32 -08:00
49 changed files with 1679 additions and 501 deletions

View File

@@ -124,7 +124,7 @@
</Target> </Target>
<Target Name="Package-SqlCe"> <Target Name="Package-SqlCe">
<ItemGroup> <ItemGroup>
<SqlCeBinariesx86 Include="$(LibFolder)\sqlce\x86\*.*" /> <SqlCeBinariesx86 Include="$(LibFolder)\sqlce\x86\*.*" />
<SqlCeBinariesx64 Include="$(LibFolder)\sqlce\amd64\*.*" /> <SqlCeBinariesx64 Include="$(LibFolder)\sqlce\amd64\*.*" />
</ItemGroup> </ItemGroup>
@@ -133,12 +133,10 @@
</Target> </Target>
<Target Name="Package-Stage"> <Target Name="Package-Stage">
<Exec
<Exec Command="&quot;$(ServiceHostingSDKBinDir)cspack&quot; &quot;$(SrcFolder)\Orchard.Azure\Orchard.Azure.CloudService\ServiceDefinition.build.csdef&quot; /role:Orchard.Azure.Web;&quot;$(CloudRootFolder)&quot;;Orchard.Azure.Web.dll /sites:Orchard.Azure.Web;Web;&quot;$(CloudRootFolder)&quot; /rolePropertiesFile:Orchard.Azure.Web;&quot;$(ServiceFolder)\Properties.txt&quot; /out:&quot;$(StageFolder)\Orchard.Azure.Web.cspkg&quot;"
Command="&quot;$(ServiceHostingSDKBinDir)cspack&quot; &quot;$(ServiceFolder)\ServiceDefinition.build.csdef&quot; /role:Orchard.Azure.Web;&quot;$(CloudRootFolder)&quot;;Orchard.Azure.Web.dll /rolePropertiesFile:Orchard.Azure.Web;&quot;$(ServiceFolder)\Properties.txt&quot; /out:&quot;$(StageFolder)\Orchard.Azure.Web.cspkg&quot;" WorkingDirectory="$(CloudRootFolder)"
WorkingDirectory="$(CloudRootFolder)" />
/>
</Target> </Target>
<Target Name="Package-Zip"> <Target Name="Package-Zip">

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -114,6 +114,10 @@
<Reference Include="System.Web.WebPages"> <Reference Include="System.Web.WebPages">
<HintPath>..\..\..\lib\aspnetmvc\System.Web.WebPages.dll</HintPath> <HintPath>..\..\..\lib\aspnetmvc\System.Web.WebPages.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Web.WebPages.Deployment, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\lib\aspnetmvc\System.Web.WebPages.Deployment.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages.Razor"> <Reference Include="System.Web.WebPages.Razor">
<HintPath>..\..\..\lib\aspnetmvc\System.Web.WebPages.Razor.dll</HintPath> <HintPath>..\..\..\lib\aspnetmvc\System.Web.WebPages.Razor.dll</HintPath>
</Reference> </Reference>

View File

@@ -1,27 +1,28 @@
Feature: Addition Feature: Addition
In order to prevent security model regressions In order to prevent security model regressions
As a user with specific permissions As a user with specific permissions
I should to be granted or denied access to various actions I should to be granted or denied access to various actions
@security @security
Scenario: Login can be automated Scenario: Login can be automated
Given I have installed Orchard Given I have installed Orchard
And I have a user "bob" with permissions "AccessFrontEnd" And I have a user "bob" with permissions "AccessFrontEnd"
When I go to "users/account/logoff" When I go to "users/account/logoff"
And I go to "users/account/logon" And I go to "users/account/logon"
And I fill in And I fill in
| name | value | | name | value |
| userNameOrEmail | bob | | userNameOrEmail | bob |
| password | qwerty123! | | password | qwerty123! |
And I hit "Sign In" And I hit "Sign In"
And I am redirected And I am redirected
Then I should see "Welcome, <strong>bob</strong>!" Then I should see "Welcome"
And I should see "bob"
@security
Scenario: Anonymous user can see the home page but not the dashboard @security
Given I have installed Orchard Scenario: Anonymous user can see the home page but not the dashboard
And I have a user "bob" with permissions "AccessFrontEnd" Given I have installed Orchard
When I sign in as "bob" And I have a user "bob" with permissions "AccessFrontEnd"
Then I should see "this is the homepage of your new site" when I go to "/" When I sign in as "bob"
And I should be denied access when I go to "admin" Then I should see "this is the homepage of your new site" when I go to "/"
And I should be denied access when I go to "admin"

View File

@@ -1,7 +1,7 @@
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by SpecFlow (http://www.specflow.org/). // This code was generated by SpecFlow (http://www.specflow.org/).
// SpecFlow Version:1.4.0.0 // SpecFlow Version:1.5.0.0
// Runtime Version:4.0.30319.1 // Runtime Version:4.0.30319.1
// //
// Changes to this file may cause incorrect behavior and will be lost if // Changes to this file may cause incorrect behavior and will be lost if
@@ -14,7 +14,7 @@ namespace Orchard.Specs
using TechTalk.SpecFlow; using TechTalk.SpecFlow;
[System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.4.0.0")] [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.5.0.0")]
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[NUnit.Framework.TestFixtureAttribute()] [NUnit.Framework.TestFixtureAttribute()]
[NUnit.Framework.DescriptionAttribute("Addition")] [NUnit.Framework.DescriptionAttribute("Addition")]
@@ -30,8 +30,8 @@ namespace Orchard.Specs
public virtual void FeatureSetup() public virtual void FeatureSetup()
{ {
testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner();
TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Addition", "In order to prevent security model regressions\nAs a user with specific permission" + TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Addition", "In order to prevent security model regressions\r\nAs a user with specific permissio" +
"s\nI should to be granted or denied access to various actions", GenerationTargetLanguage.CSharp, ((string[])(null))); "ns\r\nI should to be granted or denied access to various actions", GenerationTargetLanguage.CSharp, ((string[])(null)));
testRunner.OnFeatureStart(featureInfo); testRunner.OnFeatureStart(featureInfo);
} }
@@ -87,7 +87,9 @@ this.ScenarioSetup(scenarioInfo);
#line 17 #line 17
testRunner.And("I am redirected"); testRunner.And("I am redirected");
#line 18 #line 18
testRunner.Then("I should see \"Welcome, <strong>bob</strong>!\""); testRunner.Then("I should see \"Welcome\"");
#line 19
testRunner.And("I should see \"bob\"");
#line hidden #line hidden
testRunner.CollectScenarioErrors(); testRunner.CollectScenarioErrors();
} }
@@ -99,17 +101,17 @@ this.ScenarioSetup(scenarioInfo);
{ {
TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Anonymous user can see the home page but not the dashboard", new string[] { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("Anonymous user can see the home page but not the dashboard", new string[] {
"security"}); "security"});
#line 21
this.ScenarioSetup(scenarioInfo);
#line 22 #line 22
testRunner.Given("I have installed Orchard"); this.ScenarioSetup(scenarioInfo);
#line 23 #line 23
testRunner.And("I have a user \"bob\" with permissions \"AccessFrontEnd\""); testRunner.Given("I have installed Orchard");
#line 24 #line 24
testRunner.When("I sign in as \"bob\""); testRunner.And("I have a user \"bob\" with permissions \"AccessFrontEnd\"");
#line 25 #line 25
testRunner.Then("I should see \"this is the homepage of your new site\" when I go to \"/\""); testRunner.When("I sign in as \"bob\"");
#line 26 #line 26
testRunner.Then("I should see \"this is the homepage of your new site\" when I go to \"/\"");
#line 27
testRunner.And("I should be denied access when I go to \"admin\""); testRunner.And("I should be denied access when I go to \"admin\"");
#line hidden #line hidden
testRunner.CollectScenarioErrors(); testRunner.CollectScenarioErrors();

View File

@@ -51,4 +51,4 @@ Scenario: Calling setup on a brand new install
And I hit "Finish Setup" And I hit "Finish Setup"
And I go to "/" And I go to "/"
Then I should see "My Site" Then I should see "My Site"
And I should see "Welcome, <strong>admin</strong>!" And I should see "Welcome, <strong><a href="/Users/Account/ChangePassword">admin</a></strong>!"

View File

@@ -1,7 +1,7 @@
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by SpecFlow (http://www.specflow.org/). // This code was generated by SpecFlow (http://www.specflow.org/).
// SpecFlow Version:1.4.0.0 // SpecFlow Version:1.5.0.0
// Runtime Version:4.0.30319.1 // Runtime Version:4.0.30319.1
// //
// Changes to this file may cause incorrect behavior and will be lost if // Changes to this file may cause incorrect behavior and will be lost if
@@ -14,7 +14,7 @@ namespace Orchard.Specs
using TechTalk.SpecFlow; using TechTalk.SpecFlow;
[System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.4.0.0")] [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "1.5.0.0")]
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[NUnit.Framework.TestFixtureAttribute()] [NUnit.Framework.TestFixtureAttribute()]
[NUnit.Framework.DescriptionAttribute("Setup")] [NUnit.Framework.DescriptionAttribute("Setup")]
@@ -212,7 +212,8 @@ this.ScenarioSetup(scenarioInfo);
#line 53 #line 53
testRunner.Then("I should see \"My Site\""); testRunner.Then("I should see \"My Site\"");
#line 54 #line 54
testRunner.And("I should see \"Welcome, <strong>admin</strong>!\""); testRunner.And("I should see \"Welcome, <strong><a href=\"/Users/Account/ChangePassword\">admin</a><" +
"/strong>!\"");
#line hidden #line hidden
testRunner.CollectScenarioErrors(); testRunner.CollectScenarioErrors();
} }

View File

@@ -11,6 +11,8 @@ using Orchard.Tests.Stubs;
namespace Orchard.Tests.Modules.Packaging { namespace Orchard.Tests.Modules.Packaging {
[TestFixture] [TestFixture]
public class PackageBuilderTests : ContainerTestBase { public class PackageBuilderTests : ContainerTestBase {
private const string PackageIdentifier = "Hello.World";
protected override void Register(Autofac.ContainerBuilder builder) { protected override void Register(Autofac.ContainerBuilder builder) {
builder.RegisterType<PackageBuilder>().As<IPackageBuilder>(); builder.RegisterType<PackageBuilder>().As<IPackageBuilder>();
builder.RegisterType<InMemoryWebSiteFolder>().As<IWebSiteFolder>() builder.RegisterType<InMemoryWebSiteFolder>().As<IWebSiteFolder>()
@@ -27,7 +29,7 @@ namespace Orchard.Tests.Modules.Packaging {
return packageBuilder.BuildPackage(new ExtensionDescriptor { return packageBuilder.BuildPackage(new ExtensionDescriptor {
ExtensionType = DefaultExtensionTypes.Module, ExtensionType = DefaultExtensionTypes.Module,
Id = "Hello.World", Id = PackageIdentifier,
Version = "1.0", Version = "1.0",
Description = "a", Description = "a",
Author = "b" Author = "b"
@@ -41,7 +43,7 @@ namespace Orchard.Tests.Modules.Packaging {
var package = Package.Open(stream); var package = Package.Open(stream);
Assert.That(package, Is.Not.Null); Assert.That(package, Is.Not.Null);
Assert.That(package.PackageProperties.Identifier, Is.EqualTo("Orchard.Module.Hello.World")); Assert.That(package.PackageProperties.Identifier, Is.EqualTo(PackageBuilder.BuildPackageId(PackageIdentifier, DefaultExtensionTypes.Module)));
} }
[Test] [Test]

View File

@@ -371,6 +371,9 @@
<ItemGroup> <ItemGroup>
<Content Include="Containers\Views\Parts.Container.Contained.SummaryAdmin.cshtml" /> <Content Include="Containers\Views\Parts.Container.Contained.SummaryAdmin.cshtml" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Content Include="Shapes\Views\ShapeResult\Display.cshtml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" /> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -0,0 +1 @@
@Display(Model)

View File

@@ -2,12 +2,14 @@
<div class="user-display"> <div class="user-display">
@if (Request.IsAuthenticated) { @if (Request.IsAuthenticated) {
<span class="welcome">@T("Welcome, <strong>{0}</strong>!", WorkContext.CurrentUser.UserName)</span> <span class="user-actions welcome">
<span class="user-actions"> @T("Welcome, <strong>{0}</strong>!", new HtmlString(Html.ActionLink( WorkContext.CurrentUser.UserName, "ChangePassword", new { Controller = "Account", Area = "Orchard.Users" }).ToString()))
@Html.ActionLink(T("Sign Out").ToString(), "LogOff", new { Controller = "Account", Area = "Orchard.Users", ReturnUrl = Context.Request.RawUrl }) </span>
@Html.ActionLink("Dashboard", "Index", new { Area = "Dashboard", Controller = "Admin" }) <span class="user-actions">
</span> @Html.ActionLink(T("Sign Out").ToString(), "LogOff", new { Controller = "Account", Area = "Orchard.Users", ReturnUrl = Context.Request.RawUrl })
@Html.ActionLink("Dashboard", "Index", new { Area = "Dashboard", Controller = "Admin" })
</span>
} else { } else {
<span class="user-actions">@Html.ActionLink(T("Sign In").ToString(), "LogOn", new { Controller = "Account", Area = "Orchard.Users", ReturnUrl = Context.Request.RawUrl })</span> <span class="user-actions">@Html.ActionLink(T("Sign In").ToString(), "LogOn", new { Controller = "Account", Area = "Orchard.Users", ReturnUrl = Context.Request.RawUrl })</span>
} }
</div> </div>

View File

@@ -1,8 +1,11 @@
@model Orchard.ContentTypes.ViewModels.EditTypePartViewModel @model Orchard.ContentTypes.ViewModels.EditTypePartViewModel
@using Orchard.Core.Contents.Settings;
<fieldset class="manage-part" itemscope="itemscope" itemid="@Model.PartDefinition.Name" itemtype="http://orchardproject.net/data/ContentTypePart"> <fieldset class="manage-part" itemscope="itemscope" itemid="@Model.PartDefinition.Name" itemtype="http://orchardproject.net/data/ContentTypePart">
<h3 itemprop="Name">@Model.PartDefinition.DisplayName</h3> <h3 itemprop="Name">@Model.PartDefinition.DisplayName</h3>
<div class="manage"> <div class="manage">
@Html.ActionLink(T("Remove").Text, "RemovePartFrom", new { area = "Orchard.ContentTypes", id = Model.Type.Name, Model.PartDefinition.Name }, new { itemprop = "RemoveUrl UnsafeUrl" }) @* <- some experimentation *@ @if (Model.PartDefinition.Settings.GetModel<ContentPartSettings>().Attachable) {
@Html.ActionLink(T("Remove").Text, "RemovePartFrom", new { area = "Orchard.ContentTypes", id = Model.Type.Name, Model.PartDefinition.Name }, new { itemprop = "RemoveUrl UnsafeUrl" });
}
</div> </div>
<div class="details">@Html.EditorFor(m => m.PartDefinition.Fields, "TypePartFields", "PartDefinition") <div class="details">@Html.EditorFor(m => m.PartDefinition.Fields, "TypePartFields", "PartDefinition")
@if (Model.Templates.Any()) { @if (Model.Templates.Any()) {

View File

@@ -84,25 +84,25 @@ namespace Orchard.Experimental.Controllers {
public ActionResult UsingShapes() { public ActionResult UsingShapes() {
ViewModel.Page = Shape.Page() ViewBag.Page = Shape.Page()
.Main(Shape.Zone(typeof (Array), Name: "Main")) .Main(Shape.Zone(typeof (Array), Name: "Main"))
.Messages(Shape.Zone(typeof (Array), Name: "Messages")) .Messages(Shape.Zone(typeof (Array), Name: "Messages"))
.Sidebar(Shape.Zone(typeof (Array), Name: "Sidebar")); .Sidebar(Shape.Zone(typeof (Array), Name: "Sidebar"));
//ViewModel.Page.Add("Messages:5", New.Message(Content: T("This is a test"), Severity: "Really bad!!!")); //ViewModel.Page.Add("Messages:5", New.Message(Content: T("This is a test"), Severity: "Really bad!!!"));
ViewModel.Page.Messages.Add( ViewBag.Page.Messages.Add(
Shape.Message(Content: T("This is a test"), Severity: "Really bad!!!")); Shape.Message(Content: T("This is a test"), Severity: "Really bad!!!"));
ViewModel.Page.Sidebar.Add( ViewBag.Page.Sidebar.Add(
Shape.Link(Url: "http://orchard.codeplex.com", Content: Shape.Image(Url: "http://orchardproject.net/Content/images/orchardLogo.jpg").Attributes(new { @class = "bigredborderfromabadclassname" }))); Shape.Link(Url: "http://orchard.codeplex.com", Content: Shape.Image(Url: "http://orchardproject.net/Content/images/orchardLogo.jpg").Attributes(new { @class = "bigredborderfromabadclassname" })));
var model = Shape.Message( var model = Shape.Message(
Content: Shape.Explosion(Height: 100, Width: 200), Content: Shape.Explosion(Height: 100, Width: 200),
Severity: "Meh"); Severity: "Meh");
ViewModel.Page.Messages.Add(new HtmlString("<hr/>abuse<hr/>")); ViewBag.Page.Messages.Add(new HtmlString("<hr/>abuse<hr/>"));
ViewModel.Page.Messages.Add("<hr/>encoded<hr/>"); ViewBag.Page.Messages.Add("<hr/>encoded<hr/>");
return View(model); return View(model);
} }

View File

@@ -103,8 +103,7 @@ namespace Orchard.Indexing.Services {
? _repository.Fetch(x => true).ToArray() ? _repository.Fetch(x => true).ToArray()
: _repository.Fetch(x => x.CreatedUtc >= lastIndexUtc).ToArray(); // CreatedUtc and lastIndexUtc might be equal if a content item is created in a background task : _repository.Fetch(x => x.CreatedUtc >= lastIndexUtc).ToArray(); // CreatedUtc and lastIndexUtc might be equal if a content item is created in a background task
// nothing to do ?)))
// nothing to do ?
if (taskRecords.Length + updateIndexDocuments.Count == 0) { if (taskRecords.Length + updateIndexDocuments.Count == 0) {
Logger.Information("Index update requested, nothing to do"); Logger.Information("Index update requested, nothing to do");
return; return;
@@ -140,7 +139,7 @@ namespace Orchard.Indexing.Services {
try { try {
var documentIndex = _indexProvider.New(task.ContentItem.Id); var documentIndex = _indexProvider.New(task.ContentItem.Id);
_contentManager.Index(task.ContentItem, documentIndex); _contentManager.Index(task.ContentItem, documentIndex);
if (documentIndex.IsDirty) { if (!addedContentItemIds.Contains(task.ContentItem.Id.ToString()) && documentIndex.IsDirty) {
updateIndexDocuments.Add(documentIndex); updateIndexDocuments.Add(documentIndex);
} }

View File

@@ -58,16 +58,18 @@ namespace Orchard.Modules.Services {
public void EnableFeatures(IEnumerable<string> features, bool force) { public void EnableFeatures(IEnumerable<string> features, bool force) {
var shellDescriptor = _shellDescriptorManager.GetShellDescriptor(); var shellDescriptor = _shellDescriptorManager.GetShellDescriptor();
var enabledFeatures = shellDescriptor.Features.ToList(); var enabledFeatures = shellDescriptor.Features.ToList();
var availableFeatures = GetAvailableFeatures().ToList();
var featuresToEnable = var featuresToEnable = features
features.Select(s => EnableFeature(s, GetAvailableFeatures(), force)). .Select(s => EnableFeature(s, availableFeatures, force)).ToList()
SelectMany(ies => ies.Select(s => s)); .SelectMany(ies => ies.Select(s => s));
if (featuresToEnable.Count() == 0) if (featuresToEnable.Count() == 0)
return; return;
foreach (var featureToEnable in featuresToEnable) { foreach (var featureToEnable in featuresToEnable) {
enabledFeatures.Add(new ShellFeature {Name = featureToEnable}); var feature = featureToEnable;
enabledFeatures.Add(new ShellFeature { Name = feature });
Services.Notifier.Information(T("{0} was enabled", featureToEnable)); Services.Notifier.Information(T("{0} was enabled", featureToEnable));
} }
@@ -84,9 +86,9 @@ namespace Orchard.Modules.Services {
var enabledFeatures = shellDescriptor.Features.ToList(); var enabledFeatures = shellDescriptor.Features.ToList();
var availableFeatures = GetAvailableFeatures().ToList(); var availableFeatures = GetAvailableFeatures().ToList();
var featuresToDisable = var featuresToDisable = features
features.Select(s => DisableFeature(s, availableFeatures, force)).SelectMany( .Select(s => DisableFeature(s, availableFeatures, force)).ToList()
ies => ies.Select(s => s)); .SelectMany(ies => ies.Select(s => s));
if (featuresToDisable.Count() == 0) if (featuresToDisable.Count() == 0)
return; return;

View File

@@ -25,7 +25,10 @@
<ul class="pageStatus" style="color:#666; margin:.6em 0 0 0;"> <ul class="pageStatus" style="color:#666; margin:.6em 0 0 0;">
<li>@T("Features: {0}", MvcHtmlString.Create(string.Join(", ", module.Features.Select(f => Html.Link(string.IsNullOrEmpty(f.Name) ? f.Id : f.Name, string.Format("{0}#{1}", Url.Action("features", new { area = "Orchard.Modules" }), f.Id.AsFeatureId(n => T(n)))).ToString()).OrderBy(s => s).ToArray())))</li> <li>@T("Features: {0}", MvcHtmlString.Create(string.Join(", ", module.Features.Select(f => Html.Link(string.IsNullOrEmpty(f.Name) ? f.Id : f.Name, string.Format("{0}#{1}", Url.Action("features", new { area = "Orchard.Modules" }), f.Id.AsFeatureId(n => T(n)))).ToString()).OrderBy(s => s).ToArray())))</li>
<li>&nbsp;&#124;&nbsp;@T("Author: {0}", !string.IsNullOrEmpty(module.Author) ? module.Author : T("Unknown").ToString())</li> <li>&nbsp;&#124;&nbsp;@T("Author: {0}", !string.IsNullOrEmpty(module.Author) ? module.Author : T("Unknown").ToString())</li>
<li>&nbsp;&#124;&nbsp;@T("Website: {0}", !string.IsNullOrEmpty(module.WebSite) ? module.WebSite : "http://orchardproject.net")</li> <li>&nbsp;&#124;&nbsp;@T("Website: ")
@if (!string.IsNullOrEmpty(module.WebSite)) { <a href="@module.WebSite">@module.WebSite</a> }
else { @T("Unknown").ToString() }
</li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -4,7 +4,6 @@ using System.Web;
using System.Web.Hosting; using System.Web.Hosting;
using Orchard.Commands; using Orchard.Commands;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
using Orchard.Packaging.Services; using Orchard.Packaging.Services;
using Orchard.UI.Notify; using Orchard.UI.Notify;
@@ -39,11 +38,10 @@ namespace Orchard.Packaging.Commands {
} }
// append "Orchard.[ExtensionType]" to prevent conflicts with other packages (e.g, TinyMce, jQuery, ...) // append "Orchard.[ExtensionType]" to prevent conflicts with other packages (e.g, TinyMce, jQuery, ...)
string extensionPrefix = DefaultExtensionTypes.IsTheme(packageData.ExtensionType) ? var filename = string.Format("{0}{1}.{2}.nupkg",
PackagingSourceManager.ThemesPrefix : PackagingSourceManager.GetExtensionPrefix(packageData.ExtensionType),
PackagingSourceManager.ModulesPrefix; packageData.ExtensionName,
packageData.ExtensionVersion);
var filename = string.Format("{0}{1}.{2}.nupkg", extensionPrefix, packageData.ExtensionName, packageData.ExtensionVersion);
if ( !Directory.Exists(path) ) { if ( !Directory.Exists(path) ) {
Directory.CreateDirectory(path); Directory.CreateDirectory(path);
@@ -77,7 +75,11 @@ namespace Orchard.Packaging.Commands {
} }
} }
[CommandHelp("package uninstall <packageId> \r\n\t" + "Uninstall a module or a theme.")] [CommandHelp(@"package uninstall <packageId>
Uninstall a module or a theme.
The <packageId> should take the format Orchard.[Module|Theme].<extensionName>.
For example, ""package uninstall Orchard.Module.SampleModule"" will uninstall the Module under the ""~/Modules/SampleModule"" directory and
""package uninstall Orchard.Theme.SampleTheme"" will uninstall the Theme under the ""~/Themes/SampleTheme"" directory.")]
[CommandName("package uninstall")] [CommandName("package uninstall")]
public void UninstallPackage(string packageId) { public void UninstallPackage(string packageId) {
try { try {

View File

@@ -6,8 +6,10 @@ using System.Web.Hosting;
using System.Web.Mvc; using System.Web.Mvc;
using System.Xml.Linq; using System.Xml.Linq;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Packaging.Models;
using Orchard.Packaging.Services; using Orchard.Packaging.Services;
using Orchard.Packaging.ViewModels; using Orchard.Packaging.ViewModels;
using Orchard.Security; using Orchard.Security;
@@ -113,7 +115,15 @@ namespace Orchard.Packaging.Controllers {
} }
public ActionResult Modules(int? sourceId) { public ActionResult Modules(int? sourceId) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to list modules"))) return ListExtensions(sourceId, DefaultExtensionTypes.Module, "Modules", source => _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<PackagingSource, PackagingEntry[]> getList) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to list {0}", extensionType)))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
var selectedSource = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault(); var selectedSource = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault();
@@ -126,35 +136,16 @@ namespace Orchard.Packaging.Controllers {
IEnumerable<PackagingEntry> extensions = null; IEnumerable<PackagingEntry> extensions = null;
foreach (var source in sources) { foreach (var source in sources) {
try { try {
var sourceExtensions = _packagingSourceManager.GetModuleList(source).ToArray(); var sourceExtensions = getList(source);
extensions = extensions == null ? sourceExtensions : extensions.Concat(sourceExtensions); extensions = extensions == null ? sourceExtensions : extensions.Concat(sourceExtensions);
} } catch (Exception ex) {
catch (Exception ex) {
Logger.Error(ex, "Error loading extensions from gallery source '{0}'. {1}.", source.FeedTitle, ex.Message); 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)); _notifier.Error(T("Error loading extensions from gallery source '{0}'. {1}.", source.FeedTitle, ex.Message));
} }
} }
return View("Modules", new PackagingExtensionsViewModel { return View(returnView, new PackagingExtensionsViewModel {
Extensions = extensions ?? new PackagingEntry[] {}, Extensions = extensions ?? new PackagingEntry[] { },
Sources = _packagingSourceManager.GetSources().OrderBy(s => s.FeedTitle),
SelectedSource = selectedSource
});
}
public ActionResult Themes(int? sourceId) {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to list themes")))
return new HttpUnauthorizedResult();
var selectedSource = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault();
var sources = selectedSource != null
? new[] { selectedSource }
: _packagingSourceManager.GetSources()
;
return View("Themes", new PackagingExtensionsViewModel {
Extensions = sources.SelectMany(source => _packagingSourceManager.GetThemeList(source)),
Sources = _packagingSourceManager.GetSources().OrderBy(s => s.FeedTitle), Sources = _packagingSourceManager.GetSources().OrderBy(s => s.FeedTitle),
SelectedSource = selectedSource SelectedSource = selectedSource
}); });

View File

@@ -5,6 +5,7 @@ using System.Web.Hosting;
using System.Web.Mvc; using System.Web.Mvc;
using NuGet; using NuGet;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.AppData; using Orchard.FileSystems.AppData;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Mvc.Extensions; using Orchard.Mvc.Extensions;
@@ -14,6 +15,7 @@ using Orchard.Themes;
using Orchard.UI.Admin; using Orchard.UI.Admin;
using Orchard.UI.Notify; using Orchard.UI.Notify;
using IPackageManager = Orchard.Packaging.Services.IPackageManager; using IPackageManager = Orchard.Packaging.Services.IPackageManager;
using PackageBuilder = Orchard.Packaging.Services.PackageBuilder;
namespace Orchard.Packaging.Controllers { namespace Orchard.Packaging.Controllers {
[OrchardFeature("PackagingServices")] [OrchardFeature("PackagingServices")]
@@ -60,7 +62,7 @@ namespace Orchard.Packaging.Controllers {
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to remove themes"))) if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to remove themes")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
return UninstallPackage(PackagingSourceManager.ThemesPrefix + themeId, returnUrl, retryUrl); return UninstallPackage(PackageBuilder.BuildPackageId(themeId, DefaultExtensionTypes.Theme), returnUrl, retryUrl);
} }
public ActionResult AddModule(string returnUrl) { public ActionResult AddModule(string returnUrl) {

View File

@@ -20,7 +20,7 @@ namespace Orchard.Packaging {
public void Installed(Feature feature) { public void Installed(Feature feature) {
if (feature.Descriptor.Id == "Gallery") { if (feature.Descriptor.Id == "Gallery") {
_packagingSourceManager.AddSource("Orchard Extensions Gallery", "http://orchardproject.net/gallery09/server/feedservice.svc"); _packagingSourceManager.AddSource("Orchard Extensions Gallery", "http://orchardproject.net/gallery09/server/FeedService.svc");
} }
} }

View File

@@ -93,6 +93,9 @@
<Compile Include="ViewModels\PackagingSourcesViewModel.cs" /> <Compile Include="ViewModels\PackagingSourcesViewModel.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Content\Images\moduleDefaultIcon.png" />
<Content Include="Content\Images\packageDefaultIcon.png" />
<Content Include="Content\Images\themeDefaultIcon.png" />
<Content Include="Module.txt" /> <Content Include="Module.txt" />
<Content Include="Service References\GalleryServer\Reference.datasvcmap"> <Content Include="Service References\GalleryServer\Reference.datasvcmap">
<Generator>DataServiceClientGenerator</Generator> <Generator>DataServiceClientGenerator</Generator>

View File

@@ -39,7 +39,7 @@ namespace Orchard.Packaging.Services {
public override IQueryable<IPackage> GetPackages() { public override IQueryable<IPackage> GetPackages() {
IEnumerable<IPackage> packages = from extension in _extensionManager.AvailableExtensions() IEnumerable<IPackage> packages = from extension in _extensionManager.AvailableExtensions()
let id = "Orchard." + extension.ExtensionType + "." + extension.Id let id = PackageBuilder.BuildPackageId(extension.Id, extension.ExtensionType)
let version = Version.Parse(extension.Version) let version = Version.Parse(extension.Version)
let package = SourceRepository.FindPackage(id, version) let package = SourceRepository.FindPackage(id, version)
where package != null where package != null

View File

@@ -20,6 +20,7 @@ namespace Orchard.Packaging.Services {
private static readonly string[] _ignoredThemeExtensions = new[] { private static readonly string[] _ignoredThemeExtensions = new[] {
"obj", "pdb", "exclude" "obj", "pdb", "exclude"
}; };
private static readonly string[] _ignoredThemePaths = new[] { private static readonly string[] _ignoredThemePaths = new[] {
"/obj/" "/obj/"
}; };
@@ -61,13 +62,13 @@ namespace Orchard.Packaging.Services {
return context.Stream; return context.Stream;
} }
private static void SetCoreProperties(CreateContext context, ExtensionDescriptor extensionDescriptor) {
string idPrefix = DefaultExtensionTypes.IsTheme(extensionDescriptor.ExtensionType) ?
PackagingSourceManager.ThemesPrefix :
PackagingSourceManager.ModulesPrefix;
context.Builder.Id = idPrefix + extensionDescriptor.Id; public static string BuildPackageId(string extensionName, string extensionType) {
return PackagingSourceManager.GetExtensionPrefix(extensionType) + extensionName;
}
private static void SetCoreProperties(CreateContext context, ExtensionDescriptor extensionDescriptor) {
context.Builder.Id = BuildPackageId(extensionDescriptor.Id, extensionDescriptor.ExtensionType);
context.Builder.Version = new Version(extensionDescriptor.Version); context.Builder.Version = new Version(extensionDescriptor.Version);
context.Builder.Title = extensionDescriptor.Name ?? extensionDescriptor.Id; context.Builder.Title = extensionDescriptor.Name ?? extensionDescriptor.Id;
context.Builder.Description = extensionDescriptor.Description; context.Builder.Description = extensionDescriptor.Description;

View File

@@ -93,19 +93,33 @@ namespace Orchard.Packaging.Services {
return new PackageInfo { return new PackageInfo {
ExtensionName = package.Title ?? package.Id, ExtensionName = package.Title ?? package.Id,
ExtensionVersion = package.Version.ToString(), ExtensionVersion = package.Version.ToString(),
ExtensionType = package.Id.StartsWith(PackagingSourceManager.ThemesPrefix) ? DefaultExtensionTypes.Theme : DefaultExtensionTypes.Module, ExtensionType = package.Id.StartsWith(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Theme)) ? DefaultExtensionTypes.Theme : DefaultExtensionTypes.Module,
ExtensionPath = applicationPath ExtensionPath = applicationPath
}; };
} }
public void Uninstall(string packageId, string applicationPath) { public void Uninstall(string packageId, string applicationPath) {
// this logger is used to render NuGet's log on the notifier
var logger = new NugetLogger(_notifier);
string solutionPath; string solutionPath;
string extensionFullPath = string.Empty;
if (packageId.StartsWith(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Theme))) {
extensionFullPath = HostingEnvironment.MapPath("~/Themes/" + packageId.Substring(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Theme).Length));
} else if (packageId.StartsWith(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Module))) {
extensionFullPath = HostingEnvironment.MapPath("~/Modules/" + packageId.Substring(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Module).Length));
}
if (string.IsNullOrEmpty(extensionFullPath) ||
!Directory.Exists(extensionFullPath)) {
throw new OrchardException(T("Package not found: {0}", packageId));
}
// if we can access the parent directory, and the solution is inside, NuGet-uninstall the package here // if we can access the parent directory, and the solution is inside, NuGet-uninstall the package here
if (TryGetSolutionPath(applicationPath, out solutionPath)) { if (TryGetSolutionPath(applicationPath, out solutionPath)) {
// this logger is used to render NuGet's log on the notifier
var logger = new NugetLogger(_notifier);
var installedPackagesPath = Path.Combine(solutionPath, PackagesPath); var installedPackagesPath = Path.Combine(solutionPath, PackagesPath);
var sourcePackageRepository = new LocalPackageRepository(installedPackagesPath); var sourcePackageRepository = new LocalPackageRepository(installedPackagesPath);
@@ -139,19 +153,10 @@ namespace Orchard.Packaging.Services {
} }
} }
// Make sure folder is deleted (themes scenario where there is no project) // If the package was not installed through nuget we still need to try to uninstall it by removing its directory
string extensionPath = packageId.StartsWith(PackagingSourceManager.ThemesPrefix) if(Directory.Exists(extensionFullPath)) {
? "~/Themes/" + packageId.Substring(PackagingSourceManager.ThemesPrefix.Length)
: "~/Modules/" + packageId.Substring(PackagingSourceManager.ThemesPrefix.Length);
string extensionFullPath = HostingEnvironment.MapPath(extensionPath);
if (Directory.Exists(extensionFullPath)) {
Directory.Delete(extensionFullPath, true); Directory.Delete(extensionFullPath, true);
} }
else {
throw new OrchardException(T("Package not found: ", packageId));
}
} }
private static bool TryGetSolutionPath(string applicationPath, out string parentPath) { private static bool TryGetSolutionPath(string applicationPath, out string parentPath) {

View File

@@ -12,5 +12,9 @@ namespace Orchard.Packaging.Services {
public DateTime LastUpdated { get; set; } public DateTime LastUpdated { get; set; }
public string Authors { get; set; } public string Authors { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string FirstScreenshot { get; set; }
public string IconUrl { get; set; }
public double Rating { get; set; }
public int RatingsCount { get; set; }
} }
} }

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NuGet;
using Orchard.Data; using Orchard.Data;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models; using Orchard.Environment.Extensions.Models;
@@ -12,8 +11,9 @@ using Orchard.Packaging.Models;
namespace Orchard.Packaging.Services { namespace Orchard.Packaging.Services {
[OrchardFeature("Gallery")] [OrchardFeature("Gallery")]
public class PackagingSourceManager : IPackagingSourceManager { public class PackagingSourceManager : IPackagingSourceManager {
public const string ThemesPrefix = "Orchard.Themes."; public static string GetExtensionPrefix(string extensionType) {
public const string ModulesPrefix = "Orchard.Modules."; return string.Format("Orchard.{0}.", extensionType);
}
private readonly IRepository<PackagingSource> _packagingSourceRecordRepository; private readonly IRepository<PackagingSource> _packagingSourceRecordRepository;
@@ -63,19 +63,25 @@ namespace Orchard.Packaging.Services {
} }
private static PackagingEntry CreatePackageEntry(PublishedPackage package, PackagingSource source, Uri downloadUri) { private static PackagingEntry CreatePackageEntry(PublishedPackage package, PackagingSource source, Uri downloadUri) {
PublishedScreenshot firstScreenshot = package.Screenshots.FirstOrDefault();
return new PackagingEntry { return new PackagingEntry {
Title = String.IsNullOrWhiteSpace(package.Title) ? package.Id : package.Title, Title = string.IsNullOrWhiteSpace(package.Title) ? package.Id : package.Title,
PackageId = package.Id, PackageId = package.Id,
PackageStreamUri = downloadUri.ToString(), PackageStreamUri = downloadUri.ToString(),
ProjectUrl = package.ProjectUrl, ProjectUrl = package.ProjectUrl,
Source = source, Source = source,
Version = package.Version ?? String.Empty, Version = package.Version ?? string.Empty,
Description = package.Description, Description = package.Description,
Authors = package.Authors, Authors = package.Authors,
LastUpdated = package.LastUpdated LastUpdated = package.LastUpdated,
IconUrl = package.IconUrl,
FirstScreenshot = firstScreenshot != null ? firstScreenshot.ScreenshotUri : string.Empty,
Rating = package.Rating,
RatingsCount = package.RatingsCount
}; };
} }
#endregion
#endregion
} }
} }

View File

@@ -1,17 +1,22 @@
.moduleName { .extensionName {
float:left; float:left;
} }
.contentItems .related { .contentItems .related {
padding:1.2em 0.4em 0.5em padding: 1.2em 0.4em 0.5em
} }
.contentItems .properties { .contentItems .properties {
float:none; float:left;
clear:both;
} }
.contentItems .pageStatus { .contentItems .pageStatus {
margin:.8em 0; margin:.8em 0;
color:#666; color:#666;
}
.thumbnail {
float: left;
padding: 1.2em 1.2em 0.5em 0em;
width: 10%;
}
.extensionDetails {
float: left;
width: 85%;
} }

View File

@@ -22,23 +22,38 @@
<ul class="contentItems"> <ul class="contentItems">
@foreach (var item in Model.Extensions) { @foreach (var item in Model.Extensions) {
<li> <li>
<div class="moduleName"> @{
<h2>@item.Title<span> - @T("Version: {0}", item.Version)</span></h2> string iconUrl = @item.IconUrl;
if (string.IsNullOrWhiteSpace(iconUrl)) {
iconUrl = Href("../../Content/Images/ModuleDefaultIcon.png");
}
}
<img src="@iconUrl" class="thumbnail"/>
<div class="extensionDetails">
<div class="extensionName">
<h2>@item.Title<span> - @T("Version: {0}", item.Version)</span></h2>
</div>
<div class="related">
@Html.ActionLink(T("Install").ToString(), "Install", new RouteValueDictionary {{"packageId", item.PackageId}, {"version", item.Version}, {"sourceId", item.Source.Id}, {"redirectTo", "Modules"}})@T(" | ")
<a href="@item.PackageStreamUri">@T("Download")</a>
</div>
<div class="properties">
<p>@(item.Description == null ? T("(No description").Text : item.Description)</p>
<ul class="pageStatus">
<li>@T("Last Updated: {0}", DateTime.Now.ToLocalTime())</li>
<li>&nbsp;&#124;&nbsp;@T("Author: {0}", !string.IsNullOrEmpty(item.Authors) ? item.Authors : T("Unknown").ToString())</li>
<li>&nbsp;&#124;&nbsp;@T("Rating: {0}", item.Rating)</li>
<li>&nbsp;&#124;&nbsp;@T("Ratings Count: {0}", item.RatingsCount)</li>
<li>&nbsp;&#124;&nbsp;@T("Website: ")
@if(!string.IsNullOrEmpty(item.ProjectUrl)) { <a href="@item.ProjectUrl">@item.ProjectUrl</a> }
else { @T("Unknown").ToString() }
</li>
</ul>
</div>
</div> </div>
<div class="related">
@Html.ActionLink(T("Install").ToString(), "Install", new RouteValueDictionary {{"packageId", item.PackageId}, {"version", item.Version}, {"sourceId", item.Source.Id}, {"redirectTo", "Modules"}})@T(" | ")
<a href="@item.PackageStreamUri">@T("Download")</a>
</div>
<div class="properties">
<p>@(item.Description == null ? T("(No description").Text : item.Description)</p>
<ul class="pageStatus">
<li>@T("Last Updated: {0}", DateTime.Now.ToLocalTime())</li>
<li>&nbsp;&#124;&nbsp;@T("Author: {0}", item.Authors)</li>
<li>&nbsp;&#124;&nbsp;@T("Project Url: ")<a href="@item.ProjectUrl">@item.ProjectUrl</a></li>
</ul>
</div>
</li>} </li>}
</ul> </ul>
} }

View File

@@ -22,23 +22,41 @@
<ul class="contentItems"> <ul class="contentItems">
@foreach (var item in Model.Extensions) { @foreach (var item in Model.Extensions) {
<li> <li>
<div class="moduleName"> @{
<h2>@item.Title<span> - @T("Version: {0}", item.Version)</span></h2> string iconUrl = @item.IconUrl;
if (!string.IsNullOrWhiteSpace(@item.FirstScreenshot)) {
iconUrl = Href(@item.FirstScreenshot);
}
else if (string.IsNullOrWhiteSpace(iconUrl)) {
iconUrl = Href("../../Content/Images/imagePlaceholder.png");
}
}
<img src="@iconUrl" class="thumbnail" />
<div class="extensionDetails">
<div class="extensionName">
<h2>@item.Title<span> - @T("Version: {0}", item.Version)</span></h2>
</div>
<div class="related">
@Html.ActionLink(T("Install").ToString(), "Install", new RouteValueDictionary {{"packageId", item.PackageId}, {"version", item.Version}, {"sourceId", item.Source.Id}, {"redirectTo", "Themes"}})@T(" | ")
<a href="@item.PackageStreamUri">@T("Download")</a>
</div>
<div class="properties">
<p>@(item.Description == null ? T("(No description").Text : item.Description)</p>
<ul class="pageStatus">
<li>@T("Last Updated: {0}", DateTime.Now.ToLocalTime())</li>
<li>&nbsp;&#124;&nbsp;@T("Author: {0}", !string.IsNullOrEmpty(item.Authors) ? item.Authors : T("Unknown").ToString())</li>
<li>&nbsp;&#124;&nbsp;@T("Rating: {0}", item.Rating)</li>
<li>&nbsp;&#124;&nbsp;@T("Ratings Count: {0}", item.RatingsCount)</li>
<li>&nbsp;&#124;&nbsp;@T("Website: ")
@if(!string.IsNullOrEmpty(item.ProjectUrl)) { <a href="@item.ProjectUrl">@item.ProjectUrl</a> }
else { @T("Unknown").ToString() }
</li>
</ul>
</div>
</div> </div>
<div class="related">
@Html.ActionLink(T("Install").ToString(), "Install", new RouteValueDictionary {{"packageId", item.PackageId}, {"version", item.Version}, {"sourceId", item.Source.Id}, {"redirectTo", "Themes"}})@T(" | ")
<a href="@item.PackageStreamUri">@T("Download")</a>
</div>
<div class="properties">
<p>@(item.Description == null ? T("(No description").Text : item.Description)</p>
<ul class="pageStatus">
<li>@T("Last Updated: {0}", DateTime.Now.ToLocalTime())</li>
<li>&nbsp;&#124;&nbsp;@T("Author: {0}", item.Authors)</li>
<li>&nbsp;&#124;&nbsp;@T("Project Url: ")<a href="@item.ProjectUrl">@item.ProjectUrl</a></li>
</ul>
</div>
</li>} </li>}
</ul> </ul>
} }

View File

@@ -9,7 +9,7 @@
<h1>@Html.TitleForPage(T("Manage Tags").ToString()) </h1> <h1>@Html.TitleForPage(T("Manage Tags").ToString()) </h1>
@Html.ValidationSummary() @Html.ValidationSummary()
<div class="manage"> <div class="manage">
@Display.EditorTemplate(TemplateName: "Parts/CreateTag", Model: View.CreateTag != null ? View.CreateTag : new TagsAdminCreateViewModel()) @Display.EditorTemplate(TemplateName: "Parts/CreateTag", Model: ViewData["CreateTag"] != null ? ViewData["CreateTag"] : new TagsAdminCreateViewModel())
</div> </div>
@using(Html.BeginFormAntiForgeryPost()) { @using(Html.BeginFormAntiForgeryPost()) {
<fieldset class="bulk-actions"> <fieldset class="bulk-actions">

View File

@@ -5,11 +5,11 @@ using System.Security.Principal;
using System.Web.Mvc; using System.Web.Mvc;
using System.Web.Security; using System.Web.Security;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Mvc;
using Orchard.Mvc.Extensions; using Orchard.Mvc.Extensions;
using Orchard.Security; using Orchard.Security;
using Orchard.Themes; using Orchard.Themes;
using Orchard.Users.Services; using Orchard.Users.Services;
using Orchard.Users.ViewModels;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Users.Models; using Orchard.Users.Models;
using Orchard.UI.Notify; using Orchard.UI.Notify;
@@ -44,7 +44,8 @@ namespace Orchard.Users.Controllers {
if (currentUser == null) { if (currentUser == null) {
Logger.Information("Access denied to anonymous request on {0}", returnUrl); Logger.Information("Access denied to anonymous request on {0}", returnUrl);
return View("LogOn", new LogOnViewModel {Title = "Access Denied"}); var shape = _orchardServices.New.LogOn().Title(T("Access Denied").Text);
return new ShapeResult(shape);
} }
//TODO: (erikpo) Add a setting for whether or not to log access denieds since these can fill up a database pretty fast from bots on a high traffic site //TODO: (erikpo) Add a setting for whether or not to log access denieds since these can fill up a database pretty fast from bots on a high traffic site
@@ -57,7 +58,8 @@ namespace Orchard.Users.Controllers {
if (_authenticationService.GetAuthenticatedUser() != null) if (_authenticationService.GetAuthenticatedUser() != null)
return Redirect("~/"); return Redirect("~/");
return View(new LogOnViewModel { Title = T("Log On").Text }); var shape = _orchardServices.New.LogOn().Title(T("Log On").Text);
return new ShapeResult(shape);
} }
[HttpPost] [HttpPost]
@@ -66,7 +68,8 @@ namespace Orchard.Users.Controllers {
public ActionResult LogOn(string userNameOrEmail, string password, string returnUrl) { public ActionResult LogOn(string userNameOrEmail, string password, string returnUrl) {
var user = ValidateLogOn(userNameOrEmail, password); var user = ValidateLogOn(userNameOrEmail, password);
if (!ModelState.IsValid) { if (!ModelState.IsValid) {
return View(new LogOnViewModel { Title = T("Log On").Text }); var shape = _orchardServices.New.LogOn().Title(T("Log On").Text);
return new ShapeResult(shape);
} }
_authenticationService.SignIn(user, false); _authenticationService.SignIn(user, false);
@@ -157,7 +160,7 @@ namespace Orchard.Users.Controllers {
return View(); return View();
} }
_userService.SendLostPasswordEmail(username, nonce => Url.AbsoluteAction(() => Url.Action("ValidateLostPassword", "Account", new { Area = "Orchard.Users", nonce = nonce }))); _userService.SendLostPasswordEmail(username, nonce => Url.AbsoluteAction(() => Url.Action("LostPassword", "Account", new { Area = "Orchard.Users", nonce = nonce })));
_orchardServices.Notifier.Information(T("Check your e-mail for the confirmation link.")); _orchardServices.Notifier.Information(T("Check your e-mail for the confirmation link."));
@@ -259,7 +262,6 @@ namespace Orchard.Users.Controllers {
var user = _userService.ValidateChallenge(nonce); var user = _userService.ValidateChallenge(nonce);
if ( user != null ) { if ( user != null ) {
_authenticationService.SignIn(user, false /* createPersistentCookie */);
return RedirectToAction("ChallengeEmailSuccess"); return RedirectToAction("ChallengeEmailSuccess");
} }

View File

@@ -31,30 +31,42 @@ namespace Orchard.Users.Handlers {
if ( recipient == null ) if ( recipient == null )
return; return;
if ( context.Type == MessageTypes.Moderation ) { switch (context.Type) {
context.MailMessage.Subject = T("User needs moderation").Text; case MessageTypes.Moderation:
context.MailMessage.Body = T("The following user account needs to be moderated: {0}", recipient.UserName).Text; context.MailMessage.Subject = T("New account").Text;
context.MailMessage.Body =
T("The user <b>{0}</b> with email <b>{1}</b> has requested a new account. This user won't be able to log while his account has not been approved.",
context.Properties["UserName"], context.Properties["Email"]).Text;
FormatEmailBody(context);
context.MessagePrepared = true;
break;
case MessageTypes.Validation:
var registeredWebsite = _siteService.GetSiteSettings().As<RegistrationSettingsPart>().ValidateEmailRegisteredWebsite;
var contactEmail = _siteService.GetSiteSettings().As<RegistrationSettingsPart>().ValidateEmailContactEMail;
context.MailMessage.Subject = T("Verification E-Mail").Text;
context.MailMessage.Body =
T("Thank you for registering with {0}.<br/><br/><br/><b>Final Step</b><br/>To verify that you own this e-mail address, please click the following link:<br/><a href=\"{1}\">{1}</a><br/><br/><b>Troubleshooting:</b><br/>If clicking on the link above does not work, try the following:<br/><br/>Select and copy the entire link.<br/>Open a browser window and paste the link in the address bar.<br/>Click <b>Go</b> or, on your keyboard, press <b>Enter</b> or <b>Return</b>.",
registeredWebsite, context.Properties["ChallengeUrl"]).Text;
if (!String.IsNullOrWhiteSpace(contactEmail)) {
context.MailMessage.Body +=
T("<br/><br/>If you continue to have access problems or want to report other issues, please <a href=\"mailto:{0}\">Contact Us</a>.",
contactEmail).Text;
}
FormatEmailBody(context);
context.MessagePrepared = true;
break;
case MessageTypes.LostPassword:
context.MailMessage.Subject = T("Lost password").Text;
context.MailMessage.Body =
T("Dear {0}, please <a href=\"{1}\">click here</a> to change your password.", recipient.UserName,
context.Properties["LostPasswordUrl"]).Text;
FormatEmailBody(context);
context.MessagePrepared = true;
break;
} }
if (context.Type == MessageTypes.Validation) {
var registeredWebsite = _siteService.GetSiteSettings().As<RegistrationSettingsPart>().ValidateEmailRegisteredWebsite;
var contactEmail = _siteService.GetSiteSettings().As<RegistrationSettingsPart>().ValidateEmailContactEMail;
context.MailMessage.Subject = T("Verification E-Mail").Text;
context.MailMessage.Body =
T("Thank you for registering with {0}.<br/><br/><br/><b>Final Step</b><br/>To verify that you own this e-mail address, please click the following link:<br/><a href=\"{1}\">{1}</a><br/><br/><b>Troubleshooting:</b><br/>If clicking on the link above does not work, try the following:<br/><br/>Select and copy the entire link.<br/>Open a browser window and paste the link in the address bar.<br/>Click <b>Go</b> or, on your keyboard, press <b>Enter</b> or <b>Return</b>.", registeredWebsite, context.Properties["ChallengeUrl"]).Text;
if (!String.IsNullOrWhiteSpace(contactEmail)) {
context.MailMessage.Body += T("<br/><br/>If you continue to have access problems or want to report other issues, please <a href=\"mailto:{0}\">Contact Us</a>.", contactEmail).Text;
}
}
if (context.Type == MessageTypes.LostPassword) {
context.MailMessage.Subject = T("Lost password").Text;
context.MailMessage.Body = T("Dear {0}, please <a href=\"{1}\">click here</a> to change your password.", recipient.UserName, context.Properties["LostPasswordUrl"]).Text;
}
FormatEmailBody(context);
context.MessagePrepared = true;
} }
private static void FormatEmailBody(MessageContext context) { private static void FormatEmailBody(MessageContext context) {

View File

@@ -75,7 +75,6 @@
<Compile Include="AdminMenu.cs" /> <Compile Include="AdminMenu.cs" />
<Compile Include="Services\MissingSettingsBanner.cs" /> <Compile Include="Services\MissingSettingsBanner.cs" />
<Compile Include="Services\UserService.cs" /> <Compile Include="Services\UserService.cs" />
<Compile Include="ViewModels\LogOnViewModel.cs" />
<Compile Include="ViewModels\UserCreateViewModel.cs" /> <Compile Include="ViewModels\UserCreateViewModel.cs" />
<Compile Include="ViewModels\UserEditViewModel.cs" /> <Compile Include="ViewModels\UserEditViewModel.cs" />
<Compile Include="ViewModels\UsersIndexViewModel.cs" /> <Compile Include="ViewModels\UsersIndexViewModel.cs" />
@@ -90,7 +89,6 @@
<Content Include="Views\Account\ChallengeEmailSuccess.cshtml" /> <Content Include="Views\Account\ChallengeEmailSuccess.cshtml" />
<Content Include="Views\Account\ChallengeEmailSent.cshtml" /> <Content Include="Views\Account\ChallengeEmailSent.cshtml" />
<Content Include="Views\Account\ChallengeEmailFail.cshtml" /> <Content Include="Views\Account\ChallengeEmailFail.cshtml" />
<Content Include="Views\Account\LogOn.cshtml" />
<Content Include="Views\Account\Register.cshtml" /> <Content Include="Views\Account\Register.cshtml" />
<Content Include="Views\Admin\Edit.cshtml" /> <Content Include="Views\Admin\Edit.cshtml" />
<Content Include="Views\Admin\Create.cshtml" /> <Content Include="Views\Admin\Create.cshtml" />
@@ -129,6 +127,9 @@
<ItemGroup> <ItemGroup>
<Content Include="Views\Account\LostPassword.cshtml" /> <Content Include="Views\Account\LostPassword.cshtml" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Content Include="Views\LogOn.cshtml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" /> <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -89,7 +89,7 @@ namespace Orchard.Users.Services {
} }
var recipient = GetUser(userName); var recipient = GetUser(userName);
if (recipient != null) if (recipient != null)
_messageManager.Send(recipient.ContentItem.Record, MessageTypes.Moderation, "email"); _messageManager.Send(recipient.ContentItem.Record, MessageTypes.Moderation, "email" , new Dictionary<string, string> { { "UserName", createUserParams.Username}, { "Email" , createUserParams.Email } });
} }
} }

View File

@@ -1,5 +0,0 @@
namespace Orchard.Users.ViewModels {
public class LogOnViewModel {
public string Title { get; set; }
}
}

View File

@@ -1,12 +1,11 @@
@model Orchard.Users.ViewModels.LogOnViewModel @using Orchard.ContentManagement;
@using Orchard.ContentManagement;
@{ @{
var userCanRegister = @WorkContext.CurrentSite.As<Orchard.Users.Models.RegistrationSettingsPart>().UsersCanRegister; var userCanRegister = @WorkContext.CurrentSite.As<Orchard.Users.Models.RegistrationSettingsPart>().UsersCanRegister;
var enableLostPassword = @WorkContext.CurrentSite.As<Orchard.Users.Models.RegistrationSettingsPart>().EnableLostPassword; var enableLostPassword = @WorkContext.CurrentSite.As<Orchard.Users.Models.RegistrationSettingsPart>().EnableLostPassword;
} }
<h1 class="page-title">@Html.TitleForPage(Model.Title)</h1> <h1 class="page-title">@Html.TitleForPage((string)Model.Title)</h1>
<p> <p>
@T("Please enter your username and password.") @T("Please enter your username and password.")
@if(userCanRegister) { @Html.ActionLink(T("Register").Text, "Register") @T(" if you don't have an account.") } @if(userCanRegister) { @Html.ActionLink(T("Register").Text, "Register") @T(" if you don't have an account.") }

View File

@@ -100,6 +100,10 @@
<HintPath>..\..\lib\aspnetmvc\System.Web.WebPages.dll</HintPath> <HintPath>..\..\lib\aspnetmvc\System.Web.WebPages.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System.Web.WebPages.Deployment, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\aspnetmvc\System.Web.WebPages.Deployment.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Reference Include="System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\aspnetmvc\System.Web.WebPages.Razor.dll</HintPath> <HintPath>..\..\lib\aspnetmvc\System.Web.WebPages.Razor.dll</HintPath>

View File

@@ -217,7 +217,7 @@ input[type="submit"]:focus::-moz-focus-inner, button:focus::-moz-focus-inner, .b
} }
#throbber .curtain #throbber .curtain
{ {
position:absolute; position:fixed;
left:0; left:0;
top:0; top:0;
width:100%; width:100%;
@@ -239,7 +239,6 @@ input[type="submit"]:focus::-moz-focus-inner, button:focus::-moz-focus-inner, .b
padding:250px; padding:250px;
color:White; color:White;
} }
.message, .validation-summary-errors { .message, .validation-summary-errors {
margin:10px 0 4px 0; margin:10px 0 4px 0;
padding:4px; padding:4px;

View File

@@ -171,7 +171,8 @@ namespace Orchard.Environment.State {
} }
// raise install and enabled states in order // raise install and enabled states in order
foreach (var entry in allEntries.Where(entry => IsRising(entry.FeatureState))) { foreach (var entry in allEntries.Reverse().Where(entry => IsRising(entry.FeatureState)))
{
if (entry.FeatureState.InstallState == ShellFeatureState.State.Rising) { if (entry.FeatureState.InstallState == ShellFeatureState.State.Rising) {
Logger.Information("Installing feature '{0}'", entry.Feature.Descriptor.Id); Logger.Information("Installing feature '{0}'", entry.Feature.Descriptor.Id);
_featureEvents.Installing(entry.Feature); _featureEvents.Installing(entry.Feature);

View File

@@ -0,0 +1,10 @@
using System.Web.Mvc;
namespace Orchard.Mvc {
public class ShapeResult : ViewResult {
public ShapeResult(dynamic shape) {
ViewData.Model = shape;
ViewName = "~/Core/Shapes/Views/ShapeResult/Display.cshtml";
}
}
}

View File

@@ -139,6 +139,10 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\aspnetmvc\System.Web.WebPages.dll</HintPath> <HintPath>..\..\lib\aspnetmvc\System.Web.WebPages.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Web.WebPages.Deployment, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\aspnetmvc\System.Web.WebPages.Deployment.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages.Razor"> <Reference Include="System.Web.WebPages.Razor">
<HintPath>..\..\lib\aspnetmvc\System.Web.WebPages.Razor.dll</HintPath> <HintPath>..\..\lib\aspnetmvc\System.Web.WebPages.Razor.dll</HintPath>
</Reference> </Reference>
@@ -181,6 +185,7 @@
<Compile Include="Messaging\Services\DefaultMessageManager.cs" /> <Compile Include="Messaging\Services\DefaultMessageManager.cs" />
<Compile Include="Mvc\Extensions\ControllerExtensions.cs" /> <Compile Include="Mvc\Extensions\ControllerExtensions.cs" />
<Compile Include="Mvc\IOrchardViewPage.cs" /> <Compile Include="Mvc\IOrchardViewPage.cs" />
<Compile Include="Mvc\ShapeResult.cs" />
<Compile Include="Mvc\Spooling\HtmlStringWriter.cs" /> <Compile Include="Mvc\Spooling\HtmlStringWriter.cs" />
<Compile Include="Mvc\ViewEngines\Razor\IRazorCompilationEvents.cs" /> <Compile Include="Mvc\ViewEngines\Razor\IRazorCompilationEvents.cs" />
<Compile Include="Security\IEncryptionService.cs" /> <Compile Include="Security\IEncryptionService.cs" />