- Finish up live writer support for blogs.

--HG--
branch : dev
This commit is contained in:
Suha Can
2010-03-02 12:10:49 -08:00
parent 388bd803c6
commit 49a9c6cc98
19 changed files with 276 additions and 61 deletions

View File

@@ -40,7 +40,7 @@ namespace Orchard.Core.XmlRpc.Controllers {
}
private XRpcMethodResponse Dispatch(XRpcMethodCall request) {
var context = new XmlRpcContext { HttpContext = HttpContext, Request = request };
var context = new XmlRpcContext { ControllerContext = ControllerContext, HttpContext = HttpContext, Request = request };
foreach (var handler in _xmlRpcHandlers)
handler.Process(context);
return context.Response;

View File

@@ -16,9 +16,10 @@ namespace Orchard.Core.XmlRpc.Services {
{
{typeof(int), p=>new XElement("int", (int)p.Value)},
{typeof(bool), p=>new XElement("boolean", (bool)p.Value?"1":"0")},
{typeof(string), p=>new XElement("string", (string)p.Value)},
{typeof(string), p=>new XElement("string", p.Value)},
{typeof(double), p=>new XElement("double", (double)p.Value)},
{typeof(DateTime), p=>new XElement("dateTime.iso8601", ((DateTime)p.Value).ToString("o"))},
{typeof(DateTime?), p=>new XElement("dateTime.iso8601", ((DateTime?)p.Value).Value.ToString("o"))},
{typeof(byte[]), p=>new XElement("base64", Convert.ToBase64String((byte[])p.Value))},
{typeof(XRpcStruct), p=>Map((XRpcStruct)p.Value)},
{typeof(XRpcArray), p=>Map((XRpcArray)p.Value)},

View File

@@ -1,8 +1,10 @@
using System.Web;
using System.Web.Mvc;
using Orchard.Core.XmlRpc.Models;
namespace Orchard.Core.XmlRpc {
public class XmlRpcContext {
public ControllerContext ControllerContext { get; set; }
public HttpContextBase HttpContext { get; set; }
public XRpcMethodCall Request { get; set; }
public XRpcMethodResponse Response { get; set; }

View File

@@ -1,6 +1,7 @@
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;
@@ -15,14 +16,17 @@ namespace Orchard.Blogs.Controllers {
private readonly IOrchardServices _services;
private readonly IBlogService _blogService;
private readonly IFeedManager _feedManager;
private readonly RouteCollection _routeCollection;
public BlogController(
IOrchardServices services,
IBlogService blogService,
IFeedManager feedManager) {
IFeedManager feedManager,
RouteCollection routeCollection) {
_services = services;
_blogService = blogService;
_feedManager = feedManager;
_routeCollection = routeCollection;
Logger = NullLogger.Instance;
}
@@ -52,15 +56,22 @@ namespace Orchard.Blogs.Controllers {
return View(model);
}
public ActionResult LiveWriterManifest() {
public ActionResult LiveWriterManifest(string blogSlug) {
Logger.Debug("Live Writer Manifest requested");
Blog blog = _blogService.Get(blogSlug);
if (blog == null)
return new NotFoundResult();
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("supportsSlug", manifestUri), "Yes"),
new XElement(XName.Get("supportsKeywords", manifestUri), "Yes"));
var doc = new XDocument(new XElement(
XName.Get("manifest", manifestUri),
@@ -69,5 +80,39 @@ namespace Orchard.Blogs.Controllers {
Response.Cache.SetCacheability(HttpCacheability.NoCache);
return Content(doc.ToString(), "text/xml");
}
public ActionResult Rsd(string blogSlug) {
Logger.Debug("RSD requested");
Blog blog = _blogService.Get(blogSlug);
if (blog == null)
return new NotFoundResult();
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), "Orchar 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", blog.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

@@ -1,4 +1,5 @@
using System.Web.Mvc;
using Orchard.Mvc.Extensions;
namespace Orchard.Blogs.Extensions {
public static class UrlHelperExtensions {
@@ -18,6 +19,10 @@ namespace Orchard.Blogs.Extensions {
return urlHelper.Action("LiveWriterManifest", "Blog", new { blogSlug, area = "Orchard.Blogs" });
}
public static string BlogRsd(this UrlHelper urlHelper, string blogSlug) {
return urlHelper.AbsoluteAction(() => urlHelper.Action("Rsd", "Blog", new { blogSlug, area = "Orchard.Blogs" }));
}
public static string BlogArchiveYear(this UrlHelper urlHelper, string blogSlug, int year) {
return urlHelper.Action("ListByArchive", "BlogPost", new { blogSlug, archiveData = year.ToString(), area = "Orchard.Blogs" });
}

View File

@@ -14,6 +14,7 @@ namespace Orchard.Blogs.Models {
public string Title {
get { return this.As<RoutableAspect>().Title; }
set { this.As<RoutableAspect>().Title = value; }
}
public string Slug {
@@ -21,6 +22,11 @@ namespace Orchard.Blogs.Models {
set { this.As<RoutableAspect>().Slug = value; }
}
public string Text {
get { return this.As<BodyAspect>().Text; }
set { this.As<BodyAspect>().Text = value; }
}
public Blog Blog {
get { return this.As<ICommonAspect>().Container.As<Blog>(); }
set { this.As<ICommonAspect>().Container = value; }
@@ -50,6 +56,10 @@ namespace Orchard.Blogs.Models {
}
}
public DateTime? CreatedUtc {
get { return this.As<ICommonAspect>().CreatedUtc; }
}
public DateTime? PublishedUtc {
get { return this.As<ICommonAspect>().VersionPublishedUtc; }
}

View File

@@ -208,6 +208,22 @@ namespace Orchard.Blogs {
},
new MvcRouteHandler())
},
new RouteDescriptor {
Route = new Route(
"{blogSlug}/rsd",
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "Blog"},
{"action", "Rsd"}
},
new RouteValueDictionary {
{"blogSlug", new IsBlogConstraint(_containerProvider)}
},
new RouteValueDictionary {
{"area", "Orchard.Blogs"}
},
new MvcRouteHandler())
},
new RouteDescriptor {
Route = new Route(
"{blogSlug}/{postSlug}",

View File

@@ -1,38 +1,60 @@
using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using Orchard.Blogs.Controllers;
using Orchard.Blogs.Models;
using Orchard.ContentManagement;
using Orchard.Core.XmlRpc;
using Orchard.Core.XmlRpc.Models;
using Orchard.Logging;
using Orchard.Mvc.Extensions;
using Orchard.Security;
using Orchard.Blogs.Extensions;
namespace Orchard.Blogs.Services {
public class XmlRpcHandler : IXmlRpcHandler {
private readonly IBlogService _blogService;
private readonly IBlogPostService _blogPostService;
private readonly IContentManager _contentManager;
private readonly IAuthorizationService _authorizationService;
private readonly IMembershipService _membershipService;
private readonly RouteCollection _routeCollection;
public XmlRpcHandler(IBlogService blogService) {
public XmlRpcHandler(IBlogService blogService, IBlogPostService blogPostService, IContentManager contentManager,
IAuthorizationService authorizationService, IMembershipService membershipService,
RouteCollection routeCollection) {
_blogService = blogService;
_blogPostService = blogPostService;
_contentManager = contentManager;
_authorizationService = authorizationService;
_membershipService = membershipService;
_routeCollection = routeCollection;
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public void Process(XmlRpcContext context) {
var uriBuilder = new UriBuilder(context.HttpContext.Request.Url) {
Path =
context.HttpContext.Request.
ApplicationPath,
Query = string.Empty
};
var urlHelper = new UrlHelper(context.ControllerContext.RequestContext, _routeCollection);
if (context.Request.MethodName == "blogger.getUsersBlogs") {
var a = new XRpcArray();
foreach (var blog in _blogService.Get()) {
a.Add(new XRpcStruct()
.Set("url", uriBuilder.Path + blog.Slug)
.Set("blogid", blog.Id)
.Set("blogName", blog.Name));
}
var result = MetaWeblogGetUserBlogs(urlHelper,
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(a);
context.Response = new XRpcMethodResponse().Add(result);
}
if (context.Request.MethodName == "metaWeblog.getRecentPosts") {
var result = MetaWeblogGetRecentPosts(urlHelper,
Convert.ToString(context.Request.Params[0].Value),
Convert.ToString(context.Request.Params[1].Value),
Convert.ToString(context.Request.Params[2].Value),
Convert.ToInt32(context.Request.Params[3].Value));
context.Response = new XRpcMethodResponse().Add(result);
}
if (context.Request.MethodName == "metaWeblog.newPost") {
@@ -48,6 +70,7 @@ namespace Orchard.Blogs.Services {
if (context.Request.MethodName == "metaWeblog.getPost") {
var result = MetaWeblogGetPost(
urlHelper,
Convert.ToInt32(context.Request.Params[0].Value),
Convert.ToString(context.Request.Params[1].Value),
Convert.ToString(context.Request.Params[2].Value));
@@ -63,76 +86,162 @@ namespace Orchard.Blogs.Services {
Convert.ToBoolean(context.Request.Params[4].Value));
context.Response = new XRpcMethodResponse().Add(result);
}
if (context.Request.MethodName == "blogger.deletePost") {
var result = MetaWeblogDeletePost(
Convert.ToString(context.Request.Params[0].Value),
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));
context.Response = new XRpcMethodResponse().Add(result);
}
}
private XRpcArray MetaWeblogGetUserBlogs(UrlHelper urlHelper,
string appkey,
string userName,
string password) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(StandardPermissions.AccessFrontEnd, user, null);
var array = new XRpcArray();
foreach (var blog in _blogService.Get()) {
array.Add(new XRpcStruct()
.Set("url", urlHelper.AbsoluteAction(() => urlHelper.Blog(blog.Slug)))
.Set("blogid", blog.Id)
.Set("blogName", blog.Name));
}
return array;
}
private XRpcArray MetaWeblogGetRecentPosts(
UrlHelper urlHelper,
string blogId,
string userName,
string password,
int numberOfPosts) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(StandardPermissions.AccessFrontEnd, user, null);
var blog = _contentManager.Get<Blog>(Convert.ToInt32(blogId));
if (blog == null)
throw new ArgumentException();
var array = new XRpcArray();
foreach (var blogPost in _blogPostService.Get(blog).Take(numberOfPosts)) {
array.Add(CreateBlogStruct(blogPost, urlHelper));
}
return array;
}
private int MetaWeblogNewPost(
string blogId,
string user,
string userName,
string password,
XRpcStruct content,
bool publish) {
//var title = content.Optional<string>("title");
//var description = content.Optional<string>("description");
//var pageRevision = _pageManager.CreatePage(new CreatePageParams(title, null, "TwoColumns"));
//pageRevision.Contents.First().Content = description;
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(Permissions.EditBlogPost, user, null);
//if (publish) {
// if (string.IsNullOrEmpty(pageRevision.Slug))
// pageRevision.Slug = "slug" + pageRevision.Page.Id;
var blog = _contentManager.Get<Blog>(Convert.ToInt32(blogId));
if (blog == null)
throw new ArgumentException();
// _pageManager.Publish(pageRevision, new PublishOptions());
//}
var title = content.Optional<string>("title");
var description = content.Optional<string>("description");
var slug = content.Optional<string>("wp_slug");
//return pageRevision.Page.Id;
return 1;
var blogPost = _contentManager.New<BlogPost>(BlogPostDriver.ContentType.Name);
blogPost.Blog = blog;
blogPost.Title = title;
blogPost.Slug = slug;
blogPost.Text = description;
_contentManager.Create(blogPost.ContentItem, VersionOptions.Draft);
if (publish)
_blogPostService.Publish(blogPost);
return blogPost.Id;
}
private XRpcStruct MetaWeblogGetPost(
UrlHelper urlHelper,
int postId,
string user,
string userName,
string password) {
//var pageRevision = _pageManager.GetLastRevision(postId);
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(StandardPermissions.AccessFrontEnd, user, null);
//var url = "http://localhost/orchard/" + pageRevision.Slug;
//return new XRpcStruct()
// .Set("userid", 37)
// .Set("postid", pageRevision.Page.Id)
// .Set("description", pageRevision.Contents.First().Content)
// .Set("title", pageRevision.Title)
// .Set("link", url)
// .Set("permaLink", url);
var blogPost = _blogPostService.Get(postId);
if (blogPost == null)
throw new ArgumentException();
throw new NotImplementedException();
return CreateBlogStruct(blogPost, urlHelper);
}
private bool MetaWeblogEditPost(
int postId,
string user,
string userName,
string password,
XRpcStruct content,
bool publish) {
//var pageRevision = _pageManager.AcquireDraft(postId);
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(StandardPermissions.AccessFrontEnd, user, null);
//var title = content.Optional<string>("title");
//var description = content.Optional<string>("description");
var blogPost = _blogPostService.Get(postId, VersionOptions.DraftRequired);
if (blogPost == null)
throw new ArgumentException();
//pageRevision.Title = title;
//pageRevision.Contents.First().Content = description;
//if (publish) {
// if (string.IsNullOrEmpty(pageRevision.Slug))
// pageRevision.Slug = "slug" + postId;
var title = content.Optional<string>("title");
var description = content.Optional<string>("description");
var slug = content.Optional<string>("wp_slug");
// _pageManager.Publish(pageRevision, new PublishOptions());
//}
blogPost.Title = title;
blogPost.Slug = slug;
blogPost.Text = description;
//return true;
if (publish) {
_blogPostService.Publish(blogPost);
}
throw new NotImplementedException();
return true;
}
private bool MetaWeblogDeletePost(
string appkey,
string postId,
string userName,
string password,
bool publish) {
var user = _membershipService.ValidateUser(userName, password);
_authorizationService.CheckAccess(StandardPermissions.AccessFrontEnd, user, null);
var blogPost = _blogPostService.Get(Convert.ToInt32(postId), VersionOptions.Latest);
if (blogPost == null)
throw new ArgumentException();
_blogPostService.Delete(blogPost);
return true;
}
private static XRpcStruct CreateBlogStruct(BlogPost blogPost, UrlHelper urlHelper) {
var url = urlHelper.AbsoluteAction(() => urlHelper.BlogPost(blogPost.Blog.Slug, blogPost.Slug));
return new XRpcStruct()
.Set("postid", blogPost.Id)
.Set("dateCreated", blogPost.CreatedUtc)
.Set("title", blogPost.Title)
.Set("wp_slug", blogPost.Slug)
.Set("description", blogPost.Text)
.Set("link", url)
.Set("permaLink", url);
}
}
}

View File

@@ -5,5 +5,6 @@
<%@ Import Namespace="Orchard.Blogs.Models"%>
<h1><%=Html.TitleForPage(Model.Item.Name) %></h1>
<% Html.RegisterLink(new LinkEntry { Rel = "wlwmanifest", Type = "application/wlwmanifest+xml", Href = Url.BlogLiveWriterManifest(Model.Item.Slug) });%>
<% Html.RegisterLink(new LinkEntry { Rel = "EditURI", Type = "application/rsd+xml", Title = "RSD", Href = Url.BlogRsd(Model.Item.Slug) });%>
<% Html.Zone("primary", ":manage :metadata");
Html.ZonesAny(); %>

View File

@@ -6,4 +6,4 @@
<%@ Import Namespace="Orchard.Blogs.Models"%>
<h2><%=Html.Link(Html.Encode(Model.Item.Title), Url.BlogPost(Model.Item.Blog.Slug, Model.Item.Slug)) %></h2>
<div class="meta"><%=Html.PublishedState(Model.Item) %> | <%Html.Zone("meta");%></div>
<div class="content"><%=Model.Item.As<BodyAspect>().Text ?? string.Format("<p><em>{0}</em></p>", _Encoded("there's no content for this blog post"))%></div>
<div class="content"><%=Model.Item.Text ?? string.Format("<p><em>{0}</em></p>", _Encoded("there's no content for this blog post"))%></div>

View File

@@ -36,7 +36,7 @@
<%=_Encoded("Last modified: ") + Html.DateTimeRelative(Model.Item.As<CommonAspect>().ModifiedUtc.Value) %><%
} %>&nbsp;&#124;&nbsp;
</li>
<li><%=_Encoded("By {0}", Model.Item.Creator.UserName)%></li>
<li><%=_Encoded("By {0}", Model.Item.Creator == null ? String.Empty : Model.Item.Creator.UserName)%></li>
</ul>
</div>
<div class="related"><%

View File

@@ -5,5 +5,6 @@
<%@ Import Namespace="Orchard.Blogs.Models"%>
<h2><%=Html.TitleForPage(Model.Item.Name) %></h2>
<% Html.RegisterLink(new LinkEntry { Rel = "wlwmanifest", Type = "application/wlwmanifest+xml", Href = Url.BlogLiveWriterManifest(Model.Item.Slug) });%>
<% Html.RegisterLink(new LinkEntry { Rel = "EditURI", Type = "application/rsd+xml", Title = "RSD", Href = Url.BlogRsd(Model.Item.Slug) });%>
<% Html.Zone("primary", ":manage :metadata");
Html.ZonesAny(); %>

View File

@@ -6,4 +6,4 @@
<%@ Import Namespace="Orchard.Blogs.Models"%>
<h2><%=Html.Link(Html.Encode(Model.Item.Title), Url.BlogPost(Model.Item.Blog.Slug, Model.Item.Slug)) %></h2>
<div class="meta"><%=Html.PublishedState(Model.Item) %> | <%Html.Zone("meta");%></div>
<div class="postsummary"><%=Model.Item.As<BodyAspect>().Text ?? string.Format("<p><em>{0}</em></p>", _Encoded("there's no content for this blog post"))%></div>
<div class="postsummary"><%=Model.Item.Text ?? string.Format("<p><em>{0}</em></p>", _Encoded("there's no content for this blog post"))%></div>

View File

@@ -5,6 +5,7 @@
<%@ Import Namespace="Orchard.Blogs.Models"%>
<% Html.RegisterLink(new LinkEntry { Rel = "wlwmanifest", Type = "application/wlwmanifest+xml", Href = Url.BlogLiveWriterManifest(Model.Item.Slug) });%>
<% Html.RegisterLink(new LinkEntry { Rel = "EditURI", Type = "application/rsd+xml", Title = "RSD", Href = Url.BlogRsd(Model.Item.Slug) });%>
<div class="bloginfo">
<h1><%=Html.TitleForPage(Model.Item.Name) %></h1>
</div>

View File

@@ -9,4 +9,4 @@
<div class="meta"><%=Html.PublishedState(Model.Item) %> | <%Html.Zone("meta");%></div>
<div class="postsummary"><%=Model.Item.As<BodyAspect>().Text ?? string.Format("<p><em>{0}</em></p>", _Encoded("there's no content for this blog post"))%></div>
<div class="postsummary"><%=Model.Item.Text ?? string.Format("<p><em>{0}</em></p>", _Encoded("there's no content for this blog post"))%></div>

View File

@@ -0,0 +1,15 @@
using System;
using System.Web.Mvc;
namespace Orchard.Mvc.Extensions {
public static class UrlHelperExtensions {
public static string AbsoluteAction(this UrlHelper urlHelper, Func<string> urlAction) {
return urlHelper.MakeAbsolute(urlAction());
}
private static string MakeAbsolute(this UrlHelper urlHelper, string url) {
var siteUrl = urlHelper.RequestContext.HttpContext.Request.Url.GetLeftPart(UriPartial.Authority);
return siteUrl + url;
}
}
}

View File

@@ -153,6 +153,7 @@
<Compile Include="Extensions\Loaders\AreaExtensionLoader.cs" />
<Compile Include="Extensions\UriExtensions.cs" />
<Compile Include="Mvc\AntiForgery\ValidateAntiForgeryTokenOrchardAttribute.cs" />
<Compile Include="Mvc\Extensions\UrlHelperExtensions.cs" />
<Compile Include="Mvc\ViewModels\AdaptedViewModel.cs" />
<Compile Include="Mvc\ViewUserControl.cs">
<SubType>ASPXCodeBehind</SubType>

View File

@@ -2,6 +2,7 @@
public class LinkEntry {
public string Rel { get; set; }
public string Type { get; set; }
public string Title { get; set; }
public string Href { get; set; }
}
}

View File

@@ -94,6 +94,13 @@ namespace Orchard.UI.Resources {
.Append(@"""");
}
if (!string.IsNullOrEmpty(link.Title)) {
sb
.Append(@" title=""")
.Append(html.AttributeEncode(link.Title))
.Append(@"""");
}
if (!string.IsNullOrEmpty(link.Href)) {
sb
.Append(@" href=""")