Commit 64000ab5a564b9ee11a757d634c2ec1698838746

Authored by Michel Felipe
2 parents fb1e923a b4a0a739

Merge branch 'register_page' into 'master'

See merge request !47
@@ -39,7 +39,8 @@ @@ -39,7 +39,8 @@
39 "angular-click-outside": "^2.7.1", 39 "angular-click-outside": "^2.7.1",
40 "ng-ckeditor": "^0.2.1", 40 "ng-ckeditor": "^0.2.1",
41 "angular-tag-cloud": "^0.3.0", 41 "angular-tag-cloud": "^0.3.0",
42 - "angular-ui-switch": "^0.1.1" 42 + "angular-ui-switch": "^0.1.1",
  43 + "angular-password": "^1.0.1"
43 }, 44 },
44 "devDependencies": { 45 "devDependencies": {
45 "angular-mocks": "~1.5.0" 46 "angular-mocks": "~1.5.0"
src/app/account/index.ts 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +export * from "./register.component";
src/app/account/register-component.html 0 → 100644
@@ -0,0 +1,77 @@ @@ -0,0 +1,77 @@
  1 +<div class="register-page">
  2 + <div class="welcome-message">
  3 + <h1>{{"account.register.welcomeMessageTitle" | translate }}</h1>
  4 + <div class="environment-signup-intro" ng-bind-html="ctrl.environment.signup_intro"></div>
  5 + </div>
  6 + <form name="signupForm">
  7 + <div class="row">
  8 + <div class="col-md-12 register-field">
  9 + <div class="input-group">
  10 + <span class="input-group-addon"><i class="fa fa-male"></i><i class="fa fa-female"></i></span>
  11 + <input type="text" class="form-control" id="name" name="fullName" placeholder="{{'account.register.fullNameLabel' | translate }}" ng-model="ctrl.account.name">
  12 + </div>
  13 + </div>
  14 +
  15 + <div class="form-group col-md-12 register-field" ng-class="ctrl.isInvalid(signupForm.username)">
  16 + <div class="input-group">
  17 + <span class="input-group-addon" style="font-weight: bold;"><i class="fa fa-globe"></i>&nbsp;{{ ctrl.environment.host }}</span>
  18 + <input type="text" id="username" name="username" class="form-control" placeholder="{{'account.register.usernameLabel' | translate }}" ng-model="ctrl.account.login" required>
  19 + </div>
  20 + <div class="help-block" ng-show="signupForm.username.$touched" ng-messages="signupForm.username.$error">
  21 + <ul class="list-unstyled">
  22 + <li ng-messages-include="languages/messages.html"></li>
  23 + </ul>
  24 + </div>
  25 + </div>
  26 +
  27 + <div class="form-group col-md-12 register-field" ng-class="ctrl.isInvalid(signupForm.email)">
  28 + <div class="input-group">
  29 + <span class="input-group-addon"><i class="fa fa-envelope"></i></span>
  30 + <input type="email" class="form-control" id="email" name="email" placeholder="{{'account.register.emailLabel' | translate }}" ng-model="ctrl.account.email" required>
  31 + </div>
  32 + <div class="help-block" ng-show="signupForm.email.$touched" ng-messages="signupForm.email.$error">
  33 + <ul class="list-unstyled">
  34 + <li ng-messages-include="languages/messages.html"></li>
  35 + </ul>
  36 + </div>
  37 + </div>
  38 +
  39 + <div class="form-group col-md-6 register-field" ng-class="ctrl.isInvalid(signupForm.password)">
  40 + <div class="input-group">
  41 + <span class="input-group-addon"><i class="fa fa-lock"></i></span>
  42 + <input type="password" class="form-control" id="password" name="password" placeholder="{{'account.register.passwordLabel' | translate }}" ng-model="ctrl.account.password" required>
  43 + </div>
  44 + <div class="help-block" ng-show="signupForm.password.$touched" ng-messages="signupForm.password.$error">
  45 + <ul class="list-unstyled">
  46 + <li ng-messages-include="languages/messages.html"></li>
  47 + </ul>
  48 + </div>
  49 + </div>
  50 +
  51 + <div class="form-group col-md-6 register-field" ng-class="ctrl.isInvalid(signupForm.passwordConfirm)">
  52 + <div class="input-group">
  53 + <span class="input-group-addon"><i class="fa fa-unlock-alt"></i></span>
  54 + <input type="password" class="form-control" id="passwordConfirm" name="passwordConfirm" match-password="password" placeholder="{{'account.register.passwordConfirmationLabel' | translate}}" ng-model="ctrl.account.passwordConfirmation" required>
  55 + </div>
  56 + <div class="help-block" ng-show="signupForm.passwordConfirm.$touched" ng-messages="signupForm.passwordConfirm.$error">
  57 + <ul class="list-unstyled">
  58 + <li ng-messages-include="languages/messages.html"></li>
  59 + <li ng-message="passwordMatch" translate="messages.invalid.passwordMatch"></li>
  60 + </ul>
  61 + </div>
  62 + </div>
  63 +
  64 + <div class="col-md-12">
  65 + <p class="terms-info">{{"account.register.accountCreatingMessage" | translate}} <a (click)="ctrl.openTerms()" href="#">{{"account.register.termsOfUseMessage" | translate}}</a>.</p>
  66 + </div>
  67 +
  68 + <div class="col-md-12">
  69 + <button type="submit" class="btn btn-default" ng-disabled="signupForm.$invalid" ng-click="ctrl.signup()">{{"account.register.signupMessage" | translate}}</button>
  70 + </div>
  71 +
  72 + </div>
  73 + </form>
  74 +
  75 + <p class="already-registered-message">{{"account.register.haveAccountMessage" | translate}}</p>
  76 +
  77 +</div>
src/app/account/register-terms.html 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +<div class="modal-header">
  2 + <h3 class="modal-title">Register terms</h3>
  3 +</div>
  4 +<div class="modal-body modal-body-overflow" ng-bind-html="ctrl.environment.terms_of_use"></div>
  5 +<div class="modal-footer">
  6 + <button class="btn btn-primary" type="button" (click)="vm.closeTerms()">OK</button>
  7 +</div>
src/app/account/register.component.spec.ts 0 → 100644
@@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
  1 +import { ComponentTestHelper, createClass } from "../../spec/component-test-helper";
  2 +import * as helpers from "../../spec/helpers";
  3 +import { RegisterComponent } from "./register.component";
  4 +// import {RegisterService} from "../../lib/ng-noosfero-api/http/register.service"
  5 +
  6 +
  7 +describe("Register Component", () => {
  8 + const htmlTemplate: string = '<noosfero-register></noosfero-register>';
  9 +
  10 + let helper: ComponentTestHelper<RegisterComponent>;
  11 + let registerService = helpers.mocks.registerService;
  12 + let stateService = jasmine.createSpyObj("$state", ["transitionTo"]);
  13 + let notificationService = helpers.mocks.notificationService;
  14 + notificationService.success = jasmine.createSpy('success');
  15 + notificationService.error = jasmine.createSpy('error');
  16 +
  17 +
  18 + let account: any = {
  19 + id: 1,
  20 + login: 'test',
  21 + email: 'test@email.com',
  22 + password: 'xxx',
  23 + passwordConfirmation: 'xxx'
  24 + };
  25 +
  26 + beforeEach(() => {
  27 + angular.mock.module('templates');
  28 + angular.mock.module('ngSanitize');
  29 + angular.mock.module('ngMessages');
  30 + angular.mock.module('ngPassword');
  31 + });
  32 +
  33 + beforeEach((done) => {
  34 + let cls = createClass({
  35 + template: htmlTemplate,
  36 + directives: [RegisterComponent],
  37 + providers: [
  38 + helpers.createProviderToValue('$state', stateService),
  39 + helpers.createProviderToValue('$uibModal', helpers.mocks.$modal),
  40 + helpers.createProviderToValue('RegisterService', registerService),
  41 + helpers.createProviderToValue('NotificationService', notificationService),
  42 + helpers.createProviderToValue('EnvironmentService', helpers.mocks.environmentService)
  43 + ]
  44 + });
  45 + helper = new ComponentTestHelper<RegisterComponent>(cls, done);
  46 + });
  47 +
  48 + it('register page was rendered', () => {
  49 + expect(helper.debugElement.query('div.register-page').length).toEqual(1);
  50 + });
  51 +
  52 +});
src/app/account/register.component.ts 0 → 100644
@@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
  1 +import { Inject, Input, Component, Output, EventEmitter, provide } from 'ng-forward';
  2 +import { RegisterService } from "./../../lib/ng-noosfero-api/http/register.service";
  3 +import { NotificationService } from "./../shared/services/notification.service";
  4 +import { EnvironmentService } from "../../lib/ng-noosfero-api/http/environment.service";
  5 +import { RegisterController } from "./register.controller";
  6 +import { IModalComponent } from "../shared/components/interfaces";
  7 +
  8 +@Component({
  9 + selector: 'noosfero-register',
  10 + templateUrl: 'app/account/register-component.html',
  11 + providers: [
  12 + provide('registerService', { useClass: RegisterService })
  13 + ]
  14 +})
  15 +
  16 +@Inject('$state', '$uibModal', '$scope', RegisterService, NotificationService, EnvironmentService)
  17 +export class RegisterComponent {
  18 + @Input() account: any;
  19 + environment: noosfero.Environment;
  20 +
  21 + modalInstance: ng.ui.bootstrap.IModalServiceInstance;
  22 +
  23 + constructor(
  24 + private $state: ng.ui.IStateService,
  25 + private $uibModal: ng.ui.bootstrap.IModalService,
  26 + private $scope: ng.IScope,
  27 + public registerService: RegisterService,
  28 + private notificationService: NotificationService,
  29 + private environmentService: EnvironmentService
  30 + ) {
  31 + this.account = {};
  32 + this.environment = environmentService.getCurrentEnvironment();
  33 + }
  34 +
  35 + signup() {
  36 + if (this.account.password === this.account.passwordConfirmation) {
  37 + this.registerService.createAccount(this.account).then((response) => {
  38 +
  39 + if (response.status === 201) {
  40 + this.$state.transitionTo('main.environment');
  41 + this.notificationService.success({ title: "account.register.success.title", message: "account.register.success.message" });
  42 + } else {
  43 + throw new Error('Invalid attributes');
  44 + }
  45 + });
  46 + } else {
  47 + this.notificationService.error({ message: "account.register.passwordConfirmation.failed" });
  48 + }
  49 + }
  50 +
  51 + isInvalid(field: any): any {
  52 + return { 'has-error': field['$touched'] && field['$invalid'] };
  53 + }
  54 +
  55 + openTerms() {
  56 +
  57 + this.modalInstance = this.$uibModal.open({
  58 + templateUrl: 'app/account/register-terms.html',
  59 + size: 'lg',
  60 + controller: RegisterController,
  61 + controllerAs: 'vm',
  62 + bindToController: true,
  63 + scope: this.$scope
  64 + });
  65 + }
  66 +}
src/app/account/register.controller.ts 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +import { Input } from "ng-forward";
  2 +import { IModalComponent } from "../shared/components/interfaces";
  3 +
  4 +export class RegisterController {
  5 +
  6 + static $inject = ["$log", "$stateParams", "$scope"];
  7 + ctrl: IModalComponent;
  8 +
  9 + constructor(
  10 + private $log: ng.ILogService,
  11 + private $stateParams: any
  12 + ) { }
  13 +
  14 + closeTerms() {
  15 + this.ctrl.modalInstance.dismiss('ok');
  16 + }
  17 +}
src/app/account/register.html 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +<div class="row">
  2 + <div class="col-md-3"></div>
  3 +
  4 + <!-- component at center of page -->
  5 + <div class="col-md-6">
  6 + <noosfero-register></noosfero-register>
  7 + </div>
  8 +
  9 + <div class="col-md-3"></div>
  10 +</div>
src/app/account/scss/register.scss 0 → 100644
@@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
  1 +.modal .modal-body-overflow {
  2 + max-height: 420px;
  3 + overflow-y: auto;
  4 +}
  5 +
  6 +.register-page button {
  7 + width: 100%;
  8 + text-transform: uppercase;
  9 + font-weight: 600;
  10 +}
  11 +
  12 +.register-page .light-text {
  13 + color: #BBB;
  14 + margin-top: 0px;
  15 + margin-bottom: 0px;
  16 + font-weight: 600;
  17 +}
  18 +
  19 +.register-page .terms-info {
  20 + margin-top: 30px;
  21 + margin-bottom: 30px;
  22 + font-weight: bold;
  23 +}
  24 +
  25 +.register-page .welcome-message {
  26 + text-align: center;
  27 +}
  28 +
  29 +.register-page .already-registered-message {
  30 + margin-top: 60px;
  31 + text-align: center;
  32 +}
  33 +
  34 +.register-page input {
  35 + height: 40px;
  36 +}
  37 +
  38 +.register-page .register-field {
  39 + margin-bottom: 25px;
  40 +}
  41 +
  42 +.register-page input:focus {
  43 + border: 2px solid #bbb;
  44 +}
src/app/layout/blocks/block.component.ts
@@ -18,7 +18,7 @@ export class BlockComponent { @@ -18,7 +18,7 @@ export class BlockComponent {
18 @Input() block: noosfero.Block; 18 @Input() block: noosfero.Block;
19 @Input() owner: noosfero.Profile | noosfero.Environment; 19 @Input() owner: noosfero.Profile | noosfero.Environment;
20 20
21 - private modalInstance: any = null; 21 + private modalInstance: ng.ui.bootstrap.IModalServiceInstance;
22 originalBlock: noosfero.Block; 22 originalBlock: noosfero.Block;
23 23
24 currentUser: noosfero.User; 24 currentUser: noosfero.User;
@@ -26,7 +26,8 @@ export class BlockComponent { @@ -26,7 +26,8 @@ export class BlockComponent {
26 editionMode = false; 26 editionMode = false;
27 designMode = false; 27 designMode = false;
28 28
29 - constructor(private $uibModal: any, 29 + constructor(
  30 + private $uibModal: ng.ui.bootstrap.IModalService,
30 private $scope: ng.IScope, 31 private $scope: ng.IScope,
31 private $state: ng.ui.IStateService, 32 private $state: ng.ui.IStateService,
32 private $rootScope: ng.IRootScopeService, 33 private $rootScope: ng.IRootScopeService,
src/app/layout/navbar/navbar.html
@@ -20,6 +20,12 @@ @@ -20,6 +20,12 @@
20 <a ng-href="#" ng-click="ctrl.openLogin()">{{"navbar.login" | translate}}</a> 20 <a ng-href="#" ng-click="ctrl.openLogin()">{{"navbar.login" | translate}}</a>
21 </li> 21 </li>
22 22
  23 + <li ng-show="!ctrl.currentUser">
  24 + <a ui-sref="main.register">
  25 + Sign Up
  26 + </a>
  27 + </li>
  28 +
23 <li class="dropdown profile-menu" ng-show="ctrl.currentUser" uib-dropdown> 29 <li class="dropdown profile-menu" ng-show="ctrl.currentUser" uib-dropdown>
24 <a href="#" class="dropdown-toggle" aria-expanded="false" uib-dropdown-toggle> 30 <a href="#" class="dropdown-toggle" aria-expanded="false" uib-dropdown-toggle>
25 <noosfero-profile-image [profile]="ctrl.currentUser.person" class="profile-image"></noosfero-profile-image> 31 <noosfero-profile-image [profile]="ctrl.currentUser.person" class="profile-image"></noosfero-profile-image>
src/app/layout/navbar/navbar.ts
1 -import {Component, Inject, EventEmitter, Input} from "ng-forward";  
2 -import {LanguageSelectorComponent} from "../language-selector/language-selector.component";  
3 -import {SessionService, AuthService, AuthController, AuthEvents} from "./../../login";  
4 -import {EnvironmentService} from "./../../../lib/ng-noosfero-api/http/environment.service";  
5 -import {SidebarNotificationService} from "../sidebar/sidebar.notification.service";  
6 -import {BodyStateClassesService} from '../services/body-state-classes.service';  
7 -import {DesignModeTogglerComponent} from './../../admin/layout-edit/designModeToggler.component';  
8 -import {BootstrapSwitcherComponent, BootstrapSwitcherItem} from './../../shared/components/bootstrap-switcher/bootstrap-switcher.component'; 1 +import { Component, Inject, EventEmitter, Input } from "ng-forward";
  2 +import { LanguageSelectorComponent } from "../language-selector/language-selector.component";
  3 +import { SessionService, AuthService, AuthController, AuthEvents } from "./../../login";
  4 +import { EnvironmentService } from "./../../../lib/ng-noosfero-api/http/environment.service";
  5 +import { SidebarNotificationService } from "../sidebar/sidebar.notification.service";
  6 +import { BodyStateClassesService } from '../services/body-state-classes.service';
  7 +import { DesignModeTogglerComponent } from './../../admin/layout-edit/designModeToggler.component';
  8 +import { BootstrapSwitcherComponent, BootstrapSwitcherItem } from './../../shared/components/bootstrap-switcher/bootstrap-switcher.component';
9 9
10 @Component({ 10 @Component({
11 selector: "acme-navbar", 11 selector: "acme-navbar",
@@ -17,14 +17,14 @@ import {BootstrapSwitcherComponent, BootstrapSwitcherItem} from &#39;./../../shared/ @@ -17,14 +17,14 @@ import {BootstrapSwitcherComponent, BootstrapSwitcherItem} from &#39;./../../shared/
17 export class Navbar { 17 export class Navbar {
18 18
19 private currentUser: noosfero.User; 19 private currentUser: noosfero.User;
20 - private modalInstance: any = null; 20 + private modalInstance: ng.ui.bootstrap.IModalServiceInstance;
21 public showHamburger: boolean = false; 21 public showHamburger: boolean = false;
22 public currentEnvironment: noosfero.Environment = <any>{ name: '' }; 22 public currentEnvironment: noosfero.Environment = <any>{ name: '' };
23 /** 23 /**
24 * 24 *
25 */ 25 */
26 constructor( 26 constructor(
27 - private $uibModal: any, 27 + private $uibModal: ng.ui.bootstrap.IModalService,
28 public authService: AuthService, 28 public authService: AuthService,
29 private session: SessionService, 29 private session: SessionService,
30 private $state: ng.ui.IStateService, 30 private $state: ng.ui.IStateService,
src/app/layout/scss/_forms.scss
@@ -2,6 +2,10 @@ label { @@ -2,6 +2,10 @@ label {
2 cursor: pointer; 2 cursor: pointer;
3 } 3 }
4 4
  5 +.has-error .help-block {
  6 + font-weight: bold;
  7 +}
  8 +
5 .checkbox-nice { 9 .checkbox-nice {
6 position: relative; 10 position: relative;
7 padding-left: 15px; 11 padding-left: 15px;
src/app/login/login.html
@@ -21,4 +21,7 @@ @@ -21,4 +21,7 @@
21 </div> 21 </div>
22 <button type="submit" class="btn btn-default btn-block" ng-click="vm.login()">{{"auth.form.login_button" | translate}}</button> 22 <button type="submit" class="btn btn-default btn-block" ng-click="vm.login()">{{"auth.form.login_button" | translate}}</button>
23 </form> 23 </form>
  24 + <div class="text-center">
  25 + <a ui-sref="main.register" ng-click="$close()">{{"auth.createAccount" | translate}}</a>
  26 + </div>
24 </div> 27 </div>
src/app/login/session.service.ts
@@ -23,4 +23,4 @@ export class SessionService { @@ -23,4 +23,4 @@ export class SessionService {
23 return this.$localStorage.currentUser; 23 return this.$localStorage.currentUser;
24 }; 24 };
25 25
26 -}  
27 \ No newline at end of file 26 \ No newline at end of file
  27 +}
src/app/main/main.component.ts
@@ -21,6 +21,7 @@ import { PersonTagsPluginInterestsBlockComponent } from &quot;../layout/blocks/person @@ -21,6 +21,7 @@ import { PersonTagsPluginInterestsBlockComponent } from &quot;../layout/blocks/person
21 import { TagsBlockComponent } from "../layout/blocks/tags/tags-block.component"; 21 import { TagsBlockComponent } from "../layout/blocks/tags/tags-block.component";
22 import { CustomContentComponent } from "../profile/custom-content/custom-content.component"; 22 import { CustomContentComponent } from "../profile/custom-content/custom-content.component";
23 import { RecentActivitiesPluginActivitiesBlockComponent } from "../layout/blocks/recent-activities-plugin-activities/recent-activities-plugin-activities-block.component"; 23 import { RecentActivitiesPluginActivitiesBlockComponent } from "../layout/blocks/recent-activities-plugin-activities/recent-activities-plugin-activities-block.component";
  24 +import { RegisterComponent } from "../account/register.component";
24 25
25 import { MembersBlockComponent } from "../layout/blocks/members/members-block.component"; 26 import { MembersBlockComponent } from "../layout/blocks/members/members-block.component";
26 import { CommunitiesBlockComponent } from "../layout/blocks/communities/communities-block.component"; 27 import { CommunitiesBlockComponent } from "../layout/blocks/communities/communities-block.component";
@@ -34,6 +35,7 @@ import { AuthService } from &quot;../login/auth.service&quot;; @@ -34,6 +35,7 @@ import { AuthService } from &quot;../login/auth.service&quot;;
34 import { SessionService } from "../login/session.service"; 35 import { SessionService } from "../login/session.service";
35 import { EnvironmentService } from "./../../lib/ng-noosfero-api/http/environment.service"; 36 import { EnvironmentService } from "./../../lib/ng-noosfero-api/http/environment.service";
36 import { NotificationService } from "../shared/services/notification.service"; 37 import { NotificationService } from "../shared/services/notification.service";
  38 +import { RegisterService } from "./../../lib/ng-noosfero-api/http/register.service";
37 39
38 import { BodyStateClassesService } from "./../layout/services/body-state-classes.service"; 40 import { BodyStateClassesService } from "./../layout/services/body-state-classes.service";
39 41
@@ -113,16 +115,16 @@ export class EnvironmentContent { @@ -113,16 +115,16 @@ export class EnvironmentContent {
113 MainBlockComponent, RecentDocumentsBlockComponent, Navbar, SidebarComponent, ProfileImageBlockComponent, 115 MainBlockComponent, RecentDocumentsBlockComponent, Navbar, SidebarComponent, ProfileImageBlockComponent,
114 MembersBlockComponent, NoosferoTemplate, DateFormat, RawHTMLBlockComponent, StatisticsBlockComponent, 116 MembersBlockComponent, NoosferoTemplate, DateFormat, RawHTMLBlockComponent, StatisticsBlockComponent,
115 LoginBlockComponent, CustomContentComponent, PermissionDirective, SearchFormComponent, SearchComponent, 117 LoginBlockComponent, CustomContentComponent, PermissionDirective, SearchFormComponent, SearchComponent,
116 - PersonTagsPluginInterestsBlockComponent, TagsBlockComponent, RecentActivitiesPluginActivitiesBlockComponent, BlockComponent 118 + PersonTagsPluginInterestsBlockComponent, TagsBlockComponent, RecentActivitiesPluginActivitiesBlockComponent, BlockComponent, RegisterComponent
117 ].concat(plugins.mainComponents).concat(plugins.hotspots), 119 ].concat(plugins.mainComponents).concat(plugins.hotspots),
118 - providers: [AuthService, SessionService, NotificationService, BodyStateClassesService, 120 + providers: [AuthService, SessionService, NotificationService, BodyStateClassesService, RegisterService,
119 "ngAnimate", "ngCookies", "ngStorage", "ngTouch", 121 "ngAnimate", "ngCookies", "ngStorage", "ngTouch",
120 "ngSanitize", "ngMessages", "ngAria", "restangular", 122 "ngSanitize", "ngMessages", "ngAria", "restangular",
121 "ui.router", "ui.bootstrap", "toastr", "ngCkeditor", 123 "ui.router", "ui.bootstrap", "toastr", "ngCkeditor",
122 "angular-bind-html-compile", "angularMoment", "angular.filter", "akoenig.deckgrid", 124 "angular-bind-html-compile", "angularMoment", "angular.filter", "akoenig.deckgrid",
123 "angular-timeline", "duScroll", "oitozero.ngSweetAlert", 125 "angular-timeline", "duScroll", "oitozero.ngSweetAlert",
124 "pascalprecht.translate", "tmh.dynamicLocale", "angularLoad", 126 "pascalprecht.translate", "tmh.dynamicLocale", "angularLoad",
125 - "angular-click-outside", "ngTagCloud", "noosfero.init", "uiSwitch"] 127 + "angular-click-outside", "ngTagCloud", "noosfero.init", "uiSwitch", "ngPassword"]
126 }) 128 })
127 @StateConfig([ 129 @StateConfig([
128 { 130 {
@@ -143,7 +145,6 @@ export class EnvironmentContent { @@ -143,7 +145,6 @@ export class EnvironmentContent {
143 url: '/', 145 url: '/',
144 component: EnvironmentComponent, 146 component: EnvironmentComponent,
145 name: 'main.environment', 147 name: 'main.environment',
146 - abstract: true,  
147 views: { 148 views: {
148 "content": { 149 "content": {
149 templateUrl: "app/environment/environment.html", 150 templateUrl: "app/environment/environment.html",
@@ -153,6 +154,18 @@ export class EnvironmentContent { @@ -153,6 +154,18 @@ export class EnvironmentContent {
153 } 154 }
154 }, 155 },
155 { 156 {
  157 + url: '/account/signup',
  158 + component: RegisterComponent,
  159 + name: 'main.register',
  160 + views: {
  161 + "content": {
  162 + templateUrl: "app/account/register.html",
  163 + controller: RegisterComponent,
  164 + controllerAs: "vm"
  165 + }
  166 + }
  167 + },
  168 + {
156 url: "^/:profile", 169 url: "^/:profile",
157 abstract: true, 170 abstract: true,
158 component: ProfileComponent, 171 component: ProfileComponent,
src/app/profile/custom-content/custom-content.component.ts
1 -import {Component, Input, Inject} from 'ng-forward';  
2 -import {ProfileService} from '../../../lib/ng-noosfero-api/http/profile.service';  
3 -import {NotificationService} from '../../shared/services/notification.service';  
4 -import {PermissionDirective} from '../../shared/components/permission/permission.directive';  
5 -import {DesignModeService} from '../../admin/layout-edit/designMode.service'; 1 +import { Component, Input, Inject } from 'ng-forward';
  2 +import { ProfileService } from '../../../lib/ng-noosfero-api/http/profile.service';
  3 +import { NotificationService } from '../../shared/services/notification.service';
  4 +import { PermissionDirective } from '../../shared/components/permission/permission.directive';
  5 +import { DesignModeService } from '../../admin/layout-edit/designMode.service';
6 6
7 @Component({ 7 @Component({
8 selector: 'custom-content', 8 selector: 'custom-content',
@@ -21,9 +21,10 @@ export class CustomContentComponent { @@ -21,9 +21,10 @@ export class CustomContentComponent {
21 21
22 content: string; 22 content: string;
23 originalContent: string; 23 originalContent: string;
24 - private modalInstance: any = null; 24 + private modalInstance: ng.ui.bootstrap.IModalServiceInstance;
25 25
26 - constructor(private $uibModal: any, 26 + constructor(
  27 + private $uibModal: ng.ui.bootstrap.IModalService,
27 private $scope: ng.IScope, 28 private $scope: ng.IScope,
28 private profileService: ProfileService, 29 private profileService: ProfileService,
29 private notificationService: NotificationService, 30 private notificationService: NotificationService,
src/app/shared/components/interfaces.ts
1 -  
2 -  
3 export interface IComponentWithPermissions { 1 export interface IComponentWithPermissions {
4 permissions: () => string[]; 2 permissions: () => string[];
5 -}  
6 \ No newline at end of file 3 \ No newline at end of file
  4 +}
  5 +
  6 +export interface IModalComponent {
  7 + $uibModal: ng.ui.bootstrap.IModalService;
  8 + modalInstance: ng.ui.bootstrap.IModalServiceInstance;
  9 +}
src/languages/en.json
@@ -28,6 +28,7 @@ @@ -28,6 +28,7 @@
28 "auth.form.password": "Password", 28 "auth.form.password": "Password",
29 "auth.form.keepLoggedIn": "Keep me logged in", 29 "auth.form.keepLoggedIn": "Keep me logged in",
30 "auth.form.login_button": "Login", 30 "auth.form.login_button": "Login",
  31 + "auth.createAccount": "Create account",
31 "navbar.content_viewer_actions.new_item": "New Item", 32 "navbar.content_viewer_actions.new_item": "New Item",
32 "navbar.profile_actions.new_item": "New Item", 33 "navbar.profile_actions.new_item": "New Item",
33 "navbar.content_viewer_actions.new_post": "New Post", 34 "navbar.content_viewer_actions.new_post": "New Post",
@@ -100,5 +101,23 @@ @@ -100,5 +101,23 @@
100 "block.edition.language.label": "Show for:", 101 "block.edition.language.label": "Show for:",
101 "activities.event.description": "Event on", 102 "activities.event.description": "Event on",
102 "time.at": "at", 103 "time.at": "at",
103 - "date.on": "On" 104 + "date.on": "On",
  105 + "account.register.welcomeMessageTitle": "Nice to have you there!",
  106 + "account.register.fullNameLabel": "Full name",
  107 + "account.register.usernameLabel": "Username",
  108 + "account.register.emailLabel": "Email",
  109 + "account.register.passwordLabel": "Password",
  110 + "account.register.passwordConfirmationLabel": "Password confirmation",
  111 + "account.register.accountCreatingMessage": "By creating an account, you are agreeing with the ",
  112 + "account.register.signupMessage": "Register",
  113 + "account.register.haveAccountMessage": "Already have an account?",
  114 + "account.register.termsOfUseMessage": "terms of use",
  115 + "account.register.success.title": "Good job!",
  116 + "account.register.success.message": "Account created!",
  117 + "account.register.passwordConfirmation.failed": "Wrong password confirmation",
  118 + "messages.invalid.required": "This field is required",
  119 + "messages.invalid.maxlength": "This field is too long",
  120 + "messages.invalid.minlength": "This field is too short",
  121 + "messages.invalid.email": "This needs to be a valid email",
  122 + "messages.invalid.passwordMatch": "Your passwords did not match"
104 } 123 }
src/languages/messages.html 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +<li ng-message="required" translate="messages.invalid.required"></li>
  2 +<li ng-message="minlength" translate="messages.invalid.minlength"></li>
  3 +<li ng-message="maxlength" translate="messages.invalid.maxlength"></li>
  4 +<li ng-message="email" translate="messages.invalid.email"></li>
src/languages/pt.json
@@ -28,6 +28,7 @@ @@ -28,6 +28,7 @@
28 "auth.form.password": "Senha", 28 "auth.form.password": "Senha",
29 "auth.form.keepLoggedIn": "Continuar logado", 29 "auth.form.keepLoggedIn": "Continuar logado",
30 "auth.form.login_button": "Login", 30 "auth.form.login_button": "Login",
  31 + "auth.createAccount": "Criar conta",
31 "navbar.content_viewer_actions.new_item": "Novo Item", 32 "navbar.content_viewer_actions.new_item": "Novo Item",
32 "navbar.profile_actions.new_item": "Novo Item", 33 "navbar.profile_actions.new_item": "Novo Item",
33 "navbar.content_viewer_actions.new_post": "Novo Artigo", 34 "navbar.content_viewer_actions.new_post": "Novo Artigo",
@@ -100,5 +101,26 @@ @@ -100,5 +101,26 @@
100 "block.edition.language.label": "Exibir para:", 101 "block.edition.language.label": "Exibir para:",
101 "activities.event.description": "Evento em", 102 "activities.event.description": "Evento em",
102 "time.at": "às", 103 "time.at": "às",
103 - "date.on": "Em" 104 + "date.on": "Em",
  105 + "account.register.welcomeMessageTitle": "Ótimo ter você aqui!",
  106 + "account.register.seeMoreMessage": "Saiba mais ",
  107 + "account.register.informationsMessage": "informações",
  108 + "account.register.fullNameLabel": "Nome completo",
  109 + "account.register.lastNameLabel": "Sobrenome",
  110 + "account.register.usernameLabel": "Nome de usuário",
  111 + "account.register.emailLabel": "Email",
  112 + "account.register.passwordLabel": "Senha",
  113 + "account.register.passwordConfirmationLabel": "Confirmar senha",
  114 + "account.register.accountCreatingMessage": "Ao criar uma conta, você está concordando com os ",
  115 + "account.register.termsOfUseMessage": "termos de uso",
  116 + "account.register.signupMessage": "Criar Conta",
  117 + "account.register.haveAccountMessage": "Já possui uma conta?",
  118 + "account.register.success.title": "Bom trabalho!",
  119 + "account.register.success.message": "Conta criada com sucesso!",
  120 + "account.register.passwordConfirmation.failed": "A confirmação de senha não corresponde à senha",
  121 + "messages.invalid.required": "Campo obrigatório",
  122 + "messages.invalid.maxlength": "O valor é muito longo",
  123 + "messages.invalid.minlength": "O valor é muito curto",
  124 + "messages.invalid.email": "Informe um email válido",
  125 + "messages.invalid.passwordMatch": "As senhas não coincidem"
104 } 126 }
src/lib/ng-noosfero-api/http/article.service.spec.ts
@@ -17,7 +17,6 @@ describe(&quot;Services&quot;, () =&gt; { @@ -17,7 +17,6 @@ describe(&quot;Services&quot;, () =&gt; {
17 articleService = _ArticleService_; 17 articleService = _ArticleService_;
18 })); 18 }));
19 19
20 -  
21 describe("Succesfull requests", () => { 20 describe("Succesfull requests", () => {
22 21
23 it("should remove article", (done) => { 22 it("should remove article", (done) => {
@@ -92,6 +91,5 @@ describe(&quot;Services&quot;, () =&gt; { @@ -92,6 +91,5 @@ describe(&quot;Services&quot;, () =&gt; {
92 }); 91 });
93 }); 92 });
94 93
95 -  
96 }); 94 });
97 }); 95 });
src/lib/ng-noosfero-api/http/register.service.spec.ts 0 → 100644
@@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
  1 +import { RegisterService } from "./register.service";
  2 +
  3 +describe("Services", () => {
  4 +
  5 + describe("Register Service", () => {
  6 +
  7 + let $httpBackend: ng.IHttpBackendService;
  8 + let registerService: RegisterService;
  9 + let $rootScope: ng.IRootScopeService;
  10 + let user: any = {
  11 + id: 1,
  12 + login: 'test',
  13 + email: 'test@email.com'
  14 + };
  15 +
  16 + beforeEach(angular.mock.module("main", ($translateProvider: angular.translate.ITranslateProvider) => {
  17 + $translateProvider.translations('en', {});
  18 + }));
  19 +
  20 + beforeEach(inject((_$httpBackend_: ng.IHttpBackendService, _RegisterService_: RegisterService, _$rootScope_: ng.IRootScopeService) => {
  21 + $httpBackend = _$httpBackend_;
  22 + registerService = _RegisterService_;
  23 + $rootScope = _$rootScope_;
  24 + }));
  25 +
  26 + describe("Succesfull requests", () => {
  27 +
  28 + it("should creaet a new account", (done) => {
  29 +
  30 + $httpBackend.expectPOST(`/api/v1/register?email=${user.email}&id=${user.id}&login=${user.login}`).respond(201, [{ login: "test" }]);
  31 + registerService.createAccount(user).then((response: restangular.IResponse) => {
  32 + expect(response.data[0].login).toEqual("test");
  33 + done();
  34 + });
  35 + $httpBackend.flush();
  36 + });
  37 + });
  38 + });
  39 +});
src/lib/ng-noosfero-api/http/register.service.ts 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +import { Injectable, Inject } from "ng-forward";
  2 +import { RestangularService } from "./restangular_service";
  3 +
  4 +@Injectable()
  5 +@Inject("Restangular")
  6 +export class RegisterService {
  7 + constructor(private Restangular: restangular.IService) {
  8 + this.Restangular = Restangular;
  9 + }
  10 +
  11 + createAccount(user: noosfero.User): ng.IPromise<noosfero.RestResult<noosfero.User>> {
  12 + return this.Restangular.all("").customPOST(user, "register", user);
  13 + }
  14 +}
src/lib/ng-noosfero-api/http/restangular_service.ts
@@ -80,14 +80,16 @@ export abstract class RestangularService&lt;T extends noosfero.RestModel&gt; { @@ -80,14 +80,16 @@ export abstract class RestangularService&lt;T extends noosfero.RestModel&gt; {
80 } 80 }
81 return { 81 return {
82 data: (response.data[dataKey] || response.data), 82 data: (response.data[dataKey] || response.data),
83 - headers: response.headers 83 + headers: response.headers,
  84 + status: response.status
84 }; 85 };
85 }; 86 };
86 87
87 protected buildResult(response: restangular.IResponse): noosfero.RestResult<T> { 88 protected buildResult(response: restangular.IResponse): noosfero.RestResult<T> {
88 return { 89 return {
89 data: response.data, 90 data: response.data,
90 - headers: response.headers 91 + headers: response.headers,
  92 + status: response.status
91 }; 93 };
92 }; 94 };
93 /** 95 /**
src/lib/ng-noosfero-api/interfaces/environment.ts
@@ -5,7 +5,7 @@ namespace noosfero { @@ -5,7 +5,7 @@ namespace noosfero {
5 * @name noofero.Environment 5 * @name noofero.Environment
6 * @description 6 * @description
7 * A representation of a Noosfero Environment. 7 * A representation of a Noosfero Environment.
8 - */ 8 + */
9 export interface Environment extends RestModel { 9 export interface Environment extends RestModel {
10 /** 10 /**
11 * @ngdoc property 11 * @ngdoc property
@@ -23,6 +23,21 @@ namespace noosfero { @@ -23,6 +23,21 @@ namespace noosfero {
23 * @returns {string} The Environment layout (e.g. default, rightbar) 23 * @returns {string} The Environment layout (e.g. default, rightbar)
24 */ 24 */
25 layout_template: string; 25 layout_template: string;
  26 +
  27 + /**
  28 + * @ngdoc property
  29 + * @name signup_intro
  30 + * @propertyOf noofero.Environment
  31 + * @returns {string} The Environment signup introduction HTML (e.g. Welcome to Noosfero...!!)
  32 + */
  33 + signup_intro: string;
  34 +
  35 + /**
  36 + * @ngdoc property
  37 + * @name host
  38 + * @propertyOf noofero.Environment
  39 + * @returns {string} The Environment default domain address with 'http://' prefix (e.g. http://localhost)
  40 + */
  41 + host: string;
26 } 42 }
27 } 43 }
28 -  
src/lib/ng-noosfero-api/interfaces/rest_result.ts
@@ -3,5 +3,6 @@ namespace noosfero { @@ -3,5 +3,6 @@ namespace noosfero {
3 export interface RestResult<T> { 3 export interface RestResult<T> {
4 data: T; 4 data: T;
5 headers: Function; 5 headers: Function;
  6 + status: Number;
6 } 7 }
7 -}  
8 \ No newline at end of file 8 \ No newline at end of file
  9 +}
src/spec/mocks.ts
@@ -40,6 +40,11 @@ export var mocks: any = { @@ -40,6 +40,11 @@ export var mocks: any = {
40 return this.modalInstance; 40 return this.modalInstance;
41 } 41 }
42 }, 42 },
  43 + registerService: {
  44 + createAccount: (user: noosfero.User) => {
  45 + return Promise.resolve({ status: 201 });
  46 + }
  47 + },
43 authService: { 48 authService: {
44 loginSuccess: { 49 loginSuccess: {
45 event: Function, 50 event: Function,
@@ -145,6 +150,15 @@ export var mocks: any = { @@ -145,6 +150,15 @@ export var mocks: any = {
145 return mocks.promiseResultTemplate({ 150 return mocks.promiseResultTemplate({
146 people: {} 151 people: {}
147 }); 152 });
  153 + },
  154 + getCurrentEnvironment: (): any => {
  155 + return {
  156 + id: 1,
  157 + settings: {},
  158 + layout_template: '',
  159 + signup_intro: 'Welcome to Noosfero',
  160 + host: 'http://localhost'
  161 + };
148 } 162 }
149 }, 163 },
150 profileService: { 164 profileService: {
@@ -240,6 +254,7 @@ export var mocks: any = { @@ -240,6 +254,7 @@ export var mocks: any = {
240 }, 254 },
241 notificationService: { 255 notificationService: {
242 success: () => { }, 256 success: () => { },
243 - confirmation: () => { } 257 + confirmation: () => { },
  258 + error: () => { }
244 } 259 }
245 }; 260 };
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 "angular-mocks": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-mocks.d.ts", 8 "angular-mocks": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-mocks.d.ts",
9 "angular-translate": "github:DefinitelyTyped/DefinitelyTyped/angular-translate/angular-translate.d.ts#19850bf86c876e0c2544842114878ece4664941a", 9 "angular-translate": "github:DefinitelyTyped/DefinitelyTyped/angular-translate/angular-translate.d.ts#19850bf86c876e0c2544842114878ece4664941a",
10 "angular-ui-router": "github:DefinitelyTyped/DefinitelyTyped/angular-ui-router/angular-ui-router.d.ts#655f8c1bf3c71b0e1ba415b36309604f79326ac8", 10 "angular-ui-router": "github:DefinitelyTyped/DefinitelyTyped/angular-ui-router/angular-ui-router.d.ts#655f8c1bf3c71b0e1ba415b36309604f79326ac8",
  11 + "angular-ui-bootstrap": "github:DefinitelyTyped/DefinitelyTyped/angular-ui-bootstrap/angular-ui-bootstrap.d.ts",
11 "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#4de74cb527395c13ba20b438c3a7a419ad931f1c", 12 "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#4de74cb527395c13ba20b438c3a7a419ad931f1c",
12 "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#dd638012d63e069f2c99d06ef4dcc9616a943ee4", 13 "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#dd638012d63e069f2c99d06ef4dcc9616a943ee4",
13 "jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#470954c4f427e0805a2d633636a7c6aa7170def8", 14 "jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#470954c4f427e0805a2d633636a7c6aa7170def8",