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