using Disco.Plugins.ServiceTracker.Models;
using Disco.Plugins.ServiceTracker.Services;
using Disco.Services.Plugins;
using System;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
namespace Disco.Plugins.ServiceTracker.WebHandler
{
public class ServiceTrackerWebHandler : PluginWebHandler
{
private ServiceTrackerDataStore GetDataStore()
{
var dataPath = PluginConfigurationHandler.GetPluginDataDirectory(
HostController.HttpContext.Application["Disco.Plugins.ServiceTracker"] as Plugin
?? new ServiceTrackerPlugin());
// Fallback: use AppData path
if (string.IsNullOrEmpty(dataPath))
{
dataPath = System.IO.Path.Combine(
AppDomain.CurrentDomain.BaseDirectory, "App_Data", "Plugins", "Disco.Plugins.ServiceTracker");
}
return new ServiceTrackerDataStore(dataPath);
}
public override ActionResult ExecuteAction(string ActionName)
{
var action = ActionName != null ? ActionName.ToLower() : "";
switch (action)
{
case "":
case "index":
case "dashboard":
return Dashboard();
case "update":
return UpdateTicket();
case "addnote":
return AddNote();
case "detail":
return TicketDetail();
case "export":
return ExportCsv();
default:
return new HttpNotFoundResult();
}
}
private ActionResult Dashboard()
{
var dataStore = GetDataStore();
var service = new ServiceTrackerService(Database, dataStore);
var filterPriority = HostController.Request.QueryString["priority"];
var filterLocation = HostController.Request.QueryString["location"];
var filterStatus = HostController.Request.QueryString["status"];
var filterTech = HostController.Request.QueryString["tech"];
var sortBy = HostController.Request.QueryString["sort"] ?? "due";
var model = service.BuildDashboard(filterPriority, filterLocation, filterStatus, filterTech, sortBy);
return HtmlResult(BuildDashboardPage(model));
}
private ActionResult UpdateTicket()
{
if (HostController.Request.HttpMethod != "POST")
return new HttpStatusCodeResult(405);
var dataStore = GetDataStore();
var service = new ServiceTrackerService(Database, dataStore);
int jobId;
if (!int.TryParse(HostController.Request.Form["jobId"], out jobId))
return new HttpStatusCodeResult(400);
var priorityId = HostController.Request.Form["priority"];
var locationId = HostController.Request.Form["location"];
var techId = HostController.Request.Form["tech"];
var status = HostController.Request.Form["status"];
var summary = HostController.Request.Form["summary"];
DateTime? eta = null;
DateTime etaParsed;
if (DateTime.TryParse(HostController.Request.Form["eta"], out etaParsed))
eta = etaParsed;
var currentUser = HostController.HttpContext.User?.Identity?.Name ?? "system";
service.UpdateTicket(jobId, priorityId, locationId, techId, eta, status, summary, currentUser);
return new RedirectResult("/Plugin/Disco.Plugins.ServiceTracker/Dashboard");
}
private ActionResult AddNote()
{
if (HostController.Request.HttpMethod != "POST")
return new HttpStatusCodeResult(405);
var dataStore = GetDataStore();
var service = new ServiceTrackerService(Database, dataStore);
int jobId;
if (!int.TryParse(HostController.Request.Form["jobId"], out jobId))
return new HttpStatusCodeResult(400);
var content = HostController.Request.Form["note"];
var noteType = HostController.Request.Form["noteType"] ?? "general";
var currentUser = HostController.HttpContext.User?.Identity?.Name ?? "system";
var userName = currentUser; // Could resolve display name from DB
service.AddNote(jobId, currentUser, userName, content, noteType);
return new RedirectResult("/Plugin/Disco.Plugins.ServiceTracker/Detail?id=" + jobId);
}
private ActionResult TicketDetail()
{
int jobId;
if (!int.TryParse(HostController.Request.QueryString["id"], out jobId))
return new HttpStatusCodeResult(400);
var dataStore = GetDataStore();
var service = new ServiceTrackerService(Database, dataStore);
var config = dataStore.LoadConfig();
// Get the job
var job = Database.Jobs
.Include("Device").Include("Device.DeviceModel")
.Include("User").Include("OpenedTechUser")
.Include("JobType").Include("JobSubTypes")
.Include("JobLogs")
.FirstOrDefault(j => j.Id == jobId);
if (job == null)
return new HttpNotFoundResult();
var ticket = service.GetTicketDetail(jobId);
return HtmlResult(BuildDetailPage(job, ticket, config));
}
private ActionResult ExportCsv()
{
var dataStore = GetDataStore();
var service = new ServiceTrackerService(Database, dataStore);
var model = service.BuildDashboard();
var sb = new StringBuilder();
sb.AppendLine("JobId,Device,User,Priority,Location,Status,AssignedTech,OpenedDate,ETA,SlaDeadline,SlaBreached,AgeDays,Summary,NoteCount");
foreach (var t in model.Tiles)
{
sb.AppendLine(string.Join(",",
t.JobId, Csv(t.DeviceSerialNumber), Csv(t.UserDisplayName),
Csv(t.PriorityName), Csv(t.LocationName), Csv(t.StatusOverride),
Csv(t.AssignedTechName), t.OpenedDate.ToString("yyyy-MM-dd"),
t.EstimatedCompletion?.ToString("yyyy-MM-dd") ?? "",
t.SlaDeadline?.ToString("yyyy-MM-dd HH:mm") ?? "",
t.IsSlaBreached, t.AgeDays, Csv(t.Summary), t.NoteCount));
}
var fileName = "ServiceTracker_Export_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".csv";
HostController.Response.Headers.Add("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
return new ContentResult
{
Content = sb.ToString(),
ContentType = "text/csv",
ContentEncoding = Encoding.UTF8
};
}
// --- HTML Builders ---
private ActionResult HtmlResult(string html)
{
return new ContentResult { Content = html, ContentType = "text/html", ContentEncoding = Encoding.UTF8 };
}
private string Csv(string v) { return "\"" + (v ?? "").Replace("\"", "\"\"") + "\""; }
private string H(string v) { return string.IsNullOrEmpty(v) ? "" : HttpUtility.HtmlEncode(v); }
private string BuildDashboardPage(DashboardViewModel model)
{
var pluginUrl = "/Plugin/Disco.Plugins.ServiceTracker";
var sb = new StringBuilder();
// --- Head ---
sb.Append("