65.9K
CodeProject 正在变化。 阅读更多。
Home

开发简单的 Issue Tracker 模块

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.10/5 (9投票s)

2008年1月7日

CPOL

10分钟阅读

viewsIcon

82073

如何为 Cuyahoga 框架开发自己的 Issue Tracker 模块

在线查看 Pragma 问题跟踪器

下载源代码(需要注册)

下载仅安装包(二进制)

动机

PragmaSQL 最初是一个业余开发项目,随着时间的推移,PragmaSQL 发展成为一款商业产品。
如今,PragmaSQL 拥有一个专用的网站(PragmaSQL Online),该网站基于 Cuyahoga 框架构建。
PragmaSQL Online 最初是为了满足非常简单的需求而设计的,例如:

  • 托管简单的广告内容,介绍 PragmaSQL
  • 托管下载(PragmaSQL 应用程序、第三方插件和其他开源材料)
  • 通过一些 Web 服务分发和验证许可证。


随着使用 PragmaSQL 的用户数量的增加,添加了 PragmaSQL 论坛,以使用户能够进行交流
彼此以及与 PragmaSQL 开发人员交流。PragmaSQL 论坛是提交 Bug、
支持和新功能请求的唯一场所。但随着帖子数量的增加,管理所有这些内容对我来说成了一个真正的麻烦。
很难对帖子进行分组和跟踪,例如,我无法确切知道提交了多少 Bug,
以及这些 Bug 中有多少正在等待处理、进行中或已解决。
论坛维护方法对用户来说效率也很低,他们对帖子的状态一无所知,
因为论坛模块没有提供自定义帖子属性,并且通信模型非常松散。论坛模块
没有提供任何机制来通知用户其帖子的状态更改。

为了克服上述维护相关问题,解决方案是为 PragmaSQL Online 添加问题跟踪器(帮助台)
模块,但 Cuyahoga 框架没有问题跟踪器模块。
花了一些时间搜索开源问题跟踪软件后,我找到了两个项目。
但这些开源软件存在一些限制,其中一个与 Cuyahoga 框架集成不佳,
因为它不是作为 Cuyahoga 模块设计的。第二个具有非常全面的问题跟踪功能,但其方法
不支持基于角色的/用户身份验证。理想的解决方案是像 JIRA 那样的,但 JIRA 是商业产品,
而且我肯定必须自己实现 Cuyahoga 集成。

要求

因此,我决定为 Cuyahoga 编写自己的简易问题跟踪模块,以满足以下简单要求。

  • 必须是 Cuyahoga 模块
  • 支持管理多个项目
  • 支持按组件对问题进行分组
  • 支持自定义问题类型
  • 开发人员和客户之间的明确区分(基于角色/用户的身份验证)
  • 支持通用问题属性,如描述、摘要、状态、优先级和评论
  • 通过问题评论提供有效的沟通方式
  • 通过自动生成的电子邮件进行实时问题状态通知。
  • 简易问题筛选
  • 按问题状态进行简易问题统计

领域类

上述要求大部分是通过四个领域类(实际上是实体类)实现的,分别命名为 Project、IssueType、Issue 和 IssueComment。

<<>> >

从上面的类图我们可以推断出以下规则:

  • 多个项目支持通过 Project 类实现。
  • Parent 属性设置为 null 的 Project 对象用作组件的容器。
  • Project 类也用于建模组件。组件是 Parent 属性设置为另一个 Project 的 Project 实例(父项目只能是 Parent 为 null 的 Project 实例)。
  • 每个项目实例(以及组件实例)必须有一个开发人员组(Cuyahoga.Core.Domain.Role)。问题只能分配给该角色中的用户。
  • 每个项目实例(以及组件实例)必须有一个主开发人员(Cuyahoga.Core.Domain.User)。默认情况下,每个问题都会分配给主开发人员。
  • 每个组件都有一个 Key。同一项目下组件的 Key 也必须是唯一的。
  • 每个组件可以有零个或多个问题。
  • 每个问题会自动分配一个 KeyNo。这个 KeyNo 与组件的 Key 结合使用作为问题的 Key。
  • 每个问题必须有一个报告者和一个经办人(Cuyahoga.Core.Domain.User 实例)。
  • 每个问题可以有一个或多个评论。

图中列出的所有领域类都有一些共同点:

  • 它们是 NHibernate 支持的类,也就是说,每个类都嵌入了一个映射文件作为资源。
  • 它们有一个 Id 属性。此属性的值由底层数据库自动设置。
  • 它们有一个 Version 属性,用于 NHibernate 进行托管版本控制。

表示类(ASP.NET 页面和用户控件)

Cuyahoga 框架允许您轻松开发自定义模块。要开发一个基本模块,
您需要实现三个类:

  1. Module Control:这是一个用户控件,继承自 Cuyahoga.Web.UI.BaseModuleControl 类。这是访问者访问您的模块时看到的控件。Cuyahoga 框架会自动渲染此用户控件。
  2. Module Admin Page:这是一个 ASP.NET 页面,继承自 Cuyahoga.Web.UI.ModuleAdminBasePage 类。当站点管理员想要编辑您的模块时,此页面是入口点。
  3. Module:这是模块管理器类,继承自 Cuyahoga.Core.Domain.ModuleBase 并用 INHibernateModule 标记接口进行标记。此类别被 Module Control 自动实例化,您可以在 Module Control 的 Page Load 事件中获取其引用。ModuleBase 提供对 Cuyahoga 核心服务的访问,如 ISessionManager 和 IFileService。您将自定义数据访问方法包装在此类中。

Pragma Issue Tracker 除了这三个类外,还实现了其他一些 ASP.NET 页面和用户控件,具体如
下图所示。

pit_PresentationClasses.JPG

  • IssueTracker.ascx 继承自 Cuyahoga.Web.UI.BaseModuleControl。当访问者访问包含我们模块的页面时,Cuyahoga 框架会自动渲染此控件。IssueTracker 包含 IssueList 控件,该控件用作问题的通用列表。我们允许用户从下拉列表中选择预定义过滤器,并将选定的过滤器传递给 IssueList。IssueList 不仅列出问题,还按问题状态(全部、等待中、进行中和已解决)生成问题计数摘要,并允许用户按项目、组件、优先级和状态过滤问题。
  • IssueTrackerEdit.aspx 继承自 Cuyahoga.Web.UI.ModuleAdminBasePage。管理员在想要编辑 Pragma Issue Tracker 模块时看到此页面。IssueTrackerEdit 包含一个 multiview 控件,其中有两个视图。其中一个视图包含 ProjectList.ascx,第二个视图包含 IssueTypeList.ascx。网站管理员从该页面定义项目和问题类型。
  • IssueTrackerModule 继承自 Cuyahoga.Core.Domain.ModuleBase 并用 INHibernateModule 标记接口进行标记。这是我们 Cuyahoga 模块的管理器类。我们将与问题跟踪相关的数据访问功能和 Cuyahoga 集成功能包装在此类中。IssueTracker.ascx 控件在 Page Load 事件中为我们提供了 IssueTrackerModule 的一个实例,我们将其引用存储在 IssueTracker.ascx 中,并在需要数据访问功能时访问此实例。
  • ProjectList.ascx 用于列出项目或项目的组件。ProjectEdit.aspx 用于编辑项目,并包含 ProjectList.ascx 控件来列出每个项目的组件。ProjectList.ascx 将管理员重定向到 ComponentEdit.aspx 以创建新组件或编辑选定的组件。
  • ComponentEdit.aspx 用于编辑组件定义。管理员从 ProjectEdit.aspx 页面重定向到此页面。
  • IssueTypeList.ascx 用于列出自定义问题类型。
  • IssueTypeEdit.aspx:管理员从 IssueTypeList.ascx 重定向到此页面,以创建新问题类型或编辑选定的问题类型。
  • IssueEdit.aspx 用于问题编辑。

业务规则

  • 只有管理员可以定义项目、组件和问题类型。
  • 只有经过身份验证的用户才能创建问题(他们将成为问题的报告者)。
  • 匿名用户只能查看问题。
  • 对于某个组件,只有该组件的开发人员组中的用户才能被分配到问题。
  • 问题报告者不能直接更改问题状态。报告者只能重新打开已解决的问题。
  • 特定问题的经办人可以更改状态。
  • 只有特定问题的报告者和/或经办人才能删除这些问题。
  • 只有特定问题的报告者和经办人才能向该问题添加评论。
  • 特定问题的报告者或经办人只能编辑/删除自己的评论。报告者/经办人不能删除/编辑经办人/报告者的评论。
  • 管理员可以对任何问题执行所有操作。

配置

1) 我们必须执行一些特定于 Cuyahoga 的配置才能使我们的模块正常运行。浏览到 \Config 目录。将 Pragma.IssueTracker 添加到 facilities.config 文件的 元素下。facilities.config 应如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <facilities>
        <facility type="Castle.Facilities.NHibernateIntegration.NHibernateFacility, Castle.Facilities.NHibernateIntegration" 
            id="nhibernate" isWeb="true" useReflectionOptimizer="false">
            <factory id="nhibernate.factory">
                <settings>
                    <item key="hibernate.connection.provider">NHibernate.Connection.DriverConnectionProvider</item>
                    <item key="hibernate.connection.driver_class">#{nhibernateDriver}</item>
                    <item key="hibernate.dialect">#{nhibernateDialect}</item>
                    <item key="hibernate.connection.connection_string">#{connectionString}</item>
                    <item key="hibernate.cache.provider_class">NHibernate.Caches.SysCache.SysCacheProvider, NHibernate.Caches.SysCache</item>
                    <item key="hibernate.cache.use_query_cache">true</item>
                    <item key="relativeExpiration">30</item>
                </settings>
                <assemblies>
                    <assembly>Cuyahoga.Core</assembly>
                    <!--We added the following element -->
                    <assembly>Pragma.IssueTracker</assembly>
                </assemblies>
            </factory>
        </facility>
        <facility type="Castle.Facilities.AutomaticTransactionManagement.TransactionFacility, Castle.Facilities.AutomaticTransactionManagement" 
            id="autotransaction" />
    </facilities>
</configuration>

2) Cuyahoga 使用 Castle IoC 容器,并为模块开发人员提供了一些简单的方法来检索服务对象实例。例如:

_issueTrackerDao = ContainerAccessorUtil.GetContainer().Resolve<IIssueTrackerDao>()
   
/* 
 * We call this method inside a web form (aspx) which is inherited from Cuyahoga.Web.UI.GeneralPage
 * which in turn is inherited from a CuyahogaPage indirectly.
 * Container is IWindowsContainer instance provided by the base CuyahogaPage automatically
 * and we use Container instance to resolve and retreive service object instances.
*/
IIssueTrackerDao dao = this.Container.Resolve<IIssueTrackerDao>() as IIssueTrackerDao; 

利用此概念的结果是,您必须修改位于 \Config 目录下的 services.config 文件。在 components 下添加以下行:

<component
 id="pragma.issuetracker"
 service="Pragma.IssueTracker.DataAccess.IIssueTrackerDao, Pragma.IssueTracker"
 type="Pragma.IssueTracker.DataAccess.IssueTrackerDao, Pragma.IssueTracker">
</componen>

3) 由于 Pragma Issue Tracker 使用 Ajax 工具包来创建/编辑问题评论和提示电子邮件通知错误,因此我们必须修改 Web.config 文件以启用 Ajax 支持。如果我们不添加以下配置信息,当我们的模块尝试执行与 Ajax 相关的代码时,很可能会收到“Sys未定义”错误。
当我们模块尝试执行 Ajax 相关代码时,很可能会收到“Sys未定义”错误。

<system.web>
 <httpHandlers>
  <remove verb="*" path="*.asmx"/>
  <add verb="*" path="Error.aspx" type="System.Web.UI.PageHandlerFactory" />
  <add verb="*" path="*.aspx" type="Cuyahoga.Web.HttpHandlers.PageHandler, Cuyahoga.Web" />
  <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
  <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
  <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false"/>
 </httpHandlers>
 <httpModules>
  <add type="Cuyahoga.Web.HttpModules.AuthenticationModule, Cuyahoga.Web" name="AuthenticationModule" />
  <add type="Cuyahoga.Web.HttpModules.CoreRepositoryModule, Cuyahoga.Web" name="CoreRepositoryModule" />
  <add name="NHibernateSessionWebModule" type="Castle.Facilities.NHibernateIntegration.Components.SessionWebModule, Castle.Facilities.NHibernateIntegration" />
            
  <!--Ajax toolkit support-->
  <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

</httpModules>
</system.web> 

模块安装

  • 下载 Pragma Issue Tracker 包
  • 将 zip 文件内容解压到 \Modules\PragmaIssueTracker 目录
  • 将 Pragma.IssueTracker.dll 复制到 \Bin 目录
  • 以管理员身份登录到您的网站
  • 在管理面板中浏览到 Modules 页面
  • 您应该会看到 PragmaIssueTracker 模块列出。按 Install 链接按钮,Pragma Issue Tracker 模块将被安装。
  • 创建一个新页面或在现有页面中创建一个新部分来托管 Pragma Issue Tracker Module。
  • 在 section 编辑屏幕中选择 Pragma Issue Tracker Module。
  • 在自定义模块设置中,指定是否需要电子邮件通知以及是否通知用户有关电子邮件通知错误。
  • 浏览到托管 Pragma Issue Tracker Module 的页面。
  • 按 Edit 链接按钮来管理 Pragma Issue Tracker Module。
  • 定义项目和每个项目要执行问题跟踪的组件。在本例中,我们有 PragmaSQL 项目和几个组件,如 Application、Core、Server Management、HTML Help 和 External Tools。
  • 定义问题类型,如 Bug、New Feature、Improvement 和 Support。

注意:不要忘记将您的开发人员组织到某些 Cuyahoga 角色下,因为 Pragma Issue Tracker 会要求您提供
为每个项目和组件提供开发人员角色和属于指定角色的主用户。
您可以为此定义自己的自定义方案。一些可能性包括:
  • 每个项目都有自己的开发人员角色
  • 每个组件都有自己的开发人员角色
  • 所有项目和组件使用单一开发人员角色。

局限性

  • Pragma Issue Tracker 模块目前支持 MySQL 和 MSSQL Server 数据库。您可以添加对其他数据库提供商(如 Oracle)的支持。您需要将 Install\Database\mysql 文件夹中的文件复制到另一个文件夹,例如 Install\Database\oracle,并修改 SQL 脚本以支持该数据库提供商的语法。
  • Pragma Issue Tracker 模块目前不支持高级问题跟踪概念,如链接问题、创建子问题、工作日志和问题附件。由于 Pragma Issue Tracker 是一个开源项目,我们欢迎您开发这些功能并贡献它们。
  • Pragma Issue Tracker 是一个 Cuyahoga 模块,并且需要 NHibernate。如果您想在不同的 Web 框架中使用此模块,您将需要修改大量的身份验证、重定向和持久性相关代码。

可能的重构和改进

1) 我们可以设计一个具有 Id 和 Version 属性的基类,并将所有领域类继承自
此类。

public class BaseIssuTrackerClass 
{
    private long _version = 0;
    
    private int _id;
    public int Id
    {
      get { return _id; }
      internal set { _id = value; }
    }
}

2) 我们可以为 Project 和 Component 设计单独的类。
当前设计使用 Project 类来建模 Project 和 Component 实例。

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

更新

  • 2008 年 1 月 8 日:Pragma Issue Tracker 分发版中添加了 MS SQL 版本的安装/卸载脚本。
  • 2008 年 1 月 9 日:文章中添加了与 IoC(控制反转)容器相关的新配置步骤描述。
  • 2008 年 1 月 21 日
    • IssueTrackerDao.cs 中的 FindIssue_Internal() 方法被重写,以解决 NHibernate 和 MS SQL 相关的查询问题。
    • 修改了 MS SQL Server 安装脚本。在 MS SQL Server 中,我们无法对 text 数据类型使用 like,因此我们将 pragma_issue 和 pragma_issuecomment 表中的 text 字段转换为 varchar(8000)。
    • MySQL 中最小的 DateTime 是 0001-01-01,但对于 MS SQL Server 来说不是这样(该值为 1899-12-31)。因此,我们必须使用自己的最小可能值来兼容两个服务器版本。最小的 DateTime 值(我们使用此值代替 null 值)被定义为 IssueTrackeUtils 类上的一个静态属性(MinDateTime = 1900-01-01)。
© . All rights reserved.