refactor job logs/comments [#145]

This commit is contained in:
Gary Sharp
2025-07-12 16:48:27 +10:00
parent b56e82d5c4
commit 092c6249ee
14 changed files with 575 additions and 638 deletions
+9 -1
View File
@@ -1,10 +1,18 @@
using System.Web.Mvc;
using System.Net;
using System.Web.Mvc;
namespace Disco.Services.Web
{
[HandleError]
public class BaseController : Controller
{
protected static HttpStatusCodeResult Ok(string message = null)
=> StatusCode(HttpStatusCode.OK, message);
protected static HttpStatusCodeResult BadRequest(string message = null)
=> StatusCode(HttpStatusCode.BadRequest, message);
protected static HttpStatusCodeResult StatusCode(HttpStatusCode statusCode, string message = null)
=> new HttpStatusCodeResult(statusCode, message);
}
}
@@ -15,6 +15,7 @@ using Disco.Web.Extensions;
using Disco.Web.Models.Job;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
@@ -78,7 +79,7 @@ namespace Disco.Web.Areas.API.Controllers
#endregion
public virtual ActionResult Update(int id, string key, string value = null, Nullable<bool> redirect = null)
public virtual ActionResult Update(int id, string key, string value = null, bool? redirect = null)
{
try
{
@@ -311,79 +312,79 @@ namespace Disco.Web.Areas.API.Controllers
#region Update Shortcut Methods
[DiscoAuthorize(Claims.Job.Properties.ExpectedClosedDate)]
public virtual ActionResult UpdateExpectedClosedDate(int id, string ExpectedClosedDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateExpectedClosedDate(int id, string ExpectedClosedDate, bool? redirect = null)
{
return Update(id, pExpectedClosedDate, ExpectedClosedDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.DeviceHeldLocation)]
public virtual ActionResult UpdateDeviceHeldLocation(int id, string DeviceHeldLocation, Nullable<bool> redirect = null)
public virtual ActionResult UpdateDeviceHeldLocation(int id, string DeviceHeldLocation, bool? redirect = null)
{
return Update(id, pDeviceHeldLocation, DeviceHeldLocation, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.Flags)]
public virtual ActionResult UpdateFlags(int id, string Flags, Nullable<bool> redirect = null)
public virtual ActionResult UpdateFlags(int id, string Flags, bool? redirect = null)
{
return Update(id, pFlags, Flags, redirect);
}
#region NonWarranty
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.AccountingChargeRequired)]
public virtual ActionResult UpdateNonWarrantyAccountingChargeRequired(int id, string AccountingChargeRequiredDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateNonWarrantyAccountingChargeRequired(int id, string AccountingChargeRequiredDate, bool? redirect = null)
{
return Update(id, pNonWarrantyAccountingChargeRequired, AccountingChargeRequiredDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.AccountingChargeAdded)]
public virtual ActionResult UpdateNonWarrantyAccountingChargeAdded(int id, string AccountingChargeAddedDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateNonWarrantyAccountingChargeAdded(int id, string AccountingChargeAddedDate, bool? redirect = null)
{
return Update(id, pNonWarrantyAccountingChargeAdded, AccountingChargeAddedDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.AccountingChargePaid)]
public virtual ActionResult UpdateNonWarrantyAccountingChargePaid(int id, string AccountingChargePaidDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateNonWarrantyAccountingChargePaid(int id, string AccountingChargePaidDate, bool? redirect = null)
{
return Update(id, pNonWarrantyAccountingChargePaid, AccountingChargePaidDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.PurchaseOrderRaised)]
public virtual ActionResult UpdateNonWarrantyPurchaseOrderRaised(int id, string PurchaseOrderRaisedDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateNonWarrantyPurchaseOrderRaised(int id, string PurchaseOrderRaisedDate, bool? redirect = null)
{
return Update(id, pNonWarrantyPurchaseOrderRaised, PurchaseOrderRaisedDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.PurchaseOrderReference)]
public virtual ActionResult UpdateNonWarrantyPurchaseOrderReference(int id, string PurchaseOrderReference, Nullable<bool> redirect = null)
public virtual ActionResult UpdateNonWarrantyPurchaseOrderReference(int id, string PurchaseOrderReference, bool? redirect = null)
{
return Update(id, pNonWarrantyPurchaseOrderReference, PurchaseOrderReference, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.PurchaseOrderSent)]
public virtual ActionResult UpdateNonWarrantyPurchaseOrderSent(int id, string PurchaseOrderSentDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateNonWarrantyPurchaseOrderSent(int id, string PurchaseOrderSentDate, bool? redirect = null)
{
return Update(id, pNonWarrantyPurchaseOrderSent, PurchaseOrderSentDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InvoiceReceived)]
public virtual ActionResult UpdateNonWarrantyInvoiceReceived(int id, string InvoiceReceivedDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateNonWarrantyInvoiceReceived(int id, string InvoiceReceivedDate, bool? redirect = null)
{
return Update(id, pNonWarrantyInvoiceReceived, InvoiceReceivedDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.RepairerName)]
public virtual ActionResult UpdateNonWarrantyRepairerName(int id, string RepairerName, Nullable<bool> redirect = null)
public virtual ActionResult UpdateNonWarrantyRepairerName(int id, string RepairerName, bool? redirect = null)
{
return Update(id, pNonWarrantyRepairerName, RepairerName, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.RepairerLoggedDate)]
public virtual ActionResult UpdateNonWarrantyRepairerLoggedDate(int id, string RepairerLoggedDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateNonWarrantyRepairerLoggedDate(int id, string RepairerLoggedDate, bool? redirect = null)
{
return Update(id, pNonWarrantyRepairerLoggedDate, RepairerLoggedDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.RepairerReference)]
public virtual ActionResult UpdateNonWarrantyRepairerReference(int id, string RepairerReference, Nullable<bool> redirect = null)
public virtual ActionResult UpdateNonWarrantyRepairerReference(int id, string RepairerReference, bool? redirect = null)
{
return Update(id, pNonWarrantyRepairerReference, RepairerReference, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.RepairerCompletedDate)]
public virtual ActionResult UpdateNonWarrantyRepairerCompletedDate(int id, string RepairerCompletedDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateNonWarrantyRepairerCompletedDate(int id, string RepairerCompletedDate, bool? redirect = null)
{
return Update(id, pNonWarrantyRepairerCompletedDate, RepairerCompletedDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.IsInsuranceClaim)]
public virtual ActionResult UpdateNonWarrantyIsInsuranceClaim(int id, bool IsInsuranceClaim, Nullable<bool> redirect = null)
public virtual ActionResult UpdateNonWarrantyIsInsuranceClaim(int id, bool IsInsuranceClaim, bool? redirect = null)
{
return Update(id, pNonWarrantyIsInsuranceClaim, IsInsuranceClaim.ToString(), redirect);
}
@@ -392,92 +393,92 @@ namespace Disco.Web.Areas.API.Controllers
#region Insurance
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsuranceLossOrDamageDate(int id, string LossOrDamageDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsuranceLossOrDamageDate(int id, string LossOrDamageDate, bool? redirect = null)
{
return Update(id, pInsuranceLossOrDamageDate, LossOrDamageDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsuranceEventLocation(int id, string EventLocation, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsuranceEventLocation(int id, string EventLocation, bool? redirect = null)
{
return Update(id, pInsuranceEventLocation, EventLocation, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsuranceDescription(int id, string Description, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsuranceDescription(int id, string Description, bool? redirect = null)
{
return Update(id, pInsuranceDescription, Description, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsuranceThirdPartyCaused(int id, string ThirdPartyCaused, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsuranceThirdPartyCaused(int id, string ThirdPartyCaused, bool? redirect = null)
{
return Update(id, pInsuranceThirdPartyCaused, ThirdPartyCaused, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsuranceThirdPartyCausedName(int id, string ThirdPartyCausedName, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsuranceThirdPartyCausedName(int id, string ThirdPartyCausedName, bool? redirect = null)
{
return Update(id, pInsuranceThirdPartyCausedName, ThirdPartyCausedName, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsuranceThirdPartyCausedWhy(int id, string ThirdPartyCausedWhy, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsuranceThirdPartyCausedWhy(int id, string ThirdPartyCausedWhy, bool? redirect = null)
{
return Update(id, pInsuranceThirdPartyCausedWhy, ThirdPartyCausedWhy, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsuranceWitnessesNamesAddresses(int id, string WitnessesNamesAddresses, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsuranceWitnessesNamesAddresses(int id, string WitnessesNamesAddresses, bool? redirect = null)
{
return Update(id, pInsuranceWitnessesNamesAddresses, WitnessesNamesAddresses, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsuranceBurglaryTheftMethodOfEntry(int id, string BurglaryTheftMethodOfEntry, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsuranceBurglaryTheftMethodOfEntry(int id, string BurglaryTheftMethodOfEntry, bool? redirect = null)
{
return Update(id, pInsuranceBurglaryTheftMethodOfEntry, BurglaryTheftMethodOfEntry, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsurancePropertyLastSeenDate(int id, string PropertyLastSeenDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsurancePropertyLastSeenDate(int id, string PropertyLastSeenDate, bool? redirect = null)
{
return Update(id, pInsurancePropertyLastSeenDate, PropertyLastSeenDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsurancePoliceNotified(int id, string PoliceNotified, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsurancePoliceNotified(int id, string PoliceNotified, bool? redirect = null)
{
return Update(id, pInsurancePoliceNotified, PoliceNotified, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsurancePoliceNotifiedStation(int id, string PoliceNotifiedStation, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsurancePoliceNotifiedStation(int id, string PoliceNotifiedStation, bool? redirect = null)
{
return Update(id, pInsurancePoliceNotifiedStation, PoliceNotifiedStation, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsurancePoliceNotifiedDate(int id, string PoliceNotifiedDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsurancePoliceNotifiedDate(int id, string PoliceNotifiedDate, bool? redirect = null)
{
return Update(id, pInsurancePoliceNotifiedDate, PoliceNotifiedDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsurancePoliceNotifiedCrimeReportNo(int id, string PoliceNotifiedCrimeReportNo, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsurancePoliceNotifiedCrimeReportNo(int id, string PoliceNotifiedCrimeReportNo, bool? redirect = null)
{
return Update(id, pInsurancePoliceNotifiedCrimeReportNo, PoliceNotifiedCrimeReportNo, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsuranceRecoverReduceAction(int id, string RecoverReduceAction, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsuranceRecoverReduceAction(int id, string RecoverReduceAction, bool? redirect = null)
{
return Update(id, pInsuranceRecoverReduceAction, RecoverReduceAction, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsuranceOtherInterestedParties(int id, string OtherInterestedParties, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsuranceOtherInterestedParties(int id, string OtherInterestedParties, bool? redirect = null)
{
return Update(id, pInsuranceOtherInterestedParties, OtherInterestedParties, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceDetails)]
public virtual ActionResult UpdateInsuranceDateOfPurchase(int id, string DateOfPurchase, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsuranceDateOfPurchase(int id, string DateOfPurchase, bool? redirect = null)
{
return Update(id, pInsuranceDateOfPurchase, DateOfPurchase, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceClaimFormSent)]
public virtual ActionResult UpdateInsuranceClaimFormSentDate(int id, string ClaimFormSentDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsuranceClaimFormSentDate(int id, string ClaimFormSentDate, bool? redirect = null)
{
return Update(id, pInsuranceClaimFormSentDate, ClaimFormSentDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.NonWarrantyProperties.InsuranceClaimFormSent)]
public virtual ActionResult UpdateInsuranceClaimFormSentUserId(int id, string ClaimFormSentUserId, Nullable<bool> redirect = null)
public virtual ActionResult UpdateInsuranceClaimFormSentUserId(int id, string ClaimFormSentUserId, bool? redirect = null)
{
return Update(id, pInsuranceClaimFormSentUserId, ClaimFormSentUserId, redirect);
}
@@ -486,22 +487,22 @@ namespace Disco.Web.Areas.API.Controllers
#region Warranty
[DiscoAuthorize(Claims.Job.Properties.WarrantyProperties.ExternalName)]
public virtual ActionResult UpdateWarrantyExternalName(int id, string ExternalName, Nullable<bool> redirect = null)
public virtual ActionResult UpdateWarrantyExternalName(int id, string ExternalName, bool? redirect = null)
{
return Update(id, pWarrantyExternalName, ExternalName, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.WarrantyProperties.ExternalLoggedDate)]
public virtual ActionResult UpdateWarrantyExternalLoggedDate(int id, string ExternalLoggedDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateWarrantyExternalLoggedDate(int id, string ExternalLoggedDate, bool? redirect = null)
{
return Update(id, pWarrantyExternalLoggedDate, ExternalLoggedDate, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.WarrantyProperties.ExternalReference)]
public virtual ActionResult UpdateWarrantyExternalReference(int id, string ExternalReference, Nullable<bool> redirect = null)
public virtual ActionResult UpdateWarrantyExternalReference(int id, string ExternalReference, bool? redirect = null)
{
return Update(id, pWarrantyExternalReference, ExternalReference, redirect);
}
[DiscoAuthorize(Claims.Job.Properties.WarrantyProperties.ExternalCompletedDate)]
public virtual ActionResult UpdateWarrantyExternalCompletedDate(int id, string ExternalCompletedDate, Nullable<bool> redirect = null)
public virtual ActionResult UpdateWarrantyExternalCompletedDate(int id, string ExternalCompletedDate, bool? redirect = null)
{
return Update(id, pWarrantyExternalCompletedDate, ExternalCompletedDate, redirect);
}
@@ -598,7 +599,7 @@ namespace Disco.Web.Areas.API.Controllers
{
if (!job.Flags.HasValue || (long)job.Flags.Value != flags)
{
job.Flags = (Disco.Models.Repository.Job.UserManagementFlags)flags;
job.Flags = (Job.UserManagementFlags)flags;
Database.SaveChanges();
}
}
@@ -623,7 +624,7 @@ namespace Disco.Web.Areas.API.Controllers
job.JobMetaNonWarranty.IsInsuranceClaim = bIsInsuranceClaim;
if (job.JobMetaInsurance == null)
{
var jmi = new Disco.Models.Repository.JobMetaInsurance();
var jmi = new JobMetaInsurance();
jmi.JobId = job.Id;
if (job.Device.DeviceBatch != null)
@@ -1444,7 +1445,7 @@ namespace Disco.Web.Areas.API.Controllers
#region Job Actions
[DiscoAuthorize(Claims.Job.Actions.UpdateSubTypes)]
public virtual ActionResult UpdateSubTypes(int id, List<string> SubTypes = null, Nullable<bool> AddComponents = null, Nullable<bool> redirect = null)
public virtual ActionResult UpdateSubTypes(int id, List<string> SubTypes = null, bool? AddComponents = null, bool? redirect = null)
{
try
{
@@ -1480,7 +1481,7 @@ namespace Disco.Web.Areas.API.Controllers
}
[DiscoAuthorize(Claims.Job.Properties.Flags)]
public virtual ActionResult UpdateFlag(int id, long? Flag, string Reason, Nullable<bool> redirect = null)
public virtual ActionResult UpdateFlag(int id, long? Flag, string Reason, bool? redirect = null)
{
try
{
@@ -1502,7 +1503,7 @@ namespace Disco.Web.Areas.API.Controllers
{ // Remove Flag
if (flagStatus.Item2)
{
job.Flags = (Disco.Models.Repository.Job.UserManagementFlags)((long)(job.Flags ?? 0) ^ (flag * -1));
job.Flags = (Job.UserManagementFlags)((long)(job.Flags ?? 0) ^ (flag * -1));
Database.SaveChanges();
}
}
@@ -1510,7 +1511,7 @@ namespace Disco.Web.Areas.API.Controllers
{ // Add Flag
if (!flagStatus.Item2)
{
job.Flags = (Disco.Models.Repository.Job.UserManagementFlags)((long)(job.Flags ?? 0) | flag);
job.Flags = (Job.UserManagementFlags)((long)(job.Flags ?? 0) | flag);
}
// Write Reason
JobLog jobLog = new JobLog()
@@ -1546,7 +1547,7 @@ namespace Disco.Web.Areas.API.Controllers
}
[DiscoAuthorize(Claims.Job.Properties.WaitingForUserAction)]
public virtual ActionResult WaitingForUserAction(int id, string Reason, Nullable<bool> redirect = null)
public virtual ActionResult WaitingForUserAction(int id, string Reason, bool? redirect = null)
{
try
{
@@ -1577,7 +1578,7 @@ namespace Disco.Web.Areas.API.Controllers
}
[DiscoAuthorize(Claims.Job.Properties.NotWaitingForUserAction)]
public virtual ActionResult NotWaitingForUserAction(int id, string Resolution, Nullable<bool> redirect = null)
public virtual ActionResult NotWaitingForUserAction(int id, string Resolution, bool? redirect = null)
{
try
{
@@ -1681,7 +1682,7 @@ namespace Disco.Web.Areas.API.Controllers
}
[DiscoAuthorize(Claims.Job.Actions.ForceClose)]
public virtual ActionResult ForceClose(int id, string Reason, Nullable<bool> redirect = null)
public virtual ActionResult ForceClose(int id, string Reason, bool? redirect = null)
{
var j = Database.Jobs.Find(id);
Database.Configuration.LazyLoadingEnabled = true;
@@ -1810,7 +1811,8 @@ namespace Disco.Web.Areas.API.Controllers
#region Job Comments
[HttpPost, ValidateAntiForgeryToken, DiscoAuthorize(Claims.Job.Actions.Create)]
[DiscoAuthorize(Claims.Job.Actions.Create)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult InitialComments(CreateModel m)
{
m.UpdateModel(Database, Authorization);
@@ -1819,69 +1821,76 @@ namespace Disco.Web.Areas.API.Controllers
}
[DiscoAuthorize(Claims.Job.ShowLogs)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult Comments(int id)
{
var j = Database.Jobs.Include("JobLogs.TechUser").Where(m => m.Id == id).FirstOrDefault();
if (j != null)
{
var c = new Models.Job.CommentsModel() { Result = "OK" };
c.Comments = j.JobLogs.OrderByDescending(m => m.Timestamp).Select(jl => Models.Job._CommentModel.FromJobLog(jl)).ToList();
var job = Database.Jobs
.Include(j => j.JobLogs.Select(l => l.TechUser))
.Where(j => j.Id == id).FirstOrDefault();
if (job == null)
return BadRequest("Invalid Job Number");
var results = job.JobLogs.OrderByDescending(m => m.Timestamp).Select(jl => Models.Shared.CommentModel.FromJobLog(jl)).ToList();
return Json(results);
return Json(c, JsonRequestBehavior.AllowGet);
}
return Json(new Models.Job.CommentsModel() { Result = "Invalid Job Number" }, JsonRequestBehavior.AllowGet);
}
[DiscoAuthorize(Claims.Job.ShowLogs)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult Comment(int id)
{
var jl = Database.JobLogs.Include("TechUser").FirstOrDefault(l => l.Id == id);
if (jl != null)
{
var c = Models.Job._CommentModel.FromJobLog(jl);
var jobLog = Database.JobLogs
.Include(l => l.TechUser)
.FirstOrDefault(l => l.Id == id);
return Json(c, JsonRequestBehavior.AllowGet);
}
return Json(new Models.Job.CommentsModel() { Result = "Invalid Comment Id" }, JsonRequestBehavior.AllowGet);
if (jobLog == null)
return BadRequest("Invalid JobLog Id");
var c = Models.Shared.CommentModel.FromJobLog(jobLog);
return Json(c);
}
[DiscoAuthorize(Claims.Job.Actions.AddLogs)]
public virtual ActionResult CommentPost(int id, string comment)
{
var j = Database.Jobs.Find(id);
if (j != null)
{
var jl = new Disco.Models.Repository.JobLog()
{
JobId = j.Id,
TechUserId = CurrentUser.UserId,
Timestamp = DateTime.Now,
Comments = comment
};
Database.JobLogs.Add(jl);
Database.SaveChanges();
jl = Database.JobLogs.Include("TechUser").Where(m => m.Id == jl.Id).FirstOrDefault();
return Json(new Models.Job.CommentPostModel() { Result = "OK", Comment = Models.Job._CommentModel.FromJobLog(jl) }, JsonRequestBehavior.AllowGet);
}
return Json(new Models.Job.CommentPostModel() { Result = "Invalid Job Number" }, JsonRequestBehavior.AllowGet);
[DiscoAuthorize(Claims.Job.Actions.AddLogs)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult CommentAdd(int id, string comment = null)
{
if (string.IsNullOrWhiteSpace(comment))
return BadRequest("Comment is required");
var job = Database.Jobs.Find(id);
if (job == null)
return BadRequest("Invalid Job Number");
var jl = new JobLog()
{
JobId = job.Id,
TechUserId = CurrentUser.UserId,
Timestamp = DateTime.Now,
Comments = comment
};
Database.JobLogs.Add(jl);
Database.SaveChanges();
return Json(jl.Id);
}
[DiscoAuthorizeAny(Claims.Job.Actions.RemoveAnyLogs, Claims.Job.Actions.RemoveOwnLogs)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult CommentRemove(int id)
{
var jl = Database.JobLogs.Find(id);
if (jl != null)
var jobLog = Database.JobLogs.Find(id);
if (jobLog != null)
{
if (jl.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase))
if (jobLog.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase))
Authorization.RequireAny(Claims.Job.Actions.RemoveAnyLogs, Claims.Job.Actions.RemoveOwnLogs);
else
Authorization.Require(Claims.Job.Actions.RemoveAnyLogs);
Database.JobLogs.Remove(jl);
Database.JobLogs.Remove(jobLog);
Database.SaveChanges();
return Json("OK", JsonRequestBehavior.AllowGet);
}
// Doesn't Exist/Already Deleted - OK
return Json("OK", JsonRequestBehavior.AllowGet);
return Ok();
}
#endregion
@@ -2066,7 +2075,7 @@ namespace Disco.Web.Areas.API.Controllers
Cost = Cost.Substring(Cost.IndexOf("$") + 1);
decimal.TryParse(Cost, out cost);
var jc = new Disco.Models.Repository.JobComponent()
var jc = new JobComponent()
{
JobId = j.Id,
Description = Description,
@@ -1,8 +0,0 @@
namespace Disco.Web.Areas.API.Models.Job
{
public class CommentPostModel
{
public string Result { get; set; }
public _CommentModel Comment { get; set; }
}
}
@@ -1,10 +0,0 @@
using System.Collections.Generic;
namespace Disco.Web.Areas.API.Models.Job
{
public class CommentsModel
{
public string Result { get; set; }
public List<_CommentModel> Comments { get; set; }
}
}
@@ -1,25 +1,28 @@
using System;
using Disco.Models.Repository;
using System;
namespace Disco.Web.Areas.API.Models.Job
namespace Disco.Web.Areas.API.Models.Shared
{
public class _CommentModel
public class CommentModel
{
public int Id { get; set; }
public int JobId { get; set; }
public AttachmentTypes TargetType { get; set; }
public string TargetId { get; set; }
public string AuthorId { get; set; }
public string Author { get; set; }
public DateTime Timestamp { get; set; }
public string Comments { get; set; }
public string HtmlComments { get; set; }
public long TimestampUnixEpoc { get { return this.Timestamp.ToUnixEpoc(); } }
public string TimestampFull { get { return Timestamp.ToFullDateTime(); } }
public long TimestampUnixEpoc => Timestamp.ToUnixEpoc();
public string TimestampFull => Timestamp.ToFullDateTime();
public static _CommentModel FromJobLog(Disco.Models.Repository.JobLog jl)
public static CommentModel FromJobLog(JobLog jl)
{
return new _CommentModel
return new CommentModel
{
Id = jl.Id,
JobId = jl.JobId,
TargetType = AttachmentTypes.Job,
TargetId = jl.JobId.ToString(),
AuthorId = jl.TechUserId,
Author = jl.TechUser.ToString(),
Timestamp = jl.Timestamp,
+8 -3
View File
@@ -4999,9 +4999,14 @@ table th {
table.none {
border: none !important;
}
table.none tr,
table.none td,
table.none th {
table.none > tr > td,
table.none > thead > tr > td,
table.none > tbody > tr > td,
table.none > tfoot > tr > td,
table.none > tr > th,
table.none > thead > tr > th,
table.none > tbody > tr > th,
table.none > tfoot > tr > th {
padding: 0 !important;
margin: 0 !important;
background: none !important;
File diff suppressed because one or more lines are too long
+8 -3
View File
@@ -567,9 +567,14 @@ table th {
table.none {
border: none !important;
}
table.none tr,
table.none td,
table.none th {
table.none > tr > td,
table.none > thead > tr > td,
table.none > tbody > tr > td,
table.none > tfoot > tr > td,
table.none > tr > th,
table.none > thead > tr > th,
table.none > tbody > tr > th,
table.none > tfoot > tr > th {
padding: 0 !important;
margin: 0 !important;
background: none !important;
+7 -5
View File
@@ -519,11 +519,13 @@ table {
table.none {
border: none !important;
tr, td, th {
padding: 0 !important;
margin: 0 !important;
background: none !important;
border: none !important;
& > tr, & > thead > tr, & > tbody > tr, & > tfoot > tr {
& > td, & > th {
padding: 0 !important;
margin: 0 !important;
background: none !important;
border: none !important;
}
}
}
File diff suppressed because one or more lines are too long
+1 -3
View File
@@ -503,10 +503,8 @@
<Compile Include="Areas\API\Models\DocumentTemplate\ImporterUndetectedDataIdLookupModel.cs" />
<Compile Include="Areas\API\Models\DocumentTemplate\ImporterUndetectedFilesModel.cs" />
<Compile Include="Areas\API\Models\Expressions\ValidateExpressionModel.cs" />
<Compile Include="Areas\API\Models\Job\CommentPostModel.cs" />
<Compile Include="Areas\API\Models\Job\CommentsModel.cs" />
<Compile Include="Areas\API\Models\Job\ComponentModel.cs" />
<Compile Include="Areas\API\Models\Job\_CommentModel.cs" />
<Compile Include="Areas\API\Models\Shared\CommentModel.cs" />
<Compile Include="Areas\API\Models\Job\_ComponentModel.cs" />
<Compile Include="Areas\API\Models\Job\_DateChangeModel.cs" />
<Compile Include="Areas\API\Models\Logs\LogEventTypeModel.cs" />
@@ -379,9 +379,9 @@ namespace Disco.Web.Areas.API.Controllers
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult CommentPost()
public virtual System.Web.Mvc.ActionResult CommentAdd()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.CommentPost);
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.CommentAdd);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
@@ -549,7 +549,7 @@ namespace Disco.Web.Areas.API.Controllers
public readonly string InitialComments = "InitialComments";
public readonly string Comments = "Comments";
public readonly string Comment = "Comment";
public readonly string CommentPost = "CommentPost";
public readonly string CommentAdd = "CommentAdd";
public readonly string CommentRemove = "CommentRemove";
public readonly string AttachmentDownload = "AttachmentDownload";
public readonly string AttachmentThumbnail = "AttachmentThumbnail";
@@ -626,7 +626,7 @@ namespace Disco.Web.Areas.API.Controllers
public const string InitialComments = "InitialComments";
public const string Comments = "Comments";
public const string Comment = "Comment";
public const string CommentPost = "CommentPost";
public const string CommentAdd = "CommentAdd";
public const string CommentRemove = "CommentRemove";
public const string AttachmentDownload = "AttachmentDownload";
public const string AttachmentThumbnail = "AttachmentThumbnail";
@@ -1168,11 +1168,11 @@ namespace Disco.Web.Areas.API.Controllers
{
public readonly string id = "id";
}
static readonly ActionParamsClass_CommentPost s_params_CommentPost = new ActionParamsClass_CommentPost();
static readonly ActionParamsClass_CommentAdd s_params_CommentAdd = new ActionParamsClass_CommentAdd();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_CommentPost CommentPostParams { get { return s_params_CommentPost; } }
public ActionParamsClass_CommentAdd CommentAddParams { get { return s_params_CommentAdd; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_CommentPost
public class ActionParamsClass_CommentAdd
{
public readonly string id = "id";
public readonly string comment = "comment";
@@ -2064,15 +2064,15 @@ namespace Disco.Web.Areas.API.Controllers
}
[NonAction]
partial void CommentPostOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, int id, string comment);
partial void CommentAddOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, int id, string comment);
[NonAction]
public override System.Web.Mvc.ActionResult CommentPost(int id, string comment)
public override System.Web.Mvc.ActionResult CommentAdd(int id, string comment)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.CommentPost);
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.CommentAdd);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "comment", comment);
CommentPostOverride(callInfo, id, comment);
CommentAddOverride(callInfo, id, comment);
return callInfo;
}
+103 -116
View File
@@ -29,13 +29,14 @@
@if (canShowLogs)
{
<td id="CommentsContainer">
<div id="Comments" class="@(canAddLogs ? "canAddLogs" : "cannotAddLogs")">
<div id="Comments" class="@(canAddLogs ? "canAddLogs" : "cannotAddLogs") @(canRemoveAnyLogs ? "canRemoveAnyLogs" : "cannotRemoveAnyLogs") @(canRemoveOwnLogs ? "canRemoveOwnLogs" : "cannotRemoveOwnLogs")" data-jobid="@Model.Job.Id" data-addurl="@Url.Action(MVC.API.Job.CommentAdd(Model.Job.Id))" data-removeurl="@Url.Action(MVC.API.Job.CommentRemove())" data-geturl="@Url.Action(MVC.API.Job.Comment())" data-userid="@CurrentUser.UserId">
@Html.AntiForgeryToken()
<div class="commentOutput">
@foreach (var jl in Model.Job.JobLogs.OrderBy(m => m.Timestamp))
{
<div data-logid="@jl.Id">
<span class="author">@jl.TechUser.ToStringFriendly()</span>@if (canRemoveAnyLogs || (canRemoveOwnLogs && jl.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase)))
{<text><span class="remove fa fa-times-circle"></span></text>}<span class="timestamp" data-livestamp="@(jl.Timestamp.ToUnixEpoc())" title="@jl.Timestamp.ToFullDateTime()">@jl.Timestamp.ToFullDateTime()</span>
{<text><span class="remove fa fa-times-circle"></span></text>}<span class="timestamp" data-livestamp="@(jl.Timestamp.ToUnixEpoc())" title="@jl.Timestamp.ToFullDateTime()">@jl.Timestamp.ToFullDateTime()</span>
<div class="comment">@jl.Comments.ToHtmlComment()</div>
</div>
}
@@ -43,8 +44,8 @@
@if (canAddLogs)
{
<div class="commentInput clearfix">
<textarea class="commentInput" placeholder="write comment..." accesskey="l"></textarea>
<span class="action post commentInputPost fa fa-comment disabled" title="Post Comment"></span>
<textarea class="commentInput" placeholder="add comment..." accesskey="l"></textarea>
<span class="action post commentInputPost fa fa-comment disabled" title="Add Comment"></span>
</div>
}
</div>
@@ -87,22 +88,6 @@
}
</tr>
</table>
@if (canShowLogs && (canRemoveAnyLogs || canRemoveOwnLogs))
{
<div id="dialogRemoveLog" class="dialog" title="Remove this Comment?">
<p>
<i class="fa fa-exclamation-triangle fa-lg"></i>&nbsp;Are you sure?
</p>
</div>
}
@if (canShowAttachments && (canRemoveAnyAttachments || canRemoveOwnAttachments))
{
<div id="dialogRemoveAttachment" class="dialog" title="Remove this Attachment?">
<p>
<i class="fa fa-exclamation-triangle fa-lg"></i>&nbsp;Are you sure?
</p>
</div>
}
@if (canShowLogs)
{
<script>
@@ -111,12 +96,12 @@
}
$(function () {
var jobId = parseInt('@(Model.Job.Id)');
//#region Comments
var $Comments = $('#Comments');
var $CommentOutput = $Comments.find('.commentOutput');
var $CommentOutputContainer = $Comments.find('.commentOutputContainer');
const $Comments = $('#Comments');
const jobId = parseInt($Comments.attr('data-jobid'));
const $CommentOutput = $Comments.find('.commentOutput');
const $CommentOutputContainer = $Comments.find('.commentOutputContainer');
window.setTimeout(function () {
$CommentOutput[0].scrollTop = $CommentOutput[0].scrollHeight; // Scroll to Bottom
@@ -131,23 +116,23 @@
{<text>
//#region Add Logs
var $CommentInput = $Comments.find('textarea.commentInput');
$Comments.find('.commentInputPost').click(postComment);
$CommentInput.keypress(function (e) {
const $CommentInput = $Comments.find('textarea.commentInput');
const $CommentInputPost = $Comments.find('.commentInputPost');
$CommentInputPost.on('click', postComment);
$CommentInput.on('keypress', function (e) {
if (e.which == 13 && !e.shiftKey) {
postComment();
return false;
}
});
function postComment() {
if ($Comments.find('.commentInputPost').hasClass('disabled')) {
async function postComment() {
if ($CommentInputPost.hasClass('disabled')) {
alert('Disconnected from the Disco ICT Server, please refresh this page and try again');
return;
}
var comment = $CommentInput.val();
const comment = $CommentInput.val();
if (comment == '') {
alert('Enter a comment to post');
@@ -155,26 +140,23 @@
return;
}
var data = { comment: comment }
$.ajax({
url: '@Url.Action(MVC.API.Job.CommentPost(Model.Job.Id, null))',
dataType: 'json',
data: data,
success: function (d) {
if (d.Result == 'OK') {
// Should be added via Repository Notifications
// addComment(d.Comment, false);
$CommentInput.val('').attr('disabled', false).focus();
} else {
alert('Unable to post comment: ' + d.Result);
$CommentInput.attr('disabled', false);
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Unable to post comment: ' + textStatus);
$CommentInput.attr('disabled', false);
}
$CommentInput.prop('disabled', true);
const formData = new FormData();
formData.append('__RequestVerificationToken', $Comments.find('input[name="__RequestVerificationToken"]').val());
formData.append('comment', comment);
const response = await fetch($Comments.attr('data-addurl'), {
method: 'POST',
body: formData
});
if (response.ok) {
$CommentInput.val('').prop('disabled', false).focus();
} else {
alert('Unable to add comment: ' + response.statusText);
$CommentInput.prop('disabled', false).focus();
}
}
//#endregion
@@ -183,100 +165,101 @@
{<text>
//#region Remove Logs
var $dialogRemoveLog;
let $dialogRemoveLog = null;
$CommentOutput.find('span.remove').click(removePost);
$CommentOutput.on('click', 'span.remove', removePost);
async function removeComment(commentId) {
const formData = new FormData();
formData.append('__RequestVerificationToken', $Comments.find('input[name="__RequestVerificationToken"]').val());
formData.append('id', commentId);
const response = await fetch($Comments.attr('data-removeurl'), {
method: 'POST',
body: formData
});
if (!response.ok) {
alert('Unable to remove comment: ' + response.statusText);
}
$dialogRemoveLog.dialog("close");
}
function removePost(e) {
e.preventDefault();
function removePost() {
$this = $(this);
var data = { id: $this.closest('div').attr('data-logid') };
const commentId = $this.closest('div').attr('data-logid');
if (!$dialogRemoveLog) {
$dialogRemoveLog = $('#dialogRemoveLog').dialog({
resizable: false,
height: 140,
modal: true,
autoOpen: false
});
$dialogRemoveLog = $('<div class="dialog" title="Remove this Comment?"><p><i class="fa fa-exclamation-triangle fa-lg"></i>&nbsp;Are you sure?</p></div>')
.appendTo(document.body)
.dialog({
resizable: false,
height: 140,
modal: true,
autoOpen: false
});
}
$dialogRemoveLog.dialog("enable").dialog('option', 'buttons', {
"Remove": function () {
$dialogRemoveLog.dialog("disable");
$dialogRemoveLog.dialog("option", "buttons", null);
$.ajax({
url: '@Url.Action(MVC.API.Job.CommentRemove())',
dataType: 'json',
data: data,
success: function (d) {
if (d == 'OK') {
// Should be removed via Repository Notifications
//$this.closest('div').slideUp(300).delay(300).queue(function () {
// $(this).remove();
//});
} else {
alert('Unable to remove comment: ' + d);
}
$dialogRemoveLog.dialog("close");
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Unable to remove comment: ' + textStatus);
$dialogRemoveLog.dialog("close");
}
});
removeComment(commentId);
},
"Cancel": function () {
$dialogRemoveLog.dialog("close");
}
}).dialog('open');
return false;
}
//#endregion
</text>}
function loadLiveComment(key) {
$.ajax({
url: '@Url.Action(MVC.API.Job.Comment())',
dataType: 'json',
data: { id: key },
success: function (d) {
if (d && d.JobId == jobId) {
@if (canRemoveAnyLogs)
{<text>addComment(d, false, true);</text>}
else if (canRemoveOwnLogs)
{<text>addComment(d, false, (d.AuthorId === '@(CurrentUser.UserId)'));</text>}
else
{<text>addComment(d, false, false);</text>}
async function loadLiveComment(id) {
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Unable to load live comment ' + id + ': ' + textStatus);
}
const formData = new FormData();
formData.append('__RequestVerificationToken', $Comments.find('input[name="__RequestVerificationToken"]').val());
formData.append('id', id);
const response = await fetch($Comments.attr('data-geturl'), {
method: 'POST',
body: formData
});
if (!response.ok) {
alert('Unable to load live comment ' + id + ': ' + textStatus);
} else {
const comment = await response.json();
if ($Comments.hasClass('canRemoveAnyLogs'))
addComment(comment, false, true);
else if ($Comments.hasClass('canRemoveOwnLogs'))
addComment(comment, false, (comment.AuthorId === $Comments.attr('data-userid')));
else
addComment(comment, false, false);
}
}
function liveRemoveComment(key) {
$CommentOutput.children('div[data-logid="' + key + '"]').slideUp(300).delay(300).queue(function () {
var $this = $(this);
function liveRemoveComment(id) {
$CommentOutput.children('div[data-logid="' + id + '"]').slideUp(300).delay(300).queue(function () {
const $this = $(this);
$this.find('.timestamp').livestamp('destroy');
$this.remove();
});
}
function addComment(c, quick, canRemove) {
var t = '<div><span class="author" />';
let t = '<div><span class="author" />';
if (canRemove)
t += '<span class="remove fa fa-times-circle" />';
t += '<span class="timestamp" /><div class="comment" /></div>';
var e = $(t);
const e = $(t);
e.attr('data-logid', c.Id);
e.find('.author').text(c.Author);
e.find('.timestamp').text(c.TimestampFull).attr('title', c.TimestampFull).livestamp(c.TimestampUnixEpoc);
if (canRemove)
e.find('.remove').click(removePost);
var eComment = e.find('.comment').html(c.HtmlComments);
e.find('.comment').html(c.HtmlComments);
$CommentOutput.append(e);
@@ -291,7 +274,9 @@
}
// Add Globally Available Functions
document.DiscoFunctions.liveLoadComment = loadLiveComment;
document.DiscoFunctions.liveLoadComment = function (id) {
loadLiveComment(id);
};
document.DiscoFunctions.liveRemoveComment = liveRemoveComment;
//#endregion
});
@@ -379,12 +364,14 @@
var data = { id: $this.attr('data-attachmentid') };
if (!$dialogRemoveAttachment) {
$dialogRemoveAttachment = $('#dialogRemoveAttachment').dialog({
resizable: false,
height: 140,
modal: true,
autoOpen: false
});
$dialogRemoveAttachment = $('<div class="dialog" title="Remove this Attachment?"><p><i class="fa fa-exclamation-triangle fa-lg"></i>&nbsp;Are you sure?</p></div>')
.appendTo(document.body)
.dialog({
resizable: false,
height: 140,
modal: true,
autoOpen: false
});
}
$dialogRemoveAttachment.dialog("enable").dialog('option', 'buttons', {
File diff suppressed because it is too large Load Diff