Click here to Skip to main content
15,896,153 members
Articles / Web Development / ASP.NET

Race to Linux - Race 2: Time Tracker Starter Kit

Rate me:
Please Sign up or sign in to vote.
4.25/5 (5 votes)
26 Sep 20051 min read 40.4K   274   16  
Time Tracker Starter Kit port to Linux using Mono and FireBird
using System;
using System.Web;
using System.Web.UI.WebControls;
using ASPNET.StarterKit.TimeTracker.BusinessLogicLayer;

namespace ASPNET.StarterKit.TimeTracker.Web
{
	//*********************************************************************
	//
	// ProjectDetails.aspx
	//
	// The ProjectDetails.aspx page is used to add new projects or make changes to
	// existing projects.  Project membership are associated using this page.
	// In addition, project categories are added and changed on this page.
	// Only members of the Admin or Manager Role can access this page.
	// Members of the Admin group can modify all projects, while members of the
	// Managers group can only modify the projects they are managing.
	//
	//*********************************************************************

	public class ProjectDetails : System.Web.UI.Page
	{
		protected System.Web.UI.WebControls.TextBox	ProjectName;
		protected System.Web.UI.WebControls.TextBox	Description;
		protected System.Web.UI.WebControls.TextBox CompletionDate;
		protected System.Web.UI.WebControls.TextBox	Duration;
		protected System.Web.UI.WebControls.ListBox	Members;
		protected System.Web.UI.WebControls.Button CopyButton;
		protected System.Web.UI.WebControls.Button AddButton;
		protected System.Web.UI.WebControls.Button SaveButton;
		protected System.Web.UI.WebControls.DropDownList Managers;
		protected System.Web.UI.WebControls.DropDownList Projects;
		protected System.Web.UI.WebControls.TextBox CategoryName;
		protected System.Web.UI.WebControls.TextBox	Abbrev;
		protected System.Web.UI.WebControls.TextBox	CatDuration;
		protected System.Web.UI.WebControls.DataGrid CategoriesGrid;
		protected System.Web.UI.WebControls.RequiredFieldValidator ProjectNameRequiredfieldvalidator;
		protected System.Web.UI.WebControls.RequiredFieldValidator ManagerRequiredFieldValidator;
		protected System.Web.UI.WebControls.CompareValidator CompletionDateCompareValidator;
		protected System.Web.UI.WebControls.RequiredFieldValidator CompletionDateRequiredFieldValidator;
		protected System.Web.UI.WebControls.CompareValidator DurationCompareValidator;
		protected System.Web.UI.WebControls.RequiredFieldValidator DurationRequiredFieldValidator;
		protected System.Web.UI.WebControls.CustomValidator	ProjectsGridCustomValidator;
		protected System.Web.UI.WebControls.RegularExpressionValidator RegularExpressionValidatorAbbrev;
		protected System.Web.UI.WebControls.CompareValidator CatDurationValidator;
		protected System.Web.UI.WebControls.CustomValidator AbbrevCustomValidator;
		protected System.Web.UI.WebControls.Label ErrorMessage;
		protected System.Web.UI.WebControls.Button CancelButton;
		protected System.Web.UI.WebControls.Button CancelButton2;
		protected System.Web.UI.WebControls.Button CancelButton3;
		protected System.Web.UI.WebControls.Button DeleteButton;
		protected System.Web.UI.WebControls.Button DeleteButton2;
		protected System.Web.UI.WebControls.Button SaveButton2;
		protected System.Web.UI.WebControls.RangeValidator RangeValidator1;
		protected System.Web.UI.WebControls.RangeValidator RangeValidator2;
		protected System.Web.UI.WebControls.Label CategoryErrorMessage;
		protected System.Web.UI.WebControls.RegularExpressionValidator CategoryNameValidator;
		protected System.Web.UI.WebControls.RegularExpressionValidator RegularExpressionValidator1;
		
		// Contains the id of current project
		private int _projID;
	
		private void Page_Load(object sender, System.EventArgs e)
		{
			// Ensure that the visiting user has access to view the current page
			if (TTSecurity.IsInRole(TTUser.UserRoleAdminPMgr) == false) 
			{
				Response.Redirect("AccessDenied.aspx?Index=-1", true);
			}

			// Obtain project id from the QueryString.
			_projID = (Request.QueryString["id"]==null) ? 0 : Convert.ToInt32(Request.QueryString["id"]);

			if (!IsPostBack)
			{
				// The categories collection is stored in session
				// Also the categories are not saved in the database until the user clicks Save for the whole Project
				Session["catArray"] = new CategoriesCollection();

				BindManagers();
				BindMembers();
				BindOtherProjects();

				// Load project with _projID when project id exists in the QueryString
				if (_projID != 0)
					BindProject();
			}

			// Add warning and confirmation when user tries to delete a project
			DeleteButton.Attributes.Add("onclick", "return confirm('Deleting a project will also delete all the time entries and categories associated with the project. This deletion cannot be undone. Are you sure you want to delete this project?')");
			DeleteButton2.Attributes.Add("onclick", "return confirm('Deleting a project will also delete all the time entries and categories associated with the project. This deletion cannot be undone. Are you sure you want to delete this project?')");
		}

		#region Web Form Designer generated code
		override protected void OnInit(EventArgs e)
		{
			//
			// CODEGEN: This call is required by the ASP.NET Web Form Designer.
			//
			InitializeComponent();
			base.OnInit(e);
		}
		
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{    
			this.SaveButton.Click += new System.EventHandler(this.SaveButton_Click);
			this.CancelButton.Click += new System.EventHandler(this.CancelButton_Click);
			this.DeleteButton.Click += new System.EventHandler(this.DeleteButton_Click);
			this.AddButton.Click += new System.EventHandler(this.AddButton_Click);
			this.AbbrevCustomValidator.ServerValidate += new System.Web.UI.WebControls.ServerValidateEventHandler(this.AbbrevCustomValidator_ServerValidate);
			this.CopyButton.Click += new System.EventHandler(this.CopyButton_Click);
			this.CategoriesGrid.ItemCreated += new System.Web.UI.WebControls.DataGridItemEventHandler(this.CategoriesGrid_ItemCreated);
			this.CategoriesGrid.SortCommand += new System.Web.UI.WebControls.DataGridSortCommandEventHandler(this.CategoriesGrid_Sort);
			this.ProjectsGridCustomValidator.ServerValidate += new System.Web.UI.WebControls.ServerValidateEventHandler(this.ValidateCategories);
			this.SaveButton2.Click += new System.EventHandler(this.SaveButton_Click);
			this.CancelButton2.Click += new System.EventHandler(this.CancelButton_Click);
			this.DeleteButton2.Click += new System.EventHandler(this.DeleteButton_Click);
			this.Load += new System.EventHandler(this.Page_Load);

		}
		#endregion

		//*********************************************************************
		//
		// The BindManagers method retrieves the list of users that are in the Managers Role
		// and then databinds them to the Managers dropdownlist.
		//
		//*********************************************************************

		private void BindManagers()
		{
			Managers.DataSource = TTUser.ListManagers();
			Managers.DataValueField = "UserID";
			Managers.DataTextField = "Name";
			Managers.DataBind();

			// insert blank choice on top of the managers dropdownlist.
			Managers.Items.Insert(0, new ListItem("Select Manager...", String.Empty));
		}

		//*********************************************************************
		//
		// The BindMembers method retrieves the list of Users the current user can view and 
		// then databinds them to the Members listbox.
		//
		//*********************************************************************

		private void BindMembers()
		{
			Members.DataSource = TTUser.GetAllUsers(TTSecurity.GetUserID());
			Members.DataValueField = "UserID";
			Members.DataTextField = "Name";
			Members.DataBind();
		}

		//*********************************************************************
		//
		// The BindOtherProjects method retrieves the list of all projects, databinds to
		// the Projects dropdownlist, and then remove the current project from that list.
		//
		//*********************************************************************

		private void BindOtherProjects()
		{
			Projects.DataSource = Project.GetProjects();
			Projects.DataTextField = "Name";
			Projects.DataValueField = "ProjectID";
			Projects.DataBind();

			// remove current project from list of projects
			Projects.Items.Remove(Projects.Items.FindByValue(_projID.ToString()));

			// Disable "Copy" functionality if there are no projects in the list
			if (Projects.Items.Count == 0)
				CopyButton.Enabled = false;
		}

		//*********************************************************************
		//
		// The BindProject method retrieves the project with _projID and populates
		// the web controls with the project's info.
		//
		//*********************************************************************

		private void BindProject()
		{
			Project project = new Project(_projID);
			project.Load();

			// Populate web controls with the project's info.
			ProjectName.Text = project.Name;
			Description.Text = project.Description;
			CompletionDate.Text = project.EstCompletionDate.ToShortDateString();
			Duration.Text = project.EstDuration.ToString();
			Managers.Items.FindByValue(project.ManagerUserID.ToString()).Selected = true;

			// Sets the selected members of the project.
			foreach (TTUser user in project.Members)
			{
				Members.Items.FindByValue(user.UserID.ToString()).Selected = true;
			}

			BindCategoriesGrid(project.Categories);
		}

		//*********************************************************************
		//
		// The BindCategoriesGrid method is a helper take takes in a collection of categories 
		// and databinds the Categories datagrid with that collection.
		//
		// The categories are also then stored in session.
		//
		//*********************************************************************

		private void BindCategoriesGrid(CategoriesCollection cats)
		{
			// Call method to sort the data before databinding
			SortGridData(cats, SortField, SortAscending);

			CategoriesGrid.DataSource = cats;
			CategoriesGrid.DataBind();

			// Store the list of categories in session
			Session["catArray"] = cats;
		}

		//*********************************************************************
		//
		// The ReturnToProjectList method redirects to the ProjectList.aspx page.
		//
		//*********************************************************************

		private void ReturnToProjectList()
		{
			// Clear the current project categories that are stored in session.
			Session["catArray"] = null;

			// Return user to Project List Page.
			int mainIndex = (Request["index"]==null) ? 0 : Convert.ToInt32(Request["index"]);
			int adminIndex = (Request["adminindex"]==null) ? 0 : Convert.ToInt32(Request["adminindex"]);
			Response.Redirect(String.Format("ProjectList.aspx?index={0}&adminindex={1}", mainIndex, adminIndex), false);
		}

		//*********************************************************************
		//
		// The SortGridData method is a helper method called when databinding the Categories grid 
		// to sort the columns of the grid.
		//
		//*********************************************************************

		private void SortGridData(CategoriesCollection list, string sortField, bool asc)
		{
			CategoriesCollection.CategoryFields sortCol = CategoriesCollection.CategoryFields.InitValue;

			switch(sortField)
			{
				case "Name":
					sortCol = CategoriesCollection.CategoryFields.Name;
					break;
				case "Abbrev":
					sortCol = CategoriesCollection.CategoryFields.Abbreviation;
					break;
				case "Duration":
					sortCol = CategoriesCollection.CategoryFields.Duration;
					break;
			}

			list.Sort(sortCol, asc);
		}

		private void CancelButton_Click(object sender, System.EventArgs e)
		{
			ReturnToProjectList();
		}

		//*********************************************************************
		//
		// The DeleteButton_Click event handler calls a method that deletes the project, 
		// all of its categories, projectmembers and their time entries.
		//
		//*********************************************************************
		
		private void DeleteButton_Click(object sender, System.EventArgs e)
		{
			Project.Remove(_projID);
			ReturnToProjectList();
		}

		//*********************************************************************
		//
		// The SaveButton_Click event handler saves the configuration of the project.
		// It updates if the current project id is not 0 and inserts if it is 0.
		//
		//*********************************************************************

		private void SaveButton_Click(object sender, System.EventArgs e)
		{
			// Add the project manager as member of the project.
			Members.Items.FindByValue(Managers.SelectedItem.Value).Selected = true;

			// Make sure that there is at least one category.
			ProjectsGridCustomValidator.Validate();
			if (!ProjectsGridCustomValidator.IsValid)
				return;
			
			// Make sure that there are no duplicate categories.
			AbbrevCustomValidator.Validate();
			if (!AbbrevCustomValidator.IsValid)
				return;

			// Retrieve the current list of categories from session.
			CategoriesCollection catArray = (CategoriesCollection)Session["catArray"];

			// Get list of members the user selected.
			UsersCollection selectedMembers = new UsersCollection();
			foreach (ListItem li in Members.Items)
			{
				if (li.Selected)
				{
					TTUser user = new TTUser();
					user.UserID = Convert.ToInt32(li.Value);
					selectedMembers.Add(user);
				}
			}

			Project prj = new Project(
				_projID, 
				TTSecurity.CleanStringRegex(ProjectName.Text),
				TTSecurity.CleanStringRegex(Description.Text), 
				Convert.ToInt32(Managers.SelectedItem.Value), 
				Convert.ToDateTime(CompletionDate.Text),
				Convert.ToDecimal(Duration.Text)
				);
			prj.Categories = catArray;
			prj.Members = selectedMembers;
			
			if (prj.Save())
			{
				ReturnToProjectList();
			}
			else
			{
				ErrorMessage.Text = "There was an error.  You cannot remove a member with time entries from this project.";
			}
		}

		//*********************************************************************
		//
		// The AddButton_Click event handler adds a category to the categories collection
		// in session and displays it in the datagrid.
		//
		//*********************************************************************

		private void AddButton_Click(object sender, System.EventArgs e)
		{
			// check to make sure duplicated category abbreviations are avoided.
			if (!AbbrevCustomValidator.IsValid)
				return;

			// a required field validator is not used for this case because only the add button click should 
			// check for this and not the save button.
			if (CategoryName.Text == "")
			{
				CategoryErrorMessage.Text = "Category name is required.";
				return;
			}

			// a required field validator is not used for this case because only the add button click should 
			// check for this and not the save button.
			if (Abbrev.Text == "")
			{
				CategoryErrorMessage.Text = "Category abbreviation is required.";
				return;
			}

			CategoriesCollection catArray = (CategoriesCollection)Session["catArray"];
			if (catArray == null) 
				catArray = new CategoriesCollection();

			// categories need a unique identifier when added, since they are not yet saved to 
			// the database but in session, a counter is used to populate their id.
			int catID = (Session["catID"] != null) ? (Convert.ToInt32(Session["catID"]) - 1) : -1;
			Session["catID"] = catID;

			Category cat = new Category();
			cat.CategoryID = catID;
			cat.Name = TTSecurity.CleanStringRegex(CategoryName.Text);
			cat.Abbreviation = TTSecurity.CleanStringRegex(Abbrev.Text);
			cat.EstDuration = (CatDuration.Text.Length==0) ? 0 : Convert.ToDecimal(CatDuration.Text);
			catArray.Add(cat);

			// Re-Validate now that users have added a new category.
			ProjectsGridCustomValidator.Validate();

			BindCategoriesGrid(catArray);

			CategoryName.Text = string.Empty;
			Abbrev.Text = string.Empty;
			CatDuration.Text = string.Empty;
		}

		//*********************************************************************
		//
		// The CopyButton_Click event handler copies the list of categories from the 
		// selected project in the Projects dropdownlist.
		//
		//*********************************************************************

		private void CopyButton_Click(object sender, System.EventArgs e)
		{
			int catID;
			CategoriesCollection catArray = (CategoriesCollection)Session["catArray"];
			if (catArray == null) 
				catArray = new CategoriesCollection();

			CategoriesCollection projcatArray = Project.GetCategories(Convert.ToInt32(Projects.SelectedItem.Value));
			foreach (Category cat in projcatArray)
			{
				// categories need a unique identifier when added, since they are not yet saved to 
				// the database but in session, a counter is used to populate their id.
				catID = (Session["catID"] != null) ? (Convert.ToInt32(Session["catID"]) + 1) : 1;
				Session["catID"] = catID;
				cat.CategoryID = catID;
				catArray.Add(cat);
			}

			// Re-Validate to make sure duplicate categories are not copied.
			ProjectsGridCustomValidator.Validate();

			Session["catArray"] = catArray;

			BindCategoriesGrid(catArray);
		}

		//*********************************************************************
		//
		// The CategoriesGrid_OnDelete event handler deletes a category from the categories grid.
		//
		//*********************************************************************

		protected void CategoriesGrid_OnDelete(Object sender, DataGridCommandEventArgs e)
		{
			int catID = Convert.ToInt32(CategoriesGrid.DataKeys[(int)e.Item.ItemIndex]);
			CategoriesCollection catArray = (CategoriesCollection)Session["catArray"];

			for (int i = 0;i < catArray.Count;i++)
			{
				if (((Category)catArray[i]).CategoryID == catID)
				{
					catArray.RemoveAt(i);
				}
			}

			BindCategoriesGrid(catArray);
		}

		//*********************************************************************
		//
		// The CategoriesGrid_OnCancel event handler cancels an edit on the categories grid.
		//
		//*********************************************************************

		protected void CategoriesGrid_OnCancel(Object sender, DataGridCommandEventArgs e)
		{
			CategoriesGrid.EditItemIndex = -1;

			BindCategoriesGrid((CategoriesCollection)Session["catArray"]);		
		}

		//*********************************************************************
		//
		// The CategoriesGrid_OnUpdate event handler updates changes on an edit of the categories grid.
		//
		//*********************************************************************

		protected void CategoriesGrid_OnUpdate(Object sender, DataGridCommandEventArgs e)
		{
			// set up the editted category
			Category editCat = new Category();
			editCat.CategoryID = Convert.ToInt32(CategoriesGrid.DataKeys[(int)e.Item.ItemIndex]);
			editCat.Name = TTSecurity.CleanStringRegex(((TextBox) e.Item.FindControl("EditName")).Text);
			editCat.Abbreviation = TTSecurity.CleanStringRegex(((TextBox) e.Item.FindControl("EditAbbreviation")).Text);
			editCat.EstDuration = Convert.ToDecimal(((TextBox) e.Item.FindControl("EditDuration")).Text);

			// check to make sure that category abbreviations are not being duplicated.
			CategoriesCollection catArray = (CategoriesCollection)Session["catArray"];
			if (catArray != null) 
			{
				string editAbbrev = ((TextBox) e.Item.FindControl("EditAbbreviation")).Text;
				foreach (Category cat in catArray)
				{
					if (cat.Abbreviation == editCat.Abbreviation && cat.CategoryID != editCat.CategoryID)
					{
						CategoryErrorMessage.Text = "Duplicate categories abbreviations are not allowed";
						return;
					}
				}
			}

			// container for new list of categories
			CategoriesCollection catNew = new CategoriesCollection();

			// Add the editted category to our a new arraylist
			catNew.Add(editCat);

			if (catArray == null) 
				catArray = new CategoriesCollection();
			foreach (Category cat in catArray)
			{
				// category id does not exist when users are creating new projects so we cannot use it as comparer here
				// since categories abbreviation must be unique per project we can use it as a comparer
				if (cat.CategoryID != editCat.CategoryID)
				{
					catNew.Add(cat);
				}
			}

			CategoriesGrid.EditItemIndex = -1;
			BindCategoriesGrid(catNew);
		}
		
		//*********************************************************************
		//
		// The CategoriesGrid_OnEdit event handler sets up editing for the categories grid
		//
		//*********************************************************************

		protected void CategoriesGrid_OnEdit(Object sender, DataGridCommandEventArgs e)
		{
			CategoriesGrid.EditItemIndex = e.Item.ItemIndex;

			BindCategoriesGrid((CategoriesCollection)Session["catArray"]);
		}

		//*********************************************************************
		//
		// CategoriesGrid_Sort handles sorting of the categories grid.
		//
		//*********************************************************************

		private void CategoriesGrid_Sort(object source, System.Web.UI.WebControls.DataGridSortCommandEventArgs e)
		{
			SortField = e.SortExpression;

			BindCategoriesGrid((CategoriesCollection)Session["catArray"]);
		}

		//*********************************************************************
		//
		// Custom Validator event handler to make sure that there are categories in the categories grid.
		//
		//*********************************************************************

		private void ValidateCategories(object source, System.Web.UI.WebControls.ServerValidateEventArgs args)
		{
			CategoriesCollection catArray = (CategoriesCollection)Session["catArray"];
			if (catArray != null) 
			{
				if (catArray.Count > 0)
				{
					args.IsValid = true;
					return;
				}
			}
			args.IsValid = false;
		}

		//*********************************************************************
		//
		// Custom Validator event handler to make sure that category abbreviations are not duplicated.
		//
		//*********************************************************************

		private void AbbrevCustomValidator_ServerValidate(object source, System.Web.UI.WebControls.ServerValidateEventArgs args)
		{
			CategoriesCollection catArray = (CategoriesCollection)Session["catArray"];
			if (catArray.Count != 0) 
			{
				catArray.Sort(CategoriesCollection.CategoryFields.Abbreviation, true);
				for(int i=0; i < catArray.Count; i++)
				{
					if (((Category)catArray[i]).Abbreviation == Abbrev.Text)
					{
						args.IsValid = false;
						return;
					}
					if (i!=0 && ((Category)catArray[i]).Abbreviation == ((Category)catArray[i-1]).Abbreviation )
					{
						args.IsValid = false;
						return;
					}
					
				}
				
				
			}
			args.IsValid = true;
		}

		private void CategoriesGrid_ItemCreated(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
		{
			// add confirmation on deletion of categories
			if (e.Item.ItemType	== ListItemType.Item || e.Item.ItemType	== ListItemType.AlternatingItem)
			{
				((ImageButton)e.Item.FindControl("CatDeleteButton")).Attributes.Add("onclick", "return confirm('Deleting an existing category will also delete all the time entries and categories associated with the category. Are you sure you want to delete this category?')");
			}
		}

		string SortField 
		{
			get 
			{
				object o = ViewState["SortField"];
				if (o == null) 
				{
					return String.Empty;
				}
				return (string)o;
			}

			set 
			{
				if (value == SortField) 
				{
					// same as current sort file, toggle sort direction
					SortAscending = !SortAscending;
				}
				ViewState["SortField"] = value;
			}
		}

		//*********************************************************************
		//
		// SortAscending property is tracked in ViewState
		//
		//*********************************************************************

		bool SortAscending 
		{
			get 
			{
				object o = ViewState["SortAscending"];
				if (o == null) 
				{
					return true;
				}
				return (bool)o;
			}

			set 
			{
				ViewState["SortAscending"] = value;
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Uruguay Uruguay
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions