diff --git a/.gitignore b/.gitignore index ce40c45..663ef0c 100644 --- a/.gitignore +++ b/.gitignore @@ -139,4 +139,5 @@ segments_2i **/CMSModules/WebFarm/* # Files Generated by this integration -**/App_Data/Zapier/* \ No newline at end of file +**/App_Data/Zapier/* +/examples/DancingGoat/appsettings.Development.json diff --git a/Directory.Packages.props b/Directory.Packages.props index 5db38a0..0d33c80 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,10 +6,10 @@ true - - - - + + + + diff --git a/README.md b/README.md index 9544ee6..2f17d38 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,11 @@ Zapier integration enables seamless connectivity between a wide range of web app ## Library Version Matrix +This version supports content workflows added in version 28.3.0. Please ensure that your versions are up to date. | Xperience Version | Library Version | | ----------------- | --------------- | -| >= 28.1.0 | PREVIEW | +| >= 28.3.* | PREVIEW | ### Dependencies @@ -41,7 +42,7 @@ Add the package to your application using the .NET CLI dotnet add package Kentico.Xperience.Zapier ``` -## Quick Start +## Quick Start (with trigger example) 1. Register required services into DI container. @@ -62,10 +63,29 @@ dotnet add package Kentico.Xperience.Zapier app.UseAuthorization() //place under app.UseKentico() ``` -2. In the administration go to UI application 'Zapier'. -3. On the API Key menu generate new API key for your Zapier application. +2. Configure Zapier using ZapierConfiguration in appsettings.json of your application. + * Specify the domain of your application and the allowed objects that can interact with your Zapier triggers and handlers. + + ```csharp + // appsettings.json + "ZapierConfiguration": { + "WebAdminDomain": "myzapierapp.com", + "AllowedObjects": [ + "cms.user", + "CMS.EventLog", + // ... + "DancingGoat.Banner", + "DancingGoat.ConfirmationPage", + // ... + "BizForm.DancingGoatContactUs", + ] + } + ``` + +3. In the administration go to UI application 'Zapier'. +4. On the API Key menu generate new API key for your Zapier application. * Save the API key as it will appear only once. -4. Open your Zapier UI and create new Zap. +5. Open your Zapier UI and create new Zap. * As a trigger pick Xperience by Kentico application * Select Event "Catch Xperience by Kentico Webhook" * Then you have to connect an Account using URL of your website (without trailing slash) and your generated API Key from previous step @@ -74,12 +94,86 @@ dotnet add package Kentico.Xperience.Zapier * Pick object in Xperience by Kentico which you want to set for an automation process * Select type Event for your object * Test your trigger -5. Now you can create your own workflow eg. connect with Gmail, Microsoft Teams, ... +6. Now you can create your own workflow eg. connect with Gmail, Microsoft Teams, ... * You can find more information on https://zapier.com/workflows -6. After you finish your automation workflow... Publication of your Zap will create an object in your Xperience by Kentico application. +7. After you finish your automation workflow... Publication of your Zap will create an object in your Xperience by Kentico application. * You can find it in administration -> Zapier UI application -> List of Zapier triggers +## Full Instructions + +### Configure your application +Prerequisites for using this integration are a public application running on Xperience by Kentico and a Zapier account. + +In the beginning, it is necessary to **register services into the DI container** in your application and to **configure Zapier in the appropriate appsettings** file in your application. +These steps are displayed in the first two points of our Quick Start section. + * In the appsettings configuration, you need to specify the domain of your application in the correct format, e.g., 'myzapierapp.com', and list the allowed objects. + * Setting the allowed objects list in appsettings.json affects the object selection in the Zapier UI. Make sure you set up the appropriate objects for your application. + +You can view sample of such configuration [here](./docs/Configuration-example.md). + +### Zapier admin application +After configuring your application, a new application named 'Zapier' should appear in your application's administration. +This application provides a list of created Zapier triggers from the Zapier UI and a submodule for the API Key. + * On the 'List Zapier Triggers' tab, you can view the list of active zapier triggers. Items cannot be manually changed in the Admin application. Therefore, you must (and should) manage your triggers directly from the Zapier UI. + * On the 'API Key' tab, you can generate API Key for communication between your application and Zapier itself. + * **Note that there is only one API Key per application**. It is crucial to securely store it and share it only with your zapier editors. Once the API key is generated, you can only view it once. + + +### Authentication in Zapier +To connect zapier with your application, you must authenticate your app first. + * In the Zapier UI, you will be asked for the **domain of your application**. + * Also, you must provide the **API Key** for your application. + +The API Key is used consistently throughout the integration process. Only regenerate your API Key if you are aware of the potential consequences, such as invalidating existing Zapier triggers and actions connected to your application. + + +### Supported scenarios + +In the Zapier user interface, two primary features are available: triggers and actions. + * Zapier trigger is an event or an action that initiates a workflow or a sequence of actions in Zapier. + * Event in your Xperince by Kentico is the starting point of automation workflow. + * Zapier action is a task or operation that Zapier performs as part of an automated workflow, triggered by an event in one application. + * Action results in creating, updating or otherwise managing data in your Xperince by Kentico application. + +Several scenarios that this integration allows are described below. The 'Catch Xperience by Kentico Webhook' trigger allows for more complex scenarios, offering numerous possibilities due to its generic design. + +**BizForm** - triggers and actions interacting with Xperience by Kentico forms. + * Trigger Create - Listening for form submission + * 'Catch Xperience by Kentico Webhook' connected to specific form class and listening to 'Create' event. + * Action 'Insert form record' - Enables to create a form submission based on third party apps eg. Google Forms or based on another source of data. + + +**Event Log** - interaction based on event logs insertion + * Trigger Create - Listening for the creation of a record in the event log + * 'Catch Xperience by Kentico Webhook' connected to CMS.EventLog type and listening to 'Create' event. + +**Activity** + * Trigger Create - Listening for some activity + * Set up similarly to the previous examples using a trigger 'Catch Xperience by Kentico Webhook' + +**Contact** + * Trigger Create - Listening for the creation of a contact eg. to send it to CRM + * Set up similarly to the previous examples using a trigger 'Catch Xperience by Kentico Webhook' + +**Page, headless item, reusable item** +* Trigger Create - Listening for creation page or reusable item + * Set up similarly to the previous examples using a trigger 'Catch Xperience by Kentico Webhook' +* Trigger 'Move to step' - Listening for a workflow change of a specific object (custom content workflow) + * Set up similarly to the previous examples using a 'Catch Xperience by Kentico Webhook' trigger, but with a workflow step event. +* Action 'Move to step' - Pages, headless items, or reusable items can be moved to a specific step within a custom content workflow for the respective object. +* Action 'Publish' - Pages, headless items, or reusable items can be published using this action + + +### Trigger Catch Xperience by Kentico Webhook +The 'Catch Xperience by Kentico Webhook' trigger, being a complex feature, facilitates listening on multiple events such as Create, Update, and Delete (Enabled for Info objects, BizForm objects, Pages, Headless, Reusable). + +Additionally, Pages, headless items, and reusable items can also monitor the publish event. +Furthermore, if any of these types are under custom workflows, you can also listen for specific custom step events. +For instance, detecting when a Page is moved to the prepublished step in a custom content workflow step created manually. + +With this general settings it is possible to cover a large number of use cases. + ## Contributing To see the guidelines for Contributing to Kentico open source software, please see [Kentico's `CONTRIBUTING.md`](https://github.com/Kentico/.github/blob/main/CONTRIBUTING.md) for more information and follow the [Kentico's `CODE_OF_CONDUCT`](https://github.com/Kentico/.github/blob/main/CODE_OF_CONDUCT.md). diff --git a/docs/Configuration-example.md b/docs/Configuration-example.md new file mode 100644 index 0000000..de36b01 --- /dev/null +++ b/docs/Configuration-example.md @@ -0,0 +1,121 @@ +# Configuration of Zapier + +This is example of ZapierConfiguration in appsettings.json. +The appropriate name of the allowed object corresponds to the ClassName in the CMS Class table. + +```json +{ + "ZapierConfiguration": { + "WebAdminDomain": "dancinggoatzapier.com", + "AllowedObjects": [ + "cms.Role", + "cms.user", + "cms.UserRole", + "CMS.EventLog", + "cms.workflow", + "cms.workflowstep", + "cms.form", + "cms.ScheduledTask", + "cms.LicenseKey", + "cms.WebFarmServer", + "cms.WebFarmTask", + "CMS.SettingsKey", + "cms.FormRole", + "cms.settingscategory", + "CMS.ResourceString", + "CMS.ResourceTranslation", + "cms.AlternativeForm", + "cms.EmailAttachment", + "cms.email", + "cms.attachmentforemail", + "media.library", + "media.file", + "OM.Account", + "OM.AccountStatus", + "OM.Contact", + "OM.ContactStatus", + "OM.ContactRole", + "OM.AccountContact", + "OM.ContactGroup", + "OM.ContactGroupMember", + "OM.Activity", + "OM.ActivityType", + "CMS.WorkflowTransition", + "CMS.MacroRule", + "cms.workflowaction", + "CMS.AutomationHistory", + "CMS.ObjectWorkflowTrigger", + "CMS.AutomationState", + "cms.webfarmservertask", + "CMS.WebFarmServerMonitoring", + "CMS.WebFarmServerLog", + "OM.ActivityRecalculationQueue", + "CMS.ExternalLogin", + "OM.ContactChangeRecalculationQueue", + "OM.VisitorToContact", + "CMS.MacroIdentity", + "CMS.UserMacroIdentity", + "CMS.Consent", + "CMS.ConsentAgreement", + "CMS.ConsentArchive", + "Temp.PageBuilderWidgets", + "CMS.PageTemplateConfiguration", + "CMS.AutomationTemplate", + "CMS.FormFeaturedField", + "CMS.MacroRuleCategory", + "CMS.MacroRuleMacroRuleCategory", + "OM.TrackedWebsite", + "EmailLibrary.EmailConfiguration", + "EmailLibrary.EmailTemplate", + "CMS.ApplicationPermission", + "CMS.Channel", + "CMS.ContentItem", + "CMS.ContentLanguage", + "CMS.ContentTypeChannel", + "CMS.WebPageFormerUrlPath", + "CMS.WebPageItem", + "CMS.WebPageUrlPath", + "CMS.WebsiteCaptchaSettings", + "CMS.WebsiteChannel", + "EmailLibrary.EmailBounce", + "EmailLibrary.EmailChannel", + "EmailLibrary.EmailChannelSender", + "EmailLibrary.EmailLink", + "EmailLibrary.EmailMarketingRecipient", + "EmailLibrary.EmailStatistics", + "EmailLibrary.EmailStatisticsHits", + "EmailLibrary.EmailSubscriptionConfirmation", + "EmailLibrary.EmailTemplateContentType", + "EmailLibrary.RecipientListSettings", + "EmailLibrary.SendConfiguration", + "CMS.Member", + "CMS.MemberExternalLogin", + "CMS.HeadlessChannel", + "CMS.HeadlessItem", + "CMS.HeadlessToken", + "DancingGoat.ArticlePage", + "DancingGoat.ArticlesSection", + "DancingGoat.Banner", + "DancingGoat.Cafe", + "DancingGoat.Coffee", + "DancingGoat.ConfirmationPage", + "DancingGoat.Contact", + "DancingGoat.ContactsPage", + "DancingGoat.Email", + "DancingGoat.Event", + "DancingGoat.HomePage", + "DancingGoat.Image", + "DancingGoat.LandingPage", + "DancingGoat.NavigationItem", + "DancingGoat.PrivacyPage", + "DancingGoat.Reference", + "DancingGoat.SocialLink", + "BizForm.DancingGoatCoffeeSampleList", + "BizForm.DancingGoatContactUs", + "BizForm.DancingGoatSubscription", + "KenticoZapier.ZapierTrigger", + "DancingGoat.HeadlessUser" + ] + } +} +``` diff --git a/examples/DancingGoat/Properties/launchSettings.json b/examples/DancingGoat/Properties/launchSettings.json index a5a91f6..cbdc73c 100644 --- a/examples/DancingGoat/Properties/launchSettings.json +++ b/examples/DancingGoat/Properties/launchSettings.json @@ -8,7 +8,6 @@ }, "DancingGoat": { "commandName": "Project", - "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, diff --git a/examples/DancingGoat/appsettings.json b/examples/DancingGoat/appsettings.json index 83a6654..e2f11b8 100644 --- a/examples/DancingGoat/appsettings.json +++ b/examples/DancingGoat/appsettings.json @@ -16,5 +16,117 @@ "ConnectionStrings": { "CMSConnectionString": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=DancingGoatZapier;Integrated Security=True;Persist Security Info=False;Connect Timeout=60;Encrypt=False;Current Language=English;" }, - "CMSHashStringSalt": "40974ad7-76dd-4d5d-a70e-4539d5410492" + "CMSHashStringSalt": "40974ad7-76dd-4d5d-a70e-4539d5410492", + "ZapierConfiguration": { + "WebAdminDomain": "nf54t8h6-26547.euw.devtunnels.ms", + "AllowedObjects": [ + "cms.Role", + "cms.user", + "cms.UserRole", + "CMS.EventLog", + "cms.workflow", + "cms.workflowstep", + "cms.form", + "cms.ScheduledTask", + "cms.LicenseKey", + "cms.WebFarmServer", + "cms.WebFarmTask", + "CMS.SettingsKey", + "cms.FormRole", + "cms.settingscategory", + "CMS.ResourceString", + "CMS.ResourceTranslation", + "cms.AlternativeForm", + "cms.EmailAttachment", + "cms.email", + "cms.attachmentforemail", + "media.library", + "media.file", + "OM.Account", + "OM.AccountStatus", + "OM.Contact", + "OM.ContactStatus", + "OM.ContactRole", + "OM.AccountContact", + "OM.ContactGroup", + "OM.ContactGroupMember", + "OM.Activity", + "OM.ActivityType", + "CMS.WorkflowTransition", + "CMS.MacroRule", + "cms.workflowaction", + "CMS.AutomationHistory", + "CMS.ObjectWorkflowTrigger", + "CMS.AutomationState", + "cms.webfarmservertask", + "CMS.WebFarmServerMonitoring", + "CMS.WebFarmServerLog", + "OM.ActivityRecalculationQueue", + "CMS.ExternalLogin", + "OM.ContactChangeRecalculationQueue", + "OM.VisitorToContact", + "CMS.MacroIdentity", + "CMS.UserMacroIdentity", + "CMS.Consent", + "CMS.ConsentAgreement", + "CMS.ConsentArchive", + "Temp.PageBuilderWidgets", + "CMS.PageTemplateConfiguration", + "CMS.AutomationTemplate", + "CMS.FormFeaturedField", + "CMS.MacroRuleCategory", + "CMS.MacroRuleMacroRuleCategory", + "OM.TrackedWebsite", + "EmailLibrary.EmailConfiguration", + "EmailLibrary.EmailTemplate", + "CMS.ApplicationPermission", + "CMS.Channel", + "CMS.ContentItem", + "CMS.ContentLanguage", + "CMS.ContentTypeChannel", + "CMS.WebPageFormerUrlPath", + "CMS.WebPageItem", + "CMS.WebPageUrlPath", + "CMS.WebsiteCaptchaSettings", + "CMS.WebsiteChannel", + "EmailLibrary.EmailBounce", + "EmailLibrary.EmailChannel", + "EmailLibrary.EmailChannelSender", + "EmailLibrary.EmailLink", + "EmailLibrary.EmailMarketingRecipient", + "EmailLibrary.EmailStatistics", + "EmailLibrary.EmailStatisticsHits", + "EmailLibrary.EmailSubscriptionConfirmation", + "EmailLibrary.EmailTemplateContentType", + "EmailLibrary.RecipientListSettings", + "EmailLibrary.SendConfiguration", + "CMS.Member", + "CMS.MemberExternalLogin", + "CMS.HeadlessChannel", + "CMS.HeadlessItem", + "CMS.HeadlessToken", + "DancingGoat.ArticlePage", + "DancingGoat.ArticlesSection", + "DancingGoat.Banner", + "DancingGoat.Cafe", + "DancingGoat.Coffee", + "DancingGoat.ConfirmationPage", + "DancingGoat.Contact", + "DancingGoat.ContactsPage", + "DancingGoat.Email", + "DancingGoat.Event", + "DancingGoat.HomePage", + "DancingGoat.Image", + "DancingGoat.LandingPage", + "DancingGoat.NavigationItem", + "DancingGoat.PrivacyPage", + "DancingGoat.Reference", + "DancingGoat.SocialLink", + "BizForm.DancingGoatCoffeeSampleList", + "BizForm.DancingGoatContactUs", + "BizForm.DancingGoatSubscription", + "KenticoZapier.ZapierTrigger", + "DancingGoat.HeadlessUser" + ] + } } \ No newline at end of file diff --git a/examples/DancingGoat/packages.lock.json b/examples/DancingGoat/packages.lock.json index 3065a4f..807af13 100644 --- a/examples/DancingGoat/packages.lock.json +++ b/examples/DancingGoat/packages.lock.json @@ -4,52 +4,52 @@ "net8.0": { "Kentico.Xperience.Admin": { "type": "Direct", - "requested": "[28.1.0, )", - "resolved": "28.1.0", - "contentHash": "xT8nUXUPMCqCT4NycL4G7bFpJrVqL8KTLzJU33kQWkdbzVxdqq4o75f9ysjmH83W4XOj6AG1xIzmZAYVdXdWCA==", + "requested": "[28.3.2, )", + "resolved": "28.3.2", + "contentHash": "3PU1HBlsUrHZ0uD+dPo7B45p/cP+/Ax1F4/KWh237CHLf7BQkyh+7ByWcLdJUkrZq1iF0e2XvGHGliE0Ux6c2A==", "dependencies": { - "Kentico.Aira.Client": "1.0.23", - "Kentico.Xperience.WebApp": "[28.1.0]", - "Microsoft.AspNetCore.SpaServices.Extensions": "6.0.25", - "Microsoft.Extensions.FileProviders.Embedded": "6.0.25" + "Kentico.Aira.Client": "1.0.25", + "Kentico.Xperience.WebApp": "[28.3.2]", + "Microsoft.AspNetCore.SpaServices.Extensions": "6.0.27", + "Microsoft.Extensions.FileProviders.Embedded": "6.0.27" } }, "Kentico.Xperience.AzureStorage": { "type": "Direct", - "requested": "[28.1.0, )", - "resolved": "28.1.0", - "contentHash": "ixTjaZ1KFKHArOutrw4L21Xm7vYnGG26przhq1UkpzN2csXlkq0xVggAAA/2mptuvoIynFH3oypGoDoNYmkkUQ==", + "requested": "[28.3.2, )", + "resolved": "28.3.2", + "contentHash": "X4K/wDHa7m/ML+UvY3iRs0C7jPJb101bWwTTNriJoFEJkd06h7w8zZPDUXCAoDp5tOI9EwRNBBtsJ6e160XYyg==", "dependencies": { "Azure.Storage.Blobs": "12.19.1", "Azure.Storage.Queues": "12.17.1", - "Kentico.Xperience.Core": "28.1.0", + "Kentico.Xperience.Core": "28.3.2", "Newtonsoft.Json": "13.0.3" } }, "Kentico.Xperience.ImageProcessing": { "type": "Direct", - "requested": "[28.1.0, )", - "resolved": "28.1.0", - "contentHash": "RTM7mnEHEJptFxEa3KwHIMg+KAtNrJOYphfLVbOnOLZ3Ld8egrqCVJtd5uh5GLeuqoZMyUrAsnyF1cVW5keB3g==", + "requested": "[28.3.2, )", + "resolved": "28.3.2", + "contentHash": "GkBAvAjyzsqaQQyzkZocpAJEuK4UU2DlUp2Z39CSMdLdcmVyFOy7qai3Gawfg8R/9pXbGGElgucTUWLrqDHh6A==", "dependencies": { - "Kentico.Xperience.Core": "28.1.0", - "SkiaSharp": "2.88.6", - "SkiaSharp.NativeAssets.Linux.NoDependencies": "2.88.6" + "Kentico.Xperience.Core": "28.3.2", + "SkiaSharp": "2.88.7", + "SkiaSharp.NativeAssets.Linux.NoDependencies": "2.88.7" } }, "Kentico.Xperience.WebApp": { "type": "Direct", - "requested": "[28.1.0, )", - "resolved": "28.1.0", - "contentHash": "JY2Ng+q6+mTM45GV/3o0w75mDmCa8jRzdi75nYJBU0GwCnKlC1shqtaQzjIJ2dVR55wdh4bqMpX40laaFc0AKw==", + "requested": "[28.3.2, )", + "resolved": "28.3.2", + "contentHash": "l6yuLb2KqU4azWIdapktABRoARLW0ySkPMj/+Kod31X0G29NSkbB6keDw5C9F9mkUZyKPjIMPv9z+4QjVRSd0w==", "dependencies": { "CommandLineParser": "2.9.1", - "HotChocolate.AspNetCore": "13.7.0", - "HotChocolate.Data": "13.7.0", - "HtmlSanitizer": "8.0.795", - "Kentico.Xperience.Core": "[28.1.0]", - "Microsoft.Extensions.FileProviders.Embedded": "6.0.25", - "Microsoft.Extensions.Localization": "6.0.25", + "HotChocolate.AspNetCore": "13.8.1", + "HotChocolate.Data": "13.8.1", + "HtmlSanitizer": "8.0.843", + "Kentico.Xperience.Core": "[28.3.2]", + "Microsoft.Extensions.FileProviders.Embedded": "6.0.27", + "Microsoft.Extensions.Localization": "6.0.27", "System.Runtime.Caching": "8.0.0" } }, @@ -92,12 +92,12 @@ }, "Azure.Identity": { "type": "Transitive", - "resolved": "1.7.0", - "contentHash": "eHEiCO/8+MfNc9nH5dVew/+FvxdaGrkRL4OMNwIz0W79+wtJyEoeRlXJ3SrXhoy9XR58geBYKmzMR83VO7bcAw==", + "resolved": "1.10.3", + "contentHash": "l1Xm2MWOF2Mzcwuarlw8kWQXLZk3UeB55aQXVyjj23aBfDwOZ3gu5GP2kJ6KlmZeZv2TCzw7x4L3V36iNr3gww==", "dependencies": { - "Azure.Core": "1.25.0", - "Microsoft.Identity.Client": "4.39.0", - "Microsoft.Identity.Client.Extensions.Msal": "2.19.3", + "Azure.Core": "1.35.0", + "Microsoft.Identity.Client": "4.56.0", + "Microsoft.Identity.Client.Extensions.Msal": "4.56.0", "System.Memory": "4.5.4", "System.Security.Cryptography.ProtectedData": "4.7.0", "System.Text.Json": "4.7.2", @@ -134,8 +134,8 @@ }, "BananaCakePop.Middleware": { "type": "Transitive", - "resolved": "7.0.4", - "contentHash": "MjXgiZ2WTmijyojmuiDMoqa2rokg0yNROwpe6yQibFre6D3CPdmCiIt48YE9+8ZBwgss5BK49iluktHFuf0XfQ==", + "resolved": "13.0.0", + "contentHash": "6Zj/vfmnCXLjBG7WNdtOgZZ5ZDR3Sy1FQSshZUonIYs3OdzozmsFmqPXMd9XJ0QE9aAildgVGq/lDLpLrMI4Yw==", "dependencies": { "Yarp.ReverseProxy": "2.0.1" } @@ -152,245 +152,255 @@ }, "GreenDonut": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "BjZ2KbrQT36hEYW4Hj9lzA/nH514jgFD1e1zDprxBOfQMGbD2mMlGaU4sBJf4GEYdKYRUdxUHSACK7yDUDTYVA==", + "resolved": "13.8.1", + "contentHash": "KgsJ88vcX0UfSKAO7uzbEPOGu8wwJU3Vkgz7AgeTrnfdgIVjZFkesvMxDqjzY6F3fmMbJmfAOLjufYLFs1Fq1g==", "dependencies": { - "Microsoft.Extensions.ObjectPool": "8.0.0-rc.2.23480.2", - "System.Diagnostics.DiagnosticSource": "8.0.0-rc.2.23479.6", + "Microsoft.Extensions.ObjectPool": "8.0.0", + "System.Diagnostics.DiagnosticSource": "8.0.0", "System.Threading.Tasks.Extensions": "4.5.0" } }, "HotChocolate": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "x8BIqnynoXLoHT9WeXmNSbfD6G+xv6ABMj6MkrDBInHBZ7B35rajCAcGdYOGJvi3ON+zSNgRMqiSkJzQocsW6g==", + "resolved": "13.8.1", + "contentHash": "Dfue5pJ99mNWaIBYv6VupDLtZo8KhIGC9blQy76BAvkipd7m9K3xhBLNyxnUA5AmTXDrKdS+RVZ21ghG/pqeAw==", "dependencies": { - "HotChocolate.Authorization": "13.7.0", - "HotChocolate.Execution": "13.7.0", - "HotChocolate.Fetching": "13.7.0", - "HotChocolate.Types": "13.7.0", - "HotChocolate.Types.CursorPagination": "13.7.0", - "HotChocolate.Types.Mutations": "13.7.0", - "HotChocolate.Types.OffsetPagination": "13.7.0", - "HotChocolate.Validation": "13.7.0" + "HotChocolate.Authorization": "13.8.1", + "HotChocolate.Execution": "13.8.1", + "HotChocolate.Fetching": "13.8.1", + "HotChocolate.Types": "13.8.1", + "HotChocolate.Types.CursorPagination": "13.8.1", + "HotChocolate.Types.Mutations": "13.8.1", + "HotChocolate.Types.OffsetPagination": "13.8.1", + "HotChocolate.Validation": "13.8.1" } }, "HotChocolate.Abstractions": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "D7ITncily71twwVwH68vOW7epqVvduZGDcqg0J9Cuct4QxFAkxc/YcVh0c8WxM1i4O915xJuJBpEQxLr+q1AlA==", + "resolved": "13.8.1", + "contentHash": "+llX8ziARzp+aKsOaXQfZAtqE+lF8gSmTiMiRCdpf03M+IWl/uCD9965nhqkM4mauWufwBXlwA7TE4uIUu+UjQ==", "dependencies": { - "HotChocolate.Language": "13.7.0", - "System.Collections.Immutable": "8.0.0-rc.2.23479.6" + "HotChocolate.Language": "13.8.1", + "System.Collections.Immutable": "8.0.0" } }, "HotChocolate.AspNetCore": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "omEK1nxwKeTSo81rx49fhhL2Cjmp+sEOYegYACmUju4DEmLwm10sA2T8Zo3SoNt0imYTysgibEgxLwjjQ214DA==", + "resolved": "13.8.1", + "contentHash": "Pg4/+sGPCn5qNwo9z8GP/LcGHKaCRsozOwNw2XVnLRY9EDIOoN2jzblgaFuDqWkXe+rd2yAnxE7NHcdBohTEFQ==", "dependencies": { - "BananaCakePop.Middleware": "7.0.4", - "HotChocolate": "13.7.0", - "HotChocolate.Subscriptions.InMemory": "13.7.0", - "HotChocolate.Transport.Sockets": "13.7.0", - "HotChocolate.Types.Scalars.Upload": "13.7.0" + "BananaCakePop.Middleware": "13.0.0", + "HotChocolate": "13.8.1", + "HotChocolate.Subscriptions.InMemory": "13.8.1", + "HotChocolate.Transport.Sockets": "13.8.1", + "HotChocolate.Types.Scalars.Upload": "13.8.1", + "HotChocolate.Utilities.DependencyInjection": "13.8.1" } }, "HotChocolate.Authorization": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "bIvUiYKOpUOuaFtf1OyZd8MgvHEMSwHzhqZyGqURWRCHdXVch1cS73laSm2i1RB0cKJ7dMOlG6+LvvvtmF7mbw==", + "resolved": "13.8.1", + "contentHash": "y+eLkswOMnSsPaO0fmY1gfNQD6I55SzXtAXhJIqsai1NpPeG2pu5b29y5UoGXNRQgb5/243gazbQbdM5j1S6PQ==", "dependencies": { - "HotChocolate.Execution": "13.7.0" + "HotChocolate.Execution": "13.8.1" } }, "HotChocolate.Data": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "9hNGSb+aoo8YOVUQoONSr6/YNGFLt4waZnT/PisX8qtLK7GxnCVMrJO8MnueR9KACEaYSEKIE/hTgXOhe3x8MA==", + "resolved": "13.8.1", + "contentHash": "tgXDs0TuyyPUMAUbPJltjll+HDSU19lX14IVe8J9WdDHGQXTScjyn1px8tX537wYh6Fy1XfBgrCKwmTV21+IdQ==", "dependencies": { - "HotChocolate.Execution": "13.7.0", - "HotChocolate.Types.CursorPagination": "13.7.0" + "HotChocolate.Execution": "13.8.1", + "HotChocolate.Types.CursorPagination": "13.8.1" } }, "HotChocolate.Execution": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "TbIimwWmlK3CtOJi3GpRS46x9K3D0NYawEdHV287wSNDxrceoxRuZNWBGx7017ExpfcV5gcJlLdaQP5Ao/gzug==", + "resolved": "13.8.1", + "contentHash": "co/VtIsOf3wqabsQLwO6HbTPi4UfL8UnzFlRkP2K4NNsNRdDkurYDdECS89swAuvfttzNua4MFOA4PclbW6Y/Q==", "dependencies": { - "HotChocolate.Abstractions": "13.7.0", - "HotChocolate.Execution.Abstractions": "13.7.0", - "HotChocolate.Fetching": "13.7.0", - "HotChocolate.Types": "13.7.0", - "HotChocolate.Validation": "13.7.0", - "Microsoft.Extensions.DependencyInjection": "8.0.0-rc.2.23479.6", - "System.Threading.Channels": "8.0.0-rc.2.23479.6" + "HotChocolate.Abstractions": "13.8.1", + "HotChocolate.Execution.Abstractions": "13.8.1", + "HotChocolate.Fetching": "13.8.1", + "HotChocolate.Types": "13.8.1", + "HotChocolate.Utilities.DependencyInjection": "13.8.1", + "HotChocolate.Validation": "13.8.1", + "Microsoft.Extensions.DependencyInjection": "8.0.0", + "System.Threading.Channels": "8.0.0" } }, "HotChocolate.Execution.Abstractions": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "7gzjF4xqCa0BYIzJ/nDTlnhdjYOJdydhYi7X5Be4PV41iy3V3rG74Pus+LcvOEi+5INFtxAhbXkDQR7n/rQwpQ==", + "resolved": "13.8.1", + "contentHash": "sAL6A/Qa23inTgu8sWiNoaKpaJ3MosXLsiP908+XUogMOjudpWnaSWPYu5THgl1deaQ6q55gbyiFvwJx5lRR8A==", "dependencies": { - "HotChocolate.Abstractions": "13.7.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0-rc.2.23479.6" + "HotChocolate.Abstractions": "13.8.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, "HotChocolate.Fetching": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "llRUlvdHTgJnSn3c3wpWEHMXIq0SVnf3m4q9JPwqS50fIRTVr7NMTgU0mbrnVcumccNo87dBBH8bZdj92uYZRQ==", + "resolved": "13.8.1", + "contentHash": "b1o8+gKmaE7rVX+fq/vFNFj+lcY414LoadaCcriEGEsz5fwIX5+SadmUIiaSuFOhuL+T8VLngh0zJXvPBI3sSA==", "dependencies": { - "GreenDonut": "13.7.0", - "HotChocolate.Types": "13.7.0" + "GreenDonut": "13.8.1", + "HotChocolate.Types": "13.8.1" } }, "HotChocolate.Language": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "/11gk8iCVUWsLaZAM0DB5SYzn8kJKI+trnzd/XEcY2Mj1HbAw8h9QMuLLx978zVA3KGn85hFdLFvPHSgSVilxA==", + "resolved": "13.8.1", + "contentHash": "qlljQwU51ecUyYa0qdOGHnWgP481QwwZsZRGwFuH/RbUwDVQOF8Fz/9aZxFmECkpiaCBfb8fHJOlzQGE52V6JQ==", "dependencies": { - "HotChocolate.Language.SyntaxTree": "13.7.0", - "HotChocolate.Language.Utf8": "13.7.0", - "HotChocolate.Language.Visitors": "13.7.0", - "HotChocolate.Language.Web": "13.7.0" + "HotChocolate.Language.SyntaxTree": "13.8.1", + "HotChocolate.Language.Utf8": "13.8.1", + "HotChocolate.Language.Visitors": "13.8.1", + "HotChocolate.Language.Web": "13.8.1" } }, "HotChocolate.Language.SyntaxTree": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "oU1hquKD90p3NxEXgQ2kd4F92ceGVO1uFVfuQ9YV8oQ3lCa6xm8UTVSHJX0nnKAmv59deolaMdfXAV16sKMWOg==", + "resolved": "13.8.1", + "contentHash": "0RYVxhsxR1vf0ue/V8GZnN8UVxh1bI74KPe0vFLLlNXRSq55LXTuGt3gYc6+LxSCc4KaItzRl6DwdgRuDRINjw==", "dependencies": { - "Microsoft.Extensions.ObjectPool": "8.0.0-rc.2.23480.2" + "Microsoft.Extensions.ObjectPool": "8.0.0" } }, "HotChocolate.Language.Utf8": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "NVX/h8oknpCSPnncGQfWi23tASto8hlczFhZwcYQxRRTcD1FDx6pJhCuUkGqajg1bAAtiOVhYPtdF7nqbOvN7w==", + "resolved": "13.8.1", + "contentHash": "y7YY6usRd72eAHjPS/NffT9cX92FJLg1Q6litLSCdjps1PnYVYTPnkNu5Ys1ngCJjOLsB71Or5CyjO5+Q8XSxA==", "dependencies": { - "HotChocolate.Language.SyntaxTree": "13.7.0" + "HotChocolate.Language.SyntaxTree": "13.8.1" } }, "HotChocolate.Language.Visitors": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "pnk408/UF7VGI9rsQ5oe05bfRWOlxYXMa2gc99VwZVDpG+3ZMVI+EhLulTz3CLs+861cR/1d/7Bgm9BcYUURoA==", + "resolved": "13.8.1", + "contentHash": "aMibQ+gWIB+L+jZhiq2Vq+Jr6DsKcLwXAwr0GY8Dx54GPq9f/UHgtMi0KWrZ3sJck5/FwvENjLAuOtb2DFBREA==", "dependencies": { - "HotChocolate.Language.SyntaxTree": "13.7.0" + "HotChocolate.Language.SyntaxTree": "13.8.1" } }, "HotChocolate.Language.Web": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "KI6TB3+hY2eS6G2NcTjKrzWG1dxbFBcImxnKrEeRot7zzBcHm0ZU6WfHqiUABo4kvnnPItaqoJiQjbt1ePW1ZA==", + "resolved": "13.8.1", + "contentHash": "rQ0jTiWoHuPyF58bZ17AdfYezmrpwcHthNhjYBcVfAxkATsvrHzoPqNDIgpv8xv3xaMlpxsv+nPg+i9mW/zS2Q==", "dependencies": { - "HotChocolate.Language.Utf8": "13.7.0" + "HotChocolate.Language.Utf8": "13.8.1" } }, "HotChocolate.Subscriptions": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "u8kR/au74TtsxOHAEcfpP9NDvWMSCRpCTNsAYoMcX9AnKw5126fJttbVtZzdnbYKI1Ceq214o77yV5KrJDroQw==", + "resolved": "13.8.1", + "contentHash": "RD0eebXDBvfILKsy8dF7kMyR1puoPDzp0/BPUBzfEQalGi66F76P/cuGHN1fJrzTr1x2MIINsPmQN2udlfTTKQ==", "dependencies": { - "HotChocolate.Abstractions": "13.7.0", - "HotChocolate.Execution.Abstractions": "13.7.0" + "HotChocolate.Abstractions": "13.8.1", + "HotChocolate.Execution.Abstractions": "13.8.1" } }, "HotChocolate.Subscriptions.InMemory": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "kKmJertu6LleVVyjFb/+df0mgswHJ885nDKGbd9cEwHT9h8CbHSF05/qAJFo6xm2rUM8fMsBPFME/DOTDIaTgg==", + "resolved": "13.8.1", + "contentHash": "8A0K4bTBd1CfWbPovj/b1WYb52S8ElaOxghlS8Dea3GN8q4CCF3vSwXrzfkdVynCmrv3AFQYIXV1ddMJG1YqFQ==", "dependencies": { - "HotChocolate.Execution.Abstractions": "13.7.0", - "HotChocolate.Subscriptions": "13.7.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0-rc.2.23479.6" + "HotChocolate.Execution.Abstractions": "13.8.1", + "HotChocolate.Subscriptions": "13.8.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, "HotChocolate.Transport.Sockets": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "DoRW/Htb6G/SHbWuPiq+mDqL5TdEsTbmuOQ19B9x1Z5X7iDW64N5hNTfR6YbT17J5OgQvb7XrPQLhVl6DALagQ==", + "resolved": "13.8.1", + "contentHash": "YVfn1O+B0UlGKtieqRoGEeZjnFpSNjK1ZQVLvfKZ/DfCh+7FR9CwZ6II7YXWCE+M9sCQTvEo9Cz5XCpsnJDhIw==", "dependencies": { - "System.IO.Pipelines": "8.0.0-rc.2.23479.6" + "System.IO.Pipelines": "8.0.0" } }, "HotChocolate.Types": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "kVWrhbkFvZWSZ7X3PY5MoL3bTmv2erRFI7kuvoo1nVGtYUeC05b+5MCh0RHzL7IFnIxf67RrDRFWWxL6bbZ7ug==", + "resolved": "13.8.1", + "contentHash": "EK5PodS+N+Oi77jmBFucS6Leq0mL4xYjC2fDTq6Le+cNxMLYx+cY8PE5Kjg3rMtrd/MFOOvUSQ/heAes5nuBHQ==", "dependencies": { - "HotChocolate.Abstractions": "13.7.0", - "HotChocolate.Types.Shared": "13.7.0", - "HotChocolate.Utilities": "13.7.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0-rc.2.23479.6", - "Microsoft.Extensions.ObjectPool": "8.0.0-rc.2.23480.2", + "HotChocolate.Abstractions": "13.8.1", + "HotChocolate.Types.Shared": "13.8.1", + "HotChocolate.Utilities": "13.8.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.ObjectPool": "8.0.0", "System.ComponentModel.Annotations": "5.0.0", - "System.Text.Json": "8.0.0-rc.2.23479.6" + "System.Text.Json": "8.0.0" } }, "HotChocolate.Types.CursorPagination": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "86YCkEUFBuq5ZEIdmAolW2/YLhVKyWjzg6hUZEBMMD3yE85xpgIdPd0wsyxwnF9hREyl8f/LMWO7epALBjnjow==", + "resolved": "13.8.1", + "contentHash": "Nu7ERbmzIkZKeCx/dwMQDIEVXDk7fgMrGGsnBTBVNyk5YA/hyto54CNhlM7TeUqqhYUze3wKynA8rB1sr0f+cw==", "dependencies": { - "HotChocolate.Execution": "13.7.0", - "HotChocolate.Types": "13.7.0" + "HotChocolate.Execution": "13.8.1", + "HotChocolate.Types": "13.8.1" } }, "HotChocolate.Types.Mutations": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "lAZWOeAXNB0A2QsJRhhtuOsyrofEqKxvS5b3qgYR+LqwL9G8EHyJA3gN9GjqoRMz8c+DtSCHyAVxXydhvRx2gw==", + "resolved": "13.8.1", + "contentHash": "euXYibxZS11BTQ+nhY991u4mfd72xK/25KYaA6/mkLR/to9z9Xb27QSukVF5cdCTEWnqBix6CdX3S5fq2YIYGw==", "dependencies": { - "HotChocolate.Execution": "13.7.0", - "HotChocolate.Types": "13.7.0" + "HotChocolate.Execution": "13.8.1", + "HotChocolate.Types": "13.8.1" } }, "HotChocolate.Types.OffsetPagination": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "Z+lXxKMf3ksdP6z2MkgZttMQ2V2AtCcdz+S2STOdJiahj1OZ7bx12Cq5l6GK3KVIT40NgYOkXqnU/fVWxB0b8g==", + "resolved": "13.8.1", + "contentHash": "cwspQsQEOUBxjOAOvcmYObf4ol5pcI6epKQahrwfOX7v8GJd+FU0Sh8YmqOA1bks4VyjueDR06t88lw6XNeJIw==", "dependencies": { - "HotChocolate.Execution": "13.7.0", - "HotChocolate.Types": "13.7.0" + "HotChocolate.Execution": "13.8.1", + "HotChocolate.Types": "13.8.1" } }, "HotChocolate.Types.Scalars.Upload": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "4C/cs0SFhv+jeN7itzy4W5rKj5p2aPfUVr3N71PW5WtgYE5Ntc31Umz+dqjcFRPTVhhWecuCYAMGFPAED1H9BQ==", + "resolved": "13.8.1", + "contentHash": "cUMEyPMt57kEhB8kXvF5/lCyBZQkzkTFuSpTIZwTX3RmJ08bYWaXxpYLpor/jxjoe4qTIyGR+z7z2p8sIearMg==", "dependencies": { - "HotChocolate.Types": "13.7.0" + "HotChocolate.Types": "13.8.1" } }, "HotChocolate.Types.Shared": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "No0VSatuyjiie0SXzLHER0Pc5bs7lq6MO0Sq0FUSw6MpV5ElX0kaR1TrrZCYZJa5ok9NRev6y52DzT+2Y+msvA==", + "resolved": "13.8.1", + "contentHash": "vPpDZdVLahXD+a9xweLclWyIy3GH8IcKHmzZpOz4zeoZlxUuQCrx0ViXrSdiX1WdtOoV0nc5c26WKPIgCAVJIw==", "dependencies": { - "HotChocolate.Language.SyntaxTree": "13.7.0" + "HotChocolate.Language.SyntaxTree": "13.8.1" } }, "HotChocolate.Utilities": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "Jhg/lrJrrrY2GHCavfjKKwdR0GI5bhKN9v9SWn9SYCoL21UfWtc0C6Qr4o3I/MCfQnktPiCH6WkPVS9VgipbRA==" + "resolved": "13.8.1", + "contentHash": "Z33UtFR96+iDR6uyjIW3qU3skvYEnhE/DGYnCoZUCh119t9OebvDW7ANCeL6oGXv0sZDJERvGQRhOZiBWZnqKA==" + }, + "HotChocolate.Utilities.DependencyInjection": { + "type": "Transitive", + "resolved": "13.8.1", + "contentHash": "4tEg4xfDfiahuLrC59gH+BYfAFqDPEvoyBK7PU3ep7O2cmQgnqeE3tKMqJ1UovGMsVQ5nYwcQ98LhqrPOxECUw==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "8.0.0" + } }, "HotChocolate.Validation": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "/y6kX7cBkRbI9UgeWHgs/Kt8phJql1IrZjwSwdU6s8QOidFbanhsBU4euqVnM+hSeCbArzzKdrKt98DoPyfldA==", + "resolved": "13.8.1", + "contentHash": "kmPmYrtCt1NtmyZiSvfjDU+Abc/4hI2wDLe1uDEZW8JC8O2uwH0becZm1K6j9ZUfVMLp/5ZNsQONOXzL1VwxLA==", "dependencies": { - "HotChocolate.Types": "13.7.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0-rc.2.23479.6", - "Microsoft.Extensions.Options": "8.0.0-rc.2.23479.6" + "HotChocolate.Types": "13.8.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0" } }, "HtmlSanitizer": { "type": "Transitive", - "resolved": "8.0.795", - "contentHash": "wwX7RaYITdjdoc+t99vaPgoJtAaHJWZ1Y7IhdlP8oLpD1P1a4PaR8oCAKvvXpn9JHS9DB8gTqxFuSkyJmHS6iw==", + "resolved": "8.0.843", + "contentHash": "XfmHK4rFz9PPN0gcv7J7pc+MRpcni1mrnO04mwA+9/1zIHLgdOvLJeDwWnX5a+up4tioPvGreB+p+KljLJ32wg==", "dependencies": { "AngleSharp": "[0.17.1]", "AngleSharp.Css": "[0.17.0]", @@ -399,35 +409,36 @@ }, "Kentico.Aira.Client": { "type": "Transitive", - "resolved": "1.0.23", - "contentHash": "16jt+oHW6Fa6fDmJlJBTJuMK+A6nwXDX7IcYygYFzq01Sek43oQB2wjhXPRhntsvFYhAbWcBwXPzn0ALlMggSQ==", + "resolved": "1.0.25", + "contentHash": "Hu3xxl89ZWWU6iGkpnTCIXE/L3DNU+i/ZUZaRESYP6BJANlThPRFCIkrDwNx+daAsda5B/n5iApFzk5nH6qPOA==", "dependencies": { "Microsoft.Extensions.DependencyInjection": "6.0.1", "Microsoft.Extensions.Http": "6.0.0", "Microsoft.Extensions.Options": "6.0.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "6.0.0", - "System.IdentityModel.Tokens.Jwt": "6.31.0" + "System.IdentityModel.Tokens.Jwt": "7.3.1" } }, "Kentico.Xperience.Core": { "type": "Transitive", - "resolved": "28.1.0", - "contentHash": "vi81eejMIjPaSK1R/H0i6XAkeIV2EgAuPwdsafmR1+IQJ28jNSlGV/gteHXgxfIuQWjJDNayJInG7ggLCjlLJQ==", + "resolved": "28.3.2", + "contentHash": "DW4pX1en1r4aKzNiKv0wvag6FPmyU8Z/AQVXkr2AGdyFykEnmzvcQbRoakhZ7Mj290MdzRNQLHducQpDetOtEQ==", "dependencies": { "AngleSharp": "0.17.1", "MailKit": "4.3.0", - "Microsoft.Data.SqlClient": "5.1.2", + "Microsoft.AspNetCore.Http.Abstractions": "2.1.1", + "Microsoft.Data.SqlClient": "5.1.5", "Microsoft.Extensions.Caching.Memory": "6.0.1", "Microsoft.Extensions.Configuration": "6.0.1", "Microsoft.Extensions.Configuration.Binder": "6.0.0", "Microsoft.Extensions.DependencyInjection": "6.0.1", "Microsoft.Extensions.FileProviders.Physical": "6.0.0", "Microsoft.Extensions.Hosting.Abstractions": "6.0.0", - "Microsoft.Extensions.Localization": "6.0.25", + "Microsoft.Extensions.Localization": "6.0.27", "Microsoft.Extensions.Options.ConfigurationExtensions": "6.0.0", "Mono.Cecil": "0.11.5", "Newtonsoft.Json": "13.0.3", - "System.CodeDom": "7.0.0", + "System.CodeDom": "8.0.0", "System.Configuration.ConfigurationManager": "6.0.1" } }, @@ -439,10 +450,27 @@ "MimeKit": "4.3.0" } }, + "Microsoft.AspNetCore.Http.Abstractions": { + "type": "Transitive", + "resolved": "2.1.1", + "contentHash": "kQUEVOU4loc8CPSb2WoHFTESqwIa8Ik7ysCBfTwzHAd0moWovc9JQLmhDIHlYLjHbyexqZAlkq/FPRUZqokebw==", + "dependencies": { + "Microsoft.AspNetCore.Http.Features": "2.1.1", + "System.Text.Encodings.Web": "4.5.0" + } + }, + "Microsoft.AspNetCore.Http.Features": { + "type": "Transitive", + "resolved": "2.1.1", + "contentHash": "VklZ7hWgSvHBcDtwYYkdMdI/adlf7ebxTZ9kdzAhX+gUs5jSHE9mZlTamdgf9miSsxc1QjNazHXTDJdVPZKKTw==", + "dependencies": { + "Microsoft.Extensions.Primitives": "2.1.1" + } + }, "Microsoft.AspNetCore.SpaServices.Extensions": { "type": "Transitive", - "resolved": "6.0.25", - "contentHash": "zrpq53bEpjusCgaNigpRZkKqkDr2X2guJQqvUI0bLbq+u34kTg7WmWwJaaOUNBXdp9sgzMkkqmh35/ajKzZfdQ==", + "resolved": "6.0.27", + "contentHash": "sJ3wibVaTldyWtQXz2zollxKJO1tnfIcuta5iqqiOHayEJwlbRFDz1qWpinC8hKnGCJ76PMm5bJ+g98KlXegRw==", "dependencies": { "Microsoft.Extensions.FileProviders.Physical": "6.0.0" } @@ -452,24 +480,19 @@ "resolved": "1.1.1", "contentHash": "yuvf07qFWFqtK3P/MRkEKLhn5r2UbSpVueRziSqj0yJQIKFwG1pq9mOayK3zE5qZCTs0CbrwL9M6R8VwqyGy2w==" }, - "Microsoft.CSharp": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "kaj6Wb4qoMuH3HySFJhxwQfe8R/sJsNJnANrvv8WdFPMoNbKY5htfNscv+LHCu5ipz+49m2e+WQXpLXr9XYemQ==" - }, "Microsoft.Data.SqlClient": { "type": "Transitive", - "resolved": "5.1.2", - "contentHash": "q/F1HTOn9QLwgRp4esJIA1b2X15faeV8WozkNhvU3Zk0DcYDWUsEf5WMkbypY4CaNkZntOduods5wLyv8I699w==", + "resolved": "5.1.5", + "contentHash": "6kvhQjY5uBCdBccezFD2smfnpQjQ33cZtUZVrNvxlwoBu6uopM5INH6uSgLI7JRLtlQ3bMPwnhMq4kchsXeZ5w==", "dependencies": { - "Azure.Identity": "1.7.0", + "Azure.Identity": "1.10.3", "Microsoft.Data.SqlClient.SNI.runtime": "5.1.1", - "Microsoft.Identity.Client": "4.47.2", - "Microsoft.IdentityModel.JsonWebTokens": "6.24.0", - "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.24.0", + "Microsoft.Identity.Client": "4.56.0", + "Microsoft.IdentityModel.JsonWebTokens": "6.35.0", + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.35.0", "Microsoft.SqlServer.Server": "1.0.0", "System.Configuration.ConfigurationManager": "6.0.1", - "System.Diagnostics.DiagnosticSource": "6.0.0", + "System.Diagnostics.DiagnosticSource": "6.0.1", "System.Runtime.Caching": "6.0.0", "System.Security.Cryptography.Cng": "5.0.0", "System.Security.Principal.Windows": "5.0.0", @@ -529,16 +552,16 @@ }, "Microsoft.Extensions.DependencyInjection": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "pUD/Gjd0MTrWPD4/SnKazYQvky2EHEtPyGb3FWZkEPWAfYPFVVw5fMRTkfoBPivpWLuxEw4FNK7GX77xEErUQQ==", + "resolved": "8.0.0", + "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0-rc.2.23479.6" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "QLTBDvE/E05Xl2UVFXOBFIW0VLn/mMJ8DSbTyK6ODsO3sqDs0fyPqydACTnX/nbGZRrTMeud3XDbUrt24ab1EA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.FileProviders.Abstractions": { "type": "Transitive", @@ -550,8 +573,8 @@ }, "Microsoft.Extensions.FileProviders.Embedded": { "type": "Transitive", - "resolved": "6.0.25", - "contentHash": "q1S6iVA2+kvwuSt21zcjKLzQDGTyMwVlEGhucOu8xNIQiHjcvWrKHtwlBIJzIE1EIcxQL/4w3iQw9W665i5WdQ==", + "resolved": "6.0.27", + "contentHash": "trrI4tXQsOIB56H3u/wD4aVu5QtF8nJPtBuQ6wm8phlYSFTR3Rj3/9fXA5Mrz4X2B0lwOk1QndCPL/fWhH9Izw==", "dependencies": { "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0" } @@ -594,19 +617,19 @@ }, "Microsoft.Extensions.Localization": { "type": "Transitive", - "resolved": "6.0.25", - "contentHash": "7g6QtX+XkdtirCP3eLRnd4x6s7Q6LMlRZnby0iqRIhKBZ7CEwMVAfOODRHRqUMZ6n1f67OY+yGmZSpKtbGmp+w==", + "resolved": "6.0.27", + "contentHash": "sqwoeaqGTeSMBTrUV8ysD8JPfUcH8sdkmv4oCfz9i5WHAGfsS/eHCpoff87sukoxwgaEBBd9YPhTwdaFE9njlw==", "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Localization.Abstractions": "6.0.25", + "Microsoft.Extensions.Localization.Abstractions": "6.0.27", "Microsoft.Extensions.Logging.Abstractions": "6.0.4", "Microsoft.Extensions.Options": "6.0.0" } }, "Microsoft.Extensions.Localization.Abstractions": { "type": "Transitive", - "resolved": "6.0.25", - "contentHash": "41x/D64w2kEjeKxC8nkB6lBmw731FoTjFoy8caE7063aNo/fwB/B4p39G0dn7nu752GznHT3I+sLWJG/tdzw6A==" + "resolved": "6.0.27", + "contentHash": "virsfnfbV6uJASaNKUXLQpdY0qGr48R6dUFwY00Qja5ea+kgntRgm7qzAH6GLeJjfW3zjoltrTiTrCbrAP3KCA==" }, "Microsoft.Extensions.Logging": { "type": "Transitive", @@ -627,16 +650,16 @@ }, "Microsoft.Extensions.ObjectPool": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23480.2", - "contentHash": "iL9VcNK4dbMOLqAHInwcmVxzr+5sXp70m5Tt1uyIkc5SfJUTuFN6VaxrZy3k91oquTtYrkK9DbE5IP18iJUrtw==" + "resolved": "8.0.0", + "contentHash": "4pm+XgxSukskwjzDDfSjG4KNUIOdFF2VaqZZDtTzoyQMOVSnlV6ZM8a9aVu5dg9LVZTB//utzSc8fOi0b0Mb2Q==" }, "Microsoft.Extensions.Options": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "f2uTnKEleplKK+pVKEg1rOCmM3+cuLpafTpKJzbj9lm8dmj0+dWxb0L6MAt9r1s3OYlIKY5IdkW0TUFKXvRCMg==", + "resolved": "8.0.0", + "contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0-rc.2.23479.6", - "Microsoft.Extensions.Primitives": "8.0.0-rc.2.23479.6" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" } }, "Microsoft.Extensions.Options.ConfigurationExtensions": { @@ -653,87 +676,78 @@ }, "Microsoft.Extensions.Primitives": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "I3fTiDmV+2cCR3VjH+oz49AMgrAqX1cmNiWXmEAituAI7jCLA16uXzvYQTwxhQzov5BTdPVXKGNTxsMb1GpcLQ==" + "resolved": "8.0.0", + "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, "Microsoft.Identity.Client": { "type": "Transitive", - "resolved": "4.47.2", - "contentHash": "SPgesZRbXoDxg8Vv7k5Ou0ee7uupVw0E8ZCc4GKw25HANRLz1d5OSr0fvTVQRnEswo5Obk8qD4LOapYB+n5kzQ==", + "resolved": "4.56.0", + "contentHash": "rr4zbidvHy9r4NvOAs5hdd964Ao2A0pAeFBJKR95u1CJAVzbd1p6tPTXUZ+5ld0cfThiVSGvz6UHwY6JjraTpA==", "dependencies": { "Microsoft.IdentityModel.Abstractions": "6.22.0" } }, "Microsoft.Identity.Client.Extensions.Msal": { "type": "Transitive", - "resolved": "2.19.3", - "contentHash": "zVVZjn8aW7W79rC1crioDgdOwaFTQorsSO6RgVlDDjc7MvbEGz071wSNrjVhzR0CdQn6Sefx7Abf1o7vasmrLg==", + "resolved": "4.56.0", + "contentHash": "H12YAzEGK55vZ+QpxUzozhW8ZZtgPDuWvgA0JbdIR9UhMUplj29JhIgE2imuH8W2Nw9D8JKygR1uxRFtpSNcrg==", "dependencies": { - "Microsoft.Identity.Client": "4.38.0", + "Microsoft.Identity.Client": "4.56.0", + "System.IO.FileSystem.AccessControl": "5.0.0", "System.Security.Cryptography.ProtectedData": "4.5.0" } }, "Microsoft.IdentityModel.Abstractions": { "type": "Transitive", - "resolved": "6.31.0", - "contentHash": "SBa2DGEZpMThT3ki6lOK5SwH+fotHddNBKH+pfqrlINnl999BreRS9G0QiLruwfmcTDnFr8xwmNjoGnPQqfZwg==" + "resolved": "7.3.1", + "contentHash": "gIw8Sr5ZpuzKFBTfJonh2F54DivTzm5IIK15QB4Y6uE30uQdEO1NnCojTC/b6sWZoZzD0sdBa6SqwMXhucD+nA==" }, "Microsoft.IdentityModel.JsonWebTokens": { "type": "Transitive", - "resolved": "6.31.0", - "contentHash": "r0f4clrrlFApwSf2GRpS5X8hL54h1WUlZdq9ZoOy+cJOOqtNhhdfkfkqwxsTGCH/Ae7glOWNxykZzyRXpwcXVQ==", + "resolved": "7.3.1", + "contentHash": "mXA6AoaD5uZqtsKghgRiupBhyXNii8p9F2BjNLnDGud0tZLS5+4Fio2YAGjFXhnkc80CqgQ61X5U1gUNnDEoKQ==", "dependencies": { - "Microsoft.IdentityModel.Tokens": "6.31.0", - "System.Text.Encoding": "4.3.0", - "System.Text.Encodings.Web": "4.7.2", - "System.Text.Json": "4.7.2" + "Microsoft.IdentityModel.Tokens": "7.3.1" } }, "Microsoft.IdentityModel.Logging": { "type": "Transitive", - "resolved": "6.31.0", - "contentHash": "YzW5O27nTXxNgNKm+Pud7hXjUlDa2JshtRG+WftQvQIsBUpFA/WjhxG2uO8YanfXbb/IT9r8Cu/VdYkvZ3+9/g==", + "resolved": "7.3.1", + "contentHash": "uPt2aiRUCbcOc0Wk+dDCSClFfPNs3S3Z7fmy50MoxJ1mGmtVUDMpyRJeYzZ/16x4rL19T+g2zrzjcWoitp5+gQ==", "dependencies": { - "Microsoft.IdentityModel.Abstractions": "6.31.0" + "Microsoft.IdentityModel.Abstractions": "7.3.1" } }, "Microsoft.IdentityModel.Protocols": { "type": "Transitive", - "resolved": "6.24.0", - "contentHash": "+NzKCkvsQ8X1r/Ff74V7CFr9OsdMRaB6DsV+qpH7NNLdYJ8O4qHbmTnNEsjFcDmk/gVNDwhoL2gN5pkPVq0lwQ==", + "resolved": "6.35.0", + "contentHash": "BPQhlDzdFvv1PzaUxNSk+VEPwezlDEVADIKmyxubw7IiELK18uJ06RQ9QKKkds30XI+gDu9n8j24XQ8w7fjWcg==", "dependencies": { - "Microsoft.IdentityModel.Logging": "6.24.0", - "Microsoft.IdentityModel.Tokens": "6.24.0" + "Microsoft.IdentityModel.Logging": "6.35.0", + "Microsoft.IdentityModel.Tokens": "6.35.0" } }, "Microsoft.IdentityModel.Protocols.OpenIdConnect": { "type": "Transitive", - "resolved": "6.24.0", - "contentHash": "a/2RRrc8C9qaw8qdD9hv1ES9YKFgxaqr/SnwMSLbwQZJSUQDd4qx1K4EYgWaQWs73R+VXLyKSxN0f/uE9CsBiQ==", + "resolved": "6.35.0", + "contentHash": "LMtVqnECCCdSmyFoCOxIE5tXQqkOLrvGrL7OxHg41DIm1bpWtaCdGyVcTAfOQpJXvzND9zUKIN/lhngPkYR8vg==", "dependencies": { - "Microsoft.IdentityModel.Protocols": "6.24.0", - "System.IdentityModel.Tokens.Jwt": "6.24.0" + "Microsoft.IdentityModel.Protocols": "6.35.0", + "System.IdentityModel.Tokens.Jwt": "6.35.0" } }, "Microsoft.IdentityModel.Tokens": { "type": "Transitive", - "resolved": "6.31.0", - "contentHash": "Q1Ej/OAiqi5b/eB8Ozo5FnQ6vlxjgiomnWWenDi2k7+XqhkA2d5TotGtNXpWcWiGmrotNA/o8p51YesnziA0Sw==", + "resolved": "7.3.1", + "contentHash": "/c/p8/3CAH706c0ii5uTgSb/8M/jwyuurtdMeKTBeKFU9aA+EZrLu1M8aaS3CSlGaxoxsoaxr4/+KXykgQ4VgQ==", "dependencies": { - "Microsoft.CSharp": "4.5.0", - "Microsoft.IdentityModel.Logging": "6.31.0", - "System.Security.Cryptography.Cng": "4.5.0" + "Microsoft.IdentityModel.Logging": "7.3.1" } }, "Microsoft.NETCore.Platforms": { "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" - }, - "Microsoft.NETCore.Targets": { - "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" + "resolved": "5.0.0", + "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" }, "Microsoft.SqlServer.Server": { "type": "Transitive", @@ -763,30 +777,30 @@ }, "SkiaSharp": { "type": "Transitive", - "resolved": "2.88.6", - "contentHash": "wdfeBAQrEQCbJIRgAiargzP1Uy+0grZiG4CSgBnhAgcJTsPzlifIaO73JRdwIlT3TyBoeU9jEqzwFUhl4hTYnQ==", + "resolved": "2.88.7", + "contentHash": "LJHAMrbWO00J7jXWLWehyjqFo29T4VzABimfJb4nICqpEe3c/KvQGWL4ItON8ymzhxYOeFgyxeRzuNzO4GHSug==", "dependencies": { - "SkiaSharp.NativeAssets.Win32": "2.88.6", - "SkiaSharp.NativeAssets.macOS": "2.88.6" + "SkiaSharp.NativeAssets.Win32": "2.88.7", + "SkiaSharp.NativeAssets.macOS": "2.88.7" } }, "SkiaSharp.NativeAssets.Linux.NoDependencies": { "type": "Transitive", - "resolved": "2.88.6", - "contentHash": "ecgMclPor+X1wi2dZSVDo1sV2Dm8gwEKNRtS+qiE9qfnQzGHbYWlbTBWalnZBaIl3BLC21b1QO8gMgabhSAh+g==", + "resolved": "2.88.7", + "contentHash": "KkMftfAz1lGPnuhyecuLJzeyvMjXtHp9cYVQc/oeLhF8KYrxtUxRy5LOX5oROhyLHy/CyqEl9MoAhqmSH7cV7g==", "dependencies": { - "SkiaSharp": "2.88.6" + "SkiaSharp": "2.88.7" } }, "SkiaSharp.NativeAssets.macOS": { "type": "Transitive", - "resolved": "2.88.6", - "contentHash": "Sko9LFxRXSjb3OGh5/RxrVRXxYo48tr5NKuuSy6jB85GrYt8WRqVY1iLOLwtjPiVAt4cp+pyD4i30azanS64dw==" + "resolved": "2.88.7", + "contentHash": "3jNzco4VjcYPFNxR9aNWcgweFXbTSdM1VpNRzCS4X0i1A1OuNqcaulrAvmntNpujeWxHo9e6WGh6FN8Jf5+XhA==" }, "SkiaSharp.NativeAssets.Win32": { "type": "Transitive", - "resolved": "2.88.6", - "contentHash": "7TzFO0u/g2MpQsTty4fyCDdMcfcWI+aLswwfnYXr3gtNS6VLKdMXPMeKpJa3pJSLnUBN6wD0JjuCe8OoLBQ6cQ==" + "resolved": "2.88.7", + "contentHash": "BCXmWdQ0oVck9vRwC8U3ocSaTHEx28VB+6qw9OxGIMQ86iO5bp4Flqk3IXH0l9Pbr7vWAUOpI212iaL9mTaUZQ==" }, "System.Buffers": { "type": "Transitive", @@ -795,8 +809,8 @@ }, "System.CodeDom": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "GLltyqEsE5/3IE+zYRP5sNa1l44qKl9v+bfdMcwg+M9qnQf47wK3H0SUR/T+3N4JEQXF3vV4CSuuo0rsg+nq2A==" + "resolved": "8.0.0", + "contentHash": "WTlRjL6KWIMr/pAaq3rYqh0TJlzpouaQ/W1eelssHgtlwHAH25jXTkUphTYx9HaIIf7XA6qs/0+YhtLEQRkJ+Q==" }, "System.Collections.Immutable": { "type": "Transitive", @@ -819,8 +833,8 @@ }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "D1Fi5wRyRVwriEdlSniYlo2kW8SCGaSCM/alsY8R7eXcW+xCPRB7gohE45X00EiNkhdUrJ3yNfltV8lLK0HoWQ==" + "resolved": "8.0.0", + "contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ==" }, "System.Diagnostics.EventLog": { "type": "Transitive", @@ -834,11 +848,20 @@ }, "System.IdentityModel.Tokens.Jwt": { "type": "Transitive", - "resolved": "6.31.0", - "contentHash": "OTlLhhNHODxZvqst0ku8VbIdYNKi25SyM6/VdbpNUe6aItaecVRPtURGvpcQpzltr9H0wy+ycAqBqLUI4SBtaQ==", + "resolved": "7.3.1", + "contentHash": "iE8biOWyAC1NnYcZGcgXErNACvIQ6Gcmg5s28gsjVbyyYdF9NdKsYzAPAsO3KGK86EQjpToI1AO82XbG8chkzA==", + "dependencies": { + "Microsoft.IdentityModel.JsonWebTokens": "7.3.1", + "Microsoft.IdentityModel.Tokens": "7.3.1" + } + }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", "dependencies": { - "Microsoft.IdentityModel.JsonWebTokens": "6.31.0", - "Microsoft.IdentityModel.Tokens": "6.31.0" + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" } }, "System.IO.Hashing": { @@ -848,8 +871,8 @@ }, "System.IO.Pipelines": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "4bqn2Kj0keumJ0x3wdZtO1Ex/5Ppu01fP7Rtmn1uJBR08WWRKeKSX6U9a/BiEieE9JjhzapvhjPtFypE7ZIAyQ==" + "resolved": "8.0.0", + "contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA==" }, "System.Memory": { "type": "Transitive", @@ -870,15 +893,6 @@ "resolved": "4.5.0", "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" }, - "System.Runtime": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, "System.Runtime.Caching": { "type": "Transitive", "resolved": "8.0.0", @@ -892,6 +906,15 @@ "resolved": "6.0.0", "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.Cng": { "type": "Transitive", "resolved": "5.0.0", @@ -918,16 +941,6 @@ "resolved": "5.0.0", "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, - "System.Text.Encoding": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, "System.Text.Encoding.CodePages": { "type": "Transitive", "resolved": "7.0.0", @@ -935,21 +948,21 @@ }, "System.Text.Encodings.Web": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "n66ZIJjetmrMq9hJ61Xed2cp9O2zr/VdzhhURjkLDEFOZ38/VpOWnvM3CWCXA18NbM7x0tdKZYex9rj0NimpPA==" + "resolved": "8.0.0", + "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==" }, "System.Text.Json": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "SXMjrmm/e0Om+731AEUgm+81dC+i9mV54nKJGOq9+zTYpzujMCmSQSMS1sgQb0gmiiAfTfRC5WgD3l92cfAP+g==", + "resolved": "8.0.0", + "contentHash": "OdrZO2WjkiEG6ajEFRABTRCi/wuXQPxeV6g8xvUJqdxMvvuCCEk86zPla8UiIQJz3durtUEbNyY/3lIhS0yZvQ==", "dependencies": { - "System.Text.Encodings.Web": "8.0.0-rc.2.23479.6" + "System.Text.Encodings.Web": "8.0.0" } }, "System.Threading.Channels": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "z8/q0WPKxQsxuzywRbY1oCb2ZO4qgRbE0nYwXjwrIJ7y10796vJl9P2++MF4JcBcKXfNLgw0JSQslMTxXB+C/A==" + "resolved": "8.0.0", + "contentHash": "CMaFr7v+57RW7uZfZkPExsPB6ljwzhjACWW1gfU35Y56rk72B/Wu+sTqxVmGSk4SFUlPc3cjeKND0zktziyjBA==" }, "System.Threading.Tasks.Extensions": { "type": "Transitive", @@ -968,8 +981,8 @@ "type": "Project", "dependencies": { "AspNetCore.Authentication.ApiKey": "[8.0.0, )", - "Kentico.Xperience.Admin": "[28.1.0, )", - "Kentico.Xperience.WebApp": "[28.1.0, )" + "Kentico.Xperience.Admin": "[28.3.2, )", + "Kentico.Xperience.WebApp": "[28.3.2, )" } }, "AspNetCore.Authentication.ApiKey": { diff --git a/src/Kentico.Xperience.Zapier/Actions/ActionFormInsertController.cs b/src/Kentico.Xperience.Zapier/Actions/ActionFormInsertController.cs new file mode 100644 index 0000000..dd8609f --- /dev/null +++ b/src/Kentico.Xperience.Zapier/Actions/ActionFormInsertController.cs @@ -0,0 +1,117 @@ +using CMS.DataEngine; +using CMS.OnlineForms; +using Kentico.Xperience.Admin.Base; +using Kentico.Xperience.Zapier.Admin; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System.Text; +using System.Text.Json; + +namespace Kentico.Xperience.Zapier.Actions; + +[Authorize(AuthenticationSchemes = ZapierConstants.AuthenticationScheme.XbyKZapierApiKeyScheme)] +[ApiController] +public class ActionFormInsertController : ControllerBase +{ + private readonly ILogger logger; + private readonly ZapierConfiguration zapierConfiguration; + + public ActionFormInsertController(ILogger logger, + IOptionsMonitor zapierConfiguration) + { + this.logger = logger; + this.zapierConfiguration = zapierConfiguration.CurrentValue; + } + + [HttpPost] + [Route("zapier/actions/biz-form/{classname}")] + public ActionResult InsertFormRecord( + string classname, + [FromBody] IDictionary values) + { + + var newFormItem = BizFormItem.New(classname); + if (newFormItem == null || !zapierConfiguration.AllowedObjects.Contains(classname)) + { + return BadRequest(); + } + foreach (var item in values) + { + switch (item.Value.ValueKind) + { + case JsonValueKind.Number: + case JsonValueKind.String: + newFormItem.SetValue(item.Key, item.Value.GetString()); + break; + case JsonValueKind.True: + newFormItem.SetValue(item.Key, true); + break; + case JsonValueKind.False: + newFormItem.SetValue(item.Key, false); + break; + case JsonValueKind.Undefined: + break; + case JsonValueKind.Object: + break; + case JsonValueKind.Array: + break; + case JsonValueKind.Null: + break; + default: + break; + } + } + var sb = new StringBuilder(); + foreach (var kvp in values) + { + sb.Append($"{kvp.Key}: {kvp.Value}\n"); + } + try + { + newFormItem.Insert(); + logger.LogInformation("Zapier InsertFormRecordAction | Record saved into {0}. \n Values: {1}", classname, sb.ToString()); + return Ok(new { FormId = newFormItem.ItemID }); + } + catch (Exception) + { + logger.LogWarning("Zapier InsertFormRecordAction | Error occured during inserting into form {0}. \n Values: {1}", classname, sb.ToString()); + return BadRequest(); + } + } + + [HttpGet] + [Route("zapier/actions/biz-form/{classname}")] + public async Task GetFormFields(string classname) + { + var allowedObjects = zapierConfiguration.AllowedObjects.ToList(); + var dataClass = DataClassInfoProvider.ProviderObject.Get() + .WhereIn(nameof(DataClassInfo.ClassName), allowedObjects) + .WhereEquals(nameof(DataClassInfo.ClassType), ClassType.FORM) + .WhereEquals(nameof(DataClassInfo.ClassName), classname) + .WhereNotEmpty(nameof(DataClassInfo.ClassFormDefinition)) + .FirstOrDefault(); + if (dataClass == null) + { + return BadRequest(); + } + return Ok(dataClass.ClassFormDefinition); + } + + [HttpGet] + [Route("zapier/actions/biz-form/classnames")] + public async Task>> GetFormClassnames() + { + var allowedObjects = zapierConfiguration.AllowedObjects.ToList(); + var res = DataClassInfoProvider.ProviderObject.Get() + .WhereIn(nameof(DataClassInfo.ClassName), allowedObjects) + .WhereEquals(nameof(DataClassInfo.ClassType), ClassType.FORM) + .WhereNotEmpty(nameof(DataClassInfo.ClassFormDefinition)) + .Columns(nameof(DataClassInfo.ClassDisplayName), nameof(DataClassInfo.ClassName)) + .OrderBy(nameof(DataClassInfo.ClassName)) + .GetEnumerableTypedResult(); + return res.Select(x => new { Id = x.ClassName, Name = x.ClassDisplayName }).ToList(); + } +} + diff --git a/src/Kentico.Xperience.Zapier/Actions/ActionMoveToStepWorkflowController.cs b/src/Kentico.Xperience.Zapier/Actions/ActionMoveToStepWorkflowController.cs new file mode 100644 index 0000000..9a86010 --- /dev/null +++ b/src/Kentico.Xperience.Zapier/Actions/ActionMoveToStepWorkflowController.cs @@ -0,0 +1,122 @@ +using CMS.ContentWorkflowEngine; +using CMS.ContentWorkflowEngine.Internal; +using CMS.DataEngine; +using CMS.Membership; +using Kentico.Xperience.Zapier.Admin; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Kentico.Xperience.Zapier.Actions; + +[Authorize(AuthenticationSchemes = ZapierConstants.AuthenticationScheme.XbyKZapierApiKeyScheme)] +[ApiController] + +public class ActionMoveToStepWorkflowController : ControllerBase +{ + private readonly IWorkflowScopeService workflowScopeService; + private readonly IContentItemWorkflowManager contentItemWorkflowManager; + private readonly IWebPageWorkflowManager webPageWorkflowManager; + private readonly IHeadlessItemWorkflowManager headlessItemWorkflowManager; + private readonly ZapierConfiguration zapierConfiguration; + private readonly ILogger logger; + + public ActionMoveToStepWorkflowController(IContentItemWorkflowManagerFactory contentItemWorkflowManagerFactory, IWebPageWorkflowManagerFactory webPageWorkflowManagerFactory, ILogger logger, IWorkflowScopeService workflowScopeService, IOptionsMonitor zapierConfiguration, IHeadlessItemWorkflowManagerFactory headlessItemWorkflowManagerFactory) + { + contentItemWorkflowManager = contentItemWorkflowManagerFactory.Create(UserInfoProvider.AdministratorUser.UserID); + webPageWorkflowManager = webPageWorkflowManagerFactory.Create(UserInfoProvider.AdministratorUser.UserID); + headlessItemWorkflowManager = headlessItemWorkflowManagerFactory.Create(UserInfoProvider.AdministratorUser.UserID); + this.logger = logger; + this.workflowScopeService = workflowScopeService; + this.zapierConfiguration = zapierConfiguration.CurrentValue; + } + + [HttpPost] + [Route($"zapier/actions/movetostep/{ClassContentTypeType.REUSABLE}/{{stepName}}/{{id}}/{{languageName}}")] + public async Task> MoveToStepReusable( + string stepName, + int id, + string languageName) + { + try + { + await contentItemWorkflowManager.MoveToStep(id, languageName, stepName); + + return Ok(new { Id = id, LanguageName = languageName, Type = ClassContentTypeType.REUSABLE }); + } + catch (Exception) + { + logger.LogError($"Error occured during reusable item moving to step {stepName} (id: {id}, language: {languageName})"); + return BadRequest($"Error occured during reusable item moving to step {stepName} (id: {id}, language: {languageName})"); + } + } + + + + [HttpPost] + [Route($"zapier/actions/movetostep/{ClassContentTypeType.WEBSITE}/{{stepName}}/{{websiteChannelID}}/{{id}}/{{languageName}}")] + public async Task> MoveToStepPage( + string stepName, + int websiteChannelID, + int id, + string languageName) + { + + try + { + await webPageWorkflowManager.MoveToStep(id, languageName, stepName); + + return Ok(new { Id = id, LanguageName = languageName, Type = ClassContentTypeType.WEBSITE }); + } + catch (Exception) + { + logger.LogError($"Error occured during page moving to step (id: {id}, language: {languageName}, websiteChannelID: {websiteChannelID})"); + return BadRequest($"Error occured during page moving to step (id: {id}, language: {languageName}, websiteChannelID: {websiteChannelID})"); + } + } + + [HttpPost] + [Route($"zapier/actions/movetostep/{ClassContentTypeType.HEADLESS}/{{stepName}}/{{headlessChannelID}}/{{id}}/{{languageName}}")] + public async Task> MoveToStepHeadlessItem( + string stepName, + int headlessChannelID, + int id, + string languageName) + { + + try + { + await headlessItemWorkflowManager.MoveToStep(id, languageName, stepName); + + return Ok(new { Id = id, LanguageName = languageName, Type = ClassContentTypeType.HEADLESS }); + } + catch (Exception) + { + logger.LogError($"Error occured during headless item moving to step (id: {id}, language: {languageName}, headlessChannelID: {headlessChannelID})"); + return BadRequest($"Error occured during headless item moving to step (id: {id}, language: {languageName}, headlessChannelID: {headlessChannelID})"); + } + } + + + + [HttpGet] + [Route($"zapier/actions/movetostep/steps/{{className}}")] + public ActionResult> GetSteps(string className) + { + if (!zapierConfiguration.AllowedObjects.Contains(className)) + { + return BadRequest(); + } + var data = DataClassInfoProvider.ProviderObject.Get(className); + var steps = workflowScopeService.GetStepsByContentTypeID(data.ClassID) + .Where(step => step.ContentWorkflowStepType == ContentWorkflowStepType.Custom); + return Ok(steps + .Select(s => new + { + Id = s.ContentWorkflowStepName, + Name = s.ContentWorkflowStepDisplayName + })); + } + +} diff --git a/src/Kentico.Xperience.Zapier/Actions/ActionPublishController.cs b/src/Kentico.Xperience.Zapier/Actions/ActionPublishController.cs new file mode 100644 index 0000000..642a5f6 --- /dev/null +++ b/src/Kentico.Xperience.Zapier/Actions/ActionPublishController.cs @@ -0,0 +1,119 @@ +using CMS.ContentEngine; +using CMS.DataEngine; +using CMS.Headless.Internal; +using CMS.Membership; +using CMS.Websites; +using Kentico.Xperience.Admin.Base; +using Kentico.Xperience.Zapier.Admin; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +namespace Kentico.Xperience.Zapier.Actions; + +[Authorize(AuthenticationSchemes = ZapierConstants.AuthenticationScheme.XbyKZapierApiKeyScheme)] +[ApiController] +public class ActionPublishController : ControllerBase +{ + private readonly ILogger logger; + private readonly IContentItemManager contentItemManager; + private readonly IWebPageManagerFactory webPageManagerFactory; + private readonly IHeadlessItemManagerFactory headlessItemManagerFactory; + + public ActionPublishController( + ILogger logger, + IWebPageManagerFactory webPageManagerFactory, + IContentItemManagerFactory contentItemManagerFactory, + IHeadlessItemManagerFactory headlessItemManagerFactory) + { + this.logger = logger; + this.webPageManagerFactory = webPageManagerFactory; + this.headlessItemManagerFactory = headlessItemManagerFactory; + contentItemManager = contentItemManagerFactory.Create(AuthenticationHelper.GlobalPublicUser.UserID); + } + + [HttpPost] + [Route($"zapier/actions/publish/{ClassContentTypeType.REUSABLE}/{{id}}/{{languageName}}")] + public async Task> PublishReusable( + int id, + string languageName) + { + try + { + if (await contentItemManager.TryPublish(id, languageName)) + { + logger.LogInformation($"Reusable item successfully published. (id: {id}, language: {languageName}"); + return Ok(new { Id = id, LanguageName = languageName, Type = ClassContentTypeType.REUSABLE }); + } + else + { + logger.LogInformation($"Reusable item already published. (id: {id}, language: {languageName}"); + return Ok(new { Message = "Already published", Id = id, LanguageName = languageName, Type = ClassContentTypeType.REUSABLE }); + } + } + catch (Exception) + { + logger.LogError($"Error occured during reusable item publishing (id: {id}, language: {languageName})"); + return BadRequest($"Error occured during reusable item publising (id: {id}, language: {languageName})"); + } + } + + [HttpPost] + [Route($"zapier/actions/publish/{ClassContentTypeType.WEBSITE}/{{websiteChannelID}}/{{id}}/{{languageName}}")] + public async Task> PublishPage( + int websiteChannelID, + int id, + string languageName) + { + var webPageManager = webPageManagerFactory.Create(websiteChannelID, AuthenticationHelper.GlobalPublicUser.UserID); + + try + { + if (await webPageManager.TryPublish(id, languageName)) + { + logger.LogInformation($"Page successfully published (id: {id}, language: {languageName})"); + return Ok(new { Id = id, LanguageName = languageName, Type = ClassContentTypeType.WEBSITE }); + } + else + { + logger.LogInformation($"Page already published (id: {id}, language: {languageName})"); + return Ok(new { Message = "Already published", Id = id, LanguageName = languageName, Type = ClassContentTypeType.WEBSITE }); + } + } + catch (Exception) + { + logger.LogError($"Error occured during page publishing (id: {id}, language: {languageName})"); + return BadRequest($"Error occured during page publishing (id: {id}, language: {languageName})"); + } + } + + [HttpPost] + [Route($"zapier/actions/publish/{ClassContentTypeType.HEADLESS}/{{headlessChannelID}}/{{id}}/{{languageName}}")] + public async Task> PublishHeadlessItem( + int headlessChannelID, + int id, + string languageName) + { + var headlessItemManager = headlessItemManagerFactory.Create(headlessChannelID, AuthenticationHelper.GlobalPublicUser.UserID); + + try + { + if (await headlessItemManager.TryPublish(id, languageName)) + { + logger.LogInformation($"Headless item successfully published (id: {id}, language: {languageName})"); + return Ok(new { Id = id, LanguageName = languageName, Type = ClassContentTypeType.HEADLESS }); + } + else + { + logger.LogInformation($"Headless item already published (id: {id}, language: {languageName})"); + return Ok(new { Message = "Already published", Id = id, LanguageName = languageName, Type = ClassContentTypeType.HEADLESS }); + } + } + catch (Exception) + { + logger.LogError($"Error occured during headless item publishing (id: {id}, language: {languageName})"); + return BadRequest($"Error occured during headless item publishing (id: {id}, language: {languageName})"); + } + } +} + diff --git a/src/Kentico.Xperience.Zapier/Actions/SelectorController.cs b/src/Kentico.Xperience.Zapier/Actions/SelectorController.cs new file mode 100644 index 0000000..c5256ee --- /dev/null +++ b/src/Kentico.Xperience.Zapier/Actions/SelectorController.cs @@ -0,0 +1,248 @@ +using System.Data; +using CMS.ContentEngine; +using CMS.ContentEngine.Internal; +using CMS.DataEngine; +using CMS.Headless; +using CMS.Headless.Internal; +using CMS.Helpers; +using CMS.Websites; +using Kentico.Xperience.Admin.Base; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Kentico.Xperience.Zapier.Actions; + +//[Authorize(AuthenticationSchemes = ZapierConstants.AuthenticationScheme.XbyKZapierApiKeyScheme)] +[ApiController] +public class SelectorController : ControllerBase +{ + private readonly ILogger logger; + private readonly IContentQueryExecutor contentQueryExecutor; + private readonly ZapierConfiguration zapierConfiguration; + public SelectorController( + ILogger logger, + IContentQueryExecutor contentQueryExecutor, + IOptionsMonitor zapierConfiguration) + { + this.logger = logger; + this.contentQueryExecutor = contentQueryExecutor; + this.zapierConfiguration = zapierConfiguration.CurrentValue; + } + + [HttpGet] + [Route($"zapier/actions/{ClassContentTypeType.HEADLESS}/{{className}}/{{headlessChannelId}}/{{languageName}}")] + public async Task>> GetHeadlessItemsAsync(string className, int headlessChannelId, string languageName) + { + if (!zapierConfiguration.AllowedObjects.Contains(className)) + { + return BadRequest(); + } + int channelId = HeadlessChannelInfo.Provider.Get(headlessChannelId).HeadlessChannelChannelID; + var itemsData = ContentItemLanguageMetadataInfo.Provider.Get() + .Source(x => x.Join( + nameof(ContentItemLanguageMetadataInfo.ContentItemLanguageMetadataContentItemID), nameof(ContentItemInfo.ContentItemID))) + .Source(x => x.Join( + $"[CMS_ContentItemLanguageMetadata].{nameof(ContentItemLanguageMetadataInfo.ContentItemLanguageMetadataContentLanguageID)}", $"[CMS_ContentLanguage].{nameof(ContentLanguageInfo.ContentLanguageID)}")) + .Source(x => x.Join( + $"[CMS_ContentItem].{nameof(ContentItemInfo.ContentItemContentTypeID)}", $"[CMS_Class].{nameof(DataClassInfo.ClassID)}")) + .Source(x => x.Join( + $"[CMS_ContentItem].{nameof(ContentItemInfo.ContentItemID)}", $"[CMS_HeadlessItem].{nameof(HeadlessItemInfo.HeadlessItemContentItemID)}")) + .WhereEquals(nameof(ContentLanguageInfo.ContentLanguageName), languageName) + .WhereEquals(nameof(DataClassInfo.ClassName), className) + .WhereEquals(nameof(DataClassInfo.ClassContentTypeType), ClassContentTypeType.HEADLESS) + .WhereEquals(nameof(ContentItemInfo.ContentItemChannelID), channelId) + .Columns(nameof(ContentItemLanguageMetadataInfo.ContentItemLanguageMetadataDisplayName), nameof(HeadlessItemInfo.HeadlessItemID)) + .Result; + if (DataHelper.DataSourceIsEmpty(itemsData)) + { + return Array.Empty(); + } + return Ok(itemsData.Tables[0] + .AsEnumerable() + .Select(row => new + { + Id = row[nameof(HeadlessItemInfo.HeadlessItemID)], + Name = row[nameof(ContentItemLanguageMetadataInfo.ContentItemLanguageMetadataDisplayName)] + })); + } + + [HttpGet] + [Route($"zapier/actions/{ClassContentTypeType.WEBSITE}/{{className}}/{{websiteChannelId}}/{{languageName}}")] + public async Task>> GetWebPagesAsync(string className, int websiteChannelId, string languageName) + { + if (!zapierConfiguration.AllowedObjects.Contains(className)) + { + return BadRequest(); + } + string channelName = ChannelInfoProvider.ProviderObject.Get() + .Source(x => x.Join(nameof(ChannelInfo.ChannelID), nameof(WebsiteChannelInfo.WebsiteChannelChannelID))) + .WhereEquals(nameof(WebsiteChannelInfo.WebsiteChannelID), websiteChannelId) + .Column(nameof(ChannelInfo.ChannelName)) + .TopN(1) + .GetScalarResult(); + if (channelName == null) + { + return BadRequest(); + } + int languageId = await ContentLanguageInfoProvider.ProviderObject.Get() + .WhereEquals(nameof(ContentLanguageInfo.ContentLanguageName), languageName) + .Column(nameof(ContentLanguageInfo.ContentLanguageID)) + .GetScalarResultAsync(); + var builder = new ContentItemQueryBuilder() + .ForContentType(className, + c => c.ForWebsite(channelName) + .Where(x => x.WhereEquals(nameof(WebPageFields.ContentItemCommonDataContentLanguageID), languageId)) + .Columns(nameof(WebPageFields.WebPageUrlPath), + nameof(WebPageFields.WebPageItemName), + nameof(WebPageFields.WebPageItemID))); + var res = await contentQueryExecutor.GetWebPageResult(builder, resultSelector: rowData => + { + string Name = $"{rowData.WebPageItemName} ({rowData.WebPageUrlPath})"; + return new { Id = rowData.WebPageItemID, Name }; + }); + return Ok(res); + } + + [HttpGet] + [Route($"zapier/actions/{ClassContentTypeType.REUSABLE}/{{className}}/{{languageName}}")] + public ActionResult> GetReusableItems(string className, string languageName) + { + if (!zapierConfiguration.AllowedObjects.Contains(className)) + { + return BadRequest(); + } + var itemsData = ContentItemLanguageMetadataInfo.Provider.Get() + .Source(x => x.Join( + nameof(ContentItemLanguageMetadataInfo.ContentItemLanguageMetadataContentItemID), nameof(ContentItemInfo.ContentItemID))) + .Source(x => x.Join( + $"[CMS_ContentItemLanguageMetadata].{nameof(ContentItemLanguageMetadataInfo.ContentItemLanguageMetadataContentLanguageID)}", $"[CMS_ContentLanguage].{nameof(ContentLanguageInfo.ContentLanguageID)}")) + .Source(x => x.Join( + $"[CMS_ContentItem].{nameof(ContentItemInfo.ContentItemContentTypeID)}", $"[CMS_Class].{nameof(DataClassInfo.ClassID)}")) + .WhereEquals(nameof(ContentLanguageInfo.ContentLanguageName), languageName) + .WhereEquals(nameof(DataClassInfo.ClassName), className) + .WhereEquals(nameof(DataClassInfo.ClassContentTypeType), ClassContentTypeType.REUSABLE) + .Columns(nameof(ContentItemLanguageMetadataInfo.ContentItemLanguageMetadataDisplayName), nameof(ContentItemInfo.ContentItemID)) + .Result; + if (DataHelper.DataSourceIsEmpty(itemsData)) + { + return Array.Empty(); + } + return Ok(itemsData.Tables[0] + .AsEnumerable() + .Select(row => new + { + Id = row[nameof(ContentItemInfo.ContentItemID)], + Name = row[nameof(ContentItemLanguageMetadataInfo.ContentItemLanguageMetadataDisplayName)] + })); + } + + [HttpGet] + [Route($"zapier/actions/types/{ClassContentTypeType.REUSABLE}")] + public ActionResult> GetReusableTypes() => + GetTypes(ClassContentTypeType.REUSABLE); + + [HttpGet] + [Route($"zapier/actions/types/{ClassContentTypeType.WEBSITE}/{{websiteChannelId}}")] + public ActionResult> GetWebsiteTypes(int websiteChannelId) + { + int channelId = WebsiteChannelInfoProvider.ProviderObject.Get(websiteChannelId).WebsiteChannelChannelID; + return GetTypes(ClassContentTypeType.WEBSITE, channelId); + } + + [HttpGet] + [Route($"zapier/actions/types/{ClassContentTypeType.HEADLESS}/{{headlessChannelId}}")] + public ActionResult> GetHeadlessTypes(int headlessChannelId) + { + int channelId = HeadlessChannelInfo.Provider.Get(headlessChannelId).HeadlessChannelChannelID; + return GetTypes(ClassContentTypeType.HEADLESS, channelId); + } + + private ActionResult> GetTypes(string classContentTypeType, int? channelId = null) + { + var allowedObjects = zapierConfiguration.AllowedObjects.ToList(); + var query = DataClassInfoProvider.ProviderObject.Get(); + if (channelId != null) + { + query = query.Source(x => + x.Join( + nameof(DataClassInfo.ClassID), + nameof(ContentTypeChannelInfo.ContentTypeChannelContentTypeID)) + ) + .WhereEquals(nameof(ContentTypeChannelInfo.ContentTypeChannelChannelID), channelId); + } + var res = query + .WhereEquals(nameof(DataClassInfo.ClassContentTypeType), classContentTypeType) + .WhereIn(nameof(DataClassInfo.ClassName), allowedObjects) + .Columns(nameof(DataClassInfo.ClassDisplayName), nameof(DataClassInfo.ClassName)) + .OrderBy(nameof(DataClassInfo.ClassName)) + .Select(x => new { Id = x.ClassName, Name = x.ClassDisplayName }) + .ToList(); + return Ok(res); + } + + [HttpGet] + [Route("zapier/actions/languages")] + public ActionResult> GetLanguages() => + Ok(ContentLanguageInfoProvider.ProviderObject.Get() + .OrderBy(nameof(ContentLanguageInfo.ContentLanguageIsDefault)) + .Columns(nameof(ContentLanguageInfo.ContentLanguageName), + nameof(ContentLanguageInfo.ContentLanguageDisplayName)) + .Select(x => new { Id = x.ContentLanguageName, Name = x.ContentLanguageDisplayName }) + .ToList()); + + [HttpGet] + [Route("zapier/actions/types")] + public ActionResult> GetClassContentTypesTypes() + { + var res = new string[] { ClassContentTypeType.WEBSITE, ClassContentTypeType.REUSABLE, ClassContentTypeType.HEADLESS } + .Select(x => new { Id = x, Name = x }) + .ToList(); + return Ok(res); + } + + [HttpGet] + [Route($"zapier/actions/{ClassContentTypeType.WEBSITE}/channels")] + public ActionResult> GetWebsiteChannels() + { + var channelsData = WebsiteChannelInfoProvider.ProviderObject.Get() + .Source(x => + x.Join(nameof(WebsiteChannelInfo.WebsiteChannelChannelID), nameof(ChannelInfo.ChannelID))) + .Columns(nameof(WebsiteChannelInfo.WebsiteChannelID), nameof(ChannelInfo.ChannelDisplayName)) + .Result; + if (DataHelper.DataSourceIsEmpty(channelsData)) + { + return Array.Empty(); + } + return Ok(channelsData.Tables[0] + .AsEnumerable() + .Select(row => new + { + Id = row[nameof(WebsiteChannelInfo.WebsiteChannelID)], + Name = row[nameof(ChannelInfo.ChannelDisplayName)] + })); + } + + [HttpGet] + [Route($"zapier/actions/{ClassContentTypeType.HEADLESS}/channels")] + public ActionResult> GetHeadlessChannels() + { + var channelsData = HeadlessChannelInfo.Provider.Get() + .Source(x => + x.Join(nameof(HeadlessChannelInfo.HeadlessChannelChannelID), nameof(ChannelInfo.ChannelID))) + .Columns(nameof(HeadlessChannelInfo.HeadlessChannelID), nameof(ChannelInfo.ChannelDisplayName)) + .Result; + if (DataHelper.DataSourceIsEmpty(channelsData)) + { + return Array.Empty(); + } + return Ok(channelsData.Tables[0] + .AsEnumerable() + .Select(row => new + { + Id = row[nameof(HeadlessChannelInfo.HeadlessChannelID)], + Name = row[nameof(ChannelInfo.ChannelDisplayName)] + })); + } +} + diff --git a/src/Kentico.Xperience.Zapier/Admin/Providers/ZapierTriggerEventTypesDropdownOptionsProvider.cs b/src/Kentico.Xperience.Zapier/Admin/Providers/ZapierTriggerEventTypesDropdownOptionsProvider.cs index 8929948..ac1b236 100644 --- a/src/Kentico.Xperience.Zapier/Admin/Providers/ZapierTriggerEventTypesDropdownOptionsProvider.cs +++ b/src/Kentico.Xperience.Zapier/Admin/Providers/ZapierTriggerEventTypesDropdownOptionsProvider.cs @@ -5,24 +5,31 @@ namespace Kentico.Xperience.Zapier.Admin.Providers; internal class ZapierTriggerEventTypesDropdownOptionsProvider : IDropDownOptionsProvider { - public Task> GetOptionItems() => Task.FromResult>( -[ - new DropDownOptionItem - { - Value = nameof(ZapierTriggerEvents.Create), - Text = "Create" - }, - new DropDownOptionItem - { - Value = nameof(ZapierTriggerEvents.Update), - Text = "Update" - }, - new DropDownOptionItem + private readonly IWorkflowScopeService workflowScopeService; + + public ZapierTriggerEventTypesDropdownOptionsProvider(IWorkflowScopeService workflowScopeService) => this.workflowScopeService = workflowScopeService; + + public Task> GetOptionItems() { - Value = nameof(ZapierTriggerEvents.Delete), - Text = "Delete" + var dropDownOptions = new List() + { + new () { Value = nameof(ZapierTriggerEvents.Create), Text = "Create" }, + new () { Value = nameof(ZapierTriggerEvents.Update), Text = "Update" }, + new () { Value = nameof(ZapierTriggerEvents.Delete), Text = "Delete" } + }; + + var steps = workflowScopeService.GetAllSteps(); + + var items = steps.Select(s => new DropDownOptionItem + { + Value = s.ContentWorkflowStepName, + Text = $"{s.ContentWorkflowStepDisplayName} - workflow step" + }); + + dropDownOptions.AddRange(items); + + return Task.FromResult>(dropDownOptions); } -]); } @@ -35,5 +42,10 @@ internal class ZapierTriggerObjectTypesDropdownOptionsProvider : IDropDownOption internal class ZapierTriggerObjectTypesWhereConditionProvider : IObjectSelectorWhereConditionProvider { - public WhereCondition Get() => new WhereCondition().WhereNull(nameof(DataClassInfo.ClassContentTypeType)); + public WhereCondition Get() => new WhereCondition().Where(w => + w.WhereNull(nameof(DataClassInfo.ClassContentTypeType)) + .Or() + .WhereEquals(nameof(DataClassInfo.ClassContentTypeType), ClassContentTypeType.REUSABLE) + .Or() + .WhereEquals(nameof(DataClassInfo.ClassContentTypeType), ClassContentTypeType.WEBSITE)); } diff --git a/src/Kentico.Xperience.Zapier/Admin/UIPages/ZapierApiKeyListingPage.cs b/src/Kentico.Xperience.Zapier/Admin/UIPages/ZapierApiKeyListingPage.cs index ceca9dc..9e8b97d 100644 --- a/src/Kentico.Xperience.Zapier/Admin/UIPages/ZapierApiKeyListingPage.cs +++ b/src/Kentico.Xperience.Zapier/Admin/UIPages/ZapierApiKeyListingPage.cs @@ -1,6 +1,4 @@ - -using CMS.DataEngine.Internal; -using CMS.DataEngine; +using CMS.DataEngine; using CMS.Membership; using Kentico.Integration.Zapier; using Kentico.Xperience.Admin.Base; diff --git a/src/Kentico.Xperience.Zapier/Admin/UIPages/ZapierTriggerEditModel.cs b/src/Kentico.Xperience.Zapier/Admin/UIPages/ZapierTriggerEditModel.cs index 3ad35fc..23d4215 100644 --- a/src/Kentico.Xperience.Zapier/Admin/UIPages/ZapierTriggerEditModel.cs +++ b/src/Kentico.Xperience.Zapier/Admin/UIPages/ZapierTriggerEditModel.cs @@ -36,7 +36,7 @@ public void MapToZapierTriggerInfoObject(ZapierTriggerInfo infoObject) infoObject.ZapierTriggerObjectClassType = ZapierTriggerExtensions.GetType(objectType); infoObject.ZapierTriggerDisplayName = Name; - infoObject.ZapierTriggerCodeName = ValidationHelper.GetCodeName(Name); + infoObject.ZapierTriggerCodeName = ZapierTriggerExtensions.GetUniqueCodename(Name); infoObject.ZapierTriggerEnabled = Enabled; infoObject.ZapierTriggerEventType = EventType; infoObject.mZapierTriggerObjectType = objectType; @@ -63,7 +63,17 @@ public static string GetType(string objectType) return !string.IsNullOrEmpty(contentType) ? contentType : type; } + public static string GetUniqueCodename(string? name) + { + string codeName = ValidationHelper.GetCodeName(name); + + string guid = Guid.NewGuid().ToString(); + string? randString = guid.Split('-').FirstOrDefault(); + string uniqueCodeName = $"{codeName}-{randString}"; + + return uniqueCodeName; + } public static bool IsForm(this ZapierTriggerInfo info) => Enum.TryParse(info.ZapierTriggerObjectClassType, out ZapierTriggerObjectClassType type) && type == ZapierTriggerObjectClassType.Form; @@ -76,5 +86,6 @@ public enum ZapierTriggerObjectClassType System, Website, Reusable, + Headless, Email, } diff --git a/src/Kentico.Xperience.Zapier/ContentHelper.cs b/src/Kentico.Xperience.Zapier/ContentHelper.cs new file mode 100644 index 0000000..5cef539 --- /dev/null +++ b/src/Kentico.Xperience.Zapier/ContentHelper.cs @@ -0,0 +1,81 @@ +using CMS.ContentEngine; +using CMS.DataEngine; +using CMS.Websites; + +namespace Kentico.Xperience.Zapier; + + +public interface IContentHelper +{ + Task?> GetContentItemDataByGuid(Guid contentItemGuid, string contentTypeName); + + Task?> GetWebItemDataByGuid(Guid webItemGuid, string contentTypeName, string websiteChannelName); +} + + +public class ContentHelper : IContentHelper +{ + private readonly IContentQueryExecutor contentQueryExecutor; + + private readonly IContentQueryResultMapper contentQueryResultMapper; + private readonly IWebPageQueryResultMapper webPageQueryResultMapper; + + + public ContentHelper(IContentQueryExecutor contentQueryExecutor, IContentQueryResultMapper contentQueryResultMapper, IWebPageQueryResultMapper webPageQueryResultMapper) + { + this.contentQueryExecutor = contentQueryExecutor; + this.contentQueryResultMapper = contentQueryResultMapper; + this.webPageQueryResultMapper = webPageQueryResultMapper; + } + + public async Task?> GetContentItemDataByGuid(Guid contentItemGuid, string contentTypeName) + { + var builder = new ContentItemQueryBuilder() + .ForContentType(contentTypeName, + c => c.Where(w => w.WhereEquals(nameof(IContentQueryDataContainer.ContentItemGUID), contentItemGuid)).TopN(1)); + + var data = await contentQueryExecutor.GetResult(builder, contentQueryResultMapper.MapReusable, new ContentQueryExecutionOptions { ForPreview = true }); + + return data.FirstOrDefault(); + } + + public async Task?> GetWebItemDataByGuid(Guid webItemGuid, string contentTypeName, string websiteChannelName) + { + var builder = new ContentItemQueryBuilder() + .ForContentType(contentTypeName, + c => c.ForWebsite(websiteChannelName) + .Where(w => w.WhereEquals(nameof(IWebPageContentQueryDataContainer.WebPageItemGUID), webItemGuid)) + .TopN(1)); + + var data = await contentQueryExecutor.GetWebPageResult(builder, webPageQueryResultMapper.MapPages, new ContentQueryExecutionOptions { ForPreview = true }); + + + return data.FirstOrDefault(); + } + +} + + + +public static class MapperExtensions +{ + public static Dictionary MapReusable(this IContentQueryResultMapper _, IContentQueryDataContainer container) => GetProperties(container); + + public static Dictionary MapPages(this IWebPageQueryResultMapper _, IWebPageContentQueryDataContainer container) => GetProperties(container); + + private static Dictionary GetProperties(IContentQueryDataContainer container) + { + var obj = new Dictionary() { }; + + var classStructure = ClassStructureInfo.GetClassInfo(container.ContentTypeName); + + var forbiddenCols = new List { "ContentItemDataID", "ContentItemDataCommonDataID", "ContentItemDataGUID" }; + + foreach (string? col in classStructure.ColumnNames.Where(x => !forbiddenCols.Contains(x))) + { + obj[col] = container.GetValue(col); + } + obj.TryAdd("ContentTypeName", container.ContentTypeName); + return obj; + } +} diff --git a/src/Kentico.Xperience.Zapier/Extensions/ContentItemDataExtension.cs b/src/Kentico.Xperience.Zapier/Extensions/ContentItemDataExtension.cs new file mode 100644 index 0000000..ee64c79 --- /dev/null +++ b/src/Kentico.Xperience.Zapier/Extensions/ContentItemDataExtension.cs @@ -0,0 +1,37 @@ +using CMS.ContentEngine; +using CMS.DataEngine; + +namespace Kentico.Xperience.Zapier.Extensions; + + +public static class ContentItemDataExtension +{ + public delegate bool MyFunc(T1 a, out T2 b); + + public static readonly List ForbiddenCols = ["ContentItemDataID", "ContentItemDataCommonDataID", "ContentItemDataGUID"]; + + public static Dictionary GetDataForZapier(this ContentItemData contentItemData, string contentTypeName) => GetData(contentItemData.TryGetValue, contentTypeName); + + + public static Dictionary GetDataForZapier(this ContentItemDataEventContainer contentItemDataContainer, string contentTypeName) => GetData(contentItemDataContainer.TryGetValue, contentTypeName); + + public static Dictionary GetData(MyFunc tryGetMethod, string contentTypeName) + { + var obj = new Dictionary(); + + var classStructure = ClassStructureInfo.GetClassInfo(contentTypeName); + + foreach (string col in classStructure.ColumnNames.Where(x => !ForbiddenCols.Contains(x))) + { + if (tryGetMethod(col, out object value)) + { + obj[col] = value; + } + } + + obj.TryAdd("ContentTypeName", contentTypeName); + + return obj; + } + +} diff --git a/src/Kentico.Xperience.Zapier/Extensions/MapperExtension.cs b/src/Kentico.Xperience.Zapier/Extensions/MapperExtension.cs new file mode 100644 index 0000000..2a1b016 --- /dev/null +++ b/src/Kentico.Xperience.Zapier/Extensions/MapperExtension.cs @@ -0,0 +1,28 @@ + +using CMS.ContentEngine; +using CMS.DataEngine; +using CMS.Websites; + +namespace Kentico.Xperience.Zapier.Extensions; + +public static class MapperExtension +{ + public static Dictionary MapReusable(this IContentQueryResultMapper _, IContentQueryDataContainer container) => GetProperties(container); + + public static Dictionary MapPages(this IWebPageQueryResultMapper _, IWebPageContentQueryDataContainer container) => GetProperties(container); + + private static Dictionary GetProperties(IContentQueryDataContainer container) + { + var obj = new Dictionary() { }; + + var classStructure = ClassStructureInfo.GetClassInfo(container.ContentTypeName); + + var forbiddenCols = new List { "ContentItemDataID", "ContentItemDataCommonDataID", "ContentItemDataGUID" }; + + foreach (string? col in classStructure.ColumnNames.Where(x => !forbiddenCols.Contains(x))) + { + obj[col] = container.GetValue(col); + } + return obj; + } +} diff --git a/src/Kentico.Xperience.Zapier/Helper/ZapierDataHelper.cs b/src/Kentico.Xperience.Zapier/Helper/ZapierDataHelper.cs new file mode 100644 index 0000000..4736eb7 --- /dev/null +++ b/src/Kentico.Xperience.Zapier/Helper/ZapierDataHelper.cs @@ -0,0 +1,33 @@ + +using CMS.ContentWorkflowEngine; + +namespace Kentico.Xperience.Zapier.Helper; + +public static class ZapierDataHelper +{ + + public static Dictionary GetZapierWorkflowPostObject(this ContentItemWorkflowMoveToStepArguments a) => + CreateDictionary(a.DisplayName, a.ContentTypeName, a.StepName, a.OriginalStepName, a.UserID); + + + public static Dictionary GetZapierWorkflowPostObject(this WebPageWorkflowMoveToStepArguments w) => + CreateDictionary(w.DisplayName, w.ContentTypeName, w.StepName, w.OriginalStepName, w.UserID); + + public static Dictionary GetZapierWorkflowPostObject(this HeadlessItemWorkflowMoveToStepArguments w) => + CreateDictionary(w.DisplayName, w.ContentTypeName, w.StepName, w.OriginalStepName, w.UserID); + + private static Dictionary CreateDictionary(string displayName, string contentTypeName, string stepName, string originalStepName, int userID) + { + Dictionary result = []; + + result.TryAdd("DisplayName", displayName); + result.TryAdd("ContentTypeName", contentTypeName); + result.TryAdd("StepName", stepName); + result.TryAdd("OriginalStepName", originalStepName); + result.TryAdd("UserID", userID); + return result; + } + + + +} diff --git a/src/Kentico.Xperience.Zapier/WorkflowScopeService.cs b/src/Kentico.Xperience.Zapier/WorkflowScopeService.cs new file mode 100644 index 0000000..fb7751d --- /dev/null +++ b/src/Kentico.Xperience.Zapier/WorkflowScopeService.cs @@ -0,0 +1,75 @@ +using CMS.ContentWorkflowEngine; +using CMS.DataEngine; + +namespace Kentico.Xperience.Zapier; + +public interface IWorkflowScopeService +{ + List GetEventItemsByContentType(int contentTypeID); + bool IsMatchingWorflowEventPerObject(string workflowEvent, int contentTypeID); + IEnumerable GetAllSteps(); + IEnumerable GetStepsByContentTypeID(int contentTypeID); +} + + +public class WorkflowScopeService : IWorkflowScopeService +{ + private readonly IInfoProvider contentWorkflowContentTypeProvider; + private readonly IInfoProvider contentWorkflowStepProvider; + + public WorkflowScopeService( + IInfoProvider contentWorkflowContentTypeProvider, + IInfoProvider contentWorkflowStepProvider) + { + this.contentWorkflowContentTypeProvider = contentWorkflowContentTypeProvider; + this.contentWorkflowStepProvider = contentWorkflowStepProvider; + } + + public List GetEventItemsByContentType(int contentTypeID) + { + var stepInfos = GetStepsByContentTypeID(contentTypeID); + + var customSteps = stepInfos.Where(step => step.ContentWorkflowStepType == ContentWorkflowStepType.Custom).ToList(); + + return customSteps.Select(s => new EventItemDto(s.ContentWorkflowStepName, $"{s.ContentWorkflowStepDisplayName} - (Workflow step)")).ToList(); + } + + + + public bool IsMatchingWorflowEventPerObject(string workflowEvent, int contentTypeID) + { + var stepInfos = GetStepsByContentTypeID(contentTypeID); + + var matches = stepInfos.Where(s => s.ContentWorkflowStepName == workflowEvent).ToList(); + + return matches.Any(); + + } + + + public IEnumerable GetStepsByContentTypeID(int contentTypeID) + { + var contentTypeWorkflows = contentWorkflowContentTypeProvider.Get() + .WhereEquals("ContentWorkflowContentTypeContentTypeID", contentTypeID) + .GetEnumerableTypedResult(); + + var steps = contentWorkflowStepProvider.Get() + .WhereIn("ContentWorkflowStepWorkflowID", contentTypeWorkflows.Select(x => x.ContentWorkflowContentTypeContentWorkflowID).ToList()) + .GetEnumerableTypedResult(); + + return steps ?? []; + } + + public IEnumerable GetAllSteps() + { + var contentTypeWorkflows = contentWorkflowContentTypeProvider.Get() + .GetEnumerableTypedResult(); + + var steps = contentWorkflowStepProvider.Get() + .WhereIn("ContentWorkflowStepWorkflowID", contentTypeWorkflows.Select(x => x.ContentWorkflowContentTypeContentWorkflowID).ToList()) + .GetEnumerableTypedResult(); + + return steps ?? []; + } +} + diff --git a/src/Kentico.Xperience.Zapier/ZapierConfigurationController.cs b/src/Kentico.Xperience.Zapier/ZapierConfigurationController.cs index 9182d5d..0245474 100644 --- a/src/Kentico.Xperience.Zapier/ZapierConfigurationController.cs +++ b/src/Kentico.Xperience.Zapier/ZapierConfigurationController.cs @@ -3,8 +3,8 @@ using CMS.ContentEngine; using CMS.DataEngine; using CMS.DataEngine.Internal; -using CMS.Helpers; using CMS.OnlineForms; +using CMS.Websites; using CMS.Websites.Routing; using Kentico.Integration.Zapier; using Kentico.Xperience.Admin.Base; @@ -13,6 +13,8 @@ using Kentico.Xperience.Zapier.Resources; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using ActionResult = Microsoft.AspNetCore.Mvc.ActionResult; namespace Kentico.Xperience.Zapier; @@ -24,21 +26,46 @@ public class ZapierConfigurationController : ControllerBase private readonly IZapierTriggerInfoProvider zapierTriggerInfoProvider; private readonly IWebsiteChannelContext websiteChannelContext; + private readonly ZapierConfiguration zapierConfiguration; + + private readonly IWorkflowScopeService workflowScopeService; + private readonly IContentQueryExecutor contentQueryExecutor; - private readonly IContentQueryResultMapper mapper; - public static readonly List EnabledEvents = [ZapierTriggerEvents.Create, ZapierTriggerEvents.Update, ZapierTriggerEvents.Delete]; + private readonly IContentQueryResultMapper contentQueryResultMapper; + private readonly IWebPageQueryResultMapper webPageQueryResultMapper; + + public static readonly Dictionary WorkflowEvents = new() + { + { "DisplayName", "Content item name" }, + { "ContentTypeName", "ContentType.Type" }, + { "StepName", "Step name" }, + { "OriginalStepName", "Original step name" }, + { "UserID", 132 }, + { "AdminLink", "https://xperienceTestApp.com/admin/#item#"} + }; + + public static readonly List InfoEvents = [ZapierTriggerEvents.Create, ZapierTriggerEvents.Update, ZapierTriggerEvents.Delete]; + + public static readonly List ContentItemEvents = [ZapierTriggerEvents.Create, ZapierTriggerEvents.Update, ZapierTriggerEvents.Delete, ZapierTriggerEvents.Publish]; + public ZapierConfigurationController( IZapierTriggerInfoProvider zapierTriggerInfoProvider, IWebsiteChannelContext websiteChannelContext, + IWorkflowScopeService workflowScopeService, IContentQueryExecutor contentQueryExecutor, - IContentQueryResultMapper mapper) + IOptionsMonitor zapierConfiguration, + IContentQueryResultMapper contentQueryResultMapper, + IWebPageQueryResultMapper webPageQueryResultMapper) { this.zapierTriggerInfoProvider = zapierTriggerInfoProvider; this.websiteChannelContext = websiteChannelContext; + this.workflowScopeService = workflowScopeService; this.contentQueryExecutor = contentQueryExecutor; - this.mapper = mapper; + this.zapierConfiguration = zapierConfiguration.CurrentValue; + this.contentQueryResultMapper = contentQueryResultMapper; + this.webPageQueryResultMapper = webPageQueryResultMapper; } [HttpGet] @@ -47,53 +74,116 @@ public ZapierConfigurationController( [HttpGet] [Route("zapier/data/events")] - public ActionResult> Events() => EnabledEvents.Select(e => new EventItemDto((int)e, e.ToString())).ToList(); + public ActionResult> Events() => InfoEvents.Select(e => new EventItemDtoOld((int)e, e.ToString())).ToList(); + + + [HttpGet] + [Route("zapier/data/events/{objectType}")] + public async Task>> EventsByType(string objectType) + { + var dataClass = DataClassInfoProvider.ProviderObject.Get(objectType); + + if (dataClass.IsContentType()) + { + List typesAllowingEvents = [ClassContentTypeType.WEBSITE, ClassContentTypeType.REUSABLE, ClassContentTypeType.HEADLESS]; + + if (!typesAllowingEvents.Contains(dataClass.ClassContentTypeType)) + { + return new List(); + } + + int contentTypeID = dataClass.ClassID; + var events = ContentItemEvents.Select(e => new EventItemDto(e.ToString(), e.ToString())).ToList(); + + var workflowSteps = workflowScopeService.GetEventItemsByContentType(contentTypeID); + + events.AddRange(workflowSteps); + + return events; + } + + return InfoEvents.Select(e => new EventItemDto(e.ToString(), e.ToString())).ToList(); + } + [HttpGet] [Route("zapier/data/objects")] public ActionResult> Objects() { + var allowedObjects = zapierConfiguration.AllowedObjects.ToList(); + var infoObjects = DataClassInfoProvider.ProviderObject.Get() - .WhereNull(nameof(DataClassInfo.ClassContentTypeType)) - .Columns(nameof(DataClassInfo.ClassDisplayName), nameof(DataClassInfo.ClassName)) + .WhereIn(nameof(DataClassInfo.ClassName), allowedObjects) + .WhereNotEquals(nameof(DataClassInfo.ClassContentTypeType), ClassContentTypeType.EMAIL) + .Columns(nameof(DataClassInfo.ClassDisplayName), nameof(DataClassInfo.ClassName), nameof(DataClassInfo.ClassType), nameof(DataClassInfo.ClassContentTypeType)) .OrderBy(nameof(DataClassInfo.ClassName)) .GetEnumerableTypedResult(); - return infoObjects.Select(x => new KenticoInfoDto(x.ClassName, x.ClassDisplayName)).ToList(); + return infoObjects.Select(x => new KenticoInfoDto(x.ClassName, $"{x.ClassDisplayName} ({x.ClassType}{(!string.IsNullOrEmpty(x.ClassContentTypeType) ? $" - {x.ClassContentTypeType}" : string.Empty)})")) + .ToList(); } [HttpGet] - [Route("zapier/object/{objectType}")] - public ActionResult GetSampleObject(string objectType) + [Route("zapier/object/{objectType}/{eventType}")] + public async Task GetSampleObject(string objectType, string eventType) { var dataClass = DataClassInfoProvider.ProviderObject.Get(objectType); - //nebo switch + if (dataClass.ClassContentTypeType == ClassContentTypeType.EMAIL) + { + return BadRequest(); + } + + if (!Enum.TryParse(eventType, out ZapierTriggerEvents eventTypeEnum)) + { + bool isValid = workflowScopeService.IsMatchingWorflowEventPerObject(eventType, dataClass.ClassID); + + return isValid ? Ok(WorkflowEvents) : BadRequest(); + } + if (dataClass.IsContentType()) { - //todo - //IReusableContentItemReferenceProvider + var result = new Dictionary(); + + if (dataClass.ClassContentTypeType is ClassContentTypeType.REUSABLE or + ClassContentTypeType.HEADLESS) + { + var builder = new ContentItemQueryBuilder().ForContentType(objectType, + config => config + .WithLinkedItems(1) + .TopN(1)); + var reus = await contentQueryExecutor.GetResult(builder, contentQueryResultMapper.MapReusable); + result = reus.FirstOrDefault(); + } - //var builder = new ContentItemQueryBuilder().ForContentType(objectType, - // config => config - // .WithLinkedItems(1) - // .TopN(1)); - //var result = await contentQueryExecutor.GetResult(builder,); + if (dataClass.ClassContentTypeType == ClassContentTypeType.WEBSITE) + { + var builder = new ContentItemQueryBuilder().ForContentType(objectType, + config => config + .WithLinkedItems(1) + .ForWebsite(websiteChannelContext.WebsiteChannelName ?? string.Empty) + .TopN(1)); + var pages = await contentQueryExecutor.GetWebPageResult(builder, webPageQueryResultMapper.MapPages); + result = pages.FirstOrDefault(); + } - return NotFound(); + return Ok(result ?? GetSampleContentItem(objectType)); } if (dataClass.IsForm()) { + var actualForm = GetDataFromForm(objectType); + var objectTypeInfo = BizFormItemProvider.GetTypeInfo(objectType); - return Ok(GetDataFromObjectTypeInfo(objectTypeInfo)); + return Ok(actualForm ?? GetSampleDataFromObjectTypeInfo(objectTypeInfo)); } - var typeInfo = ObjectTypeManager.GetTypeInfo(objectType); - return Ok(GetDataFromObjectTypeInfo(typeInfo)); + var actualInfo = GetDataFromInfoObject(objectType); + var typeInfo = ObjectTypeManager.GetTypeInfo(objectType); + return Ok(actualInfo ?? GetSampleDataFromObjectTypeInfo(typeInfo)); } @@ -102,13 +192,14 @@ public ActionResult GetSampleObject(string objectType) [Route("zapier/trigger")] public ActionResult CreateTrigger(TriggerDto newTrigger) { + var infoObject = new ZapierTriggerInfo { ZapierTriggerDisplayName = newTrigger.Name, - ZapierTriggerCodeName = ValidationHelper.GetCodeName(newTrigger.Name), + ZapierTriggerCodeName = ZapierTriggerExtensions.GetUniqueCodename(newTrigger.Name), ZapierTriggerObjectClassType = ZapierTriggerExtensions.GetType(newTrigger.ObjectType), ZapierTriggerEnabled = true, - ZapierTriggerEventType = ((ZapierTriggerEvents)newTrigger.EventType).ToString(), + ZapierTriggerEventType = newTrigger.EventType, mZapierTriggerObjectType = newTrigger.ObjectType, ZapierTriggerZapierURL = newTrigger.ZapierUrl }; @@ -138,9 +229,25 @@ public IActionResult DeleteTrigger(string zapId) return Ok(new { Status = ZapInfoToDelete != null ? "Success" : $"Info object with provided id {zapierTriggerID} does not exist" }); } + private Dictionary GetSampleContentItem(string objectType) + { + var result = new Dictionary(); + var classStructure = ClassStructureInfo.GetClassInfo(objectType); + var defs = classStructure.ColumnDefinitions; - private Dictionary GetDataFromObjectTypeInfo(ObjectTypeInfo objectTypeInfo) + var forbiddenCols = new List { "ContentItemDataID", "ContentItemDataCommonDataID", "ContentItemDataGUID" }; + + foreach (var colDef in defs.Where(x => !forbiddenCols.Contains(x.ColumnName))) + { + result[colDef.ColumnName] = GetDefaultValue(colDef.ColumnType); + } + + result.TryAdd("ContentTypeName", objectType); + return result; + } + + private Dictionary GetSampleDataFromObjectTypeInfo(ObjectTypeInfo objectTypeInfo) { var result = new Dictionary(); @@ -174,9 +281,10 @@ private object GetDefaultValue(Type t) return Activator.CreateInstance(t)!; } + //serialized strings if (t == typeof(string)) { - return "text"; + return "text or serialized content"; } if (t.IsAssignableTo(typeof(IEnumerable))) @@ -187,10 +295,69 @@ private object GetDefaultValue(Type t) return new object(); } -} -public record EventItemDto(int Id, string Name); + + private Dictionary? GetDataFromInfoObject(string objectType) + { + var generalizedInfo = (GeneralizedInfo)ModuleManager.GetObject(objectType); + var type = ObjectTypeManager.GetTypeInfo(objectType); + + if (generalizedInfo == null || type == null) + { + return null; + } + + var result = generalizedInfo.GetDataQuery(true, s => s.TopN(1)); + + var dataSet = result.Result; + + var dataTable = dataSet.Tables[0]; + + type?.SensitiveColumns? + .ForEach(colName => dataSet.Tables[0].Columns.Remove(colName)); + + var columns = dataTable.Columns.OfType(); + + var data = dataTable.Rows.OfType().Select(r => columns.ToDictionary(c => c.ColumnName, c => r[c])); + + return data.FirstOrDefault(); + } + + + private Dictionary? GetDataFromForm(string objectType) + { + var formData = BizFormItemProvider.GetItems(objectType).TopN(1).GetEnumerableTypedResult(); + + if (formData is null || !formData.Any()) + { + return null; + } + + var cols = formData.FirstOrDefault()?.ColumnNames; + + if (cols is null) + { + return null; + } + + var result = new Dictionary(); + + foreach (string? col in cols) + { + result[col] = formData.First().GetValue(col); + } + return result; + } +} + +public record EventItemDto(string Id, string Name); public record KenticoInfoDto(string Id, string Name); +public record TriggerDto(string Name, string ObjectType, string EventType, string ZapierUrl); + + + + +public record EventItemDtoOld(int Id, string Name); +public record TriggerDtoOld(string Name, string ObjectType, int EventType, string ZapierUrl); -public record TriggerDto(string Name, string ObjectType, int EventType, string ZapierUrl); diff --git a/src/Kentico.Xperience.Zapier/ZapierRegistrationService.cs b/src/Kentico.Xperience.Zapier/ZapierRegistrationService.cs index 6b57cdd..7fcc208 100644 --- a/src/Kentico.Xperience.Zapier/ZapierRegistrationService.cs +++ b/src/Kentico.Xperience.Zapier/ZapierRegistrationService.cs @@ -1,6 +1,9 @@ using System.Collections.Concurrent; +using CMS.ContentEngine; using CMS.Core; +using CMS.DataEngine; using Kentico.Integration.Zapier; +using Microsoft.Extensions.Options; namespace Kentico.Xperience.Zapier; @@ -15,18 +18,27 @@ public class ZapierRegistrationService : IZapierRegistrationService { private readonly IEventLogService logService; private readonly HttpClient client; + private readonly IWorkflowScopeService workflowScopeService; + private readonly IContentHelper contentHelper; + private readonly IOptionsMonitor options; + private readonly IInfoProvider contentLanguageProvider; + protected ConcurrentDictionary ZapierHandlers = []; - public ZapierRegistrationService(IEventLogService logService, HttpClient client) + public ZapierRegistrationService(IEventLogService logService, HttpClient client, IWorkflowScopeService workflowScopeService, IContentHelper contentHelper, IOptionsMonitor options, IInfoProvider contentLanguageProvider) { this.logService = logService; this.client = client; + this.workflowScopeService = workflowScopeService; + this.contentHelper = contentHelper; + this.options = options; + this.contentLanguageProvider = contentLanguageProvider; } public void RegisterWebhook(ZapierTriggerInfo webhook) { - var handler = new ZapierTriggerHandler(webhook, client, logService); + var handler = new ZapierTriggerHandler(webhook, client, logService, workflowScopeService, contentHelper, options.CurrentValue, contentLanguageProvider); if (!ZapierHandlers.TryAdd(webhook.ZapierTriggerID, handler)) { diff --git a/src/Kentico.Xperience.Zapier/ZapierServiceCollectionExtensions.cs b/src/Kentico.Xperience.Zapier/ZapierServiceCollectionExtensions.cs index af2b231..0cfadb6 100644 --- a/src/Kentico.Xperience.Zapier/ZapierServiceCollectionExtensions.cs +++ b/src/Kentico.Xperience.Zapier/ZapierServiceCollectionExtensions.cs @@ -13,10 +13,14 @@ public static class ZapierServiceCollectionExtensions { public static IServiceCollection AddKenticoZapier(this IServiceCollection services) { + services.AddOptions().BindConfiguration("ZapierConfiguration"); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddAuthentication() .AddApiKeyInAuthorizationHeader(ZapierConstants.AuthenticationScheme.XbyKZapierApiKeyScheme, options => { @@ -57,3 +61,11 @@ public static IServiceCollection AddKenticoZapier(this IServiceCollection servic } } + + +public class ZapierConfiguration +{ + public string? WebAdminDomain { get; set; } + public HashSet AllowedObjects { get; set; } = []; +} + diff --git a/src/Kentico.Xperience.Zapier/ZapierTriggerEvents.cs b/src/Kentico.Xperience.Zapier/ZapierTriggerEvents.cs index 0aea23b..ef7911e 100644 --- a/src/Kentico.Xperience.Zapier/ZapierTriggerEvents.cs +++ b/src/Kentico.Xperience.Zapier/ZapierTriggerEvents.cs @@ -6,4 +6,5 @@ public enum ZapierTriggerEvents Create, Update, Delete, + Publish } diff --git a/src/Kentico.Xperience.Zapier/ZapierTriggerHandler.cs b/src/Kentico.Xperience.Zapier/ZapierTriggerHandler.cs index 10136fb..221a01a 100644 --- a/src/Kentico.Xperience.Zapier/ZapierTriggerHandler.cs +++ b/src/Kentico.Xperience.Zapier/ZapierTriggerHandler.cs @@ -1,12 +1,18 @@ using System.Net; using System.Net.Http.Json; +using CMS.ContentEngine; +using CMS.ContentWorkflowEngine; using CMS.Core; using CMS.DataEngine; +using CMS.Headless; using CMS.Helpers; using CMS.OnlineForms; +using CMS.Websites; using Kentico.Integration.Zapier; using Kentico.Xperience.Zapier.Admin; using Kentico.Xperience.Zapier.Admin.UIPages; +using Kentico.Xperience.Zapier.Extensions; +using Kentico.Xperience.Zapier.Helper; namespace Kentico.Xperience.Zapier; @@ -15,15 +21,24 @@ public class ZapierTriggerHandler private readonly IEventLogService? eventLogService; private readonly HttpClient client; + private readonly IWorkflowScopeService workflowScopeService; + private readonly IContentHelper contentHelper; + private readonly IInfoProvider contentLanguageProvider; + + public ZapierConfiguration ZapierConfiguration { get; set; } public ZapierTriggerInfo ZapierTrigger { get; set; } - public ZapierTriggerHandler(ZapierTriggerInfo zapInfo, HttpClient httpClient, IEventLogService eventLogService) + public ZapierTriggerHandler(ZapierTriggerInfo zapInfo, HttpClient httpClient, IEventLogService eventLogService, IWorkflowScopeService workflowScopeService, IContentHelper contentHelper, ZapierConfiguration zapierConfiguration, IInfoProvider contentLanguageProvider) { ZapierTrigger = zapInfo; client = httpClient; this.eventLogService = eventLogService; + this.workflowScopeService = workflowScopeService; + this.contentHelper = contentHelper; + ZapierConfiguration = zapierConfiguration; + this.contentLanguageProvider = contentLanguageProvider; } public bool Register() => RegistrationProcessor(); @@ -34,14 +49,35 @@ private bool RegistrationProcessor(bool toRegister = true) { if (ZapierTrigger != null) { - if (!Enum.TryParse(ZapierTrigger.ZapierTriggerEventType, out ZapierTriggerEvents eventType)) + if (!Enum.TryParse(ZapierTrigger.ZapierTriggerObjectClassType, out ZapierTriggerObjectClassType classType)) { return false; } - if (!Enum.TryParse(ZapierTrigger.ZapierTriggerObjectClassType, out ZapierTriggerObjectClassType classType)) + if (!Enum.TryParse(ZapierTrigger.ZapierTriggerEventType, out ZapierTriggerEvents eventType)) { - return false; + var dataClass = DataClassInfoProvider.ProviderObject.Get(ZapierTrigger.mZapierTriggerObjectType); + if (dataClass is null || string.IsNullOrEmpty(ZapierTrigger.ZapierTriggerEventType)) + { + return false; + } + + bool isWorkflow = workflowScopeService.IsMatchingWorflowEventPerObject(ZapierTrigger.ZapierTriggerEventType, dataClass.ClassID); + + if (!isWorkflow) + { + return false; + } + + bool workflowResult = classType switch + { + ZapierTriggerObjectClassType.Website => RegisterWorkflowPages(ZapierTrigger.ZapierTriggerEventType, toRegister), + ZapierTriggerObjectClassType.Reusable => RegisterWorkflowReusable(ZapierTrigger.ZapierTriggerEventType, toRegister), + ZapierTriggerObjectClassType.Headless => RegisterWorkflowHeadless(ZapierTrigger.ZapierTriggerEventType, toRegister), + _ => throw new NotImplementedException() + }; + + return workflowResult; } bool result = classType switch @@ -49,8 +85,9 @@ private bool RegistrationProcessor(bool toRegister = true) ZapierTriggerObjectClassType.Other => RegisterInfoObject(eventType, toRegister), ZapierTriggerObjectClassType.System => RegisterInfoObject(eventType, toRegister), ZapierTriggerObjectClassType.Form => RegisterForm(eventType, toRegister), - ZapierTriggerObjectClassType.Website => throw new NotImplementedException(), - ZapierTriggerObjectClassType.Reusable => throw new NotImplementedException(), + ZapierTriggerObjectClassType.Website => RegisterPages(eventType, toRegister), + ZapierTriggerObjectClassType.Reusable => RegisterReusable(eventType, toRegister), + ZapierTriggerObjectClassType.Headless => RegisterHeadless(eventType, toRegister), ZapierTriggerObjectClassType.Email => throw new NotImplementedException(), _ => throw new NotImplementedException() }; @@ -150,6 +187,359 @@ private bool RegisterForm(ZapierTriggerEvents eventType, bool register) return true; } + private bool RegisterReusable(ZapierTriggerEvents eventType, bool register) + { + switch (eventType) + { + case ZapierTriggerEvents.Create: + + if (register) + { + ContentItemEvents.Create.After += ReusableCreateHandler; + } + else + { + ContentItemEvents.Create.After -= ReusableCreateHandler; + } + + break; + + case ZapierTriggerEvents.Update: + + if (register) + { + ContentItemEvents.UpdateDraft.After += ReusableUpdateHandler; + } + else + { + ContentItemEvents.UpdateDraft.After -= ReusableUpdateHandler; + } + + break; + case ZapierTriggerEvents.Delete: + + if (register) + { + ContentItemEvents.Delete.Execute += ReusableDeleteHandler; + } + else + { + ContentItemEvents.Delete.Execute -= ReusableDeleteHandler; + } + break; + case ZapierTriggerEvents.Publish: + + if (register) + { + ContentItemEvents.Publish.Execute += ReusablePublishHandler; + } + else + { + ContentItemEvents.Publish.Execute -= ReusablePublishHandler; + } + break; + default: + eventLogService.LogEvent(EventTypeEnum.Error, nameof(ZapierTriggerHandler), $"{(register ? "REGISTER" : "UNREGISTER")}", $"Action for reusable handler '{ZapierTrigger.ZapierTriggerDisplayName}' to {ZapierTrigger.mZapierTriggerObjectType} for event {eventType} was not successful."); + return false; + + } + + eventLogService.LogEvent(EventTypeEnum.Information, nameof(ZapierTriggerHandler), $"{(register ? "REGISTER" : "UNREGISTER")}", $"Action for reusable handler '{ZapierTrigger.ZapierTriggerDisplayName}' to {ZapierTrigger.mZapierTriggerObjectType} for event {eventType} was successful."); + return true; + } + + private bool RegisterWorkflowPages(string eventType, bool register) + { + if (register) + { + WebPageWorkflowEvents.MoveToStep.Execute += WorkflowPagesHandler; + } + else + { + WebPageWorkflowEvents.MoveToStep.Execute -= WorkflowPagesHandler; + } + + eventLogService.LogEvent(EventTypeEnum.Information, nameof(ZapierTriggerHandler), $"{(register ? "REGISTER" : "UNREGISTER")}", $"Action for pages workflow handler '{ZapierTrigger.ZapierTriggerDisplayName}' to {ZapierTrigger.mZapierTriggerObjectType} for event {eventType} was successful."); + return true; + } + + + private bool RegisterWorkflowReusable(string eventType, bool register) + { + if (register) + { + ContentItemWorkflowEvents.MoveToStep.Execute += WorkflowReusableHandler; + } + else + { + ContentItemWorkflowEvents.MoveToStep.Execute -= WorkflowReusableHandler; + } + + eventLogService.LogEvent(EventTypeEnum.Information, nameof(ZapierTriggerHandler), $"{(register ? "REGISTER" : "UNREGISTER")}", $"Action for reusable workflow handler '{ZapierTrigger.ZapierTriggerDisplayName}' to {ZapierTrigger.mZapierTriggerObjectType} for event {eventType} was successful."); + return true; + } + + private bool RegisterWorkflowHeadless(string eventType, bool register) + { + if (register) + { + HeadlessItemWorkflowEvents.MoveToStep.Execute += WorkflowHeadlessHandler; + } + else + { + HeadlessItemWorkflowEvents.MoveToStep.Execute -= WorkflowHeadlessHandler; + } + + eventLogService.LogEvent(EventTypeEnum.Information, nameof(ZapierTriggerHandler), $"{(register ? "REGISTER" : "UNREGISTER")}", $"Action for headless workflow handler '{ZapierTrigger.ZapierTriggerDisplayName}' to {ZapierTrigger.mZapierTriggerObjectType} for event {eventType} was successful."); + return true; + } + + private bool RegisterPages(ZapierTriggerEvents eventType, bool register) + { + switch (eventType) + { + case ZapierTriggerEvents.Create: + + if (register) + { + WebPageEvents.Create.After += PagesCreateHandler; + } + else + { + WebPageEvents.Create.After -= PagesCreateHandler; + } + + break; + + case ZapierTriggerEvents.Update: + + if (register) + { + WebPageEvents.UpdateDraft.After += PagesUpdateHandler; + } + else + { + WebPageEvents.UpdateDraft.After -= PagesUpdateHandler; + } + + break; + case ZapierTriggerEvents.Delete: + + if (register) + { + WebPageEvents.Delete.Execute += PagesDeleteHandler; + } + else + { + WebPageEvents.Delete.Execute -= PagesDeleteHandler; + } + break; + case ZapierTriggerEvents.Publish: + + if (register) + { + WebPageEvents.Publish.Execute += PagesPublishHandler; + } + else + { + WebPageEvents.Publish.Execute -= PagesPublishHandler; + } + break; + default: + eventLogService.LogEvent(EventTypeEnum.Error, nameof(ZapierTriggerHandler), $"{(register ? "REGISTER" : "UNREGISTER")}", $"Action for pages handler '{ZapierTrigger.ZapierTriggerDisplayName}' to {ZapierTrigger.mZapierTriggerObjectType} for event {eventType} was not successful."); + return false; + + } + + eventLogService.LogEvent(EventTypeEnum.Information, nameof(ZapierTriggerHandler), $"{(register ? "REGISTER" : "UNREGISTER")}", $"Action for pages handler '{ZapierTrigger.ZapierTriggerDisplayName}' to {ZapierTrigger.mZapierTriggerObjectType} for event {eventType} was successful."); + return true; + } + + private bool RegisterHeadless(ZapierTriggerEvents eventType, bool register) + { + switch (eventType) + { + case ZapierTriggerEvents.Create: + + if (register) + { + HeadlessItemEvents.Create.After += HeadlessCreateHandler; + } + else + { + HeadlessItemEvents.Create.After -= HeadlessCreateHandler; + } + + break; + + case ZapierTriggerEvents.Update: + + if (register) + { + HeadlessItemEvents.UpdateDraft.After += HeadlessUpdateHandler; + } + else + { + HeadlessItemEvents.UpdateDraft.After -= HeadlessUpdateHandler; + } + + break; + case ZapierTriggerEvents.Delete: + + if (register) + { + HeadlessItemEvents.Delete.Execute += HeadlessDeleteHandler; + } + else + { + HeadlessItemEvents.Delete.Execute -= HeadlessDeleteHandler; + } + break; + case ZapierTriggerEvents.Publish: + + if (register) + { + HeadlessItemEvents.Publish.Execute += HeadlessPublishHandler; + } + else + { + HeadlessItemEvents.Publish.Execute -= HeadlessPublishHandler; + } + break; + default: + eventLogService.LogEvent(EventTypeEnum.Error, nameof(ZapierTriggerHandler), $"{(register ? "REGISTER" : "UNREGISTER")}", $"Action for headless handler '{ZapierTrigger.ZapierTriggerDisplayName}' to {ZapierTrigger.mZapierTriggerObjectType} for event {eventType} was not successful."); + return false; + } + + eventLogService.LogEvent(EventTypeEnum.Information, nameof(ZapierTriggerHandler), $"{(register ? "REGISTER" : "UNREGISTER")}", $"Action for headless handler '{ZapierTrigger.ZapierTriggerDisplayName}' to {ZapierTrigger.mZapierTriggerObjectType} for event {eventType} was successful."); + return true; + } + + #region PagesHandlers + + private void PagesCreateHandler(object? sender, CreateWebPageEventArgs e) => ContentItemsHandler(e.ContentItemData.GetDataForZapier, e.ContentTypeName); + + private void PagesUpdateHandler(object? sender, UpdateWebPageDraftEventArgs e) => ContentItemsHandler(e.ContentItemData.GetDataForZapier, e.ContentTypeName); + + private void PagesDeleteHandler(object? sender, DeleteWebPageEventArgs e) => ContentItemsHandler(e.ContentItemData.GetDataForZapier, e.ContentTypeName); + + private void PagesPublishHandler(object? sender, PublishWebPageEventArgs e) => ContentItemsHandler(e.ContentItemData.GetDataForZapier, e.ContentTypeName); + #endregion + + #region ReusableHandlers + private void ReusableDeleteHandler(object? sender, DeleteContentItemEventArgs e) => ContentItemsHandler(e.ContentItemData.GetDataForZapier, e.ContentTypeName); + + private void ReusableUpdateHandler(object? sender, UpdateContentItemDraftEventArgs e) => ContentItemsHandler(e.ContentItemData.GetDataForZapier, e.ContentTypeName); + + private void ReusableCreateHandler(object? sender, CreateContentItemEventArgs e) => ContentItemsHandler(e.ContentItemData.GetDataForZapier, e.ContentTypeName); + + private void ReusablePublishHandler(object? sender, PublishContentItemEventArgs e) => ContentItemsHandler(e.ContentItemData.GetDataForZapier, e.ContentTypeName); + + #endregion + + #region HeadlessHandlers + private void HeadlessDeleteHandler(object? sender, DeleteHeadlessItemEventArgs e) => ContentItemsHandler(e.ContentItemData.GetDataForZapier, e.ContentTypeName); + private void HeadlessUpdateHandler(object? sender, UpdateHeadlessItemDraftEventArgs e) => ContentItemsHandler(e.ContentItemData.GetDataForZapier, e.ContentTypeName); + private void HeadlessCreateHandler(object? sender, CreateHeadlessItemEventArgs e) => ContentItemsHandler(e.ContentItemData.GetDataForZapier, e.ContentTypeName); + private void HeadlessPublishHandler(object? sender, PublishHeadlessItemEventArgs e) => ContentItemsHandler(e.ContentItemData.GetDataForZapier, e.ContentTypeName); + #endregion + + #region WorkflowHandlers + + private void WorkflowReusableHandler(object? sender, ContentItemWorkflowMoveToStepArguments e) + { + if (!ZapierTrigger.mZapierTriggerObjectType.Equals(e.ContentTypeName, StringComparison.OrdinalIgnoreCase)) + { + return; + } + + if (ZapierTrigger.ZapierTriggerEventType != e.StepName) + { + return; + } + + var data = e.GetZapierWorkflowPostObject(); + + var info = contentLanguageProvider.Get(e.ContentLanguageID); + + var websiteUri = new Uri($"https://{ZapierConfiguration.WebAdminDomain}"); + var adminUrl = new Uri(websiteUri, $"/admin/content-hub/{info.ContentLanguageName}/list/{e.ID}"); + + data.TryAdd("AdminLink", adminUrl); + + + if (ZapierTrigger != null) + { + _ = DoPost(ZapierTrigger.ZapierTriggerZapierURL, data); + } + } + + private void WorkflowPagesHandler(object? sender, WebPageWorkflowMoveToStepArguments e) + { + if (!ZapierTrigger.mZapierTriggerObjectType.Equals(e.ContentTypeName, StringComparison.OrdinalIgnoreCase)) + { + return; + } + + if (ZapierTrigger.ZapierTriggerEventType != e.StepName) + { + return; + } + + + var data = e.GetZapierWorkflowPostObject(); + var websiteUri = new Uri($"https://{ZapierConfiguration.WebAdminDomain}"); + var adminUrl = new Uri(websiteUri, $"/admin/webpages-{e.WebsiteChannelID}/{e.ContentLanguageName}_{e.ID}"); + + data.TryAdd("AdminLink", adminUrl); + + + if (ZapierTrigger != null) + { + _ = DoPost(ZapierTrigger.ZapierTriggerZapierURL, data); + } + } + + private void WorkflowHeadlessHandler(object? sender, HeadlessItemWorkflowMoveToStepArguments e) + { + if (!ZapierTrigger.mZapierTriggerObjectType.Equals(e.ContentTypeName, StringComparison.OrdinalIgnoreCase)) + { + return; + } + + if (ZapierTrigger.ZapierTriggerEventType != e.StepName) + { + return; + } + + var data = e.GetZapierWorkflowPostObject(); + var websiteUri = new Uri($"https://{ZapierConfiguration.WebAdminDomain}"); + var adminUrl = new Uri(websiteUri, $"/admin/headless-{e.HeadlessChannelID}/{e.ContentLanguageName}/list/{e.ID}"); + data.TryAdd("AdminLink", adminUrl); + + if (ZapierTrigger != null) + { + _ = DoPost(ZapierTrigger.ZapierTriggerZapierURL, data); + } + } + + + #endregion + + private void ContentItemsHandler(Func?> dataCaller, string contentTypeName) + { + if (!ZapierTrigger.mZapierTriggerObjectType.Equals(contentTypeName, StringComparison.OrdinalIgnoreCase)) + { + return; + } + + var data = dataCaller(contentTypeName); + + if (ZapierTrigger != null && data != null) + { + _ = DoPost(ZapierTrigger.ZapierTriggerZapierURL, data); + } + } private void ObjectInfoHandler(object? sender, ObjectEventArgs e) => Handler(e.Object); private void FormHandler(object? sender, BizFormItemEventArgs e) @@ -175,6 +565,9 @@ private void Handler(BaseInfo @object) private async Task SendPostToWebhook(string url, BaseInfo data) => await DoPost(url, data.TozapierDictionary()); #region PostData + + + private async Task DoPost(string url, Dictionary? content) { var contentResult = content ?? []; diff --git a/src/Kentico.Xperience.Zapier/packages.lock.json b/src/Kentico.Xperience.Zapier/packages.lock.json index b850d1c..4b0144a 100644 --- a/src/Kentico.Xperience.Zapier/packages.lock.json +++ b/src/Kentico.Xperience.Zapier/packages.lock.json @@ -10,29 +10,29 @@ }, "Kentico.Xperience.Admin": { "type": "Direct", - "requested": "[28.1.0, )", - "resolved": "28.1.0", - "contentHash": "xT8nUXUPMCqCT4NycL4G7bFpJrVqL8KTLzJU33kQWkdbzVxdqq4o75f9ysjmH83W4XOj6AG1xIzmZAYVdXdWCA==", + "requested": "[28.3.2, )", + "resolved": "28.3.2", + "contentHash": "3PU1HBlsUrHZ0uD+dPo7B45p/cP+/Ax1F4/KWh237CHLf7BQkyh+7ByWcLdJUkrZq1iF0e2XvGHGliE0Ux6c2A==", "dependencies": { - "Kentico.Aira.Client": "1.0.23", - "Kentico.Xperience.WebApp": "[28.1.0]", - "Microsoft.AspNetCore.SpaServices.Extensions": "6.0.25", - "Microsoft.Extensions.FileProviders.Embedded": "6.0.25" + "Kentico.Aira.Client": "1.0.25", + "Kentico.Xperience.WebApp": "[28.3.2]", + "Microsoft.AspNetCore.SpaServices.Extensions": "6.0.27", + "Microsoft.Extensions.FileProviders.Embedded": "6.0.27" } }, "Kentico.Xperience.WebApp": { "type": "Direct", - "requested": "[28.1.0, )", - "resolved": "28.1.0", - "contentHash": "JY2Ng+q6+mTM45GV/3o0w75mDmCa8jRzdi75nYJBU0GwCnKlC1shqtaQzjIJ2dVR55wdh4bqMpX40laaFc0AKw==", + "requested": "[28.3.2, )", + "resolved": "28.3.2", + "contentHash": "l6yuLb2KqU4azWIdapktABRoARLW0ySkPMj/+Kod31X0G29NSkbB6keDw5C9F9mkUZyKPjIMPv9z+4QjVRSd0w==", "dependencies": { "CommandLineParser": "2.9.1", - "HotChocolate.AspNetCore": "13.7.0", - "HotChocolate.Data": "13.7.0", - "HtmlSanitizer": "8.0.795", - "Kentico.Xperience.Core": "[28.1.0]", - "Microsoft.Extensions.FileProviders.Embedded": "6.0.25", - "Microsoft.Extensions.Localization": "6.0.25", + "HotChocolate.AspNetCore": "13.8.1", + "HotChocolate.Data": "13.8.1", + "HtmlSanitizer": "8.0.843", + "Kentico.Xperience.Core": "[28.3.2]", + "Microsoft.Extensions.FileProviders.Embedded": "6.0.27", + "Microsoft.Extensions.Localization": "6.0.27", "System.Runtime.Caching": "8.0.0" } }, @@ -61,11 +61,11 @@ }, "Azure.Core": { "type": "Transitive", - "resolved": "1.25.0", - "contentHash": "X8Dd4sAggS84KScWIjEbFAdt2U1KDolQopTPoHVubG2y3CM54f9l6asVrP5Uy384NWXjsspPYaJgz5xHc+KvTA==", + "resolved": "1.35.0", + "contentHash": "hENcx03Jyuqv05F4RBEPbxz29UrM3Nbhnr6Wl6NQpoU9BCIbL3XLentrxDCTrH54NLS11Exxi/o8MYgT/cnKFA==", "dependencies": { "Microsoft.Bcl.AsyncInterfaces": "1.1.1", - "System.Diagnostics.DiagnosticSource": "4.6.0", + "System.Diagnostics.DiagnosticSource": "6.0.1", "System.Memory.Data": "1.0.2", "System.Numerics.Vectors": "4.5.0", "System.Text.Encodings.Web": "4.7.2", @@ -75,12 +75,12 @@ }, "Azure.Identity": { "type": "Transitive", - "resolved": "1.7.0", - "contentHash": "eHEiCO/8+MfNc9nH5dVew/+FvxdaGrkRL4OMNwIz0W79+wtJyEoeRlXJ3SrXhoy9XR58geBYKmzMR83VO7bcAw==", + "resolved": "1.10.3", + "contentHash": "l1Xm2MWOF2Mzcwuarlw8kWQXLZk3UeB55aQXVyjj23aBfDwOZ3gu5GP2kJ6KlmZeZv2TCzw7x4L3V36iNr3gww==", "dependencies": { - "Azure.Core": "1.25.0", - "Microsoft.Identity.Client": "4.39.0", - "Microsoft.Identity.Client.Extensions.Msal": "2.19.3", + "Azure.Core": "1.35.0", + "Microsoft.Identity.Client": "4.56.0", + "Microsoft.Identity.Client.Extensions.Msal": "4.56.0", "System.Memory": "4.5.4", "System.Security.Cryptography.ProtectedData": "4.7.0", "System.Text.Json": "4.7.2", @@ -89,8 +89,8 @@ }, "BananaCakePop.Middleware": { "type": "Transitive", - "resolved": "7.0.4", - "contentHash": "MjXgiZ2WTmijyojmuiDMoqa2rokg0yNROwpe6yQibFre6D3CPdmCiIt48YE9+8ZBwgss5BK49iluktHFuf0XfQ==", + "resolved": "13.0.0", + "contentHash": "6Zj/vfmnCXLjBG7WNdtOgZZ5ZDR3Sy1FQSshZUonIYs3OdzozmsFmqPXMd9XJ0QE9aAildgVGq/lDLpLrMI4Yw==", "dependencies": { "Yarp.ReverseProxy": "2.0.1" } @@ -107,245 +107,255 @@ }, "GreenDonut": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "BjZ2KbrQT36hEYW4Hj9lzA/nH514jgFD1e1zDprxBOfQMGbD2mMlGaU4sBJf4GEYdKYRUdxUHSACK7yDUDTYVA==", + "resolved": "13.8.1", + "contentHash": "KgsJ88vcX0UfSKAO7uzbEPOGu8wwJU3Vkgz7AgeTrnfdgIVjZFkesvMxDqjzY6F3fmMbJmfAOLjufYLFs1Fq1g==", "dependencies": { - "Microsoft.Extensions.ObjectPool": "8.0.0-rc.2.23480.2", - "System.Diagnostics.DiagnosticSource": "8.0.0-rc.2.23479.6", + "Microsoft.Extensions.ObjectPool": "8.0.0", + "System.Diagnostics.DiagnosticSource": "8.0.0", "System.Threading.Tasks.Extensions": "4.5.0" } }, "HotChocolate": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "x8BIqnynoXLoHT9WeXmNSbfD6G+xv6ABMj6MkrDBInHBZ7B35rajCAcGdYOGJvi3ON+zSNgRMqiSkJzQocsW6g==", + "resolved": "13.8.1", + "contentHash": "Dfue5pJ99mNWaIBYv6VupDLtZo8KhIGC9blQy76BAvkipd7m9K3xhBLNyxnUA5AmTXDrKdS+RVZ21ghG/pqeAw==", "dependencies": { - "HotChocolate.Authorization": "13.7.0", - "HotChocolate.Execution": "13.7.0", - "HotChocolate.Fetching": "13.7.0", - "HotChocolate.Types": "13.7.0", - "HotChocolate.Types.CursorPagination": "13.7.0", - "HotChocolate.Types.Mutations": "13.7.0", - "HotChocolate.Types.OffsetPagination": "13.7.0", - "HotChocolate.Validation": "13.7.0" + "HotChocolate.Authorization": "13.8.1", + "HotChocolate.Execution": "13.8.1", + "HotChocolate.Fetching": "13.8.1", + "HotChocolate.Types": "13.8.1", + "HotChocolate.Types.CursorPagination": "13.8.1", + "HotChocolate.Types.Mutations": "13.8.1", + "HotChocolate.Types.OffsetPagination": "13.8.1", + "HotChocolate.Validation": "13.8.1" } }, "HotChocolate.Abstractions": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "D7ITncily71twwVwH68vOW7epqVvduZGDcqg0J9Cuct4QxFAkxc/YcVh0c8WxM1i4O915xJuJBpEQxLr+q1AlA==", + "resolved": "13.8.1", + "contentHash": "+llX8ziARzp+aKsOaXQfZAtqE+lF8gSmTiMiRCdpf03M+IWl/uCD9965nhqkM4mauWufwBXlwA7TE4uIUu+UjQ==", "dependencies": { - "HotChocolate.Language": "13.7.0", - "System.Collections.Immutable": "8.0.0-rc.2.23479.6" + "HotChocolate.Language": "13.8.1", + "System.Collections.Immutable": "8.0.0" } }, "HotChocolate.AspNetCore": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "omEK1nxwKeTSo81rx49fhhL2Cjmp+sEOYegYACmUju4DEmLwm10sA2T8Zo3SoNt0imYTysgibEgxLwjjQ214DA==", + "resolved": "13.8.1", + "contentHash": "Pg4/+sGPCn5qNwo9z8GP/LcGHKaCRsozOwNw2XVnLRY9EDIOoN2jzblgaFuDqWkXe+rd2yAnxE7NHcdBohTEFQ==", "dependencies": { - "BananaCakePop.Middleware": "7.0.4", - "HotChocolate": "13.7.0", - "HotChocolate.Subscriptions.InMemory": "13.7.0", - "HotChocolate.Transport.Sockets": "13.7.0", - "HotChocolate.Types.Scalars.Upload": "13.7.0" + "BananaCakePop.Middleware": "13.0.0", + "HotChocolate": "13.8.1", + "HotChocolate.Subscriptions.InMemory": "13.8.1", + "HotChocolate.Transport.Sockets": "13.8.1", + "HotChocolate.Types.Scalars.Upload": "13.8.1", + "HotChocolate.Utilities.DependencyInjection": "13.8.1" } }, "HotChocolate.Authorization": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "bIvUiYKOpUOuaFtf1OyZd8MgvHEMSwHzhqZyGqURWRCHdXVch1cS73laSm2i1RB0cKJ7dMOlG6+LvvvtmF7mbw==", + "resolved": "13.8.1", + "contentHash": "y+eLkswOMnSsPaO0fmY1gfNQD6I55SzXtAXhJIqsai1NpPeG2pu5b29y5UoGXNRQgb5/243gazbQbdM5j1S6PQ==", "dependencies": { - "HotChocolate.Execution": "13.7.0" + "HotChocolate.Execution": "13.8.1" } }, "HotChocolate.Data": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "9hNGSb+aoo8YOVUQoONSr6/YNGFLt4waZnT/PisX8qtLK7GxnCVMrJO8MnueR9KACEaYSEKIE/hTgXOhe3x8MA==", + "resolved": "13.8.1", + "contentHash": "tgXDs0TuyyPUMAUbPJltjll+HDSU19lX14IVe8J9WdDHGQXTScjyn1px8tX537wYh6Fy1XfBgrCKwmTV21+IdQ==", "dependencies": { - "HotChocolate.Execution": "13.7.0", - "HotChocolate.Types.CursorPagination": "13.7.0" + "HotChocolate.Execution": "13.8.1", + "HotChocolate.Types.CursorPagination": "13.8.1" } }, "HotChocolate.Execution": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "TbIimwWmlK3CtOJi3GpRS46x9K3D0NYawEdHV287wSNDxrceoxRuZNWBGx7017ExpfcV5gcJlLdaQP5Ao/gzug==", + "resolved": "13.8.1", + "contentHash": "co/VtIsOf3wqabsQLwO6HbTPi4UfL8UnzFlRkP2K4NNsNRdDkurYDdECS89swAuvfttzNua4MFOA4PclbW6Y/Q==", "dependencies": { - "HotChocolate.Abstractions": "13.7.0", - "HotChocolate.Execution.Abstractions": "13.7.0", - "HotChocolate.Fetching": "13.7.0", - "HotChocolate.Types": "13.7.0", - "HotChocolate.Validation": "13.7.0", - "Microsoft.Extensions.DependencyInjection": "8.0.0-rc.2.23479.6", - "System.Threading.Channels": "8.0.0-rc.2.23479.6" + "HotChocolate.Abstractions": "13.8.1", + "HotChocolate.Execution.Abstractions": "13.8.1", + "HotChocolate.Fetching": "13.8.1", + "HotChocolate.Types": "13.8.1", + "HotChocolate.Utilities.DependencyInjection": "13.8.1", + "HotChocolate.Validation": "13.8.1", + "Microsoft.Extensions.DependencyInjection": "8.0.0", + "System.Threading.Channels": "8.0.0" } }, "HotChocolate.Execution.Abstractions": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "7gzjF4xqCa0BYIzJ/nDTlnhdjYOJdydhYi7X5Be4PV41iy3V3rG74Pus+LcvOEi+5INFtxAhbXkDQR7n/rQwpQ==", + "resolved": "13.8.1", + "contentHash": "sAL6A/Qa23inTgu8sWiNoaKpaJ3MosXLsiP908+XUogMOjudpWnaSWPYu5THgl1deaQ6q55gbyiFvwJx5lRR8A==", "dependencies": { - "HotChocolate.Abstractions": "13.7.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0-rc.2.23479.6" + "HotChocolate.Abstractions": "13.8.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, "HotChocolate.Fetching": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "llRUlvdHTgJnSn3c3wpWEHMXIq0SVnf3m4q9JPwqS50fIRTVr7NMTgU0mbrnVcumccNo87dBBH8bZdj92uYZRQ==", + "resolved": "13.8.1", + "contentHash": "b1o8+gKmaE7rVX+fq/vFNFj+lcY414LoadaCcriEGEsz5fwIX5+SadmUIiaSuFOhuL+T8VLngh0zJXvPBI3sSA==", "dependencies": { - "GreenDonut": "13.7.0", - "HotChocolate.Types": "13.7.0" + "GreenDonut": "13.8.1", + "HotChocolate.Types": "13.8.1" } }, "HotChocolate.Language": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "/11gk8iCVUWsLaZAM0DB5SYzn8kJKI+trnzd/XEcY2Mj1HbAw8h9QMuLLx978zVA3KGn85hFdLFvPHSgSVilxA==", + "resolved": "13.8.1", + "contentHash": "qlljQwU51ecUyYa0qdOGHnWgP481QwwZsZRGwFuH/RbUwDVQOF8Fz/9aZxFmECkpiaCBfb8fHJOlzQGE52V6JQ==", "dependencies": { - "HotChocolate.Language.SyntaxTree": "13.7.0", - "HotChocolate.Language.Utf8": "13.7.0", - "HotChocolate.Language.Visitors": "13.7.0", - "HotChocolate.Language.Web": "13.7.0" + "HotChocolate.Language.SyntaxTree": "13.8.1", + "HotChocolate.Language.Utf8": "13.8.1", + "HotChocolate.Language.Visitors": "13.8.1", + "HotChocolate.Language.Web": "13.8.1" } }, "HotChocolate.Language.SyntaxTree": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "oU1hquKD90p3NxEXgQ2kd4F92ceGVO1uFVfuQ9YV8oQ3lCa6xm8UTVSHJX0nnKAmv59deolaMdfXAV16sKMWOg==", + "resolved": "13.8.1", + "contentHash": "0RYVxhsxR1vf0ue/V8GZnN8UVxh1bI74KPe0vFLLlNXRSq55LXTuGt3gYc6+LxSCc4KaItzRl6DwdgRuDRINjw==", "dependencies": { - "Microsoft.Extensions.ObjectPool": "8.0.0-rc.2.23480.2" + "Microsoft.Extensions.ObjectPool": "8.0.0" } }, "HotChocolate.Language.Utf8": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "NVX/h8oknpCSPnncGQfWi23tASto8hlczFhZwcYQxRRTcD1FDx6pJhCuUkGqajg1bAAtiOVhYPtdF7nqbOvN7w==", + "resolved": "13.8.1", + "contentHash": "y7YY6usRd72eAHjPS/NffT9cX92FJLg1Q6litLSCdjps1PnYVYTPnkNu5Ys1ngCJjOLsB71Or5CyjO5+Q8XSxA==", "dependencies": { - "HotChocolate.Language.SyntaxTree": "13.7.0" + "HotChocolate.Language.SyntaxTree": "13.8.1" } }, "HotChocolate.Language.Visitors": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "pnk408/UF7VGI9rsQ5oe05bfRWOlxYXMa2gc99VwZVDpG+3ZMVI+EhLulTz3CLs+861cR/1d/7Bgm9BcYUURoA==", + "resolved": "13.8.1", + "contentHash": "aMibQ+gWIB+L+jZhiq2Vq+Jr6DsKcLwXAwr0GY8Dx54GPq9f/UHgtMi0KWrZ3sJck5/FwvENjLAuOtb2DFBREA==", "dependencies": { - "HotChocolate.Language.SyntaxTree": "13.7.0" + "HotChocolate.Language.SyntaxTree": "13.8.1" } }, "HotChocolate.Language.Web": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "KI6TB3+hY2eS6G2NcTjKrzWG1dxbFBcImxnKrEeRot7zzBcHm0ZU6WfHqiUABo4kvnnPItaqoJiQjbt1ePW1ZA==", + "resolved": "13.8.1", + "contentHash": "rQ0jTiWoHuPyF58bZ17AdfYezmrpwcHthNhjYBcVfAxkATsvrHzoPqNDIgpv8xv3xaMlpxsv+nPg+i9mW/zS2Q==", "dependencies": { - "HotChocolate.Language.Utf8": "13.7.0" + "HotChocolate.Language.Utf8": "13.8.1" } }, "HotChocolate.Subscriptions": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "u8kR/au74TtsxOHAEcfpP9NDvWMSCRpCTNsAYoMcX9AnKw5126fJttbVtZzdnbYKI1Ceq214o77yV5KrJDroQw==", + "resolved": "13.8.1", + "contentHash": "RD0eebXDBvfILKsy8dF7kMyR1puoPDzp0/BPUBzfEQalGi66F76P/cuGHN1fJrzTr1x2MIINsPmQN2udlfTTKQ==", "dependencies": { - "HotChocolate.Abstractions": "13.7.0", - "HotChocolate.Execution.Abstractions": "13.7.0" + "HotChocolate.Abstractions": "13.8.1", + "HotChocolate.Execution.Abstractions": "13.8.1" } }, "HotChocolate.Subscriptions.InMemory": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "kKmJertu6LleVVyjFb/+df0mgswHJ885nDKGbd9cEwHT9h8CbHSF05/qAJFo6xm2rUM8fMsBPFME/DOTDIaTgg==", + "resolved": "13.8.1", + "contentHash": "8A0K4bTBd1CfWbPovj/b1WYb52S8ElaOxghlS8Dea3GN8q4CCF3vSwXrzfkdVynCmrv3AFQYIXV1ddMJG1YqFQ==", "dependencies": { - "HotChocolate.Execution.Abstractions": "13.7.0", - "HotChocolate.Subscriptions": "13.7.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0-rc.2.23479.6" + "HotChocolate.Execution.Abstractions": "13.8.1", + "HotChocolate.Subscriptions": "13.8.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, "HotChocolate.Transport.Sockets": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "DoRW/Htb6G/SHbWuPiq+mDqL5TdEsTbmuOQ19B9x1Z5X7iDW64N5hNTfR6YbT17J5OgQvb7XrPQLhVl6DALagQ==", + "resolved": "13.8.1", + "contentHash": "YVfn1O+B0UlGKtieqRoGEeZjnFpSNjK1ZQVLvfKZ/DfCh+7FR9CwZ6II7YXWCE+M9sCQTvEo9Cz5XCpsnJDhIw==", "dependencies": { - "System.IO.Pipelines": "8.0.0-rc.2.23479.6" + "System.IO.Pipelines": "8.0.0" } }, "HotChocolate.Types": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "kVWrhbkFvZWSZ7X3PY5MoL3bTmv2erRFI7kuvoo1nVGtYUeC05b+5MCh0RHzL7IFnIxf67RrDRFWWxL6bbZ7ug==", + "resolved": "13.8.1", + "contentHash": "EK5PodS+N+Oi77jmBFucS6Leq0mL4xYjC2fDTq6Le+cNxMLYx+cY8PE5Kjg3rMtrd/MFOOvUSQ/heAes5nuBHQ==", "dependencies": { - "HotChocolate.Abstractions": "13.7.0", - "HotChocolate.Types.Shared": "13.7.0", - "HotChocolate.Utilities": "13.7.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0-rc.2.23479.6", - "Microsoft.Extensions.ObjectPool": "8.0.0-rc.2.23480.2", + "HotChocolate.Abstractions": "13.8.1", + "HotChocolate.Types.Shared": "13.8.1", + "HotChocolate.Utilities": "13.8.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.ObjectPool": "8.0.0", "System.ComponentModel.Annotations": "5.0.0", - "System.Text.Json": "8.0.0-rc.2.23479.6" + "System.Text.Json": "8.0.0" } }, "HotChocolate.Types.CursorPagination": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "86YCkEUFBuq5ZEIdmAolW2/YLhVKyWjzg6hUZEBMMD3yE85xpgIdPd0wsyxwnF9hREyl8f/LMWO7epALBjnjow==", + "resolved": "13.8.1", + "contentHash": "Nu7ERbmzIkZKeCx/dwMQDIEVXDk7fgMrGGsnBTBVNyk5YA/hyto54CNhlM7TeUqqhYUze3wKynA8rB1sr0f+cw==", "dependencies": { - "HotChocolate.Execution": "13.7.0", - "HotChocolate.Types": "13.7.0" + "HotChocolate.Execution": "13.8.1", + "HotChocolate.Types": "13.8.1" } }, "HotChocolate.Types.Mutations": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "lAZWOeAXNB0A2QsJRhhtuOsyrofEqKxvS5b3qgYR+LqwL9G8EHyJA3gN9GjqoRMz8c+DtSCHyAVxXydhvRx2gw==", + "resolved": "13.8.1", + "contentHash": "euXYibxZS11BTQ+nhY991u4mfd72xK/25KYaA6/mkLR/to9z9Xb27QSukVF5cdCTEWnqBix6CdX3S5fq2YIYGw==", "dependencies": { - "HotChocolate.Execution": "13.7.0", - "HotChocolate.Types": "13.7.0" + "HotChocolate.Execution": "13.8.1", + "HotChocolate.Types": "13.8.1" } }, "HotChocolate.Types.OffsetPagination": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "Z+lXxKMf3ksdP6z2MkgZttMQ2V2AtCcdz+S2STOdJiahj1OZ7bx12Cq5l6GK3KVIT40NgYOkXqnU/fVWxB0b8g==", + "resolved": "13.8.1", + "contentHash": "cwspQsQEOUBxjOAOvcmYObf4ol5pcI6epKQahrwfOX7v8GJd+FU0Sh8YmqOA1bks4VyjueDR06t88lw6XNeJIw==", "dependencies": { - "HotChocolate.Execution": "13.7.0", - "HotChocolate.Types": "13.7.0" + "HotChocolate.Execution": "13.8.1", + "HotChocolate.Types": "13.8.1" } }, "HotChocolate.Types.Scalars.Upload": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "4C/cs0SFhv+jeN7itzy4W5rKj5p2aPfUVr3N71PW5WtgYE5Ntc31Umz+dqjcFRPTVhhWecuCYAMGFPAED1H9BQ==", + "resolved": "13.8.1", + "contentHash": "cUMEyPMt57kEhB8kXvF5/lCyBZQkzkTFuSpTIZwTX3RmJ08bYWaXxpYLpor/jxjoe4qTIyGR+z7z2p8sIearMg==", "dependencies": { - "HotChocolate.Types": "13.7.0" + "HotChocolate.Types": "13.8.1" } }, "HotChocolate.Types.Shared": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "No0VSatuyjiie0SXzLHER0Pc5bs7lq6MO0Sq0FUSw6MpV5ElX0kaR1TrrZCYZJa5ok9NRev6y52DzT+2Y+msvA==", + "resolved": "13.8.1", + "contentHash": "vPpDZdVLahXD+a9xweLclWyIy3GH8IcKHmzZpOz4zeoZlxUuQCrx0ViXrSdiX1WdtOoV0nc5c26WKPIgCAVJIw==", "dependencies": { - "HotChocolate.Language.SyntaxTree": "13.7.0" + "HotChocolate.Language.SyntaxTree": "13.8.1" } }, "HotChocolate.Utilities": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "Jhg/lrJrrrY2GHCavfjKKwdR0GI5bhKN9v9SWn9SYCoL21UfWtc0C6Qr4o3I/MCfQnktPiCH6WkPVS9VgipbRA==" + "resolved": "13.8.1", + "contentHash": "Z33UtFR96+iDR6uyjIW3qU3skvYEnhE/DGYnCoZUCh119t9OebvDW7ANCeL6oGXv0sZDJERvGQRhOZiBWZnqKA==" + }, + "HotChocolate.Utilities.DependencyInjection": { + "type": "Transitive", + "resolved": "13.8.1", + "contentHash": "4tEg4xfDfiahuLrC59gH+BYfAFqDPEvoyBK7PU3ep7O2cmQgnqeE3tKMqJ1UovGMsVQ5nYwcQ98LhqrPOxECUw==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "8.0.0" + } }, "HotChocolate.Validation": { "type": "Transitive", - "resolved": "13.7.0", - "contentHash": "/y6kX7cBkRbI9UgeWHgs/Kt8phJql1IrZjwSwdU6s8QOidFbanhsBU4euqVnM+hSeCbArzzKdrKt98DoPyfldA==", + "resolved": "13.8.1", + "contentHash": "kmPmYrtCt1NtmyZiSvfjDU+Abc/4hI2wDLe1uDEZW8JC8O2uwH0becZm1K6j9ZUfVMLp/5ZNsQONOXzL1VwxLA==", "dependencies": { - "HotChocolate.Types": "13.7.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0-rc.2.23479.6", - "Microsoft.Extensions.Options": "8.0.0-rc.2.23479.6" + "HotChocolate.Types": "13.8.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0" } }, "HtmlSanitizer": { "type": "Transitive", - "resolved": "8.0.795", - "contentHash": "wwX7RaYITdjdoc+t99vaPgoJtAaHJWZ1Y7IhdlP8oLpD1P1a4PaR8oCAKvvXpn9JHS9DB8gTqxFuSkyJmHS6iw==", + "resolved": "8.0.843", + "contentHash": "XfmHK4rFz9PPN0gcv7J7pc+MRpcni1mrnO04mwA+9/1zIHLgdOvLJeDwWnX5a+up4tioPvGreB+p+KljLJ32wg==", "dependencies": { "AngleSharp": "[0.17.1]", "AngleSharp.Css": "[0.17.0]", @@ -354,35 +364,36 @@ }, "Kentico.Aira.Client": { "type": "Transitive", - "resolved": "1.0.23", - "contentHash": "16jt+oHW6Fa6fDmJlJBTJuMK+A6nwXDX7IcYygYFzq01Sek43oQB2wjhXPRhntsvFYhAbWcBwXPzn0ALlMggSQ==", + "resolved": "1.0.25", + "contentHash": "Hu3xxl89ZWWU6iGkpnTCIXE/L3DNU+i/ZUZaRESYP6BJANlThPRFCIkrDwNx+daAsda5B/n5iApFzk5nH6qPOA==", "dependencies": { "Microsoft.Extensions.DependencyInjection": "6.0.1", "Microsoft.Extensions.Http": "6.0.0", "Microsoft.Extensions.Options": "6.0.0", "Microsoft.Extensions.Options.ConfigurationExtensions": "6.0.0", - "System.IdentityModel.Tokens.Jwt": "6.31.0" + "System.IdentityModel.Tokens.Jwt": "7.3.1" } }, "Kentico.Xperience.Core": { "type": "Transitive", - "resolved": "28.1.0", - "contentHash": "vi81eejMIjPaSK1R/H0i6XAkeIV2EgAuPwdsafmR1+IQJ28jNSlGV/gteHXgxfIuQWjJDNayJInG7ggLCjlLJQ==", + "resolved": "28.3.2", + "contentHash": "DW4pX1en1r4aKzNiKv0wvag6FPmyU8Z/AQVXkr2AGdyFykEnmzvcQbRoakhZ7Mj290MdzRNQLHducQpDetOtEQ==", "dependencies": { "AngleSharp": "0.17.1", "MailKit": "4.3.0", - "Microsoft.Data.SqlClient": "5.1.2", + "Microsoft.AspNetCore.Http.Abstractions": "2.1.1", + "Microsoft.Data.SqlClient": "5.1.5", "Microsoft.Extensions.Caching.Memory": "6.0.1", "Microsoft.Extensions.Configuration": "6.0.1", "Microsoft.Extensions.Configuration.Binder": "6.0.0", "Microsoft.Extensions.DependencyInjection": "6.0.1", "Microsoft.Extensions.FileProviders.Physical": "6.0.0", "Microsoft.Extensions.Hosting.Abstractions": "6.0.0", - "Microsoft.Extensions.Localization": "6.0.25", + "Microsoft.Extensions.Localization": "6.0.27", "Microsoft.Extensions.Options.ConfigurationExtensions": "6.0.0", "Mono.Cecil": "0.11.5", "Newtonsoft.Json": "13.0.3", - "System.CodeDom": "7.0.0", + "System.CodeDom": "8.0.0", "System.Configuration.ConfigurationManager": "6.0.1" } }, @@ -394,10 +405,27 @@ "MimeKit": "4.3.0" } }, + "Microsoft.AspNetCore.Http.Abstractions": { + "type": "Transitive", + "resolved": "2.1.1", + "contentHash": "kQUEVOU4loc8CPSb2WoHFTESqwIa8Ik7ysCBfTwzHAd0moWovc9JQLmhDIHlYLjHbyexqZAlkq/FPRUZqokebw==", + "dependencies": { + "Microsoft.AspNetCore.Http.Features": "2.1.1", + "System.Text.Encodings.Web": "4.5.0" + } + }, + "Microsoft.AspNetCore.Http.Features": { + "type": "Transitive", + "resolved": "2.1.1", + "contentHash": "VklZ7hWgSvHBcDtwYYkdMdI/adlf7ebxTZ9kdzAhX+gUs5jSHE9mZlTamdgf9miSsxc1QjNazHXTDJdVPZKKTw==", + "dependencies": { + "Microsoft.Extensions.Primitives": "2.1.1" + } + }, "Microsoft.AspNetCore.SpaServices.Extensions": { "type": "Transitive", - "resolved": "6.0.25", - "contentHash": "zrpq53bEpjusCgaNigpRZkKqkDr2X2guJQqvUI0bLbq+u34kTg7WmWwJaaOUNBXdp9sgzMkkqmh35/ajKzZfdQ==", + "resolved": "6.0.27", + "contentHash": "sJ3wibVaTldyWtQXz2zollxKJO1tnfIcuta5iqqiOHayEJwlbRFDz1qWpinC8hKnGCJ76PMm5bJ+g98KlXegRw==", "dependencies": { "Microsoft.Extensions.FileProviders.Physical": "6.0.0" } @@ -407,24 +435,19 @@ "resolved": "1.1.1", "contentHash": "yuvf07qFWFqtK3P/MRkEKLhn5r2UbSpVueRziSqj0yJQIKFwG1pq9mOayK3zE5qZCTs0CbrwL9M6R8VwqyGy2w==" }, - "Microsoft.CSharp": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "kaj6Wb4qoMuH3HySFJhxwQfe8R/sJsNJnANrvv8WdFPMoNbKY5htfNscv+LHCu5ipz+49m2e+WQXpLXr9XYemQ==" - }, "Microsoft.Data.SqlClient": { "type": "Transitive", - "resolved": "5.1.2", - "contentHash": "q/F1HTOn9QLwgRp4esJIA1b2X15faeV8WozkNhvU3Zk0DcYDWUsEf5WMkbypY4CaNkZntOduods5wLyv8I699w==", + "resolved": "5.1.5", + "contentHash": "6kvhQjY5uBCdBccezFD2smfnpQjQ33cZtUZVrNvxlwoBu6uopM5INH6uSgLI7JRLtlQ3bMPwnhMq4kchsXeZ5w==", "dependencies": { - "Azure.Identity": "1.7.0", + "Azure.Identity": "1.10.3", "Microsoft.Data.SqlClient.SNI.runtime": "5.1.1", - "Microsoft.Identity.Client": "4.47.2", - "Microsoft.IdentityModel.JsonWebTokens": "6.24.0", - "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.24.0", + "Microsoft.Identity.Client": "4.56.0", + "Microsoft.IdentityModel.JsonWebTokens": "6.35.0", + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.35.0", "Microsoft.SqlServer.Server": "1.0.0", "System.Configuration.ConfigurationManager": "6.0.1", - "System.Diagnostics.DiagnosticSource": "6.0.0", + "System.Diagnostics.DiagnosticSource": "6.0.1", "System.Runtime.Caching": "6.0.0", "System.Security.Cryptography.Cng": "5.0.0", "System.Security.Principal.Windows": "5.0.0", @@ -484,16 +507,16 @@ }, "Microsoft.Extensions.DependencyInjection": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "pUD/Gjd0MTrWPD4/SnKazYQvky2EHEtPyGb3FWZkEPWAfYPFVVw5fMRTkfoBPivpWLuxEw4FNK7GX77xEErUQQ==", + "resolved": "8.0.0", + "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0-rc.2.23479.6" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "QLTBDvE/E05Xl2UVFXOBFIW0VLn/mMJ8DSbTyK6ODsO3sqDs0fyPqydACTnX/nbGZRrTMeud3XDbUrt24ab1EA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.FileProviders.Abstractions": { "type": "Transitive", @@ -505,8 +528,8 @@ }, "Microsoft.Extensions.FileProviders.Embedded": { "type": "Transitive", - "resolved": "6.0.25", - "contentHash": "q1S6iVA2+kvwuSt21zcjKLzQDGTyMwVlEGhucOu8xNIQiHjcvWrKHtwlBIJzIE1EIcxQL/4w3iQw9W665i5WdQ==", + "resolved": "6.0.27", + "contentHash": "trrI4tXQsOIB56H3u/wD4aVu5QtF8nJPtBuQ6wm8phlYSFTR3Rj3/9fXA5Mrz4X2B0lwOk1QndCPL/fWhH9Izw==", "dependencies": { "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0" } @@ -549,19 +572,19 @@ }, "Microsoft.Extensions.Localization": { "type": "Transitive", - "resolved": "6.0.25", - "contentHash": "7g6QtX+XkdtirCP3eLRnd4x6s7Q6LMlRZnby0iqRIhKBZ7CEwMVAfOODRHRqUMZ6n1f67OY+yGmZSpKtbGmp+w==", + "resolved": "6.0.27", + "contentHash": "sqwoeaqGTeSMBTrUV8ysD8JPfUcH8sdkmv4oCfz9i5WHAGfsS/eHCpoff87sukoxwgaEBBd9YPhTwdaFE9njlw==", "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", - "Microsoft.Extensions.Localization.Abstractions": "6.0.25", + "Microsoft.Extensions.Localization.Abstractions": "6.0.27", "Microsoft.Extensions.Logging.Abstractions": "6.0.4", "Microsoft.Extensions.Options": "6.0.0" } }, "Microsoft.Extensions.Localization.Abstractions": { "type": "Transitive", - "resolved": "6.0.25", - "contentHash": "41x/D64w2kEjeKxC8nkB6lBmw731FoTjFoy8caE7063aNo/fwB/B4p39G0dn7nu752GznHT3I+sLWJG/tdzw6A==" + "resolved": "6.0.27", + "contentHash": "virsfnfbV6uJASaNKUXLQpdY0qGr48R6dUFwY00Qja5ea+kgntRgm7qzAH6GLeJjfW3zjoltrTiTrCbrAP3KCA==" }, "Microsoft.Extensions.Logging": { "type": "Transitive", @@ -582,16 +605,16 @@ }, "Microsoft.Extensions.ObjectPool": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23480.2", - "contentHash": "iL9VcNK4dbMOLqAHInwcmVxzr+5sXp70m5Tt1uyIkc5SfJUTuFN6VaxrZy3k91oquTtYrkK9DbE5IP18iJUrtw==" + "resolved": "8.0.0", + "contentHash": "4pm+XgxSukskwjzDDfSjG4KNUIOdFF2VaqZZDtTzoyQMOVSnlV6ZM8a9aVu5dg9LVZTB//utzSc8fOi0b0Mb2Q==" }, "Microsoft.Extensions.Options": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "f2uTnKEleplKK+pVKEg1rOCmM3+cuLpafTpKJzbj9lm8dmj0+dWxb0L6MAt9r1s3OYlIKY5IdkW0TUFKXvRCMg==", + "resolved": "8.0.0", + "contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0-rc.2.23479.6", - "Microsoft.Extensions.Primitives": "8.0.0-rc.2.23479.6" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" } }, "Microsoft.Extensions.Options.ConfigurationExtensions": { @@ -608,87 +631,78 @@ }, "Microsoft.Extensions.Primitives": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "I3fTiDmV+2cCR3VjH+oz49AMgrAqX1cmNiWXmEAituAI7jCLA16uXzvYQTwxhQzov5BTdPVXKGNTxsMb1GpcLQ==" + "resolved": "8.0.0", + "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, "Microsoft.Identity.Client": { "type": "Transitive", - "resolved": "4.47.2", - "contentHash": "SPgesZRbXoDxg8Vv7k5Ou0ee7uupVw0E8ZCc4GKw25HANRLz1d5OSr0fvTVQRnEswo5Obk8qD4LOapYB+n5kzQ==", + "resolved": "4.56.0", + "contentHash": "rr4zbidvHy9r4NvOAs5hdd964Ao2A0pAeFBJKR95u1CJAVzbd1p6tPTXUZ+5ld0cfThiVSGvz6UHwY6JjraTpA==", "dependencies": { "Microsoft.IdentityModel.Abstractions": "6.22.0" } }, "Microsoft.Identity.Client.Extensions.Msal": { "type": "Transitive", - "resolved": "2.19.3", - "contentHash": "zVVZjn8aW7W79rC1crioDgdOwaFTQorsSO6RgVlDDjc7MvbEGz071wSNrjVhzR0CdQn6Sefx7Abf1o7vasmrLg==", + "resolved": "4.56.0", + "contentHash": "H12YAzEGK55vZ+QpxUzozhW8ZZtgPDuWvgA0JbdIR9UhMUplj29JhIgE2imuH8W2Nw9D8JKygR1uxRFtpSNcrg==", "dependencies": { - "Microsoft.Identity.Client": "4.38.0", + "Microsoft.Identity.Client": "4.56.0", + "System.IO.FileSystem.AccessControl": "5.0.0", "System.Security.Cryptography.ProtectedData": "4.5.0" } }, "Microsoft.IdentityModel.Abstractions": { "type": "Transitive", - "resolved": "6.31.0", - "contentHash": "SBa2DGEZpMThT3ki6lOK5SwH+fotHddNBKH+pfqrlINnl999BreRS9G0QiLruwfmcTDnFr8xwmNjoGnPQqfZwg==" + "resolved": "7.3.1", + "contentHash": "gIw8Sr5ZpuzKFBTfJonh2F54DivTzm5IIK15QB4Y6uE30uQdEO1NnCojTC/b6sWZoZzD0sdBa6SqwMXhucD+nA==" }, "Microsoft.IdentityModel.JsonWebTokens": { "type": "Transitive", - "resolved": "6.31.0", - "contentHash": "r0f4clrrlFApwSf2GRpS5X8hL54h1WUlZdq9ZoOy+cJOOqtNhhdfkfkqwxsTGCH/Ae7glOWNxykZzyRXpwcXVQ==", + "resolved": "7.3.1", + "contentHash": "mXA6AoaD5uZqtsKghgRiupBhyXNii8p9F2BjNLnDGud0tZLS5+4Fio2YAGjFXhnkc80CqgQ61X5U1gUNnDEoKQ==", "dependencies": { - "Microsoft.IdentityModel.Tokens": "6.31.0", - "System.Text.Encoding": "4.3.0", - "System.Text.Encodings.Web": "4.7.2", - "System.Text.Json": "4.7.2" + "Microsoft.IdentityModel.Tokens": "7.3.1" } }, "Microsoft.IdentityModel.Logging": { "type": "Transitive", - "resolved": "6.31.0", - "contentHash": "YzW5O27nTXxNgNKm+Pud7hXjUlDa2JshtRG+WftQvQIsBUpFA/WjhxG2uO8YanfXbb/IT9r8Cu/VdYkvZ3+9/g==", + "resolved": "7.3.1", + "contentHash": "uPt2aiRUCbcOc0Wk+dDCSClFfPNs3S3Z7fmy50MoxJ1mGmtVUDMpyRJeYzZ/16x4rL19T+g2zrzjcWoitp5+gQ==", "dependencies": { - "Microsoft.IdentityModel.Abstractions": "6.31.0" + "Microsoft.IdentityModel.Abstractions": "7.3.1" } }, "Microsoft.IdentityModel.Protocols": { "type": "Transitive", - "resolved": "6.24.0", - "contentHash": "+NzKCkvsQ8X1r/Ff74V7CFr9OsdMRaB6DsV+qpH7NNLdYJ8O4qHbmTnNEsjFcDmk/gVNDwhoL2gN5pkPVq0lwQ==", + "resolved": "6.35.0", + "contentHash": "BPQhlDzdFvv1PzaUxNSk+VEPwezlDEVADIKmyxubw7IiELK18uJ06RQ9QKKkds30XI+gDu9n8j24XQ8w7fjWcg==", "dependencies": { - "Microsoft.IdentityModel.Logging": "6.24.0", - "Microsoft.IdentityModel.Tokens": "6.24.0" + "Microsoft.IdentityModel.Logging": "6.35.0", + "Microsoft.IdentityModel.Tokens": "6.35.0" } }, "Microsoft.IdentityModel.Protocols.OpenIdConnect": { "type": "Transitive", - "resolved": "6.24.0", - "contentHash": "a/2RRrc8C9qaw8qdD9hv1ES9YKFgxaqr/SnwMSLbwQZJSUQDd4qx1K4EYgWaQWs73R+VXLyKSxN0f/uE9CsBiQ==", + "resolved": "6.35.0", + "contentHash": "LMtVqnECCCdSmyFoCOxIE5tXQqkOLrvGrL7OxHg41DIm1bpWtaCdGyVcTAfOQpJXvzND9zUKIN/lhngPkYR8vg==", "dependencies": { - "Microsoft.IdentityModel.Protocols": "6.24.0", - "System.IdentityModel.Tokens.Jwt": "6.24.0" + "Microsoft.IdentityModel.Protocols": "6.35.0", + "System.IdentityModel.Tokens.Jwt": "6.35.0" } }, "Microsoft.IdentityModel.Tokens": { "type": "Transitive", - "resolved": "6.31.0", - "contentHash": "Q1Ej/OAiqi5b/eB8Ozo5FnQ6vlxjgiomnWWenDi2k7+XqhkA2d5TotGtNXpWcWiGmrotNA/o8p51YesnziA0Sw==", + "resolved": "7.3.1", + "contentHash": "/c/p8/3CAH706c0ii5uTgSb/8M/jwyuurtdMeKTBeKFU9aA+EZrLu1M8aaS3CSlGaxoxsoaxr4/+KXykgQ4VgQ==", "dependencies": { - "Microsoft.CSharp": "4.5.0", - "Microsoft.IdentityModel.Logging": "6.31.0", - "System.Security.Cryptography.Cng": "4.5.0" + "Microsoft.IdentityModel.Logging": "7.3.1" } }, "Microsoft.NETCore.Platforms": { "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" - }, - "Microsoft.NETCore.Targets": { - "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" + "resolved": "5.0.0", + "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" }, "Microsoft.SqlServer.Server": { "type": "Transitive", @@ -723,8 +737,8 @@ }, "System.CodeDom": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "GLltyqEsE5/3IE+zYRP5sNa1l44qKl9v+bfdMcwg+M9qnQf47wK3H0SUR/T+3N4JEQXF3vV4CSuuo0rsg+nq2A==" + "resolved": "8.0.0", + "contentHash": "WTlRjL6KWIMr/pAaq3rYqh0TJlzpouaQ/W1eelssHgtlwHAH25jXTkUphTYx9HaIIf7XA6qs/0+YhtLEQRkJ+Q==" }, "System.Collections.Immutable": { "type": "Transitive", @@ -747,8 +761,8 @@ }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "D1Fi5wRyRVwriEdlSniYlo2kW8SCGaSCM/alsY8R7eXcW+xCPRB7gohE45X00EiNkhdUrJ3yNfltV8lLK0HoWQ==" + "resolved": "8.0.0", + "contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ==" }, "System.Diagnostics.EventLog": { "type": "Transitive", @@ -762,11 +776,20 @@ }, "System.IdentityModel.Tokens.Jwt": { "type": "Transitive", - "resolved": "6.31.0", - "contentHash": "OTlLhhNHODxZvqst0ku8VbIdYNKi25SyM6/VdbpNUe6aItaecVRPtURGvpcQpzltr9H0wy+ycAqBqLUI4SBtaQ==", + "resolved": "7.3.1", + "contentHash": "iE8biOWyAC1NnYcZGcgXErNACvIQ6Gcmg5s28gsjVbyyYdF9NdKsYzAPAsO3KGK86EQjpToI1AO82XbG8chkzA==", + "dependencies": { + "Microsoft.IdentityModel.JsonWebTokens": "7.3.1", + "Microsoft.IdentityModel.Tokens": "7.3.1" + } + }, + "System.IO.FileSystem.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", "dependencies": { - "Microsoft.IdentityModel.JsonWebTokens": "6.31.0", - "Microsoft.IdentityModel.Tokens": "6.31.0" + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" } }, "System.IO.Hashing": { @@ -776,8 +799,8 @@ }, "System.IO.Pipelines": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "4bqn2Kj0keumJ0x3wdZtO1Ex/5Ppu01fP7Rtmn1uJBR08WWRKeKSX6U9a/BiEieE9JjhzapvhjPtFypE7ZIAyQ==" + "resolved": "8.0.0", + "contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA==" }, "System.Memory": { "type": "Transitive", @@ -798,15 +821,6 @@ "resolved": "4.5.0", "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" }, - "System.Runtime": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, "System.Runtime.Caching": { "type": "Transitive", "resolved": "8.0.0", @@ -820,6 +834,15 @@ "resolved": "6.0.0", "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, "System.Security.Cryptography.Cng": { "type": "Transitive", "resolved": "5.0.0", @@ -846,16 +869,6 @@ "resolved": "5.0.0", "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" }, - "System.Text.Encoding": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, "System.Text.Encoding.CodePages": { "type": "Transitive", "resolved": "7.0.0", @@ -863,21 +876,21 @@ }, "System.Text.Encodings.Web": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "n66ZIJjetmrMq9hJ61Xed2cp9O2zr/VdzhhURjkLDEFOZ38/VpOWnvM3CWCXA18NbM7x0tdKZYex9rj0NimpPA==" + "resolved": "8.0.0", + "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==" }, "System.Text.Json": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "SXMjrmm/e0Om+731AEUgm+81dC+i9mV54nKJGOq9+zTYpzujMCmSQSMS1sgQb0gmiiAfTfRC5WgD3l92cfAP+g==", + "resolved": "8.0.0", + "contentHash": "OdrZO2WjkiEG6ajEFRABTRCi/wuXQPxeV6g8xvUJqdxMvvuCCEk86zPla8UiIQJz3durtUEbNyY/3lIhS0yZvQ==", "dependencies": { - "System.Text.Encodings.Web": "8.0.0-rc.2.23479.6" + "System.Text.Encodings.Web": "8.0.0" } }, "System.Threading.Channels": { "type": "Transitive", - "resolved": "8.0.0-rc.2.23479.6", - "contentHash": "z8/q0WPKxQsxuzywRbY1oCb2ZO4qgRbE0nYwXjwrIJ7y10796vJl9P2++MF4JcBcKXfNLgw0JSQslMTxXB+C/A==" + "resolved": "8.0.0", + "contentHash": "CMaFr7v+57RW7uZfZkPExsPB6ljwzhjACWW1gfU35Y56rk72B/Wu+sTqxVmGSk4SFUlPc3cjeKND0zktziyjBA==" }, "System.Threading.Tasks.Extensions": { "type": "Transitive", diff --git a/src/XbKcli/actions/insertFormRecordAction.js b/src/XbKcli/actions/insertFormRecordAction.js new file mode 100644 index 0000000..1bf7125 --- /dev/null +++ b/src/XbKcli/actions/insertFormRecordAction.js @@ -0,0 +1,50 @@ +const getFormClassNamesField = require("../fields/getFormClassNamesField"); +const getFormInputsField = require("../fields/getFormInputsField"); +const getFormSchema = require("../utils/getFormSchema"); + +async function execute(z, bundle) { + const schema = await getFormSchema(z, bundle, bundle.inputData.classname); + const input = JSON.parse(JSON.stringify(bundle.inputData)); + const keys = schema.map((c) => c.column); + for (const prop in input) { + if (!keys.includes(prop)) { + delete input[prop]; + } + } + + const options = { + url: `${bundle.authData.website}/zapier/actions/biz-form/${bundle.inputData.classname}`, + method: "POST", + headers: { + Accept: "application/json", + }, + body: input, + }; + + const response = await z.request(options); + return z.JSON.parse(response.content); +} + +const insertFormRecordAction = { + noun: "Insert form record action", + display: { + hidden: false, + description: "Insert record into XbK form", + label: "Insert Form Record", + }, + key: "insertFormRecordAction", + operation: { + perform: execute, + inputFields: [ + getFormClassNamesField({ required: true, altersDynamicFields: true }), + async function (z, bundle) { + return await getFormInputsField(z, bundle, bundle.inputData.classname); + }, + ], + sample: { + classname: "BizForm.DancingGoatContactUs", + }, + }, +}; + +module.exports = insertFormRecordAction; diff --git a/src/XbKcli/actions/moveToStepAction.js b/src/XbKcli/actions/moveToStepAction.js new file mode 100644 index 0000000..86db4d8 --- /dev/null +++ b/src/XbKcli/actions/moveToStepAction.js @@ -0,0 +1,186 @@ +const getWebsiteChannelsField = require("../fields/getWebsiteChannelsField"); +const getLanguageNamesField = require("../fields/getLanguageNamesField"); +const getClassContentTypeTypesField = require("../fields/getClassContentTypeTypesField"); +const getReusableTypesField = require("../fields/getReusableTypesField"); +const getReusableItemsField = require("../fields/getReusableItemsField"); +const getWebsiteItemsField = require("../fields/getWebsiteItemsField"); +const getWebsiteTypesField = require("../fields/getWebsiteTypesField"); +const getHeadlessItemsField = require("../fields/getHeadlessItemsField"); +const getHeadlessTypesField = require("../fields/getHeadlessTypesField"); +const getHeadlessChannelsField = require("../fields/getHeadlessChannelsField"); +const getStepsField = require("../fields/getStepsField"); +const ClassContentTypeType = require("../utils/enums"); + +async function execute(z, bundle) { + let url = ""; + const inputData = bundle.inputData; + if (inputData.classContentTypeType == ClassContentTypeType.WEBSITE) { + url = `${ClassContentTypeType.WEBSITE}/${inputData.stepName}/${inputData.websiteChannelId}/${inputData.pageId}/${inputData.languageName}`; + } else if (inputData.classContentTypeType == ClassContentTypeType.REUSABLE) { + url = `${ClassContentTypeType.REUSABLE}/${inputData.stepName}/${inputData.reusableItemId}/${inputData.languageName}`; + } else if (inputData.classContentTypeType == ClassContentTypeType.HEADLESS) { + url = `${ClassContentTypeType.HEADLESS}/${inputData.stepName}/${inputData.headlessChannelId}/${inputData.headlessItemId}/${inputData.languageName}`; + } + + const options = { + url: `${bundle.authData.website}/zapier/actions/movetostep/${url}`, + method: "POST", + headers: { + Accept: "application/json", + }, + }; + + const response = await z.request(options); + return z.JSON.parse(response.content); +} + +async function makeFieldsForWebsite(z, bundle) { + const res = []; + res.push( + getWebsiteChannelsField({ + required: true, + altersDynamicFields: true, + }) + ); + if (bundle.inputData.websiteChannelId != undefined) { + res.push( + getWebsiteTypesField({ + required: true, + altersDynamicFields: true, + }) + ); + if ( + bundle.inputData.languageName != undefined && + bundle.inputData.websiteClassname != undefined + ) { + res.push( + getWebsiteItemsField({ + required: true, + altersDynamicFields: true, + }) + ); + } + } + if (bundle.inputData.pageId != undefined) { + res.push( + getStepsField({ + required: true, + altersDynamicFields: true, + }) + ); + } + return res; +} + +async function makeFieldsForReusable(z, bundle) { + const res = []; + res.push( + getReusableTypesField({ + required: true, + altersDynamicFields: true, + }) + ); + if ( + bundle.inputData.languageName != undefined && + bundle.inputData.reusableClassname != undefined + ) { + res.push( + getReusableItemsField({ + required: true, + altersDynamicFields: true, + }) + ); + } + if (bundle.inputData.reusableItemId != undefined) { + res.push( + getStepsField({ + required: true, + altersDynamicFields: true, + }) + ); + } + return res; +} + +async function makeFieldsForHeadless(z, bundle) { + const res = []; + res.push( + getHeadlessChannelsField({ + required: true, + altersDynamicFields: true, + }) + ); + if (bundle.inputData.headlessChannelId != undefined) { + res.push( + getHeadlessTypesField({ + required: true, + altersDynamicFields: true, + }) + ); + if ( + bundle.inputData.languageName != undefined && + bundle.inputData.headlessClassname != undefined + ) { + res.push( + getHeadlessItemsField({ + required: true, + altersDynamicFields: true, + }) + ); + } + } + if (bundle.inputData.headlessItemId != undefined) { + res.push( + getStepsField({ + required: true, + altersDynamicFields: true, + }) + ); + } + return res; +} + +const moveToStepAction = { + noun: "Move to step action", + display: { + hidden: false, + description: "Move to step content type in XbK", + label: "Move to Step", + }, + key: "moveToStepAction", + operation: { + perform: execute, + inputFields: [ + getClassContentTypeTypesField({ + required: true, + altersDynamicFields: true, + }), + getLanguageNamesField({ + required: true, + altersDynamicFields: true, + }), + async function (z, bundle) { + if ( + bundle.inputData.classContentTypeType == ClassContentTypeType.WEBSITE + ) { + return await makeFieldsForWebsite(z, bundle); + } + if ( + bundle.inputData.classContentTypeType == ClassContentTypeType.REUSABLE + ) { + return await makeFieldsForReusable(z, bundle); + } + if ( + bundle.inputData.classContentTypeType == ClassContentTypeType.HEADLESS + ) { + return await makeFieldsForHeadless(z, bundle); + } + }, + ], + sample: { + classname: "BizForm.DancingGoatContactUs", + }, + }, +}; + +module.exports = moveToStepAction; diff --git a/src/XbKcli/actions/publishAction.js b/src/XbKcli/actions/publishAction.js new file mode 100644 index 0000000..cfa1573 --- /dev/null +++ b/src/XbKcli/actions/publishAction.js @@ -0,0 +1,161 @@ +const getLanguageNamesField = require("../fields/getLanguageNamesField"); +const getClassContentTypeTypesField = require("../fields/getClassContentTypeTypesField"); +const getReusableTypesField = require("../fields/getReusableTypesField"); +const getReusableItemsField = require("../fields/getReusableItemsField"); +const getWebsiteItemsField = require("../fields/getWebsiteItemsField"); +const getWebsiteTypesField = require("../fields/getWebsiteTypesField"); +const getWebsiteChannelsField = require("../fields/getWebsiteChannelsField"); +const getHeadlessItemsField = require("../fields/getHeadlessItemsField"); +const getHeadlessTypesField = require("../fields/getHeadlessTypesField"); +const getHeadlessChannelsField = require("../fields/getHeadlessChannelsField"); +const ClassContentTypeType = require("../utils/enums"); + +async function execute(z, bundle) { + let url = ""; + const inputData = bundle.inputData; + if (inputData.classContentTypeType == ClassContentTypeType.WEBSITE) { + url = `${ClassContentTypeType.WEBSITE}/${inputData.websiteChannelId}/${inputData.pageId}/${inputData.languageName}`; + } else if (inputData.classContentTypeType == ClassContentTypeType.REUSABLE) { + url = `${ClassContentTypeType.REUSABLE}/${inputData.reusableItemId}/${inputData.languageName}`; + } else if (inputData.classContentTypeType == ClassContentTypeType.HEADLESS) { + url = `${ClassContentTypeType.HEADLESS}/${inputData.headlessChannelId}/${inputData.headlessItemId}/${inputData.languageName}`; + } + + const options = { + url: `${bundle.authData.website}/zapier/actions/publish/${url}`, + method: "POST", + headers: { + Accept: "application/json", + }, + }; + + const response = await z.request(options); + return z.JSON.parse(response.content); +} + +async function makeFieldsForWebsite(z, bundle) { + const res = []; + res.push( + getWebsiteChannelsField({ + required: true, + altersDynamicFields: true, + }) + ); + if (bundle.inputData.websiteChannelId != undefined) { + res.push( + getWebsiteTypesField({ + required: true, + altersDynamicFields: true, + }) + ); + if ( + bundle.inputData.languageName != undefined && + bundle.inputData.websiteClassname != undefined + ) { + res.push( + getWebsiteItemsField({ + required: true, + altersDynamicFields: true, + }) + ); + } + } + return res; +} + +async function makeFieldsForReusable(z, bundle) { + const res = []; + res.push( + getReusableTypesField({ + required: true, + altersDynamicFields: true, + }) + ); + if ( + bundle.inputData.languageName != undefined && + bundle.inputData.reusableClassname != undefined + ) { + res.push( + getReusableItemsField({ + required: true, + altersDynamicFields: true, + }) + ); + } + return res; +} + +async function makeFieldsForHeadless(z, bundle) { + const res = []; + res.push( + getHeadlessChannelsField({ + required: true, + altersDynamicFields: true, + }) + ); + if (bundle.inputData.headlessChannelId != undefined) { + res.push( + getHeadlessTypesField({ + required: true, + altersDynamicFields: true, + }) + ); + if ( + bundle.inputData.languageName != undefined && + bundle.inputData.headlessClassname != undefined + ) { + res.push( + getHeadlessItemsField({ + required: true, + altersDynamicFields: true, + }) + ); + } + } + return res; +} + +const publishAction = { + noun: "Publish action", + display: { + hidden: false, + description: "Publish content type in XbK", + label: "Publish", + }, + key: "publishAction", + operation: { + perform: execute, + inputFields: [ + getClassContentTypeTypesField({ + required: true, + altersDynamicFields: true, + }), + getLanguageNamesField({ + required: true, + altersDynamicFields: true, + }), + async function (z, bundle) { + if ( + bundle.inputData.classContentTypeType == ClassContentTypeType.WEBSITE + ) { + return await makeFieldsForWebsite(z, bundle); + } + if ( + bundle.inputData.classContentTypeType == ClassContentTypeType.REUSABLE + ) { + return await makeFieldsForReusable(z, bundle); + } + if ( + bundle.inputData.classContentTypeType == ClassContentTypeType.HEADLESS + ) { + return await makeFieldsForHeadless(z, bundle); + } + }, + ], + sample: { + classname: "BizForm.DancingGoatContactUs", + }, + }, +}; + +module.exports = publishAction; diff --git a/src/XbKcli/fields/getClassContentTypeTypesField.js b/src/XbKcli/fields/getClassContentTypeTypesField.js new file mode 100644 index 0000000..da1bb8e --- /dev/null +++ b/src/XbKcli/fields/getClassContentTypeTypesField.js @@ -0,0 +1,14 @@ +function getClassContentTypeTypesField(extras) { + return Object.assign( + { + label: "Content type", + key: "classContentTypeType", + required: true, + type: "string", + dynamic: "get_class_content_type_types.id.name", + }, + extras || {} + ); +} + +module.exports = getClassContentTypeTypesField; diff --git a/src/XbKcli/fields/getEventTypesField.js b/src/XbKcli/fields/getEventTypesField.js index 78d8367..9858085 100644 --- a/src/XbKcli/fields/getEventTypesField.js +++ b/src/XbKcli/fields/getEventTypesField.js @@ -4,7 +4,7 @@ function getEventTypesField(extras) { label: 'Event type', key: 'eventType', required: true, - type: 'integer', + type: 'string', dynamic: 'get_event_types.id.name', }, extras || {}, diff --git a/src/XbKcli/fields/getFormClassNamesField.js b/src/XbKcli/fields/getFormClassNamesField.js new file mode 100644 index 0000000..6fd31a5 --- /dev/null +++ b/src/XbKcli/fields/getFormClassNamesField.js @@ -0,0 +1,13 @@ +function getFormClassNamesField(extras) { + return Object.assign( + { + label: "Form", + key: "classname", + type: "string", + dynamic: "get_form_class_names.id.name", + }, + extras || {} + ); +} + +module.exports = getFormClassNamesField; diff --git a/src/XbKcli/fields/getFormInputsField.js b/src/XbKcli/fields/getFormInputsField.js new file mode 100644 index 0000000..a78f855 --- /dev/null +++ b/src/XbKcli/fields/getFormInputsField.js @@ -0,0 +1,14 @@ +const getFormSchema = require("../utils/getFormSchema"); +const getSimpleField = require("./getSimpleField"); + +async function getFormInputsField(z, bundle, classname) { + const schema = await getFormSchema(z, bundle, classname); + const fields = schema.map(getSimpleField); + + // Sort by columnn + fields.sort((a, b) => a.key.localeCompare(b.key)); + + return fields; +} + +module.exports = getFormInputsField; diff --git a/src/XbKcli/fields/getHeadlessChannelsField.js b/src/XbKcli/fields/getHeadlessChannelsField.js new file mode 100644 index 0000000..4681c5d --- /dev/null +++ b/src/XbKcli/fields/getHeadlessChannelsField.js @@ -0,0 +1,14 @@ +function getHeadlessChannelsField(extras) { + return Object.assign( + { + label: "Headless channel", + key: "headlessChannelId", + required: true, + type: "string", + dynamic: "get_headless_channels.id.name", + }, + extras || {} + ); +} + +module.exports = getHeadlessChannelsField; diff --git a/src/XbKcli/fields/getHeadlessItemsField.js b/src/XbKcli/fields/getHeadlessItemsField.js new file mode 100644 index 0000000..4cdb9fd --- /dev/null +++ b/src/XbKcli/fields/getHeadlessItemsField.js @@ -0,0 +1,14 @@ +function getHeadlessItemsField(extras) { + return Object.assign( + { + label: "Headless item", + key: "headlessItemId", + required: true, + type: "string", + dynamic: "get_headless_items.id.name", + }, + extras || {} + ); +} + +module.exports = getHeadlessItemsField; diff --git a/src/XbKcli/fields/getHeadlessTypesField.js b/src/XbKcli/fields/getHeadlessTypesField.js new file mode 100644 index 0000000..f4938d6 --- /dev/null +++ b/src/XbKcli/fields/getHeadlessTypesField.js @@ -0,0 +1,15 @@ +function getHeadlessTypesField(extras) { + return Object.assign( + { + label: "Headless type", + key: "headlessClassname", + required: true, + type: "string", + dynamic: "get_headless_types.id.name", + altersDynamicFields: true, + }, + extras || {} + ); +} + +module.exports = getHeadlessTypesField; diff --git a/src/XbKcli/fields/getLanguageNamesField.js b/src/XbKcli/fields/getLanguageNamesField.js new file mode 100644 index 0000000..7f98fe6 --- /dev/null +++ b/src/XbKcli/fields/getLanguageNamesField.js @@ -0,0 +1,14 @@ +function getLanguageNamesField(extras) { + return Object.assign( + { + label: "Language", + key: "languageName", + required: true, + type: "string", + dynamic: "get_language_names.id.name", + }, + extras || {} + ); +} + +module.exports = getLanguageNamesField; diff --git a/src/XbKcli/fields/getObjectTypesField.js b/src/XbKcli/fields/getObjectTypesField.js index 5d465fd..e84e333 100644 --- a/src/XbKcli/fields/getObjectTypesField.js +++ b/src/XbKcli/fields/getObjectTypesField.js @@ -6,6 +6,7 @@ function getObjectTypesField(extras) { required: true, type: 'string', dynamic: 'get_object_types.id.name', + altersDynamicFields: true, }, extras || {}, ); diff --git a/src/XbKcli/fields/getReusableItemsField.js b/src/XbKcli/fields/getReusableItemsField.js new file mode 100644 index 0000000..ad90313 --- /dev/null +++ b/src/XbKcli/fields/getReusableItemsField.js @@ -0,0 +1,14 @@ +function getReusableItemsField(extras) { + return Object.assign( + { + label: "Reusable item", + key: "reusableItemId", + required: true, + type: "string", + dynamic: "get_reusable_items.id.name", + }, + extras || {} + ); +} + +module.exports = getReusableItemsField; diff --git a/src/XbKcli/fields/getReusableTypesField.js b/src/XbKcli/fields/getReusableTypesField.js new file mode 100644 index 0000000..de8c55b --- /dev/null +++ b/src/XbKcli/fields/getReusableTypesField.js @@ -0,0 +1,14 @@ +function getReusableTypesField(extras) { + return Object.assign( + { + label: "Reusable type", + key: "reusableClassname", + required: true, + type: "string", + dynamic: "get_reusable_types.id.name", + }, + extras || {} + ); +} + +module.exports = getReusableTypesField; diff --git a/src/XbKcli/fields/getSimpleField.js b/src/XbKcli/fields/getSimpleField.js new file mode 100644 index 0000000..8427514 --- /dev/null +++ b/src/XbKcli/fields/getSimpleField.js @@ -0,0 +1,50 @@ +function getSimpleField(field) { + function getField(field, extra) { + const base = { + key: field.column, + label: `${field.fieldcaption ? field.fieldcaption : field.column}`, + required: !field.allowempty, + helpText: field.fielddescription || field.explanationtext, + default: + field.defaultvalue && typeof field.defaultvalue === "string" + ? field.defaultvalue + : "", + }; + + // Add extras + let retVal = Object.assign(base, extra); + + // Add current datetime if is datetime field with no default value + if (retVal.type === "datetime" && retVal.default === "") { + retVal.default = new Date().toLocaleString(); + } + + return retVal; + } + + switch (field.columntype) { + case "text": + case "guid": + return getField(field, { type: "string" }); + + case "longtext": + return getField(field, { type: "text" }); + + case "integer": + case "longinteger": + return getField(field, { type: "integer" }); + + case "decimal": + case "double": + case "float": + return getField(field, { type: "number" }); + + case "datetime": + return getField(field, { type: "datetime" }); + + case "boolean": + return getField(field, { type: "boolean" }); + } +} + +module.exports = getSimpleField; diff --git a/src/XbKcli/fields/getStepsField.js b/src/XbKcli/fields/getStepsField.js new file mode 100644 index 0000000..4652a43 --- /dev/null +++ b/src/XbKcli/fields/getStepsField.js @@ -0,0 +1,14 @@ +function getStepsField(extras) { + return Object.assign( + { + label: "Step name", + key: "stepName", + required: true, + type: "string", + dynamic: "get_steps_for_item.id.name", + }, + extras || {} + ); + } + + module.exports = getStepsField; \ No newline at end of file diff --git a/src/XbKcli/fields/getWebsiteChannelsField.js b/src/XbKcli/fields/getWebsiteChannelsField.js new file mode 100644 index 0000000..87bba15 --- /dev/null +++ b/src/XbKcli/fields/getWebsiteChannelsField.js @@ -0,0 +1,14 @@ +function getWebsiteChannelsField(extras) { + return Object.assign( + { + label: "Website channel", + key: "websiteChannelId", + required: true, + type: "string", + dynamic: "get_website_channels.id.name", + }, + extras || {} + ); +} + +module.exports = getWebsiteChannelsField; diff --git a/src/XbKcli/fields/getWebsiteItemsField.js b/src/XbKcli/fields/getWebsiteItemsField.js new file mode 100644 index 0000000..c45a8f0 --- /dev/null +++ b/src/XbKcli/fields/getWebsiteItemsField.js @@ -0,0 +1,14 @@ +function getWebsiteItemsField(extras) { + return Object.assign( + { + label: "Website item", + key: "pageId", + required: true, + type: "string", + dynamic: "get_website_items.id.name", + }, + extras || {} + ); +} + +module.exports = getWebsiteItemsField; diff --git a/src/XbKcli/fields/getWebsiteTypesField.js b/src/XbKcli/fields/getWebsiteTypesField.js new file mode 100644 index 0000000..185363f --- /dev/null +++ b/src/XbKcli/fields/getWebsiteTypesField.js @@ -0,0 +1,15 @@ +function getWebsiteTypesField(extras) { + return Object.assign( + { + label: "Website type", + key: "websiteClassname", + required: true, + type: "string", + dynamic: "get_website_types.id.name", + altersDynamicFields: true, + }, + extras || {} + ); +} + +module.exports = getWebsiteTypesField; diff --git a/src/XbKcli/index.js b/src/XbKcli/index.js index d4d8e66..eec9d4a 100644 --- a/src/XbKcli/index.js +++ b/src/XbKcli/index.js @@ -2,19 +2,35 @@ const { config: authentication, befores = [], afters = [], -} = require('./authentication'); - +} = require("./authentication"); const getCatchXperienceWebhook = require("./triggers/catch_xperience_webhook"); -const getObjectTypes = require('./triggers/dropdowns/getObjectTypes'); -const getEventTypes = require('./triggers/dropdowns/getEventTypes'); +const getObjectTypes = require("./triggers/dropdowns/getObjectTypes"); +const getEventTypes = require("./triggers/dropdowns/getEventTypes"); + +const insertFormRecordAction = require("./actions/insertFormRecordAction"); +const publishAction = require("./actions/publishAction"); +const moveToStepAction = require("./actions/moveToStepAction"); + +const getFormClassNames = require("./triggers/dropdowns/getFormClassNames"); +const getLanguageNames = require("./triggers/dropdowns/getLanguageNames"); +const getClassContentTypeTypes = require("./triggers/dropdowns/getClassContentTypeTypes"); +const getReusableTypes = require("./triggers/dropdowns/getReusableTypes"); +const getReusableItems = require("./triggers/dropdowns/getReusableItems"); +const getWebsiteTypes = require("./triggers/dropdowns/getWebsiteTypes"); +const getWebsiteItems = require("./triggers/dropdowns/getWebsiteItems"); +const getWebsiteChannels = require("./triggers/dropdowns/getWebsiteChannels"); +const getHeadlessTypes = require("./triggers/dropdowns/getHeadlessTypes"); +const getHeadlessItems = require("./triggers/dropdowns/getHeadlessItems"); +const getHeadlessChannels = require("./triggers/dropdowns/getHeadlessChannels"); +const getStepsForItem = require("./triggers/dropdowns/getStepsForItem"); module.exports = { // This is just shorthand to reference the installed dependencies you have. // Zapier will need to know these before we can upload. - version: require('./package.json').version, - platformVersion: require('zapier-platform-core').version, + version: require("./package.json").version, + platformVersion: require("zapier-platform-core").version, authentication, @@ -28,13 +44,29 @@ module.exports = { [getObjectTypes.key]: getObjectTypes, [getEventTypes.key]: getEventTypes, + [getFormClassNames.key]: getFormClassNames, + [getLanguageNames.key]: getLanguageNames, + [getClassContentTypeTypes.key]: getClassContentTypeTypes, + [getReusableTypes.key]: getReusableTypes, + [getWebsiteTypes.key]: getWebsiteTypes, + [getWebsiteChannels.key]: getWebsiteChannels, + [getWebsiteItems.key]: getWebsiteItems, + [getHeadlessTypes.key]: getHeadlessTypes, + [getHeadlessChannels.key]: getHeadlessChannels, + [getHeadlessItems.key]: getHeadlessItems, + [getReusableItems.key]: getReusableItems, + [getStepsForItem.key]: getStepsForItem, }, // If you want your searches to show up, you better include it here! searches: {}, // If you want your creates to show up, you better include it here! - creates: {}, + creates: { + [insertFormRecordAction.key]: insertFormRecordAction, + [publishAction.key]: publishAction, + [moveToStepAction.key]: moveToStepAction, + }, resources: {}, }; diff --git a/src/XbKcli/package-lock.json b/src/XbKcli/package-lock.json index d4710c4..b1de2a3 100644 --- a/src/XbKcli/package-lock.json +++ b/src/XbKcli/package-lock.json @@ -1,13 +1,14 @@ { "name": "xperience-by-kentico-zapier-cli", - "version": "0.0.1", + "version": "0.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "xperience-by-kentico-zapier-cli", - "version": "0.0.1", + "version": "0.1.0", "dependencies": { + "xml2js": "0.6.2", "zapier-platform-core": "15.5.2" }, "devDependencies": { @@ -3434,6 +3435,11 @@ } ] }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -3831,6 +3837,26 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -6534,6 +6560,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" + }, "semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -6824,6 +6855,20 @@ "signal-exit": "^3.0.7" } }, + "xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/src/XbKcli/package.json b/src/XbKcli/package.json index d0d7ca9..32e6ca9 100644 --- a/src/XbKcli/package.json +++ b/src/XbKcli/package.json @@ -1,13 +1,14 @@ { "name": "xperience-by-kentico-zapier-cli", - "version": "0.0.1", + "version": "0.1.0", "description": "", "main": "index.js", "scripts": { "test": "jest --testTimeout 10000" }, "dependencies": { - "zapier-platform-core": "15.5.2" + "zapier-platform-core": "15.5.2", + "xml2js": "0.6.2" }, "devDependencies": { "jest": "^29.6.0" diff --git a/src/XbKcli/test/actions/insertFormRecordAction.test.js b/src/XbKcli/test/actions/insertFormRecordAction.test.js new file mode 100644 index 0000000..4d8abd0 --- /dev/null +++ b/src/XbKcli/test/actions/insertFormRecordAction.test.js @@ -0,0 +1,30 @@ +const zapier = require("zapier-platform-core"); + +// Use this to make test calls into your app: +const App = require("../../index"); +const appTester = zapier.createAppTester(App); +// read the `.env` file into the environment, if available +zapier.tools.env.inject(); + +describe("actions.insertFormRecordAction", () => { + it("should run", async () => { + const bundle = { + inputData: { + classname: "BizForm.DancingGoatContactUs", + }, + authData: { + website: "https://vv2q1r24-26547.euw.devtunnels.ms", + apiKey: "juwcdWAffCrNsI9IHgXVWIFef8T7wjLyH7oqa4HVZcM=", + }, + }; + + const results = await appTester( + App.creates["insertFormRecordAction"].operation.perform, + bundle + ); + //expect(results).toBeDefined(); + + //const results2 = await appTester(App.triggers['get_object_types'].operation.perform, bundle); + // TODO: add more assertions + }); +}); diff --git a/src/XbKcli/triggers/catch_xperience_webhook.js b/src/XbKcli/triggers/catch_xperience_webhook.js index 7358e78..2ebe2fd 100644 --- a/src/XbKcli/triggers/catch_xperience_webhook.js +++ b/src/XbKcli/triggers/catch_xperience_webhook.js @@ -96,7 +96,7 @@ const performUnsubscribe = async (z, bundle) => { const getFallbackData = async (z, bundle) => { const options = { - url: `${bundle.authData.website}/zapier/object/${bundle.inputData.objectType}`, + url: `${bundle.authData.website}/zapier/object/${bundle.inputData.objectType}/${bundle.inputData.eventType}`, method: 'GET', params: { topN: 1, diff --git a/src/XbKcli/triggers/dropdowns/getClassContentTypeTypes.js b/src/XbKcli/triggers/dropdowns/getClassContentTypeTypes.js new file mode 100644 index 0000000..20304b7 --- /dev/null +++ b/src/XbKcli/triggers/dropdowns/getClassContentTypeTypes.js @@ -0,0 +1,37 @@ +async function execute(z, bundle) { + const options = { + url: `${bundle.authData.website}/zapier/actions/types`, + method: "GET", + headers: { + Accept: "application/json", + }, + }; + + let classnames = await z.request(options); + return z.JSON.parse(classnames.content); +} + +module.exports = { + key: "get_class_content_type_types", + noun: "Content type selector", + display: { + label: "Type", + description: "Gets content types", + hidden: true, + }, + operation: { + type: "polling", + perform: execute, + sample: { + id: "Reusable", + name: "Reusable", + }, + outputFields: [ + { + key: "name", + label: "Content type", + type: "string", + }, + ], + }, +}; diff --git a/src/XbKcli/triggers/dropdowns/getEventTypes.js b/src/XbKcli/triggers/dropdowns/getEventTypes.js index adde5e2..8f8c6da 100644 --- a/src/XbKcli/triggers/dropdowns/getEventTypes.js +++ b/src/XbKcli/triggers/dropdowns/getEventTypes.js @@ -1,42 +1,39 @@ - async function execute(z, bundle) { + const options = { + url: `${bundle.authData.website}/zapier/data/events/${bundle.inputData.objectType}`, + method: "GET", + }; - const options = { - url: `${bundle.authData.website}/zapier/data/events`, - method: 'GET' - }; - - let eventTypes = await z.request(options); - return z.JSON.parse(eventTypes.content); + let eventTypes = await z.request(options); + return z.JSON.parse(eventTypes.content); } - module.exports = { - key: 'get_event_types', - noun: 'Event type', - display: { - label: 'Event type', - description: 'Gets supported event types', - hidden: true, + key: "get_event_types", + noun: "Event type", + display: { + label: "Event type", + description: "Gets supported event types", + hidden: true, + }, + operation: { + type: "polling", + perform: execute, + sample: { + id: "event", + name: "om.contact", }, - operation: { - type: 'polling', - perform: execute, - sample: { - id: 0, - name: 'om.contact', - }, - outputFields: [ - { - key: 'name', - label: 'Event type display name', - type: 'string', - }, - { - key: 'id', - label: 'Event type codename', - type: 'integer', - } - ] - } -}; \ No newline at end of file + outputFields: [ + { + key: "name", + label: "Event type display name", + type: "string", + }, + { + key: "id", + label: "Event type codename", + type: "string", + }, + ], + }, +}; diff --git a/src/XbKcli/triggers/dropdowns/getFormClassNames.js b/src/XbKcli/triggers/dropdowns/getFormClassNames.js new file mode 100644 index 0000000..bcba743 --- /dev/null +++ b/src/XbKcli/triggers/dropdowns/getFormClassNames.js @@ -0,0 +1,42 @@ +async function execute(z, bundle) { + const options = { + url: `${bundle.authData.website}/zapier/actions/biz-form/classnames`, + method: "GET", + headers: { + Accept: "application/json", + }, + }; + + let classnames = await z.request(options); + return z.JSON.parse(classnames.content); +} + +module.exports = { + key: "get_form_class_names", + noun: "Form class name", + display: { + label: "Form class name", + description: "Gets supported form class names", + hidden: true, + }, + operation: { + type: "polling", + perform: execute, + sample: { + id: "BizForm.DancingGoatContactUs", + name: "Contact Us", + }, + outputFields: [ + { + key: "id", + label: "Form class name", + type: "string", + }, + { + key: "name", + label: "Form name", + type: "string", + }, + ], + }, +}; diff --git a/src/XbKcli/triggers/dropdowns/getHeadlessChannels.js b/src/XbKcli/triggers/dropdowns/getHeadlessChannels.js new file mode 100644 index 0000000..5bcc23c --- /dev/null +++ b/src/XbKcli/triggers/dropdowns/getHeadlessChannels.js @@ -0,0 +1,44 @@ +const ClassContentTypeType = require("../../utils/enums"); + +async function execute(z, bundle) { + const options = { + url: `${bundle.authData.website}/zapier/actions/${ClassContentTypeType.HEADLESS}/channels`, + method: "GET", + headers: { + Accept: "application/json", + }, + }; + + let classnames = await z.request(options); + return z.JSON.parse(classnames.content); +} + +module.exports = { + key: "get_headless_channels", + noun: "Headless channel selector", + display: { + label: "Headless channel", + description: "Gets headless channels", + hidden: true, + }, + operation: { + type: "polling", + perform: execute, + sample: { + id: "en", + name: "English", + }, + outputFields: [ + { + key: "id", + label: "Headless channel identifier", + type: "string", + }, + { + key: "name", + label: "Headless channel", + type: "string", + }, + ], + }, +}; diff --git a/src/XbKcli/triggers/dropdowns/getHeadlessItems.js b/src/XbKcli/triggers/dropdowns/getHeadlessItems.js new file mode 100644 index 0000000..0ab84fc --- /dev/null +++ b/src/XbKcli/triggers/dropdowns/getHeadlessItems.js @@ -0,0 +1,42 @@ +const ClassContentTypeType = require("../../utils/enums"); + +async function execute(z, bundle) { + const options = { + url: `${bundle.authData.website}/zapier/actions/${ClassContentTypeType.HEADLESS}/${bundle.inputData.headlessClassname}/${bundle.inputData.headlessChannelId}/${bundle.inputData.languageName}`, + method: "GET", + }; + + let headlessItems = await z.request(options); + + return z.JSON.parse(headlessItems.content); +} + +module.exports = { + key: "get_headless_items", + noun: "Headless item selector", + display: { + label: "Headless item", + description: "Gets supported headless items", + hidden: true, + }, + operation: { + type: "polling", + perform: execute, + sample: { + id: "DancingGoat.Coffee", + name: "Boston coffee place", + }, + outputFields: [ + { + key: "id", + label: "Classname", + type: "string", + }, + { + key: "name", + label: "Display name", + type: "string", + }, + ], + }, +}; diff --git a/src/XbKcli/triggers/dropdowns/getHeadlessTypes.js b/src/XbKcli/triggers/dropdowns/getHeadlessTypes.js new file mode 100644 index 0000000..4bfb3d1 --- /dev/null +++ b/src/XbKcli/triggers/dropdowns/getHeadlessTypes.js @@ -0,0 +1,42 @@ +const ClassContentTypeType = require("../../utils/enums"); + +async function execute(z, bundle) { + const options = { + url: `${bundle.authData.website}/zapier/actions/types/${ClassContentTypeType.HEADLESS}/${bundle.inputData.headlessChannelId}`, + method: "GET", + }; + + let headlessTypes = await z.request(options); + + return z.JSON.parse(headlessTypes.content); +} + +module.exports = { + key: "get_headless_types", + noun: "Headless type", + display: { + label: "Headless type", + description: "Gets supported headless types", + hidden: true, + }, + operation: { + type: "polling", + perform: execute, + sample: { + id: "DancingGoat.Coffee", + name: "Coffee", + }, + outputFields: [ + { + key: "id", + label: "Classname", + type: "string", + }, + { + key: "name", + label: "Display name", + type: "string", + }, + ], + }, +}; diff --git a/src/XbKcli/triggers/dropdowns/getLanguageNames.js b/src/XbKcli/triggers/dropdowns/getLanguageNames.js new file mode 100644 index 0000000..27dfffe --- /dev/null +++ b/src/XbKcli/triggers/dropdowns/getLanguageNames.js @@ -0,0 +1,42 @@ +async function execute(z, bundle) { + const options = { + url: `${bundle.authData.website}/zapier/actions/languages`, + method: "GET", + headers: { + Accept: "application/json", + }, + }; + + let classnames = await z.request(options); + return z.JSON.parse(classnames.content); +} + +module.exports = { + key: "get_language_names", + noun: "Language name selector", + display: { + label: "Language name", + description: "Gets supported languages", + hidden: true, + }, + operation: { + type: "polling", + perform: execute, + sample: { + id: "en", + name: "English", + }, + outputFields: [ + { + key: "id", + label: "Language shortcut", + type: "string", + }, + { + key: "name", + label: "Language name", + type: "string", + }, + ], + }, +}; diff --git a/src/XbKcli/triggers/dropdowns/getReusableItems.js b/src/XbKcli/triggers/dropdowns/getReusableItems.js new file mode 100644 index 0000000..0e34f89 --- /dev/null +++ b/src/XbKcli/triggers/dropdowns/getReusableItems.js @@ -0,0 +1,42 @@ +const ClassContentTypeType = require("../../utils/enums"); + +async function execute(z, bundle) { + const options = { + url: `${bundle.authData.website}/zapier/actions/${ClassContentTypeType.REUSABLE}/${bundle.inputData.reusableClassname}/${bundle.inputData.languageName}`, + method: "GET", + }; + + let reusableItems = await z.request(options); + + return z.JSON.parse(reusableItems.content); +} + +module.exports = { + key: "get_reusable_items", + noun: "Reusable item selector", + display: { + label: "Reusable item", + description: "Gets supported reusable items", + hidden: true, + }, + operation: { + type: "polling", + perform: execute, + sample: { + id: "DancingGoat.Coffee", + name: "Boston coffee place", + }, + outputFields: [ + { + key: "id", + label: "Classname", + type: "string", + }, + { + key: "name", + label: "Display name", + type: "string", + }, + ], + }, +}; diff --git a/src/XbKcli/triggers/dropdowns/getReusableTypes.js b/src/XbKcli/triggers/dropdowns/getReusableTypes.js new file mode 100644 index 0000000..09ed2ef --- /dev/null +++ b/src/XbKcli/triggers/dropdowns/getReusableTypes.js @@ -0,0 +1,40 @@ +async function execute(z, bundle) { + const options = { + url: `${bundle.authData.website}/zapier/actions/types/reusable`, + method: "GET", + }; + + let reusableTypes = await z.request(options); + + return z.JSON.parse(reusableTypes.content); +} + +module.exports = { + key: "get_reusable_types", + noun: "Reusable type", + display: { + label: "Reusable type", + description: "Gets supported reusable types", + hidden: true, + }, + operation: { + type: "polling", + perform: execute, + sample: { + id: "DancingGoat.Coffee", + name: "Coffee", + }, + outputFields: [ + { + key: "id", + label: "Classname", + type: "string", + }, + { + key: "name", + label: "Display name", + type: "string", + }, + ], + }, +}; diff --git a/src/XbKcli/triggers/dropdowns/getStepsForItem.js b/src/XbKcli/triggers/dropdowns/getStepsForItem.js new file mode 100644 index 0000000..34f1d29 --- /dev/null +++ b/src/XbKcli/triggers/dropdowns/getStepsForItem.js @@ -0,0 +1,56 @@ +const ClassContentTypeType = require("../../utils/enums"); + +async function execute(z, bundle) { + let type = ""; + + if (bundle.inputData.classContentTypeType == ClassContentTypeType.WEBSITE) { + type = bundle.inputData.websiteClassname; + } else if ( + bundle.inputData.classContentTypeType == ClassContentTypeType.REUSABLE + ) { + type = bundle.inputData.reusableClassname; + } else if ( + bundle.inputData.classContentTypeType == ClassContentTypeType.HEADLESS + ) { + type = bundle.inputData.headlessClassname; + } + + const options = { + url: `${bundle.authData.website}/zapier/actions/movetostep/steps/${type}`, + method: "GET", + }; + + let result = await z.request(options); + + return z.JSON.parse(result.content); +} + +module.exports = { + key: "get_steps_for_item", + noun: "Step selector", + display: { + label: "Step name", + description: "Gets supported steps", + hidden: true, + }, + operation: { + type: "polling", + perform: execute, + sample: { + id: "DancingGoat.Coffee", + name: "Boston coffee place", + }, + outputFields: [ + { + key: "id", + label: "Step name", + type: "string", + }, + { + key: "name", + label: "Step display name", + type: "string", + }, + ], + }, +}; diff --git a/src/XbKcli/triggers/dropdowns/getWebsiteChannels.js b/src/XbKcli/triggers/dropdowns/getWebsiteChannels.js new file mode 100644 index 0000000..0eb82ac --- /dev/null +++ b/src/XbKcli/triggers/dropdowns/getWebsiteChannels.js @@ -0,0 +1,44 @@ +const ClassContentTypeType = require("../../utils/enums"); + +async function execute(z, bundle) { + const options = { + url: `${bundle.authData.website}/zapier/actions/${ClassContentTypeType.WEBSITE}/channels`, + method: "GET", + headers: { + Accept: "application/json", + }, + }; + + let classnames = await z.request(options); + return z.JSON.parse(classnames.content); +} + +module.exports = { + key: "get_website_channels", + noun: "Website channel selector", + display: { + label: "Website channel", + description: "Gets website channels", + hidden: true, + }, + operation: { + type: "polling", + perform: execute, + sample: { + id: "en", + name: "English", + }, + outputFields: [ + { + key: "id", + label: "Website channel identifier", + type: "string", + }, + { + key: "name", + label: "Website channel", + type: "string", + }, + ], + }, +}; diff --git a/src/XbKcli/triggers/dropdowns/getWebsiteItems.js b/src/XbKcli/triggers/dropdowns/getWebsiteItems.js new file mode 100644 index 0000000..6564417 --- /dev/null +++ b/src/XbKcli/triggers/dropdowns/getWebsiteItems.js @@ -0,0 +1,42 @@ +const ClassContentTypeType = require("../../utils/enums"); + +async function execute(z, bundle) { + const options = { + url: `${bundle.authData.website}/zapier/actions/${ClassContentTypeType.WEBSITE}/${bundle.inputData.websiteClassname}/${bundle.inputData.websiteChannelId}/${bundle.inputData.languageName}`, + method: "GET", + }; + + let websiteItems = await z.request(options); + + return z.JSON.parse(websiteItems.content); +} + +module.exports = { + key: "get_website_items", + noun: "Website item selector", + display: { + label: "Website item", + description: "Gets supported website items", + hidden: true, + }, + operation: { + type: "polling", + perform: execute, + sample: { + id: "DancingGoat.Coffee", + name: "Boston coffee place", + }, + outputFields: [ + { + key: "id", + label: "Classname", + type: "string", + }, + { + key: "name", + label: "Display name", + type: "string", + }, + ], + }, +}; diff --git a/src/XbKcli/triggers/dropdowns/getWebsiteTypes.js b/src/XbKcli/triggers/dropdowns/getWebsiteTypes.js new file mode 100644 index 0000000..7ec7a50 --- /dev/null +++ b/src/XbKcli/triggers/dropdowns/getWebsiteTypes.js @@ -0,0 +1,42 @@ +const ClassContentTypeType = require("../../utils/enums"); + +async function execute(z, bundle) { + const options = { + url: `${bundle.authData.website}/zapier/actions/types/${ClassContentTypeType.WEBSITE}/${bundle.inputData.websiteChannelId}`, + method: "GET", + }; + + let websiteTypes = await z.request(options); + + return z.JSON.parse(websiteTypes.content); +} + +module.exports = { + key: "get_website_types", + noun: "Website type", + display: { + label: "Website type", + description: "Gets supported website types", + hidden: true, + }, + operation: { + type: "polling", + perform: execute, + sample: { + id: "DancingGoat.Coffee", + name: "Coffee", + }, + outputFields: [ + { + key: "id", + label: "Classname", + type: "string", + }, + { + key: "name", + label: "Display name", + type: "string", + }, + ], + }, +}; diff --git a/src/XbKcli/utils/enums.js b/src/XbKcli/utils/enums.js new file mode 100644 index 0000000..ad27fc6 --- /dev/null +++ b/src/XbKcli/utils/enums.js @@ -0,0 +1,7 @@ +const ClassContentTypeType = { + HEADLESS: "Headless", + REUSABLE: "Reusable", + WEBSITE: "Website", +}; + +module.exports = ClassContentTypeType; diff --git a/src/XbKcli/utils/getFormSchema.js b/src/XbKcli/utils/getFormSchema.js new file mode 100644 index 0000000..39fb4e6 --- /dev/null +++ b/src/XbKcli/utils/getFormSchema.js @@ -0,0 +1,59 @@ +const parseString = require("xml2js").parseString; + +async function getFormSchema(z, bundle, classname) { + let retVal = []; + if (!classname) return retVal; + function makeField(fieldDefinition) { + const fieldAttrs = fieldDefinition["$"]; + let fieldProps = fieldDefinition.properties; + let field = { + column: fieldAttrs.column, + columntype: fieldAttrs.columntype, + columnsize: fieldAttrs.columnsize, + isPK: fieldAttrs.isPK || false, + allowempty: fieldAttrs.allowempty || false, + visible: fieldAttrs.visible && fieldAttrs.visible === "true", + system: fieldAttrs.system && fieldAttrs.system === "true", + }; + if (fieldProps) { + fieldProps = fieldProps[0]; + (field.defaultvalue = fieldProps.defaultvalue + ? fieldProps.defaultvalue[0] + : undefined), + (field.fieldcaption = fieldProps.fieldcaption + ? fieldProps.fieldcaption[0] + : undefined), + (field.explanationtext = fieldProps.explanationtext + ? fieldProps.explanationtext[0] + : undefined), + (field.fielddescription = fieldProps.fielddescription + ? fieldProps.fielddescription[0] + : undefined); + } + + return field; + } + + const options = { + url: `${bundle.authData.website}/zapier/actions/biz-form/${classname}`, + method: "GET", + headers: { + Accept: "application/json", + }, + }; + const response = await z.request(options); + const classFormDefinition = z.JSON.parse(response.content); + + parseString(classFormDefinition, function (err, json) { + const fields = json.form.field; + if (fields && fields.length > 0) { + retVal = fields.map(makeField); + } + }); + retVal = retVal.filter( + (f) => !f.isPK && f.columntype !== "guid" && !f.system + ); + return retVal; +} + +module.exports = getFormSchema;