Feature #42: Active Directory Interop Upgrade

AD Interop moved to Disco.Services; Supports multi-domain environments,
sites, and searching restricted with OUs.
This commit is contained in:
Gary Sharp
2014-04-10 17:58:04 +10:00
parent b841c6b2c0
commit db73cc1a12
218 changed files with 6383 additions and 2535 deletions
@@ -1,9 +1,9 @@
using Disco.BI.Extensions;
using Disco.BI.Interop.ActiveDirectory;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Authorization.Roles;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Users;
using Disco.Services.Web;
using System;
@@ -75,7 +75,7 @@ namespace Disco.Web.Areas.API.Controllers
var oldRoleName = AuthorizationRole.Name;
AuthorizationRole.Name = Name;
UserService.UpdateAuthorizationRole(Database, AuthorizationRole);
AuthorizationLog.LogRoleConfiguredRenamed(AuthorizationRole, CurrentUser.Id, oldRoleName);
AuthorizationLog.LogRoleConfiguredRenamed(AuthorizationRole, CurrentUser.UserId, oldRoleName);
}
}
}
@@ -93,9 +93,9 @@ namespace Disco.Web.Areas.API.Controllers
UserService.UpdateAuthorizationRole(Database, AuthorizationRole);
if (removedClaims.Length > 0)
AuthorizationLog.LogRoleConfiguredClaimsRemoved(AuthorizationRole, CurrentUser.Id, removedClaims);
AuthorizationLog.LogRoleConfiguredClaimsRemoved(AuthorizationRole, CurrentUser.UserId, removedClaims);
if (addedClaims.Length > 0)
AuthorizationLog.LogRoleConfiguredClaimsAdded(AuthorizationRole, CurrentUser.Id, addedClaims);
AuthorizationLog.LogRoleConfiguredClaimsAdded(AuthorizationRole, CurrentUser.UserId, addedClaims);
}
private void UpdateSubjects(AuthorizationRole AuthorizationRole, string[] Subjects)
@@ -107,7 +107,7 @@ namespace Disco.Web.Areas.API.Controllers
// Validate Subjects
if (Subjects != null && Subjects.Length > 0)
{
var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple<string, IActiveDirectoryObject>(s, ActiveDirectory.GetObject(s))).ToList();
var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple<string, IActiveDirectoryObject>(s, ActiveDirectory.RetrieveObject(s))).ToList();
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
if (invalidSubjects.Count > 0)
@@ -130,9 +130,9 @@ namespace Disco.Web.Areas.API.Controllers
UserService.UpdateAuthorizationRole(Database, AuthorizationRole);
if (removedSubjects != null && removedSubjects.Length > 0)
AuthorizationLog.LogRoleConfiguredSubjectsRemoved(AuthorizationRole, CurrentUser.Id, removedSubjects);
AuthorizationLog.LogRoleConfiguredSubjectsRemoved(AuthorizationRole, CurrentUser.UserId, removedSubjects);
if (addedSubjects != null && addedSubjects.Length > 0)
AuthorizationLog.LogRoleConfiguredSubjectsAdded(AuthorizationRole, CurrentUser.Id, addedSubjects);
AuthorizationLog.LogRoleConfiguredSubjectsAdded(AuthorizationRole, CurrentUser.UserId, addedSubjects);
}
}
@@ -234,8 +234,8 @@ namespace Disco.Web.Areas.API.Controllers
public virtual ActionResult SearchSubjects(string term)
{
var groupResults = BI.Interop.ActiveDirectory.ActiveDirectory.SearchGroups(term).Cast<IActiveDirectoryObject>();
var userResults = BI.Interop.ActiveDirectory.ActiveDirectory.SearchUsers(term).Cast<IActiveDirectoryObject>();
var groupResults = ActiveDirectory.SearchGroups(term).Cast<IActiveDirectoryObject>();
var userResults = ActiveDirectory.SearchUserAccounts(term).Cast<IActiveDirectoryObject>();
var results = groupResults.Concat(userResults).OrderBy(r => r.SamAccountName)
.Select(r => Models.AuthorizationRole.SubjectItem.FromActiveDirectoryObject(r)).ToList();
@@ -245,7 +245,7 @@ namespace Disco.Web.Areas.API.Controllers
public virtual ActionResult Subject(string Id)
{
var subject = ActiveDirectory.GetObject(Id);
var subject = ActiveDirectory.RetrieveObject(Id);
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
return Json(null, JsonRequestBehavior.AllowGet);
@@ -1,6 +1,6 @@
using Disco.BI.Extensions;
using Disco.BI.Interop.ActiveDirectory;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Users;
using Disco.Services.Web;
using System;
@@ -148,9 +148,9 @@ namespace Disco.Web.Areas.API.Controllers
device.DeviceProfile = p;
// Update AD Account
if (!string.IsNullOrEmpty(device.ComputerName) && device.ComputerName.Length <= 24)
if (!string.IsNullOrEmpty(device.DeviceDomainId) && device.DeviceDomainId.Length <= 24)
{
var adMachineAccount = ActiveDirectory.GetMachineAccount(device.ComputerName);
var adMachineAccount = ActiveDirectory.RetrieveMachineAccount(device.DeviceDomainId);
if (adMachineAccount != null)
adMachineAccount.SetDescription(device);
}
@@ -501,7 +501,7 @@ namespace Disco.Web.Areas.API.Controllers
var da = Database.DeviceAttachments.Include("TechUser").Where(m => m.Id == id).FirstOrDefault();
if (da != null)
{
if (da.TechUserId.Equals(CurrentUser.Id, StringComparison.InvariantCultureIgnoreCase))
if (da.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
Authorization.RequireAny(Claims.Device.Actions.RemoveAnyAttachments, Claims.Device.Actions.RemoveOwnAttachments);
else
Authorization.Require(Claims.Device.Actions.RemoveAnyAttachments);
@@ -1,6 +1,7 @@
using Disco.BI.Extensions;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Web;
using System;
using System.Linq;
@@ -90,7 +91,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Device Profile Number");
}
if (redirect.HasValue && redirect.Value)
return RedirectToAction(MVC.Config.DeviceModel.Index(deviceProfile.Id));
return RedirectToAction(MVC.Config.DeviceProfile.Index(deviceProfile.Id));
else
return Json("OK", JsonRequestBehavior.AllowGet);
}
@@ -245,11 +246,13 @@ namespace Disco.Web.Areas.API.Controllers
private void UpdateOrganisationalUnit(Disco.Models.Repository.DeviceProfile deviceProfile, string OrganisationalUnit)
{
if (string.IsNullOrWhiteSpace(OrganisationalUnit))
OrganisationalUnit = null;
OrganisationalUnit = ActiveDirectory.PrimaryDomain.GetDefaultComputerContainer();
deviceProfile.OrganisationalUnit = OrganisationalUnit;
Database.SaveChanges();
if (OrganisationalUnit != deviceProfile.OrganisationalUnit)
{
deviceProfile.OrganisationalUnit = OrganisationalUnit;
Database.SaveChanges();
}
}
private void UpdateComputerNameTemplate(Disco.Models.Repository.DeviceProfile deviceProfile, string ComputerNameTemplate)
@@ -364,13 +367,6 @@ namespace Disco.Web.Areas.API.Controllers
}
#endregion
[DiscoAuthorize(Claims.Config.DeviceProfile.Configure)]
public virtual ActionResult OrganisationalUnits()
{
var OUs = BI.Interop.ActiveDirectory.ActiveDirectory.GetOrganisationalUnitStructure();
return Json(OUs, JsonRequestBehavior.AllowGet);
}
#region Actions
[DiscoAuthorize(Claims.Config.DeviceProfile.Delete)]
@@ -663,7 +663,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Date Format");
}
}
job.JobMetaNonWarranty.AccountingChargeRequiredUserId = CurrentUser.Id;
job.JobMetaNonWarranty.AccountingChargeRequiredUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -697,7 +697,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Date Format");
}
}
job.JobMetaNonWarranty.AccountingChargeAddedUserId = CurrentUser.Id;
job.JobMetaNonWarranty.AccountingChargeAddedUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -731,7 +731,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Date Format");
}
}
job.JobMetaNonWarranty.AccountingChargePaidUserId = CurrentUser.Id;
job.JobMetaNonWarranty.AccountingChargePaidUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -765,7 +765,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Date Format");
}
}
job.JobMetaNonWarranty.PurchaseOrderRaisedUserId = CurrentUser.Id;
job.JobMetaNonWarranty.PurchaseOrderRaisedUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -808,7 +808,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Date Format");
}
}
job.JobMetaNonWarranty.PurchaseOrderSentUserId = CurrentUser.Id;
job.JobMetaNonWarranty.PurchaseOrderSentUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -842,7 +842,7 @@ namespace Disco.Web.Areas.API.Controllers
throw new Exception("Invalid Date Format");
}
}
job.JobMetaNonWarranty.InvoiceReceivedUserId = CurrentUser.Id;
job.JobMetaNonWarranty.InvoiceReceivedUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -991,7 +991,7 @@ namespace Disco.Web.Areas.API.Controllers
}
}
}
job.JobMetaInsurance.ClaimFormSentUserId = CurrentUser.Id;
job.JobMetaInsurance.ClaimFormSentUserId = CurrentUser.UserId;
Database.SaveChanges();
return new Models.Job._DateChangeModel()
{
@@ -1508,7 +1508,7 @@ namespace Disco.Web.Areas.API.Controllers
JobLog jobLog = new JobLog()
{
JobId = job.Id,
TechUserId = CurrentUser.Id,
TechUserId = CurrentUser.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("Added Flag: {0}{1}Reason: {2}", flagStatus.Item1, Environment.NewLine, Reason)
};
@@ -1857,7 +1857,7 @@ namespace Disco.Web.Areas.API.Controllers
var jl = new Disco.Models.Repository.JobLog()
{
JobId = j.Id,
TechUserId = CurrentUser.Id,
TechUserId = CurrentUser.UserId,
Timestamp = DateTime.Now,
Comments = comment
};
@@ -1876,7 +1876,7 @@ namespace Disco.Web.Areas.API.Controllers
var jl = Database.JobLogs.Find(id);
if (jl != null)
{
if (jl.TechUserId.Equals(CurrentUser.Id, StringComparison.InvariantCultureIgnoreCase))
if (jl.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
Authorization.RequireAny(Claims.Job.Actions.RemoveAnyLogs, Claims.Job.Actions.RemoveOwnLogs);
else
Authorization.Require(Claims.Job.Actions.RemoveAnyLogs);
@@ -1950,7 +1950,7 @@ namespace Disco.Web.Areas.API.Controllers
var ja = new Disco.Models.Repository.JobAttachment()
{
JobId = j.Id,
TechUserId = CurrentUser.Id,
TechUserId = CurrentUser.UserId,
Filename = file.FileName,
MimeType = contentType,
Timestamp = DateTime.Now,
@@ -2012,7 +2012,7 @@ namespace Disco.Web.Areas.API.Controllers
var ja = Database.JobAttachments.Include("TechUser").Where(m => m.Id == id).FirstOrDefault();
if (ja != null)
{
if (ja.TechUserId.Equals(CurrentUser.Id, StringComparison.InvariantCultureIgnoreCase))
if (ja.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
Authorization.RequireAny(Claims.Job.Actions.RemoveAnyAttachments, Claims.Job.Actions.RemoveOwnAttachments);
else
Authorization.Require(Claims.Job.Actions.RemoveAnyAttachments);
@@ -2046,7 +2046,7 @@ namespace Disco.Web.Areas.API.Controllers
JobId = j.Id,
Description = Description,
Cost = cost,
TechUserId = CurrentUser.Id
TechUserId = CurrentUser.UserId
};
Database.JobComponents.Add(jc);
Database.SaveChanges();
@@ -1,5 +1,4 @@
using Disco.BI.Interop.ActiveDirectory;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Jobs.JobQueues;
@@ -9,6 +8,7 @@ using System;
using System.Linq;
using System.Web.Mvc;
using System.Collections.Generic;
using Disco.Services.Interop.ActiveDirectory;
namespace Disco.Web.Areas.API.Controllers
{
@@ -288,7 +288,7 @@ namespace Disco.Web.Areas.API.Controllers
// Validate Subjects
if (Subjects != null && Subjects.Length > 0)
{
var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple<string, IActiveDirectoryObject>(s, ActiveDirectory.GetObject(s))).ToList();
var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple<string, IActiveDirectoryObject>(s, ActiveDirectory.RetrieveObject(s))).ToList();
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
if (invalidSubjects.Count > 0)
@@ -370,8 +370,8 @@ namespace Disco.Web.Areas.API.Controllers
[DiscoAuthorize(Claims.Config.JobQueue.Configure)]
public virtual ActionResult SearchSubjects(string term)
{
var groupResults = BI.Interop.ActiveDirectory.ActiveDirectory.SearchGroups(term).Cast<IActiveDirectoryObject>();
var userResults = BI.Interop.ActiveDirectory.ActiveDirectory.SearchUsers(term).Cast<IActiveDirectoryObject>();
var groupResults = ActiveDirectory.SearchGroups(term).Cast<IActiveDirectoryObject>();
var userResults = ActiveDirectory.SearchUserAccounts(term).Cast<IActiveDirectoryObject>();
var results = groupResults.Concat(userResults).OrderBy(r => r.SamAccountName)
.Select(r => Models.JobQueue.SubjectItem.FromActiveDirectoryObject(r)).ToList();
@@ -382,7 +382,7 @@ namespace Disco.Web.Areas.API.Controllers
[DiscoAuthorize(Claims.Config.JobQueue.Configure)]
public virtual ActionResult Subject(string Id)
{
var subject = ActiveDirectory.GetObject(Id);
var subject = ActiveDirectory.RetrieveObject(Id);
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
return Json(null, JsonRequestBehavior.AllowGet);
@@ -1,8 +1,11 @@
using Disco.BI.Extensions;
using Disco.BI.Interop.ActiveDirectory;
using Disco.Data.Configuration;
using Disco.Models.Interop.ActiveDirectory;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Web;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
@@ -17,7 +20,7 @@ namespace Disco.Web.Areas.API.Controllers
[DiscoAuthorize(Claims.Config.System.Show)]
public virtual ActionResult UpdateLastNetworkLogonDates()
{
var taskStatus = ActiveDirectoryUpdateLastNetworkLogonDateJob.ScheduleImmediately();
var taskStatus = Disco.Services.Interop.ActiveDirectory.Internal.ADUpdateLastNetworkLogonDateJob.ScheduleImmediately();
return RedirectToAction(MVC.Config.Logging.TaskStatus(taskStatus.SessionId));
}
@@ -219,5 +222,97 @@ namespace Disco.Web.Areas.API.Controllers
#endregion
#region Active Directory
[DiscoAuthorize(Claims.Config.System.ConfigureActiveDirectory)]
public virtual ActionResult UpdateActiveDirectorySearchScope(List<string> Containers, bool redirect = false)
{
ActiveDirectory.UpdateSearchContainers(Database, Containers);
Database.SaveChanges();
if (redirect)
return RedirectToAction(MVC.Config.SystemConfig.Index());
else
return Json("OK", JsonRequestBehavior.AllowGet);
}
[DiscoAuthorize(Claims.Config.System.ConfigureActiveDirectory)]
public virtual ActionResult UpdateActiveDirectorySearchEntireForest(bool SearchEntireForest, bool redirect = false)
{
try
{
var result = ActiveDirectory.UpdateSearchEntireForest(Database, SearchEntireForest);
Database.SaveChanges();
if (!result)
{
var forestServers = ActiveDirectory.LoadForestServers();
if (forestServers.Count > ActiveDirectory.MaxForestServerSearch)
throw new InvalidOperationException(string.Format("This forest contains more than the Max Forest Server Search restriction ({0})", ActiveDirectory.MaxForestServerSearch));
else
throw new InvalidOperationException("Unable to change the 'SearchEntireForest' property for an unknown reason, please report this bug");
}
if (redirect)
return RedirectToAction(MVC.Config.SystemConfig.Index());
else
return Json("OK", JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
if (redirect)
throw;
else
return Json(string.Format("Error: {0}", ex.Message), JsonRequestBehavior.AllowGet);
}
}
[DiscoAuthorizeAny(Claims.Config.System.ConfigureActiveDirectory, Claims.Config.DeviceProfile.Configure)]
public virtual ActionResult DomainOrganisationalUnits()
{
var domainOUs = ActiveDirectory.Domains
.Select(d => new Models.System.DomainOrganisationalUnitsModel() { Domain = d, OrganisationalUnits = ActiveDirectory.RetrieveOrganisationalUnitStructure(d) })
.Select(ous => ous.ToFancyTreeNode()).ToList();
return Json(domainOUs, JsonRequestBehavior.AllowGet);
}
#endregion
#region Proxy Settings
[DiscoAuthorize(Claims.Config.System.ConfigureProxy)]
public virtual ActionResult UpdateProxySettings(string ProxyAddress, int? ProxyPort, string ProxyUsername, string ProxyPassword, bool redirect = false)
{
// Default Proxy Port
if (!ProxyPort.HasValue)
ProxyPort = 8080;
SystemConfiguration config = Database.DiscoConfiguration;
//config.DataStoreLocation = DataStoreLocation;
config.ProxyAddress = ProxyAddress;
config.ProxyPort = ProxyPort.Value;
config.ProxyUsername = ProxyUsername;
config.ProxyPassword = ProxyPassword;
DiscoApplication.SetGlobalProxy(ProxyAddress, ProxyPort.Value, ProxyUsername, ProxyPassword);
Database.SaveChanges();
// Try and check for updates if needed - After Proxy Changed
if (Database.DiscoConfiguration.UpdateLastCheck == null
|| Database.DiscoConfiguration.UpdateLastCheck.ResponseTimestamp < DateTime.Now.AddDays(-1))
{
Disco.BI.Interop.Community.UpdateCheckTask.ScheduleNow();
}
if (redirect)
return RedirectToAction(MVC.Config.SystemConfig.Index());
else
return Json("OK", JsonRequestBehavior.AllowGet);
}
#endregion
}
}
@@ -1,5 +1,6 @@
using Disco.BI.Extensions;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Users;
using Disco.Services.Web;
using System;
@@ -61,8 +62,13 @@ namespace Disco.Web.Areas.API.Controllers
}
[DiscoAuthorize(Claims.User.Actions.AddAttachments)]
public virtual ActionResult AttachmentUpload(string id, string Comments)
public virtual ActionResult AttachmentUpload(string id, string Domain, string Comments)
{
if (string.IsNullOrEmpty(Domain))
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
else
id = Domain + @"\" + id;
var u = Database.Users.Find(id);
if (u != null)
{
@@ -77,7 +83,7 @@ namespace Disco.Web.Areas.API.Controllers
var ua = new Disco.Models.Repository.UserAttachment()
{
UserId = u.Id,
UserId = u.UserId,
TechUserId = UserService.CurrentUserId,
Filename = file.FileName,
MimeType = contentType,
@@ -118,9 +124,14 @@ namespace Disco.Web.Areas.API.Controllers
}
[DiscoAuthorize(Claims.User.ShowAttachments)]
public virtual ActionResult Attachments(string id)
public virtual ActionResult Attachments(string id, string Domain)
{
var u = Database.Users.Include("UserAttachments.TechUser").Where(m => m.Id == id).FirstOrDefault();
if (string.IsNullOrEmpty(Domain))
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
else
id = Domain + @"\" + id;
var u = Database.Users.Include("UserAttachments.TechUser").Where(m => m.UserId == id).FirstOrDefault();
if (u != null)
{
var m = new Models.Attachment.AttachmentsModel()
@@ -140,7 +151,7 @@ namespace Disco.Web.Areas.API.Controllers
var ua = Database.UserAttachments.Include("TechUser").Where(m => m.Id == id).FirstOrDefault();
if (ua != null)
{
if (ua.TechUserId.Equals(CurrentUser.Id, StringComparison.InvariantCultureIgnoreCase))
if (ua.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase))
Authorization.RequireAny(Claims.User.Actions.RemoveAnyAttachments, Claims.User.Actions.RemoveOwnAttachments);
else
Authorization.Require(Claims.User.Actions.RemoveAnyAttachments);
@@ -155,12 +166,18 @@ namespace Disco.Web.Areas.API.Controllers
#endregion
[DiscoAuthorize(Claims.User.Actions.GenerateDocuments)]
public virtual ActionResult GeneratePdf(string id, string DocumentTemplateId)
public virtual ActionResult GeneratePdf(string id, string Domain, string DocumentTemplateId)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException("id");
if (string.IsNullOrEmpty(DocumentTemplateId))
throw new ArgumentNullException("AttachmentTypeId");
if (string.IsNullOrEmpty(Domain))
id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id;
else
id = Domain + @"\" + id;
var user = Database.Users.Find(id);
if (user != null)
{
@@ -174,7 +191,7 @@ namespace Disco.Web.Areas.API.Controllers
pdf = documentTemplate.GeneratePdf(Database, user, UserService.CurrentUser, timeStamp, generationState);
}
Database.SaveChanges();
return File(pdf, "application/pdf", string.Format("{0}_{1}_{2:yyyyMMdd-HHmmss}.pdf", documentTemplate.Id, user.Id, timeStamp));
return File(pdf, "application/pdf", string.Format("{0}_{1}_{2:yyyyMMdd-HHmmss}.pdf", documentTemplate.Id, user.UserId, timeStamp));
}
else
{