Commit 22c795d6dcb9a4e296a2e860dced7a2b52e25f76
1 parent
0456e67c
Exists in
master
and in
14 other branches
Hide action buttons related to articles when user doesn't have permission to execute it
Showing
10 changed files
with
98 additions
and
15 deletions
Show diff stats
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 "../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 "./../shared/services/notification.service"; |
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 "../layout/sidebar/sidebar.component"; |
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("Components", () => { |
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 | +} | ... | ... |