Merge branch 'temp8' into temp8-di2690

This commit is contained in:
Stephan
2019-01-02 15:42:57 +01:00
32 changed files with 1064 additions and 1142 deletions

View File

@@ -6,11 +6,11 @@
function link($scope) {
$scope.outSideClick = function() {
navigationService.hideNavigation();
navigationService.hideDialog();
}
keyboardService.bind("esc", function() {
navigationService.hideNavigation();
navigationService.hideDialog();
});
//ensure to unregister from all events!

View File

@@ -940,8 +940,116 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
),
"Failed to roll back content item with id " + contentId
);
}
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#getPublicAccess
* @methodOf umbraco.resources.contentResource
*
* @description
* Returns the public access protection for a content item
*
* ##usage
* <pre>
* contentResource.getPublicAccess(contentId)
* .then(function(publicAccess) {
* // do your thing
* });
* </pre>
*
* @param {Int} contentId The content Id
* @returns {Promise} resourcePromise object containing the public access protection
*
*/
getPublicAccess: function (contentId) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl("contentApiBaseUrl", "GetPublicAccess", {
contentId: contentId
})
),
"Failed to get public access for content item with id " + contentId
);
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#updatePublicAccess
* @methodOf umbraco.resources.contentResource
*
* @description
* Sets or updates the public access protection for a content item
*
* ##usage
* <pre>
* contentResource.updatePublicAccess(contentId, userName, password, roles, loginPageId, errorPageId)
* .then(function() {
* // do your thing
* });
* </pre>
*
* @param {Int} contentId The content Id
* @param {Array} groups The names of the groups that should have access (if using group based protection)
* @param {Array} usernames The usernames of the members that should have access (if using member based protection)
* @param {Int} loginPageId The Id of the login page
* @param {Int} errorPageId The Id of the error page
* @returns {Promise} resourcePromise object containing the public access protection
*
*/
updatePublicAccess: function (contentId, groups, usernames, loginPageId, errorPageId) {
var publicAccess = {
contentId: contentId,
loginPageId: loginPageId,
errorPageId: errorPageId
};
if (angular.isArray(groups) && groups.length) {
publicAccess.groups = groups;
}
else if (angular.isArray(usernames) && usernames.length) {
publicAccess.usernames = usernames;
}
else {
throw "must supply either userName/password or roles";
}
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl("contentApiBaseUrl", "PostPublicAccess", publicAccess)
),
"Failed to update public access for content item with id " + contentId
);
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#removePublicAccess
* @methodOf umbraco.resources.contentResource
*
* @description
* Removes the public access protection for a content item
*
* ##usage
* <pre>
* contentResource.removePublicAccess(contentId)
* .then(function() {
* // do your thing
* });
* </pre>
*
* @param {Int} contentId The content Id
* @returns {Promise} resourcePromise object that's resolved once the public access has been removed
*
*/
removePublicAccess: function (contentId) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl("contentApiBaseUrl", "RemovePublicAccess", {
contentId: contentId
})
),
"Failed to remove public access for content item with id " + contentId
);
}
};
}

View File

@@ -70,6 +70,8 @@ function appState(eventsService) {
currentNode: null,
//Whether the menu's dialog is being shown or not
showMenuDialog: null,
//Whether the menu's dialog can be hidden or not
allowHideMenuDialog: true,
// The dialogs template
dialogTemplateUrl: null,
//Whether the context menu is being shown or not
@@ -369,4 +371,4 @@ angular.module('umbraco.services').factory("editorState", function() {
});
return state;
});
});

View File

@@ -53,6 +53,7 @@ function navigationService($routeParams, $location, $q, $timeout, $injector, eve
appState.setGlobalState("showNavigation", true);
appState.setMenuState("showMenu", false);
appState.setMenuState("showMenuDialog", true);
appState.setMenuState("allowHideMenuDialog", true);
break;
case 'search':
appState.setGlobalState("navMode", "search");
@@ -66,6 +67,7 @@ function navigationService($routeParams, $location, $q, $timeout, $injector, eve
appState.setGlobalState("navMode", "default");
appState.setMenuState("showMenu", false);
appState.setMenuState("showMenuDialog", false);
appState.setMenuState("allowHideMenuDialog", true);
appState.setSectionState("showSearchResults", false);
appState.setGlobalState("stickyNavigation", false);
appState.setGlobalState("showTray", false);
@@ -570,6 +572,22 @@ function navigationService($routeParams, $location, $q, $timeout, $injector, eve
},
/**
* @ngdoc method
* @name umbraco.services.navigationService#allowHideDialog
* @methodOf umbraco.services.navigationService
*
* @param {boolean} allow false if the navigation service should disregard instructions to hide the current dialog, true otherwise
* @description
* instructs the navigation service whether it's allowed to hide the current dialog
*/
allowHideDialog: function (allow) {
if (appState.getGlobalState("navMode") !== "dialog") {
return;
}
appState.setMenuState("allowHideMenuDialog", allow);
},
/**
* @ngdoc method
* @name umbraco.services.navigationService#hideDialog
@@ -579,7 +597,9 @@ function navigationService($routeParams, $location, $q, $timeout, $injector, eve
* hides the currently open dialog
*/
hideDialog: function (showMenu) {
if (appState.getMenuState("allowHideMenuDialog") === false) {
return;
}
if (showMenu) {
this.showMenu({ skipDefault: true, node: appState.getMenuState("currentNode") });
} else {

View File

@@ -106,7 +106,6 @@ iframe, .content-column-body {
display: flex;
flex-wrap: nowrap;
flex-direction: row;
justify-content: center;
align-items: flex-start;
margin-top: 15px;

View File

@@ -0,0 +1,255 @@
(function () {
"use strict";
function ContentProtectController($scope, $q, contentResource, memberResource, memberGroupResource, navigationService, localizationService, editorService) {
var vm = this;
var id = $scope.currentNode.id;
vm.loading = false;
vm.buttonState = "init";
vm.isValid = isValid;
vm.next = next;
vm.save = save;
vm.close = close;
vm.toggle = toggle;
vm.pickLoginPage = pickLoginPage;
vm.pickErrorPage = pickErrorPage;
vm.pickGroup = pickGroup;
vm.removeGroup = removeGroup;
vm.pickMember = pickMember;
vm.removeMember = removeMember;
vm.removeProtection = removeProtection;
vm.removeProtectionConfirm = removeProtectionConfirm;
vm.type = null;
vm.step = null;
function onInit() {
vm.loading = true;
// get the current public access protection
contentResource.getPublicAccess(id).then(function (publicAccess) {
vm.loading = false;
// init the current settings for public access (if any)
vm.loginPage = publicAccess.loginPage;
vm.errorPage = publicAccess.errorPage;
vm.groups = publicAccess.groups || [];
vm.members = publicAccess.members || [];
vm.canRemove = true;
if (vm.members.length) {
vm.type = "member";
next();
}
else if (vm.groups.length) {
vm.type = "group";
next();
}
else {
vm.canRemove = false;
}
});
}
function next() {
if (vm.type === "group") {
vm.loading = true;
// get all existing member groups for lookup upon selection
// NOTE: if/when member groups support infinite editing, we can't rely on using a cached lookup list of valid groups anymore
memberGroupResource.getGroups().then(function (groups) {
vm.step = vm.type;
vm.allGroups = groups;
vm.hasGroups = groups.length > 0;
vm.loading = false;
});
}
else {
vm.step = vm.type;
}
}
function isValid() {
if (!vm.type) {
return false;
}
if (!vm.protectForm.$valid) {
return false;
}
if (!vm.loginPage || !vm.errorPage) {
return false;
}
if (vm.type === "group") {
return vm.groups && vm.groups.length > 0;
}
if (vm.type === "member") {
return vm.members && vm.members.length > 0;
}
return true;
}
function save() {
vm.buttonState = "busy";
var groups = _.map(vm.groups, function (group) { return group.name; });
var usernames = _.map(vm.members, function (member) { return member.username; });
contentResource.updatePublicAccess(id, groups, usernames, vm.loginPage.id, vm.errorPage.id).then(
function () {
localizationService.localize("publicAccess_paIsProtected", [$scope.currentNode.name]).then(function (value) {
vm.success = {
message: value
};
});
navigationService.syncTree({ tree: "content", path: $scope.currentNode.path, forceReload: true });
}, function (error) {
vm.error = error;
vm.buttonState = "error";
}
);
}
function close() {
// ensure that we haven't set a locked state on the dialog before closing it
navigationService.allowHideDialog(true);
navigationService.hideDialog();
}
function toggle(group) {
group.selected = !group.selected;
}
function pickGroup() {
navigationService.allowHideDialog(false);
editorService.memberGroupPicker({
multiPicker: true,
submit: function(model) {
var selectedGroupIds = model.selectedMemberGroups
? model.selectedMemberGroups
: [model.selectedMemberGroup];
_.each(selectedGroupIds,
function (groupId) {
// find the group in the lookup list and add it if it isn't already
var group = _.find(vm.allGroups, function(g) { return g.id === parseInt(groupId); });
if (group && !_.find(vm.groups, function (g) { return g.id === group.id })) {
vm.groups.push(group);
}
});
editorService.close();
navigationService.allowHideDialog(true);
},
close: function() {
editorService.close();
navigationService.allowHideDialog(true);
}
});
}
function removeGroup(group) {
vm.groups = _.reject(vm.groups, function(g) { return g.id === group.id });
}
function pickMember() {
navigationService.allowHideDialog(false);
// TODO: once editorService has a memberPicker method, use that instead
editorService.treePicker({
multiPicker: true,
entityType: "Member",
section: "member",
treeAlias: "member",
filter: function (i) {
return i.metaData.isContainer;
},
filterCssClass: "not-allowed",
submit: function (model) {
if (model.selection && model.selection.length) {
var promises = [];
// get the selected member usernames
_.each(model.selection,
function (member) {
// TODO:
// as-is we need to fetch all the picked members one at a time to get their usernames.
// when editorService has a memberPicker method, see if this can't be avoided - otherwise
// add a memberResource.getByKeys() method to do all this in one request
promises.push(
memberResource.getByKey(member.key).then(function(newMember) {
if (!_.find(vm.members, function (currentMember) { return currentMember.username === newMember.username })) {
vm.members.push(newMember);
}
})
);
});
editorService.close();
navigationService.allowHideDialog(true);
// wait for all the member lookups to complete
vm.loading = true;
$q.all(promises).then(function() {
vm.loading = false;
});
}
},
close: function () {
editorService.close();
navigationService.allowHideDialog(true);
}
});
}
function removeMember(member) {
vm.members = _.without(vm.members, member);
}
function pickLoginPage() {
pickPage(vm.loginPage);
}
function pickErrorPage() {
pickPage(vm.errorPage);
}
function pickPage(page) {
navigationService.allowHideDialog(false);
editorService.contentPicker({
submit: function (model) {
if (page === vm.loginPage) {
vm.loginPage = model.selection[0];
}
else {
vm.errorPage = model.selection[0];
}
editorService.close();
navigationService.allowHideDialog(true);
},
close: function () {
editorService.close();
navigationService.allowHideDialog(true);
}
});
}
function removeProtection() {
vm.removing = true;
}
function removeProtectionConfirm() {
vm.buttonState = "busy";
contentResource.removePublicAccess(id).then(
function () {
localizationService.localize("publicAccess_paIsRemoved", [$scope.currentNode.name]).then(function(value) {
vm.success = {
message: value
};
});
navigationService.syncTree({ tree: "content", path: $scope.currentNode.path, forceReload: true });
}, function (error) {
vm.error = error;
vm.buttonState = "error";
}
);
}
onInit();
}
angular.module("umbraco").controller("Umbraco.Editors.Content.ProtectController", ContentProtectController);
})();

View File

@@ -0,0 +1,186 @@
<div ng-controller="Umbraco.Editors.Content.ProtectController as vm">
<form name="vm.protectForm" novalidate>
<div class="umb-dialog-body form-horizontal" ng-cloak>
<umb-pane ng-hide="vm.success">
<div ng-show="vm.error">
<div class="alert alert-error">
<div><strong>{{vm.error.errorMsg}}</strong></div>
<div>{{vm.error.data.message}}</div>
</div>
</div>
<umb-load-indicator ng-show="vm.loading">
</umb-load-indicator>
<div ng-show="!vm.step && !vm.loading">
<p class="abstract" ng-hide="success">
<localize key="publicAccess_paHowWould" tokens="[currentNode.name]">Choose how to restrict access to this page</localize>
</p>
<umb-pane>
<div class="pa-select-type">
<input id="protectionTypeMember" type="radio" name="protectionType" value="member" ng-model="vm.type">
<label for="protectionTypeMember">
<h5 class="pa-access-header"><localize key="publicAccess_paMembers">Specific members protection</localize></h5>
<p><localize key="publicAccess_paMembersHelp">If you want to grant access to specific members</localize></p>
</label>
</div>
<div class="pa-select-type">
<input id="protectionTypeGroup" type="radio" name="protectionType" value="group" ng-model="vm.type">
<label for="protectionTypeGroup">
<h5 class="pa-access-header"><localize key="publicAccess_paGroups">Group based protection</localize></h5>
<p><localize key="publicAccess_paGroupsHelp">If you want to grant access to all members of specific member groups</localize></p>
</label>
</div>
</umb-pane>
</div>
<div ng-show="vm.step && !vm.loading && !vm.removing">
<div ng-if="vm.step === 'member'">
<p><localize key="publicAccess_paSelectMembers" tokens="[currentNode.name]">Select the members that should have access to this page</localize></p>
<umb-pane>
<umb-node-preview ng-repeat="member in vm.members | orderBy:'name'"
icon="'icon-user'"
name="member.name"
allow-remove="true"
on-remove="vm.removeMember(member)">
</umb-node-preview>
<a href ng-click="vm.pickMember()" class="umb-node-preview-add" prevent-default>
<localize key="general_add">Add</localize>
</a>
</umb-pane>
</div>
<div ng-show="vm.step === 'group' && !vm.hasGroups">
<p><localize key="publicAccess_paGroupsNoGroups">You need to create a member group before you can use group based authentication</localize></p>
</div>
<div ng-show="vm.step === 'group' && vm.hasGroups">
<p><localize key="publicAccess_paSelectGroups" tokens="[currentNode.name]">Select the groups that should have access to this page</localize></p>
<umb-pane>
<umb-node-preview ng-repeat="group in vm.groups | orderBy:'name'"
icon="'icon-users'"
name="group.name"
allow-remove="true"
on-remove="vm.removeGroup(group)">
</umb-node-preview>
<a href ng-click="vm.pickGroup()" class="umb-node-preview-add" prevent-default>
<localize key="general_add">Add</localize>
</a>
</umb-pane>
</div>
<div ng-show="vm.step === 'member' || vm.hasGroups">
<p class="mt4"><localize key="publicAccess_paSelectPages">Select the pages that contain login form and error messages</localize></p>
<umb-pane>
<div class="control-group umb-control-group -no-border">
<div class="umb-el-wrap">
<label>
<strong><localize key="publicAccess_paLoginPage">Login Page</localize></strong>
<small><localize key="publicAccess_paLoginPageHelp">Choose the page that contains the login form</localize></small>
</label>
<a href ng-show="!vm.loginPage" ng-click="vm.pickLoginPage()" class="umb-node-preview-add" prevent-default>
<localize key="general_add">Add</localize>
</a>
<umb-node-preview ng-show="vm.loginPage"
icon="vm.loginPage.icon"
name="vm.loginPage.name"
allow-remove="true"
on-remove="vm.loginPage = null">
</umb-node-preview>
</div>
</div>
<div class="control-group umb-control-group">
<div class="umb-el-wrap">
<label>
<strong><localize key="publicAccess_paErrorPage">Error Page</localize></strong>
<small><localize key="publicAccess_paErrorPageHelp">Used when people are logged on, but do not have access</localize></small>
</label>
<a href ng-show="!vm.errorPage" ng-click="vm.pickErrorPage()" class="umb-node-preview-add" prevent-default>
<localize key="general_add">Add</localize>
</a>
<umb-node-preview ng-show="vm.errorPage"
icon="vm.errorPage.icon"
name="vm.errorPage.name"
allow-remove="true"
on-remove="vm.errorPage = null">
</umb-node-preview>
</div>
</div>
</umb-pane>
</div>
</div>
<div ng-show="vm.removing">
<p><localize key="publicAccess_paRemoveProtectionConfirm" tokens="[currentNode.name]">Are you sure you want to remove the protection from this page?</localize></p>
</div>
<!--<pre>{{vm | json}}</pre>-->
</umb-pane>
<umb-pane ng-show="vm.success">
<div class="alert alert-success" ng-bind-html="vm.success.message"></div>
<umb-button type="button"
action="vm.close()"
button-style="success"
label-key="general_ok">
</umb-button>
</umb-pane>
</div>
<div class="umb-dialog-footer umb-btn-toolbar" ng-hide="vm.loading || vm.success">
<umb-button ng-hide="vm.removing"
type="button"
button-style="link"
action="vm.close()"
label-key="general_close">
</umb-button>
<umb-button ng-hide="vm.step || vm.removing"
type="button"
action="vm.next()"
button-style="success"
label-key="general_next"
disabled="vm.loading || !vm.type">
</umb-button>
<umb-button ng-show="vm.canRemove && !vm.removing"
type="button"
action="vm.removeProtection()"
button-style="warning"
label-key="publicAccess_paRemoveProtection"
disabled="vm.buttonState === 'busy'">
</umb-button>
<umb-button ng-show="vm.step && !vm.removing"
type="button"
action="vm.save()"
state="vm.buttonState"
button-style="success"
label-key="buttons_save"
disabled="vm.buttonState === 'busy' || !vm.isValid()">
</umb-button>
<umb-button ng-show="vm.removing"
type="button"
button-style="link"
action="vm.close()"
label-key="buttons_confirmActionCancel">
</umb-button>
<umb-button ng-show="vm.removing"
type="button"
action="vm.removeProtectionConfirm()"
state="vm.buttonState"
button-style="success"
label-key="buttons_confirmActionConfirm"
disabled="vm.buttonState === 'busy'">
</umb-button>
</div>
</form>
</div>