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 | } | ... | ... |