Merge branch '1.9.x' into dev

Conflicts:
	src/Orchard.Web/Modules/Orchard.ContentTypes/Views/Admin/EditPlacement.cshtml
	src/Orchard.Web/Modules/Orchard.Layouts/Assets/JavaScript/Models/Element.js
	src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj
	src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.js
	src/Orchard.Web/Modules/Orchard.Layouts/Scripts/LayoutEditor.min.js
	src/Orchard.Web/Modules/Orchard.Layouts/Scripts/Models.js
	src/Orchard.Web/Modules/Orchard.Layouts/Scripts/Models.min.js
	src/Orchard.Web/Modules/Orchard.Layouts/Views/LayoutEditor.Template.Toolbox.cshtml
	src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/ClientStorageController.cs
	src/Orchard.Web/Modules/Orchard.Search/Drivers/SearchSettingsPartDriver.cs
	src/Orchard.Web/Modules/Orchard.Search/ViewModels/SearchSettingsIndexViewModel.cs
	src/Orchard.Web/Modules/Orchard.Search/Views/EditorTemplates/Parts/Search.SiteSettings.cshtml
	src/Orchard.Web/Modules/Orchard.Widgets/Controllers/AdminController.cs
	src/Orchard/Orchard.Framework.csproj
This commit is contained in:
Sebastien Ros 2015-09-21 16:15:40 -07:00
commit 80c600fa02
83 changed files with 648 additions and 381 deletions

View File

@ -264,9 +264,6 @@ namespace Orchard.Tests.Modules.DesignerTools.Services
new JProperty("name", "TestingPart"), new JProperty("name", "TestingPart"),
new JProperty("value", "ContentPart"), new JProperty("value", "ContentPart"),
new JProperty("children", new JArray( new JProperty("children", new JArray(
new JObject(
new JProperty("name", "Zones"),
new JProperty("value", "ZoneCollection")),
new JObject( new JObject(
new JProperty("name", "Id"), new JProperty("name", "Id"),
new JProperty("value", "0")), new JProperty("value", "0")),
@ -327,9 +324,6 @@ namespace Orchard.Tests.Modules.DesignerTools.Services
new JProperty("name", "TestingPart"), new JProperty("name", "TestingPart"),
new JProperty("value", "ContentPart"), new JProperty("value", "ContentPart"),
new JProperty("children", new JArray( new JProperty("children", new JArray(
new JObject(
new JProperty("name", "Zones"),
new JProperty("value", "ZoneCollection")),
new JObject( new JObject(
new JProperty("name", "Id"), new JProperty("name", "Id"),
new JProperty("value", "0")), new JProperty("value", "0")),

View File

@ -512,7 +512,7 @@ Features:
Dependencies: Beta Dependencies: Beta
"); ");
moduleExtensionFolder.Manifests.Add("Classic", @" themeExtensionFolder.Manifests.Add("Classic", @"
Name: Classic Name: Classic
Version: 1.0.3 Version: 1.0.3
OrchardVersion: 1 OrchardVersion: 1

View File

@ -8,7 +8,7 @@
<autofac defaultAssembly="Orchard.Framework"> <autofac defaultAssembly="Orchard.Framework">
<!-- <!--
To create tenant specific configurations, copy this file to ~/Congig/Sites.{tenant}.config To create tenant specific configurations, copy this file to ~/Config/Sites.{tenant}.config
where {tenant} is the technical name of the targetted tenant where {tenant} is the technical name of the targetted tenant
Allowed scopes: per-dependency, single-instance or per-lifetime-scope Allowed scopes: per-dependency, single-instance or per-lifetime-scope
@ -47,4 +47,4 @@
</components> </components>
</autofac> </autofac>
</configuration> </configuration>

View File

@ -52,7 +52,7 @@ namespace Orchard.Core.Containers.Drivers {
if (updater != null) { if (updater != null) {
var oldContainerId = model.ContainerId; var oldContainerId = model.ContainerId;
updater.TryUpdateModel(model, "Containable", null, new[] { "ShowContainerPicker", "ShowPositionEditor" }); updater.TryUpdateModel(model, "Containable", null, new[] { "ShowContainerPicker", "ShowPositionEditor" });
if (oldContainerId != model.ContainerId) { if (oldContainerId != model.ContainerId && settings.ShowContainerPicker) {
if (commonPart != null) { if (commonPart != null) {
var containerItem = _contentManager.Get(model.ContainerId, VersionOptions.Latest); var containerItem = _contentManager.Get(model.ContainerId, VersionOptions.Latest);
commonPart.Container = containerItem; commonPart.Container = containerItem;
@ -61,20 +61,23 @@ namespace Orchard.Core.Containers.Drivers {
part.Position = model.Position; part.Position = model.Position;
} }
var containers = _contentManager if (settings.ShowContainerPicker) {
.Query<ContainerPart, ContainerPartRecord>(VersionOptions.Latest) var containers = _contentManager
.List() .Query<ContainerPart, ContainerPartRecord>(VersionOptions.Latest)
.Where(container => container.ItemContentTypes.Any(type => type.Name == part.TypeDefinition.Name)); .List()
.Where(container => container.ItemContentTypes.Any(type => type.Name == part.TypeDefinition.Name));
var listItems = new[] { new SelectListItem { Text = T("(None)").Text, Value = "0" } } var listItems = new[] { new SelectListItem { Text = T("(None)").Text, Value = "0" } }
.Concat(containers.Select(x => new SelectListItem { .Concat(containers.Select(x => new SelectListItem {
Value = Convert.ToString(x.Id), Value = Convert.ToString(x.Id),
Text = x.ContentItem.TypeDefinition.DisplayName + ": " + _contentManager.GetItemMetadata(x.ContentItem).DisplayText, Text = x.ContentItem.TypeDefinition.DisplayName + ": " + _contentManager.GetItemMetadata(x.ContentItem).DisplayText,
Selected = x.Id == model.ContainerId, Selected = x.Id == model.ContainerId,
})) }))
.ToList(); .ToList();
model.AvailableContainers = new SelectList(listItems, "Value", "Text", model.ContainerId);
}
model.AvailableContainers = new SelectList(listItems, "Value", "Text", model.ContainerId);
model.Position = part.Position; model.Position = part.Position;
return shapeHelper.EditorTemplate(TemplateName: "Containable", Model: model, Prefix: "Containable"); return shapeHelper.EditorTemplate(TemplateName: "Containable", Model: model, Prefix: "Containable");

View File

@ -88,6 +88,10 @@ namespace Orchard.Core.Containers.Drivers {
protected override DriverResult Editor(ContainerPart part, IUpdateModel updater, dynamic shapeHelper) { protected override DriverResult Editor(ContainerPart part, IUpdateModel updater, dynamic shapeHelper) {
return ContentShape("Parts_Container_Edit", () => { return ContentShape("Parts_Container_Edit", () => {
if(!part.ContainerSettings.DisplayContainerEditor) {
return null;
}
var containables = !part.ContainerSettings.RestrictItemContentTypes ? _containerService.GetContainableTypes().ToList() : new List<ContentTypeDefinition>(0); var containables = !part.ContainerSettings.RestrictItemContentTypes ? _containerService.GetContainableTypes().ToList() : new List<ContentTypeDefinition>(0);
var model = new ContainerViewModel { var model = new ContainerViewModel {
AdminMenuPosition = part.AdminMenuPosition, AdminMenuPosition = part.AdminMenuPosition,

View File

@ -48,6 +48,10 @@ namespace Orchard.Core.Containers.Settings {
} }
public class ContainerTypePartSettings { public class ContainerTypePartSettings {
public ContainerTypePartSettings() {
DisplayContainerEditor = true;
}
public bool? ItemsShownDefault { get; set; } public bool? ItemsShownDefault { get; set; }
public int? PageSizeDefault { get; set; } public int? PageSizeDefault { get; set; }
public bool? PaginatedDefault { get; set; } public bool? PaginatedDefault { get; set; }
@ -55,6 +59,7 @@ namespace Orchard.Core.Containers.Settings {
public bool RestrictItemContentTypes { get; set; } public bool RestrictItemContentTypes { get; set; }
public bool? EnablePositioning { get; set; } public bool? EnablePositioning { get; set; }
public string AdminListViewName { get; set; } public string AdminListViewName { get; set; }
public bool DisplayContainerEditor { get; set; }
} }
public class ContainerSettingsHooks : ContentDefinitionEditorEventsBase { public class ContainerSettingsHooks : ContentDefinitionEditorEventsBase {
@ -93,7 +98,8 @@ namespace Orchard.Core.Containers.Settings {
EnablePositioning = model.EnablePositioning, EnablePositioning = model.EnablePositioning,
AdminListViewName = model.AdminListViewName, AdminListViewName = model.AdminListViewName,
AvailableItemContentTypes = _containerService.GetContainableTypes().ToList(), AvailableItemContentTypes = _containerService.GetContainableTypes().ToList(),
ListViewProviders = _listViewService.Providers.ToList() ListViewProviders = _listViewService.Providers.ToList(),
DisplayContainerEditor = model.DisplayContainerEditor
}; };
yield return DefinitionTemplate(viewModel); yield return DefinitionTemplate(viewModel);
@ -122,6 +128,7 @@ namespace Orchard.Core.Containers.Settings {
builder.WithSetting("ContainerTypePartSettings.RestrictItemContentTypes", viewModel.RestrictItemContentTypes.ToString()); builder.WithSetting("ContainerTypePartSettings.RestrictItemContentTypes", viewModel.RestrictItemContentTypes.ToString());
builder.WithSetting("ContainerTypePartSettings.EnablePositioning", viewModel.EnablePositioning.ToString()); builder.WithSetting("ContainerTypePartSettings.EnablePositioning", viewModel.EnablePositioning.ToString());
builder.WithSetting("ContainerTypePartSettings.AdminListViewName", viewModel.AdminListViewName); builder.WithSetting("ContainerTypePartSettings.AdminListViewName", viewModel.AdminListViewName);
builder.WithSetting("ContainerTypePartSettings.DisplayContainerEditor", viewModel.DisplayContainerEditor.ToString());
yield return DefinitionTemplate(viewModel); yield return DefinitionTemplate(viewModel);
} }

View File

@ -16,5 +16,6 @@ namespace Orchard.Core.Containers.ViewModels {
[UIHint("ListViewPicker")] [UIHint("ListViewPicker")]
public string AdminListViewName { get; set; } public string AdminListViewName { get; set; }
public bool DisplayContainerEditor { get; set; }
} }
} }

View File

@ -2,6 +2,11 @@
@{ @{
Script.Require("ShapesBase"); Script.Require("ShapesBase");
} }
<fieldset>
@Html.CheckBoxFor(m => m.DisplayContainerEditor)
@Html.LabelFor(m => m.DisplayContainerEditor, @T("Display settings editor").ToString(), new { @class = "forcheckbox" })
<span class="hint">@T("When checked, users can change the settings for each content item.")</span>
</fieldset>
<fieldset> <fieldset>
<label for="@Html.FieldIdFor(m => m.ItemsShownDefault)">@T("Default Items Shown")</label> <label for="@Html.FieldIdFor(m => m.ItemsShownDefault)">@T("Default Items Shown")</label>
@Html.EditorFor(m => m.ItemsShownDefault) @Html.EditorFor(m => m.ItemsShownDefault)

View File

@ -65,8 +65,7 @@ namespace Orchard.Core.Contents.Controllers {
Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters); Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters);
var versionOptions = VersionOptions.Latest; var versionOptions = VersionOptions.Latest;
switch (model.Options.ContentsStatus) switch (model.Options.ContentsStatus) {
{
case ContentsStatus.Published: case ContentsStatus.Published:
versionOptions = VersionOptions.Published; versionOptions = VersionOptions.Published;
break; break;
@ -112,6 +111,10 @@ namespace Orchard.Core.Contents.Controllers {
query = _cultureFilter.FilterCulture(query, model.Options.SelectedCulture); query = _cultureFilter.FilterCulture(query, model.Options.SelectedCulture);
} }
if(model.Options.ContentsStatus == ContentsStatus.Owner) {
query = query.Where<CommonPartRecord>(cr => cr.OwnerId == Services.WorkContext.CurrentUser.Id);
}
model.Options.SelectedFilter = model.TypeName; model.Options.SelectedFilter = model.TypeName;
model.Options.FilterOptions = GetListableTypes(false) model.Options.FilterOptions = GetListableTypes(false)
.Select(ctd => new KeyValuePair<string, string>(ctd.Name, ctd.DisplayName)) .Select(ctd => new KeyValuePair<string, string>(ctd.Name, ctd.DisplayName))

View File

@ -49,12 +49,12 @@ namespace Orchard.Core.Contents.ViewModels {
Created Created
} }
public enum ContentsStatus public enum ContentsStatus {
{
Draft, Draft,
Published, Published,
AllVersions, AllVersions,
Latest Latest,
Owner
} }
public enum ContentsBulkAction { public enum ContentsBulkAction {

View File

@ -56,6 +56,7 @@
</select> </select>
<label for="contentResults" class="bulk-order">@T("Filter by")</label> <label for="contentResults" class="bulk-order">@T("Filter by")</label>
<select id="contentResults" name="Options.ContentsStatus"> <select id="contentResults" name="Options.ContentsStatus">
@Html.SelectOption((ContentsStatus)Model.Options.ContentsStatus, ContentsStatus.Owner, T("owned by me").ToString())
@Html.SelectOption((ContentsStatus)Model.Options.ContentsStatus, ContentsStatus.Latest, T("latest").ToString()) @Html.SelectOption((ContentsStatus)Model.Options.ContentsStatus, ContentsStatus.Latest, T("latest").ToString())
@Html.SelectOption((ContentsStatus)Model.Options.ContentsStatus, ContentsStatus.Published, T("published").ToString()) @Html.SelectOption((ContentsStatus)Model.Options.ContentsStatus, ContentsStatus.Published, T("published").ToString())
@Html.SelectOption((ContentsStatus)Model.Options.ContentsStatus, ContentsStatus.Draft, T("unpublished").ToString()) @Html.SelectOption((ContentsStatus)Model.Options.ContentsStatus, ContentsStatus.Draft, T("unpublished").ToString())

View File

@ -69,11 +69,12 @@ namespace Orchard.Core.Settings.Drivers {
var previousBaseUrl = model.Site.BaseUrl; var previousBaseUrl = model.Site.BaseUrl;
updater.TryUpdateModel(model, Prefix, null, new [] { "Site.SuperUser", "Site.MaxPageSize" }); // Update all properties but not SuperUser, MaxPageSize and BaseUrl.
updater.TryUpdateModel(model, Prefix, null, new [] { "Site.SuperUser", "Site.MaxPageSize", "Site.BaseUrl", "Site.MaxPagedCount" });
// only a user with SiteOwner permission can change the site owner // only a user with SiteOwner permission can change the site owner
if (_authorizer.Authorize(StandardPermissions.SiteOwner)) { if (_authorizer.Authorize(StandardPermissions.SiteOwner)) {
updater.TryUpdateModel(model, Prefix, new[] { "Site.SuperUser", "Site.MaxPageSize" }, null); updater.TryUpdateModel(model, Prefix, new[] { "Site.SuperUser", "Site.MaxPageSize", "Site.BaseUrl", "Site.MaxPagedCount" }, null);
// ensures the super user is fully empty // ensures the super user is fully empty
if (String.IsNullOrEmpty(model.SuperUser)) { if (String.IsNullOrEmpty(model.SuperUser)) {
@ -86,30 +87,30 @@ namespace Orchard.Core.Settings.Drivers {
updater.AddModelError("SuperUser", T("The user {0} was not found", model.SuperUser)); updater.AddModelError("SuperUser", T("The user {0} was not found", model.SuperUser));
} }
} }
}
// ensure the base url is absolute if provided // ensure the base url is absolute if provided
if (!String.IsNullOrWhiteSpace(model.Site.BaseUrl)) { if (!String.IsNullOrWhiteSpace(model.Site.BaseUrl)) {
if (!Uri.IsWellFormedUriString(model.Site.BaseUrl, UriKind.Absolute)) { if (!Uri.IsWellFormedUriString(model.Site.BaseUrl, UriKind.Absolute)) {
updater.AddModelError("BaseUrl", T("The base url must be absolute.")); updater.AddModelError("BaseUrl", T("The base url must be absolute."));
} }
// if the base url has been modified, try to ping it // if the base url has been modified, try to ping it
else if (!String.Equals(previousBaseUrl, model.Site.BaseUrl, StringComparison.OrdinalIgnoreCase)) { else if (!String.Equals(previousBaseUrl, model.Site.BaseUrl, StringComparison.OrdinalIgnoreCase)) {
try { try {
var request = WebRequest.Create(model.Site.BaseUrl) as HttpWebRequest; var request = WebRequest.Create(model.Site.BaseUrl) as HttpWebRequest;
if (request != null) { if (request != null) {
using (request.GetResponse() as HttpWebResponse) {} using (request.GetResponse() as HttpWebResponse) { }
}
} }
} catch (Exception ex) {
catch (Exception ex) { if (ex.IsFatal()) {
if (ex.IsFatal()) { throw;
throw; }
_notifier.Warning(T("The base url you entered could not be requested from current location."));
Logger.Warning(ex, "Could not query base url: {0}", model.Site.BaseUrl);
} }
_notifier.Warning(T("The base url you entered could not be requested from current location."));
Logger.Warning(ex, "Could not query base url: {0}", model.Site.BaseUrl);
} }
} }
} }
return ContentShape("Parts_Settings_SiteSettingsPart", return ContentShape("Parts_Settings_SiteSettingsPart",
() => shapeHelper.EditorTemplate(TemplateName: "Parts.Settings.SiteSettingsPart", Model: model, Prefix: Prefix)); () => shapeHelper.EditorTemplate(TemplateName: "Parts.Settings.SiteSettingsPart", Model: model, Prefix: Prefix));

View File

@ -16,7 +16,10 @@
</div> </div>
<div> <div>
<label for="@Html.FieldIdFor(m => m.BaseUrl)">@T("Base URL")</label> <label for="@Html.FieldIdFor(m => m.BaseUrl)">@T("Base URL")</label>
@Html.TextBoxFor(m => m.BaseUrl, new { @class = "text medium is-url" }) @Html.TextBoxFor(m => m.BaseUrl,
(object)(AuthorizedFor(Orchard.Security.StandardPermissions.SiteOwner)
? (dynamic)new { @class = "text medium is-url" }
: (dynamic)new { @class = "text medium is-url", @readonly = "readonly" }))
<span class="hint">@T("Enter the fully qualified base URL of the web site.")</span> <span class="hint">@T("Enter the fully qualified base URL of the web site.")</span>
<span class="hint">@T("e.g., http://localhost:30320/orchardlocal, http://www.yourdomain.com")</span> <span class="hint">@T("e.g., http://localhost:30320/orchardlocal, http://www.yourdomain.com")</span>
</div> </div>
@ -45,14 +48,15 @@
@Html.EditorFor(x => x.PageTitleSeparator) @Html.EditorFor(x => x.PageTitleSeparator)
@Html.ValidationMessage("PageTitleSeparator", "*") @Html.ValidationMessage("PageTitleSeparator", "*")
</div> </div>
@if (AuthorizedFor(Orchard.Security.StandardPermissions.SiteOwner)) {
<div> <div>
<label for="SuperUser">@T("Super user")</label> <label for="SuperUser">@T("Super user")</label>
@Html.EditorFor(x => x.SuperUser) @Html.TextBoxFor(x => x.SuperUser,
(object)(AuthorizedFor(Orchard.Security.StandardPermissions.SiteOwner)
? (dynamic)new { @class = "text single-line" }
: (dynamic)new { @class = "text single-line", @readonly = "readonly" }))
@Html.ValidationMessage("SuperUser", "*") @Html.ValidationMessage("SuperUser", "*")
<span class="hint">@T("Enter an existing account name, or nothing if you don't want a Super user account")</span> <span class="hint">@T("Enter an existing account name, or nothing if you don't want a Super user account")</span>
</div> </div>
}
<div> <div>
<label for="SiteDebugMode">@T("Resource Debug Mode")</label> <label for="SiteDebugMode">@T("Resource Debug Mode")</label>
@Html.DropDownList("ResourceDebugMode", resourceDebugMode) @Html.DropDownList("ResourceDebugMode", resourceDebugMode)

View File

@ -319,9 +319,12 @@ namespace Orchard.Core.Shapes {
var progress = 1; var progress = 1;
var flatPositionComparer = new FlatPositionComparer(); var flatPositionComparer = new FlatPositionComparer();
var ordering = unordered.Select(item => { var ordering = unordered.Select(item => {
var position = (item == null || item.GetType().GetProperty("Metadata") == null || item.Metadata.GetType().GetProperty("Position") == null) string position = null;
? null var itemPosition = item as IPositioned;
: item.Metadata.Position; if (itemPosition != null) {
position = itemPosition.Position;
}
return new { item, position }; return new { item, position };
}).ToList(); }).ToList();

View File

@ -236,7 +236,13 @@
} }
if (_this.filter("[itemprop~='RemoveUrl']").length == 1) { if (_this.filter("[itemprop~='RemoveUrl']").length == 1) {
if (!confirm(confirmRemoveMessage)) { // use a custom message if its set in data-message
var dataMessage = _this.data('message');
if (dataMessage === undefined) {
dataMessage = confirmRemoveMessage;
}
if (!confirm(dataMessage)) {
return false; return false;
} }
} }

View File

@ -25,6 +25,7 @@
<IISExpressAnonymousAuthentication /> <IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication /> <IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode /> <IISExpressUseClassicPipelineMode />
<UseGlobalApplicationHostFile />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -73,6 +74,10 @@
<Name>Orchard.Core</Name> <Name>Orchard.Core</Name>
<Private>false</Private> <Private>false</Private>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\Orchard.MediaLibrary\Orchard.MediaLibrary.csproj">
<Project>{73a7688a-5bd3-4f7e-adfa-ce36c5a10e3b}</Project>
<Name>Orchard.MediaLibrary</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Content\Admin\Images\grippie.png" /> <Content Include="Content\Admin\Images\grippie.png" />

View File

@ -5,70 +5,72 @@
editors.each(function() { editors.each(function() {
var idPostfix = $(this).attr('id').substr('wmd-input'.length); var idPostfix = $(this).attr('id').substr('wmd-input'.length);
var editor = new Markdown.Editor(converter, idPostfix, { var editor = new Markdown.Editor(converter, idPostfix, {
handler: function() { window.open("http://daringfireball.net/projects/markdown/syntax"); } handler: function() { window.open("http://daringfireball.net/projects/markdown/syntax"); }
}); });
editor.hooks.set("insertImageDialog", function(callback) { if (Boolean($(this).data("manage-media"))) {
// see if there's an image selected that they intend on editing editor.hooks.set("insertImageDialog", function (callback) {
var wmd = $('#wmd-input' + idPostfix); // see if there's an image selected that they intend on editing
var wmd = $('#wmd-input' + idPostfix);
var editImage, content = wmd.selection ? wmd.selection.createRange().text : null; var editImage, content = wmd.selection ? wmd.selection.createRange().text : null;
var adminIndex = location.href.toLowerCase().indexOf("/admin/"); var adminIndex = location.href.toLowerCase().indexOf("/admin/");
if (adminIndex === -1) return; if (adminIndex === -1) return;
var url = location.href.substr(0, adminIndex) + "/Admin/Orchard.MediaLibrary?dialog=true"; var url = location.href.substr(0, adminIndex) + "/Admin/Orchard.MediaLibrary?dialog=true";
$.colorbox({ $.colorbox({
href: url, href: url,
iframe: true, iframe: true,
reposition: true, reposition: true,
width: "90%", width: "90%",
height: "90%", height: "90%",
onLoad: function () { onLoad: function () {
// hide the scrollbars from the main window // hide the scrollbars from the main window
$('html, body').css('overflow', 'hidden'); $('html, body').css('overflow', 'hidden');
}, },
onClosed: function () { onClosed: function () {
$('html, body').css('overflow', ''); $('html, body').css('overflow', '');
var selectedData = $.colorbox.selectedData; var selectedData = $.colorbox.selectedData;
if (selectedData == null) // Dialog cancelled, do nothing if (selectedData == null) // Dialog cancelled, do nothing
return; return;
var newContent = ''; var newContent = '';
for (var i = 0; i < selectedData.length; i++) { for (var i = 0; i < selectedData.length; i++) {
var renderMedia = location.href.substr(0, adminIndex) + "/Admin/Orchard.MediaLibrary/MediaItem/" + selectedData[i].id + "?displayType=Raw"; var renderMedia = location.href.substr(0, adminIndex) + "/Admin/Orchard.MediaLibrary/MediaItem/" + selectedData[i].id + "?displayType=Raw";
$.ajax({ $.ajax({
async: false, async: false,
type: 'GET', type: 'GET',
url: renderMedia, url: renderMedia,
success: function (data) { success: function (data) {
newContent += data; newContent += data;
} }
}); });
} }
var result = $.parseHTML(newContent); var result = $.parseHTML(newContent);
var img = $(result).filter('img'); var img = $(result).filter('img');
// if this is an image, use the callback which will format it in markdown // if this is an image, use the callback which will format it in markdown
if (img.length > 0 && img.attr('src')) { if (img.length > 0 && img.attr('src')) {
callback(img.attr('src')); callback(img.attr('src'));
} }
// otherwise, insert the raw HTML // otherwise, insert the raw HTML
else { else {
if (wmd.selection) { if (wmd.selection) {
wmd.selection.replace('.*', newContent); wmd.selection.replace('.*', newContent);
} else { } else {
wmd.text(newContent); wmd.text(newContent);
}
callback();
} }
callback();
} }
} });
return true;
}); });
return true; }
});
editor.run(); editor.run();
}); });

View File

@ -21,7 +21,8 @@
{"id", "wmd-input" + "-" + idPostfix}, {"id", "wmd-input" + "-" + idPostfix},
{"class", "wmd-input"}, {"class", "wmd-input"},
{"data-mediapicker-uploadpath", Model.AddMediaPath}, {"data-mediapicker-uploadpath", Model.AddMediaPath},
{"data-mediapicker-title", T("Insert/Update Media")} {"data-mediapicker-title", T("Insert/Update Media")},
{"data-manage-media", AuthorizedFor(Orchard.MediaLibrary.Permissions.ManageMediaContent) ? "true" : "false" }
}; };
// The markdown editor itself doesn't seem to (yet) support autofocus, but we'll set it on the textarea nonetheless. // The markdown editor itself doesn't seem to (yet) support autofocus, but we'll set it on the textarea nonetheless.

View File

@ -144,7 +144,7 @@ namespace Orchard.AntiSpam.Controllers {
if (spam != null) { if (spam != null) {
spam.As<SpamFilterPart>().Status = SpamStatus.Spam; spam.As<SpamFilterPart>().Status = SpamStatus.Spam;
_spamService.ReportSpam(spam.As<SpamFilterPart>()); _spamService.ReportSpam(spam.As<SpamFilterPart>());
Services.ContentManager.Publish(spam); Services.ContentManager.Unpublish(spam);
} }
return this.RedirectLocal(returnUrl, "~/"); return this.RedirectLocal(returnUrl, "~/");
@ -158,7 +158,7 @@ namespace Orchard.AntiSpam.Controllers {
var spam = Services.ContentManager.Get(id, VersionOptions.Latest); var spam = Services.ContentManager.Get(id, VersionOptions.Latest);
if (spam != null) { if (spam != null) {
spam.As<SpamFilterPart>().Status = SpamStatus.Ham; spam.As<SpamFilterPart>().Status = SpamStatus.Ham;
_spamService.ReportSpam(spam.As<SpamFilterPart>()); _spamService.ReportHam(spam.As<SpamFilterPart>());
Services.ContentManager.Publish(spam); Services.ContentManager.Publish(spam);
} }

View File

@ -1,6 +1,5 @@
using System; using System;
using Orchard.AntiSpam.Models; using Orchard.AntiSpam.Models;
using Orchard.AntiSpam.Services;
using Orchard.AntiSpam.Settings; using Orchard.AntiSpam.Settings;
using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
@ -8,11 +7,9 @@ using Orchard.Localization;
namespace Orchard.AntiSpam.Drivers { namespace Orchard.AntiSpam.Drivers {
public class SpamFilterPartDriver : ContentPartDriver<SpamFilterPart> { public class SpamFilterPartDriver : ContentPartDriver<SpamFilterPart> {
private readonly ISpamService _spamService;
private const string TemplateName = "Parts/SpamFilter"; private const string TemplateName = "Parts/SpamFilter";
public SpamFilterPartDriver(IOrchardServices services, ISpamService spamService) { public SpamFilterPartDriver(IOrchardServices services) {
_spamService = spamService;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
Services = services; Services = services;
} }
@ -25,8 +22,6 @@ namespace Orchard.AntiSpam.Drivers {
} }
protected override DriverResult Editor(SpamFilterPart part, ContentManagement.IUpdateModel updater, dynamic shapeHelper) { protected override DriverResult Editor(SpamFilterPart part, ContentManagement.IUpdateModel updater, dynamic shapeHelper) {
part.Status = _spamService.CheckForSpam(part);
if (part.Settings.GetModel<SpamFilterPartSettings>().DeleteSpam) { if (part.Settings.GetModel<SpamFilterPartSettings>().DeleteSpam) {
updater.AddModelError("Spam", T("Spam detected.")); updater.AddModelError("Spam", T("Spam detected."));
} }

View File

@ -1,5 +1,5 @@
using Orchard.AntiSpam.Models; using Orchard.AntiSpam.Models;
using Orchard.AntiSpam.Services;
using Orchard.AntiSpam.Settings; using Orchard.AntiSpam.Settings;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
using Orchard.Data; using Orchard.Data;
@ -7,14 +7,22 @@ using Orchard.Data;
namespace Orchard.AntiSpam.Handlers { namespace Orchard.AntiSpam.Handlers {
public class SpamFilterPartHandler : ContentHandler { public class SpamFilterPartHandler : ContentHandler {
private readonly ITransactionManager _transactionManager; private readonly ITransactionManager _transactionManager;
private readonly ISpamService _spamService;
public SpamFilterPartHandler( public SpamFilterPartHandler(
IRepository<SpamFilterPartRecord> repository, IRepository<SpamFilterPartRecord> repository,
ITransactionManager transactionManager ITransactionManager transactionManager,
ISpamService spamService
) { ) {
_transactionManager = transactionManager; _transactionManager = transactionManager;
_spamService = spamService;
Filters.Add(StorageFilter.For(repository)); Filters.Add(StorageFilter.For(repository));
OnCreating<SpamFilterPart>((context, part) => {
part.Status = _spamService.CheckForSpam(part);
});
OnPublishing<SpamFilterPart>((context, part) => { OnPublishing<SpamFilterPart>((context, part) => {
if (part.Status == SpamStatus.Spam) { if (part.Status == SpamStatus.Spam) {
if (part.Settings.GetModel<SpamFilterPartSettings>().DeleteSpam) { if (part.Settings.GetModel<SpamFilterPartSettings>().DeleteSpam) {

View File

@ -126,6 +126,7 @@ namespace Orchard.AntiSpam.Services {
CommentAuthorEmail = _tokenizer.Replace(settings.CommentAuthorEmailPattern, data), CommentAuthorEmail = _tokenizer.Replace(settings.CommentAuthorEmailPattern, data),
CommentAuthorUrl = _tokenizer.Replace(settings.CommentAuthorUrlPattern, data), CommentAuthorUrl = _tokenizer.Replace(settings.CommentAuthorUrlPattern, data),
CommentContent = _tokenizer.Replace(settings.CommentContentPattern, data), CommentContent = _tokenizer.Replace(settings.CommentContentPattern, data),
CommentType = part.ContentItem.ContentType.ToLower()
}; };
if(workContext.HttpContext != null) { if(workContext.HttpContext != null) {

View File

@ -117,7 +117,7 @@ namespace Orchard.Comments.Drivers {
// prevent users from commenting on a closed thread by hijacking the commentedOn property // prevent users from commenting on a closed thread by hijacking the commentedOn property
var commentsPart = commentedOn.As<CommentsPart>(); var commentsPart = commentedOn.As<CommentsPart>();
if (!commentsPart.CommentsActive) { if (commentsPart == null || !commentsPart.CommentsActive) {
_orchardServices.TransactionManager.Cancel(); _orchardServices.TransactionManager.Cancel();
return Editor(part, shapeHelper); return Editor(part, shapeHelper);
} }

View File

@ -118,7 +118,8 @@ namespace Orchard.Comments.Services {
} }
public void DeleteComment(int commentId) { public void DeleteComment(int commentId) {
_orchardServices.ContentManager.Remove(_orchardServices.ContentManager.Get<CommentPart>(commentId).ContentItem); // Get latest because the comment may be unpublished if the anti-spam module has caught it
_orchardServices.ContentManager.Remove(_orchardServices.ContentManager.Get<CommentPart>(commentId, VersionOptions.Latest).ContentItem);
} }
public bool CommentsDisabledForCommentedContent(int id) { public bool CommentsDisabledForCommentedContent(int id) {

View File

@ -43,7 +43,7 @@
<fieldset class="action"> <fieldset class="action">
<button class="primaryAction" type="submit" name="submit.Save" value="Save">@T("Save")</button> <button class="primaryAction" type="submit" name="submit.Save" value="Save">@T("Save")</button>
<button class="primaryAction" type="submit" name="submit.Restore" value="Restore">@T("Restore")</button> <button class="primaryAction" type="submit" name="submit.Restore" value="Restore" itemprop="RemoveUrl" data-message="@T("Are you sure you want to restore these placements?")">@T("Restore")</button>
</fieldset> </fieldset>
} }

View File

@ -136,7 +136,7 @@ namespace Orchard.DynamicForms.Drivers {
var runtimeValues = GetRuntimeValues(element); var runtimeValues = GetRuntimeValues(element);
if (!String.IsNullOrWhiteSpace(optionLabel)) { if (!String.IsNullOrWhiteSpace(optionLabel)) {
yield return new SelectListItem { Text = displayType != "Design" ? _tokenizer.Replace(optionLabel, tokenData) : optionLabel }; yield return new SelectListItem { Text = displayType != "Design" ? _tokenizer.Replace(optionLabel, tokenData) : optionLabel, Value = string.Empty };
} }
if (queryId == null) if (queryId == null)

View File

@ -138,7 +138,7 @@ namespace Orchard.DynamicForms.Drivers {
var runtimeValues = GetRuntimeValues(element); var runtimeValues = GetRuntimeValues(element);
if (!String.IsNullOrWhiteSpace(optionLabel)) { if (!String.IsNullOrWhiteSpace(optionLabel)) {
yield return new SelectListItem { Text = displayType != "Design" ? _tokenizer.Replace(optionLabel, tokenData) : optionLabel }; yield return new SelectListItem { Text = displayType != "Design" ? _tokenizer.Replace(optionLabel, tokenData) : optionLabel, Value = string.Empty };
} }
if (taxonomyId == null) if (taxonomyId == null)

View File

@ -8,34 +8,34 @@
<label for="@Html.FieldIdFor(m => m.Value)" @if(settings.Required) { <text>class="required"</text> }>@Model.DisplayName</label> <label for="@Html.FieldIdFor(m => m.Value)" @if(settings.Required) { <text>class="required"</text> }>@Model.DisplayName</label>
@switch (settings.ListMode) { @switch (settings.ListMode) {
case ListMode.Dropdown: case ListMode.Dropdown:
@Html.DropDownListFor(m => m.Value, new SelectList(options, Model.Value)) @Html.DropDownListFor(m => m.Value, new SelectList(options, Model.Value), settings.Required ? new {required = "required"} : null)
break; break;
case ListMode.Radiobutton: case ListMode.Radiobutton:
foreach (var option in options) { foreach (var option in options) {
if (string.IsNullOrWhiteSpace(option)) { if (string.IsNullOrWhiteSpace(option)) {
<label>@Html.RadioButton("Value", "", string.IsNullOrWhiteSpace(Model.Value))<i>@T("unset")</i></label> <label>@Html.RadioButton("Value", "", string.IsNullOrWhiteSpace(Model.Value), settings.Required ? new {required = "required"} : null)<i>@T("unset")</i></label>
} }
else { else {
<label>@Html.RadioButton("Value", option, (option == Model.Value))@option</label> <label>@Html.RadioButton("Value", option, (option == Model.Value), settings.Required ? new {required = "required"} : null)@option</label>
} }
} }
break; break;
case ListMode.Listbox: case ListMode.Listbox:
<input name="@Html.FieldNameFor(m => m.SelectedValues)" type="hidden" /> <input name="@Html.FieldNameFor(m => m.SelectedValues)" type="hidden" />
@Html.ListBoxFor(m => m.SelectedValues, new MultiSelectList(options, Model.SelectedValues)) @Html.ListBoxFor(m => m.SelectedValues, new MultiSelectList(options, Model.SelectedValues), settings.Required ? new {required = "required"} : null)
break; break;
case ListMode.Checkbox: case ListMode.Checkbox:
int index = 0; int index = 0;
<input name="@Html.FieldNameFor(m => m.SelectedValues)" type="hidden" /> <input name="@Html.FieldNameFor(m => m.SelectedValues)" type="hidden" />
foreach (var option in options) { foreach (var option in options) {
index++; index++;
if (!string.IsNullOrWhiteSpace(option)) { if (!string.IsNullOrWhiteSpace(option)) {
<div> <div>
<input type="checkbox" name="@Html.FieldNameFor(m => m.SelectedValues)" value="@option" @((Model.SelectedValues != null && Model.SelectedValues.Contains(option)) ? "checked=\"checked\"" : "") class="check-box" id="@Html.FieldIdFor(m => m.SelectedValues)-@index" /> <input type="checkbox" name="@Html.FieldNameFor(m => m.SelectedValues)" value="@option" @((Model.SelectedValues != null && Model.SelectedValues.Contains(option)) ? "checked=\"checked\"" : "") class="check-box" id="@Html.FieldIdFor(m => m.SelectedValues)-@index" @if(settings.Required) {<text> required="required"</text> } />
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.SelectedValues)-@index">@T(option)</label> <label class="forcheckbox" for="@Html.FieldIdFor(m => m.SelectedValues)-@index">@T(option)</label>
</div> </div>
} }
} }

View File

@ -4,7 +4,9 @@
<fieldset> <fieldset>
<label for="@Html.FieldIdFor(m => m.Value)" @if(Model.Settings.Required) { <text>class="required"</text> }>@Model.Field.DisplayName</label> <label for="@Html.FieldIdFor(m => m.Value)" @if(Model.Settings.Required) { <text>class="required"</text> }>@Model.Field.DisplayName</label>
@Html.TextBoxFor(m => m.Value, new { @class = "text small", type = "text", min = (Model.Settings.Minimum.HasValue) ? Model.Settings.Minimum.Value : 0, max = (Model.Settings.Maximum.HasValue) ? Model.Settings.Maximum.Value : 1000000, step = Math.Pow(10, 0 - Model.Settings.Scale).ToString(CultureInfo.InvariantCulture) }) @(Model.Settings.Required
? Html.TextBoxFor(m => m.Value, new {@class = "text-small", type = "text", min = (Model.Settings.Minimum.HasValue) ? Model.Settings.Minimum.Value : 0, max = (Model.Settings.Maximum.HasValue) ? Model.Settings.Maximum.Value : 1000000, step = Math.Pow(10, 0 - Model.Settings.Scale).ToString(CultureInfo.InvariantCulture), required = "required"})
: Html.TextBoxFor(m => m.Value, new {@class = "text-small", type = "text", min = (Model.Settings.Minimum.HasValue) ? Model.Settings.Minimum.Value : 0, max = (Model.Settings.Maximum.HasValue) ? Model.Settings.Maximum.Value : 1000000, step = Math.Pow(10, 0 - Model.Settings.Scale).ToString(CultureInfo.InvariantCulture)}))
@Html.ValidationMessageFor(m => m.Value) @Html.ValidationMessageFor(m => m.Value)
@if (HasText(Model.Settings.Hint)) { @if (HasText(Model.Settings.Hint)) {
<span class="hint">@Model.Settings.Hint</span> <span class="hint">@Model.Settings.Hint</span>

View File

@ -45,6 +45,15 @@ namespace Orchard.ImageEditor.Controllers {
[Themed(false)] [Themed(false)]
public ActionResult Edit(string folderPath, string filename) { public ActionResult Edit(string folderPath, string filename) {
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia))
return new HttpUnauthorizedResult();
// Check permission.
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
return new HttpUnauthorizedResult();
}
var media = Services.ContentManager.Query<MediaPart, MediaPartRecord>().Where(x => x.FolderPath == folderPath && x.FileName == filename).Slice(0, 1).FirstOrDefault(); var media = Services.ContentManager.Query<MediaPart, MediaPartRecord>().Where(x => x.FolderPath == folderPath && x.FileName == filename).Slice(0, 1).FirstOrDefault();
if (media == null) { if (media == null) {
@ -64,12 +73,21 @@ namespace Orchard.ImageEditor.Controllers {
[HttpPost] [HttpPost]
public ActionResult Upload(int id, string content, int width, int height) { public ActionResult Upload(int id, string content, int width, int height) {
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia))
return new HttpUnauthorizedResult();
var media = Services.ContentManager.Get(id).As<MediaPart>(); var media = Services.ContentManager.Get(id).As<MediaPart>();
if (media == null) { if (media == null) {
return HttpNotFound(); return HttpNotFound();
} }
// Check permission.
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(media.FolderPath)) {
return new HttpUnauthorizedResult();
}
const string signature = "data:image/jpeg;base64,"; const string signature = "data:image/jpeg;base64,";
if (!content.StartsWith(signature, StringComparison.OrdinalIgnoreCase)) { if (!content.StartsWith(signature, StringComparison.OrdinalIgnoreCase)) {
@ -96,7 +114,7 @@ namespace Orchard.ImageEditor.Controllers {
} }
public ActionResult Proxy(string url) { public ActionResult Proxy(string url) {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent)) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia))
return HttpNotFound(); return HttpNotFound();
var sslFailureCallback = new RemoteCertificateValidationCallback((o, cert, chain, errors) => true); var sslFailureCallback = new RemoteCertificateValidationCallback((o, cert, chain, errors) => true);

View File

@ -11,9 +11,9 @@ namespace Orchard.Layouts {
builder builder
.AddImageSet("layouts") .AddImageSet("layouts")
.Add(T("Layouts"), "8.5", layouts => layouts .Add(T("Layouts"), "8.5", layouts => layouts
.Action("List", "Admin", new {id = "Layout", area = "Contents"}) .Action("List", "Admin", new {id = "Layout", area = "Contents"}).Permission(Permissions.ManageLayouts)
.LinkToFirstChild(false) .LinkToFirstChild(false)
.Add(T("Elements"), "1", elements => elements.Action("Index", "BlueprintAdmin", new {area = "Orchard.Layouts"}))); .Add(T("Elements"), "1", elements => elements.Action("Index", "BlueprintAdmin", new {area = "Orchard.Layouts"}).Permission(Permissions.ManageLayouts)));
} }
} }
} }

View File

@ -74,45 +74,6 @@
return host.addElement(contentType); return host.addElement(contentType);
}; };
$scope.toggleInlineEditing = function () {
if (!$scope.element.inlineEditingIsActive) {
$scope.element.inlineEditingIsActive = true;
$element.find(".layout-toolbar-container").show();
var selector = "#layout-editor-" + $scope.$id + " .layout-html .layout-content-markup[data-templated=false]";
var firstContentEditorId = $(selector).first().attr("id");
tinymce.init({
selector: selector,
theme: "modern",
schema: "html5",
plugins: [
"advlist autolink lists link image charmap print preview hr anchor pagebreak",
"searchreplace wordcount visualblocks visualchars code fullscreen",
"insertdatetime media nonbreaking table contextmenu directionality",
"emoticons template paste textcolor colorpicker textpattern",
"fullscreen autoresize"
],
toolbar: "undo redo cut copy paste | bold italic | bullist numlist outdent indent formatselect | alignleft aligncenter alignright alignjustify ltr rtl | link unlink charmap | code fullscreen close",
convert_urls: false,
valid_elements: "*[*]",
// Shouldn't be needed due to the valid_elements setting, but TinyMCE would strip script.src without it.
extended_valid_elements: "script[type|defer|src|language]",
statusbar: false,
skin: "orchardlightgray",
inline: true,
fixed_toolbar_container: "#layout-editor-" + $scope.$id + " .layout-toolbar-container",
init_instance_callback: function (editor) {
if (editor.id == firstContentEditorId)
tinymce.execCommand("mceFocus", false, editor.id);
}
});
}
else {
tinymce.remove("#layout-editor-" + $scope.$id + " .layout-content-markup");
$element.find(".layout-toolbar-container").hide();
$scope.element.inlineEditingIsActive = false;
}
};
$(document).on("cut copy paste", function (e) { $(document).on("cut copy paste", function (e) {
// If the pseudo clipboard was already invoked (which happens on the first clipboard // If the pseudo clipboard was already invoked (which happens on the first clipboard
// operation after page load even if native clipboard support exists) then sit this // operation after page load even if native clipboard support exists) then sit this
@ -164,23 +125,12 @@
element.find(".layout-toolbar-container").click(function (e) { element.find(".layout-toolbar-container").click(function (e) {
e.stopPropagation(); e.stopPropagation();
}); });
// Intercept mousedown on editor while in inline editing mode to
// prevent current editor from losing focus.
element.mousedown(function (e) {
if (scope.element.inlineEditingIsActive) {
e.preventDefault();
e.stopPropagation();
}
})
// Unfocus and unselect everything on click outside of canvas. // Unfocus and unselect everything on click outside of canvas.
$(window).click(function (e) { $(window).click(function (e) {
// Except when in inline editing mode. scope.$apply(function () {
if (!scope.element.inlineEditingIsActive) { scope.element.activeElement = null;
scope.$apply(function () { scope.element.focusedElement = null;
scope.element.activeElement = null; });
scope.element.focusedElement = null;
});
}
}); });
} }
}; };

View File

@ -35,13 +35,6 @@
templateUrl: environment.templateUrl("Html"), templateUrl: environment.templateUrl("Html"),
replace: true, replace: true,
link: function (scope, element) { link: function (scope, element) {
// Mouse down events must not be intercepted by drag and drop while inline editing is active,
// otherwise clicks in inline editors will have no effect.
element.find(".layout-content-markup").mousedown(function (e) {
if (scope.element.editor.inlineEditingIsActive) {
e.stopPropagation();
}
});
} }
}; };
} }

View File

@ -15,7 +15,7 @@
var resetFocus = false; var resetFocus = false;
var element = $scope.element; var element = $scope.element;
if (element.editor.isDragging || element.editor.inlineEditingIsActive) if (element.editor.isDragging)
return; return;
// If native clipboard support exists, the pseudo-clipboard will have been disabled. // If native clipboard support exists, the pseudo-clipboard will have been disabled.

View File

@ -9,7 +9,6 @@
this.focusedElement = null; this.focusedElement = null;
this.dropTargetElement = null; this.dropTargetElement = null;
this.isDragging = false; this.isDragging = false;
this.inlineEditingIsActive = false;
this.isResizing = false; this.isResizing = false;
this.resetToolboxElements = function () { this.resetToolboxElements = function () {

View File

@ -57,7 +57,7 @@
this.setIsActive = function (value) { this.setIsActive = function (value) {
if (!this.editor) if (!this.editor)
return; return;
if (this.editor.isDragging || this.editor.inlineEditingIsActive || this.editor.isResizing) if (this.editor.isDragging || this.editor.isResizing)
return; return;
if (value) if (value)
@ -81,7 +81,7 @@
return; return;
if (this.isTemplated && !this.allowSealedFocus()) if (this.isTemplated && !this.allowSealedFocus())
return; return;
if (this.editor.isDragging || this.editor.inlineEditingIsActive || this.editor.isResizing) if (this.editor.isDragging || this.editor.isResizing)
return; return;
this.editor.focusedElement = this; this.editor.focusedElement = this;

View File

@ -34,7 +34,8 @@ namespace Orchard.Layouts.Controllers {
ICultureAccessor cultureAccessor, ICultureAccessor cultureAccessor,
IShapeFactory shapeFactory, IShapeFactory shapeFactory,
ITransactionManager transactionManager, ITransactionManager transactionManager,
ISignals signals) { ISignals signals,
IOrchardServices orchardServices) {
_elementBlueprintService = elementBlueprintService; _elementBlueprintService = elementBlueprintService;
_notifier = notifier; _notifier = notifier;
@ -43,12 +44,19 @@ namespace Orchard.Layouts.Controllers {
_shapeFactory = shapeFactory; _shapeFactory = shapeFactory;
_transactionManager = transactionManager; _transactionManager = transactionManager;
_signals = signals; _signals = signals;
Services = orchardServices;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
} }
public IOrchardServices Services { get; set; }
public Localizer T { get; set; } public Localizer T { get; set; }
public ActionResult Index() { public ActionResult Index() {
if (!Services.Authorizer.Authorize(Permissions.ManageLayouts, T("Not authorized to manage layouts."))) {
return new HttpUnauthorizedResult();
}
var blueprints = _elementBlueprintService.GetBlueprints().ToArray(); var blueprints = _elementBlueprintService.GetBlueprints().ToArray();
var viewModel = new BlueprintsIndexViewModel { var viewModel = new BlueprintsIndexViewModel {
Blueprints = blueprints Blueprints = blueprints
@ -57,6 +65,10 @@ namespace Orchard.Layouts.Controllers {
} }
public ActionResult Browse() { public ActionResult Browse() {
if (!Services.Authorizer.Authorize(Permissions.ManageLayouts, T("Not authorized to manage layouts."))) {
return new HttpUnauthorizedResult();
}
var categories = RemoveBlueprints(_elementManager.GetCategories(DescribeElementsContext.Empty)).ToArray(); var categories = RemoveBlueprints(_elementManager.GetCategories(DescribeElementsContext.Empty)).ToArray();
var viewModel = new BrowseElementsViewModel { var viewModel = new BrowseElementsViewModel {
Categories = categories Categories = categories
@ -65,6 +77,10 @@ namespace Orchard.Layouts.Controllers {
} }
public ActionResult Create(string id) { public ActionResult Create(string id) {
if (!Services.Authorizer.Authorize(Permissions.ManageLayouts, T("Not authorized to manage layouts."))) {
return new HttpUnauthorizedResult();
}
if (String.IsNullOrWhiteSpace(id)) if (String.IsNullOrWhiteSpace(id))
return RedirectToAction("Browse"); return RedirectToAction("Browse");
@ -80,6 +96,10 @@ namespace Orchard.Layouts.Controllers {
[HttpPost] [HttpPost]
public ActionResult Create(string id, CreateElementBlueprintViewModel model) { public ActionResult Create(string id, CreateElementBlueprintViewModel model) {
if (!Services.Authorizer.Authorize(Permissions.ManageLayouts, T("Not authorized to manage layouts."))) {
return new HttpUnauthorizedResult();
}
var describeContext = DescribeElementsContext.Empty; var describeContext = DescribeElementsContext.Empty;
var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, id); var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, id);
var baseElement = _elementManager.ActivateElement(descriptor); var baseElement = _elementManager.ActivateElement(descriptor);
@ -100,7 +120,11 @@ namespace Orchard.Layouts.Controllers {
return RedirectToAction("Edit", new { id = blueprint.Id }); return RedirectToAction("Edit", new { id = blueprint.Id });
} }
public ViewResult Edit(int id) { public ActionResult Edit(int id) {
if (!Services.Authorizer.Authorize(Permissions.ManageLayouts, T("Not authorized to manage layouts."))) {
return new HttpUnauthorizedResult();
}
var blueprint = _elementBlueprintService.GetBlueprint(id); var blueprint = _elementBlueprintService.GetBlueprint(id);
var describeContext = DescribeElementsContext.Empty; var describeContext = DescribeElementsContext.Empty;
var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, blueprint.BaseElementTypeName); var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, blueprint.BaseElementTypeName);
@ -125,6 +149,10 @@ namespace Orchard.Layouts.Controllers {
[HttpPost] [HttpPost]
[ValidateInput(false)] [ValidateInput(false)]
public ActionResult Edit(int id, ElementDataViewModel model) { public ActionResult Edit(int id, ElementDataViewModel model) {
if (!Services.Authorizer.Authorize(Permissions.ManageLayouts, T("Not authorized to manage layouts."))) {
return new HttpUnauthorizedResult();
}
var blueprint = _elementBlueprintService.GetBlueprint(id); var blueprint = _elementBlueprintService.GetBlueprint(id);
var describeContext = DescribeElementsContext.Empty; var describeContext = DescribeElementsContext.Empty;
var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, blueprint.BaseElementTypeName); var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, blueprint.BaseElementTypeName);
@ -154,6 +182,10 @@ namespace Orchard.Layouts.Controllers {
} }
public ActionResult Properties(int id) { public ActionResult Properties(int id) {
if (!Services.Authorizer.Authorize(Permissions.ManageLayouts, T("Not authorized to manage layouts."))) {
return new HttpUnauthorizedResult();
}
var blueprint = _elementBlueprintService.GetBlueprint(id); var blueprint = _elementBlueprintService.GetBlueprint(id);
var describeContext = DescribeElementsContext.Empty; var describeContext = DescribeElementsContext.Empty;
var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, blueprint.BaseElementTypeName); var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, blueprint.BaseElementTypeName);
@ -171,6 +203,10 @@ namespace Orchard.Layouts.Controllers {
[HttpPost] [HttpPost]
public ActionResult Properties(int id, ElementBlueprintPropertiesViewModel model) { public ActionResult Properties(int id, ElementBlueprintPropertiesViewModel model) {
if (!Services.Authorizer.Authorize(Permissions.ManageLayouts, T("Not authorized to manage layouts."))) {
return new HttpUnauthorizedResult();
}
var blueprint = _elementBlueprintService.GetBlueprint(id); var blueprint = _elementBlueprintService.GetBlueprint(id);
var describeContext = DescribeElementsContext.Empty; var describeContext = DescribeElementsContext.Empty;
var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, blueprint.BaseElementTypeName); var descriptor = _elementManager.GetElementDescriptorByTypeName(describeContext, blueprint.BaseElementTypeName);
@ -191,7 +227,12 @@ namespace Orchard.Layouts.Controllers {
return RedirectToAction("Index"); return RedirectToAction("Index");
} }
[HttpPost]
public ActionResult Delete(int id) { public ActionResult Delete(int id) {
if (!Services.Authorizer.Authorize(Permissions.ManageLayouts, T("Not authorized to manage layouts."))) {
return new HttpUnauthorizedResult();
}
var blueprint = _elementBlueprintService.GetBlueprint(id); var blueprint = _elementBlueprintService.GetBlueprint(id);
if (blueprint == null) if (blueprint == null)
@ -204,7 +245,12 @@ namespace Orchard.Layouts.Controllers {
[FormValueRequired("submit.BulkEdit")] [FormValueRequired("submit.BulkEdit")]
[ActionName("Index")] [ActionName("Index")]
[HttpPost]
public ActionResult BulkDelete(IEnumerable<int> blueprintIds) { public ActionResult BulkDelete(IEnumerable<int> blueprintIds) {
if (!Services.Authorizer.Authorize(Permissions.ManageLayouts, T("Not authorized to manage layouts."))) {
return new HttpUnauthorizedResult();
}
if (blueprintIds == null || !blueprintIds.Any()) { if (blueprintIds == null || !blueprintIds.Any()) {
_notifier.Error(T("Please select the blueprints to delete.")); _notifier.Error(T("Please select the blueprints to delete."));
} }

View File

@ -142,18 +142,7 @@ namespace Orchard.Layouts.Controllers {
_objectStore.Set(session, state); _objectStore.Set(session, state);
return RedirectToAction("Edit", new {session = session}); return RedirectToAction("Edit", new {session = session});
} }
public RedirectToRouteResult Add(string session, string typeName, int? contentId = null, string contentType = null) {
var state = new ElementSessionState {
TypeName = typeName,
ContentId = contentId,
ContentType = contentType
};
_objectStore.Set(session, state);
return RedirectToAction("Edit", new { session = session });
}
public ViewResult Edit(string session) { public ViewResult Edit(string session) {
var sessionState = _objectStore.Get<ElementSessionState>(session); var sessionState = _objectStore.Get<ElementSessionState>(session);
var contentId = sessionState.ContentId; var contentId = sessionState.ContentId;

View File

@ -6,6 +6,7 @@ using Orchard.ContentManagement;
using Orchard.Layouts.Elements; using Orchard.Layouts.Elements;
using Orchard.Layouts.Framework.Elements; using Orchard.Layouts.Framework.Elements;
using Orchard.Layouts.Services; using Orchard.Layouts.Services;
using Orchard.Localization;
using Orchard.UI.Admin; using Orchard.UI.Admin;
namespace Orchard.Layouts.Controllers { namespace Orchard.Layouts.Controllers {
@ -15,15 +16,25 @@ namespace Orchard.Layouts.Controllers {
private readonly ILayoutManager _layoutManager; private readonly ILayoutManager _layoutManager;
private readonly ILayoutModelMapper _mapper; private readonly ILayoutModelMapper _mapper;
public LayoutController(IContentManager contentManager, ILayoutManager layoutManager, ILayoutModelMapper mapper) { public LayoutController(
IContentManager contentManager,
ILayoutManager layoutManager,
ILayoutModelMapper mapper,
IOrchardServices orchardServices) {
_contentManager = contentManager; _contentManager = contentManager;
_layoutManager = layoutManager; _layoutManager = layoutManager;
_mapper = mapper; _mapper = mapper;
Services = orchardServices;
T = NullLocalizer.Instance;
} }
public IOrchardServices Services { get; set; }
public Localizer T { get; set; }
[HttpPost, ValidateInput(enableValidation: false)] [HttpPost, ValidateInput(enableValidation: false)]
public ContentResult ApplyTemplate(int? templateId = null, string layoutData = null, int? contentId = null, string contentType = null) { public ActionResult ApplyTemplate(int? templateId = null, string layoutData = null, int? contentId = null, string contentType = null) {
var template = templateId != null ? _layoutManager.GetLayout(templateId.Value) : null; var template = templateId != null ? _layoutManager.GetLayout(templateId.Value) : null;
var templateElements = template != null ? _layoutManager.LoadElements(template).ToList() : default(IEnumerable<Element>); var templateElements = template != null ? _layoutManager.LoadElements(template).ToList() : default(IEnumerable<Element>);
var describeContext = CreateDescribeElementsContext(contentId, contentType); var describeContext = CreateDescribeElementsContext(contentId, contentType);

View File

@ -33,7 +33,6 @@ namespace Orchard.Layouts {
.WithPart("LayoutPart", p => p .WithPart("LayoutPart", p => p
.WithSetting("LayoutTypePartSettings.IsTemplate", "True")) .WithSetting("LayoutTypePartSettings.IsTemplate", "True"))
.DisplayedAs("Layout") .DisplayedAs("Layout")
.Listable()
.Draftable()); .Draftable());
ContentDefinitionManager.AlterTypeDefinition("LayoutWidget", type => type ContentDefinitionManager.AlterTypeDefinition("LayoutWidget", type => type

View File

@ -368,6 +368,7 @@
<Compile Include="Helpers\PrefixHelper.cs" /> <Compile Include="Helpers\PrefixHelper.cs" />
<Compile Include="Helpers\JsonHelper.cs" /> <Compile Include="Helpers\JsonHelper.cs" />
<Compile Include="Helpers\StringHelper.cs" /> <Compile Include="Helpers\StringHelper.cs" />
<Compile Include="Permissions.cs" />
<Compile Include="Recipes\Builders\CustomElementsStep.cs" /> <Compile Include="Recipes\Builders\CustomElementsStep.cs" />
<Compile Include="Recipes\Executors\CustomElementsStep.cs" /> <Compile Include="Recipes\Executors\CustomElementsStep.cs" />
<Compile Include="Providers\BlueprintElementHarvester.cs" /> <Compile Include="Providers\BlueprintElementHarvester.cs" />

View File

@ -0,0 +1,40 @@
using System.Collections.Generic;
using Orchard.Environment.Extensions.Models;
using Orchard.Security.Permissions;
namespace Orchard.Layouts {
public class Permissions : IPermissionProvider {
public static readonly Permission ManageLayouts = new Permission { Description = "Managing Layouts", Name = "ManageLayouts" };
public virtual Feature Feature { get; set; }
public IEnumerable<Permission> GetPermissions() {
return new[] {
ManageLayouts,
};
}
public IEnumerable<PermissionStereotype> GetDefaultStereotypes() {
return new[] {
new PermissionStereotype {
Name = "Administrator",
Permissions = new[] { ManageLayouts }
},
new PermissionStereotype {
Name = "Editor",
Permissions = new[] { ManageLayouts }
},
new PermissionStereotype {
Name = "Moderator",
},
new PermissionStereotype {
Name = "Author"
},
new PermissionStereotype {
Name = "Contributor",
},
};
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@
@foreach (var contentItemShape in Model.ContentItems) { @foreach (var contentItemShape in Model.ContentItems) {
var contentItem = (ContentItem)contentItemShape.ContentItem; var contentItem = (ContentItem)contentItemShape.ContentItem;
var displayTextHtmlString = Html.ItemDisplayText(contentItem); var displayTextHtmlString = Html.ItemDisplayText(contentItem);
var displayText = displayTextHtmlString != null ? displayTextHtmlString.ToString() : T("-").ToString(); var displayText = displayTextHtmlString != null ? (IHtmlString)displayTextHtmlString : T("-");
<div class="layout-snippet"> <div class="layout-snippet">
@displayText @displayText
</div> </div>

View File

@ -1,10 +1,6 @@
<div class="layout-toolbox-wrapper"> <div class="layout-toolbox-wrapper">
<div class="layout-toolbox"> <div class="layout-toolbox">
<label> <ul class="layout-toolbox-groups">
<input type="checkbox" ng-checked="element.inlineEditingIsActive" ng-click="toggleInlineEditing()" />
@T("Edit HTML content inline")
</label>
<ul class="layout-toolbox-groups" ng-hide="element.inlineEditingIsActive">
<li class="layout-toolbox-group" ng-class="{collapsed: layoutIsCollapsed}"> <li class="layout-toolbox-group" ng-class="{collapsed: layoutIsCollapsed}">
<a href="#" class="layout-toolbox-group-heading" ng-click="toggleLayoutIsCollapsed($event)">@T("Layout")</a> <a href="#" class="layout-toolbox-group-heading" ng-click="toggleLayoutIsCollapsed($event)">@T("Layout")</a>
<ul class="layout-toolbox-items"> <ul class="layout-toolbox-items">

View File

@ -53,10 +53,7 @@ namespace Orchard.Localization.Controllers {
var contentItemTranslation = _contentManager.New<LocalizationPart>(masterContentItem.ContentType); var contentItemTranslation = _contentManager.New<LocalizationPart>(masterContentItem.ContentType);
contentItemTranslation.MasterContentItem = masterContentItem; contentItemTranslation.MasterContentItem = masterContentItem;
// build the editor using the master content item so that var content = _contentManager.BuildEditor(contentItemTranslation);
// the form is pre-populated with the original values
var content = _contentManager.BuildEditor(masterContentItem);
return View(content); return View(content);
} }

View File

@ -15,7 +15,7 @@ namespace Orchard.MediaLibrary {
builder.AddImageSet("media-library") builder.AddImageSet("media-library")
.Add(T("Media"), "6", .Add(T("Media"), "6",
menu => menu.Add(T("Media"), "0", item => item.Action("Index", "Admin", new { area = "Orchard.MediaLibrary" }) menu => menu.Add(T("Media"), "0", item => item.Action("Index", "Admin", new { area = "Orchard.MediaLibrary" })
.Permission(Permissions.ManageMediaContent))); .Permission(Permissions.ManageOwnMedia)));
} }
} }
} }

View File

@ -14,6 +14,7 @@ using Orchard.Themes;
using Orchard.UI.Navigation; using Orchard.UI.Navigation;
using Orchard.ContentManagement.MetaData; using Orchard.ContentManagement.MetaData;
using Orchard.Validation; using Orchard.Validation;
using System.Collections.Generic;
namespace Orchard.MediaLibrary.Controllers { namespace Orchard.MediaLibrary.Controllers {
[ValidateInput(false)] [ValidateInput(false)]
@ -41,17 +42,21 @@ namespace Orchard.MediaLibrary.Controllers {
public ILogger Logger { get; set; } public ILogger Logger { get; set; }
public ActionResult Index(string folderPath = "", bool dialog = false) { public ActionResult Index(string folderPath = "", bool dialog = false) {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot view media"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot view media")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
// If the user is trying to access a folder above his boundaries, redirect him to his home folder
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
return RedirectToAction("Index", new { folderPath = rootMediaFolder.MediaPath, dialog });
}
// let other modules enhance the ui by providing custom navigation and actions // let other modules enhance the ui by providing custom navigation and actions
var explorer = Services.ContentManager.New("MediaLibraryExplorer"); var explorer = Services.ContentManager.New("MediaLibraryExplorer");
explorer.Weld(new MediaLibraryExplorerPart()); explorer.Weld(new MediaLibraryExplorerPart());
var explorerShape = Services.ContentManager.BuildDisplay(explorer); var explorerShape = Services.ContentManager.BuildDisplay(explorer);
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
var viewModel = new MediaManagerIndexViewModel { var viewModel = new MediaManagerIndexViewModel {
DialogMode = dialog, DialogMode = dialog,
FolderPath = folderPath, FolderPath = folderPath,
@ -73,7 +78,7 @@ namespace Orchard.MediaLibrary.Controllers {
} }
public ActionResult Import(string folderPath) { public ActionResult Import(string folderPath) {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot import media"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot import media")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
var mediaProviderMenu = _navigationManager.BuildMenu("mediaproviders"); var mediaProviderMenu = _navigationManager.BuildMenu("mediaproviders");
@ -91,9 +96,20 @@ namespace Orchard.MediaLibrary.Controllers {
[Themed(false)] [Themed(false)]
public ActionResult MediaItems(string folderPath, int skip = 0, int count = 0, string order = "created", string mediaType = "") { public ActionResult MediaItems(string folderPath, int skip = 0, int count = 0, string order = "created", string mediaType = "") {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot view media"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot view media")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
// Check permission.var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
var model = new MediaManagerMediaItemsViewModel {
MediaItems = new List<MediaManagerMediaItemViewModel>(),
MediaItemsCount = 0,
FolderPath = folderPath
};
return View(model);
}
var mediaParts = _mediaLibraryService.GetMediaContentItems(folderPath, skip, count, order, mediaType, VersionOptions.Latest); var mediaParts = _mediaLibraryService.GetMediaContentItems(folderPath, skip, count, order, mediaType, VersionOptions.Latest);
var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(folderPath, mediaType, VersionOptions.Latest); var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(folderPath, mediaType, VersionOptions.Latest);
@ -113,9 +129,19 @@ namespace Orchard.MediaLibrary.Controllers {
[Themed(false)] [Themed(false)]
public ActionResult ChildFolders(string folderPath = null) { public ActionResult ChildFolders(string folderPath = null) {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot get child folder listing"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot get child folder listing")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
// Check permission.
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
var model = new MediaManagerChildFoldersViewModel {
Children = new IMediaFolder[0]
};
return View(model);
}
var viewModel = new MediaManagerChildFoldersViewModel { var viewModel = new MediaManagerChildFoldersViewModel {
Children = _mediaLibraryService.GetMediaFolders(folderPath) Children = _mediaLibraryService.GetMediaFolders(folderPath)
}; };
@ -127,11 +153,13 @@ namespace Orchard.MediaLibrary.Controllers {
[Themed(false)] [Themed(false)]
public ActionResult RecentMediaItems(int skip = 0, int count = 0, string order = "created", string mediaType = "") { public ActionResult RecentMediaItems(int skip = 0, int count = 0, string order = "created", string mediaType = "") {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot view media"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot view media")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
var mediaParts = _mediaLibraryService.GetMediaContentItems(skip, count, order, mediaType); var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder().MediaPath;
var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(mediaType);
var mediaParts = _mediaLibraryService.GetMediaContentItems(rootMediaFolder, skip, count, order, mediaType);
var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(rootMediaFolder, mediaType);
var mediaItems = mediaParts.Select(x => new MediaManagerMediaItemViewModel { var mediaItems = mediaParts.Select(x => new MediaManagerMediaItemViewModel {
@ -149,12 +177,13 @@ namespace Orchard.MediaLibrary.Controllers {
[Themed(false)] [Themed(false)]
public ActionResult MediaItem(int id, string displayType = "SummaryAdmin") { public ActionResult MediaItem(int id, string displayType = "SummaryAdmin") {
var contentItem = Services.ContentManager.Get(id, VersionOptions.Latest); var contentItem = Services.ContentManager.Get<MediaPart>(id, VersionOptions.Latest);
if (contentItem == null) if (contentItem == null)
return HttpNotFound(); return HttpNotFound();
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, contentItem, T("Cannot view media"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, contentItem, T("Cannot view media"))
|| !_mediaLibraryService.CanManageMediaFolder(contentItem.FolderPath))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
dynamic model = Services.ContentManager.BuildDisplay(contentItem, displayType); dynamic model = Services.ContentManager.BuildDisplay(contentItem, displayType);
@ -164,13 +193,20 @@ namespace Orchard.MediaLibrary.Controllers {
[HttpPost] [HttpPost]
public ActionResult Delete(int[] mediaItemIds) { public ActionResult Delete(int[] mediaItemIds) {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't delete media items"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't delete media items")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
var mediaItems = Services.ContentManager
.Query(VersionOptions.Latest)
.ForContentItems(mediaItemIds)
.List()
.Select(x => x.As<MediaPart>())
.Where(x => x != null);
try { try {
foreach (var media in Services.ContentManager.Query(VersionOptions.Latest).ForContentItems(mediaItemIds).List()) { foreach (var media in mediaItems) {
if (media != null) { if (_mediaLibraryService.CanManageMediaFolder(media.FolderPath)) {
Services.ContentManager.Remove(media); Services.ContentManager.Remove(media.ContentItem);
} }
} }
@ -184,12 +220,16 @@ namespace Orchard.MediaLibrary.Controllers {
[HttpPost] [HttpPost]
public ActionResult Clone(int mediaItemId) { public ActionResult Clone(int mediaItemId) {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't clone media items"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't clone media items")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
try { try {
var media = Services.ContentManager.Get(mediaItemId).As<MediaPart>(); var media = Services.ContentManager.Get(mediaItemId).As<MediaPart>();
if(!_mediaLibraryService.CanManageMediaFolder(media.FolderPath)) {
return new HttpUnauthorizedResult();
}
var newFileName = Path.GetFileNameWithoutExtension(media.FileName) + " Copy" + Path.GetExtension(media.FileName); var newFileName = Path.GetFileNameWithoutExtension(media.FileName) + " Copy" + Path.GetExtension(media.FileName);
_mediaLibraryService.CopyFile(media.FolderPath, media.FileName, media.FolderPath, newFileName); _mediaLibraryService.CopyFile(media.FolderPath, media.FileName, media.FolderPath, newFileName);

View File

@ -17,10 +17,13 @@ namespace Orchard.MediaLibrary.Controllers {
public class ClientStorageController : Controller { public class ClientStorageController : Controller {
private readonly IMediaLibraryService _mediaLibraryService; private readonly IMediaLibraryService _mediaLibraryService;
public ClientStorageController(IMediaLibraryService mediaManagerService, IOrchardServices orchardServices) { public ClientStorageController(
IMediaLibraryService mediaManagerService,
IContentManager contentManager,
IOrchardServices orchardServices) {
_mediaLibraryService = mediaManagerService; _mediaLibraryService = mediaManagerService;
Services = orchardServices; Services = orchardServices;
Services = orchardServices;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
} }
@ -42,7 +45,13 @@ namespace Orchard.MediaLibrary.Controllers {
[HttpPost] [HttpPost]
public ActionResult Upload(string folderPath, string type) { public ActionResult Upload(string folderPath, string type) {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot manage media"))) { if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) {
return new HttpUnauthorizedResult();
}
// Check permission.
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
} }

View File

@ -32,9 +32,15 @@ namespace Orchard.MediaLibrary.Controllers {
public Localizer T { get; set; } public Localizer T { get; set; }
public ActionResult Create(string folderPath) { public ActionResult Create(string folderPath) {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't create media folder"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't create media folder")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
// If the user is trying to access a folder above his boundaries, redirect him to his home folder
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
return RedirectToAction("Create", new { folderPath = rootMediaFolder.MediaPath });
}
var viewModel = new MediaManagerFolderCreateViewModel { var viewModel = new MediaManagerFolderCreateViewModel {
Hierarchy = _mediaLibraryService.GetMediaFolders(folderPath), Hierarchy = _mediaLibraryService.GetMediaFolders(folderPath),
FolderPath = folderPath FolderPath = folderPath
@ -45,12 +51,16 @@ namespace Orchard.MediaLibrary.Controllers {
[HttpPost, ActionName("Create")] [HttpPost, ActionName("Create")]
public ActionResult Create() { public ActionResult Create() {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't create media folder"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't create media folder")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
var viewModel = new MediaManagerFolderCreateViewModel(); var viewModel = new MediaManagerFolderCreateViewModel();
UpdateModel(viewModel); UpdateModel(viewModel);
if (!_mediaLibraryService.CanManageMediaFolder(viewModel.FolderPath)) {
return new HttpUnauthorizedResult();
}
try { try {
_mediaLibraryService.CreateFolder(viewModel.FolderPath, viewModel.Name); _mediaLibraryService.CreateFolder(viewModel.FolderPath, viewModel.Name);
Services.Notifier.Information(T("Media folder created")); Services.Notifier.Information(T("Media folder created"));
@ -66,9 +76,13 @@ namespace Orchard.MediaLibrary.Controllers {
} }
public ActionResult Edit(string folderPath) { public ActionResult Edit(string folderPath) {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't edit media folder"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't edit media folder")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
if (!_mediaLibraryService.CanManageMediaFolder(folderPath)) {
return new HttpUnauthorizedResult();
}
var viewModel = new MediaManagerFolderEditViewModel { var viewModel = new MediaManagerFolderEditViewModel {
FolderPath = folderPath, FolderPath = folderPath,
Name = folderPath.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar).Last() Name = folderPath.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar).Last()
@ -80,12 +94,16 @@ namespace Orchard.MediaLibrary.Controllers {
[HttpPost, ActionName("Edit")] [HttpPost, ActionName("Edit")]
[FormValueRequired("submit.Save")] [FormValueRequired("submit.Save")]
public ActionResult Edit() { public ActionResult Edit() {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't edit media folder"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't edit media folder")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
var viewModel = new MediaManagerFolderEditViewModel(); var viewModel = new MediaManagerFolderEditViewModel();
UpdateModel(viewModel); UpdateModel(viewModel);
if (!_mediaLibraryService.CanManageMediaFolder(viewModel.FolderPath)) {
return new HttpUnauthorizedResult();
}
try { try {
_mediaLibraryService.RenameFolder(viewModel.FolderPath, viewModel.Name); _mediaLibraryService.RenameFolder(viewModel.FolderPath, viewModel.Name);
Services.Notifier.Information(T("Media folder renamed")); Services.Notifier.Information(T("Media folder renamed"));
@ -101,12 +119,16 @@ namespace Orchard.MediaLibrary.Controllers {
[HttpPost, ActionName("Edit")] [HttpPost, ActionName("Edit")]
[FormValueRequired("submit.Delete")] [FormValueRequired("submit.Delete")]
public ActionResult Delete() { public ActionResult Delete() {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't delete media folder"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't delete media folder")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
var viewModel = new MediaManagerFolderEditViewModel(); var viewModel = new MediaManagerFolderEditViewModel();
UpdateModel(viewModel); UpdateModel(viewModel);
if (!_mediaLibraryService.CanManageMediaFolder(viewModel.FolderPath)) {
return new HttpUnauthorizedResult();
}
try { try {
_mediaLibraryService.DeleteFolder(viewModel.FolderPath); _mediaLibraryService.DeleteFolder(viewModel.FolderPath);
Services.Notifier.Information(T("Media folder deleted")); Services.Notifier.Information(T("Media folder deleted"));
@ -122,9 +144,13 @@ namespace Orchard.MediaLibrary.Controllers {
[HttpPost] [HttpPost]
public ActionResult Move(string folderPath, int[] mediaItemIds) { public ActionResult Move(string folderPath, int[] mediaItemIds) {
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't move media items"))) if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't move media items")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
if (!_mediaLibraryService.CanManageMediaFolder(folderPath)) {
return new HttpUnauthorizedResult();
}
foreach (var media in Services.ContentManager.Query().ForPart<MediaPart>().ForContentItems(mediaItemIds).List()) { foreach (var media in Services.ContentManager.Query().ForPart<MediaPart>().ForContentItems(mediaItemIds).List()) {
// don't try to rename the file if there is no associated media file // don't try to rename the file if there is no associated media file

View File

@ -9,12 +9,18 @@ using Orchard.MediaLibrary.ViewModels;
using Orchard.Themes; using Orchard.Themes;
using Orchard.UI.Admin; using Orchard.UI.Admin;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.MediaLibrary.Services;
namespace Orchard.MediaLibrary.Controllers { namespace Orchard.MediaLibrary.Controllers {
[Admin, Themed(false)] [Admin, Themed(false)]
public class OEmbedController : Controller { public class OEmbedController : Controller {
public OEmbedController(IOrchardServices services) { private readonly IMediaLibraryService _mediaLibraryService;
public OEmbedController(
IOrchardServices services,
IMediaLibraryService mediaManagerService) {
Services = services; Services = services;
_mediaLibraryService = mediaManagerService;
} }
public IOrchardServices Services { get; set; } public IOrchardServices Services { get; set; }
@ -32,6 +38,15 @@ namespace Orchard.MediaLibrary.Controllers {
[ActionName("Index")] [ActionName("Index")]
[ValidateInput(false)] [ValidateInput(false)]
public ActionResult IndexPOST(string folderPath, string url, string type, string title, string html, string thumbnail, string width, string height, string description) { public ActionResult IndexPOST(string folderPath, string url, string type, string title, string html, string thumbnail, string width, string height, string description) {
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia))
return new HttpUnauthorizedResult();
// Check permission.
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
return new HttpUnauthorizedResult();
}
var viewModel = new OEmbedViewModel { var viewModel = new OEmbedViewModel {
Url = url, Url = url,
FolderPath = folderPath FolderPath = folderPath

View File

@ -13,12 +13,19 @@ namespace Orchard.MediaLibrary.Controllers {
public class WebSearchController : Controller { public class WebSearchController : Controller {
private readonly IMediaLibraryService _mediaLibraryService; private readonly IMediaLibraryService _mediaLibraryService;
private readonly IContentManager _contentManager; private readonly IContentManager _contentManager;
public WebSearchController(IMediaLibraryService mediaManagerService, IContentManager contentManager) { public WebSearchController(
IMediaLibraryService mediaManagerService,
IContentManager contentManager,
IOrchardServices orchardServices) {
_mediaLibraryService = mediaManagerService; _mediaLibraryService = mediaManagerService;
_contentManager = contentManager; _contentManager = contentManager;
Services = orchardServices;
} }
public IOrchardServices Services { get; set; }
public ActionResult Index(string folderPath, string type) { public ActionResult Index(string folderPath, string type) {
var viewModel = new ImportMediaViewModel { var viewModel = new ImportMediaViewModel {
FolderPath = folderPath, FolderPath = folderPath,
@ -30,7 +37,15 @@ namespace Orchard.MediaLibrary.Controllers {
[HttpPost] [HttpPost]
public JsonResult ImagePost(string folderPath, string type, string url) { public ActionResult ImagePost(string folderPath, string type, string url) {
if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia))
return new HttpUnauthorizedResult();
// Check permission.
var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder();
if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) {
return new HttpUnauthorizedResult();
}
try { try {
var buffer = new WebClient().DownloadData(url); var buffer = new WebClient().DownloadData(url);

View File

@ -178,6 +178,7 @@
<Compile Include="Providers\OEmbedMenu.cs" /> <Compile Include="Providers\OEmbedMenu.cs" />
<Compile Include="Providers\WebSearchMenu.cs" /> <Compile Include="Providers\WebSearchMenu.cs" />
<Compile Include="ResourceManifest.cs" /> <Compile Include="ResourceManifest.cs" />
<Compile Include="Security\MediaAuthorizationEventHandler.cs" />
<Compile Include="Services\IMediaLibraryService.cs" /> <Compile Include="Services\IMediaLibraryService.cs" />
<Compile Include="Services\MediaLibraryService.cs" /> <Compile Include="Services\MediaLibraryService.cs" />
<Compile Include="Services\Shapes.cs" /> <Compile Include="Services\Shapes.cs" />

View File

@ -4,13 +4,15 @@ using Orchard.Security.Permissions;
namespace Orchard.MediaLibrary { namespace Orchard.MediaLibrary {
public class Permissions : IPermissionProvider { public class Permissions : IPermissionProvider {
public static readonly Permission ManageMediaContent = new Permission { Description = "Managing Media", Name = "ManageMediaContent" }; public static readonly Permission ManageMediaContent = new Permission { Description = "Manage Media", Name = "ManageMediaContent" };
public static readonly Permission ManageOwnMedia = new Permission { Description = "Manage Own Media", Name = "ManageOwnMedia", ImpliedBy = new[] { ManageMediaContent } };
public virtual Feature Feature { get; set; } public virtual Feature Feature { get; set; }
public IEnumerable<Permission> GetPermissions() { public IEnumerable<Permission> GetPermissions() {
return new[] { return new[] {
ManageMediaContent, ManageMediaContent,
ManageOwnMedia,
}; };
} }
@ -33,6 +35,7 @@ namespace Orchard.MediaLibrary {
}, },
new PermissionStereotype { new PermissionStereotype {
Name = "Contributor", Name = "Contributor",
Permissions = new[] {ManageOwnMedia}
}, },
}; };
} }

View File

@ -15,7 +15,7 @@ namespace Orchard.MediaLibrary.Providers {
builder.AddImageSet("clientstorage") builder.AddImageSet("clientstorage")
.Add(T("My Computer"), "5", .Add(T("My Computer"), "5",
menu => menu.Action("Index", "ClientStorage", new { area = "Orchard.MediaLibrary" }) menu => menu.Action("Index", "ClientStorage", new { area = "Orchard.MediaLibrary" })
.Permission(Permissions.ManageMediaContent)); .Permission(Permissions.ManageOwnMedia));
} }
} }
} }

View File

@ -15,7 +15,7 @@ namespace Orchard.MediaLibrary.Providers {
builder.AddImageSet("oembed") builder.AddImageSet("oembed")
.Add(T("Media Url"), "10", .Add(T("Media Url"), "10",
menu => menu.Action("Index", "OEmbed", new { area = "Orchard.MediaLibrary" }) menu => menu.Action("Index", "OEmbed", new { area = "Orchard.MediaLibrary" })
.Permission(Permissions.ManageMediaContent)); .Permission(Permissions.ManageOwnMedia));
} }
} }
} }

View File

@ -15,7 +15,7 @@ namespace Orchard.MediaLibrary.Providers {
builder.AddImageSet("websearch") builder.AddImageSet("websearch")
.Add(T("Web Search"), "7", .Add(T("Web Search"), "7",
menu => menu.Action("Index", "WebSearch", new { area = "Orchard.MediaLibrary" }) menu => menu.Action("Index", "WebSearch", new { area = "Orchard.MediaLibrary" })
.Permission(Permissions.ManageMediaContent)); .Permission(Permissions.ManageOwnMedia));
} }
} }
} }

View File

@ -0,0 +1,35 @@
using Orchard.ContentManagement;
using Orchard.MediaLibrary.Models;
using Orchard.MediaLibrary.Services;
using Orchard.Security;
namespace Orchard.MediaLibrary.Security {
public class MediaAuthorizationEventHandler : IAuthorizationServiceEventHandler {
private readonly IAuthorizer _authorizer;
private readonly IMediaLibraryService _mediaLibraryService;
public MediaAuthorizationEventHandler(
IAuthorizer authorizer,
IMediaLibraryService mediaLibraryService) {
_authorizer = authorizer;
_mediaLibraryService = mediaLibraryService;
}
public void Checking(CheckAccessContext context) { }
public void Complete(CheckAccessContext context) { }
public void Adjust(CheckAccessContext context) {
var mediaPart = context.Content.As<MediaPart>();
if (mediaPart != null) {
if(_authorizer.Authorize(Permissions.ManageMediaContent)) {
context.Granted = true;
return;
}
if(_authorizer.Authorize(Permissions.ManageOwnMedia)) {
context.Granted = _mediaLibraryService.CanManageMediaFolder(mediaPart.FolderPath);
}
}
}
}
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Web; using System.Web;
using Orchard.ContentManagement; using Orchard.ContentManagement;
@ -36,7 +37,7 @@ namespace Orchard.MediaLibrary.Services {
/// <returns>The public URL for the media.</returns> /// <returns>The public URL for the media.</returns>
string GetMediaPublicUrl(string mediaPath, string fileName); string GetMediaPublicUrl(string mediaPath, string fileName);
MediaFolder GetRootMediaFolder(); IMediaFolder GetRootMediaFolder();
/// <summary> /// <summary>
/// Retrieves the media folders within a given relative path. /// Retrieves the media folders within a given relative path.
@ -131,4 +132,30 @@ namespace Orchard.MediaLibrary.Services {
/// <returns>The path to the uploaded file.</returns> /// <returns>The path to the uploaded file.</returns>
string UploadMediaFile(string folderPath, string fileName, Stream inputStream); string UploadMediaFile(string folderPath, string fileName, Stream inputStream);
} }
public static class MediaLibrayServiceExtensions {
public static bool CanManageMediaFolder(this IMediaLibraryService service, string folderPath) {
// The current user can manage a media if he has access to the whole hierarchy
// or the media is under his personal storage folder.
var rootMediaFolder = service.GetRootMediaFolder();
if (rootMediaFolder == null) {
return true;
}
var mediaPath = folderPath + "\\";
var rootPath = rootMediaFolder.MediaPath + "\\";
return mediaPath.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase);
}
public static string GetRootedFolderPath(this IMediaLibraryService service, string folderPath) {
var rootMediaFolder = service.GetRootMediaFolder();
if (rootMediaFolder != null) {
return Path.Combine(rootMediaFolder.MediaPath, folderPath ?? "");
}
return folderPath;
}
}
} }

View File

@ -210,7 +210,21 @@ namespace Orchard.MediaLibrary.Services {
return GetPublicUrl(Path.Combine(mediaPath, fileName)); return GetPublicUrl(Path.Combine(mediaPath, fileName));
} }
public MediaFolder GetRootMediaFolder() { public IMediaFolder GetRootMediaFolder() {
if (_orchardServices.Authorizer.Authorize(Permissions.ManageMediaContent)) {
return null;
}
if (_orchardServices.Authorizer.Authorize(Permissions.ManageOwnMedia)) {
var currentUser = _orchardServices.WorkContext.CurrentUser;
var userPath = _storageProvider.Combine("Users", currentUser.UserName);
return new MediaFolder() {
Name = currentUser.UserName,
MediaPath = userPath
};
}
return null; return null;
} }

View File

@ -60,7 +60,7 @@ namespace Orchard.MediaLibrary.Services {
UrlHelper url) { UrlHelper url) {
var user = _membershipService.ValidateUser(userName, password); var user = _membershipService.ValidateUser(userName, password);
if (!_authorizationService.TryCheckAccess(Permissions.ManageMediaContent, user, null)) { if (!_authorizationService.TryCheckAccess(Permissions.ManageOwnMedia, user, null)) {
throw new OrchardCoreException(T("Access denied")); throw new OrchardCoreException(T("Access denied"));
} }
@ -72,6 +72,11 @@ namespace Orchard.MediaLibrary.Services {
directoryName = "media"; directoryName = "media";
} }
// If the user only has access to his own folder, rewrite the folder name
if (!_authorizationService.TryCheckAccess(Permissions.ManageMediaContent, user, null)) {
directoryName = Path.Combine(_mediaLibraryService.GetRootedFolderPath(directoryName));
}
try { try {
// delete the file if it already exists, e.g. an updated image in a blog post // delete the file if it already exists, e.g. an updated image in a blog post
// it's safe to delete the file as each content item gets a specific folder // it's safe to delete the file as each content item gets a specific folder

View File

@ -112,7 +112,7 @@ var mediaLibrarySettings = {
<div class="media-library-folder-title" data-bind="click: folderClicked, attr: { 'data-media-path': folderPath() }, css: {selected: isSelected()}"> <div class="media-library-folder-title" data-bind="click: folderClicked, attr: { 'data-media-path': folderPath() }, css: {selected: isSelected()}">
<a href="#" class="media-library-navigation-folder-link"><i data-bind=" css: {'icon-folder-open-alt': isExpanded(), 'icon-folder-close-alt': !isExpanded()}"></i><span data-bind=" text: name"></span></a> <a href="#" class="media-library-navigation-folder-link"><i data-bind=" css: {'icon-folder-open-alt': isExpanded(), 'icon-folder-close-alt': !isExpanded()}"></i><span data-bind=" text: name"></span></a>
</div> </div>
<ul data-bind="template: { name: 'media-folder-template', foreach: childFolders, afterRender: afterRenderMediaFolderTemplate}, visible: isExpanded()"> <ul data-bind="template: { name: 'media-folder-template', foreach: childFolders, afterRender: afterRenderMediaFolderTemplate}, visible: isExpanded()">
</ul> </ul>
</div> </div>
</li> </li>

View File

@ -6,10 +6,12 @@
<div class="breadCrumbs"> <div class="breadCrumbs">
<p>@Html.ActionLink(T("Media Library").ToString(), "Index", "Admin", new { area = "Orchard.MediaLibrary" }, new {}) &#62; <p>@Html.ActionLink(T("Media Library").ToString(), "Index", "Admin", new { area = "Orchard.MediaLibrary" }, new {}) &#62;
@if (Model.FolderPath != null) { @if (Model.FolderPath != null) {
foreach (var folder in Model.FolderPath.Split('/')) { var fullPath = "";
if (!String.IsNullOrEmpty(folder)) { foreach (var folder in Model.FolderPath.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar })) {
@Html.ActionLink(folder, "Edit", new {folderPath = folder}) if (!String.IsNullOrEmpty(folder)) {
<text>&#62;</text> fullPath = Path.Combine(fullPath, folder);
@Html.ActionLink(folder, "Index", "Admin", new {folderPath = fullPath }, null)
<text>&#62;</text>
} }
} }
} }

View File

@ -75,7 +75,7 @@ namespace Orchard.Search.Controllers {
// ignore search results which content item has been removed or unpublished // ignore search results which content item has been removed or unpublished
var foundItems = _contentManager.GetMany<IContent>(foundIds, VersionOptions.Published, new QueryHints()).ToList(); var foundItems = _contentManager.GetMany<IContent>(foundIds, VersionOptions.Published, new QueryHints()).ToList();
foreach (var contentItem in foundItems) { foreach (var contentItem in foundItems) {
list.Add(_contentManager.BuildDisplay(contentItem, "Summary")); list.Add(_contentManager.BuildDisplay(contentItem, searchSettingPart.DisplayType));
} }
searchHits.TotalItemCount -= foundIds.Count() - foundItems.Count(); searchHits.TotalItemCount -= foundIds.Count() - foundItems.Count();

View File

@ -1,7 +1,5 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Xml.Linq;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
@ -49,10 +47,13 @@ namespace Orchard.Search.Drivers {
var model = new SearchSettingsFieldsViewModel(); var model = new SearchSettingsFieldsViewModel();
var searchFields = part.SearchFields; var searchFields = part.SearchFields;
model.DisplayType = part.DisplayType;
if (updater != null) { if (updater != null) {
if (updater.TryUpdateModel(model, Prefix, null, null)) { if (updater.TryUpdateModel(model, Prefix, null, null)) {
part.SearchFields = model.Entries.ToDictionary(x => x.Index, x => x.Fields.Where(e => e.Selected).Select(e => e.Field).ToArray()); part.SearchFields = model.Entries.ToDictionary(x => x.Index, x => x.Fields.Where(e => e.Selected).Select(e => e.Field).ToArray());
part.FilterCulture = model.FilterCulture; part.FilterCulture = model.FilterCulture;
part.DisplayType = model.DisplayType;
} }
} }
else if (_indexManager.HasIndexProvider()) { else if (_indexManager.HasIndexProvider()) {

View File

@ -24,5 +24,10 @@ namespace Orchard.Search.Models {
get { return this.Retrieve(x => x.SearchIndex); } get { return this.Retrieve(x => x.SearchIndex); }
set { this.Store(x => x.SearchIndex, value); } set { this.Store(x => x.SearchIndex, value); }
} }
public string DisplayType {
get { return this.Retrieve(x => x.DisplayType, "Summary"); }
set { this.Store(x => x.DisplayType, value); }
}
} }
} }

View File

@ -16,6 +16,7 @@ namespace Orchard.Search.ViewModels {
public IList<IndexSettingsEntry> Entries { get; set; } public IList<IndexSettingsEntry> Entries { get; set; }
public bool FilterCulture { get; set; } public bool FilterCulture { get; set; }
public string DisplayType { get; set; }
} }
public class IndexSettingsEntry { public class IndexSettingsEntry {

View File

@ -44,5 +44,9 @@
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.FilterCulture)">@T("Narrow search to current culture only")</label> <label class="forcheckbox" for="@Html.FieldIdFor(m => m.FilterCulture)">@T("Narrow search to current culture only")</label>
<span class="hint">@T("If checked, search results will only include content items localized in the current culture of the request.")</span> <span class="hint">@T("If checked, search results will only include content items localized in the current culture of the request.")</span>
</div> </div>
<div>
<label for="@Html.FieldIdFor(m => m.DisplayType)">@T("Display Type")</label>
@Html.TextBoxFor(m => m.DisplayType, new { @class = "text single-line" })
<span class="hint">@T("The display type to use for content items in the search results page.")</span>
</div>
</fieldset> </fieldset>

View File

@ -1,17 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Taxonomies.Models; using Orchard.Taxonomies.Models;
namespace Orchard.Taxonomies.Services { namespace Orchard.Taxonomies.Services {
public class TermCountProcessor : ITermCountProcessor { public class TermCountProcessor : ITermCountProcessor {
private readonly IContentManager _contentManager;
private readonly ITaxonomyService _taxonomyService; private readonly ITaxonomyService _taxonomyService;
public TermCountProcessor(IContentManager contentManager, ITaxonomyService taxonomyService) { public TermCountProcessor(ITaxonomyService taxonomyService) {
_contentManager = contentManager;
_taxonomyService = taxonomyService; _taxonomyService = taxonomyService;
} }
@ -31,4 +25,4 @@ namespace Orchard.Taxonomies.Services {
} }
} }
} }
} }

View File

@ -30,9 +30,9 @@
var selectedTerms = Newtonsoft.Json.JsonConvert.SerializeObject(Model.Terms.Where(x => x.IsChecked).Select(x => new { label = x.Name, value = x.Id, levels = 0, disabled = true })); var selectedTerms = Newtonsoft.Json.JsonConvert.SerializeObject(Model.Terms.Where(x => x.IsChecked).Select(x => new { label = x.Name, value = x.Id, levels = 0, disabled = true }));
} }
<fieldset class="taxonomy-wrapper" data-name-prefix="@Html.FieldNameFor(m => m)" data-id-prefix="@Html.FieldIdFor(m => m)"> <fieldset class="taxonomy-wrapper" data-name-prefix="@Html.FieldNameFor(m => m)" data-id-prefix="@Html.FieldIdFor(m => m)">
<legend @if(Model.Settings.Required) { <text>class="required"</text> }>@Model.DisplayName</legend> <label @if(Model.Settings.Required) { <text>class="required"</text> }>@Model.DisplayName</label>
@if (Model.Settings.Autocomplete) { @if (Model.Settings.Autocomplete) {
<div class="terms-editor" data-all-terms="@allTerms" data-selected-terms="@selectedTerms" data-allow-new-terms="@Model.Settings.AllowCustomTerms.ToString().ToLower()" data-singlechoice="@Model.Settings.SingleChoice.ToString().ToLower()"> <div class="terms-editor text text-medium" data-all-terms="@allTerms" data-selected-terms="@selectedTerms" data-allow-new-terms="@Model.Settings.AllowCustomTerms.ToString().ToLower()" data-singlechoice="@Model.Settings.SingleChoice.ToString().ToLower()">
<ul></ul> <ul></ul>
@if (Model.Settings.SingleChoice) { @if (Model.Settings.SingleChoice) {
<div class="hint">@T("Enter a single term. Hit <i>tab</i> or <i>enter</i> to apply the term.") @if (!Model.Settings.AllowCustomTerms) { <text>@T("This taxonomy does not allow you to create new terms.") </text> }</div> <div class="hint">@T("Enter a single term. Hit <i>tab</i> or <i>enter</i> to apply the term.") @if (!Model.Settings.AllowCustomTerms) { <text>@T("This taxonomy does not allow you to create new terms.") </text> }</div>
@ -67,7 +67,7 @@
</ul> </ul>
</div> </div>
@if (!Model.Terms.Any()) { @if (!Model.Terms.Any() && AuthorizedFor(Orchard.Taxonomies.Permissions.CreateTerm)) {
<div class="no-terms"> <div class="no-terms">
@T("There are no terms defined for {0} yet.", Model.DisplayName) @T("There are no terms defined for {0} yet.", Model.DisplayName)
<a href="@Url.Action("Index", "TermAdmin", new { taxonomyId = Model.TaxonomyId, area = "Orchard.Taxonomies" })">@T("Create some terms")</a> <a href="@Url.Action("Index", "TermAdmin", new { taxonomyId = Model.TaxonomyId, area = "Orchard.Taxonomies" })">@T("Create some terms")</a>

View File

@ -42,7 +42,7 @@
} }
</ul> </ul>
@if (!Model.Terms.Any()) { @if (!Model.Terms.Any() && AuthorizedFor(Orchard.Taxonomies.Permissions.CreateTerm)) {
<div class="no-terms"> <div class="no-terms">
@T("There are no terms defined for {0} yet.", Model.DisplayName) @T("There are no terms defined for {0} yet.", Model.DisplayName)
<a href="@Url.Action("Index", "TermAdmin", new { taxonomyId = Model.TaxonomyId, area = "Orchard.Taxonomies" })">@T("Create some terms")</a> <a href="@Url.Action("Index", "TermAdmin", new { taxonomyId = Model.TaxonomyId, area = "Orchard.Taxonomies" })">@T("Create some terms")</a>

View File

@ -69,7 +69,8 @@ namespace Orchard.Widgets.Controllers {
} }
LayerPart currentLayer = layerId == null LayerPart currentLayer = layerId == null
? layers.FirstOrDefault(layer => layer.Name == "Default") ?? layers.FirstOrDefault() // look for the "Default" layer, or take the first if it doesn't exist
? layers.FirstOrDefault(x => x.Name == "Default") ?? layers.FirstOrDefault()
: layers.FirstOrDefault(layer => layer.Id == layerId); : layers.FirstOrDefault(layer => layer.Id == layerId);
if (currentLayer == null && layerId != null) { // Incorrect layer id passed if (currentLayer == null && layerId != null) { // Incorrect layer id passed

View File

@ -68,7 +68,13 @@
return false; return false;
} }
return confirm(confirmRemoveMessage); // use a custom message if its set in data-message
var dataMessage = $(this).data('message');
if (dataMessage === undefined) {
dataMessage = confirmRemoveMessage;
}
return confirm(dataMessage);
}); });
$(".check-all").change(function () { $(".check-all").change(function () {

View File

@ -97,7 +97,7 @@
@using (Script.Foot()) { @using (Script.Foot()) {
<script type="text/javascript"> <script type="text/javascript">
//<![CDATA[ //<![CDATA[
var confirmRemoveMessage = '@T("Are you sure you want to remove this element ?")'; var confirmRemoveMessage = '@T("Are you sure you want to remove this element?")';
//]]> //]]>
</script> </script>
} }

View File

@ -21,14 +21,6 @@ namespace Orchard.ContentManagement {
public virtual ContentItem ContentItem { get; set; } public virtual ContentItem ContentItem { get; set; }
//interesting thought, should/could parts also have zones (would then have zones on the page, content item and parts...)?
private readonly IZoneCollection _zones = new ZoneCollection();
public virtual IZoneCollection Zones {
get {
return _zones;
}
}
/// <summary> /// <summary>
/// The ContentItem's identifier. /// The ContentItem's identifier.
/// </summary> /// </summary>

View File

@ -0,0 +1,5 @@
namespace Orchard.DisplayManagement {
public interface IPositioned {
string Position { get; }
}
}

View File

@ -1,5 +1,4 @@
using System.Diagnostics; using Orchard.DisplayManagement.Shapes;
using Orchard.DisplayManagement.Shapes;
namespace Orchard.DisplayManagement { namespace Orchard.DisplayManagement {
/// <summary> /// <summary>

View File

@ -0,0 +1,26 @@
using System.Web;
namespace Orchard.DisplayManagement {
public class PositionWrapper : IHtmlString, IPositioned {
private IHtmlString _value;
public string Position { get; private set; }
public PositionWrapper(IHtmlString value, string position) {
_value = value;
Position = position;
}
public PositionWrapper(string value, string position)
: this(new HtmlString(HttpUtility.HtmlEncode(value)), position) {
}
public string ToHtmlString() {
return _value.ToHtmlString();
}
public override string ToString() {
return _value.ToString();
}
}
}

View File

@ -4,11 +4,11 @@ using System.Dynamic;
using System.Linq; using System.Linq;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Web.Mvc; using System.Web;
namespace Orchard.DisplayManagement.Shapes { namespace Orchard.DisplayManagement.Shapes {
[DebuggerTypeProxy(typeof(ShapeDebugView))] [DebuggerTypeProxy(typeof(ShapeDebugView))]
public class Shape : Composite, IShape, IEnumerable<object> { public class Shape : Composite, IShape, IPositioned, IEnumerable<object> {
private const string DefaultPosition = "5"; private const string DefaultPosition = "5";
private readonly IList<object> _items = new List<object>(); private readonly IList<object> _items = new List<object>();
@ -22,6 +22,12 @@ namespace Orchard.DisplayManagement.Shapes {
public virtual IDictionary<string, string> Attributes { get { return _attributes; } } public virtual IDictionary<string, string> Attributes { get { return _attributes; } }
public virtual IEnumerable<dynamic> Items { get { return _items; } } public virtual IEnumerable<dynamic> Items { get { return _items; } }
public string Position {
get {
return Metadata.Position;
}
}
public Shape() { public Shape() {
Metadata = new ShapeMetadata(); Metadata = new ShapeMetadata();
} }
@ -33,13 +39,14 @@ namespace Orchard.DisplayManagement.Shapes {
} }
try { try {
// todo: (sebros) this is a temporary implementation to prevent common known scenarios throwing exceptions. The final solution would need to filter based on the fact that it is a Shape instance if (position != null && item is IHtmlString) {
if (item is MvcHtmlString || item = new PositionWrapper((IHtmlString)item, position);
item is String) { }
// need to implement positioned wrapper for non-shape objects else if (position != null && item is string) {
item = new PositionWrapper((string)item, position);
} }
else if (item is IShape) { else if (item is IShape) {
((dynamic)item).Metadata.Position = position; ((IShape)item).Metadata.Position = position;
} }
} }
catch { catch {

View File

@ -151,6 +151,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="BackgroundHttpContextFactory.cs" /> <Compile Include="BackgroundHttpContextFactory.cs" />
<Compile Include="DisplayManagement\IPositioned.cs" />
<Compile Include="DisplayManagement\PositionWrapper.cs" />
<Compile Include="Data\Migration\Schema\AddUniqueConstraintCommand.cs" /> <Compile Include="Data\Migration\Schema\AddUniqueConstraintCommand.cs" />
<Compile Include="Data\Migration\Schema\DropUniqueConstraintCommand.cs" /> <Compile Include="Data\Migration\Schema\DropUniqueConstraintCommand.cs" />
<Compile Include="Environment\Extensions\Models\LifecycleStatus.cs" /> <Compile Include="Environment\Extensions\Models\LifecycleStatus.cs" />

View File

@ -155,6 +155,10 @@ namespace Orchard.UI.Resources {
return this; return this;
} }
/// <summary>
/// Sets the version of the resource.
/// </summary>
/// <param name="version">The version to set, in the form of <code>major.minor[.build[.revision]]</code></param>
public ResourceDefinition SetVersion(string version) { public ResourceDefinition SetVersion(string version) {
Version = version; Version = version;
return this; return this;