Tuesday, January 8, 2008

Developing Simple Issue Tracker Module

Motivation
PragmaSQL started as part time development effort and by time PragmaSQL evolved to a commercial product.
Today PragmaSQL has a dedicated web site (PragmaSQL Online) build on Cuyahoga Framework.
PragmaSQL Online was primarly designed to meet very simple requirements like

Host simple advertorial content introducing PragmaSQL
Host downloads ( PragmaSQL Application, 3rd party add-ins and other open source material)
Licences distribution and validation via some web services.

As the number of people using PragmaSQL increased PragmaSQL Forum was added to enable users to communicate
with each other and with PragmaSQL developers. PragmaSQL forum was the only place where people submitted bugs,
support and new feature requests. But as the number of posts increased managing all this content became a real pain for
me. It was hard to group and keep track of the posts, for example i could not know exactly how many bugs were posted
and how many of these bugs are waiting, in progress or already resolved.
Forum approach to maintainance was also inefficient for the users , they had no clue about the status of their posts
because Forum Module did not provided custom post attributes and the communication model was very loose. Forum module
did not have any mechanism to notify users about the status changes of their posts.

In order to overcome maintainance related problems listed above the solution was to add Issue Tracker (Help Desk)
module to PragmaSQL Online, but Cuyahoga Framework did not have Issue Tracker module.
After spending some time searching for open source Issue Tracking software i found two projects.
But these open source software had some limitations, one of them did not integrated well with Cuyahoga Framework
because it was not designed as Cuyahoga Module. Second one had very extensive issue tracking capabilities but their approach
did not supported role/user based authentication. The ideal solution was something like JIRA, but JIRA was a commercial
product and it was certain that I would have to implement Cuyahoga integration myself.

Requirements
So I decided to write my own simple Issue Tracker module for Cuyahoga meeting the following simple requirements.

Must be a Cuyahoga module
Support management of multiple Projects
Support grouping of issues by Components
Support for custom Issue Types
Clear distinction between developers and customers (Role/User based authentication)
Support general Issue properties like description, summary, status, priority and comments
Provide effective means for communication via Issue Comments
Real time issue status notification via auto generated e-mails.
Simple filtering of issues
Simple issue statistics by issue status
DOMAIN CLASSES
Most of the requirements listed above were implemented with four domain classes (in fact entity classes) named Project, IssueType, Issue and IssueComment.



<<>> >

From the class diagram above we can infere these rules

Multiple project support is implemented with Project class.
Project objects with Parent property set to null are used as containers for Components.
Project class is also used to model Components. A component is a Project instance with Parent property set to another Project ( parent project can only be a project instance with null Parent)
Each project instance (and Component instance as well) must have a Developer Group (Cuyahoga.Core.Domain.Role).Issues can only be assigned to Users in that Role.
Each project instance (and Component instance as well) must have a Lead Developer (Cuyahoga.Core.Domain.User).By default each issue is assigned to the Lead Developer.
Each component has a Key. Keys for components under same project must also be unique.
Each component can have zero or many Issues.
Each issue is assigned a KeyNo automatically. This KeyNo combined with the Component's key is used as the Issue's key
Each Issue must have a Reporter and an Assignee (Cuyahoga.Core.Domain.User instance)
Each issue can have zero or many comments.
All domain classes listed in the diagram has some commons

They are NHibernate powered classes, that is each class also has a mapping file embedded as a resource.
They have Id property. Value of this property is automatically set by the underlying database.
They have Version property which is used for managed versioning by NHibernate.
PRESENTATION CLASSES (ASP.NET Pages and User Controls)
Cuyahoga framework allows you to develop custom modules very easily. In order to develop a basic module
you have to implement three classes.

Module Control: This is a user control inherited from Cuyahoga.Web.UI.BaseModuleControl class. This user control is what the visitors see when they access your module. Cuyahoga framework renders this user control automatically.
Module Admin Page: This is an ASP .NET Page inherited from Cuyahoga.Web.UI.ModuleAdminBasePage class. This page is the entry point for site administrators when they want to edit your module.
Module : This is the module manager class inherited from Cuyahoga.Core.Domain.ModuleBase and marked with INHibernateModule marker interface. This class is instantiaded by the Module Control automatically and you can get its reference on page load of the Module Control. ModuleBase provides access to Cuyahoga core services like ISessionManager and IFileService. You wrap your custom data access methods inside this class.
Pragma Issue Tracker implements these three classes plus some other ASP.NET pages and user controls as specified in the
following diagram.



IssueTracker.ascx is inherited from Cuyahoga.Web.UI.BaseModuleControl. This control is automatically rendered by Cuyahoga framework when visitors access the page containing our module.IssueTracker contains IssueList control which is used as a generic list for issues.We allow users to select a predefined filter from a drop down and pass the selected filter to IssueList. IssueList then executes the filter and lists the resulting issues. IssueList not only lists the issues it also generates issue count summary by issue status (All, Waiting, InProgress and Resolved) and enables users to filter issues by Project, Component, Priority and Status.
IssueTrackerEdit.aspx is inherited from Cuyahoga.Web.UI.ModuleAdminBasePage. This page is what administrators see when they want to edit Pragma Issue Tracker module. IssueTrackerEdit contains a multiview control with two views. One of the views contains ProjectList.ascx and the second view contains IssueTypeList.ascx. Web site administrators define projects and issue types from this page.
IssueTrackerModule is inherited from Cuyahoga.Core.Domain.ModuleBase and marked with INHibernateModule marker interface. This is the manager class for our Cuyahoga module. We wrap Issue Tracking related data access functionality and Cuyahoga integration functionality inside this class. IssueTracker.ascx control provides us an instance of IssueTrackerModule in the page load event and we store the reference in IssueTracker.ascx and access this instance as we need data access functionality
ProjectList.ascx is used to list projects or components of a project. ProjectEdit.aspx is used to edit projects and includes ProjectList.ascx control to list components of each project. ProjectList.ascx redirects administrators to ComponentEdit.aspx for creating a new component or editing the selected component.
ComponentEdit.aspx is used to edit component definition.Adminsitrators are redirected to this page from ProjectEdit.aspx page.
IssueTypeList.ascx is used to list custom Issue Types.
IssueTypeEdit.aspx: Administrators are redirected to this page from IssueTypeList.ascx in order to create a new issue type or edit the selected issue type.
IssueEdit.aspx is used for issue editing.


BUSINESS RULES
Only administrators can define projects, components and issue types
Only authenticated users can create issues (they will become the reporter of issues)
Anonymous users can only view issues.
Provided a component only users from Developers Group of this component can be assigned to issues.
Issue Reporters can not change issue status directly. Reporters can only reopen a resolved issue.
Assignee of a specific issue can change status.
Only Reporter and/or assignee of a specific issue can delete that issues
Only reporter and the assignee of a specific issue can add comments to that issue.
Reporter or assignee of a specific issue can only edit/delete their own comments. Reporter/assignee can not delete/edit comments of the assignee/reporter.
Admisnitrators can perform all operations on any issue.
CONFIGURATION
1) We have to perform some Cuyahoga specific configuration in order to our module function correctly. Browse to \Config directory Add Pragma.IssueTracker under element to facilities.config file. facilities.config should look like




id="nhibernate" isWeb="true" useReflectionOptimizer="false">


NHibernate.Connection.DriverConnectionProvider
#{nhibernateDriver}
#{nhibernateDialect}
#{connectionString}
NHibernate.Caches.SysCache.SysCacheProvider, NHibernate.Caches.SysCache
true
30


Cuyahoga.Core

Pragma.IssueTracker



id="autotransaction" />



2) Because Pragma Issue Tracker uses Ajax toolkit for creating/editing issue comments and prompting e-mail notification errors we have to modify our Web.config file to enable Ajax support. If we do not add the following configuration information it is likely that
we will get "Sys not defined" error when our module tries to execute Ajax related code.





















MODULE INSTALLATION
Download Pragma Issue Tracker pakage
Extract zip file contents under \Modules\PragmaIssueTracker direcotry
Copy Pragma.IssueTracker.dll to \Bin directory
Log on as administrator to your web site
Browse to Modules page in the adminsitration panel
You shoul see PragmaIssueTracker module listed. Press Install link button and Pragma Issue Tracker module will be installed
Create new page or a new section in an existing page to host Pragma Issue Tracker Module.
Select Pragma Issue Tracker Module in section editing screen.
In custom module setting specify if you want E-Mail Notification and Notify User About E-Mail Notification errors.
Browse to the page where Pragma Issue Tracker Module is hosted.
Press Edit link button to administer Pragma Issue Tracker Module.
Define projects and components for each project you would like to perform Issue Tracking. In our case we have PragmaSQL project and several components like Application, Core, Server Management, HTML Help and External Tools
Define Issue Types like Bug, New Feature, Improvement and Support

NOTE: Do not forget to organize your developers under some Cuyahoga Roles, because Pragma Issue Tracker will ask you for
Developer roler and a lead user who is in the specified role, for each project and component.
You can define your custom scheme for this. Some possibilities are

Each project has its own role for developers
Each component has its own role for developers
Single Developer role for all projects and components.
LIMITATIONS
Pragma Issue Tracker module currently supports only MySQL database. You can add your own support for other database providers like MS SQL Server. You will have to copy files in Install\Database\mysql folder to another folder , for example Install\Database\mssql2000, and modify sql scripts to support that database providers syntax.
Pragma Issue Tracker module currently does not support advanced issue tracking concepts like linking issues to each other,creating sub-issues, work logging and issue attachments. Since Pragma Issue Tracker is an open source project you are welcome to develop these features and contribute them.
Pragma Issue Tracker is a Cuyahoga module and requires NHibernate. If you want to use this module in a different web framework you will have to modify lots of authentication, redirection and persistance related code.
REFACTORINGS AND IMPROVEMENTS
1) We may design a base class with Id and Version property and inherit all domain classes from
this class.

public class BaseIssuTrackerClass
{
private long _version = 0;

private int _id;
public int Id
{
get { return _id; }
internal set { _id = value; }
}
}

2) We may design seperate classes for Project and Component.
Current design uses Project class to model both Project and Component instances.

Collapsepublic class Project: BaseIssuTrackerClass
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}

private string _description;
public string Description
{
get { return _description; }
set { _description = value; }
}

private DateTime _createdon;
public DateTime CreatedOn
{
get { return _createdon; }
set { _createdon = value; }
}

private bool _active = true;
public bool Active
{
get { return _active; }
set { _active = value; }
}

private IList _components;
public IList Components
{
get { return _components; }
set { _components = value; }
}

public Project(){}
}

public class Component:BaseIssuTrackerClass
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}

private string _description;
public string Description
{
get { return _description; }
set { _description = value; }
}

private string _key;
public string Key
{
get { return _key; }
set { _key = value; }
}

private bool _active = true;
public bool Active
{
get { return _active; }
set { _active = value; }
}

private DateTime _createdon;
public DateTime CreatedOn
{
get { return _createdon; }
set { _createdon = value; }
}

private User _leaduser;
public User LeadUser
{
get { return _leaduser; }
set { _leaduser = value; }
}

private Role _role;
public Role Role
{
get { return _role; }
set { _role = value; }
}

private Project _parentProject;
public Project ParentProject
{
get { return _parentProject; }
internal set { _parentProject = value; }
}

internal Component()
: this(null)
{
}

public Component(Project parentProject)
{
_id = -1;
_parentProject = parentProject;
}
}

No comments: