public override void DeployModel(object modelHost, DefinitionBase model)
        {
            NintexO365HandlerOnProvisionedEvent result        = new NintexO365HandlerOnProvisionedEvent();
            NintexWorkflowO365DefinitionBase    workflowModel = (NintexWorkflowO365DefinitionBase)model;

            InvokeOnModelEvent(this, new ModelEventArgs
            {
                CurrentModelNode = null,
                Model            = null,
                EventType        = ModelEventType.OnProvisioning,
                Object           = null,
                ObjectType       = typeof(Object),
                ObjectDefinition = workflowModel,
                ModelHost        = modelHost
            });
            base.DeployModel(modelHost, model);
            var listModelHost = modelHost as ListModelHost;
            var baseModelHost = modelHost as CSOMModelHostBase;

            var    web             = baseModelHost.HostWeb;
            var    list            = listModelHost != null ? listModelHost.HostList : null;
            var    clientContext   = baseModelHost.HostClientContext;
            string formDigestValue = clientContext.GetFormDigestDirect().DigestValue;

            var clientCredentials = clientContext.Credentials.WithAssertAndCast <SharePointOnlineCredentials>("sharepoint online credentials", value => value.RequireNotNull());
            var spSiteUrl         = web.Url;

            // Create a new HTTP client and configure its base address.
            HttpClient        client  = new HttpClient();
            HttpClientWrapper wrapper = new HttpClientWrapper(client);

            client.Timeout     = NintexApiSettings.HttpRequestTimeout;
            client.BaseAddress = new Uri(spSiteUrl);
            // Add common request headers for the REST API to the HTTP client.
            client.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/json"));
            client.DefaultRequestHeaders.Add("Api-Key", NintexApiSettings.ApiKey);

            string spoCookie = clientCredentials.GetAuthenticationCookie(new Uri(spSiteUrl));

            spoCookie.WithAssert("spoCookie", value => value.RequireStringNotOrEmpty());
            //var authHeader = new AuthenticationHeaderValue(
            //    "cookie",
            //    String.Format("{0} {1}", spSiteUrl, spoCookie)
            //);
            var authHeader = new AuthenticationHeaderValue(
                "cookie",
                $"{spSiteUrl} {spoCookie}"
                );

            // Add the defined Authorization header to the HTTP client's
            // default request headers.
            client.DefaultRequestHeaders.Authorization = authHeader;



            var getFormUri1 = String.Format("{0}/api/v1/workflows",
                                            NintexApiSettings.WebServiceUrl.TrimEnd('/'));
            var getResult1       = wrapper.Get(getFormUri1);
            var getResult1String = getResult1.Content.ReadAsStringAsync().Result;
            var parsedData       = JObject.Parse(getResult1String);

            var workflowId = "";

            // trying to find id by name
            if (list != null)
            {
                workflowId = (from d in (parsedData["data"] as JArray)
                              where (d["workflowType"].Value <string>() == "List" &&
                                     d["name"].Value <string>() == workflowModel.Name &&
                                     d["listId"].Value <string>() == list.Id.ToString()
                                     )
                              select d["id"].Value <string>()).FirstOrDefault();
            }
            else
            {
                workflowId = (from d in (parsedData["data"] as JArray)
                              where (d["workflowType"].Value <string>() == "Site" &&
                                     d["name"].Value <string>() == workflowModel.Name)
                              select d["id"].Value <string>()).FirstOrDefault();
            }


            if (string.IsNullOrEmpty(workflowId))
            {
                var importFormUri = String.Format("{0}/api/v1/workflows/packages/?migrate=true",
                                                  NintexApiSettings.WebServiceUrl.TrimEnd('/'));

                if (list != null)
                {
                    importFormUri = String.Format("{0}/api/v1/workflows/packages/?migrate=true&listTitle={1}",
                                                  NintexApiSettings.WebServiceUrl.TrimEnd('/'),
                                                  Uri.EscapeUriString(list.Title.ToString())
                                                  );
                }
                HttpContent saveContent = new ByteArrayContent(workflowModel.WorkflowData);
                result.saveResponse = wrapper.Post(importFormUri, saveContent);

                var saveresult      = result.saveResponse.Content.ReadAsStringAsync().Result;
                var parsedSavedData = JObject.Parse(saveresult);
                workflowId = parsedSavedData["id"].Value <string>();
            }
            else
            {
                var importFormUri = String.Format("{0}/api/v1/workflows/packages/{1}/?migrate=true",
                                                  NintexApiSettings.WebServiceUrl.TrimEnd('/'),
                                                  Uri.EscapeUriString(workflowId));
                if (list != null)
                {
                    importFormUri = String.Format("{0}/api/v1/workflows/packages/{1}/?migrate=true&listTitle={2}",
                                                  NintexApiSettings.WebServiceUrl.TrimEnd('/'),
                                                  Uri.EscapeUriString(workflowId),
                                                  Uri.EscapeUriString(list.Title.ToString())
                                                  );
                }
                HttpContent saveContent = new ByteArrayContent(workflowModel.WorkflowData);
                result.saveResponse = wrapper.Put(importFormUri, saveContent);
            }


            if (workflowModel.AssignedUseForProduction.HasValue)
            {
                var publishFormUri = String.Format("{0}/api/v1/workflows/{1}/assigneduse",
                                                   NintexApiSettings.WebServiceUrl.TrimEnd('/'),
                                                   Uri.EscapeUriString(workflowId));
                var content = "";
                var asssignedUseStringValue = workflowModel.AssignedUseForProduction.Value ? "production" : "development";
                content = string.Format(@"{{""value"":""{0}""}}", asssignedUseStringValue);
                // interesting, this can return 405 and in details ()puiblishResponse.Content.ReadAsStringAsync()
                // in my case i had  a message saying "your license does not allow this" or something like this
                result.assignedUseForProductionValue = wrapper.Put(publishFormUri,
                                                                   new StringContent(content, null, "application/json"), "Assigned Use",
                                                                   (obj, args) => {
                    if (NintexApiSettings.ShouldApplySmartRetry(args))
                    {
                        Thread.Sleep(NintexApiSettings.SemiSuccessCheckTimeoutMs);
                        getFormUri1 = String.Format("{0}/api/v1/workflows",
                                                    NintexApiSettings.WebServiceUrl.TrimEnd('/'));
                        getResult1       = wrapper.Get(getFormUri1);
                        getResult1String = getResult1.Content.ReadAsStringAsync().Result;
                        parsedData       = JObject.Parse(getResult1String);

                        var assignedUseResult = (from d in (parsedData["data"] as JArray)
                                                 where (d["id"].Value <string>() == workflowId)
                                                 select d["assignedUse"].Value <string>()).FirstOrDefault();
                        if (asssignedUseStringValue.ToLower() == (assignedUseResult ?? "").ToLower())
                        {
                            args.Message.StatusCode = (HttpStatusCode)299;
                            args.StopProcessing     = true;
                        }
                        NintexApiSettings.SmartRetryCheckResult(args);
                    }
                });
            }
            if (workflowModel.Publish)
            {
                var publishFormUri = String.Format("{0}/api/v1/workflows/{1}/published",
                                                   NintexApiSettings.WebServiceUrl.TrimEnd('/'),
                                                   Uri.EscapeUriString(workflowId));
                var content = "";
                result.puiblishResponse = wrapper.Post(publishFormUri, new StringContent(content),
                                                       "Publish",
                                                       (obj, args) => {
                    if (NintexApiSettings.ShouldApplySmartRetry(args))
                    {
                        Thread.Sleep(NintexApiSettings.SemiSuccessCheckTimeoutMs);
                        getFormUri1 = String.Format("{0}/api/v1/workflows",
                                                    NintexApiSettings.WebServiceUrl.TrimEnd('/'));
                        getResult1       = wrapper.Get(getFormUri1);
                        getResult1String = getResult1.Content.ReadAsStringAsync().Result;
                        parsedData       = JObject.Parse(getResult1String);

                        var published = (from d in (parsedData["data"] as JArray)
                                         where (d["id"].Value <string>() == workflowId)
                                         select d["isPublished"].Value <bool>()).FirstOrDefault();
                        if (published)
                        {
                            args.Message.StatusCode = (HttpStatusCode)299;
                            args.StopProcessing     = true;
                        }
                        NintexApiSettings.SmartRetryCheckResult(args);
                    }
                });
            }

            InvokeOnModelEvent(this, new ModelEventArgs
            {
                CurrentModelNode = null,
                Model            = null,
                EventType        = ModelEventType.OnProvisioned,
                Object           = result,
                ObjectType       = typeof(NintexO365HandlerOnProvisionedEvent),
                ObjectDefinition = workflowModel,
                ModelHost        = modelHost
            });
        }
        public override void DeployModel(object modelHost, DefinitionBase model)
        {
            NintexO365HandlerOnProvisionedEvent result = new NintexO365HandlerOnProvisionedEvent();
            // we need to have list id and the sharepoint authentication cookie
            NintexFormO365Definition formModel = (NintexFormO365Definition)model;

            InvokeOnModelEvent(this, new ModelEventArgs
            {
                CurrentModelNode = null,
                Model            = null,
                EventType        = ModelEventType.OnProvisioning,
                Object           = null,
                ObjectType       = typeof(Object),
                ObjectDefinition = formModel,
                ModelHost        = modelHost
            });
            base.DeployModel(modelHost, model);
            var    listModelHost   = modelHost.WithAssertAndCast <ListModelHost>("modelHost", value => value.RequireNotNull());
            var    web             = listModelHost.HostWeb;
            var    list            = listModelHost.HostList;
            var    clientContext   = listModelHost.HostClientContext;
            string formDigestValue = clientContext.GetFormDigestDirect().DigestValue;

            var clientCredentials = clientContext.Credentials.WithAssertAndCast <SharePointOnlineCredentials>("sharepoint online credentials", value => value.RequireNotNull());
            var spSiteUrl         = web.Url;

            /// find the content type id or get the default one if not specified
            var listContentTypes = list.ContentTypes;

            clientContext.Load(listContentTypes);
            clientContext.ExecuteQueryWithTrace();
            var listContentTypesArray = listContentTypes.ToArray();
            var listContentType       = listContentTypesArray[0];

            if (!string.IsNullOrEmpty(formModel.ListContentTypeNameOrId))
            {
                foreach (var x in listContentTypesArray)
                {
                    if (
                        (x.Name == formModel.ListContentTypeNameOrId)
                        ||
                        (x.Id.StringValue.StartsWith(formModel.ListContentTypeNameOrId))
                        )
                    {
                        listContentType = x;
                    }
                }
            }

            // Create a new HTTP client and configure its base address.
            HttpClient        client  = new HttpClient();
            HttpClientWrapper wrapper = new HttpClientWrapper(client);

            client.Timeout     = NintexApiSettings.HttpRequestTimeout;
            client.BaseAddress = new Uri(spSiteUrl);
            // Add common request headers for the REST API to the HTTP client.
            client.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/json"));
            client.DefaultRequestHeaders.Add("Api-Key", NintexApiSettings.ApiKey);

            string spoCookie = clientCredentials.GetAuthenticationCookie(new Uri(spSiteUrl));

            spoCookie.WithAssert("spoCookie", value => value.RequireStringNotOrEmpty());
            //var authHeader = new AuthenticationHeaderValue(
            //    "cookie",
            //    String.Format("{0} {1}", spSiteUrl, spoCookie)
            //);
            var authHeader = new AuthenticationHeaderValue(
                "cookie",
                $"{spSiteUrl} {spoCookie}"
                );

            // Add the defined Authorization header to the HTTP client's
            // default request headers.
            client.DefaultRequestHeaders.Authorization = authHeader;

            var importFormUri = String.Format("{0}/api/v1/forms/{1}",
                                              NintexApiSettings.WebServiceUrl.TrimEnd('/'),
                                              Uri.EscapeUriString(list.Id.ToString()));

            if (!string.IsNullOrEmpty(formModel.ListContentTypeNameOrId))
            {
                importFormUri = String.Format("{0}/api/v1/forms/{1},{2}",
                                              NintexApiSettings.WebServiceUrl.TrimEnd('/'),
                                              Uri.EscapeUriString(list.Id.ToString()),
                                              listContentType.StringId);
            }

            HttpContent saveContent = new ByteArrayContent(formModel.FormData);

            result.saveResponse = wrapper.Put(importFormUri, saveContent);

            if (formModel.Publish || formModel.AssignedUseForProduction.HasValue)
            {
                //var publishFormUri = String.Format("{0}/api/v1/forms/{1}/publish",
                //    NintexFormApiKeys.WebServiceUrl.TrimEnd('/'),
                //    Uri.EscapeUriString(list.Id.ToString()));
                var publishFormUri = String.Format("{0}/api/v1/forms/{1},{2}/publish",
                                                   NintexApiSettings.WebServiceUrl.TrimEnd('/'),
                                                   Uri.EscapeUriString(list.Id.ToString()),
                                                   listContentType.StringId);
                var content = "";
                //if (!string.IsNullOrEmpty(formModel.ListContentTypeNameOrId))
                //{
                //    content = string.Format(@"{{""contentTypeId"":""{0}"",""listId"":""{1}""}}",

                //        listContentType.StringId,
                //        list.Id.ToString("B").ToUpper());
                //}
                result.puiblishResponse = wrapper.Post(publishFormUri, new StringContent(content));
            }
            if (formModel.AssignedUseForProduction.HasValue)
            {
                var publishFormUri = String.Format("{0}/api/v1/forms/{1},{2}/assigneduse",
                                                   NintexApiSettings.WebServiceUrl.TrimEnd('/'),
                                                   Uri.EscapeUriString(list.Id.ToString()),
                                                   listContentType.Id.ToString());
                var content = "";
                content = string.Format(@"{{""value"":""{0}""}}",
                                        formModel.AssignedUseForProduction.Value ? "production" : "development");
                // interesting, this can return 405 and in details ()puiblishResponse.Content.ReadAsStringAsync()
                // in my case i had  a message saying "your license does not allow this" or something like this
                result.assignedUseForProductionValue = wrapper.Put(publishFormUri,
                                                                   new StringContent(content, null, "application/json"));
            }



            InvokeOnModelEvent(this, new ModelEventArgs
            {
                CurrentModelNode = null,
                Model            = null,
                EventType        = ModelEventType.OnProvisioned,
                Object           = result,
                ObjectType       = typeof(NintexO365HandlerOnProvisionedEvent),
                ObjectDefinition = formModel,
                ModelHost        = modelHost
            });
        }