public static void CopyFile( [ActivityTrigger] ApprovalStartInfo approvalStartInfo, ILogger log, ExecutionContext context) { using (var cc = new OfficeDevPnP.Core.AuthenticationManager().GetAppOnlyAuthenticatedContext(ConfigurationManager.AppSettings["siteUrl"], ConfigurationManager.AppSettings["clientId"], ConfigurationManager.AppSettings["clientSecret"])) { List docLib = cc.Web.Lists.GetByTitle("Drafts"); ListItem item = docLib.GetItemById(approvalStartInfo.itemId); Microsoft.SharePoint.Client.File file = item.File; cc.Load(file); cc.Load(item); cc.ExecuteQuery(); string dest = ConfigurationManager.AppSettings["siteUrl"] + "Published/" + file.Name; file.CopyTo(dest, true); cc.ExecuteQuery(); }; }
public static ListItemData GetListItemData( [ActivityTrigger] ApprovalStartInfo approvalStartInfo, ILogger log, ExecutionContext context) { using (var cc = new OfficeDevPnP.Core.AuthenticationManager().GetAppOnlyAuthenticatedContext(ConfigurationManager.AppSettings["siteUrl"], ConfigurationManager.AppSettings["clientId"], ConfigurationManager.AppSettings["clientSecret"])) { List docLib = cc.Web.Lists.GetByTitle("Drafts"); ListItem item = docLib.GetItemById(approvalStartInfo.itemId); cc.Load(item); cc.ExecuteQuery(); var listItemData = new ListItemData(); listItemData.DocumentOwner = ((FieldUserValue)item["DocumentOwner"]).LookupId; listItemData.StakeHolders = new List <int>(); foreach (FieldUserValue sh in (FieldUserValue[])item["StakeHolders"]) { listItemData.StakeHolders.Add(sh.LookupId); } return(listItemData); }; }
public static async Task <HttpResponseMessage> ApprovalStart( [HttpTrigger(AuthorizationLevel.Function, "OPTIONS", "POST")] HttpRequestMessage req, [OrchestrationClient] DurableOrchestrationClient starter, TraceWriter log, ExecutionContext context) { // Function input comes from the request content. if (req.Method == HttpMethod.Options) { var response = req.CreateResponse(); if (AddCORSHeaders(req, ref response, "POST,OPTIONS", log)) { response.StatusCode = HttpStatusCode.OK; } else { response.StatusCode = HttpStatusCode.InternalServerError; } return(response); } ApprovalStartInfo approvalStartInfo = await req.Content.ReadAsAsync <ApprovalStartInfo>(); string instanceId = await starter.StartNewAsync("Publish", approvalStartInfo); log.Info($"Started orchestration with ID = '{instanceId}'."); var resp = starter.CreateCheckStatusResponse(req, instanceId); if (AddCORSHeaders(req, ref resp, "POST,OPTIONS", log)) { resp.StatusCode = HttpStatusCode.OK; } else { resp.StatusCode = HttpStatusCode.InternalServerError; } return(resp); }
public static void DocownerRejected( [ActivityTrigger] ApprovalStartInfo approvalStartInfo, TraceWriter log, ExecutionContext context ) { using (var cc = new OfficeDevPnP.Core.AuthenticationManager().GetAppOnlyAuthenticatedContext(ConfigurationManager.AppSettings["siteUrl"], ConfigurationManager.AppSettings["clientId"], ConfigurationManager.AppSettings["clientSecret"])) { var emailp = new EmailProperties(); emailp.BCC = new List <string> { approvalStartInfo.startedByEmail }; emailp.To = new List <string> { approvalStartInfo.startedByEmail }; emailp.From = "*****@*****.**"; emailp.Body = "<b>rejected</b>"; emailp.Subject = "rejected"; Utility.SendEmail(cc, emailp); cc.ExecuteQuery(); }; }
public static async Task Publish( [OrchestrationTrigger] DurableOrchestrationContext context, ILogger log ) { // get the parameters passed in to the this (the publish/orchestrator function) ApprovalStartInfo approvalStartInfo = context.GetInput <ApprovalStartInfo>(); context.SetCustomStatus("Fetching list data"); // 'Call' a function to fetch the info from the sharepoint item being approvd. // this call writes an entry to the workitem queue and stops execution of the the publish/orchestrator function) // the GetListItemData function gets triggered when it sees the entry in the workItem queue ListItemData listItemData = await context.CallActivityAsync <ListItemData>("GetListItemData", approvalStartInfo); // when the GetListItemData returns a value , that value gets written into the controle queuw // that will cause this function to restart. When this function restarts, and comes to the line above, // the CallActivityAsync method will see that GetListItemData has already been called (by looking in the control queue // So it wont call the function again, it will just put the returned valuse in the listItemData variable. context.SetCustomStatus("Sceduling Docownwer Approval"); // 'Call' a function to get the document ownwers approval // this call writes an entry to the workitem queue and stops execution of the the publish/orchestrator function) // the ScheduleDocOwnerApproval function gets triggered when it sees the entry in the workItem queue // the ScheduleDocOwnerApproval function creates a task for the document owner to approve/reject. // when the document ownwer approves or rejects the task, the TaskNotifications Azure Function will send a // DocOwnerApproved or DocOwnerRejected external event to this function. await context.CallActivityAsync <string>("ScheduleDocOwnerApproval", new ScheduleDocOwnerApprovalParms() { instanceId = context.InstanceId, DocumentOwner = listItemData.DocumentOwner }); var docOwnerApproved = context.WaitForExternalEvent("DocOwnerApproved"); var docOwnerRejected = context.WaitForExternalEvent("DocOwnerRejected"); context.SetCustomStatus("Awaiting Docownwer approval"); // wait for one of those two events (no tiemout here) var winner = await Task.WhenAny(docOwnerApproved, docOwnerRejected); if (winner == docOwnerRejected) { // if the Document Owner rejected the task trigger execution of the DocownerRejected function // which just sends an email. The workflow is then done! context.SetCustomStatus("Docownwer Rejected"); await context.CallActivityAsync <string>("DocownerRejected", approvalStartInfo); } else { // stakeholder IDs is an array of the ids of the stakeholders (fron the user information list) List <int> stakeholderIDs = listItemData.StakeHolders; // create a list of tasks that need to be approved -- one per stakeholder var stakeHolderApprovalTasks = new Task[stakeholderIDs.Count]; for (int i = 0; i < stakeholderIDs.Count; i++) { //'Call' the ScheduleStakeholderApproval function to get the stakeholders approval. // The ScheduleStakeholderApproval function will create a task in the Tasks list for the stakeholder. // When the stakeholder Approves the task, the TaskNotifications Azure Function will send a // StakeHolderApproval:xx (where xx is the ID of the stakeholder) event to this function. // When the stakeholder Rejects the task, the TaskNotifications Azure Function will send a // StakeHolderRejection event to this function. await context.CallActivityAsync("ScheduleStakeholderApproval", new ScheduleStakeHolderApprovalParams() { instanceId = context.InstanceId, stakeHolderId = stakeholderIDs[i] }); string eventName = "StakeHolderApproval:" + stakeholderIDs[i]; // add the approval task to the list of stakeholder tasks that we will be waiting on/ stakeHolderApprovalTasks[i] = context.WaitForExternalEvent(eventName); } // the stakeHolderApprovalTask will be completed when ALL stakeholders approve their tasks var stakeHolderApprovalTask = Task.WhenAll(stakeHolderApprovalTasks); // the stakeHolderRejectionTask will be completed when ANY stakeholder rejects her task var stakeHolderRejectionTask = context.WaitForExternalEvent("StakeHolderRejection"); // Now we need to set up a CancellationTokenSource so that we can wait for a certain amout of ti,e using (var cts = new CancellationTokenSource()) { //for this sample we will wait for just one minute. var timeoutAt = context.CurrentUtcDateTime.AddMinutes(1); //now we can create a task that will timeout after one minute. var timeoutTask = context.CreateTimer(timeoutAt, cts.Token); // And now.... wait for EITHER the timeout, a SINGLE rejection, or ALL stakeholders to approve. var stakeHolderResults = await Task.WhenAny(stakeHolderApprovalTask, timeoutTask, stakeHolderRejectionTask); if (stakeHolderResults == stakeHolderApprovalTask) { cts.Cancel(); // cancel the timeout task log.LogCritical("received stakeholder approvals"); // copy the file await context.CallActivityAsync <ListItemData>("CopyFile", approvalStartInfo); } else if (stakeHolderResults == stakeHolderRejectionTask) { cts.Cancel(); // we should cancel the timeout task log.LogCritical("A stakeholder rejected"); // should send email that action was rejected } else { // timed out log.LogCritical(" Timed out waiting for stakeholder approvals"); // copy the file await context.CallActivityAsync <ListItemData>("CopyFile", approvalStartInfo); } } } }