mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Including Orchard.CustomForms
--HG-- branch : 1.x
This commit is contained in:
18
src/Orchard.Web/Modules/Orchard.CustomForms/AdminMenu.cs
Normal file
18
src/Orchard.Web/Modules/Orchard.CustomForms/AdminMenu.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Orchard.Localization;
|
||||
using Orchard.Security;
|
||||
using Orchard.UI.Navigation;
|
||||
|
||||
namespace Orchard.CustomForms {
|
||||
public class AdminMenu : INavigationProvider {
|
||||
public Localizer T { get; set; }
|
||||
public string MenuName { get { return "admin"; } }
|
||||
|
||||
public void GetNavigation(NavigationBuilder builder) {
|
||||
builder.Add(T("Forms"), "4",
|
||||
menu => menu
|
||||
.Add(T("Manage Forms"), "1.0",
|
||||
item => item.Action("Index", "Admin", new { area = "Orchard.CustomForms" }).Permission(StandardPermissions.SiteOwner))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,145 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Core.Common.Models;
|
||||
using Orchard.Core.Title.Models;
|
||||
using Orchard.CustomForms.Models;
|
||||
using Orchard.CustomForms.ViewModels;
|
||||
using Orchard.DisplayManagement;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Security;
|
||||
using System;
|
||||
using Orchard.Settings;
|
||||
using Orchard.UI.Navigation;
|
||||
|
||||
namespace Orchard.CustomForms.Controllers {
|
||||
[ValidateInput(false)]
|
||||
public class AdminController : Controller {
|
||||
private readonly ISiteService _siteService;
|
||||
|
||||
public AdminController(
|
||||
IOrchardServices services,
|
||||
IShapeFactory shapeFactory,
|
||||
ISiteService siteService) {
|
||||
_siteService = siteService;
|
||||
Services = services;
|
||||
|
||||
T = NullLocalizer.Instance;
|
||||
Shape = shapeFactory;
|
||||
}
|
||||
|
||||
dynamic Shape { get; set; }
|
||||
public IOrchardServices Services { get; set; }
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public ActionResult Index(CustomFormIndexOptions options, PagerParameters pagerParameters) {
|
||||
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to list custom forms")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
|
||||
|
||||
// default options
|
||||
if (options == null)
|
||||
options = new CustomFormIndexOptions();
|
||||
|
||||
var query = Services.ContentManager.Query().ForType("CustomForm", "CustomFormWidget");
|
||||
|
||||
switch (options.Filter) {
|
||||
case CustomFormFilter.All:
|
||||
break;
|
||||
}
|
||||
|
||||
var pagerShape = Shape.Pager(pager).TotalItemCount(query.Count());
|
||||
|
||||
switch (options.Order) {
|
||||
case CustomFormOrder.Creation:
|
||||
query = query.Join<CommonPartRecord>().OrderByDescending(u => u.CreatedUtc);
|
||||
break;
|
||||
}
|
||||
|
||||
var results = query
|
||||
.Slice(pager.GetStartIndex(), pager.PageSize);
|
||||
|
||||
var model = new CustomFormIndexViewModel {
|
||||
CustomForms = results.Select(x => new CustomFormEntry { CustomForm = x.As<CustomFormPart>() }).ToList(),
|
||||
Options = options,
|
||||
Pager = pagerShape
|
||||
};
|
||||
|
||||
// maintain previous route data when generating page links
|
||||
var routeData = new RouteData();
|
||||
routeData.Values.Add("Options.Filter", options.Filter);
|
||||
routeData.Values.Add("Options.Search", options.Search);
|
||||
routeData.Values.Add("Options.Order", options.Order);
|
||||
|
||||
pagerShape.RouteData(routeData);
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Core.Contents.Controllers.FormValueRequired("submit.BulkEdit")]
|
||||
public ActionResult Index(FormCollection input) {
|
||||
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage customForm")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var viewModel = new CustomFormIndexViewModel { CustomForms = new List<CustomFormEntry>(), Options = new CustomFormIndexOptions() };
|
||||
UpdateModel(viewModel);
|
||||
|
||||
var checkedEntries = viewModel.CustomForms.Where(c => c.IsChecked);
|
||||
switch (viewModel.Options.BulkAction) {
|
||||
case CustomFormBulkAction.None:
|
||||
break;
|
||||
case CustomFormBulkAction.Publish:
|
||||
foreach (var entry in checkedEntries) {
|
||||
Services.ContentManager.Publish(Services.ContentManager.Get(entry.CustomForm.Id));
|
||||
}
|
||||
break;
|
||||
case CustomFormBulkAction.Unpublish:
|
||||
foreach (var entry in checkedEntries) {
|
||||
Services.ContentManager.Unpublish(Services.ContentManager.Get(entry.CustomForm.Id));
|
||||
}
|
||||
break;
|
||||
case CustomFormBulkAction.Delete:
|
||||
foreach (var entry in checkedEntries) {
|
||||
Services.ContentManager.Remove(Services.ContentManager.Get(entry.CustomForm.Id));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return Index(viewModel.Options, new PagerParameters());
|
||||
}
|
||||
|
||||
public ActionResult Item(int id, PagerParameters pagerParameters) {
|
||||
if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage customForm")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
|
||||
|
||||
var formPart = Services.ContentManager.Get(id, VersionOptions.Published).As<CustomFormPart>();
|
||||
if (formPart == null)
|
||||
return HttpNotFound();
|
||||
|
||||
var submissions = Services.ContentManager
|
||||
.Query<CommonPart, CommonPartRecord>()
|
||||
.ForVersion(VersionOptions.Latest)
|
||||
.Where(x => x.Container.Id == id)
|
||||
.OrderByDescending(x => x.CreatedUtc)
|
||||
.Slice(pager.GetStartIndex(), pager.PageSize)
|
||||
.Select(b => Services.ContentManager.BuildDisplay(b, "SummaryAdmin"));
|
||||
|
||||
var shape = Services.New.CustomFormList();
|
||||
|
||||
var list = Shape.List();
|
||||
list.AddRange(submissions);
|
||||
|
||||
var totalItemCount = Services.ContentManager
|
||||
.Query<CommonPart, CommonPartRecord>().Where(x => x.Container == formPart.ContentItem.Record).Count();
|
||||
shape.Pager(Services.New.Pager(pager).TotalItemCount(totalItemCount));
|
||||
shape.List(list);
|
||||
return View(shape);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Aspects;
|
||||
using Orchard.Core.Contents.Settings;
|
||||
using Orchard.CustomForms.Models;
|
||||
using Orchard.CustomForms.Rules;
|
||||
using Orchard.Data;
|
||||
using Orchard.DisplayManagement;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Mvc.Extensions;
|
||||
using Orchard.Themes;
|
||||
using Orchard.Tokens;
|
||||
using Orchard.UI.Notify;
|
||||
|
||||
namespace Orchard.CustomForms.Controllers {
|
||||
[Themed(true)]
|
||||
public class ItemController : Controller, IUpdateModel {
|
||||
private readonly IContentManager _contentManager;
|
||||
private readonly ITransactionManager _transactionManager;
|
||||
private readonly IRulesManager _rulesManager;
|
||||
private readonly ITokenizer _tokenizer;
|
||||
|
||||
public ItemController(
|
||||
IOrchardServices orchardServices,
|
||||
IContentManager contentManager,
|
||||
ITransactionManager transactionManager,
|
||||
IShapeFactory shapeFactory,
|
||||
IRulesManager rulesManager,
|
||||
ITokenizer tokenizer) {
|
||||
Services = orchardServices;
|
||||
_contentManager = contentManager;
|
||||
_transactionManager = transactionManager;
|
||||
_rulesManager = rulesManager;
|
||||
_tokenizer = tokenizer;
|
||||
T = NullLocalizer.Instance;
|
||||
Logger = NullLogger.Instance;
|
||||
Shape = shapeFactory;
|
||||
}
|
||||
|
||||
dynamic Shape { get; set; }
|
||||
public IOrchardServices Services { get; private set; }
|
||||
public Localizer T { get; set; }
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public ActionResult Create(int id) {
|
||||
var form = _contentManager.Get(id);
|
||||
|
||||
if(form == null || !form.Has<CustomFormPart>()) {
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
var customForm = form.As<CustomFormPart>();
|
||||
|
||||
var contentItem = _contentManager.New(customForm.ContentType);
|
||||
|
||||
if(!contentItem.Has<ICommonPart>()) {
|
||||
throw new OrchardException(T("The content type must have CommonPart attached"));
|
||||
}
|
||||
|
||||
if (!Services.Authorizer.Authorize(Permissions.CreateSubmitPermission(customForm.ContentType), contentItem, T("Cannot create content")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
dynamic model = _contentManager.BuildEditor(contentItem);
|
||||
|
||||
model
|
||||
.ContenItem(form)
|
||||
.ReturnUrl(Url.RouteUrl(_contentManager.GetItemMetadata(form).DisplayRouteValues));
|
||||
|
||||
// Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
|
||||
return View((object)model);
|
||||
}
|
||||
|
||||
[HttpPost, ActionName("Create")]
|
||||
[FormValueRequired("submit.Save")]
|
||||
public ActionResult CreatePOST(int id, string returnUrl) {
|
||||
return CreatePOST(id, returnUrl, contentItem => {
|
||||
if (!contentItem.Has<IPublishingControlAspect>() && !contentItem.TypeDefinition.Settings.GetModel<ContentTypeSettings>().Draftable)
|
||||
_contentManager.Publish(contentItem);
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost, ActionName("Create")]
|
||||
[FormValueRequired("submit.Publish")]
|
||||
public ActionResult CreateAndPublishPOST(int id, string returnUrl) {
|
||||
var form = _contentManager.Get(id);
|
||||
|
||||
if (form == null || !form.Has<CustomFormPart>()) {
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
var customForm = form.As<CustomFormPart>();
|
||||
|
||||
// pass a dummy content to the authorization check to check for "own" variations
|
||||
var dummyContent = _contentManager.New(customForm.ContentType);
|
||||
|
||||
if (!Services.Authorizer.Authorize(Permissions.CreateSubmitPermission(customForm.ContentType), dummyContent, T("Couldn't create content")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
return CreatePOST(id, returnUrl, contentItem => _contentManager.Publish(contentItem));
|
||||
}
|
||||
|
||||
private ActionResult CreatePOST(int id, string returnUrl, Action<ContentItem> conditionallyPublish) {
|
||||
var form = _contentManager.Get(id);
|
||||
|
||||
if (form == null || !form.Has<CustomFormPart>()) {
|
||||
return HttpNotFound();
|
||||
}
|
||||
|
||||
var customForm = form.As<CustomFormPart>();
|
||||
|
||||
var contentItem = _contentManager.New(customForm.ContentType);
|
||||
|
||||
if (!Services.Authorizer.Authorize(Permissions.CreateSubmitPermission(customForm.ContentType), contentItem, T("Couldn't create content")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
_contentManager.Create(contentItem, VersionOptions.Draft);
|
||||
|
||||
dynamic model = _contentManager.UpdateEditor(contentItem, this);
|
||||
|
||||
if (!ModelState.IsValid) {
|
||||
_transactionManager.Cancel();
|
||||
|
||||
// if custom form is inside a widget, we display the form itself
|
||||
if (form.ContentType == "CustomFormWidget") {}
|
||||
|
||||
// Casting to avoid invalid (under medium trust) reflection over the protected View method and force a static invocation.
|
||||
return View((object)model);
|
||||
}
|
||||
|
||||
contentItem.As<ICommonPart>().Container = customForm.ContentItem;
|
||||
|
||||
// triggers any event
|
||||
_rulesManager.TriggerEvent("CustomForm", "Submitted",
|
||||
() => new Dictionary<string, object> { { "Content", contentItem } });
|
||||
|
||||
if (customForm.Redirect) {
|
||||
returnUrl = _tokenizer.Replace(customForm.RedirectUrl, new Dictionary<string, object> { { "Content", contentItem } });
|
||||
}
|
||||
|
||||
// save the submitted form
|
||||
if (!customForm.SaveContentItem) {
|
||||
Services.ContentManager.Remove(contentItem);
|
||||
}
|
||||
else {
|
||||
conditionallyPublish(contentItem);
|
||||
}
|
||||
|
||||
// writes a confirmation message
|
||||
if (customForm.CustomMessage) {
|
||||
if (!String.IsNullOrWhiteSpace(customForm.Message)) {
|
||||
Services.Notifier.Information(T(customForm.Message));
|
||||
}
|
||||
}
|
||||
|
||||
return this.RedirectLocal(returnUrl, () => Redirect(Request.RawUrl));
|
||||
}
|
||||
|
||||
bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
|
||||
return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
|
||||
}
|
||||
|
||||
void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) {
|
||||
ModelState.AddModelError(key, errorMessage.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public class FormValueRequiredAttribute : ActionMethodSelectorAttribute {
|
||||
private readonly string _submitButtonName;
|
||||
|
||||
public FormValueRequiredAttribute(string submitButtonName) {
|
||||
_submitButtonName = submitButtonName;
|
||||
}
|
||||
|
||||
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) {
|
||||
var value = controllerContext.HttpContext.Request.Form[_submitButtonName];
|
||||
return !string.IsNullOrEmpty(value);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Aspects;
|
||||
using Orchard.ContentManagement.Drivers;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.CustomForms.Models;
|
||||
using Orchard.CustomForms.ViewModels;
|
||||
|
||||
namespace Orchard.CustomForms.Drivers {
|
||||
public class CustomFormPartDriver : ContentPartDriver<CustomFormPart> {
|
||||
private readonly IContentDefinitionManager _contentDefinitionManager;
|
||||
private readonly IOrchardServices _orchardServices;
|
||||
|
||||
public CustomFormPartDriver(
|
||||
IContentDefinitionManager contentDefinitionManager,
|
||||
IOrchardServices orchardServices) {
|
||||
_contentDefinitionManager = contentDefinitionManager;
|
||||
_orchardServices = orchardServices;
|
||||
}
|
||||
|
||||
protected override DriverResult Display(CustomFormPart part, string displayType, dynamic shapeHelper) {
|
||||
// this method is used by the widget to render the form when it is displayed
|
||||
|
||||
var contentItem = _orchardServices.ContentManager.New(part.ContentType);
|
||||
|
||||
if (!contentItem.Has<ICommonPart>()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ContentShape("Parts_CustomForm_Wrapper", () => {
|
||||
return shapeHelper.Parts_CustomForm_Wrapper()
|
||||
.Editor(_orchardServices.ContentManager.BuildEditor(contentItem))
|
||||
.ContenItem(part)
|
||||
.ReturnUrl(part.Redirect ? part.RedirectUrl : _orchardServices.WorkContext.HttpContext.Request.RawUrl);
|
||||
});
|
||||
}
|
||||
|
||||
protected override DriverResult Editor(CustomFormPart part, dynamic shapeHelper) {
|
||||
return ContentShape("Parts_CustomForm_Fields", () => {
|
||||
var contentTypes = _contentDefinitionManager.ListTypeDefinitions().Select(x => x.Name).OrderBy(x => x);
|
||||
var viewModel = new CustomFormPartEditViewModel {
|
||||
ContentTypes = contentTypes,
|
||||
CustomFormPart = part
|
||||
};
|
||||
|
||||
return shapeHelper.EditorTemplate(TemplateName: "Parts.CustomForm.Fields", Model: viewModel, Prefix: Prefix);
|
||||
});
|
||||
}
|
||||
|
||||
protected override DriverResult Editor(CustomFormPart part, IUpdateModel updater, dynamic shapeHelper) {
|
||||
var viewModel = new CustomFormPartEditViewModel {
|
||||
CustomFormPart = part
|
||||
};
|
||||
|
||||
updater.TryUpdateModel(viewModel, Prefix, null, null);
|
||||
return Editor(part, shapeHelper);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
using System.Web.Routing;
|
||||
using Orchard.CustomForms.Models;
|
||||
using Orchard.Data;
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
|
||||
namespace Orchard.CustomForms.Handlers {
|
||||
public class CustomFormPartHandler : ContentHandler {
|
||||
public CustomFormPartHandler(IRepository<CustomFormPartRecord> customFormRepository) {
|
||||
Filters.Add(StorageFilter.For(customFormRepository));
|
||||
}
|
||||
|
||||
protected override void GetItemMetadata(GetContentItemMetadataContext context) {
|
||||
if(context.ContentItem.ContentType != "CustomForm") {
|
||||
return;
|
||||
}
|
||||
|
||||
context.Metadata.DisplayRouteValues = new RouteValueDictionary {
|
||||
{"Area", "Orchard.CustomForms"},
|
||||
{"Controller", "Item"},
|
||||
{"Action", "Create"},
|
||||
{"Id", context.ContentItem.Id}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
52
src/Orchard.Web/Modules/Orchard.CustomForms/Migrations.cs
Normal file
52
src/Orchard.Web/Modules/Orchard.CustomForms/Migrations.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.Core.Contents.Extensions;
|
||||
using Orchard.Data.Migration;
|
||||
|
||||
namespace Orchard.CustomForms {
|
||||
public class Migrations : DataMigrationImpl {
|
||||
public int Create() {
|
||||
ContentDefinitionManager.AlterTypeDefinition("CustomForm",
|
||||
cfg => cfg
|
||||
.WithPart("CommonPart")
|
||||
.WithPart("TitlePart")
|
||||
.WithPart("AutoroutePart", builder => builder
|
||||
.WithSetting("AutorouteSettings.AllowCustomPattern", "true")
|
||||
.WithSetting("AutorouteSettings.AutomaticAdjustmentOnEdit", "false")
|
||||
.WithSetting("AutorouteSettings.PatternDefinitions", "[{Name:'Title', Pattern: '{Content.Slug}', Description: 'my-form'}]")
|
||||
.WithSetting("AutorouteSettings.DefaultPatternIndex", "0"))
|
||||
.WithPart("MenuPart")
|
||||
.WithPart("CustomFormPart")
|
||||
.DisplayedAs("Custom Form")
|
||||
.Draftable()
|
||||
);
|
||||
|
||||
SchemaBuilder.CreateTable("CustomFormPartRecord", table => table.ContentPartVersionRecord()
|
||||
.Column<string>("ContentType", c => c.WithLength(255))
|
||||
.Column<bool>("CustomMessage")
|
||||
.Column<string>("Message", c => c.Unlimited())
|
||||
.Column<bool>("Redirect")
|
||||
.Column<string>("RedirectUrl", c => c.Unlimited())
|
||||
.Column<bool>("SaveContentItem")
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int UpdateFrom1() {
|
||||
ContentDefinitionManager.AlterTypeDefinition("CustomFormWidget",
|
||||
cfg => cfg
|
||||
.WithPart("WidgetPart")
|
||||
.WithPart("CommonPart")
|
||||
.WithPart("IdentityPart")
|
||||
.WithPart("CustomFormPart")
|
||||
.WithSetting("Stereotype", "Widget")
|
||||
);
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
public void Uninstall() {
|
||||
ContentDefinitionManager.DeleteTypeDefinition("CustomForm");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Aspects;
|
||||
using Orchard.Core.Title.Models;
|
||||
|
||||
namespace Orchard.CustomForms.Models {
|
||||
public class CustomFormPart : ContentPart<CustomFormPartRecord> {
|
||||
[Required]
|
||||
public string ContentType {
|
||||
get { return Record.ContentType; }
|
||||
set { Record.ContentType = value; }
|
||||
}
|
||||
|
||||
public bool SaveContentItem {
|
||||
get { return Record.SaveContentItem; }
|
||||
set { Record.SaveContentItem = value; }
|
||||
}
|
||||
|
||||
public bool CustomMessage {
|
||||
get { return Record.CustomMessage; }
|
||||
set { Record.CustomMessage = value; }
|
||||
}
|
||||
|
||||
public string Message {
|
||||
get { return Record.Message; }
|
||||
set { Record.Message = value; }
|
||||
}
|
||||
|
||||
public bool Redirect {
|
||||
get { return Record.Redirect; }
|
||||
set { Record.Redirect = value; }
|
||||
}
|
||||
|
||||
public string RedirectUrl {
|
||||
get { return Record.RedirectUrl; }
|
||||
set { Record.RedirectUrl = value; }
|
||||
}
|
||||
|
||||
public string Title {
|
||||
get { return this.As<ITitleAspect>().Title; }
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Data.Conventions;
|
||||
|
||||
namespace Orchard.CustomForms.Models {
|
||||
public class CustomFormPartRecord : ContentPartRecord {
|
||||
[StringLength(255)]
|
||||
public virtual string ContentType { get; set; }
|
||||
|
||||
[StringLengthMax]
|
||||
public virtual string Message { get; set; }
|
||||
public virtual bool CustomMessage { get; set; }
|
||||
public virtual bool SaveContentItem { get; set; }
|
||||
[StringLengthMax]
|
||||
public virtual string RedirectUrl { get; set; }
|
||||
public virtual bool Redirect { get; set; }
|
||||
}
|
||||
}
|
13
src/Orchard.Web/Modules/Orchard.CustomForms/Module.txt
Normal file
13
src/Orchard.Web/Modules/Orchard.CustomForms/Module.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
Name: Custom Forms
|
||||
AntiForgery: enabled
|
||||
Author: The Orchard Team
|
||||
Website: http://orchardcustomforms.codeplex.com
|
||||
Version: 1.5
|
||||
OrchardVersion: 1.4
|
||||
Description: Create custom forms like contact forms or content contributions.
|
||||
Features:
|
||||
Orchard.CustomForms:
|
||||
Name: Custom Forms
|
||||
Description: Create custom forms like contact forms or content contributions.
|
||||
Category: Forms
|
||||
Dependencies: Contents, Orchard.Tokens
|
@@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.30729</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{2CF067CA-064B-43C6-8B88-5E3B99A65F1D}</ProjectGuid>
|
||||
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Orchard.CustomForms</RootNamespace>
|
||||
<AssemblyName>Orchard.CustomForms</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<MvcBuildViews>false</MvcBuildViews>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>4.0</OldToolsVersion>
|
||||
<UpgradeBackupLocation>
|
||||
</UpgradeBackupLocation>
|
||||
<TargetFrameworkProfile />
|
||||
<UseIISExpress>false</UseIISExpress>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.DynamicData" />
|
||||
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Web.Abstractions" />
|
||||
<Reference Include="System.Web.Routing" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Web.config" />
|
||||
<Content Include="Views\Web.config" />
|
||||
<Content Include="Scripts\Web.config" />
|
||||
<Content Include="Styles\Web.config" />
|
||||
<Content Include="Properties\AssemblyInfo.cs" />
|
||||
<Content Include="Module.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
|
||||
<Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project>
|
||||
<Name>Orchard.Framework</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Core\Orchard.Core.csproj">
|
||||
<Project>{9916839C-39FC-4CEB-A5AF-89CA7E87119F}</Project>
|
||||
<Name>Orchard.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Orchard.Tokens\Orchard.Tokens.csproj">
|
||||
<Project>{6F759635-13D7-4E94-BCC9-80445D63F117}</Project>
|
||||
<Name>Orchard.Tokens</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AdminMenu.cs" />
|
||||
<Compile Include="Controllers\AdminController.cs" />
|
||||
<Compile Include="Controllers\ItemController.cs" />
|
||||
<Compile Include="Drivers\CustomFormPartDriver.cs" />
|
||||
<Compile Include="Permissions.cs" />
|
||||
<Compile Include="Handlers\CustomFormPartHandler.cs" />
|
||||
<Compile Include="Migrations.cs" />
|
||||
<Compile Include="Models\CustomFormPart.cs" />
|
||||
<Compile Include="Models\CustomFormPartRecord.cs" />
|
||||
<Compile Include="Rules\CustomFormEvents.cs" />
|
||||
<Compile Include="Rules\IRulesManager.cs" />
|
||||
<Compile Include="Security\AuthorizationEventHandler.cs" />
|
||||
<Compile Include="ViewModels\CustomFormIndexViewModel.cs" />
|
||||
<Compile Include="ViewModels\CustomFormPartEditViewModel.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Admin\Index.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Admin\Item.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\EditorTemplates\Parts.CustomForm.Fields.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Item\Create.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Item\Edit.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Parts.CustomForm.Edit.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Parts.CustomForm.SummaryAdmin.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Placement.info">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Services\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\Parts.CustomForm.Wrapper.cshtml" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target> -->
|
||||
<Target Name="AfterBuild" DependsOnTargets="AfterBuildCompiler">
|
||||
<PropertyGroup>
|
||||
<AreasManifestDir>$(ProjectDir)\..\Manifests</AreasManifestDir>
|
||||
</PropertyGroup>
|
||||
<!-- If this is an area child project, uncomment the following line:
|
||||
<CreateAreaManifest AreaName="$(AssemblyName)" AreaType="Child" AreaPath="$(ProjectDir)" ManifestPath="$(AreasManifestDir)" ContentFiles="@(Content)" />
|
||||
-->
|
||||
<!-- If this is an area parent project, uncomment the following lines:
|
||||
<CreateAreaManifest AreaName="$(AssemblyName)" AreaType="Parent" AreaPath="$(ProjectDir)" ManifestPath="$(AreasManifestDir)" ContentFiles="@(Content)" />
|
||||
<CopyAreaManifests ManifestPath="$(AreasManifestDir)" CrossCopy="false" RenameViews="true" />
|
||||
-->
|
||||
</Target>
|
||||
<Target Name="AfterBuildCompiler" Condition="'$(MvcBuildViews)'=='true'">
|
||||
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(ProjectDir)\..\$(ProjectName)" />
|
||||
</Target>
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>False</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>51352</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>
|
||||
</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>True</UseCustomServer>
|
||||
<CustomServerUrl>http://orchard.codeplex.com</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
92
src/Orchard.Web/Modules/Orchard.CustomForms/Permissions.cs
Normal file
92
src/Orchard.Web/Modules/Orchard.CustomForms/Permissions.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
using Orchard.CustomForms.Models;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.Security.Permissions;
|
||||
|
||||
namespace Orchard.CustomForms {
|
||||
public class Permissions : IPermissionProvider {
|
||||
private static readonly Permission SubmitAnyForm = new Permission { Description = "Submit any forms", Name = "Submit" };
|
||||
private static readonly Permission SubmitForm = new Permission { Description = "Submit {0} forms", Name = "Submit_{0}", ImpliedBy = new[] { SubmitAnyForm } };
|
||||
|
||||
private readonly IContentDefinitionManager _contentDefinitionManager;
|
||||
private readonly IContentManager _contentManager;
|
||||
|
||||
public virtual Feature Feature { get; set; }
|
||||
|
||||
public Permissions(IContentDefinitionManager contentDefinitionManager, IContentManager contentManager) {
|
||||
_contentDefinitionManager = contentDefinitionManager;
|
||||
_contentManager = contentManager;
|
||||
}
|
||||
|
||||
public IEnumerable<Permission> GetPermissions() {
|
||||
// manage rights only for Creatable types
|
||||
var formTypes = _contentManager.Query<CustomFormPart>().List().Select(x => x.ContentType).Distinct();
|
||||
|
||||
foreach (var contentType in formTypes) {
|
||||
var typeDefinition = _contentDefinitionManager.GetTypeDefinition(contentType);
|
||||
if(typeDefinition == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return CreateSubmitPermission(typeDefinition);
|
||||
}
|
||||
|
||||
yield return SubmitAnyForm;
|
||||
}
|
||||
|
||||
public IEnumerable<PermissionStereotype> GetDefaultStereotypes() {
|
||||
return new[] {
|
||||
new PermissionStereotype {
|
||||
Name = "Administrator",
|
||||
Permissions = new[] { SubmitAnyForm }
|
||||
},
|
||||
new PermissionStereotype {
|
||||
Name = "Editor",
|
||||
Permissions = new[] { SubmitAnyForm }
|
||||
},
|
||||
new PermissionStereotype {
|
||||
Name = "Moderator",
|
||||
Permissions = new[] { SubmitAnyForm }
|
||||
},
|
||||
new PermissionStereotype {
|
||||
Name = "Author",
|
||||
Permissions = new[] { SubmitAnyForm }
|
||||
},
|
||||
new PermissionStereotype {
|
||||
Name = "Contributor",
|
||||
Permissions = new[] { SubmitAnyForm }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a permission dynamically for a content type
|
||||
/// </summary>
|
||||
public static Permission CreateSubmitPermission(ContentTypeDefinition typeDefinition) {
|
||||
return new Permission {
|
||||
Name = String.Format(SubmitForm.Name, typeDefinition.Name),
|
||||
Description = String.Format(SubmitForm.Description, typeDefinition.DisplayName),
|
||||
Category = "Custom Forms",
|
||||
ImpliedBy = new [] { SubmitForm }
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a permission dynamically for a content type
|
||||
/// </summary>
|
||||
public static Permission CreateSubmitPermission(string contentType) {
|
||||
return new Permission {
|
||||
Name = String.Format(SubmitForm.Name, contentType),
|
||||
Description = String.Format(SubmitForm.Description, contentType),
|
||||
Category = "Custom Forms",
|
||||
ImpliedBy = new[] { SubmitForm }
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,4 @@
|
||||
<Placement>
|
||||
<Place Parts_CustomForm_Wrapper="Content:1"/>
|
||||
<Place Parts_CustomForm_Fields="Content:5"/>
|
||||
</Placement>
|
@@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Orchard.CustomForms")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyProduct("Orchard")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("e7ce3952-50fa-4887-9cf5-10ec8fd6f930")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("1.5")]
|
||||
[assembly: AssemblyFileVersion("1.5")]
|
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Events;
|
||||
using Orchard.Localization;
|
||||
|
||||
namespace Orchard.CustomForms.Rules {
|
||||
public interface IEventProvider : IEventHandler {
|
||||
void Describe(dynamic describe);
|
||||
}
|
||||
|
||||
public class CustomFormEvents : IEventProvider {
|
||||
public CustomFormEvents() {
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public void Describe(dynamic describe) {
|
||||
Func<dynamic, bool> contentHasPart = ContentHasPart;
|
||||
|
||||
describe.For("CustomForm", T("Custom Forms"), T("Custom Forms"))
|
||||
.Element("Submitted", T("Custom Form Submitted"), T("Custom Form is submitted."), contentHasPart, (Func<dynamic, LocalizedString>)(context => T("When a custom form for types ({0}) is submitted.", FormatPartsList(context))), "SelectContentTypes")
|
||||
;
|
||||
}
|
||||
|
||||
private string FormatPartsList(dynamic context) {
|
||||
var contenttypes = context.Properties["contenttypes"];
|
||||
|
||||
if (String.IsNullOrEmpty(contenttypes)) {
|
||||
return T("Any").Text;
|
||||
}
|
||||
|
||||
return contenttypes;
|
||||
}
|
||||
|
||||
private static bool ContentHasPart(dynamic context) {
|
||||
string contenttypes = context.Properties["contenttypes"];
|
||||
var content = context.Tokens["Content"] as IContent;
|
||||
|
||||
// "" means 'any'
|
||||
if (String.IsNullOrEmpty(contenttypes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (content == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var contentTypes = contenttypes.Split(new[] { ',' });
|
||||
|
||||
return contentTypes.Any(contentType => content.ContentItem.TypeDefinition.Name == contentType);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Orchard.Events;
|
||||
|
||||
namespace Orchard.CustomForms.Rules {
|
||||
public interface IRulesManager : IEventHandler {
|
||||
void TriggerEvent(string category, string type, Func<Dictionary<string, object>> tokensContext);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="webpages:Enabled" value="false" />
|
||||
</appSettings>
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
<!-- iis6 - for any request in this location, return via managed static file handler -->
|
||||
<add path="*" verb="*" type="System.Web.StaticFileHandler" />
|
||||
</httpHandlers>
|
||||
</system.web>
|
||||
<system.webServer>
|
||||
<staticContent>
|
||||
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
|
||||
</staticContent>
|
||||
|
||||
<handlers accessPolicy="Script,Read">
|
||||
<!--
|
||||
iis7 - for any request to a file exists on disk, return it via native http module.
|
||||
accessPolicy 'Script' is to allow for a managed 404 page.
|
||||
-->
|
||||
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
</configuration>
|
@@ -0,0 +1,26 @@
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.CustomForms.Models;
|
||||
using Orchard.Security;
|
||||
|
||||
namespace Orchard.CustomForms.Security {
|
||||
/// <summary>
|
||||
/// Alters the Edit permission requested by the Contents module before editing a form. Returns a Submit permission instead.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class AuthorizationEventHandler : IAuthorizationServiceEventHandler {
|
||||
public void Checking(CheckAccessContext context) { }
|
||||
public void Complete(CheckAccessContext context) { }
|
||||
|
||||
public void Adjust(CheckAccessContext context) {
|
||||
if (!context.Granted
|
||||
&& context.Permission.Name == Orchard.Core.Contents.Permissions.EditContent.Name
|
||||
&& context.Content != null
|
||||
&& context.Content.ContentItem.ContentType == "CustomForm") {
|
||||
|
||||
context.Adjusted = true;
|
||||
context.Permission = Permissions.CreateSubmitPermission(context.Content.ContentItem.As<CustomFormPart>().ContentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="webpages:Enabled" value="false" />
|
||||
</appSettings>
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
<!-- iis6 - for any request in this location, return via managed static file handler -->
|
||||
<add path="*" verb="*" type="System.Web.StaticFileHandler" />
|
||||
</httpHandlers>
|
||||
</system.web>
|
||||
<system.webServer>
|
||||
<staticContent>
|
||||
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
|
||||
</staticContent>
|
||||
|
||||
<handlers accessPolicy="Script,Read">
|
||||
<!--
|
||||
iis7 - for any request to a file exists on disk, return it via native http module.
|
||||
accessPolicy 'Script' is to allow for a managed 404 page.
|
||||
-->
|
||||
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
</configuration>
|
@@ -0,0 +1,39 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.CustomForms.Models;
|
||||
|
||||
namespace Orchard.CustomForms.ViewModels {
|
||||
|
||||
public class CustomFormIndexViewModel {
|
||||
public IList<CustomFormEntry> CustomForms { get; set; }
|
||||
public CustomFormIndexOptions Options { get; set; }
|
||||
public dynamic Pager { get; set; }
|
||||
}
|
||||
|
||||
public class CustomFormEntry {
|
||||
public CustomFormPart CustomForm { get; set; }
|
||||
public bool IsChecked { get; set; }
|
||||
}
|
||||
|
||||
public class CustomFormIndexOptions {
|
||||
public string Search { get; set; }
|
||||
public CustomFormOrder Order { get; set; }
|
||||
public CustomFormFilter Filter { get; set; }
|
||||
public CustomFormBulkAction BulkAction { get; set; }
|
||||
}
|
||||
|
||||
public enum CustomFormOrder {
|
||||
Name,
|
||||
Creation
|
||||
}
|
||||
|
||||
public enum CustomFormFilter {
|
||||
All,
|
||||
}
|
||||
|
||||
public enum CustomFormBulkAction {
|
||||
None,
|
||||
Publish,
|
||||
Unpublish,
|
||||
Delete
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.CustomForms.Models;
|
||||
|
||||
namespace Orchard.CustomForms.ViewModels {
|
||||
public class CustomFormPartEditViewModel {
|
||||
public IEnumerable<string> ContentTypes { get; set; }
|
||||
public CustomFormPart CustomFormPart { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
@using Orchard.CustomForms.ViewModels
|
||||
@using Orchard.Utility.Extensions
|
||||
@model Orchard.CustomForms.ViewModels.CustomFormIndexViewModel
|
||||
|
||||
@{
|
||||
var formIndex = 0;
|
||||
|
||||
var pageSizes = new List<int?>() { 10, 50, 100 };
|
||||
var defaultPageSize = WorkContext.CurrentSite.PageSize;
|
||||
if(!pageSizes.Contains(defaultPageSize)) {
|
||||
pageSizes.Add(defaultPageSize);
|
||||
}
|
||||
}
|
||||
|
||||
<h1>@Html.TitleForPage(T("Manage Custom Forms").ToString()) </h1>
|
||||
@using (Html.BeginFormAntiForgeryPost()) {
|
||||
@Html.ValidationSummary()
|
||||
<div class="manage">@Html.ActionLink(T("Add a new Custom Form").ToString(), "Create", "Admin", new { area = "Contents", id = "CustomForm", returUrl = Request.RawUrl }, new { @class = "button primaryAction" })</div>
|
||||
|
||||
<fieldset class="bulk-actions">
|
||||
<label for="publishActions">@T("Actions:")</label>
|
||||
<select id="publishActions" name="@Html.NameOf(m => m.Options.BulkAction)">
|
||||
@Html.SelectOption(Model.Options.BulkAction, CustomFormBulkAction.None, T("Choose action...").ToString())
|
||||
@Html.SelectOption(Model.Options.BulkAction, CustomFormBulkAction.Publish, T("Publish").ToString())
|
||||
@Html.SelectOption(Model.Options.BulkAction, CustomFormBulkAction.Unpublish, T("Unpublish").ToString())
|
||||
@Html.SelectOption(Model.Options.BulkAction, CustomFormBulkAction.Delete, T("Delete").ToString())
|
||||
</select>
|
||||
<button type="submit" name="submit.BulkEdit" value="@T("Apply")">@T("Apply")</button>
|
||||
</fieldset>
|
||||
<fieldset class="bulk-actions">
|
||||
<label for="filterResults">@T("Sort by:")</label>
|
||||
<select id="filterResults" name="@Html.NameOf(m => m.Options.Order)">
|
||||
@Html.SelectOption(Model.Options.Order, CustomFormOrder.Creation, T("Creation date").ToString())
|
||||
</select>
|
||||
<input type="hidden" name="Page" value="1" />
|
||||
<label for="pageSize">@T("Show:")</label>
|
||||
<select id="pageSize" name="PageSize">
|
||||
@Html.SelectOption((int)Model.Pager.PageSize, 0, T("All").ToString())
|
||||
@foreach(int size in pageSizes.OrderBy(p => p)) {
|
||||
@Html.SelectOption((int)Model.Pager.PageSize, size, size.ToString())
|
||||
}
|
||||
</select>
|
||||
<button type="submit" name="submit.Filter" value="@T("Filter")">@T("Filter")</button>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<table class="items">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"> ↓</th>
|
||||
<th scope="col">@T("Title")</th>
|
||||
<th scope="col">@T("Content Type")</th>
|
||||
<th scope="col"> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
@foreach (var entry in Model.CustomForms) {
|
||||
<tr>
|
||||
<td>
|
||||
<input type="hidden" value="@Model.CustomForms[formIndex].CustomForm.Id" name="@Html.NameOf(m => m.CustomForms[formIndex].CustomForm.Id)"/>
|
||||
<input type="checkbox" value="true" name="@Html.NameOf(m => m.CustomForms[formIndex].IsChecked)"/>
|
||||
</td>
|
||||
<td>
|
||||
@Html.ItemEditLink(entry.CustomForm.Title, entry.CustomForm.ContentItem)
|
||||
@if (entry.CustomForm.ContentItem.ContentType == "CustomFormWidget") {
|
||||
@T("-")<text> </text>@T("Widget")
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@entry.CustomForm.ContentType.CamelFriendly()
|
||||
</td>
|
||||
<td>
|
||||
@Html.ItemEditLink(T("Edit").Text, entry.CustomForm.ContentItem) @T(" | ")
|
||||
@Html.Link(T("Delete").Text, Url.ItemRemoveUrl(entry.CustomForm.ContentItem, new { returnUrl = Request.RawUrl }), new { itemprop = "RemoveUrl UnsafeUrl" }) @T(" | ")
|
||||
@Html.ActionLink(T("Submissions").Text, "Item", "Admin", new { area = "Orchard.CustomForms", id = entry.CustomForm.Id }, new { })
|
||||
</td>
|
||||
</tr>
|
||||
formIndex++;
|
||||
}
|
||||
</table>
|
||||
@Display(Model.Pager)
|
||||
</fieldset>
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
@using Orchard.Core.Contents.ViewModels;
|
||||
@using Orchard.Utility.Extensions;
|
||||
|
||||
@{
|
||||
Model.List.Classes.Add("content-items");
|
||||
}
|
||||
|
||||
@if (Model.List.Items.Count > 0) {
|
||||
using (Html.BeginFormAntiForgeryPost(Url.Action("Item", "Admin", new { area = "Orchard.CustomForms", id = "" }))) {
|
||||
<fieldset class="bulk-actions">
|
||||
<label for="publishActions">@T("Actions:")</label>
|
||||
<select id="publishActions" name="Options.BulkAction">
|
||||
@Html.SelectOption(ContentsBulkAction.None, ContentsBulkAction.None, T("Choose action...").ToString())
|
||||
@Html.SelectOption(ContentsBulkAction.None, ContentsBulkAction.PublishNow, T("Publish Now").ToString())
|
||||
@Html.SelectOption(ContentsBulkAction.None, ContentsBulkAction.Unpublish, T("Unpublish").ToString())
|
||||
@Html.SelectOption(ContentsBulkAction.None, ContentsBulkAction.Remove, T("Delete").ToString())
|
||||
</select>
|
||||
@Html.Hidden("returnUrl", ViewContext.RequestContext.HttpContext.Request.ToUrlString())
|
||||
<button type="submit" name="submit.BulkEdit" value="yes">@T("Apply")</button>
|
||||
</fieldset>
|
||||
<fieldset class="contentItems bulk-items">
|
||||
@Display(Model.List)
|
||||
</fieldset>
|
||||
}
|
||||
}
|
||||
else {
|
||||
<div class="info message">@T("There are no submissions for this form.")</div>
|
||||
}
|
||||
|
||||
@Display(Model.Pager)
|
@@ -0,0 +1,43 @@
|
||||
@using Orchard.Utility.Extensions
|
||||
@model Orchard.CustomForms.ViewModels.CustomFormPartEditViewModel
|
||||
|
||||
@Display.TokenHint()
|
||||
|
||||
<fieldset>
|
||||
<label for="@Html.FieldIdFor(m => m.CustomFormPart.ContentType)">@T("Content Type")</label>
|
||||
<select id="@Html.FieldIdFor(m => m.CustomFormPart.ContentType)" name="@Html.FieldNameFor(m => m.CustomFormPart.ContentType)">
|
||||
@foreach(string contentType in Model.ContentTypes) {
|
||||
@Html.SelectOption(contentType, contentType.Equals(Model.CustomFormPart.ContentType, StringComparison.OrdinalIgnoreCase), contentType.CamelFriendly())
|
||||
}
|
||||
</select>
|
||||
<span class="hint">@T("Select the content type which will be used to render the custom form.")</span>
|
||||
@Html.ValidationMessageFor(m => m.CustomFormPart.ContentType)
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
@Html.EditorFor(m => m.CustomFormPart.SaveContentItem)
|
||||
<label for="@Html.FieldIdFor(m => m.CustomFormPart.SaveContentItem)" class="forcheckbox">@T("Save the content item once the form is submitted")</label>
|
||||
<span class="hint">@T("Check if you want to save the content item associated to the form. Leave empty if you just want to trigger an action on the event.")</span>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
@Html.EditorFor(m => m.CustomFormPart.CustomMessage)
|
||||
<label for="@Html.FieldIdFor(m => m.CustomFormPart.CustomMessage)" class="forcheckbox">@T("Specificy a custom message when the form is submitted")</label>
|
||||
|
||||
<div data-controllerid="@Html.FieldIdFor(m => m.CustomFormPart.CustomMessage)">
|
||||
@Html.LabelFor(m => m.CustomFormPart.Message)
|
||||
@Html.TextBoxFor(m => m.CustomFormPart.Message, new { @class = "text large"})
|
||||
<span class="hint">@T("The custom message to display to the user when the form is submitted. Leave empty if no messages should be displayed.")</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
@Html.EditorFor(m => m.CustomFormPart.Redirect)
|
||||
<label for="@Html.FieldIdFor(m => m.CustomFormPart.Redirect)" class="forcheckbox">@T("Redirect the user once the form is submitted")</label>
|
||||
|
||||
<div data-controllerid="@Html.FieldIdFor(m => m.CustomFormPart.Redirect)">
|
||||
@Html.LabelFor(m => m.CustomFormPart.RedirectUrl)
|
||||
@Html.TextBoxFor(m => m.CustomFormPart.RedirectUrl, new { @class = "text large tokenized" })
|
||||
<span class="hint">@T("The url the user should be redirected to once the form is successfully submitted. e.g.: ~/About")</span>
|
||||
</div>
|
||||
</fieldset>
|
@@ -0,0 +1,19 @@
|
||||
@using Orchard.ContentManagement
|
||||
@{
|
||||
ContentItem customForm = Model.ContentItem;
|
||||
string returnUrl = Model.ReturnUrl;
|
||||
|
||||
// remove default Save/Publish buttons
|
||||
Model.Zones["Sidebar"].Items.Clear();
|
||||
}
|
||||
|
||||
@using (Html.BeginFormAntiForgeryPost(returnUrl)) {
|
||||
@Html.ValidationSummary()
|
||||
// Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type
|
||||
@Display(Model)
|
||||
|
||||
<fieldset class="submit-button">
|
||||
<button type="submit" name="submit.Save" value="submit.Save">@T("Submit")</button>
|
||||
</fieldset>
|
||||
}
|
||||
|
@@ -0,0 +1,5 @@
|
||||
@using (Html.BeginFormAntiForgeryPost()) {
|
||||
@Html.ValidationSummary()
|
||||
// Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type
|
||||
@Display(Model)
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
@using Orchard.ContentManagement;
|
||||
|
||||
@using (Html.BeginFormAntiForgeryPost(Url.Action("Create", "Item", new { area = "Orchard.CustomForms", id = Model.ContentPart.ContentType }))) {
|
||||
@Html.ValidationSummary()
|
||||
@Display(Model.Editor)
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
@using Orchard.ContentManagement;
|
||||
@{
|
||||
ContentItem contentItem = Model.ContentItem;
|
||||
}
|
||||
|
||||
<div>
|
||||
@T("Renders a form for {0}", Model.ContentPart.ContentType)
|
||||
</div>
|
@@ -0,0 +1,21 @@
|
||||
@using Orchard.ContentManagement;
|
||||
|
||||
@{
|
||||
ContentItem customForm = Model.ContentItem;
|
||||
string returnUrl = Model.ReturnUrl;
|
||||
|
||||
// remove default Save/Publish buttons
|
||||
Model.Editor.Zones["Sidebar"].Items.Clear();
|
||||
}
|
||||
|
||||
@using (Html.BeginFormAntiForgeryPost(Url.Action("Create", "Item", new { area = "Orchard.CustomForms", id = Model.ContentItem.Id }))) {
|
||||
@Html.ValidationSummary()
|
||||
// Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type
|
||||
@Display(Model.Editor)
|
||||
|
||||
@Html.Hidden("returnUrl", returnUrl);
|
||||
|
||||
<fieldset class="submit-button">
|
||||
<button type="submit" name="submit.Save" value="submit.Save">@T("Submit")</button>
|
||||
</fieldset>
|
||||
}
|
41
src/Orchard.Web/Modules/Orchard.CustomForms/Views/Web.config
Normal file
41
src/Orchard.Web/Modules/Orchard.CustomForms/Views/Web.config
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="webpages:Enabled" value="false" />
|
||||
</appSettings>
|
||||
<system.web>
|
||||
<httpHandlers>
|
||||
</httpHandlers>
|
||||
|
||||
<!--
|
||||
Enabling request validation in view pages would cause validation to occur
|
||||
after the input has already been processed by the controller. By default
|
||||
MVC performs request validation before a controller processes the input.
|
||||
To change this behavior apply the ValidateInputAttribute to a
|
||||
controller or action.
|
||||
-->
|
||||
<pages
|
||||
validateRequest="false"
|
||||
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"
|
||||
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"
|
||||
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<controls>
|
||||
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" namespace="System.Web.Mvc" tagPrefix="mvc" />
|
||||
</controls>
|
||||
</pages>
|
||||
</system.web>
|
||||
|
||||
<system.webServer>
|
||||
<validation validateIntegratedModeConfiguration="false"/>
|
||||
<handlers>
|
||||
</handlers>
|
||||
</system.webServer>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
|
||||
<bindingRedirect oldVersion="2.0.0.0" newVersion="3.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
41
src/Orchard.Web/Modules/Orchard.CustomForms/Web.config
Normal file
41
src/Orchard.Web/Modules/Orchard.CustomForms/Web.config
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
|
||||
<configSections>
|
||||
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
|
||||
<remove name="host" />
|
||||
<remove name="pages" />
|
||||
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
|
||||
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
|
||||
<system.web.webPages.razor>
|
||||
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<pages pageBaseType="Orchard.Mvc.ViewEngines.Razor.WebViewPage">
|
||||
<namespaces>
|
||||
<add namespace="System.Web.Mvc" />
|
||||
<add namespace="System.Web.Mvc.Ajax" />
|
||||
<add namespace="System.Web.Mvc.Html" />
|
||||
<add namespace="System.Web.Routing" />
|
||||
<add namespace="System.Web.WebPages" />
|
||||
<add namespace="System.Linq"/>
|
||||
<add namespace="System.Collections.Generic"/>
|
||||
<add namespace="Orchard.Mvc.Html"/>
|
||||
</namespaces>
|
||||
</pages>
|
||||
</system.web.webPages.razor>
|
||||
|
||||
<system.web>
|
||||
<compilation targetFramework="4.0">
|
||||
<assemblies>
|
||||
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
|
||||
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
|
||||
<add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
|
||||
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
|
||||
</assemblies>
|
||||
</compilation>
|
||||
</system.web>
|
||||
|
||||
</configuration>
|
Reference in New Issue
Block a user