Commit 0055350dc62b0a178fc896d6ccdedcf6cd3923ea

Authored by Victor Costa
1 parent 0456e67c

Hide action buttons related to articles when user doesn't have permission to execute it

src/app/article/article-default-view-component.spec.ts
1 1 import {Input, provide, Component} from 'ng-forward';
2 2 import {ArticleViewComponent, ArticleDefaultViewComponent} from './article-default-view.component';
3 3 import {ComponentTestHelper, createClass} from './../../spec/component-test-helper';
  4 +import {PermissionDirective} from '../shared/components/permission/permission.directive';
4 5  
5 6 import * as helpers from "../../spec/helpers";
6 7  
... ... @@ -45,7 +46,7 @@ describe("Components", () => {
45 46 // in each test if one needs customization of these parameters per test
46 47 let cls = createClass({
47 48 template: defaultViewTemplate,
48   - directives: [ArticleDefaultViewComponent],
  49 + directives: [ArticleDefaultViewComponent, PermissionDirective],
49 50 providers: providers,
50 51 properties: {
51 52 article: article
... ... @@ -65,16 +66,24 @@ describe("Components", () => {
65 66 expect(state.transitionTo).toHaveBeenCalled();
66 67 });
67 68  
  69 + it("hide delete article button when user doesn't have permission", () => {
  70 + expect(helper.find(".article-toolbar .delete-article").attr('style')).toEqual("display: none; ");
  71 + });
  72 +
  73 + it("hide edit article button when user doesn't have permission", () => {
  74 + expect(helper.find(".article-toolbar .edit-article").attr('style')).toEqual("display: none; ");
  75 + });
  76 +
68 77 /**
69 78 * Execute the delete method on the target component
70 79 */
71 80 function doDeleteArticle() {
72 81 // Create a mock for the notification service confirmation
73   - spyOn(helper.component.notificationService, 'confirmation').and.callFake(function (params: Function) {
  82 + spyOn(helper.component.notificationService, 'confirmation').and.callFake(function(params: Function) {
74 83  
75 84 });
76 85 // Create a mock for the ArticleService removeArticle method
77   - spyOn(helper.component.articleService, 'remove').and.callFake(function (param: noosfero.Article) {
  86 + spyOn(helper.component.articleService, 'remove').and.callFake(function(param: noosfero.Article) {
78 87  
79 88 return {
80 89 catch: () => { }
... ...
src/app/article/article.html
... ... @@ -4,13 +4,15 @@
4 4 </div>
5 5  
6 6 <div class="sub-header clearfix">
7   - <a href="#" class="btn btn-default btn-xs" ui-sref="main.cmsEdit({profile: ctrl.profile.identifier, id: ctrl.article.id})">
8   - <i class="fa fa-pencil-square-o fa-fw fa-lg"></i> {{"article.actions.edit" | translate}}
9   - </a>
10   - <a href="#" class="btn btn-default btn-xs" ng-click="ctrl.delete()">
11   - <i class="fa fa-trash-o fa-fw fa-lg" ng-click="ctrl.delete()"></i> {{"article.actions.delete" | translate}}
12   - </a>
13   - <noosfero-hotspot-article-toolbar [article]="ctrl.article"></noosfero-hotspot-article-toolbar>
  7 + <div class="article-toolbar">
  8 + <a href="#" permission="ctrl.article.permissions" permission-action="allow_edit" class="btn btn-default btn-xs edit-article" ui-sref="main.cmsEdit({profile: ctrl.profile.identifier, id: ctrl.article.id})">
  9 + <i class="fa fa-pencil-square-o fa-fw fa-lg"></i> {{"article.actions.edit" | translate}}
  10 + </a>
  11 + <a href="#" permission="ctrl.article.permissions" permission-action="allow_delete" class="btn btn-default btn-xs delete-article" ng-click="ctrl.delete()">
  12 + <i class="fa fa-trash-o fa-fw fa-lg" ng-click="ctrl.delete()"></i> {{"article.actions.delete" | translate}}
  13 + </a>
  14 + <noosfero-hotspot-article-toolbar [article]="ctrl.article"></noosfero-hotspot-article-toolbar>
  15 + </div>
14 16 <div class="page-info pull-right small text-muted">
15 17 <span class="time">
16 18 <i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.article.created_at | dateFormat"></span>
... ...
src/app/article/content-viewer/navbar-actions.html
1   -<ul class="nav navbar-nav">
  1 +<ul class="nav navbar-nav" permission="vm.profile.permissions" permission-action="allow_edit">
2 2 <li class="dropdown profile-menu" uib-dropdown>
3 3 <a class="btn dropdown-toggle" data-toggle="dropdown" uib-dropdown-toggle>
4 4 {{"navbar.content_viewer_actions.new_item" | translate}}
... ... @@ -19,4 +19,3 @@
19 19 </li>
20 20  
21 21 </ul>
22   -
... ...
src/app/main/main.component.ts
... ... @@ -39,7 +39,7 @@ import {SidebarComponent} from &quot;../layout/sidebar/sidebar.component&quot;;
39 39  
40 40 import {MainBlockComponent} from "../layout/blocks/main/main-block.component";
41 41 import {HtmlEditorComponent} from "../shared/components/html-editor/html-editor.component";
42   -
  42 +import {PermissionDirective} from "../shared/components/permission/permission.directive";
43 43  
44 44 /**
45 45 * @ngdoc controller
... ... @@ -100,7 +100,7 @@ export class EnvironmentContent {
100 100 LinkListBlockComponent, CommunitiesBlockComponent, HtmlEditorComponent,
101 101 MainBlockComponent, RecentDocumentsBlockComponent, Navbar, SidebarComponent, ProfileImageBlockComponent,
102 102 MembersBlockComponent, NoosferoTemplate, DateFormat, RawHTMLBlockComponent, StatisticsBlockComponent,
103   - LoginBlockComponent, CustomContentComponent
  103 + LoginBlockComponent, CustomContentComponent, PermissionDirective
104 104 ].concat(plugins.mainComponents).concat(plugins.hotspots),
105 105  
106 106 providers: [AuthService, SessionService, NotificationService, BodyStateClassesService]
... ...
src/app/profile/custom-content/custom-content.html
1 1 <div class="custom-content">
2   - <div class="actions">
  2 + <div class="actions" permission="ctrl.profiles.permissions" permission-action="allow_edit">
3 3 <button type="submit" class="btn btn-xs btn-default" ng-click="ctrl.openEdit()"><i class="fa fa-edit fa-fw"></i> {{ctrl.label | translate}}</button>
4 4 </div>
5 5 <div class="content" ng-bind-html="ctrl.content"></div>
... ...
src/app/shared/components/permission/permission.directive.spec.ts 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +import {Input, provide, Component} from 'ng-forward';
  2 +import {PermissionDirective} from "./permission.directive";
  3 +import * as helpers from "../../../../spec/helpers";
  4 +
  5 +const htmlTemplate: string = '<div permission="ctrl.permissions" permission-action="action"></div>';
  6 +
  7 +describe("Permission directive", () => {
  8 +
  9 + let element = jasmine.createSpyObj("$element", ["css"]);
  10 + let scope = jasmine.createSpyObj("$scope", ["$watch", "$eval"]);
  11 + scope.$watch = (param: string, f: Function) => { f(); };
  12 + scope.$eval = (param: any) => { return param; };
  13 +
  14 + it("hide element when there is no permission action in the permissions array", (done: Function) => {
  15 + let attrs: any = { permission: [], permissionAction: 'action' };
  16 + let directive = new PermissionDirective(<any>attrs, scope, element);
  17 + expect(element.css).toHaveBeenCalledWith('display', 'none');
  18 + done();
  19 + });
  20 +
  21 + it("show element when the permission action exists in the permissions array", (done: Function) => {
  22 + let attrs = { permission: ['action'], permissionAction: 'action' };
  23 + let directive = new PermissionDirective(<any>attrs, scope, element);
  24 + expect(element.css).toHaveBeenCalledWith('display', '');
  25 + done();
  26 + });
  27 +});
... ...
src/app/shared/components/permission/permission.directive.ts 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +import {Directive, Inject, Input} from "ng-forward";
  2 +
  3 +@Directive({
  4 + selector: '[permission]'
  5 +})
  6 +@Inject('$attrs', '$scope', '$element')
  7 +export class PermissionDirective {
  8 +
  9 + constructor($attrs: ng.IAttributes, $scope: ng.IScope, $element: any) {
  10 + $scope.$watch($attrs['permission'], () => {
  11 + let permissions = $scope.$eval($attrs['permission']);
  12 + let permissionAction = $attrs['permissionAction'];
  13 + if (!permissions || permissions.indexOf(permissionAction) < 0) {
  14 + $element.css("display", "none");
  15 + } else {
  16 + $element.css("display", "");
  17 + }
  18 + });
  19 + }
  20 +}
... ...