diff --git a/Core/Core.csproj b/Core/Core.csproj
index ecb3020..91b3299 100644
--- a/Core/Core.csproj
+++ b/Core/Core.csproj
@@ -144,6 +144,7 @@
+
diff --git a/Core/Entities/LeafInput.cs b/Core/Entities/LeafInput.cs
index 38beabd..3d41ad6 100644
--- a/Core/Entities/LeafInput.cs
+++ b/Core/Entities/LeafInput.cs
@@ -8,15 +8,13 @@ using System.Linq;
namespace LeafWeb.Core.Entities
{
- public class LeafInput
+ public abstract class LeafInputBase
{
- public int Id { get; set; }
-
- public virtual ICollection InputFiles { get; set; }
public virtual ICollection OutputFiles { get; set; }
public LeafOutputFile OutputErrorMessage => OutputFiles?.FirstOrDefault(f => f.IsErrorMessage);
public LeafOutputFile OutputWarningMessage => OutputFiles?.FirstOrDefault(f => f.IsWarningMessage);
- public virtual ICollection LeafInputData { get; set; }
+ public bool HasOutputFiles => OutputFiles.Any();
+ public bool HasLeafChart => OutputFiles.Any(f => f.IsLeafChartFile);
public LeafInputStatusType CurrentStatus { get; set; }
public virtual ICollection StatusHistory { get; set; }
@@ -36,12 +34,71 @@ namespace LeafWeb.Core.Entities
|| IsFinishing
|| IsCancelPending
|| IsCancelling;
- public bool IsDeletable => !IsInProgress;
- public bool HasOutputFiles => OutputFiles.Any();
+
public bool IsCancellable =>
IsRunning
|| IsPending;
+ public bool IsDeletable => !IsInProgress;
+ public bool IsAtEndState => IsComplete || IsException || IsCancelled;
+
+
+ public DateTime? StartTime
+ {
+ get
+ {
+ if (IsPending)
+ {
+ return null;
+ }
+ return StatusHistory.FirstOrDefault(s => s.Status == LeafInputStatusType.Starting)?.DateTime;
+ }
+ }
+
+ public DateTime? EndTime
+ {
+ get
+ {
+ if (!IsAtEndState)
+ {
+ return null;
+ }
+ return StatusHistory.FirstOrDefault(
+ s =>
+ s.Status == LeafInputStatusType.Complete
+ || s.Status == LeafInputStatusType.Exception
+ || s.Status == LeafInputStatusType.Cancelled)?.DateTime;
+ }
+ }
+
+ public TimeSpan TotalInProgressTime
+ {
+ get
+ {
+ var start = StartTime;
+ if (!start.HasValue)
+ {
+ return TimeSpan.Zero;
+ }
+
+ var end = EndTime;
+ if (!end.HasValue)
+ {
+ return DateTime.Now - start.Value;
+ }
+
+ return end.Value - start.Value;
+ }
+ }
+ }
+
+ public class LeafInput : LeafInputBase
+ {
+ public int Id { get; set; }
+
+ public virtual ICollection InputFiles { get; set; }
+ public virtual ICollection LeafInputData { get; set; }
+
[Required(ErrorMessage = "Name required")]
public string Name { get; set; }
diff --git a/Core/Utility/TimeSpanExtensions.cs b/Core/Utility/TimeSpanExtensions.cs
new file mode 100644
index 0000000..9c67615
--- /dev/null
+++ b/Core/Utility/TimeSpanExtensions.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Runtime.Remoting.Messaging;
+
+namespace LeafWeb.Core.Utility
+{
+ public static class TimeSpanExtensions
+ {
+ public static string ToReadableString(this TimeSpan span)
+ {
+ Func pluralize = i => i > 1 ? "s" : string.Empty;
+ var formatted = string.Format("{0}{1}{2}{3}",
+ span.Duration().Days > 0 ? $"{span.Days:0} day{pluralize(span.Days)}, " : string.Empty,
+ span.Duration().Hours > 0 ? $"{span.Hours:0} hour{pluralize(span.Hours)}, " : string.Empty,
+ span.Duration().Minutes > 0 ? $"{span.Minutes:0} minute{pluralize(span.Minutes)}, " : string.Empty,
+ span.Duration().Seconds > 0 ? $"{span.Seconds:0} second{pluralize(span.Seconds)}" : string.Empty);
+
+ if (formatted.EndsWith(", ")) formatted = formatted.Substring(0, formatted.Length - 2);
+
+ if (string.IsNullOrEmpty(formatted)) formatted = "0 seconds";
+
+ return formatted;
+ }
+
+ public static string ToRoundedReadableString(this TimeSpan span)
+ {
+ Func pluralize = i => i > 1 ? "s" : string.Empty;
+ Func formatTime = (i, s) => $"{i:0} {s}{pluralize(i)}";
+ if (span.Duration().Days > 0)
+ return formatTime(span.Days, "day");
+ if (span.Duration().Hours > 0)
+ return formatTime(span.Hours, "hour");
+ if (span.Duration().Minutes > 0)
+ return formatTime(span.Minutes, "minute");
+ if (span.Duration().Seconds > 0)
+ return formatTime(span.Seconds, "second");
+
+ return "0 seconds";
+ }
+ }
+}
diff --git a/WebCms.Tests/Models/ResultStatusViewModelTests.cs b/WebCms.Tests/Models/ResultStatusViewModelTests.cs
deleted file mode 100644
index 82e68d3..0000000
--- a/WebCms.Tests/Models/ResultStatusViewModelTests.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using System;
-using LeafWeb.Core.Entities;
-using LeafWeb.WebCms.Models;
-using NUnit.Framework;
-
-namespace LeafWeb.WebCms.Tests.Models
-{
- [TestFixture]
- public class ResultStatusViewModelTests
- {
- private LeafInput GetLeafInput()
- {
- return new LeafInput
- {
- CurrentStatus = LeafInputStatusType.Complete,
- OutputFiles = new[] {new LeafOutputFile {Filename = "OutputFilename.txt"}},
- Added = DateTime.Today,
- Email = "test@email.com",
- Identifier = "Ident I Fier",
- Name = "My Name",
- PhotosynthesisType = new PhotosynthesisType {Id = "1", Name = "1", SortOrder = 1},
- InputFiles = new[]
- {
- new LeafInputFile
- {
- Filename = "MyFilename.ext",
- Id = 3
- }
- }
- };
- }
-
- [Test]
- public void CanConstructFromLeafInputFile()
- {
- var leafInput = GetLeafInput();
- var viewModel = new QueueItemViewModel(leafInput);
-
- Assert.That(viewModel.CurrentStatus, Is.EqualTo(leafInput.CurrentStatus.ToString()));
- Assert.That(viewModel.LeafInputId, Is.EqualTo(leafInput.Id));
- //Assert.That(viewModel.LeafOutputFilenames, Has.Length.EqualTo(1));
- Assert.That(viewModel.LeafInputIdentifier, Is.EqualTo(leafInput.Identifier));
- Assert.That(viewModel.LeafInputSiteId, Is.EqualTo(leafInput.SiteId));
- Assert.That(viewModel.LeafInputPhotosynthesisType, Is.EqualTo(leafInput.PhotosynthesisType.Name));
- }
-
- [Test]
- public void CanConstructFromLeafInputFile_Running()
- {
- var leafInput = GetLeafInput();
- leafInput.CurrentStatus = LeafInputStatusType.Running;
- leafInput.OutputFiles = new LeafOutputFile[0];
- var viewModel = new QueueItemViewModel(leafInput);
-
- Assert.That(viewModel.CurrentStatus, Is.EqualTo(LeafInputStatusType.Running.ToString()));
- //Assert.That(viewModel.LeafOutputFilenames, Has.Length.EqualTo(0));
- }
-
- [Test]
- public void CanConstructFromLeafInputFile_Error()
- {
- var leafInput = GetLeafInput();
- leafInput.CurrentStatus = LeafInputStatusType.Exception;
- leafInput.StatusHistory = new []
- {
- new LeafInputStatus
- {
- DateTime = DateTime.Today,
- LeafInput = leafInput,
- Description = "My Error",
- Status = LeafInputStatusType.Exception
- }
- };
- var viewModel = new QueueItemViewModel(leafInput);
-
- Assert.That(viewModel.CurrentStatus, Is.EqualTo(LeafInputStatusType.Exception.ToString()));
- //Assert.That(viewModel.ErrorMessages[0], Is.EqualTo(leafInput.StatusHistory.First().Description));
- }
- }
-}
diff --git a/WebCms.Tests/WebCms.Tests.csproj b/WebCms.Tests/WebCms.Tests.csproj
index 67d1213..21341f5 100644
--- a/WebCms.Tests/WebCms.Tests.csproj
+++ b/WebCms.Tests/WebCms.Tests.csproj
@@ -46,7 +46,6 @@
-
diff --git a/WebCms/App_Data/Models/all.dll.path b/WebCms/App_Data/Models/all.dll.path
index f027e12..cdffceb 100644
--- a/WebCms/App_Data/Models/all.dll.path
+++ b/WebCms/App_Data/Models/all.dll.path
@@ -1 +1 @@
-C:\Users\poprhythm\AppData\Local\Temp\Temporary ASP.NET Files\vs\f80e29bb\faae20bf\App_Web_all.generated.cs.8f9494c4._retrxtu.dll
\ No newline at end of file
+C:\Users\poprhythm\AppData\Local\Temp\Temporary ASP.NET Files\vs\f80e29bb\faae20bf\App_Web_all.generated.cs.8f9494c4.tezx-cyz.dll
\ No newline at end of file
diff --git a/WebCms/App_Start/RegisterServices.cs b/WebCms/App_Start/RegisterServices.cs
index 0c2b66f..1679ba6 100644
--- a/WebCms/App_Start/RegisterServices.cs
+++ b/WebCms/App_Start/RegisterServices.cs
@@ -3,6 +3,7 @@ using System.Web.Optimization;
using System.Web.Routing;
using Backload.Bundles;
using LeafWeb.Core.DAL;
+using LeafWeb.WebCms.Models;
using Umbraco.Core;
namespace LeafWeb.WebCms.App_Start
@@ -24,7 +25,7 @@ namespace LeafWeb.WebCms.App_Start
"Results/Download", // URL with parameters
new { controller = "Results", action = "Download" } // Parameter defaults
);
-
+
base.ApplicationStarted(umbracoApplication, applicationContext);
}
}
diff --git a/WebCms/Content/style.css b/WebCms/Content/style.css
index 54a5479..315e070 100644
--- a/WebCms/Content/style.css
+++ b/WebCms/Content/style.css
@@ -42,7 +42,7 @@ a.banner-link:hover {
text-decoration: none;
background: rgba(0, 0, 0, 0.6); }
a.banner-link:hover .glyphicon {
- color: #a8ed4e; }
+ color: #a8ed4f; }
.headline-icon {
/* http://glyphicons.bootstrapcheatsheets.com/ */ }
diff --git a/WebCms/Content/style.min.css b/WebCms/Content/style.min.css
index 011b68e..5746497 100644
--- a/WebCms/Content/style.min.css
+++ b/WebCms/Content/style.min.css
@@ -1 +1 @@
-h1{padding:24px 0 12px 0;}p{padding:12px 0;}footer{margin-top:24px !important;}.row-no-padding [class*="col-"]{padding-left:0 !important;padding-right:0 !important;}.home .dark .row:first-child .column:first-child h1{padding-top:0;}.home .blogarchive{padding-top:20px;}.top-buffer{margin-top:20px;}.detail-actions>a,.detail-actions>form>button{margin-top:20px;float:left;clear:left;}.banner-link{white-space:normal;padding:20px;background:#000;background:rgba(0,0,0,.5);-moz-border-radius:10px;border-radius:10px;}.banner-link .glyphicon{color:#8cc641;}a.banner-link:hover{text-decoration:none;background:rgba(0,0,0,.6);}a.banner-link:hover .glyphicon{color:#a8ed4e;}.headline-icon h1:after{color:rgba(172,214,118,.8);font-family:"Glyphicons Halflings";font-size:.8em;padding-left:10px;}.headline-icon.headline-icon-file h1:after{content:"";}.headline-icon.headline-icon-leaf h1:after{content:"";}.headline-icon.headline-icon-question h1:after{content:"";}.headline-icon.headline-icon-stats h1:after{content:"";}.headline-icon.headline-icon-user h1:after{content:"";}.headline-icon.headline-icon-list h1:after{content:"";}.status{white-space:nowrap;}.status:after{font-family:"Glyphicons Halflings";font-size:.8em;padding-left:5px;}.status.status-pending{color:#f0ad4e;}.status.status-pending:after{content:"";}.status.status-complete{color:#337ab7;}.status.status-complete:after{content:"";}.status.status-exception{color:#a94442;}.status.status-exception:after{content:"";}.status.status-running,.status.status-starting,.status.status-finishing{color:#3c763d;}.status.status-running:after{content:"";}.status.status-starting:after{content:"";}.status.status-finishing:after{content:"";}.status.status-cancelpending,.status.status-cancelling{color:#f0ad4e;}.status.status-cancelled{color:#ec971f;}.status.status-cancelpending:after{content:"";}.status.status-cancelling:after{content:"";}.status.status-cancelled:after{content:"";}#chart{padding-top:20px;}.btn-file{position:relative;overflow:hidden;}.btn-file input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:100px;text-align:right;filter:alpha(opacity=0);opacity:0;outline:none;background:#fff;cursor:inherit;display:block;}form .validation-summary-errors ul{list-style-type:none;}.autocomplete-suggestions{border:1px solid #999;background:#fff;overflow:auto;}.autocomplete-suggestion{padding:2px 5px;white-space:nowrap;overflow:hidden;}.autocomplete-selected{background:#f0f0f0;}.autocomplete-suggestions strong{font-weight:normal;color:#39f;}.autocomplete-group{padding:2px 5px;}.autocomplete-group strong{display:block;border-bottom:1px solid #000;}.toggle{width:15px;}.dropdown-menu li form .btn-link{display:block;color:#333;clear:both;float:left;font-size:1rem;font-weight:normal;line-height:1.42857;min-width:160px;padding:3px 20px;text-align:left;white-space:nowrap;}.dropdown-menu li form .btn-link:focus,.dropdown-menu li form .btn-link:hover{text-decoration:none;color:#262626;background-color:#f5f5f5;}.divider-right{border-right:1px dashed #333;}
\ No newline at end of file
+h1{padding:24px 0 12px 0;}p{padding:12px 0;}footer{margin-top:24px !important;}.row-no-padding [class*="col-"]{padding-left:0 !important;padding-right:0 !important;}.home .dark .row:first-child .column:first-child h1{padding-top:0;}.home .blogarchive{padding-top:20px;}.top-buffer{margin-top:20px;}.detail-actions>a,.detail-actions>form>button{margin-top:20px;float:left;clear:left;}.banner-link{white-space:normal;padding:20px;background:#000;background:rgba(0,0,0,.5);-moz-border-radius:10px;border-radius:10px;}.banner-link .glyphicon{color:#8cc641;}a.banner-link:hover{text-decoration:none;background:rgba(0,0,0,.6);}a.banner-link:hover .glyphicon{color:#a8ed4f;}.headline-icon h1:after{color:rgba(172,214,118,.8);font-family:"Glyphicons Halflings";font-size:.8em;padding-left:10px;}.headline-icon.headline-icon-file h1:after{content:"";}.headline-icon.headline-icon-leaf h1:after{content:"";}.headline-icon.headline-icon-question h1:after{content:"";}.headline-icon.headline-icon-stats h1:after{content:"";}.headline-icon.headline-icon-user h1:after{content:"";}.headline-icon.headline-icon-list h1:after{content:"";}.status{white-space:nowrap;}.status:after{font-family:"Glyphicons Halflings";font-size:.8em;padding-left:5px;}.status.status-pending{color:#f0ad4e;}.status.status-pending:after{content:"";}.status.status-complete{color:#337ab7;}.status.status-complete:after{content:"";}.status.status-exception{color:#a94442;}.status.status-exception:after{content:"";}.status.status-running,.status.status-starting,.status.status-finishing{color:#3c763d;}.status.status-running:after{content:"";}.status.status-starting:after{content:"";}.status.status-finishing:after{content:"";}.status.status-cancelpending,.status.status-cancelling{color:#f0ad4e;}.status.status-cancelled{color:#ec971f;}.status.status-cancelpending:after{content:"";}.status.status-cancelling:after{content:"";}.status.status-cancelled:after{content:"";}#chart{padding-top:20px;}.btn-file{position:relative;overflow:hidden;}.btn-file input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:100px;text-align:right;filter:alpha(opacity=0);opacity:0;outline:none;background:#fff;cursor:inherit;display:block;}form .validation-summary-errors ul{list-style-type:none;}.autocomplete-suggestions{border:1px solid #999;background:#fff;overflow:auto;}.autocomplete-suggestion{padding:2px 5px;white-space:nowrap;overflow:hidden;}.autocomplete-selected{background:#f0f0f0;}.autocomplete-suggestions strong{font-weight:normal;color:#39f;}.autocomplete-group{padding:2px 5px;}.autocomplete-group strong{display:block;border-bottom:1px solid #000;}.toggle{width:15px;}.dropdown-menu li form .btn-link{display:block;color:#333;clear:both;float:left;font-size:1rem;font-weight:normal;line-height:1.42857;min-width:160px;padding:3px 20px;text-align:left;white-space:nowrap;}.dropdown-menu li form .btn-link:focus,.dropdown-menu li form .btn-link:hover{text-decoration:none;color:#262626;background-color:#f5f5f5;}.divider-right{border-right:1px dashed #333;}
\ No newline at end of file
diff --git a/WebCms/Content/style.scss b/WebCms/Content/style.scss
index 37a7d4e..78f63b4 100644
--- a/WebCms/Content/style.scss
+++ b/WebCms/Content/style.scss
@@ -61,7 +61,7 @@ a.banner-link:hover {
background: rgba(0, 0, 0, 0.6);
.glyphicon {
- color: #a8ed4e;
+ color: #a8ed4f;
}
}
@@ -126,7 +126,7 @@ a.banner-link:hover {
}
}
- &.status-running,&.status-starting,&.status-finishing {
+ &.status-running, &.status-starting, &.status-finishing {
color: #3c763d;
}
&.status-running:after {
@@ -139,7 +139,7 @@ a.banner-link:hover {
content:"\e027";
}
- &.status-cancelpending,&.status-cancelling {
+ &.status-cancelpending, &.status-cancelling {
color: #f0ad4e;
}
&.status-cancelled {
diff --git a/WebCms/Controllers/LeafInputController.cs b/WebCms/Controllers/LeafInputController.cs
index c27024e..37c0f30 100644
--- a/WebCms/Controllers/LeafInputController.cs
+++ b/WebCms/Controllers/LeafInputController.cs
@@ -33,6 +33,10 @@ namespace LeafWeb.WebCms.Controllers
if (!files.Any())
ModelState.AddModelError("Files", "Must select at least one file");
+ // TODO: this keeps randomly not being mapable because string->bool binding fails. WHY
+ if (ModelState.ContainsKey("TermsOfService"))
+ ModelState["TermsOfService"].Errors.Clear();
+
if (ModelState.IsValid) // HttpParamMatch indicates it's backing out from Confirm
{
// convert viewModel into Model
diff --git a/WebCms/Controllers/QueueController.cs b/WebCms/Controllers/QueueController.cs
index a6afe9e..8ddb862 100644
--- a/WebCms/Controllers/QueueController.cs
+++ b/WebCms/Controllers/QueueController.cs
@@ -2,25 +2,23 @@
using System.Linq;
using System.Web.Mvc;
using Hangfire;
-using log4net;
using LeafWeb.Core.Entities;
using LeafWeb.Core.Utility;
-using LeafWeb.WebCms.App_Start;
using LeafWeb.WebCms.Models;
using LeafWeb.WebCms.Services;
using LeafWeb.WebCms.Services.PiscalQueue;
+using Umbraco.Web.Mvc;
namespace LeafWeb.WebCms.Controllers
{
+ [MemberAuthorize]
public class QueueController : BaseController
{
public ActionResult Index()
{
var resultItems =
DataService.GetLeafInputs()
- .OrderByDescending(f => f.Id)
- .ToList()
- .Select(leafInput => new QueueItemViewModel(leafInput));
+ .OrderByDescending(f => f.Id);
string serviceDescription;
try
@@ -134,27 +132,16 @@ namespace LeafWeb.WebCms.Controllers
return RedirectToUmbracoPage(LeafWebPageIds.ManageQueue);
}
- if (leafInput.IsPending)
- {
- LogManager.GetLogger(LoggerName(RouteData)).DebugFormat("LeafInput: {0}, Set Cancelled from Pending", leafInput.Id);
- DataService.SetLeafInputStatus(leafInput, LeafInputStatusType.Cancelled,
- "Emailing cancellation notification to user",
- $"Email: \'{leafInput.Email}\'");
+ var cancelPendingSuccess = new PiscalQueueManager().CancelPending(id);
- // send notification immediately
- BackgroundJob.Enqueue(email => email.SendLeafWebCancelled(leafInput.Id));
- SetStatusMessage($"Cancelling LeafInput '{leafInput.Identifier}'", StatusType.Success);
- }
- else if (leafInput.IsRunning)
+ if (cancelPendingSuccess)
{
- DataService.SetLeafInputStatus(leafInput, LeafInputStatusType.CancelPending);
SetStatusMessage($"Cancelling LeafInput '{leafInput.Identifier}'", StatusType.Success);
- HangfireStartup.TriggerPiscalProcessQueue();
}
else
{
// don't allow to be cancelled if it isn't currently running
- SetStatusMessage($"LeafInput '{leafInput.Identifier}' is not currently running!", StatusType.Error);
+ SetStatusMessage($"Couldn't cancel '{leafInput.Identifier}', is it currently running?", StatusType.Error);
}
return RedirectToCurrentUmbracoUrl();
}
diff --git a/WebCms/Controllers/ResultsController.cs b/WebCms/Controllers/ResultsController.cs
index dcd3314..fcfb7d4 100644
--- a/WebCms/Controllers/ResultsController.cs
+++ b/WebCms/Controllers/ResultsController.cs
@@ -12,14 +12,13 @@ namespace LeafWeb.WebCms.Controllers
public ActionResult Index()
{
var dateThreshold = DateTime.Today.Subtract(TimeSpan.FromDays(90));
- var viewModel =
+ var viewModel =
(
from li in DataService.GetLeafInputs()
where li.Added >= dateThreshold
orderby li.Id descending
select li
- ).ToList()
- .Select(leafInput => new QueueItemViewModel(leafInput));
+ );
return View(viewModel);
}
diff --git a/WebCms/Models/QueueItemViewModel.cs b/WebCms/Models/QueueItemViewModel.cs
deleted file mode 100644
index 6c29f50..0000000
--- a/WebCms/Models/QueueItemViewModel.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using System.Linq;
-using AutoMapper;
-using LeafWeb.Core.Entities;
-
-namespace LeafWeb.WebCms.Models
-{
- public class QueueItemViewModel
- {
- public int LeafInputId { get; set; }
- public string LeafInputName { get; set; }
- public string LeafInputIdentifier { get; set; }
- public string LeafInputSiteId { get; set; }
- public string LeafInputPhotosynthesisType { get; set; }
- public bool HasLeafChart { get; set; }
- public bool IsRunning { get; set; }
- public bool IsComplete { get; set; }
- public bool IsDeletable { get; set; }
- public bool IsCancellable { get; set; }
- public bool IsPending { get; set; }
- public bool HasOutputFiles { get; set; }
- public string CurrentStatus { get; set; }
-
- //public string[] ErrorMessages { get; set; }
- //public string[] LeafOutputFilenames { get; set; }
- //public bool HasLeafChartOutputFile { get; set; }
-
- static QueueItemViewModel()
- {
- Mapper.CreateMap()
- .ForMember(dest => dest.LeafInputId, opt => opt.MapFrom(src => src.Id))
- .ForMember(dest => dest.HasLeafChart, opt => opt.ResolveUsing(src => src.OutputFiles.Any(o => o.IsLeafChartFile)))
- //.ForMember(dest => dest.LeafOutputFilenames,
- // opt => opt.ResolveUsing(
- // src =>
- // src.OutputFiles?
- // .Select(o => o.Filename)
- // .ToArray()
- // ?? new string[] {}))
- //.ForMember(dest => dest.HasLeafChartOutputFile,
- // opt => opt.ResolveUsing(
- // file => file.OutputFiles?.Any(o => o.IsLeafChartFile)))
- .ForMember(dest => dest.LeafInputName, opt => opt.MapFrom(src => src.Name))
- .ForMember(dest => dest.LeafInputIdentifier, opt => opt.MapFrom(src => src.Identifier))
- .ForMember(dest => dest.LeafInputSiteId, opt => opt.MapFrom(src => src.SiteId))
- .ForMember(dest => dest.LeafInputPhotosynthesisType, opt => opt.MapFrom(src => src.PhotosynthesisType.Name))
- //.ForMember(dest => dest.ErrorMessages,
- // opt => opt.ResolveUsing(
- // src =>
- // src.StatusHistory?
- // .Where(sh => sh.Status == LeafInputStatusType.Exception)
- // .Select(sh => sh.Description)
- // .ToArray()
- // ?? new string[] {}))
- ;
- }
-
- public QueueItemViewModel(LeafInput leafInput)
- {
- Mapper.Map(leafInput, this);
- }
- }
-}
\ No newline at end of file
diff --git a/WebCms/Models/QueueViewModel.cs b/WebCms/Models/QueueViewModel.cs
index 5a2586a..7d053b5 100644
--- a/WebCms/Models/QueueViewModel.cs
+++ b/WebCms/Models/QueueViewModel.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using LeafWeb.Core.Entities;
namespace LeafWeb.WebCms.Models
{
@@ -6,6 +7,6 @@ namespace LeafWeb.WebCms.Models
{
public string ServerDescription { get; set; }
public string ServerStatus { get; set; }
- public IEnumerable Items { get; set; }
+ public IEnumerable Items { get; set; }
}
}
\ No newline at end of file
diff --git a/WebCms/Services/PiscalQueue/PiscalQueueManager.cs b/WebCms/Services/PiscalQueue/PiscalQueueManager.cs
index 22626ae..259440d 100644
--- a/WebCms/Services/PiscalQueue/PiscalQueueManager.cs
+++ b/WebCms/Services/PiscalQueue/PiscalQueueManager.cs
@@ -3,17 +3,18 @@ using System.Linq;
using System.Threading;
using LeafWeb.Core.Entities;
using LeafWeb.Core.Remote;
+using LeafWeb.WebCms.App_Start;
namespace LeafWeb.WebCms.Services.PiscalQueue
{
public class PiscalQueueManager : PiscalQueueBase
{
- private static readonly object ProcessQueueLock = new object();
+ private static readonly object Lock = new object();
public void ProcessQueue()
{
// prevent multiple entry into processing the queue
- if (Monitor.TryEnter(ProcessQueueLock))
+ if (Monitor.TryEnter(Lock))
{
Logger.DebugFormat("ProcessQueue entered");
@@ -31,7 +32,7 @@ namespace LeafWeb.WebCms.Services.PiscalQueue
{
Logger.DebugFormat("ProcessQueue exit");
- Monitor.Exit(ProcessQueueLock);
+ Monitor.Exit(Lock);
}
}
else
@@ -40,6 +41,46 @@ namespace LeafWeb.WebCms.Services.PiscalQueue
}
}
+ public bool CancelPending(int leafInputId)
+ {
+ if (Monitor.TryEnter(Lock, TimeSpan.FromSeconds(1)))
+ {
+ Logger.DebugFormat("CancelLeafInput entered");
+
+ try
+ {
+ var leafInput = DataService.GetLeafInput(leafInputId);
+ if (!leafInput.IsCancellable)
+ return false;
+ if (leafInput.IsPending)
+ {
+ Logger.DebugFormat("LeafInput: {0}, Set Cancelled from Pending", leafInput.Id);
+ DataService.SetLeafInputStatus(leafInput, LeafInputStatusType.Cancelled,
+ "Emailing cancellation notification to user",
+ $"Email: \'{leafInput.Email}\'");
+
+ // send notification immediately
+ BackgroundJobEnqueueRetry(email => email.SendLeafWebCancelled(leafInput.Id));
+ }
+ else if (leafInput.IsRunning)
+ {
+ DataService.SetLeafInputStatus(leafInput, LeafInputStatusType.CancelPending);
+ HangfireStartup.TriggerPiscalProcessQueue();
+ }
+ return true;
+ }
+ finally
+ {
+ Logger.DebugFormat("CancelLeafInput exit");
+
+ Monitor.Exit(Lock);
+ }
+ }
+
+ Logger.DebugFormat("CancelLeafInput locked");
+ return false;
+ }
+
private void StartCancelPending()
{
var cancelPendingLeafInputs =
diff --git a/WebCms/Views/Partials/MainNavigation.cshtml b/WebCms/Views/Partials/MainNavigation.cshtml
index 20d0257..df20902 100644
--- a/WebCms/Views/Partials/MainNavigation.cshtml
+++ b/WebCms/Views/Partials/MainNavigation.cshtml
@@ -55,7 +55,7 @@
@page.Name
@if (library.IsProtected(page.id, page.path)) {
-
+
}
diff --git a/WebCms/Views/Queue/Index.cshtml b/WebCms/Views/Queue/Index.cshtml
index c1a5144..fad3c1d 100644
--- a/WebCms/Views/Queue/Index.cshtml
+++ b/WebCms/Views/Queue/Index.cshtml
@@ -9,13 +9,14 @@
@Model.ServerDescription
-
@grid.Table(columns:
grid.Columns(
- grid.Column("LeafInputIdentifier", "Identifier"),
- grid.Column("LeafInputSiteId", "Site Id"),
- grid.Column("LeafInputName", "Submitted By"),
- grid.Column("CurrentStatus", "Status", item => Html.Partial("DisplayTemplates/_LeafInputStatus", (string)item.CurrentStatus)),
+ grid.Column("Identifier", "Identifier"),
+ grid.Column("SiteId", "Site Id"),
+ grid.Column("Name", "Submitted By"),
+ //grid.Column("FileCount", "Input files"),
+ grid.Column("TotalInProgressTime", "In-Progress Time", item => ((TimeSpan)item.TotalInProgressTime).ToRoundedReadableString()),
+ grid.Column("CurrentStatus", "Status", item => Html.Partial("DisplayTemplates/_LeafInputStatus", (string)item.CurrentStatus.ToString())),
grid.Column("Total Results: " + Model.Items.Count(), format: item => Btns(item))),
htmlAttributes: new { @class = "table table-striped table-bordered table-hover table-condensed" }
)
@@ -54,47 +55,47 @@
@helper DetailsLink(dynamic item)
{
-@Html.Partial("DisplayTemplates/_DetailsLink", (int)item.LeafInputId)
+@Html.Partial("DisplayTemplates/_DetailsLink", (int)item.Id)
}
@helper ChartLink(dynamic item)
{
-@Html.Partial("DisplayTemplates/_ChartLink", (int)item.LeafInputId)
+@Html.Partial("DisplayTemplates/_ChartLink", (int)item.Id)
}
@helper SetPriorityHigh(dynamic item, string label)
{
-
+
@label
}
@helper SetPriorityLow(dynamic item, string label)
{
-
+
@label
}
@helper DownloadInput(dynamic item)
{
-
+
Input
}
@helper DownloadOutputToUser(dynamic item)
{
-
+
ToUser
}
@helper DeleteLink(dynamic item)
{
-@Html.Partial("DisplayTemplates/_DeleteForm", (Tuple)Tuple.Create(item.LeafInputId, item.LeafInputIdentifier, item.IsDeletable))
+@Html.Partial("DisplayTemplates/_DeleteForm", (Tuple)Tuple.Create(item.Id, item.Identifier, item.IsDeletable))
}
@helper CancelLink(dynamic item)
{
-@Html.Partial("DisplayTemplates/_CancelForm", (Tuple)Tuple.Create(item.LeafInputId, item.LeafInputIdentifier))
+@Html.Partial("DisplayTemplates/_CancelForm", (Tuple)Tuple.Create(item.Id, item.Identifier))
}
@helper DisableItem(bool disabled)
diff --git a/WebCms/Views/Results/Index.cshtml b/WebCms/Views/Results/Index.cshtml
index bec63d0..a15b83e 100644
--- a/WebCms/Views/Results/Index.cshtml
+++ b/WebCms/Views/Results/Index.cshtml
@@ -1,4 +1,4 @@
-@model IEnumerable
+@model IOrderedQueryable
@{
var grid = new WebGrid(Model, rowsPerPage: 45);
@@ -6,10 +6,10 @@
@grid.Table(columns:
grid.Columns(
- grid.Column("LeafInputIdentifier", "Identifier"),
- grid.Column("LeafInputSiteId", "Site Id"),
- //grid.Column("LeafInputName", "Submitted By"),
- grid.Column("CurrentStatus", "Status", item => Html.Partial("DisplayTemplates/_LeafInputStatus", (string)item.CurrentStatus)),
+ grid.Column("Identifier", "Identifier"),
+ grid.Column("SiteId", "Site Id"),
+ //grid.Column("Name", "Submitted By"),
+ grid.Column("CurrentStatus", "Status", item => Html.Partial("DisplayTemplates/_LeafInputStatus", (string)item.CurrentStatus.ToString())),
grid.Column("", "", item => ChartLink(item))
),
htmlAttributes: new { @class = "table table-striped table-bordered table-hover table-condensed" }
@@ -18,5 +18,5 @@
@helper ChartLink(dynamic item)
{
- @Html.Partial("DisplayTemplates/_ChartButton", (int)item.LeafInputId, new ViewDataDictionary { { "Disabled", !item.HasLeafChart }, {"xs", true} })
+ @Html.Partial("DisplayTemplates/_ChartButton", (int)item.Id, new ViewDataDictionary { { "Disabled", !item.HasLeafChart }, {"xs", true} })
}
\ No newline at end of file
diff --git a/WebCms/Views/Shared/DisplayTemplates/LeafInputStatusViewModels.cshtml b/WebCms/Views/Shared/DisplayTemplates/LeafInputStatusViewModels.cshtml
index c002032..b6932f6 100644
--- a/WebCms/Views/Shared/DisplayTemplates/LeafInputStatusViewModels.cshtml
+++ b/WebCms/Views/Shared/DisplayTemplates/LeafInputStatusViewModels.cshtml
@@ -1,4 +1,4 @@
-@model IEnumerable
+@model IEnumerable
@{
Layout = "~/Views/Shared/DisplayTemplates/_FieldLayout.cshtml";
var grid = new WebGrid(Model, rowsPerPage: 45)
diff --git a/WebCms/Views/Shared/DisplayTemplates/_CancelForm.cshtml b/WebCms/Views/Shared/DisplayTemplates/_CancelForm.cshtml
index dcafe63..e40396e 100644
--- a/WebCms/Views/Shared/DisplayTemplates/_CancelForm.cshtml
+++ b/WebCms/Views/Shared/DisplayTemplates/_CancelForm.cshtml
@@ -5,7 +5,7 @@
var identifier = Model.Item2;
}
@using (Html.BeginUmbracoForm("Cancel", null,
- new { @class = "confirm", confirm_msg = "Cancelling cannot be undone! Confirm cancelling '" + identifier + "'." }))
+ new { @class = "confirm clearfix", confirm_msg = "Cancelling cannot be undone! Confirm cancelling '" + identifier + "'." }))
{