feature: saved exports

initial - not feature complete
This commit is contained in:
Gary Sharp
2025-02-09 17:14:04 +11:00
parent 2fce645066
commit ac24055365
35 changed files with 2244 additions and 156 deletions
@@ -1,6 +1,8 @@
using Disco.Data.Repository; using Disco.Data.Repository;
using Disco.Models.Services.Exporting;
using Disco.Models.Services.Interop.DiscoServices; using Disco.Models.Services.Interop.DiscoServices;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
namespace Disco.Data.Configuration namespace Disco.Data.Configuration
@@ -402,5 +404,11 @@ namespace Disco.Data.Configuration
} }
#endregion #endregion
public List<SavedExport> SavedExports
{
get => Get(new List<SavedExport>());
set => Set(value);
}
} }
} }
+3
View File
@@ -57,6 +57,8 @@
<Compile Include="Repository\Device\Flag\DeviceFlagAssignment.cs" /> <Compile Include="Repository\Device\Flag\DeviceFlagAssignment.cs" />
<Compile Include="Services\Devices\DeviceFlags\DeviceFlagExportOptions.cs" /> <Compile Include="Services\Devices\DeviceFlags\DeviceFlagExportOptions.cs" />
<Compile Include="Services\Devices\DeviceFlags\DeviceFlagExportRecord.cs" /> <Compile Include="Services\Devices\DeviceFlags\DeviceFlagExportRecord.cs" />
<Compile Include="Services\Exporting\SavedExport.cs" />
<Compile Include="Services\Exporting\SavedExportSchedule.cs" />
<Compile Include="Services\Expressions\Extensions\ImageExpressionFormat.cs" /> <Compile Include="Services\Expressions\Extensions\ImageExpressionFormat.cs" />
<Compile Include="ClientServices\EnrolmentInformation\BaseBoard.cs" /> <Compile Include="ClientServices\EnrolmentInformation\BaseBoard.cs" />
<Compile Include="ClientServices\EnrolmentInformation\Battery.cs" /> <Compile Include="ClientServices\EnrolmentInformation\Battery.cs" />
@@ -193,6 +195,7 @@
<Compile Include="UI\Config\DocumentTemplate\ConfigDocumentTemplateBulkGenerate.cs" /> <Compile Include="UI\Config\DocumentTemplate\ConfigDocumentTemplateBulkGenerate.cs" />
<Compile Include="UI\Config\DocumentTemplate\ConfigDocumentTemplateCreatePackageModel.cs" /> <Compile Include="UI\Config\DocumentTemplate\ConfigDocumentTemplateCreatePackageModel.cs" />
<Compile Include="UI\Config\DocumentTemplate\ConfigDocumentTemplateCreateModel.cs" /> <Compile Include="UI\Config\DocumentTemplate\ConfigDocumentTemplateCreateModel.cs" />
<Compile Include="UI\Config\Export\ConfigEnrolmentIndexModel.cs" />
<Compile Include="UI\Config\Expressions\ConfigExpressionsBrowserModel.cs" /> <Compile Include="UI\Config\Expressions\ConfigExpressionsBrowserModel.cs" />
<Compile Include="UI\Config\DocumentTemplate\ConfigDocumentTemplateImportStatusModel.cs" /> <Compile Include="UI\Config\DocumentTemplate\ConfigDocumentTemplateImportStatusModel.cs" />
<Compile Include="UI\Config\DocumentTemplate\ConfigDocumentTemplateIndexModel.cs" /> <Compile Include="UI\Config\DocumentTemplate\ConfigDocumentTemplateIndexModel.cs" />
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Disco.Models.Services.Exporting
{
public class SavedExport
{
public int Version { get; set; } = 1;
public Guid Id { get; set; }
public DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
public string Type { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public SavedExportSchedule Schedule { get; set; }
public bool TimestampSuffix { get; set; }
public string FilePath { get; set; }
public string Config { get; set; }
public List<string> OnDemandPrincipals { get; set; }
public bool Enabled { get; set; }
public DateTime? LastRunOn { get; set; }
}
}
@@ -0,0 +1,12 @@
using System;
namespace Disco.Models.Services.Exporting
{
public class SavedExportSchedule
{
public int Version { get; set; } = 1;
public byte WeekDays { get; set; }
public byte StartHour { get; set; }
public byte? EndHour { get; set; }
}
}
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
namespace Disco.Models.UI.Config.Export
{
public interface ConfigExportCreateModel : BaseUIModel
{
string ExportTypeName { get; set; }
Guid Id { get; set; }
string Name { get; set; }
string Description { get; set; }
string FilePath { get; set; }
bool TimestampSuffix { get; set; }
bool ScheduleEnabled { get; set; }
bool ScheduleMonday { get; set; }
bool ScheduleTuesday { get; set; }
bool ScheduleWednesday { get; set; }
bool ScheduleThursday { get; set; }
bool ScheduleFriday { get; set; }
bool ScheduleSaturday { get; set; }
bool ScheduleSunday { get; set; }
byte ScheduleStartHour { get; set; }
byte? ScheduleEndHour { get; set; }
List<string> OnDemandPrincipals { get; set; }
}
}
+8
View File
@@ -81,6 +81,7 @@ namespace Disco.Services.Authorization
{ "Config.UserFlag.Delete", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.UserFlag.Delete, (c, v) => c.Config.UserFlag.Delete = v, "Delete User Flags", "Can delete user flags", false) }, { "Config.UserFlag.Delete", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.UserFlag.Delete, (c, v) => c.Config.UserFlag.Delete = v, "Delete User Flags", "Can delete user flags", false) },
{ "Config.UserFlag.Export", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.UserFlag.Export, (c, v) => c.Config.UserFlag.Export = v, "Export User Flag Assignments", "Can export user flag assignments", false) }, { "Config.UserFlag.Export", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.UserFlag.Export, (c, v) => c.Config.UserFlag.Export = v, "Export User Flag Assignments", "Can export user flag assignments", false) },
{ "Config.UserFlag.Show", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.UserFlag.Show, (c, v) => c.Config.UserFlag.Show = v, "Show User Flags", "Can show user flags", false) }, { "Config.UserFlag.Show", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.UserFlag.Show, (c, v) => c.Config.UserFlag.Show = v, "Show User Flags", "Can show user flags", false) },
{ "Config.ManageSavedExports", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.ManageSavedExports, (c, v) => c.Config.ManageSavedExports = v, "Managed Saved Exports", "Can manage saved exports", false) },
{ "Config.Show", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.Show, (c, v) => c.Config.Show = v, "Show Configuration", "Can show the configuration menu", false) }, { "Config.Show", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.Show, (c, v) => c.Config.Show = v, "Show Configuration", "Can show the configuration menu", false) },
{ "Job.Lists.AllOpen", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Job.Lists.AllOpen, (c, v) => c.Job.Lists.AllOpen = v, "All Open List", "Can show list", false) }, { "Job.Lists.AllOpen", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Job.Lists.AllOpen, (c, v) => c.Job.Lists.AllOpen = v, "All Open List", "Can show list", false) },
{ "Job.Lists.AwaitingFinanceAgreementBreach", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Job.Lists.AwaitingFinanceAgreementBreach, (c, v) => c.Job.Lists.AwaitingFinanceAgreementBreach = v, "Awaiting Finance Agreement Breach List", "Can show list (NOTE: Requires Awaiting Finance List)", false) }, { "Job.Lists.AwaitingFinanceAgreementBreach", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Job.Lists.AwaitingFinanceAgreementBreach, (c, v) => c.Job.Lists.AwaitingFinanceAgreementBreach = v, "Awaiting Finance Agreement Breach List", "Can show list (NOTE: Requires Awaiting Finance List)", false) },
@@ -325,6 +326,7 @@ namespace Disco.Services.Authorization
new ClaimNavigatorItem("Config.UserFlag.Export", false), new ClaimNavigatorItem("Config.UserFlag.Export", false),
new ClaimNavigatorItem("Config.UserFlag.Show", false) new ClaimNavigatorItem("Config.UserFlag.Show", false)
}), }),
new ClaimNavigatorItem("Config.ManageSavedExports", false),
new ClaimNavigatorItem("Config.Show", false) new ClaimNavigatorItem("Config.Show", false)
}), }),
new ClaimNavigatorItem("Job", "Job", "Permissions related to Jobs", false, new List<IClaimNavigatorItem>() { new ClaimNavigatorItem("Job", "Job", "Permissions related to Jobs", false, new List<IClaimNavigatorItem>() {
@@ -623,6 +625,7 @@ namespace Disco.Services.Authorization
c.Config.UserFlag.Delete = true; c.Config.UserFlag.Delete = true;
c.Config.UserFlag.Export = true; c.Config.UserFlag.Export = true;
c.Config.UserFlag.Show = true; c.Config.UserFlag.Show = true;
c.Config.ManageSavedExports = true;
c.Config.Show = true; c.Config.Show = true;
c.Job.Lists.AllOpen = true; c.Job.Lists.AllOpen = true;
c.Job.Lists.AwaitingFinanceAgreementBreach = true; c.Job.Lists.AwaitingFinanceAgreementBreach = true;
@@ -1187,6 +1190,11 @@ namespace Disco.Services.Authorization
public const string Show = "Config.UserFlag.Show"; public const string Show = "Config.UserFlag.Show";
} }
/// <summary>Managed Saved Exports
/// <para>Can manage saved exports</para>
/// </summary>
public const string ManageSavedExports = "Config.ManageSavedExports";
/// <summary>Show Configuration /// <summary>Show Configuration
/// <para>Can show the configuration menu</para> /// <para>Can show the configuration menu</para>
/// </summary> /// </summary>
@@ -38,6 +38,9 @@ namespace Disco.Services.Authorization.Roles.ClaimGroups.Configuration
[ClaimDetails("Show Configuration", "Can show the configuration menu")] [ClaimDetails("Show Configuration", "Can show the configuration menu")]
public bool Show { get; set; } public bool Show { get; set; }
[ClaimDetails("Managed Saved Exports", "Can manage saved exports")]
public bool ManageSavedExports { get; set; }
public DeviceCertificateClaims DeviceCertificate { get; set; } public DeviceCertificateClaims DeviceCertificate { get; set; }
public EnrolmentClaims Enrolment { get; set; } public EnrolmentClaims Enrolment { get; set; }
+8 -15
View File
@@ -2,7 +2,9 @@
using Disco.Models.Exporting; using Disco.Models.Exporting;
using Disco.Models.Repository; using Disco.Models.Repository;
using Disco.Models.Services.Devices; using Disco.Models.Services.Devices;
using Disco.Models.Services.Devices.DeviceFlag;
using Disco.Models.Services.Exporting; using Disco.Models.Services.Exporting;
using Disco.Services.Devices.DeviceFlags;
using Disco.Services.Exporting; using Disco.Services.Exporting;
using Disco.Services.Plugins.Features.DetailsProvider; using Disco.Services.Plugins.Features.DetailsProvider;
using Disco.Services.Tasks; using Disco.Services.Tasks;
@@ -19,31 +21,22 @@ namespace Disco.Services.Devices
public class DeviceExport : IExport<DeviceExportOptions, DeviceExportRecord> public class DeviceExport : IExport<DeviceExportOptions, DeviceExportRecord>
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public string Name { get; set; } public string Name { get; } = "Device Export";
public string Description { get; set; }
public bool TimestampSuffix { get; set; }
public DeviceExportOptions Options { get; set; } public DeviceExportOptions Options { get; set; }
public string SuggestedFilenamePrefix { get; } = "DeviceExport"; public string FilenamePrefix { get; } = "DeviceExport";
public string ExcelWorksheetName { get; } = "DeviceExport"; public string ExcelWorksheetName { get; } = "DeviceExport";
public string ExcelTableName { get; } = "Devices"; public string ExcelTableName { get; } = "Devices";
[JsonConstructor] public DeviceExport(DeviceExportOptions options)
private DeviceExport()
{
}
public DeviceExport(string name, string description, bool timestampSuffix, DeviceExportOptions options)
{ {
Id = Guid.NewGuid(); Id = Guid.NewGuid();
Name = name;
Description = description;
TimestampSuffix = timestampSuffix;
Options = options; Options = options;
} }
public DeviceExport(DeviceExportOptions options) [JsonConstructor]
: this("Device Export", null, true, options) public DeviceExport()
: this(DeviceExportOptions.DefaultOptions())
{ {
} }
@@ -17,31 +17,22 @@ namespace Disco.Services.Devices.DeviceFlags
public class DeviceFlagExport : IExport<DeviceFlagExportOptions, DeviceFlagExportRecord> public class DeviceFlagExport : IExport<DeviceFlagExportOptions, DeviceFlagExportRecord>
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public string Name { get; set; } public string Name { get; } = "Device Flag Export";
public string Description { get; set; }
public bool TimestampSuffix { get; set; }
public DeviceFlagExportOptions Options { get; set; } public DeviceFlagExportOptions Options { get; set; }
public string SuggestedFilenamePrefix { get; } = "DeviceFlagExport"; public string FilenamePrefix { get; } = "DeviceFlagExport";
public string ExcelWorksheetName { get; } = "DeviceFlagExport"; public string ExcelWorksheetName { get; } = "DeviceFlagExport";
public string ExcelTableName { get; } = "DeviceFlags"; public string ExcelTableName { get; } = "DeviceFlags";
[JsonConstructor] public DeviceFlagExport(DeviceFlagExportOptions options)
private DeviceFlagExport()
{
}
public DeviceFlagExport(string name, string description, bool timestampSuffix, DeviceFlagExportOptions options)
{ {
Id = Guid.NewGuid(); Id = Guid.NewGuid();
Name = name;
Description = description;
TimestampSuffix = timestampSuffix;
Options = options; Options = options;
} }
public DeviceFlagExport(DeviceFlagExportOptions options) [JsonConstructor]
: this("Device Flag Export", null, true, options) public DeviceFlagExport()
: this(DeviceFlagExportOptions.DefaultOptions())
{ {
} }
+3
View File
@@ -425,6 +425,8 @@
<Compile Include="Documents\ManagedGroups\DocumentTemplateUsersManagedGroup.cs" /> <Compile Include="Documents\ManagedGroups\DocumentTemplateUsersManagedGroup.cs" />
<Compile Include="Documents\QRCodeBinaryEncoder.cs" /> <Compile Include="Documents\QRCodeBinaryEncoder.cs" />
<Compile Include="Exporting\IExport.cs" /> <Compile Include="Exporting\IExport.cs" />
<Compile Include="Exporting\SavedExports.cs" />
<Compile Include="Exporting\SavedExportTask.cs" />
<Compile Include="Expressions\EvaluateExpressionParseException.cs" /> <Compile Include="Expressions\EvaluateExpressionParseException.cs" />
<Compile Include="Expressions\EvaluateExpressionPart.cs" /> <Compile Include="Expressions\EvaluateExpressionPart.cs" />
<Compile Include="Expressions\Expression.cs" /> <Compile Include="Expressions\Expression.cs" />
@@ -531,6 +533,7 @@
<Compile Include="Plugins\Features\DetailsProvider\DetailsProviderService.cs" /> <Compile Include="Plugins\Features\DetailsProvider\DetailsProviderService.cs" />
<Compile Include="Plugins\Features\DetailsProvider\UserContactFeature.cs" /> <Compile Include="Plugins\Features\DetailsProvider\UserContactFeature.cs" />
<Compile Include="Plugins\Features\DocumentHandlerProvider\DocumentHandlerProviderFeature.cs" /> <Compile Include="Plugins\Features\DocumentHandlerProvider\DocumentHandlerProviderFeature.cs" />
<Compile Include="Plugins\Features\ExportProvider\ExportProviderFeature.cs" />
<Compile Include="Plugins\Features\ExpressionExtensionProvider\ExpressionExtensionProviderFeature.cs" /> <Compile Include="Plugins\Features\ExpressionExtensionProvider\ExpressionExtensionProviderFeature.cs" />
<Compile Include="Plugins\Features\ExpressionExtensionProvider\ExpressionExtensionRegistration.cs" /> <Compile Include="Plugins\Features\ExpressionExtensionProvider\ExpressionExtensionRegistration.cs" />
<Compile Include="Plugins\Features\InsuranceProvider\InsuranceProviderFeature.cs" /> <Compile Include="Plugins\Features\InsuranceProvider\InsuranceProviderFeature.cs" />
+2 -2
View File
@@ -11,8 +11,8 @@ namespace Disco.Services.Exporting
{ {
private IExport context; private IExport context;
public override string TaskName { get => context?.Name ?? "Exporting"; } public override string TaskName { get => context?.Name ?? "Exporting"; }
public override bool SingleInstanceTask { get { return false; } } public override bool SingleInstanceTask { get; } = false;
public override bool CancelInitiallySupported { get { return false; } } public override bool CancelInitiallySupported { get; } = false;
public static ExportTaskContext ScheduleNow(IExport export) public static ExportTaskContext ScheduleNow(IExport export)
{ {
+11 -16
View File
@@ -16,35 +16,32 @@ namespace Disco.Services.Exporting
{ {
public static class Exporter public static class Exporter
{ {
public static ExportResult Export<T, R>(IExport<T, R> context, DiscoDataContext database, IScheduledTaskStatus status) public static ExportResult Export<T, R>(IExport<T, R> export, DiscoDataContext database, IScheduledTaskStatus status)
where T : IExportOptions, new() where T : IExportOptions, new()
where R : IExportRecord where R : IExportRecord
{ {
MemoryStream stream; MemoryStream stream;
string mimeType; string mimeType;
status.UpdateStatus(1, $"Exporting {context.Name}", "Gathering data"); status.UpdateStatus(1, $"Exporting {export.Name}", "Gathering data");
var records = context.BuildRecords(database, status); var records = export.BuildRecords(database, status);
status.UpdateStatus(70, "Building metadata"); status.UpdateStatus(70, "Building metadata");
var metadata = context.BuildMetadata(database, records, status); var metadata = export.BuildMetadata(database, records, status);
if (metadata.Count == 0) if (metadata.Count == 0)
throw new ArgumentException("At least one export field must be specified", nameof(context.Options)); throw new ArgumentException("At least one export field must be specified", nameof(export.Options));
var filenameBuilder = new StringBuilder(); var filenameBuilder = new StringBuilder();
filenameBuilder.Append(context.SuggestedFilenamePrefix); filenameBuilder.Append(export.FilenamePrefix);
if (context.TimestampSuffix) filenameBuilder.Append('-');
{ filenameBuilder.Append(status.StartedTimestamp.Value.ToString("yyyyMMdd-HHmmss"));
filenameBuilder.Append('-');
filenameBuilder.Append(status.StartedTimestamp.Value.ToString("yyyyMMdd-HHmmss"));
}
status.UpdateStatus(80, $"Rendering {records.Count} records for export"); status.UpdateStatus(80, $"Rendering {records.Count} records for export");
switch (context.Options.Format) switch (export.Options.Format)
{ {
case ExportFormat.Csv: case ExportFormat.Csv:
filenameBuilder.Append(".csv"); filenameBuilder.Append(".csv");
@@ -54,10 +51,10 @@ namespace Disco.Services.Exporting
case ExportFormat.Xlsx: case ExportFormat.Xlsx:
filenameBuilder.Append(".xlsx"); filenameBuilder.Append(".xlsx");
mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
stream = WriteXlsx(context.ExcelWorksheetName, context.ExcelTableName, metadata, records); stream = WriteXlsx(export.ExcelWorksheetName, export.ExcelTableName, metadata, records);
break; break;
default: default:
throw new NotSupportedException($"Unsupported export format: {context.Options.Format}"); throw new NotSupportedException($"Unsupported export format: {export.Options.Format}");
} }
return new ExportResult() return new ExportResult()
@@ -99,7 +96,6 @@ namespace Disco.Services.Exporting
stream.Position = 0; stream.Position = 0;
return stream; return stream;
} }
private static MemoryStream WriteXlsx<T>(string worksheetName, string tableName, List<ExportMetadataField<T>> metadata, List<T> records) where T : IExportRecord private static MemoryStream WriteXlsx<T>(string worksheetName, string tableName, List<ExportMetadataField<T>> metadata, List<T> records) where T : IExportRecord
{ {
var stream = new MemoryStream(); var stream = new MemoryStream();
@@ -151,7 +147,6 @@ namespace Disco.Services.Exporting
metadata.Add(columnName, valueAccessor, csvValueEncoder); metadata.Add(columnName, valueAccessor, csvValueEncoder);
} }
public static void Add<T, V>(this ExportMetadata<T> metadata, string columnName, Func<T, V> valueAccessor, Func<object, string> csvValueEncoder = null) public static void Add<T, V>(this ExportMetadata<T> metadata, string columnName, Func<T, V> valueAccessor, Func<object, string> csvValueEncoder = null)
where T : IExportRecord where T : IExportRecord
{ {
+3 -5
View File
@@ -11,8 +11,8 @@ namespace Disco.Services.Exporting
public interface IExport public interface IExport
{ {
Guid Id { get; set; } Guid Id { get; set; }
string Name { get; set; } [JsonIgnore]
string Description { get; set; } string Name { get; }
ExportResult Export(DiscoDataContext database, IScheduledTaskStatus status); ExportResult Export(DiscoDataContext database, IScheduledTaskStatus status);
} }
@@ -22,10 +22,8 @@ namespace Disco.Services.Exporting
where T : IExportOptions, new() where T : IExportOptions, new()
where R : IExportRecord where R : IExportRecord
{ {
bool TimestampSuffix { get; set; }
[JsonIgnore] [JsonIgnore]
string SuggestedFilenamePrefix { get; } string FilenamePrefix { get; }
[JsonIgnore] [JsonIgnore]
string ExcelWorksheetName { get; } string ExcelWorksheetName { get; }
[JsonIgnore] [JsonIgnore]
@@ -0,0 +1,42 @@
using Disco.Data.Repository;
using Disco.Services.Tasks;
using Quartz;
using System;
namespace Disco.Services.Exporting
{
public class SavedExportTask : ScheduledTask
{
public override string TaskName { get; } = "Saved Export Scheduler";
public override bool SingleInstanceTask { get; } = true;
public override bool CancelInitiallySupported { get; } = false;
public override bool LogExceptionsOnly { get; } = true;
public override void InitalizeScheduledTask(DiscoDataContext Database)
{
// run in 30 seconds, then every hour on the hour
if (DateTime.Now.Minute != 59)
{
var immediateTrigger = TriggerBuilder.Create().StartAt(DateTimeOffset.Now.AddSeconds(30));
ScheduleTask(immediateTrigger);
}
var nextHourTicks = DateTime.UtcNow.Ticks;
nextHourTicks -= nextHourTicks % TimeSpan.TicksPerHour; // round down to the hour
var nextHour = new DateTime(nextHourTicks, DateTimeKind.Utc)
.AddHours(1)
.AddSeconds(1);
var hourlyTrigger = TriggerBuilder.Create()
.StartAt(nextHour)
.WithSchedule(SimpleScheduleBuilder.RepeatHourlyForever());
ScheduleTask(hourlyTrigger);
}
protected override void ExecuteTask()
{
SavedExports.EvaluateSavedExports();
}
}
}
+319
View File
@@ -0,0 +1,319 @@
using Disco.Data.Repository;
using Disco.Models.Exporting;
using Disco.Models.Repository;
using Disco.Models.Services.Devices;
using Disco.Models.Services.Devices.DeviceFlag;
using Disco.Models.Services.Exporting;
using Disco.Models.Services.Jobs;
using Disco.Models.Services.Users.UserFlags;
using Disco.Services.Authorization;
using Disco.Services.Devices;
using Disco.Services.Devices.DeviceFlags;
using Disco.Services.Jobs;
using Disco.Services.Logging;
using Disco.Services.Tasks;
using Disco.Services.Users.UserFlags;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Disco.Services.Exporting
{
public static class SavedExports
{
private static Dictionary<string, (Type Type, string Name, Func<IExport, DiscoDataContext, IScheduledTaskStatus, ExportResult> ExporterDelegate)> exportTypes = new Dictionary<string, (Type, string, Func<IExport, DiscoDataContext, IScheduledTaskStatus, ExportResult>)>();
static SavedExports()
{
RegisterExportType<DeviceFlagExport, DeviceFlagExportOptions, DeviceFlagExportRecord>();
RegisterExportType<DeviceExport, DeviceExportOptions, DeviceExportRecord>();
RegisterExportType<JobExport, JobExportOptions, JobExportRecord>();
RegisterExportType<UserFlagExport, UserFlagExportOptions, UserFlagExportRecord>();
}
internal static void RegisterExportType<T, E, R>()
where T : IExport<E, R>, new()
where E : IExportOptions, new()
where R : IExportRecord
{
var type = typeof(T);
if (exportTypes.TryGetValue(type.Name, out var existing))
{
if (existing.Type != type)
throw new InvalidOperationException($"Export type already registered ({type.FullName})");
}
else
{
var name = new T().Name;
exportTypes[type.Name] = (type, name, (i, d, s) => Exporter.Export((T)i, d, s));
}
}
public static SavedExport SaveExport<T, R>(IExport<T, R> export, DiscoDataContext database, User createdBy)
where T : IExportOptions, new()
where R : IExportRecord
{
var exportType = export.GetType();
if (!exportTypes.TryGetValue(exportType.Name, out var exportTypeRef) || exportType != exportTypeRef.Type)
throw new InvalidOperationException($"Export type not registered for saving ({exportType.FullName})");
var saved = new SavedExport()
{
Version = 1,
Id = Guid.NewGuid(),
CreatedOn = DateTime.Now,
CreatedBy = createdBy.UserId,
Type = exportType.Name,
Config = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(export, Formatting.None))),
Enabled = false,
};
var exports = database.DiscoConfiguration.SavedExports;
exports.Add(saved);
database.DiscoConfiguration.SavedExports = exports;
database.SaveChanges();
return saved;
}
public static void DeleteSavedExport(DiscoDataContext database, Guid id)
{
var exports = database.DiscoConfiguration.SavedExports;
var existing = exports.FirstOrDefault(e => e.Id == id);
if (existing == null)
return;
exports.Remove(existing);
database.DiscoConfiguration.SavedExports = exports;
database.SaveChanges();
}
public static void UpdateSavedExport(DiscoDataContext database, SavedExport export)
{
var exports = database.DiscoConfiguration.SavedExports;
var existing = exports.First(e => e.Id == export.Id);
if (string.IsNullOrWhiteSpace(export.Name))
throw new InvalidOperationException("Export name is required");
existing.Name = export.Name;
existing.Description = export.Description;
if (string.IsNullOrWhiteSpace(export.FilePath) || export.Schedule == null || export.Schedule.WeekDays == 0)
{
existing.Schedule = null;
existing.FilePath = null;
}
else
{
// new file path - file cannot exist
if (existing.FilePath == null && File.Exists(export.FilePath))
throw new InvalidOperationException("Export file path already exists, delete the file before configuring the saved export");
// directory must exist
if (!Directory.Exists(Path.GetDirectoryName(export.FilePath)))
throw new InvalidOperationException("Invalid export file path, the directory does not exist");
existing.FilePath = export.FilePath;
existing.TimestampSuffix = export.TimestampSuffix;
existing.Schedule = new SavedExportSchedule()
{
Version = 1,
WeekDays = export.Schedule.WeekDays,
StartHour = export.Schedule.EndHour.HasValue ? Math.Min(export.Schedule.StartHour, export.Schedule.EndHour.Value) : export.Schedule.StartHour,
EndHour = !export.Schedule.EndHour.HasValue ? null : (export.Schedule.EndHour.Value == export.Schedule.StartHour ? (byte?)null : Math.Max(export.Schedule.StartHour, export.Schedule.EndHour.Value)),
};
}
if (existing.FilePath != null && existing.Schedule == null)
throw new InvalidOperationException("Export file path requires a schedule");
if (export.OnDemandPrincipals == null || export.OnDemandPrincipals.Count == 0)
existing.OnDemandPrincipals = null;
else
existing.OnDemandPrincipals = new List<string>(export.OnDemandPrincipals);
existing.Enabled = true;
database.DiscoConfiguration.SavedExports = exports;
database.SaveChanges();
}
public static SavedExport GetSavedExport(DiscoDataContext database, Guid id, out string exportTypeName)
{
var export = database.DiscoConfiguration.SavedExports.FirstOrDefault(e => e.Id == id);
if (export == null)
{
exportTypeName = null;
return null;
}
exportTypeName = exportTypes[export.Type].Name;
return export;
}
public static List<SavedExport> GetSavedExports(DiscoDataContext database, string type, out string exportTypeName)
{
var exports = database.DiscoConfiguration.SavedExports.Where(e => e.Type == type).ToList();
if (exports.Count == 0)
{
exportTypeName = null;
return null;
}
exportTypeName = exportTypes[type].Name;
return exports;
}
public static bool IsAuthorized(SavedExport savedExport, AuthorizationToken authorization)
{
if (authorization.Has(Claims.Config.ManageSavedExports))
return true;
if (savedExport.OnDemandPrincipals == null || savedExport.OnDemandPrincipals.Count == 0)
return false;
if (savedExport.OnDemandPrincipals.Contains(authorization.User.UserId, StringComparer.OrdinalIgnoreCase))
return true;
if (savedExport.OnDemandPrincipals.Any(p => authorization.GroupMembership.Contains(p, StringComparer.OrdinalIgnoreCase)))
return true;
return false;
}
public static void EvaluateSavedExports()
{
using (var database = new DiscoDataContext())
{
CleanupSavedExports(database);
var scheduledExports = GetScheduledExports(database).ToList();
foreach (var scheduledExport in scheduledExports)
{
ExportResult exportResult = null;
try
{
exportResult = EvaluateSavedExport(database, scheduledExport);
}
catch (Exception ex)
{
SystemLog.LogException($"Failed to generate saved '{scheduledExport.Name}' [{scheduledExport.Id}]", ex);
continue;
}
var filePath = scheduledExport.FilePath;
if (scheduledExport.TimestampSuffix)
{
var timestamp = DateTime.Now.ToString("yyyyMMdd-HH");
var extension = Path.GetExtension(filePath);
filePath = Path.Combine(Path.GetDirectoryName(filePath), $"{Path.GetFileNameWithoutExtension(filePath)}-{timestamp}{extension}");
}
try
{
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
exportResult.Result.CopyTo(fileStream);
}
SystemLog.LogInformation($"Saved '{scheduledExport.Name}' [{scheduledExport.Name}] wrote to '{filePath}'");
}
catch (Exception ex)
{
SystemLog.LogException($"Failed to write saved '{scheduledExport.Name}' [{scheduledExport.Id}] to '{filePath}'", ex);
}
}
}
}
public static ExportResult EvaluateSavedExport(DiscoDataContext database, SavedExport savedExport)
{
var (exportType, _, exportDelegate) = exportTypes[savedExport.Type];
var export = (IExport)JsonConvert.DeserializeObject(Encoding.UTF8.GetString(Convert.FromBase64String(savedExport.Config)), exportType);
return exportDelegate(export, database, ScheduledTaskMockStatus.Create(export.Name));
}
private static void CleanupSavedExports(DiscoDataContext database)
{
var exports = database.DiscoConfiguration.SavedExports;
var changed = false;
for (int i = 0; i < exports.Count; i++)
{
var export = exports[i];
if (export.Enabled)
continue;
if (export.CreatedOn.AddDays(1) < DateTime.Now)
{
exports.RemoveAt(i);
i--;
changed = true;
}
}
if (changed)
{
database.DiscoConfiguration.SavedExports = exports;
database.SaveChanges();
}
}
private static IEnumerable<SavedExport> GetScheduledExports(DiscoDataContext database)
{
var exports = database.DiscoConfiguration.SavedExports;
var now = DateTime.Now;
var hour = now.Hour;
var day = (byte)(1 << (int)now.DayOfWeek);
foreach (var export in exports)
{
if (!export.Enabled)
continue;
if (string.IsNullOrEmpty(export.FilePath))
continue;
// skip unknown export types
if (!exportTypes.ContainsKey(export.Type))
continue;
var schedule = export.Schedule;
if (schedule == null)
continue;
// scheduled for today?
if ((schedule.WeekDays & day) == 0)
continue;
// always run if scheduled earlier today? (potentially missed)
if (schedule.StartHour >= hour || export.LastRunOn.GetValueOrDefault().Date == DateTime.Today)
{
// are we beyond the end hour?
if (schedule.EndHour.HasValue && hour > schedule.EndHour.Value)
continue;
// if no end hour and not the start hour, skip
if (!schedule.EndHour.HasValue && schedule.StartHour != hour)
continue;
// before the start hour, skip
if (hour < schedule.StartHour)
continue;
}
yield return export;
}
}
}
}
+7 -15
View File
@@ -18,31 +18,23 @@ namespace Disco.Services.Jobs
public class JobExport : IExport<JobExportOptions, JobExportRecord> public class JobExport : IExport<JobExportOptions, JobExportRecord>
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public string Name { get; set; } public string Name { get; } = "Job Export";
public string Description { get; set; }
public bool TimestampSuffix { get; set; }
public JobExportOptions Options { get; set; } public JobExportOptions Options { get; set; }
public string SuggestedFilenamePrefix { get; } = "JobExport"; public string FilenamePrefix { get; } = "JobExport";
public string ExcelWorksheetName { get; } = "JobExport"; public string ExcelWorksheetName { get; } = "JobExport";
public string ExcelTableName { get; } = "Jobs"; public string ExcelTableName { get; } = "Jobs";
[JsonConstructor] public JobExport(JobExportOptions options)
private JobExport()
{
}
public JobExport(string name, string description, bool timestampSuffix, JobExportOptions options)
{ {
Id = Guid.NewGuid(); Id = Guid.NewGuid();
Name = name;
Description = description;
TimestampSuffix = timestampSuffix;
Options = options; Options = options;
} }
public JobExport(JobExportOptions options)
: this("Job Export", null, true, options) [JsonConstructor]
public JobExport()
: this(JobExportOptions.DefaultOptions())
{ {
} }
+3 -13
View File
@@ -15,12 +15,10 @@ namespace Disco.Services.Logging
public class LogExport : IExport<LogExportOptions, LogLiveEvent> public class LogExport : IExport<LogExportOptions, LogLiveEvent>
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public string Name { get; set; } public string Name { get; } = "Log Export";
public string Description { get; set; }
public bool TimestampSuffix { get; set; }
public LogExportOptions Options { get; set; } public LogExportOptions Options { get; set; }
public string SuggestedFilenamePrefix { get; } = "DiscoIctLogs"; public string FilenamePrefix { get; } = "DiscoIctLogs";
public string ExcelWorksheetName { get; } = "Disco ICT Logs"; public string ExcelWorksheetName { get; } = "Disco ICT Logs";
public string ExcelTableName { get; } = "DiscoIctLogs"; public string ExcelTableName { get; } = "DiscoIctLogs";
@@ -29,20 +27,12 @@ namespace Disco.Services.Logging
{ {
} }
public LogExport(string name, string description, bool timestampSuffix, LogExportOptions options) public LogExport(LogExportOptions options)
{ {
Id = Guid.NewGuid(); Id = Guid.NewGuid();
Name = name;
Description = description;
TimestampSuffix = timestampSuffix;
Options = options; Options = options;
} }
public LogExport(LogExportOptions options)
: this("Log Export", null, true, options)
{
}
public ExportResult Export(DiscoDataContext database, IScheduledTaskStatus status) public ExportResult Export(DiscoDataContext database, IScheduledTaskStatus status)
=> Exporter.Export(this, database, status); => Exporter.Export(this, database, status);
@@ -0,0 +1,18 @@
using Disco.Models.Exporting;
using Disco.Models.Services.Exporting;
using Disco.Services.Exporting;
namespace Disco.Services.Plugins.Features.ExportProvider
{
[PluginFeatureCategory(DisplayName = "Exporter")]
public class ExportProviderFeature : PluginFeature
{
public void RegisterExportType<T, E, R>()
where T : IExport<E, R>, new()
where E : IExportOptions, new()
where R : IExportRecord
{
SavedExports.RegisterExportType<T, E, R>();
}
}
}
@@ -13,37 +13,32 @@ using System.Linq;
namespace Disco.Services.Users.UserFlags namespace Disco.Services.Users.UserFlags
{ {
public class UserFlagExport : IExport<UserFlagExportOptions, UserFlagExportRecord> public sealed class UserFlagExport : IExport<UserFlagExportOptions, UserFlagExportRecord>
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public string Name { get; set; } public string Name { get; } = "User Flag Export";
public string Description { get; set; } public string Description { get; set; }
public bool TimestampSuffix { get; set; }
public UserFlagExportOptions Options { get; set; } public UserFlagExportOptions Options { get; set; }
public string SuggestedFilenamePrefix { get; } = "UserFlagExport"; public string FilenamePrefix { get; } = "UserFlagExport";
public string ExcelWorksheetName { get; } = "UserFlagExport"; public string ExcelWorksheetName { get; } = "UserFlagExport";
public string ExcelTableName { get; } = "UserFlags"; public string ExcelTableName { get; } = "UserFlags";
[JsonConstructor] public UserFlagExport(UserFlagExportOptions options)
private UserFlagExport()
{
}
public UserFlagExport(string name, string description, bool timestampSuffix, UserFlagExportOptions options)
{ {
Id = Guid.NewGuid(); Id = Guid.NewGuid();
Name = name;
Description = description;
TimestampSuffix = timestampSuffix;
Options = options; Options = options;
} }
public UserFlagExport(UserFlagExportOptions options) [JsonConstructor]
: this("User Flag Export", null, true, options) public UserFlagExport()
: this(UserFlagExportOptions.DefaultOptions())
{ {
} }
public static UserFlagExport Create()
=> new UserFlagExport(new UserFlagExportOptions());
public ExportResult Export(DiscoDataContext database, IScheduledTaskStatus status) public ExportResult Export(DiscoDataContext database, IScheduledTaskStatus status)
=> Exporter.Export(this, database, status); => Exporter.Export(this, database, status);
@@ -725,6 +725,15 @@ namespace Disco.Web.Areas.API.Controllers
return this.File(fileStream.GetBuffer(), 0, (int)fileStream.Length, context.Result.MimeType, context.Result.Filename); return this.File(fileStream.GetBuffer(), 0, (int)fileStream.Length, context.Result.MimeType, context.Result.Filename);
} }
[DiscoAuthorizeAll(Claims.Config.ManageSavedExports, Claims.Device.Actions.Export)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult SaveExport(ExportModel Model)
{
var export = new DeviceExport(Model.Options);
var savedExport = SavedExports.SaveExport(export, Database, CurrentUser);
return RedirectToAction(MVC.Config.Export.Create(savedExport.Id));
}
#endregion #endregion
@@ -0,0 +1,78 @@
using Disco.Models.UI.Config.Export;
using Disco.Services.Authorization;
using Disco.Services.Exporting;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Plugins.Features.UIExtension;
using Disco.Services.Web;
using Disco.Web.Areas.API.Models.Shared;
using Disco.Web.Areas.Config.Models.Export;
using Disco.Web.Extensions;
using System;
using System.Linq;
using System.Web.Mvc;
namespace Disco.Web.Areas.Config.Controllers
{
[DiscoAuthorize(Claims.Config.ManageSavedExports)]
public partial class ExportController : AuthorizedDatabaseController
{
[HttpGet]
public virtual ActionResult Create(Guid id)
{
var export = SavedExports.GetSavedExport(Database, id, out var exportTypeName);
if (export == null)
return HttpNotFound();
var m = CreateModel.FromSavedExport(export, exportTypeName);
// UI Extensions
UIExtensions.ExecuteExtensions<ConfigExportCreateModel>(ControllerContext, m);
return View(m);
}
[HttpPost]
public virtual ActionResult Create(CreateModel model)
{
if (model.OnDemandPrincipals != null)
{
model.OnDemandSubjects = model.OnDemandPrincipals
.Where(p => !string.IsNullOrWhiteSpace(p))
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(p => ActiveDirectory.RetrieveADObject(p, true))
.Where(ad => ad is ADUserAccount || ad is ADGroup)
.Select(ad => SubjectDescriptorModel.FromActiveDirectoryObject(ad))
.ToList();
}
if (ModelState.IsValid)
{
SavedExports.UpdateSavedExport(Database, model.ToSavedExport());
}
// UI Extensions
UIExtensions.ExecuteExtensions<ConfigExportCreateModel>(ControllerContext, model);
return View(model);
}
[DiscoAuthorize]
public virtual ActionResult Run(Guid id)
{
var export = SavedExports.GetSavedExport(Database, id, out _);
if (export == null)
return HttpNotFound();
if (!SavedExports.IsAuthorized(export, Authorization))
return new HttpStatusCodeResult(System.Net.HttpStatusCode.Forbidden, "Not authorized to run export");
var exportResult = SavedExports.EvaluateSavedExport(Database, export);
var fileStream = exportResult.Result;
return this.File(fileStream.GetBuffer(), 0, (int)fileStream.Length, exportResult.MimeType, exportResult.Filename);
}
}
}
@@ -0,0 +1,83 @@
using Disco.Models.Services.Exporting;
using Disco.Models.UI.Config.Export;
using Disco.Web.Areas.API.Models.Shared;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace Disco.Web.Areas.Config.Models.Export
{
public class CreateModel : ConfigExportCreateModel
{
public string ExportTypeName { get; set; }
[Required]
public Guid Id { get; set; }
[Required]
public string Name { get; set; }
[DataType(DataType.MultilineText)]
public string Description { get; set; }
public string FilePath { get; set; }
public bool TimestampSuffix { get; set; }
public bool ScheduleEnabled { get; set; }
public bool ScheduleMonday { get; set; }
public bool ScheduleTuesday { get; set; }
public bool ScheduleWednesday { get; set; }
public bool ScheduleThursday { get; set; }
public bool ScheduleFriday { get; set; }
public bool ScheduleSaturday { get; set; }
public bool ScheduleSunday { get; set; }
[Range(0, 23)]
public byte ScheduleStartHour { get; set; }
[Range(0, 23)]
public byte? ScheduleEndHour { get; set; }
public List<SubjectDescriptorModel> OnDemandSubjects { get; set; }
public List<string> OnDemandPrincipals { get; set; }
public static CreateModel FromSavedExport(SavedExport savedExport, string exportTypeName)
{
return new CreateModel
{
Id = savedExport.Id,
ExportTypeName = exportTypeName,
ScheduleMonday = true,
ScheduleTuesday = true,
ScheduleWednesday = true,
ScheduleThursday = true,
ScheduleFriday = true,
};
}
public SavedExport ToSavedExport()
{
var weekDays = default(byte);
if (ScheduleMonday) weekDays |= 1 << (int)DayOfWeek.Monday;
if (ScheduleTuesday) weekDays |= 1 << (int)DayOfWeek.Tuesday;
if (ScheduleWednesday) weekDays |= 1 << (int)DayOfWeek.Wednesday;
if (ScheduleThursday) weekDays |= 1 << (int)DayOfWeek.Thursday;
if (ScheduleFriday) weekDays |= 1 << (int)DayOfWeek.Friday;
if (ScheduleSaturday) weekDays |= 1 << (int)DayOfWeek.Saturday;
if (ScheduleSunday) weekDays |= 1 << (int)DayOfWeek.Sunday;
return new SavedExport
{
Id = Id,
Name = Name,
Description = Description,
FilePath = FilePath,
TimestampSuffix = TimestampSuffix,
Schedule = ScheduleEnabled ? new SavedExportSchedule
{
WeekDays = weekDays,
StartHour = ScheduleStartHour,
EndHour = ScheduleEndHour,
} : null,
OnDemandPrincipals = OnDemandSubjects?.Select(s => s.Id).ToList(),
};
}
}
}
@@ -39,7 +39,7 @@ else
</table> </table>
} }
<!-- #region Administrator Subjects --> <!-- #region Administrator Subjects -->
<div id="Config_AuthRoles_Subjects_Update_Dialog" class="dialog" title="Disco Administrators"> <div id="Config_AuthRoles_Subjects_Update_Dialog" class="dialog" title="Disco ICT Administrators">
<div id="Config_AuthRoles_Subjects_Update_Dialog_ListContainer"> <div id="Config_AuthRoles_Subjects_Update_Dialog_ListContainer">
<span id="Config_AuthRoles_Subjects_Update_Dialog_None" class="smallMessage">None Associated</span> <span id="Config_AuthRoles_Subjects_Update_Dialog_None" class="smallMessage">None Associated</span>
<ul id="Config_AuthRoles_Subjects_Update_Dialog_List" class="none"> <ul id="Config_AuthRoles_Subjects_Update_Dialog_List" class="none">
@@ -181,7 +181,7 @@ WriteLiteral(" id=\"Config_AuthRoles_Subjects_Update_Dialog\"");
WriteLiteral(" class=\"dialog\""); WriteLiteral(" class=\"dialog\"");
WriteLiteral(" title=\"Disco Administrators\""); WriteLiteral(" title=\"Disco ICT Administrators\"");
WriteLiteral(">\r\n <div"); WriteLiteral(">\r\n <div");
@@ -218,14 +218,14 @@ WriteLiteral(">\r\n");
#line hidden #line hidden
WriteLiteral(" <li"); WriteLiteral(" <li");
WriteAttribute("class", Tuple.Create(" class=\"", 1805), Tuple.Create("\"", 1845) WriteAttribute("class", Tuple.Create(" class=\"", 1809), Tuple.Create("\"", 1849)
#line 49 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml" #line 49 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
, Tuple.Create(Tuple.Create("", 1813), Tuple.Create<System.Object, System.Int32>(sg.IsGroup ? "group" : "user" , Tuple.Create(Tuple.Create("", 1817), Tuple.Create<System.Object, System.Int32>(sg.IsGroup ? "group" : "user"
#line default #line default
#line hidden #line hidden
, 1813), false) , 1817), false)
); );
WriteLiteral(" data-subjectid=\""); WriteLiteral(" data-subjectid=\"");
@@ -339,14 +339,14 @@ WriteLiteral(">Add</a>\r\n </div>\r\n <form");
WriteLiteral(" id=\"Config_AuthRoles_Subjects_Update_Dialog_Form\""); WriteLiteral(" id=\"Config_AuthRoles_Subjects_Update_Dialog_Form\"");
WriteAttribute("action", Tuple.Create(" action=\"", 2876), Tuple.Create("\"", 2965) WriteAttribute("action", Tuple.Create(" action=\"", 2880), Tuple.Create("\"", 2969)
#line 64 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml" #line 64 "..\..\Areas\Config\Views\AuthorizationRole\Index.cshtml"
, Tuple.Create(Tuple.Create("", 2885), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.API.AuthorizationRole.UpdateAdministratorSubjects(null, true)) , Tuple.Create(Tuple.Create("", 2889), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.API.AuthorizationRole.UpdateAdministratorSubjects(null, true))
#line default #line default
#line hidden #line hidden
, 2885), false) , 2889), false)
); );
WriteLiteral(" method=\"post\""); WriteLiteral(" method=\"post\"");
@@ -0,0 +1,230 @@
@model Disco.Web.Areas.Config.Models.Export.CreateModel
@{
Authorization.Require(Claims.Config.ManageSavedExports);
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Exports", null, "Create Saved " + Model.ExportTypeName);
}
@using (Html.BeginForm(MVC.Config.Export.Create(), FormMethod.Post))
{
@Html.AntiForgeryToken();
@Html.HiddenFor(m => m.Id)
<div id="Config_Export_Create_Details" class="form" style="width: 530px;">
<h2>Save @Model.ExportTypeName</h2>
<table>
<tr>
<th style="width: 140px">Name:</th>
<td>
@Html.EditorFor(model => model.Name)
</td>
</tr>
<tr>
<th>
Description:<br />
<em class="small">Optional</em>
</th>
<td>
@Html.EditorFor(model => model.Description)
</td>
</tr>
</table>
</div>
<div id="Config_Export_Create_Schedule" class="form" style="width: 530px; margin-top: 10px;">
<h2>Schedule</h2>
<table>
<tr>
<th style="width: 140px">&nbsp;</th>
<td>
<label>
@Html.EditorFor(m => m.ScheduleEnabled)
Enable Scheduled Export
</label>
</td>
</tr>
<tr class="@(Model.ScheduleEnabled ? null : "hidden")">
<th>
Days:
</th>
<td>
<ul class="none">
<li><label>@Html.EditorFor(m => m.ScheduleMonday) Monday</label></li>
<li><label>@Html.EditorFor(m => m.ScheduleTuesday) Tuesday</label></li>
<li><label>@Html.EditorFor(m => m.ScheduleWednesday) Wednesday</label></li>
<li><label>@Html.EditorFor(m => m.ScheduleThursday) Thursday</label></li>
<li><label>@Html.EditorFor(m => m.ScheduleFriday) Friday</label></li>
<li><label>@Html.EditorFor(m => m.ScheduleSaturday) Saturday</label></li>
<li><label>@Html.EditorFor(m => m.ScheduleSunday) Sunday</label></li>
</ul>
</td>
</tr>
<tr class="@(Model.ScheduleEnabled ? null : "hidden")">
<th>
Start Time:
</th>
<td>
<select name="ScheduleStartHour">
@{
<option value="0" @(Model.ScheduleStartHour == 0 ? "selected" : null)>12:00 AM</option>
for (int i = 1; i < 12; i++)
{
<option value="@i" @(Model.ScheduleStartHour == i ? "selected" : null)>@i:00 AM</option>
}
<option value="12" @(Model.ScheduleStartHour == 12 ? "selected" : null)>12:00 PM</option>
for (int i = 13; i < 24; i++)
{
<option value="@i" @(Model.ScheduleStartHour == i ? "selected" : null)>@(i % 12):00 PM</option>
}
}
</select>
<div class="info-box">
<p class="fa-p">
<i class="fa fa-fw fa-info-circle"></i> By default, Disco ICT shuts down at 1:30am and does not resume again until its needed. If a scheduled export was missed during this time, it will be run as soon as Disco ICT is resumed.
</p>
</div>
</td>
</tr>
<tr class="@(Model.ScheduleEnabled ? null : "hidden")">
<th>
Repeat Hourly Until:
</th>
<td>
<select name="ScheduleEndHour">
<option value="" @(Model.ScheduleEndHour.HasValue ? null : "selected")>Run once</option>
@{
for (int i = 1; i < 12; i++)
{
<option value="@i" @(Model.ScheduleEndHour == i ? "selected" : null)>@i:00 AM</option>
}
<option value="12" @(Model.ScheduleEndHour == 12 ? "selected" : null)>12:00 PM</option>
for (int i = 12; i < 24; i++)
{
<option value="@i" @(Model.ScheduleEndHour == i ? "selected" : null)>@(i % 12):00 PM</option>
}
}
</select>
</td>
</tr>
<tr class="@(Model.ScheduleEnabled ? null : "hidden")">
<th>
File System Location:
</th>
<td>
@Html.EditorFor(m => m.FilePath)
<div class="info-box">
<p class="fa-p">
<i class="fa fa-fw fa-info-circle"></i> This is the full file path on the Disco ICT server (<code>@Environment.MachineName</code>). The location may be a network path. The Disco ICT Service Account (<code>@Environment.UserDomainName\@Environment.UserName</code>) must have write access to the location.
</p>
</div>
<label>
@Html.EditorFor(m => m.TimestampSuffix) Add time stamp suffix to file name
</label>
<div class="info-box">
<p class="fa-p">
<i class="fa fa-fw fa-info-circle"></i> This will create a new file each time the export runs.
</p>
</div>
</td>
</tr>
</table>
</div>
<div id="Config_Export_Create_OnDemand" class="form" style="width: 530px; margin-top: 10px;">
<h2>On Demand Export</h2>
<table>
<tr>
<th style="width: 140px">
Additional Users/Groups:
</th>
<td>
<ul id="Config_Export_Create_OnDemand_List" class="none">
@if (Model.OnDemandSubjects != null)
{
foreach (var sg in Model.OnDemandSubjects)
{
<li>
<input type="hidden" name="OnDemandPrincipals" value="@sg.Id" />
<i class="fa fa-user@(sg.IsGroup ? "s" : null) fa-lg"></i>
@sg.Name [@sg.Id]
<i class="fa fa-times-circle remove"></i>
</li>
}
}
</ul>
<div>
<input type="text" id="Config_Export_Create_OnDemand_Input" placeholder="Search users and groups" data-url="@(Url.Action(MVC.API.System.SearchSubjects()))" data-subjecturl="@Url.Action(MVC.API.System.Subject())" />
<button type="button" id="Config_Export_Create_OnDemand_Add" class="button small">Add</button>
</div>
<div class="info-box">
<p class="fa-p">
<i class="fa fa-fw fa-info-circle"></i> Users with the Manage Saved Exports permission (including Disco ICT Administrators) can perform an on-demand export at any time.
Users or Group Members can be added to this list. These will also be able to perform an on-demand export using the link available after saving.
</p>
</div>
</td>
</tr>
</table>
</div>
<div class="actionBar">
<button type="submit" class="button">Save</button>
</div>
}
<script>
$(function () {
$('#ScheduleEnabled').on('change', function () {
const enabled = $(this).is(':checked');
$('#Config_Export_Create_Schedule tr:not(:first)').toggleClass('hidden', !enabled);
});
const onDemandInput = $('#Config_Export_Create_OnDemand_Input');
onDemandInput
.autocomplete({
source: onDemandInput.attr('data-url'),
minLength: 2,
focus: function (e, ui) {
onDemandInput.val(ui.item.Id);
return false;
},
select: function (e, ui) {
onDemandInput.val(ui.item.Id).blur();
return false;
}
}).data('ui-autocomplete')._renderItem = function (ul, item) {
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a><strong>" + item.Name + "</strong><br>" + item.Id + " (" + item.Type + ")</a>")
.appendTo(ul);
};
$('#Config_Export_Create_OnDemand_Add').on('click', async function () {
const id = onDemandInput.val();
const body = new FormData();
body.append('Id', id);
const response = await fetch(onDemandInput.attr('data-subjecturl'), {
method: 'POST',
body: body
});
if (!response.ok) {
alert('Error: ' + response.statusText);
return;
}
const data = await response.json();
if (!data.IsGroup && !data.IsUserAccount) {
alert('Error: Only users and groups can be added.');
return;
}
const $li = $('<li><input type="hidden" name="OnDemandPrincipals" /><i class="fa fa-lg"></i> <span></span><i class="fa fa-times-circle remove"></i></li>');
$li.find('input').val(data.Id);
$li.find('i.fa-lg').addClass(data.Type === 'user' ? 'fa-user' : 'fa-users');
$li.find('span').text(data.Name + ' [' + data.Id + ']');
$li.appendTo('#Config_Export_Create_OnDemand_List');
});
$('#Config_Export_Create_OnDemand_List').on('click', '.remove', function () {
$(this).closest('li').remove();
})
})
</script>
@@ -0,0 +1,905 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Disco.Web.Areas.Config.Views.Export
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.Mvc.Html;
using System.Web.Routing;
using System.Web.Security;
using System.Web.UI;
using System.Web.WebPages;
using Disco;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
using Disco.Web.Extensions;
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/Export/Create.cshtml")]
public partial class Create : Disco.Services.Web.WebViewPage<Disco.Web.Areas.Config.Models.Export.CreateModel>
{
public Create()
{
}
public override void Execute()
{
#line 2 "..\..\Areas\Config\Views\Export\Create.cshtml"
Authorization.Require(Claims.Config.ManageSavedExports);
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Exports", null, "Create Saved " + Model.ExportTypeName);
#line default
#line hidden
WriteLiteral("\r\n\r\n");
#line 8 "..\..\Areas\Config\Views\Export\Create.cshtml"
using (Html.BeginForm(MVC.Config.Export.Create(), FormMethod.Post))
{
#line default
#line hidden
#line 10 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.AntiForgeryToken());
#line default
#line hidden
#line 10 "..\..\Areas\Config\Views\Export\Create.cshtml"
;
#line default
#line hidden
#line 11 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.HiddenFor(m => m.Id));
#line default
#line hidden
#line 11 "..\..\Areas\Config\Views\Export\Create.cshtml"
#line default
#line hidden
WriteLiteral(" <div");
WriteLiteral(" id=\"Config_Export_Create_Details\"");
WriteLiteral(" class=\"form\"");
WriteLiteral(" style=\"width: 530px;\"");
WriteLiteral(">\r\n <h2>Save ");
#line 14 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Model.ExportTypeName);
#line default
#line hidden
WriteLiteral("</h2>\r\n <table>\r\n <tr>\r\n <th");
WriteLiteral(" style=\"width: 140px\"");
WriteLiteral(">Name:</th>\r\n <td>\r\n");
WriteLiteral(" ");
#line 19 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.EditorFor(model => model.Name));
#line default
#line hidden
WriteLiteral("\r\n </td>\r\n </tr>\r\n <tr>\r\n <th" +
">\r\n Description:<br />\r\n <em");
WriteLiteral(" class=\"small\"");
WriteLiteral(">Optional</em>\r\n </th>\r\n <td>\r\n");
WriteLiteral(" ");
#line 28 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.EditorFor(model => model.Description));
#line default
#line hidden
WriteLiteral("\r\n </td>\r\n </tr>\r\n </table>\r\n </div>\r\n");
#line 33 "..\..\Areas\Config\Views\Export\Create.cshtml"
#line default
#line hidden
WriteLiteral(" <div");
WriteLiteral(" id=\"Config_Export_Create_Schedule\"");
WriteLiteral(" class=\"form\"");
WriteLiteral(" style=\"width: 530px; margin-top: 10px;\"");
WriteLiteral(">\r\n <h2>Schedule</h2>\r\n <table>\r\n <tr>\r\n " +
"<th");
WriteLiteral(" style=\"width: 140px\"");
WriteLiteral(">&nbsp;</th>\r\n <td>\r\n <label>\r\n");
WriteLiteral(" ");
#line 41 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.EditorFor(m => m.ScheduleEnabled));
#line default
#line hidden
WriteLiteral("\r\n Enable Scheduled Export\r\n </label>\r\n" +
" </td>\r\n </tr>\r\n <tr");
WriteAttribute("class", Tuple.Create(" class=\"", 1528), Tuple.Create("\"", 1578)
#line 46 "..\..\Areas\Config\Views\Export\Create.cshtml"
, Tuple.Create(Tuple.Create("", 1536), Tuple.Create<System.Object, System.Int32>(Model.ScheduleEnabled ? null : "hidden"
#line default
#line hidden
, 1536), false)
);
WriteLiteral(">\r\n <th>\r\n Days:\r\n </th>\r\n " +
" <td>\r\n <ul");
WriteLiteral(" class=\"none\"");
WriteLiteral(">\r\n <li><label>");
#line 52 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.EditorFor(m => m.ScheduleMonday));
#line default
#line hidden
WriteLiteral(" Monday</label></li>\r\n <li><label>");
#line 53 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.EditorFor(m => m.ScheduleTuesday));
#line default
#line hidden
WriteLiteral(" Tuesday</label></li>\r\n <li><label>");
#line 54 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.EditorFor(m => m.ScheduleWednesday));
#line default
#line hidden
WriteLiteral(" Wednesday</label></li>\r\n <li><label>");
#line 55 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.EditorFor(m => m.ScheduleThursday));
#line default
#line hidden
WriteLiteral(" Thursday</label></li>\r\n <li><label>");
#line 56 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.EditorFor(m => m.ScheduleFriday));
#line default
#line hidden
WriteLiteral(" Friday</label></li>\r\n <li><label>");
#line 57 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.EditorFor(m => m.ScheduleSaturday));
#line default
#line hidden
WriteLiteral(" Saturday</label></li>\r\n <li><label>");
#line 58 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.EditorFor(m => m.ScheduleSunday));
#line default
#line hidden
WriteLiteral(" Sunday</label></li>\r\n </ul>\r\n </td>\r\n " +
" </tr>\r\n <tr");
WriteAttribute("class", Tuple.Create(" class=\"", 2480), Tuple.Create("\"", 2530)
#line 62 "..\..\Areas\Config\Views\Export\Create.cshtml"
, Tuple.Create(Tuple.Create("", 2488), Tuple.Create<System.Object, System.Int32>(Model.ScheduleEnabled ? null : "hidden"
#line default
#line hidden
, 2488), false)
);
WriteLiteral(">\r\n <th>\r\n Start Time:\r\n </th>\r\n" +
" <td>\r\n <select");
WriteLiteral(" name=\"ScheduleStartHour\"");
WriteLiteral(">\r\n");
#line 68 "..\..\Areas\Config\Views\Export\Create.cshtml"
#line default
#line hidden
#line 68 "..\..\Areas\Config\Views\Export\Create.cshtml"
#line default
#line hidden
WriteLiteral(" <option");
WriteLiteral(" value=\"0\"");
WriteLiteral(" ");
#line 69 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Model.ScheduleStartHour == 0 ? "selected" : null);
#line default
#line hidden
WriteLiteral(">12:00 AM</option>\r\n");
#line 70 "..\..\Areas\Config\Views\Export\Create.cshtml"
for (int i = 1; i < 12; i++)
{
#line default
#line hidden
WriteLiteral(" <option");
WriteAttribute("value", Tuple.Create(" value=\"", 2962), Tuple.Create("\"", 2972)
#line 72 "..\..\Areas\Config\Views\Export\Create.cshtml"
, Tuple.Create(Tuple.Create("", 2970), Tuple.Create<System.Object, System.Int32>(i
#line default
#line hidden
, 2970), false)
);
WriteLiteral(" ");
#line 72 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Model.ScheduleStartHour == i ? "selected" : null);
#line default
#line hidden
WriteLiteral(">");
#line 72 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(i);
#line default
#line hidden
WriteLiteral(":00 AM</option>\r\n");
#line 73 "..\..\Areas\Config\Views\Export\Create.cshtml"
}
#line default
#line hidden
WriteLiteral(" <option");
WriteLiteral(" value=\"12\"");
WriteLiteral(" ");
#line 74 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Model.ScheduleStartHour == 12 ? "selected" : null);
#line default
#line hidden
WriteLiteral(">12:00 PM</option>\r\n");
#line 75 "..\..\Areas\Config\Views\Export\Create.cshtml"
for (int i = 13; i < 24; i++)
{
#line default
#line hidden
WriteLiteral(" <option");
WriteAttribute("value", Tuple.Create(" value=\"", 3324), Tuple.Create("\"", 3334)
#line 77 "..\..\Areas\Config\Views\Export\Create.cshtml"
, Tuple.Create(Tuple.Create("", 3332), Tuple.Create<System.Object, System.Int32>(i
#line default
#line hidden
, 3332), false)
);
WriteLiteral(" ");
#line 77 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Model.ScheduleStartHour == i ? "selected" : null);
#line default
#line hidden
WriteLiteral(">");
#line 77 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(i % 12);
#line default
#line hidden
WriteLiteral(":00 PM</option>\r\n");
#line 78 "..\..\Areas\Config\Views\Export\Create.cshtml"
}
#line default
#line hidden
WriteLiteral("\r\n </select>\r\n <div");
WriteLiteral(" class=\"info-box\"");
WriteLiteral(">\r\n <p");
WriteLiteral(" class=\"fa-p\"");
WriteLiteral(">\r\n <i");
WriteLiteral(" class=\"fa fa-fw fa-info-circle\"");
WriteLiteral(@"></i> By default, Disco ICT shuts down at 1:30am and does not resume again until its needed. If a scheduled export was missed during this time, it will be run as soon as Disco ICT is resumed.
</p>
</div>
</td>
</tr>
<tr");
WriteAttribute("class", Tuple.Create(" class=\"", 3959), Tuple.Create("\"", 4009)
#line 88 "..\..\Areas\Config\Views\Export\Create.cshtml"
, Tuple.Create(Tuple.Create("", 3967), Tuple.Create<System.Object, System.Int32>(Model.ScheduleEnabled ? null : "hidden"
#line default
#line hidden
, 3967), false)
);
WriteLiteral(">\r\n <th>\r\n Repeat Hourly Until:\r\n " +
" </th>\r\n <td>\r\n <select");
WriteLiteral(" name=\"ScheduleEndHour\"");
WriteLiteral(">\r\n <option");
WriteLiteral(" value=\"\"");
WriteLiteral(" ");
#line 94 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Model.ScheduleEndHour.HasValue ? null : "selected");
#line default
#line hidden
WriteLiteral(">Run once</option>\r\n");
#line 95 "..\..\Areas\Config\Views\Export\Create.cshtml"
#line default
#line hidden
#line 95 "..\..\Areas\Config\Views\Export\Create.cshtml"
for (int i = 1; i < 12; i++)
{
#line default
#line hidden
WriteLiteral(" <option");
WriteAttribute("value", Tuple.Create(" value=\"", 4445), Tuple.Create("\"", 4455)
#line 98 "..\..\Areas\Config\Views\Export\Create.cshtml"
, Tuple.Create(Tuple.Create("", 4453), Tuple.Create<System.Object, System.Int32>(i
#line default
#line hidden
, 4453), false)
);
WriteLiteral(" ");
#line 98 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Model.ScheduleEndHour == i ? "selected" : null);
#line default
#line hidden
WriteLiteral(">");
#line 98 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(i);
#line default
#line hidden
WriteLiteral(":00 AM</option>\r\n");
#line 99 "..\..\Areas\Config\Views\Export\Create.cshtml"
}
#line default
#line hidden
WriteLiteral(" <option");
WriteLiteral(" value=\"12\"");
WriteLiteral(" ");
#line 100 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Model.ScheduleEndHour == 12 ? "selected" : null);
#line default
#line hidden
WriteLiteral(">12:00 PM</option>\r\n");
#line 101 "..\..\Areas\Config\Views\Export\Create.cshtml"
for (int i = 12; i < 24; i++)
{
#line default
#line hidden
WriteLiteral(" <option");
WriteAttribute("value", Tuple.Create(" value=\"", 4803), Tuple.Create("\"", 4813)
#line 103 "..\..\Areas\Config\Views\Export\Create.cshtml"
, Tuple.Create(Tuple.Create("", 4811), Tuple.Create<System.Object, System.Int32>(i
#line default
#line hidden
, 4811), false)
);
WriteLiteral(" ");
#line 103 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Model.ScheduleEndHour == i ? "selected" : null);
#line default
#line hidden
WriteLiteral(">");
#line 103 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(i % 12);
#line default
#line hidden
WriteLiteral(":00 PM</option>\r\n");
#line 104 "..\..\Areas\Config\Views\Export\Create.cshtml"
}
#line default
#line hidden
WriteLiteral("\r\n </select>\r\n </td>\r\n </tr>\r\n " +
" <tr");
WriteAttribute("class", Tuple.Create(" class=\"", 5037), Tuple.Create("\"", 5087)
#line 109 "..\..\Areas\Config\Views\Export\Create.cshtml"
, Tuple.Create(Tuple.Create("", 5045), Tuple.Create<System.Object, System.Int32>(Model.ScheduleEnabled ? null : "hidden"
#line default
#line hidden
, 5045), false)
);
WriteLiteral(">\r\n <th>\r\n File System Location:\r\n " +
" </th>\r\n <td>\r\n");
WriteLiteral(" ");
#line 114 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.EditorFor(m => m.FilePath));
#line default
#line hidden
WriteLiteral("\r\n <div");
WriteLiteral(" class=\"info-box\"");
WriteLiteral(">\r\n <p");
WriteLiteral(" class=\"fa-p\"");
WriteLiteral(">\r\n <i");
WriteLiteral(" class=\"fa fa-fw fa-info-circle\"");
WriteLiteral("></i> This is the full file path on the Disco ICT server (<code>");
#line 117 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Environment.MachineName);
#line default
#line hidden
WriteLiteral("</code>). The location may be a network path. The Disco ICT Service Account (<cod" +
"e>");
#line 117 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Environment.UserDomainName);
#line default
#line hidden
WriteLiteral("\\");
#line 117 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Environment.UserName);
#line default
#line hidden
WriteLiteral("</code>) must have write access to the location.\r\n </p>\r\n " +
" </div>\r\n <label>\r\n");
WriteLiteral(" ");
#line 121 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Html.EditorFor(m => m.TimestampSuffix));
#line default
#line hidden
WriteLiteral(" Add time stamp suffix to file name\r\n </label>\r\n " +
" <div");
WriteLiteral(" class=\"info-box\"");
WriteLiteral(">\r\n <p");
WriteLiteral(" class=\"fa-p\"");
WriteLiteral(">\r\n <i");
WriteLiteral(" class=\"fa fa-fw fa-info-circle\"");
WriteLiteral("></i> This will create a new file each time the export runs.\r\n " +
" </p>\r\n </div>\r\n </td>\r\n </tr>\r" +
"\n </table>\r\n </div>\r\n");
#line 132 "..\..\Areas\Config\Views\Export\Create.cshtml"
#line default
#line hidden
WriteLiteral(" <div");
WriteLiteral(" id=\"Config_Export_Create_OnDemand\"");
WriteLiteral(" class=\"form\"");
WriteLiteral(" style=\"width: 530px; margin-top: 10px;\"");
WriteLiteral(">\r\n <h2>On Demand Export</h2>\r\n <table>\r\n <tr>\r\n " +
" <th");
WriteLiteral(" style=\"width: 140px\"");
WriteLiteral(">\r\n Additional Users/Groups:\r\n </th>\r\n " +
" <td>\r\n <ul");
WriteLiteral(" id=\"Config_Export_Create_OnDemand_List\"");
WriteLiteral(" class=\"none\"");
WriteLiteral(">\r\n");
#line 142 "..\..\Areas\Config\Views\Export\Create.cshtml"
#line default
#line hidden
#line 142 "..\..\Areas\Config\Views\Export\Create.cshtml"
if (Model.OnDemandSubjects != null)
{
foreach (var sg in Model.OnDemandSubjects)
{
#line default
#line hidden
WriteLiteral(" <li>\r\n <input");
WriteLiteral(" type=\"hidden\"");
WriteLiteral(" name=\"OnDemandPrincipals\"");
WriteAttribute("value", Tuple.Create(" value=\"", 6926), Tuple.Create("\"", 6940)
#line 147 "..\..\Areas\Config\Views\Export\Create.cshtml"
, Tuple.Create(Tuple.Create("", 6934), Tuple.Create<System.Object, System.Int32>(sg.Id
#line default
#line hidden
, 6934), false)
);
WriteLiteral(" />\r\n <i");
WriteAttribute("class", Tuple.Create(" class=\"", 6984), Tuple.Create("\"", 7034)
, Tuple.Create(Tuple.Create("", 6992), Tuple.Create("fa", 6992), true)
, Tuple.Create(Tuple.Create(" ", 6994), Tuple.Create("fa-user", 6995), true)
#line 148 "..\..\Areas\Config\Views\Export\Create.cshtml"
, Tuple.Create(Tuple.Create("", 7002), Tuple.Create<System.Object, System.Int32>(sg.IsGroup ? "s" : null
#line default
#line hidden
, 7002), false)
, Tuple.Create(Tuple.Create(" ", 7028), Tuple.Create("fa-lg", 7029), true)
);
WriteLiteral("></i>\r\n");
WriteLiteral(" ");
#line 149 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(sg.Name);
#line default
#line hidden
WriteLiteral(" [");
#line 149 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(sg.Id);
#line default
#line hidden
WriteLiteral("]\r\n <i");
WriteLiteral(" class=\"fa fa-times-circle remove\"");
WriteLiteral("></i>\r\n </li>\r\n");
#line 152 "..\..\Areas\Config\Views\Export\Create.cshtml"
}
}
#line default
#line hidden
WriteLiteral(" </ul>\r\n <div>\r\n <in" +
"put");
WriteLiteral(" type=\"text\"");
WriteLiteral(" id=\"Config_Export_Create_OnDemand_Input\"");
WriteLiteral(" placeholder=\"Search users and groups\"");
WriteLiteral(" data-url=\"");
#line 156 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Url.Action(MVC.API.System.SearchSubjects()));
#line default
#line hidden
WriteLiteral("\"");
WriteLiteral(" data-subjecturl=\"");
#line 156 "..\..\Areas\Config\Views\Export\Create.cshtml"
Write(Url.Action(MVC.API.System.Subject()));
#line default
#line hidden
WriteLiteral("\"");
WriteLiteral(" />\r\n <button");
WriteLiteral(" type=\"button\"");
WriteLiteral(" id=\"Config_Export_Create_OnDemand_Add\"");
WriteLiteral(" class=\"button small\"");
WriteLiteral(">Add</button>\r\n </div>\r\n <div");
WriteLiteral(" class=\"info-box\"");
WriteLiteral(">\r\n <p");
WriteLiteral(" class=\"fa-p\"");
WriteLiteral(">\r\n <i");
WriteLiteral(" class=\"fa fa-fw fa-info-circle\"");
WriteLiteral(@"></i> Users with the Manage Saved Exports permission (including Disco ICT Administrators) can perform an on-demand export at any time.
Users or Group Members can be added to this list. These will also be able to perform an on-demand export using the link available after saving.
</p>
</div>
</td>
</tr>
</table>
</div>
");
#line 169 "..\..\Areas\Config\Views\Export\Create.cshtml"
#line default
#line hidden
WriteLiteral(" <div");
WriteLiteral(" class=\"actionBar\"");
WriteLiteral(">\r\n <button");
WriteLiteral(" type=\"submit\"");
WriteLiteral(" class=\"button\"");
WriteLiteral(">Save</button>\r\n </div>\r\n");
#line 173 "..\..\Areas\Config\Views\Export\Create.cshtml"
}
#line default
#line hidden
WriteLiteral("<script>\r\n $(function () {\r\n $(\'#ScheduleEnabled\').on(\'change\', functio" +
"n () {\r\n const enabled = $(this).is(\':checked\');\r\n $(\'#Con" +
"fig_Export_Create_Schedule tr:not(:first)\').toggleClass(\'hidden\', !enabled);\r\n " +
" });\r\n\r\n const onDemandInput = $(\'#Config_Export_Create_OnDemand_Inp" +
"ut\');\r\n\r\n onDemandInput\r\n .autocomplete({\r\n sou" +
"rce: onDemandInput.attr(\'data-url\'),\r\n minLength: 2,\r\n " +
" focus: function (e, ui) {\r\n onDemandInput.val(ui.item.Id" +
");\r\n return false;\r\n },\r\n selec" +
"t: function (e, ui) {\r\n onDemandInput.val(ui.item.Id).blur();" +
"\r\n return false;\r\n }\r\n }).data(\'ui-" +
"autocomplete\')._renderItem = function (ul, item) {\r\n return $(\"<l" +
"i></li>\")\r\n .data(\"item.autocomplete\", item)\r\n " +
" .append(\"<a><strong>\" + item.Name + \"</strong><br>\" + item.Id + \" (\" + item" +
".Type + \")</a>\")\r\n .appendTo(ul);\r\n };\r\n $(" +
"\'#Config_Export_Create_OnDemand_Add\').on(\'click\', async function () {\r\n " +
" const id = onDemandInput.val();\r\n const body = new FormData();\r\n " +
" body.append(\'Id\', id);\r\n const response = await fetch(onDem" +
"andInput.attr(\'data-subjecturl\'), {\r\n method: \'POST\',\r\n " +
" body: body\r\n });\r\n if (!response.ok) {\r\n " +
" alert(\'Error: \' + response.statusText);\r\n return;\r\n " +
" }\r\n const data = await response.json();\r\n\r\n if (!data.Is" +
"Group && !data.IsUserAccount) {\r\n alert(\'Error: Only users and gr" +
"oups can be added.\');\r\n return;\r\n }\r\n\r\n con" +
"st $li = $(\'<li><input type=\"hidden\" name=\"OnDemandPrincipals\" /><i class=\"fa fa" +
"-lg\"></i> <span></span><i class=\"fa fa-times-circle remove\"></i></li>\');\r\n " +
" $li.find(\'input\').val(data.Id);\r\n $li.find(\'i.fa-lg\').addClass(" +
"data.Type === \'user\' ? \'fa-user\' : \'fa-users\');\r\n $li.find(\'span\').te" +
"xt(data.Name + \' [\' + data.Id + \']\');\r\n $li.appendTo(\'#Config_Export_" +
"Create_OnDemand_List\');\r\n });\r\n $(\'#Config_Export_Create_OnDemand_" +
"List\').on(\'click\', \'.remove\', function () {\r\n $(this).closest(\'li\').r" +
"emove();\r\n })\r\n })\r\n</script>\r\n");
}
}
}
#pragma warning restore 1591
+29
View File
@@ -2038,3 +2038,32 @@ h1.Config_DocumentTemplates {
cursor: not-allowed; cursor: not-allowed;
background-color: #f4f4f4; background-color: #f4f4f4;
} }
#Config_Export_Create_OnDemand #Config_Export_Create_OnDemand_List {
height: 120px;
overflow-y: auto;
background-color: #fff;
border: 1px solid #d8d8d8;
margin-bottom: 10px;
}
#Config_Export_Create_OnDemand #Config_Export_Create_OnDemand_List li {
cursor: pointer;
margin: 2px 4px;
}
#Config_Export_Create_OnDemand #Config_Export_Create_OnDemand_List li:hover {
background-color: #f4f4f4;
}
#Config_Export_Create_OnDemand #Config_Export_Create_OnDemand_List li:hover .remove {
opacity: 0.8;
}
#Config_Export_Create_OnDemand #Config_Export_Create_OnDemand_List li .remove {
margin-top: 2px;
padding-right: 6px;
float: right;
cursor: pointer;
opacity: 0;
color: #e51400;
font-size: 1.3em;
}
#Config_Export_Create_OnDemand #Config_Export_Create_OnDemand_List li .remove:hover {
opacity: 1;
}
+37
View File
@@ -2460,3 +2460,40 @@ h1.Config_DocumentTemplates {
.dialog-bulk-generate { .dialog-bulk-generate {
} }
#Config_Export_Create_OnDemand {
#Config_Export_Create_OnDemand_List {
height: 120px;
overflow-y: auto;
background-color: @white;
border: 1px solid @TableDataDarkBorderColour;
margin-bottom: 10px;
li {
cursor: pointer;
margin: 2px 4px;
&:hover {
background-color: @TableDataBorderColour;
.remove {
opacity: .8;
}
}
.remove {
margin-top: 2px;
padding-right: 6px;
float: right;
cursor: pointer;
opacity: 0;
color: @StatusRemove;
font-size: 1.3em;
&:hover {
opacity: 1;
}
}
}
}
}
File diff suppressed because one or more lines are too long
+14
View File
@@ -233,6 +233,7 @@
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
</Compile> </Compile>
<Compile Include="Areas\Config\Controllers\AuthorizationRoleController.cs" /> <Compile Include="Areas\Config\Controllers\AuthorizationRoleController.cs" />
<Compile Include="Areas\Config\Controllers\ExportController.cs" />
<Compile Include="Areas\Config\Controllers\DeviceFlagController.cs" /> <Compile Include="Areas\Config\Controllers\DeviceFlagController.cs" />
<Compile Include="Areas\Config\Controllers\UserFlagController.cs" /> <Compile Include="Areas\Config\Controllers\UserFlagController.cs" />
<Compile Include="Areas\Config\Controllers\JobPreferencesController.cs" /> <Compile Include="Areas\Config\Controllers\JobPreferencesController.cs" />
@@ -244,6 +245,7 @@
<Compile Include="Areas\Config\Models\DocumentTemplate\BulkGenerateModel.cs" /> <Compile Include="Areas\Config\Models\DocumentTemplate\BulkGenerateModel.cs" />
<Compile Include="Areas\Config\Models\DocumentTemplate\CreatePackageModel.cs" /> <Compile Include="Areas\Config\Models\DocumentTemplate\CreatePackageModel.cs" />
<Compile Include="Areas\Config\Models\DocumentTemplate\ShowPackageModel.cs" /> <Compile Include="Areas\Config\Models\DocumentTemplate\ShowPackageModel.cs" />
<Compile Include="Areas\Config\Models\Export\CreateModel.cs" />
<Compile Include="Areas\Config\Models\Shared\DeviceGroupDocumentTemplateBulkGenerateModel.cs" /> <Compile Include="Areas\Config\Models\Shared\DeviceGroupDocumentTemplateBulkGenerateModel.cs" />
<Compile Include="Areas\Config\Models\Shared\LinkedGroupModel.cs" /> <Compile Include="Areas\Config\Models\Shared\LinkedGroupModel.cs" />
<Compile Include="Areas\Config\Models\DeviceFlag\CreateModel.cs" /> <Compile Include="Areas\Config\Models\DeviceFlag\CreateModel.cs" />
@@ -296,6 +298,11 @@
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<DependentUpon>ShowPackage.cshtml</DependentUpon> <DependentUpon>ShowPackage.cshtml</DependentUpon>
</Compile> </Compile>
<Compile Include="Areas\Config\Views\Export\Create.generated.cs">
<DependentUpon>Create.cshtml</DependentUpon>
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
</Compile>
<Compile Include="Areas\Config\Views\Expressions\Browser.generated.cs"> <Compile Include="Areas\Config\Views\Expressions\Browser.generated.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
@@ -711,6 +718,9 @@
<Compile Include="Extensions\T4MVC\Config.DeviceFlagController.generated.cs"> <Compile Include="Extensions\T4MVC\Config.DeviceFlagController.generated.cs">
<DependentUpon>T4MVC.tt</DependentUpon> <DependentUpon>T4MVC.tt</DependentUpon>
</Compile> </Compile>
<Compile Include="Extensions\T4MVC\Config.ExportController.generated.cs">
<DependentUpon>T4MVC.tt</DependentUpon>
</Compile>
<Compile Include="Extensions\T4MVC\T4MVCExtensions.cs" /> <Compile Include="Extensions\T4MVC\T4MVCExtensions.cs" />
<Compile Include="Extensions\T4MVC\API.AuthorizationRoleController.generated.cs"> <Compile Include="Extensions\T4MVC\API.AuthorizationRoleController.generated.cs">
<DependentUpon>T4MVC.tt</DependentUpon> <DependentUpon>T4MVC.tt</DependentUpon>
@@ -1349,6 +1359,10 @@
<Generator>RazorGenerator</Generator> <Generator>RazorGenerator</Generator>
<LastGenOutput>CreatePackage.generated.cs</LastGenOutput> <LastGenOutput>CreatePackage.generated.cs</LastGenOutput>
</None> </None>
<Content Include="Areas\Config\Views\Export\Create.cshtml">
<Generator>RazorGenerator</Generator>
<LastGenOutput>Create.generated.cs</LastGenOutput>
</Content>
<None Include="Areas\Config\Views\JobPreferences\Index.cshtml"> <None Include="Areas\Config\Views\JobPreferences\Index.cshtml">
<Generator>RazorGenerator</Generator> <Generator>RazorGenerator</Generator>
<LastGenOutput>Index.generated.cs</LastGenOutput> <LastGenOutput>Index.generated.cs</LastGenOutput>
@@ -221,6 +221,12 @@ namespace Disco.Web.Areas.API.Controllers
{ {
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ExportRetrieve); return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ExportRetrieve);
} }
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult SaveExport()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SaveExport);
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public DeviceController Actions { get { return MVC.API.Device; } } public DeviceController Actions { get { return MVC.API.Device; } }
@@ -264,6 +270,7 @@ namespace Disco.Web.Areas.API.Controllers
public readonly string ImportApply = "ImportApply"; public readonly string ImportApply = "ImportApply";
public readonly string Export = "Export"; public readonly string Export = "Export";
public readonly string ExportRetrieve = "ExportRetrieve"; public readonly string ExportRetrieve = "ExportRetrieve";
public readonly string SaveExport = "SaveExport";
public readonly string MigrateDeviceMacAddressesFromLog = "MigrateDeviceMacAddressesFromLog"; public readonly string MigrateDeviceMacAddressesFromLog = "MigrateDeviceMacAddressesFromLog";
} }
@@ -297,6 +304,7 @@ namespace Disco.Web.Areas.API.Controllers
public const string ImportApply = "ImportApply"; public const string ImportApply = "ImportApply";
public const string Export = "Export"; public const string Export = "Export";
public const string ExportRetrieve = "ExportRetrieve"; public const string ExportRetrieve = "ExportRetrieve";
public const string SaveExport = "SaveExport";
public const string MigrateDeviceMacAddressesFromLog = "MigrateDeviceMacAddressesFromLog"; public const string MigrateDeviceMacAddressesFromLog = "MigrateDeviceMacAddressesFromLog";
} }
@@ -548,6 +556,14 @@ namespace Disco.Web.Areas.API.Controllers
{ {
public readonly string id = "id"; public readonly string id = "id";
} }
static readonly ActionParamsClass_SaveExport s_params_SaveExport = new ActionParamsClass_SaveExport();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_SaveExport SaveExportParams { get { return s_params_SaveExport; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_SaveExport
{
public readonly string Model = "Model";
}
static readonly ViewsClass s_views = new ViewsClass(); static readonly ViewsClass s_views = new ViewsClass();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ViewsClass Views { get { return s_views; } } public ViewsClass Views { get { return s_views; } }
@@ -922,6 +938,18 @@ namespace Disco.Web.Areas.API.Controllers
return callInfo; return callInfo;
} }
[NonAction]
partial void SaveExportOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, Disco.Web.Models.Device.ExportModel Model);
[NonAction]
public override System.Web.Mvc.ActionResult SaveExport(Disco.Web.Models.Device.ExportModel Model)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SaveExport);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Model", Model);
SaveExportOverride(callInfo, Model);
return callInfo;
}
[NonAction] [NonAction]
partial void MigrateDeviceMacAddressesFromLogOverride(T4MVC_System_Web_Mvc_ActionResult callInfo); partial void MigrateDeviceMacAddressesFromLogOverride(T4MVC_System_Web_Mvc_ActionResult callInfo);
@@ -0,0 +1,180 @@
// <auto-generated />
// This file was generated by a T4 template.
// Don't change it directly as your change would get overwritten. Instead, make changes
// to the .tt file (i.e. the T4 template) and save it to regenerate this file.
// Make sure the compiler doesn't complain about missing Xml comments and CLS compliance
// 0108: suppress "Foo hides inherited member Foo. Use the new keyword if hiding was intended." when a controller and its abstract parent are both processed
// 0114: suppress "Foo.BarController.Baz()' hides inherited member 'Qux.BarController.Baz()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." when an action (with an argument) overrides an action in a parent controller
#pragma warning disable 1591, 3008, 3009, 0108, 0114
#region T4MVC
using System;
using System.Diagnostics;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Web;
using System.Web.Hosting;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.Mvc.Html;
using System.Web.Routing;
using T4MVC;
namespace Disco.Web.Areas.Config.Controllers
{
public partial class ExportController
{
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ExportController() { }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
protected ExportController(Dummy d) { }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
protected RedirectToRouteResult RedirectToAction(ActionResult result)
{
var callInfo = result.GetT4MVCResult();
return RedirectToRoute(callInfo.RouteValueDictionary);
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
protected RedirectToRouteResult RedirectToAction(Task<ActionResult> taskResult)
{
return RedirectToAction(taskResult.Result);
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
protected RedirectToRouteResult RedirectToActionPermanent(ActionResult result)
{
var callInfo = result.GetT4MVCResult();
return RedirectToRoutePermanent(callInfo.RouteValueDictionary);
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
protected RedirectToRouteResult RedirectToActionPermanent(Task<ActionResult> taskResult)
{
return RedirectToActionPermanent(taskResult.Result);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult Create()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Create);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult Run()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Run);
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ExportController Actions { get { return MVC.Config.Export; } }
[GeneratedCode("T4MVC", "2.0")]
public readonly string Area = "Config";
[GeneratedCode("T4MVC", "2.0")]
public readonly string Name = "Export";
[GeneratedCode("T4MVC", "2.0")]
public const string NameConst = "Export";
[GeneratedCode("T4MVC", "2.0")]
static readonly ActionNamesClass s_actions = new ActionNamesClass();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionNamesClass ActionNames { get { return s_actions; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionNamesClass
{
public readonly string Create = "Create";
public readonly string Run = "Run";
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionNameConstants
{
public const string Create = "Create";
public const string Run = "Run";
}
static readonly ActionParamsClass_Create s_params_Create = new ActionParamsClass_Create();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_Create CreateParams { get { return s_params_Create; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_Create
{
public readonly string id = "id";
public readonly string model = "model";
}
static readonly ActionParamsClass_Run s_params_Run = new ActionParamsClass_Run();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_Run RunParams { get { return s_params_Run; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_Run
{
public readonly string id = "id";
}
static readonly ViewsClass s_views = new ViewsClass();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ViewsClass Views { get { return s_views; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ViewsClass
{
static readonly _ViewNamesClass s_ViewNames = new _ViewNamesClass();
public _ViewNamesClass ViewNames { get { return s_ViewNames; } }
public class _ViewNamesClass
{
public readonly string Create = "Create";
}
public readonly string Create = "~/Areas/Config/Views/Export/Create.cshtml";
}
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public partial class T4MVC_ExportController : Disco.Web.Areas.Config.Controllers.ExportController
{
public T4MVC_ExportController() : base(Dummy.Instance) { }
[NonAction]
partial void CreateOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, System.Guid id);
[NonAction]
public override System.Web.Mvc.ActionResult Create(System.Guid id)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Create);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id);
CreateOverride(callInfo, id);
return callInfo;
}
[NonAction]
partial void CreateOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, Disco.Web.Areas.Config.Models.Export.CreateModel model);
[NonAction]
public override System.Web.Mvc.ActionResult Create(Disco.Web.Areas.Config.Models.Export.CreateModel model)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Create);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "model", model);
CreateOverride(callInfo, model);
return callInfo;
}
[NonAction]
partial void RunOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, System.Guid id);
[NonAction]
public override System.Web.Mvc.ActionResult Run(System.Guid id)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Run);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id);
RunOverride(callInfo, id);
return callInfo;
}
}
}
#endregion T4MVC
#pragma warning restore 1591, 3008, 3009, 0108, 0114
+1
View File
@@ -89,6 +89,7 @@ namespace T4MVC
public Disco.Web.Areas.Config.Controllers.DeviceProfileController DeviceProfile = new Disco.Web.Areas.Config.Controllers.T4MVC_DeviceProfileController(); public Disco.Web.Areas.Config.Controllers.DeviceProfileController DeviceProfile = new Disco.Web.Areas.Config.Controllers.T4MVC_DeviceProfileController();
public Disco.Web.Areas.Config.Controllers.DocumentTemplateController DocumentTemplate = new Disco.Web.Areas.Config.Controllers.T4MVC_DocumentTemplateController(); public Disco.Web.Areas.Config.Controllers.DocumentTemplateController DocumentTemplate = new Disco.Web.Areas.Config.Controllers.T4MVC_DocumentTemplateController();
public Disco.Web.Areas.Config.Controllers.EnrolmentController Enrolment = new Disco.Web.Areas.Config.Controllers.T4MVC_EnrolmentController(); public Disco.Web.Areas.Config.Controllers.EnrolmentController Enrolment = new Disco.Web.Areas.Config.Controllers.T4MVC_EnrolmentController();
public Disco.Web.Areas.Config.Controllers.ExportController Export = new Disco.Web.Areas.Config.Controllers.T4MVC_ExportController();
public Disco.Web.Areas.Config.Controllers.ExpressionsController Expressions = new Disco.Web.Areas.Config.Controllers.T4MVC_ExpressionsController(); public Disco.Web.Areas.Config.Controllers.ExpressionsController Expressions = new Disco.Web.Areas.Config.Controllers.T4MVC_ExpressionsController();
public Disco.Web.Areas.Config.Controllers.JobPreferencesController JobPreferences = new Disco.Web.Areas.Config.Controllers.T4MVC_JobPreferencesController(); public Disco.Web.Areas.Config.Controllers.JobPreferencesController JobPreferences = new Disco.Web.Areas.Config.Controllers.T4MVC_JobPreferencesController();
public Disco.Web.Areas.Config.Controllers.JobQueueController JobQueue = new Disco.Web.Areas.Config.Controllers.T4MVC_JobQueueController(); public Disco.Web.Areas.Config.Controllers.JobQueueController JobQueue = new Disco.Web.Areas.Config.Controllers.T4MVC_JobQueueController();
+15 -2
View File
@@ -10,7 +10,7 @@
.GroupBy(m => m.ShortDisplayName); .GroupBy(m => m.ShortDisplayName);
} }
<div id="Devices_Export"> <div id="Devices_Export">
@using (Html.BeginForm(MVC.API.Device.Export())) @using (Html.BeginForm(MVC.API.Device.Export(), FormMethod.Post, new { @data_saveaction = Url.Action(MVC.API.Device.SaveExport()) }))
{ {
@Html.AntiForgeryToken() @Html.AntiForgeryToken()
<div id="Devices_Export_Type" class="form" style="width: 570px"> <div id="Devices_Export_Type" class="form" style="width: 570px">
@@ -171,6 +171,10 @@
$('#Devices_Export_Button').click(function () { $('#Devices_Export_Button').click(function () {
$form.submit(); $form.submit();
}); });
$('#Devices_Export_Save_Button').click(function () {
$form.attr('action', $form.data('saveaction'));
$form.submit();
});
}); });
</script> </script>
} }
@@ -205,5 +209,14 @@
<h4><i class="fa fa-lg fa-cog fa-spin" title="Please Wait"></i>Exporting devices...</h4> <h4><i class="fa fa-lg fa-cog fa-spin" title="Please Wait"></i>Exporting devices...</h4>
</div> </div>
<div class="actionBar"> <div class="actionBar">
<a id="Devices_Export_Button" href="#" class="button">Export Devices</a> @if (Authorization.Has(Claims.Config.ManageSavedExports))
{
<button type="button" id="Devices_Export_Save_Button" class="button">Save Export</button>
}
else
{
<button type="button" class="button" disabled title="Requires Manage Saved Exports Permission">Save Export</button>
}
<button type="button" id="Devices_Export_Button" class="button">Export Now</button>
</div> </div>
+105 -49
View File
@@ -77,7 +77,7 @@ WriteLiteral(">\r\n");
#line hidden #line hidden
#line 13 "..\..\Views\Device\Export.cshtml" #line 13 "..\..\Views\Device\Export.cshtml"
using (Html.BeginForm(MVC.API.Device.Export())) using (Html.BeginForm(MVC.API.Device.Export(), FormMethod.Post, new { @data_saveaction = Url.Action(MVC.API.Device.SaveExport()) }))
{ {
@@ -323,40 +323,40 @@ WriteLiteral(">\r\n");
#line hidden #line hidden
WriteLiteral(" <li"); WriteLiteral(" <li");
WriteAttribute("title", Tuple.Create(" title=\"", 3918), Tuple.Create("\"", 3949) WriteAttribute("title", Tuple.Create(" title=\"", 4003), Tuple.Create("\"", 4034)
#line 67 "..\..\Views\Device\Export.cshtml" #line 67 "..\..\Views\Device\Export.cshtml"
, Tuple.Create(Tuple.Create("", 3926), Tuple.Create<System.Object, System.Int32>(optionItem.Description , Tuple.Create(Tuple.Create("", 4011), Tuple.Create<System.Object, System.Int32>(optionItem.Description
#line default #line default
#line hidden #line hidden
, 3926), false) , 4011), false)
); );
WriteLiteral(">\r\n <input"); WriteLiteral(">\r\n <input");
WriteLiteral(" type=\"checkbox\""); WriteLiteral(" type=\"checkbox\"");
WriteAttribute("id", Tuple.Create(" id=\"", 4031), Tuple.Create("\"", 4068) WriteAttribute("id", Tuple.Create(" id=\"", 4116), Tuple.Create("\"", 4153)
, Tuple.Create(Tuple.Create("", 4036), Tuple.Create("Options_", 4036), true) , Tuple.Create(Tuple.Create("", 4121), Tuple.Create("Options_", 4121), true)
#line 68 "..\..\Views\Device\Export.cshtml" #line 68 "..\..\Views\Device\Export.cshtml"
, Tuple.Create(Tuple.Create("", 4044), Tuple.Create<System.Object, System.Int32>(optionItem.PropertyName , Tuple.Create(Tuple.Create("", 4129), Tuple.Create<System.Object, System.Int32>(optionItem.PropertyName
#line default #line default
#line hidden #line hidden
, 4044), false) , 4129), false)
); );
WriteAttribute("name", Tuple.Create(" name=\"", 4069), Tuple.Create("\"", 4108) WriteAttribute("name", Tuple.Create(" name=\"", 4154), Tuple.Create("\"", 4193)
, Tuple.Create(Tuple.Create("", 4076), Tuple.Create("Options.", 4076), true) , Tuple.Create(Tuple.Create("", 4161), Tuple.Create("Options.", 4161), true)
#line 68 "..\..\Views\Device\Export.cshtml" #line 68 "..\..\Views\Device\Export.cshtml"
, Tuple.Create(Tuple.Create("", 4084), Tuple.Create<System.Object, System.Int32>(optionItem.PropertyName , Tuple.Create(Tuple.Create("", 4169), Tuple.Create<System.Object, System.Int32>(optionItem.PropertyName
#line default #line default
#line hidden #line hidden
, 4084), false) , 4169), false)
); );
WriteLiteral(" value=\"true\""); WriteLiteral(" value=\"true\"");
@@ -372,15 +372,15 @@ WriteLiteral(" ");
#line hidden #line hidden
WriteLiteral(" /><label"); WriteLiteral(" /><label");
WriteAttribute("for", Tuple.Create(" for=\"", 4179), Tuple.Create("\"", 4217) WriteAttribute("for", Tuple.Create(" for=\"", 4264), Tuple.Create("\"", 4302)
, Tuple.Create(Tuple.Create("", 4185), Tuple.Create("Options_", 4185), true) , Tuple.Create(Tuple.Create("", 4270), Tuple.Create("Options_", 4270), true)
#line 68 "..\..\Views\Device\Export.cshtml" #line 68 "..\..\Views\Device\Export.cshtml"
, Tuple.Create(Tuple.Create("", 4193), Tuple.Create<System.Object, System.Int32>(optionItem.PropertyName , Tuple.Create(Tuple.Create("", 4278), Tuple.Create<System.Object, System.Int32>(optionItem.PropertyName
#line default #line default
#line hidden #line hidden
, 4193), false) , 4278), false)
); );
WriteLiteral(">"); WriteLiteral(">");
@@ -428,40 +428,40 @@ WriteLiteral(">\r\n");
#line hidden #line hidden
WriteLiteral(" <li"); WriteLiteral(" <li");
WriteAttribute("title", Tuple.Create(" title=\"", 4806), Tuple.Create("\"", 4837) WriteAttribute("title", Tuple.Create(" title=\"", 4891), Tuple.Create("\"", 4922)
#line 77 "..\..\Views\Device\Export.cshtml" #line 77 "..\..\Views\Device\Export.cshtml"
, Tuple.Create(Tuple.Create("", 4814), Tuple.Create<System.Object, System.Int32>(optionItem.Description , Tuple.Create(Tuple.Create("", 4899), Tuple.Create<System.Object, System.Int32>(optionItem.Description
#line default #line default
#line hidden #line hidden
, 4814), false) , 4899), false)
); );
WriteLiteral(">\r\n <input"); WriteLiteral(">\r\n <input");
WriteLiteral(" type=\"checkbox\""); WriteLiteral(" type=\"checkbox\"");
WriteAttribute("id", Tuple.Create(" id=\"", 4919), Tuple.Create("\"", 4956) WriteAttribute("id", Tuple.Create(" id=\"", 5004), Tuple.Create("\"", 5041)
, Tuple.Create(Tuple.Create("", 4924), Tuple.Create("Options_", 4924), true) , Tuple.Create(Tuple.Create("", 5009), Tuple.Create("Options_", 5009), true)
#line 78 "..\..\Views\Device\Export.cshtml" #line 78 "..\..\Views\Device\Export.cshtml"
, Tuple.Create(Tuple.Create("", 4932), Tuple.Create<System.Object, System.Int32>(optionItem.PropertyName , Tuple.Create(Tuple.Create("", 5017), Tuple.Create<System.Object, System.Int32>(optionItem.PropertyName
#line default #line default
#line hidden #line hidden
, 4932), false) , 5017), false)
); );
WriteAttribute("name", Tuple.Create(" name=\"", 4957), Tuple.Create("\"", 4996) WriteAttribute("name", Tuple.Create(" name=\"", 5042), Tuple.Create("\"", 5081)
, Tuple.Create(Tuple.Create("", 4964), Tuple.Create("Options.", 4964), true) , Tuple.Create(Tuple.Create("", 5049), Tuple.Create("Options.", 5049), true)
#line 78 "..\..\Views\Device\Export.cshtml" #line 78 "..\..\Views\Device\Export.cshtml"
, Tuple.Create(Tuple.Create("", 4972), Tuple.Create<System.Object, System.Int32>(optionItem.PropertyName , Tuple.Create(Tuple.Create("", 5057), Tuple.Create<System.Object, System.Int32>(optionItem.PropertyName
#line default #line default
#line hidden #line hidden
, 4972), false) , 5057), false)
); );
WriteLiteral(" value=\"true\""); WriteLiteral(" value=\"true\"");
@@ -477,15 +477,15 @@ WriteLiteral(" ");
#line hidden #line hidden
WriteLiteral(" /><label"); WriteLiteral(" /><label");
WriteAttribute("for", Tuple.Create(" for=\"", 5067), Tuple.Create("\"", 5105) WriteAttribute("for", Tuple.Create(" for=\"", 5152), Tuple.Create("\"", 5190)
, Tuple.Create(Tuple.Create("", 5073), Tuple.Create("Options_", 5073), true) , Tuple.Create(Tuple.Create("", 5158), Tuple.Create("Options_", 5158), true)
#line 78 "..\..\Views\Device\Export.cshtml" #line 78 "..\..\Views\Device\Export.cshtml"
, Tuple.Create(Tuple.Create("", 5081), Tuple.Create<System.Object, System.Int32>(optionItem.PropertyName , Tuple.Create(Tuple.Create("", 5166), Tuple.Create<System.Object, System.Int32>(optionItem.PropertyName
#line default #line default
#line hidden #line hidden
, 5081), false) , 5166), false)
); );
WriteLiteral(">"); WriteLiteral(">");
@@ -570,10 +570,12 @@ WriteLiteral(" <script>\r\n $(function () {\r\n
" resizable: false,\r\n modal: true,\r\n " + " resizable: false,\r\n modal: true,\r\n " +
" autoOpen: true\r\n });\r\n $(\'#Devices_Export_Butto" + " autoOpen: true\r\n });\r\n $(\'#Devices_Export_Butto" +
"n\').click(function () {\r\n $form.submit();\r\n })" + "n\').click(function () {\r\n $form.submit();\r\n })" +
";\r\n });\r\n </script>\r\n"); ";\r\n $(\'#Devices_Export_Save_Button\').click(function () {\r\n " +
" $form.attr(\'action\', $form.data(\'saveaction\'));\r\n " +
" $form.submit();\r\n });\r\n });\r\n </script>\r\n");
#line 176 "..\..\Views\Device\Export.cshtml" #line 180 "..\..\Views\Device\Export.cshtml"
} }
@@ -582,7 +584,7 @@ WriteLiteral(" <script>\r\n $(function () {\r\n
WriteLiteral("</div>\r\n"); WriteLiteral("</div>\r\n");
#line 178 "..\..\Views\Device\Export.cshtml" #line 182 "..\..\Views\Device\Export.cshtml"
if (Model.ExportId.HasValue) if (Model.ExportId.HasValue)
{ {
@@ -600,13 +602,13 @@ WriteLiteral(" title=\"Export Devices\"");
WriteLiteral(">\r\n"); WriteLiteral(">\r\n");
#line 181 "..\..\Views\Device\Export.cshtml" #line 185 "..\..\Views\Device\Export.cshtml"
#line default #line default
#line hidden #line hidden
#line 181 "..\..\Views\Device\Export.cshtml" #line 185 "..\..\Views\Device\Export.cshtml"
if (Model.ExportResult.RecordCount == 0) if (Model.ExportResult.RecordCount == 0)
{ {
@@ -616,7 +618,7 @@ WriteLiteral(">\r\n");
WriteLiteral(" <h4>No records matched the filter criteria</h4>\r\n"); WriteLiteral(" <h4>No records matched the filter criteria</h4>\r\n");
#line 184 "..\..\Views\Device\Export.cshtml" #line 188 "..\..\Views\Device\Export.cshtml"
} }
else else
{ {
@@ -627,7 +629,7 @@ WriteLiteral(" <h4>No records matched the filter criteria</h4>\r\n");
WriteLiteral(" <h4>"); WriteLiteral(" <h4>");
#line 187 "..\..\Views\Device\Export.cshtml" #line 191 "..\..\Views\Device\Export.cshtml"
Write(Model.ExportResult.RecordCount); Write(Model.ExportResult.RecordCount);
@@ -636,7 +638,7 @@ WriteLiteral(" <h4>");
WriteLiteral(" record"); WriteLiteral(" record");
#line 187 "..\..\Views\Device\Export.cshtml" #line 191 "..\..\Views\Device\Export.cshtml"
Write(Model.ExportResult.RecordCount != 1 ? "s" : null); Write(Model.ExportResult.RecordCount != 1 ? "s" : null);
@@ -646,14 +648,14 @@ WriteLiteral(" were successfully exported.</h4>\r\n");
WriteLiteral(" <a"); WriteLiteral(" <a");
WriteAttribute("href", Tuple.Create(" href=\"", 9673), Tuple.Create("\"", 9744) WriteAttribute("href", Tuple.Create(" href=\"", 9955), Tuple.Create("\"", 10026)
#line 188 "..\..\Views\Device\Export.cshtml" #line 192 "..\..\Views\Device\Export.cshtml"
, Tuple.Create(Tuple.Create("", 9680), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.API.Device.ExportRetrieve(Model.ExportId.Value)) , Tuple.Create(Tuple.Create("", 9962), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.API.Device.ExportRetrieve(Model.ExportId.Value))
#line default #line default
#line hidden #line hidden
, 9680), false) , 9962), false)
); );
WriteLiteral(" class=\"button\""); WriteLiteral(" class=\"button\"");
@@ -665,7 +667,7 @@ WriteLiteral(" class=\"fa fa-download fa-lg\"");
WriteLiteral("></i>Download Device Export</a>\r\n"); WriteLiteral("></i>Download Device Export</a>\r\n");
#line 189 "..\..\Views\Device\Export.cshtml" #line 193 "..\..\Views\Device\Export.cshtml"
} }
@@ -688,7 +690,7 @@ WriteLiteral(@" <script>
"); ");
#line 203 "..\..\Views\Device\Export.cshtml" #line 207 "..\..\Views\Device\Export.cshtml"
} }
@@ -712,15 +714,69 @@ WriteLiteral("></i>Exporting devices...</h4>\r\n</div>\r\n<div");
WriteLiteral(" class=\"actionBar\""); WriteLiteral(" class=\"actionBar\"");
WriteLiteral(">\r\n <a"); WriteLiteral(">\r\n");
WriteLiteral(" id=\"Devices_Export_Button\"");
WriteLiteral(" href=\"#\""); #line 212 "..\..\Views\Device\Export.cshtml"
#line default
#line hidden
#line 212 "..\..\Views\Device\Export.cshtml"
if (Authorization.Has(Claims.Config.ManageSavedExports))
{
#line default
#line hidden
WriteLiteral(" <button");
WriteLiteral(" type=\"button\"");
WriteLiteral(" id=\"Devices_Export_Save_Button\"");
WriteLiteral(" class=\"button\""); WriteLiteral(" class=\"button\"");
WriteLiteral(">Export Devices</a>\r\n</div>\r\n"); WriteLiteral(">Save Export</button>\r\n");
#line 215 "..\..\Views\Device\Export.cshtml"
}
else
{
#line default
#line hidden
WriteLiteral(" <button");
WriteLiteral(" type=\"button\"");
WriteLiteral(" class=\"button\"");
WriteLiteral(" disabled");
WriteLiteral(" title=\"Requires Manage Saved Exports Permission\"");
WriteLiteral(">Save Export</button>\r\n");
#line 219 "..\..\Views\Device\Export.cshtml"
}
#line default
#line hidden
WriteLiteral("\r\n <button");
WriteLiteral(" type=\"button\"");
WriteLiteral(" id=\"Devices_Export_Button\"");
WriteLiteral(" class=\"button\"");
WriteLiteral(">Export Now</button>\r\n</div>\r\n");
} }
} }