Этюды на ASP2. Простейший баг-трекер.
Микрософт предполагает, что для учета багов в программе народ будет применять TEAM FOUNDATION SERVER. Что ж, это не исключено, если у вас есть заведомо лишние семь тысяч долларов. А можете установить вот эту мою прогу, которую я публикую здесь с открытым исходным кодом.
К моей проге тут еще не прикручет репорт-сервер и вот таких симпотичных отчетов, как в TFS - вы в ней не получите пока не докрутите сюда reportviewer, но во многих отношениях даже такой элементарный багтрекер гораздо более практичен и функционален, чем навороченный микрософтовский монстр.
Ну хотя бы в той части, что тупой мискрософтовский монстр не позволяет ВЕСТИ ОБСУЖДЕНИЕ проблемы. Сценарий предполагает что тестер вбил ошибку, а программер ее исправил. И все. Да, в теории все красиво. Но в жизни - тестеры, это малоквалифицированные полуставочники и половина того, что они вбивают как баги - является совершенно безумным бредом. И требует тчательного разжевавания программистом азбуки ASP.NET или, например, различий между обязанностями программиста и обязанностями верстальщика. Во многих случаях так называемые баги не имеют даже косвенного отношения к программисту - например модератор ведет в SQL базу стран - а тестеры вбивают программеру баг: "почему у вас сайт показывает страну Умумбу - такой страны нету!".
Собственно говоря, на моем сайте лежит МНОЖЕСТВО описаний различных моих баг-трекеров, сделанных мною в разные годы для разных фирм. Например тут - лежит мой баг-трекер для WIN-приложений 2005-го года рождения, который я сделал для ДигиталШопа.
Кроме того, в 2007-м году я работал в одном шизоидном микрософтовском проекте, практическое приложение которого было тоже в виде баг трекера. Это такой универсальный конфигуратор, который позволял смоделировать организационную структуру сначала - те тестер, программер. Потом обьекты, которыми манипулирует эта оргструктура - проекты, баги, версии. Потом например программер поправляет баг - идут оповещения между обьектами - тестеру, руководителю проекта, если баг последний - выпускающему Менеджеру проекта. Пара скринов этой шизоидной системы у меня лежит здесь.
Эта система была гораздо лучше TFS и даже немного приближалась по качеству к моим старинным разработкам типа ProjectExplorer, не шизоидность ее заключалась в том, что перед ее пользованием администратора системы, преодолевая тонны документации и горы багов - сначала должен был ее СКОНФИГУРИРОВАТЬ. Те занести в нее тесторов, девелоперов, админов и тд. Потом в жутких муках настроить ОПОВЕЩЕНИЯ, которые система отправляла мылом членам этой организационной структуры...
Не знаю, какой админ бы сумел асилить все глубину микрасофтовских задумок и асилить все конфигурирование очередного микрасофтоского монстра, но... шизо-идея ТЗ состояла в том, что это все надо было выложить в виде публичного сервиса, что-то по типу MAIL.RU - админы организаций бы это чудо конфигурили, а тестеры и проггеры этим чудом бы пользовались. При этом MS собирался НЕ ДОПЛАЧИВАТЬ фирмам за пользование этим своим логическим глюком (моего производства), а ВЗИМАТЬ с них деньги.
Я долго хохотал над этой шизо-идеей, над техническим заданием, над прототипом проекта на PHP, который уже был до начала моей работы в проекте - но от участия в проекте не отказался, тк очень хочелось бы получть с биллагейтса хоть какие-нибудь деньги. Но как я и предполагал, через несколько месяцев у проекта начались финансовые сложности. Морду микрософатавцам конечно не били, за их грязные предложения оплатить право пользования их чудо-сайтом коммунального баг-трекинга, но денег им никто так и не заплатил. Естественно, с моей ЗП уже через несколько месяцев у них начались сложности и они разрешились естественным образом - я уволился и этот чудо-проект скорее всего исчез в небытие..
Ну вот, собственно, и весь Background-рассказик у этой моей крошечной проги. Я написал ее за один день - сев за камп часов в шесть вечера. Мне даже лень было для такой крошечной проги придумывать осмысленные имена идентификаторов и обравнивать длины полей на формах и в базе, ибо я ее даже не отлаживал - она пошла сразу. С защитой и безопасностью я тут тоже не заморачивался - это ведь все междусобойчик тестеров и девелоперов. С другой стороны, элементарность этой проги доказывает полный тупизм микрасофтовцев, которые вознамерились на такой крошечной проге, написанной за пару часов - взимать с народа деньги. Продавать право пользования этим сайтом за нехилые деньги, причем с помесячным поступлением платежей ... Хм, ну надо ж до такого додуматся - изловчится и даже с кучки гавна сладенькую пеночку слизнуть... Ай-да, детеныши билла гейтса !!!
Эта прога элементарно расширяема как в плане отсылки мыльных сообщений, так и в плане отчетов. Только мой вам совет - при расширениях постарайтесь избежать микрософтовского тупизма с безумными глючными конфигураторами шаблонов почтовых сообщений. Делайте все просто - состояние бага такого-то изменилось с такого-то на такое-то. И все. Это ровно одна строка кода на форме BugChange. Ну тут будет куча специфики доступа к почтовику. И вам проще самому дописать мыльный функционал любимым вами способом, чем разбиратся в причинах неработоспособности моего кода.
Если вы сидите на SQL2005 - тыкайтесь в почтовик через DBMAIL - это лучше чем вот так.
Теперь собственно о проге. Она докручивается в любой ASP.NET сайт, в котором работает AU на стандартной микрософтовской базе юзеров. Прога состоит из пяти страничек, код которых будет приведен ниже в исходном виде и трех табличек, которые вам надо установить в рабочую базу сайта:
00001: SET ANSI_NULLS ON 00002: GO 00003: SET QUOTED_IDENTIFIER ON 00004: GO 00005: CREATE TABLE [dbo].[BugState]( 00006: [i] [int] IDENTITY(1,1) NOT NULL, 00007: [Image] [nvarchar](1000) NOT NULL, 00008: [Descr] [nvarchar](4000) NOT NULL, 00009: CONSTRAINT [PK_BugState] PRIMARY KEY CLUSTERED 00010: ( 00011: [i] ASC 00012: ) ON [PRIMARY] 00013: ) ON [PRIMARY] 00014: GO 00015: SET ANSI_NULLS ON 00016: GO 00017: SET QUOTED_IDENTIFIER ON 00018: GO 00019: CREATE TABLE [dbo].[BugComment]( 00020: [i] [int] IDENTITY(1,1) NOT NULL, 00021: [ToBug] [int] NOT NULL, 00022: [ToUser] [uniqueidentifier] NOT NULL, 00023: [Date] [datetime] NOT NULL, 00024: [NewState] [int] NOT NULL, 00025: [ToImage] [nvarchar](1000) NULL, 00026: [Comment] [nvarchar](4000) NULL, 00027: CONSTRAINT [PK_BugForum] PRIMARY KEY CLUSTERED 00028: ( 00029: [i] ASC 00030: ) ON [PRIMARY] 00031: ) ON [PRIMARY] 00032: GO 00033: SET ANSI_NULLS ON 00034: GO 00035: SET QUOTED_IDENTIFIER ON 00036: GO 00037: CREATE TABLE [dbo].[Bugs]( 00038: [i] [int] IDENTITY(1,1) NOT NULL, 00039: [ToState] [int] NOT NULL, 00040: [TXT] [nvarchar](4000) NULL, 00041: [Page] [nvarchar](1000) NULL, 00042: [ToImage] [nvarchar](1000) NULL, 00043: [CrDate] [datetime] NOT NULL, 00044: [ToUser] [uniqueidentifier] NOT NULL, 00045: CONSTRAINT [PK_Bugs] PRIMARY KEY CLUSTERED 00046: ( 00047: [i] ASC 00048: ) ON [PRIMARY] 00049: ) ON [PRIMARY] 00050: GO 00051: ALTER TABLE [dbo].[BugComment] WITH CHECK ADD CONSTRAINT [FK_BugForum_Bugs] FOREIGN KEY([ToBug]) 00052: REFERENCES [dbo].[Bugs] ([i]) 00053: GO 00054: ALTER TABLE [dbo].[BugComment] CHECK CONSTRAINT [FK_BugForum_Bugs] 00055: GO 00056: ALTER TABLE [dbo].[BugComment] WITH CHECK ADD CONSTRAINT [FK_BugForum_BugState1] FOREIGN KEY([NewState]) 00057: REFERENCES [dbo].[BugState] ([i]) 00058: GO 00059: ALTER TABLE [dbo].[BugComment] CHECK CONSTRAINT [FK_BugForum_BugState1] 00060: GO 00061: ALTER TABLE [dbo].[Bugs] WITH CHECK ADD CONSTRAINT [FK_Bugs_BugState] FOREIGN KEY([ToState]) 00062: REFERENCES [dbo].[BugState] ([i]) 00063: GO 00064: ALTER TABLE [dbo].[Bugs] CHECK CONSTRAINT [FK_Bugs_BugState] 00065: GO 00066: INSERT [BugState]([Image],[Descr]) VALUES(N'Add.gif',N'Проблема сформулирована.') 00067: INSERT [BugState]([Image],[Descr]) VALUES(N'Mail.gif',N'Обсуждение и уточнение задачи.') 00068: INSERT [BugState]([Image],[Descr]) VALUES(N'Time.gif',N'Решение задачи отложено на более позднее время.') 00069: INSERT [BugState]([Image],[Descr]) VALUES(N'Close.gif',N'Задача не может быть выполнена.') 00070: INSERT [BugState]([Image],[Descr]) VALUES(N'Write.gif',N'Задача полностью понятна и взята программистом в разработку.') 00071: INSERT [BugState]([Image],[Descr]) VALUES(N'Atten.gif',N'Обработка проблемы программистом завершена!') 00072: INSERT [BugState]([Image],[Descr]) VALUES(N'Quest.gif',N'Решение задачи не найдено, непонятно или не соответствует поставленной задаче.') 00073: INSERT [BugState]([Image],[Descr]) VALUES(N'OK.gif',N'Решение задачи перепроверено, принято и проблема полностью закрыта.') 00074: GO
В этом коде нет никаких особенностей, он должен пойти даже под SQL2000. А вот странички ссылаются на эту базу строкой коннекта с именем SQLServer_ConnectionStrings - и это единственное конфигурирование моего баг-трекера, которое вам потребуется!
Теперь собственно код первой формы:
00001: <%@ Page Language="VB" AutoEventWireup="false" CodeFile="BugList.aspx.vb" Inherits="BugList" %> 00002: 00003: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 00004: 00005: <html xmlns="http://www.w3.org/1999/xhtml"> 00006: <head runat="server"> 00007: <title>Баг-трекер</title> 00008: </head> 00009: <body> 00010: <form id="form1" runat="server"> 00011: <div> 00012: <div style="text-align:center; font-size:20px"> 00013: <asp:HyperLink ID="HyperLink1" NavigateUrl="~/Default.aspx" runat="server">На главную</asp:HyperLink> 00014: </div> 00015: <div style="height:10px"></div> 00016: <table><tr><td> 00017: <asp:Label ID="Label1" runat="server" Text="Отобрать только:"></asp:Label> 00018: </td><td> 00019: <asp:ImageButton ID="ImageButton2" ImageUrl="~/BugImage/Info.gif" CommandArgument=0 runat="server" Height="50px" Width="50px" ToolTip="Все" /> 00020: </td><td> 00021: <asp:ImageButton ID="ImageButton3" ImageUrl="~/BugImage/Add.gif" runat="server" CommandArgument=1 Height="50px" Width="50px" ToolTip="Только что добавленные" /> 00022: </td><td> 00023: <asp:ImageButton ID="ImageButton4" ImageUrl="~/BugImage/Mail.gif" CommandArgument="2" runat="server" Height="50px" Width="50px" ToolTip="Находящиеся в обсуждение и уточнении." /> 00024: </td><td> 00025: <asp:ImageButton ID="ImageButton5" ImageUrl="~/BugImage/Time.gif" CommandArgument="3" runat="server" Height="50px" Width="50px" ToolTip="Отложенные на неопределенное время." /> 00026: </td><td> 00027: <asp:ImageButton ID="ImageButton6" ImageUrl="~/BugImage/Close.gif" CommandArgument="4" runat="server" Height="50px" Width="50px" ToolTip="Позиции, выполнение которых невозможно." /> 00028: </td><td> 00029: <asp:ImageButton ID="ImageButton7" ImageUrl="~/BugImage/Write.gif" CommandArgument="5" runat="server" Height="50px" Width="50px" ToolTip="Находящиеся в данный момент в разработке у программиста." /> 00030: </td><td> 00031: <asp:ImageButton ID="ImageButton8" ImageUrl="~/BugImage/Atten.gif" CommandArgument="6" runat="server" Height="50px" Width="50px" ToolTip="Позиции, разработка которых программистом завершена." /> 00032: </td><td> 00033: <asp:ImageButton ID="ImageButton9" ImageUrl="~/BugImage/Quest.gif" CommandArgument="7" runat="server" Height="50px" Width="50px" ToolTip="Позиции, завершенные программистом, но не принятые." /> 00034: </td><td> 00035: <asp:ImageButton ID="ImageButton10" ImageUrl="~/BugImage/OK.gif" CommandArgument="8" runat="server" Height="50px" Width="50px" ToolTip="Полностью принятые и закрытые позиции." /> 00036: </td> </tr></table> 00037: <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 00038: DataKeyNames="i" Width="100%" 00039: AllowPaging="True" PageSize="20"> 00040: <Columns> 00041: <asp:BoundField DataField="i" HeaderText="#" InsertVisible="False" 00042: ReadOnly="True" SortExpression="i" /> 00043: <asp:TemplateField HeaderText="State"> 00044: <ItemTemplate> 00045: <asp:ImageButton ID="ImageButton1" Width="50" Height="50" runat="server" 00046: onclick="ImageButton1_Click" /> 00047: </ItemTemplate> 00048: </asp:TemplateField> 00049: <asp:TemplateField > 00050: <ItemTemplate> 00051: <asp:Label ID="KTO" runat="server"></asp:Label> 00052: </ItemTemplate> 00053: </asp:TemplateField> 00054: <asp:TemplateField HeaderText="Bug/Task"> 00055: <ItemTemplate> 00056: <asp:HyperLink ID="HyperLink1" runat="server" ></asp:HyperLink> 00057: </ItemTemplate> 00058: </asp:TemplateField> 00059: </Columns> 00060: </asp:GridView> 00061: <div style="height:10px"></div> 00062: <table><tr><td> 00063: <asp:ImageButton ID="ImageButton1" ImageUrl="~/BugImage/Add.gif" runat="server" 00064: Height="50px" Width="50px" /> 00065: </td><td> 00066: Добавить новый баг или новую задачу.</td> 00067: </tr></table> 00068: </div> 00069: <asp:SqlDataSource ID="GetBugList" runat="server" 00070: ConnectionString="<%$ ConnectionStrings:SQLServer_ConnectionStrings %>" 00071: SelectCommand="select Bugs.*,Image,Descr from Bugs join BugState on Bugs.ToState=BugState.i"> 00072: </asp:SqlDataSource> 00073: <asp:SqlDataSource ID="GetBugList1" runat="server" 00074: ConnectionString="<%$ ConnectionStrings:SQLServer_ConnectionStrings %>" 00075: SelectCommand="select Bugs.*,Image,Descr from Bugs join BugState on Bugs.ToState=BugState.i where Bugs.ToState=@i"> 00076: <SelectParameters> 00077: <asp:Parameter Name="i" /> 00078: </SelectParameters> 00079: </asp:SqlDataSource> 00080: </form> 00081: </body> 00082: </html> 00001: Partial Class BugList 00002: Inherits System.Web.UI.Page 00003: 00004: Protected Sub BugAdd_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 00005: If Not IsPostBack Then 00006: If User.Identity.Name = "" Then Response.Redirect("~/Default.aspx") 00007: Dim CurUser As MembershipUser = Membership.GetUser(User.Identity.Name) 00008: ImageButton1.PostBackUrl = "~/BugAdd.aspx?i=" & CurUser.ProviderUserKey.ToString 00009: GridView1.DataSourceID = "GetBugList" 00010: GridView1.DataBind() 00011: End If 00012: End Sub 00013: 00014: Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound 00015: If e.Row.DataItem IsNot Nothing Then 00016: Dim KTO As Label = CType(e.Row.FindControl("KTO"), Label) 00017: Dim User1 As MembershipUser = Membership.GetUser(e.Row.DataItem("ToUser")) 00018: KTO.Text = User1.UserName & " (" & e.Row.DataItem("CrDate") & ")" 00019: Dim ImageButton1 As ImageButton = CType(e.Row.FindControl("ImageButton1"), ImageButton) 00020: ImageButton1.ToolTip = e.Row.DataItem("Descr") 00021: ImageButton1.ImageUrl = "~/BugImage/" & e.Row.DataItem("Image") 00022: ImageButton1.CommandArgument = e.Row.DataItem("i") 00023: Dim HyperLink1 As HyperLink = CType(e.Row.FindControl("HyperLink1"), HyperLink) 00024: HyperLink1.NavigateUrl = "~/BugComments.aspx?i=" & User1.ProviderUserKey.ToString & "&j=" & e.Row.DataItem("i") 00025: HyperLink1.Text = Left(e.Row.DataItem("TXT"), 180) & " ..." 00026: End If 00027: End Sub 00028: 00029: Protected Sub ImageButton1_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) 00030: Dim User1 As MembershipUser = Membership.GetUser(User.Identity.Name) 00031: Dim ImageButton1 As ImageButton = CType(sender, ImageButton) 00032: Response.Redirect("~/BugComments.aspx?i=" & User1.ProviderUserKey.ToString & "&j=" & ImageButton1.CommandArgument) 00033: End Sub 00034: 00035: Protected Sub ImageButton2_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles ImageButton2.Click 00036: GridView1.DataSourceID = "GetBugList" 00037: GridView1.DataBind() 00038: End Sub 00039: 00040: Protected Sub ImageButton3_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles ImageButton3.Click, ImageButton4.Click, ImageButton5.Click, ImageButton6.Click, ImageButton7.Click, ImageButton8.Click, ImageButton9.Click, ImageButton10.Click 00041: Dim Button1 As ImageButton = CType(sender, ImageButton) 00042: GetBugList1.SelectParameters("i").DefaultValue = Button1.CommandArgument 00043: GridView1.DataSourceID = "GetBugList1" 00044: GridView1.DataBind() 00045: End Sub 00046: End Class
Вторая форма
00001: <%@ Page Language="VB" AutoEventWireup="false" CodeFile="BugAdd.aspx.vb" Inherits="BugAdd" %> 00002: 00003: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 00004: 00005: <html xmlns="http://www.w3.org/1999/xhtml"> 00006: <head runat="server"> 00007: <title>Баг-трекер</title> 00008: </head> 00009: <body> 00010: <form id="form1" runat="server"> 00011: <div> 00012: <div style="text-align:center; font-size:20px"> 00013: <asp:HyperLink ID="HyperLink1" NavigateUrl="~/BugList.aspx" runat="server">Баг-трекер</asp:HyperLink> -> 00014: Добавление нового описания бага или задачи</div> 00015: <div style="height:10px"></div> 00016: <table width=100%> 00017: <tr><td> </td></tr> 00018: <tr><td>URL странички с ошибкой: </td></tr> 00019: <tr><td> 00020: <asp:TextBox ID="TextBox1" Width=100% runat="server"></asp:TextBox> </td></tr> 00021: <tr><td> </td></tr> 00022: <tr><td>Подробное описание проблемы </td></tr> 00023: <tr><td><asp:TextBox ID="TextBox2" Width=100% runat="server" MaxLength="4000" 00024: Rows="10" TextMode="MultiLine"></asp:TextBox></td></tr> 00025: <tr><td> </td></tr> 00026: <tr><td>Рисунок: </td></tr> 00027: <tr><td> 00028: <asp:FileUpload ID="FileUpload1" runat="server" Width="100%" /> 00029: </td></tr> 00030: <tr><td> </td></tr> 00031: </table> 00032: <div style="height:10px"></div> 00033: <table><tr><td> 00034: <asp:ImageButton ID="ImageButton1" ImageUrl="~/BugImage/Add.gif" ToolTip="Добавить баг" runat="server" 00035: Height="50px" Width="50px" /> 00036: 00037: </td><td>Добавить баг</td></tr></table> 00038: 00039: 00040: </div> 00041: <asp:SqlDataSource ID="AddBug" runat="server" 00042: ConnectionString="<%$ ConnectionStrings:SQLServer_ConnectionStrings %>" 00043: SelectCommand="INSERT [Bugs] ([ToState],[TXT],[Page],[ToImage],[CrDate],[ToUser]) Values (1,@TXT,@Page,@ToImage, GetDate(), @ToUser)"> 00044: <SelectParameters> 00045: <asp:ControlParameter ControlID="TextBox2" Name="TXT" PropertyName="Text" /> 00046: <asp:ControlParameter ControlID="TextBox1" Name="Page" PropertyName="Text" /> 00047: <asp:Parameter Name="ToImage" Type="String" /> 00048: <asp:Parameter Name="ToUser" Type="String" /> 00049: </SelectParameters> 00050: </asp:SqlDataSource> 00051: </form> 00052: </body> 00053: </html> 00001: Partial Class BugAdd 00002: Inherits System.Web.UI.Page 00003: 00004: Protected Sub BugAdd_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 00005: If Not IsPostBack Then 00006: If User.Identity.Name = "" Then Response.Redirect("~/Default.aspx") 00007: TextBox1.Focus() 00008: End If 00009: End Sub 00010: 00011: Protected Sub ImageButton1_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles ImageButton1.Click 00012: Dim CurUser As MembershipUser = Membership.GetUser(User.Identity.Name) 00013: If FileUpload1.FileName <> "" Then 00014: Dim ImageName As String = Guid.NewGuid.ToString 00015: FileUpload1.SaveAs(System.IO.Path.Combine(Server.MapPath("~/BugImage"), ImageName & ".gif")) 00016: AddBug.SelectParameters("ToImage").DefaultValue = ImageName & ".gif" 00017: Else 00018: AddBug.SelectParameters("ToImage").DefaultValue = "нет" 00019: End If 00020: If TextBox1.Text = "" Then AddBug.SelectParameters("Page").DefaultValue = " " 00021: If TextBox2.Text = "" Then AddBug.SelectParameters("TXT").DefaultValue = " " 00022: AddBug.SelectParameters("ToUser").DefaultValue = CurUser.ProviderUserKey.ToString 00023: AddBug.Select(New DataSourceSelectArguments) 00024: Response.Redirect("~/BugList.aspx") 00025: End Sub 00026: End Class
Третья форма.
00001: <%@ Page Language="VB" AutoEventWireup="false" CodeFile="BugChange.aspx.vb" Inherits="BugChange" %> 00002: 00003: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 00004: 00005: <html xmlns="http://www.w3.org/1999/xhtml"> 00006: <head runat="server"> 00007: <title>Баг-трекер</title> 00008: </head> 00009: <body> 00010: <form id="form1" runat="server"> 00011: <div> 00012: <div style="text-align:center; font-size:20px"> 00013: <asp:HyperLink ID="HyperLink1" NavigateUrl="~/BugList.aspx" runat="server">Баг-трекер</asp:HyperLink> -> 00014: <asp:HyperLink ID="HyperLink2" runat="server">История</asp:HyperLink> -> 00015: Сохраните ваше сообщение, установив текущее состояние проблемы.</div> 00016: 00017: <table width="100%"> 00018: <tr><td> </td></tr> 00019: <tr><td><asp:TextBox ID="TextBox1" Width=100% runat="server" MaxLength="4000" 00020: Rows="10" TextMode="MultiLine"></asp:TextBox></td></tr> 00021: <tr><td> </td></tr> 00022: <tr><td>При необходимости подкрепите ваше мнение рисунком: </td></tr> 00023: <tr><td> 00024: <asp:FileUpload ID="FileUpload1" runat="server" Width="100%" /> 00025: </td></tr> 00026: <tr><td> </td></tr> 00027: </table> 00028: 00029: <table width="100%"> 00030: <tr><td align="left" valign="top"> 00031: <asp:ImageButton ID="ImageButton1" ImageUrl="~/BugImage/Mail.gif" 00032: CommandArgument="2" runat="server" Height="50px" Width="50px" /> 00033: </td><td style="font-size:14px">Обсуждение и уточнение задачи. 00034: </td></tr> 00035: <tr><td align="left" valign="top"> 00036: <asp:ImageButton ID="ImageButton2" ImageUrl="~/BugImage/Time.gif" CommandArgument="3" 00037: runat="server" Height="50px" Width="50px" /> 00038: </td><td style="font-size:14px">Решение задачи отложено на более позднее время. 00039: </td></tr> 00040: <tr><td align=left valign=top style="font-size:14px"> 00041: <asp:ImageButton ID="ImageButton3" ImageUrl="~/BugImage/Close.gif" CommandArgument="4" runat="server" Height="50px" Width="50px" /></td><td style="font-size:14px"> 00042: Задача не может быть выполнена:<br /> 00043: <ul> 00044: <li style="font-size:12px">Это заведомо предусмотренное штатное поведение данной программы. Изменение этого поведения противоречит уже принятым и реализованным проектным решениям.</li> 00045: <li style="font-size:12px">Данная программа не предназначена для решения этой задачи.</li> 00046: <li style="font-size:12px">Решение этой задачи выходит за рамки технологии ASP NET.</li> 00047: <li style="font-size:12px">Это снижает юзабилити, поведение программы становится неожиданным и непонятным в глазах пользователя.</li> 00048: <li style="font-size:12px">Решение этой задачи слишком сложно. Программа становится слишком громоздкой, неуправляемой и трудно сопровождаемой.</li> 00049: <li style="font-size:12px">Это стандартное поведение серверной среды программирования ASP NET, WEB-сервера, SQL-сервера, браузера.</li> 00050: <li style="font-size:12px">Этот вопрос не в компетенции программиста. Следует обратится к верстальщику, дизайнеру, контент-менеджеру, SQL-программисту, администратору, модератору. 00051: </ul> 00052: </td></tr> 00053: <tr><td align="left" valign="top"> 00054: <asp:ImageButton ID="ImageButton4" ImageUrl="~/BugImage/Write.gif" CommandArgument="5" runat="server" Height="50px" Width="50px" /> 00055: </td><td style="font-size:14px">Задача полностью понятна и взята программистом в разработку. 00056: </td></tr> 00057: <tr><td align="left" valign="top"> 00058: <asp:ImageButton ID="ImageButton5" ImageUrl="~/BugImage/Atten.gif" CommandArgument="6" runat="server" Height="50px" Width="50px" /> 00059: </td><td style="font-size:14px">Обработка проблемы программистом завершена! 00060: </td></tr> 00061: 00062: <tr><td align="left" valign="top"> 00063: <asp:ImageButton ID="ImageButton6" ImageUrl="~/BugImage/Quest.gif" CommandArgument="7" runat="server" Height="50px" Width="50px" /> 00064: </td><td style="font-size:14px">Решение задачи не найдено, непонятно или не соответствует поставленной задаче. 00065: </td></tr> 00066: <tr><td align="left" valign="top"> 00067: <asp:ImageButton ID="ImageButton7" ImageUrl="~/BugImage/OK.gif" CommandArgument="8" runat="server" Height="50px" Width="50px" /> 00068: </td><td style="font-size:14px">Решение задачи перепроверено, принято и проблема полностью закрыта. 00069: </td></tr> 00070: 00071: </table> 00072: </div> 00073: <asp:SqlDataSource ID="AddComment" runat="server" 00074: ConnectionString="<%$ ConnectionStrings:SQLServer_ConnectionStrings %>" 00075: SelectCommand="INSERT [BugComment] ([ToBug] , [ToUser] ,[NewState] ,[Comment], [Date], [ToImage]) VALUES (@ToBug , @ToUser ,@NewState ,@Comment, GetDate(), @ToImage)"> 00076: <SelectParameters> 00077: <asp:QueryStringParameter Name="ToBug" QueryStringField="j" /> 00078: <asp:QueryStringParameter Name="ToUser" QueryStringField="i" /> 00079: <asp:Parameter Name="NewState" Type="Int32" /> 00080: <asp:Parameter Name="ToImage" Type="String" /> 00081: <asp:ControlParameter ControlID="TextBox1" Name="Comment" PropertyName="Text" /> 00082: </SelectParameters> 00083: </asp:SqlDataSource> 00084: 00085: 00086: <asp:SqlDataSource ID="SetState" runat="server" 00087: ConnectionString="<%$ ConnectionStrings:SQLServer_ConnectionStrings %>" 00088: SelectCommand="update Bugs set ToState=@NewState where i=@i"> 00089: <SelectParameters> 00090: <asp:Parameter Name="NewState" Type="Int32" /> 00091: <asp:QueryStringParameter Name="i" QueryStringField="j" /> 00092: </SelectParameters> 00093: </asp:SqlDataSource> 00094: 00095: 00096: </form> 00097: </body> 00098: </html> 00001: Partial Class BugChange 00002: Inherits System.Web.UI.Page 00003: 00004: Protected Sub BugChange_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 00005: If Not IsPostBack Then 00006: If User.Identity.Name = "" Then Response.Redirect("~/Default.aspx") 00007: Dim CurUser As MembershipUser = Membership.GetUser(User.Identity.Name) 00008: HyperLink2.NavigateUrl = "~/BugComments.aspx?i=" & CurUser.ProviderUserKey.ToString & "&j=" & Request.QueryString("j") 00009: HyperLink2.Text = "История задачи # " & Request.QueryString("j") 00010: TextBox1.Focus() 00011: End If 00012: End Sub 00013: 00014: Protected Sub ImageButton1_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles ImageButton1.Click, ImageButton2.Click, ImageButton3.Click, ImageButton4.Click, ImageButton5.Click, ImageButton6.Click, ImageButton7.Click 00015: Dim Button1 As ImageButton = CType(sender, ImageButton) 00016: 'при желании это можно в транзакцию обьединить 00017: If FileUpload1.FileName <> "" Then 00018: Dim ImageName As String = Guid.NewGuid.ToString 00019: FileUpload1.SaveAs(System.IO.Path.Combine(Server.MapPath("~/BugImage"), ImageName & ".gif")) 00020: AddComment.SelectParameters("ToImage").DefaultValue = ImageName & ".gif" 00021: Else 00022: AddComment.SelectParameters("ToImage").DefaultValue = "нет" 00023: End If 00024: If TextBox1.Text = "" Then AddComment.SelectParameters("Comment").DefaultValue = " " 00025: AddComment.SelectParameters("NewState").DefaultValue = Button1.CommandArgument 00026: AddComment.Select(New DataSourceSelectArguments) 00027: SetState.SelectParameters("NewState").DefaultValue = Button1.CommandArgument 00028: SetState.Select(New DataSourceSelectArguments) 00029: Response.Redirect("~/BugList.aspx") 00030: End Sub 00031: 00032: End Class
Четвертая форма
00001: <%@ Page Language="VB" AutoEventWireup="false" CodeFile="BugComment.aspx.vb" Inherits="BugComment" %> 00002: 00003: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 00004: 00005: <html xmlns="http://www.w3.org/1999/xhtml"> 00006: <head runat="server"> 00007: <title>Баг-трекер</title> 00008: </head> 00009: <body> 00010: <form id="form1" runat="server"> 00011: <div> 00012: 00013: <div> 00014: <div style="text-align:center; font-size:20px"> 00015: <asp:HyperLink ID="HyperLink1" NavigateUrl="~/BugList.aspx" runat="server">Баг-трекер</asp:HyperLink> -> 00016: <asp:HyperLink ID="Label1" runat="server" ></asp:HyperLink> -> 00017: <asp:Label ID="Label2" runat="server" ></asp:Label></div> 00018: <div style="height:10px"></div> 00019: <table width="100%"> 00020: <tr><td> 00021: <asp:Image ID="Image2" Width="50" Height="50" runat="server" /> 00022: </td><td> 00023: <asp:Label ID="Label3" runat="server" ></asp:Label></td></tr> 00024: <tr><td colspan="2"> 00025: <asp:Image ID="Image1" runat="server" /></td></tr> 00026: </table> 00027: <div style="height:10px"></div> 00028: <table><tr><td> 00029: <asp:ImageButton ID="ImageButton2" runat="server" Height="50px" 00030: ImageUrl="~/BugImage/Circle.gif" 00031: ToolTip="Добавить сообщение или изменить состояние." Width="50px" /> 00032: </td><td> 00033: Добавить сообщение или изменить состояние.</td> 00034: </tr></table> 00035: </div> 00036: 00037: </form> 00038: <asp:SqlDataSource ID="GetOneComment" runat="server" 00039: ConnectionString="<%$ ConnectionStrings:SQLServer_ConnectionStrings %>" 00040: SelectCommand="select BugComment.*,BugState.Image,BugState.Descr from BugComment join BugState on BugState.i=BugComment.NewState where BugComment.i=@i"> 00041: <SelectParameters> 00042: <asp:QueryStringParameter Name="i" QueryStringField="k" Type="String" /> 00043: </SelectParameters> 00044: </asp:SqlDataSource> 00045: 00046: 00047: </body> 00048: </html> 00001: Partial Class BugComment 00002: Inherits System.Web.UI.Page 00003: 00004: Protected Sub BugChange_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 00005: If Not IsPostBack Then 00006: If User.Identity.Name = "" Then Response.Redirect("~/Default.aspx") 00007: Dim CurUser As MembershipUser = Membership.GetUser(User.Identity.Name) 00008: Label1.Text = "История задачи # " & Request.QueryString("j") 00009: Label1.NavigateUrl = "~/BugComments.aspx?i=" & CurUser.ProviderUserKey.ToString & "&j=" & Request.QueryString("j") 00010: Label2.Text = "Комментарий # " & Request.QueryString("k") 00011: Dim DV1 As Data.DataView = GetOneComment.Select(New DataSourceSelectArguments) 00012: If DV1 IsNot Nothing Then 00013: If DV1.Count > 0 Then 00014: If IsDBNull(DV1(0)("ToImage")) Then 00015: Image1.Visible = False 00016: Else 00017: If DV1(0)("ToImage") <> "нет" Then 00018: Image1.ImageUrl = "~/BugImage/" & DV1(0)("ToImage") 00019: End If 00020: End If 00021: Image2.ImageUrl = "~/BugImage/" & DV1(0)("Image") 00022: Image2.ToolTip = DV1(0)("Descr") 00023: Label3.Text = DV1(0)("Comment") 00024: End If 00025: End If 00026: End If 00027: End Sub 00028: 00029: Protected Sub ImageButton2_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles ImageButton2.Click 00030: Dim CurUser As MembershipUser = Membership.GetUser(User.Identity.Name) 00031: Response.Redirect("~/BugChange.aspx?i=" & CurUser.ProviderUserKey.ToString & "&j=" & Request.QueryString("j")) 00032: End Sub 00033: End Class
Пятая форма
00001: <%@ Page Language="VB" AutoEventWireup="false" CodeFile="BugComments.aspx.vb" Inherits="BugComments" %> 00002: 00003: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 00004: 00005: <html xmlns="http://www.w3.org/1999/xhtml"> 00006: <head runat="server"> 00007: <title>Баг-трекер</title> 00008: </head> 00009: <body> 00010: <form id="form1" runat="server"> 00011: <div> 00012: <div style="text-align:center; font-size:20px"> 00013: <asp:HyperLink ID="HyperLink1" NavigateUrl="~/BugList.aspx" runat="server">Баг-трекер</asp:HyperLink> -> 00014: <asp:Label ID="Label4" runat="server" ></asp:Label></div> 00015: <div style="height:10px"></div> 00016: <table width="100%"> 00017: <tr><td> 00018: <asp:Label ID="Label2" runat="server" ></asp:Label></td></tr> 00019: <tr><td> 00020: <asp:HyperLink ID="HyperLink3" runat="server"></asp:HyperLink></td></tr> 00021: <tr><td> 00022: <asp:Image ID="Image1" runat="server" /></td></tr> 00023: <tr><td> 00024: <asp:Label ID="Label3" runat="server" ></asp:Label></td></tr> 00025: </table> 00026: <div style="height:10px"></div> 00027: <asp:GridView ID="GridView1" runat="server" AllowPaging="True" 00028: AutoGenerateColumns="False" DataMember="DefaultView" DataKeyNames="i" 00029: DataSourceID="GetComment" PageSize="20" Width="100%"> 00030: <Columns> 00031: <asp:TemplateField HeaderText="State"> 00032: <ItemTemplate> 00033: <asp:ImageButton ID="ImageButton1" Width="50" Height="50" runat="server" CommandArgument='<%# Eval("i") %>' /> 00034: </ItemTemplate> 00035: </asp:TemplateField> 00036: <asp:TemplateField > 00037: <ItemTemplate> 00038: <asp:Label ID="KTO" runat="server"></asp:Label> 00039: </ItemTemplate> 00040: </asp:TemplateField> 00041: <asp:TemplateField HeaderText="Bug/Task"> 00042: <ItemTemplate> 00043: <asp:HyperLink ID="HyperLink2" runat="server" Text='<%# Eval("Comment") %>'></asp:HyperLink> 00044: </ItemTemplate> 00045: </asp:TemplateField> 00046: 00047: </Columns> 00048: </asp:GridView> 00049: <div style="height:10px"></div> 00050: <table><tr><td> 00051: <asp:ImageButton ID="ImageButton2" runat="server" Height="50px" 00052: ImageUrl="~/BugImage/Circle.gif" 00053: ToolTip="Добавить сообщение или изменить состояние." Width="50px" /> 00054: </td><td> 00055: Добавить сообщение или изменить состояние.</td> 00056: </tr></table> 00057: </div> 00058: <asp:SqlDataSource ID="GetBug" runat="server" 00059: ConnectionString="<%$ ConnectionStrings:SQLServer_ConnectionStrings %>" 00060: SelectCommand="select * from Bugs join BugState on Bugs.ToState=BugState.i where Bugs.i=@i"> 00061: <SelectParameters> 00062: <asp:QueryStringParameter Name="i" QueryStringField="j" Type="String" /> 00063: </SelectParameters> 00064: </asp:SqlDataSource> 00065: <asp:SqlDataSource ID="GetComment" runat="server" 00066: ConnectionString="<%$ ConnectionStrings:SQLServer_ConnectionStrings %>" 00067: SelectCommand="select BugComment.*,BugState.Image,BugState.Descr from BugComment join BugState on BugState.i=BugComment.NewState where ToBug=@i order by BugComment.i"> 00068: <SelectParameters> 00069: <asp:QueryStringParameter Name="i" QueryStringField="j" Type="String" /> 00070: </SelectParameters> 00071: </asp:SqlDataSource> 00072: </form> 00073: </body> 00074: </html> 00001: Partial Class BugComments 00002: Inherits System.Web.UI.Page 00003: 00004: Protected Sub BugChange_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 00005: If Not IsPostBack Then 00006: If User.Identity.Name = "" Then Response.Redirect("~/Default.aspx") 00007: Label4.Text = "История задачи # " & Request.QueryString("j") 00008: Dim DV1 As Data.DataView = GetBug.Select(New DataSourceSelectArguments) 00009: Dim CurUser As MembershipUser = Membership.GetUser(User.Identity.Name) 00010: If DV1 IsNot Nothing Then 00011: If DV1.Count > 0 Then 00012: HyperLink3.Text = DV1(0)("Page") : HyperLink3.NavigateUrl = DV1(0)("Page") 00013: Dim User1 As MembershipUser = Membership.GetUser(DV1(0)("ToUser")) 00014: Label2.Text = User1.UserName & " (" & DV1(0)("CrDate") & ")" 00015: Label3.Text = DV1(0)("TXT") 00016: If IsDBNull(DV1(0)("ToImage")) Then 00017: Image1.Visible = False 00018: Else 00019: If DV1(0)("ToImage") = "нет" Then 00020: Image1.Visible = False 00021: Else 00022: Image1.ImageUrl = "~/BugImage/" & DV1(0)("ToImage") 00023: End If 00024: End If 00025: 00026: End If 00027: End If 00028: End If 00029: End Sub 00030: 00031: Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound 00032: If e.Row.DataItem IsNot Nothing Then 00033: Dim KTO As Label = CType(e.Row.FindControl("KTO"), Label) 00034: Dim User1 As MembershipUser = Membership.GetUser(e.Row.DataItem("ToUser")) 00035: KTO.Text = User1.UserName & " (" & e.Row.DataItem("Date") & ")" 00036: Dim ImageButton1 As ImageButton = CType(e.Row.FindControl("ImageButton1"), ImageButton) 00037: ImageButton1.ToolTip = e.Row.DataItem("Descr") 00038: ImageButton1.ImageUrl = "~/BugImage/" & e.Row.DataItem("Image") 00039: Dim HyperLink2 As HyperLink = CType(e.Row.FindControl("HyperLink2"), HyperLink) 00040: If Not IsDBNull(e.Row.DataItem("ToImage")) Then 00041: If e.Row.DataItem("ToImage") <> "нет" Then 00042: ImageButton1.PostBackUrl = "~/BugComment.aspx?i=" & User1.ProviderUserKey.ToString & "&j=" & Request.QueryString("j") & "&k=" & e.Row.DataItem("i") 00043: HyperLink2.NavigateUrl = "~/BugComment.aspx?i=" & User1.ProviderUserKey.ToString & "&j=" & Request.QueryString("j") & "&k=" & e.Row.DataItem("i") 00044: End If 00045: End If 00046: End If 00047: End Sub 00048: 00049: 00050: Protected Sub ImageButton2_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles ImageButton2.Click 00051: Dim CurUser As MembershipUser = Membership.GetUser(User.Identity.Name) 00052: Response.Redirect("~/BugChange.aspx?i=" & CurUser.ProviderUserKey.ToString & "&j=" & Request.QueryString("j")) 00053: End Sub 00054: 00055: End Class
После того, как вы создадите в свое базе три таблички, добавите в конфиг строчку, ссылающуюся на базу с этими тремя табличками - добавьте в свой проект эти пять форм и создайте в своем сайте поддиректорию BugImage. В эту поддиректорию вкачайте вот эти рисунки.
Впоследствии я расширил описанную тут прогу. Во-первых, она стала многопользовательским отдельным приложением (а не просто каталогом внутри проекта - как это описано на этой страничке), добавил важную кнопку NEW - те по каким топикам идут последние обсуждения, публичные и приватные проекты, почтовые оповещения и так далее.
|