diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/AddModelErrorActivity.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/AddModelErrorActivity.cs new file mode 100644 index 000000000..4347e4c4d --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/AddModelErrorActivity.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using Orchard.ContentManagement; +using Orchard.Localization; +using Orchard.Workflows.Models; +using Orchard.Workflows.Services; + +namespace Orchard.DynamicForms.Activities { + public class AddModelErrorActivity : Task { + public AddModelErrorActivity() { + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + public override string Name { + get { return "AddModelError"; } + } + + public override LocalizedString Category { + get { return T("Forms"); } + } + + public override LocalizedString Description { + get { return T("Add a model validation error"); } + } + + public override string Form { + get { return "AddModelError"; } + } + + public override IEnumerable GetPossibleOutcomes(WorkflowContext workflowContext, ActivityContext activityContext) { + return new[] {T("Done")}; + } + + public override bool CanExecute(WorkflowContext workflowContext, ActivityContext activityContext) { + return workflowContext.Tokens.ContainsKey("Updater") && workflowContext.Tokens["Updater"] is IUpdateModel; + } + + public override IEnumerable Execute(WorkflowContext workflowContext, ActivityContext activityContext) { + var key = activityContext.GetState("Key"); + var message = activityContext.GetState("ErrorMessage"); + var updater = (IUpdateModel) workflowContext.Tokens["Updater"]; + + updater.AddModelError(key, T(message)); + + return new[] { T("Done") }; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/DynamicFormActivity.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/DynamicFormActivity.cs new file mode 100644 index 000000000..b0a2a8062 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/DynamicFormActivity.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Orchard.DynamicForms.Services.Models; +using Orchard.Localization; +using Orchard.Workflows.Models; +using Orchard.Workflows.Services; + +namespace Orchard.DynamicForms.Activities { + public abstract class DynamicFormActivity : Event { + protected DynamicFormActivity() { + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + public override bool CanStartWorkflow { + get { return true; } + } + + public override bool CanExecute(WorkflowContext workflowContext, ActivityContext activityContext) { + var forms = activityContext.GetState("DynamicForms"); + + // "" means 'any'. + if (String.IsNullOrEmpty(forms)) { + return true; + } + + var submission = (FormSubmissionTokenContext)workflowContext.Tokens["FormSubmission"]; + + if (submission == null) { + return false; + } + + var formNames = forms.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + return formNames.Any(x => x == submission.Form.Name); + } + + public override IEnumerable GetPossibleOutcomes(WorkflowContext workflowContext, ActivityContext activityContext) { + return new[] { T("Done") }; + } + + public override IEnumerable Execute(WorkflowContext workflowContext, ActivityContext activityContext) { + yield return T("Done"); + } + + public override string Form { + get { + return "SelectDynamicForms"; + } + } + + public override LocalizedString Category { + get { return T("Forms"); } + } + } + +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/DynamicFormSubmittedActivity.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/DynamicFormSubmittedActivity.cs index 899823e16..d3462b1c1 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/DynamicFormSubmittedActivity.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/DynamicFormSubmittedActivity.cs @@ -1,66 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Orchard.DynamicForms.Elements; -using Orchard.DynamicForms.Services.Models; -using Orchard.Localization; -using Orchard.Workflows.Models; -using Orchard.Workflows.Services; +using Orchard.Localization; namespace Orchard.DynamicForms.Activities { - public class DynamicFormSubmittedActivity : Event { + public class DynamicFormSubmittedActivity : DynamicFormActivity { public const string EventName = "DynamicFormSubmitted"; - public Localizer T { get; set; } - - public override bool CanStartWorkflow { - get { return true; } - } - - public override bool CanExecute(WorkflowContext workflowContext, ActivityContext activityContext) { - var forms = activityContext.GetState("DynamicForms"); - - // "" means 'any'. - if (String.IsNullOrEmpty(forms)) { - return true; - } - - var submission = (FormSubmissionTokenContext)workflowContext.Tokens["FormSubmission"]; - - if (submission == null) { - return false; - } - - var formNames = forms.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - return formNames.Any(x => x == submission.Form.Name); - } - - public override IEnumerable GetPossibleOutcomes(WorkflowContext workflowContext, ActivityContext activityContext) { - return new[] { T("Done") }; - } - - public override IEnumerable Execute(WorkflowContext workflowContext, ActivityContext activityContext) { - yield return T("Done"); - } - - public override string Form { - get { - return "SelectDynamicForms"; - } - } - public override string Name { get { return EventName; } } - public override LocalizedString Category { - get { return T("Forms"); } - } - public override LocalizedString Description { get { return T("A dynamic form is submitted."); } } } - } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/DynamicFormValidatingActivity.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/DynamicFormValidatingActivity.cs new file mode 100644 index 000000000..3835eb1a9 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/DynamicFormValidatingActivity.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using Orchard.DynamicForms.Services.Models; +using Orchard.Localization; +using Orchard.Scripting.CSharp.Services; +using Orchard.Workflows.Models; + +namespace Orchard.DynamicForms.Activities { + public class DynamicFormValidatingActivity : DynamicFormActivity { + private readonly ICSharpService _csharpService; + private readonly IOrchardServices _orchardServices; + private readonly IWorkContextAccessor _workContextAccessor; + + public DynamicFormValidatingActivity(ICSharpService csharpService, IOrchardServices orchardServices, IWorkContextAccessor workContextAccessor) { + _csharpService = csharpService; + _orchardServices = orchardServices; + _workContextAccessor = workContextAccessor; + } + + public const string EventName = "DynamicFormValidating"; + + public override string Name { + get { return EventName; } + } + + public override LocalizedString Description { + get { return T("A dynamic form is being validated."); } + } + + public override IEnumerable Execute(WorkflowContext workflowContext, ActivityContext activityContext) { + var script = activityContext.GetState("Script"); + + if (!String.IsNullOrWhiteSpace(script)) { + var submission = (FormSubmissionTokenContext) workflowContext.Tokens["FormSubmission"]; + + // Start the script with the new token syntax. + script = "// #{ }" + System.Environment.NewLine + script; + + if (workflowContext.Content != null) + _csharpService.SetParameter("ContentItem", (dynamic) workflowContext.Content.ContentItem); + + _csharpService.SetParameter("Services", _orchardServices); + _csharpService.SetParameter("WorkContext", _workContextAccessor.GetContext()); + _csharpService.SetParameter("Workflow", workflowContext); + _csharpService.SetFunction("T", (Func) (x => T(x).Text)); + _csharpService.SetFunction("AddModelError", (Action) ((key, message) => submission.ModelState.AddModelError(key, message.Text))); + + _csharpService.Run(script); + } + + return base.Execute(workflowContext, activityContext); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/AddModelErrorForm.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/AddModelErrorForm.cs new file mode 100644 index 000000000..2c21df9a8 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/AddModelErrorForm.cs @@ -0,0 +1,28 @@ +using Orchard.Forms.Services; + +namespace Orchard.DynamicForms.Forms { + public class AddModelErrorForm : Component, IFormProvider { + + public void Describe(DescribeContext context) { + context.Form("AddModelError", factory => { + var shape = (dynamic)factory; + var form = shape.Form( + Id: "AddModelError", + _Key: shape.Textbox( + Id: "key", + Name: "Key", + Title: "Key", + Classes: new[] { "text", "large", "tokenized" }, + Description: T("The key / form field name for which to add a model validation error.")), + _Message: shape.Textbox( + Id: "errorMessage", + Name: "ErrorMessage", + Title: "Error Message", + Classes: new[] { "text", "large", "tokenized" }, + Description: T("The model validation error message to add."))); + + return form; + }); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/DynamicFormValidatingForm.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/DynamicFormValidatingForm.cs new file mode 100644 index 000000000..11b10e708 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/DynamicFormValidatingForm.cs @@ -0,0 +1,21 @@ +using Orchard.Forms.Services; + +namespace Orchard.DynamicForms.Forms { + public class DynamicFormValidatingForm : Component, IFormProvider { + public void Describe(DescribeContext context) { + context.Form("DynamicFormValidatingScript", shapeFactory => { + var shape = (dynamic) shapeFactory; + var form = shape.Form( + Id: "DynamicFormValidatingScript", + _Script: shape.TextArea( + Id: "Script", + Name: "Script", + Title: T("Script"), + Description: T("The script to validate the submitted form. You can use ContentItem, Services, WorkContext, Workflow and T(). Call AddModelError(string key, LocalizedString errorMessage) to add modelstate errors."), + Classes: new[] {"tokenized"})); + + return form; + }); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/SelectDynamicForms.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/SelectDynamicForms.cs similarity index 86% rename from src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/SelectDynamicForms.cs rename to src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/SelectDynamicForms.cs index e7ce09fb8..2fc565bb9 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Activities/SelectDynamicForms.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Forms/SelectDynamicForms.cs @@ -1,12 +1,8 @@ -using System; -using System.Linq; -using System.Web.Mvc; -using Orchard.ContentManagement; -using Orchard.DisplayManagement; +using Orchard.DisplayManagement; using Orchard.Forms.Services; using Orchard.Localization; -namespace Orchard.DynamicForms.Activities { +namespace Orchard.DynamicForms.Forms { public class SelectDynamicForms : IFormProvider { protected dynamic Shape { get; set; } public Localizer T { get; set; } diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Handlers/WorkflowValidatorCoordinator.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Handlers/WorkflowValidatorCoordinator.cs new file mode 100644 index 000000000..3f6c9e523 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Handlers/WorkflowValidatorCoordinator.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using Orchard.DynamicForms.Activities; +using Orchard.DynamicForms.Services; +using Orchard.DynamicForms.Services.Models; +using Orchard.Layouts.Helpers; +using Orchard.Workflows.Services; + +namespace Orchard.DynamicForms.Handlers { + public class WorkflowValidatorCoordinator : FormEventHandlerBase { + private readonly IWorkflowManager _workflowManager; + public WorkflowValidatorCoordinator(IWorkflowManager workflowManager) { + _workflowManager = workflowManager; + } + + public override void Validating(FormValidatingEventContext context) { + var form = context.Form; + var values = context.Values; + var formValuesDictionary = values.ToTokenDictionary(); + + var formTokenContext = new FormSubmissionTokenContext { + Form = form, + ModelState = context.ModelState, + PostedValues = values + }; + var tokensData = new Dictionary(formValuesDictionary) { + {"Updater", context.Updater}, + {"FormSubmission", formTokenContext}, + }; + + _workflowManager.TriggerEvent(name: DynamicFormValidatingActivity.EventName, target: null, tokensContext: () => tokensData); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Module.txt b/src/Orchard.Web/Modules/Orchard.DynamicForms/Module.txt index 4a1df83ba..8c9cbbea7 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Module.txt @@ -10,7 +10,7 @@ Features: Name: Dynamic Forms Description: Create custom forms like contact forms using layouts. Category: Forms - Dependencies: Orchard.Layouts, Orchard.Tokens, Orchard.Workflows, Orchard.Users, Orchard.AuditTrail, Common + Dependencies: Orchard.Layouts, Orchard.Scripting.CSharp, Orchard.Tokens, Orchard.Workflows, Orchard.Users, Orchard.AuditTrail, Common Orchard.DynamicForms.AntiSpam: Name: Anti-Spam Elements Description: Provides anti-spam elements to protect your content from malicious submissions. diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Orchard.DynamicForms.csproj b/src/Orchard.Web/Modules/Orchard.DynamicForms/Orchard.DynamicForms.csproj index 1da2dec0b..4741c2cff 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Orchard.DynamicForms.csproj +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Orchard.DynamicForms.csproj @@ -119,6 +119,10 @@ {5531e894-d259-45a3-aa61-26dbe720c1ce} Orchard.Projections + + {5d13ef34-8b39-4ec5-847f-e12892acf841} + Orchard.Scripting.CSharp + {e649ea64-d213-461b-87f7-d67035801443} Orchard.Taxonomies @@ -137,8 +141,12 @@ + + + - + + @@ -157,7 +165,9 @@ + + diff --git a/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/FormService.cs b/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/FormService.cs index 62e0575bf..8ec388484 100644 --- a/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/FormService.cs +++ b/src/Orchard.Web/Modules/Orchard.DynamicForms/Services/FormService.cs @@ -269,9 +269,11 @@ namespace Orchard.DynamicForms.Services { } var contentTypeSettings = contentTypeDefinition.Settings.GetModel(); - var versionOptions = form.Publication == "Publish" || !contentTypeSettings.Draftable ? VersionOptions.Published : VersionOptions.Draft; - - _contentManager.Create(contentItem, versionOptions); + _contentManager.Create(contentItem, VersionOptions.Draft); + + if (form.Publication == "Publish" || !contentTypeSettings.Draftable) { + _contentManager.Publish(contentItem); + } return contentItem; }