Fix WorkPackageAuthorization in new resource

The project is not loaded in the resource from the table when compared
to the single request.

I believe we should remove the entire authorization class and replace it
with something closely related to the way HalResources work.
pull/4605/head
Oliver Günther 8 years ago
parent 7780126274
commit f78d2041f8
  1. 17
      frontend/app/components/context-menus/wp-context-menu/wp-context-menu.service.test.ts
  2. 103
      frontend/app/components/work-packages/work-package-authorization.service.ts
  3. 47
      frontend/app/components/wp-details/wp-details-toolbar.directive.ts
  4. 9
      frontend/app/components/wp-table/context-menu-helper/wp-context-menu-helper.service.js
  5. 1
      frontend/app/work_packages/models/index.js
  6. 90
      frontend/app/work_packages/models/work-package-authorization.js
  7. 6
      frontend/tests/unit/tests/work_packages/directives/work-package-details-toolbar-test.js
  8. 15
      frontend/tests/unit/tests/work_packages/helpers/work-package-context-menu-helper-test.js

@ -80,13 +80,11 @@ describe('workPackageContextMenu', () => {
describe('when the context menu context contains one work package', () => {
var I18n;
var actions = ['edit', 'move'];
var actionLinks = {
var workPackage = {
id: 123,
update: '/work_packages/123/edit',
move: '/work_packages/move/new?ids%5B%5D=123',
};
var workPackage = Factory.build('PlanningElement');
workPackage.$source = { _links: actionLinks };
workPackage.$links = actionLinks;
}
var directListElements;
@ -108,7 +106,7 @@ describe('workPackageContextMenu', () => {
});
it('lists link tags for any permitted action', () =>{
expect(directListElements.length).to.equal(4);
expect(directListElements.length).to.equal(5);
});
it('assigns a css class named by the action', () =>{
@ -124,12 +122,7 @@ describe('workPackageContextMenu', () => {
});
describe('when delete is permitted on a work package', () => {
var actionLinks = {
'delete': '/work_packages/bulk',
};
var workPackage = Factory.build('PlanningElement');
workPackage.$source = { _links: actionLinks };
workPackage.$links = actionLinks;
workPackage['delete'] = '/work_packages/bulk';
beforeEach(() => {
$rootScope.rows = [];

@ -0,0 +1,103 @@
//-- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2013 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
import {opWorkPackagesModule} from '../../angular-modules';
import {WorkPackageResourceInterface} from '../api/api-v3/hal-resources/work-package-resource.service';
var $state;
var PathHelper;
export class WorkPackageAuthorization {
public project:any;
constructor(public workPackage:WorkPackageResourceInterface) {
this.project = workPackage.project;
}
public get allActions() {
return {
workPackage: this.workPackage,
project: this.project
};
}
public copyLink() {
if ($state.current.name.indexOf('work-packages.show') === 0) {
return PathHelper.workPackageCopyPath(this.workPackage.id);
}
else if ($state.current.name.indexOf('work-packages.list.details') === 0) {
return PathHelper.workPackageDetailsCopyPath(this.project.identifier, this.workPackage.id);
}
}
public linkForAction(action) {
if (action.key === 'copy') {
action.link = this.copyLink();
}
else {
action.link = this.allActions[action.resource][action.link].href;
}
return action;
}
public isPermitted(action) {
return this.allActions[action.resource] !== undefined &&
this.allActions[action.resource][action.link] !== undefined;
}
public permittedActionKeys(allowedActions) {
var validActions = _.filter(allowedActions, this.isPermitted, this);
return _.map(validActions, function (action) {
return action.key;
});
}
public permittedActionsWithLinks(allowedActions) {
var validActions = _.filter(_.cloneDeep(allowedActions), this.isPermitted, this);
var allowed = _.map(validActions, this.linkForAction, this);
return allowed;
}
}
function wpAuthorizationService(...args) {
[$state, PathHelper] = args;
return WorkPackageAuthorization;
}
wpAuthorizationService.$inject = [
'$state',
'PathHelper'
];
opWorkPackagesModule.factory('WorkPackageAuthorization', wpAuthorizationService);

@ -83,28 +83,31 @@ function wpDetailsToolbar(
},
link: function(scope, attr, element) {
var authorization = new WorkPackageAuthorization(scope.workPackage);
scope.displayWatchButton = scope.workPackage.hasOwnProperty('unwatch') ||
scope.workPackage.hasOwnProperty('watch');
scope.I18n = I18n;
scope.permittedActions = angular.extend(getPermittedActions(authorization, PERMITTED_MORE_MENU_ACTIONS),
getPermittedPluginActions(authorization));
scope.actionsAvailable = Object.keys(scope.permittedActions).length > 0;
scope.triggerMoreMenuAction = function(action, link) {
switch (action) {
case 'delete':
deleteSelectedWorkPackage();
break;
default:
$window.location.href = link;
break;
}
};
scope.wpEditModeState = wpEditModeState;
scope.workPackage.project.$load().then(() => {
var authorization = new WorkPackageAuthorization(scope.workPackage);
scope.displayWatchButton = scope.workPackage.hasOwnProperty('unwatch') ||
scope.workPackage.hasOwnProperty('watch');
scope.I18n = I18n;
scope.permittedActions = angular.extend(getPermittedActions(authorization, PERMITTED_MORE_MENU_ACTIONS),
getPermittedPluginActions(authorization));
scope.actionsAvailable = Object.keys(scope.permittedActions).length > 0;
scope.triggerMoreMenuAction = function(action, link) {
switch (action) {
case 'delete':
deleteSelectedWorkPackage();
break;
default:
$window.location.href = link;
break;
}
};
scope.wpEditModeState = wpEditModeState;
});
function deleteSelectedWorkPackage() {
var workPackageDeletionId = scope.workPackage.id;

@ -41,10 +41,7 @@ function WorkPackageContextMenuHelper(PERMITTED_BULK_ACTIONS, WorkPackagesTableS
singularPermittedActions.push({
icon: allowedAction.icon,
text: allowedAction.text,
link: workPackage
.$source
._links[allowedAction.link]
.href
link: workPackage[allowedAction.link].href
});
});
@ -92,14 +89,14 @@ function WorkPackageContextMenuHelper(PERMITTED_BULK_ACTIONS, WorkPackagesTableS
var allowedActions = [];
angular.forEach(actions, function(action) {
if (workPackage.$links.hasOwnProperty(action.link)) {
if (workPackage.hasOwnProperty(action.link)) {
action.text = I18n.t('js.button_' + action.icon);
allowedActions.push(action);
}
});
angular.forEach(HookService.call('workPackageTableContextMenu'), function(action) {
if (workPackage.$links.hasOwnProperty(action.link)) {
if (workPackage.hasOwnProperty(action.link)) {
var index = action.indexBy ? action.indexBy(allowedActions) : allowedActions.length;
allowedActions.splice(index, 0, action)
}

@ -27,6 +27,5 @@
//++
angular.module('openproject.workPackages.models')
.factory('WorkPackageAuthorization', ['ProjectService', '$state', 'PathHelper', require('./work-package-authorization')])
.factory('Datepicker', ['TimezoneService', 'ConfigurationService',
'$timeout', require('./datepicker.js')]);

@ -1,90 +0,0 @@
//-- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2013 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
module.exports = function(ProjectService, $state, PathHelper) {
var WorkPackageAuthorization = function (workPackage) {
this.workPackage = workPackage;
if (angular.isDefined(this.workPackage.project)) {
this.project = workPackage.project;
}
else {
this.project = ProjectService.getWorkPackageProject(this.workPackage).then(function(project) {
return project;
});
}
this.allActions = {
workPackage: this.workPackage,
project: this.project
};
};
WorkPackageAuthorization.prototype = {
copyLink: function() {
if ($state.current.name.indexOf('work-packages.show') === 0){
return PathHelper.workPackageCopyPath(this.workPackage.id);
}
else if ($state.current.name.indexOf('work-packages.list.details') === 0) {
return PathHelper.workPackageDetailsCopyPath(this.project.identifier,
this.workPackage.id);
}
},
linkForAction: function(action) {
if (action.key === 'copy') {
action.link = this.copyLink();
}
else {
action.link = this.allActions[action.resource][action.link].href;
}
return action;
},
isPermitted: function(action) {
return this.allActions[action.resource] !== undefined &&
this.allActions[action.resource][action.link] !== undefined;
},
permittedActionKeys: function(allowedActions) {
var validActions = _.filter(allowedActions, this.isPermitted, this);
return _.map(validActions, function(action) {
return action.key;
});
},
permittedActionsWithLinks: function(allowedActions) {
var validActions = _.filter(_.cloneDeep(allowedActions), this.isPermitted, this);
var allowed = _.map(validActions, this.linkForAction, this);
return allowed;
}
};
return WorkPackageAuthorization;
};

@ -29,7 +29,7 @@
/*jshint expr: true*/
describe('workPackageDetailsToolbar', function() {
var I18n, HookService, compile, scope, element, stateParams;
var I18n, $q, HookService, compile, scope, element, stateParams;
var html = "<wp-details-toolbar work-package='workPackage'></wp-details-toolbar>";
stateParams = {};
@ -56,7 +56,8 @@ describe('workPackageDetailsToolbar', function() {
$provide.constant('ConfigurationService', configurationService);
}));
beforeEach(inject(function($rootScope, $compile, _I18n_, _HookService_) {
beforeEach(inject(function($rootScope, $compile, _I18n_, _HookService_, _$q_) {
$q = _$q_;
I18n = _I18n_;
HookService = _HookService_;
var stub = sinon.stub(I18n, 't');
@ -104,6 +105,7 @@ describe('workPackageDetailsToolbar', function() {
plugin_action_1: { href: 'plugin_actionMeLink' },
plugin_action_2: { href: 'plugin_actionMeLink' },
project: {
$load: function() { return $q.when(true) },
createWorkPackage: { href: 'createWorkPackageLink' }
}
};

@ -93,7 +93,7 @@ describe('WorkPackageContextMenuHelper', function() {
}));
describe('getPermittedActions', function() {
var actionLinks = {
var workPackage = {
update: {
href: '/work_packages/123/edit'
},
@ -102,10 +102,6 @@ describe('WorkPackageContextMenuHelper', function() {
}
};
var workPackage = Factory.build('PlanningElement');
workPackage.$source = { _links : actionLinks };
workPackage.$links = actionLinks;
describe('when an array with a single work package is passed as an argument', function() {
var workPackages = new Array(workPackage);
@ -126,12 +122,9 @@ describe('WorkPackageContextMenuHelper', function() {
});
describe('when more than one work package is passed as an argument', function() {
var anotherWorkPackage = Factory.build('PlanningElement');
anotherWorkPackage.$source = {
_links: {
update: {
href: '/work_packages/234/edit'
}
var anotherWorkPackage = {
update: {
href: '/work_packages/234/edit'
}
};
anotherWorkPackage.$links = { update: '/work_packages/234/edit' };

Loading…
Cancel
Save