Jonathan Ouellette 580e90f6a2 initial add
2022-09-27 14:10:30 -07:00

754 lines
26 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Fab2ApprovalSystem.Models;
using Fab2ApprovalSystem.DMO;
using Fab2ApprovalSystem.Misc;
using Kendo.Mvc.Extensions;
using Kendo.Mvc.UI;
namespace Fab2ApprovalSystem.Controllers
{
[Authorize]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
[SessionExpireFilter]
public class PartsRequestController : Controller
{
PartsRequestDMO prDMO = new PartsRequestDMO();
UserAccountDMO userDMO = new UserAccountDMO();
WorkflowDMO wfDMO = new WorkflowDMO();
const int WorkflowNumber = 1;
public PartsRequestController()
{
ViewBag.ShowReAssignApprovers = false;
}
protected ActionResult HandleValidationError(string msg)
{
Response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest;
return Json(new { result = "Invalid", detail = msg });
}
protected ActionResult HandleAPIException(int issueID, Exception ex, string additionalKeys = "")
{
HandleException(issueID, ex, additionalKeys);
Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
return Json(new { result = "Error", issueID = issueID, detail = ex.Message });
}
protected void HandleException(int issueID, Exception ex, string additionalKeys = "")
{
var st = new System.Diagnostics.StackTrace();
var sf = st.GetFrame(1);
String controller = sf.GetMethod().DeclaringType.Name.Replace("Controller", "");
String method = sf.GetMethod().Name;
string detailedException = String.Format(
"Exception for issue # {0}\r\n" +
"Controller: {1}, Method: {2}, User: {3}, Keys: {4}\r\n" +
"=====\r\n",
issueID,
controller,
method,
User?.Identity?.Name,
additionalKeys);
Exception x = ex;
while (x != null)
{
detailedException += x.ToString();
detailedException += "\r\n=====\r\n";
x = x.InnerException;
}
Functions.WriteEvent(detailedException, System.Diagnostics.EventLogEntryType.Error);
EventLogDMO.Add(new WinEventLog()
{
IssueID = issueID,
UserID = @User.Identity.Name,
DocumentType = controller,
OperationType = "Error",
Comments = detailedException
});
}
// GET: PartsRequest
public ActionResult Index()
{
return View();
}
public ActionResult Edit(int issueID)
{
var pr = new PartsRequest();
try
{
pr = prDMO.Get(issueID);
if (pr == null)
{
ViewBag.ErrorDescription = "Document does not exist";
return View("Error");
}
else if (pr.CurrentStep < 0)
{
ViewBag.ErrorDescription = "Document is deleted";
return View("Error");
}
else if (pr.CurrentStep >= 1)
{
return RedirectToAction("EditApproval", new { issueID = issueID });
}
else
{
if (pr.OriginatorID != (int)Session[GlobalVars.SESSION_USERID])
{
if (Convert.ToBoolean(Session[GlobalVars.IS_ADMIN]) == false)
{
return RedirectToAction("ReadOnly", new { issueID = issueID });
}
}
ViewBag.UserList = userDMO.GetAllUsers();
return View(pr);
}
}
catch (Exception e)
{
HandleException(issueID, e);
return View("Error");
}
}
[HttpPost]
public ActionResult Edit(PartsRequest pr)
{
try
{
var pr_srv = prDMO.Get(pr.PRNumber);
if (pr_srv == null)
{
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Document does not exist");
}
if (pr_srv.CurrentStep < 0)
{
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Document is deleted");
}
if (pr_srv.CurrentStep >= 1)
{
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Parts Request is not editable");
}
prDMO.Update(pr);
return Content("");
}
catch (Exception e)
{
return HandleAPIException(pr.PRNumber, e);
}
}
public ActionResult EditApproval(int issueID)
{
var pr = new PartsRequest();
try
{
int myUserID = (int)Session[GlobalVars.SESSION_USERID];
pr = prDMO.Get(issueID);
if (pr == null)
{
ViewBag.ErrorDescription = "Document does not exist";
return View("Error");
}
if (pr.CurrentStep < 0)
{
ViewBag.ErrorDescription = "Document is deleted";
return View("Error");
}
var wfStep = wfDMO.GetWorkflowStep((int)GlobalVars.DocumentType.PartsRequest, WorkflowNumber, pr.CurrentStep);
var userList = MiscDMO.GetPendingApproversListByDocument(issueID, Convert.ToByte(pr.CurrentStep), (int)GlobalVars.DocumentType.PartsRequest);
ViewBag.IsApprover = (userList.Count(u => u.UserID == myUserID) > 0);
if (ViewBag.IsApprover == false)
{
if (pr.OriginatorID != myUserID)
{
if (Convert.ToBoolean(Session[GlobalVars.IS_ADMIN]) == false)
{
return RedirectToAction("ReadOnly", new { issueID = issueID });
}
}
}
ViewBag.IsAdmin = Convert.ToBoolean(Session[GlobalVars.IS_ADMIN]);
ViewBag.IsOriginator = (pr.OriginatorID == myUserID);
ViewBag.AllowReject = (wfStep != null ? (wfStep.AllowReject.HasValue && wfStep.AllowReject.Value) : false);
ViewBag.ShowReAssignApprovers = ViewBag.IsAdmin || ViewBag.IsOriginator;
ViewBag.ShowAddApprovers = ViewBag.IsAdmin || ViewBag.IsApprover || ViewBag.IsOriginator;
ViewBag.UserList = userDMO.GetAllUsers();
return View(pr);
}
catch (Exception e)
{
HandleException(issueID, e);
return View("Error");
}
}
public ActionResult ReadOnly(int issueID)
{
var pr = new PartsRequest();
try
{
int myUserID = (int)Session[GlobalVars.SESSION_USERID];
pr = prDMO.Get(issueID);
if (pr == null)
{
ViewBag.ErrorDescription = "Document does not exist";
return View("Error");
}
if (pr.CurrentStep < 0)
{
ViewBag.ErrorDescription = "Document is deleted";
return View("Error");
}
ViewBag.IsAdmin = Convert.ToBoolean(Session[GlobalVars.IS_ADMIN]);
ViewBag.IsOriginator = (pr.OriginatorID == myUserID);
ViewBag.UserList = userDMO.GetAllUsers();
return View(pr);
}
catch (Exception e)
{
HandleException(issueID, e);
return View("Error");
}
}
public ActionResult Create()
{
var pr = new PartsRequest();
try
{
pr.OriginatorID = (int)Session[GlobalVars.SESSION_USERID];
if (!CanCreatePartsRequest(pr.OriginatorID) && Convert.ToBoolean(Session[GlobalVars.CAN_CREATE_PARTS_REQUEST]) == false)
throw new Exception("User does not have permission to create Parts Request");
prDMO.Insert(pr);
return RedirectToAction("Edit", new { issueID = pr.PRNumber });
}
catch (Exception e)
{
return HandleAPIException(pr.PRNumber, e);
}
}
public static bool CanCreatePartsRequest(int userID)
{
var adminDMO = new AdminDMO();
var role = adminDMO.GetSubRoles().Where(r => string.Equals(r.RoleName, "Parts Request", StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
if (role != null)
{
var subrole = role.SubRoles.FirstOrDefault(sr => string.Equals(sr.SubRoleCategoryItem, "Originator", StringComparison.OrdinalIgnoreCase));
if (subrole != null)
{
var users = adminDMO.GetAllUsersBySubRole(subrole.SubRoleID);
if (users.Count(u => u.UserID == userID) > 0)
{
return true;
}
}
}
return false;
}
public ActionResult Attachment_Read([DataSourceRequest]DataSourceRequest request, int prNumber)
{
try
{
return Json(prDMO.GetAttachments(prNumber).ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return HandleAPIException(prNumber, ex);
}
}
[HttpPost]
public ActionResult AttachSave(IEnumerable<HttpPostedFileBase> files, int prNumber)
{
// The Name of the Upload component is "files"
if (files != null)
{
foreach (var file in files)
{
// Some browsers send file names with full path.
// We are only interested in the file name.
var fileName = System.IO.Path.GetFileName(file.FileName);
string prFolderPath = Functions.GetAttachmentFolder() + "PartsRequest\\" + prNumber.ToString();
var di = new System.IO.DirectoryInfo(prFolderPath);
if (!di.Exists)
di.Create();
var physicalPath = System.IO.Path.Combine(prFolderPath, fileName);
file.SaveAs(physicalPath);
var attach = new PartsRequestAttachment()
{
PRNumber = prNumber,
FileName = fileName,
UserID = (int)Session[GlobalVars.SESSION_USERID],
};
prDMO.InsertAttachment(attach);
}
}
return Content("");
}
public FileResult DownloadFile(string attachmentID, string prNumber)
{
string fileName = prDMO.GetFileName(attachmentID);
string folderPath = Functions.GetAttachmentFolder() + "PartsRequest\\" + prNumber.ToString();
var sDocument = System.IO.Path.Combine(folderPath, fileName);
var FDir_AppData = Functions.GetAttachmentFolder();
if (!sDocument.StartsWith(FDir_AppData))
{
// Ensure that we are serving file only inside the Fab2ApprovalAttachments folder
// and block requests outside like "../web.config"
throw new HttpException(403, "Forbidden");
}
if (!System.IO.File.Exists(sDocument))
return null;
return File(sDocument, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
[HttpPost]
public ActionResult DeleteAttachment(int attachmentID, string fileName, int prNumber)
{
try
{
if (ModelState.IsValid)
{
prDMO.DeleteAttachment(attachmentID);
var physicalPath = System.IO.Path.Combine(Functions.GetAttachmentFolder() + @"PartsRequest\" + prNumber.ToString(), fileName);
if (System.IO.File.Exists(physicalPath))
{
System.IO.File.Delete(physicalPath);
}
}
return Content("");
}
catch (Exception e)
{
return HandleAPIException(prNumber, e, "AttachmentID=" + attachmentID.ToString());
}
}
[HttpPost]
public ActionResult Submit(int prNumber)
{
try
{
int myUserID = (int)Session[GlobalVars.SESSION_USERID];
var pr = prDMO.Get(prNumber);
if (pr == null)
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Document does not exist");
if (String.IsNullOrWhiteSpace(pr.Title))
return HandleValidationError("Title is required");
if (pr.RequestorID <= 0)
return HandleValidationError("Requestor is required");
if (pr.TechLeadID <= 0)
return HandleValidationError("Tech Lead is required");
prDMO.Submit(prNumber, myUserID);
var approvers = MiscDMO.GetApprovalsByDocument(prNumber, (int)GlobalVars.DocumentType.PartsRequest);
if (approvers.Count(a => a.Step.HasValue && a.Step.Value == 1 && a.UserID == myUserID) > 0)
{
// Auto-Approve if the user is an approver for workflow step 1
var c = Approve(prNumber, 1, "Auto-Approve");
if (c != null && c is ContentResult)
{
var result = ((ContentResult)c).Content;
if (!String.Equals(result, "OK"))
throw new Exception(result);
}
if (c != null && c is JsonResult)
return c;
}
else
{
// Do step 1 notification
NotifyApprovers(prNumber, 1);
}
if (Request.IsAjaxRequest())
{
return Content("Redirect");
}
else
{
return Content("Invalid");
}
}
catch (Exception e)
{
return HandleAPIException(prNumber, e);
}
}
public ActionResult GetApproversList([DataSourceRequest]DataSourceRequest request, int issueID, byte step)
{
try
{
return Json(MiscDMO.GetApproversListByDocument(issueID, step, (int)GlobalVars.DocumentType.PartsRequest).ToDataSourceResult(request));
}
catch (Exception e)
{
return HandleAPIException(issueID, e, "Step=" + step.ToString());
}
}
public ActionResult GetAllUsersList()
{
try
{
UserAccountDMO userDMO = new UserAccountDMO();
IEnumerable<LoginModel> userlist = userDMO.GetAllUsers();
return Json(userlist, JsonRequestBehavior.AllowGet);
}
catch (Exception e)
{
return HandleAPIException(0, e);
}
}
[HttpPost]
public ActionResult ReAssignApproval(int issueID, int fromUserID, int userIDs, byte step)
{
try
{
String email = wfDMO.ReAssignApproval(
issueID, fromUserID, userIDs, step, (int)GlobalVars.DocumentType.PartsRequest);
NotifyReAssignment(issueID, email);
return Content("OK");
}
catch (Exception e)
{
return HandleAPIException(issueID, e);
}
}
[HttpPost]
public ActionResult Approve(int prNumber, byte currentStep, string comments)
{
try
{
bool lastStep = false;
bool lastApproverInCurrentStep = false;
int myUserID = (int)Session[GlobalVars.SESSION_USERID];
var pr = prDMO.Get(prNumber);
if (pr == null)
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Document does not exist");
while (true)
{
lastApproverInCurrentStep = wfDMO.Approve(
prNumber, currentStep, comments, out lastStep,
(int)Session[GlobalVars.SESSION_USERID],
(int)GlobalVars.DocumentType.PartsRequest,
WorkflowNumber);
if (!lastApproverInCurrentStep) break;
if (lastStep)
{
NotifyCompletion(prNumber);
break;
}
currentStep++;
var approvers = MiscDMO.GetApprovalsByDocument(prNumber, (int)GlobalVars.DocumentType.PartsRequest);
if (approvers.Count(a => a.Step.HasValue && a.Step.Value == currentStep) == 0)
return Content("No approvers found for next step, contact support!");
// only continue with approving if the next step has me as an approver also
if (approvers.Count(a => a.Step.HasValue && a.Step.Value == currentStep && a.UserID == myUserID) == 0)
{
NotifyApprovers(prNumber, currentStep);
break;
}
}
return Content("OK");
}
catch (Exception e)
{
return HandleAPIException(prNumber, e);
}
}
protected void SendEmailNotification(String subject, int prNumber, string toEmail, string emailTemplate)
{
string senderName = "Parts Request";
EmailNotification en = new EmailNotification(subject, System.Configuration.ConfigurationManager.AppSettings["EmailTemplatesPath"]);
string[] emailparams = new string[5];
emailparams[0] = prNumber.ToString();
emailparams[1] = prNumber.ToString();
emailparams[2] = GlobalVars.hostURL;
emailparams[3] = "Parts Request";
emailparams[4] = Session[GlobalVars.SESSION_USERNAME].ToString();
String userEmail = toEmail;
en.SendNotificationEmail(emailTemplate, GlobalVars.SENDER_EMAIL, senderName, userEmail, null, subject, emailparams);
}
protected void NotifyReAssignment(int prNumber, string email)
{
var pr = prDMO.Get(prNumber);
if (pr == null)
return;
SendEmailNotification(
subject: String.Format("Parts Request Re-Assignment notice for # {0} - {1}", pr.PRNumber, pr.Title),
prNumber: prNumber,
toEmail: email,
emailTemplate: "PRReAssigned.txt");
EventLogDMO.Add(new WinEventLog()
{
IssueID = prNumber,
UserID = @User.Identity.Name,
DocumentType = "PR",
OperationType = "Email",
Comments = "ReAssigned Approver: " + email
});
}
protected void NotifyCompletion(int prNumber)
{
var pr = prDMO.Get(prNumber);
if (pr == null)
return;
var u = userDMO.GetUserByID(pr.RequestorID);
if ((u != null) && (!String.IsNullOrWhiteSpace(u.Email)))
{
SendEmailNotification(
subject: String.Format("Parts Request Completion notice for # {0} - {1}", pr.PRNumber, pr.Title),
prNumber: prNumber,
toEmail: u.Email,
emailTemplate: "PRCompleted.txt");
EventLogDMO.Add(new WinEventLog()
{
IssueID = prNumber,
UserID = @User.Identity.Name,
DocumentType = "PR",
OperationType = "Email",
Comments = "Completed: " + u.Email
});
}
}
public void NotifyRejection(int prNumber)
{
var pr = prDMO.Get(prNumber);
if (pr == null)
return;
var u = userDMO.GetUserByID(pr.OriginatorID);
if ((u != null) && (!String.IsNullOrWhiteSpace(u.Email)))
{
SendEmailNotification(
subject: String.Format("Parts Request Rejection notice for # {0} - {1}", pr.PRNumber, pr.Title),
prNumber: prNumber,
toEmail: u.Email,
emailTemplate: "PRReject.txt");
EventLogDMO.Add(new WinEventLog()
{
IssueID = prNumber,
UserID = @User.Identity.Name,
DocumentType = "PR",
OperationType = "Email",
Comments = "Rejected: " + u.Email
});
}
}
protected void NotifyApprovers(int prNumber, byte step)
{
try
{
string emailSentList = "";
var pr = prDMO.Get(prNumber);
if (pr == null)
throw new Exception("Invalid pr#");
List<string> emailList = MiscDMO.GetApproverEmailListByDocument(
prNumber, step, (int)GlobalVars.DocumentType.PartsRequest).Distinct().ToList();
foreach (string email in emailList)
{
try
{
SendEmailNotification(
subject: String.Format("Parts Request Assignment notice for # {0} - {1}", pr.PRNumber, pr.Title),
prNumber: prNumber,
toEmail: email,
emailTemplate: "PRAssigned.txt");
}
catch (Exception ex)
{
HandleException(prNumber, ex, "email=" + email);
}
emailSentList += email + ",";
}
try
{
EventLogDMO.Add(new WinEventLog() {
IssueID = prNumber, UserID = @User.Identity.Name, DocumentType = "PR", OperationType = "Email",
Comments = "Approvers for Step " + step.ToString() + ":" + emailSentList });
}
catch { }
}
catch (Exception e)
{
HandleException(prNumber, e, "Step=" + step.ToString());
}
}
[HttpPost]
public ActionResult Reject(int prNumber, byte currentStep, string comments)
{
try
{
if (Session[GlobalVars.SESSION_USERID] != null)
{
wfDMO.Reject(prNumber, currentStep, comments, (int)Session[GlobalVars.SESSION_USERID], (int)GlobalVars.DocumentType.PartsRequest);
NotifyRejection(prNumber);
}
else
{
Response.Redirect("~/Account/Login");
}
return Content("OK");
}
catch (Exception e)
{
return HandleAPIException(prNumber, e);
}
}
public ActionResult ApprovalLogHistory_Read([DataSourceRequest] DataSourceRequest request, int prNumber)
{
return Json(prDMO.GetApprovalLogHistory(prNumber).ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
protected void NotifyAssignment(int prNumber, string email)
{
var pr = prDMO.Get(prNumber);
if (pr == null)
return;
SendEmailNotification(
subject: String.Format("Parts Request Assignment notice for # {0} - {1}", pr.PRNumber, pr.Title),
prNumber: prNumber,
toEmail: email,
emailTemplate: "PRAssigned.txt");
EventLogDMO.Add(new WinEventLog()
{
IssueID = prNumber,
UserID = @User.Identity.Name,
DocumentType = "PR",
OperationType = "Email",
Comments = "Assigned Approver: " + email
});
}
[HttpPost]
public void AddAdditionalApproval(int issueID, byte step, string userIDs)
{
var emailArray = "";
try
{
emailArray = wfDMO.AddAdditionalApproval(issueID, userIDs, step, (int)GlobalVars.DocumentType.PartsRequest);
}
catch (Exception e)
{
HandleAPIException(issueID, e);
}
string emailSentList = "";
string[] emaiList = emailArray.Split(new char[] { '~' });
foreach (string email in emaiList)
{
if (email.Length > 0)
{
NotifyAssignment(issueID, email);
emailSentList += email + ",";
}
}
try
{
EventLogDMO.Add(new WinEventLog() { IssueID = issueID, UserID = @User.Identity.Name, DocumentType = "PR",
OperationType = "Email", Comments = "Additional Approver: " + emailSentList });
}
catch { }
}
}
}