public static async Task <HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestMessage req, TraceWriter log) { log.Info("C# HTTP trigger function BetterCopyFunction processed a request."); string errorMsg = ""; try { dynamic data = await req.Content.ReadAsAsync <object>(); string targetUrl = data?.targetUrl; string sourceUrl = data?.sourceUrl; Uri targetSiteUri = new Uri(targetUrl); Uri sourceSiteUri = new Uri(sourceUrl); string pageLayout = data?.pageLayout; string fileName = ""; // we get this from the source item int sourceId; try { string strSourceId = data?.sourceId; sourceId = int.Parse(strSourceId); } catch (Exception) { log.Error("Setting up variables failed."); errorMsg += "Setting up variables failed."; throw; } log.Info("Got the variables! Now connecting to SharePoint..."); // Get the realm for the URL var realm = TokenHelper.GetRealmFromTargetUrl(targetSiteUri); // parse tenant admin url from the sourceUrl (there's probably a cuter way to do this but this is simple :]) string tenantAdminUrl = sourceUrl.Substring(0, sourceUrl.IndexOf(".com") + 4).TrimEnd(new[] { '/' }).Replace(".sharepoint", "-admin.sharepoint"); // parse tenant url from the admin url var tenantUrl = tenantAdminUrl.Substring(0, tenantAdminUrl.IndexOf(".com") + 4).Replace("-admin", ""); AzureEnvironment env = TokenHelper.getAzureEnvironment(tenantAdminUrl); using (var ctx_target = new OfficeDevPnP.Core.AuthenticationManager().GetAppOnlyAuthenticatedContext(targetSiteUri.ToString(), clientId, clientSecret, env)) { log.Info("Target site context built successfully!"); using (var ctx_source = new OfficeDevPnP.Core.AuthenticationManager().GetAppOnlyAuthenticatedContext(sourceSiteUri.ToString(), clientId, clientSecret, env)) { log.Info("Source site context built successfully!"); var exists = ctx_target.WebExistsFullUrl(targetUrl); string targetWebUrl = targetUrl.Replace(tenantUrl, ""); var targetWeb = ctx_target.Site.OpenWeb(targetWebUrl); ctx_target.Load(ctx_target.Site); ctx_target.Load(targetWeb); ctx_target.ExecuteQuery(); var sourceWeb = ctx_source.Site.OpenWeb(sourceUrl.Replace(tenantUrl, "")); ctx_source.Load(sourceWeb); ctx_source.ExecuteQuery(); log.Info("SharePoint connection fine! Connected to: " + targetWeb.Title); pageLayout = ctx_target.Site.Url + pageLayout.Substring(pageLayout.IndexOf("/_catalogs")); var sourceList = sourceWeb.Lists.GetByTitle("Pages"); ctx_source.Load(sourceList); ctx_source.ExecuteQuery(); var targetList = targetWeb.Lists.GetByTitle("Pages"); ctx_target.Load(targetList); ctx_target.ExecuteQuery(); log.Info("... and: " + targetList.Title + " " + targetList.ItemCount); string publishingPageContent = ""; ListItem sourceItem = null; try { sourceItem = sourceList.GetItemById(sourceId); if (sourceItem == null) { string qs = String.Format("<View><Query><Where><Eq><FieldRef Name=\"ID\"></FieldRef><Value Type=\"Number\">{0}</Value></Eq></Where></Query></View>", sourceId); CamlQuery query = new CamlQuery(); query.ViewXml = qs; var items = sourceList.GetItems(query); ctx_source.Load(items); ctx_source.ExecuteQuery(); sourceItem = items.First(); } } catch (Exception ex) { sourceItem = sourceWeb.GetListItem("/Pages/Forms/DispForm.aspx?ID=" + sourceId); errorMsg += ex.Message + " "; } finally { ctx_source.Load(sourceItem); ctx_source.Load(sourceItem.File); ctx_source.Load(sourceItem, r => r.Client_Title, r => r.Properties); ctx_source.ExecuteQueryRetry(); log.Info("Got source item! Title: " + sourceItem.Client_Title); if (sourceItem["PublishingPageContent"] != null) { publishingPageContent = sourceItem["PublishingPageContent"].ToString(); } } fileName = sourceItem.File.Name; // at this point, we've fetched all the info we needed. On to getting the target item, and then updating the fields there. ListItem targetItem = null; try { targetItem = targetList.GetItemById(sourceId); if (targetItem == null) { string qs1 = String.Format("<View><Query><Where><Eq><FieldRef Name=\"ID\"></FieldRef><Value Type=\"Number\">{0}</Value></Eq></Where></Query></View>", sourceId); CamlQuery query1 = new CamlQuery(); query1.ViewXml = qs1; var items1 = targetList.GetItems(query1); ctx_target.Load(items1); ctx_target.ExecuteQuery(); targetItem = items1.First(); } } catch (Exception ex) { log.Warning("Getting source item via conventional ways failed. Trying the unorthodox ones..."); targetItem = targetWeb.GetListItem("/Pages/Forms/DispForm.aspx?ID=" + sourceId); var items = targetList.GetItems(CamlQuery.CreateAllItemsQuery()); ctx_target.Load(items); ctx_target.ExecuteQueryRetry(); for (int i = 0; i < items.Count; i++) { if (items[i].Id == sourceId) { targetItem = items[i]; } } } finally { try { string str = "Published automatically by an Azure Function (BetterCopyFunction)."; targetItem.File.CheckIn(str, CheckinType.MajorCheckIn); targetItem.File.Publish(str); ctx_target.Load(targetItem); ctx_target.ExecuteQueryRetry(); } catch (Exception ex) { log.Info("Error: " + ex.Message); } ctx_target.Load(targetItem); ctx_target.Load(targetItem, r => r.Client_Title, r => r.Properties); ctx_target.ExecuteQueryRetry(); } log.Info("Target item title: " + targetItem.Client_Title); try { targetItem["PublishingPageLayout"] = pageLayout; targetItem["PublishingPageContent"] = publishingPageContent; targetItem.SystemUpdate(); ctx_target.ExecuteQuery(); } catch (Exception ex) { log.Warning("There was an error in saving target item values. Values were: " + pageLayout + " " + publishingPageContent); log.Warning("Error was: " + ex.Message); } finally { log.Info("Target item updated!"); } } } } catch (Exception ex) { errorMsg += ex.Message; errorMsg += "\r\n " + ex.StackTrace; throw; } return(String.IsNullOrEmpty(errorMsg) ? req.CreateResponse(HttpStatusCode.OK, "Function run was a success.") : req.CreateResponse(HttpStatusCode.InternalServerError, errorMsg)); }
public static async Task <object> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage req, TraceWriter log) { log.Info($"Webhook was triggered!"); // Grab the validationToken URL parameter string validationToken = req.GetQueryNameValuePairs() .FirstOrDefault(q => string.Compare(q.Key, "validationtoken", true) == 0) .Value; // If a validation token is present, we need to respond within 5 seconds by // returning the given validation token. This only happens when a new // web hook is being added if (validationToken != null) { log.Info($"Validation token {validationToken} received"); var response = req.CreateResponse(HttpStatusCode.OK); response.Content = new StringContent(validationToken); return(response); } log.Info($"SharePoint triggered our webhook...great :-)"); var content = await req.Content.ReadAsStringAsync(); log.Info($"Received following payload: {content}"); var notifications = JsonConvert.DeserializeObject <ResponseModel <NotificationModel> >(content).Value; log.Info($"Found {notifications.Count} notifications"); // there should always be just one so let's get the first item var notification = notifications.First(); // Get the realm for the URL var tenantAdminUrl = ConfigurationManager.AppSettings["SiteCollectionRequests_TenantAdminSite"].TrimEnd(new[] { '/' }); var tenantUrl = tenantAdminUrl.Substring(0, tenantAdminUrl.IndexOf(".com") + 4).Replace("-admin", ""); AzureEnvironment env = TokenHelper.getAzureEnvironment(tenantAdminUrl); log.Info($"Tenant url {tenantUrl} and notification from {notification.SiteUrl} "); string fullUrl = string.Format("{0}{1}", tenantUrl, notification.SiteUrl); log.Info($"{fullUrl}"); Uri targetSiteUri = new Uri(fullUrl); log.Info($"Connecting to SharePoint at {targetSiteUri.AbsoluteUri}"); var realm = TokenHelper.GetRealmFromTargetUrl(targetSiteUri); try { using (var ctx = new OfficeDevPnP.Core.AuthenticationManager().GetAppOnlyAuthenticatedContext(targetSiteUri.ToString(), clientId, clientSecret, env)) { log.Info("Connected to SharePoint!"); var ctxWeb = ctx.Site.OpenWebById(new Guid(notification.WebId)); try { ctx.ExecuteQueryRetry(); } catch (Exception ex) { log.Error("Error in ctx ExecuteQueryRetry, stage 1: " + ex.Message); throw; } Guid listId = new Guid(notification.Resource); List targetList = ctxWeb.Lists.GetById(listId); ctx.Load(targetList, List => List.ParentWebUrl); ctx.Load(targetList, List => List.Title); ctx.Load(targetList, List => List.DefaultViewUrl); ctx.Load(ctxWeb, Web => Web.Url); ctx.ExecuteQueryRetry(); log.Info($"Got list {targetList.Title} at {ctxWeb.Url} !"); // now send the query to a custom API as a POST var values = new Dictionary <string, string>(); if (notifications.Count > 0) { log.Info($"Processing notifications..."); StringContent stringcontent; HttpResponseMessage apiresponse; if (enrichViaExternalAPI) { for (int i = 0; i < notifications.Count; i++) { var n = notifications[i]; // CloudStorageAccount storageAccount = CloudStorageAccount.Parse("<YOUR STORAGE ACCOUNT>"); // // Get queue... create if does not exist. // CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient(); // CloudQueue queue = queueClient.GetQueueReference("sharepointlistwebhookeventazuread"); // queue.CreateIfNotExists(); // // add message to the queue string m = JsonConvert.SerializeObject(n); // log.Info($"Before adding a message to the queue. Message content: {message}"); // queue.AddMessage(new CloudQueueMessage(message)); // log.Info($"Message added :-)"); values.Add("message" + i, m); log.Info($"Notification {i} : {m}"); } //stringcontent = new FormUrlEncodedContent(values); apiresponse = await _client.PostAsync(_apiAddress, stringcontent); var responseString = await apiresponse.Content.ReadAsStringAsync(); log.Info($"Got response: " + responseString); } // we have the response, now we let another flow know about it - through a call to the API! var message = JsonConvert.SerializeObject(notification); string link = tenantUrl + targetList.DefaultViewUrl; var obj = new Dictionary <string, string>(); obj.Add("message", "New item on a list: " + targetList.Title); obj.Add("link", link); var serializer = new JavaScriptSerializer(); var json = serializer.Serialize(obj); stringcontent = new StringContent(json, Encoding.UTF8, "application/json"); //stringcontent = new FormUrlEncodedContent(obj); log.Info($"Now pushing this: " + stringcontent); apiresponse = await _client.PostAsync(_notificationFlowAddress, stringcontent); log.Info($"Pushed to Flow! Got this back: " + apiresponse); // if we get here we assume the request was well received return(new HttpResponseMessage(HttpStatusCode.OK)); } } } catch (Exception ex) { log.Error(ex.Message); throw; } log.Info($"Got nothing! Logging bad request."); return(new HttpResponseMessage(HttpStatusCode.BadRequest)); }