Fixes content service publishing status when parent isn't published, fixes listview to properly have selected checkbox (ng-checked is not supposed to be used), fixes the pre-check if nothing is actually selected before performing bulk operations - U4-3149

This commit is contained in:
Shannon
2013-10-15 14:11:28 +11:00
parent 754ed06d86
commit e2e40a3356
5 changed files with 238 additions and 200 deletions

View File

@@ -1633,11 +1633,14 @@ namespace Umbraco.Core.Services
//Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
publishStatus.StatusType = CheckAndLogIsPublishable(content);
//Content contains invalid property values and can therefore not be published - fire event?
publishStatus.StatusType = CheckAndLogIsValid(content);
//set the invalid properties (if there are any)
publishStatus.InvalidProperties = ((ContentBase) content).LastInvalidProperties;
//if it is not successful, then check if the props are valid
if ((int)publishStatus.StatusType < 10)
{
//Content contains invalid property values and can therefore not be published - fire event?
publishStatus.StatusType = CheckAndLogIsValid(content);
//set the invalid properties (if there are any)
publishStatus.InvalidProperties = ((ContentBase)content).LastInvalidProperties;
}
//if we're still successful, then publish using the strategy
if (publishStatus.StatusType == PublishStatusType.Success)
{

View File

@@ -53,8 +53,10 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser
}
//check for changed built-in properties of the content
if (!_.isEqual(origContent.name, newContent.name)) {
origContent.name = newContent.name;
for (var o in origContent) {
if (!_.isEqual(origContent[o], newContent[o])) {
origContent[o] = newContent[o];
}
}
//check for changed properties of the content

View File

@@ -1,206 +1,213 @@
angular.module("umbraco")
.controller("Umbraco.PropertyEditors.ListViewController",
function ($rootScope, $scope, $routeParams, contentResource, contentTypeResource, notificationsService, iconHelper) {
.controller("Umbraco.PropertyEditors.ListViewController",
function ($rootScope, $scope, $routeParams, contentResource, contentTypeResource, notificationsService, iconHelper, dialogService) {
$scope.selected = [];
$scope.actionInProgress = false;
$scope.options = {
pageSize: 10,
pageNumber: 1,
filter: '',
orderBy: 'Id',
orderDirection: "desc"
};
$scope.actionInProgress = false;
$scope.listViewResultSet = {
totalPages: 0,
items: []
};
$scope.next = function(){
if ($scope.options.pageNumber < $scope.listViewResultSet.totalPages) {
$scope.options.pageNumber++;
$scope.options = {
pageSize: 10,
pageNumber: 1,
filter: '',
orderBy: 'Id',
orderDirection: "desc"
};
$scope.next = function () {
if ($scope.options.pageNumber < $scope.listViewResultSet.totalPages) {
$scope.options.pageNumber++;
$scope.reloadView($scope.contentId);
}
};
$scope.goToPage = function (pageNumber) {
$scope.options.pageNumber = pageNumber + 1;
$scope.reloadView($scope.contentId);
}
};
};
$scope.goToPage = function (pageNumber) {
$scope.options.pageNumber = pageNumber + 1;
$scope.reloadView($scope.contentId);
};
$scope.sort = function (field) {
$scope.options.orderBy = field;
if ($scope.options.orderDirection === "desc") {
$scope.options.orderDirection = "asc";
} else {
$scope.options.orderDirection = "desc";
}
$scope.sort = function (field) {
$scope.options.orderBy = field;
if ($scope.options.orderDirection === "desc") {
$scope.options.orderDirection = "asc";
}else{
$scope.options.orderDirection = "desc";
}
$scope.reloadView($scope.contentId);
};
$scope.prev = function(){
if ($scope.options.pageNumber > 1) {
$scope.options.pageNumber--;
$scope.reloadView($scope.contentId);
}
};
};
/*Loads the search results, based on parameters set in prev,next,sort and so on*/
/*Pagination is done by an array of objects, due angularJS's funky way of monitoring state
with simple values */
$scope.prev = function () {
if ($scope.options.pageNumber > 1) {
$scope.options.pageNumber--;
$scope.reloadView($scope.contentId);
}
};
/*Loads the search results, based on parameters set in prev,next,sort and so on*/
/*Pagination is done by an array of objects, due angularJS's funky way of monitoring state
with simple values */
$scope.reloadView = function (id) {
contentResource.getChildren(id, $scope.options).then(function (data) {
$scope.listViewResultSet = data;
$scope.pagination = [];
for (var i = $scope.listViewResultSet.totalPages - 1; i >= 0; i--) {
$scope.pagination[i] = { index: i, name: i + 1 };
}
if ($scope.options.pageNumber > $scope.listViewResultSet.totalPages) {
$scope.options.pageNumber = $scope.listViewResultSet.totalPages;
}
});
};
$scope.selectAll = function ($event) {
var checkbox = $event.target;
for (var i = 0; i < $scope.listViewResultSet.items.length; i++) {
var entity = $scope.listViewResultSet.items[i];
entity.selected = checkbox.checked;
}
};
$scope.isSelectedAll = function () {
return _.every($scope.listViewResultSet.items, function (item) {
return item.selected;
});
};
$scope.isAnythingSelected = function () {
return _.some($scope.listViewResultSet.items, function (item) {
return item.selected;
});
};
$scope.getIcon = function (entry) {
return iconHelper.convertFromLegacyIcon(entry.icon);
};
$scope.delete = function () {
var selected = _.filter($scope.listViewResultSet.items, function (item) {
return item.selected;
});
var total = selected.length;
if (total === 0) {
return;
}
if (confirm("Sure you want to delete?") == true) {
$scope.actionInProgress = true;
$scope.bulkStatus = "Starting with delete";
var current = 1;
for (var i = 0; i < selected.length; i++) {
$scope.bulkStatus = "Deleted doc " + current + " out of " + total + " documents";
contentResource.deleteById(selected[i].id).then(function (data) {
if (current === total) {
notificationsService.success("Bulk action", "Deleted " + total + "documents");
$scope.bulkStatus = "";
$scope.reloadView($scope.contentId);
$scope.actionInProgress = false;
}
current++;
});
}
}
};
$scope.publish = function () {
var selected = _.filter($scope.listViewResultSet.items, function (item) {
return item.selected;
});
var total = selected.length;
if (total === 0) {
return;
}
$scope.reloadView = function(id) {
contentResource.getChildren(id, $scope.options).then(function(data) {
$scope.listViewResultSet = data;
$scope.pagination = [];
for (var i = $scope.listViewResultSet.totalPages - 1; i >= 0; i--) {
$scope.pagination[i] = { index: i, name: i + 1 };
}
if ($scope.options.pageNumber > $scope.listViewResultSet.totalPages) {
$scope.options.pageNumber = $scope.listViewResultSet.totalPages;
}
});
};
var updateSelected = function (action, id) {
if (action === 'add' && $scope.selected.indexOf(id) === -1) {
$scope.selected.push(id);
}
if (action === 'remove' && $scope.selected.indexOf(id) !== -1) {
$scope.selected.splice($scope.selected.indexOf(id), 1);
}
};
$scope.updateSelection = function ($event, item) {
if(item.selected){
item.selected = false;
var index = $scope.selected.indexOf(item.id);
if(index){
$scope.selected.splice(index, 1);
}
}else{
item.selected = true;
$scope.selected.push(item.id);
}
};
$scope.selectAll = function ($event) {
var checkbox = $event.target;
var action = (checkbox.checked ? 'add' : 'remove');
for (var i = 0; i < $scope.listViewResultSet.items.length; i++) {
var entity = $scope.listViewResultSet.items[i];
entity.selected = checkbox.checked;
updateSelected(action, entity.id);
}
};
$scope.getSelectedClass = function (entity) {
return $scope.isSelected(entity.id) ? 'selected' : '';
};
$scope.isSelected = function (id) {
return $scope.selected.indexOf(id) >= 0;
};
$scope.isSelectedAll = function () {
if ($scope.listViewResultSet != null)
return $scope.selected.length === $scope.listViewResultSet.items.length;
else
return false;
};
$scope.isAnythingSelected = function() {
return $scope.selected.length > 0;
};
$scope.getIcon = function(entry){
return iconHelper.convertFromLegacyIcon(entry.icon);
};
$scope.delete = function () {
if (confirm("Sure you want to delete?") == true) {
$scope.actionInProgress = true;
$scope.bulkStatus = "Starting with delete";
$scope.bulkStatus = "Starting with publish";
var current = 1;
var total = $scope.selected.length;
for (var i = 0; i < $scope.selected.length; i++) {
$scope.bulkStatus = "Deleted doc " + current + " out of " + total + " documents";
contentResource.deleteById($scope.selected[i]).then(function(data) {
if (current == total) {
notificationsService.success("Bulk action", "Deleted " + total + "documents");
for (var i = 0; i < selected.length; i++) {
$scope.bulkStatus = "Publishing " + current + " out of " + total + " documents";
contentResource.publishById(selected[i].id)
.then(function (content) {
if (current == total) {
notificationsService.success("Bulk action", "Published " + total + "documents");
$scope.bulkStatus = "";
$scope.reloadView($scope.contentId);
$scope.actionInProgress = false;
}
current++;
}, function (err) {
$scope.bulkStatus = "";
$scope.selected = [];
$scope.reloadView($scope.contentId);
$scope.actionInProgress = false;
}
current++;
});
//if there are validation errors for publishing then we need to show them
if (err.status === 400 && err.data && err.data.Message) {
notificationsService.error("Publish error", err.data.Message);
}
else {
dialogService.ysodDialog(err);
}
});
}
};
$scope.unpublish = function () {
var selected = _.filter($scope.listViewResultSet.items, function (item) {
return item.selected;
});
var total = selected.length;
if (total === 0) {
return;
}
$scope.actionInProgress = true;
$scope.bulkStatus = "Starting with publish";
var current = 1;
for (var i = 0; i < selected.length; i++) {
$scope.bulkStatus = "Unpublishing " + current + " out of " + total + " documents";
contentResource.unPublish(selected[i].id)
.then(function (content) {
if (current == total) {
notificationsService.success("Bulk action", "Published " + total + "documents");
$scope.bulkStatus = "";
$scope.reloadView($scope.contentId);
$scope.actionInProgress = false;
}
current++;
});
}
};
if ($routeParams.id) {
$scope.pagination = new Array(100);
$scope.listViewAllowedTypes = contentTypeResource.getAllowedTypes($routeParams.id);
$scope.reloadView($routeParams.id);
$scope.contentId = $routeParams.id;
}
};
$scope.publish = function () {
$scope.actionInProgress = true;
$scope.bulkStatus = "Starting with publish";
var current = 1;
var total = $scope.selected.length;
for (var i = 0; i < $scope.selected.length; i++) {
$scope.bulkStatus = "Publishing " + current + " out of " + total + " documents";
contentResource.publishById($scope.selected[i])
.then(function(content){
if (current == total) {
notificationsService.success("Bulk action", "Published " + total + "documents");
$scope.bulkStatus = "";
$scope.reloadView($scope.contentId);
$scope.actionInProgress = false;
}
current++;
});
}
};
$scope.unpublish = function () {
$scope.actionInProgress = true;
$scope.bulkStatus = "Starting with publish";
var current = 1;
var total = $scope.selected.length;
for (var i = 0; i < $scope.selected.length; i++) {
$scope.bulkStatus = "Unpublishing " + current + " out of " + total + " documents";
contentResource.unPublish($scope.selected[i])
.then(function(content){
if (current == total) {
notificationsService.success("Bulk action", "Published " + total + "documents");
$scope.bulkStatus = "";
$scope.reloadView($scope.contentId);
$scope.actionInProgress = false;
}
current++;
});
}
};
if ($routeParams.id) {
$scope.pagination = new Array(100);
$scope.listViewAllowedTypes = contentTypeResource.getAllowedTypes($routeParams.id);
$scope.reloadView($routeParams.id);
$scope.contentId = $routeParams.id;
}
});
});

View File

@@ -31,8 +31,8 @@
</div>
<span ng-bind="bulkStatus" ng-show="isAnythingSelected()"></span>
</div>
<table class="table table-striped">
<table class="table table-striped">
<thead>
<tr>
<td with="20"><input type="checkbox" ng-click="selectAll($event)" ng-checked="isSelectedAll()"></td>
@@ -53,8 +53,7 @@
<td>
<i class="icon {{result.icon}}" ng-class="getIcon(result)"></i>
<input type="checkbox"
ng-checked="result.selected" ng-click="updateSelection($event, result)"></td>
<input type="checkbox" ng-model="result.selected"></td>
<td>
<a ng-class="{inactive:!result.published}" href="#/content/content/edit/{{result.id}}">{{result.name}}</a></td>
<td>{{result.updateDate|date:'medium'}}

View File

@@ -309,7 +309,34 @@ namespace Umbraco.Web.Editors
return HandleContentNotFound(id, false);
}
Services.ContentService.Publish(foundContent, UmbracoUser.Id);
var publishResult = Services.ContentService.PublishWithStatus(foundContent, UmbracoUser.Id);
if (publishResult.Success == false)
{
switch (publishResult.Result.StatusType)
{
case PublishStatusType.FailedPathNotPublished:
return Request.CreateValidationErrorResponse(
ui.Text("publish", "contentPublishedFailedByParent",
string.Format("{0} ({1})", publishResult.Result.ContentItem.Name, publishResult.Result.ContentItem.Id),
Security.CurrentUser).Trim());
case PublishStatusType.FailedCancelledByEvent:
return Request.CreateValidationErrorResponse(
ui.Text("speechBubbles", "contentPublishedFailedByEvent"));
case PublishStatusType.FailedHasExpired:
case PublishStatusType.FailedAwaitingRelease:
case PublishStatusType.FailedIsTrashed:
case PublishStatusType.FailedContentInvalid:
return Request.CreateValidationErrorResponse(
ui.Text("publish", "contentPublishedFailedInvalid",
new[]
{
string.Format("{0} ({1})", publishResult.Result.ContentItem.Name, publishResult.Result.ContentItem.Id),
string.Join(",", publishResult.Result.InvalidProperties.Select(x => x.Alias))
}, Security.CurrentUser));
}
}
//return ok
return Request.CreateResponse(HttpStatusCode.OK);
}