Commit d14121298f31300970fed97c1216414bbcdb5037

Authored by Victor Costa
2 parents f5a45d92 a3e051be
Exists in master and in 1 other branch dev-fixes

Merge branch 'ngforward' of softwarepublico.gov.br:noosfero-themes/angular-theme into ngforward

Showing 261 changed files with 3984 additions and 3345 deletions   Show diff stats
.vscode/settings.json
@@ -3,7 +3,9 @@ @@ -3,7 +3,9 @@
3 "files.exclude": { 3 "files.exclude": {
4 "**/.git": true, 4 "**/.git": true,
5 "**/.DS_Store": true, 5 "**/.DS_Store": true,
6 - "src/app/*.js": false 6 + "src/**/*.js": true,
  7 + "src/**/*.js.map": true,
  8 + "coverage": true
7 }, 9 },
8 "editor.fontSize": 14, 10 "editor.fontSize": 14,
9 "typescript.useCodeSnippetsOnMethodSuggest": true 11 "typescript.useCodeSnippetsOnMethodSuggest": true
dev-scripts/fix-jqlite.ts 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +let replace = require("replace");
  2 +
  3 +import * as path from "path";
  4 +
  5 +let wrong_jqlite_d_ts_file = path.join(__dirname, "../node_modules/ng-forward/cjs/util/jqlite-extensions.d.ts");
  6 +
  7 +replace({
  8 + regex: /import JQuery from \".\/\";/,
  9 + replacement: "",
  10 + paths: [wrong_jqlite_d_ts_file],
  11 + sillent: false
  12 +});
  13 +
@@ -4,21 +4,23 @@ @@ -4,21 +4,23 @@
4 "dependencies": { 4 "dependencies": {
5 "angular": "^1.5.0", 5 "angular": "^1.5.0",
6 "angular-mock": "^1.0.0", 6 "angular-mock": "^1.0.0",
7 - "moment": "^2.11.2" 7 + "moment": "^2.11.2",
  8 + "ng-forward": "0.0.1-alpha.12"
8 }, 9 },
9 "scripts": { 10 "scripts": {
10 "build": "webpack; gulp build", 11 "build": "webpack; gulp build",
11 "webpack": "webpack", 12 "webpack": "webpack",
  13 + "karma": "concurrently \"webpack -w\" \"karma start\"",
12 "docs": "gulp ngdocs; static-server docs", 14 "docs": "gulp ngdocs; static-server docs",
13 - "karma": "karma",  
14 "coverage": "karma start --single-run; npm run remap-coverage", 15 "coverage": "karma start --single-run; npm run remap-coverage",
15 "remap-coverage": "ts-node --project ./dev-scripts ./dev-scripts/remapCoverage.ts", 16 "remap-coverage": "ts-node --project ./dev-scripts ./dev-scripts/remapCoverage.ts",
16 "test-single": "karma start --single-run", 17 "test-single": "karma start --single-run",
17 "test-and-coverage": "karma start & npm run remap-coverage", 18 "test-and-coverage": "karma start & npm run remap-coverage",
18 "test": "webpack -w --test", 19 "test": "webpack -w --test",
19 - "postinstall": "npm install -g bower && bower install && typings install && cd dev-scripts && typings install", 20 + "postinstall": "npm install -g bower; bower install; typings install; npm run fix-jqlite; cd dev-scripts; typings install",
20 "start": "concurrently \"webpack -w\" \"gulp serve\"", 21 "start": "concurrently \"webpack -w\" \"gulp serve\"",
21 - "generate-indexes": "ts-node --project ./dev-scripts ./dev-scripts/generate-index-modules.ts" 22 + "generate-indexes": "ts-node --project ./dev-scripts ./dev-scripts/generate-index-modules.ts",
  23 + "fix-jqlite": "ts-node --project ./dev-scripts dev-scripts/fix-jqlite.ts"
22 }, 24 },
23 "devDependencies": { 25 "devDependencies": {
24 "browser-sync": "~2.9.11", 26 "browser-sync": "~2.9.11",
@@ -71,7 +73,6 @@ @@ -71,7 +73,6 @@
71 "karma-webpack": "^1.7.0", 73 "karma-webpack": "^1.7.0",
72 "lodash": "~3.10.1", 74 "lodash": "~3.10.1",
73 "main-bower-files": "~2.9.0", 75 "main-bower-files": "~2.9.0",
74 - "ng-forward": "0.0.1-alpha.12",  
75 "on-build-webpack": "^0.1.0", 76 "on-build-webpack": "^0.1.0",
76 "phantomjs": "~1.9.18", 77 "phantomjs": "~1.9.18",
77 "phantomjs-polyfill": "0.0.2", 78 "phantomjs-polyfill": "0.0.2",
src/app/admin/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
src/app/article/article-default-view-component.spec.ts 0 → 100644
@@ -0,0 +1,108 @@ @@ -0,0 +1,108 @@
  1 +
  2 +import {Input, provide, Component} from 'ng-forward';
  3 +import {ArticleViewComponent, ArticleDefaultViewComponent} from './article-default-view.component';
  4 +
  5 +import {createComponentFromClass, quickCreateComponent} from "../../spec/helpers";
  6 +
  7 +// this htmlTemplate will be re-used between the container components in this spec file
  8 +const htmlTemplate: string = '<noosfero-article [article]="ctrl.article" [profile]="ctrl.profile"></noosfero-article>';
  9 +
  10 +
  11 +describe("Components", () => {
  12 +
  13 + describe("ArticleView Component", () => {
  14 +
  15 + // the karma preprocessor html2js transform the templates html into js files which put
  16 + // the templates to the templateCache into the module templates
  17 + // we need to load the module templates here as the template for the
  18 + // component Noosfero ArtileView will be load on our tests
  19 + beforeEach(angular.mock.module("templates"));
  20 +
  21 + it("renders the default component when no specific component is found", (done: Function) => {
  22 + // Creating a container component (ArticleContainerComponent) to include
  23 + // the component under test (ArticleView)
  24 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [ArticleViewComponent] })
  25 + class ArticleContainerComponent {
  26 + article = { type: 'anyArticleType' };
  27 + profile = { name: 'profile-name' };
  28 + constructor() {
  29 + }
  30 + }
  31 +
  32 + createComponentFromClass(ArticleContainerComponent).then((fixture) => {
  33 + // and here we can inspect and run the test assertions
  34 +
  35 + // gets the children component of ArticleContainerComponent
  36 + let articleView: ArticleViewComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  37 +
  38 + // and checks if the article View rendered was the Default Article View
  39 + expect(articleView.constructor.prototype).toEqual(ArticleDefaultViewComponent.prototype);
  40 +
  41 + // done needs to be called (it isn't really needed, as we can read in
  42 + // here (https://github.com/ngUpgraders/ng-forward/blob/master/API.md#createasync)
  43 + // because createAsync in ng-forward is not really async, but as the intention
  44 + // here is write tests in angular 2 ways, this is recommended
  45 + done();
  46 + });
  47 +
  48 + });
  49 +
  50 + it("receives the article and profile as inputs", (done: Function) => {
  51 +
  52 + // Creating a container component (ArticleContainerComponent) to include
  53 + // the component under test (ArticleView)
  54 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [ArticleViewComponent] })
  55 + class ArticleContainerComponent {
  56 + article = { type: 'anyArticleType' };
  57 + profile = { name: 'profile-name' };
  58 + constructor() {
  59 + }
  60 + }
  61 +
  62 + // uses the TestComponentBuilder instance to initialize the component
  63 + createComponentFromClass(ArticleContainerComponent).then((fixture) => {
  64 + // and here we can inspect and run the test assertions
  65 + let articleView: ArticleViewComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  66 +
  67 + // assure the article object inside the ArticleView matches
  68 + // the provided through the parent component
  69 + expect(articleView.article.type).toEqual("anyArticleType");
  70 + expect(articleView.profile.name).toEqual("profile-name");
  71 +
  72 + // done needs to be called (it isn't really needed, as we can read in
  73 + // here (https://github.com/ngUpgraders/ng-forward/blob/master/API.md#createasync)
  74 + // because createAsync in ng-forward is not really async, but as the intention
  75 + // here is write tests in angular 2 ways, this is recommended
  76 + done();
  77 + });
  78 + });
  79 +
  80 +
  81 + it("renders a article view which matches to the article type", done => {
  82 + // NoosferoTinyMceArticle component created to check if it will be used
  83 + // when a article with type 'TinyMceArticle' is provided to the noosfero-article (ArticleView)
  84 + // *** Important *** - the selector is what ng-forward uses to define the name of the directive provider
  85 + @Component({ selector: 'noosfero-tiny-mce-article', template: "<h1>TinyMceArticle</h1>" })
  86 + class TinyMceArticleView {
  87 + @Input() article: any;
  88 + @Input() profile: any;
  89 + }
  90 +
  91 + // Creating a container component (ArticleContainerComponent) to include our NoosferoTinyMceArticle
  92 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [ArticleViewComponent, TinyMceArticleView] })
  93 + class CustomArticleType {
  94 + article = { type: 'TinyMceArticle' };
  95 + profile = { name: 'profile-name' };
  96 + constructor() {
  97 + }
  98 + }
  99 + createComponentFromClass(CustomArticleType).then(fixture => {
  100 + let myComponent: CustomArticleType = fixture.componentInstance;
  101 + expect(myComponent.article.type).toEqual("TinyMceArticle");
  102 + expect(fixture.debugElement.componentViewChildren[0].text()).toEqual("TinyMceArticle");
  103 + done();
  104 + });
  105 + });
  106 +
  107 + });
  108 +});
0 \ No newline at end of file 109 \ No newline at end of file
src/app/article/article-default-view.component.ts 0 → 100644
@@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
  1 +import { bundle, Input, Inject, Component, Directive } from 'ng-forward';
  2 +import {ArticleBlogComponent} from "./types/blog/blog.component";
  3 +
  4 +/**
  5 + * @ngdoc controller
  6 + * @name ArticleDefaultView
  7 + * @description
  8 + * A default view for Noosfero Articles. If the specific article view is
  9 + * not implemented, then this view is used.
  10 + */
  11 +@Component({
  12 + selector: 'noosfero-default-article',
  13 + templateUrl: 'app/article/article.html'
  14 +})
  15 +export class ArticleDefaultViewComponent {
  16 +
  17 + @Input() article: noosfero.Article;
  18 + @Input() profile: noosfero.Profile;
  19 +
  20 +}
  21 +
  22 +/**
  23 + * @ngdoc controller
  24 + * @name ArticleView
  25 + * @description
  26 + * A dynamic view for articles. It uses the article type to replace
  27 + * the default template with the custom article directive.
  28 + */
  29 +@Component({
  30 + selector: 'noosfero-article',
  31 + template: 'not-used',
  32 + directives: [ArticleDefaultViewComponent, ArticleBlogComponent]
  33 +})
  34 +@Inject("$element", "$scope", "$injector", "$compile")
  35 +export class ArticleViewComponent {
  36 +
  37 + @Input() article: noosfero.Article;
  38 + @Input() profile: noosfero.Profile;
  39 + directiveName: string;
  40 +
  41 + ngOnInit() {
  42 + let specificDirective = 'noosfero' + this.article.type;
  43 + this.directiveName = "noosfero-default-article";
  44 + if (this.$injector.has(specificDirective + 'Directive')) {
  45 + this.directiveName = specificDirective.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
  46 + }
  47 + this.$element.replaceWith(this.$compile('<' + this.directiveName + ' [article]="ctrl.article" [profile]="ctrl.profile"></' + this.directiveName + '>')(this.$scope));
  48 + }
  49 +
  50 + constructor(
  51 + private $element: any,
  52 + private $scope: ng.IScope,
  53 + private $injector: ng.auto.IInjectorService,
  54 + private $compile: ng.ICompileService) {
  55 +
  56 + }
  57 +}
src/app/article/article.html 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +<div class="article">
  2 + <div class="page-header">
  3 + <h3 ng-bind="ctrl.article.title"></h3>
  4 + </div>
  5 +
  6 + <div class="sub-header clearfix">
  7 + <div class="page-info pull-right small text-muted">
  8 + <span class="time">
  9 + <i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.article.created_at | dateFormat"></span>
  10 + </span>
  11 + <span class="author" ng-if="ctrl.article.author">
  12 + <i class="fa fa-user"></i>
  13 + <a ui-sref="main.profile.home({profile: ctrl.article.author.identifier})">
  14 + <span class="author-name" ng-bind="ctrl.article.author.name"></span>
  15 + </a>
  16 + </span>
  17 + </div>
  18 + </div>
  19 +
  20 + <div class="page-body">
  21 + <div ng-bind-html="ctrl.article.body"></div>
  22 + </div>
  23 +</div>
src/app/article/article.scss 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +.article {
  2 + .page-info {
  3 + .author {
  4 + a {
  5 + color: #b4bcc2;
  6 + }
  7 + }
  8 + }
  9 +
  10 + .page-header {
  11 + margin-bottom: 5px;
  12 + }
  13 +
  14 + .sub-header {
  15 + margin-bottom: 20px;
  16 + }
  17 +}
src/app/article/basic-editor.component.spec.ts 0 → 100644
@@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
  1 +import {quickCreateComponent} from "../../spec/helpers";
  2 +import {BasicEditorComponent} from "./basic-editor.component";
  3 +
  4 +
  5 +describe("Article BasicEditor", () => {
  6 +
  7 + let $rootScope: ng.IRootScopeService;
  8 + let $q: ng.IQService;
  9 + let articleServiceMock: any;
  10 + let profileServiceMock: any;
  11 + let $state: any;
  12 + let profile = { id: 1 };
  13 + let notification: any;
  14 +
  15 +
  16 + beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => {
  17 + $rootScope = _$rootScope_;
  18 + $q = _$q_;
  19 + }));
  20 +
  21 + beforeEach(() => {
  22 + $state = jasmine.createSpyObj("$state", ["transitionTo"]);
  23 + notification = jasmine.createSpyObj("notification", ["success"]);
  24 + profileServiceMock = jasmine.createSpyObj("profileServiceMock", ["getCurrentProfile"]);
  25 + articleServiceMock = jasmine.createSpyObj("articleServiceMock", ["createInProfile"]);
  26 +
  27 + let getCurrentProfileResponse = $q.defer();
  28 + getCurrentProfileResponse.resolve(profile);
  29 +
  30 + let articleCreate = $q.defer();
  31 + articleCreate.resolve({ data: { path: "path", profile: { identifier: "profile" } } });
  32 +
  33 + profileServiceMock.getCurrentProfile = jasmine.createSpy("getCurrentProfile").and.returnValue(getCurrentProfileResponse.promise);
  34 + articleServiceMock.createInProfile = jasmine.createSpy("createInProfile").and.returnValue(articleCreate.promise);
  35 + });
  36 +
  37 + it("create an article in the current profile when save", done => {
  38 + let component: BasicEditorComponent = new BasicEditorComponent(articleServiceMock, profileServiceMock, $state, notification);
  39 + component.save();
  40 + $rootScope.$apply();
  41 + expect(profileServiceMock.getCurrentProfile).toHaveBeenCalled();
  42 + expect(articleServiceMock.createInProfile).toHaveBeenCalledWith(profile, component.article);
  43 + done();
  44 + });
  45 +
  46 + it("got to the new article page and display an alert when saving sucessfully", done => {
  47 + let component: BasicEditorComponent = new BasicEditorComponent(articleServiceMock, profileServiceMock, $state, notification);
  48 + component.save();
  49 + $rootScope.$apply();
  50 + expect($state.transitionTo).toHaveBeenCalledWith("main.profile.page", { page: "path", profile: "profile" });
  51 + expect(notification.success).toHaveBeenCalled();
  52 + done();
  53 + });
  54 +
  55 +});
src/app/article/basic-editor.component.ts 0 → 100644
@@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
  1 +import {StateConfig, Component, Inject, provide} from 'ng-forward';
  2 +import {ArticleService} from "../../lib/ng-noosfero-api/http/article.service";
  3 +import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service";
  4 +import {NotificationService} from "../shared/services/notification.service.ts";
  5 +
  6 +@Component({
  7 + selector: 'article-basic-editor',
  8 + templateUrl: "app/article/basic-editor.html",
  9 + providers: [
  10 + provide('articleService', { useClass: ArticleService }),
  11 + provide('profileService', { useClass: ProfileService }),
  12 + provide('notification', { useClass: NotificationService })
  13 + ]
  14 +})
  15 +@Inject(ArticleService, ProfileService, "$state", NotificationService)
  16 +export class BasicEditorComponent {
  17 +
  18 + article: noosfero.Article = <noosfero.Article>{};
  19 +
  20 + constructor(private articleService: ArticleService,
  21 + private profileService: ProfileService,
  22 + private $state: ng.ui.IStateService,
  23 + private notification: NotificationService) { }
  24 +
  25 + save() {
  26 + this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => {
  27 + return this.articleService.createInProfile(profile, this.article);
  28 + }).then((response: noosfero.RestResult<noosfero.Article>) => {
  29 + let article = (<noosfero.Article>response.data);
  30 + this.$state.transitionTo('main.profile.page', { page: article.path, profile: article.profile.identifier });
  31 + this.notification.success("Good job!", "Article saved!");
  32 + });
  33 + }
  34 +
  35 +}
src/app/article/basic-editor.html 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +<form>
  2 + <div class="form-group">
  3 + <label for="titleInput">Title</label>
  4 + <input type="text" class="form-control" id="titleInput" placeholder="title" ng-model="vm.article.name">
  5 + </div>
  6 + <div class="form-group">
  7 + <label for="bodyInput">Text</label>
  8 + <textarea class="form-control" id="bodyInput" rows="10" ng-model="vm.article.body"></textarea>
  9 + </div>
  10 + <button type="submit" class="btn btn-default" ng-click="vm.save()">Save</button>
  11 +</form>
src/app/article/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/article/content-viewer/content-viewer-actions.component.ts 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +import {Component, Inject, provide} from "ng-forward";
  2 +import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service";
  3 +
  4 +@Component({
  5 + selector: "content-viewer-actions",
  6 + templateUrl: "app/article/content-viewer/navbar-actions.html",
  7 + providers: [provide('profileService', { useClass: ProfileService })]
  8 +})
  9 +@Inject(ProfileService)
  10 +export class ContentViewerActions {
  11 +
  12 + article: noosfero.Article;
  13 + profile: noosfero.Profile;
  14 +
  15 + constructor(profileService: ProfileService) {
  16 + profileService.getCurrentProfile().then((profile: noosfero.Profile) => {
  17 + this.profile = profile;
  18 + });
  19 + }
  20 +}
src/app/article/content-viewer/content-viewer.component.spec.ts 0 → 100644
@@ -0,0 +1,88 @@ @@ -0,0 +1,88 @@
  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 {ContentViewerComponent} 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: [ContentViewerComponent],
  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 + let article: any = {
  59 + id: 1,
  60 + title: 'The article test'
  61 + };
  62 + let 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.getArticleByProfileAndPath = (profile: noosfero.Profile, path: string) => {
  73 + return helpers.mocks.promiseResultTemplate({
  74 + data: article
  75 + });
  76 + };
  77 +
  78 +
  79 + buildComponent().then((fixture: ComponentFixture) => {
  80 + let contentViewerComp: ContentViewerComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  81 +
  82 + expect(contentViewerComp.profile).toEqual(profile);
  83 + expect(contentViewerComp.article).toEqual(article);
  84 +
  85 + done();
  86 + });
  87 + });
  88 +});
src/app/article/content-viewer/content-viewer.component.ts 0 → 100644
@@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
  1 +import {ArticleViewComponent} from "./../article-default-view.component";
  2 +import {Input, Component, StateConfig, Inject, provide} from "ng-forward";
  3 +
  4 +import {ArticleBlogComponent} from "./../types/blog/blog.component";
  5 +import {ArticleService} from "../../../lib/ng-noosfero-api/http/article.service";
  6 +import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service";
  7 +
  8 +@Component({
  9 + selector: "content-viewer",
  10 + templateUrl: "app/article/content-viewer/page.html",
  11 + directives: [ArticleBlogComponent, ArticleViewComponent],
  12 + providers: [
  13 + provide('articleService', { useClass: ArticleService }),
  14 + provide('profileService', { useClass: ProfileService })
  15 + ]
  16 +})
  17 +@Inject(ArticleService, ProfileService, "$log", "$stateParams")
  18 +export class ContentViewerComponent {
  19 +
  20 + @Input()
  21 + article: noosfero.Article = null;
  22 +
  23 + @Input()
  24 + profile: noosfero.Profile = null;
  25 +
  26 + constructor(private articleService: ArticleService, private profileService: ProfileService, private $log: ng.ILogService, private $stateParams: angular.ui.IStateParamsService) {
  27 + this.activate();
  28 + }
  29 +
  30 + activate() {
  31 + this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => {
  32 + this.profile = profile;
  33 + return this.articleService.getArticleByProfileAndPath(this.profile, this.$stateParams["page"]);
  34 + }).then((result: noosfero.RestResult<any>) => {
  35 + this.article = <noosfero.Article>result.data;
  36 + });
  37 + }
  38 +}
src/app/article/content-viewer/index.ts 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./content-viewer-actions.component";
  3 +export * from "./content-viewer.component";
src/app/article/content-viewer/navbar-actions.html 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +<ul class="nav navbar-nav">
  2 + <li ng-show="vm.profile">
  3 + <a href="#" role="button" ui-sref="main.profile.cms({profile: vm.profile.identifier})">
  4 + <i class="fa fa-file fa-fw fa-lg"></i> {{"navbar.content_viewer_actions.new_post" | translate}}
  5 + </a>
  6 + </li>
  7 +</ul>
src/app/article/content-viewer/page.html 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +<noosfero-article ng-if="vm.article" [article]="vm.article" [profile]="vm.profile"></noosfero-article>
src/app/article/index.ts 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./article-default-view.component";
  3 +export * from "./basic-editor.component";
src/app/article/types/blog/blog.component.spec.ts 0 → 100644
@@ -0,0 +1,129 @@ @@ -0,0 +1,129 @@
  1 +import {
  2 +providers
  3 +} from 'ng-forward/cjs/testing/providers';
  4 +
  5 +import {
  6 +Input,
  7 +Component
  8 +} from 'ng-forward';
  9 +import {
  10 +ArticleBlogComponent
  11 +} from './blog.component';
  12 +
  13 +import {
  14 +createComponentFromClass,
  15 +quickCreateComponent,
  16 +provideEmptyObjects,
  17 +createProviderToValue,
  18 +provideFilters
  19 +} from "../../../../spec/helpers.ts";
  20 +
  21 +// this htmlTemplate will be re-used between the container components in this spec file
  22 +const htmlTemplate: string = '<noosfero-blog [article]="ctrl.article" [profile]="ctrl.profile"></noosfero-blog>';
  23 +
  24 +describe("Blog Component", () => {
  25 +
  26 + function promiseResultTemplate(response?: {}) {
  27 + let thenFuncEmpty = (func: Function) => {
  28 + // does nothing
  29 + };
  30 + if (response) {
  31 + return {
  32 + then: (func: (response: any) => void) => {
  33 + func(response);
  34 + }
  35 + };
  36 + } else {
  37 + return {
  38 + then: (func: (response: any) => void) => {
  39 + // does nothing
  40 + }
  41 + };
  42 + }
  43 + }
  44 +
  45 + let articleService = {
  46 + getChildren: (article_id: number, filters: {}) => {
  47 + return promiseResultTemplate(null);
  48 + }
  49 + };
  50 +
  51 + @Component({
  52 + selector: 'test-container-component',
  53 + template: htmlTemplate,
  54 + directives: [ArticleBlogComponent],
  55 + providers: [
  56 + provideEmptyObjects('Restangular'),
  57 + createProviderToValue('ArticleService', articleService),
  58 + provideFilters('truncateFilter')
  59 + ]
  60 + })
  61 + class BlogContainerComponent {
  62 + article = {
  63 + type: 'anyArticleType'
  64 + };
  65 + profile = {
  66 + name: 'profile-name'
  67 + };
  68 + }
  69 +
  70 + beforeEach(() => {
  71 +
  72 + // the karma preprocessor html2js transform the templates html into js files which put
  73 + // the templates to the templateCache into the module templates
  74 + // we need to load the module templates here as the template for the
  75 + // component Noosfero ArtileView will be load on our tests
  76 + angular.mock.module("templates");
  77 +
  78 + providers((provide: any) => {
  79 + return <any>[
  80 + provide('ArticleService', {
  81 + useValue: articleService
  82 + })
  83 + ];
  84 + });
  85 + });
  86 +
  87 + it("renders the blog content", (done: Function) => {
  88 +
  89 + createComponentFromClass(BlogContainerComponent).then((fixture) => {
  90 +
  91 + expect(fixture.debugElement.query('div.blog').length).toEqual(1);
  92 +
  93 + done();
  94 + });
  95 + });
  96 +
  97 + it("verify the blog data", (done: Function) => {
  98 +
  99 + let articles = [{
  100 + id: 1,
  101 + title: 'The article test'
  102 + }];
  103 +
  104 + let result = { data: articles, headers: (name: string) => { return 1; } };
  105 +
  106 + // defining a mock result to articleService.getChildren method
  107 + articleService.getChildren = (article_id: number, filters: {}) => {
  108 + return promiseResultTemplate(result);
  109 + };
  110 +
  111 + createComponentFromClass(BlogContainerComponent).then((fixture) => {
  112 +
  113 + // gets the children component of BlogContainerComponent
  114 + let articleBlog: BlogContainerComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  115 +
  116 + // check if the component property are the provided by the mocked articleService
  117 + let post = {
  118 + id: 1,
  119 + title: 'The article test'
  120 + };
  121 + expect((<any>articleBlog)["posts"][0]).toEqual(jasmine.objectContaining(post));
  122 + expect((<any>articleBlog)["totalPosts"]).toEqual(1);
  123 +
  124 + done();
  125 + });
  126 +
  127 + });
  128 +
  129 +});
0 \ No newline at end of file 130 \ No newline at end of file
src/app/article/types/blog/blog.component.ts 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +import {Component, Input, Inject} from "ng-forward";
  2 +
  3 +import {ArticleService} from "../../../../lib/ng-noosfero-api/http/article.service";
  4 +
  5 +/**
  6 + * @ngdoc controller
  7 + * @name ArticleBlog
  8 + * @description
  9 + * An specific {@link ArticleView} for Blog articles.
  10 + */
  11 +@Component({
  12 + selector: "noosfero-blog",
  13 + templateUrl: "app/article/types/blog/blog.html"
  14 +})
  15 +@Inject(ArticleService)
  16 +export class ArticleBlogComponent {
  17 +
  18 + @Input() article: noosfero.Article;
  19 + @Input() profile: noosfero.Profile;
  20 +
  21 + private posts: noosfero.Article[];
  22 + private perPage: number = 3;
  23 + private currentPage: number;
  24 + private totalPosts: number = 0;
  25 +
  26 + constructor(private articleService: ArticleService) { }
  27 +
  28 + ngOnInit() {
  29 + this.loadPage();
  30 + }
  31 +
  32 + loadPage() {
  33 + let filters = {
  34 + content_type: "TinyMceArticle",
  35 + per_page: this.perPage,
  36 + page: this.currentPage
  37 + };
  38 +
  39 + this.articleService
  40 + .getChildren(this.article, filters)
  41 + .then((result: noosfero.RestResult<noosfero.Article[]>) => {
  42 + this.totalPosts = <number>result.headers("total");
  43 + this.posts = result.data;
  44 + });
  45 + }
  46 +
  47 +}
src/app/article/types/blog/blog.html 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +<div class="blog">
  2 + <div class="blog-cover" ng-show="ctrl.article.image">
  3 + <img ng-src="{{ctrl.article.image.url}}" class="img-responsive">
  4 + <h3 ng-bind="ctrl.article.title"></h3>
  5 + </div>
  6 +
  7 + <div class="page-header" ng-show="!ctrl.article.image">
  8 + <h3 ng-bind="ctrl.article.title"></h3>
  9 + </div>
  10 +
  11 + <div>
  12 + <div ng-repeat="child in ctrl.posts | orderBy: 'created_at':true">
  13 + <div class="page-header">
  14 + <a class="title" ui-sref="main.profile.page({profile: ctrl.profile.identifier, page: child.path})"><h4 ng-bind="child.title"></h4></a>
  15 + <div class="post-lead" ng-bind-html="child.body | truncate: 500: '...': true"></div>
  16 + </div>
  17 + </div>
  18 + </div>
  19 +
  20 + <pagination ng-model="ctrl.currentPage" total-items="ctrl.totalPosts" class="pagination-sm center-block"
  21 + boundary-links="true" items-per-page="ctrl.perPage" ng-change="ctrl.loadPage()"
  22 + first-text="«" last-text="»" previous-text="‹" next-text="›">
  23 + </pagination>
  24 +</div>
src/app/article/types/blog/blog.scss 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +.blog {
  2 + .blog-cover {
  3 + margin: -15px;
  4 + position: relative;
  5 + h3 {
  6 + position: absolute;
  7 + bottom: 0;
  8 + background-color: rgba(0, 0, 0, 0.4);
  9 + color: white;
  10 + padding: 10px 15px;
  11 + margin: 0;
  12 + width: 100%;
  13 + }
  14 + }
  15 +}
src/app/article/types/blog/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./blog.component";
src/app/article/types/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
src/app/cms/cms.component.spec.ts
@@ -1,54 +0,0 @@ @@ -1,54 +0,0 @@
1 -import {quickCreateComponent} from "../../spec/helpers";  
2 -import {Cms} from "./cms.component";  
3 -  
4 -describe("Components", () => {  
5 - describe("Cms Component", () => {  
6 -  
7 - let $rootScope: ng.IRootScopeService;  
8 - let $q: ng.IQService;  
9 - let articleServiceMock: any;  
10 - let profileServiceMock: any;  
11 - let $state: any;  
12 - let notification: any;  
13 -  
14 - beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => {  
15 - $rootScope = _$rootScope_;  
16 - $q = _$q_;  
17 - }));  
18 -  
19 - beforeEach(() => {  
20 - $state = jasmine.createSpyObj("$state", ["transitionTo"]);  
21 - notification = jasmine.createSpyObj("notification", ["success"]);  
22 - profileServiceMock = jasmine.createSpyObj("profileServiceMock", ["getCurrentProfile"]);  
23 - articleServiceMock = jasmine.createSpyObj("articleServiceMock", ["create"]);  
24 -  
25 - let getCurrentProfileResponse = $q.defer();  
26 - getCurrentProfileResponse.resolve({ id: 1 });  
27 -  
28 - let articleCreate = $q.defer();  
29 - articleCreate.resolve({ data: { article: { path: "path", profile: { identifier: "profile" } } } });  
30 -  
31 - profileServiceMock.getCurrentProfile = jasmine.createSpy("getCurrentProfile").and.returnValue(getCurrentProfileResponse.promise);  
32 - articleServiceMock.create = jasmine.createSpy("create").and.returnValue(articleCreate.promise);  
33 - });  
34 -  
35 - it("create an article in the current profile when save", done => {  
36 - let component: Cms = new Cms(articleServiceMock, profileServiceMock, $state, notification);  
37 - component.save();  
38 - $rootScope.$apply();  
39 - expect(profileServiceMock.getCurrentProfile).toHaveBeenCalled();  
40 - expect(articleServiceMock.create).toHaveBeenCalledWith(1, component.article);  
41 - done();  
42 - });  
43 -  
44 - it("got to the new article page and display an alert when saving sucessfully", done => {  
45 - let component: Cms = new Cms(articleServiceMock, profileServiceMock, $state, notification);  
46 - component.save();  
47 - $rootScope.$apply();  
48 - expect($state.transitionTo).toHaveBeenCalledWith("main.profile.page", { page: "path", profile: "profile" });  
49 - expect(notification.success).toHaveBeenCalled();  
50 - done();  
51 - });  
52 -  
53 - });  
54 -});  
src/app/cms/cms.component.ts
@@ -1,35 +0,0 @@ @@ -1,35 +0,0 @@
1 -import {StateConfig, Component, Inject, provide} from 'ng-forward';  
2 -import {Profile} from "./../models/interfaces";  
3 -import {ArticleService} from "../../lib/ng-noosfero-api/http/article.service";  
4 -import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service";  
5 -import {Notification} from "../components/notification/notification.component";  
6 -  
7 -@Component({  
8 - selector: 'cms',  
9 - templateUrl: "app/cms/cms.html",  
10 - providers: [  
11 - provide('articleService', { useClass: ArticleService }),  
12 - provide('profileService', { useClass: ProfileService }),  
13 - provide('notification', { useClass: Notification })  
14 - ]  
15 -})  
16 -@Inject(ArticleService, ProfileService, "$state", Notification)  
17 -export class Cms {  
18 -  
19 - article: any = {};  
20 -  
21 - constructor(private articleService: ArticleService,  
22 - private profileService: ProfileService,  
23 - private $state: ng.ui.IStateService,  
24 - private notification: Notification) { }  
25 -  
26 - save() {  
27 - this.profileService.getCurrentProfile().then((profile: Profile) => {  
28 - return this.articleService.create(profile.id, this.article);  
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!");  
32 - });  
33 - }  
34 -  
35 -}  
src/app/cms/cms.html
@@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
1 -<form>  
2 - <div class="form-group">  
3 - <label for="titleInput">Title</label>  
4 - <input type="text" class="form-control" id="titleInput" placeholder="title" ng-model="vm.article.name">  
5 - </div>  
6 - <div class="form-group">  
7 - <label for="bodyInput">Text</label>  
8 - <textarea class="form-control" id="bodyInput" rows="10" ng-model="vm.article.body"></textarea>  
9 - </div>  
10 - <button type="submit" class="btn btn-default" ng-click="vm.save()">Save</button>  
11 -</form>  
src/app/cms/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./cms.component";  
src/app/components/auth/auth_controller.spec.ts
@@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
1 -import {AuthController} from "./auth_controller";  
2 -import {AuthService} from "./auth_service";  
3 -  
4 -describe("Controllers", () => {  
5 -  
6 -  
7 - describe("AuthController", () => {  
8 -  
9 - it("calls authenticate on AuthService when login called", () => {  
10 -  
11 - // creating a Mock AuthService  
12 - let AuthServiceMock: AuthService = jasmine.createSpyObj("AuthService", ["login"]);  
13 -  
14 - // pass AuthServiceMock into the constructor  
15 - let authController = new AuthController(null, null, AuthServiceMock);  
16 -  
17 - // setup of authController -> set the credentials instance property  
18 - let credentials = { username: "username", password: "password" };  
19 -  
20 - authController.credentials = credentials;  
21 -  
22 - // calls the authController login method  
23 - authController.login();  
24 -  
25 - // checks if the method login of the injected AuthService has been called  
26 - expect(AuthServiceMock.login).toHaveBeenCalledWith(credentials);  
27 -  
28 - });  
29 -  
30 -  
31 -  
32 - });  
33 -});  
src/app/components/auth/auth_controller.ts
@@ -1,21 +0,0 @@ @@ -1,21 +0,0 @@
1 -import {Credentials} from "./../../models/interfaces";  
2 -import {AuthService} from "./auth_service";  
3 -  
4 -export class AuthController {  
5 -  
6 - static $inject = ["$log", "$stateParams", "AuthService"];  
7 -  
8 - constructor(  
9 - private $log: ng.ILogService,  
10 - private $stateParams: any,  
11 - private AuthService: AuthService  
12 - ) {  
13 -  
14 - }  
15 -  
16 - credentials: Credentials;  
17 -  
18 - login() {  
19 - this.AuthService.login(this.credentials);  
20 - }  
21 -}  
src/app/components/auth/auth_events.ts
@@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
1 -export interface IAuthEvents {  
2 - loginSuccess: string;  
3 - loginFailed: string;  
4 - logoutSuccess: string;  
5 -}  
6 -  
7 -export const AUTH_EVENTS: IAuthEvents = {  
8 - loginSuccess: "auth-login-success",  
9 - loginFailed: "auth-login-failed",  
10 - logoutSuccess: "auth-logout-success"  
11 -};  
12 \ No newline at end of file 0 \ No newline at end of file
src/app/components/auth/auth_service.spec.ts
@@ -1,82 +0,0 @@ @@ -1,82 +0,0 @@
1 -  
2 -  
3 -import {AuthService, AUTH_EVENTS} from "./";  
4 -import {User, Credentials} from "./../../models/interfaces";  
5 -  
6 -describe("Services", () => {  
7 -  
8 -  
9 - describe("Auth Service", () => {  
10 -  
11 - let $httpBackend: ng.IHttpBackendService;  
12 - let authService: AuthService;  
13 - let credentials: Credentials;  
14 - let $rootScope: ng.IRootScopeService;  
15 - let user: User;  
16 -  
17 - beforeEach(angular.mock.module("noosferoApp", ($translateProvider: angular.translate.ITranslateProvider) => {  
18 - $translateProvider.translations('en', {});  
19 - }));  
20 -  
21 - beforeEach(inject((_$httpBackend_: ng.IHttpBackendService, _$rootScope_: ng.IRootScopeService, _AuthService_: AuthService) => {  
22 - $httpBackend = _$httpBackend_;  
23 - authService = _AuthService_;  
24 - $rootScope = _$rootScope_;  
25 -  
26 - user = <User>{  
27 - id: 1,  
28 - login: "user"  
29 - };  
30 - }));  
31 -  
32 -  
33 - describe("Succesffull login", () => {  
34 -  
35 - beforeEach(() => {  
36 - credentials = { username: "user", password: "password" };  
37 -  
38 - $httpBackend.expectPOST("/api/v1/login", "login=user&password=password").respond(200, { user: user });  
39 - });  
40 -  
41 - it("should return loggedUser", (done) => {  
42 - authService.login(credentials).then((loggedUser) => {  
43 - expect(loggedUser).toBeDefined();  
44 - done();  
45 - });  
46 - $httpBackend.flush();  
47 - expect($httpBackend.verifyNoOutstandingRequest());  
48 - });  
49 -  
50 -  
51 - it("should emit event loggin successful with user logged data", () => {  
52 -  
53 - authService.login(credentials);  
54 -  
55 - let eventEmmited: boolean = false;  
56 - $rootScope.$on(AUTH_EVENTS.loginSuccess, (event: ng.IAngularEvent, userThroughEvent: User) => {  
57 - eventEmmited = true;  
58 - expect(userThroughEvent).toEqual(user)  
59 - });  
60 -  
61 - $httpBackend.flush();  
62 -  
63 - expect(eventEmmited).toBeTruthy(AUTH_EVENTS.loginSuccess + " was not emmited!");  
64 - });  
65 -  
66 - it("should return the current logged in user", () => {  
67 - authService.login(credentials);  
68 - $httpBackend.flush();  
69 - let actual: User = authService.currentUser();  
70 - expect(actual).toEqual(user, "The returned user must be present");  
71 - });  
72 -  
73 - it("should not return the current user after logout", () => {  
74 - authService.logout();  
75 - let actual: any = authService.currentUser();  
76 - expect(actual).toEqual(undefined, "The returned user must not be defined");  
77 - });  
78 - });  
79 -  
80 -  
81 - });  
82 -});  
src/app/components/auth/auth_service.ts
@@ -1,69 +0,0 @@ @@ -1,69 +0,0 @@
1 -import {Injectable, Inject} from "ng-forward";  
2 -  
3 -import {Credentials, NoosferoRootScope, User, UserResponse} from "./../../models/interfaces";  
4 -import {Session} from "./session";  
5 -  
6 -import {AUTH_EVENTS, IAuthEvents} from "./auth_events";  
7 -  
8 -@Injectable()  
9 -@Inject("$q", "$http", "$rootScope", "Session", "$log", "AUTH_EVENTS")  
10 -export class AuthService {  
11 -  
12 - constructor(private $q: ng.IQService,  
13 - private $http: ng.IHttpService,  
14 - private $rootScope: NoosferoRootScope,  
15 - private session: Session,  
16 - private $log: ng.ILogService,  
17 - private auth_events: IAuthEvents) {  
18 -  
19 - }  
20 -  
21 - loginFromCookie() {  
22 - let url: string = '/api/v1/login_from_cookie';  
23 - return this.$http.post(url, null).then(this.loginSuccessCallback.bind(this), this.loginFailedCallback.bind(this));  
24 - }  
25 -  
26 -  
27 - private loginSuccessCallback(response: ng.IHttpPromiseCallbackArg<UserResponse>) {  
28 - this.$log.debug('AuthService.login [SUCCESS] response', response);  
29 - let currentUser: User = this.session.create(response.data);  
30 - this.$rootScope.currentUser = currentUser;  
31 - this.$rootScope.$broadcast(this.auth_events.loginSuccess, currentUser);  
32 - return currentUser;  
33 - }  
34 -  
35 - login(credentials: Credentials): ng.IPromise<User> {  
36 - let url = '/api/v1/login';  
37 - let encodedData = 'login=' + credentials.username + '&password=' + credentials.password;  
38 - return this.$http.post(url, encodedData).then(this.loginSuccessCallback.bind(this), this.loginFailedCallback.bind(this));  
39 - }  
40 -  
41 - private loginFailedCallback(response: ng.IHttpPromiseCallbackArg<any>): any {  
42 - this.$log.debug('AuthService.login [FAIL] response', response);  
43 - this.$rootScope.$broadcast(this.auth_events.loginFailed);  
44 - // return $q.reject(response);  
45 - return null;  
46 - }  
47 -  
48 - public logout() {  
49 - this.session.destroy();  
50 - this.$rootScope.currentUser = undefined;  
51 - this.$rootScope.$broadcast(this.auth_events.logoutSuccess);  
52 - this.$http.jsonp('/account/logout'); // FIXME logout from noosfero to sync login state  
53 - }  
54 -  
55 - public isAuthenticated() {  
56 - return !!this.session.currentUser();  
57 - }  
58 -  
59 - public currentUser(): User {  
60 - return this.session.currentUser();  
61 - }  
62 -  
63 - public isAuthorized(authorizedRoles: string | string[]) {  
64 - if (!angular.isArray(authorizedRoles)) {  
65 - authorizedRoles = [<string>authorizedRoles];  
66 - }  
67 - return (this.isAuthenticated() && authorizedRoles.indexOf(this.session.currentUser().userRole) !== -1);  
68 - }  
69 -}  
70 \ No newline at end of file 0 \ No newline at end of file
src/app/components/auth/index.ts
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./auth_controller";  
3 -export * from "./auth_events";  
4 -export * from "./auth_service";  
5 -export * from "./session";  
src/app/components/auth/login.html
@@ -1,16 +0,0 @@ @@ -1,16 +0,0 @@
1 -<div class="modal-header">  
2 - <h3 class="modal-title">{{"auth.title" | translate}}</h3>  
3 -</div>  
4 -<div class="modal-body">  
5 - <form>  
6 - <div class="form-group">  
7 - <label for="exampleInputEmail1">{{"auth.form.login" | translate}}</label>  
8 - <input type="text" class="form-control" id="exampleInputEmail1" placeholder="Login / Email" ng-model="vm.credentials.username">  
9 - </div>  
10 - <div class="form-group">  
11 - <label for="exampleInputPassword1">{{"auth.form.password" | translate}}</label>  
12 - <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password" ng-model="vm.credentials.password">  
13 - </div>  
14 - <button type="submit" class="btn btn-default" ng-click="vm.login()">{{"auth.form.login_button" | translate}}</button>  
15 - </form>  
16 -</div>  
src/app/components/auth/session.ts
@@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
1 -import {Injectable, Inject} from "ng-forward";  
2 -import {UserResponse, User, INoosferoLocalStorage} from "./../../models/interfaces";  
3 -  
4 -@Injectable()  
5 -@Inject("$localStorage", "$log")  
6 -export class Session {  
7 -  
8 - constructor(private $localStorage: INoosferoLocalStorage, private $log: ng.ILogService) {  
9 -  
10 - }  
11 -  
12 - create(data: UserResponse): User {  
13 - this.$localStorage.currentUser = data.user;  
14 - this.$log.debug('User session created.', this.$localStorage.currentUser);  
15 - return this.$localStorage.currentUser;  
16 - };  
17 -  
18 - destroy() {  
19 - delete this.$localStorage.currentUser;  
20 - this.$log.debug('User session destroyed.');  
21 - };  
22 -  
23 - currentUser(): User {  
24 - return this.$localStorage.currentUser;  
25 - };  
26 -  
27 -}  
28 \ No newline at end of file 0 \ No newline at end of file
src/app/components/auth/session_spec.ts
@@ -1,49 +0,0 @@ @@ -1,49 +0,0 @@
1 -import {Component} from "ng-forward";  
2 -import {Session} from "./";  
3 -import {fixtures, createComponentFromClass, createProviderToValue} from "./../../../spec/helpers";  
4 -import {UserResponse, User, INoosferoLocalStorage} from "./../../models/interfaces";  
5 -  
6 -  
7 -describe("Services", () => {  
8 -  
9 -  
10 - describe("Session Service", () => {  
11 -  
12 - let $localStorage: INoosferoLocalStorage = null;  
13 - let $log: any;  
14 -  
15 - beforeEach(() => {  
16 - $localStorage = <INoosferoLocalStorage>{ currentUser: null };  
17 - $log = jasmine.createSpyObj('$log', ['debug']);  
18 - });  
19 -  
20 - it("method 'create()' saves the current user on $localstorage service", () => {  
21 - let session = new Session($localStorage, $log);  
22 - let userResponse = <UserResponse>{  
23 - user: fixtures.user  
24 - };  
25 - session.create(userResponse);  
26 - expect($localStorage.currentUser).toEqual(userResponse.user);  
27 - });  
28 -  
29 - it("method 'destroy()' clean the currentUser on $localstorage", () => {  
30 - let session = new Session($localStorage, $log);  
31 - let userResponse = <UserResponse>{  
32 - user: fixtures.user  
33 - };  
34 - $localStorage.currentUser = fixtures.user;  
35 - session.destroy();  
36 - expect($localStorage.currentUser).toBeUndefined();  
37 - });  
38 -  
39 - it("method 'currentUser()' returns the user recorded on $localstorage service", () => {  
40 - let session = new Session($localStorage, $log);  
41 - let userResponse = <UserResponse>{  
42 - user: fixtures.user  
43 - };  
44 - $localStorage.currentUser = fixtures.user;  
45 - expect(session.currentUser()).toEqual($localStorage.currentUser);  
46 - });  
47 - });  
48 -  
49 -});  
50 \ No newline at end of file 0 \ No newline at end of file
src/app/components/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/language-selector/language-selector.component.spec.ts
@@ -1,46 +0,0 @@ @@ -1,46 +0,0 @@
1 -import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {provide} from 'ng-forward';  
3 -  
4 -import {LanguageSelector} from './language-selector.component';  
5 -  
6 -import * as helpers from "../../../spec/helpers";  
7 -  
8 -describe("Components", () => {  
9 -  
10 - describe("Language Selector Component", () => {  
11 -  
12 - beforeEach(angular.mock.module("templates"));  
13 -  
14 - let translatorService: any;  
15 -  
16 - let buildComponent = (): Promise<ComponentFixture> => {  
17 - translatorService = jasmine.createSpyObj("translatorService", ["availableLanguages", "currentLanguage"])  
18 - return helpers.quickCreateComponent({  
19 - template: "<language-selector></language-selector>",  
20 - directives: [LanguageSelector],  
21 - providers: [  
22 - provide('TranslatorService', {  
23 - useValue: translatorService  
24 - })  
25 - ].concat(helpers.provideFilters("translateFilter"))  
26 - });  
27 - }  
28 -  
29 - it("display language options", (done) => {  
30 - buildComponent().then(fixture => {  
31 - fixture.debugElement.getLocal("$rootScope").$apply();  
32 - expect(fixture.debugElement.queryAll('li.language').length).toEqual(2);  
33 - done();  
34 - });  
35 - });  
36 -  
37 - it("call the translator service when change the language", (done) => {  
38 - let translatorService = jasmine.createSpyObj("translatorService", ["changeLanguage"]);  
39 - let languageSelector = new LanguageSelector(<any>translatorService);  
40 - languageSelector.changeLanguage("en");  
41 - expect(translatorService.changeLanguage).toHaveBeenCalledWith("en");  
42 - done();  
43 - });  
44 -  
45 - });  
46 -});  
src/app/components/language-selector/language-selector.component.ts
@@ -1,24 +0,0 @@ @@ -1,24 +0,0 @@
1 -import {Component, Inject} from "ng-forward";  
2 -import {TranslatorService} from "../translator/translator.service";  
3 -  
4 -@Component({  
5 - selector: "language-selector",  
6 - templateUrl: "app/components/language-selector/language-selector.html"  
7 -})  
8 -@Inject(TranslatorService)  
9 -export class LanguageSelector {  
10 -  
11 - constructor(private translatorService: TranslatorService) { }  
12 -  
13 - currentLanguage() {  
14 - return this.translatorService.currentLanguage();  
15 - }  
16 -  
17 - changeLanguage(language: string) {  
18 - this.translatorService.changeLanguage(language);  
19 - }  
20 -  
21 - availableLanguages() {  
22 - return this.translatorService.availableLanguages;  
23 - }  
24 -}  
src/app/components/language-selector/language-selector.html
@@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
1 -<li class="dropdown profile-menu" dropdown>  
2 - <a href="#" class="dropdown-toggle" aria-expanded="false" dropdown-toggle>  
3 - <span>{{"language.selector" | translate}}</span> <b class="caret"></b>  
4 - </a>  
5 - <ul class="dropdown-menu" dropdown-menu>  
6 - <li ng-repeat="(language, description) in ctrl.availableLanguages()"  
7 - class="language language-{{language}}" ng-class="{'active': language==ctrl.currentLanguage()}">  
8 - <a href="#" ng-click="ctrl.changeLanguage(language)">  
9 - {{description}}  
10 - </a>  
11 - </li>  
12 - </ul>  
13 -</li>  
src/app/components/navbar/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./navbar";  
src/app/components/navbar/navbar.directive.spec.js
@@ -1,45 +0,0 @@ @@ -1,45 +0,0 @@
1 -(function() {  
2 - 'use strict';  
3 -  
4 - describe('directive navbar', function() {  
5 - var vm;  
6 - var el;  
7 - var AUTH_EVENTS;  
8 - var $state;  
9 -  
10 - beforeEach(module('angular'));  
11 - beforeEach(inject(function($compile, $rootScope, $httpBackend, _AUTH_EVENTS_, _$state_) {  
12 - $state = _$state_;  
13 - AUTH_EVENTS = _AUTH_EVENTS_;  
14 - $httpBackend.when('POST','/api/v1/login_from_cookie').respond({});  
15 -  
16 - el = angular.element('<acme-navbar></acme-navbar>');  
17 -  
18 - $compile(el)($rootScope.$new());  
19 - $rootScope.$digest();  
20 - vm = el.isolateScope().vm;  
21 - }));  
22 -  
23 - it('should be compiled', function() {  
24 - expect(el.html()).not.toEqual(null);  
25 - });  
26 -  
27 - it('should have isolate scope object with instanciate members', function() {  
28 - expect(vm).toEqual(jasmine.any(Object));  
29 - expect(vm.currentUser).toEqual(undefined);  
30 - });  
31 -  
32 - it('should reload current state after login', function() {  
33 - spyOn($state, 'go');  
34 - el.isolateScope().$broadcast(AUTH_EVENTS.loginSuccess, {});  
35 - expect($state.go).toHaveBeenCalled();  
36 - });  
37 -  
38 - it('should open login when not logged in', function() {  
39 - spyOn(vm, 'openLogin');  
40 - vm.activate();  
41 - expect(vm.openLogin).toHaveBeenCalled();  
42 - });  
43 -  
44 - });  
45 -})();  
src/app/components/navbar/navbar.html
@@ -1,49 +0,0 @@ @@ -1,49 +0,0 @@
1 -<nav class="navbar navbar-static-top navbar-inverse">  
2 - <div class="container-fluid">  
3 - <div class="navbar-header">  
4 - <button type="button" class="navbar-toggle collapsed" ng-click="isCollapsed = !isCollapsed">  
5 - <span class="sr-only">{{"navbar.toggle_menu" | translate}}</span>  
6 - <span class="icon-bar"></span>  
7 - <span class="icon-bar"></span>  
8 - <span class="icon-bar"></span>  
9 - </button>  
10 - <a class="navbar-brand" ui-sref="main">  
11 - <span class="noosfero-logo"><img src="assets/images/logo-noosfero.png"></span> {{"noosfero.name" | translate}}  
12 - </a>  
13 - </div>  
14 -  
15 - <div class="collapse navbar-collapse" id="navbar-collapse" collapse="isCollapsed">  
16 - <ul class="nav navbar-nav">  
17 - </ul>  
18 -  
19 - <ul class="nav navbar-nav navbar-right">  
20 - <li ng-show="!ctrl.currentUser">  
21 - <a ng-href="#" ng-click="ctrl.openLogin()">{{"navbar.login" | translate}}</a>  
22 - </li>  
23 -  
24 - <li class="dropdown profile-menu" ng-show="ctrl.currentUser" dropdown>  
25 - <a href="#" class="dropdown-toggle" aria-expanded="false" dropdown-toggle>  
26 - <noosfero-profile-image [profile]="ctrl.currentUser.person" class="profile-image"></noosfero-profile-image>  
27 - <span ng-bind="ctrl.currentUser.person.name"></span> <b class="caret"></b>  
28 - </a>  
29 - <ul class="dropdown-menu" dropdown-menu>  
30 - <li>  
31 - <a ui-sref="main.profile.info({profile: ctrl.currentUser.person.identifier})"><i class="fa fa-fw fa-user"></i> {{"navbar.profile" | translate}}</a>  
32 - </li>  
33 - <li>  
34 - <a target="_self" ui-sref="main.profile.settings({profile: ctrl.currentUser.person.identifier})"><i class="fa fa-fw fa-gear"></i> {{"navbar.settings" | translate}}</a>  
35 - </li>  
36 - <li class="divider"></li>  
37 - <li>  
38 - <a href="#" ng-click="ctrl.logout()"><i class="fa fa-fw fa-power-off"></i> {{"navbar.logout" | translate}}</a>  
39 - </li>  
40 - </ul>  
41 - </li>  
42 - </ul>  
43 - <ul class="nav navbar-nav navbar-right">  
44 - <language-selector class="nav navbar-nav navbar-right"></language-selector>  
45 - </ul>  
46 - <div ui-view="actions"></div>  
47 - </div>  
48 - </div>  
49 -</nav>  
src/app/components/navbar/navbar.scss
@@ -1,31 +0,0 @@ @@ -1,31 +0,0 @@
1 -.navbar {  
2 -  
3 - .container-fluid {  
4 - padding-right: 12%;  
5 - padding-left: 12%;  
6 - @media (max-width: 978px) {  
7 - padding-right: 2%;  
8 - padding-left: 2%;  
9 - }  
10 -  
11 - .navbar-brand {  
12 - .noosfero-logo img {  
13 - height: 35px;  
14 - }  
15 - }  
16 -  
17 - .navbar-nav {  
18 - .profile-menu .profile-image {  
19 - img {  
20 - height: 30px;  
21 - width: 30px;  
22 - display: inline-block;  
23 - @extend .img-circle;  
24 - }  
25 - i {  
26 - font-size: 1.7em;  
27 - }  
28 - }  
29 - }  
30 - }  
31 -}  
src/app/components/navbar/navbar.spec.ts
@@ -1,188 +0,0 @@ @@ -1,188 +0,0 @@
1 -import * as helpers from "./../../../spec/helpers";  
2 -import {Navbar} from "./navbar";  
3 -import {AUTH_EVENTS} from "./../auth";  
4 -import {User} from "./../../models/interfaces";  
5 -import {Injectable, Provider, provide} from "ng-forward";  
6 -  
7 -import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';  
8 -  
9 -import {Session, AuthService, AuthController, IAuthEvents} from "./../auth";  
10 -  
11 -  
12 -describe("Components", () => {  
13 -  
14 - describe("Navbar Component", () => {  
15 -  
16 - let user: User = null;  
17 - let scope: any;  
18 - let $rootScope: ng.IRootScopeService;  
19 -  
20 - let modalInstance: any;  
21 - let $modal: any;  
22 - let authService: any;  
23 - let stateService: any;  
24 - let sessionService: Session;  
25 -  
26 - let provideFunc = provide;  
27 -  
28 - // before Each -> loading mocks on locals variables  
29 - beforeEach(() => {  
30 - user = <User>{  
31 - id: 1,  
32 - login: "user"  
33 - };  
34 - scope = helpers.mocks.scopeWithEvents;  
35 - modalInstance = helpers.mocks.modalInstance;  
36 - $modal = helpers.mocks.$modal;  
37 - authService = helpers.mocks.authService;  
38 - stateService = jasmine.createSpyObj("$state", ["go"]);  
39 - sessionService = <any>helpers.mocks.sessionWithCurrentUser(user);  
40 - });  
41 -  
42 -  
43 - // loading the templates  
44 - beforeEach(angular.mock.module("templates"));  
45 -  
46 -  
47 - // this function allow build the fixture of the container component  
48 - // and is reused in each test  
49 - // The main idea behing not prebuild it on a general beforeEach block is  
50 - // to allow tests configure the mock services accordilly their own needs  
51 - let buildComponent = (): Promise<ComponentFixture> => {  
52 - return helpers.quickCreateComponent({  
53 - providers: [  
54 - provide('$modal', {  
55 - useValue: $modal  
56 - }),  
57 - provide('AuthService', {  
58 - useValue: authService  
59 - }),  
60 - helpers.provideEmptyObjects('moment'),  
61 - provide('$state', {  
62 - useValue: stateService  
63 - }),  
64 - provide("$scope", {  
65 - useValue: scope  
66 - }),  
67 - provide('Session', {  
68 - useValue: sessionService  
69 - }),  
70 - provide('AUTH_EVENTS', {  
71 - useValue: {  
72 - AUTH_EVENTS  
73 - }  
74 - }),  
75 - provide('TranslatorService', {  
76 - useValue: helpers.mocks.translatorService  
77 - })  
78 - ].concat(helpers.provideFilters("translateFilter")),  
79 - directives: [Navbar],  
80 - template: '<acme-navbar></acme-navbar>'  
81 - });  
82 - }  
83 -  
84 -  
85 - it('should get the loggedIn user', (done: Function) => {  
86 - buildComponent().then((fixture: ComponentFixture) => {  
87 - let navbarInstance: Navbar = fixture.debugElement.componentViewChildren[0].componentInstance;  
88 - expect(navbarInstance).toBeDefined();  
89 - expect(navbarInstance["currentUser"]).toEqual(user);  
90 - done();  
91 - });  
92 - });  
93 -  
94 - it('should open on click', (done: Function) => {  
95 - spyOn($modal, "open");  
96 - buildComponent().then((fixture: ComponentFixture) => {  
97 - let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;  
98 - navbarComp.openLogin();  
99 - expect($modal.open).toHaveBeenCalled();  
100 - expect($modal.open).toHaveBeenCalledWith({  
101 - templateUrl: 'app/components/auth/login.html',  
102 - controller: AuthController,  
103 - controllerAs: 'vm',  
104 - bindToController: true  
105 - });  
106 - done();  
107 - });  
108 - });  
109 -  
110 - it('should logout', (done: Function) => {  
111 - buildComponent().then((fixture: ComponentFixture) => {  
112 - let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;  
113 - spyOn(authService, "logout");  
114 - try {  
115 - navbarComp.logout();  
116 - expect(authService.logout).toHaveBeenCalled();  
117 - done();  
118 - } catch (e) {  
119 - console.error(e);  
120 - fail(e.message);  
121 - done();  
122 - }  
123 - });  
124 - });  
125 -  
126 -  
127 - it('should not activate user when logged in', (done: Function) => {  
128 - buildComponent().then((fixture: ComponentFixture) => {  
129 - let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;  
130 - spyOn(navbarComp, "openLogin");  
131 - navbarComp.activate();  
132 - expect((<any>navbarComp.openLogin).calls.count()).toBe(0);  
133 - done();  
134 - });  
135 - });  
136 -  
137 - it('should activate when user not logged in', (done: Function) => {  
138 - spyOn(sessionService, 'currentUser').and.returnValue(null);  
139 - buildComponent().then((fixture: ComponentFixture) => {  
140 - let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;  
141 - spyOn(navbarComp, "openLogin");  
142 - navbarComp.activate();  
143 - expect(navbarComp.openLogin).toHaveBeenCalled();  
144 - done();  
145 - });  
146 - });  
147 -  
148 -  
149 - it('closes the modal after login', (done: Function) => {  
150 - modalInstance = jasmine.createSpyObj("modalInstance", ["close"]);  
151 - modalInstance.close = jasmine.createSpy("close");  
152 -  
153 - $modal.open = () => {  
154 - return modalInstance;  
155 - };  
156 -  
157 - buildComponent().then((fixture: ComponentFixture) => {  
158 - let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;  
159 - let localScope: ng.IScope = navbarComp["$scope"];  
160 -  
161 - navbarComp.openLogin();  
162 - localScope.$emit(AUTH_EVENTS.loginSuccess);  
163 - expect(modalInstance.close).toHaveBeenCalled();  
164 - done();  
165 - });  
166 - });  
167 -  
168 - it('updates current user on logout', (done: Function) => {  
169 - buildComponent().then((fixture: ComponentFixture) => {  
170 - let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;  
171 - let localScope: ng.IScope = navbarComp["$scope"];  
172 -  
173 - // init navbar currentUser with some user  
174 - navbarComp["currentUser"] = user;  
175 -  
176 - // changes the current User to return null,  
177 - // and emmit the 'logoutSuccess' event  
178 - // just what happens when user logsout  
179 - sessionService.currentUser = () => { return null; };  
180 - localScope.$emit(AUTH_EVENTS.logoutSuccess);  
181 - expect(navbarComp["currentUser"]).toBeNull();  
182 - done();  
183 - });  
184 - });  
185 -  
186 -  
187 - });  
188 -});  
src/app/components/navbar/navbar.ts
@@ -1,67 +0,0 @@ @@ -1,67 +0,0 @@
1 -import {Component, Inject} from "ng-forward";  
2 -import {LanguageSelector} from "../language-selector/language-selector.component";  
3 -  
4 -  
5 -import {Session, AuthService, AuthController, IAuthEvents, AUTH_EVENTS} from "./../auth";  
6 -import {User} from "./../../models/interfaces";  
7 -  
8 -@Component({  
9 - selector: "acme-navbar",  
10 - templateUrl: "app/components/navbar/navbar.html",  
11 - directives: [LanguageSelector],  
12 - providers: [AuthService, Session]  
13 -})  
14 -@Inject("$modal", AuthService, "Session", "$scope", "$state")  
15 -export class Navbar {  
16 -  
17 - private currentUser: User;  
18 - private modalInstance: any = null;  
19 - /**  
20 - *  
21 - */  
22 - constructor(  
23 - private $modal: any,  
24 - private authService: AuthService,  
25 - private session: Session,  
26 - private $scope: ng.IScope,  
27 - private $state: ng.ui.IStateService  
28 - ) {  
29 - this.currentUser = this.session.currentUser();  
30 -  
31 - this.$scope.$on(AUTH_EVENTS.loginSuccess, () => {  
32 - if (this.modalInstance) {  
33 - this.modalInstance.close();  
34 - this.modalInstance = null;  
35 - }  
36 -  
37 - this.$state.go(this.$state.current, {}, { reload: true }); // TODO move to auth  
38 - });  
39 -  
40 - this.$scope.$on(AUTH_EVENTS.logoutSuccess, () => {  
41 - this.currentUser = this.session.currentUser();  
42 - });  
43 - }  
44 -  
45 - openLogin() {  
46 - this.modalInstance = this.$modal.open({  
47 - templateUrl: 'app/components/auth/login.html',  
48 - controller: AuthController,  
49 - controllerAs: 'vm',  
50 - bindToController: true  
51 - });  
52 - };  
53 -  
54 - logout() {  
55 - this.authService.logout();  
56 - this.$state.go(this.$state.current, {}, { reload: true }); // TODO move to auth  
57 - };  
58 -  
59 -  
60 -  
61 - activate() {  
62 - if (!this.currentUser) {  
63 - this.openLogin();  
64 - }  
65 - }  
66 -  
67 -}  
src/app/components/noosfero-activities/activities.component.spec.ts
@@ -1,36 +0,0 @@ @@ -1,36 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Pipe, Input, provide, Component} from 'ng-forward';  
3 -import {provideFilters} from '../../../spec/helpers';  
4 -  
5 -import {NoosferoActivities} from './activities.component';  
6 -  
7 -const tcb = new TestComponentBuilder();  
8 -  
9 -const htmlTemplate: string = '<noosfero-activities [activities]="ctrl.activities"></noosfero-activities>';  
10 -  
11 -  
12 -describe("Components", () => {  
13 -  
14 - describe("Noosfero Activities", () => {  
15 -  
16 - beforeEach(angular.mock.module("templates"));  
17 -  
18 - @Component({  
19 - selector: 'test-container-component',  
20 - template: htmlTemplate,  
21 - directives: [NoosferoActivities],  
22 - providers: provideFilters("truncateFilter", "stripTagsFilter", "translateFilter")  
23 - })  
24 - class BlockContainerComponent {  
25 - activities = [{ name: "activity1", verb: "create_article" }, { name: "activity2", verb: "create_article" }];  
26 - }  
27 -  
28 - it("render a noosfero activity tag for each activity", done => {  
29 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
30 - expect(fixture.debugElement.queryAll("noosfero-activity").length).toEqual(2);  
31 - done();  
32 - });  
33 - });  
34 - });  
35 -  
36 -});  
src/app/components/noosfero-activities/activities.component.ts
@@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
1 -import {Component, Input} from "ng-forward";  
2 -import {NoosferoActivity} from "./activity/activity.component";  
3 -import {Activity} from "../../models/interfaces";  
4 -  
5 -/**  
6 - * @ngdoc controller  
7 - * @name NoosferoActivities  
8 - * @description  
9 - * The controller responsible to retreive profile activities.  
10 - */  
11 -  
12 -@Component({  
13 - selector: "noosfero-activities",  
14 - templateUrl: 'app/components/noosfero-activities/activities.html',  
15 - directives: [NoosferoActivity]  
16 -})  
17 -export class NoosferoActivities {  
18 -  
19 - /**  
20 - * @ngdoc property  
21 - * @propertyOf NoosferoActivities  
22 - * @name activities  
23 - * @returns {Activity[]} An array of {@link Activity}.  
24 - */  
25 - @Input() activities: Activity[];  
26 -  
27 -}  
src/app/components/noosfero-activities/activities.html
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -<timeline>  
2 - <timeline-event ng-repeat="activity in ctrl.activities | orderBy: 'created_at':true">  
3 - <noosfero-activity [activity]="activity"></noosfero-activity>  
4 - </timeline-event>  
5 -</timeline>  
src/app/components/noosfero-activities/activities.scss
@@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
1 -.comma-separated {  
2 - .separated-item {  
3 - &:after {  
4 - content: ", ";  
5 - margin-left: -3px;  
6 - }  
7 - &:last-child:after {  
8 - content: "";  
9 - }  
10 - }  
11 -}  
src/app/components/noosfero-activities/activity/activity.component.spec.ts
@@ -1,38 +0,0 @@ @@ -1,38 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Pipe, Input, provide, Component} from 'ng-forward';  
3 -import {provideFilters} from '../../../../spec/helpers';  
4 -  
5 -import {NoosferoActivity} from './activity.component';  
6 -  
7 -const tcb = new TestComponentBuilder();  
8 -  
9 -const htmlTemplate: string = '<noosfero-activity [activity]="ctrl.activity"></noosfero-activity>';  
10 -  
11 -  
12 -describe("Components", () => {  
13 -  
14 - describe("Noosfero Activity", () => {  
15 -  
16 - beforeEach(angular.mock.module("templates"));  
17 -  
18 - @Component({  
19 - selector: 'test-container-component',  
20 - template: htmlTemplate,  
21 - directives: [NoosferoActivity],  
22 - providers: provideFilters("truncateFilter", "stripTagsFilter", "translateFilter")  
23 - })  
24 - class BlockContainerComponent {  
25 - activity = { name: "activity1", verb: "create_article" };  
26 - }  
27 -  
28 - it("render the specific template for an activity verb", done => {  
29 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
30 - let component: NoosferoActivity = fixture.debugElement.componentViewChildren[0].componentInstance;  
31 - expect(component.getActivityTemplate()).toEqual('app/components/noosfero-activities/activity/create_article.html');  
32 - expect(fixture.debugElement.queryAll(".activity.create_article").length).toEqual(1);  
33 - done();  
34 - });  
35 - });  
36 - });  
37 -  
38 -});  
src/app/components/noosfero-activities/activity/activity.component.ts
@@ -1,16 +0,0 @@ @@ -1,16 +0,0 @@
1 -import {Component, Input} from "ng-forward";  
2 -import {Activity} from "../../../models/interfaces";  
3 -  
4 -@Component({  
5 - selector: "noosfero-activity",  
6 - templateUrl: 'app/components/noosfero-activities/activity/activity.html'  
7 -})  
8 -export class NoosferoActivity {  
9 -  
10 - @Input() activity: Activity;  
11 -  
12 - getActivityTemplate() {  
13 - return 'app/components/noosfero-activities/activity/' + this.activity.verb + '.html';  
14 - }  
15 -  
16 -}  
src/app/components/noosfero-activities/activity/activity.html
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -<div class="activity {{ctrl.activity.verb}}">  
2 - <ng-include src="ctrl.getActivityTemplate()"></ng-include>  
3 -</div>  
src/app/components/noosfero-activities/activity/add_member_in_community.html
@@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
1 -<timeline-badge class="info">  
2 - <i class="fa fa-user-plus"></i>  
3 -</timeline-badge>  
4 -<timeline-panel>  
5 - <timeline-heading>  
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>  
8 - <span> {{"activities.add_member_in_community.description" | translate}}</span>  
9 - </h4>  
10 - <p><small class="text-muted"><i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.activity.created_at | dateFormat"></span></small></p>  
11 - </timeline-heading>  
12 - <div class="timeline-body"></div>  
13 -</timeline-panel>  
src/app/components/noosfero-activities/activity/create_article.html
@@ -1,26 +0,0 @@ @@ -1,26 +0,0 @@
1 -<timeline-badge class="success">  
2 - <i class="fa fa-file-text"></i>  
3 -</timeline-badge>  
4 -<timeline-panel>  
5 - <timeline-heading>  
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>  
8 - <span> {{"activities.create_article.description" | translate}} </span>  
9 - <a ui-sref="main.profile.info({profile: ctrl.activity.target.article.profile.identifier})">  
10 - <strong ng-bind="ctrl.activity.target.article.profile.name"></strong></span>  
11 - </a>  
12 - </h4>  
13 - <p><small class="text-muted"><i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.activity.created_at | dateFormat"></span></small></p>  
14 - </timeline-heading>  
15 - <div class="timeline-body">  
16 - <div class="article">  
17 - <div class="title">  
18 - <a ui-sref="main.profile.page({profile: ctrl.activity.target.article.profile.identifier, page: ctrl.activity.target.article.path})"  
19 - ng-bind="ctrl.activity.target.article.title"></a>  
20 - </div>  
21 - <div class="lead small">  
22 - <div ng-bind-html="ctrl.activity.target.article.body | stripTags | truncate: 100 : '...': true"></div>  
23 - </div>  
24 - </div>  
25 - </div>  
26 -</timeline-panel>  
src/app/components/noosfero-activities/activity/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero-activities/activity/new_friendship.html
@@ -1,18 +0,0 @@ @@ -1,18 +0,0 @@
1 -<timeline-badge class="info">  
2 - <i class="fa fa-user-plus"></i>  
3 -</timeline-badge>  
4 -<timeline-panel>  
5 - <timeline-heading>  
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>  
8 - <span> {{"activities.new_friendship.description" | translate:{friends: ctrl.activity.params.friend_name.length}:"messageformat" }} </span>  
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">  
11 - <strong ng-bind="friend"></strong>  
12 - </a>  
13 - </span>  
14 - </h4>  
15 - <p><small class="text-muted"><i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.activity.created_at | dateFormat"></span></small></p>  
16 - </timeline-heading>  
17 - <div class="timeline-body"></div>  
18 -</timeline-panel>  
src/app/components/noosfero-activities/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero-articles/article/article.html
@@ -1,23 +0,0 @@ @@ -1,23 +0,0 @@
1 -<div class="article">  
2 - <div class="page-header">  
3 - <h3 ng-bind="ctrl.article.title"></h3>  
4 - </div>  
5 -  
6 - <div class="sub-header clearfix">  
7 - <div class="page-info pull-right small text-muted">  
8 - <span class="time">  
9 - <i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.article.created_at | dateFormat"></span>  
10 - </span>  
11 - <span class="author" ng-if="ctrl.article.author">  
12 - <i class="fa fa-user"></i>  
13 - <a ui-sref="main.profile.home({profile: ctrl.article.author.identifier})">  
14 - <span class="author-name" ng-bind="ctrl.article.author.name"></span>  
15 - </a>  
16 - </span>  
17 - </div>  
18 - </div>  
19 -  
20 - <div class="page-body">  
21 - <div ng-bind-html="ctrl.article.body"></div>  
22 - </div>  
23 -</div>  
src/app/components/noosfero-articles/article/article.scss
@@ -1,17 +0,0 @@ @@ -1,17 +0,0 @@
1 -.article {  
2 - .page-info {  
3 - .author {  
4 - a {  
5 - color: #b4bcc2;  
6 - }  
7 - }  
8 - }  
9 -  
10 - .page-header {  
11 - margin-bottom: 5px;  
12 - }  
13 -  
14 - .sub-header {  
15 - margin-bottom: 20px;  
16 - }  
17 -}  
src/app/components/noosfero-articles/article/article_view.spec.ts
@@ -1,108 +0,0 @@ @@ -1,108 +0,0 @@
1 -  
2 -import {Input, provide, Component} from 'ng-forward';  
3 -import {ArticleView, ArticleDefaultView} from './article_view';  
4 -  
5 -import {createComponentFromClass, quickCreateComponent} from "../../../../spec/helpers";  
6 -  
7 -// this htmlTemplate will be re-used between the container components in this spec file  
8 -const htmlTemplate: string = '<noosfero-article [article]="ctrl.article" [profile]="ctrl.profile"></noosfero-article>';  
9 -  
10 -  
11 -describe("Components", () => {  
12 -  
13 - describe("ArticleView Component", () => {  
14 -  
15 - // the karma preprocessor html2js transform the templates html into js files which put  
16 - // the templates to the templateCache into the module templates  
17 - // we need to load the module templates here as the template for the  
18 - // component Noosfero ArtileView will be load on our tests  
19 - beforeEach(angular.mock.module("templates"));  
20 -  
21 - it("renders the default component when no specific component is found", (done: Function) => {  
22 - // Creating a container component (ArticleContainerComponent) to include  
23 - // the component under test (ArticleView)  
24 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [ArticleView] })  
25 - class ArticleContainerComponent {  
26 - article = { type: 'anyArticleType' };  
27 - profile = { name: 'profile-name' };  
28 - constructor() {  
29 - }  
30 - }  
31 -  
32 - createComponentFromClass(ArticleContainerComponent).then((fixture) => {  
33 - // and here we can inspect and run the test assertions  
34 -  
35 - // gets the children component of ArticleContainerComponent  
36 - let articleView: ArticleView = fixture.debugElement.componentViewChildren[0].componentInstance;  
37 -  
38 - // and checks if the article View rendered was the Default Article View  
39 - expect(articleView.constructor.prototype).toEqual(ArticleDefaultView.prototype);  
40 -  
41 - // done needs to be called (it isn't really needed, as we can read in  
42 - // here (https://github.com/ngUpgraders/ng-forward/blob/master/API.md#createasync)  
43 - // because createAsync in ng-forward is not really async, but as the intention  
44 - // here is write tests in angular 2 ways, this is recommended  
45 - done();  
46 - });  
47 -  
48 - });  
49 -  
50 - it("receives the article and profile as inputs", (done: Function) => {  
51 -  
52 - // Creating a container component (ArticleContainerComponent) to include  
53 - // the component under test (ArticleView)  
54 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [ArticleView] })  
55 - class ArticleContainerComponent {  
56 - article = { type: 'anyArticleType' };  
57 - profile = { name: 'profile-name' };  
58 - constructor() {  
59 - }  
60 - }  
61 -  
62 - // uses the TestComponentBuilder instance to initialize the component  
63 - createComponentFromClass(ArticleContainerComponent).then((fixture) => {  
64 - // and here we can inspect and run the test assertions  
65 - let articleView: ArticleView = fixture.debugElement.componentViewChildren[0].componentInstance;  
66 -  
67 - // assure the article object inside the ArticleView matches  
68 - // the provided through the parent component  
69 - expect(articleView.article.type).toEqual("anyArticleType");  
70 - expect(articleView.profile.name).toEqual("profile-name");  
71 -  
72 - // done needs to be called (it isn't really needed, as we can read in  
73 - // here (https://github.com/ngUpgraders/ng-forward/blob/master/API.md#createasync)  
74 - // because createAsync in ng-forward is not really async, but as the intention  
75 - // here is write tests in angular 2 ways, this is recommended  
76 - done();  
77 - });  
78 - });  
79 -  
80 -  
81 - it("renders a article view which matches to the article type", done => {  
82 - // NoosferoTinyMceArticle component created to check if it will be used  
83 - // when a article with type 'TinyMceArticle' is provided to the noosfero-article (ArticleView)  
84 - // *** Important *** - the selector is what ng-forward uses to define the name of the directive provider  
85 - @Component({ selector: 'noosfero-tiny-mce-article', template: "<h1>TinyMceArticle</h1>" })  
86 - class TinyMceArticleView {  
87 - @Input() article: any;  
88 - @Input() profile: any;  
89 - }  
90 -  
91 - // Creating a container component (ArticleContainerComponent) to include our NoosferoTinyMceArticle  
92 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [ArticleView, TinyMceArticleView] })  
93 - class CustomArticleType {  
94 - article = { type: 'TinyMceArticle' };  
95 - profile = { name: 'profile-name' };  
96 - constructor() {  
97 - }  
98 - }  
99 - createComponentFromClass(CustomArticleType).then(fixture => {  
100 - let myComponent: CustomArticleType = fixture.componentInstance;  
101 - expect(myComponent.article.type).toEqual("TinyMceArticle");  
102 - expect(fixture.debugElement.componentViewChildren[0].text()).toEqual("TinyMceArticle");  
103 - done();  
104 - });  
105 - });  
106 -  
107 - });  
108 -});  
109 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-articles/article/article_view.ts
@@ -1,57 +0,0 @@ @@ -1,57 +0,0 @@
1 -import { bundle, Input, Inject, Component, Directive } from 'ng-forward';  
2 -import {ArticleBlog} from "../blog/blog.component";  
3 -  
4 -/**  
5 - * @ngdoc controller  
6 - * @name ArticleDefaultView  
7 - * @description  
8 - * A default view for Noosfero Articles. If the specific article view is  
9 - * not implemented, then this view is used.  
10 - */  
11 -@Component({  
12 - selector: 'noosfero-default-article',  
13 - templateUrl: 'app/components/noosfero-articles/article/article.html'  
14 -})  
15 -export class ArticleDefaultView {  
16 -  
17 - @Input() article: any;  
18 - @Input() profile: any;  
19 -  
20 -}  
21 -  
22 -/**  
23 - * @ngdoc controller  
24 - * @name ArticleView  
25 - * @description  
26 - * A dynamic view for articles. It uses the article type to replace  
27 - * the default template with the custom article directive.  
28 - */  
29 -@Component({  
30 - selector: 'noosfero-article',  
31 - template: 'not-used',  
32 - directives: [ArticleDefaultView, ArticleBlog]  
33 -})  
34 -@Inject("$element", "$scope", "$injector", "$compile")  
35 -export class ArticleView {  
36 -  
37 - @Input() article: any;  
38 - @Input() profile: any;  
39 - directiveName: string;  
40 -  
41 - ngOnInit() {  
42 - let specificDirective = 'noosfero' + this.article.type;  
43 - this.directiveName = "noosfero-default-article";  
44 - if (this.$injector.has(specificDirective + 'Directive')) {  
45 - this.directiveName = specificDirective.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();  
46 - }  
47 - this.$element.replaceWith(this.$compile('<' + this.directiveName + ' [article]="ctrl.article" [profile]="ctrl.profile"></' + this.directiveName + '>')(this.$scope));  
48 - }  
49 -  
50 - constructor(  
51 - private $element: any,  
52 - private $scope: ng.IScope,  
53 - private $injector: ng.auto.IInjectorService,  
54 - private $compile: ng.ICompileService) {  
55 -  
56 - }  
57 -}  
src/app/components/noosfero-articles/article/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./article_view";  
src/app/components/noosfero-articles/blog/blog.component.spec.ts
@@ -1,132 +0,0 @@ @@ -1,132 +0,0 @@
1 -import {  
2 - providers  
3 -} from 'ng-forward/cjs/testing/providers';  
4 -  
5 -import {  
6 - Input,  
7 - Component  
8 -} from 'ng-forward';  
9 -import {  
10 - ArticleBlog  
11 -} from './blog.component';  
12 -  
13 -import {  
14 - createComponentFromClass,  
15 - quickCreateComponent,  
16 - provideEmptyObjects,  
17 - createProviderToValue,  
18 - provideFilters  
19 -} from "../../../../spec/helpers.ts";  
20 -  
21 -// this htmlTemplate will be re-used between the container components in this spec file  
22 -const htmlTemplate: string = '<noosfero-blog [article]="ctrl.article" [profile]="ctrl.profile"></noosfero-blog>';  
23 -  
24 -describe("Blog Component", () => {  
25 -  
26 - function promiseResultTemplate(response ? : {}) {  
27 - let thenFuncEmpty = (func: Function) => {  
28 - // does nothing  
29 - };  
30 - if (response) {  
31 - return {  
32 - then: (func: (response: any) => void) => {  
33 - func(response);  
34 - }  
35 - };  
36 - } else {  
37 - return {  
38 - then: (func: (response: any) => void) => {  
39 - // does nothing  
40 - }  
41 - };  
42 - }  
43 - }  
44 -  
45 - let articleService = {  
46 - getChildren: (article_id: number, filters: {}) => {  
47 - return promiseResultTemplate(null);  
48 - }  
49 - };  
50 -  
51 - @Component({  
52 - selector: 'test-container-component',  
53 - template: htmlTemplate,  
54 - directives: [ArticleBlog],  
55 - providers: [  
56 - provideEmptyObjects('Restangular'),  
57 - createProviderToValue('ArticleService', articleService),  
58 - provideFilters('truncateFilter')  
59 - ]  
60 - })  
61 - class BlogContainerComponent {  
62 - article = {  
63 - type: 'anyArticleType'  
64 - };  
65 - profile = {  
66 - name: 'profile-name'  
67 - };  
68 - }  
69 -  
70 - beforeEach(() => {  
71 -  
72 - // the karma preprocessor html2js transform the templates html into js files which put  
73 - // the templates to the templateCache into the module templates  
74 - // we need to load the module templates here as the template for the  
75 - // component Noosfero ArtileView will be load on our tests  
76 - angular.mock.module("templates")  
77 -  
78 - providers((provide: any) => {  
79 - return <any > [  
80 - provide('ArticleService', {  
81 - useValue: articleService  
82 - })  
83 - ]  
84 - });  
85 - });  
86 -  
87 - it("renders the blog content", (done: Function) => {  
88 -  
89 - createComponentFromClass(BlogContainerComponent).then((fixture) => {  
90 -  
91 - expect(fixture.debugElement.query('div.blog').length).toEqual(1);  
92 -  
93 - done();  
94 - });  
95 - });  
96 -  
97 - it("verify the blog data", (done: Function) => {  
98 -  
99 - // defining a mock result to articleService.getChildren method  
100 - 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 - });  
112 - };  
113 -  
114 - createComponentFromClass(BlogContainerComponent).then((fixture) => {  
115 -  
116 - // gets the children component of BlogContainerComponent  
117 - let articleBlog: BlogContainerComponent = fixture.debugElement.componentViewChildren[0].componentInstance;  
118 -  
119 - // check if the component property are the provided by the mocked articleService  
120 - let post = {  
121 - id: 1,  
122 - title: 'The article test'  
123 - };  
124 - expect(( < any > articleBlog)["posts"][0]).toEqual(jasmine.objectContaining(post));  
125 - expect(( < any > articleBlog)["totalPosts"]).toEqual(1);  
126 -  
127 - done();  
128 - });  
129 -  
130 - });  
131 -  
132 -});  
133 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-articles/blog/blog.component.ts
@@ -1,48 +0,0 @@ @@ -1,48 +0,0 @@
1 -import {Component, Input, Inject} from "ng-forward";  
2 -  
3 -import {Article, Profile} from "./../../../models/interfaces";  
4 -import {ArticleService} from "../../../../lib/ng-noosfero-api/http/article.service";  
5 -  
6 -/**  
7 - * @ngdoc controller  
8 - * @name ArticleBlog  
9 - * @description  
10 - * An specific {@link ArticleView} for Blog articles.  
11 - */  
12 -@Component({  
13 - selector: "noosfero-blog",  
14 - templateUrl: "app/components/noosfero-articles/blog/blog.html"  
15 -})  
16 -@Inject(ArticleService)  
17 -export class ArticleBlog {  
18 -  
19 - @Input() article: Article;  
20 - @Input() profile: Profile;  
21 -  
22 - private posts: any[];  
23 - private perPage: number = 3;  
24 - private currentPage: number;  
25 - private totalPosts: number = 0;  
26 -  
27 - constructor(private articleService: ArticleService) { }  
28 -  
29 - ngOnInit() {  
30 - this.loadPage();  
31 - }  
32 -  
33 - loadPage() {  
34 - let filters = {  
35 - content_type: "TinyMceArticle",  
36 - per_page: this.perPage,  
37 - page: this.currentPage  
38 - };  
39 -  
40 - this.articleService  
41 - .getChildren(this.article.id, filters)  
42 - .then((response: restangular.IResponse) => {  
43 - this.totalPosts = <number>(<any>response.headers("total"));  
44 - this.posts = response.data.articles;  
45 - });  
46 - }  
47 -  
48 -}  
src/app/components/noosfero-articles/blog/blog.html
@@ -1,24 +0,0 @@ @@ -1,24 +0,0 @@
1 -<div class="blog">  
2 - <div class="blog-cover" ng-show="ctrl.article.image">  
3 - <img ng-src="{{ctrl.article.image.url}}" class="img-responsive">  
4 - <h3 ng-bind="ctrl.article.title"></h3>  
5 - </div>  
6 -  
7 - <div class="page-header" ng-show="!ctrl.article.image">  
8 - <h3 ng-bind="ctrl.article.title"></h3>  
9 - </div>  
10 -  
11 - <div>  
12 - <div ng-repeat="child in ctrl.posts | orderBy: 'created_at':true">  
13 - <div class="page-header">  
14 - <a class="title" ui-sref="main.profile.page({profile: ctrl.profile.identifier, page: child.path})"><h4 ng-bind="child.title"></h4></a>  
15 - <div class="post-lead" ng-bind-html="child.body | truncate: 500: '...': true"></div>  
16 - </div>  
17 - </div>  
18 - </div>  
19 -  
20 - <pagination ng-model="ctrl.currentPage" total-items="ctrl.totalPosts" class="pagination-sm center-block"  
21 - boundary-links="true" items-per-page="ctrl.perPage" ng-change="ctrl.loadPage()"  
22 - first-text="«" last-text="»" previous-text="‹" next-text="›">  
23 - </pagination>  
24 -</div>  
src/app/components/noosfero-articles/blog/blog.scss
@@ -1,15 +0,0 @@ @@ -1,15 +0,0 @@
1 -.blog {  
2 - .blog-cover {  
3 - margin: -15px;  
4 - position: relative;  
5 - h3 {  
6 - position: absolute;  
7 - bottom: 0;  
8 - background-color: rgba(0, 0, 0, 0.4);  
9 - color: white;  
10 - padding: 10px 15px;  
11 - margin: 0;  
12 - width: 100%;  
13 - }  
14 - }  
15 -}  
src/app/components/noosfero-articles/blog/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./blog.component";  
src/app/components/noosfero-articles/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero-blocks/block.component.spec.ts
@@ -1,91 +0,0 @@ @@ -1,91 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Input, provide, Component} from 'ng-forward';  
3 -  
4 -import {Block} from './block.component';  
5 -  
6 -const tcb = new TestComponentBuilder();  
7 -  
8 -const htmlTemplate: string = '<noosfero-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-block>';  
9 -  
10 -describe("Components", () => {  
11 - describe("Block Component", () => {  
12 -  
13 - // the karma preprocessor html2js transform the templates html into js files which put  
14 - // the templates to the templateCache into the module templates  
15 - // we need to load the module templates here as the template for the  
16 - // component Block will be load on our tests  
17 - beforeEach(angular.mock.module("templates"));  
18 -  
19 - it("receives the block and the owner as inputs", done => {  
20 -  
21 - // Creating a container component (BlockContainerComponent) to include  
22 - // the component under test (Block)  
23 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [Block] })  
24 - class BlockContainerComponent {  
25 - block = { type: 'Block' };  
26 - owner = { name: 'profile-name' };  
27 - constructor() {  
28 - }  
29 - }  
30 -  
31 - // uses the TestComponentBuilder instance to initialize the component  
32 - tcb  
33 - .createAsync(BlockContainerComponent).then(fixture => {  
34 - // and here we can inspect and run the test assertions  
35 - let myComponent: Block = fixture.componentInstance;  
36 -  
37 - // assure the block object inside the Block matches  
38 - // the provided through the parent component  
39 - expect(myComponent.block.type).toEqual("Block");  
40 - expect(myComponent.owner.name).toEqual("profile-name");  
41 - done();  
42 - });  
43 - });  
44 -  
45 -  
46 - it("renders a component which matches to the block type", done => {  
47 - // CustomBlock component created to check if it will be used  
48 - // when a block with type 'CustomBlock' is provided to the noosfero-block (Block)  
49 - // *** Important *** - the selector is what ng-forward uses to define the name of the directive provider  
50 - @Component({ selector: 'noosfero-custom-block', template: "<h1>My Custom Block</h1>" })  
51 - class CustomBlock {  
52 - @Input() block: any;  
53 - @Input() owner: any;  
54 - }  
55 -  
56 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [Block, CustomBlock] })  
57 - class CustomBlockType {  
58 - block = { type: 'CustomBlock' };  
59 - owner = { name: 'profile-name' };  
60 - constructor() {  
61 - }  
62 - }  
63 - tcb  
64 - .createAsync(CustomBlockType).then(fixture => {  
65 - let myComponent: CustomBlockType = fixture.componentInstance;  
66 - expect(myComponent.block.type).toEqual("CustomBlock");  
67 - expect(fixture.debugElement.componentViewChildren[0].text()).toEqual("My Custom Block");  
68 - done();  
69 - });  
70 - });  
71 -  
72 -  
73 - it("renders the default block when hasn't defined a block type", done => {  
74 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [Block] })  
75 - class CustomBlockType {  
76 - block: any = { type: null };  
77 - owner: any = { name: 'profile-name' };  
78 - constructor() {  
79 - }  
80 - }  
81 - tcb  
82 - .createAsync(CustomBlockType).then(fixture => {  
83 - let myComponent: CustomBlockType = fixture.componentInstance;  
84 - expect(myComponent.block.type).toBeNull();  
85 - expect(!!fixture.debugElement.nativeElement.querySelector("noosfero-default-block")).toBeTruthy();  
86 - done();  
87 - });  
88 - });  
89 -  
90 - });  
91 -});  
92 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-blocks/block.component.ts
@@ -1,20 +0,0 @@ @@ -1,20 +0,0 @@
1 -import { Input, Inject, Component } from 'ng-forward';  
2 -  
3 -@Component({  
4 - selector: 'noosfero-block',  
5 - template: '<div></div>'  
6 -})  
7 -@Inject("$element", "$scope", "$injector", "$compile")  
8 -export class Block {  
9 -  
10 - @Input() block: any;  
11 - @Input() owner: any;  
12 -  
13 - ngOnInit() {  
14 - let blockName = (this.block && this.block.type) ? this.block.type.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase() : "default-block";  
15 - this.$element.replaceWith(this.$compile('<noosfero-' + blockName + ' [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-' + blockName + '>')(this.$scope));  
16 - }  
17 -  
18 - constructor(private $element: any, private $scope: ng.IScope, private $injector: ng.auto.IInjectorService, private $compile: ng.ICompileService) {  
19 - }  
20 -}  
src/app/components/noosfero-blocks/block.scss
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -.block {  
2 - .panel-title {  
3 - font-size: 15px;  
4 - font-weight: bold;  
5 - }  
6 - .panel-heading {  
7 - background-color: transparent;  
8 - border: 0;  
9 - }  
10 -}  
src/app/components/noosfero-blocks/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./block.component";  
src/app/components/noosfero-blocks/link-list/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./link-list.component";  
src/app/components/noosfero-blocks/link-list/link-list.component.spec.ts
@@ -1,65 +0,0 @@ @@ -1,65 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Pipe, Input, provide, Component} from 'ng-forward';  
3 -import {provideFilters} from '../../../../spec/helpers';  
4 -  
5 -import {LinkListBlock} from './link-list.component';  
6 -  
7 -const tcb = new TestComponentBuilder();  
8 -  
9 -const htmlTemplate: string = '<noosfero-link-list-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-link-list-block>';  
10 -  
11 -  
12 -describe("Components", () => {  
13 -  
14 - describe("Link List Block Component", () => {  
15 -  
16 - beforeEach(angular.mock.module("templates"));  
17 -  
18 - it("receives the block and the owner as inputs", done => {  
19 -  
20 - // Creating a container component (BlockContainerComponent) to include  
21 - // the component under test (Block)  
22 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [LinkListBlock] })  
23 - class BlockContainerComponent {  
24 - block = { type: 'Block' };  
25 - owner = { name: 'profile-name' };  
26 - constructor() {  
27 - }  
28 - }  
29 -  
30 - // uses the TestComponentBuilder instance to initialize the component  
31 - //.overrideView(LinkListBlock, { template: 'asdasdasd', pipes: [NoosferoTemplate] })  
32 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
33 - // and here we can inspect and run the test assertions  
34 - let myComponent: LinkListBlock = fixture.componentInstance;  
35 -  
36 - // assure the block object inside the Block matches  
37 - // the provided through the parent component  
38 - expect(myComponent.block.type).toEqual("Block");  
39 - expect(myComponent.owner.name).toEqual("profile-name");  
40 - done();  
41 - });  
42 - });  
43 -  
44 -  
45 - it("display links stored in block settings", done => {  
46 -  
47 - @Component({  
48 - selector: 'test-container-component',  
49 - template: htmlTemplate,  
50 - directives: [LinkListBlock],  
51 - providers: provideFilters("noosferoTemplateFilter")  
52 - })  
53 - class CustomBlockType {  
54 - block: any = { settings: { links: [{ name: 'link1', address: 'address1' }, { name: 'link2', address: 'address2' }] } };  
55 - owner: any = { name: 'profile-name' };  
56 - }  
57 - tcb.createAsync(CustomBlockType).then(fixture => {  
58 - expect(fixture.debugElement.queryAll(".link-list-block a").length).toEqual(2);  
59 - done();  
60 - });  
61 - });  
62 -  
63 - });  
64 -  
65 -});  
66 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-blocks/link-list/link-list.component.ts
@@ -1,20 +0,0 @@ @@ -1,20 +0,0 @@
1 -import {Component, Input} from "ng-forward";  
2 -  
3 -@Component({  
4 - selector: "noosfero-link-list-block",  
5 - templateUrl: "app/components/noosfero-blocks/link-list/link-list.html"  
6 -})  
7 -export class LinkListBlock {  
8 -  
9 - @Input() block: any;  
10 - @Input() owner: any;  
11 -  
12 - links: any;  
13 -  
14 - ngOnInit() {  
15 - if (this.block && this.block.settings) {  
16 - this.links = this.block.settings.links;  
17 - }  
18 - }  
19 -  
20 -}  
src/app/components/noosfero-blocks/link-list/link-list.html
@@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
1 -<div class="link-list-block">  
2 - <div ng-repeat="link in ctrl.links">  
3 - <a ng-href="{{link.address | noosferoTemplate:{profile: ctrl.owner.identifier} }}">  
4 - <i class="fa fa-fw icon-{{link.icon}}"></i> <span>{{link.name}}</span>  
5 - </a>  
6 - </div>  
7 -</div>  
src/app/components/noosfero-blocks/link-list/link-list.scss
@@ -1,34 +0,0 @@ @@ -1,34 +0,0 @@
1 -.icon-event {  
2 - @extend .fa-calendar;  
3 -}  
4 -.icon-photos {  
5 - @extend .fa-photo;  
6 -}  
7 -.icon-edit {  
8 - @extend .fa-edit;  
9 -}  
10 -.icon-ok {  
11 - @extend .fa-check;  
12 -}  
13 -.icon-send {  
14 - @extend .fa-send-o;  
15 -}  
16 -.icon-menu-people {  
17 - @extend .fa-user;  
18 -}  
19 -.icon-forum {  
20 - @extend .fa-users;  
21 -}  
22 -.icon-new {  
23 - @extend .fa-file-o;  
24 -}  
25 -.icon-save {  
26 - @extend .fa-save;  
27 -}  
28 -  
29 -.link-list-block {  
30 - a i {  
31 - line-height: 25px;  
32 - color: #949494;  
33 - }  
34 -}  
src/app/components/noosfero-blocks/main-block/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero-blocks/main-block/main-block.component.spec.ts
@@ -1,41 +0,0 @@ @@ -1,41 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Input, provide, Component, StateConfig} from 'ng-forward';  
3 -  
4 -import {MainBlock} from './main-block.component';  
5 -import {NoosferoApp} from '../../../index.module';  
6 -  
7 -const tcb = new TestComponentBuilder();  
8 -  
9 -const htmlTemplate: string = '<noosfero-main-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-main-block>';  
10 -  
11 -describe("Components", () => {  
12 - describe("Main Block Component", () => {  
13 -  
14 - // the karma preprocessor html2js transform the templates html into js files which put  
15 - // the templates to the templateCache into the module templates  
16 - // we need to load the module templates here as the template for the  
17 - // component Block will be load on our tests  
18 - beforeEach(angular.mock.module("templates"));  
19 -  
20 - it("check if the main block has a tag with ui-view attribute", done => {  
21 -  
22 - // Creating a container component (BlockContainerComponent) to include  
23 - // the component under test (Block)  
24 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [MainBlock] })  
25 - class BlockContainerComponent {  
26 - }  
27 -  
28 - // uses the TestComponentBuilder instance to initialize the component  
29 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
30 - // and here we can inspect and run the test assertions  
31 - //let myComponent: MainBlock = fixture.componentInstance;  
32 -  
33 - // assure the block object inside the Block matches  
34 - // the provided through the parent component  
35 - expect(fixture.debugElement.queryAll('[ui-view="mainBlockContent"]').length).toEqual(1)  
36 - done();  
37 - });  
38 - });  
39 -  
40 - });  
41 -});  
42 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-blocks/main-block/main-block.component.ts
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -import {Component, Input} from 'ng-forward'  
2 -import {Block} from '../block.component';  
3 -  
4 -@Component({  
5 - selector: 'noosfero-main-block',  
6 - templateUrl: 'app/components/noosfero-blocks/main-block/main-block.html'  
7 -})  
8 -export class MainBlock {  
9 -  
10 -}  
src/app/components/noosfero-blocks/main-block/main-block.html
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -<div ui-view="mainBlockContent" autoscroll></div>  
src/app/components/noosfero-blocks/members-block/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero-blocks/members-block/members-block.component.spec.ts
@@ -1,53 +0,0 @@ @@ -1,53 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Provider, Input, provide, Component} from 'ng-forward';  
3 -  
4 -import {MembersBlock} from './members-block.component';  
5 -  
6 -const htmlTemplate: string = '<noosfero-members-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-members-block>';  
7 -  
8 -const tcb = new TestComponentBuilder();  
9 -  
10 -describe("Components", () => {  
11 - describe("Members Block Component", () => {  
12 -  
13 - beforeEach(angular.mock.module("templates"));  
14 -  
15 - let state = jasmine.createSpyObj("state", ["go"]);  
16 - let providers = [  
17 - new Provider('truncateFilter', { useValue: () => { } }),  
18 - new Provider('stripTagsFilter', { useValue: () => { } }),  
19 - new Provider('$state', { useValue: state }),  
20 - new Provider('ProfileService', {  
21 - useValue: {  
22 - getProfileMembers: (profileId: number, filters: any): any => {  
23 - return Promise.resolve({ data: { people: [{ identifier: "person1" }] } });  
24 - }  
25 - }  
26 - }),  
27 - ];  
28 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [MembersBlock], providers: providers })  
29 - class BlockContainerComponent {  
30 - block = { type: 'Block', settings: {} };  
31 - owner = { name: 'profile-name' };  
32 - constructor() {  
33 - }  
34 - }  
35 -  
36 - it("get members of the block owner", done => {  
37 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
38 - let block: MembersBlock = fixture.debugElement.componentViewChildren[0].componentInstance;  
39 - expect(block.members).toEqual([{ identifier: "person1" }]);  
40 - done();  
41 - });  
42 - });  
43 -  
44 - it("render the profile image for each member", done => {  
45 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
46 - fixture.debugElement.getLocal("$rootScope").$apply();  
47 - expect(fixture.debugElement.queryAll("noosfero-profile-image").length).toEqual(1);  
48 - done();  
49 - });  
50 - });  
51 -  
52 - });  
53 -});  
54 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-blocks/members-block/members-block.component.ts
@@ -1,25 +0,0 @@ @@ -1,25 +0,0 @@
1 -import {Input, Inject, Component} from "ng-forward";  
2 -import {ProfileService} from "../../../../lib/ng-noosfero-api/http/profile.service";  
3 -  
4 -@Component({  
5 - selector: "noosfero-members-block",  
6 - templateUrl: 'app/components/noosfero-blocks/members-block/members-block.html',  
7 -})  
8 -@Inject(ProfileService)  
9 -export class MembersBlock {  
10 -  
11 - @Input() block: any;  
12 - @Input() owner: any;  
13 -  
14 - members: any = [];  
15 -  
16 - constructor(private profileService: ProfileService) {  
17 -  
18 - }  
19 -  
20 - ngOnInit() {  
21 - this.profileService.getProfileMembers(this.owner.id, { per_page: 6 }).then((response: any) => {  
22 - this.members = response.data.people;  
23 - });  
24 - }  
25 -}  
src/app/components/noosfero-blocks/members-block/members-block.html
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -<div class="members-block">  
2 - <a ng-repeat="member in ctrl.members" ui-sref="main.profile.home({profile: member.identifier})" class="member">  
3 - <noosfero-profile-image [profile]="member"></noosfero-profile-image>  
4 - </a>  
5 -</div>  
src/app/components/noosfero-blocks/members-block/members-block.scss
@@ -1,17 +0,0 @@ @@ -1,17 +0,0 @@
1 -.members-block {  
2 - .member {  
3 - img, i.profile-image {  
4 - width: 60px;  
5 - }  
6 - img {  
7 - display: inline-block;  
8 - vertical-align: top;  
9 - }  
10 - i.profile-image {  
11 - text-align: center;  
12 - background-color: #889DB1;  
13 - color: #F1F1F1;  
14 - font-size: 4.5em;  
15 - }  
16 - }  
17 -}  
src/app/components/noosfero-blocks/profile-image-block/profile-image-block.component.spec.ts
@@ -1,46 +0,0 @@ @@ -1,46 +0,0 @@
1 -import {TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Pipe, Input, provide, Component} from 'ng-forward';  
3 -  
4 -import {ProfileImageBlock} from './profile-image-block.component';  
5 -  
6 -import * as helpers from "./../../../../spec/helpers";  
7 -  
8 -const tcb = new TestComponentBuilder();  
9 -  
10 -const htmlTemplate: string = '<noosfero-profile-image-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-profile-image-block>';  
11 -  
12 -describe("Components", () => {  
13 -  
14 - describe("Profile Image Block Component", () => {  
15 -  
16 - beforeEach(angular.mock.module("templates"));  
17 -  
18 - @Component({  
19 - selector: 'test-container-component',  
20 - template: htmlTemplate,  
21 - directives: [ProfileImageBlock],  
22 - providers: helpers.provideFilters("translateFilter")  
23 - })  
24 - class BlockContainerComponent {  
25 - block = { type: 'Block' };  
26 - owner = { name: 'profile-name' };  
27 - constructor() {  
28 - }  
29 - }  
30 -  
31 - it("show image if present", () => {  
32 - helpers.tcb.createAsync(BlockContainerComponent).then(fixture => {  
33 - var elProfile = fixture.debugElement.componentViewChildren[0];  
34 - expect(elProfile.query('div.profile-image-block').length).toEqual(1);  
35 - });  
36 - });  
37 -  
38 - it("has link to the profile", () => {  
39 - helpers.tcb.createAsync(BlockContainerComponent).then(fixture => {  
40 - var elProfile = fixture.debugElement.componentViewChildren[0];  
41 - expect(elProfile.query('a.settings-link').length).toEqual(1);  
42 - });  
43 - });  
44 -  
45 - });  
46 -});  
src/app/components/noosfero-blocks/profile-image-block/profile-image-block.component.ts
@@ -1,14 +0,0 @@ @@ -1,14 +0,0 @@
1 -import {Inject, Input, Component} from "ng-forward";  
2 -import {ProfileImage} from "./../../../components/noosfero/profile-image/profile-image.component";  
3 -  
4 -@Component({  
5 - selector: "noosfero-profile-image-block",  
6 - templateUrl: 'app/components/noosfero-blocks/profile-image-block/profile-image-block.html',  
7 - directives: [ProfileImage]  
8 -})  
9 -export class ProfileImageBlock {  
10 -  
11 - @Input() block: any;  
12 - @Input() owner: any;  
13 -  
14 -}  
src/app/components/noosfero-blocks/profile-image-block/profile-image-block.html
@@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
1 -<div class="center-block text-center profile-image-block">  
2 - <a ui-sref="main.profile.info({profile: ctrl.owner.identifier})">  
3 - <noosfero-profile-image [profile]="ctrl.owner"></noosfero-profile-image>  
4 - </a>  
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>  
src/app/components/noosfero-blocks/profile-image-block/profile-image-block.scss
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -.profile-image-block {  
2 - .settings-link {  
3 - display: block;  
4 - }  
5 -}  
src/app/components/noosfero-blocks/raw-html/raw-html.component.spec.ts
@@ -1,36 +0,0 @@ @@ -1,36 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Component} from 'ng-forward';  
3 -  
4 -import {RawHTMLBlock} from './raw-html.component';  
5 -  
6 -const tcb = new TestComponentBuilder();  
7 -  
8 -const htmlTemplate: string = '<noosfero-raw-htmlblock [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-raw-htmlblock>';  
9 -  
10 -describe("Components", () => {  
11 -  
12 - describe("Raw Html Block Component", () => {  
13 -  
14 - beforeEach(angular.mock.module("templates"));  
15 - beforeEach(angular.mock.module("ngSanitize"));  
16 -  
17 - it("display html stored in block settings", done => {  
18 -  
19 - @Component({  
20 - selector: 'test-container-component',  
21 - template: htmlTemplate,  
22 - directives: [RawHTMLBlock],  
23 - })  
24 - class CustomBlockType {  
25 - block: any = { settings: { html: '<em>block content</em>' } };  
26 - owner: any = { name: 'profile-name' };  
27 - }  
28 - tcb.createAsync(CustomBlockType).then(fixture => {  
29 - expect(fixture.debugElement.query(".raw-html-block em").text().trim()).toEqual('block content');  
30 - done();  
31 - });  
32 - });  
33 -  
34 - });  
35 -  
36 -});  
src/app/components/noosfero-blocks/raw-html/raw-html.component.ts
@@ -1,18 +0,0 @@ @@ -1,18 +0,0 @@
1 -import {Component, Input} from "ng-forward";  
2 -  
3 -@Component({  
4 - selector: "noosfero-raw-htmlblock",  
5 - templateUrl: 'app/components/noosfero-blocks/raw-html/raw-html.html'  
6 -})  
7 -  
8 -export class RawHTMLBlock {  
9 -  
10 - @Input() block: any;  
11 - @Input() owner: any;  
12 -  
13 - html: string;  
14 -  
15 - ngOnInit() {  
16 - this.html = this.block.settings.html;  
17 - }  
18 -}  
src/app/components/noosfero-blocks/raw-html/raw-html.html
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -<div class="raw-html-block" ng-bind-html="ctrl.html">  
2 -</div>  
src/app/components/noosfero-blocks/recent-documents/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero-blocks/recent-documents/recent-documents.component.spec.ts
@@ -1,53 +0,0 @@ @@ -1,53 +0,0 @@
1 -import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {Provider, Input, provide, Component} from 'ng-forward';  
3 -import {provideFilters} from '../../../../spec/helpers';  
4 -import {RecentDocumentsBlock} from './recent-documents.component';  
5 -  
6 -const htmlTemplate: string = '<noosfero-recent-documents-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-recent-documents-block>';  
7 -  
8 -const tcb = new TestComponentBuilder();  
9 -  
10 -describe("Components", () => {  
11 - describe("Recent Documents Block Component", () => {  
12 -  
13 - beforeEach(angular.mock.module("templates"));  
14 -  
15 - let state = jasmine.createSpyObj("state", ["go"]);  
16 - let providers = [  
17 - new Provider('$state', { useValue: state }),  
18 - new Provider('ArticleService', {  
19 - useValue: {  
20 - getByProfile: (profileId: number, filters: any): any => {  
21 - return Promise.resolve({ data: { articles: [{ name: "article1" }] } });  
22 - }  
23 - }  
24 - }),  
25 - ].concat(provideFilters("truncateFilter", "stripTagsFilter"));  
26 -  
27 - @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [RecentDocumentsBlock], providers: providers })  
28 - class BlockContainerComponent {  
29 - block = { type: 'Block', settings: {} };  
30 - owner = { name: 'profile-name' };  
31 - constructor() {  
32 - }  
33 - }  
34 -  
35 - it("get recent documents from the article service", done => {  
36 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
37 - let recentDocumentsBlock: RecentDocumentsBlock = fixture.debugElement.componentViewChildren[0].componentInstance;  
38 - expect(recentDocumentsBlock.documents).toEqual([{ name: "article1" }]);  
39 - done();  
40 - });  
41 - });  
42 -  
43 - it("go to article page when open a document", done => {  
44 - tcb.createAsync(BlockContainerComponent).then(fixture => {  
45 - let recentDocumentsBlock: RecentDocumentsBlock = fixture.debugElement.componentViewChildren[0].componentInstance;  
46 - recentDocumentsBlock.openDocument({ path: "path", profile: { identifier: "identifier" } });  
47 - expect(state.go).toHaveBeenCalledWith("main.profile.page", { page: "path", profile: "identifier" });  
48 - done();  
49 - });  
50 - });  
51 -  
52 - });  
53 -});  
54 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero-blocks/recent-documents/recent-documents.component.ts
@@ -1,38 +0,0 @@ @@ -1,38 +0,0 @@
1 -import {Component, Inject, Input} from "ng-forward";  
2 -import {ArticleService} from "../../../../lib/ng-noosfero-api/http/article.service";  
3 -  
4 -@Component({  
5 - selector: "noosfero-recent-documents-block",  
6 - templateUrl: 'app/components/noosfero-blocks/recent-documents/recent-documents.html'  
7 -})  
8 -@Inject(ArticleService, "$state")  
9 -export class RecentDocumentsBlock {  
10 -  
11 - @Input() block: any;  
12 - @Input() owner: any;  
13 -  
14 - profile: any;  
15 - documents: any;  
16 -  
17 - documentsLoaded: boolean = false;  
18 -  
19 - constructor(private articleService: ArticleService, private $state: any) {  
20 - }  
21 -  
22 - ngOnInit() {  
23 - this.profile = this.owner;  
24 - this.documents = [];  
25 -  
26 - var limit = (this.block && this.block.settings) ? this.block.settings.limit : null || 5;  
27 - //FIXME get all text articles  
28 - this.articleService.getByProfile(this.profile.id, { content_type: 'TinyMceArticle', per_page: limit }).then((response: any) => {  
29 - this.documents = response.data.articles;  
30 - this.documentsLoaded = true;  
31 - });  
32 - }  
33 -  
34 - openDocument(article: any) {  
35 - this.$state.go("main.profile.page", { page: article.path, profile: article.profile.identifier });  
36 - }  
37 -  
38 -}  
src/app/components/noosfero-blocks/recent-documents/recent-documents.html
@@ -1,18 +0,0 @@ @@ -1,18 +0,0 @@
1 -<div deckgrid source="ctrl.documents" class="deckgrid">  
2 - <div class="a-card panel media" ng-click="mother.ctrl.openDocument(card);">  
3 - <div class="author media-left" ng-show="card.author.image">  
4 - <img ng-src="{{card.author.image.url}}" class="img-circle">  
5 - </div>  
6 - <div class="header media-body">  
7 - <h5 class="title media-heading" ng-bind="card.title"></h5>  
8 -  
9 - <div class="subheader">  
10 - <span class="time">  
11 - <i class="fa fa-clock-o"></i> <span am-time-ago="card.created_at | dateFormat"></span>  
12 - </span>  
13 - </div>  
14 - </div>  
15 - <img ng-show="card.image" ng-src="{{card.image.url}}" class="img-responsive article-image">  
16 - <div class="post-lead" ng-bind-html="card.body | stripTags | truncate: 100: '...': true"></div>  
17 - </div>  
18 -</div>  
src/app/components/noosfero-blocks/recent-documents/recent-documents.scss
@@ -1,65 +0,0 @@ @@ -1,65 +0,0 @@
1 -.block.recentdocumentsblock {  
2 - .deckgrid[deckgrid]::before {  
3 - font-size: 0; /* See https://github.com/akoenig/angular-deckgrid/issues/14#issuecomment-35728861 */  
4 - visibility: hidden;  
5 - }  
6 - .author {  
7 - img {  
8 - width: 30px;  
9 - height: 30px;  
10 - }  
11 - }  
12 - .header {  
13 - .subheader {  
14 - color: #C1C1C1;  
15 - font-size: 10px;  
16 - }  
17 - }  
18 - .post-lead {  
19 - color: #8E8E8E;  
20 - font-size: 14px;  
21 - }  
22 - .article-image {  
23 - margin: 10px 0;  
24 - }  
25 -}  
26 -  
27 -.col-md-2-5 {  
28 - .deckgrid[deckgrid]::before {  
29 - content: '1 .deck-column';  
30 - }  
31 -}  
32 -  
33 -.col-md-7 {  
34 - .block.recentdocumentsblock {  
35 - background-color: transparent;  
36 - border: 0;  
37 -  
38 - .deckgrid[deckgrid]::before {  
39 - content: '3 .deck-column';  
40 - }  
41 -  
42 - .panel-heading {  
43 - display: none;  
44 - }  
45 - .panel-body {  
46 - padding: 0;  
47 - }  
48 -  
49 - .deckgrid {  
50 - .column {  
51 - float: left;  
52 - }  
53 -  
54 - .deck-column {  
55 - @extend .col-md-4;  
56 - padding: 0;  
57 -  
58 - .a-card {  
59 - padding: 10px;  
60 - margin: 3px;  
61 - }  
62 - }  
63 - }  
64 - }  
65 -}  
src/app/components/noosfero-boxes/box.html
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -<div ng-class="{'col-md-2-5': box.position!=1, 'col-md-7': box.position==1}">  
2 - <div ng-repeat="block in box.blocks | orderBy: 'position'" class="panel panel-default block {{block.type | lowercase}}" >  
3 - <div class="panel-heading" ng-show="block.title">  
4 - <h3 class="panel-title">{{block.title}}</h3>  
5 - </div>  
6 - <div class="panel-body">  
7 - <noosfero-block [block]="block" [owner]="ctrl.owner"></noosfero-block>  
8 - </div>  
9 - </div>  
10 -</div>  
src/app/components/noosfero-boxes/boxes.component.spec.ts
@@ -1,67 +0,0 @@ @@ -1,67 +0,0 @@
1 -import {Component} from 'ng-forward';  
2 -  
3 -import {Box, Profile} from "../../models/interfaces";  
4 -import {Boxes} from './boxes.component';  
5 -  
6 -import {  
7 - createComponentFromClass,  
8 - quickCreateComponent,  
9 - provideEmptyObjects,  
10 - createProviderToValue,  
11 - getAngularServiceFactory,  
12 - provideFilters  
13 -} from "../../../spec/helpers";  
14 -  
15 -// this htmlTemplate will be re-used between the container components in this spec file  
16 -const htmlTemplate: string = '<noosfero-boxes [boxes]="ctrl.boxes" [owner]="ctrl.profile"></noosfero-blog>';  
17 -  
18 -  
19 -describe("Boxes Component", () => {  
20 -  
21 - beforeEach(() => {  
22 - angular.mock.module("templates")  
23 - })  
24 -  
25 - @Component({  
26 - selector: 'test-container-component',  
27 - template: htmlTemplate,  
28 - directives: [Boxes],  
29 - providers: []  
30 - })  
31 - class BoxesContainerComponent {  
32 - boxes: Box[] = [  
33 - { id: 1, position: 1 },  
34 - { id: 2, position: 2 }  
35 - ];  
36 -  
37 - owner: Profile = {  
38 - id: 1,  
39 - identifier: 'profile-name',  
40 - type: 'Person'  
41 - };  
42 - }  
43 -  
44 - it("renders boxes into a container", (done: Function) => {  
45 - createComponentFromClass(BoxesContainerComponent).then((fixture) => {  
46 -  
47 - var boxesHtml = fixture.debugElement;  
48 - expect(boxesHtml.query('div.col-md-7').length).toEqual(1);  
49 - expect(boxesHtml.query('div.col-md-2-5').length).toEqual(1);  
50 -  
51 - done();  
52 - });  
53 - });  
54 -  
55 - it("check the boxes order", (done: Function) => {  
56 - createComponentFromClass(BoxesContainerComponent).then((fixture) => {  
57 -  
58 - let boxesComponent: Boxes = fixture.debugElement.componentViewChildren[0].componentInstance;  
59 - let boxesContainer: BoxesContainerComponent = fixture.componentInstance;  
60 -  
61 - expect(boxesComponent.boxesOrder(boxesContainer.boxes[0])).toEqual(1);  
62 - expect(boxesComponent.boxesOrder(boxesContainer.boxes[1])).toEqual(0);  
63 -  
64 - done();  
65 - });  
66 - });  
67 -});  
src/app/components/noosfero-boxes/boxes.component.ts
@@ -1,17 +0,0 @@ @@ -1,17 +0,0 @@
1 -import {Input, Inject, Component} from 'ng-forward';  
2 -import {Box, Profile} from "./../../models/interfaces";  
3 -  
4 -@Component({  
5 - selector: "noosfero-boxes",  
6 - templateUrl: "app/components/noosfero-boxes/boxes.html"  
7 -})  
8 -export class Boxes {  
9 -  
10 - @Input() boxes: Box[];  
11 - @Input() owner: Profile;  
12 -  
13 - boxesOrder(box: Box) {  
14 - if (box.position === 2) return 0;  
15 - return box.position;  
16 - }  
17 -}  
src/app/components/noosfero-boxes/boxes.html
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -<ng-include ng-repeat="box in ctrl.boxes | orderBy: ctrl.boxesOrder" src="'app/components/noosfero-boxes/box.html'"></ng-include>  
src/app/components/noosfero-boxes/boxes.scss
@@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
1 -.col-md-2-5 {  
2 - @extend .col-md-3;  
3 - @media (min-width: 920px) {  
4 - width: 20.83%;  
5 - }  
6 -}  
src/app/components/noosfero-boxes/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./boxes.component";  
src/app/components/noosfero/date-format/date-format.filter.spec.ts
@@ -1,20 +0,0 @@ @@ -1,20 +0,0 @@
1 -import {quickCreateComponent} from "../../../../spec/helpers";  
2 -import {DateFormat} from './date-format.filter';  
3 -  
4 -describe("Filters", () => {  
5 - describe("Date Format Filter", () => {  
6 -  
7 - beforeEach(angular.mock.module("templates"));  
8 - beforeEach(angular.mock.module("angularMoment"));  
9 -  
10 - it("convert date from the format returned by noosfero api to an ISO format", done => {  
11 - let date = "2016/03/10 10:46:47";  
12 - let htmlTemplate = `{{ '${date}' | dateFormat }}`;  
13 - quickCreateComponent({ providers: [DateFormat], template: htmlTemplate }).then(fixture => {  
14 - expect(fixture.debugElement.text()).toEqual('2016-03-10T13:46:47.000Z');  
15 - done();  
16 - });  
17 - });  
18 -  
19 - });  
20 -});  
src/app/components/noosfero/date-format/date-format.filter.ts
@@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
1 -import {Pipe, Inject} from "ng-forward";  
2 -  
3 -@Pipe("dateFormat")  
4 -@Inject("amParseFilter")  
5 -export class DateFormat {  
6 -  
7 - constructor(private amParseFilter: any) { }  
8 -  
9 - transform(date: string, options: any) {  
10 - return this.amParseFilter(date, "YYYY/MM/DD HH:mm:ss").toISOString();  
11 - }  
12 -  
13 -}  
src/app/components/noosfero/index.ts
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero/noosfero-template.filter.spec.ts
@@ -1,19 +0,0 @@ @@ -1,19 +0,0 @@
1 -import {quickCreateComponent} from "../../../spec/helpers";  
2 -import {NoosferoTemplate} from './noosfero-template.filter';  
3 -  
4 -describe("Filters", () => {  
5 - describe("Noosfero Template Filter", () => {  
6 -  
7 - beforeEach(angular.mock.module("templates"));  
8 -  
9 - it("replace the options in text with the values passed on options", done => {  
10 - let text = 'profile: {profile}, other: {other}';  
11 - let htmlTemplate = `{{ '${text}' | noosferoTemplate: {profile: 'profile1', other: 'other value'} }}`;  
12 - quickCreateComponent({ providers: [NoosferoTemplate], template: htmlTemplate }).then(fixture => {  
13 - expect(fixture.debugElement.text()).toEqual("profile: profile1, other: other value");  
14 - done();  
15 - });  
16 - });  
17 -  
18 - });  
19 -});  
src/app/components/noosfero/noosfero-template.filter.ts
@@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
1 -import {Pipe} from "ng-forward";  
2 -  
3 -@Pipe("noosferoTemplate")  
4 -export class NoosferoTemplate {  
5 -  
6 - transform(text: string, options: any) {  
7 - for (var option in options) {  
8 - text = text.replace('{' + option + '}', options[option]);  
9 - }  
10 - return text;  
11 - }  
12 -  
13 -}  
src/app/components/noosfero/profile-image/index.ts
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -/**  
2 - * Module for the image component in the Noosfero Angular Theme  
3 - * @namespace components.noosfero.profile-image  
4 - */  
5 -/* Module Index Entry - generated using the script npm run generate-index */  
src/app/components/noosfero/profile-image/profile-image.component.spec.ts
@@ -1,51 +0,0 @@ @@ -1,51 +0,0 @@
1 -/**  
2 - * @ngdoc overview  
3 - * @name components.noosfero.profile-image.ProfileImageSpec  
4 - * @description  
5 - * This file contains the tests for the {@link components.noosfero.profile-image.ProfileImage} component.  
6 - */  
7 -  
8 -import {TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';  
9 -import {Pipe, Input, provide, Component} from 'ng-forward';  
10 -  
11 -import * as helpers from "./../../../../spec/helpers";  
12 -  
13 -import {ProfileImage} from "./profile-image.component"  
14 -  
15 -const tcb = new TestComponentBuilder();  
16 -  
17 -describe("Components", () => {  
18 -  
19 - describe("Profile Image Component", () => {  
20 -  
21 - beforeEach(angular.mock.module("templates"));  
22 -  
23 - it("show community users image if profile is not Person", done => {  
24 - helpers.tcb.createAsync(ProfileImage).then(fixture => {  
25 - let profileImageComponent : ProfileImage = fixture.componentInstance  
26 - let profile = { id: 1, identifier: "myprofile", type: "Community" }  
27 - profileImageComponent.profile = profile  
28 - profileImageComponent.ngOnInit();  
29 -  
30 - // Check the attribute  
31 - expect(profileImageComponent.defaultIcon).toBe("fa-users", "The default icon should be community users");  
32 - //var elProfile = fixture.debugElement.componentViewChildren[0];  
33 - //expect(elProfile.query('div.profile-image-block').length).toEqual(1);  
34 - done();  
35 - });  
36 - });  
37 -  
38 - it("show Person image if profile is Person", done => {  
39 - tcb.createAsync(ProfileImage).then(fixture => {  
40 - let profileImageComponent : ProfileImage = fixture.componentInstance  
41 - let profile = { id: 1, identifier: "myprofile", type: "Person" }  
42 - profileImageComponent.profile = profile  
43 - profileImageComponent.ngOnInit();  
44 - // Check the attribute  
45 - expect(profileImageComponent.defaultIcon).toEqual("fa-user", "The default icon should be person user");  
46 - done();  
47 - });  
48 - });  
49 -  
50 - });  
51 -});  
52 \ No newline at end of file 0 \ No newline at end of file
src/app/components/noosfero/profile-image/profile-image.component.ts
@@ -1,50 +0,0 @@ @@ -1,50 +0,0 @@
1 -import {Inject, Input, Component} from "ng-forward";  
2 -import {Profile} from "./../../../models/interfaces";  
3 -  
4 -  
5 -/**  
6 - * @ngdoc controller  
7 - * @name components.noosfero.profile-image.ProfileImage  
8 - * @description The component responsible for rendering the profile image  
9 - * @exports ProfileImage  
10 - */  
11 -@Component({  
12 - selector: "noosfero-profile-image",  
13 - templateUrl: 'app/components/noosfero/profile-image/profile-image.html',  
14 -})  
15 -export class ProfileImage {  
16 -  
17 -  
18 - /**  
19 - * @ngdoc property  
20 - * @name profile  
21 - * @propertyOf components.noosfero.profile-image.ProfileImage  
22 - * @description  
23 - * The Noosfero {@link models.Profile} holding the image.  
24 - */  
25 - @Input() profile: Profile;  
26 - /**  
27 - * @ngdoc property  
28 - * @name defaultIcon  
29 - * @propertyOf components.noosfero.profile-image.ProfileImage  
30 - * @descritpion  
31 - * The default icon used by this profile  
32 - */  
33 - defaultIcon: string;  
34 -  
35 -  
36 - /**  
37 - * @ngdoc method  
38 - * @name ngOnInit  
39 - * @methodOf components.noosfero.profile-image.ProfileImage  
40 - * @description  
41 - * Initializes the icon names to their corresponding values depending on the profile type passed to the controller  
42 - */  
43 - ngOnInit() {  
44 - this.defaultIcon = 'fa-users';  
45 - if (this.profile && this.profile.type === 'Person') {  
46 - this.defaultIcon = 'fa-user';  
47 - }  
48 - }  
49 -}  
50 -  
src/app/components/noosfero/profile-image/profile-image.html
@@ -1,4 +0,0 @@ @@ -1,4 +0,0 @@
1 -<span title="{{ctrl.profile.name}}">  
2 - <img ng-if="ctrl.profile.image" ng-src="{{ctrl.profile.image.url}}" class="img-responsive profile-image">  
3 - <i ng-if="!ctrl.profile.image" class="fa {{ctrl.defaultIcon}} fa-5x profile-image"></i>  
4 -</span>  
src/app/components/noosfero/profile-image/profile-image.scss
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -i.profile-image {  
2 - color: rgb(44, 62, 80);  
3 -}  
src/app/components/notification/notification.component.spec.ts
@@ -1,80 +0,0 @@ @@ -1,80 +0,0 @@
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("display an error message when notify an error", 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.translatorService);  
21 - component.error("message", "title");  
22 - expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({  
23 - text: "message",  
24 - title: "title",  
25 - type: "error"  
26 - }));  
27 - done();  
28 - });  
29 -  
30 - it("use the default message when call notification component without a message", done => {  
31 - let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);  
32 - sweetAlert.swal = jasmine.createSpy("swal");  
33 -  
34 - let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);  
35 - component.error();  
36 - expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({  
37 - text: Notification.DEFAULT_ERROR_MESSAGE,  
38 - type: "error"  
39 - }));  
40 - done();  
41 - });  
42 -  
43 - it("display a success message when call notification success", done => {  
44 - let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);  
45 - sweetAlert.swal = jasmine.createSpy("swal");  
46 -  
47 - let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);  
48 - component.success("title", "message", 1000);  
49 - expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({  
50 - type: "success"  
51 - }));  
52 - done();  
53 - });  
54 -  
55 - it("display a message relative to the http error code", done => {  
56 - let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);  
57 - sweetAlert.swal = jasmine.createSpy("swal");  
58 -  
59 - let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);  
60 - component.httpError(500, {});  
61 - expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({  
62 - text: "notification.http_error.500.message"  
63 - }));  
64 - done();  
65 - });  
66 -  
67 - it("set the default timer in success messages", done => {  
68 - let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);  
69 - sweetAlert.swal = jasmine.createSpy("swal");  
70 -  
71 - let component: Notification = new Notification(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);  
72 - component.success("title", "message");  
73 - expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({  
74 - type: "success",  
75 - timer: Notification.DEFAULT_SUCCESS_TIMER  
76 - }));  
77 - done();  
78 - });  
79 - });  
80 -});  
src/app/components/notification/notification.component.ts
@@ -1,41 +0,0 @@ @@ -1,41 +0,0 @@
1 -import {Injectable, Inject} from "ng-forward";  
2 -import {TranslatorService} from "../translator/translator.service";  
3 -  
4 -@Injectable()  
5 -@Inject("$log", "SweetAlert", TranslatorService)  
6 -export class Notification {  
7 -  
8 - constructor(  
9 - private $log: ng.ILogService,  
10 - private SweetAlert: any,  
11 - private translatorService: TranslatorService  
12 - ) { }  
13 -  
14 - public static DEFAULT_ERROR_TITLE = "notification.error.default.title";  
15 - public static DEFAULT_ERROR_MESSAGE = "notification.error.default.message";  
16 - public static DEFAULT_SUCCESS_TIMER = 1000;  
17 -  
18 - error(message: string = Notification.DEFAULT_ERROR_MESSAGE, title: string = Notification.DEFAULT_ERROR_TITLE) {  
19 - this.$log.debug("Notification error:", title, message, this.translatorService.currentLanguage());  
20 - this.SweetAlert.swal({  
21 - title: this.translatorService.translate(title),  
22 - text: this.translatorService.translate(message),  
23 - type: "error"  
24 - });  
25 - }  
26 -  
27 - httpError(status: number, data: any): boolean {  
28 - this.error(`notification.http_error.${status}.message`);  
29 - return true; // return true to indicate that the error was already handled  
30 - }  
31 -  
32 - success(title: string, text: string, timer: number = Notification.DEFAULT_SUCCESS_TIMER) {  
33 - this.SweetAlert.swal({  
34 - title: title,  
35 - text: text,  
36 - type: "success",  
37 - timer: timer  
38 - });  
39 - }  
40 -  
41 -}  
src/app/components/translator/translator.service.spec.ts
@@ -1,116 +0,0 @@ @@ -1,116 +0,0 @@
1 -import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';  
2 -import {provide} from 'ng-forward';  
3 -  
4 -import {TranslatorService} from './translator.service';  
5 -  
6 -import * as helpers from "../../../spec/helpers";  
7 -  
8 -describe("Services", () => {  
9 -  
10 - describe("Translator Service", () => {  
11 -  
12 - let $rootScope: ng.IScope;  
13 - let $q: ng.IQService;  
14 -  
15 - beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => {  
16 - $rootScope = _$rootScope_;  
17 - $q = _$q_;  
18 - }));  
19 -  
20 - function createComponent() {  
21 - return new TranslatorService(  
22 - <any>helpers.mocks.$translate,  
23 - <any>helpers.mocks.tmhDynamicLocale,  
24 - <any>helpers.mocks.amMoment,  
25 - <any>helpers.mocks.angularLoad,  
26 - $rootScope  
27 - );  
28 - }  
29 -  
30 - it("set available languages when change language", (done) => {  
31 - let component: TranslatorService = createComponent();  
32 - component.availableLanguages = null;  
33 - expect(component.availableLanguages).toBeNull();  
34 - $rootScope.$emit("$translateChangeSuccess");  
35 - expect(component.availableLanguages).not.toBeNull();  
36 - done();  
37 - });  
38 -  
39 - it("change the language", (done) => {  
40 - let component: TranslatorService = createComponent();  
41 - let loadScripPromise = $q.defer();  
42 - loadScripPromise.resolve();  
43 - component["angularLoad"].loadScript = jasmine.createSpy("loadScript").and.returnValue(loadScripPromise.promise);  
44 - component["tmhDynamicLocale"].set = jasmine.createSpy("set");  
45 - component["tmhDynamicLocale"].get = jasmine.createSpy("get").and.returnValue("en");  
46 - component["$translate"].use = jasmine.createSpy("use");  
47 -  
48 - component.changeLanguage('pt');  
49 - $rootScope.$digest();  
50 -  
51 - expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/moment/locale/pt.js");  
52 - expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/messageformat/locale/pt.js");  
53 - expect(component["tmhDynamicLocale"].set).toHaveBeenCalledWith("pt");  
54 - expect(component["$translate"].use).toHaveBeenCalledWith("pt");  
55 - done();  
56 - });  
57 -  
58 - it("do not load moment locale when change the language to english", (done) => {  
59 - let component: TranslatorService = createComponent();  
60 - component["angularLoad"].loadScript = jasmine.createSpy("loadScript").and.returnValue($q.defer().promise);  
61 - component.changeLanguage('en');  
62 - expect(component["angularLoad"].loadScript).not.toHaveBeenCalledWith("/bower_components/moment/locale/pt.js");  
63 - done();  
64 - });  
65 -  
66 - it("do nothing when call change language with null", (done) => {  
67 - let component: TranslatorService = createComponent();  
68 - component["angularLoad"].loadScript = jasmine.createSpy("loadScript");  
69 - component["tmhDynamicLocale"].set = jasmine.createSpy("set");  
70 - component["$translate"].use = jasmine.createSpy("use");  
71 -  
72 - component.changeLanguage(null);  
73 -  
74 - expect(component["angularLoad"].loadScript).not.toHaveBeenCalled();  
75 - expect(component["tmhDynamicLocale"].set).not.toHaveBeenCalled();  
76 - expect(component["$translate"].use).not.toHaveBeenCalled();  
77 - done();  
78 - });  
79 -  
80 - it("return the current language used by the translator", (done) => {  
81 - let component: TranslatorService = createComponent();  
82 - component["$translate"].use = jasmine.createSpy("use").and.returnValue("en");  
83 - expect(component.currentLanguage()).toEqual("en");  
84 - expect(component["$translate"].use).toHaveBeenCalled();  
85 - done();  
86 - });  
87 -  
88 - it("call translate service when translate a text", (done) => {  
89 - let component: TranslatorService = createComponent();  
90 - component["$translate"].instant = jasmine.createSpy("instant");  
91 - component.translate("text");  
92 - expect(component["$translate"].instant).toHaveBeenCalledWith("text");  
93 - done();  
94 - });  
95 -  
96 - it("change the language when receive an event", (done) => {  
97 - let component: TranslatorService = createComponent();  
98 - component.changeLanguage = jasmine.createSpy("changeLanguage");  
99 - $rootScope.$emit("$localeChangeSuccess");  
100 - expect(component.changeLanguage).toHaveBeenCalled();  
101 - done();  
102 - });  
103 -  
104 - it("use the translate language when receive a change language event and there is no language previously selected", (done) => {  
105 - let component: TranslatorService = createComponent();  
106 - component.changeLanguage = jasmine.createSpy("changeLanguage");  
107 - component["tmhDynamicLocale"].get = jasmine.createSpy("get").and.returnValue(null);  
108 - component["$translate"].use = jasmine.createSpy("use").and.returnValue("en");  
109 -  
110 - $rootScope.$emit("$localeChangeSuccess");  
111 - expect(component["$translate"].use).toHaveBeenCalled();  
112 - expect(component.changeLanguage).toHaveBeenCalledWith("en");  
113 - done();  
114 - });  
115 - });  
116 -});  
src/app/components/translator/translator.service.ts
@@ -1,59 +0,0 @@ @@ -1,59 +0,0 @@
1 -import {Injectable, Inject} from "ng-forward";  
2 -  
3 -@Injectable()  
4 -@Inject("$translate", "tmhDynamicLocale", "amMoment", "angularLoad", "$rootScope")  
5 -export class TranslatorService {  
6 -  
7 - availableLanguages: any;  
8 -  
9 - constructor(private $translate: angular.translate.ITranslateService,  
10 - private tmhDynamicLocale: angular.dynamicLocale.tmhDynamicLocaleService,  
11 - private amMoment: any,  
12 - private angularLoad: any,  
13 - private $rootScope: any) {  
14 -  
15 - this.$rootScope.$on("$localeChangeSuccess", () => {  
16 - this.changeLanguage(tmhDynamicLocale.get() || $translate.use());  
17 - });  
18 - this.$rootScope.$on("$translateChangeSuccess", () => {  
19 - this.configAvailableLanguages();  
20 - });  
21 - }  
22 -  
23 - currentLanguage() {  
24 - return this.$translate.use();  
25 - }  
26 -  
27 - changeLanguage(language: string) {  
28 - if (!language) {  
29 - console.log("WARN: language undefined");  
30 - return;  
31 - }  
32 - this.changeMomentLocale(language);  
33 - this.tmhDynamicLocale.set(language);  
34 - this.angularLoad.loadScript(`/bower_components/messageformat/locale/${language}.js`).then(() => {  
35 - return this.$translate.use(language);  
36 - });  
37 - }  
38 -  
39 - translate(text: string) {  
40 - return this.$translate.instant(text);  
41 - }  
42 -  
43 - private configAvailableLanguages() {  
44 - this.availableLanguages = {  
45 - "en": this.$translate.instant("language.en"),  
46 - "pt": this.$translate.instant("language.pt")  
47 - };  
48 - }  
49 -  
50 - private changeMomentLocale(language: string) {  
51 - let localePromise = Promise.resolve();  
52 - if (language != "en") {  
53 - localePromise = this.angularLoad.loadScript(`/bower_components/moment/locale/${language}.js`);  
54 - }  
55 - localePromise.then(() => {  
56 - this.amMoment.changeLocale(language);  
57 - });  
58 - }  
59 -}  
src/app/content-viewer/content-viewer-actions.component.spec.ts
@@ -1,67 +0,0 @@ @@ -1,67 +0,0 @@
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,22 +0,0 @@ @@ -1,22 +0,0 @@
1 -import {Component, Inject, provide} from "ng-forward";  
2 -import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service";  
3 -  
4 -import {Profile} from "./../models/interfaces";  
5 -  
6 -@Component({  
7 - selector: "content-viewer-actions",  
8 - templateUrl: "app/content-viewer/navbar-actions.html",  
9 - providers: [provide('profileService', { useClass: ProfileService })]  
10 -})  
11 -@Inject(ProfileService)  
12 -export class ContentViewerActions {  
13 -  
14 - article: any;  
15 - profile: any;  
16 -  
17 - constructor(profileService: ProfileService) {  
18 - profileService.getCurrentProfile().then((profile: Profile) => {  
19 - this.profile = profile;  
20 - });  
21 - }  
22 -}  
src/app/content-viewer/content-viewer.component.spec.ts
@@ -1,90 +0,0 @@ @@ -1,90 +0,0 @@
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
@@ -1,37 +0,0 @@ @@ -1,37 +0,0 @@
1 -import * as noosfero from "../models/interfaces";  
2 -  
3 -  
4 -import {ArticleView} from "../components/noosfero-articles/article/article_view";  
5 -import {Input, Component, StateConfig, Inject, provide} from "ng-forward";  
6 -  
7 -import {ArticleBlog} from "./../components/noosfero-articles/blog/blog.component";  
8 -import {ArticleService} from "../../lib/ng-noosfero-api/http/article.service";  
9 -import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service";  
10 -  
11 -@Component({  
12 - selector: "content-viewer",  
13 - templateUrl: "app/content-viewer/page.html",  
14 - directives: [ArticleBlog, ArticleView],  
15 - providers: [  
16 - provide('articleService', { useClass: ArticleService }),  
17 - provide('profileService', { useClass: ProfileService })  
18 - ]  
19 -})  
20 -@Inject(ArticleService, ProfileService, "$log", "$stateParams")  
21 -export class ContentViewer {  
22 -  
23 - @Input()  
24 - article: noosfero.Article = null;  
25 -  
26 - @Input()  
27 - profile: noosfero.Profile = null;  
28 -  
29 - constructor(private articleService: ArticleService, private profileService: ProfileService, private $log: ng.ILogService, private $stateParams: angular.ui.IStateParamsService) {  
30 - this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => {  
31 - this.profile = profile;  
32 - return this.articleService.getByProfile(this.profile.id, { path: this.$stateParams["page"] });  
33 - }).then((response: restangular.IResponse) => {  
34 - this.article = response.data.article;  
35 - });  
36 - }  
37 -}  
src/app/content-viewer/index.ts
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./content-viewer-actions.component";  
3 -export * from "./content-viewer.component";  
src/app/content-viewer/navbar-actions.html
@@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
1 -<ul class="nav navbar-nav">  
2 - <li ng-show="vm.profile">  
3 - <a href="#" role="button" ui-sref="main.profile.cms({profile: vm.profile.identifier})">  
4 - <i class="fa fa-file fa-fw fa-lg"></i> {{"navbar.content_viewer_actions.new_post" | translate}}  
5 - </a>  
6 - </li>  
7 -</ul>  
src/app/content-viewer/page.html
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -<noosfero-article ng-if="vm.article" [article]="vm.article" [profile]="vm.profile"></noosfero-article>  
src/app/index.module.ts
@@ -15,13 +15,13 @@ export class NoosferoApp { @@ -15,13 +15,13 @@ export class NoosferoApp {
15 * @returns {string} the name of this application ('noosferoApp') 15 * @returns {string} the name of this application ('noosferoApp')
16 */ 16 */
17 static appName: string = "noosferoApp"; 17 static appName: string = "noosferoApp";
18 - 18 +
19 /** 19 /**
20 * @ngdoc property 20 * @ngdoc property
21 * @name angularModule 21 * @name angularModule
22 * @propertyOf NoosferoApp 22 * @propertyOf NoosferoApp
23 * @returns {any} all the modules installed for this application 23 * @returns {any} all the modules installed for this application
24 - */ 24 + */
25 static angularModule: any; 25 static angularModule: any;
26 26
27 /** 27 /**
src/app/index.run.ts
1 -import {Session} from "./components/auth/session";  
2 -import {Notification} from "./components/notification/notification.component"; 1 +import {SessionService} from "./login";
  2 +import {NotificationService} from "./shared/services/notification.service";
3 3
4 /** @ngInject */ 4 /** @ngInject */
5 export function noosferoAngularRunBlock( 5 export function noosferoAngularRunBlock(
6 $log: ng.ILogService, 6 $log: ng.ILogService,
7 Restangular: restangular.IService, 7 Restangular: restangular.IService,
8 - Session: Session,  
9 - Notification: Notification 8 + SessionService: SessionService,
  9 + NotificationService: NotificationService
10 ) { 10 ) {
11 11
12 Restangular.addFullRequestInterceptor((element: any, operation: string, route: string, url: string, headers: string) => { 12 Restangular.addFullRequestInterceptor((element: any, operation: string, route: string, url: string, headers: string) => {
13 - if (Session.currentUser()) {  
14 - (<any>headers)["Private-Token"] = Session.currentUser().private_token; 13 + if (SessionService.currentUser()) {
  14 + (<any>headers)["Private-Token"] = SessionService.currentUser().private_token;
15 } 15 }
16 return <any>{ headers: <any>headers }; 16 return <any>{ headers: <any>headers };
17 }); 17 });
18 Restangular.setErrorInterceptor((response: restangular.IResponse, deferred: ng.IDeferred<any>) => { 18 Restangular.setErrorInterceptor((response: restangular.IResponse, deferred: ng.IDeferred<any>) => {
19 // return false to break the promise chain and don't call catch 19 // return false to break the promise chain and don't call catch
20 - return !Notification.httpError(response.status, response.data); 20 + return !NotificationService.httpError(response.status, response.data);
21 }); 21 });
22 } 22 }
src/app/index.ts
@@ -5,10 +5,10 @@ import {noosferoAngularRunBlock} from &quot;./index.run&quot;; @@ -5,10 +5,10 @@ import {noosferoAngularRunBlock} from &quot;./index.run&quot;;
5 import {Main} from "./main/main.component"; 5 import {Main} from "./main/main.component";
6 import {bootstrap, bundle} from "ng-forward"; 6 import {bootstrap, bundle} from "ng-forward";
7 7
8 -import {AUTH_EVENTS} from "./components/auth/auth_events";  
9 -import {AuthController} from "./components/auth/auth_controller"; 8 +import {AUTH_EVENTS} from "./login/auth-events";
  9 +import {AuthController} from "./login/auth.controller";
10 10
11 -import {Navbar} from "./components/navbar/navbar"; 11 +import {Navbar} from "./layout/navbar/navbar";
12 12
13 declare var moment: any; 13 declare var moment: any;
14 14
src/app/layout/blocks/block.component.spec.ts 0 → 100644
@@ -0,0 +1,91 @@ @@ -0,0 +1,91 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Input, provide, Component} from 'ng-forward';
  3 +
  4 +import {BlockComponent} from './block.component';
  5 +
  6 +const tcb = new TestComponentBuilder();
  7 +
  8 +const htmlTemplate: string = '<noosfero-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-block>';
  9 +
  10 +describe("Components", () => {
  11 + describe("Block Component", () => {
  12 +
  13 + // the karma preprocessor html2js transform the templates html into js files which put
  14 + // the templates to the templateCache into the module templates
  15 + // we need to load the module templates here as the template for the
  16 + // component Block will be load on our tests
  17 + beforeEach(angular.mock.module("templates"));
  18 +
  19 + it("receives the block and the owner as inputs", done => {
  20 +
  21 + // Creating a container component (BlockContainerComponent) to include
  22 + // the component under test (Block)
  23 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [BlockComponent] })
  24 + class BlockContainerComponent {
  25 + block = { type: 'Block' };
  26 + owner = { name: 'profile-name' };
  27 + constructor() {
  28 + }
  29 + }
  30 +
  31 + // uses the TestComponentBuilder instance to initialize the component
  32 + tcb
  33 + .createAsync(BlockContainerComponent).then(fixture => {
  34 + // and here we can inspect and run the test assertions
  35 + let myComponent: BlockComponent = fixture.componentInstance;
  36 +
  37 + // assure the block object inside the Block matches
  38 + // the provided through the parent component
  39 + expect(myComponent.block.type).toEqual("Block");
  40 + expect(myComponent.owner.name).toEqual("profile-name");
  41 + done();
  42 + });
  43 + });
  44 +
  45 +
  46 + it("renders a component which matches to the block type", done => {
  47 + // CustomBlock component created to check if it will be used
  48 + // when a block with type 'CustomBlock' is provided to the noosfero-block (Block)
  49 + // *** Important *** - the selector is what ng-forward uses to define the name of the directive provider
  50 + @Component({ selector: 'noosfero-custom-block', template: "<h1>My Custom Block</h1>" })
  51 + class CustomBlock {
  52 + @Input() block: any;
  53 + @Input() owner: any;
  54 + }
  55 +
  56 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [BlockComponent, CustomBlock] })
  57 + class CustomBlockType {
  58 + block = { type: 'CustomBlock' };
  59 + owner = { name: 'profile-name' };
  60 + constructor() {
  61 + }
  62 + }
  63 + tcb
  64 + .createAsync(CustomBlockType).then(fixture => {
  65 + let myComponent: CustomBlockType = fixture.componentInstance;
  66 + expect(myComponent.block.type).toEqual("CustomBlock");
  67 + expect(fixture.debugElement.componentViewChildren[0].text()).toEqual("My Custom Block");
  68 + done();
  69 + });
  70 + });
  71 +
  72 +
  73 + it("renders the default block when hasn't defined a block type", done => {
  74 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [BlockComponent] })
  75 + class CustomBlockType {
  76 + block: any = { type: null };
  77 + owner: any = { name: 'profile-name' };
  78 + constructor() {
  79 + }
  80 + }
  81 + tcb
  82 + .createAsync(CustomBlockType).then(fixture => {
  83 + let myComponent: CustomBlockType = fixture.componentInstance;
  84 + expect(myComponent.block.type).toBeNull();
  85 + expect(!!fixture.debugElement.nativeElement.querySelector("noosfero-default-block")).toBeTruthy();
  86 + done();
  87 + });
  88 + });
  89 +
  90 + });
  91 +});
0 \ No newline at end of file 92 \ No newline at end of file
src/app/layout/blocks/block.component.ts 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +import { Input, Inject, Component } from 'ng-forward';
  2 +
  3 +@Component({
  4 + selector: 'noosfero-block',
  5 + template: '<div></div>'
  6 +})
  7 +@Inject("$element", "$scope", "$injector", "$compile")
  8 +export class BlockComponent {
  9 +
  10 + @Input() block: any;
  11 + @Input() owner: any;
  12 +
  13 + ngOnInit() {
  14 + let blockName = (this.block && this.block.type) ? this.block.type.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase() : "default-block";
  15 + this.$element.replaceWith(this.$compile('<noosfero-' + blockName + ' [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-' + blockName + '>')(this.$scope));
  16 + }
  17 +
  18 + constructor(private $element: any, private $scope: ng.IScope, private $injector: ng.auto.IInjectorService, private $compile: ng.ICompileService) {
  19 + }
  20 +}
src/app/layout/blocks/block.scss 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +.block {
  2 + .panel-title {
  3 + font-size: 15px;
  4 + font-weight: bold;
  5 + }
  6 + .panel-heading {
  7 + background-color: transparent;
  8 + border: 0;
  9 + }
  10 +}
src/app/layout/blocks/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./block.component";
src/app/layout/blocks/link-list/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./link-list.component";
src/app/layout/blocks/link-list/link-list.component.spec.ts 0 → 100644
@@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Pipe, Input, provide, Component} from 'ng-forward';
  3 +import {provideFilters} from '../../../../spec/helpers';
  4 +
  5 +import {LinkListBlockComponent} from './link-list.component';
  6 +
  7 +const tcb = new TestComponentBuilder();
  8 +
  9 +const htmlTemplate: string = '<noosfero-link-list-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-link-list-block>';
  10 +
  11 +
  12 +describe("Components", () => {
  13 +
  14 + describe("Link List Block Component", () => {
  15 +
  16 + beforeEach(angular.mock.module("templates"));
  17 +
  18 + it("receives the block and the owner as inputs", done => {
  19 +
  20 + // Creating a container component (BlockContainerComponent) to include
  21 + // the component under test (Block)
  22 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [LinkListBlockComponent] })
  23 + class BlockContainerComponent {
  24 + block = { type: 'Block' };
  25 + owner = { name: 'profile-name' };
  26 + constructor() {
  27 + }
  28 + }
  29 +
  30 + // uses the TestComponentBuilder instance to initialize the component
  31 + // .overrideView(LinkListBlock, { template: 'asdasdasd', pipes: [NoosferoTemplate] })
  32 + tcb.createAsync(BlockContainerComponent).then(fixture => {
  33 + // and here we can inspect and run the test assertions
  34 + let myComponent: LinkListBlockComponent = fixture.componentInstance;
  35 +
  36 + // assure the block object inside the Block matches
  37 + // the provided through the parent component
  38 + expect(myComponent.block.type).toEqual("Block");
  39 + expect(myComponent.owner.name).toEqual("profile-name");
  40 + done();
  41 + });
  42 + });
  43 +
  44 +
  45 + it("display links stored in block settings", done => {
  46 +
  47 + @Component({
  48 + selector: 'test-container-component',
  49 + template: htmlTemplate,
  50 + directives: [LinkListBlockComponent],
  51 + providers: provideFilters("noosferoTemplateFilter")
  52 + })
  53 + class CustomBlockType {
  54 + block: any = { settings: { links: [{ name: 'link1', address: 'address1' }, { name: 'link2', address: 'address2' }] } };
  55 + owner: any = { name: 'profile-name' };
  56 + }
  57 + tcb.createAsync(CustomBlockType).then(fixture => {
  58 + expect(fixture.debugElement.queryAll(".link-list-block a").length).toEqual(2);
  59 + done();
  60 + });
  61 + });
  62 +
  63 + });
  64 +
  65 +});
0 \ No newline at end of file 66 \ No newline at end of file
src/app/layout/blocks/link-list/link-list.component.ts 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +import {Component, Input} from "ng-forward";
  2 +
  3 +@Component({
  4 + selector: "noosfero-link-list-block",
  5 + templateUrl: "app/layout/blocks/link-list/link-list.html"
  6 +})
  7 +export class LinkListBlockComponent {
  8 +
  9 + @Input() block: any;
  10 + @Input() owner: any;
  11 +
  12 + links: any;
  13 +
  14 + ngOnInit() {
  15 + if (this.block && this.block.settings) {
  16 + this.links = this.block.settings.links;
  17 + }
  18 + }
  19 +
  20 +}
src/app/layout/blocks/link-list/link-list.html 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +<div class="link-list-block">
  2 + <div ng-repeat="link in ctrl.links">
  3 + <a ng-href="{{link.address | noosferoTemplate:{profile: ctrl.owner.identifier} }}">
  4 + <i class="fa fa-fw icon-{{link.icon}}"></i> <span>{{link.name}}</span>
  5 + </a>
  6 + </div>
  7 +</div>
src/app/layout/blocks/link-list/link-list.scss 0 → 100644
@@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
  1 +.icon-event {
  2 + @extend .fa-calendar;
  3 +}
  4 +.icon-photos {
  5 + @extend .fa-photo;
  6 +}
  7 +.icon-edit {
  8 + @extend .fa-edit;
  9 +}
  10 +.icon-ok {
  11 + @extend .fa-check;
  12 +}
  13 +.icon-send {
  14 + @extend .fa-send-o;
  15 +}
  16 +.icon-menu-people {
  17 + @extend .fa-user;
  18 +}
  19 +.icon-forum {
  20 + @extend .fa-users;
  21 +}
  22 +.icon-new {
  23 + @extend .fa-file-o;
  24 +}
  25 +.icon-save {
  26 + @extend .fa-save;
  27 +}
  28 +
  29 +.link-list-block {
  30 + a i {
  31 + line-height: 25px;
  32 + color: #949494;
  33 + }
  34 +}
src/app/layout/blocks/main-block/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./main-block.component";
src/app/layout/blocks/main-block/main-block.component.spec.ts 0 → 100644
@@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Input, provide, Component, StateConfig} from 'ng-forward';
  3 +
  4 +import {MainBlockComponent} from './main-block.component';
  5 +import {NoosferoApp} from '../../../index.module';
  6 +
  7 +const tcb = new TestComponentBuilder();
  8 +
  9 +const htmlTemplate: string = '<noosfero-main-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-main-block>';
  10 +
  11 +describe("Components", () => {
  12 + describe("Main Block Component", () => {
  13 +
  14 + // the karma preprocessor html2js transform the templates html into js files which put
  15 + // the templates to the templateCache into the module templates
  16 + // we need to load the module templates here as the template for the
  17 + // component Block will be load on our tests
  18 + beforeEach(angular.mock.module("templates"));
  19 +
  20 + it("check if the main block has a tag with ui-view attribute", done => {
  21 +
  22 + // Creating a container component (BlockContainerComponent) to include
  23 + // the component under test (Block)
  24 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [MainBlockComponent] })
  25 + class BlockContainerComponent {
  26 + }
  27 +
  28 + // uses the TestComponentBuilder instance to initialize the component
  29 + tcb.createAsync(BlockContainerComponent).then(fixture => {
  30 + // and here we can inspect and run the test assertions
  31 + // let myComponent: MainBlockComponent = fixture.componentInstance;
  32 +
  33 + // assure the block object inside the Block matches
  34 + // the provided through the parent component
  35 + expect(fixture.debugElement.queryAll('[ui-view="mainBlockContent"]').length).toEqual(1);
  36 + done();
  37 + });
  38 + });
  39 + });
  40 +});
0 \ No newline at end of file 41 \ No newline at end of file
src/app/layout/blocks/main-block/main-block.component.ts 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +import {Component, Input} from 'ng-forward';
  2 +import {BlockComponent} from '../block.component';
  3 +
  4 +@Component({
  5 + selector: 'noosfero-main-block',
  6 + templateUrl: 'app/layout/blocks/main-block/main-block.html'
  7 +})
  8 +export class MainBlockComponent {
  9 +
  10 +}
src/app/layout/blocks/main-block/main-block.html 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +<div ui-view="mainBlockContent" autoscroll></div>
src/app/layout/blocks/members-block/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./members-block.component";
src/app/layout/blocks/members-block/members-block.component.spec.ts 0 → 100644
@@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Provider, Input, provide, Component} from 'ng-forward';
  3 +
  4 +import {MembersBlockComponent} from './members-block.component';
  5 +
  6 +const htmlTemplate: string = '<noosfero-members-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-members-block>';
  7 +
  8 +const tcb = new TestComponentBuilder();
  9 +
  10 +describe("Components", () => {
  11 + describe("Members Block Component", () => {
  12 +
  13 + beforeEach(angular.mock.module("templates"));
  14 +
  15 + let state = jasmine.createSpyObj("state", ["go"]);
  16 + let providers = [
  17 + new Provider('truncateFilter', { useValue: () => { } }),
  18 + new Provider('stripTagsFilter', { useValue: () => { } }),
  19 + new Provider('$state', { useValue: state }),
  20 + new Provider('ProfileService', {
  21 + useValue: {
  22 + getProfileMembers: (profileId: number, filters: any): any => {
  23 + return Promise.resolve({ data: { people: [{ identifier: "person1" }] } });
  24 + }
  25 + }
  26 + }),
  27 + ];
  28 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [MembersBlockComponent], providers: providers })
  29 + class BlockContainerComponent {
  30 + block = { type: 'Block', settings: {} };
  31 + owner = { name: 'profile-name' };
  32 + constructor() {
  33 + }
  34 + }
  35 +
  36 + it("get members of the block owner", done => {
  37 + tcb.createAsync(BlockContainerComponent).then(fixture => {
  38 + let block: MembersBlockComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  39 + expect(block.members).toEqual([{ identifier: "person1" }]);
  40 + done();
  41 + });
  42 + });
  43 +
  44 + it("render the profile image for each member", done => {
  45 + tcb.createAsync(BlockContainerComponent).then(fixture => {
  46 + fixture.debugElement.getLocal("$rootScope").$apply();
  47 + expect(fixture.debugElement.queryAll("noosfero-profile-image").length).toEqual(1);
  48 + done();
  49 + });
  50 + });
  51 +
  52 + });
  53 +});
0 \ No newline at end of file 54 \ No newline at end of file
src/app/layout/blocks/members-block/members-block.component.ts 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +import {Input, Inject, Component} from "ng-forward";
  2 +import {ProfileService} from "../../../../lib/ng-noosfero-api/http/profile.service";
  3 +
  4 +@Component({
  5 + selector: "noosfero-members-block",
  6 + templateUrl: 'app/layout/blocks/members-block/members-block.html',
  7 +})
  8 +@Inject(ProfileService)
  9 +export class MembersBlockComponent {
  10 +
  11 + @Input() block: noosfero.Block;
  12 + @Input() owner: noosfero.Profile;
  13 +
  14 + members: any = [];
  15 +
  16 + constructor(private profileService: ProfileService) {
  17 +
  18 + }
  19 +
  20 + ngOnInit() {
  21 + this.profileService.getProfileMembers(this.owner.id, { per_page: 6 }).then((response: any) => {
  22 + this.members = response.data.people;
  23 + });
  24 + }
  25 +}
src/app/layout/blocks/members-block/members-block.html 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +<div class="members-block">
  2 + <a ng-repeat="member in ctrl.members" ui-sref="main.profile.home({profile: member.identifier})" class="member">
  3 + <noosfero-profile-image [profile]="member"></noosfero-profile-image>
  4 + </a>
  5 +</div>
src/app/layout/blocks/members-block/members-block.scss 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +.members-block {
  2 + .member {
  3 + img, i.profile-image {
  4 + width: 60px;
  5 + }
  6 + img {
  7 + display: inline-block;
  8 + vertical-align: top;
  9 + }
  10 + i.profile-image {
  11 + text-align: center;
  12 + background-color: #889DB1;
  13 + color: #F1F1F1;
  14 + font-size: 4.5em;
  15 + }
  16 + }
  17 +}
src/app/layout/blocks/profile-image-block/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./profile-image-block.component";
src/app/layout/blocks/profile-image-block/profile-image-block.component.spec.ts 0 → 100644
@@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
  1 +import {TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Pipe, Input, provide, Component} from 'ng-forward';
  3 +
  4 +import {ProfileImageBlockComponent} from './profile-image-block.component';
  5 +
  6 +import * as helpers from "./../../../../spec/helpers";
  7 +
  8 +const tcb = new TestComponentBuilder();
  9 +
  10 +const htmlTemplate: string = '<noosfero-profile-image-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-profile-image-block>';
  11 +
  12 +describe("Components", () => {
  13 +
  14 + describe("Profile Image Block Component", () => {
  15 +
  16 + beforeEach(angular.mock.module("templates"));
  17 +
  18 + @Component({
  19 + selector: 'test-container-component',
  20 + template: htmlTemplate,
  21 + directives: [ProfileImageBlockComponent],
  22 + providers: helpers.provideFilters("translateFilter")
  23 + })
  24 + class BlockContainerComponent {
  25 + block = { type: 'Block' };
  26 + owner = { name: 'profile-name' };
  27 + constructor() {
  28 + }
  29 + }
  30 +
  31 + it("show image if present", () => {
  32 + helpers.tcb.createAsync(BlockContainerComponent).then(fixture => {
  33 + let elProfile = fixture.debugElement.componentViewChildren[0];
  34 + expect(elProfile.query('div.profile-image-block').length).toEqual(1);
  35 + });
  36 + });
  37 +
  38 + it("has link to the profile", () => {
  39 + helpers.tcb.createAsync(BlockContainerComponent).then(fixture => {
  40 + let elProfile = fixture.debugElement.componentViewChildren[0];
  41 + expect(elProfile.query('a.settings-link').length).toEqual(1);
  42 + });
  43 + });
  44 +
  45 + });
  46 +});
src/app/layout/blocks/profile-image-block/profile-image-block.component.ts 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +import {Inject, Input, Component} from "ng-forward";
  2 +import {ProfileImageComponent} from "./../../../profile/image/image.component";
  3 +
  4 +@Component({
  5 + selector: "noosfero-profile-image-block",
  6 + templateUrl: 'app/layout/blocks/profile-image-block/profile-image-block.html',
  7 + directives: [ProfileImageComponent]
  8 +})
  9 +export class ProfileImageBlockComponent {
  10 +
  11 + @Input() block: noosfero.Block;
  12 + @Input() owner: noosfero.Profile;
  13 +
  14 +}
src/app/layout/blocks/profile-image-block/profile-image-block.html 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +<div class="center-block text-center profile-image-block">
  2 + <a ui-sref="main.profile.info({profile: ctrl.owner.identifier})">
  3 + <noosfero-profile-image [profile]="ctrl.owner"></noosfero-profile-image>
  4 + </a>
  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>
src/app/layout/blocks/profile-image-block/profile-image-block.scss 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +.profile-image-block {
  2 + .settings-link {
  3 + display: block;
  4 + }
  5 +}
src/app/layout/blocks/raw-html/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./raw-html.component";
src/app/layout/blocks/raw-html/raw-html.component.spec.ts 0 → 100644
@@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Component} from 'ng-forward';
  3 +
  4 +import {RawHTMLBlockComponent} from './raw-html.component';
  5 +
  6 +const tcb = new TestComponentBuilder();
  7 +
  8 +const htmlTemplate: string = '<noosfero-raw-htmlblock [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-raw-htmlblock>';
  9 +
  10 +describe("Components", () => {
  11 +
  12 + describe("Raw Html Block Component", () => {
  13 +
  14 + beforeEach(angular.mock.module("templates"));
  15 + beforeEach(angular.mock.module("ngSanitize"));
  16 +
  17 + it("display html stored in block settings", done => {
  18 +
  19 + @Component({
  20 + selector: 'test-container-component',
  21 + template: htmlTemplate,
  22 + directives: [RawHTMLBlockComponent],
  23 + })
  24 + class CustomBlockType {
  25 + block: any = { settings: { html: '<em>block content</em>' } };
  26 + owner: any = { name: 'profile-name' };
  27 + }
  28 + tcb.createAsync(CustomBlockType).then(fixture => {
  29 + expect(fixture.debugElement.query(".raw-html-block em").text().trim()).toEqual('block content');
  30 + done();
  31 + });
  32 + });
  33 +
  34 + });
  35 +
  36 +});
src/app/layout/blocks/raw-html/raw-html.component.ts 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +import {Component, Input} from "ng-forward";
  2 +
  3 +@Component({
  4 + selector: "noosfero-raw-htmlblock",
  5 + templateUrl: 'app/layout/blocks/raw-html/raw-html.html'
  6 +})
  7 +
  8 +export class RawHTMLBlockComponent {
  9 +
  10 + @Input() block: any;
  11 + @Input() owner: any;
  12 +
  13 + html: string;
  14 +
  15 + ngOnInit() {
  16 + this.html = this.block.settings.html;
  17 + }
  18 +}
src/app/layout/blocks/raw-html/raw-html.html 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +<div class="raw-html-block" ng-bind-html="ctrl.html">
  2 +</div>
src/app/layout/blocks/recent-documents/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./recent-documents.component";
src/app/layout/blocks/recent-documents/recent-documents.component.spec.ts 0 → 100644
@@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Provider, Input, provide, Component} from 'ng-forward';
  3 +import {provideFilters} from '../../../../spec/helpers';
  4 +import {RecentDocumentsBlockComponent} from './recent-documents.component';
  5 +
  6 +const htmlTemplate: string = '<noosfero-recent-documents-block [block]="ctrl.block" [owner]="ctrl.owner"></noosfero-recent-documents-block>';
  7 +
  8 +const tcb = new TestComponentBuilder();
  9 +
  10 +describe("Components", () => {
  11 + describe("Recent Documents Block Component", () => {
  12 +
  13 + let settingsObj = {};
  14 + let mockedArticleService = {
  15 + getByProfile: (profile: noosfero.Profile, filters: any): any => {
  16 + return Promise.resolve({ data: [{ name: "article1" }], headers: (name: string) => { return name; } });
  17 + }
  18 + };
  19 + let profile = { name: 'profile-name' };
  20 + beforeEach(angular.mock.module("templates"));
  21 +
  22 + let state = jasmine.createSpyObj("state", ["go"]);
  23 +
  24 +
  25 + function getProviders() {
  26 + return [
  27 + new Provider('$state', { useValue: state }),
  28 + new Provider('ArticleService', {
  29 + useValue: mockedArticleService
  30 + }),
  31 + ].concat(provideFilters("truncateFilter", "stripTagsFilter"));
  32 + }
  33 + let componentClass: any = null;
  34 +
  35 + function getComponent() {
  36 + @Component({ selector: 'test-container-component', template: htmlTemplate, directives: [RecentDocumentsBlockComponent], providers: getProviders() })
  37 + class BlockContainerComponent {
  38 + block = { type: 'Block', settings: settingsObj };
  39 + owner = profile;
  40 + constructor() {
  41 + }
  42 + }
  43 + return BlockContainerComponent;
  44 + }
  45 +
  46 +
  47 + it("get recent documents from the article service", done => {
  48 + tcb.createAsync(getComponent()).then(fixture => {
  49 + let recentDocumentsBlock: RecentDocumentsBlockComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  50 + expect(recentDocumentsBlock.documents).toEqual([{ name: "article1" }]);
  51 + done();
  52 + });
  53 + });
  54 +
  55 + it("go to article page when open a document", done => {
  56 + tcb.createAsync(getComponent()).then(fixture => {
  57 + let recentDocumentsBlock: RecentDocumentsBlockComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  58 + recentDocumentsBlock.openDocument({ path: "path", profile: { identifier: "identifier" } });
  59 + expect(state.go).toHaveBeenCalledWith("main.profile.page", { page: "path", profile: "identifier" });
  60 + done();
  61 + });
  62 + });
  63 +
  64 + it("it uses default limit 5 if not defined on block", done => {
  65 + settingsObj = null;
  66 + mockedArticleService = jasmine.createSpyObj("mockedArticleService", ["getByProfile"]);
  67 + (<any>mockedArticleService).mocked = true;
  68 + let thenMocked = jasmine.createSpy("then");
  69 + mockedArticleService.getByProfile = jasmine.createSpy("getByProfile").and.returnValue({then: thenMocked});
  70 + let getByProfileFunct = mockedArticleService.getByProfile;
  71 + tcb.createAsync(getComponent()).then(fixture => {
  72 + let recentDocumentsBlock: RecentDocumentsBlockComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  73 + recentDocumentsBlock.openDocument({ path: "path", profile: { identifier: "identifier" } });
  74 + expect(getByProfileFunct).toHaveBeenCalledWith(profile, { content_type: 'TinyMceArticle', per_page: 5 });
  75 + done();
  76 + });
  77 + });
  78 +
  79 + });
  80 +});
0 \ No newline at end of file 81 \ No newline at end of file
src/app/layout/blocks/recent-documents/recent-documents.component.ts 0 → 100644
@@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
  1 +import {Component, Inject, Input} from "ng-forward";
  2 +import {ArticleService} from "../../../../lib/ng-noosfero-api/http/article.service";
  3 +
  4 +@Component({
  5 + selector: "noosfero-recent-documents-block",
  6 + templateUrl: 'app/layout/blocks/recent-documents/recent-documents.html'
  7 +})
  8 +@Inject(ArticleService, "$state")
  9 +export class RecentDocumentsBlockComponent {
  10 +
  11 + @Input() block: any;
  12 + @Input() owner: any;
  13 +
  14 + profile: any;
  15 + documents: any;
  16 +
  17 + documentsLoaded: boolean = false;
  18 +
  19 + constructor(private articleService: ArticleService, private $state: any) {
  20 + }
  21 +
  22 + ngOnInit() {
  23 + this.profile = this.owner;
  24 + this.documents = [];
  25 +
  26 + let limit = ((this.block && this.block.settings) ? this.block.settings.limit : null) || 5;
  27 + // FIXME get all text articles
  28 + // FIXME make the getByProfile a generic method where we tell the type passing a class TinyMceArticle
  29 + // and the promise should be of type TinyMceArticle[], per example
  30 + this.articleService.getByProfile(this.profile, { content_type: 'TinyMceArticle', per_page: limit })
  31 + .then((result: noosfero.RestResult<noosfero.Article[]>) => {
  32 + this.documents = <noosfero.Article[]>result.data;
  33 + this.documentsLoaded = true;
  34 + });
  35 + }
  36 +
  37 + openDocument(article: any) {
  38 + this.$state.go("main.profile.page", { page: article.path, profile: article.profile.identifier });
  39 + }
  40 +
  41 +}
src/app/layout/blocks/recent-documents/recent-documents.html 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +<div deckgrid source="ctrl.documents" class="deckgrid">
  2 + <div class="a-card panel media" ng-click="mother.ctrl.openDocument(card);">
  3 + <div class="author media-left" ng-show="card.author.image">
  4 + <img ng-src="{{card.author.image.url}}" class="img-circle">
  5 + </div>
  6 + <div class="header media-body">
  7 + <h5 class="title media-heading" ng-bind="card.title"></h5>
  8 +
  9 + <div class="subheader">
  10 + <span class="time">
  11 + <i class="fa fa-clock-o"></i> <span am-time-ago="card.created_at | dateFormat"></span>
  12 + </span>
  13 + </div>
  14 + </div>
  15 + <img ng-show="card.image" ng-src="{{card.image.url}}" class="img-responsive article-image">
  16 + <div class="post-lead" ng-bind-html="card.body | stripTags | truncate: 100: '...': true"></div>
  17 + </div>
  18 +</div>
src/app/layout/blocks/recent-documents/recent-documents.scss 0 → 100644
@@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
  1 +.block.recentdocumentsblock {
  2 + .deckgrid[deckgrid]::before {
  3 + font-size: 0; /* See https://github.com/akoenig/angular-deckgrid/issues/14#issuecomment-35728861 */
  4 + visibility: hidden;
  5 + }
  6 + .author {
  7 + img {
  8 + width: 30px;
  9 + height: 30px;
  10 + }
  11 + }
  12 + .header {
  13 + .subheader {
  14 + color: #C1C1C1;
  15 + font-size: 10px;
  16 + }
  17 + }
  18 + .post-lead {
  19 + color: #8E8E8E;
  20 + font-size: 14px;
  21 + }
  22 + .article-image {
  23 + margin: 10px 0;
  24 + }
  25 +}
  26 +
  27 +.col-md-2-5 {
  28 + .deckgrid[deckgrid]::before {
  29 + content: '1 .deck-column';
  30 + }
  31 +}
  32 +
  33 +.col-md-7 {
  34 + .block.recentdocumentsblock {
  35 + background-color: transparent;
  36 + border: 0;
  37 +
  38 + .deckgrid[deckgrid]::before {
  39 + content: '3 .deck-column';
  40 + }
  41 +
  42 + .panel-heading {
  43 + display: none;
  44 + }
  45 + .panel-body {
  46 + padding: 0;
  47 + }
  48 +
  49 + .deckgrid {
  50 + .column {
  51 + float: left;
  52 + }
  53 +
  54 + .deck-column {
  55 + @extend .col-md-4;
  56 + padding: 0;
  57 +
  58 + .a-card {
  59 + padding: 10px;
  60 + margin: 3px;
  61 + }
  62 + }
  63 + }
  64 + }
  65 +}
src/app/layout/boxes/box.html 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +<div ng-class="{'col-md-2-5': box.position!=1, 'col-md-7': box.position==1}">
  2 + <div ng-repeat="block in box.blocks | orderBy: 'position'" class="panel panel-default block {{block.type | lowercase}}" >
  3 + <div class="panel-heading" ng-show="block.title">
  4 + <h3 class="panel-title">{{block.title}}</h3>
  5 + </div>
  6 + <div class="panel-body">
  7 + <noosfero-block [block]="block" [owner]="ctrl.owner"></noosfero-block>
  8 + </div>
  9 + </div>
  10 +</div>
src/app/layout/boxes/boxes.component.spec.ts 0 → 100644
@@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
  1 +import {Component} from 'ng-forward';
  2 +
  3 +import {BoxesComponent} from './boxes.component';
  4 +
  5 +import {
  6 + createComponentFromClass,
  7 + quickCreateComponent,
  8 + provideEmptyObjects,
  9 + createProviderToValue,
  10 + getAngularServiceFactory,
  11 + provideFilters
  12 +} from "../../../spec/helpers";
  13 +
  14 +// this htmlTemplate will be re-used between the container components in this spec file
  15 +const htmlTemplate: string = '<noosfero-boxes [boxes]="ctrl.boxes" [owner]="ctrl.profile"></noosfero-blog>';
  16 +
  17 +
  18 +describe("Boxes Component", () => {
  19 +
  20 + beforeEach(() => {
  21 + angular.mock.module("templates");
  22 + });
  23 +
  24 + @Component({
  25 + selector: 'test-container-component',
  26 + template: htmlTemplate,
  27 + directives: [BoxesComponent],
  28 + providers: []
  29 + })
  30 + class BoxesContainerComponent {
  31 + boxes: noosfero.Box[] = [
  32 + { id: 1, position: 1 },
  33 + { id: 2, position: 2 }
  34 + ];
  35 +
  36 + owner: noosfero.Profile = <noosfero.Profile> {
  37 + id: 1,
  38 + identifier: 'profile-name',
  39 + type: 'Person'
  40 + };
  41 + }
  42 +
  43 + it("renders boxes into a container", (done: Function) => {
  44 + createComponentFromClass(BoxesContainerComponent).then((fixture) => {
  45 + let boxesHtml = fixture.debugElement;
  46 + expect(boxesHtml.query('div.col-md-7').length).toEqual(1);
  47 + expect(boxesHtml.query('div.col-md-2-5').length).toEqual(1);
  48 +
  49 + done();
  50 + });
  51 + });
  52 +
  53 + it("check the boxes order", (done: Function) => {
  54 + createComponentFromClass(BoxesContainerComponent).then((fixture) => {
  55 +
  56 + let boxesComponent: BoxesComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  57 + let boxesContainer: BoxesContainerComponent = fixture.componentInstance;
  58 +
  59 + expect(boxesComponent.boxesOrder(boxesContainer.boxes[0])).toEqual(1);
  60 + expect(boxesComponent.boxesOrder(boxesContainer.boxes[1])).toEqual(0);
  61 +
  62 + done();
  63 + });
  64 + });
  65 +});
src/app/layout/boxes/boxes.component.ts 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +import {Input, Inject, Component} from 'ng-forward';
  2 +
  3 +@Component({
  4 + selector: "noosfero-boxes",
  5 + templateUrl: "app/layout/boxes/boxes.html"
  6 +})
  7 +export class BoxesComponent {
  8 +
  9 + @Input() boxes: noosfero.Box[];
  10 + @Input() owner: noosfero.Profile;
  11 +
  12 + boxesOrder(box: noosfero.Box) {
  13 + if (box.position === 2) return 0;
  14 + return box.position;
  15 + }
  16 +}
src/app/layout/boxes/boxes.html 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +<ng-include ng-repeat="box in ctrl.boxes | orderBy: ctrl.boxesOrder" src="'app/layout/boxes/box.html'"></ng-include>
src/app/layout/boxes/boxes.scss 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +.col-md-2-5 {
  2 + @extend .col-md-3;
  3 + @media (min-width: 920px) {
  4 + width: 20.83%;
  5 + }
  6 +}
src/app/layout/boxes/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./boxes.component";
src/app/layout/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
src/app/layout/language-selector/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./language-selector.component";
src/app/layout/language-selector/language-selector.component.spec.ts 0 → 100644
@@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
  1 +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {provide} from 'ng-forward';
  3 +
  4 +import {LanguageSelectorService} from './language-selector.component';
  5 +
  6 +import * as helpers from "../../../spec/helpers";
  7 +
  8 +describe("Components", () => {
  9 +
  10 + describe("Language Selector Component", () => {
  11 +
  12 + beforeEach(angular.mock.module("templates"));
  13 +
  14 + let translatorService: any;
  15 +
  16 + let buildComponent = (): Promise<ComponentFixture> => {
  17 + translatorService = jasmine.createSpyObj("translatorService", ["availableLanguages", "currentLanguage"]);
  18 + return helpers.quickCreateComponent({
  19 + template: "<language-selector></language-selector>",
  20 + directives: [LanguageSelectorService],
  21 + providers: [
  22 + provide('TranslatorService', {
  23 + useValue: translatorService
  24 + })
  25 + ].concat(helpers.provideFilters("translateFilter"))
  26 + });
  27 + };
  28 +
  29 + it("display language options", (done) => {
  30 + buildComponent().then(fixture => {
  31 + fixture.debugElement.getLocal("$rootScope").$apply();
  32 + expect(fixture.debugElement.queryAll('li.language').length).toEqual(2);
  33 + done();
  34 + });
  35 + });
  36 +
  37 + it("call the translator service when change the language", (done) => {
  38 + let translatorService = jasmine.createSpyObj("translatorService", ["changeLanguage"]);
  39 + let languageSelector = new LanguageSelectorService(<any>translatorService);
  40 + languageSelector.changeLanguage("en");
  41 + expect(translatorService.changeLanguage).toHaveBeenCalledWith("en");
  42 + done();
  43 + });
  44 +
  45 + });
  46 +});
src/app/layout/language-selector/language-selector.component.ts 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +import {Component, Inject} from "ng-forward";
  2 +import {TranslatorService} from "../../shared/services/translator.service";
  3 +
  4 +@Component({
  5 + selector: "language-selector",
  6 + templateUrl: "app/layout/language-selector/language-selector.html"
  7 +})
  8 +@Inject(TranslatorService)
  9 +export class LanguageSelectorService {
  10 +
  11 + constructor(private translatorService: TranslatorService) { }
  12 +
  13 + currentLanguage() {
  14 + return this.translatorService.currentLanguage();
  15 + }
  16 +
  17 + changeLanguage(language: string) {
  18 + this.translatorService.changeLanguage(language);
  19 + }
  20 +
  21 + availableLanguages() {
  22 + return this.translatorService.availableLanguages;
  23 + }
  24 +}
src/app/layout/language-selector/language-selector.html 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +<li class="dropdown profile-menu" dropdown>
  2 + <a href="#" class="dropdown-toggle" aria-expanded="false" dropdown-toggle>
  3 + <span>{{"language.selector" | translate}}</span> <b class="caret"></b>
  4 + </a>
  5 + <ul class="dropdown-menu" dropdown-menu>
  6 + <li ng-repeat="(language, description) in ctrl.availableLanguages()"
  7 + class="language language-{{language}}" ng-class="{'active': language==ctrl.currentLanguage()}">
  8 + <a href="#" ng-click="ctrl.changeLanguage(language)">
  9 + {{description}}
  10 + </a>
  11 + </li>
  12 + </ul>
  13 +</li>
src/app/layout/navbar/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./navbar";
src/app/layout/navbar/navbar.directive.spec.js 0 → 100644
@@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
  1 +(function() {
  2 + 'use strict';
  3 +
  4 + describe('directive navbar', function() {
  5 + var vm;
  6 + var el;
  7 + var AUTH_EVENTS;
  8 + var $state;
  9 +
  10 + beforeEach(module('angular'));
  11 + beforeEach(inject(function($compile, $rootScope, $httpBackend, _AUTH_EVENTS_, _$state_) {
  12 + $state = _$state_;
  13 + AUTH_EVENTS = _AUTH_EVENTS_;
  14 + $httpBackend.when('POST','/api/v1/login_from_cookie').respond({});
  15 +
  16 + el = angular.element('<acme-navbar></acme-navbar>');
  17 +
  18 + $compile(el)($rootScope.$new());
  19 + $rootScope.$digest();
  20 + vm = el.isolateScope().vm;
  21 + }));
  22 +
  23 + it('should be compiled', function() {
  24 + expect(el.html()).not.toEqual(null);
  25 + });
  26 +
  27 + it('should have isolate scope object with instanciate members', function() {
  28 + expect(vm).toEqual(jasmine.any(Object));
  29 + expect(vm.currentUser).toEqual(undefined);
  30 + });
  31 +
  32 + it('should reload current state after login', function() {
  33 + spyOn($state, 'go');
  34 + el.isolateScope().$broadcast(AUTH_EVENTS.loginSuccess, {});
  35 + expect($state.go).toHaveBeenCalled();
  36 + });
  37 +
  38 + it('should open login when not logged in', function() {
  39 + spyOn(vm, 'openLogin');
  40 + vm.activate();
  41 + expect(vm.openLogin).toHaveBeenCalled();
  42 + });
  43 +
  44 + });
  45 +})();
src/app/layout/navbar/navbar.html 0 → 100644
@@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
  1 +<nav class="navbar navbar-static-top navbar-inverse">
  2 + <div class="container-fluid">
  3 + <div class="navbar-header">
  4 + <button type="button" class="navbar-toggle collapsed" ng-click="isCollapsed = !isCollapsed">
  5 + <span class="sr-only">{{"navbar.toggle_menu" | translate}}</span>
  6 + <span class="icon-bar"></span>
  7 + <span class="icon-bar"></span>
  8 + <span class="icon-bar"></span>
  9 + </button>
  10 + <a class="navbar-brand" ui-sref="main">
  11 + <span class="noosfero-logo"><img src="assets/images/logo-noosfero.png"></span> {{"noosfero.name" | translate}}
  12 + </a>
  13 + </div>
  14 +
  15 + <div class="collapse navbar-collapse" id="navbar-collapse" collapse="isCollapsed">
  16 + <ul class="nav navbar-nav">
  17 + </ul>
  18 +
  19 + <ul class="nav navbar-nav navbar-right">
  20 + <li ng-show="!ctrl.currentUser">
  21 + <a ng-href="#" ng-click="ctrl.openLogin()">{{"navbar.login" | translate}}</a>
  22 + </li>
  23 +
  24 + <li class="dropdown profile-menu" ng-show="ctrl.currentUser" dropdown>
  25 + <a href="#" class="dropdown-toggle" aria-expanded="false" dropdown-toggle>
  26 + <noosfero-profile-image [profile]="ctrl.currentUser.person" class="profile-image"></noosfero-profile-image>
  27 + <span ng-bind="ctrl.currentUser.person.name"></span> <b class="caret"></b>
  28 + </a>
  29 + <ul class="dropdown-menu" dropdown-menu>
  30 + <li>
  31 + <a ui-sref="main.profile.info({profile: ctrl.currentUser.person.identifier})"><i class="fa fa-fw fa-user"></i> {{"navbar.profile" | translate}}</a>
  32 + </li>
  33 + <li>
  34 + <a target="_self" ui-sref="main.profile.settings({profile: ctrl.currentUser.person.identifier})"><i class="fa fa-fw fa-gear"></i> {{"navbar.settings" | translate}}</a>
  35 + </li>
  36 + <li class="divider"></li>
  37 + <li>
  38 + <a href="#" ng-click="ctrl.logout()"><i class="fa fa-fw fa-power-off"></i> {{"navbar.logout" | translate}}</a>
  39 + </li>
  40 + </ul>
  41 + </li>
  42 + </ul>
  43 + <ul class="nav navbar-nav navbar-right">
  44 + <language-selector class="nav navbar-nav navbar-right"></language-selector>
  45 + </ul>
  46 + <div ui-view="actions"></div>
  47 + </div>
  48 + </div>
  49 +</nav>
src/app/layout/navbar/navbar.scss 0 → 100644
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
  1 +.navbar {
  2 +
  3 + .container-fluid {
  4 + padding-right: 12%;
  5 + padding-left: 12%;
  6 + @media (max-width: 978px) {
  7 + padding-right: 2%;
  8 + padding-left: 2%;
  9 + }
  10 +
  11 + .navbar-brand {
  12 + .noosfero-logo img {
  13 + height: 35px;
  14 + }
  15 + }
  16 +
  17 + .navbar-nav {
  18 + .profile-menu .profile-image {
  19 + img {
  20 + height: 30px;
  21 + width: 30px;
  22 + display: inline-block;
  23 + @extend .img-circle;
  24 + }
  25 + i {
  26 + font-size: 1.7em;
  27 + }
  28 + }
  29 + }
  30 + }
  31 +}
src/app/layout/navbar/navbar.spec.ts 0 → 100644
@@ -0,0 +1,187 @@ @@ -0,0 +1,187 @@
  1 +import * as helpers from "./../../../spec/helpers";
  2 +import {Navbar} from "./navbar";
  3 +
  4 +import {Injectable, Provider, provide} from "ng-forward";
  5 +
  6 +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  7 +
  8 +import {SessionService, AuthService, AuthController, IAuthEvents, AUTH_EVENTS} from "./../../login";
  9 +
  10 +
  11 +describe("Components", () => {
  12 +
  13 + describe("Navbar Component", () => {
  14 +
  15 + let user: noosfero.User = null;
  16 + let scope: any;
  17 + let $rootScope: ng.IRootScopeService;
  18 +
  19 + let modalInstance: any;
  20 + let $modal: any;
  21 + let authService: any;
  22 + let stateService: any;
  23 + let sessionService: SessionService;
  24 +
  25 + let provideFunc = provide;
  26 +
  27 + // before Each -> loading mocks on locals variables
  28 + beforeEach(() => {
  29 + user = <noosfero.User>{
  30 + id: 1,
  31 + login: "user"
  32 + };
  33 + scope = helpers.mocks.scopeWithEvents;
  34 + modalInstance = helpers.mocks.modalInstance;
  35 + $modal = helpers.mocks.$modal;
  36 + authService = helpers.mocks.authService;
  37 + stateService = jasmine.createSpyObj("$state", ["go"]);
  38 + sessionService = <any>helpers.mocks.sessionWithCurrentUser(user);
  39 + });
  40 +
  41 +
  42 + // loading the templates
  43 + beforeEach(angular.mock.module("templates"));
  44 +
  45 +
  46 + // this function allow build the fixture of the container component
  47 + // and is reused in each test
  48 + // The main idea behing not prebuild it on a general beforeEach block is
  49 + // to allow tests configure the mock services accordilly their own needs
  50 + let buildComponent = (): Promise<ComponentFixture> => {
  51 + return helpers.quickCreateComponent({
  52 + providers: [
  53 + provide('$modal', {
  54 + useValue: $modal
  55 + }),
  56 + provide('AuthService', {
  57 + useValue: authService
  58 + }),
  59 + helpers.provideEmptyObjects('moment'),
  60 + provide('$state', {
  61 + useValue: stateService
  62 + }),
  63 + provide("$scope", {
  64 + useValue: scope
  65 + }),
  66 + provide('SessionService', {
  67 + useValue: sessionService
  68 + }),
  69 + provide('AUTH_EVENTS', {
  70 + useValue: {
  71 + AUTH_EVENTS
  72 + }
  73 + }),
  74 + provide('TranslatorService', {
  75 + useValue: helpers.mocks.translatorService
  76 + })
  77 + ].concat(helpers.provideFilters("translateFilter")),
  78 + directives: [Navbar],
  79 + template: '<acme-navbar></acme-navbar>'
  80 + });
  81 + };
  82 +
  83 +
  84 + it('should get the loggedIn user', (done: Function) => {
  85 + buildComponent().then((fixture: ComponentFixture) => {
  86 + let navbarInstance: Navbar = fixture.debugElement.componentViewChildren[0].componentInstance;
  87 + expect(navbarInstance).toBeDefined();
  88 + expect(navbarInstance["currentUser"]).toEqual(user);
  89 + done();
  90 + });
  91 + });
  92 +
  93 + it('should open on click', (done: Function) => {
  94 + spyOn($modal, "open");
  95 + buildComponent().then((fixture: ComponentFixture) => {
  96 + let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;
  97 + navbarComp.openLogin();
  98 + expect($modal.open).toHaveBeenCalled();
  99 + expect($modal.open).toHaveBeenCalledWith({
  100 + templateUrl: 'app/components/auth/login.html',
  101 + controller: AuthController,
  102 + controllerAs: 'vm',
  103 + bindToController: true
  104 + });
  105 + done();
  106 + });
  107 + });
  108 +
  109 + it('should logout', (done: Function) => {
  110 + buildComponent().then((fixture: ComponentFixture) => {
  111 + let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;
  112 + spyOn(authService, "logout");
  113 + try {
  114 + navbarComp.logout();
  115 + expect(authService.logout).toHaveBeenCalled();
  116 + done();
  117 + } catch (e) {
  118 + console.error(e);
  119 + fail(e.message);
  120 + done();
  121 + }
  122 + });
  123 + });
  124 +
  125 +
  126 + it('should not activate user when logged in', (done: Function) => {
  127 + buildComponent().then((fixture: ComponentFixture) => {
  128 + let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;
  129 + spyOn(navbarComp, "openLogin");
  130 + navbarComp.activate();
  131 + expect((<any>navbarComp.openLogin).calls.count()).toBe(0);
  132 + done();
  133 + });
  134 + });
  135 +
  136 + it('should activate when user not logged in', (done: Function) => {
  137 + spyOn(sessionService, 'currentUser').and.returnValue(null);
  138 + buildComponent().then((fixture: ComponentFixture) => {
  139 + let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;
  140 + spyOn(navbarComp, "openLogin");
  141 + navbarComp.activate();
  142 + expect(navbarComp.openLogin).toHaveBeenCalled();
  143 + done();
  144 + });
  145 + });
  146 +
  147 +
  148 + it('closes the modal after login', (done: Function) => {
  149 + modalInstance = jasmine.createSpyObj("modalInstance", ["close"]);
  150 + modalInstance.close = jasmine.createSpy("close");
  151 +
  152 + $modal.open = () => {
  153 + return modalInstance;
  154 + };
  155 +
  156 + buildComponent().then((fixture: ComponentFixture) => {
  157 + let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;
  158 + let localScope: ng.IScope = navbarComp["$scope"];
  159 +
  160 + navbarComp.openLogin();
  161 + localScope.$emit(AUTH_EVENTS.loginSuccess);
  162 + expect(modalInstance.close).toHaveBeenCalled();
  163 + done();
  164 + });
  165 + });
  166 +
  167 + it('updates current user on logout', (done: Function) => {
  168 + buildComponent().then((fixture: ComponentFixture) => {
  169 + let navbarComp: Navbar = <Navbar>fixture.debugElement.componentViewChildren[0].componentInstance;
  170 + let localScope: ng.IScope = navbarComp["$scope"];
  171 +
  172 + // init navbar currentUser with some user
  173 + navbarComp["currentUser"] = user;
  174 +
  175 + // changes the current User to return null,
  176 + // and emmit the 'logoutSuccess' event
  177 + // just what happens when user logsout
  178 + sessionService.currentUser = () => { return null; };
  179 + localScope.$emit(AUTH_EVENTS.logoutSuccess);
  180 + expect(navbarComp["currentUser"]).toBeNull();
  181 + done();
  182 + });
  183 + });
  184 +
  185 +
  186 + });
  187 +});
src/app/layout/navbar/navbar.ts 0 → 100644
@@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
  1 +import {Component, Inject} from "ng-forward";
  2 +import {LanguageSelectorService} from "../language-selector/language-selector.component";
  3 +
  4 +
  5 +import {SessionService, AuthService, AuthController, IAuthEvents, AUTH_EVENTS} from "./../../login";
  6 +
  7 +@Component({
  8 + selector: "acme-navbar",
  9 + templateUrl: "app/layout/navbar/navbar.html",
  10 + directives: [LanguageSelectorService],
  11 + providers: [AuthService, SessionService]
  12 +})
  13 +@Inject("$modal", AuthService, "SessionService", "$scope", "$state")
  14 +export class Navbar {
  15 +
  16 + private currentUser: noosfero.User;
  17 + private modalInstance: any = null;
  18 + /**
  19 + *
  20 + */
  21 + constructor(
  22 + private $modal: any,
  23 + private authService: AuthService,
  24 + private session: SessionService,
  25 + private $scope: ng.IScope,
  26 + private $state: ng.ui.IStateService
  27 + ) {
  28 + this.currentUser = this.session.currentUser();
  29 +
  30 + this.$scope.$on(AUTH_EVENTS.loginSuccess, () => {
  31 + if (this.modalInstance) {
  32 + this.modalInstance.close();
  33 + this.modalInstance = null;
  34 + }
  35 +
  36 + this.$state.go(this.$state.current, {}, { reload: true }); // TODO move to auth
  37 + });
  38 +
  39 + this.$scope.$on(AUTH_EVENTS.logoutSuccess, () => {
  40 + this.currentUser = this.session.currentUser();
  41 + });
  42 + }
  43 +
  44 + openLogin() {
  45 + this.modalInstance = this.$modal.open({
  46 + templateUrl: 'app/components/auth/login.html',
  47 + controller: AuthController,
  48 + controllerAs: 'vm',
  49 + bindToController: true
  50 + });
  51 + };
  52 +
  53 + logout() {
  54 + this.authService.logout();
  55 + this.$state.go(this.$state.current, {}, { reload: true }); // TODO move to auth
  56 + };
  57 +
  58 +
  59 +
  60 + activate() {
  61 + if (!this.currentUser) {
  62 + this.openLogin();
  63 + }
  64 + }
  65 +
  66 +}
src/app/login/auth-events.ts 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +export interface IAuthEvents {
  2 + loginSuccess: string;
  3 + loginFailed: string;
  4 + logoutSuccess: string;
  5 +}
  6 +
  7 +export const AUTH_EVENTS: IAuthEvents = {
  8 + loginSuccess: "auth-login-success",
  9 + loginFailed: "auth-login-failed",
  10 + logoutSuccess: "auth-logout-success"
  11 +};
0 \ No newline at end of file 12 \ No newline at end of file
src/app/login/auth.controller.spec.ts 0 → 100644
@@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
  1 +import {AuthController} from "./auth.controller";
  2 +import {AuthService} from "./auth.service";
  3 +
  4 +describe("Controllers", () => {
  5 +
  6 +
  7 + describe("AuthController", () => {
  8 +
  9 + it("calls authenticate on AuthService when login called", () => {
  10 +
  11 + // creating a Mock AuthService
  12 + let AuthServiceMock: AuthService = jasmine.createSpyObj("AuthService", ["login"]);
  13 +
  14 + // pass AuthServiceMock into the constructor
  15 + let authController = new AuthController(null, null, AuthServiceMock);
  16 +
  17 + // setup of authController -> set the credentials instance property
  18 + let credentials = { username: "username", password: "password" };
  19 +
  20 + authController.credentials = credentials;
  21 +
  22 + // calls the authController login method
  23 + authController.login();
  24 +
  25 + // checks if the method login of the injected AuthService has been called
  26 + expect(AuthServiceMock.login).toHaveBeenCalledWith(credentials);
  27 +
  28 + });
  29 +
  30 +
  31 +
  32 + });
  33 +});
src/app/login/auth.controller.ts 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +import {AuthService} from "./auth.service";
  2 +
  3 +export class AuthController {
  4 +
  5 + static $inject = ["$log", "$stateParams", "AuthService"];
  6 +
  7 + constructor(
  8 + private $log: ng.ILogService,
  9 + private $stateParams: any,
  10 + private AuthService: AuthService
  11 + ) {
  12 +
  13 + }
  14 +
  15 + credentials: noosfero.Credentials;
  16 +
  17 + login() {
  18 + this.AuthService.login(this.credentials);
  19 + }
  20 +}
src/app/login/auth.service.spec.ts 0 → 100644
@@ -0,0 +1,81 @@ @@ -0,0 +1,81 @@
  1 +
  2 +
  3 +import {AuthService, AUTH_EVENTS} from "./";
  4 +
  5 +describe("Services", () => {
  6 +
  7 +
  8 + describe("Auth Service", () => {
  9 +
  10 + let $httpBackend: ng.IHttpBackendService;
  11 + let authService: AuthService;
  12 + let credentials: noosfero.Credentials;
  13 + let $rootScope: ng.IRootScopeService;
  14 + let user: noosfero.User;
  15 +
  16 + beforeEach(angular.mock.module("noosferoApp", ($translateProvider: angular.translate.ITranslateProvider) => {
  17 + $translateProvider.translations('en', {});
  18 + }));
  19 +
  20 + beforeEach(inject((_$httpBackend_: ng.IHttpBackendService, _$rootScope_: ng.IRootScopeService, _AuthService_: AuthService) => {
  21 + $httpBackend = _$httpBackend_;
  22 + authService = _AuthService_;
  23 + $rootScope = _$rootScope_;
  24 +
  25 + user = <noosfero.User>{
  26 + id: 1,
  27 + login: "user"
  28 + };
  29 + }));
  30 +
  31 +
  32 + describe("Succesffull login", () => {
  33 +
  34 + beforeEach(() => {
  35 + credentials = { username: "user", password: "password" };
  36 +
  37 + $httpBackend.expectPOST("/api/v1/login", "login=user&password=password").respond(200, { user: user });
  38 + });
  39 +
  40 + it("should return loggedUser", (done) => {
  41 + authService.login(credentials).then((loggedUser) => {
  42 + expect(loggedUser).toBeDefined();
  43 + done();
  44 + });
  45 + $httpBackend.flush();
  46 + expect($httpBackend.verifyNoOutstandingRequest());
  47 + });
  48 +
  49 +
  50 + it("should emit event loggin successful with user logged data", () => {
  51 +
  52 + authService.login(credentials);
  53 +
  54 + let eventEmmited: boolean = false;
  55 + $rootScope.$on(AUTH_EVENTS.loginSuccess, (event: ng.IAngularEvent, userThroughEvent: noosfero.User) => {
  56 + eventEmmited = true;
  57 + expect(userThroughEvent).toEqual(user);
  58 + });
  59 +
  60 + $httpBackend.flush();
  61 +
  62 + expect(eventEmmited).toBeTruthy(AUTH_EVENTS.loginSuccess + " was not emmited!");
  63 + });
  64 +
  65 + it("should return the current logged in user", () => {
  66 + authService.login(credentials);
  67 + $httpBackend.flush();
  68 + let actual: noosfero.User = authService.currentUser();
  69 + expect(actual).toEqual(user, "The returned user must be present");
  70 + });
  71 +
  72 + it("should not return the current user after logout", () => {
  73 + authService.logout();
  74 + let actual: any = authService.currentUser();
  75 + expect(actual).toEqual(undefined, "The returned user must not be defined");
  76 + });
  77 + });
  78 +
  79 +
  80 + });
  81 +});
src/app/login/auth.service.ts 0 → 100644
@@ -0,0 +1,69 @@ @@ -0,0 +1,69 @@
  1 +import {Injectable, Inject} from "ng-forward";
  2 +
  3 +import {NoosferoRootScope, UserResponse} from "./../shared/models/interfaces";
  4 +import {SessionService} from "./session.service";
  5 +
  6 +import {AUTH_EVENTS, IAuthEvents} from "./auth-events";
  7 +
  8 +@Injectable()
  9 +@Inject("$q", "$http", "$rootScope", "SessionService", "$log", "AUTH_EVENTS")
  10 +export class AuthService {
  11 +
  12 + constructor(private $q: ng.IQService,
  13 + private $http: ng.IHttpService,
  14 + private $rootScope: NoosferoRootScope,
  15 + private sessionService: SessionService,
  16 + private $log: ng.ILogService,
  17 + private auth_events: IAuthEvents) {
  18 +
  19 + }
  20 +
  21 + loginFromCookie() {
  22 + let url: string = '/api/v1/login_from_cookie';
  23 + return this.$http.post(url, null).then(this.loginSuccessCallback.bind(this), this.loginFailedCallback.bind(this));
  24 + }
  25 +
  26 +
  27 + private loginSuccessCallback(response: ng.IHttpPromiseCallbackArg<UserResponse>) {
  28 + this.$log.debug('AuthService.login [SUCCESS] response', response);
  29 + let currentUser: noosfero.User = this.sessionService.create(response.data);
  30 + this.$rootScope.currentUser = currentUser;
  31 + this.$rootScope.$broadcast(this.auth_events.loginSuccess, currentUser);
  32 + return currentUser;
  33 + }
  34 +
  35 + login(credentials: noosfero.Credentials): ng.IPromise<noosfero.User> {
  36 + let url = '/api/v1/login';
  37 + let encodedData = 'login=' + credentials.username + '&password=' + credentials.password;
  38 + return this.$http.post(url, encodedData).then(this.loginSuccessCallback.bind(this), this.loginFailedCallback.bind(this));
  39 + }
  40 +
  41 + private loginFailedCallback(response: ng.IHttpPromiseCallbackArg<any>): any {
  42 + this.$log.debug('AuthService.login [FAIL] response', response);
  43 + this.$rootScope.$broadcast(this.auth_events.loginFailed);
  44 + // return $q.reject(response);
  45 + return null;
  46 + }
  47 +
  48 + public logout() {
  49 + this.sessionService.destroy();
  50 + this.$rootScope.currentUser = undefined;
  51 + this.$rootScope.$broadcast(this.auth_events.logoutSuccess);
  52 + this.$http.jsonp('/account/logout'); // FIXME logout from noosfero to sync login state
  53 + }
  54 +
  55 + public isAuthenticated() {
  56 + return !!this.sessionService.currentUser();
  57 + }
  58 +
  59 + public currentUser(): noosfero.User {
  60 + return this.sessionService.currentUser();
  61 + }
  62 +
  63 + public isAuthorized(authorizedRoles: string | string[]) {
  64 + if (!angular.isArray(authorizedRoles)) {
  65 + authorizedRoles = [<string>authorizedRoles];
  66 + }
  67 + return (this.isAuthenticated() && authorizedRoles.indexOf(this.sessionService.currentUser().userRole) !== -1);
  68 + }
  69 +}
0 \ No newline at end of file 70 \ No newline at end of file
src/app/login/index.ts 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./auth-events";
  3 +export * from "./auth.controller";
  4 +export * from "./auth.service";
  5 +export * from "./session.service";
src/app/login/login.html 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +<div class="modal-header">
  2 + <h3 class="modal-title">{{"auth.title" | translate}}</h3>
  3 +</div>
  4 +<div class="modal-body">
  5 + <form>
  6 + <div class="form-group">
  7 + <label for="exampleInputEmail1">{{"auth.form.login" | translate}}</label>
  8 + <input type="text" class="form-control" id="exampleInputEmail1" placeholder="Login / Email" ng-model="vm.credentials.username">
  9 + </div>
  10 + <div class="form-group">
  11 + <label for="exampleInputPassword1">{{"auth.form.password" | translate}}</label>
  12 + <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password" ng-model="vm.credentials.password">
  13 + </div>
  14 + <button type="submit" class="btn btn-default" ng-click="vm.login()">{{"auth.form.login_button" | translate}}</button>
  15 + </form>
  16 +</div>
src/app/login/session.service.spec.ts 0 → 100644
@@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
  1 +import {Component} from "ng-forward";
  2 +import {SessionService} from "./session.service";
  3 +import {fixtures, createComponentFromClass, createProviderToValue} from "./../../spec/helpers";
  4 +import {UserResponse, INoosferoLocalStorage} from "./../shared/models/interfaces";
  5 +
  6 +
  7 +describe("Services", () => {
  8 +
  9 +
  10 + describe("Session Service", () => {
  11 +
  12 + let $localStorage: INoosferoLocalStorage = null;
  13 + let $log: any;
  14 +
  15 + beforeEach(() => {
  16 + $localStorage = <INoosferoLocalStorage>{ currentUser: null };
  17 + $log = jasmine.createSpyObj('$log', ['debug']);
  18 + });
  19 +
  20 + it("method 'create()' saves the current user on $localstorage service", () => {
  21 + let session = new SessionService($localStorage, $log);
  22 + let userResponse = <UserResponse>{
  23 + user: fixtures.user
  24 + };
  25 + session.create(userResponse);
  26 + expect($localStorage.currentUser).toEqual(userResponse.user);
  27 + });
  28 +
  29 + it("method 'destroy()' clean the currentUser on $localstorage", () => {
  30 + let session = new SessionService($localStorage, $log);
  31 + let userResponse = <UserResponse>{
  32 + user: fixtures.user
  33 + };
  34 + $localStorage.currentUser = fixtures.user;
  35 + session.destroy();
  36 + expect($localStorage.currentUser).toBeUndefined();
  37 + });
  38 +
  39 + it("method 'currentUser()' returns the user recorded on $localstorage service", () => {
  40 + let session = new SessionService($localStorage, $log);
  41 + let userResponse = <UserResponse>{
  42 + user: fixtures.user
  43 + };
  44 + $localStorage.currentUser = fixtures.user;
  45 + expect(session.currentUser()).toEqual($localStorage.currentUser);
  46 + });
  47 + });
  48 +
  49 +});
0 \ No newline at end of file 50 \ No newline at end of file
src/app/login/session.service.ts 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +import {Injectable, Inject} from "ng-forward";
  2 +import {UserResponse, INoosferoLocalStorage} from "./../shared/models/interfaces";
  3 +
  4 +@Injectable()
  5 +@Inject("$localStorage", "$log")
  6 +export class SessionService {
  7 +
  8 + constructor(private $localStorage: INoosferoLocalStorage, private $log: ng.ILogService) {
  9 +
  10 + }
  11 +
  12 + create(data: UserResponse): noosfero.User {
  13 + this.$localStorage.currentUser = data.user;
  14 + this.$log.debug('User session created.', this.$localStorage.currentUser);
  15 + return this.$localStorage.currentUser;
  16 + };
  17 +
  18 + destroy() {
  19 + delete this.$localStorage.currentUser;
  20 + this.$log.debug('User session destroyed.');
  21 + };
  22 +
  23 + currentUser(): noosfero.User {
  24 + return this.$localStorage.currentUser;
  25 + };
  26 +
  27 +}
0 \ No newline at end of file 28 \ No newline at end of file
src/app/main/main.component.ts
1 import {bundle, Component, StateConfig} from "ng-forward"; 1 import {bundle, Component, StateConfig} from "ng-forward";
2 -import {ArticleBlog} from "./../components/noosfero-articles/blog/blog.component"; 2 +import {ArticleBlogComponent} from "./../article/types/blog/blog.component";
3 3
4 -import {ArticleView} from "../components/noosfero-articles/article/article_view"; 4 +import {ArticleViewComponent} from "./../article/article-default-view.component";
5 5
6 -import {Profile} from "../profile/profile.component";  
7 -import {Boxes} from "../components/noosfero-boxes/boxes.component";  
8 -import {Block} from "../components/noosfero-blocks/block.component";  
9 -import {LinkListBlock} from "../components/noosfero-blocks/link-list/link-list.component";  
10 -import {RecentDocumentsBlock} from "../components/noosfero-blocks/recent-documents/recent-documents.component";  
11 -import {ProfileImageBlock} from "../components/noosfero-blocks/profile-image-block/profile-image-block.component";  
12 -import {RawHTMLBlock} from "../components/noosfero-blocks/raw-html/raw-html.component"; 6 +import {ProfileComponent} from "../profile/profile.component";
  7 +import {BoxesComponent} from "../layout/boxes/boxes.component";
  8 +import {BlockComponent} from "../layout/blocks/block.component";
  9 +import {LinkListBlockComponent} from "./../layout/blocks/link-list/link-list.component";
  10 +import {RecentDocumentsBlockComponent} from "../layout/blocks/recent-documents/recent-documents.component";
  11 +import {ProfileImageBlockComponent} from "../layout/blocks/profile-image-block/profile-image-block.component";
  12 +import {RawHTMLBlockComponent} from "../layout/blocks/raw-html/raw-html.component";
13 13
14 -import {MembersBlock} from "../components/noosfero-blocks/members-block/members-block.component";  
15 -import {NoosferoTemplate} from "../components/noosfero/noosfero-template.filter";  
16 -import {DateFormat} from "../components/noosfero/date-format/date-format.filter"; 14 +import {MembersBlockComponent} from "./../layout/blocks/members-block/members-block.component";
  15 +import {NoosferoTemplate} from "../shared/pipes/noosfero-template.filter";
  16 +import {DateFormat} from "../shared/pipes/date-format.filter";
17 17
18 -import {AuthService} from "./../components/auth/auth_service";  
19 -import {Session} from "./../components/auth/session";  
20 -import {Notification} from "./../components/notification/notification.component"; 18 +import {AuthService} from "../login/auth.service";
  19 +import {SessionService} from "../login/session.service";
21 20
  21 +import {NotificationService} from "../shared/services/notification.service";
22 22
23 -import {Navbar} from "../components/navbar/navbar";  
24 23
25 -import {MainBlock} from "../components/noosfero-blocks/main-block/main-block.component"; 24 +import {Navbar} from "../layout/navbar/navbar";
  25 +
  26 +import {MainBlockComponent} from "../layout/blocks/main-block/main-block.component";
26 27
27 28
28 /** 29 /**
@@ -38,7 +39,7 @@ import {MainBlock} from &quot;../components/noosfero-blocks/main-block/main-block.com @@ -38,7 +39,7 @@ import {MainBlock} from &quot;../components/noosfero-blocks/main-block/main-block.com
38 @Component({ 39 @Component({
39 selector: 'main-content', 40 selector: 'main-content',
40 templateUrl: "app/main/main.html", 41 templateUrl: "app/main/main.html",
41 - providers: [AuthService, Session] 42 + providers: [AuthService, SessionService]
42 }) 43 })
43 export class MainContent { 44 export class MainContent {
44 45
@@ -62,11 +63,11 @@ export class MainContent { @@ -62,11 +63,11 @@ export class MainContent {
62 selector: 'main', 63 selector: 'main',
63 template: '<div ng-view></div>', 64 template: '<div ng-view></div>',
64 directives: [ 65 directives: [
65 - ArticleBlog, ArticleView, Boxes, Block, LinkListBlock,  
66 - MainBlock, RecentDocumentsBlock, Navbar, ProfileImageBlock,  
67 - MembersBlock, NoosferoTemplate, DateFormat, RawHTMLBlock 66 + ArticleBlogComponent, ArticleViewComponent, BoxesComponent, BlockComponent, LinkListBlockComponent,
  67 + MainBlockComponent, RecentDocumentsBlockComponent, Navbar, ProfileImageBlockComponent,
  68 + MembersBlockComponent, NoosferoTemplate, DateFormat, RawHTMLBlockComponent
68 ], 69 ],
69 - providers: [AuthService, Session, Notification] 70 + providers: [AuthService, SessionService, NotificationService]
70 }) 71 })
71 @StateConfig([ 72 @StateConfig([
72 { 73 {
@@ -77,12 +78,12 @@ export class MainContent { @@ -77,12 +78,12 @@ export class MainContent {
77 { 78 {
78 url: "^/:profile", 79 url: "^/:profile",
79 abstract: true, 80 abstract: true,
80 - component: Profile, 81 + component: ProfileComponent,
81 name: 'main.profile', 82 name: 'main.profile',
82 views: { 83 views: {
83 "content": { 84 "content": {
84 templateUrl: "app/profile/profile.html", 85 templateUrl: "app/profile/profile.html",
85 - controller: Profile, 86 + controller: ProfileComponent,
86 controllerAs: "vm" 87 controllerAs: "vm"
87 } 88 }
88 } 89 }
src/app/models/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./interfaces";  
src/app/models/interfaces.ts
@@ -1,113 +0,0 @@ @@ -1,113 +0,0 @@
1 -export interface NoosferoRootScope extends ng.IScope {  
2 - currentUser: User;  
3 -}  
4 -  
5 -export interface Event extends Article {  
6 - id: number;  
7 -}  
8 -  
9 -export interface Article {  
10 - id: number;  
11 -}  
12 -  
13 -/**  
14 - * @ngdoc interface  
15 - * @name models.Profile  
16 - * @description  
17 - * A representation of a Noosfero Profile.  
18 - */  
19 -export interface Profile {  
20 -  
21 - /**  
22 - * @ngdoc property  
23 - * @name id  
24 - * @propertyOf models.Profile  
25 - * @returns {number} The Profile id  
26 - */  
27 - id: number;  
28 -  
29 - /**  
30 - * @ngdoc property  
31 - * @name identifier  
32 - * @propertyOf models.Profile  
33 - * @returns {string} The unque identifier for the Profile  
34 - */  
35 - identifier: string;  
36 -  
37 - /**  
38 - * @ngdoc property  
39 - * @name type  
40 - * @propertyOf models.Profile  
41 - * @returns {string} The Profile type (e.g.: "Person", etc.)  
42 - */  
43 - type: string;  
44 -}  
45 -  
46 -  
47 -/**  
48 - * @ngdoc interface  
49 - * @name models.Person  
50 - * @description  
51 - * A representation of a Person in Noosfero.  
52 - */  
53 -export interface Person extends Profile {  
54 - /**  
55 - * @ngdoc property  
56 - * @name id  
57 - * @propertyOf models.Person  
58 - * @returns {number} The Person id  
59 - */  
60 - id: number;  
61 -}  
62 -  
63 -export interface TynyMceArticle extends Article {  
64 - id: number;  
65 -}  
66 -  
67 -export interface Blog extends Article {  
68 - id: number;  
69 -}  
70 -  
71 -export interface Credentials {  
72 - username: string;  
73 - password: string;  
74 -}  
75 -  
76 -export interface User {  
77 - id: number;  
78 - login: string;  
79 - email: string;  
80 - person: Person;  
81 - private_token: string;  
82 - userRole: string;  
83 -}  
84 -  
85 -export interface UserResponse {  
86 - user: User;  
87 -}  
88 -  
89 -  
90 -export interface Box {  
91 - id: number;  
92 - position: number;  
93 -}  
94 -  
95 -/**  
96 - * @ngdoc interface  
97 - * @name models.Activity  
98 - * @description  
99 - * A representation of a {@link models.Profile} activity in Noosfero.  
100 - */  
101 -export interface Activity {  
102 - /**  
103 - * @ngdoc property  
104 - * @name verb  
105 - * @propertyOf models.Activity  
106 - * @returns {string} The activity verb.  
107 - */  
108 - verb: string;  
109 -}  
110 -  
111 -export interface INoosferoLocalStorage extends angular.storage.ILocalStorageService {  
112 - currentUser: User;  
113 -}  
src/app/profile-info/index.ts
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -/* Module Index Entry - generated using the script npm run generate-index */  
2 -export * from "./profile-info.component";  
src/app/profile-info/profile-info.component.spec.ts
@@ -1,40 +0,0 @@ @@ -1,40 +0,0 @@
1 -import {quickCreateComponent} from "../../spec/helpers";  
2 -import {ProfileInfo} from "./profile-info.component";  
3 -  
4 -describe("Components", () => {  
5 - describe("Profile Info Component", () => {  
6 -  
7 - let $rootScope: ng.IRootScopeService;  
8 - let $q: ng.IQService;  
9 - let profileServiceMock: any;  
10 - let $stateParams: any;  
11 -  
12 - beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => {  
13 - $rootScope = _$rootScope_;  
14 - $q = _$q_;  
15 - }));  
16 -  
17 - beforeEach(() => {  
18 - $stateParams = jasmine.createSpyObj("$stateParams", ["profile"]);  
19 - profileServiceMock = jasmine.createSpyObj("profileServiceMock", ["getCurrentProfile", "getActivities"]);  
20 -  
21 - let getCurrentProfileResponse = $q.defer();  
22 - getCurrentProfileResponse.resolve({ id: 1 });  
23 -  
24 - let getActivitiesResponse = $q.defer();  
25 - getActivitiesResponse.resolve({ data: { activities: [{ id: 1 }, { id: 2 }] } });  
26 -  
27 - profileServiceMock.getCurrentProfile = jasmine.createSpy("getCurrentProfile").and.returnValue(getCurrentProfileResponse.promise);  
28 - profileServiceMock.getActivities = jasmine.createSpy("getActivities").and.returnValue(getActivitiesResponse.promise);  
29 - });  
30 -  
31 - it("get the profile activities", done => {  
32 - let component: ProfileInfo = new ProfileInfo(profileServiceMock);  
33 - $rootScope.$apply();  
34 - expect(profileServiceMock.getCurrentProfile).toHaveBeenCalled();  
35 - expect(profileServiceMock.getActivities).toHaveBeenCalled();  
36 - expect(component.activities).toEqual([{ id: 1 }, { id: 2 }]);  
37 - done();  
38 - });  
39 - });  
40 -});  
src/app/profile-info/profile-info.component.ts
@@ -1,29 +0,0 @@ @@ -1,29 +0,0 @@
1 -import {StateConfig, Component, Inject, provide} from 'ng-forward';  
2 -  
3 -import {Profile} from "./../models/interfaces";  
4 -import {ProfileService} from "../../lib/ng-noosfero-api/http/profile.service";  
5 -  
6 -@Component({  
7 - selector: 'profile',  
8 - templateUrl: "app/profile-info/profile-info.html",  
9 - providers: [provide('profileService', { useClass: ProfileService })]  
10 -})  
11 -@Inject(ProfileService)  
12 -export class ProfileInfo {  
13 -  
14 - activities: any  
15 - profile: any  
16 -  
17 - constructor(private profileService: ProfileService) {  
18 - this.activate();  
19 - }  
20 -  
21 - activate() {  
22 - this.profileService.getCurrentProfile().then((profile: Profile) => {  
23 - this.profile = profile;  
24 - return this.profileService.getActivities(this.profile.id);  
25 - }).then((response: restangular.IResponse) => {  
26 - this.activities = response.data.activities;  
27 - });  
28 - }  
29 -}  
src/app/profile-info/profile-info.html
@@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
1 -<h3>{{vm.profile.name}}</h3>  
2 -  
3 -<div class="profile-wall">  
4 - <h4>{{"profile.wall" | translate}}</h4>  
5 - <noosfero-activities [activities]="vm.activities"></noosfero-activities>  
6 -</div>  
src/app/profile/activities/activities.component.spec.ts 0 → 100644
@@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Pipe, Input, provide, Component} from 'ng-forward';
  3 +import {provideFilters} from '../../../spec/helpers';
  4 +
  5 +import {ActivitiesComponent} from './activities.component';
  6 +
  7 +const tcb = new TestComponentBuilder();
  8 +
  9 +const htmlTemplate: string = '<noosfero-activities [activities]="ctrl.activities"></noosfero-activities>';
  10 +
  11 +
  12 +describe("Components", () => {
  13 +
  14 + describe("Noosfero Activities", () => {
  15 +
  16 + beforeEach(angular.mock.module("templates"));
  17 +
  18 + @Component({
  19 + selector: 'test-container-component',
  20 + template: htmlTemplate,
  21 + directives: [ActivitiesComponent],
  22 + providers: provideFilters("truncateFilter", "stripTagsFilter", "translateFilter")
  23 + })
  24 + class BlockContainerComponent {
  25 + activities = [{ name: "activity1", verb: "create_article" }, { name: "activity2", verb: "create_article" }];
  26 + }
  27 +
  28 + it("render a noosfero activity tag for each activity", done => {
  29 + tcb.createAsync(BlockContainerComponent).then(fixture => {
  30 + expect(fixture.debugElement.queryAll("noosfero-activity").length).toEqual(2);
  31 + done();
  32 + });
  33 + });
  34 + });
  35 +
  36 +});
src/app/profile/activities/activities.component.ts 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +import {Component, Input} from "ng-forward";
  2 +import {ActivityComponent} from "./activity/activity.component";
  3 +
  4 +/**
  5 + * @ngdoc controller
  6 + * @name NoosferoActivities
  7 + * @description
  8 + * The controller responsible to retreive profile activities.
  9 + */
  10 +
  11 +@Component({
  12 + selector: "noosfero-activities",
  13 + templateUrl: 'app/profile/activities/activities.html',
  14 + directives: [ActivityComponent]
  15 +})
  16 +export class ActivitiesComponent {
  17 +
  18 + /**
  19 + * @ngdoc property
  20 + * @propertyOf NoosferoActivities
  21 + * @name activities
  22 + * @returns {Activity[]} An array of {@link Activity}.
  23 + */
  24 + @Input() activities: noosfero.Activity[];
  25 +
  26 +
  27 +}
src/app/profile/activities/activities.html 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +<timeline>
  2 + <timeline-event ng-repeat="activity in ctrl.activities | orderBy: 'created_at':true">
  3 + <noosfero-activity [activity]="activity"></noosfero-activity>
  4 + </timeline-event>
  5 +</timeline>
src/app/profile/activities/activities.scss 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +.comma-separated {
  2 + .separated-item {
  3 + &:after {
  4 + content: ", ";
  5 + margin-left: -3px;
  6 + }
  7 + &:last-child:after {
  8 + content: "";
  9 + }
  10 + }
  11 +}
src/app/profile/activities/activity/activity.component.spec.ts 0 → 100644
@@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Pipe, Input, provide, Component} from 'ng-forward';
  3 +import {provideFilters} from '../../../../spec/helpers';
  4 +
  5 +import {ActivityComponent} from './activity.component';
  6 +
  7 +const tcb = new TestComponentBuilder();
  8 +
  9 +const htmlTemplate: string = '<noosfero-activity [activity]="ctrl.activity"></noosfero-activity>';
  10 +
  11 +
  12 +describe("Components", () => {
  13 +
  14 + describe("Noosfero Activity", () => {
  15 +
  16 + beforeEach(angular.mock.module("templates"));
  17 +
  18 + @Component({
  19 + selector: 'test-container-component',
  20 + template: htmlTemplate,
  21 + directives: [ActivityComponent],
  22 + providers: provideFilters("truncateFilter", "stripTagsFilter", "translateFilter")
  23 + })
  24 + class BlockContainerComponent {
  25 + activity = { name: "activity1", verb: "create_article" };
  26 + }
  27 +
  28 + it("render the specific template for an activity verb", done => {
  29 + tcb.createAsync(BlockContainerComponent).then(fixture => {
  30 + let component: ActivityComponent = fixture.debugElement.componentViewChildren[0].componentInstance;
  31 + expect(component.getActivityTemplate()).toEqual('app/profile/activities/activity/create_article.html');
  32 + expect(fixture.debugElement.queryAll(".activity.create_article").length).toEqual(1);
  33 + done();
  34 + });
  35 + });
  36 + });
  37 +
  38 +});
src/app/profile/activities/activity/activity.component.ts 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +import {Component, Input} from "ng-forward";
  2 +
  3 +@Component({
  4 + selector: "noosfero-activity",
  5 + templateUrl: 'app/profile/activities/activity/activity.html'
  6 +})
  7 +export class ActivityComponent {
  8 +
  9 + @Input() activity: noosfero.Activity;
  10 +
  11 + getActivityTemplate() {
  12 + return 'app/profile/activities/activity/' + this.activity.verb + '.html';
  13 + }
  14 +
  15 +}
src/app/profile/activities/activity/activity.html 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<div class="activity {{ctrl.activity.verb}}">
  2 + <ng-include src="ctrl.getActivityTemplate()"></ng-include>
  3 +</div>
src/app/profile/activities/activity/add_member_in_community.html 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +<timeline-badge class="info">
  2 + <i class="fa fa-user-plus"></i>
  3 +</timeline-badge>
  4 +<timeline-panel>
  5 + <timeline-heading>
  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>
  8 + <span> {{"activities.add_member_in_community.description" | translate}}</span>
  9 + </h4>
  10 + <p><small class="text-muted"><i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.activity.created_at | dateFormat"></span></small></p>
  11 + </timeline-heading>
  12 + <div class="timeline-body"></div>
  13 +</timeline-panel>
src/app/profile/activities/activity/create_article.html 0 → 100644
@@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
  1 +<timeline-badge class="success">
  2 + <i class="fa fa-file-text"></i>
  3 +</timeline-badge>
  4 +<timeline-panel>
  5 + <timeline-heading>
  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>
  8 + <span> {{"activities.create_article.description" | translate}} </span>
  9 + <a ui-sref="main.profile.info({profile: ctrl.activity.target.article.profile.identifier})">
  10 + <strong ng-bind="ctrl.activity.target.article.profile.name"></strong></span>
  11 + </a>
  12 + </h4>
  13 + <p><small class="text-muted"><i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.activity.created_at | dateFormat"></span></small></p>
  14 + </timeline-heading>
  15 + <div class="timeline-body">
  16 + <div class="article">
  17 + <div class="title">
  18 + <a ui-sref="main.profile.page({profile: ctrl.activity.target.article.profile.identifier, page: ctrl.activity.target.article.path})"
  19 + ng-bind="ctrl.activity.target.article.title"></a>
  20 + </div>
  21 + <div class="lead small">
  22 + <div ng-bind-html="ctrl.activity.target.article.body | stripTags | truncate: 100 : '...': true"></div>
  23 + </div>
  24 + </div>
  25 + </div>
  26 +</timeline-panel>
src/app/profile/activities/activity/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./activity.component";
src/app/profile/activities/activity/new_friendship.html 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +<timeline-badge class="info">
  2 + <i class="fa fa-user-plus"></i>
  3 +</timeline-badge>
  4 +<timeline-panel>
  5 + <timeline-heading>
  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>
  8 + <span> {{"activities.new_friendship.description" | translate:{friends: ctrl.activity.params.friend_name.length}:"messageformat" }} </span>
  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">
  11 + <strong ng-bind="friend"></strong>
  12 + </a>
  13 + </span>
  14 + </h4>
  15 + <p><small class="text-muted"><i class="fa fa-clock-o"></i> <span am-time-ago="ctrl.activity.created_at | dateFormat"></span></small></p>
  16 + </timeline-heading>
  17 + <div class="timeline-body"></div>
  18 +</timeline-panel>
src/app/profile/activities/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./activities.component";
src/app/profile/image/image.component.spec.ts 0 → 100644
@@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
  1 +/**
  2 + * @ngdoc overview
  3 + * @name components.noosfero.profile-image.ProfileImageSpec
  4 + * @description
  5 + * This file contains the tests for the {@link components.noosfero.profile-image.ProfileImage} component.
  6 + */
  7 +
  8 +import {TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  9 +import {Pipe, Input, provide, Component} from 'ng-forward';
  10 +
  11 +import * as helpers from "../../../spec/helpers";
  12 +
  13 +import {ProfileImageComponent} from "./image.component";
  14 +
  15 +const tcb = new TestComponentBuilder();
  16 +
  17 +describe("Components", () => {
  18 +
  19 + describe("Profile Image Component", () => {
  20 +
  21 + beforeEach(angular.mock.module("templates"));
  22 +
  23 + it("show community users image if profile is not Person", done => {
  24 + helpers.tcb.createAsync(ProfileImageComponent).then(fixture => {
  25 + let profileImageComponent: ProfileImageComponent = fixture.componentInstance;
  26 + let profile = <noosfero.Profile>{ id: 1, identifier: "myprofile", type: "Community" };
  27 + profileImageComponent.profile = profile;
  28 + profileImageComponent.ngOnInit();
  29 +
  30 + // Check the attribute
  31 + expect(profileImageComponent.defaultIcon).toBe("fa-users", "The default icon should be community users");
  32 + // var elProfile = fixture.debugElement.componentViewChildren[0];
  33 + // expect(elProfile.query('div.profile-image-block').length).toEqual(1);
  34 + done();
  35 + });
  36 + });
  37 +
  38 + it("show Person image if profile is Person", done => {
  39 + tcb.createAsync(ProfileImageComponent).then(fixture => {
  40 + let profileImageComponent: ProfileImageComponent = fixture.componentInstance;
  41 + let profile = <noosfero.Profile>{ id: 1, identifier: "myprofile", type: "Person" };
  42 + profileImageComponent.profile = profile;
  43 + profileImageComponent.ngOnInit();
  44 + // Check the attribute
  45 + expect(profileImageComponent.defaultIcon).toEqual("fa-user", "The default icon should be person user");
  46 + done();
  47 + });
  48 + });
  49 +
  50 + });
  51 +});
0 \ No newline at end of file 52 \ No newline at end of file
src/app/profile/image/image.component.ts 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +import {Inject, Input, Component} from "ng-forward";
  2 +
  3 +
  4 +/**
  5 + * @ngdoc controller
  6 + * @name components.noosfero.profile-image.ProfileImage
  7 + * @description The component responsible for rendering the profile image
  8 + * @exports ProfileImage
  9 + */
  10 +@Component({
  11 + selector: "noosfero-profile-image",
  12 + templateUrl: 'app/profile/image/image.html',
  13 +})
  14 +export class ProfileImageComponent {
  15 +
  16 + /**
  17 + * @ngdoc property
  18 + * @name profile
  19 + * @propertyOf components.noosfero.profile-image.ProfileImage
  20 + * @description
  21 + * The Noosfero {@link models.Profile} holding the image.
  22 + */
  23 + @Input() profile: noosfero.Profile;
  24 + /**
  25 + * @ngdoc property
  26 + * @name defaultIcon
  27 + * @propertyOf components.noosfero.profile-image.ProfileImage
  28 + * @descritpion
  29 + * The default icon used by this profile
  30 + */
  31 + defaultIcon: string;
  32 +
  33 + /**
  34 + * @ngdoc method
  35 + * @name ngOnInit
  36 + * @methodOf components.noosfero.profile-image.ProfileImage
  37 + * @description
  38 + * Initializes the icon names to their corresponding values depending on the profile type passed to the controller
  39 + */
  40 + ngOnInit() {
  41 + this.defaultIcon = 'fa-users';
  42 + if (this.profile && this.profile.type === 'Person') {
  43 + this.defaultIcon = 'fa-user';
  44 + }
  45 + }
  46 +}
  47 +
src/app/profile/image/image.html 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +<span title="{{ctrl.profile.name}}">
  2 + <img ng-if="ctrl.profile.image" ng-src="{{ctrl.profile.image.url}}" class="img-responsive profile-image">
  3 + <i ng-if="!ctrl.profile.image" class="fa {{ctrl.defaultIcon}} fa-5x profile-image"></i>
  4 +</span>
src/app/profile/image/image.scss 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +i.profile-image {
  2 + color: rgb(44, 62, 80);
  3 +}
src/app/profile/image/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./image.component";
src/app/profile/index.ts
1 /* Module Index Entry - generated using the script npm run generate-index */ 1 /* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./myprofile.component";
2 export * from "./profile-home.component"; 3 export * from "./profile-home.component";
3 export * from "./profile.component"; 4 export * from "./profile.component";
src/app/profile/info/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./profile-info.component";
src/app/profile/info/profile-info.component.spec.ts 0 → 100644
@@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
  1 +import {quickCreateComponent} from "../../../spec/helpers";
  2 +import {ProfileInfoComponent} from "./profile-info.component";
  3 +
  4 +describe("Components", () => {
  5 + describe("Profile Info Component", () => {
  6 +
  7 + let $rootScope: ng.IRootScopeService;
  8 + let $q: ng.IQService;
  9 + let profileServiceMock: any;
  10 + let $stateParams: any;
  11 +
  12 + beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => {
  13 + $rootScope = _$rootScope_;
  14 + $q = _$q_;
  15 + }));
  16 +
  17 + beforeEach(() => {
  18 + $stateParams = jasmine.createSpyObj("$stateParams", ["profile"]);
  19 + profileServiceMock = jasmine.createSpyObj("profileServiceMock", ["getCurrentProfile", "getActivities"]);
  20 +
  21 + let getCurrentProfileResponse = $q.defer();
  22 + getCurrentProfileResponse.resolve({ id: 1 });
  23 +
  24 + let getActivitiesResponse = $q.defer();
  25 + getActivitiesResponse.resolve({ data: { activities: [{ id: 1 }, { id: 2 }] } });
  26 +
  27 + profileServiceMock.getCurrentProfile = jasmine.createSpy("getCurrentProfile").and.returnValue(getCurrentProfileResponse.promise);
  28 + profileServiceMock.getActivities = jasmine.createSpy("getActivities").and.returnValue(getActivitiesResponse.promise);
  29 + });
  30 +
  31 + it("get the profile activities", done => {
  32 + let component: ProfileInfoComponent = new ProfileInfoComponent(profileServiceMock);
  33 + $rootScope.$apply();
  34 + expect(profileServiceMock.getCurrentProfile).toHaveBeenCalled();
  35 + expect(profileServiceMock.getActivities).toHaveBeenCalled();
  36 + expect(component.activities).toEqual([{ id: 1 }, { id: 2 }]);
  37 + done();
  38 + });
  39 + });
  40 +});
src/app/profile/info/profile-info.component.ts 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +import {StateConfig, Component, Inject, provide} from 'ng-forward';
  2 +import {ProfileService} from "../../../lib/ng-noosfero-api/http/profile.service";
  3 +
  4 +@Component({
  5 + selector: 'profile',
  6 + templateUrl: "app/profile/info/profile-info.html",
  7 + providers: [provide('profileService', { useClass: ProfileService })]
  8 +})
  9 +@Inject(ProfileService)
  10 +export class ProfileInfoComponent {
  11 +
  12 + activities: any;
  13 + profile: noosfero.Profile;
  14 +
  15 + constructor(private profileService: ProfileService) {
  16 + this.activate();
  17 + }
  18 +
  19 + activate() {
  20 + this.profileService.getCurrentProfile().then((profile: noosfero.Profile) => {
  21 + this.profile = profile;
  22 + return this.profileService.getActivities(<number>this.profile.id);
  23 + }).then((response: restangular.IResponse) => {
  24 + this.activities = response.data.activities;
  25 + });
  26 + }
  27 +}
src/app/profile/info/profile-info.html 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +<h3>{{vm.profile.name}}</h3>
  2 +
  3 +<div class="profile-wall">
  4 + <h4>{{"profile.wall" | translate}}</h4>
  5 + <noosfero-activities [activities]="vm.activities"></noosfero-activities>
  6 +</div>
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 &quot;../../lib/ng-noosfero-api/http/profile.service&quot;; @@ -11,12 +10,12 @@ import {ProfileService} from &quot;../../lib/ng-noosfero-api/http/profile.service&quot;;
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
1 import {quickCreateComponent} from "../../spec/helpers"; 1 import {quickCreateComponent} from "../../spec/helpers";
2 -import {Profile} from "./profile.component"; 2 +import {ProfileComponent} from "./profile.component";
3 3
4 describe("Components", () => { 4 describe("Components", () => {
5 describe("Profile Component", () => { 5 describe("Profile Component", () => {
@@ -30,7 +30,7 @@ describe(&quot;Components&quot;, () =&gt; { @@ -30,7 +30,7 @@ describe(&quot;Components&quot;, () =&gt; {
30 }); 30 });
31 31
32 it("get the profile and store in profile service", done => { 32 it("get the profile and store in profile service", done => {
33 - let component: Profile = new Profile(profileServiceMock, $stateParams, notificationMock); 33 + let component: ProfileComponent = new ProfileComponent(profileServiceMock, $stateParams, notificationMock);
34 $rootScope.$apply(); 34 $rootScope.$apply();
35 expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled(); 35 expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled();
36 expect(component.profile).toEqual({ id: 1 }); 36 expect(component.profile).toEqual({ id: 1 });
@@ -38,7 +38,7 @@ describe(&quot;Components&quot;, () =&gt; { @@ -38,7 +38,7 @@ describe(&quot;Components&quot;, () =&gt; {
38 }); 38 });
39 39
40 it("get the profile boxes", done => { 40 it("get the profile boxes", done => {
41 - let component: Profile = new Profile(profileServiceMock, $stateParams, notificationMock); 41 + let component: ProfileComponent = new ProfileComponent(profileServiceMock, $stateParams, notificationMock);
42 $rootScope.$apply(); 42 $rootScope.$apply();
43 expect(profileServiceMock.getBoxes).toHaveBeenCalled(); 43 expect(profileServiceMock.getBoxes).toHaveBeenCalled();
44 expect(component.boxes).toEqual([{ id: 2 }]); 44 expect(component.boxes).toEqual([{ id: 2 }]);
@@ -50,7 +50,7 @@ describe(&quot;Components&quot;, () =&gt; { @@ -50,7 +50,7 @@ describe(&quot;Components&quot;, () =&gt; {
50 profileResponse.reject(); 50 profileResponse.reject();
51 profileServiceMock.setCurrentProfileByIdentifier = jasmine.createSpy("setCurrentProfileByIdentifier").and.returnValue(profileResponse.promise); 51 profileServiceMock.setCurrentProfileByIdentifier = jasmine.createSpy("setCurrentProfileByIdentifier").and.returnValue(profileResponse.promise);
52 52
53 - let component: Profile = new Profile(profileServiceMock, $stateParams, notificationMock); 53 + let component: ProfileComponent = new ProfileComponent(profileServiceMock, $stateParams, notificationMock);
54 $rootScope.$apply(); 54 $rootScope.$apply();
55 55
56 expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled(); 56 expect(profileServiceMock.setCurrentProfileByIdentifier).toHaveBeenCalled();
src/app/profile/profile.component.ts
1 import {StateConfig, Component, Inject, provide} from 'ng-forward'; 1 import {StateConfig, Component, Inject, provide} from 'ng-forward';
2 -import {ProfileInfo} from '../profile-info/profile-info.component';  
3 -import {ProfileHome} from '../profile/profile-home.component';  
4 -import {Cms} from '../cms/cms.component';  
5 -import {ContentViewer} from "../content-viewer/content-viewer.component";  
6 -import {ContentViewerActions} from "../content-viewer/content-viewer-actions.component";  
7 -import {NoosferoActivities} from "../components/noosfero-activities/activities.component"; 2 +import {ProfileInfoComponent} from './info/profile-info.component';
  3 +import {ProfileHome} from './profile-home.component';
  4 +import {BasicEditorComponent} from '../article/basic-editor.component';
  5 +import {ContentViewerComponent} from "../article/content-viewer/content-viewer.component";
  6 +import {ContentViewerActions} from "../article/content-viewer/content-viewer-actions.component";
  7 +import {ActivitiesComponent} from "./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 -import {Notification} from "../components/notification/notification.component"; 9 +import {NotificationService} from "../shared/services/notification.service";
10 import {MyProfile} from "./myprofile.component"; 10 import {MyProfile} from "./myprofile.component";
11 11
12 -import * as noosferoModels from "./../models/interfaces";  
13 12
14 /** 13 /**
15 * @ngdoc controller 14 * @ngdoc controller
@@ -17,24 +16,25 @@ import * as noosferoModels from &quot;./../models/interfaces&quot;; @@ -17,24 +16,25 @@ import * as noosferoModels from &quot;./../models/interfaces&quot;;
17 * @description 16 * @description
18 * This is the profile controller. It provide routes to supported Noosfero Profiles. 17 * This is the profile controller. It provide routes to supported Noosfero Profiles.
19 */ 18 */
  19 +
20 @Component({ 20 @Component({
21 selector: 'profile', 21 selector: 'profile',
22 templateUrl: "app/profile/profile.html", 22 templateUrl: "app/profile/profile.html",
23 - directives: [NoosferoActivities], 23 + directives: [ActivitiesComponent],
24 providers: [ 24 providers: [
25 provide('profileService', { useClass: ProfileService }), 25 provide('profileService', { useClass: ProfileService }),
26 - provide('notification', { useClass: Notification }) 26 + provide('notificationService', { useClass: NotificationService })
27 ] 27 ]
28 }) 28 })
29 @StateConfig([ 29 @StateConfig([
30 { 30 {
31 name: 'main.profile.info', 31 name: 'main.profile.info',
32 url: "^/profile/:profile", 32 url: "^/profile/:profile",
33 - component: ProfileInfo, 33 + component: ProfileInfoComponent,
34 views: { 34 views: {
35 "mainBlockContent": { 35 "mainBlockContent": {
36 - templateUrl: "app/profile-info/profile-info.html",  
37 - controller: ProfileInfo, 36 + templateUrl: "app/profile/info/profile-info.html",
  37 + controller: ProfileInfoComponent,
38 controllerAs: "vm" 38 controllerAs: "vm"
39 } 39 }
40 } 40 }
@@ -47,11 +47,11 @@ import * as noosferoModels from &quot;./../models/interfaces&quot;; @@ -47,11 +47,11 @@ import * as noosferoModels from &quot;./../models/interfaces&quot;;
47 { 47 {
48 name: 'main.profile.cms', 48 name: 'main.profile.cms',
49 url: "^/myprofile/:profile/cms", 49 url: "^/myprofile/:profile/cms",
50 - component: Cms, 50 + component: BasicEditorComponent,
51 views: { 51 views: {
52 "mainBlockContent": { 52 "mainBlockContent": {
53 - templateUrl: "app/cms/cms.html",  
54 - controller: Cms, 53 + templateUrl: "app/article/basic-editor.html",
  54 + controller: BasicEditorComponent,
55 controllerAs: "vm" 55 controllerAs: "vm"
56 } 56 }
57 } 57 }
@@ -70,15 +70,15 @@ import * as noosferoModels from &quot;./../models/interfaces&quot;; @@ -70,15 +70,15 @@ import * as noosferoModels from &quot;./../models/interfaces&quot;;
70 { 70 {
71 name: 'main.profile.page', 71 name: 'main.profile.page',
72 url: "/{page:any}", 72 url: "/{page:any}",
73 - component: ContentViewer, 73 + component: ContentViewerComponent,
74 views: { 74 views: {
75 "mainBlockContent": { 75 "mainBlockContent": {
76 - templateUrl: "app/content-viewer/page.html",  
77 - controller: ContentViewer, 76 + templateUrl: "app/article/content-viewer/page.html",
  77 + controller: ContentViewerComponent,
78 controllerAs: "vm" 78 controllerAs: "vm"
79 }, 79 },
80 "actions@main": { 80 "actions@main": {
81 - templateUrl: "app/content-viewer/navbar-actions.html", 81 + templateUrl: "app/article/content-viewer/navbar-actions.html",
82 controller: ContentViewerActions, 82 controller: ContentViewerActions,
83 controllerAs: "vm" 83 controllerAs: "vm"
84 } 84 }
@@ -86,19 +86,19 @@ import * as noosferoModels from &quot;./../models/interfaces&quot;; @@ -86,19 +86,19 @@ import * as noosferoModels from &quot;./../models/interfaces&quot;;
86 } 86 }
87 ]) 87 ])
88 @Inject(ProfileService, "$stateParams") 88 @Inject(ProfileService, "$stateParams")
89 -export class Profile { 89 +export class ProfileComponent {
90 90
91 - boxes: noosferoModels.Box[];  
92 - profile: noosferoModels.Profile; 91 + boxes: noosfero.Box[];
  92 + profile: noosfero.Profile;
93 93
94 - constructor(profileService: ProfileService, $stateParams: ng.ui.IStateParamsService, notification: Notification) {  
95 - profileService.setCurrentProfileByIdentifier($stateParams["profile"]).then((profile: noosferoModels.Profile) => { 94 + constructor(profileService: ProfileService, $stateParams: ng.ui.IStateParamsService, notificationService: NotificationService) {
  95 + profileService.setCurrentProfileByIdentifier($stateParams["profile"]).then((profile: noosfero.Profile) => {
96 this.profile = profile; 96 this.profile = profile;
97 - return profileService.getBoxes(this.profile.id); 97 + return profileService.getBoxes(<number>this.profile.id);
98 }).then((response: restangular.IResponse) => { 98 }).then((response: restangular.IResponse) => {
99 this.boxes = response.data.boxes; 99 this.boxes = response.data.boxes;
100 }).catch(() => { 100 }).catch(() => {
101 - notification.error("notification.profile.not_found"); 101 + notificationService.error("notification.profile.not_found");
102 }); 102 });
103 } 103 }
104 } 104 }
src/app/profile/profile.scss
1 .profile-container { 1 .profile-container {
2 @extend .container-fluid; 2 @extend .container-fluid;
3 - padding: 0 12%; 3 + padding: 0 1%;
4 @media (max-width: 978px) { 4 @media (max-width: 978px) {
5 padding: 0 2%; 5 padding: 0 2%;
6 } 6 }
src/app/registration/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
src/app/shared/components/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
src/app/shared/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
src/app/shared/models/index.ts 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./interfaces";
src/app/shared/models/interfaces.ts 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +export interface NoosferoRootScope extends ng.IScope {
  2 + currentUser: noosfero.User;
  3 +}
  4 +
  5 +export interface UserResponse {
  6 + user: noosfero.User;
  7 +}
  8 +
  9 +
  10 +export interface INoosferoLocalStorage extends angular.storage.ILocalStorageService {
  11 + currentUser: noosfero.User;
  12 +}
src/app/shared/pipes/date-format.filter.spec.ts 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +import {quickCreateComponent} from "../../../spec/helpers";
  2 +import {DateFormat} from './date-format.filter';
  3 +
  4 +describe("Filters", () => {
  5 + describe("Date Format Filter", () => {
  6 +
  7 + beforeEach(angular.mock.module("templates"));
  8 + beforeEach(angular.mock.module("angularMoment"));
  9 +
  10 + it("convert date from the format returned by noosfero api to an ISO format", done => {
  11 + let date = "2016/03/10 10:46:47";
  12 + let htmlTemplate = `{{ '${date}' | dateFormat }}`;
  13 + quickCreateComponent({ providers: [DateFormat], template: htmlTemplate }).then(fixture => {
  14 + expect(fixture.debugElement.text()).toEqual('2016-03-10T13:46:47.000Z');
  15 + done();
  16 + });
  17 + });
  18 +
  19 + });
  20 +});
src/app/shared/pipes/date-format.filter.ts 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +import {Pipe, Inject} from "ng-forward";
  2 +
  3 +@Pipe("dateFormat")
  4 +@Inject("amParseFilter")
  5 +export class DateFormat {
  6 +
  7 + constructor(private amParseFilter: any) { }
  8 +
  9 + transform(date: string, options: any) {
  10 + return this.amParseFilter(date, "YYYY/MM/DD HH:mm:ss").toISOString();
  11 + }
  12 +
  13 +}
src/app/shared/pipes/index.ts 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./date-format.filter";
  3 +export * from "./noosfero-template.filter";
src/app/shared/pipes/noosfero-template.filter.spec.ts 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +import {quickCreateComponent} from "../../../spec/helpers";
  2 +import {NoosferoTemplate} from './noosfero-template.filter';
  3 +
  4 +describe("Filters", () => {
  5 + describe("Noosfero Template Filter", () => {
  6 +
  7 + beforeEach(angular.mock.module("templates"));
  8 +
  9 + it("replace the options in text with the values passed on options", done => {
  10 + let text = 'profile: {profile}, other: {other}';
  11 + let htmlTemplate = `{{ '${text}' | noosferoTemplate: {profile: 'profile1', other: 'other value'} }}`;
  12 + quickCreateComponent({ providers: [NoosferoTemplate], template: htmlTemplate }).then(fixture => {
  13 + expect(fixture.debugElement.text()).toEqual("profile: profile1, other: other value");
  14 + done();
  15 + });
  16 + });
  17 +
  18 + });
  19 +});
src/app/shared/pipes/noosfero-template.filter.ts 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +import {Pipe} from "ng-forward";
  2 +
  3 +@Pipe("noosferoTemplate")
  4 +export class NoosferoTemplate {
  5 +
  6 + transform(text: string, options: any) {
  7 + for (let option in options) {
  8 + text = text.replace('{' + option + '}', options[option]);
  9 + }
  10 + return text;
  11 + }
  12 +
  13 +}
src/app/shared/services/index.ts 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +/* Module Index Entry - generated using the script npm run generate-index */
  2 +export * from "./notification.service";
  3 +export * from "./translator.service";
src/app/shared/services/notification.service.spec.ts 0 → 100644
@@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
  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 {NotificationService} from "./notification.service";
  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("display an error message when notify an error", done => {
  17 + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
  18 + sweetAlert.swal = jasmine.createSpy("swal");
  19 +
  20 + let component: NotificationService = new NotificationService(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);
  21 + component.error("message", "title");
  22 + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
  23 + text: "message",
  24 + title: "title",
  25 + type: "error"
  26 + }));
  27 + done();
  28 + });
  29 +
  30 + it("use the default message when call notification component without a message", done => {
  31 + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
  32 + sweetAlert.swal = jasmine.createSpy("swal");
  33 +
  34 + let component: NotificationService = new NotificationService(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);
  35 + component.error();
  36 + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
  37 + text: NotificationService.DEFAULT_ERROR_MESSAGE,
  38 + type: "error"
  39 + }));
  40 + done();
  41 + });
  42 +
  43 + it("display a success message when call notification success", done => {
  44 + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
  45 + sweetAlert.swal = jasmine.createSpy("swal");
  46 +
  47 + let component: NotificationService = new NotificationService(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);
  48 + component.success("title", "message", 1000);
  49 + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
  50 + type: "success"
  51 + }));
  52 + done();
  53 + });
  54 +
  55 + it("display a message relative to the http error code", done => {
  56 + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
  57 + sweetAlert.swal = jasmine.createSpy("swal");
  58 +
  59 + let component: NotificationService = new NotificationService(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);
  60 + component.httpError(500, {});
  61 + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
  62 + text: "notification.http_error.500.message"
  63 + }));
  64 + done();
  65 + });
  66 +
  67 + it("set the default timer in success messages", done => {
  68 + let sweetAlert = jasmine.createSpyObj("sweetAlert", ["swal"]);
  69 + sweetAlert.swal = jasmine.createSpy("swal");
  70 +
  71 + let component: NotificationService = new NotificationService(<any>helpers.mocks.$log, <any>sweetAlert, <any>helpers.mocks.translatorService);
  72 + component.success("title", "message");
  73 + expect(sweetAlert.swal).toHaveBeenCalledWith(jasmine.objectContaining({
  74 + type: "success",
  75 + timer: NotificationService.DEFAULT_SUCCESS_TIMER
  76 + }));
  77 + done();
  78 + });
  79 + });
  80 +});
src/app/shared/services/notification.service.ts 0 → 100644
@@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
  1 +import {Injectable, Inject} from "ng-forward";
  2 +import {TranslatorService} from "./translator.service";
  3 +
  4 +@Injectable()
  5 +@Inject("$log", "SweetAlert", TranslatorService)
  6 +export class NotificationService {
  7 +
  8 + constructor(
  9 + private $log: ng.ILogService,
  10 + private SweetAlert: any,
  11 + private translatorService: TranslatorService
  12 + ) { }
  13 +
  14 + public static DEFAULT_ERROR_TITLE = "notification.error.default.title";
  15 + public static DEFAULT_ERROR_MESSAGE = "notification.error.default.message";
  16 + public static DEFAULT_SUCCESS_TIMER = 1000;
  17 +
  18 + error(message: string = NotificationService.DEFAULT_ERROR_MESSAGE, title: string = NotificationService.DEFAULT_ERROR_TITLE) {
  19 + this.$log.debug("Notification error:", title, message, this.translatorService.currentLanguage());
  20 + this.SweetAlert.swal({
  21 + title: this.translatorService.translate(title),
  22 + text: this.translatorService.translate(message),
  23 + type: "error"
  24 + });
  25 + }
  26 +
  27 + httpError(status: number, data: any): boolean {
  28 + this.error(`notification.http_error.${status}.message`);
  29 + return true; // return true to indicate that the error was already handled
  30 + }
  31 +
  32 + success(title: string, text: string, timer: number = NotificationService.DEFAULT_SUCCESS_TIMER) {
  33 + this.SweetAlert.swal({
  34 + title: title,
  35 + text: text,
  36 + type: "success",
  37 + timer: timer
  38 + });
  39 + }
  40 +
  41 +}
src/app/shared/services/translator.service.spec.ts 0 → 100644
@@ -0,0 +1,116 @@ @@ -0,0 +1,116 @@
  1 +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {provide} from 'ng-forward';
  3 +
  4 +import {TranslatorService} from './translator.service';
  5 +
  6 +import * as helpers from "../../../spec/helpers";
  7 +
  8 +describe("Services", () => {
  9 +
  10 + describe("Translator Service", () => {
  11 +
  12 + let $rootScope: ng.IScope;
  13 + let $q: ng.IQService;
  14 +
  15 + beforeEach(inject((_$rootScope_: ng.IRootScopeService, _$q_: ng.IQService) => {
  16 + $rootScope = _$rootScope_;
  17 + $q = _$q_;
  18 + }));
  19 +
  20 + function createComponent() {
  21 + return new TranslatorService(
  22 + <any>helpers.mocks.$translate,
  23 + <any>helpers.mocks.tmhDynamicLocale,
  24 + <any>helpers.mocks.amMoment,
  25 + <any>helpers.mocks.angularLoad,
  26 + $rootScope
  27 + );
  28 + }
  29 +
  30 + it("set available languages when change language", (done) => {
  31 + let component: TranslatorService = createComponent();
  32 + component.availableLanguages = null;
  33 + expect(component.availableLanguages).toBeNull();
  34 + $rootScope.$emit("$translateChangeSuccess");
  35 + expect(component.availableLanguages).not.toBeNull();
  36 + done();
  37 + });
  38 +
  39 + it("change the language", (done) => {
  40 + let component: TranslatorService = createComponent();
  41 + let loadScripPromise = $q.defer();
  42 + loadScripPromise.resolve();
  43 + component["angularLoad"].loadScript = jasmine.createSpy("loadScript").and.returnValue(loadScripPromise.promise);
  44 + component["tmhDynamicLocale"].set = jasmine.createSpy("set");
  45 + component["tmhDynamicLocale"].get = jasmine.createSpy("get").and.returnValue("en");
  46 + component["$translate"].use = jasmine.createSpy("use");
  47 +
  48 + component.changeLanguage('pt');
  49 + $rootScope.$digest();
  50 +
  51 + expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/moment/locale/pt.js");
  52 + expect(component["angularLoad"].loadScript).toHaveBeenCalledWith("/bower_components/messageformat/locale/pt.js");
  53 + expect(component["tmhDynamicLocale"].set).toHaveBeenCalledWith("pt");
  54 + expect(component["$translate"].use).toHaveBeenCalledWith("pt");
  55 + done();
  56 + });
  57 +
  58 + it("do not load moment locale when change the language to english", (done) => {
  59 + let component: TranslatorService = createComponent();
  60 + component["angularLoad"].loadScript = jasmine.createSpy("loadScript").and.returnValue($q.defer().promise);
  61 + component.changeLanguage('en');
  62 + expect(component["angularLoad"].loadScript).not.toHaveBeenCalledWith("/bower_components/moment/locale/pt.js");
  63 + done();
  64 + });
  65 +
  66 + it("do nothing when call change language with null", (done) => {
  67 + let component: TranslatorService = createComponent();
  68 + component["angularLoad"].loadScript = jasmine.createSpy("loadScript");
  69 + component["tmhDynamicLocale"].set = jasmine.createSpy("set");
  70 + component["$translate"].use = jasmine.createSpy("use");
  71 +
  72 + component.changeLanguage(null);
  73 +
  74 + expect(component["angularLoad"].loadScript).not.toHaveBeenCalled();
  75 + expect(component["tmhDynamicLocale"].set).not.toHaveBeenCalled();
  76 + expect(component["$translate"].use).not.toHaveBeenCalled();
  77 + done();
  78 + });
  79 +
  80 + it("return the current language used by the translator", (done) => {
  81 + let component: TranslatorService = createComponent();
  82 + component["$translate"].use = jasmine.createSpy("use").and.returnValue("en");
  83 + expect(component.currentLanguage()).toEqual("en");
  84 + expect(component["$translate"].use).toHaveBeenCalled();
  85 + done();
  86 + });
  87 +
  88 + it("call translate service when translate a text", (done) => {
  89 + let component: TranslatorService = createComponent();
  90 + component["$translate"].instant = jasmine.createSpy("instant");
  91 + component.translate("text");
  92 + expect(component["$translate"].instant).toHaveBeenCalledWith("text");
  93 + done();
  94 + });
  95 +
  96 + it("change the language when receive an event", (done) => {
  97 + let component: TranslatorService = createComponent();
  98 + component.changeLanguage = jasmine.createSpy("changeLanguage");
  99 + $rootScope.$emit("$localeChangeSuccess");
  100 + expect(component.changeLanguage).toHaveBeenCalled();
  101 + done();
  102 + });
  103 +
  104 + it("use the translate language when receive a change language event and there is no language previously selected", (done) => {
  105 + let component: TranslatorService = createComponent();
  106 + component.changeLanguage = jasmine.createSpy("changeLanguage");
  107 + component["tmhDynamicLocale"].get = jasmine.createSpy("get").and.returnValue(null);
  108 + component["$translate"].use = jasmine.createSpy("use").and.returnValue("en");
  109 +
  110 + $rootScope.$emit("$localeChangeSuccess");
  111 + expect(component["$translate"].use).toHaveBeenCalled();
  112 + expect(component.changeLanguage).toHaveBeenCalledWith("en");
  113 + done();
  114 + });
  115 + });
  116 +});
src/app/shared/services/translator.service.ts 0 → 100644
@@ -0,0 +1,59 @@ @@ -0,0 +1,59 @@
  1 +import {Injectable, Inject} from "ng-forward";
  2 +
  3 +@Injectable()
  4 +@Inject("$translate", "tmhDynamicLocale", "amMoment", "angularLoad", "$rootScope")
  5 +export class TranslatorService {
  6 +
  7 + availableLanguages: any;
  8 +
  9 + constructor(private $translate: angular.translate.ITranslateService,
  10 + private tmhDynamicLocale: angular.dynamicLocale.tmhDynamicLocaleService,
  11 + private amMoment: any,
  12 + private angularLoad: any,
  13 + private $rootScope: any) {
  14 +
  15 + this.$rootScope.$on("$localeChangeSuccess", () => {
  16 + this.changeLanguage(tmhDynamicLocale.get() || $translate.use());
  17 + });
  18 + this.$rootScope.$on("$translateChangeSuccess", () => {
  19 + this.configAvailableLanguages();
  20 + });
  21 + }
  22 +
  23 + currentLanguage() {
  24 + return this.$translate.use();
  25 + }
  26 +
  27 + changeLanguage(language: string) {
  28 + if (!language) {
  29 + console.log("WARN: language undefined");
  30 + return;
  31 + }
  32 + this.changeMomentLocale(language);
  33 + this.tmhDynamicLocale.set(language);
  34 + this.angularLoad.loadScript(`/bower_components/messageformat/locale/${language}.js`).then(() => {
  35 + return this.$translate.use(language);
  36 + });
  37 + }
  38 +
  39 + translate(text: string) {
  40 + return this.$translate.instant(text);
  41 + }
  42 +
  43 + private configAvailableLanguages() {
  44 + this.availableLanguages = {
  45 + "en": this.$translate.instant("language.en"),
  46 + "pt": this.$translate.instant("language.pt")
  47 + };
  48 + }
  49 +
  50 + private changeMomentLocale(language: string) {
  51 + let localePromise = Promise.resolve();
  52 + if (language !== "en") {
  53 + localePromise = this.angularLoad.loadScript(`/bower_components/moment/locale/${language}.js`);
  54 + }
  55 + localePromise.then(() => {
  56 + this.amMoment.changeLocale(language);
  57 + });
  58 + }
  59 +}
src/lib/ng-noosfero-api/http/article.service.spec.ts
1 -import {Article} from "../../../app/models/interfaces";  
2 import {ArticleService} from "./article.service"; 1 import {ArticleService} from "./article.service";
3 2
4 3
@@ -24,8 +23,8 @@ describe(&quot;Services&quot;, () =&gt; { @@ -24,8 +23,8 @@ describe(&quot;Services&quot;, () =&gt; {
24 it("should return article children", (done) => { 23 it("should return article children", (done) => {
25 let articleId = 1; 24 let articleId = 1;
26 $httpBackend.expectGET(`/api/v1/articles/${articleId}/children`).respond(200, { articles: [{ name: "article1" }] }); 25 $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" }]); 26 + articleService.getChildren(<noosfero.Article>{id: articleId}).then((result: noosfero.RestResult<noosfero.Article[]>) => {
  27 + expect(result.data).toEqual([{ name: "article1" }]);
29 done(); 28 done();
30 }); 29 });
31 $httpBackend.flush(); 30 $httpBackend.flush();
@@ -34,8 +33,8 @@ describe(&quot;Services&quot;, () =&gt; { @@ -34,8 +33,8 @@ describe(&quot;Services&quot;, () =&gt; {
34 it("should get articles by profile", (done) => { 33 it("should get articles by profile", (done) => {
35 let profileId = 1; 34 let profileId = 1;
36 $httpBackend.expectGET(`/api/v1/profiles/${profileId}/articles`).respond(200, { articles: [{ name: "article1" }] }); 35 $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" }]); 36 + articleService.getByProfile(<noosfero.Profile>{id: profileId}).then((result: noosfero.RestResult<noosfero.Article[]>) => {
  37 + expect(result.data).toEqual([{ name: "article1" }]);
39 done(); 38 done();
40 }); 39 });
41 $httpBackend.flush(); 40 $httpBackend.flush();
@@ -44,8 +43,8 @@ describe(&quot;Services&quot;, () =&gt; { @@ -44,8 +43,8 @@ describe(&quot;Services&quot;, () =&gt; {
44 it("should get articles by profile with additional filters", (done) => { 43 it("should get articles by profile with additional filters", (done) => {
45 let profileId = 1; 44 let profileId = 1;
46 $httpBackend.expectGET(`/api/v1/profiles/${profileId}/articles?path=test`).respond(200, { articles: [{ name: "article1" }] }); 45 $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" }]); 46 + articleService.getByProfile(<noosfero.Profile>{id: profileId}, { path: 'test' }).then((result: noosfero.RestResult<noosfero.Article[]>) => {
  47 + expect(result.data).toEqual([{ name: "article1" }]);
49 done(); 48 done();
50 }); 49 });
51 $httpBackend.flush(); 50 $httpBackend.flush();
@@ -54,8 +53,8 @@ describe(&quot;Services&quot;, () =&gt; { @@ -54,8 +53,8 @@ describe(&quot;Services&quot;, () =&gt; {
54 it("should get article children with additional filters", (done) => { 53 it("should get article children with additional filters", (done) => {
55 let articleId = 1; 54 let articleId = 1;
56 $httpBackend.expectGET(`/api/v1/articles/${articleId}/children?path=test`).respond(200, { articles: [{ name: "article1" }] }); 55 $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" }]); 56 + articleService.getChildren(<noosfero.Article>{id: articleId}, { path: 'test' }).then((result: noosfero.RestResult<noosfero.Article[]>) => {
  57 + expect(result.data).toEqual([{ name: "article1" }]);
59 done(); 58 done();
60 }); 59 });
61 $httpBackend.flush(); 60 $httpBackend.flush();
@@ -63,10 +62,10 @@ describe(&quot;Services&quot;, () =&gt; { @@ -63,10 +62,10 @@ describe(&quot;Services&quot;, () =&gt; {
63 62
64 it("should create an article in a profile", (done) => { 63 it("should create an article in a profile", (done) => {
65 let profileId = 1; 64 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 }]); 65 + let article: noosfero.Article = <any>{ id: null};
  66 + $httpBackend.expectPOST(`/api/v1/profiles/${profileId}/articles`, { article: article }).respond(200, {article: { id: 2 }});
  67 + articleService.createInProfile(<noosfero.Profile>{id: profileId}, article).then((result: noosfero.RestResult<noosfero.Article>) => {
  68 + expect(result.data).toEqual({ id: 2 });
70 done(); 69 done();
71 }); 70 });
72 $httpBackend.flush(); 71 $httpBackend.flush();
src/lib/ng-noosfero-api/http/article.service.ts
1 import { Injectable, Inject } from "ng-forward"; 1 import { Injectable, Inject } from "ng-forward";
2 -import {Article} from "../../../app/models/interfaces"; 2 +import {RestangularService} from "./restangular_service";
  3 +import {ProfileService} from "./profile.service";
3 4
4 @Injectable() 5 @Injectable()
5 -@Inject("Restangular")  
6 -export class ArticleService { 6 +@Inject("Restangular", "$q", "$log", ProfileService)
7 7
8 - constructor(private Restangular: any) { } 8 +export class ArticleService extends RestangularService<noosfero.Article> {
9 9
10 - create(profileId: number, article: Article) {  
11 - return this.Restangular.one('profiles', profileId).customPOST(  
12 - { article: article },  
13 - 'articles',  
14 - {},  
15 - { 'Content-Type': 'application/json' }  
16 - ); 10 + constructor(Restangular: restangular.IService, $q: ng.IQService, $log: ng.ILogService, protected profileService: ProfileService) {
  11 + super(Restangular, $q, $log);
17 } 12 }
18 13
19 - getByProfile(profileId: number, params?: any) {  
20 - return this.Restangular.one('profiles', profileId).customGET('articles', params); 14 + getResourcePath() {
  15 + return "articles";
21 } 16 }
22 17
23 - getChildren(articleId: number, params?: any) {  
24 - return this.get(articleId).customGET('children', params); 18 + getDataKeys() {
  19 + return {
  20 + singular: 'article',
  21 + plural: 'articles'
  22 + };
25 } 23 }
26 24
27 - private get(articleId: number) {  
28 - return this.Restangular.one('articles', articleId); 25 +
  26 + createInProfile(profile: noosfero.Profile, article: noosfero.Article): ng.IPromise<noosfero.RestResult<noosfero.Article>> {
  27 + let profileElement = this.profileService.get(<number>profile.id);
  28 + (<any>profileElement).id = profile.id;
  29 + let headers = {
  30 + 'Content-Type': 'application/json'
  31 + };
  32 + return this.create(article, <noosfero.RestModel>profileElement, null, headers);
  33 + }
  34 +
  35 +
  36 + getAsCollectionChildrenOf<C>(rootElement: noosfero.Environment | noosfero.Article | noosfero.Profile, path: string, queryParams?: any, headers?: any): restangular.ICollectionPromise<C> {
  37 + return rootElement.getList<C>(path, queryParams, headers);
  38 + }
  39 +
  40 + getAsElementChildrenOf<C>(rootElement: noosfero.Environment | noosfero.Article | noosfero.Profile, path: string, id: number, queryParams?: any, headers?: any) {
  41 + return rootElement.one(path, id).get<C>(queryParams, headers);
29 } 42 }
30 43
  44 + getByProfile<T>(profile: noosfero.Profile, params?: any): ng.IPromise<noosfero.RestResult<noosfero.Article[]>> {
  45 + let profileElement = this.profileService.get(<number>profile.id);
  46 + return this.list(profileElement, params);
  47 + }
  48 +
  49 + getArticleByProfileAndPath(profile: noosfero.Profile, path: string): ng.IPromise<noosfero.RestResult<noosfero.Article>> {
  50 + let deferred = this.$q.defer<noosfero.RestResult<noosfero.Article>>();
  51 + let profileElement = this.profileService.get(<number>profile.id);
  52 +
  53 + let restRequest: ng.IPromise<any>;
  54 +
  55 + let params = { path: path };
  56 +
  57 + restRequest = profileElement.customGET(this.getResourcePath(), params);
  58 +
  59 +
  60 + restRequest
  61 + .then(this.getHandleSuccessFunction(deferred))
  62 + .catch(this.getHandleErrorFunction(deferred));
  63 +
  64 +
  65 + return deferred.promise;
  66 + }
  67 +
  68 + getOneByProfile<T>(profile: noosfero.Profile, params?: any): ng.IPromise<noosfero.RestResult<noosfero.Article>> {
  69 + let profileElement = this.profileService.get(<number>profile.id);
  70 + return this.getSub(profileElement, params);
  71 + }
  72 +
  73 + getChildren<T>(article: noosfero.Article, params?: any): ng.IPromise<noosfero.RestResult<noosfero.Article[]>> {
  74 + let articleElement = this.getElement(article.id);
  75 + articleElement.id = article.id;
  76 + return this.listSubElements(<noosfero.Article>articleElement, "children", params);
  77 + }
  78 +
  79 +
  80 +
31 } 81 }
src/lib/ng-noosfero-api/http/http_client.ts
@@ -1,11 +0,0 @@ @@ -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 \ No newline at end of file 0 \ No newline at end of file
src/lib/ng-noosfero-api/http/profile.service.spec.ts
1 -import {Profile} from "../../../app/models/interfaces";  
2 import {ProfileService} from "./profile.service"; 1 import {ProfileService} from "./profile.service";
3 2
4 describe("Services", () => { 3 describe("Services", () => {
@@ -24,7 +23,7 @@ describe(&quot;Services&quot;, () =&gt; { @@ -24,7 +23,7 @@ describe(&quot;Services&quot;, () =&gt; {
24 it("should return profile by its identifier", (done) => { 23 it("should return profile by its identifier", (done) => {
25 let identifier = 'profile1'; 24 let identifier = 'profile1';
26 $httpBackend.expectGET(`/api/v1/profiles?identifier=${identifier}`).respond(200, [{ name: "profile1" }]); 25 $httpBackend.expectGET(`/api/v1/profiles?identifier=${identifier}`).respond(200, [{ name: "profile1" }]);
27 - profileService.getByIdentifier(identifier).then((profile: Profile) => { 26 + profileService.getByIdentifier(identifier).then((profile: noosfero.Profile) => {
28 expect(profile).toEqual({ name: "profile1" }); 27 expect(profile).toEqual({ name: "profile1" });
29 done(); 28 done();
30 }); 29 });
@@ -72,11 +71,11 @@ describe(&quot;Services&quot;, () =&gt; { @@ -72,11 +71,11 @@ describe(&quot;Services&quot;, () =&gt; {
72 71
73 it("should resolve the current profile", (done) => { 72 it("should resolve the current profile", (done) => {
74 let profile = { id: 1, identifier: "profile1" }; 73 let profile = { id: 1, identifier: "profile1" };
75 - profileService.getCurrentProfile().then((currentProfile: Profile) => { 74 + profileService.getCurrentProfile().then((currentProfile: noosfero.Profile) => {
76 expect(currentProfile).toEqual(currentProfile); 75 expect(currentProfile).toEqual(currentProfile);
77 done(); 76 done();
78 }); 77 });
79 - profileService.setCurrentProfile(<Profile>profile); 78 + profileService.setCurrentProfile(<any>profile);
80 $rootScope.$apply(); 79 $rootScope.$apply();
81 }); 80 });
82 81
@@ -93,9 +92,9 @@ describe(&quot;Services&quot;, () =&gt; { @@ -93,9 +92,9 @@ describe(&quot;Services&quot;, () =&gt; {
93 it("should find the profile by identifier, set and resolve the current profile", (done) => { 92 it("should find the profile by identifier, set and resolve the current profile", (done) => {
94 let identifier = 'profile1'; 93 let identifier = 'profile1';
95 $httpBackend.expectGET(`/api/v1/profiles?identifier=${identifier}`).respond(200, [{ name: "profile1" }]); 94 $httpBackend.expectGET(`/api/v1/profiles?identifier=${identifier}`).respond(200, [{ name: "profile1" }]);
96 - profileService.setCurrentProfileByIdentifier(identifier).then((profile: Profile) => { 95 + profileService.setCurrentProfileByIdentifier(identifier).then((profile: noosfero.Profile) => {
97 expect(profile).toEqual({ name: "profile1" }); 96 expect(profile).toEqual({ name: "profile1" });
98 - profileService.getCurrentProfile().then((profile: Profile) => { 97 + profileService.getCurrentProfile().then((profile: noosfero.Profile) => {
99 expect(profile).toEqual({ name: "profile1" }); 98 expect(profile).toEqual({ name: "profile1" });
100 done(); 99 done();
101 }); 100 });
src/lib/ng-noosfero-api/http/profile.service.ts
1 import { Injectable, Inject } from "ng-forward"; 1 import { Injectable, Inject } from "ng-forward";
2 -import {Profile} from "../../../app/models/interfaces";  
3 2
4 @Injectable() 3 @Injectable()
5 @Inject("Restangular", "$q") 4 @Inject("Restangular", "$q")
6 export class ProfileService { 5 export class ProfileService {
7 6
8 - private _currentProfilePromise: ng.IDeferred<Profile>; 7 + private _currentProfilePromise: ng.IDeferred<noosfero.Profile>;
9 8
10 constructor(private restangular: restangular.IService, private $q: ng.IQService) { 9 constructor(private restangular: restangular.IService, private $q: ng.IQService) {
11 this.resetCurrentProfile(); 10 this.resetCurrentProfile();
@@ -15,17 +14,17 @@ export class ProfileService { @@ -15,17 +14,17 @@ export class ProfileService {
15 this._currentProfilePromise = this.$q.defer(); 14 this._currentProfilePromise = this.$q.defer();
16 } 15 }
17 16
18 - getCurrentProfile(): ng.IPromise<Profile> { 17 + getCurrentProfile(): ng.IPromise<noosfero.Profile> {
19 return this._currentProfilePromise.promise; 18 return this._currentProfilePromise.promise;
20 } 19 }
21 20
22 - setCurrentProfile(profile: Profile) { 21 + setCurrentProfile(profile: noosfero.Profile) {
23 this._currentProfilePromise.resolve(profile); 22 this._currentProfilePromise.resolve(profile);
24 } 23 }
25 24
26 setCurrentProfileByIdentifier(identifier: string) { 25 setCurrentProfileByIdentifier(identifier: string) {
27 this.resetCurrentProfile(); 26 this.resetCurrentProfile();
28 - return this.getByIdentifier(identifier).then((profile: Profile) => { 27 + return this.getByIdentifier(identifier).then((profile: noosfero.Profile) => {
29 this.setCurrentProfile(profile); 28 this.setCurrentProfile(profile);
30 return this.getCurrentProfile(); 29 return this.getCurrentProfile();
31 }); 30 });
@@ -35,10 +34,10 @@ export class ProfileService { @@ -35,10 +34,10 @@ export class ProfileService {
35 return this.get(profileId).customGET("home_page", params); 34 return this.get(profileId).customGET("home_page", params);
36 } 35 }
37 36
38 - getByIdentifier(identifier: string): ng.IPromise<any> { 37 + getByIdentifier(identifier: string): ng.IPromise<noosfero.Profile> {
39 let p = this.restangular.one('profiles').get({ identifier: identifier }); 38 let p = this.restangular.one('profiles').get({ identifier: identifier });
40 return p.then((response: restangular.IResponse) => { 39 return p.then((response: restangular.IResponse) => {
41 - if (response.data.length == 0) { 40 + if (response.data.length === 0) {
42 return this.$q.reject(p); 41 return this.$q.reject(p);
43 } 42 }
44 return response.data[0]; 43 return response.data[0];
src/lib/ng-noosfero-api/http/rest.decorator.ts 0 → 100644
@@ -0,0 +1,16 @@ @@ -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 \ No newline at end of file 17 \ No newline at end of file
src/lib/ng-noosfero-api/http/restangular_service.spec.ts 0 → 100644
@@ -0,0 +1,210 @@ @@ -0,0 +1,210 @@
  1 +import {RestangularService} from "./restangular_service";
  2 +
  3 +interface ObjectModel extends noosfero.RestModel {
  4 +}
  5 +
  6 +interface RootObjectModel extends noosfero.RestModel {
  7 +
  8 +}
  9 +
  10 +describe("Restangular Service - base Class", () => {
  11 +
  12 + class ObjectRestService extends RestangularService<ObjectModel> {
  13 + public getDataKeys() {
  14 + return {
  15 + singular: "object",
  16 + plural: "objects"
  17 + };
  18 + }
  19 +
  20 + public getResourcePath() {
  21 + return "objects";
  22 + }
  23 + }
  24 +
  25 + class RootObjectRestService extends RestangularService<ObjectModel> {
  26 + public getDataKeys() {
  27 + return {
  28 + singular: "rootObject",
  29 + plural: "rootObjects"
  30 + };
  31 + }
  32 +
  33 + public getResourcePath() {
  34 + return "rootObjects";
  35 + }
  36 + }
  37 +
  38 + let restangularService: restangular.IService;
  39 + let $httpBackend: ng.IHttpBackendService;
  40 + let objectRestService: ObjectRestService;
  41 + let rootObjectRestService: RootObjectRestService;
  42 +
  43 + beforeEach(angular.mock.module("noosferoApp", ($translateProvider: angular.translate.ITranslateProvider) => {
  44 + $translateProvider.translations('en', {});
  45 + }));
  46 +
  47 + beforeEach(inject((_Restangular_: restangular.IService, _$q_: ng.IQService, _$httpBackend_: ng.IHttpBackendService) => {
  48 + restangularService = _Restangular_;
  49 + objectRestService = new ObjectRestService(_Restangular_, _$q_, null);
  50 + rootObjectRestService = new RootObjectRestService(_Restangular_, _$q_, null);
  51 + $httpBackend = _$httpBackend_;
  52 + }));
  53 +
  54 + it("list() calls GET /objects", (done) => {
  55 + $httpBackend.expectGET("/api/v1/objects").respond(200, { objects: [{ id: 1 }, { id: 2 }] });
  56 +
  57 + objectRestService.list().then((result: noosfero.RestResult<ObjectModel[]>) => {
  58 + expect(result.data).toBeDefined();
  59 + expect((<ObjectModel[]>result.data).length).toEqual(2);
  60 + done();
  61 + });
  62 +
  63 + $httpBackend.flush();
  64 +
  65 + $httpBackend.verifyNoOutstandingExpectation();
  66 + });
  67 +
  68 + it("list(rootObject) calls GET /rootObjects/1/objects", (done) => {
  69 +
  70 + $httpBackend.expectGET("/api/v1/rootObjects/1/objects").respond(200, { objects: [{ id: 1 }, { id: 2 }] });
  71 + let rootObj: RootObjectModel = rootObjectRestService.getElement(1);
  72 +
  73 + objectRestService.list(rootObj).then((result: noosfero.RestResult<ObjectModel[]>) => {
  74 + expect(result.data).toBeDefined();
  75 + expect((<ObjectModel[]>result.data).length).toEqual(2);
  76 + done();
  77 + });
  78 +
  79 + $httpBackend.flush();
  80 +
  81 + $httpBackend.verifyNoOutstandingExpectation();
  82 + });
  83 +
  84 + it("get(1) calls GET /objects/1", (done) => {
  85 + $httpBackend.expectGET("/api/v1/objects/1").respond(200, { object: { id: 1 } });
  86 +
  87 + objectRestService.get(1).then((result: noosfero.RestResult<ObjectModel>) => {
  88 + expect(result.data).toBeDefined();
  89 + expect((<ObjectModel>result.data).id).toEqual(1);
  90 + done();
  91 + });
  92 + $httpBackend.flush();
  93 + $httpBackend.verifyNoOutstandingExpectation();
  94 + });
  95 +
  96 + it("objectService.get(1, rootObject) calls GET /rootObjects/1/objects/1", (done) => {
  97 + let rootObj: RootObjectModel = rootObjectRestService.getElement(1);
  98 + $httpBackend.expectGET("/api/v1/rootObjects/1/objects/1").respond(200, { object: { id: 1 } });
  99 +
  100 + objectRestService.get(1, rootObj).then((result: noosfero.RestResult<ObjectModel>) => {
  101 + expect(result.data).toBeDefined();
  102 + expect((<ObjectModel>result.data).id).toEqual(1);
  103 + done();
  104 + });
  105 + $httpBackend.flush();
  106 + $httpBackend.verifyNoOutstandingExpectation();
  107 + });
  108 +
  109 + it("remove(object) calls DELETE /objects/1", (done) => {
  110 + $httpBackend.expectGET("/api/v1/objects/1").respond(200, { object: { id: 1 } });
  111 + objectRestService.get(1).then((result: noosfero.RestResult<ObjectModel>) => {
  112 + let object: ObjectModel = <ObjectModel>result.data;
  113 +
  114 + $httpBackend.expectDELETE("/api/v1/objects/1").respond(204, { object: { id: 1 } });
  115 +
  116 + objectRestService.remove(object).then((result: noosfero.RestResult<ObjectModel>) => {
  117 + expect(result.data).toBeDefined();
  118 + expect((<ObjectModel>result.data).id).toEqual(1);
  119 + done();
  120 + });
  121 + });
  122 +
  123 + $httpBackend.flush();
  124 + $httpBackend.verifyNoOutstandingExpectation();
  125 + });
  126 +
  127 +
  128 + it("remove(object, rootObject) calls DELETE /rootObjects/1/objects/1", (done) => {
  129 + let rootObj: RootObjectModel = rootObjectRestService.getElement(1);
  130 +
  131 + let obj: ObjectModel = objectRestService.getElement(1, rootObj);
  132 +
  133 + $httpBackend.expectDELETE("/api/v1/rootObjects/1/objects/1").respond(204, { object: { id: 1, rootId: 1 } });
  134 +
  135 + objectRestService.remove(obj, rootObj).then((result: noosfero.RestResult<ObjectModel>) => {
  136 + expect(result.data).toBeDefined();
  137 + expect((<ObjectModel>result.data).id).toEqual(1);
  138 + expect((<any>result.data).rootId).toEqual(1);
  139 + done();
  140 + });
  141 + $httpBackend.flush();
  142 + });
  143 +
  144 +
  145 + it("update(object) calls PUT /objects/1", (done) => {
  146 + $httpBackend.expectPUT("/api/v1/objects/1").respond(200, { object: { id: 1 } });
  147 +
  148 + let object: ObjectModel = objectRestService.getElement(1);
  149 +
  150 + objectRestService.update(object).then((result: noosfero.RestResult<ObjectModel>) => {
  151 + expect(result.data).toBeDefined();
  152 + expect((<ObjectModel>result.data).id).toEqual(1);
  153 + done();
  154 + });
  155 +
  156 + $httpBackend.flush();
  157 + $httpBackend.verifyNoOutstandingExpectation();
  158 + });
  159 +
  160 +
  161 + it("update(object, rootObject) calls PUT /rootObjects/1/objects/1", (done) => {
  162 + let rootObj: RootObjectModel = rootObjectRestService.getElement(1);
  163 +
  164 + let obj: ObjectModel = objectRestService.getElement(1, rootObj);
  165 +
  166 + $httpBackend.expectPUT("/api/v1/rootObjects/1/objects/1").respond(200, { object: { id: 1, rootId: 1 } });
  167 +
  168 + objectRestService.update(obj, rootObj).then((result: noosfero.RestResult<ObjectModel>) => {
  169 + expect(result.data).toBeDefined();
  170 + expect((<ObjectModel>result.data).id).toEqual(1);
  171 + expect((<any>result.data).rootId).toEqual(1);
  172 + done();
  173 + });
  174 + $httpBackend.flush();
  175 + });
  176 +
  177 +
  178 + it("save(object) calls POST /objects", (done) => {
  179 + $httpBackend.expectPOST("/api/v1/objects").respond(201, { object: { attr: 1 } });
  180 +
  181 + let object: ObjectModel = objectRestService.getElement(1);
  182 +
  183 + objectRestService.create(object).then((result: noosfero.RestResult<ObjectModel>) => {
  184 + expect(result.data).toBeDefined();
  185 + expect((<any>result.data).attr).toEqual(1);
  186 + done();
  187 + });
  188 +
  189 + $httpBackend.flush();
  190 + $httpBackend.verifyNoOutstandingExpectation();
  191 + });
  192 +
  193 +
  194 + it("save(object, rootObject) calls POST /rootObjects/1/objects", (done) => {
  195 + let rootObj: RootObjectModel = rootObjectRestService.getElement(1);
  196 +
  197 + let obj: ObjectModel = objectRestService.getElement(1, rootObj);
  198 +
  199 + $httpBackend.expectPOST("/api/v1/rootObjects/1/objects").respond(201, { object: { attr: 1, rootId: 1 } });
  200 +
  201 + objectRestService.create(obj, rootObj).then((result: noosfero.RestResult<ObjectModel>) => {
  202 + expect(result.data).toBeDefined();
  203 + expect((<any>result.data).attr).toEqual(1);
  204 + expect((<any>result.data).rootId).toEqual(1);
  205 + done();
  206 + });
  207 + $httpBackend.flush();
  208 + });
  209 +
  210 +});
0 \ No newline at end of file 211 \ No newline at end of file
src/lib/ng-noosfero-api/http/restangular_service.ts 0 → 100644
@@ -0,0 +1,297 @@ @@ -0,0 +1,297 @@
  1 +/**
  2 + * @name RestangularService
  3 + * Base class to be extended by classes which will provide access
  4 + * to te Noosfero REST API
  5 + *
  6 + * @export RestangularService
  7 + * @abstract
  8 + * @class RestangularService
  9 + * @template T
  10 + */
  11 +export abstract class RestangularService<T extends noosfero.RestModel> {
  12 +
  13 + private baseResource: restangular.IElement;
  14 + /**
  15 + * Creates an instance of RestangularService.
  16 + *
  17 + * @param {restangular.IService} Restangular (description)
  18 + * @param {ng.IQService} $q (description)
  19 + * @param {ng.ILogService} $log (description)
  20 + */
  21 + constructor(protected restangularService: restangular.IService, protected $q: ng.IQService, protected $log: ng.ILogService) {
  22 + this.baseResource = restangularService.all(this.getResourcePath());
  23 + // TODO
  24 + // this.restangularService.setResponseInterceptor((data, operation, what, url, response, deferred) => {
  25 + // let transformedData: any = data;
  26 + // if (operation === "getList" && url.endsWith("/" + this.getDataKeys().plural)) {
  27 + // transformedData = data[this.getDataKeys()["plural"]];
  28 + // return transformedData;
  29 + // } else {
  30 + // return data;
  31 + // }
  32 + // });
  33 + }
  34 +
  35 + protected extractData(response: restangular.IResponse): noosfero.RestResult<T> {
  36 + let dataKey: string;
  37 + if (response.data && this.getDataKeys()) {
  38 + if ((<Object>response.data).hasOwnProperty(this.getDataKeys().singular)) {
  39 + dataKey = this.getDataKeys().singular;
  40 + } else if ((<Object>response.data).hasOwnProperty(this.getDataKeys().plural)) {
  41 + dataKey = this.getDataKeys().plural;
  42 + }
  43 + }
  44 + return {
  45 + data: response.data[dataKey],
  46 + headers: response.headers
  47 + };
  48 + };
  49 +
  50 + protected buildResult(response: restangular.IResponse): noosfero.RestResult<T> {
  51 + return {
  52 + data: response.data,
  53 + headers: response.headers
  54 + };
  55 + };
  56 + /**
  57 + * Abstract getPath() method is used to mount the url
  58 + * on REST Operations
  59 + * @protected
  60 + * @abstract
  61 + * @returns {string} The path of the REST endpoint
  62 + */
  63 + public abstract getResourcePath(): string;
  64 +
  65 + /**
  66 + * Abstract getDataKeys()
  67 + *
  68 + * Should be implemented into the child classes and
  69 + * returns the singular and plural names of the represented resource
  70 + *
  71 + * @protected
  72 + * @abstract
  73 + * @returns {{ singular: string, plural: string }} (description)
  74 + */
  75 + protected abstract getDataKeys(): { singular: string, plural: string };
  76 +
  77 + /**
  78 + * Do a HTTP GET call to the resource represented using the id provided
  79 + *
  80 + * @protected
  81 + * @param {number} id The resource id
  82 + * @returns {ng.IPromise<T>} Returns a Promise to the Generic Type
  83 + */
  84 + public get(id: number, rootElement?: restangular.IElement, queryParams?: any, headers?: any): ng.IPromise<noosfero.RestResult<T>> {
  85 + let deferred = this.$q.defer<noosfero.RestResult<T>>();
  86 +
  87 + let restRequest: ng.IPromise<noosfero.RestResult<T>>;
  88 +
  89 + if (rootElement) {
  90 + restRequest = rootElement.one(this.getResourcePath(), id).get(queryParams, headers);
  91 + } else {
  92 + restRequest = this.restangularService.one(this.getResourcePath(), id).get(queryParams, headers);
  93 + }
  94 +
  95 + restRequest.then(this.getHandleSuccessFunction(deferred))
  96 + .catch(this.getHandleErrorFunction(deferred));
  97 +
  98 +
  99 + return deferred.promise;
  100 + }
  101 +
  102 + /**
  103 + * Do a HTTP GET call to the resource collection represented
  104 + *
  105 + * @protected
  106 + * @param {number} id (description)
  107 + * @returns {ng.IPromise<T>} Returns a Promise to the Generic Type
  108 + */
  109 + public list(rootElement?: restangular.IElement, queryParams?: any, headers?: any): ng.IPromise<noosfero.RestResult<T[]>> {
  110 + let deferred = this.$q.defer<noosfero.RestResult<T[]>>();
  111 +
  112 + let restRequest: ng.IPromise<any>;
  113 +
  114 + if (rootElement) {
  115 + restRequest = rootElement.customGET(this.getResourcePath(), queryParams, headers);
  116 + } else {
  117 + restRequest = this.baseResource.customGET("", queryParams, headers);
  118 + }
  119 +
  120 +
  121 + restRequest
  122 + .then(this.getHandleSuccessFunction(deferred))
  123 + .catch(this.getHandleErrorFunction(deferred));
  124 +
  125 +
  126 + return deferred.promise;
  127 + }
  128 +
  129 + /**
  130 + * Do a HTTP GET call to the resource collection represented
  131 + *
  132 + * @protected
  133 + * @param {number} id (description)
  134 + * @returns {ng.IPromise<T>} Returns a Promise to the Generic Type
  135 + */
  136 + public getSub(rootElement?: restangular.IElement, queryParams?: any, headers?: any): ng.IPromise<noosfero.RestResult<T>> {
  137 + let deferred = this.$q.defer<noosfero.RestResult<T>>();
  138 +
  139 + let restRequest: ng.IPromise<any>;
  140 +
  141 + if (rootElement) {
  142 + restRequest = rootElement.customGET(this.getResourcePath(), queryParams, headers);
  143 + } else {
  144 + restRequest = this.baseResource.customGET("", queryParams, headers);
  145 + }
  146 +
  147 +
  148 + restRequest
  149 + .then(this.getHandleSuccessFunction(deferred))
  150 + .catch(this.getHandleErrorFunction(deferred));
  151 +
  152 +
  153 + return deferred.promise;
  154 + }
  155 +
  156 + public listSubElements<C>(obj: T, subElement: string, queryParams?: any, headers?: any): ng.IPromise<noosfero.RestResult<C>> {
  157 + let deferred = this.$q.defer<noosfero.RestResult<C>>();
  158 + let restRequest: ng.IPromise<noosfero.RestResult<T>>;
  159 + let objElement = this.getElement(obj.id);
  160 + objElement.id = obj.id;
  161 + restRequest = objElement.customGET(subElement, queryParams, headers);
  162 + restRequest.then(this.getHandleSuccessFunction(deferred))
  163 + .catch(this.getHandleErrorFunction(deferred));
  164 + return deferred.promise;
  165 + }
  166 +
  167 + /**
  168 + * Removes the object provided from the resource collection,
  169 + * calls DELETE /resourcepath/:resourceId
  170 + */
  171 + public remove(obj: T, rootElement?: noosfero.RestModel, queryParams?: any, headers?: any): ng.IPromise<noosfero.RestResult<T>> {
  172 + let restangularObj: restangular.IElement;
  173 +
  174 +
  175 +
  176 + if (rootElement) {
  177 + restangularObj = rootElement.one(this.getResourcePath(), obj.id);
  178 + } else {
  179 + restangularObj = this.restangularService.one(this.getResourcePath(), obj.id);
  180 + }
  181 +
  182 + let deferred = this.$q.defer<noosfero.RestResult<T>>();
  183 +
  184 + let restRequest: ng.IPromise<noosfero.RestResult<T>>;
  185 +
  186 + restRequest = restangularObj.remove(queryParams, headers);
  187 +
  188 + restRequest
  189 + .then(this.getHandleSuccessFunction(deferred))
  190 + .catch(this.getHandleErrorFunction(deferred));
  191 +
  192 + return deferred.promise;
  193 + }
  194 +
  195 + /**
  196 + * Updates the object into the resource collection
  197 + * calls PUT /resourcePath/:resourceId {object}
  198 + */
  199 + public update(obj: T, rootElement?: noosfero.RestModel, queryParams?: any, headers?: any): ng.IPromise<noosfero.RestResult<T>> {
  200 + let deferred = this.$q.defer<noosfero.RestResult<T>>();
  201 +
  202 + let restRequest: ng.IPromise<noosfero.RestResult<T>>;
  203 +
  204 + let restangularObj: restangular.IElement;
  205 +
  206 + if (rootElement) {
  207 + restangularObj = rootElement.one(this.getResourcePath(), obj.id);
  208 + } else {
  209 + restangularObj = this.restangularService.one(this.getResourcePath(), obj.id);
  210 + }
  211 +
  212 + restRequest = restangularObj.put(queryParams, headers);
  213 +
  214 + restRequest.then(this.getHandleSuccessFunction(deferred))
  215 + .catch(this.getHandleErrorFunction(deferred));
  216 +
  217 + return deferred.promise;
  218 + }
  219 +
  220 + /**
  221 + * Creates a new Resource into the resource collection
  222 + * calls POST /resourcePath
  223 + */
  224 + public create(obj: T, rootElement?: noosfero.RestModel, queryParams?: any, headers?: any): ng.IPromise<noosfero.RestResult<T>> {
  225 + let deferred = this.$q.defer<noosfero.RestResult<T>>();
  226 +
  227 + let restRequest: ng.IPromise<noosfero.RestResult<T>>;
  228 +
  229 + let data = <any>{ };
  230 + data[this.getDataKeys().singular] = obj;
  231 +
  232 + if (rootElement) {
  233 + restRequest = rootElement.all(this.getResourcePath()).post(data, queryParams, headers);
  234 + } else {
  235 + restRequest = this.baseResource.post(data, queryParams, headers);
  236 + }
  237 +
  238 + restRequest.then(this.getHandleSuccessFunction(deferred))
  239 + .catch(this.getHandleErrorFunction(deferred));
  240 +
  241 + return deferred.promise;
  242 + }
  243 +
  244 + /**
  245 + * Returns a Restangular IElement representing the
  246 + */
  247 + public getElement(id: number, rootElement?: noosfero.RestModel): noosfero.RestModel {
  248 + if (rootElement) {
  249 + return <noosfero.RestModel>rootElement.one(this.getResourcePath(), id);
  250 + } else {
  251 + return <noosfero.RestModel>this.restangularService.one(this.getResourcePath(), id);
  252 + }
  253 + }
  254 +
  255 + /** HANDLERS */
  256 + protected getHandleSuccessFunction<C>(deferred: ng.IDeferred<noosfero.RestResult<C | T | any>>, responseKey?: string): (response: restangular.IResponse) => void {
  257 + let self = this;
  258 +
  259 + /**
  260 + * (description)
  261 + *
  262 + * @param {restangular.IResponse} response (description)
  263 + */
  264 + let successFunction = (response: restangular.IResponse): void => {
  265 + if (self.$log) {
  266 + self.$log.debug("Request successfull executed", response.data, self, response);
  267 + }
  268 + deferred.resolve(<any>this.extractData(response));
  269 + };
  270 + return successFunction;
  271 + }
  272 +
  273 + /**
  274 + * (description)
  275 + *
  276 + * @template T
  277 + * @param {ng.IDeferred<T>} deferred (description)
  278 + * @returns {(response: restangular.IResponse) => void} (description)
  279 + */
  280 + getHandleErrorFunction<T>(deferred: ng.IDeferred<T>): (response: restangular.IResponse) => void {
  281 + let self = this;
  282 + /**
  283 + * (description)
  284 + *
  285 + * @param {restangular.IResponse} response (description)
  286 + */
  287 + let successFunction = (response: restangular.IResponse): void => {
  288 + if (self.$log) {
  289 + self.$log.error("Error executing request", self, response);
  290 + }
  291 + deferred.reject(response);
  292 + };
  293 + return successFunction;
  294 + }
  295 + /** END HANDLERS */
  296 +
  297 +}
src/lib/ng-noosfero-api/interfaces/activity.ts 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +namespace noosfero {
  2 + /**
  3 + * @ngdoc interface
  4 + * @name noofero.Activity
  5 + * @description
  6 + * A representation of a {@link noosfero.Profile} activity in Noosfero.
  7 + */
  8 + export interface Activity {
  9 + /**
  10 + * @ngdoc property
  11 + * @name verb
  12 + * @propertyOf noofero.Activity
  13 + * @returns {string} The activity verb.
  14 + */
  15 + verb: string;
  16 + }
  17 +}
0 \ No newline at end of file 18 \ No newline at end of file
src/lib/ng-noosfero-api/interfaces/article.ts 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +
  2 +namespace noosfero {
  3 + export interface Article extends RestModel {
  4 + path: string;
  5 + profile: Profile;
  6 + type: string;
  7 + }
  8 +}
0 \ No newline at end of file 9 \ No newline at end of file
src/lib/ng-noosfero-api/interfaces/block.ts 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +namespace noosfero {
  2 + export interface Block {
  3 + id: number;
  4 + }
  5 +}
0 \ No newline at end of file 6 \ No newline at end of file
src/lib/ng-noosfero-api/interfaces/blog.ts 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +namespace noosfero {
  2 + export interface Blog extends Article {
  3 + }
  4 +}
0 \ No newline at end of file 5 \ No newline at end of file
src/lib/ng-noosfero-api/interfaces/box.ts 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +namespace noosfero {
  2 + export interface Box {
  3 + id: number;
  4 + position: number;
  5 + }
  6 +}
0 \ No newline at end of file 7 \ No newline at end of file
src/lib/ng-noosfero-api/interfaces/credentials.ts 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +namespace noosfero {
  2 + export interface Credentials {
  3 + username: string;
  4 + password: string;
  5 + }
  6 +}
0 \ No newline at end of file 7 \ No newline at end of file
src/lib/ng-noosfero-api/interfaces/environment.ts 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +
  2 +namespace noosfero {
  3 + export interface Environment extends RestModel {
  4 + }
  5 +}
0 \ No newline at end of file 6 \ No newline at end of file
src/lib/ng-noosfero-api/interfaces/event.ts 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +namespace noosfero {
  2 + interface Event extends Article {
  3 + }
  4 +}
src/lib/ng-noosfero-api/interfaces/person.ts 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +namespace noosfero {
  2 + /**
  3 + * @ngdoc interface
  4 + * @name noosfero.Person
  5 + * @description
  6 + * A representation of a Person in Noosfero.
  7 + */
  8 + export interface Person extends Profile {
  9 +
  10 + }
  11 +}
0 \ No newline at end of file 12 \ No newline at end of file
src/lib/ng-noosfero-api/interfaces/profile.ts 0 → 100644
@@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
  1 +
  2 +namespace noosfero {
  3 + /**
  4 + * @ngdoc interface
  5 + * @name noofero.Profile
  6 + * @description
  7 + * A representation of a Noosfero Profile.
  8 + */
  9 + export interface Profile extends RestModel {
  10 + /**
  11 + * @ngdoc property
  12 + * @name id
  13 + * @propertyOf noofero.Profile
  14 + * @returns {number} The Profile id
  15 + */
  16 + id: number;
  17 +
  18 + /**
  19 + * @ngdoc property
  20 + * @name identifier
  21 + * @propertyOf noofero.Profile
  22 + * @returns {string} The unque identifier for the Profile
  23 + */
  24 + identifier: string;
  25 +
  26 + /**
  27 + * @ngdoc property
  28 + * @name type
  29 + * @propertyOf noofero.Profile
  30 + * @returns {string} The Profile type (e.g.: "Person", etc.)
  31 + */
  32 + type: string;
  33 +
  34 + name: string;
  35 + }
  36 +}
0 \ No newline at end of file 37 \ No newline at end of file
src/lib/ng-noosfero-api/interfaces/rest_model.ts 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +namespace noosfero {
  2 + export interface RestModel extends restangular.IElement {
  3 + id: number;
  4 + }
  5 +}
0 \ No newline at end of file 6 \ No newline at end of file
src/lib/ng-noosfero-api/interfaces/rest_result.ts 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +
  2 +namespace noosfero {
  3 + export interface RestResult<T> {
  4 + data: T;
  5 + headers: Function;
  6 + }
  7 +}
0 \ No newline at end of file 8 \ No newline at end of file
src/lib/ng-noosfero-api/interfaces/tinymce_article.ts 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +namespace noosfero {
  2 + export interface TynyMceArticle extends Article {
  3 + }
  4 +}
0 \ No newline at end of file 5 \ No newline at end of file
src/lib/ng-noosfero-api/interfaces/user.ts 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +namespace noosfero {
  2 + export interface User {
  3 + id: number;
  4 + login: string;
  5 + email: string;
  6 + person: Person;
  7 + private_token: string;
  8 + userRole: string;
  9 + }
  10 +}
0 \ No newline at end of file 11 \ No newline at end of file
src/spec/helpers.ts
@@ -2,7 +2,6 @@ @@ -2,7 +2,6 @@
2 import {ngClass, TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder'; 2 import {ngClass, TestComponentBuilder, ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
3 import {providers} from 'ng-forward/cjs/testing/providers'; 3 import {providers} from 'ng-forward/cjs/testing/providers';
4 import {Injectable, Inject, Provider, Input, provide, Component} from 'ng-forward'; 4 import {Injectable, Inject, Provider, Input, provide, Component} from 'ng-forward';
5 -import {User, Person} from "./../app/models/interfaces";  
6 5
7 6
8 export var ngforward = { 7 export var ngforward = {
@@ -101,7 +100,7 @@ export var fixtures = { @@ -101,7 +100,7 @@ export var fixtures = {
101 id: 1, 100 id: 1,
102 login: 'user', 101 login: 'user',
103 email: 'user@company.com', 102 email: 'user@company.com',
104 - person: <Person>{ 103 + person: <noosfero.Person>{
105 id: 1, 104 id: 1,
106 identifier: 'user' 105 identifier: 'user'
107 }, 106 },
src/spec/mocks.ts
@@ -48,6 +48,17 @@ export var mocks = { @@ -48,6 +48,17 @@ export var mocks = {
48 } 48 }
49 }; 49 };
50 }, 50 },
  51 + getArticleByProfileAndPath: (profile: noosfero.Profile, path: string) => {
  52 + return {
  53 + then: (func?: Function) => {
  54 + if (func) func({
  55 + data: {
  56 + article: null
  57 + }
  58 + });
  59 + }
  60 + };
  61 + },
51 getChildren: (articleId: number, params?: any) => { 62 getChildren: (articleId: number, params?: any) => {
52 return { 63 return {
53 then: (func?: Function) => { if (func) func(); } 64 then: (func?: Function) => { if (func) func(); }
@@ -71,7 +82,7 @@ export var mocks = { @@ -71,7 +82,7 @@ export var mocks = {
71 use: (lang?: string) => { 82 use: (lang?: string) => {
72 return lang ? Promise.resolve(lang) : "en"; 83 return lang ? Promise.resolve(lang) : "en";
73 }, 84 },
74 - instant: (text: string) => { return text } 85 + instant: (text: string) => { return text; }
75 }, 86 },
76 tmhDynamicLocale: { 87 tmhDynamicLocale: {
77 get: () => { }, 88 get: () => { },
@@ -99,6 +110,6 @@ export var mocks = { @@ -99,6 +110,6 @@ export var mocks = {
99 translatorService: { 110 translatorService: {
100 currentLanguage: () => { }, 111 currentLanguage: () => { },
101 changeLanguage: (lang: string) => { }, 112 changeLanguage: (lang: string) => { },
102 - translate: (text: string) => { return text } 113 + translate: (text: string) => { return text; }
103 } 114 }
104 }; 115 };