diff --git a/WebHandler/ServiceTrackerWebHandler.cs b/WebHandler/ServiceTrackerWebHandler.cs index b5e3a0f..080824b 100644 --- a/WebHandler/ServiceTrackerWebHandler.cs +++ b/WebHandler/ServiceTrackerWebHandler.cs @@ -13,14 +13,8 @@ namespace Disco.Plugins.ServiceTracker.WebHandler { private ServiceTrackerDataStore GetDataStore() { - var dataPath = PluginConfigurationHandler.GetPluginDataDirectory( - HostController.HttpContext.Application["Disco.Plugins.ServiceTracker"] as Plugin - ?? new ServiceTrackerPlugin()); - if (string.IsNullOrEmpty(dataPath)) - { - dataPath = System.IO.Path.Combine( - AppDomain.CurrentDomain.BaseDirectory, "App_Data", "Plugins", "Disco.Plugins.ServiceTracker"); - } + var dataPath = System.IO.Path.Combine( + AppDomain.CurrentDomain.BaseDirectory, "App_Data", "Plugins", "Disco.Plugins.ServiceTracker"); return new ServiceTrackerDataStore(dataPath); } @@ -77,7 +71,7 @@ namespace Disco.Plugins.ServiceTracker.WebHandler DateTime etaParsed; if (DateTime.TryParse(HostController.Request.Form["eta"], out etaParsed)) eta = etaParsed; - var currentUser = HostController.HttpContext.User?.Identity?.Name ?? "system"; + var currentUser = GetCurrentUser(); service.UpdateTicket(jobId, priorityId, locationId, techId, eta, status, summary, currentUser); return new RedirectResult("/Plugin/Disco.Plugins.ServiceTracker/Dashboard"); } @@ -93,7 +87,7 @@ namespace Disco.Plugins.ServiceTracker.WebHandler 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 currentUser = GetCurrentUser(); service.AddNote(jobId, currentUser, currentUser, content, noteType); return new RedirectResult("/Plugin/Disco.Plugins.ServiceTracker/Detail?id=" + jobId); } @@ -127,19 +121,28 @@ namespace Disco.Plugins.ServiceTracker.WebHandler sb.AppendLine("JobId,Device,User,Priority,Location,Status,AssignedTech,OpenedDate,ETA,SlaDeadline,SlaBreached,AgeDays,Summary,NoteCount"); foreach (var t in model.Tiles) { + var etaStr = t.EstimatedCompletion.HasValue ? t.EstimatedCompletion.Value.ToString("yyyy-MM-dd") : ""; + var slaStr = t.SlaDeadline.HasValue ? t.SlaDeadline.Value.ToString("yyyy-MM-dd HH:mm") : ""; 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)); + etaStr, slaStr, 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 }; } + // --- Helpers --- + + private string GetCurrentUser() + { + if (HostController.HttpContext.User != null && HostController.HttpContext.User.Identity != null) + return HostController.HttpContext.User.Identity.Name ?? "system"; + return "system"; + } + private ActionResult HtmlResult(string html) { return new ContentResult { Content = html, ContentType = "text/html", ContentEncoding = Encoding.UTF8 }; @@ -147,15 +150,50 @@ namespace Disco.Plugins.ServiceTracker.WebHandler private string Csv(string v) { return "\"" + (v ?? "").Replace("\"", "\"\"") + "\""; } private string H(string v) { return string.IsNullOrEmpty(v) ? "" : HttpUtility.HtmlEncode(v); } + // --- Safe accessors for job navigation properties (C#5 compatible) --- + private string SafeDeviceDomainId(Disco.Models.Repository.Job job) + { + return job.Device != null ? job.Device.DeviceDomainId : null; + } + private string SafeDeviceModelDesc(Disco.Models.Repository.Job job) + { + return (job.Device != null && job.Device.DeviceModel != null) ? job.Device.DeviceModel.Description : null; + } + private string SafeUserDisplay(Disco.Models.Repository.Job job) + { + return job.User != null ? job.User.DisplayName : job.UserId; + } + private string SafeJobTypeDesc(Disco.Models.Repository.Job job) + { + return job.JobType != null ? job.JobType.Description : job.JobTypeId; + } + private string SafeTechDisplay(Disco.Models.Repository.Job job) + { + return job.OpenedTechUser != null ? job.OpenedTechUser.DisplayName : job.OpenedTechUserId; + } + private string SafeTicketStr(ServiceTicket ticket, string field) + { + if (ticket == null) return null; + switch (field) + { + case "PriorityId": return ticket.PriorityId; + case "LocationId": return ticket.LocationId; + case "AssignedTechId": return ticket.AssignedTechId; + case "StatusOverride": return ticket.StatusOverride; + case "Summary": return ticket.Summary; + default: return null; + } + } + + // --- HTML Builders --- + private string BuildDashboardPage(DashboardViewModel model) { var pluginUrl = "/Plugin/Disco.Plugins.ServiceTracker"; var sb = new StringBuilder(); sb.Append("
"); sb.Append("| Device | " + H(job.DeviceSerialNumber) + (job.Device?.DeviceDomainId != null ? " (" + H(job.Device.DeviceDomainId) + ")" : "") + " |
|---|---|
| Model | " + H(job.Device?.DeviceModel?.Description) + " |
| User | " + H(job.User?.DisplayName ?? job.UserId) + " |
| Type | " + H(job.JobType?.Description ?? job.JobTypeId) + " |
| Opened | " + job.OpenedDate.ToString("dd MMM yyyy HH:mm") + " by " + H(job.OpenedTechUser?.DisplayName ?? job.OpenedTechUserId) + " |
| Device | " + H(job.DeviceSerialNumber) + (domainId != null ? " (" + H(domainId) + ")" : "") + " |
| Model | " + H(SafeDeviceModelDesc(job)) + " |
| User | " + H(SafeUserDisplay(job)) + " |
| Type | " + H(SafeJobTypeDesc(job)) + " |
| Opened | " + job.OpenedDate.ToString("dd MMM yyyy HH:mm") + " by " + H(SafeTechDisplay(job)) + " |
| Expected Close | " + job.ExpectedClosedDate.Value.ToString("dd MMM yyyy") + " |
No notes yet.
"); + } sb.Append("