PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/Implementations/Events/Oxite.Blogs/Controllers/MetaWeblogController.cs

#
C# | 245 lines | 200 code | 35 blank | 10 comment | 10 complexity | 647d38bd6e28d7e089ed1c4e88852b4e MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. // --------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. // This source code is made available under the terms of the Microsoft Public License (Ms-PL)
  4. // http://www.codeplex.com/oxite/license
  5. // ---------------------------------
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Security.Authentication;
  10. using System.Security.Cryptography;
  11. using System.Text;
  12. using System.Web.Mvc;
  13. using System.Web.Routing;
  14. using System.Xml.Linq;
  15. using Oxite.Extensions;
  16. using Oxite.Infrastructure;
  17. using Oxite.Infrastructure.XmlRpc;
  18. using Oxite.Models;
  19. using Oxite.Modules.Blogs.Models;
  20. using Oxite.Modules.Blogs.Services;
  21. using Oxite.Modules.FormsAuthentication.Extensions;
  22. using Oxite.Modules.Membership.Services;
  23. using Oxite.Modules.Blogs.Extensions;
  24. using Oxite.Modules.Tags.Services;
  25. using Oxite.Services;
  26. namespace Oxite.Modules.Blogs.Controllers
  27. {
  28. public class MetaWeblogController : Controller
  29. {
  30. private readonly IBlogService blogService;
  31. private readonly IPostService postService;
  32. private readonly ITagService tagService;
  33. private readonly IUserService userService;
  34. private readonly IRegularExpressions expressions;
  35. private readonly OxiteContext context;
  36. public MetaWeblogController(IBlogService blogService, IPostService postService, ITagService tagService, IUserService userService, IRegularExpressions expressions, OxiteContext context)
  37. {
  38. this.blogService = blogService;
  39. this.postService = postService;
  40. this.tagService = tagService;
  41. this.userService = userService;
  42. this.expressions = expressions;
  43. this.context = context;
  44. }
  45. public ContentResult Rsd(BlogAddress blogAddress)
  46. {
  47. return Content(GenerateRsd(blogAddress).ToString(), "text/xml");
  48. }
  49. protected XDocument GenerateRsd(BlogAddress blogAddress)
  50. {
  51. XNamespace rsdNamespace = "http://archipelago.phrasewise.com/rsd";
  52. XDocument rsd = new XDocument(
  53. new XElement(rsdNamespace + "rsd", new XAttribute("version", "1.0"),
  54. new XElement(rsdNamespace + "service",
  55. new XElement(rsdNamespace + "engineName", "Oxite"),
  56. new XElement(rsdNamespace + "engineLink", Url.Oxite()),
  57. new XElement(rsdNamespace + "homePageLink", Url.AbsolutePath(Url.Home())),
  58. new XElement(rsdNamespace + "apis",
  59. GenerateRsdApiList(blogAddress, rsdNamespace)
  60. )
  61. )
  62. ));
  63. return rsd;
  64. }
  65. protected XElement[] GenerateRsdApiList(BlogAddress blogAddress, XNamespace rsdNamespace)
  66. {
  67. IEnumerable<Blog> blogs = blogAddress != null ? new Blog[] { blogService.GetBlog(blogAddress) } : blogService.GetBlogs(0, 10000).ToArray();
  68. List<XElement> elements = new List<XElement>(blogs.Count());
  69. string apiLink = new UriBuilder(context.Site.Host) { Path = Url.MetaWeblog() }.Uri.ToString();
  70. foreach (Blog blog in blogs)
  71. {
  72. elements.Add(
  73. new XElement(
  74. rsdNamespace + "api",
  75. new XAttribute("name", "MetaWeblog"),
  76. new XAttribute("blogID", blog.Name),
  77. new XAttribute(
  78. "preferred",
  79. (blogs.Count() == 1 || string.Compare(blog.Name, blogAddress.BlogName, true) == 0).ToString().ToLower()
  80. ),
  81. new XAttribute("apiLink", apiLink)
  82. )
  83. );
  84. }
  85. return elements.ToArray();
  86. }
  87. [ActionName("metaWeblog.newPost")]
  88. public ActionResult NewPost(string blogId, string username, string password, IDictionary<string, object> post, bool publish)
  89. {
  90. if (string.IsNullOrEmpty(blogId)) throw new ArgumentException();
  91. Blog blog = blogService.GetBlog(new BlogAddress(blogId));
  92. //TODO: (erikpo) Move into a model binder?
  93. PostInput postInput = new PostInput(blog.Name, post["title"] as string, post["description"] as string,
  94. post["mt_excerpt"] as string,
  95. (post["categories"] as object[]).OfType<string>() ??
  96. Enumerable.Empty<string>(),
  97. string.IsNullOrEmpty(post["mt_basename"] as string)
  98. ? expressions.Slugify(post["title"] as string)
  99. : post["mt_basename"] as string,
  100. publish ? DateTime.UtcNow : (DateTime?) null,
  101. blog.CommentingDisabled);
  102. ModelResult<Post> results = postService.AddPost(postInput, EntityState.Normal);
  103. if (results.IsValid)
  104. return new XmlRpcResult(results.Item.ID.ToString());
  105. return new XmlRpcFaultResult(0, results.GetFirstException().Message);
  106. }
  107. [ActionName("metaWeblog.editPost")]
  108. public ActionResult EditPost(string postId, string username, string password, IDictionary<string, object> post, bool publish)
  109. {
  110. if (string.IsNullOrEmpty(postId)) throw new ArgumentException();
  111. Post existingPost = postService.GetPost(new MetaWeblogPostAddress(new Guid(postId)));
  112. //TODO: (erikpo) Move into a model binder?
  113. PostInput postInput = new PostInput(existingPost.Blog.Name, post["title"] as string,
  114. post["description"] as string, post["mt_excerpt"] as string,
  115. (post["categories"] as object[]).OfType<string>() ??
  116. Enumerable.Empty<string>(),
  117. string.IsNullOrEmpty(post["mt_basename"] as string)
  118. ? expressions.Slugify(post["title"] as string)
  119. : post["mt_basename"] as string,
  120. publish
  121. ? existingPost.Published.HasValue
  122. ? existingPost.Published.Value
  123. : DateTime.UtcNow
  124. : (DateTime?) null,
  125. existingPost.CommentingDisabled);
  126. ModelResult<Post> results = postService.EditPost(new PostAddress(existingPost.Blog.Name, existingPost.Slug), postInput, EntityState.Normal);
  127. if (results.IsValid)
  128. return new XmlRpcResult(true);
  129. return new XmlRpcFaultResult(0, results.GetFirstException().Message);
  130. }
  131. [ActionName("metaWeblog.getPost")]
  132. public ActionResult GetPost(string postId, string username, string password)
  133. {
  134. Post post = postService.GetPost(new MetaWeblogPostAddress(new Guid(postId)));
  135. if (post == null) throw new ArgumentOutOfRangeException();
  136. return new XmlRpcResult(ModelPostToServicePost(post));
  137. }
  138. //TODO: (erikpo) Need to implement this method if the current setup supports writing to the file system
  139. [ActionName("metaWeblog.newMediaObject")]
  140. public ActionResult NewMediaObject(string blogId, string username, string password, IDictionary<string, object> file)
  141. {
  142. return new XmlRpcFaultResult(0, "Not Implemented");
  143. }
  144. [ActionName("metaWeblog.getCategories")]
  145. public ActionResult GetCategories(string blogId, string username, string password)
  146. {
  147. return new XmlRpcResult(tagService.GetTags().Select(t => new Dictionary<string, object>{{"description", t.Name}, {"htmlUrl", string.Empty}, {"rssUrl", string.Empty}}).ToArray());
  148. }
  149. [ActionName("metaWeblog.getRecentPosts")]
  150. public ActionResult GetRecentPosts(string blogId, string username, string password, int numberOfPosts)
  151. {
  152. return new XmlRpcResult(postService.GetPostsWithDrafts(0, numberOfPosts, new BlogAddress(blogId)).Select(p => ModelPostToServicePost(p)).ToArray());
  153. }
  154. [ActionName("blogger.getUsersBlogs")]
  155. public ActionResult GetUsersBlogs(string apikey, string username, string password)
  156. {
  157. //TODO: (erikpo) Make this return only the list of blogs the current user has explicit access to
  158. return new XmlRpcResult(blogService.GetBlogs(0, 10000).Select(b => new Dictionary<string, object>{{"url", string.Empty}, {"blogid", b.Name}, {"blogName", b.DisplayName}}).ToArray());
  159. }
  160. [ActionName("blogger.deletePost")]
  161. public ActionResult DeletePost(string appkey, string postid, string username, string password, bool publish)
  162. {
  163. postService.RemovePost(new MetaWeblogPostAddress(new Guid(postid)));
  164. return new XmlRpcResult(true);
  165. }
  166. public ContentResult LiveWriterManifest()
  167. {
  168. XNamespace ns = "http://schemas.microsoft.com/wlw/manifest/weblog";
  169. //TODO: (erikpo) Make these settings dynamic based on capabilities
  170. XDocument doc =
  171. new XDocument(
  172. new XDeclaration("1.0", "utf-8", "no"),
  173. new XElement(
  174. ns + "manifest",
  175. new XElement(
  176. ns + "options",
  177. new XElement[]
  178. {
  179. new XElement(ns + "clientType", "Metaweblog"),
  180. new XElement(ns + "supportsExcerpt", "Yes"),
  181. new XElement(ns + "supportsNewCategories", "Yes"),
  182. new XElement(ns + "supportsNewCategoriesInline", "Yes"),
  183. new XElement(ns + "requiresHtmlTitles", "No"),
  184. new XElement(ns + "requiresXHTML", "Yes"),
  185. new XElement(ns + "supportsScripts", "Yes"),
  186. new XElement(ns + "supportsEmbeds", "Yes"),
  187. new XElement(ns + "supportsSlug", "Yes"),
  188. new XElement(ns + "supportsFileUpload", "No")
  189. }
  190. )
  191. )
  192. );
  193. return Content(doc.ToString(), "text/xml");
  194. }
  195. private static IDictionary<string, object> ModelPostToServicePost(Post post)
  196. {
  197. return new Dictionary<string, object>
  198. {
  199. { "categories", post.Tags.Select(t => t.Name).ToArray() },
  200. { "dateCreated", post.Created },
  201. { "description", post.Body },
  202. { "mt_basename", post.Slug },
  203. { "mt_excerpt", post.BodyShort },
  204. { "postid", post.ID.ToString() },
  205. { "title", post.Title },
  206. { "userid", post.Creator.ID.ToString() },
  207. };
  208. }
  209. }
  210. }