Exemplo n.º 1
0
        /// <summary>
        /// Send email notification after Response
        /// Emails sent to Group  of the release and all Power Users
        /// </summary>
        /// <param name="rspDTO"></param>
        /// <param name="releaseDTO"></param>
        internal void EmailResponse(WorkflowRequest_DTO requestDTO, WorkflowResponse_DTO rspDTO, Release_DTO releaseDTO)
        {
            eMail email = new eMail();

            Account_BSO aBso = new Account_BSO();

            ADO_readerOutput recipients = new ADO_readerOutput();

            string subject    = "";
            string body       = "";
            string releaseUrl = getReleaseUrl(releaseDTO);
            string rqsvalue   = Label.Get("workflow.request." + requestDTO.RqsValue);

            switch (rspDTO.RspCode)
            {
            case Constants.C_WORKFLOW_STATUS_APPROVE:
                //Send the email to power users only
                recipients = aBso.getUsersOfPrivilege(Resources.Constants.C_SECURITY_PRIVILEGE_POWER_USER);

                subject = string.Format(Label.Get("email.subject.response-approve"), releaseDTO.MtrCode, releaseDTO.RlsVersion, releaseDTO.RlsRevision);
                body    = string.Format(Label.Get("email.body.response-approve"), rqsvalue, releaseDTO.MtrCode, releaseDTO.RlsVersion, releaseDTO.RlsRevision, releaseUrl, rspDTO.ResponseAccount.CcnEmail, rspDTO.ResponseAccount.CcnUsername, rspDTO.ResponseAccount.CcnName);

                break;

            case Constants.C_WORKFLOW_STATUS_REJECT:

                //Send the email to
                recipients = aBso.getReleaseUsers(releaseDTO.RlsCode, false);

                subject = string.Format(Label.Get("email.subject.response-reject"), releaseDTO.MtrCode, releaseDTO.RlsVersion, releaseDTO.RlsRevision);
                body    = string.Format(Label.Get("email.body.response-reject"), rqsvalue, releaseDTO.MtrCode, releaseDTO.RlsVersion, releaseDTO.RlsRevision, releaseUrl, rspDTO.ResponseAccount.CcnEmail, rspDTO.ResponseAccount.CcnUsername, rspDTO.ResponseAccount.CcnName);

                break;
            }
            List <string> allEmails = new List <string>();


            allEmails.AddRange(getEmailAddresses(recipients));


            if (allEmails.Count == 0)
            {
                return;
            }

            foreach (string person in allEmails)
            {
                email.Bcc.Add(person);
            }


            sendMail(email, Configuration_BSO.GetCustomConfig("title"), subject, body);
            email.Dispose();
        }
Exemplo n.º 2
0
        /// <summary>
        /// Send email notifications after a WorkflowRequest has been created.
        /// Emails sent to the Group of the release
        /// </summary>
        /// <param name="requestDTO"></param>
        /// <param name="releaseDTO"></param>
        internal void EmailRequest(WorkflowRequest_DTO requestDTO, Release_DTO releaseDTO)
        {
            eMail email = new eMail();

            var v = getReleaseUrl(releaseDTO);

            Account_BSO      aBso      = new Account_BSO();
            ADO_readerOutput approvers = aBso.getReleaseUsers(releaseDTO.RlsCode, true);

            if (!approvers.hasData)
            {
                return;
            }

            List <string> emails = getEmailAddresses(approvers);


            if (emails.Count == 0)
            {
                return;
            }

            foreach (string person in emails)
            {
                email.Bcc.Add(person);
            }

            string rqsvalue = Label.Get("workflow.request." + requestDTO.RqsValue);

            string releaseUrl = getReleaseUrl(releaseDTO);
            String subject    = string.Format(Label.Get("email.subject.request-create"), releaseDTO.MtrCode, releaseDTO.RlsVersion, releaseDTO.RlsRevision);
            String body       = string.Format(Label.Get("email.body.request-create"), rqsvalue, releaseDTO.MtrCode, releaseDTO.RlsVersion, releaseDTO.RlsRevision, releaseUrl, requestDTO.RequestAccount.CcnEmail, requestDTO.RequestAccount.CcnUsername, requestDTO.RequestAccount.CcnName);

            sendMail(email, Configuration_BSO.GetCustomConfig("title"), subject, body);

            email.Dispose();
        }
Exemplo n.º 3
0
        internal JSONRPC_Output WorkflowSignoffCreate(ADO Ado, WorkflowSignoff_DTO DTO, string SamAccountName)
        {
            JSONRPC_Output   response   = new JSONRPC_Output();
            ADO_readerOutput moderators = new ADO_readerOutput();
            ADO_readerOutput powerUsers = new ADO_readerOutput();

            var adoWorkflowRequest  = new WorkflowRequest_ADO();
            var adoWorkflowResponse = new WorkflowResponse_ADO();

            Release_DTO dtoWip = null;


            if (!adoWorkflowResponse.IsInUse(Ado, DTO)) // is current workflow -- this should be the response!!
            {
                //No Live workflow found so we can't proceed
                Log.Instance.Debug("No Current workflow response found for this Release Code");
                response.error = Label.Get("error.create");
                return(response);
            }

            //Is this awaiting signoff?
            var adoWorkflow = new Workflow_ADO();
            ADO_readerOutput resultStatus = adoWorkflow.ReadAwaitingSignoff(Ado, SamAccountName, DTO.RlsCode, Configuration_BSO.GetCustomConfig(ConfigType.global, "language.iso.code"));

            if (!resultStatus.hasData)
            {
                //Release not awaiting signoff so we can't proceed
                Log.Instance.Debug("Release not in status Awaiting Signoff");
                response.error = Label.Get("error.update");
                return(response);
            }

            Security.ActiveDirectory_DTO signoffUser = new Security.ActiveDirectory_DTO()
            {
                CcnUsername = SamAccountName
            };
            Security.ActiveDirectory_ADO accAdo = new Security.ActiveDirectory_ADO();
            Security.Account_DTO_Read    accDto = new Security.Account_DTO_Read()
            {
                CcnUsername = signoffUser.CcnUsername
            };

            DTO.SignoffAccount = accAdo.GetUser(Ado, accDto);


            var adoSignoff = new WorkflowSignoff_ADO();

            //Create a comment
            var adoComment  = new Comment_ADO();
            int commentCode = adoComment.Create(Ado, DTO, SamAccountName);

            if (commentCode == 0)
            {
                // Can't create a comment so we can't proceed
                Log.Instance.Debug("Can't create a comment ");
                response.error = Label.Get("error.create");
                return(response);
            }

            DTO.CmmCode = commentCode;

            //We must read the Request and in order to see how we are going to proceed
            WorkflowRequest_ADO        adoWrq     = new WorkflowRequest_ADO();
            List <WorkflowRequest_DTO> dtoWrqList = adoWrq.Read(Ado, DTO.RlsCode, true);

            if (dtoWrqList.Count > 1)
            {
                //Multiple requests found for this release
                Log.Instance.Debug("More than one request found for this release ");
                response.error = Label.Get("error.create");
                return(response);
            }

            //there must be exactly one live Workflow request at this point
            WorkflowRequest_DTO dtoWrq = dtoWrqList.Find(x => x.RqsCode != null);

            //Get the current Release
            Release_ADO adoRelease = new Release_ADO(Ado);
            Release_DTO dtoRelease = Release_ADO.GetReleaseDTO(adoRelease.Read(DTO.RlsCode, SamAccountName));

            if (dtoRelease == null)
            {
                Log.Instance.Debug("Release not found");
                response.error = Label.Get("error.create");
                return(response);
            }

            Account_BSO aBso = new Account_BSO(Ado);

            moderators = aBso.getReleaseUsers(DTO.RlsCode, null);
            powerUsers = aBso.getUsersOfPrivilege(Constants.C_SECURITY_PRIVILEGE_POWER_USER);

            //Is this a Reject?
            if (DTO.SgnCode.Equals(Constants.C_WORKFLOW_STATUS_REJECT))
            {
                int res = adoSignoff.Create(Ado, DTO, SamAccountName);

                if (res == 0)
                {
                    //Can't create a Workflow Signoff so we can't proceed
                    Log.Instance.Debug("Can't create a Workflow Signoff ");
                    response.error = Label.Get("error.create");
                    return(response);
                }


                WorkflowRequest_DTO_Update dtoReq = new WorkflowRequest_DTO_Update(DTO.RlsCode);
                dtoReq.WrqCurrentFlag = false;

                //update the request
                int reqUpdate = adoWorkflowRequest.Update(Ado, dtoReq, SamAccountName);
                if (reqUpdate == 0)
                {
                    //Can't save the Request so we can't proceed
                    Log.Instance.Debug("Can't save the Workflow Request");
                    response.error = Label.Get("error.update");
                    return(response);
                }

                DTO.MtrCode = dtoRelease.MtrCode; // we need this to see which cache we must flush

                response.data = JSONRPC.success;

                Email_BSO_NotifyWorkflow notifyReject = new Email_BSO_NotifyWorkflow();

                try
                {
                    notifyReject.EmailSignoff(dtoWrq, DTO, dtoRelease, moderators, powerUsers);
                }
                catch { }

                return(response);
            }

            //Not a Reject so we proceed...
            switch (dtoWrq.RqsCode)
            {
            case Constants.C_WORKFLOW_REQUEST_PUBLISH:

                if (String.IsNullOrEmpty(dtoRelease.PrcCode))
                {
                    //There must be a valid product for this release
                    Log.Instance.Debug("No product found for the release ");
                    response.error = Label.Get("error.publish");
                    return(response);
                }

                //Update the current release LiveDatetimeTo to the request Date time
                dtoRelease.RlsLiveDatetimeFrom = dtoWrq.WrqDatetime;

                //set the release live flag
                //update the release version and set the current revision to 0
                DateTime switchDate;
                switchDate = DateTime.Now > dtoWrq.WrqDatetime ? DateTime.Now : dtoWrq.WrqDatetime;
                dtoRelease.RlsVersion++;
                dtoRelease.RlsRevision         = 0;
                dtoRelease.RlsLiveFlag         = true;
                dtoRelease.RlsExceptionalFlag  = dtoWrq.WrqExceptionalFlag != null ? dtoWrq.WrqExceptionalFlag.Value : false;
                dtoRelease.RlsReservationFlag  = dtoWrq.WrqReservationFlag != null ? dtoWrq.WrqReservationFlag.Value : false;
                dtoRelease.RlsArchiveFlag      = dtoWrq.WrqArchiveFlag != null ? dtoWrq.WrqArchiveFlag.Value : false;
                dtoRelease.RlsExperimentalFlag = dtoWrq.WrqExperimentalFlag != null ? dtoWrq.WrqExperimentalFlag.Value : false;
                dtoRelease.RlsLiveDatetimeFrom = switchDate;



                //get the current live release

                Release_DTO releaseDTONow = Release_ADO.GetReleaseDTO(adoRelease.ReadLiveNow(DTO.RlsCode));

                //Save the changes for the release we're changing
                int update = adoRelease.Update(dtoRelease, SamAccountName);
                if (update == 0)
                {
                    Log.Instance.Debug("Can't update the Release, RlsCode:" + dtoRelease.RlsCode);
                    response.error = Label.Get("error.update");
                    return(response);
                }

                if (releaseDTONow != null)
                {
                    //...if there is a previous release
                    if (releaseDTONow.RlsCode != 0)
                    {
                        //Update the  Live LiveDatetimeTo to the request Datetime
                        releaseDTONow.RlsLiveDatetimeTo = switchDate;
                        //Save the changes for the previous release
                        adoRelease.Update(releaseDTONow, SamAccountName);
                    }
                }


                break;

            case Constants.C_WORKFLOW_REQUEST_PROPERTY:
                //update release to transfer all flag values from the request to the release
                dtoRelease.RlsReservationFlag  = dtoWrq.WrqReservationFlag != null ? dtoWrq.WrqReservationFlag.Value : false;
                dtoRelease.RlsArchiveFlag      = dtoWrq.WrqArchiveFlag != null ? dtoWrq.WrqArchiveFlag.Value : false;
                dtoRelease.RlsExperimentalFlag = dtoWrq.WrqExperimentalFlag != null ? dtoWrq.WrqExperimentalFlag.Value : false;

                //Save the release
                int updateCount = adoRelease.Update(dtoRelease, SamAccountName);
                if (updateCount == 0)
                {
                    //Update of Release failed
                    Log.Instance.Debug("Can't update the Release, RlsCode:" + DTO.RlsCode);
                    response.error = Label.Get("error.update");
                    return(response);
                }



                //if there is a WIP or a pending live associated with this matrix then we need to update the WIP/Pending Live as well:
                Release_BSO rBso       = new Release_BSO(Ado);
                dynamic     wipForLive = rBso.GetWipForLive(dtoRelease.RlsCode, SamAccountName);
                if (wipForLive == null)
                {
                    wipForLive = rBso.GetPendingLiveForLive(dtoRelease.RlsCode, SamAccountName);
                }
                if (wipForLive != null)
                {
                    //if a workflow exists for wipForLive, then we must update the flags on that workflow as well
                    var wfForLive = adoWorkflowRequest.Read(Ado, wipForLive.RlsCode, true);
                    if (wfForLive != null)
                    {
                        if (wfForLive.Count > 0)
                        {
                            adoWorkflowRequest.Update(Ado, new WorkflowRequest_DTO_Update()
                            {
                                RlsCode             = wipForLive.RlsCode,
                                WrqArchiveFlag      = dtoWrq.WrqArchiveFlag,
                                WrqCurrentFlag      = true,
                                WrqExperimentalFlag = dtoWrq.WrqExperimentalFlag,
                                WrqReservationFlag  = dtoWrq.WrqReservationFlag
                            }, SamAccountName);
                        }
                    }

                    dtoWip = Release_ADO.GetReleaseDTO(adoRelease.Read(wipForLive.RlsCode, SamAccountName));
                    dtoWip.RlsReservationFlag  = dtoRelease.RlsReservationFlag;
                    dtoWip.RlsArchiveFlag      = dtoRelease.RlsArchiveFlag;
                    dtoWip.RlsExperimentalFlag = dtoRelease.RlsExperimentalFlag;

                    if (adoRelease.Update(dtoWip, SamAccountName) == 0)
                    {
                        Log.Instance.Debug("Failed to update associated WIP " + dtoWip.MtrCode + " " + dtoWip.RlsVersion + '.' + dtoWip.RlsRevision);
                    }

                    //if this wip has a workflow request, then the workflow request details must also be updated

                    List <WorkflowRequest_DTO> wfList = adoWrq.Read(Ado, dtoWip.RlsCode, true);
                    if (wfList.Count > 0)
                    {
                        foreach (var wf in wfList)
                        {
                            wf.WrqReservationFlag  = dtoWrq.WrqReservationFlag;
                            wf.WrqArchiveFlag      = dtoWrq.WrqArchiveFlag;
                            wf.WrqExperimentalFlag = dtoWrq.WrqExperimentalFlag;
                            adoWrq.Update(Ado, new WorkflowRequest_DTO_Update()
                            {
                                RlsCode             = wf.RlsCode,
                                WrqCurrentFlag      = dtoWrq.WrqCurrentFlag,
                                WrqArchiveFlag      = dtoWrq.WrqArchiveFlag,
                                WrqExperimentalFlag = dtoWrq.WrqExperimentalFlag,
                                WrqReservationFlag  = dtoWrq.WrqReservationFlag
                            }, SamAccountName);
                        }
                    }
                }

                break;

            case Constants.C_WORKFLOW_REQUEST_DELETE:
                //We can't soft delete the release just yet. We need it to be live until the Request is updated.

                break;

            case Constants.C_WORKFLOW_REQUEST_ROLLBACK:

                //Delete the future release if it exists and set the current to_date to null
                //Otherwise delete the current release and make the previous release current by setting its to_date to null



                if (adoRelease.IsLiveNext(dtoRelease.RlsCode))    //this is a future release so get the previous release to roll back to (even if that previous is now historical)
                {
                    Compare_ADO cAdo          = new Compare_ADO(Ado);
                    Release_DTO dtoNowRelease = Release_ADO.GetReleaseDTO(adoRelease.Read(cAdo.ReadPreviousRelease(DTO.RlsCode), SamAccountName));


                    dtoNowRelease.RlsLiveDatetimeTo = default(DateTime);
                    int rows = adoRelease.Update(dtoNowRelease, SamAccountName);
                    if (rows == 0)
                    {
                        Log.Instance.Debug("Can't update the Release, RlsCode:" + dtoNowRelease.RlsCode);
                        response.error = Label.Get("error.update");
                        return(response);
                    }

                    //As things stand, dtoRelease is the requested Release (which is a Live Next). This will be deleted in the Delete section below
                }
                else
                {
                    //This isn't a future release - it had better be a Live Now (with a previous)
                    if (!adoRelease.IsLiveNow(dtoRelease.RlsCode))
                    {
                        //If the request is neither a Live Now release then there's a problem
                        Log.Instance.Debug("Can't delete the Release, RlsCode:" + dtoRelease.RlsCode + ". Release is not current live");
                        response.error = Label.Get("error.delete");
                        return(response);
                    }

                    //Find the release that we're trying to rollback to
                    Release_DTO dtoPrevious = Release_ADO.GetReleaseDTO(adoRelease.ReadLivePrevious(dtoRelease.RlsCode));
                    if (dtoPrevious.RlsCode == 0)
                    {
                        //Previous release not found
                        //You can't roll back unless there's something to roll back to, so...
                        Log.Instance.Debug("Can't delete the Release, RlsCode:" + dtoRelease.RlsCode + ". Release is not current live");
                        response.error = Label.Get("error.delete");
                        return(response);
                    }


                    //We set the DatetimeTo to null in the previous release
                    dtoPrevious.RlsLiveDatetimeTo = default(DateTime);
                    int rows = adoRelease.Update(dtoPrevious, SamAccountName);
                    if (rows == 0)
                    {
                        Log.Instance.Debug("Can't update the Release, RlsCode:" + dtoPrevious.RlsCode);
                        response.error = Label.Get("error.update");
                        return(response);
                    }


                    //Do the rollback of the current release
                    dtoRelease.RlsVersion          = dtoPrevious.RlsVersion;
                    dtoRelease.RlsLiveDatetimeFrom = default(DateTime);

                    rows = adoRelease.Update(dtoRelease, SamAccountName);
                    if (rows == 0)
                    {
                        Log.Instance.Debug("Can't update the Release, RlsCode:" + dtoRelease.RlsCode);
                        response.error = Label.Get("error.update");
                        return(response);
                    }

                    adoRelease.IncrementRevision(dtoRelease.RlsCode, SamAccountName);
                }


                break;

            default:
                response.error = Label.Get("error.update");
                return(response);
            }

            int signoffID = adoSignoff.Create(Ado, DTO, SamAccountName);

            if (signoffID == 0)
            {
                //Can't create a Workflow Signoff so we can't proceed
                Log.Instance.Debug("Can't create a Workflow Signoff ");
                response.error = Label.Get("error.create");
                return(response);
            }

            //In all cases, if we have reached this stage, we must update the request to make it non-current
            WorkflowRequest_DTO_Update dtoRequest = new WorkflowRequest_DTO_Update(DTO.RlsCode);

            dtoRequest.WrqCurrentFlag = false;

            //save the request
            int updated = adoWorkflowRequest.Update(Ado, dtoRequest, SamAccountName);

            if (updated == 0)
            {
                //Can't save the Request so we can't proceed
                Log.Instance.Debug("Can't save the Workflow Signoff");
                response.error = Label.Get("error.update");
                return(response);
            }

            // We may now proceed with the soft delete
            Release_BSO_Delete bsoDelete = new Release_BSO_Delete();

            System.Navigation.Keyword_Release_ADO krbAdo = new System.Navigation.Keyword_Release_ADO();

            switch (dtoWrq.RqsCode)
            {
            case Constants.C_WORKFLOW_REQUEST_DELETE:
                //Soft delete the Release. We had to hold this over to last because the Request updates wouldn't work without a live Release
                dtoRelease.RlsCode = DTO.RlsCode;
                Request_ADO adoRequest = new Request_ADO();

                if (adoRelease.IsLiveNow(dtoRelease.RlsCode))
                {
                    Release_DTO dtoNowRelease = Release_ADO.GetReleaseDTO(adoRelease.ReadLiveNow(dtoRequest.RlsCode));

                    //Set the toDate to now, thus setting the release to historical
                    if (dtoNowRelease != null)
                    {
                        dtoNowRelease.RlsLiveDatetimeTo = DateTime.Now;
                        int updateCount = adoRelease.Update(dtoNowRelease, SamAccountName);
                        if (updateCount == 0)
                        {
                            Log.Instance.Debug("Can't update the Release, RlsCode:" + dtoNowRelease.RlsCode);
                            response.error = Label.Get("error.update");
                            return(response);
                        }
                    }

                    //Delete the search keywords for this release
                    krbAdo.Delete(Ado, DTO.RlsCode, null, true);
                }
                else if (adoRelease.IsLiveNext(dtoRelease.RlsCode) || adoRelease.IsWip(dtoRelease.RlsCode))
                {
                    //Find the previous list if it exists
                    Compare_ADO cAdo = new Compare_ADO(Ado);
                    Release_DTO dtoPreviousRelease = Release_ADO.GetReleaseDTO(adoRelease.Read(cAdo.ReadPreviousRelease(DTO.RlsCode), SamAccountName));

                    //if there is a previous live set it to historical, but not if we're deleting a WIP
                    if (dtoPreviousRelease != null && !adoRelease.IsWip(dtoRelease.RlsCode))
                    {
                        //Delete the search keywords for the previous release
                        krbAdo.Delete(Ado, dtoPreviousRelease.RlsCode, null, true);

                        dtoPreviousRelease.RlsLiveDatetimeTo = DateTime.Now;
                        int updateCount = adoRelease.Update(dtoPreviousRelease, SamAccountName);
                        if (updateCount == 0)
                        {
                            Log.Instance.Debug("Can't update the Release, RlsCode:" + dtoPreviousRelease.RlsCode);
                            response.error = Label.Get("error.update");
                            return(response);
                        }
                    }


                    //Delete the search keywords for this release
                    krbAdo.Delete(Ado, DTO.RlsCode, null, true);

                    // We may now proceed with the soft delete
                    if (bsoDelete.Delete(Ado, DTO.RlsCode, SamAccountName, true) == 0)
                    {
                        Log.Instance.Debug("Can't delete the Release, RlsCode:" + DTO.RlsCode);
                        response.error = Label.Get("error.delete");
                        return(response);
                    }
                }
                else
                {
                    //Only LiveNow, LiveNext and WIP releases can be deleted. Anything else means there's a problem.
                    Log.Instance.Debug("Can't delete the Release - invalid release status, RlsCode:" + DTO.RlsCode);
                    response.error = Label.Get("error.delete");
                    return(response);
                }

                break;

            case Constants.C_WORKFLOW_REQUEST_ROLLBACK:

                //First, if there is a WIP ahead of this live release then that WIP must be deleted
                Release_ADO releaseAdo     = new Release_ADO(Ado);
                var         releaseDTORead = new Release_DTO_Read()
                {
                    MtrCode = dtoRelease.MtrCode
                };
                var latestRelease = releaseAdo.ReadLatest(releaseDTORead);
                if (latestRelease != null)
                {
                    if (dtoRelease.RlsCode != latestRelease.RlsCode)
                    {
                        if (bsoDelete.Delete(Ado, latestRelease.RlsCode, SamAccountName, true) == 0)
                        {
                            Log.Instance.Debug("Can't delete the Release, RlsCode:" + latestRelease.RlsCode);
                            response.error = Label.Get("error.delete");
                            return(response);
                        }
                    }
                }

                // Only Live Next gets soft deleted, while Live Now is turned historical above
                if (adoRelease.IsLiveNext(dtoRelease.RlsCode))
                {
                    if (bsoDelete.Delete(Ado, DTO.RlsCode, SamAccountName, true) == 0)
                    {
                        Log.Instance.Debug("Can't delete the Release, RlsCode:" + DTO.RlsCode);
                        response.error = Label.Get("error.delete");
                        return(response);
                    }

                    //Delete the search keywords for this release
                    krbAdo.Delete(Ado, DTO.RlsCode, null, true);
                }

                // Delete the requested release (it may have been live but may also have been demoted to WIP by now)
                if (adoRelease.IsWip(dtoRelease.RlsCode))
                {
                    if (bsoDelete.Delete(Ado, dtoRelease.RlsCode, SamAccountName, true) == 0)
                    {
                        Log.Instance.Debug("Can't delete the Release, RlsCode:" + dtoRelease.RlsCode);
                        response.error = Label.Get("error.delete");
                        return(response);
                    }

                    //Delete the search keywords for this release
                    krbAdo.Delete(Ado, DTO.RlsCode, null, true);
                }
                break;
            }


            DTO.MtrCode = dtoRelease.MtrCode; // we need this to see which cache we must flush

            response.data = JSONRPC.success;
            Email_BSO_NotifyWorkflow notify = new Email_BSO_NotifyWorkflow();

            var sendMailThread = new Thread(() =>
            {
                //If an email error occurs, just ignore it and continue as before
                try
                {
                    notify.EmailSignoff(dtoWrq, DTO, dtoRelease, moderators, powerUsers);
                }
                catch { }
            });

            sendMailThread.Start();

            // Clean up caching
            MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_COMPARE_READ_ADDITION + DTO.RlsCode);
            MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_COMPARE_READ_DELETION + DTO.RlsCode);
            MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_COMPARE_READ_AMENDMENT + DTO.RlsCode);

            MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_CUBE_READ_PRE_DATASET + DTO.RlsCode);
            MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_CUBE_READ_PRE_METADATA + DTO.RlsCode);

            if (dtoWip != null)
            {
                MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_COMPARE_READ_ADDITION + dtoWip.RlsCode);
                MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_COMPARE_READ_DELETION + dtoWip.RlsCode);
                MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_COMPARE_READ_AMENDMENT + dtoWip.RlsCode);

                MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_CUBE_READ_PRE_DATASET + dtoWip.RlsCode);
                MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_CUBE_READ_PRE_METADATA + dtoWip.RlsCode);
            }

            MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_NAVIGATION_SEARCH);
            MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_NAVIGATION_READ);
            MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_CUBE_READ_COLLECTION);

            MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_CUBE_READ_DATASET + DTO.MtrCode);

            MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_CUBE_READ_DATASET + DTO.MtrCode);

            MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_CUBE_READ_METADATA + DTO.MtrCode);

            MemCacheD.CasRepositoryFlush(Resources.Constants.C_CAS_DATA_CUBE_READ_COLLECTION_PXAPI);



            return(response);
        }