Real - World ASP .NET—Building a Content Management System - StephenR. G. Fraser
.pdf
EmailAlert ea = new EmailAlert(Context, code,
Convert.ToInt32(dt.Rows[0]["ByLine"]));
ea.Send();
Response.Redirect("EdList.aspx");
}
The Approval Phase
The approval process is actually very simple. As you can see in the AppList Web page (see Figure 14-9), the approver can only view, add a note to, approve, return (to the editor), or cancel the content. The code to handle these (except View and Notes) is very simple because all they deal with is changing status codes and updating the approver on the content database record.
Figure 14-9: The AppList Web page
Approving Content
The AppApprove Web page, as you can see in Figure 14-10, is virtually the same as the submit Web page of the author or editor. It has the standard headline, body, warning, and buttons that you found on the other submit Web pages.
Figure 14-10: The AppApprove Web page
The only difference between AppApprove and the other submits is that the status code is set to Approved and the Approver ID is set to the current approver. As the AppAppove Codebehind shows (see Listing 14-17), there is little new in the way of code.
Listing 14-17: The AppApprove Codebehind
private void bnApprove_Click(object sender, System.EventArgs e)
{
Account account = new Account(appEnv.GetConnection());
content.SetApproval(Convert.ToInt32(dt.Rows[0]["ContentID"]),
Convert.ToInt32(dt.Rows[0]["Version"]),
account.GetAccountID(User.Identity.Name));
EmailAlert ea = new EmailAlert(Context, StatusCodes.Approved, 0);
ea.Send();
Response.Redirect("AppList.aspx");
}
Returning Content to the Editor
The AppReturn Web page (see Figure 14-11) is nearly a clone of the EdReturn Web page. In fact, the code is nearly identical. The only difference is that the status is changed to RequiresEditing instead of RequiresUpdating, and the page jumps back to the AppList Web page instead of the EdList Web page, for obvious reasons.
Figure 14-11: The AppReturn Web page
The AppReturn Web page's purpose is to return the page back to the editor because he is unhappy with something about the content.
Canceling or Discontinuing Content
The last thing an approver can do is cancel the content. In other words, the approver has the option to discontinue or can the content altogether. There are times when a piece of content simply does not belong on the Web site. For example, the story may be a duplicate.
The AppDiscont Web page (see Figure 14-12) is a little more elaborate than the other submit-type Web pages. This is due to CMS.NET's belief that the editor and author should be given an explanation of why their efforts were canceled. As you can see, two edit boxes are provided: one for an explanation to the editor and the other for the author. Thus, it is possible to provide different levels of detail in the explanations provided to the editor or author.
Figure 14-12: The AppDiscont Web page
The main thing the AppDiscont Page_Load() method (see Listing 14-18) does differently from the standard submit-type Web page is that it fills in the edit boxes with default information, saving the approver time. It then displays these edit boxes.
Listing 14-18: The AppDiscont Codebehind
private void Page_Load(object sender, System.EventArgs e)
{
cid = Convert.ToInt32(Request.QueryString["ContentID"]);
if (cid == 0)
{
Page_Error("ContentID Missing");
}
content = new Content(appEnv.GetConnection());
dt = content.GetContentForID(cid);
lbWhichHeadline.Text = dt.Rows[0]["Headline"].ToString(); lbWhichBody.Text = dt.Rows[0]["Body"].ToString();
tbEdReason.Text = "ContentID: " + cid + "\nHeadline : " + dt.Rows[0]["Headline"].ToString() + "\n";
tbAutReason.Text = "ContentID: " + cid + "\nHeadline : " + dt.Rows[0]["Headline"].ToString() + "\n";
}
private void bnDiscontinue_Click(object sender, System.EventArgs e)
{
int code;
Account account = new Account(appEnv.GetConnection());
content.SetApproval(Convert.ToInt32(dt.Rows[0]["ContentID"]),
Convert.ToInt32(dt.Rows[0]["Version"]),
account.GetAccountID(User.Identity.Name));
content.SetStatus(Convert.ToInt32(dt.Rows[0]["ContentID"]),
Convert.ToInt32(dt.Rows[0]["Version"]),
(code = StatusCodes.Discontinued));
EmailAlert ea = new EmailAlert(Context, code, Convert.ToInt32(dt.Rows[0]["Editor"]));
ea.Body = tbEdReason.Text; ea.Send();
ea = new EmailAlert(Context, code, Convert.ToInt32(dt.Rows[0]["ByLine"]));
ea.Body = tbAutReason.Text;
ea.Send();
Response.Redirect("AppList.aspx");
}
When the approver clicks the Discontinue Content button, it sets the approver column in the Content database to the current user and then sets the status to Discontinued. Next, it sends out different EmailAlerts to the editor and author. Finally, it returns to the AppList Web page.
The Deployment Phase
Providing the content to the users is probably one of the most important phases of the CMS.NET workflow. Without this phase, you wouldn't have much of a Web site. In fact, you wouldn't have a Web site at all.
The deployment process of CMS.NET is designed to be as simple as possible, but this simplicity in use causes a lot more complexity in development. CMS.NET makes a few assumptions when deploying content that are designed to simplify the process:
§There is only one lead per zone.
§Ranking of content is done on a four-level scale.
§A piece of content can be placed in more than one zone.
§Ranking can be unique for each zone.
§Maintenance of the content is handled manually. (This assumption on a large site would definitely not be acceptable. This book makes this assumption to simplify the process.)
§When a piece of content gets archived, it is done in all zones in which it is deployed.
As you can see, the DeployList Web page (see Figure 14-13) is actually broken up into two lists. The first list contains all the new content that is yet to be deployed. The second list contains all deployed content.
Figure 14-13: The DeployList Web page
Viewing Previously Deployed Content
Creating the previously deployed list looks complicated but, if broken into its parts, is really very straightforward. The first time the Web page is posted, a drop-down list of zones is built and displayed with an empty table. Then, when the user selects a zone from the drop-down list, the Web page immediately gets posted. The result of this post is that all the deployed content for the selected zone is displayed.
The DeployList Codebehind (see Listing 14-19) for selecting all content from a zone is straightforward. The Page_Load() method simply cycles through all the distribution records, looking for any record with the same ZoneID as selected by the user. When a matching record is found, a subsequent lookup in the Content database is done to retrieve the corresponding content record.
Listing 14-19: The DeployList Codebehind
private void Page_Load(object sender, System.EventArgs e)
{
zone = new Zone(appEnv.GetConnection());
dist = new Distribution(appEnv.GetConnection()); content = new Content(appEnv.GetConnection());
LiteralControl lit;
TableCell cell;
DropDownList ddlRank;
DataTable AllRanks = null;
DataTable dtz = zone.GetAllZones();
DataTable dt = content.GetHeadlines();
...
if (!IsPostBack)
{
ListItem item;
ddlZones.Items.Add(new ListItem("None")); ddlZones.Items.Add(new ListItem("All"));
foreach (DataRow dr in dtz.Rows)
{
ddlZones.Items.Add(new ListItem(dr["Title"].ToString()));
}
}
else
{
foreach (DataRow dr in dtz.Rows)
{
DataTable dtd = dist.GetOrdered(Convert.ToInt32(dr["ZoneID"]));
if (ddlZones.SelectedItem.Text.Equals("All") || ddlZones.SelectedItem.Text.Equals(dr["Title"]))
{
if (dtd.Rows.Count == 0)
{
TableRow row = new TableRow();
tblSiteContent.Rows.Add(row);
lit = new LiteralControl(dr["Title"].ToString()); cell = new TableCell();
cell.Controls.Add(lit);
row.Cells.Add(cell);
lit = new LiteralControl("No Content"); cell = new TableCell(); cell.ColumnSpan = 4; cell.Controls.Add(lit); row.Cells.Add(cell);
}
foreach (DataRow drd in dtd.Rows)
{
TableRow row = new TableRow(); tblSiteContent.Rows.Add(row);
lit = new LiteralControl(dr["Title"].ToString()); cell = new TableCell();
cell.Controls.Add(lit);
row.Cells.Add(cell);
DataRow drc = content.GetContentForIDVer(
Convert.ToInt32(drd["ContentID"]),
Convert.ToInt32(drd["Version"]));
lit = new LiteralControl(drc["Headline"].ToString()); cell = new TableCell();
cell.Controls.Add(lit);
row.Cells.Add(cell);
if (AllRanks == null)
{
AllRanks =
new ContentRank(appEnv.GetConnection()).GetRanks();
}
cell = new TableCell();
ddlRank = new DropDownList();
foreach (DataRow drr in AllRanks.Rows)
{
ddlRank.Items.Add(
new ListItem(drr["Rank"].ToString(),
drr["RankID"].ToString()));
}
ddlRank.Items.FindByValue(
drd["Ranking"].ToString()).Selected = true;
cell.Controls.Add(ddlRank);
row.Cells.Add(cell);
BuildImageButton(row, "DeployView.aspx?ID=" +
drd["ContentID"] +
"&Ver=" + drd["Version"]); BuildImageButton(row, "DeployArchive.aspx?ID=" +
drd["ContentID"] +
"&Ver=" + drd["Version"]);
}
}
}
}
}
private void bnUpdtRanks_Click(object sender, System.EventArgs e)
{
int crow;
DataTable dtz = zone.GetAllZones();
DropDownList ddl;
crow = 1; // row 0 is titles
foreach (DataRow dr in dtz.Rows)
{
DataTable dtd = dist.GetOrdered(Convert.ToInt32(dr["ZoneID"]));
if (ddlZones.SelectedItem.Text.Equals("All") || ddlZones.SelectedItem.Text.Equals(dr["Title"]))
{
if (dtd.Rows.Count <= 0) crow++;
int LeadCount = 0;
foreach (DataRow drd in dtd.Rows)
{
TableCellCollection tcc = tblSiteContent.Rows[crow++].Cells; ddl = (DropDownList)tcc[2].Controls[0];
if (ddl.SelectedItem.Text.Trim().Equals("Lead")) LeadCount++;
}
if (LeadCount > 1)
Page_Error("<h2>**Error** Multiple Leads found</h2>" + "Only allowed one lead per zone");
}
}
crow = 1; // row 0 is titles
foreach (DataRow dr in dtz.Rows)
{
DataTable dtd = dist.GetOrdered(Convert.ToInt32(dr["ZoneID"]));
if (ddlZones.SelectedItem.Text.Equals("All") || ddlZones.SelectedItem.Text.Equals(dr["Title"]))
{
if (dtd.Rows.Count <= 0) crow++;
foreach (DataRow drd in dtd.Rows)
{
TableCellCollection tcc = tblSiteContent.Rows[crow++].Cells; ddl = (DropDownList)tcc[2].Controls[0];
if (ddl.SelectedIndex+1 != Convert.ToInt32(drd["Ranking"]))
{
dist.UpdateRank(Convert.ToInt32(dr["ZoneID"]),
Convert.ToInt32(drd["ContentID"]),
Convert.ToInt32(drd["Version"]),
ddl.SelectedIndex+1);
}
}
}
}
}
