generated from noisedestroyers/claude
364 lines
13 KiB
C#
364 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Security.Policy;
|
|
using System.Text;
|
|
using System.Xml;
|
|
using System.Xml.Serialization;
|
|
|
|
namespace FogbugzWrapper
|
|
{
|
|
public class FogbugzClient
|
|
{
|
|
public string Token { get; } = "1u4thrqm93uqpfr8ptbj2bc112gseo";
|
|
public static string FogbugzURL { get; set; }
|
|
private bool _loggedOn = false;
|
|
|
|
public string FogbugzLogDir { get; set; } = "FogbugzLog\\";
|
|
|
|
public bool IsLoggedIn()
|
|
{
|
|
return _loggedOn;
|
|
}
|
|
|
|
public FogbugzClient()
|
|
{
|
|
}
|
|
public FogbugzClient(string uRL, string token)
|
|
{
|
|
Init(uRL);
|
|
Token = token;
|
|
_loggedOn = LogOn();
|
|
}
|
|
public FogbugzClient(string uRL, string email, string password)
|
|
{
|
|
Init(uRL);
|
|
var doc = new XmlDocument();
|
|
var resp = Command($"logon&email={System.Net.WebUtility.UrlEncode(email)}&password={password}");
|
|
doc.LoadXml(resp);
|
|
|
|
Token = doc.SelectSingleNode("response").FirstChild.InnerText;
|
|
_loggedOn = LogOn();
|
|
}
|
|
private void Init(string uRL)
|
|
{
|
|
if (!Directory.Exists($"{FogbugzLogDir}"))
|
|
{
|
|
Directory.CreateDirectory($"{FogbugzLogDir}");
|
|
}
|
|
FogbugzURL = uRL;
|
|
}
|
|
|
|
private string TokenedCommand(string command)
|
|
{
|
|
return Command($"{command}&token={Token}");
|
|
}
|
|
|
|
private string Command(string command)
|
|
{
|
|
// Create a request using a URL that can receive a post.
|
|
WebRequest request = WebRequest.Create(FogbugzURL);
|
|
request.Proxy = null;
|
|
// Set the Method property of the request to POST.
|
|
request.Method = "POST";
|
|
|
|
// Create POST data and convert it to a byte array.
|
|
string postData = $"cmd={command}";
|
|
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
|
|
|
|
// Set the ContentType property of the WebRequest.
|
|
request.ContentType = "application/x-www-form-urlencoded";
|
|
// Set the ContentLength property of the WebRequest.
|
|
request.ContentLength = byteArray.Length;
|
|
|
|
// Get the request stream.
|
|
Stream dataStream = request.GetRequestStream();
|
|
// Write the data to the request stream.
|
|
dataStream.Write(byteArray, 0, byteArray.Length);
|
|
// Close the Stream object.
|
|
dataStream.Close();
|
|
|
|
// Get the response.
|
|
var response = request.GetResponse();
|
|
// Display the status.
|
|
//Console.WriteLine(((HttpWebResponse)response).StatusDescription);
|
|
|
|
var responseFromServer = string.Empty;
|
|
// Get the stream containing content returned by the server.
|
|
// The using block ensures the stream is automatically closed.
|
|
using (dataStream = response.GetResponseStream())
|
|
{
|
|
// Open the stream using a StreamReader for easy access.
|
|
StreamReader reader = new StreamReader(dataStream);
|
|
// Read the content.
|
|
responseFromServer = reader.ReadToEnd();
|
|
// Display the content.
|
|
//Console.WriteLine(responseFromServer);
|
|
}
|
|
// Close the response.
|
|
response.Close();
|
|
return responseFromServer;
|
|
}
|
|
|
|
public string GetArea(int bugNumber)
|
|
{
|
|
var doc = new XmlDocument();
|
|
var resp = TokenedCommand($"search&q={bugNumber}&cols=sArea");
|
|
doc.LoadXml(resp);
|
|
|
|
return doc.SelectSingleNode("response").FirstChild.FirstChild.FirstChild.InnerText;
|
|
}
|
|
|
|
public void CreateNewTicket(string projectName, string projArea, string title, string description, string assignedTo)
|
|
{
|
|
var doc = new XmlDocument();
|
|
var resp = TokenedCommand($"new&sProject={projectName}&sArea={projArea}&sTitle={title}&sEvent={description}&sPersonAssignedTo={assignedTo}&fRichText=1");
|
|
doc.LoadXml(resp);
|
|
|
|
//return doc.SelectSingleNode("response").FirstChild.FirstChild.FirstChild.InnerText;
|
|
}
|
|
|
|
public string GetTitle(int bugNumber)
|
|
{
|
|
var doc = new XmlDocument();
|
|
var resp = TokenedCommand($"search&q={bugNumber}&cols=sTitle");
|
|
doc.LoadXml(resp);
|
|
|
|
return doc.SelectSingleNode("response").FirstChild.FirstChild.FirstChild.InnerText;
|
|
}
|
|
|
|
public string GetProject(int bugNumber)
|
|
{
|
|
var doc = new XmlDocument();
|
|
var resp = TokenedCommand($"search&q={bugNumber}&cols=sProject");
|
|
doc.LoadXml(resp);
|
|
|
|
return doc.SelectSingleNode("response").FirstChild.FirstChild.FirstChild.InnerText;
|
|
}
|
|
public void TouchCase(int caseIdx)
|
|
{
|
|
TokenedCommand($"edit&ixBug={caseIdx}&sEvent=Touched");
|
|
}
|
|
public void ResolveAndClose(int caseIdx)
|
|
{
|
|
TokenedCommand($"resolve&ixBug={caseIdx}&sEvent=ResolvedByManuscriptEdit");
|
|
TokenedCommand($"close&ixBug={caseIdx}&sEvent=ClosedByManuscriptEdit");
|
|
}
|
|
public ProjectResponse GetProjects()
|
|
{
|
|
var resp = TokenedCommand($"listProjects");
|
|
var serializer = new XmlSerializer(typeof(ProjectResponse));
|
|
|
|
using (var reader = new StringReader(resp))
|
|
{
|
|
return (ProjectResponse)serializer.Deserialize(reader);
|
|
}
|
|
}
|
|
|
|
public CasesResponse GetCases(int filter)
|
|
{
|
|
var resp = TokenedCommand($"listCases&sFilter={filter}&cols=ixBug,ixProject,fOpen,sTitle,sProject,sArea,sStatus,dtLastUpdated,events");
|
|
var serializer = new XmlSerializer(typeof(CasesResponse));
|
|
using (var reader = new StringReader(resp))
|
|
{
|
|
return (CasesResponse)serializer.Deserialize(reader);
|
|
}
|
|
}
|
|
public List<FBEvent> GetEvents(int bugNumber)
|
|
{
|
|
var doc = new XmlDocument();
|
|
var resp = TokenedCommand($"search&q={bugNumber}&cols=events,plugin_customfield");
|
|
doc.LoadXml(resp);
|
|
var timeStamps = doc.GetElementsByTagName("dt");
|
|
if (timeStamps.Count == 0) return new List<FBEvent>();
|
|
var lastUpdate = DateTime.Parse(timeStamps.Item(timeStamps.Count - 1).InnerText);
|
|
|
|
if (File.Exists($"{FogbugzLogDir}{bugNumber}.{lastUpdate.Ticks}.xml"))
|
|
{
|
|
return DeSerializeObject<List<FBEvent>>($"{FogbugzLogDir}{bugNumber}.{lastUpdate.Ticks}.xml");
|
|
}
|
|
|
|
var fbEventList = new List<FBEvent>();
|
|
var events = doc.SelectSingleNode("response").FirstChild.FirstChild.FirstChild;
|
|
|
|
foreach (XmlNode eventNode in doc.SelectSingleNode("response").FirstChild.FirstChild.FirstChild)
|
|
{
|
|
fbEventList.Add(new FBEvent(eventNode));
|
|
}
|
|
fbEventList.Reverse();
|
|
SerializeObject(fbEventList, $"{FogbugzLogDir}{bugNumber}.{lastUpdate.Ticks}.xml");
|
|
|
|
return fbEventList;
|
|
}
|
|
public List<ZendeskCase> GetZendeskCases(int updatedMinutes)
|
|
{
|
|
Console.WriteLine($"GetZendeskCases - updatedMinutes:{updatedMinutes}");
|
|
var rt = new List<ZendeskCase>();
|
|
var doc = new XmlDocument();
|
|
if (!IsLoggedIn())
|
|
{
|
|
Console.WriteLine("GetZendeskCases - Not Logged In.");
|
|
return null;
|
|
}
|
|
var resp = TokenedCommand($"search&q=ZendeskTicketNumber:* lastupdated:\"-{updatedMinutes}m..now\"&cols=plugin_customfields_at_fogcreek_com_zendeskxissuea73,events,sStatus");
|
|
doc.LoadXml(resp);
|
|
//Console.WriteLine($"Full Response: {doc.SelectSingleNode("response").InnerText}");
|
|
var zdCases = doc.SelectSingleNode("response").ChildNodes[0];
|
|
if (zdCases == null)
|
|
{
|
|
Console.WriteLine($"GetZendeskCases - zdCases is null");
|
|
return null;
|
|
}
|
|
Console.WriteLine($"GetZendeskCases - zdCases.ChildNodes.Count:{zdCases.ChildNodes.Count}");
|
|
foreach (XmlNode zdNode in zdCases)
|
|
{
|
|
if (0 == zdNode.SelectNodes("events").Count
|
|
|| string.IsNullOrEmpty(zdNode.SelectSingleNode("plugin_customfields_at_fogcreek_com_zendeskxissuea73").InnerText))
|
|
{ continue; }
|
|
var zdNumber = int.Parse(zdNode.SelectSingleNode("plugin_customfields_at_fogcreek_com_zendeskxissuea73").InnerText);
|
|
var fbNumber = int.Parse(zdNode.Attributes["ixBug"].Value);
|
|
var oldFbStatus = FBEvent.FBStatuses.UNKNOWN;
|
|
foreach (XmlNode fbEvent in zdNode.SelectSingleNode("events"))
|
|
{
|
|
var fbLatestEvent = new FBEvent(fbEvent);
|
|
if (DateTime.Parse(fbLatestEvent.TimeStamp) > DateTime.Now.AddMinutes(-updatedMinutes) &&
|
|
fbLatestEvent.Status != oldFbStatus &&
|
|
fbLatestEvent.StatusString != "Edited" &&
|
|
fbLatestEvent.StatusString != "Assigned")
|
|
{
|
|
rt.Add(new ZendeskCase(zdNumber, fbNumber, fbLatestEvent));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
}
|
|
oldFbStatus = fbLatestEvent.Status;
|
|
}
|
|
|
|
}
|
|
return rt;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Serializes an object.
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="serializableObject"></param>
|
|
/// <param name="fileName"></param>
|
|
public void SerializeObject<T>(T serializableObject, string fileName)
|
|
{
|
|
if (serializableObject == null) { return; }
|
|
|
|
try
|
|
{
|
|
XmlDocument xmlDocument = new XmlDocument();
|
|
XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
|
|
using (MemoryStream stream = new MemoryStream())
|
|
{
|
|
serializer.Serialize(stream, serializableObject);
|
|
stream.Position = 0;
|
|
xmlDocument.Load(stream);
|
|
xmlDocument.Save(fileName);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
//Log exception here
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deserializes an xml file into an object list
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="fileName"></param>
|
|
/// <returns></returns>
|
|
public T DeSerializeObject<T>(string fileName)
|
|
{
|
|
if (string.IsNullOrEmpty(fileName)) { return default(T); }
|
|
|
|
T objectOut = default(T);
|
|
|
|
try
|
|
{
|
|
XmlDocument xmlDocument = new XmlDocument();
|
|
xmlDocument.Load(fileName);
|
|
string xmlString = xmlDocument.OuterXml;
|
|
|
|
using (StringReader read = new StringReader(xmlString))
|
|
{
|
|
Type outType = typeof(T);
|
|
|
|
XmlSerializer serializer = new XmlSerializer(outType);
|
|
using (XmlReader reader = new XmlTextReader(read))
|
|
{
|
|
objectOut = (T)serializer.Deserialize(reader);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
//Log exception here
|
|
}
|
|
|
|
return objectOut;
|
|
}
|
|
|
|
public FBEvent.FBStatuses GetStatus(int bugNumber)
|
|
{
|
|
var fbevents = GetEvents(bugNumber);
|
|
|
|
foreach (var e in fbevents)
|
|
{
|
|
if (e.Status != FBEvent.FBStatuses.UNKNOWN)
|
|
{
|
|
return e.Status;
|
|
}
|
|
}
|
|
return FBEvent.FBStatuses.UNKNOWN;
|
|
}
|
|
|
|
public string GetReleaseNote(int bugNumber)
|
|
{
|
|
var fbevents = GetEvents(bugNumber);
|
|
|
|
foreach (var e in fbevents)
|
|
{
|
|
if (!string.IsNullOrEmpty(e.ReleaseNote))
|
|
{
|
|
return e.ReleaseNote;
|
|
}
|
|
}
|
|
return string.Empty;
|
|
}
|
|
|
|
public int GetZendeskNumber(int bugNumber)
|
|
{
|
|
var fbevents = GetEvents(bugNumber);
|
|
|
|
foreach (var e in fbevents)
|
|
{
|
|
if (0 != e.ZendeskNumber)
|
|
{
|
|
return e.ZendeskNumber;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
public bool LogOn()
|
|
{
|
|
_loggedOn = true;
|
|
return _loggedOn;
|
|
}
|
|
|
|
public void LogOff()
|
|
{
|
|
var resp = TokenedCommand("logoff");
|
|
_loggedOn = false;
|
|
}
|
|
}
|
|
} |