Commit 9e3a58f8acfe2bd0dee59401bf8b84e8e4ccb875
1 parent
eef070ef
Exists in
master
and in
1 other branch
changes on article service
Showing
11 changed files
with
197 additions
and
80 deletions
Show diff stats
src/app/cms/cms.component.spec.ts
... | ... | @@ -26,7 +26,7 @@ describe("Components", () => { |
26 | 26 | getCurrentProfileResponse.resolve({ id: 1 }); |
27 | 27 | |
28 | 28 | let articleCreate = $q.defer(); |
29 | - articleCreate.resolve({ data: { article: { path: "path", profile: { identifier: "profile" } } } }); | |
29 | + articleCreate.resolve({ path: "path", profile: { identifier: "profile" } }); | |
30 | 30 | |
31 | 31 | profileServiceMock.getCurrentProfile = jasmine.createSpy("getCurrentProfile").and.returnValue(getCurrentProfileResponse.promise); |
32 | 32 | articleServiceMock.create = jasmine.createSpy("create").and.returnValue(articleCreate.promise); | ... | ... |
src/app/cms/cms.component.ts
... | ... | @@ -23,8 +23,8 @@ export class Cms { |
23 | 23 | save() { |
24 | 24 | this.profileService.getCurrentProfile().then((profile: Profile) => { |
25 | 25 | return this.articleService.create(profile.id, this.article); |
26 | - }).then((response: restangular.IResponse) => { | |
27 | - this.$state.transitionTo('main.profile.page', { page: response.data.article.path, profile: response.data.article.profile.identifier }); | |
26 | + }).then((article: noosfero.Article) => { | |
27 | + this.$state.transitionTo('main.profile.page', { page: article.path, profile: article.profile.identifier }); | |
28 | 28 | this.SweetAlert.swal({ |
29 | 29 | title: "Good job!", |
30 | 30 | text: "Article saved!", | ... | ... |
src/app/components/noosfero-articles/blog/blog.component.spec.ts
1 | 1 | import { |
2 | - providers | |
2 | +providers | |
3 | 3 | } from 'ng-forward/cjs/testing/providers'; |
4 | 4 | |
5 | 5 | import { |
6 | - Input, | |
7 | - Component | |
6 | +Input, | |
7 | +Component | |
8 | 8 | } from 'ng-forward'; |
9 | 9 | import { |
10 | - ArticleBlog | |
10 | +ArticleBlog | |
11 | 11 | } from './blog.component'; |
12 | 12 | |
13 | 13 | import { |
14 | - createComponentFromClass, | |
15 | - quickCreateComponent, | |
16 | - provideEmptyObjects, | |
17 | - createProviderToValue, | |
18 | - provideFilters | |
14 | +createComponentFromClass, | |
15 | +quickCreateComponent, | |
16 | +provideEmptyObjects, | |
17 | +createProviderToValue, | |
18 | +provideFilters | |
19 | 19 | } from "../../../../spec/helpers.ts"; |
20 | 20 | |
21 | 21 | // this htmlTemplate will be re-used between the container components in this spec file |
... | ... | @@ -23,7 +23,7 @@ const htmlTemplate: string = '<noosfero-blog [article]="ctrl.article" [profile]= |
23 | 23 | |
24 | 24 | describe("Blog Component", () => { |
25 | 25 | |
26 | - function promiseResultTemplate(response ? : {}) { | |
26 | + function promiseResultTemplate(response?: {}) { | |
27 | 27 | let thenFuncEmpty = (func: Function) => { |
28 | 28 | // does nothing |
29 | 29 | }; |
... | ... | @@ -76,7 +76,7 @@ describe("Blog Component", () => { |
76 | 76 | angular.mock.module("templates") |
77 | 77 | |
78 | 78 | providers((provide: any) => { |
79 | - return <any > [ | |
79 | + return <any>[ | |
80 | 80 | provide('ArticleService', { |
81 | 81 | useValue: articleService |
82 | 82 | }) |
... | ... | @@ -96,19 +96,16 @@ describe("Blog Component", () => { |
96 | 96 | |
97 | 97 | it("verify the blog data", (done: Function) => { |
98 | 98 | |
99 | + let articles = [{ | |
100 | + id: 1, | |
101 | + title: 'The article test' | |
102 | + }]; | |
103 | + | |
104 | + (<any>articles)['_headers'] = { total: 1 }; | |
105 | + | |
99 | 106 | // defining a mock result to articleService.getChildren method |
100 | 107 | articleService.getChildren = (article_id: number, filters: {}) => { |
101 | - return promiseResultTemplate({ | |
102 | - headers: (headerName: string) => { | |
103 | - return 1; | |
104 | - }, | |
105 | - data: < any > { | |
106 | - articles: [{ | |
107 | - id: 1, | |
108 | - title: 'The article test' | |
109 | - }] | |
110 | - } | |
111 | - }); | |
108 | + return promiseResultTemplate(articles); | |
112 | 109 | }; |
113 | 110 | |
114 | 111 | createComponentFromClass(BlogContainerComponent).then((fixture) => { |
... | ... | @@ -121,8 +118,8 @@ describe("Blog Component", () => { |
121 | 118 | id: 1, |
122 | 119 | title: 'The article test' |
123 | 120 | }; |
124 | - expect(( < any > articleBlog)["posts"][0]).toEqual(jasmine.objectContaining(post)); | |
125 | - expect(( < any > articleBlog)["totalPosts"]).toEqual(1); | |
121 | + expect((<any>articleBlog)["posts"][0]).toEqual(jasmine.objectContaining(post)); | |
122 | + expect((<any>articleBlog)["totalPosts"]).toEqual(1); | |
126 | 123 | |
127 | 124 | done(); |
128 | 125 | }); | ... | ... |
src/app/components/noosfero-articles/blog/blog.component.ts
... | ... | @@ -33,9 +33,9 @@ export class ArticleBlog { |
33 | 33 | |
34 | 34 | this.articleService |
35 | 35 | .getChildren(this.article.id, filters) |
36 | - .then((response: restangular.IResponse) => { | |
37 | - this.totalPosts = <number>(<any>response.headers("total")); | |
38 | - this.posts = response.data.articles; | |
36 | + .then((articles: noosfero.Article[]) => { | |
37 | + this.totalPosts = <number>(<any>articles)["_headers"]["total"]; | |
38 | + this.posts = articles; | |
39 | 39 | }); |
40 | 40 | } |
41 | 41 | ... | ... |
src/lib/ng-noosfero-api/http/article.service.spec.ts
... | ... | @@ -24,8 +24,8 @@ describe("Services", () => { |
24 | 24 | it("should return article children", (done) => { |
25 | 25 | let articleId = 1; |
26 | 26 | $httpBackend.expectGET(`/api/v1/articles/${articleId}/children`).respond(200, { articles: [{ name: "article1" }] }); |
27 | - articleService.getChildren(articleId).then((response: restangular.IResponse) => { | |
28 | - expect(response.data.articles).toEqual([{ name: "article1" }]); | |
27 | + articleService.getChildren<noosfero.ArticlesResult>(articleId).then((result: noosfero.ArticlesResult) => { | |
28 | + expect(result.articles).toEqual([{ name: "article1" }]); | |
29 | 29 | done(); |
30 | 30 | }); |
31 | 31 | $httpBackend.flush(); |
... | ... | @@ -34,8 +34,8 @@ describe("Services", () => { |
34 | 34 | it("should get articles by profile", (done) => { |
35 | 35 | let profileId = 1; |
36 | 36 | $httpBackend.expectGET(`/api/v1/profiles/${profileId}/articles`).respond(200, { articles: [{ name: "article1" }] }); |
37 | - articleService.getByProfile(profileId).then((response: restangular.IResponse) => { | |
38 | - expect(response.data.articles).toEqual([{ name: "article1" }]); | |
37 | + articleService.getByProfile<noosfero.ArticlesResult>(profileId).then((result: noosfero.ArticlesResult) => { | |
38 | + expect(result.articles).toEqual([{ name: "article1" }]); | |
39 | 39 | done(); |
40 | 40 | }); |
41 | 41 | $httpBackend.flush(); |
... | ... | @@ -44,8 +44,8 @@ describe("Services", () => { |
44 | 44 | it("should get articles by profile with additional filters", (done) => { |
45 | 45 | let profileId = 1; |
46 | 46 | $httpBackend.expectGET(`/api/v1/profiles/${profileId}/articles?path=test`).respond(200, { articles: [{ name: "article1" }] }); |
47 | - articleService.getByProfile(profileId, { path: 'test' }).then((response: restangular.IResponse) => { | |
48 | - expect(response.data.articles).toEqual([{ name: "article1" }]); | |
47 | + articleService.getByProfile<noosfero.ArticlesResult>(profileId, { path: 'test' }).then((result: noosfero.ArticlesResult) => { | |
48 | + expect(result.articles).toEqual([{ name: "article1" }]); | |
49 | 49 | done(); |
50 | 50 | }); |
51 | 51 | $httpBackend.flush(); |
... | ... | @@ -54,8 +54,8 @@ describe("Services", () => { |
54 | 54 | it("should get article children with additional filters", (done) => { |
55 | 55 | let articleId = 1; |
56 | 56 | $httpBackend.expectGET(`/api/v1/articles/${articleId}/children?path=test`).respond(200, { articles: [{ name: "article1" }] }); |
57 | - articleService.getChildren(articleId, { path: 'test' }).then((response: restangular.IResponse) => { | |
58 | - expect(response.data.articles).toEqual([{ name: "article1" }]); | |
57 | + articleService.getChildren<noosfero.ArticlesResult>(articleId, { path: 'test' }).then((result: noosfero.ArticlesResult) => { | |
58 | + expect(result.articles).toEqual([{ name: "article1" }]); | |
59 | 59 | done(); |
60 | 60 | }); |
61 | 61 | $httpBackend.flush(); |
... | ... | @@ -63,10 +63,10 @@ describe("Services", () => { |
63 | 63 | |
64 | 64 | it("should create an article in a profile", (done) => { |
65 | 65 | let profileId = 1; |
66 | - let article: Article = { id: null }; | |
67 | - $httpBackend.expectPOST(`/api/v1/profiles/${profileId}/articles`, { article: article }).respond(200, { articles: [{ id: 2 }] }); | |
68 | - articleService.create(profileId, article).then((response: restangular.IResponse) => { | |
69 | - expect(response.data.articles).toEqual([{ id: 2 }]); | |
66 | + let article: noosfero.Article = <any>{ id: null}; | |
67 | + $httpBackend.expectPOST(`/api/v1/profiles/${profileId}/articles`, { article: article }).respond(200, { id: 2 }); | |
68 | + articleService.create(profileId, article).then((result: noosfero.Article) => { | |
69 | + expect(article).toEqual({ id: 2 }); | |
70 | 70 | done(); |
71 | 71 | }); |
72 | 72 | $httpBackend.flush(); | ... | ... |
src/lib/ng-noosfero-api/http/article.service.ts
1 | 1 | import { Injectable, Inject } from "ng-forward"; |
2 | -import {Article} from "../../../app/models/interfaces"; | |
3 | - | |
2 | +import {RestangularWrapperService} from "./restangular_wrapper_service"; | |
4 | 3 | @Injectable() |
5 | 4 | @Inject("Restangular", "$q") |
6 | 5 | |
6 | +export class ArticleService extends RestangularWrapperService<noosfero.Article> { | |
7 | 7 | |
8 | -export class ArticleService { | |
8 | + constructor(Restangular: restangular.IService, $q: ng.IQService, $log: ng.ILogService) { | |
9 | + super(Restangular, $q, $log); | |
10 | + } | |
9 | 11 | |
10 | - constructor(private Restangular: restangular.IService, private $q: ng.IQService, private $log: ng.ILogService) { } | |
12 | + getPath() { | |
13 | + return "articles"; | |
14 | + } | |
11 | 15 | |
12 | - create(profileId: number, article: Article) { | |
13 | - return this.Restangular.one('profiles', profileId).customPOST( | |
14 | - { article: article }, | |
15 | - 'articles', | |
16 | - {}, | |
17 | - { 'Content-Type': 'application/json' } | |
18 | - ); | |
16 | + getDataKeys() { | |
17 | + return { | |
18 | + singular: 'article', | |
19 | + plural: 'articles' | |
20 | + } | |
19 | 21 | } |
20 | 22 | |
21 | - // TODO create a handle ErrorFactory too and move handleSuccessFactory and handleErrorFactory | |
22 | - // to a base class (of course we will have to creates a base class too) | |
23 | - handleSuccessFactory<T>(deferred: ng.IDeferred<T>): (response: restangular.IResponse) => void { | |
24 | - let self = this; | |
25 | - let successFunction = (response: restangular.IResponse): void => { | |
26 | - this.$log.debug("Request successfull executed", this, response); | |
27 | - deferred.resolve(response.data); | |
28 | - }; | |
29 | - return successFunction; | |
23 | + create(profileId: number, article: noosfero.Article): ng.IPromise<noosfero.Article> { | |
24 | + return this.post(this.Restangular.one('profiles', profileId), article); | |
30 | 25 | } |
31 | 26 | |
27 | + // // TODO create a handle ErrorFactory too and move handleSuccessFactory and handleErrorFactory | |
28 | + // // to a base class (of course we will have to creates a base class too) | |
29 | + // handleSuccessFactory<T>(deferred: ng.IDeferred<T>): (response: restangular.IResponse) => void { | |
30 | + // let self = this; | |
31 | + // let successFunction = (response: restangular.IResponse): void => { | |
32 | + // this.$log.debug("Request successfull executed", self, response); | |
33 | + // deferred.resolve(response.data); | |
34 | + // }; | |
35 | + // return successFunction; | |
36 | + // } | |
37 | + // | |
38 | + // handleErrorFactory<T>(deferred: ng.IDeferred<T>): (response: restangular.IResponse) => void { | |
39 | + // let self = this; | |
40 | + // let successFunction = (response: restangular.IResponse): void => { | |
41 | + // this.$log.error("Error executing request", self, response); | |
42 | + // deferred.reject(response.data); | |
43 | + // }; | |
44 | + // return successFunction; | |
45 | + // } | |
46 | + | |
32 | 47 | // TODO -> change all Restangular services to this approach "Return promise to a specific type" |
33 | 48 | // it makes easy consume the service |
34 | 49 | getByProfile<T>(profileId: number, params?: any): ng.IPromise<T> { |
35 | 50 | let deferred = this.$q.defer<T>(); |
36 | - this.Restangular.one('profiles', profileId).customGET('articles', params).then(this.handleSuccessFactory(deferred)); | |
51 | + this.Restangular.one('profiles', profileId).customGET('articles', params) | |
52 | + .then(this.getHandleSuccessFunction<T>(deferred, 'articles')) | |
53 | + .catch(this.getHandleErrorFunction(deferred)); | |
37 | 54 | return deferred.promise; |
38 | 55 | } |
39 | 56 | |
40 | - getChildren(articleId: number, params?: any) { | |
41 | - return this.get(articleId).customGET('children', params); | |
42 | - } | |
57 | + getChildren<T>(articleId: number, params?: any): ng.IPromise<T> { | |
58 | + let deferred = this.$q.defer<T>(); | |
59 | + | |
60 | + this.get(articleId).customGET('children', params) | |
61 | + .then(this.getHandleSuccessFunction<T>(deferred, 'articles').bind(this)) | |
62 | + .catch(this.getHandleErrorFunction(deferred)); | |
43 | 63 | |
44 | - private get(articleId: number) { | |
45 | - return this.Restangular.one('articles', articleId); | |
64 | + return deferred.promise; | |
46 | 65 | } |
47 | 66 | |
67 | + | |
68 | + | |
48 | 69 | } | ... | ... |
src/lib/ng-noosfero-api/http/http_client.ts
... | ... | @@ -1,11 +0,0 @@ |
1 | -namespace NgNoosferoAPI { | |
2 | - export class NoosferoHttpClient { | |
3 | - static $inject = ['$http', '$q']; | |
4 | - | |
5 | - constructor(private $http: ng.IHttpService, private $q: ng.IQService) { | |
6 | - | |
7 | - } | |
8 | - } | |
9 | - | |
10 | - NgNoosferoAPI.ngModule.service(NoosferoHttpClient); | |
11 | -} | |
12 | 0 | \ No newline at end of file |
... | ... | @@ -0,0 +1,16 @@ |
1 | +namespace noosfero.http { | |
2 | + export function Rest(config: { | |
3 | + path: string | |
4 | + } | |
5 | + ): Function { | |
6 | + let path = config.path; | |
7 | + return (t: Function) => { | |
8 | + if (!path) { | |
9 | + throw new Error(`Rest decorator error in ${(<any>t).name}. Rest path should be provided`); | |
10 | + } | |
11 | + t.prototype.getPath = function() { | |
12 | + return path; | |
13 | + }; | |
14 | + }; | |
15 | + } | |
16 | +} | |
0 | 17 | \ No newline at end of file | ... | ... |
src/lib/ng-noosfero-api/http/restangular_wrapper_service.ts
0 → 100644
... | ... | @@ -0,0 +1,80 @@ |
1 | +export abstract class RestangularWrapperService<T> { | |
2 | + | |
3 | + private lastResponse: restangular.IResponse; | |
4 | + constructor(protected Restangular: restangular.IService, protected $q: ng.IQService, protected $log: ng.ILogService) { | |
5 | + | |
6 | + } | |
7 | + | |
8 | + protected abstract getPath(): string; | |
9 | + | |
10 | + protected abstract getDataKeys(): { singular: string, plural: string }; | |
11 | + | |
12 | + protected get(id: number): restangular.IElement { | |
13 | + return this.Restangular.one(this.getPath(), id); | |
14 | + } | |
15 | + | |
16 | + protected post(elementRoot: restangular.IElement, element?: any, path?: string, params?: any, headers?: any): ng.IPromise<T> { | |
17 | + let deferred = this.$q.defer<T>(); | |
18 | + | |
19 | + this.customPOST( | |
20 | + elementRoot, | |
21 | + element, | |
22 | + this.getPath(), | |
23 | + {} | |
24 | + ) | |
25 | + .then(this.getHandleSuccessFunction(deferred)) | |
26 | + .catch(this.getHandleErrorFunction(deferred)); | |
27 | + | |
28 | + return deferred.promise; | |
29 | + } | |
30 | + | |
31 | + protected customPOST(elementRoot: restangular.IElement, elem?: any, path?: string, params?: any, headers?: any) { | |
32 | + if (headers) { | |
33 | + headers['Content-Type'] = 'application/json'; | |
34 | + } else { | |
35 | + headers = { 'Content-Type': 'application/json' }; | |
36 | + } | |
37 | + return elementRoot.customPOST(elem, path, params, headers); | |
38 | + } | |
39 | + | |
40 | + // TODO create a handle ErrorFactory too and move handleSuccessFactory and handleErrorFactory | |
41 | + // to a base class (of course we will have to creates a base class too) | |
42 | + getHandleSuccessFunction<C>(deferred: ng.IDeferred<C>, responseKey?: string): (response: restangular.IResponse) => void { | |
43 | + let self = this; | |
44 | + let successFunction = (response: restangular.IResponse): void => { | |
45 | + if (self.$log) { | |
46 | + self.$log.debug("Request successfull executed", self, response); | |
47 | + } | |
48 | + let data = response.data; | |
49 | + | |
50 | + let dataKey: string; | |
51 | + | |
52 | + if (data && self.getDataKeys()) { | |
53 | + if ((<Object>data).hasOwnProperty(self.getDataKeys().singular)) { | |
54 | + data = data[self.getDataKeys().singular]; | |
55 | + dataKey = self.getDataKeys().singular; | |
56 | + } else if ((<Object>data).hasOwnProperty(self.getDataKeys().plural)) { | |
57 | + data = data[self.getDataKeys().plural]; | |
58 | + dataKey = self.getDataKeys().plural; | |
59 | + } | |
60 | + } | |
61 | + | |
62 | + let result: any = {}; | |
63 | + result[dataKey] = data; | |
64 | + result.headers = response.headers; | |
65 | + deferred.resolve(result); | |
66 | + }; | |
67 | + return successFunction; | |
68 | + } | |
69 | + | |
70 | + getHandleErrorFunction<T>(deferred: ng.IDeferred<T>): (response: restangular.IResponse) => void { | |
71 | + let self = this; | |
72 | + let successFunction = (response: restangular.IResponse): void => { | |
73 | + if (self.$log) { | |
74 | + self.$log.error("Error executing request", self, response); | |
75 | + } | |
76 | + deferred.reject(response); | |
77 | + }; | |
78 | + return successFunction; | |
79 | + } | |
80 | +} | ... | ... |
src/lib/ng-noosfero-api/interfaces/article.ts