diff --git a/Project-Unite/Controllers/BlogController.cs b/Project-Unite/Controllers/BlogController.cs new file mode 100644 index 0000000..d1aa0f9 --- /dev/null +++ b/Project-Unite/Controllers/BlogController.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using Microsoft.AspNet.Identity; +using Project_Unite.Models; + +namespace Project_Unite.Controllers +{ + public class BlogController : Controller + { + // GET: Blog + public ActionResult Index() + { + return View(new ApplicationDbContext().BlogPosts); + } + + public ActionResult ViewBlog(string id) + { + var db = new ApplicationDbContext(); + var blog = db.BlogPosts.FirstOrDefault(x => x.Id == id); + if (blog == null) + return new HttpStatusCodeResult(404); + return View(blog); + } + + [Authorize] + public ActionResult DislikePost(string id) + { + var db = new ApplicationDbContext(); + var topic = db.BlogPosts.FirstOrDefault(x => x.Id == id); + var uid = User.Identity.GetUserId(); + if (topic == null) + return new HttpStatusCodeResult(404); + if (topic.EditHistory.OrderBy(x => x.EditedAt).First().UserId == User.Identity.GetUserId()) + return RedirectToAction("Index", new { id = id, triedtolikeowntopic = true }); + var like = db.Likes.Where(x => x.Topic == topic.Id).FirstOrDefault(x => x.User == uid); + if (like != null) + { + if (like.IsDislike == false) + { + like.IsDislike = true; + } + else + { + db.Likes.Remove(like); + } + } + else + { + like = new Models.Like(); + like.Id = Guid.NewGuid().ToString(); + like.User = User.Identity.GetUserId(); + like.Topic = topic.Id; + like.LikedAt = DateTime.Now; + like.IsDislike = true; + db.Likes.Add(like); + } + db.SaveChanges(); + return RedirectToAction("Index", new { id = id }); + } + + [Authorize] + public ActionResult LikePost(string id) + { + var db = new ApplicationDbContext(); + var topic = db.BlogPosts.FirstOrDefault(x => x.Id == id); + var uid = User.Identity.GetUserId(); + if (topic == null) + return new HttpStatusCodeResult(404); + if (topic.EditHistory.OrderBy(x => x.EditedAt).First().UserId == User.Identity.GetUserId()) + return RedirectToAction("Index", new { id = id, triedtolikeowntopic = true }); + var like = db.Likes.Where(x => x.Topic == topic.Id).FirstOrDefault(x => x.User == uid); + if (like != null) + { + if (like.IsDislike == true) + { + like.IsDislike = false; + } + else + { + db.Likes.Remove(like); + } + } + else + { + like = new Models.Like(); + like.Id = Guid.NewGuid().ToString(); + like.User = User.Identity.GetUserId(); + like.Topic = topic.Id; + like.LikedAt = DateTime.Now; + like.IsDislike = false; + db.Likes.Add(like); + } + db.SaveChanges(); + return RedirectToAction("Index", new { id = id }); + } + + + [ValidateInput(false)] + [Authorize] + [HttpPost] + [ValidateAntiForgeryToken] + public ActionResult ViewBlog(string id, string comment) + { + var db = new ApplicationDbContext(); + var blog = db.BlogPosts.FirstOrDefault(x => x.Id == id); + if (blog == null) + return new HttpStatusCodeResult(404); + if (string.IsNullOrWhiteSpace(comment)) + { + ViewBag.Error = "You must enter a comment with actual text in it."; + return View(blog); + } + if(comment.Length < 20) + { + ViewBag.Error = "Your comment must have at least 20 characters in it."; + return View(blog); + } + var post = new ForumPost(); + post.AuthorId = User.Identity.GetUserId(); + post.Body = comment; + post.Id = Guid.NewGuid().ToString(); + post.Parent = id; + post.PostedAt = DateTime.Now; + db.ForumPosts.Add(post); + db.SaveChanges(); + + return View(blog); + } + + [Authorize] + public ActionResult PostBlog() + { + if (!ACL.Granted(User.Identity.Name, "CanBlog")) + return new HttpStatusCodeResult(403); + + var model = new PostBlogViewModel(); + return View(model); + } + + [Authorize] + [ValidateAntiForgeryToken] + [HttpPost] + public ActionResult PostBlog(PostBlogViewModel model) + { + if (!ModelState.IsValid) + return View(model); + + var db = new ApplicationDbContext(); + var blog = new BlogPost(); + blog.AuthorId = User.Identity.GetUserId(); + blog.Contents = model.Contents; + blog.Name = model.Name; + blog.Id = model.Name.ToLower(); + string allowed = "-_abcdefghijklmnopqrstuvwxyz1234567890"; + foreach(var c in blog.Id.ToCharArray()) + { + if (!allowed.Contains(c)) + blog.Id = blog.Id.Replace(c, '_'); + } + blog.PostedAt = DateTime.Now; + db.BlogPosts.Add(blog); + db.SaveChanges(); + return RedirectToAction("ViewBlog", new { id = blog.Id }); + } + } +} \ No newline at end of file diff --git a/Project-Unite/Models/BlogModels.cs b/Project-Unite/Models/BlogModels.cs new file mode 100644 index 0000000..00ffbea --- /dev/null +++ b/Project-Unite/Models/BlogModels.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Web; +using System.Web.Mvc; + +namespace Project_Unite.Models +{ + public class PostBlogViewModel + { + [Required(ErrorMessage="Please enter a name for your post!")] + [MinLength(5, ErrorMessage ="Your post's name must have at least 5 characters.")] + [MaxLength(50, ErrorMessage = "Your post's name must have at least 50 characters.")] + public string Name { get; set; } + + [AllowHtml] + [Required(ErrorMessage ="You can't post an empty blog post!")] + [MinLength(20, ErrorMessage = "Your post must have at least 20 characters.")] + public string Contents { get; set; } + } + + public class BlogPost + { + public string Id { get; set; } + public string AuthorId { get; set; } + public ForumPost[] Comments + { + get + { + return new ApplicationDbContext().ForumPosts.Where(x => x.Parent == this.Id).ToArray(); + } + } + public Like[] Likes + { + get + { + return new ApplicationDbContext().Likes.Where(x => x.Topic == this.Id&&x.IsDislike == false).ToArray(); + } + } + + public string Name { get; set; } + + public string Summary + { + get + { + return Contents.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)[0]; + } + } + + public Like[] Dislikes + { + get + { + return new ApplicationDbContext().Likes.Where(x => x.Topic == this.Id && x.IsDislike == true).ToArray(); + + } + } + + public DateTime PostedAt { get; set; } + + public string Contents { get; set; } + } +} \ No newline at end of file diff --git a/Project-Unite/Models/IdentityModels.cs b/Project-Unite/Models/IdentityModels.cs index cf04def..42f9e30 100644 --- a/Project-Unite/Models/IdentityModels.cs +++ b/Project-Unite/Models/IdentityModels.cs @@ -219,6 +219,7 @@ namespace Project_Unite.Models return new ApplicationDbContext(); } + public DbSet BlogPosts { get; set; } public DbSet ReadPosts { get; set; } public DbSet Downloads { get; set; } public DbSet Backups { get; set; } diff --git a/Project-Unite/Project-Unite.csproj b/Project-Unite/Project-Unite.csproj index 5f09e0c..cde0944 100644 --- a/Project-Unite/Project-Unite.csproj +++ b/Project-Unite/Project-Unite.csproj @@ -243,6 +243,7 @@ + @@ -424,6 +425,7 @@ + @@ -554,6 +556,9 @@ + + + diff --git a/Project-Unite/Views/Blog/Index.cshtml b/Project-Unite/Views/Blog/Index.cshtml new file mode 100644 index 0000000..56af4ef --- /dev/null +++ b/Project-Unite/Views/Blog/Index.cshtml @@ -0,0 +1,27 @@ +@model IEnumerable +@{ + ViewBag.Title = "Blog"; +} + +

Developer Blog

+ +

We ShiftOS devs have a lot going on. If you want to find out a bit more about what we do behind the scenes, this is the place for you. We'll post lots of things for you to read here.

+ +@if(ACL.Granted(User.Identity.Name, "CanBlog")) +{ + +} + +@foreach(var blog in Model) +{ +
+
+

@blog.Name

+

Posted by @Html.UserLink(blog.AuthorId) at @blog.PostedAt - @blog.Likes.Length likes, @blog.Dislikes.Length dislikes

+

@Html.Markdown(blog.Summary)

+ @Html.ActionLink("Read more", "ViewBlog", "Blog", new { id = blog.Id }, new { @class = "btn btn-default" }) +
+
+} \ No newline at end of file diff --git a/Project-Unite/Views/Blog/PostBlog.cshtml b/Project-Unite/Views/Blog/PostBlog.cshtml new file mode 100644 index 0000000..e3ad6f7 --- /dev/null +++ b/Project-Unite/Views/Blog/PostBlog.cshtml @@ -0,0 +1,32 @@ +@model Project_Unite.Models.PostBlogViewModel +@{ + ViewBag.Title = "Post blog"; +} + +

Post a blog

+ +

Just fill in the form and we'll get the post up onto the cloud.

+ +@using (Html.BeginForm()) +{ +
+
+ @Html.ValidationSummary() +
+
+ + + + + + + + + + + + + + +
Name:@Html.TextBoxFor(Model=>Model.Name, new{@class="form-control"})
Body:@Html.TextAreaFor(Model => Model.Contents, new { @class = "form-control", rows="10" })
+} \ No newline at end of file diff --git a/Project-Unite/Views/Blog/ViewBlog.cshtml b/Project-Unite/Views/Blog/ViewBlog.cshtml new file mode 100644 index 0000000..0511698 --- /dev/null +++ b/Project-Unite/Views/Blog/ViewBlog.cshtml @@ -0,0 +1,71 @@ +@model Project_Unite.Models.BlogPost +@{ + ViewBag.Title = Model.Name; +} + +

Developer Blog

+ +

@Model.Name

+ +@if (!string.IsNullOrWhiteSpace(ViewBag.Error)) +{ +
+
+

@ViewBag.Error

+
+
+} + +

Posted by @Html.UserLink(Model.AuthorId) at @Model.PostedAt

+ +
+
+ @Html.Markdown(Model.Contents) +
+
+ + + +
+ +

Comments

+ +@if (Request.IsAuthenticated) +{ +
+
+ @using (Html.BeginForm()) + { + + @Html.AntiForgeryToken() + + + + } +
+
+} + +@foreach(var comment in Model.Comments.OrderBy(x=>x.PostedAt)) +{ +
+
+

@Html.UserLink(comment.AuthorId) said on @comment.PostedAt:

+

@Html.Markdown(comment.Body)

+
+
+} \ No newline at end of file