Commit 22c795d6dcb9a4e296a2e860dced7a2b52e25f76

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
... ... @@ -65,16 +65,36 @@ describe("Components", () => {
65 65 expect(state.transitionTo).toHaveBeenCalled();
66 66 });
67 67  
  68 + it("hide button to delete article when user doesn't have permission", () => {
  69 + expect(helper.find(".article-toolbar .delete-article").attr('style')).toEqual("display: none; ");
  70 + });
  71 +
  72 + it("hide button to edit article when user doesn't have permission", () => {
  73 + expect(helper.find(".article-toolbar .edit-article").attr('style')).toEqual("display: none; ");
  74 + });
  75 +
  76 + it("show button to edit article when user has permission", () => {
  77 + (<any>helper.component['article'])['permissions'] = ['allow_edit'];
  78 + helper.detectChanges();
  79 + expect(helper.find(".article-toolbar .edit-article").attr('style')).toEqual('');
  80 + });
  81 +
  82 + it("show button to delete article when user has permission", () => {
  83 + (<any>helper.component['article'])['permissions'] = ['allow_delete'];
  84 + helper.detectChanges();
  85 + expect(helper.find(".article-toolbar .delete-article").attr('style')).toEqual('');
  86 + });
  87 +
68 88 /**
69 89 * Execute the delete method on the target component
70 90 */
71 91 function doDeleteArticle() {
72 92 // Create a mock for the notification service confirmation
73   - spyOn(helper.component.notificationService, 'confirmation').and.callFake(function (params: Function) {
  93 + spyOn(helper.component.notificationService, 'confirmation').and.callFake(function(params: Function) {
74 94  
75 95 });
76 96 // Create a mock for the ArticleService removeArticle method
77   - spyOn(helper.component.articleService, 'remove').and.callFake(function (param: noosfero.Article) {
  97 + spyOn(helper.component.articleService, 'remove').and.callFake(function(param: noosfero.Article) {
78 98  
79 99 return {
80 100 catch: () => { }
... ...
src/app/article/article-default-view.component.ts
... ... @@ -6,6 +6,7 @@ import {ArticleToolbarHotspotComponent} from &quot;../hotspot/article-toolbar-hotspot
6 6 import {ArticleContentHotspotComponent} from "../hotspot/article-content-hotspot.component";
7 7 import {ArticleService} from "./../../lib/ng-noosfero-api/http/article.service";
8 8 import { NotificationService } from "./../shared/services/notification.service";
  9 +import {PermissionDirective} from '../shared/components/permission/permission.directive';
9 10  
10 11 /**
11 12 * @ngdoc controller
... ... @@ -16,7 +17,8 @@ import { NotificationService } from &quot;./../shared/services/notification.service&quot;;
16 17 */
17 18 @Component({
18 19 selector: 'noosfero-default-article',
19   - templateUrl: 'app/article/article.html'
  20 + templateUrl: 'app/article/article.html',
  21 + directives: [PermissionDirective]
20 22 })
21 23 @Inject("$state", ArticleService, NotificationService)
22 24 export class ArticleDefaultViewComponent {
... ...
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.component.spec.ts
... ... @@ -73,5 +73,16 @@ describe(&quot;Components&quot;, () =&gt; {
73 73 helper.component.save();
74 74 expect(helper.component['notificationService'].success).toHaveBeenCalled();
75 75 });
  76 +
  77 + it("hide button to edit content when user doesn't have the permission", () => {
  78 + helper.detectChanges();
  79 + expect(helper.find(".actions").attr('style')).toEqual('display: none; ');
  80 + });
  81 +
  82 + it("show button to edit content when user has the permission", () => {
  83 + (<any>helper.component['profile'])['permissions'] = ['allow_edit'];
  84 + helper.detectChanges();
  85 + expect(helper.find(".actions").attr('style')).toEqual('');
  86 + });
76 87 });
77 88 });
... ...
src/app/profile/custom-content/custom-content.component.ts
1 1 import {Component, Input, Inject} from 'ng-forward';
2 2 import {ProfileService} from '../../../lib/ng-noosfero-api/http/profile.service';
3 3 import {NotificationService} from '../../shared/services/notification.service';
  4 +import {PermissionDirective} from '../../shared/components/permission/permission.directive';
4 5  
5 6 @Component({
6 7 selector: 'custom-content',
7 8 templateUrl: "app/profile/custom-content/custom-content.html",
  9 + directives: [PermissionDirective]
8 10 })
9 11 @Inject("$uibModal", "$scope", ProfileService, NotificationService)
10 12 export class CustomContentComponent {
... ...
src/app/profile/custom-content/custom-content.html
1 1 <div class="custom-content">
2   - <div class="actions">
  2 + <div class="actions" permission="ctrl.profile.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 +}
... ...