Commit 7309dec7eb553f6697496fd8364618aab1854db1

Authored by Victor Costa
1 parent f74c41d2

Add button to join in community

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(&quot;Services&quot;, () =&gt; {
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 }
... ...