Commit a9aa5894a1fc1bb78101e52eb04152a7c24f8f5b
Exists in
master
and in
1 other branch
merge with master
Showing
26 changed files
with
487 additions
and
110 deletions
Show diff stats
bower.json
@@ -33,7 +33,8 @@ | @@ -33,7 +33,8 @@ | ||
33 | "angular-translate-handler-log": "^2.10.0", | 33 | "angular-translate-handler-log": "^2.10.0", |
34 | "angular-dynamic-locale": "^0.1.30", | 34 | "angular-dynamic-locale": "^0.1.30", |
35 | "angular-i18n": "^1.5.0", | 35 | "angular-i18n": "^1.5.0", |
36 | - "angular-load": "^0.4.1" | 36 | + "angular-load": "^0.4.1", |
37 | + "angular-translate-interpolation-messageformat": "^2.10.0" | ||
37 | }, | 38 | }, |
38 | "devDependencies": { | 39 | "devDependencies": { |
39 | "angular-mocks": "~1.5.0" | 40 | "angular-mocks": "~1.5.0" |
gulp/build.js
@@ -48,6 +48,7 @@ gulp.task('html', ['inject', 'partials'], function () { | @@ -48,6 +48,7 @@ gulp.task('html', ['inject', 'partials'], function () { | ||
48 | .pipe($.replace('/languages/', noosferoThemePrefix + 'languages/')) | 48 | .pipe($.replace('/languages/', noosferoThemePrefix + 'languages/')) |
49 | .pipe($.replace('bower_components/angular-i18n/', noosferoThemePrefix + 'locale/angular-i18n/')) | 49 | .pipe($.replace('bower_components/angular-i18n/', noosferoThemePrefix + 'locale/angular-i18n/')) |
50 | .pipe($.replace('bower_components/moment/', noosferoThemePrefix + 'locale/moment/')) | 50 | .pipe($.replace('bower_components/moment/', noosferoThemePrefix + 'locale/moment/')) |
51 | + .pipe($.replace('bower_components/messageformat/', noosferoThemePrefix + 'locale/messageformat/')) | ||
51 | .pipe($.sourcemaps.init()) | 52 | .pipe($.sourcemaps.init()) |
52 | .pipe($.ngAnnotate()) | 53 | .pipe($.ngAnnotate()) |
53 | .pipe($.uglify({ preserveComments: $.uglifySaveLicense })).on('error', conf.errorHandler('Uglify')) | 54 | .pipe($.uglify({ preserveComments: $.uglifySaveLicense })).on('error', conf.errorHandler('Uglify')) |
@@ -88,6 +89,7 @@ gulp.task('locale', function () { | @@ -88,6 +89,7 @@ gulp.task('locale', function () { | ||
88 | return gulp.src([ | 89 | return gulp.src([ |
89 | path.join("bower_components/angular-i18n", '*.js'), | 90 | path.join("bower_components/angular-i18n", '*.js'), |
90 | path.join("bower_components/moment/locale", '*.js'), | 91 | path.join("bower_components/moment/locale", '*.js'), |
92 | + path.join("bower_components/messageformat/locale", '*.js'), | ||
91 | ], {base: 'bower_components/'}) | 93 | ], {base: 'bower_components/'}) |
92 | .pipe(gulp.dest(path.join(conf.paths.dist, '/locale/'))); | 94 | .pipe(gulp.dest(path.join(conf.paths.dist, '/locale/'))); |
93 | }); | 95 | }); |
src/app/cms/cms.component.spec.ts
@@ -9,8 +9,9 @@ describe("Components", () => { | @@ -9,8 +9,9 @@ describe("Components", () => { | ||
9 | let articleServiceMock: any; | 9 | let articleServiceMock: any; |
10 | let profileServiceMock: any; | 10 | let profileServiceMock: any; |
11 | let $state: any; | 11 | let $state: any; |
12 | - let sweetAlert: any; | ||
13 | let profile = { id: 1 }; | 12 | let profile = { id: 1 }; |
13 | + let notification: any; | ||
14 | + | ||
14 | 15 | ||
15 | beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => { | 16 | beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => { |
16 | $rootScope = _$rootScope_; | 17 | $rootScope = _$rootScope_; |
@@ -19,7 +20,7 @@ describe("Components", () => { | @@ -19,7 +20,7 @@ describe("Components", () => { | ||
19 | 20 | ||
20 | beforeEach(() => { | 21 | beforeEach(() => { |
21 | $state = jasmine.createSpyObj("$state", ["transitionTo"]); | 22 | $state = jasmine.createSpyObj("$state", ["transitionTo"]); |
22 | - sweetAlert = jasmine.createSpyObj("SweetAlert", ["swal"]); | 23 | + notification = jasmine.createSpyObj("notification", ["success"]); |
23 | profileServiceMock = jasmine.createSpyObj("profileServiceMock", ["getCurrentProfile"]); | 24 | profileServiceMock = jasmine.createSpyObj("profileServiceMock", ["getCurrentProfile"]); |
24 | articleServiceMock = jasmine.createSpyObj("articleServiceMock", ["create"]); | 25 | articleServiceMock = jasmine.createSpyObj("articleServiceMock", ["create"]); |
25 | 26 | ||
@@ -34,7 +35,7 @@ describe("Components", () => { | @@ -34,7 +35,7 @@ describe("Components", () => { | ||
34 | }); | 35 | }); |
35 | 36 | ||
36 | it("create an article in the current profile when save", done => { | 37 | it("create an article in the current profile when save", done => { |
37 | - let component: Cms = new Cms(articleServiceMock, profileServiceMock, $state, sweetAlert); | 38 | + let component: Cms = new Cms(articleServiceMock, profileServiceMock, $state, notification); |
38 | component.save(); | 39 | component.save(); |
39 | $rootScope.$apply(); | 40 | $rootScope.$apply(); |
40 | expect(profileServiceMock.getCurrentProfile).toHaveBeenCalled(); | 41 | expect(profileServiceMock.getCurrentProfile).toHaveBeenCalled(); |
@@ -43,11 +44,11 @@ describe("Components", () => { | @@ -43,11 +44,11 @@ describe("Components", () => { | ||
43 | }); | 44 | }); |
44 | 45 | ||
45 | it("got to the new article page and display an alert when saving sucessfully", done => { | 46 | it("got to the new article page and display an alert when saving sucessfully", done => { |
46 | - let component: Cms = new Cms(articleServiceMock, profileServiceMock, $state, sweetAlert); | 47 | + let component: Cms = new Cms(articleServiceMock, profileServiceMock, $state, notification); |
47 | component.save(); | 48 | component.save(); |
48 | $rootScope.$apply(); | 49 | $rootScope.$apply(); |
49 | expect($state.transitionTo).toHaveBeenCalledWith("main.profile.page", { page: "path", profile: "profile" }); | 50 | expect($state.transitionTo).toHaveBeenCalledWith("main.profile.page", { page: "path", profile: "profile" }); |
50 | - expect(sweetAlert.swal).toHaveBeenCalled(); | 51 | + expect(notification.success).toHaveBeenCalled(); |
51 | done(); | 52 | done(); |
52 | }); | 53 | }); |
53 | 54 |
src/app/cms/cms.component.ts
@@ -2,37 +2,33 @@ import {StateConfig, Component, Inject, provide} from 'ng-forward'; | @@ -2,37 +2,33 @@ import {StateConfig, Component, Inject, provide} from 'ng-forward'; | ||
2 | import {Profile} from "./../models/interfaces"; | 2 | import {Profile} from "./../models/interfaces"; |
3 | import {ArticleService} from "../../lib/ng-noosfero-api/http/article.service"; | 3 | import {ArticleService} from "../../lib/ng-noosfero-api/http/article.service"; |
4 | import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; | 4 | import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; |
5 | +import {Notification} from "../components/notification/notification.component"; | ||
5 | 6 | ||
6 | @Component({ | 7 | @Component({ |
7 | selector: 'cms', | 8 | selector: 'cms', |
8 | templateUrl: "app/cms/cms.html", | 9 | templateUrl: "app/cms/cms.html", |
9 | providers: [ | 10 | providers: [ |
10 | provide('articleService', { useClass: ArticleService }), | 11 | provide('articleService', { useClass: ArticleService }), |
11 | - provide('profileService', { useClass: ProfileService }) | 12 | + provide('profileService', { useClass: ProfileService }), |
13 | + provide('notification', { useClass: Notification }) | ||
12 | ] | 14 | ] |
13 | }) | 15 | }) |
14 | -@Inject(ArticleService, ProfileService, "$state", "SweetAlert") | 16 | +@Inject(ArticleService, ProfileService, "$state", Notification) |
15 | export class Cms { | 17 | export class Cms { |
16 | 18 | ||
17 | article: any = {}; | 19 | article: any = {}; |
18 | 20 | ||
19 | constructor(private articleService: ArticleService, | 21 | constructor(private articleService: ArticleService, |
20 | private profileService: ProfileService, | 22 | private profileService: ProfileService, |
21 | - private $state: ng.ui.IStateService, private SweetAlert: any) { } | 23 | + private $state: ng.ui.IStateService, |
24 | + private notification: Notification) { } | ||
22 | 25 | ||
23 | save() { | 26 | save() { |
24 | - this.profileService.getCurrentProfile().then((profile: Profile) => { | ||
25 | - return this.articleService.create(this.article, <any>profile); | ||
26 | - }).then((result: noosfero.RestResult<noosfero.Article>) => { | ||
27 | - console.log('RESULT', result); | ||
28 | - let resultData: noosfero.Article = <noosfero.Article>result.data; | ||
29 | - this.$state.transitionTo('main.profile.page', { page: resultData.path, profile: resultData.profile.identifier }); | ||
30 | - this.SweetAlert.swal({ | ||
31 | - title: "Good job!", | ||
32 | - text: "Article saved!", | ||
33 | - type: "success", | ||
34 | - timer: 1000 | ||
35 | - }); | 27 | + this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => { |
28 | + return this.articleService.create(this.article, profile); | ||
29 | + }).then((response: restangular.IResponse) => { | ||
30 | + this.$state.transitionTo('main.profile.page', { page: response.data.article.path, profile: response.data.article.profile.identifier }); | ||
31 | + this.notification.success("Good job!", "Article saved!"); | ||
36 | }); | 32 | }); |
37 | } | 33 | } |
38 | 34 |
src/app/components/language-selector/language-selector.component.spec.ts
1 | -import {TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder'; | ||
2 | -import {Pipe, Input, provide, Component} from 'ng-forward'; | 1 | +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder'; |
2 | +import {provide} from 'ng-forward'; | ||
3 | 3 | ||
4 | import {LanguageSelector} from './language-selector.component'; | 4 | import {LanguageSelector} from './language-selector.component'; |
5 | 5 | ||
6 | import * as helpers from "../../../spec/helpers"; | 6 | import * as helpers from "../../../spec/helpers"; |
7 | 7 | ||
8 | -const tcb = new TestComponentBuilder(); | ||
9 | - | ||
10 | -const htmlTemplate: string = '<language-selector></language-selector>'; | ||
11 | - | ||
12 | describe("Components", () => { | 8 | describe("Components", () => { |
13 | 9 | ||
14 | describe("Language Selector Component", () => { | 10 | describe("Language Selector Component", () => { |
15 | 11 | ||
16 | beforeEach(angular.mock.module("templates")); | 12 | beforeEach(angular.mock.module("templates")); |
17 | 13 | ||
18 | - @Component({ | ||
19 | - selector: 'test-container-component', | ||
20 | - template: htmlTemplate, | ||
21 | - directives: [LanguageSelector], | ||
22 | - providers: [ | ||
23 | - provide('$translate', { | ||
24 | - useValue: helpers.mocks.$translate | ||
25 | - }), | ||
26 | - provide('tmhDynamicLocale', { | ||
27 | - useValue: helpers.mocks.tmhDynamicLocale | ||
28 | - }), | ||
29 | - provide('amMoment', { | ||
30 | - useValue: helpers.mocks.amMoment | ||
31 | - }), | ||
32 | - provide('angularLoad', { | ||
33 | - useValue: helpers.mocks.angularLoad | ||
34 | - }) | ||
35 | - ].concat(helpers.provideFilters("translateFilter")) | ||
36 | - }) | ||
37 | - class BlockContainerComponent { } | ||
38 | - | ||
39 | - it("set available languages when change language", () => { | 14 | + let buildComponent = (): Promise<ComponentFixture> => { |
15 | + return helpers.quickCreateComponent({ | ||
16 | + template: "<language-selector></language-selector>", | ||
17 | + directives: [LanguageSelector], | ||
18 | + providers: [ | ||
19 | + provide('$translate', { | ||
20 | + useValue: helpers.mocks.$translate | ||
21 | + }), | ||
22 | + provide('tmhDynamicLocale', { | ||
23 | + useValue: helpers.mocks.tmhDynamicLocale | ||
24 | + }), | ||
25 | + provide('amMoment', { | ||
26 | + useValue: helpers.mocks.amMoment | ||
27 | + }), | ||
28 | + provide('angularLoad', { | ||
29 | + useValue: helpers.mocks.angularLoad | ||
30 | + }) | ||
31 | + ].concat(helpers.provideFilters("translateFilter")) | ||
32 | + }); | ||
33 | + } | ||
34 | + | ||
35 | + it("set available languages when change language", (done) => { | ||
40 | let component: LanguageSelector = new LanguageSelector( | 36 | let component: LanguageSelector = new LanguageSelector( |
41 | <any>helpers.mocks.$translate, | 37 | <any>helpers.mocks.$translate, |
42 | <any>helpers.mocks.tmhDynamicLocale, | 38 | <any>helpers.mocks.tmhDynamicLocale, |
@@ -47,11 +43,35 @@ describe("Components", () => { | @@ -47,11 +43,35 @@ describe("Components", () => { | ||
47 | expect(component.availableLanguages).toBeNull(); | 43 | expect(component.availableLanguages).toBeNull(); |
48 | component.changeLanguage('en'); | 44 | component.changeLanguage('en'); |
49 | expect(component.availableLanguages).toBeDefined(); | 45 | expect(component.availableLanguages).toBeDefined(); |
46 | + done(); | ||
50 | }); | 47 | }); |
51 | 48 | ||
52 | - it("display language options", () => { | ||
53 | - helpers.createComponentFromClass(BlockContainerComponent).then(fixture => { | 49 | + it("display language options", (done) => { |
50 | + buildComponent().then(fixture => { | ||
54 | expect(fixture.debugElement.queryAll('li.language').length).toEqual(2); | 51 | expect(fixture.debugElement.queryAll('li.language').length).toEqual(2); |
52 | + done(); | ||
53 | + }); | ||
54 | + }); | ||
55 | + | ||
56 | + it("change the language", (done) => { | ||
57 | + buildComponent().then(fixture => { | ||
58 | + let component: LanguageSelector = fixture.debugElement.componentViewChildren[0].componentInstance; | ||
59 | + let $q = fixture.debugElement.getLocal("$q"); | ||
60 | + let loadScripPromise = $q.defer(); | ||
61 | + loadScripPromise.resolve(); | ||
62 | + component["angularLoad"].loadScript = jasmine.createSpy("loadScript").and.returnValue(loadScripPromise.promise); | ||
63 | + component["tmhDynamicLocale"].set = jasmine.createSpy("set"); | ||
64 | + component["tmhDynamicLocale"].get = jasmine.createSpy("get").and.returnValue("en"); | ||
65 | + component["$translate"].use = jasmine.createSpy("use"); | ||
66 | + | ||
67 | + component.changeLanguage('pt'); | ||
68 | + fixture.debugElement.getLocal("$rootScope").$digest(); | ||
69 | + | ||
70 | + expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/moment/locale/pt.js"); | ||
71 | + expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/messageformat/locale/pt.js"); | ||
72 | + expect(component["tmhDynamicLocale"].set).toHaveBeenCalledWith("pt"); | ||
73 | + expect(component["$translate"].use).toHaveBeenCalledWith("pt"); | ||
74 | + done(); | ||
55 | }); | 75 | }); |
56 | }); | 76 | }); |
57 | 77 |
src/app/components/language-selector/language-selector.component.ts
@@ -14,6 +14,7 @@ export class LanguageSelector { | @@ -14,6 +14,7 @@ export class LanguageSelector { | ||
14 | private amMoment: any, | 14 | private amMoment: any, |
15 | private angularLoad: any) { | 15 | private angularLoad: any) { |
16 | 16 | ||
17 | + this.configAvailableLanguages(); | ||
17 | this.changeLanguage(tmhDynamicLocale.get() || $translate.use()); | 18 | this.changeLanguage(tmhDynamicLocale.get() || $translate.use()); |
18 | } | 19 | } |
19 | 20 | ||
@@ -24,14 +25,20 @@ export class LanguageSelector { | @@ -24,14 +25,20 @@ export class LanguageSelector { | ||
24 | changeLanguage(language: string) { | 25 | changeLanguage(language: string) { |
25 | this.changeMomentLocale(language); | 26 | this.changeMomentLocale(language); |
26 | this.tmhDynamicLocale.set(language); | 27 | this.tmhDynamicLocale.set(language); |
27 | - this.$translate.use(language).then((lang) => { | ||
28 | - this.availableLanguages = { | ||
29 | - "en": this.$translate.instant("language.en"), | ||
30 | - "pt": this.$translate.instant("language.pt") | ||
31 | - }; | 28 | + this.angularLoad.loadScript(`/bower_components/messageformat/locale/${language}.js`).then(() => { |
29 | + return this.$translate.use(language); | ||
30 | + }).then(() => { | ||
31 | + this.configAvailableLanguages(); | ||
32 | }); | 32 | }); |
33 | } | 33 | } |
34 | 34 | ||
35 | + private configAvailableLanguages() { | ||
36 | + this.availableLanguages = { | ||
37 | + "en": this.$translate.instant("language.en"), | ||
38 | + "pt": this.$translate.instant("language.pt") | ||
39 | + }; | ||
40 | + } | ||
41 | + | ||
35 | private changeMomentLocale(language: string) { | 42 | private changeMomentLocale(language: string) { |
36 | let localePromise = Promise.resolve(); | 43 | let localePromise = Promise.resolve(); |
37 | if (language != "en") { | 44 | if (language != "en") { |
src/app/components/noosfero-activities/activity/new_friendship.html
@@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
5 | <timeline-heading> | 5 | <timeline-heading> |
6 | <h4 class="timeline-title"> | 6 | <h4 class="timeline-title"> |
7 | <a ui-sref="main.profile.info({profile: ctrl.activity.user.identifier})"><strong ng-bind="ctrl.activity.user.name"></strong></a> | 7 | <a ui-sref="main.profile.info({profile: ctrl.activity.user.identifier})"><strong ng-bind="ctrl.activity.user.name"></strong></a> |
8 | - <span> {{"activities.new_friendship.description" | translate:{friends: ctrl.activity.params.friend_name.length} }} </span> | 8 | + <span> {{"activities.new_friendship.description" | translate:{friends: ctrl.activity.params.friend_name.length}:"messageformat" }} </span> |
9 | <span class="comma-separated"> | 9 | <span class="comma-separated"> |
10 | <a class="separated-item" ui-sref="main.profile.info({profile: ctrl.activity.params.friend_url[$index].profile})" ng-repeat="friend in ctrl.activity.params.friend_name"> | 10 | <a class="separated-item" ui-sref="main.profile.info({profile: ctrl.activity.params.friend_url[$index].profile})" ng-repeat="friend in ctrl.activity.params.friend_name"> |
11 | <strong ng-bind="friend"></strong> | 11 | <strong ng-bind="friend"></strong> |
src/app/components/notification/notification.component.spec.ts
0 → 100644
@@ -0,0 +1,67 @@ | @@ -0,0 +1,67 @@ | ||
1 | +import {TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder'; | ||
2 | +import {Pipe, Input, provide, Component} from 'ng-forward'; | ||
3 | + | ||
4 | +import * as helpers from "../../../spec/helpers"; | ||
5 | + | ||
6 | +import {Notification} from "./notification.component"; | ||
7 | + | ||
8 | +const tcb = new TestComponentBuilder(); | ||
9 | + | ||
10 | +describe("Components", () => { | ||
11 | + | ||
12 | + describe("Profile Image Component", () => { | ||
13 | + | ||
14 | + beforeEach(angular.mock.module("templates")); | ||
15 | + | ||
16 | + it("use the default message when call notification component without a specific message", done => { | ||
17 | + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]); | ||
18 | + sweetAlert.swal = jasmine.createSpy("swal"); | ||
19 | + | ||
20 | + let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.$translate); | ||
21 | + component.httpError(500, {}); | ||
22 | + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({ | ||
23 | + text: Notification.DEFAULT_HTTP_ERROR_MESSAGE, | ||
24 | + type: "error" | ||
25 | + })); | ||
26 | + done(); | ||
27 | + }); | ||
28 | + | ||
29 | + it("use the default message when call notification component without error data", done => { | ||
30 | + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]); | ||
31 | + sweetAlert.swal = jasmine.createSpy("swal"); | ||
32 | + | ||
33 | + let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.$translate); | ||
34 | + component.httpError(500, null); | ||
35 | + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({ | ||
36 | + text: Notification.DEFAULT_HTTP_ERROR_MESSAGE, | ||
37 | + type: "error" | ||
38 | + })); | ||
39 | + done(); | ||
40 | + }); | ||
41 | + | ||
42 | + it("display a success message when call notification success", done => { | ||
43 | + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]); | ||
44 | + sweetAlert.swal = jasmine.createSpy("swal"); | ||
45 | + | ||
46 | + let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.$translate); | ||
47 | + component.success("title", "message", 1000); | ||
48 | + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({ | ||
49 | + type: "success" | ||
50 | + })); | ||
51 | + done(); | ||
52 | + }); | ||
53 | + | ||
54 | + it("set the default timer in success messages", done => { | ||
55 | + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]); | ||
56 | + sweetAlert.swal = jasmine.createSpy("swal"); | ||
57 | + | ||
58 | + let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.$translate); | ||
59 | + component.success("title", "message"); | ||
60 | + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({ | ||
61 | + type: "success", | ||
62 | + timer: Notification.DEFAULT_SUCCESS_TIMER | ||
63 | + })); | ||
64 | + done(); | ||
65 | + }); | ||
66 | + }); | ||
67 | +}); |
src/app/components/notification/notification.component.ts
0 → 100644
@@ -0,0 +1,38 @@ | @@ -0,0 +1,38 @@ | ||
1 | +import {Injectable, Inject} from "ng-forward"; | ||
2 | + | ||
3 | +@Injectable() | ||
4 | +@Inject("$log", "SweetAlert", "$translate") | ||
5 | +export class Notification { | ||
6 | + | ||
7 | + constructor( | ||
8 | + private $log: ng.ILogService, | ||
9 | + private SweetAlert: any, | ||
10 | + private $translate: angular.translate.ITranslateService | ||
11 | + ) { } | ||
12 | + | ||
13 | + public static DEFAULT_HTTP_ERROR_TITLE = "notification.http-error.default.title"; | ||
14 | + public static DEFAULT_HTTP_ERROR_MESSAGE = "notification.http-error.default.message"; | ||
15 | + public static DEFAULT_SUCCESS_TIMER = 1000; | ||
16 | + | ||
17 | + httpError(status: number, data: any): boolean { | ||
18 | + this.$log.debug(status, data); | ||
19 | + | ||
20 | + let message = (data || {}).message || Notification.DEFAULT_HTTP_ERROR_MESSAGE; | ||
21 | + this.SweetAlert.swal({ | ||
22 | + title: this.$translate.instant(Notification.DEFAULT_HTTP_ERROR_TITLE), | ||
23 | + text: this.$translate.instant(message), | ||
24 | + type: "error" | ||
25 | + }); | ||
26 | + return true; // return true to indicate that the error was already handled | ||
27 | + } | ||
28 | + | ||
29 | + success(title: string, text: string, timer: number = Notification.DEFAULT_SUCCESS_TIMER) { | ||
30 | + this.SweetAlert.swal({ | ||
31 | + title: title, | ||
32 | + text: text, | ||
33 | + type: "success", | ||
34 | + timer: timer | ||
35 | + }); | ||
36 | + } | ||
37 | + | ||
38 | +} |
src/app/content-viewer/content-viewer-actions.component.spec.ts
0 → 100644
@@ -0,0 +1,67 @@ | @@ -0,0 +1,67 @@ | ||
1 | +import {providers} from 'ng-forward/cjs/testing/providers'; | ||
2 | + | ||
3 | +import {Input, Component, provide} from 'ng-forward'; | ||
4 | + | ||
5 | +import * as helpers from "../../spec/helpers"; | ||
6 | + | ||
7 | +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder'; | ||
8 | +import {ContentViewerActions} from './content-viewer-actions.component'; | ||
9 | + | ||
10 | +// this htmlTemplate will be re-used between the container components in this spec file | ||
11 | +const htmlTemplate: string = '<content-viewer-actions [article]="ctrl.article" [profile]="ctrl.profile"></content-viewer-actions>'; | ||
12 | + | ||
13 | +describe('Content Viewer Actions Component', () => { | ||
14 | + | ||
15 | + beforeEach(() => { | ||
16 | + | ||
17 | + angular.mock.module("templates"); | ||
18 | + | ||
19 | + providers((provide: any) => { | ||
20 | + return <any>[ | ||
21 | + provide('ProfileService', { | ||
22 | + useValue: helpers.mocks.profileService | ||
23 | + }) | ||
24 | + ]; | ||
25 | + }); | ||
26 | + }); | ||
27 | + | ||
28 | + let buildComponent = (): Promise<ComponentFixture> => { | ||
29 | + return helpers.quickCreateComponent({ | ||
30 | + providers: [ | ||
31 | + helpers.provideEmptyObjects('Restangular'), | ||
32 | + helpers.provideFilters('translateFilter') | ||
33 | + ], | ||
34 | + directives: [ContentViewerActions], | ||
35 | + template: htmlTemplate | ||
36 | + }); | ||
37 | + }; | ||
38 | + | ||
39 | + it('renders content viewer actions directive', (done: Function) => { | ||
40 | + buildComponent().then((fixture: ComponentFixture) => { | ||
41 | + expect(fixture.debugElement.query('content-viewer-actions').length).toEqual(1); | ||
42 | + | ||
43 | + done(); | ||
44 | + }); | ||
45 | + }); | ||
46 | + | ||
47 | + it('check if profile was loaded', (done: Function) => { | ||
48 | + let profile: any = { | ||
49 | + id: 1, | ||
50 | + identifier: 'the-profile-test', | ||
51 | + type: 'Person' | ||
52 | + }; | ||
53 | + | ||
54 | + helpers.mocks.profileService.getCurrentProfile = () => { | ||
55 | + return helpers.mocks.promiseResultTemplate(profile); | ||
56 | + }; | ||
57 | + | ||
58 | + buildComponent().then((fixture: ComponentFixture) => { | ||
59 | + let contentViewerComp: ContentViewerActions = fixture.debugElement.componentViewChildren[0].componentInstance; | ||
60 | + | ||
61 | + expect(contentViewerComp.profile).toEqual(jasmine.objectContaining(profile)); | ||
62 | + | ||
63 | + done(); | ||
64 | + }); | ||
65 | + }); | ||
66 | + | ||
67 | +}); |
src/app/content-viewer/content-viewer-actions.component.ts
1 | import {Component, Inject, provide} from "ng-forward"; | 1 | import {Component, Inject, provide} from "ng-forward"; |
2 | import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; | 2 | import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; |
3 | 3 | ||
4 | -import {Profile} from "./../models/interfaces"; | ||
5 | - | ||
6 | @Component({ | 4 | @Component({ |
7 | selector: "content-viewer-actions", | 5 | selector: "content-viewer-actions", |
8 | templateUrl: "app/content-viewer/navbar-actions.html", | 6 | templateUrl: "app/content-viewer/navbar-actions.html", |
@@ -11,11 +9,11 @@ import {Profile} from "./../models/interfaces"; | @@ -11,11 +9,11 @@ import {Profile} from "./../models/interfaces"; | ||
11 | @Inject(ProfileService) | 9 | @Inject(ProfileService) |
12 | export class ContentViewerActions { | 10 | export class ContentViewerActions { |
13 | 11 | ||
14 | - article: any; | ||
15 | - profile: any; | 12 | + article: noosfero.Article; |
13 | + profile: noosfero.Profile; | ||
16 | 14 | ||
17 | constructor(profileService: ProfileService) { | 15 | constructor(profileService: ProfileService) { |
18 | - profileService.getCurrentProfile().then((profile: Profile) => { | 16 | + profileService.getCurrentProfile().then((profile: noosfero.Profile) => { |
19 | this.profile = profile; | 17 | this.profile = profile; |
20 | }); | 18 | }); |
21 | } | 19 | } |
@@ -0,0 +1,90 @@ | @@ -0,0 +1,90 @@ | ||
1 | +import {providers} from 'ng-forward/cjs/testing/providers'; | ||
2 | + | ||
3 | +import {Input, Component, provide} from 'ng-forward'; | ||
4 | + | ||
5 | +import * as helpers from "../../spec/helpers"; | ||
6 | + | ||
7 | +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder'; | ||
8 | +import {ContentViewer} from './content-viewer.component'; | ||
9 | + | ||
10 | +// this htmlTemplate will be re-used between the container components in this spec file | ||
11 | +const htmlTemplate: string = '<content-viewer [article]="ctrl.article" [profile]="ctrl.profile"></content-viewer>'; | ||
12 | + | ||
13 | +describe('Content Viewer Component', () => { | ||
14 | + | ||
15 | + let stateParamsService: any; | ||
16 | + | ||
17 | + //loading the templates | ||
18 | + beforeEach(() => { | ||
19 | + angular.mock.module("templates"); | ||
20 | + | ||
21 | + stateParamsService = { page: 1 }; | ||
22 | + | ||
23 | + providers((provide: any) => { | ||
24 | + return <any>[ | ||
25 | + provide('ArticleService', { | ||
26 | + useValue: helpers.mocks.articleService | ||
27 | + }), | ||
28 | + provide('ProfileService', { | ||
29 | + useValue: helpers.mocks.profileService | ||
30 | + }), | ||
31 | + // TODO: Como criar um mock do atributo "page" de stateParams | ||
32 | + provide('$stateParams', { | ||
33 | + useValue: stateParamsService | ||
34 | + }) | ||
35 | + ] | ||
36 | + }); | ||
37 | + }); | ||
38 | + | ||
39 | + let buildComponent = (): Promise<ComponentFixture> => { | ||
40 | + return helpers.quickCreateComponent({ | ||
41 | + providers: [ | ||
42 | + helpers.provideEmptyObjects('Restangular') | ||
43 | + ], | ||
44 | + directives: [ContentViewer], | ||
45 | + template: htmlTemplate | ||
46 | + }); | ||
47 | + }; | ||
48 | + | ||
49 | + it('renders content viewer directive', (done: Function) => { | ||
50 | + buildComponent().then((fixture: ComponentFixture) => { | ||
51 | + expect(fixture.debugElement.query('content-viewer').length).toEqual(1); | ||
52 | + | ||
53 | + done(); | ||
54 | + }) | ||
55 | + }); | ||
56 | + | ||
57 | + it('check if article was loaded', (done: Function) => { | ||
58 | + var article: any = { | ||
59 | + id: 1, | ||
60 | + title: 'The article test' | ||
61 | + }; | ||
62 | + var profile: any = { | ||
63 | + id: 1, | ||
64 | + identifier: 'the-profile-test', | ||
65 | + type: 'Person' | ||
66 | + }; | ||
67 | + | ||
68 | + helpers.mocks.profileService.getCurrentProfile = () => { | ||
69 | + return helpers.mocks.promiseResultTemplate(profile); | ||
70 | + }; | ||
71 | + | ||
72 | + helpers.mocks.articleService.getByProfile = (id: number, params: any) => { | ||
73 | + return helpers.mocks.promiseResultTemplate({ | ||
74 | + data: { | ||
75 | + article: article | ||
76 | + } | ||
77 | + }); | ||
78 | + }; | ||
79 | + | ||
80 | + | ||
81 | + buildComponent().then((fixture: ComponentFixture) => { | ||
82 | + let contentViewerComp: ContentViewer = fixture.debugElement.componentViewChildren[0].componentInstance; | ||
83 | + | ||
84 | + expect(contentViewerComp.profile).toEqual(jasmine.objectContaining(profile)); | ||
85 | + expect(contentViewerComp.article).toEqual(jasmine.objectContaining(article)); | ||
86 | + | ||
87 | + done(); | ||
88 | + }); | ||
89 | + }); | ||
90 | +}); |
src/app/content-viewer/content-viewer.component.ts
@@ -21,14 +21,14 @@ export class ContentViewer { | @@ -21,14 +21,14 @@ export class ContentViewer { | ||
21 | article: noosfero.Article = null; | 21 | article: noosfero.Article = null; |
22 | 22 | ||
23 | @Input() | 23 | @Input() |
24 | - profile: Profile = null; | 24 | + profile: noosfero.Profile = null; |
25 | 25 | ||
26 | constructor(private articleService: ArticleService, private profileService: ProfileService, private $log: ng.ILogService, private $stateParams: angular.ui.IStateParamsService) { | 26 | constructor(private articleService: ArticleService, private profileService: ProfileService, private $log: ng.ILogService, private $stateParams: angular.ui.IStateParamsService) { |
27 | this.activate(); | 27 | this.activate(); |
28 | } | 28 | } |
29 | 29 | ||
30 | activate() { | 30 | activate() { |
31 | - this.profileService.getCurrentProfile().then((profile: Profile) => { | 31 | + this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => { |
32 | this.profile = profile; | 32 | this.profile = profile; |
33 | return this.articleService.getByProfile(<any>this.profile, { path: this.$stateParams["page"] }); | 33 | return this.articleService.getByProfile(<any>this.profile, { path: this.$stateParams["page"] }); |
34 | }).then((result: noosfero.RestResult<noosfero.Article>) => { | 34 | }).then((result: noosfero.RestResult<noosfero.Article>) => { |
src/app/index.config.ts
@@ -29,6 +29,7 @@ function configTranslation($translateProvider: angular.translate.ITranslateProvi | @@ -29,6 +29,7 @@ function configTranslation($translateProvider: angular.translate.ITranslateProvi | ||
29 | prefix: '/languages/', | 29 | prefix: '/languages/', |
30 | suffix: '.json' | 30 | suffix: '.json' |
31 | }); | 31 | }); |
32 | + $translateProvider.addInterpolation('$translateMessageFormatInterpolation'); | ||
32 | $translateProvider.useMissingTranslationHandlerLog(); | 33 | $translateProvider.useMissingTranslationHandlerLog(); |
33 | $translateProvider.preferredLanguage('en'); | 34 | $translateProvider.preferredLanguage('en'); |
34 | $translateProvider.useSanitizeValueStrategy('escape'); | 35 | $translateProvider.useSanitizeValueStrategy('escape'); |
src/app/index.run.ts
1 | import {Session} from "./components/auth/session"; | 1 | import {Session} from "./components/auth/session"; |
2 | +import {Notification} from "./components/notification/notification.component"; | ||
2 | 3 | ||
3 | /** @ngInject */ | 4 | /** @ngInject */ |
4 | -export function noosferoAngularRunBlock($log: ng.ILogService, Restangular: restangular.IService, Session: Session) { | ||
5 | - Restangular.addFullRequestInterceptor((element: any, operation: string, route: string, url: string, headers: string) => { | 5 | +export function noosferoAngularRunBlock( |
6 | + $log: ng.ILogService, | ||
7 | + Restangular: restangular.IService, | ||
8 | + Session: Session, | ||
9 | + Notification: Notification | ||
10 | +) { | ||
11 | + | ||
12 | + Restangular.addFullRequestInterceptor((element: any, operation: string, route: string, url: string, headers: string) => { | ||
6 | if (Session.currentUser()) { | 13 | if (Session.currentUser()) { |
7 | (<any>headers)["Private-Token"] = Session.currentUser().private_token; | 14 | (<any>headers)["Private-Token"] = Session.currentUser().private_token; |
8 | } | 15 | } |
9 | return <any>{ headers: <any>headers }; | 16 | return <any>{ headers: <any>headers }; |
10 | }); | 17 | }); |
18 | + Restangular.setErrorInterceptor((response: restangular.IResponse, deferred: ng.IDeferred<any>) => { | ||
19 | + // return false to break the promise chain and don't call catch | ||
20 | + return !Notification.httpError(response.status, response.data); | ||
21 | + }); | ||
11 | } | 22 | } |
12 | - |
src/app/main/main.component.ts
@@ -17,6 +17,7 @@ import {DateFormat} from "../components/noosfero/date-format/date-format.filter" | @@ -17,6 +17,7 @@ import {DateFormat} from "../components/noosfero/date-format/date-format.filter" | ||
17 | 17 | ||
18 | import {AuthService} from "./../components/auth/auth_service"; | 18 | import {AuthService} from "./../components/auth/auth_service"; |
19 | import {Session} from "./../components/auth/session"; | 19 | import {Session} from "./../components/auth/session"; |
20 | +import {Notification} from "./../components/notification/notification.component"; | ||
20 | 21 | ||
21 | 22 | ||
22 | import {Navbar} from "../components/navbar/navbar"; | 23 | import {Navbar} from "../components/navbar/navbar"; |
@@ -41,7 +42,7 @@ export class MainContent { | @@ -41,7 +42,7 @@ export class MainContent { | ||
41 | MainBlock, RecentDocumentsBlock, Navbar, ProfileImageBlock, | 42 | MainBlock, RecentDocumentsBlock, Navbar, ProfileImageBlock, |
42 | MembersBlock, NoosferoTemplate, DateFormat, RawHTMLBlock | 43 | MembersBlock, NoosferoTemplate, DateFormat, RawHTMLBlock |
43 | ], | 44 | ], |
44 | - providers: [AuthService, Session] | 45 | + providers: [AuthService, Session, Notification] |
45 | }) | 46 | }) |
46 | @StateConfig([ | 47 | @StateConfig([ |
47 | { | 48 | { |
src/app/profile-info/profile-info.component.ts
@@ -11,17 +11,17 @@ import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; | @@ -11,17 +11,17 @@ import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; | ||
11 | @Inject(ProfileService) | 11 | @Inject(ProfileService) |
12 | export class ProfileInfo { | 12 | export class ProfileInfo { |
13 | 13 | ||
14 | - activities: any | ||
15 | - profile: any | 14 | + activities: any; |
15 | + profile: noosfero.Profile; | ||
16 | 16 | ||
17 | constructor(private profileService: ProfileService) { | 17 | constructor(private profileService: ProfileService) { |
18 | this.activate(); | 18 | this.activate(); |
19 | } | 19 | } |
20 | 20 | ||
21 | activate() { | 21 | activate() { |
22 | - this.profileService.getCurrentProfile().then((profile: Profile) => { | 22 | + this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => { |
23 | this.profile = profile; | 23 | this.profile = profile; |
24 | - return this.profileService.getActivities(this.profile.id); | 24 | + return this.profileService.getActivities(<number>this.profile.id); |
25 | }).then((response: restangular.IResponse) => { | 25 | }).then((response: restangular.IResponse) => { |
26 | this.activities = response.data.activities; | 26 | this.activities = response.data.activities; |
27 | }); | 27 | }); |
src/app/profile/profile-home.component.ts
1 | import {StateConfig, Component, Inject, provide} from 'ng-forward'; | 1 | import {StateConfig, Component, Inject, provide} from 'ng-forward'; |
2 | 2 | ||
3 | -import {Profile} from "./../models/interfaces"; | ||
4 | import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; | 3 | import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; |
5 | 4 | ||
6 | @Component({ | 5 | @Component({ |
@@ -11,12 +10,12 @@ import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; | @@ -11,12 +10,12 @@ import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; | ||
11 | @Inject(ProfileService, "$state") | 10 | @Inject(ProfileService, "$state") |
12 | export class ProfileHome { | 11 | export class ProfileHome { |
13 | 12 | ||
14 | - profile: Profile; | 13 | + profile: noosfero.Profile; |
15 | 14 | ||
16 | constructor(profileService: ProfileService, $state: ng.ui.IStateService) { | 15 | constructor(profileService: ProfileService, $state: ng.ui.IStateService) { |
17 | - profileService.getCurrentProfile().then((profile: Profile) => { | 16 | + profileService.getCurrentProfile().then((profile: noosfero.Profile) => { |
18 | this.profile = profile; | 17 | this.profile = profile; |
19 | - return profileService.getHomePage(this.profile.id, { fields: 'path' }); | 18 | + return profileService.getHomePage(<number>this.profile.id, { fields: 'path' }); |
20 | }).then((response: restangular.IResponse) => { | 19 | }).then((response: restangular.IResponse) => { |
21 | if (response.data.article) { | 20 | if (response.data.article) { |
22 | $state.transitionTo('main.profile.page', { page: response.data.article.path, profile: this.profile.identifier }, { location: false }); | 21 | $state.transitionTo('main.profile.page', { page: response.data.article.path, profile: this.profile.identifier }, { location: false }); |
src/app/profile/profile.component.spec.ts
@@ -7,6 +7,7 @@ describe("Components", () => { | @@ -7,6 +7,7 @@ describe("Components", () => { | ||
7 | let $rootScope: ng.IRootScopeService; | 7 | let $rootScope: ng.IRootScopeService; |
8 | let $q: ng.IQService; | 8 | let $q: ng.IQService; |
9 | let profileServiceMock: any; | 9 | let profileServiceMock: any; |
10 | + let notificationMock: any; | ||
10 | let $stateParams: any; | 11 | let $stateParams: any; |
11 | 12 | ||
12 | beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => { | 13 | beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => { |
@@ -17,6 +18,7 @@ describe("Components", () => { | @@ -17,6 +18,7 @@ describe("Components", () => { | ||
17 | beforeEach(() => { | 18 | beforeEach(() => { |
18 | $stateParams = jasmine.createSpyObj("$stateParams", ["profile"]); | 19 | $stateParams = jasmine.createSpyObj("$stateParams", ["profile"]); |
19 | profileServiceMock = jasmine.createSpyObj("profileServiceMock", ["setCurrentProfileByIdentifier", "getBoxes"]); | 20 | profileServiceMock = jasmine.createSpyObj("profileServiceMock", ["setCurrentProfileByIdentifier", "getBoxes"]); |
21 | + notificationMock = jasmine.createSpyObj("notificationMock", ["httpError"]); | ||
20 | 22 | ||
21 | let profileResponse = $q.defer(); | 23 | let profileResponse = $q.defer(); |
22 | profileResponse.resolve({ id: 1 }); | 24 | profileResponse.resolve({ id: 1 }); |
@@ -28,7 +30,7 @@ describe("Components", () => { | @@ -28,7 +30,7 @@ describe("Components", () => { | ||
28 | }); | 30 | }); |
29 | 31 | ||
30 | it("get the profile and store in profile service", done => { | 32 | it("get the profile and store in profile service", done => { |
31 | - let component: Profile = new Profile(profileServiceMock, $stateParams); | 33 | + let component: Profile = new Profile(profileServiceMock, $stateParams, notificationMock); |
32 | $rootScope.$apply(); | 34 | $rootScope.$apply(); |
33 | expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled(); | 35 | expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled(); |
34 | expect(component.profile).toEqual({ id: 1 }); | 36 | expect(component.profile).toEqual({ id: 1 }); |
@@ -36,11 +38,26 @@ describe("Components", () => { | @@ -36,11 +38,26 @@ describe("Components", () => { | ||
36 | }); | 38 | }); |
37 | 39 | ||
38 | it("get the profile boxes", done => { | 40 | it("get the profile boxes", done => { |
39 | - let component: Profile = new Profile(profileServiceMock, $stateParams); | 41 | + let component: Profile = new Profile(profileServiceMock, $stateParams, notificationMock); |
40 | $rootScope.$apply(); | 42 | $rootScope.$apply(); |
41 | expect(profileServiceMock.getBoxes).toHaveBeenCalled(); | 43 | expect(profileServiceMock.getBoxes).toHaveBeenCalled(); |
42 | expect(component.boxes).toEqual([{ id: 2 }]); | 44 | expect(component.boxes).toEqual([{ id: 2 }]); |
43 | done(); | 45 | done(); |
44 | }); | 46 | }); |
47 | + | ||
48 | + it("display notification error when the profile wasn't found", done => { | ||
49 | + let profileResponse = $q.defer(); | ||
50 | + profileResponse.reject(); | ||
51 | + profileServiceMock.setCurrentProfileByIdentifier = jasmine.createSpy("setCurrentProfileByIdentifier").and.returnValue(profileResponse.promise); | ||
52 | + | ||
53 | + let component: Profile = new Profile(profileServiceMock, $stateParams, notificationMock); | ||
54 | + $rootScope.$apply(); | ||
55 | + | ||
56 | + expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled(); | ||
57 | + expect(notificationMock.httpError).toHaveBeenCalled(); | ||
58 | + expect(component.profile).toBeUndefined(); | ||
59 | + done(); | ||
60 | + }); | ||
61 | + | ||
45 | }); | 62 | }); |
46 | }); | 63 | }); |
src/app/profile/profile.component.ts
@@ -6,14 +6,16 @@ import {ContentViewer} from "../content-viewer/content-viewer.component"; | @@ -6,14 +6,16 @@ import {ContentViewer} from "../content-viewer/content-viewer.component"; | ||
6 | import {ContentViewerActions} from "../content-viewer/content-viewer-actions.component"; | 6 | import {ContentViewerActions} from "../content-viewer/content-viewer-actions.component"; |
7 | import {NoosferoActivities} from "../components/noosfero-activities/activities.component"; | 7 | import {NoosferoActivities} from "../components/noosfero-activities/activities.component"; |
8 | import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; | 8 | import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service"; |
9 | - | ||
10 | -import * as noosferoModels from "./../models/interfaces"; | 9 | +import {Notification} from "../components/notification/notification.component"; |
11 | 10 | ||
12 | @Component({ | 11 | @Component({ |
13 | selector: 'profile', | 12 | selector: 'profile', |
14 | templateUrl: "app/profile/profile.html", | 13 | templateUrl: "app/profile/profile.html", |
15 | directives: [NoosferoActivities], | 14 | directives: [NoosferoActivities], |
16 | - providers: [provide('profileService', { useClass: ProfileService })] | 15 | + providers: [ |
16 | + provide('profileService', { useClass: ProfileService }), | ||
17 | + provide('notification', { useClass: Notification }) | ||
18 | + ] | ||
17 | }) | 19 | }) |
18 | @StateConfig([ | 20 | @StateConfig([ |
19 | { | 21 | { |
@@ -72,15 +74,17 @@ import * as noosferoModels from "./../models/interfaces"; | @@ -72,15 +74,17 @@ import * as noosferoModels from "./../models/interfaces"; | ||
72 | @Inject(ProfileService, "$stateParams") | 74 | @Inject(ProfileService, "$stateParams") |
73 | export class Profile { | 75 | export class Profile { |
74 | 76 | ||
75 | - boxes: noosferoModels.Box[]; | ||
76 | - profile: noosferoModels.Profile; | 77 | + boxes: noosfero.Box[]; |
78 | + profile: noosfero.Profile; | ||
77 | 79 | ||
78 | - constructor(profileService: ProfileService, $stateParams: ng.ui.IStateParamsService) { | ||
79 | - profileService.setCurrentProfileByIdentifier($stateParams["profile"]).then((profile: noosferoModels.Profile) => { | 80 | + constructor(profileService: ProfileService, $stateParams: ng.ui.IStateParamsService, notification: Notification) { |
81 | + profileService.setCurrentProfileByIdentifier($stateParams["profile"]).then((profile: noosfero.Profile) => { | ||
80 | this.profile = profile; | 82 | this.profile = profile; |
81 | - return profileService.getBoxes(this.profile.id); | 83 | + return profileService.getBoxes(<number>this.profile.id); |
82 | }).then((response: restangular.IResponse) => { | 84 | }).then((response: restangular.IResponse) => { |
83 | this.boxes = response.data.boxes; | 85 | this.boxes = response.data.boxes; |
86 | + }).catch(() => { | ||
87 | + notification.httpError(404, { message: "Profile not found!" }); | ||
84 | }); | 88 | }); |
85 | } | 89 | } |
86 | } | 90 | } |
src/languages/en.json
@@ -12,10 +12,12 @@ | @@ -12,10 +12,12 @@ | ||
12 | "profile.wall": "Profile Wall", | 12 | "profile.wall": "Profile Wall", |
13 | "activities.create_article.description": "has published on", | 13 | "activities.create_article.description": "has published on", |
14 | "activities.add_member_in_community.description": "has joined the community", | 14 | "activities.add_member_in_community.description": "has joined the community", |
15 | - "activities.new_friendship.description": "has made {{friends}} new friend(s):", | 15 | + "activities.new_friendship.description": "has made {friends, plural, one{one new friend} other{# new friends}}:", |
16 | "auth.title": "Login", | 16 | "auth.title": "Login", |
17 | "auth.form.login": "Login / Email address", | 17 | "auth.form.login": "Login / Email address", |
18 | "auth.form.password": "Password", | 18 | "auth.form.password": "Password", |
19 | "auth.form.login_button": "Login", | 19 | "auth.form.login_button": "Login", |
20 | - "navbar.content_viewer_actions.new_post": "New Post" | 20 | + "navbar.content_viewer_actions.new_post": "New Post", |
21 | + "notification.http-error.default.message": "Something went wrong!", | ||
22 | + "notification.http-error.default.title": "Oops..." | ||
21 | } | 23 | } |
src/languages/pt.json
@@ -12,10 +12,12 @@ | @@ -12,10 +12,12 @@ | ||
12 | "profile.wall": "Mural do Perfil", | 12 | "profile.wall": "Mural do Perfil", |
13 | "activities.create_article.description": "publicou em", | 13 | "activities.create_article.description": "publicou em", |
14 | "activities.add_member_in_community.description": "entrou na comunidade", | 14 | "activities.add_member_in_community.description": "entrou na comunidade", |
15 | - "activities.new_friendship.description": "fez {{friends}} novo(s) amigo(s):", | 15 | + "activities.new_friendship.description": "fez {friends, plural, one{um novo amigo} other{# novos amigos}}:", |
16 | "auth.title": "Login", | 16 | "auth.title": "Login", |
17 | "auth.form.login": "Login / Email", | 17 | "auth.form.login": "Login / Email", |
18 | "auth.form.password": "Senha", | 18 | "auth.form.password": "Senha", |
19 | "auth.form.login_button": "Login", | 19 | "auth.form.login_button": "Login", |
20 | - "navbar.content_viewer_actions.new_post": "Novo Artigo" | 20 | + "navbar.content_viewer_actions.new_post": "Novo Artigo", |
21 | + "notification.http-error.default.message": "Algo deu errado!", | ||
22 | + "notification.http-error.default.title": "Oops..." | ||
21 | } | 23 | } |
src/lib/ng-noosfero-api/http/profile.service.spec.ts
@@ -24,8 +24,17 @@ describe("Services", () => { | @@ -24,8 +24,17 @@ describe("Services", () => { | ||
24 | it("should return profile by its identifier", (done) => { | 24 | it("should return profile by its identifier", (done) => { |
25 | let identifier = 'profile1'; | 25 | let identifier = 'profile1'; |
26 | $httpBackend.expectGET(`/api/v1/profiles?identifier=${identifier}`).respond(200, [{ name: "profile1" }]); | 26 | $httpBackend.expectGET(`/api/v1/profiles?identifier=${identifier}`).respond(200, [{ name: "profile1" }]); |
27 | - profileService.getByIdentifier(identifier).then((response: restangular.IResponse) => { | ||
28 | - expect(response.data[0]).toEqual({ name: "profile1" }); | 27 | + profileService.getByIdentifier(identifier).then((profile: noosfero.Profile) => { |
28 | + expect(profile).toEqual({ name: "profile1" }); | ||
29 | + done(); | ||
30 | + }); | ||
31 | + $httpBackend.flush(); | ||
32 | + }); | ||
33 | + | ||
34 | + it("should reject the promise if the profile wasn't found", (done) => { | ||
35 | + let identifier = 'profile1'; | ||
36 | + $httpBackend.expectGET(`/api/v1/profiles?identifier=${identifier}`).respond(200, []); | ||
37 | + profileService.getByIdentifier(identifier).catch(() => { | ||
29 | done(); | 38 | done(); |
30 | }); | 39 | }); |
31 | $httpBackend.flush(); | 40 | $httpBackend.flush(); |
@@ -63,11 +72,11 @@ describe("Services", () => { | @@ -63,11 +72,11 @@ describe("Services", () => { | ||
63 | 72 | ||
64 | it("should resolve the current profile", (done) => { | 73 | it("should resolve the current profile", (done) => { |
65 | let profile = { id: 1, identifier: "profile1" }; | 74 | let profile = { id: 1, identifier: "profile1" }; |
66 | - profileService.getCurrentProfile().then((currentProfile: Profile) => { | 75 | + profileService.getCurrentProfile().then((currentProfile: noosfero.Profile) => { |
67 | expect(currentProfile).toEqual(currentProfile); | 76 | expect(currentProfile).toEqual(currentProfile); |
68 | done(); | 77 | done(); |
69 | }); | 78 | }); |
70 | - profileService.setCurrentProfile(<Profile>profile); | 79 | + profileService.setCurrentProfile(<any>profile); |
71 | $rootScope.$apply(); | 80 | $rootScope.$apply(); |
72 | }); | 81 | }); |
73 | 82 | ||
@@ -84,9 +93,9 @@ describe("Services", () => { | @@ -84,9 +93,9 @@ describe("Services", () => { | ||
84 | it("should find the profile by identifier, set and resolve the current profile", (done) => { | 93 | it("should find the profile by identifier, set and resolve the current profile", (done) => { |
85 | let identifier = 'profile1'; | 94 | let identifier = 'profile1'; |
86 | $httpBackend.expectGET(`/api/v1/profiles?identifier=${identifier}`).respond(200, [{ name: "profile1" }]); | 95 | $httpBackend.expectGET(`/api/v1/profiles?identifier=${identifier}`).respond(200, [{ name: "profile1" }]); |
87 | - profileService.setCurrentProfileByIdentifier(identifier).then((profile: Profile) => { | 96 | + profileService.setCurrentProfileByIdentifier(identifier).then((profile: noosfero.Profile) => { |
88 | expect(profile).toEqual({ name: "profile1" }); | 97 | expect(profile).toEqual({ name: "profile1" }); |
89 | - profileService.getCurrentProfile().then((profile: Profile) => { | 98 | + profileService.getCurrentProfile().then((profile: noosfero.Profile) => { |
90 | expect(profile).toEqual({ name: "profile1" }); | 99 | expect(profile).toEqual({ name: "profile1" }); |
91 | done(); | 100 | done(); |
92 | }); | 101 | }); |
src/lib/ng-noosfero-api/http/profile.service.ts
@@ -5,7 +5,7 @@ import {Profile} from "../../../app/models/interfaces"; | @@ -5,7 +5,7 @@ import {Profile} from "../../../app/models/interfaces"; | ||
5 | @Inject("Restangular", "$q") | 5 | @Inject("Restangular", "$q") |
6 | export class ProfileService { | 6 | export class ProfileService { |
7 | 7 | ||
8 | - private _currentProfilePromise: ng.IDeferred<Profile>; | 8 | + private _currentProfilePromise: ng.IDeferred<noosfero.Profile>; |
9 | 9 | ||
10 | constructor(private restangular: restangular.IService, private $q: ng.IQService) { | 10 | constructor(private restangular: restangular.IService, private $q: ng.IQService) { |
11 | this.resetCurrentProfile(); | 11 | this.resetCurrentProfile(); |
@@ -15,18 +15,18 @@ export class ProfileService { | @@ -15,18 +15,18 @@ export class ProfileService { | ||
15 | this._currentProfilePromise = this.$q.defer(); | 15 | this._currentProfilePromise = this.$q.defer(); |
16 | } | 16 | } |
17 | 17 | ||
18 | - getCurrentProfile(): ng.IPromise<Profile> { | 18 | + getCurrentProfile(): ng.IPromise<noosfero.Profile> { |
19 | return this._currentProfilePromise.promise; | 19 | return this._currentProfilePromise.promise; |
20 | } | 20 | } |
21 | 21 | ||
22 | - setCurrentProfile(profile: Profile) { | 22 | + setCurrentProfile(profile: noosfero.Profile) { |
23 | this._currentProfilePromise.resolve(profile); | 23 | this._currentProfilePromise.resolve(profile); |
24 | } | 24 | } |
25 | 25 | ||
26 | setCurrentProfileByIdentifier(identifier: string) { | 26 | setCurrentProfileByIdentifier(identifier: string) { |
27 | this.resetCurrentProfile(); | 27 | this.resetCurrentProfile(); |
28 | - return this.getByIdentifier(identifier).then((response: restangular.IResponse) => { | ||
29 | - this.setCurrentProfile(response.data[0]); | 28 | + return this.getByIdentifier(identifier).then((profile: noosfero.Profile) => { |
29 | + this.setCurrentProfile(profile); | ||
30 | return this.getCurrentProfile(); | 30 | return this.getCurrentProfile(); |
31 | }); | 31 | }); |
32 | } | 32 | } |
@@ -35,8 +35,14 @@ export class ProfileService { | @@ -35,8 +35,14 @@ export class ProfileService { | ||
35 | return this.get(profileId).customGET("home_page", params); | 35 | return this.get(profileId).customGET("home_page", params); |
36 | } | 36 | } |
37 | 37 | ||
38 | - getByIdentifier(identifier: string): restangular.IPromise<any> { | ||
39 | - return this.restangular.one('profiles').get({ identifier: identifier }); | 38 | + getByIdentifier(identifier: string): ng.IPromise<noosfero.Profile> { |
39 | + let p = this.restangular.one('profiles').get({ identifier: identifier }); | ||
40 | + return p.then((response: restangular.IResponse) => { | ||
41 | + if (response.data.length === 0) { | ||
42 | + return this.$q.reject(p); | ||
43 | + } | ||
44 | + return response.data[0]; | ||
45 | + }); | ||
40 | } | 46 | } |
41 | 47 | ||
42 | getProfileMembers(profileId: number, params?: any): restangular.IPromise<any> { | 48 | getProfileMembers(profileId: number, params?: any): restangular.IPromise<any> { |
src/spec/mocks.ts
@@ -38,6 +38,32 @@ export var mocks = { | @@ -38,6 +38,32 @@ export var mocks = { | ||
38 | authService: { | 38 | authService: { |
39 | logout: () => { } | 39 | logout: () => { } |
40 | }, | 40 | }, |
41 | + articleService: { | ||
42 | + getByProfile: (profileId: number, params?: any) => { | ||
43 | + return { | ||
44 | + then: (func?: Function) => { | ||
45 | + if (func) func({ | ||
46 | + data: { | ||
47 | + article: null | ||
48 | + } | ||
49 | + }); | ||
50 | + } | ||
51 | + }; | ||
52 | + }, | ||
53 | + getChildren: (articleId: number, params?: any) => { | ||
54 | + return { | ||
55 | + then: (func?: Function) => { if (func) func(); } | ||
56 | + }; | ||
57 | + } | ||
58 | + }, | ||
59 | + profileService: { | ||
60 | + getCurrentProfile: (profile: any) => { | ||
61 | + return mocks.promiseResultTemplate({ | ||
62 | + profile: profile | ||
63 | + }); | ||
64 | + }, | ||
65 | + instant: () => { } | ||
66 | + }, | ||
41 | sessionWithCurrentUser: (user: any) => { | 67 | sessionWithCurrentUser: (user: any) => { |
42 | return { | 68 | return { |
43 | currentUser: () => { return user; } | 69 | currentUser: () => { return user; } |
@@ -45,11 +71,9 @@ export var mocks = { | @@ -45,11 +71,9 @@ export var mocks = { | ||
45 | }, | 71 | }, |
46 | $translate: { | 72 | $translate: { |
47 | use: (lang?: string) => { | 73 | use: (lang?: string) => { |
48 | - return { | ||
49 | - then: (func?: any) => { if (func) func() } | ||
50 | - } | 74 | + return lang ? Promise.resolve(lang) : "en"; |
51 | }, | 75 | }, |
52 | - instant: () => { } | 76 | + instant: (text: string) => { return text } |
53 | }, | 77 | }, |
54 | tmhDynamicLocale: { | 78 | tmhDynamicLocale: { |
55 | get: () => { }, | 79 | get: () => { }, |
@@ -60,9 +84,18 @@ export var mocks = { | @@ -60,9 +84,18 @@ export var mocks = { | ||
60 | }, | 84 | }, |
61 | angularLoad: { | 85 | angularLoad: { |
62 | loadScript: (script?: string) => { | 86 | loadScript: (script?: string) => { |
63 | - return { | ||
64 | - then: (func?: any) => { if (func) func() } | ||
65 | - } | 87 | + return Promise.resolve(); |
66 | } | 88 | } |
89 | + }, | ||
90 | + promiseResultTemplate: (response?: {}) => { | ||
91 | + | ||
92 | + return { | ||
93 | + then: (func?: (response: any) => void) => { | ||
94 | + if (func) { return func(response); } | ||
95 | + } | ||
96 | + }; | ||
97 | + }, | ||
98 | + $log: { | ||
99 | + debug: () => { } | ||
67 | } | 100 | } |
68 | }; | 101 | }; |