Commit 7309dec7eb553f6697496fd8364618aab1854db1
1 parent
f74c41d2
Exists in
master
and in
7 other branches
Add button to join in community
Showing
7 changed files
with
169 additions
and
1 deletions
Show diff stats
src/app/layout/blocks/profile-image/profile-image-block.component.spec.ts
| ... | ... | @@ -15,11 +15,18 @@ describe("Components", () => { |
| 15 | 15 | |
| 16 | 16 | beforeEach(angular.mock.module("templates")); |
| 17 | 17 | |
| 18 | + let profileService = jasmine.createSpyObj("ProfileService", ["isMember", "addMember", "removeMember"]); | |
| 19 | + profileService.isMember = jasmine.createSpy("isMember").and.returnValue(Promise.resolve(false)); | |
| 20 | + | |
| 18 | 21 | @Component({ |
| 19 | 22 | selector: 'test-container-component', |
| 20 | 23 | template: htmlTemplate, |
| 21 | 24 | directives: [ProfileImageBlockComponent], |
| 22 | - providers: helpers.provideFilters("translateFilter") | |
| 25 | + providers: [ | |
| 26 | + helpers.createProviderToValue('SessionService', helpers.mocks.sessionWithCurrentUser({})), | |
| 27 | + helpers.createProviderToValue('ProfileService', profileService), | |
| 28 | + helpers.createProviderToValue('NotificationService', helpers.mocks.notificationService) | |
| 29 | + ].concat(helpers.provideFilters("translateFilter")) | |
| 23 | 30 | }) |
| 24 | 31 | class BlockContainerComponent { |
| 25 | 32 | block = { type: 'Block' }; |
| ... | ... | @@ -42,5 +49,42 @@ describe("Components", () => { |
| 42 | 49 | }); |
| 43 | 50 | }); |
| 44 | 51 | |
| 52 | + it("display button to join community", (done: Function) => { | |
| 53 | + helpers.tcb.createAsync(BlockContainerComponent).then(fixture => { | |
| 54 | + let elProfile = fixture.debugElement.componentViewChildren[0]; | |
| 55 | + expect(elProfile.query('.actions .join').length).toEqual(1); | |
| 56 | + done(); | |
| 57 | + }); | |
| 58 | + }); | |
| 59 | + | |
| 60 | + it("display button to leave community", (done: Function) => { | |
| 61 | + helpers.tcb.createAsync(BlockContainerComponent).then(fixture => { | |
| 62 | + let elProfile = fixture.debugElement.componentViewChildren[0]; | |
| 63 | + elProfile.componentInstance['isMember'] = true; | |
| 64 | + fixture.detectChanges(); | |
| 65 | + expect(elProfile.query('.actions .leave').length).toEqual(1); | |
| 66 | + done(); | |
| 67 | + }); | |
| 68 | + }); | |
| 69 | + | |
| 70 | + it("join community", (done: Function) => { | |
| 71 | + helpers.tcb.createAsync(BlockContainerComponent).then(fixture => { | |
| 72 | + let elProfile = fixture.debugElement.componentViewChildren[0]; | |
| 73 | + profileService.addMember = jasmine.createSpy("addMember").and.returnValue(Promise.resolve({ data: {} })); | |
| 74 | + elProfile.componentInstance.join(); | |
| 75 | + expect(profileService.addMember).toHaveBeenCalled(); | |
| 76 | + done(); | |
| 77 | + }); | |
| 78 | + }); | |
| 79 | + | |
| 80 | + it("leave community", (done: Function) => { | |
| 81 | + helpers.tcb.createAsync(BlockContainerComponent).then(fixture => { | |
| 82 | + let elProfile = fixture.debugElement.componentViewChildren[0]; | |
| 83 | + profileService.removeMember = jasmine.createSpy("removeMember").and.returnValue(Promise.resolve({ data: {} })); | |
| 84 | + elProfile.componentInstance.leave(); | |
| 85 | + expect(profileService.removeMember).toHaveBeenCalled(); | |
| 86 | + done(); | |
| 87 | + }); | |
| 88 | + }); | |
| 45 | 89 | }); |
| 46 | 90 | }); | ... | ... |
src/app/layout/blocks/profile-image/profile-image-block.component.ts
| 1 | 1 | import {Inject, Input, Component} from "ng-forward"; |
| 2 | 2 | import {ProfileImageComponent} from "./../../../profile/image/image.component"; |
| 3 | +import {ProfileService} from "../../../../lib/ng-noosfero-api/http/profile.service"; | |
| 4 | +import {SessionService} from "./../../../login"; | |
| 5 | +import {NotificationService} from "../../../shared/services/notification.service"; | |
| 3 | 6 | |
| 4 | 7 | @Component({ |
| 5 | 8 | selector: "noosfero-profile-image-block", |
| 6 | 9 | templateUrl: 'app/layout/blocks/profile-image/profile-image-block.html', |
| 7 | 10 | directives: [ProfileImageComponent] |
| 8 | 11 | }) |
| 12 | +@Inject(ProfileService, SessionService, NotificationService) | |
| 9 | 13 | export class ProfileImageBlockComponent { |
| 10 | 14 | |
| 11 | 15 | @Input() block: noosfero.Block; |
| 12 | 16 | @Input() owner: noosfero.Profile; |
| 13 | 17 | |
| 18 | + private isMember: boolean; | |
| 19 | + | |
| 20 | + constructor(private profileService: ProfileService, private session: SessionService, private notificationService: NotificationService) { | |
| 21 | + } | |
| 22 | + | |
| 23 | + ngOnInit() { | |
| 24 | + this.loadMembership(); | |
| 25 | + } | |
| 26 | + | |
| 27 | + loadMembership() { | |
| 28 | + let person = this.session.currentUser() ? this.session.currentUser().person : null; | |
| 29 | + this.profileService.isMember(person, this.owner).then((val: boolean) => { | |
| 30 | + this.isMember = val; | |
| 31 | + }); | |
| 32 | + } | |
| 33 | + | |
| 34 | + join() { | |
| 35 | + let person = this.session.currentUser() ? this.session.currentUser().person : null; | |
| 36 | + this.profileService.addMember(person, this.owner).then((result: any) => { | |
| 37 | + if (result.data.pending) { | |
| 38 | + this.notificationService.success({ title: "blocks.profile_image.join.moderation.title", message: "blocks.profile_image.join.moderation.message" }); | |
| 39 | + } else { | |
| 40 | + this.loadMembership(); | |
| 41 | + } | |
| 42 | + }); | |
| 43 | + } | |
| 44 | + | |
| 45 | + leave() { | |
| 46 | + let person = this.session.currentUser() ? this.session.currentUser().person : null; | |
| 47 | + this.profileService.removeMember(person, this.owner).then(() => { | |
| 48 | + this.loadMembership(); | |
| 49 | + }); | |
| 50 | + } | |
| 14 | 51 | } | ... | ... |
src/app/layout/blocks/profile-image/profile-image-block.html
| ... | ... | @@ -3,4 +3,8 @@ |
| 3 | 3 | <noosfero-profile-image [profile]="ctrl.owner"></noosfero-profile-image> |
| 4 | 4 | </a> |
| 5 | 5 | <a class="settings-link" target="_self" ui-sref="main.profile.settings({profile: ctrl.owner.identifier})">{{"blocks.profile_image.control_panel" | translate}}</a> |
| 6 | + <div class="actions" ng-show="ctrl.isMember!=null"> | |
| 7 | + <a ng-if="!ctrl.isMember" ng-click="ctrl.join()" class="btn btn-primary btn-sm join" href="#">{{"blocks.profile_image.join" | translate}}</a> | |
| 8 | + <a ng-if="ctrl.isMember" ng-click="ctrl.leave()" class="btn btn-warning btn-sm leave" href="#">{{"blocks.profile_image.leave" | translate}}</a> | |
| 9 | + </div> | |
| 6 | 10 | </div> | ... | ... |
src/languages/en.json
| 1 | 1 | { |
| 2 | 2 | "noosfero.name" : "Noosfero", |
| 3 | 3 | "blocks.profile_image.control_panel": "Control Panel", |
| 4 | + "blocks.profile_image.join": "Join community", | |
| 5 | + "blocks.profile_image.leave": "Leave community", | |
| 6 | + "blocks.profile_image.join.moderation.title": "Good job!", | |
| 7 | + "blocks.profile_image.join.moderation.message": "Your membership is waiting for approval", | |
| 4 | 8 | "navbar.profile": "Profile", |
| 5 | 9 | "navbar.settings": "Settings", |
| 6 | 10 | "navbar.logout": "Log Out", | ... | ... |
src/languages/pt.json
| 1 | 1 | { |
| 2 | 2 | "noosfero.name" : "Noosfero", |
| 3 | 3 | "blocks.profile_image.control_panel": "Painel de Controle", |
| 4 | + "blocks.profile_image.join": "Entrar na comunidade", | |
| 5 | + "blocks.profile_image.leave": "Sair da comunidade", | |
| 6 | + "blocks.profile_image.join.moderation.title": "Bom trabalho!", | |
| 7 | + "blocks.profile_image.join.moderation.message": "Sua participação está pendente de aprovação", | |
| 4 | 8 | "navbar.profile": "Perfil", |
| 5 | 9 | "navbar.settings": "Configurações", |
| 6 | 10 | "navbar.logout": "Sair", | ... | ... |
src/lib/ng-noosfero-api/http/profile.service.spec.ts
| ... | ... | @@ -111,6 +111,56 @@ describe("Services", () => { |
| 111 | 111 | }); |
| 112 | 112 | $httpBackend.flush(); |
| 113 | 113 | }); |
| 114 | + | |
| 115 | + it("should return the profile members", (done) => { | |
| 116 | + let profileId = 1; | |
| 117 | + $httpBackend.expectGET(`/api/v1/profiles/${profileId}/members`).respond(200, { people: [{ id: 2 }] }); | |
| 118 | + profileService.getMembers(<any>{ id: profileId }).then((response: restangular.IResponse) => { | |
| 119 | + expect(response.data.people).toEqual([{ id: 2 }]); | |
| 120 | + done(); | |
| 121 | + }); | |
| 122 | + $httpBackend.flush(); | |
| 123 | + }); | |
| 124 | + | |
| 125 | + it("should return true if the person is a profile member", (done) => { | |
| 126 | + let profileId = 1; | |
| 127 | + $httpBackend.expectGET(`/api/v1/profiles/${profileId}/members`).respond(200, { people: [{ id: 2 }] }); | |
| 128 | + profileService.isMember(<any>{ id: 2 }, <any>{ id: profileId }).then((response: restangular.IResponse) => { | |
| 129 | + expect(response).toEqual(true); | |
| 130 | + done(); | |
| 131 | + }); | |
| 132 | + $httpBackend.flush(); | |
| 133 | + }); | |
| 134 | + | |
| 135 | + it("should return false if the person is a profile member", (done) => { | |
| 136 | + let profileId = 1; | |
| 137 | + $httpBackend.expectGET(`/api/v1/profiles/${profileId}/members`).respond(200, { people: [] }); | |
| 138 | + profileService.isMember(<any>{ id: 2 }, <any>{ id: profileId }).then((response: restangular.IResponse) => { | |
| 139 | + expect(response).toEqual(false); | |
| 140 | + done(); | |
| 141 | + }); | |
| 142 | + $httpBackend.flush(); | |
| 143 | + }); | |
| 144 | + | |
| 145 | + it("should add member to profile", (done) => { | |
| 146 | + let profileId = 1; | |
| 147 | + $httpBackend.expectPOST(`/api/v1/profiles/${profileId}/members`).respond(200, { pending: false }); | |
| 148 | + profileService.addMember(<any>{ id: 2 }, <any>{ id: profileId }).then((response: restangular.IResponse) => { | |
| 149 | + expect(response.data.pending).toEqual(false); | |
| 150 | + done(); | |
| 151 | + }); | |
| 152 | + $httpBackend.flush(); | |
| 153 | + }); | |
| 154 | + | |
| 155 | + it("should remove member from profile", (done) => { | |
| 156 | + let profileId = 1; | |
| 157 | + $httpBackend.expectDELETE(`/api/v1/profiles/${profileId}/members`).respond(200, { person: { id: 2 } }); | |
| 158 | + profileService.removeMember(<any>{ id: 2 }, <any>{ id: profileId }).then((response: restangular.IResponse) => { | |
| 159 | + expect(response.data.person).toEqual({ id: 2 }); | |
| 160 | + done(); | |
| 161 | + }); | |
| 162 | + $httpBackend.flush(); | |
| 163 | + }); | |
| 114 | 164 | }); |
| 115 | 165 | |
| 116 | 166 | ... | ... |
src/lib/ng-noosfero-api/http/profile.service.ts
| ... | ... | @@ -64,4 +64,29 @@ export class ProfileService { |
| 64 | 64 | let headers = { 'Content-Type': 'application/json' }; |
| 65 | 65 | return this.get(profile.id).customPOST({ profile: profile }, null, null, headers); |
| 66 | 66 | } |
| 67 | + | |
| 68 | + getMembers(profile: noosfero.Profile, params?: any) { | |
| 69 | + let p = this.get(profile.id); | |
| 70 | + return p.customGET('members', params); | |
| 71 | + } | |
| 72 | + | |
| 73 | + isMember(person: noosfero.Person, profile: noosfero.Profile) { | |
| 74 | + let deferred = this.$q.defer(); | |
| 75 | + if (person) { | |
| 76 | + this.getMembers(profile, { identifier: person.identifier }).then((result: any) => { | |
| 77 | + deferred.resolve(result.data.people.length > 0); | |
| 78 | + }); | |
| 79 | + } else { | |
| 80 | + deferred.resolve(false); | |
| 81 | + } | |
| 82 | + return deferred.promise; | |
| 83 | + } | |
| 84 | + | |
| 85 | + addMember(person: noosfero.Person, profile: noosfero.Profile) { | |
| 86 | + return this.get(profile.id).customPOST({}, "members", null, null); | |
| 87 | + } | |
| 88 | + | |
| 89 | + removeMember(person: noosfero.Person, profile: noosfero.Profile) { | |
| 90 | + return this.get(profile.id).customDELETE("members", null, null); | |
| 91 | + } | |
| 67 | 92 | } | ... | ... |