public async Task DeleteAttachment(AttachmentInfo attachment) { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "DELETEATTACHMENT", attachment.AttachmentName); var externalId = GetAttachmentExternalId(attachment.AttachmentGUID); await DeleteAsset(externalId); } catch (HttpException ex) { if (ex.GetHttpCode() == 404) { // May not be there yet, 404 is OK return; } throw; } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "DELETEATTACHMENT", ex, 0, attachment.AttachmentName); throw; } }
public async Task SyncRelationships() { try { SyncLog.Log($"Synchronizing relationships"); SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "SYNCRELATIONSHIPS"); var kontentSnippet = await GetSnippet(RELATED_PAGES_GUID); if (kontentSnippet != null) { await PatchRelationshipsSnippet(kontentSnippet); } else { await CreateRelationshipsSnippet(); } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "SYNCRELATIONSHIPS", ex); throw; } }
private async Task PatchRelationshipsSnippet(SnippetData kontentSnippet) { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "PATCHRELATIONSHIPSSNIPPET"); var externalId = GetSnippetExternalId(RELATED_PAGES_GUID); var endpoint = $"/snippets/external-id/{HttpUtility.UrlEncode(externalId)}"; var removeAllExisting = kontentSnippet.Elements.Select(element => new { op = "remove", path = $"/elements/id:{element.Id}" }); var addAllCurrent = GetRelationshipElements().Select(element => new { op = "addInto", path = "/elements", value = element }); var payload = removeAllExisting.AsEnumerable <object>().Concat(addAllCurrent).ToList(); if (payload.Count > 0) { await ExecuteWithoutResponse(endpoint, PATCH, payload); } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "PATCHRELATIONSHIPSSNIPPET", ex); throw; } }
public async Task DeletePages(CancellationToken?cancellation, ICollection <TreeNode> nodes, string info) { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "DELETEPAGES", info); var index = 0; foreach (var node in nodes) { if (cancellation?.IsCancellationRequested == true) { return; } index++; SyncLog.Log($"Deleting page {node.NodeAliasPath} ({index}/{nodes.Count})"); await DeletePage(node); } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "DELETEPAGES", ex); throw; } }
public async Task DeleteContentType(DataClassInfo contentType) { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "DELETECONTENTTYPE", contentType.ClassDisplayName); var externalId = GetPageTypeExternalId(contentType.ClassGUID); var endpoint = $"/types/external-id/{HttpUtility.UrlEncode(externalId)}"; await ExecuteWithoutResponse(endpoint, HttpMethod.Delete); } catch (HttpException ex) { if (ex.GetHttpCode() == 404) { // May not be there yet, 404 is OK return; } throw; } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "DELETECONTENTTYPE", ex); throw; } }
public async Task DeleteMediaFiles(CancellationToken?cancellation, ICollection <MediaFileInfo> mediaFiles, string info) { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "DELETEMEDIAFILES", info); var index = 0; foreach (var mediaFile in mediaFiles) { if (cancellation?.IsCancellationRequested == true) { return; } index++; SyncLog.Log($"Deleting media file {mediaFile.FileName} ({index}/{mediaFiles.Count})"); await DeleteMediaFile(mediaFile); } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "DELETEMEDIAFILES", ex); throw; } }
public async Task CreateContentType(DataClassInfo contentType) { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "CREATECONTENTTYPE", contentType.ClassDisplayName); var endpoint = $"/types"; var payload = new { name = contentType.ClassDisplayName.LimitedTo(ELEMENT_MAXLENGTH), code_name = contentType.ClassName.LimitedTo(ELEMENT_MAXLENGTH), external_id = GetPageTypeExternalId(contentType.ClassGUID), content_groups = GetContentTypeGroups(contentType), elements = GetContentTypeElements(contentType), }; await ExecuteWithoutResponse(endpoint, HttpMethod.Post, payload); } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "CREATECONTENTTYPE", ex); throw; } }
public async Task DeleteAllAssets(CancellationToken?cancellation) { try { SyncLog.Log("Deleting all assets"); SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "DELETEALLASSETS"); var assetIds = await GetAllAssetIds(); var index = 0; foreach (var assetId in assetIds) { if (cancellation?.IsCancellationRequested == true) { return; } await DeleteAsset(assetId); index++; if (index % 10 == 0) { SyncLog.Log($"Deleted assets ({index}/{assetIds.Count})"); } } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "DELETEALLASSETS", ex); throw; } }
public async Task UpsertAllMediaFiles(MediaLibraryInfo mediaLibrary) { try { SyncLog.Log($"Synchronizing files for media library {mediaLibrary.LibraryDisplayName}"); SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "UPSERTMEDIAFILES", mediaLibrary.LibraryDisplayName); var mediaFiles = MediaFileInfoProvider.GetMediaFiles() .WhereEquals("FileLibraryID", mediaLibrary.LibraryID) .BinaryData(false); var index = 0; foreach (var mediaFile in mediaFiles) { index++; SyncLog.Log($"Media file {mediaFile.FilePath} ({index}/{mediaFiles.Count})"); await SyncMediaFile(mediaFile); } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "UPSERTMEDIAFILES", ex); throw; } }
public async Task DeleteAllContentTypes(CancellationToken?cancellation) { try { SyncLog.Log("Deleting content types"); SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "DELETEALLCONTENTTYPES"); var contentTypeIds = await GetAllContentTypeIds(); foreach (var contentTypeId in contentTypeIds) { if (cancellation?.IsCancellationRequested == true) { return; } await DeleteContentType(contentTypeId); } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "DELETEALLCONTENTTYPES", ex); throw; } }
private async Task DeleteCategoriesTaxonomy() { try { SyncLog.Log("Deleting categories"); SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "DELETECATEGORIESTAXONOMY"); var externalId = GetTaxonomyExternalId(CATEGORIES_GUID); var endpoint = $"/taxonomies/external-id/{HttpUtility.UrlEncode(externalId)}"; await ExecuteWithoutResponse(endpoint, HttpMethod.Delete); } catch (HttpException ex) { if (ex.GetHttpCode() == 404) { // May not be there yet, 404 is OK return; } throw; } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "DELETECATEGORIESTAXONOMY", ex); throw; } }
private async Task CreateCategoriesTaxonomy() { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "CREATECATEGORIESTAXONOMY"); var categories = CategoryInfoProvider.GetCategories() .OnSite(Settings.Sitename, true) .WhereNull("CategoryUserID") // Global first .OrderBy("CategorySiteID", "CategoryOrder") .TypedResult; var externalId = GetTaxonomyExternalId(CATEGORIES_GUID); var endpoint = $"/taxonomies"; var payload = new { name = "Categories", codename = CATEGORIES.ToLower(), external_id = externalId, terms = GetCategoryTerms(categories), }; await ExecuteWithoutResponse(endpoint, HttpMethod.Post, payload); } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "CREATECATEGORIESTAXONOMY", ex); throw; } }
public async Task DeleteAllTaxonomies(CancellationToken?cancellation) { try { SyncLog.Log("Deleting all taxonomies"); SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "DELETEALLTAXONOMIES"); var taxonomyIds = await GetAllTaxonomyIds(); foreach (var taxonomyId in taxonomyIds) { if (cancellation?.IsCancellationRequested == true) { return; } await DeleteTaxonomy(taxonomyId); } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "DELETEALLTAXONOMIES", ex); throw; } }
public async Task UnpublishPage(TreeNode node) { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "UNPUBLISHPAGE", $"{node.NodeAliasPath} - {node.DocumentCulture} ({node.NodeGUID})"); if (node == null) { throw new ArgumentNullException(nameof(node)); } await CancelScheduling(node); await UnpublishVariant(node); } catch (HttpException ex) { switch (ex.GetHttpCode()) { case 404: case 400: // May not be there yet, 404 and 400 is OK break; default: throw; } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "UNPUBLISHPAGE", ex, 0, $"{node.NodeAliasPath} - {node.DocumentCulture} ({node.NodeGUID})"); throw; } }
public async Task DeleteAllItems(CancellationToken?cancellation, Guid?contentTypeId = null) { try { SyncLog.Log("Deleting all content items"); SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "DELETEALLITEMS"); var itemIds = await GetAllItemIds(contentTypeId); var index = 0; foreach (var itemId in itemIds) { if (cancellation?.IsCancellationRequested == true) { return; } await DeleteItem(itemId); index++; if (index % 10 == 0) { SyncLog.Log($"Deleted content items ({index}/{itemIds.Count})"); } } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "DELETEALLITEMS", ex); throw; } }
public async Task SyncPage(TreeNode node) { if (node == null) { throw new ArgumentNullException(nameof(node)); } if (!CanBePublished(node)) { // Not published pages should be deleted in KC, but we never delete their attachments, attachments always reflect state in the CMS_Attachment table await DeletePage(node); return; } try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "SYNCPAGE", $"{node.NodeAliasPath} ({node.DocumentCulture}) {node.NodeGUID}"); await UpsertItem(node); await CancelScheduling(node); await CreateNewVersion(node); await UpsertVariant(node); await PublishVariant(node, node.DocumentPublishFrom); } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "SYNCPAGE", ex, 0, $"{node.NodeAliasPath} - {node.DocumentCulture} ({node.NodeGUID})"); throw; } }
private async Task CreateLanguage(CultureInfo culture) { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "CREATELANGUAGE", $"{culture.CultureName} ({culture.CultureCode})"); var externalId = GetLanguageExternalId(culture.CultureGUID); var endpoint = $"/languages"; var payload = new { name = culture.CultureName.LimitedTo(CULTURE_MAXLENGTH), codename = culture.CultureCode.LimitedTo(CULTURE_MAXLENGTH), external_id = externalId, is_active = true, // Default language is always empty, and no fallback is used as a result // If Kontent supported language without fallback, this needs to be updated // fallback_language = new { id = Guid.Empty } }; await ExecuteWithoutResponse(endpoint, HttpMethod.Post, payload); } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "CREATELANGUAGE", ex); throw; } }
private async Task PatchDefaultLanguage() { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "PATCHDEFAULTLANGUAGE"); var endpoint = $"/languages/{Guid.Empty}"; var payload = new object[] { new { op = "replace", property_name = "name", value = "Default (do not use)", }, new { op = "replace", property_name = "codename", value = "default_do_not_use", }, }; await ExecuteWithoutResponse(endpoint, PATCH, payload); } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "PATCHDEFAULTLANGUAGE", ex); throw; } }
public async Task DeleteAttachments(CancellationToken?cancellation, ICollection <AttachmentInfo> attachments, string info) { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "DELETEATTACHMENTS", info); var index = 0; foreach (var attachment in attachments) { if (cancellation?.IsCancellationRequested == true) { return; } index++; SyncLog.Log($"Deleting attachment {attachment.AttachmentName} ({index}/{attachments.Count})"); await DeleteAttachment(attachment); } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "DELETEATTACHMENTS", ex); throw; } }
public async Task PatchContentType(ContentTypeData kontentContentType, DataClassInfo contentType) { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "PATCHCONTENTTYPE", contentType.ClassDisplayName); var externalId = GetPageTypeExternalId(contentType.ClassGUID); var endpoint = $"/types/external-id/{HttpUtility.UrlEncode(externalId)}"; var removeAllExistingElements = kontentContentType.Elements.Select(element => new { op = "remove", path = $"/elements/id:{element.Id}" }); var removeAllExistingGroups = kontentContentType.ContentGroups.Select(group => new { op = "remove", path = $"/content_groups/id:{group.Id}" }); var addAllCurrentElements = GetContentTypeElements(contentType).Select(element => new { op = "addInto", path = "/elements", value = element }); var addAllCurrentGroups = GetContentTypeGroups(contentType).Select(group => new { op = "addInto", path = "/content_groups", value = group }); var payload = removeAllExistingElements .AsEnumerable <object>() .Concat(removeAllExistingGroups) .Concat(addAllCurrentGroups) .Concat(addAllCurrentElements) .ToList(); if (payload.Count > 0) { await ExecuteWithoutResponse(endpoint, PATCH, payload); } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "PATCHCONTENTTYPE", ex); throw; } }
private async Task <string> ReplaceMediaLink(Match match) { var start = Convert.ToString(match.Groups["start"]); var url = HttpUtility.HtmlDecode(Convert.ToString(match.Groups["url"])); var query = HttpUtility.HtmlDecode(Convert.ToString(match.Groups["query"])); var end = Convert.ToString(match.Groups["end"]); try { // We need to set current site before every call to GetMediaData to avoid null reference SiteContext.CurrentSiteName = _settings.Sitename; var data = CMSDialogHelper.GetMediaData(url, _settings.Sitename); if (data != null) { switch (data.SourceType) { case MediaSourceEnum.Attachment: case MediaSourceEnum.DocumentAttachments: { var assetUrl = await _assetSync.GetAssetUrl("attachment", data.AttachmentGuid); var newQuery = TranslateMediaQuery(query); return($"{start}{HttpUtility.HtmlEncode(assetUrl)}{HttpUtility.HtmlEncode(newQuery)}{end}"); } case MediaSourceEnum.MediaLibraries: { var assetUrl = await _assetSync.GetAssetUrl("media", data.MediaFileGuid); var newQuery = TranslateMediaQuery(query); return($"{start}{HttpUtility.HtmlEncode(assetUrl)}{HttpUtility.HtmlEncode(newQuery)}{end}"); } } } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "TRANSLATEURL", ex, 0, $"Failed to replace media URL '{url + query}', keeping the original URL."); } // Keep as it is if translation is not successful, only resolve to absolute URL if needed if (url.StartsWith("~")) { return($"{start}{HttpUtility.HtmlEncode(_settings.WebRoot)}{HttpUtility.HtmlEncode(url.Substring(1))}{HttpUtility.HtmlEncode(query)}{end}"); } return(match.ToString()); }
public async Task DeleteMediaFile(MediaFileInfo mediaFile) { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "DELETEMEDIAFILE", mediaFile.FileName); var externalId = GetMediaFileExternalId(mediaFile.FileGUID); await DeleteAsset(externalId); } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "DELETEMEDIAFILE", ex, 0, mediaFile.FileName); throw; } }
public async Task SyncAllAttachments(CancellationToken?cancellation, TreeNode node) { try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "SYNCALLATTACHMENTS", node.NodeAliasPath); var attachments = AttachmentInfoProvider.GetAttachments(node.DocumentID, false); await SyncAttachments(cancellation, attachments); } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "SYNCALLATTACHMENTS", ex); throw; } }
public async Task SyncAttachment(AttachmentInfo attachment) { if (attachment == null) { throw new ArgumentNullException(nameof(attachment)); } // Do not synchronize variants if (attachment.IsVariant()) { return; } try { var fullFileName = attachment.AttachmentName; SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "SYNCATTACHMENT", fullFileName); var externalId = GetAttachmentExternalId(attachment.AttachmentGUID); var fileName = GetShortenedFileName(fullFileName); var title = string.IsNullOrEmpty(attachment.AttachmentTitle) ? fileName : attachment.AttachmentTitle; var existing = await GetAsset(externalId); // TODO - Consider detection by something more sophisticated than file size + name, but be careful, last modified may be off due to metadata changes if ((existing == null) || (attachment.AttachmentSize != existing.Size) || (fileName != existing.FileName)) { // Upload new var data = AttachmentBinaryHelper.GetAttachmentBinary((DocumentAttachment)attachment); var fileReference = await UploadBinaryFile(data, attachment.AttachmentMimeType, fileName); await UpsertAsset(externalId, title, attachment.AttachmentDescription, fileReference.Id); } else { // Update metadata of existing await UpsertAsset(externalId, title, attachment.AttachmentDescription, existing.FileReference.Id); } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "SYNCATTACHMENT", ex); throw; } }
public async Task SyncCategories() { try { SyncLog.Log("Synchronizing categories"); SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "SYNCCATEGORIES"); // TODO - consider patch await DeleteCategoriesTaxonomy(); await CreateCategoriesTaxonomy(); } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "SYNCCATEGORIES", ex); throw; } }
public async Task SyncAllPages(CancellationToken?cancellation, DataClassInfo contentType = null, string path = null) { if (contentType == null) { throw new ArgumentNullException(nameof(contentType)); } try { SyncLog.Log($"Synchronizing pages for content type {contentType.ClassDisplayName}"); SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "SYNCALLPAGES", contentType.ClassDisplayName); var documents = GetSourceDocuments(contentType.ClassName) .OnSite(Settings.Sitename) .AllCultures() .PublishedVersion(); var documentsOnPath = string.IsNullOrEmpty(path) ? documents : documents.Path(path, PathTypeEnum.Section); var index = 0; foreach (var node in documents) { if (cancellation?.IsCancellationRequested == true) { return; } index++; SyncLog.Log($"Synchronizing page { node.NodeAliasPath} - { node.DocumentCulture} ({ node.NodeGUID}) - {index}/{documents.Count}"); await SyncPage(node); } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "SYNCALLPAGES", ex); throw; } }
public async Task DeletePage(TreeNode node) { if (node == null) { throw new ArgumentNullException(nameof(node)); } try { SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "DELETEPAGE", $"{node.NodeAliasPath} - {node.DocumentCulture} ({node.NodeGUID})"); var variantDeleted = await DeleteVariant(node); } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "DELETEPAGE", ex, 0, $"{node.NodeAliasPath} - {node.DocumentCulture} ({node.NodeGUID})"); throw; } }
public async Task SyncAllAttachments(CancellationToken?cancellation) { try { SyncLog.Log("Synchronizing page attachments"); SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "SYNCALLATTACHMENTS"); var attachments = AttachmentInfoProvider.GetAttachments() .OnSite(Settings.Sitename); await SyncAttachments(cancellation, attachments); } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "SYNCALLATTACHMENTS", ex); throw; } }
public async Task SyncMediaFile(MediaFileInfo mediaFile) { if (mediaFile == null) { throw new ArgumentNullException(nameof(mediaFile)); } try { var fullFileName = mediaFile.FileName + mediaFile.FileExtension; SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "SYNCMEDIAFILE", fullFileName); var externalId = GetMediaFileExternalId(mediaFile.FileGUID); var existing = await GetAsset(externalId); var fileName = GetShortenedFileName(fullFileName); var title = string.IsNullOrEmpty(mediaFile.FileTitle) ? fileName : mediaFile.FileTitle; // TODO - Consider detection by something more sophisticated than file size + name, but be careful, last modified may be off due to metadata changes if ((existing == null) || (mediaFile.FileSize != existing.Size) || (fileName != existing.FileName)) { // Upload new var filePath = MediaFileInfoProvider.GetMediaFilePath(mediaFile.FileLibraryID, mediaFile.FilePath); var data = File.ReadAllBytes(filePath); var fileReference = await UploadBinaryFile(data, mediaFile.FileMimeType, fileName); await UpsertAsset(externalId, title, mediaFile.FileDescription, fileReference.Id); } else { // Update metadata of existing await UpsertAsset(externalId, title, mediaFile.FileDescription, existing.FileReference.Id); } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "SYNCMEDIAFILE", ex); throw; } }
public async Task SyncCultures() { try { SyncLog.Log("Synchronizing cultures"); SyncLog.LogEvent(EventType.INFORMATION, "KenticoKontentPublishing", "SYNCCULTURES"); var existingLanguages = await GetAllLanguages(); var cultures = CultureSiteInfoProvider.GetSiteCultures(Settings.Sitename).ToList(); await PatchDefaultLanguage(); // Deactivate all unknown languages to make sure they don't conflict with the active ones foreach (var language in existingLanguages) { if (language.IsActive && (language.Id != Guid.Empty) && !cultures.Exists(culture => GetLanguageExternalId(culture.CultureGUID).Equals(language.ExternalId))) { await DeactivateLanguage(language); } } // Create or update all known languages foreach (var culture in cultures) { if (existingLanguages.Exists(language => language.ExternalId?.Equals(GetLanguageExternalId(culture.CultureGUID)) == true)) { await PatchLanguage(culture); } else { await CreateLanguage(culture); } } } catch (Exception ex) { SyncLog.LogException("KenticoKontentPublishing", "SYNCCULTURES", ex); throw; } }