Merge Request #34
← To merge requests
From
article-actions-permission
into
master
Hide article buttons when user doesn't have permission to execute it
Commits (1)
Showing
10 changed files
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 | +} | ... | ... |
-
Reassigned to @carloseugenio
-
Assignee removed
-
Reassigned to @carloseugenio
-
mentioned in commit b6a7edb744689b21a1c0f81e21a3eb0f2a05ef70
-
Assignee removed