Edit and Delete a Blog
12 Jun 2009 @ 02:54PM

Updated: 26 Jan 2010 @ 03:05PM
Now that we can create a blog, let's make it so we can both edit and delete blogs. We'll begin this by editing our showBlogs() method. You may have noticed that the edit and delete links are still visible to everyone. We'll change that and make them actually do something.
private string showBlogs()
{
     string content = null;
     string select = "SELECT top 30 blogID, blogTitle, blogText, displayName, displayDate, " +
          "CASE " +
               "WHEN showEmail = 1 THEN ' (<a href="mailto: ' + email + '">' + email + '</a>)' " +
               "ELSE '' " +
          "END AS 'email', " +
           "(SELECT COUNT(*) FROM comments WHERE blogID=a.blogID and visible=1) as Comments, " +
           "b.userID " +
     "FROM blogs a " +
          "JOIN users b on " +
               "a.userID=b.userID " +
     "WHERE visible=1 " +
     "ORDER BY displayDate Desc";

     SqlDataReader dr = query(select);
     while (dr.Read())
     {
          bool allowEdit = (accessLevel == 255 || (accessLevel >= 100 && userid == Convert.ToInt16(dr["userID"])))? true: false;

          content += @"<div class='blogEntry'>
               <div class='blogTitle'>
                    <div class='title'>"
+ dr["blogTitle"] + @"</div>";
          if (allowEdit)
          {
               content += "<div class='commands'>" +
                    "<a href='default.aspx?option=editBlog&blogID=" + dr["blogID"] + " '>Edit</a> / " +
                    "<a href='default.aspx?option=deleteBlog&blogID=" + dr["blogID"] + "'>Delete</a>" +
               "</div>";
          }
          content += @"</div>
               <div class='blogSubTitle'>
                    <div class='author'>By "
+ dr["displayName"] + dr["email"] + @"</div>
                    <div class='date'>"
+ Convert.ToDateTime(dr["displayDate"]).ToString("hh:mmtt dd MMM yyyy") + @"</div>
               </div>
               <div class='text'>"
+ Convert.ToString(dr["blogText"]).Replace("n", "<br>") + @"</div>
               <div class='comments'><a href=''>Comments ("
+ dr["Comments"] + @") </a></div>
          </div>"
;
     }
     dr.Dispose();
     return content;
}

So, to begin with, I made some changes to the select statement by adding the userID and adding a WHERE clause. The WHERE clause makes it so people can only see blogs with visible set to 1... this should've been set that way from the beginning, but c'est la vie. The userid is for our use in restricing access to edit and delete blogs.

Within the dr.Read() loop, I create a bool called allowEdit. If the user's accessLevel is 255, they can edit/delete any blog. Otherwise, if it's >= 100 and the userID of the user matches the userID of the blog creator, they can edit/delete the blog. So, basically a site admin (accessLevel 255) can edit any blog, while anyone else can only edit their own blogs. The last thing I did was alter the edit and delete links to pass different options, either editBlog or deleteBlog, as well as the blogID.
Comments (0)
Next we alter our Page_Load() method to look for those variables.
switch (getVariable("option", var.GET))
{
     case "writeBlog":
     case "editBlog":
          if (accessLevel < 100)
          {
               break;
          }
          showblogs = false;
          try
          {
               blogID = Convert.ToInt16(getVariable("blogID", var.GET));
          }
          catch { }
          content += writeBlog(blogID);
          break;
     case "deleteBlog":
          if (accessLevel < 100)
          {
               break;
          }
          try
          {
               blogID = Convert.ToInt16(getVariable("blogID", var.GET));
          }
          catch { }
          content += deleteBlog(blogID);
          break;
}

That's the full GET case. We can see our writeBlog option at the top. I've also added editBlog directly underneath it. Basically, the two execute exactly the same code paths. Then there's the deleteBlog option underneath which is used to execute another method called deleteBlog(). We'll check this method out first since it's quite easy.
Comments (0)
private string deleteBlog(int blogID)
{
     string content = null;
     string select = null;

     //see if the user can delete this blog
     if (accessLevel < 255)
     {
          bool mayEdit = false;
          select = "SELECT userid FROM blogs WHERE blogID=" + blogID;
          SqlDataReader dr = query(select);
          if (dr.HasRows)
          {
               dr.Read();
               if (Convert.ToInt16(dr["userid"]) == userid)
               {
                    mayEdit = true;
               }
          }
          dr.Dispose();
          if(!mayEdit){
               return "<div class='error'>Error: Not Authorized</div>";
          }
     }

     select = "UPDATE blogs SET visible=0, modifiedDate=getdate() WHERE blogID=" + blogID;
     query(select);
     content += "<div class='error'>Blog Deleted</div>";
     return content;
}

So here the first thing we do is make sure the user is authorized to delete the blog. If they're an admin, we just go directly to the update statement. If they're not, we retrieve the userid for the blog. We set mayEdit to false. If dr HasRows, we check to see if the userid matches the current user's userid. If it does, we set mayEdit to true. Afterward we check to see if mayEdit is false. If it is, we return an error.

After that we just set the deleted blog to not be visible. Why not delete the row? You can't undo a delete. This is good enough. If you wanted to permanently delete it you could always make a delete statement, or even do an update if a user deletes it, or a delete if an admin selects delete. There are many ways you can swing this. Please note that there's no prompt of 'are you sure'. If you click delete, it's done.
Comments (0)
Next, the edit.
private string writeBlog(int blogID)
{
     string content = null, blogTitle = null, blogText = "", blogDisplayName = displayName, blogEmail = email;
     DateTime displayDate = DateTime.Now, blogCreateDate = DateTime.Now, modifiedDate = DateTime.Now;
     bool visible = true, blogShowEmail = showEmail;
     int numComments = 0;

     if (blogID > 0)
     {
          //editing blog
          string select = @"SELECT a.userID, blogTitle, blogText, visible, a.createDate, displayDate, modifiedDate,
               (SELECT COUNT(*) FROM comments WHERE blogID=a.blogID and visible=1) as Comments,
               displayName, email, showEmail
          FROM blogs a
               JOIN users b
                    on a.userID = b.userID
          WHERE a.blogID = "
+ blogID;
          bool mayEdit = false;
          SqlDataReader dr = query(select);
          if (dr.HasRows)
          {
               dr.Read();
               if (accessLevel == 255 || (userid == Convert.ToInt16(dr["userID"])))
               {
                    mayEdit = true;
                    blogTitle = Convert.ToString(dr["blogTitle"]);
                    blogText = Convert.ToString(dr["blogText"]);
                    visible = (Convert.ToInt16(dr["visible"]) == 0) ? false : true;
                    try { blogCreateDate = Convert.ToDateTime(dr["createDate"]); } catch { }
                    try { modifiedDate = Convert.ToDateTime(dr["modifiedDate"]); } catch { }
                    numComments = Convert.ToInt16(dr["Comments"]);
                    blogDisplayName = Convert.ToString(dr["displayName"]);
                    blogEmail = Convert.ToString(dr["email"]);
                    blogShowEmail = (Convert.ToInt16(dr["showEmail"]) == 1) ? true : false;
               }
          }
          dr.Dispose();
          if (!mayEdit)
          {
               return "<div class='error'>Error: Not Authorized</div>";
          }

     }
     content += @"<form method='POST' action='default.aspx' style='display: inline;'><div class='blogEntry'>
          <div class='blogTitle'>
               <div class='title'>Title:<input name='blogTitle' size=60 value='"
+ blogTitle + @"'> Visible:<input type='checkbox' name='visible'";
     if (visible) { content += " checked"; }
     content += @"></div>
          </div>
          <div class='blogSubTitle'>
               <div class='author'>By "
+ blogDisplayName;
     if (blogShowEmail) { content += " (<a href=\"mailto: " + blogEmail + "\">" + blogEmail + "</a>)"; }
     content += "</div><div class='date'>";
     if (blogID < 0)
     {
          content += "Display<input name='displayDate' value='" + displayDate + @"'><br>" +
               "Modified<input name='displayDate' value='" + modifiedDate + @"' disabled><br>" +
               "Created<input name='displayDate' value='" + blogCreateDate + @"' disabled><br>";
     }
     else
     {
          content += "<input name='displayDate' value='" + displayDate + @"'>";
     }
     
     content += @"</div>
          </div>
          <div class='text'><textarea name='blogText' rows=10 style='width: 100%;'>"
+ blogText + @"</textarea></div>
          <div class='comments'>Comments ("
+ numComments + @")</div>
     </div>
     <input type='hidden' name='blogID' value='"
+ blogID + @"'>
     <input type='submit' name='option' value='Save Blog'>
     <input type='reset' value='Clear'></form>
     <form action='default.aspx' style='display: inline;'>
          <input type='submit' value='Cancel'>
     </form>"
;

     return content;
}

Ok, we started out with the writeBlog() method we had before, but made quite a few changes. In the first section, we initialized a bunch more variables. These include the modifiedDate and blogCreateDate variables which wouldn't have been used when creating a new blog. We also have some variables relating to the author's displayname and email. If you're creating a blog, you're the author and the info is your own. However, if you're an admin you can edit someone else's blog, so we need to keep the original author's name, email and email visibility settings, hence the reset of the new variables.

Within the if(blogID > 0) block, we set up our editing. We query the database for all the info we need, then process that request. Like in the delete command, if the user isn't an admin and not the creator of the blog, we just throw an unauthorized error and exit. Otherwise, we populate all our variables. We then head into the form for editing the blog.

This is almost the same, with a few changes. We now use the email, email visibility and displayname settings that we created earlier, rather than just defaulting to the current user's information. As mentioned, this is in case an admin edits someone else's blog. We don't want the blog to contain the admin's info, we want it to contain the info for the original creator. We also change the way we display dates. We don't actually allow the user to change the created and modified dates, but at least you can see them here. For all intents and purposes, that's it.
Comments (0)
So next, we need to be able to catch a save request.
     if (blogID > 0)
     {
          //edit an existing blog
          if (accessLevel < 255)
          {
               bool mayEdit = false;
               select = "SELECT userid FROM blogs WHERE blogID=" + blogID;
               SqlDataReader dr = query(select);
               if (dr.HasRows)
               {
                    dr.Read();
                    if (userid == Convert.ToInt16(dr["userid"]))
                    {
                         mayEdit = true;
                    }
               }
               dr.Dispose();
               if (!mayEdit)
               {
                    return "<div class='error'>Error: Not Authorized</div>";
               }
          }

          select = @"UPDATE blogs SET
               blogTitle='"
+ blogTitle + @"',
               blogText='"
+ blogText + @"',
               visible="
+ visible + @",
               displayDate='"
+ displayDate + @"',
               modifiedDate=getdate()
          WHERE blogID="
+ blogID;
     }
     else
     {
          //create a new blog

I've edited the saveBlog() method, specifically the block that begins with if(blogID > 0). Within here I verify the user is actually allowed to make these changes, then I build an update statement. It's actually fairly straight forward and quick since we'd designed this method with that functionality in mind.

Files To This Point

With that change, we can now log in, log out, create blogs, edit blogs and delete blogs. Not so bad, right? Right. So next, let's tackle user management. We need to be able to create, edit and delete users.
Comments (0)