Commit 0528af25750ee54081c9e38e0498c2c9e3404722

Authored by Caio Almeida
2 parents 2d6e6299 9a88aab0

Merge branch 'master' into tags-block

bower.json
... ... @@ -36,14 +36,21 @@
36 36 "angular-load": "^0.4.1",
37 37 "angular-translate-interpolation-messageformat": "^2.10.0",
38 38 "angular-bind-html-compile": "^1.2.1",
39   - "angular-click-outside": "^2.7.1"
  39 + "angular-click-outside": "^2.7.1",
  40 + "ng-ckeditor": "^0.2.1"
40 41 },
41 42 "devDependencies": {
42   - "angular-mocks": "~1.5.0",
43   - "ng-ckeditor": "^0.2.1",
44   - "ckeditor": "^4.5.8"
  43 + "angular-mocks": "~1.5.0"
45 44 },
46 45 "overrides": {
  46 + "ng-ckeditor": {
  47 + "main": [
  48 + "ng-ckeditor.js",
  49 + "libs/ckeditor/lang",
  50 + "libs/ckeditor/ckeditor.js",
  51 + "libs/ckeditor/config.js"
  52 + ]
  53 + },
47 54 "bootstrap-sass": {
48 55 "main": [
49 56 "assets/stylesheets/_bootstrap.scss",
... ...
gulp/build.js
... ... @@ -103,6 +103,7 @@ gulp.task('fonts', function () {
103 103 });
104 104  
105 105 gulp.task('ckeditor', function () {
  106 + conf.wiredep.exclude.push(/ckeditor/); // exclude ckeditor from build to improve performance
106 107 return gulp.src(['bower_components/ng-ckeditor/**/*']).pipe(gulp.dest(path.join(conf.paths.dist, '/ng-ckeditor')));
107 108 });
108 109  
... ... @@ -153,4 +154,4 @@ gulp.task('noosfero', ['html'], function () {
153 154 return merge(layouts, theme, index);
154 155 });
155 156  
156   -gulp.task('build', ['html', 'fonts', 'other', 'locale', 'ckeditor', 'plugin-languages', 'noosfero']);
  157 +gulp.task('build', ['ckeditor', 'html', 'fonts', 'other', 'locale', 'plugin-languages', 'noosfero']);
... ...
gulp/conf.js
... ... @@ -36,7 +36,7 @@ exports.configTheme(argv.theme);
36 36 * to inject css preprocessor deps and js files in karma
37 37 */
38 38 exports.wiredep = {
39   - exclude: [/jquery/, /\/bootstrap\.js$/, /\/bootstrap-sass\/.*\.js/, /\/bootstrap\.css/, /ckeditor/],
  39 + exclude: [/jquery/, /\/bootstrap\.js$/, /\/bootstrap-sass\/.*\.js/, /\/bootstrap\.css/],
40 40 directory: 'bower_components'
41 41 };
42 42  
... ...
src/app/article/cms/cms.component.spec.ts
... ... @@ -55,6 +55,7 @@ describe("Article Cms", () => {
55 55 });
56 56  
57 57 it("got to the new article page and display an alert when saving sucessfully", done => {
  58 + $stateParams['parent_id'] = 1;
58 59 let component: CmsComponent = new CmsComponent(articleServiceMock, profileServiceMock, $state, notification, $stateParams, $window);
59 60 component.save();
60 61 $rootScope.$apply();
... ...
src/app/layout/blocks/login-block/index.ts 0 → 100644
src/app/layout/blocks/login-block/login-block.component.spec.ts 0 → 100644
... ... @@ -0,0 +1,110 @@
  1 +import {TestComponentBuilder} from 'ng-forward/cjs/testing/test-component-builder';
  2 +import {Injectable, Provider, provide} from "ng-forward";
  3 +import {ComponentTestHelper, createClass} from './../../../../spec/component-test-helper';
  4 +import {ComponentFixture} from 'ng-forward/cjs/testing/test-component-builder';
  5 +import {providers} from 'ng-forward/cjs/testing/providers';
  6 +import {LoginBlockComponent} from './login-block.component';
  7 +import * as helpers from "./../../../../spec/helpers";
  8 +import {SessionService, AuthService, AuthController, AuthEvents} from "./../../../login";
  9 +
  10 +const htmlTemplate: string = '<noosfero-login-block></noosfero-login-block>';
  11 +
  12 +describe("Components", () => {
  13 +
  14 + describe("Login Block Component", () => {
  15 + let helper: ComponentTestHelper<LoginBlockComponent>;
  16 + let person: any = null;
  17 +
  18 + /**
  19 + * Mock objects
  20 + */
  21 + let authService: any = helpers.mocks.authService;
  22 + let user = <noosfero.User>{ person: person };
  23 + let sessionService: any = <any>helpers.mocks.sessionWithCurrentUser(user);
  24 + let state = jasmine.createSpyObj("$state", ["go"]);
  25 + let scope = helpers.mocks.scopeWithEvents;
  26 +
  27 + let providers = [
  28 + new Provider('SessionService', { useValue: sessionService }),
  29 + new Provider('$state', { useValue: state }),
  30 + new Provider('AuthService', { useValue: authService }),
  31 + new Provider('$scope', { useValue: scope })
  32 + ];
  33 +
  34 + beforeEach( angular.mock.module("templates") );
  35 +
  36 + beforeEach( (done: Function) => {
  37 + let cls = createClass({
  38 + template: htmlTemplate,
  39 + directives: [LoginBlockComponent],
  40 + providers: providers,
  41 + properties: {}
  42 + });
  43 + helper = new ComponentTestHelper<LoginBlockComponent>(cls, done);
  44 + });
  45 +
  46 + it("expect person to be null with no logged in user", () => {
  47 + expect(helper.component.currentUser).toBeNull;
  48 + });
  49 +
  50 + it("expect person to be defined when user login", () => {
  51 + // Executes the login method on the component
  52 + doComponentLogin();
  53 + expect(helper.component.currentUser.person).toBe(person);
  54 + });
  55 +
  56 + it("expect person to be null when user logout", () => {
  57 + // First do a login
  58 + doComponentLogin();
  59 + // The logout the user
  60 + doComponentLogout();
  61 + // Check if the current user was cleared
  62 + expect(helper.component.currentUser).toBeNull;
  63 + });
  64 +
  65 + /**
  66 + * Execute the logout method on the target component
  67 + */
  68 + function doComponentLogout() {
  69 + // Create a mock for the AuthService logout method
  70 + spyOn(authService, "logout");
  71 + helper.component.logout();
  72 + expect(authService.logout).toHaveBeenCalled();
  73 + // After the component logout method execution, fire the
  74 + // AuthService event
  75 + simulateLogoutEvent();
  76 + }
  77 +
  78 + /**
  79 + * Execute the login method on the target component
  80 + */
  81 + function doComponentLogin() {
  82 + // Create a mock for the AuthService login method
  83 + spyOn(authService, "login");
  84 + helper.component.login();
  85 + expect(authService.login).toHaveBeenCalled();
  86 + // After the component login method execution, fire the
  87 + // AuthService event
  88 + simulateLoginEvent();
  89 + }
  90 +
  91 + /**
  92 + * Simulate the AuthService loginSuccess event
  93 + */
  94 + function simulateLoginEvent() {
  95 + let successEvent: string = AuthEvents[AuthEvents.loginSuccess];
  96 +
  97 + (<any>helper.component.authService)[successEvent].next(user);
  98 + }
  99 +
  100 + /**
  101 + * Simulate the AuthService logoutSuccess event
  102 + */
  103 + function simulateLogoutEvent() {
  104 + let successEvent: string = AuthEvents[AuthEvents.logoutSuccess];
  105 +
  106 + (<any>helper.component.authService)[successEvent].next(user);
  107 + }
  108 + });
  109 +
  110 +});
0 111 \ No newline at end of file
... ...
src/app/layout/blocks/login-block/login-block.component.ts 0 → 100644
... ... @@ -0,0 +1,73 @@
  1 +import {Input, Inject, Component} from "ng-forward";
  2 +import {SessionService, AuthService, AuthEvents} from "./../../../login";
  3 +
  4 +/**
  5 + * @ngdoc controller
  6 + * @name layout.blocks.LoginBlockComponent
  7 + * @description
  8 + * The Noosfero block responible for presenting a login form and user status
  9 + */
  10 +@Component({
  11 + selector: "noosfero-login-block",
  12 + templateUrl: 'app/layout/blocks/login-block/login-block.html',
  13 +})
  14 +@Inject("SessionService", "$state", 'AuthService', "$scope")
  15 +export class LoginBlockComponent {
  16 +
  17 + /**
  18 + * @ngdoc property
  19 + * @name currentUser
  20 + * @propertyOf layout.blocks.LoginBlockComponent
  21 + * @description
  22 + * The current loged in user
  23 + */
  24 + currentUser: noosfero.User;
  25 +
  26 + /**
  27 + * @ngdoc property
  28 + * @name credentials
  29 + * @propertyOf layout.blocks.LoginBlockComponent
  30 + * @description
  31 + * The credentials of the currentUser
  32 + */
  33 + credentials: noosfero.Credentials;
  34 +
  35 + constructor(
  36 + private session: SessionService,
  37 + private $state: ng.ui.IStateService,
  38 + public authService: AuthService,
  39 + private $scope: ng.IScope) {
  40 + this.currentUser = this.session.currentUser();
  41 +
  42 + this.authService.subscribe(AuthEvents[AuthEvents.loginSuccess], () => {
  43 + this.currentUser = this.session.currentUser();
  44 + });
  45 +
  46 + this.authService.subscribe(AuthEvents[AuthEvents.logoutSuccess], () => {
  47 + this.currentUser = this.session.currentUser();
  48 + });
  49 +
  50 + }
  51 +
  52 + /**
  53 + * @ngdoc method
  54 + * @name login
  55 + * @methodOf layout.blocks.LoginBlockComponent
  56 + * @description
  57 + * Logs in the user using its credentials
  58 + */
  59 + login() {
  60 + this.authService.login(this.credentials);
  61 + }
  62 +
  63 + /**
  64 + * @ngdoc method
  65 + * @name logout
  66 + * @methodOf layout.blocks.LoginBlockComponent
  67 + * @description
  68 + * Logout the user
  69 + */
  70 + logout() {
  71 + this.authService.logout();
  72 + };
  73 +}
... ...
src/app/layout/blocks/login-block/login-block.html 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +<div class="logged-user-info" ng-show="ctrl.currentUser">
  2 + <h4>Logged in as {{ctrl.currentUser.person.identifier}}</h4>
  3 + <ul>
  4 + <li>User since
  5 + <span class="time">
  6 + <span am-time-ago="ctrl.currentUser.person.created_at | dateFormat"></span>
  7 + </span>
  8 + </li>
  9 + <li><a ui-sref="main.profile.info({profile: ctrl.currentUser.person.identifier})">Profile Homepage</a></li>
  10 + </ul>
  11 + <div class="user-actions">
  12 + <a href="#" ng-click="ctrl.logout()"><i class="fa fa-fw fa-power-off"></i> {{"navbar.logout" | translate}}</a>
  13 + </div>
  14 +</div>
  15 +<div class="logged-user-info" ng-show="!ctrl.currentUser">
  16 + <form>
  17 + <div class="form-group">
  18 + <label for="exampleInputEmail1">{{"auth.form.login" | translate}}</label>
  19 + <input type="text" class="form-control" id="exampleInputEmail1" placeholder="Login / Email" ng-model="ctrl.credentials.username">
  20 + </div>
  21 + <div class="form-group">
  22 + <label for="exampleInputPassword1">{{"auth.form.password" | translate}}</label>
  23 + <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password" ng-model="ctrl.credentials.password">
  24 + </div>
  25 + <button type="submit" class="btn btn-default" ng-click="ctrl.login()">{{"auth.form.login_button" | translate}}</button>
  26 + </form>
  27 +</div>
0 28 \ No newline at end of file
... ...
src/app/layout/services/body-state-classes.service.spec.ts
... ... @@ -152,7 +152,7 @@ describe(&quot;BodyStateClasses Service&quot;, () =&gt; {
152 152 it("add a css class to content wrapper element", () => {
153 153 let service = getService();
154 154  
155   - let contentWrapperMock = jasmine.createSpyObj("contentWrapperMock", ["addClass", "removeClass"])
  155 + let contentWrapperMock = jasmine.createSpyObj("contentWrapperMock", ["addClass", "removeClass"]);
156 156 service["getContentWrapper"] = jasmine.createSpy("getContentWrapper").and.returnValue(contentWrapperMock);
157 157 service.addContentClass(true);
158 158  
... ... @@ -162,7 +162,7 @@ describe(&quot;BodyStateClasses Service&quot;, () =&gt; {
162 162 it("remove a css class from content wrapper element", () => {
163 163 let service = getService();
164 164  
165   - let contentWrapperMock = jasmine.createSpyObj("contentWrapperMock", ["addClass", "removeClass"])
  165 + let contentWrapperMock = jasmine.createSpyObj("contentWrapperMock", ["addClass", "removeClass"]);
166 166 service["getContentWrapper"] = jasmine.createSpy("getContentWrapper").and.returnValue(contentWrapperMock);
167 167 service.addContentClass(false);
168 168  
... ...
src/app/login/session.service.ts
... ... @@ -11,13 +11,11 @@ export class SessionService {
11 11  
12 12 create(data: UserResponse): noosfero.User {
13 13 this.$localStorage.currentUser = data.user;
14   - this.$log.debug('User session created.', this.$localStorage.currentUser);
15 14 return this.$localStorage.currentUser;
16 15 };
17 16  
18 17 destroy() {
19 18 delete this.$localStorage.currentUser;
20   - this.$log.debug('User session destroyed.');
21 19 };
22 20  
23 21 currentUser(): noosfero.User {
... ...
src/app/main/main.component.ts
... ... @@ -19,6 +19,7 @@ import {StatisticsBlockComponent} from &quot;../layout/blocks/statistics/statistics-b
19 19 import {MembersBlockComponent} from "./../layout/blocks/members/members-block.component";
20 20 import {CommunitiesBlockComponent} from "./../layout/blocks/communities/communities-block.component";
21 21  
  22 +import {LoginBlockComponent} from "../layout/blocks/login-block/login-block.component";
22 23  
23 24 import {NoosferoTemplate} from "../shared/pipes/noosfero-template.filter";
24 25 import {DateFormat} from "../shared/pipes/date-format.filter";
... ... @@ -96,7 +97,8 @@ export class EnvironmentContent {
96 97 EnvironmentComponent, PeopleBlockComponent,
97 98 LinkListBlockComponent, CommunitiesBlockComponent, HtmlEditorComponent,
98 99 MainBlockComponent, RecentDocumentsBlockComponent, Navbar, SidebarComponent, ProfileImageBlockComponent,
99   - MembersBlockComponent, NoosferoTemplate, DateFormat, RawHTMLBlockComponent, StatisticsBlockComponent
  100 + MembersBlockComponent, NoosferoTemplate, DateFormat, RawHTMLBlockComponent, StatisticsBlockComponent,
  101 + LoginBlockComponent
100 102 ].concat(plugins.mainComponents).concat(plugins.hotspots),
101 103  
102 104 providers: [AuthService, SessionService, NotificationService, BodyStateClassesService]
... ...
src/lib/ng-noosfero-api/interfaces/person.ts
... ... @@ -6,6 +6,5 @@ namespace noosfero {
6 6 * A representation of a Person in Noosfero.
7 7 */
8 8 export interface Person extends Profile {
9   -
10 9 }
11 10 }
12 11 \ No newline at end of file
... ...
src/lib/ng-noosfero-api/interfaces/profile.ts
... ... @@ -22,6 +22,14 @@ namespace noosfero {
22 22 * @returns {string} The unque identifier for the Profile
23 23 */
24 24 identifier: string;
  25 +
  26 + /**
  27 + * @ngdoc property
  28 + * @name created_at
  29 + * @propertyOf noofero.Profile
  30 + * @returns {string} The timestamp this object was created
  31 + */
  32 + created_at: string;
25 33  
26 34 /**
27 35 * @ngdoc property
... ...
src/spec/component-test-helper.ts
... ... @@ -2,6 +2,7 @@ import { Component } from &quot;ng-forward&quot;;
2 2 import { TestComponentBuilder, ngClass } from 'ng-forward/cjs/testing/test-component-builder';
3 3 import { INgForwardJQuery } from "ng-forward/cjs/util/jqlite-extensions";
4 4 import { ComponentFixture } from 'ng-forward/cjs/testing/test-component-builder';
  5 +import * as helpers from './helpers';
5 6  
6 7 /**
7 8 * @ngdoc object
... ... @@ -149,6 +150,7 @@ export function createClass({
149 150 providers = <any[]>[],
150 151 properties = <any>{}
151 152 }): any {
  153 + providers = providers.concat(helpers.provideFilters("translateFilter"));
152 154 @Component({ selector: 'component-test-helper-container', template, directives, providers })
153 155 class Test {
154 156 constructor() {
... ...
src/spec/mocks.ts
... ... @@ -68,6 +68,7 @@ export var mocks: any = {
68 68 mocks.authService['logoutSuccess'].event(param);
69 69 }
70 70 },
  71 + login: () => { },
71 72 logout: () => { },
72 73 subscribe: (eventName: string, fn: Function) => {
73 74 mocks.authService[eventName].subscribe(fn);
... ...
themes/participa-consulta/app/participa-consulta.scss
... ... @@ -5,3 +5,63 @@ body &gt; .ng-scope {
5 5 html, body {
6 6 height:100%;
7 7 }
  8 +
  9 +.box-default{
  10 + border: none;
  11 + border-radius: 3px 3px 0 0;
  12 + font-family: "Ubuntu Mediun";
  13 + font-size: 15px;
  14 + font-variant: normal;
  15 + font-weight: normal;
  16 + line-height: 30px;
  17 + padding: 15px 15px 15px 55px;
  18 + text-transform: capitalize;
  19 + background-size: 30px 30px;
  20 +}
  21 +
  22 +.skin-whbl .membersblock > .panel-heading{
  23 + @extend .box-default;
  24 + background: #DAE1C4 url("../assets/images/participa-consulta/pessoas.png") no-repeat 15px center;
  25 + color: #4F9CAC;
  26 +}
  27 +
  28 +.skin-whbl .statisticsblock > .panel-heading{
  29 + @extend .box-default;
  30 + background: #69677C url("../assets/images/participa-consulta/indicadores.png") no-repeat 15px center;
  31 + color: #DAE1C4;
  32 +}
  33 +
  34 +.link-list-block{
  35 + width: 900px; //Apagar depois!!!!
  36 + font-family: "Ubuntu";
  37 + font-size: 12px;
  38 + background: #69677C;
  39 + border-radius: 0 0 3px 3px;
  40 + margin-bottom: 30px;
  41 + padding: 20px;
  42 + margin: 0 0 30px 0;
  43 + position: relative;
  44 +}
  45 +
  46 +.link-list-block div, .link-list-block a{
  47 + display: inline-block;
  48 + background: #69677C;
  49 + border-radius: 0;
  50 + color: #FFF;
  51 + font-family: "Ubuntu Mediun";
  52 + font-size: 16px;
  53 + margin: 0;
  54 + padding: 0;
  55 + font-weight: bold;
  56 +}
  57 +
  58 +.link-list-block div:first-child{
  59 + padding: 15px 15px 15px 55px;
  60 + background: #69677C url("../assets/images/participa-consulta/home.png") no-repeat 15px center;
  61 + color: #FFF;
  62 + background-size: 30px 30px;
  63 +}
  64 +
  65 +.profile-header{
  66 + text-align: center;
  67 +}
... ...
themes/participa-consulta/assets/images/participa-consulta/home.png 0 → 100644

777 Bytes

themes/participa-consulta/assets/images/participa-consulta/indicadores.png 0 → 100644

1004 Bytes

themes/participa-consulta/assets/images/participa-consulta/pessoas.png 0 → 100644

1.27 KB