Developer blog

This commit is contained in:
Michael 2017-04-07 21:13:44 -04:00
parent 1de8bc4bd0
commit b1e6d3dee9
7 changed files with 370 additions and 0 deletions

View file

@ -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 });
}
}
}

View file

@ -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; }
}
}

View file

@ -219,6 +219,7 @@ namespace Project_Unite.Models
return new ApplicationDbContext(); return new ApplicationDbContext();
} }
public DbSet<BlogPost> BlogPosts { get; set; }
public DbSet<ReadPost> ReadPosts { get; set; } public DbSet<ReadPost> ReadPosts { get; set; }
public DbSet<Download> Downloads { get; set; } public DbSet<Download> Downloads { get; set; }
public DbSet<DatabaseBackup> Backups { get; set; } public DbSet<DatabaseBackup> Backups { get; set; }

View file

@ -243,6 +243,7 @@
<Compile Include="Controllers\AccountController.cs" /> <Compile Include="Controllers\AccountController.cs" />
<Compile Include="Controllers\AdminController.cs" /> <Compile Include="Controllers\AdminController.cs" />
<Compile Include="Controllers\APIController.cs" /> <Compile Include="Controllers\APIController.cs" />
<Compile Include="Controllers\BlogController.cs" />
<Compile Include="Controllers\DeveloperController.cs" /> <Compile Include="Controllers\DeveloperController.cs" />
<Compile Include="Controllers\DownloadController.cs" /> <Compile Include="Controllers\DownloadController.cs" />
<Compile Include="Controllers\ForumController.cs" /> <Compile Include="Controllers\ForumController.cs" />
@ -424,6 +425,7 @@
<Compile Include="Models\AccountViewModels.cs" /> <Compile Include="Models\AccountViewModels.cs" />
<Compile Include="Models\AddUserToRoleViewModel.cs" /> <Compile Include="Models\AddUserToRoleViewModel.cs" />
<Compile Include="Models\AdminViewModels.cs" /> <Compile Include="Models\AdminViewModels.cs" />
<Compile Include="Models\BlogModels.cs" />
<Compile Include="Models\Download.cs" /> <Compile Include="Models\Download.cs" />
<Compile Include="Models\ForumCategory.cs" /> <Compile Include="Models\ForumCategory.cs" />
<Compile Include="Models\ForumViewModels.cs" /> <Compile Include="Models\ForumViewModels.cs" />
@ -554,6 +556,9 @@
<Content Include="Views\Wiki\AddPage.cshtml" /> <Content Include="Views\Wiki\AddPage.cshtml" />
<Content Include="Views\Wiki\EditPage.cshtml" /> <Content Include="Views\Wiki\EditPage.cshtml" />
<Content Include="Views\Home\Search.cshtml" /> <Content Include="Views\Home\Search.cshtml" />
<Content Include="Views\Blog\ViewBlog.cshtml" />
<Content Include="Views\Blog\Index.cshtml" />
<Content Include="Views\Blog\PostBlog.cshtml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="App_Data\" /> <Folder Include="App_Data\" />

View file

@ -0,0 +1,27 @@
@model IEnumerable<Project_Unite.Models.BlogPost>
@{
ViewBag.Title = "Blog";
}
<h2>Developer Blog</h2>
<p>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.</p>
@if(ACL.Granted(User.Identity.Name, "CanBlog"))
{
<ul class="nav nav-pills">
<li><a href="@Url.Action("PostBlog")"><span class="glyphicon glyphicon-file"></span> Post</a></li>
</ul>
}
@foreach(var blog in Model)
{
<div class="panel">
<div class="panel-body">
<h4>@blog.Name</h4>
<p>Posted by @Html.UserLink(blog.AuthorId) at @blog.PostedAt - @blog.Likes.Length likes, @blog.Dislikes.Length dislikes</p>
<p>@Html.Markdown(blog.Summary)</p>
@Html.ActionLink("Read more", "ViewBlog", "Blog", new { id = blog.Id }, new { @class = "btn btn-default" })
</div>
</div>
}

View file

@ -0,0 +1,32 @@
@model Project_Unite.Models.PostBlogViewModel
@{
ViewBag.Title = "Post blog";
}
<h2>Post a blog</h2>
<p>Just fill in the form and we'll get the post up onto the cloud.</p>
@using (Html.BeginForm())
{
<div class="panel-danger panel">
<div class="panel-body">
@Html.ValidationSummary()
</div>
</div>
<table class="table">
<tr>
<td style="width:25%">Name:</td>
<td>@Html.TextBoxFor(Model=>Model.Name, new{@class="form-control"})</td>
</tr>
<tr>
<td style="width:25%">Body:</td>
<td>@Html.TextAreaFor(Model => Model.Contents, new { @class = "form-control", rows="10" })</td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Post!" class="btn btn-primary" /></td>
</tr>
</table>
}

View file

@ -0,0 +1,71 @@
@model Project_Unite.Models.BlogPost
@{
ViewBag.Title = Model.Name;
}
<h2>Developer Blog</h2>
<h3>@Model.Name</h3>
@if (!string.IsNullOrWhiteSpace(ViewBag.Error))
{
<div class="panel panel-danger">
<div class="panel-body">
<p><span class="glyphicon glyphicon-exclamation-sign"></span> @ViewBag.Error</p>
</div>
</div>
}
<p>Posted by @Html.UserLink(Model.AuthorId) at @Model.PostedAt</p>
<div class="panel">
<div class="panel-body">
@Html.Markdown(Model.Contents)
</div>
</div>
<ul class="nav nav-pills">
@{
string like_uri = "#";
string dislike_uri = "#";
if (Request.IsAuthenticated)
{
like_uri = Url.Action("LikePost", new { id = Model.Id });
dislike_uri = Url.Action("DislikePost", new { id = Model.Id });
}
<li><a href="@like_uri"><span class="glyphicon glyphicon-thumbs-up"></span> @Model.Likes.Length</a></li>
<li><a href="@dislike_uri"><span class="glyphicon glyphicon-thumbs-down"></span> @Model.Dislikes.Length</a></li>
}
</ul>
<hr/>
<h4>Comments</h4>
@if (Request.IsAuthenticated)
{
<div class="panel">
<div class="panel-body">
@using (Html.BeginForm())
{
<input type="hidden" name="id" value="@Model.Id" />
@Html.AntiForgeryToken()
<textarea class="form-control" rows="5" name="comment" value=""></textarea>
<input type="submit" class="btn btn-primary" value="Comment" />
}
</div>
</div>
}
@foreach(var comment in Model.Comments.OrderBy(x=>x.PostedAt))
{
<div class="panel">
<div class="panel-body">
<p><strong>@Html.UserLink(comment.AuthorId)</strong> said on @comment.PostedAt:</p>
<p>@Html.Markdown(comment.Body)</p>
</div>
</div>
}