--HG--
branch : dev
This commit is contained in:
Dave Reed
2010-11-17 15:47:16 -08:00
17 changed files with 331 additions and 111 deletions

View File

@@ -147,6 +147,7 @@
<Compile Include="Widgets\RuleEngine\UrlRuleProviderTest.cs" />
<Compile Include="Widgets\Services\WidgetsServiceTest.cs" />
<Compile Include="Widgets\WidgetsTests.cs" />
<Compile Include="XmlRpc\Controllers\LiveWriterControllerTests.cs" />
<Compile Include="XmlRpc\Controllers\HomeControllerTests.cs" />
<Compile Include="XmlRpc\Services\XmlRpcReaderTests.cs" />
<Compile Include="XmlRpc\Services\XmlRpcWriterTests.cs" />

View File

@@ -37,6 +37,8 @@ namespace Orchard.Tests.Modules.XmlRpc.Controllers {
}
public class StubHandler : IXmlRpcHandler {
public void SetCapabilities(XElement element) {}
public void Process(XmlRpcContext context) {
ProcessCalls++;
context.Response = new XRpcMethodResponse();

View File

@@ -0,0 +1,60 @@
using System;
using System.Web.Mvc;
using System.Xml.Linq;
using Autofac;
using NUnit.Framework;
using Orchard.Core.XmlRpc;
using Orchard.Core.XmlRpc.Controllers;
using Orchard.Core.XmlRpc.Models;
using Orchard.Core.XmlRpc.Services;
namespace Orchard.Tests.Modules.XmlRpc.Controllers {
[TestFixture]
public class LiveWriterControllerTests {
[Test]
public void HandlersShouldSetCapabilitiesForManifest() {
var thing = new StubHandler();
var thingToo = new StubTooHandler();
var builder = new ContainerBuilder();
builder.RegisterType<LiveWriterController>();
builder.RegisterType<XmlRpcReader>().As<IMapper<XElement, XRpcMethodCall>>();
builder.RegisterType<XmlRpcWriter>().As<IMapper<XRpcMethodResponse, XElement>>();
builder.RegisterInstance(thing).As<IXmlRpcHandler>();
builder.RegisterInstance(thingToo).As<IXmlRpcHandler>();
var container = builder.Build();
var controller = container.Resolve<LiveWriterController>();
var result = controller.Manifest() as ContentResult;
Assert.That(result, Is.Not.Null);
Assert.That(result.Content, Is.StringContaining("<supportsGetTags>No</supportsGetTags>"));
Assert.That(result.Content, Is.StringContaining("<keywordsAsTags>Yes</keywordsAsTags>"));
Assert.That(result.Content, Is.StringContaining("<supportsKeywords>Maybe</supportsKeywords>"));
}
public class StubHandler : IXmlRpcHandler {
public void SetCapabilities(XElement options) {
const string manifestUri = "http://schemas.microsoft.com/wlw/manifest/weblog";
options.SetElementValue(XName.Get("supportsGetTags", manifestUri), "No");
options.SetElementValue(XName.Get("keywordsAsTags", manifestUri), "Yes");
}
public void Process(XmlRpcContext context) { }
public int ProcessCalls { get; set; }
}
public class StubTooHandler : IXmlRpcHandler {
public void SetCapabilities(XElement options) {
const string manifestUri = "http://schemas.microsoft.com/wlw/manifest/weblog";
options.SetElementValue(XName.Get("supportsKeywords", manifestUri), "Maybe");
}
public void Process(XmlRpcContext context) { }
public int ProcessCalls { get; set; }
}
}
}

View File

@@ -245,6 +245,7 @@
<Compile Include="Shapes\DateTimeShapes.cs" />
<Compile Include="XmlRpc\Controllers\HomeController.cs" />
<Compile Include="XmlRpc\Controllers\LiveWriterController.cs" />
<Compile Include="XmlRpc\IXmlRpcDriver.cs" />
<Compile Include="XmlRpc\IXmlRpcHandler.cs" />
<Compile Include="XmlRpc\Models\ModelBinderProvider.cs" />
<Compile Include="XmlRpc\Models\XRpcArray.cs" />

View File

@@ -1,33 +1,52 @@
using System.Web;
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Xml.Linq;
using Orchard.Logging;
namespace Orchard.Core.XmlRpc.Controllers {
public class LiveWriterController : Controller {
private readonly IEnumerable<IXmlRpcHandler> _xmlRpcHandlers;
private const string ManifestUri = "http://schemas.microsoft.com/wlw/manifest/weblog";
public LiveWriterController() {
public LiveWriterController(IEnumerable<IXmlRpcHandler> xmlRpcHandlers) {
_xmlRpcHandlers = xmlRpcHandlers;
Logger = NullLogger.Instance;
}
protected ILogger Logger { get; set; }
[NoCache]
public ActionResult Manifest() {
Logger.Debug("Manifest requested");
var options = new XElement(
XName.Get("options", ManifestUri),
new XElement(XName.Get("clientType", ManifestUri), "Metaweblog"),
new XElement(XName.Get("supportsSlug", ManifestUri), "Yes"));
new XElement(XName.Get("supportsKeywords", ManifestUri), "No"),
new XElement(XName.Get("supportsCategories", ManifestUri), "No"),
new XElement(XName.Get("supportsFileUpload", ManifestUri), "No"));
foreach (var handler in _xmlRpcHandlers)
handler.SetCapabilities(options);
var doc = new XDocument(new XElement(
XName.Get("manifest", ManifestUri),
options));
Response.Cache.SetCacheability(HttpCacheability.NoCache);
return Content(doc.ToString(), "text/xml");
}
public class NoCache : ActionFilterAttribute {
public override void OnResultExecuting(ResultExecutingContext filterContext) {
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.SetNoStore();
base.OnResultExecuting(filterContext);
}
}
}
}

View File

@@ -0,0 +1,5 @@
namespace Orchard.Core.XmlRpc {
public interface IXmlRpcDriver {
void Process(int id);
}
}

View File

@@ -1,5 +1,8 @@
namespace Orchard.Core.XmlRpc {
using System.Xml.Linq;
namespace Orchard.Core.XmlRpc {
public interface IXmlRpcHandler : IDependency {
void SetCapabilities(XElement element);
void Process(XmlRpcContext context);
}
}

View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using Orchard.Core.XmlRpc.Models;
@@ -8,5 +9,6 @@ namespace Orchard.Core.XmlRpc {
public HttpContextBase HttpContext { get; set; }
public XRpcMethodCall Request { get; set; }
public XRpcMethodResponse Response { get; set; }
public ICollection<IXmlRpcDriver> _drivers = new List<IXmlRpcDriver>();
}
}

View File

@@ -1,10 +1,6 @@
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Xml.Linq;
using Orchard.Blogs.Extensions;
using Orchard.Blogs.Models;
using Orchard.Blogs.Routing;
using Orchard.Blogs.Services;
using Orchard.Core.Feeds;
@@ -21,22 +17,19 @@ namespace Orchard.Blogs.Controllers {
private readonly IBlogPostService _blogPostService;
private readonly IBlogSlugConstraint _blogSlugConstraint;
private readonly IFeedManager _feedManager;
private readonly RouteCollection _routeCollection;
public BlogController(
IOrchardServices services,
IBlogService blogService,
IBlogPostService blogPostService,
IBlogSlugConstraint blogSlugConstraint,
IFeedManager feedManager,
RouteCollection routeCollection,
IFeedManager feedManager,
IShapeFactory shapeFactory) {
_services = services;
_blogService = blogService;
_blogPostService = blogPostService;
_blogSlugConstraint = blogSlugConstraint;
_feedManager = feedManager;
_routeCollection = routeCollection;
Logger = NullLogger.Instance;
Shape = shapeFactory;
}
@@ -79,64 +72,5 @@ namespace Orchard.Blogs.Controllers {
return View(blog);
}
public ActionResult LiveWriterManifest(string blogSlug) {
Logger.Debug("Live Writer Manifest requested");
BlogPart blogPart = _blogService.Get(blogSlug);
if (blogPart == null)
return HttpNotFound();
const string manifestUri = "http://schemas.microsoft.com/wlw/manifest/weblog";
var options = new XElement(
XName.Get("options", manifestUri),
new XElement(XName.Get("clientType", manifestUri), "Metaweblog"),
new XElement(XName.Get("supportsSlug", manifestUri), "Yes"),
new XElement(XName.Get("supportsKeywords", manifestUri), "Yes"));
var doc = new XDocument(new XElement(
XName.Get("manifest", manifestUri),
options));
Response.Cache.SetCacheability(HttpCacheability.NoCache);
return Content(doc.ToString(), "text/xml");
}
public ActionResult Rsd(string blogSlug) {
Logger.Debug("RSD requested");
BlogPart blogPart = _blogService.Get(blogSlug);
if (blogPart == null)
return HttpNotFound();
const string manifestUri = "http://archipelago.phrasewise.com/rsd";
var urlHelper = new UrlHelper(ControllerContext.RequestContext, _routeCollection);
var url = urlHelper.Action("", "", new { Area = "XmlRpc" });
var options = new XElement(
XName.Get("service", manifestUri),
new XElement(XName.Get("engineName", manifestUri), "Orchard CMS"),
new XElement(XName.Get("engineLink", manifestUri), "http://orchardproject.net"),
new XElement(XName.Get("homePageLink", manifestUri), "http://orchardproject.net"),
new XElement(XName.Get("apis", manifestUri),
new XElement(XName.Get("api", manifestUri),
new XAttribute("name", "MetaWeblog"),
new XAttribute("preferred", true),
new XAttribute("apiLink", url),
new XAttribute("blogID", blogPart.Id))));
var doc = new XDocument(new XElement(
XName.Get("rsd", manifestUri),
new XAttribute("version", "1.0"),
options));
Response.Cache.SetCacheability(HttpCacheability.NoCache);
return Content(doc.ToString(), "text/xml");
}
}
}

View File

@@ -0,0 +1,59 @@
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Xml.Linq;
using Orchard.Blogs.Models;
using Orchard.Blogs.Services;
using Orchard.Environment.Extensions;
using Orchard.Logging;
namespace Orchard.Blogs.Controllers {
[OrchardFeature("Orchard.Blogs.RemotePublishing")]
public class RemoteBlogPublishingController : Controller {
private readonly IBlogService _blogService;
private readonly RouteCollection _routeCollection;
public RemoteBlogPublishingController(IOrchardServices services, IBlogService blogService, RouteCollection routeCollection) {
_blogService = blogService;
_routeCollection = routeCollection;
Logger = NullLogger.Instance;
}
protected ILogger Logger { get; set; }
public ActionResult Rsd(string blogSlug) {
Logger.Debug("RSD requested");
BlogPart blogPart = _blogService.Get(blogSlug);
if (blogPart == null)
return HttpNotFound();
const string manifestUri = "http://archipelago.phrasewise.com/rsd";
var urlHelper = new UrlHelper(ControllerContext.RequestContext, _routeCollection);
var url = urlHelper.Action("", "", new { Area = "XmlRpc" });
var options = new XElement(
XName.Get("service", manifestUri),
new XElement(XName.Get("engineName", manifestUri), "Orchard CMS"),
new XElement(XName.Get("engineLink", manifestUri), "http://orchardproject.net"),
new XElement(XName.Get("homePageLink", manifestUri), "http://orchardproject.net"),
new XElement(XName.Get("apis", manifestUri),
new XElement(XName.Get("api", manifestUri),
new XAttribute("name", "MetaWeblog"),
new XAttribute("preferred", true),
new XAttribute("apiLink", url),
new XAttribute("blogID", blogPart.Id))));
var doc = new XDocument(new XElement(
XName.Get("rsd", manifestUri),
new XAttribute("version", "1.0"),
options));
Response.Cache.SetCacheability(HttpCacheability.NoCache);
return Content(doc.ToString(), "text/xml");
}
}
}

View File

@@ -20,11 +20,11 @@ namespace Orchard.Blogs.Extensions {
}
public static string BlogLiveWriterManifest(this UrlHelper urlHelper, BlogPart blogPart) {
return urlHelper.AbsoluteAction(() => urlHelper.Action("LiveWriterManifest", "Blog", new { blogSlug = blogPart.As<IRoutableAspect>().Path, area = "Orchard.Blogs" }));
return urlHelper.AbsoluteAction(() => urlHelper.Action("Manifest", "LiveWriter", new { area = "XmlRpc" }));
}
public static string BlogRsd(this UrlHelper urlHelper, BlogPart blogPart) {
return urlHelper.AbsoluteAction(() => urlHelper.Action("Rsd", "Blog", new { blogSlug = blogPart.As<IRoutableAspect>().Path, area = "Orchard.Blogs" }));
return urlHelper.AbsoluteAction(() => urlHelper.Action("Rsd", "RemoteBlogPublishing", new { blogSlug = blogPart.As<IRoutableAspect>().Path, area = "Orchard.Blogs" }));
}
public static string BlogArchiveYear(this UrlHelper urlHelper, BlogPart blogPart, int year) {

View File

@@ -67,6 +67,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AdminMenu.cs" />
<Compile Include="Controllers\RemoteBlogPublishingController.cs" />
<Compile Include="Drivers\BlogArchivesPartDriver.cs" />
<Compile Include="Drivers\RemoteBlogPublishingDriver.cs" />
<Compile Include="Drivers\RecentBlogPostsPartDriver.cs" />

View File

@@ -202,30 +202,13 @@ namespace Orchard.Blogs {
},
new MvcRouteHandler())
},
new RouteDescriptor {
Priority = 11,
Route = new Route(
"{blogSlug}/wlwmanifest.xml",
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "Blog"},
{"action", "LiveWriterManifest"}
},
new RouteValueDictionary {
{"blogSlug", _blogSlugConstraint}
},
new RouteValueDictionary {
{"area", "Orchard.Blogs"}
},
new MvcRouteHandler())
},
new RouteDescriptor {
Priority = 11,
Route = new Route(
"{blogSlug}/rsd",
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "Blog"},
{"controller", "RemoteBlogPublishing"},
{"action", "Rsd"}
},
new RouteValueDictionary {

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using System.Xml.Linq;
using JetBrains.Annotations;
using Orchard.Blogs.Models;
using Orchard.ContentManagement;
@@ -44,6 +46,11 @@ namespace Orchard.Blogs.Services {
public ILogger Logger { get; set; }
public void SetCapabilities(XElement options) {
const string manifestUri = "http://schemas.microsoft.com/wlw/manifest/weblog";
options.SetElementValue(XName.Get("supportsSlug", manifestUri), "Yes");
}
public void Process(XmlRpcContext context) {
var urlHelper = new UrlHelper(context.ControllerContext.RequestContext, _routeCollection);
@@ -72,7 +79,8 @@ namespace Orchard.Blogs.Services {
Convert.ToString(context.Request.Params[1].Value),
Convert.ToString(context.Request.Params[2].Value),
(XRpcStruct)context.Request.Params[3].Value,
Convert.ToBoolean(context.Request.Params[4].Value));
Convert.ToBoolean(context.Request.Params[4].Value),
context._drivers);
context.Response = new XRpcMethodResponse().Add(result);
}
@@ -92,7 +100,8 @@ namespace Orchard.Blogs.Services {
Convert.ToString(context.Request.Params[1].Value),
Convert.ToString(context.Request.Params[2].Value),
(XRpcStruct)context.Request.Params[3].Value,
Convert.ToBoolean(context.Request.Params[4].Value));
Convert.ToBoolean(context.Request.Params[4].Value),
context._drivers);
context.Response = new XRpcMethodResponse().Add(result);
}
@@ -102,7 +111,8 @@ namespace Orchard.Blogs.Services {
Convert.ToString(context.Request.Params[1].Value),
Convert.ToString(context.Request.Params[2].Value),
Convert.ToString(context.Request.Params[3].Value),
Convert.ToBoolean(context.Request.Params[4].Value));
Convert.ToBoolean(context.Request.Params[4].Value),
context._drivers);
context.Response = new XRpcMethodResponse().Add(result);
}
}
@@ -152,7 +162,8 @@ namespace Orchard.Blogs.Services {
string userName,
string password,
XRpcStruct content,
bool publish) {
bool publish,
IEnumerable<IXmlRpcDriver> drivers) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(Permissions.EditBlogPost, user, null);
@@ -191,6 +202,9 @@ namespace Orchard.Blogs.Services {
if (publish)
_blogPostService.Publish(blogPost);
foreach (var driver in drivers)
driver.Process(blogPost.Id);
return blogPost.Id;
}
@@ -210,12 +224,7 @@ namespace Orchard.Blogs.Services {
return CreateBlogStruct(blogPost, urlHelper);
}
private bool MetaWeblogEditPost(
int postId,
string userName,
string password,
XRpcStruct content,
bool publish) {
private bool MetaWeblogEditPost(int postId, string userName, string password, XRpcStruct content, bool publish, ICollection<IXmlRpcDriver> drivers) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(StandardPermissions.AccessFrontEnd, user, null);
@@ -233,19 +242,16 @@ namespace Orchard.Blogs.Services {
blogPost.Slug = slug;
blogPost.Text = description;
if (publish) {
if (publish)
_blogPostService.Publish(blogPost);
}
foreach (var driver in drivers)
driver.Process(blogPost.Id);
return true;
}
private bool MetaWeblogDeletePost(
string appkey,
string postId,
string userName,
string password,
bool publish) {
private bool MetaWeblogDeletePost(string appkey, string postId, string userName, string password, bool publish, ICollection<IXmlRpcDriver> drivers) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(StandardPermissions.AccessFrontEnd, user, null);
@@ -253,6 +259,9 @@ namespace Orchard.Blogs.Services {
if (blogPost == null)
throw new ArgumentException();
foreach (var driver in drivers)
driver.Process(blogPost.Id);
_blogPostService.Delete(blogPost);
return true;
}

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Web;
using System.Xml.Linq;
using JetBrains.Annotations;
using Orchard.Core.XmlRpc;
using Orchard.Core.XmlRpc.Models;
@@ -18,6 +19,11 @@ namespace Orchard.Media.Services {
_authorizationService = authorizationService;
}
public void SetCapabilities(XElement options) {
const string manifestUri = "http://schemas.microsoft.com/wlw/manifest/weblog";
options.SetElementValue(XName.Get("supportsFileUpload", manifestUri), "Yes");
}
public void Process(XmlRpcContext context) {
var uriBuilder = new UriBuilder(context.HttpContext.Request.ToUrlString()) {
Path = context.HttpContext.Request.ApplicationPath,

View File

@@ -72,6 +72,7 @@
<Compile Include="Models\TagsContentItems.cs" />
<Compile Include="ResourceManifest.cs" />
<Compile Include="Services\ITagService.cs" />
<Compile Include="Services\XmlRpcHandler.cs" />
<Compile Include="ViewModels\EditTagsViewModel.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Drivers\TagsPartDriver.cs" />

View File

@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Orchard.ContentManagement;
using Orchard.Core.XmlRpc;
using Orchard.Core.XmlRpc.Models;
using Orchard.Security;
using Orchard.Tags.Helpers;
namespace Orchard.Tags.Services {
public class XmlRpcHandler : IXmlRpcHandler {
private readonly IMembershipService _membershipService;
private readonly IAuthorizationService _authorizationService;
private readonly IContentManager _contentManager;
private readonly ITagService _tagService;
private readonly IOrchardServices _orchardServices;
private IEnumerable<string> _tags;
public XmlRpcHandler(
IMembershipService membershipService,
IAuthorizationService authorizationService,
IContentManager contentManager,
ITagService tagService,
IOrchardServices orchardServices) {
_membershipService = membershipService;
_authorizationService = authorizationService;
_contentManager = contentManager;
_tagService = tagService;
_orchardServices = orchardServices;
}
public void SetCapabilities(XElement options) {
const string manifestUri = "http://schemas.microsoft.com/wlw/manifest/weblog";
options.SetElementValue(XName.Get("supportsKeywords", manifestUri), "Yes");
options.SetElementValue(XName.Get("supportsGetTags", manifestUri), "Yes");
options.SetElementValue(XName.Get("keywordsAsTags", manifestUri), "Yes");
}
public void Process(XmlRpcContext context) {
switch (context.Request.MethodName) {
case "wp.getTags":
var tags = MetaWeblogGetTags(
Convert.ToString(context.Request.Params[0].Value),
Convert.ToString(context.Request.Params[1].Value),
Convert.ToString(context.Request.Params[2].Value));
context.Response = new XRpcMethodResponse().Add(tags);
break;
case "metaWeblog.newPost":
MetaWeblogUpdateTags(
GetId(context.Response),
Convert.ToString(context.Request.Params[0].Value),
Convert.ToString(context.Request.Params[1].Value),
Convert.ToString(context.Request.Params[2].Value),
(XRpcStruct)context.Request.Params[3].Value,
Convert.ToBoolean(context.Request.Params[4].Value),
context._drivers);
break;
case "metaWeblog.editPost":
MetaWeblogUpdateTags(
GetId(context.Response),
Convert.ToString(context.Request.Params[0].Value),
Convert.ToString(context.Request.Params[1].Value),
Convert.ToString(context.Request.Params[2].Value),
(XRpcStruct)context.Request.Params[3].Value,
Convert.ToBoolean(context.Request.Params[4].Value),
context._drivers);
break;
}
}
private static int GetId(XRpcMethodResponse response) {
return response != null && response.Params.Count == 1 && response.Params[0].Value is int
? Convert.ToInt32(response.Params[0].Value)
: 0;
}
private XRpcArray MetaWeblogGetTags(string appKey, string userName, string password) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(StandardPermissions.AccessFrontEnd, user, null);
var array = new XRpcArray();
foreach (var tag in _tagService.GetTags()) {
var thisTag = tag;
array.Add(new XRpcStruct()
.Set("tag_id", thisTag.TagName)
.Set("name", thisTag.TagName));
// nyi - not yet implemented
//.Set("count", "")
//.Set("slug", "")
//.Set("html_url", "")
//.Set("rss_url", ""));
}
return array;
}
private void MetaWeblogUpdateTags(int contentItemId, string appKey, string userName, string password, XRpcStruct content, bool publish, ICollection<IXmlRpcDriver> drivers) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(Permissions.ApplyTag, user, null);
var rawTags = content.Optional<string>("mt_keywords");
if (string.IsNullOrWhiteSpace(rawTags))
return;
var driver = new XmlRpcDriver(id => {
var contentItem = _contentManager.Get(id);
if (contentItem == null)
return;
_orchardServices.WorkContext.CurrentUser = user;
_tagService.UpdateTagsForContentItem(id, _tags);
});
_tags = TagHelpers.ParseCommaSeparatedTagNames(rawTags);
if (contentItemId > 0)
driver.Process(contentItemId);
else
drivers.Add(driver);
}
public class XmlRpcDriver : IXmlRpcDriver {
private readonly Action<int> _process;
public XmlRpcDriver(Action<int> process) {
_process = process;
}
public void Process(int id) {
_process(id);
}
}
}
}