Commit 64000ab5a564b9ee11a757d634c2ec1698838746
Exists in
master
and in
7 other branches
Merge branch 'register_page' into 'master'
See merge request !47
Showing
29 changed files
with
474 additions
and
38 deletions
Show diff stats
bower.json
@@ -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" |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +export * from "./register.component"; |
@@ -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> {{ 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> |
@@ -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> |
@@ -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 | +}); |
@@ -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 | +} |
@@ -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 | +} |
@@ -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 './../../shared/ | @@ -17,14 +17,14 @@ import {BootstrapSwitcherComponent, BootstrapSwitcherItem} from './../../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
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
src/app/main/main.component.ts
@@ -21,6 +21,7 @@ import { PersonTagsPluginInterestsBlockComponent } from "../layout/blocks/person | @@ -21,6 +21,7 @@ import { PersonTagsPluginInterestsBlockComponent } from "../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 "../login/auth.service"; | @@ -34,6 +35,7 @@ import { AuthService } from "../login/auth.service"; | ||
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 | } |
@@ -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("Services", () => { | @@ -17,7 +17,6 @@ describe("Services", () => { | ||
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("Services", () => { | @@ -92,6 +91,5 @@ describe("Services", () => { | ||
92 | }); | 91 | }); |
93 | }); | 92 | }); |
94 | 93 | ||
95 | - | ||
96 | }); | 94 | }); |
97 | }); | 95 | }); |
@@ -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 | +}); |
@@ -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<T extends noosfero.RestModel> { | @@ -80,14 +80,16 @@ export abstract class RestangularService<T extends noosfero.RestModel> { | ||
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 | }; |
typings.json
@@ -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", |