Merge Request #59

Closed
noosfero-themes/angular-theme!59
Created by Daniela Feitosa

Forgot password

Assignee: Caio Almeida
Milestone: None

Closed by Leandro Santos

Changes were not merged into target branch

Commits (2)
4 participants
src/app/login/auth.controller.spec.ts
1 1 import {AuthController} from "./auth.controller";
2 2 import {AuthService} from "./auth.service";
  3 +import * as helpers from "./../../spec/helpers";
3 4  
4 5 describe("Controllers", () => {
5 6  
6 7  
7 8 describe("AuthController", () => {
8 9  
9   - it("calls authenticate on AuthService when login called", () => {
  10 + let $modal: any;
  11 + let notificationService = helpers.mocks.notificationService;
  12 + notificationService.success = jasmine.createSpy('info');
  13 + notificationService.error = jasmine.createSpy('error');
10 14  
11   - // creating a Mock AuthService
12   - let AuthServiceMock: AuthService = jasmine.createSpyObj("AuthService", ["login"]);
  15 + let authController: any;
  16 + let AuthServiceMock: AuthService;
  17 + let username: string;
13 18  
14   - // pass AuthServiceMock into the constructor
15   - let authController = new AuthController(null, null, AuthServiceMock);
  19 + beforeEach(() => {
  20 + $modal = helpers.mocks.$modal;
  21 + AuthServiceMock = jasmine.createSpyObj("AuthService", ["login",
  22 +"forgotPassword"]);
  23 + authController = new AuthController(null, null, AuthServiceMock, $modal, notificationService);
  24 + });
16 25  
17   - // setup of authController -> set the credentials instance property
18   - let credentials = { username: "username", password: "password" };
19 26  
  27 + it("calls authenticate on AuthService when login called", () => {
  28 + let credentials = { username: "username", password: "password" };
20 29 authController.credentials = credentials;
21   -
22   - // calls the authController login method
23 30 authController.login();
24   -
25   - // checks if the method login of the injected AuthService has been called
26 31 expect(AuthServiceMock.login).toHaveBeenCalledWith(credentials);
27   -
28 32 });
29 33  
  34 + it('should open forgot password on click', (done: Function) => {
  35 + spyOn($modal, "open");
  36 + authController.openForgotPassword();
  37 + expect($modal.open).toHaveBeenCalled();
  38 + expect($modal.open).toHaveBeenCalledWith({
  39 + templateUrl: 'app/login/forgot-password.html',
  40 + controller: AuthController,
  41 + controllerAs: 'vm',
  42 + bindToController: true
  43 + });
  44 + done();
  45 + });
30 46  
  47 + it("calls forgotPassword on AuthService when sendPasswdInfo called", done => {
  48 + authController.username = "john";
  49 + AuthServiceMock.forgotPassword = jasmine.createSpy("forgotPassword").and.returnValue(Promise.resolve());
  50 + authController.sendPasswdInfo();
  51 + expect(AuthServiceMock.forgotPassword).toHaveBeenCalledWith("john");
  52 + done();
  53 + });
31 54  
32 55 });
33 56 });
... ...
src/app/login/auth.controller.ts
1   -import {AuthService} from "./auth.service";
  1 +import { AuthService } from "./auth.service";
  2 +import { NotificationService } from "./../shared/services/notification.service";
2 3  
3 4 export class AuthController {
4 5  
5   - static $inject = ["$log", "$stateParams", "AuthService"];
  6 + static $inject = ["$log", "$stateParams", "AuthService", "$uibModal", "NotificationService"];
  7 + modalInstance: ng.ui.bootstrap.IModalServiceInstance;
6 8  
7 9 constructor(
8 10 private $log: ng.ILogService,
9 11 private $stateParams: any,
10   - private AuthService: AuthService
  12 + private AuthService: AuthService,
  13 + private $uibModal: ng.ui.bootstrap.IModalService,
  14 + private notificationService: NotificationService
11 15 ) {
12 16  
13 17 }
14 18  
15 19 credentials: noosfero.Credentials;
  20 + username: string;
16 21  
17 22 login() {
18 23 this.AuthService.login(this.credentials);
19 24 }
  25 +
  26 + openForgotPassword() {
  27 + this.modalInstance = this.$uibModal.open({
  28 + templateUrl: 'app/login/forgot-password.html',
  29 + controller: AuthController,
  30 + controllerAs: 'vm',
  31 + bindToController: true,
  32 + });
  33 + }
  34 +
  35 + sendPasswdInfo() {
  36 + this.AuthService.forgotPassword(this.username).then((response) => {
  37 + this.notificationService.info({ title: "forgotPasswd.email_sent.title.info", message: "forgotPasswd.email_sent.message.info" });
  38 + }).catch((response) => {
  39 + this.notificationService.error({ title: "forgotPasswd.not_found.title.error", message: "forgotPasswd.not_found.message.error" });
  40 + this.openForgotPassword();
  41 + });
  42 + }
20 43 }
... ...
src/app/login/auth.service.ts
... ... @@ -2,11 +2,12 @@ import {Injectable, Inject, EventEmitter} from "ng-forward";
2 2  
3 3 import {NoosferoRootScope, UserResponse} from "./../shared/models/interfaces";
4 4 import {SessionService} from "./session.service";
  5 +import { RestangularService } from "./../../lib/ng-noosfero-api/http/restangular_service";
5 6  
6 7 import {AuthEvents} from "./auth-events";
7 8  
8 9 @Injectable()
9   -@Inject("$http", SessionService, "$log")
  10 +@Inject("$http", SessionService, "$log", "Restangular")
10 11 export class AuthService {
11 12  
12 13 public loginSuccess: EventEmitter<noosfero.User> = new EventEmitter<noosfero.User>();
... ... @@ -15,7 +16,10 @@ export class AuthService {
15 16  
16 17 constructor(private $http: ng.IHttpService,
17 18 private sessionService: SessionService,
18   - private $log: ng.ILogService) {
  19 + private $log: ng.ILogService,
  20 + private Restangular: restangular.IService
  21 + ) {
  22 + this.Restangular = Restangular;
19 23 }
20 24  
21 25 loginFromCookie() {
... ... @@ -76,4 +80,9 @@ export class AuthService {
76 80 throw new Error(`The event: ${eventName} not exists`);
77 81 }
78 82 }
  83 +
  84 + forgotPassword(value: string): ng.IPromise<noosfero.RestResult<any>> {
  85 + return this.Restangular.all("").customPOST("", "forgot_password", {value: value});
  86 + }
  87 +
79 88 }
... ...
src/app/login/forgot-password.html 0 → 100644
... ... @@ -0,0 +1,20 @@
  1 +<div class="modal-header">
  2 + <h3 class="modal-title">{{"auth.form.forgot_passwd" | translate}}</h3>
  3 +</div>
  4 +<div class="modal-body">
  5 + <form name="forgotPasswdForm">
  6 + <div class="form-group" ng-class="{'has-error': forgotPasswdForm.username.$error.required }">
  7 + <label for="forgotPasswdLogin">{{"auth.form.login" | translate}}</label>
  8 + <input type="text" name="username" class="form-control" id="forgotPasswdLogin" placeholder="{{'auth.form.login' | translate}}" ng-model="vm.username" required>
  9 + <div class="help-block" ng-messages="forgotPasswdForm.username.$error">
  10 + <div ng-if="forgotPasswdForm.username.$touched">
  11 + <ul class="list-unstyled">
  12 + <li ng-messages-include="app/shared/messages/form-errors.html"></li>
  13 + </ul>
  14 + </div>
  15 + </div>
  16 + </div>
  17 + <button type="submit" class="btn btn-default btn-block" ng-click="vm.sendPasswdInfo(); $close()" ng-disabled="forgotPasswdForm.$invalid">{{"forgotPasswd.send_instructions_button" | translate}}</button>
  18 + </form>
  19 + <p>{{"forgotPasswd.info" | translate}}</p>
  20 +</div>
... ...
src/app/login/login.html
... ... @@ -18,6 +18,9 @@
18 18 {{"auth.form.keepLoggedIn" | translate}}
19 19 </label>
20 20 </div>
  21 + <div class="pull-right">
  22 + <a ng-click="vm.openForgotPassword()" href="">{{"auth.form.forgot_passwd" | translate}}</a>
  23 + </div>
21 24 </div>
22 25 <button type="submit" class="btn btn-default btn-block" ng-click="vm.login()">{{"auth.form.login_button" | translate}}</button>
23 26 </form>
... ...
src/app/login/login.scss
... ... @@ -10,6 +10,12 @@
10 10 margin-top: 20px;
11 11 text-transform: uppercase;
12 12 }
  13 + .form-inline {
  14 + display: inline;
  15 + div {
  16 + display: inline-block;
  17 + }
  18 + }
13 19 }
14 20 }
15 21  
... ...
src/app/login/new-password.component.spec.ts 0 → 100644
... ... @@ -0,0 +1,87 @@
  1 +import { ComponentTestHelper, createClass } from "../../spec/component-test-helper";
  2 +import * as helpers from "../../spec/helpers";
  3 +import { PasswordComponent } from "./new-password.component";
  4 +
  5 +
  6 +describe("Password Component", () => {
  7 + const htmlTemplate: string = '<new-password></new-password>';
  8 +
  9 + let helper: ComponentTestHelper<PasswordComponent>;
  10 + let passwordService = helpers.mocks.passwordService;
  11 + let stateService = jasmine.createSpyObj("$state", ["transitionTo"]);
  12 + let stateParams = jasmine.createSpyObj("$stateParams", ["code"]);
  13 + let notificationService = helpers.mocks.notificationService;
  14 + notificationService.success = jasmine.createSpy('success');
  15 + notificationService.error = jasmine.createSpy('error');
  16 +
  17 +
  18 + let data: any;
  19 +
  20 + beforeEach(() => {
  21 + angular.mock.module('templates');
  22 + angular.mock.module('ngSanitize');
  23 + angular.mock.module('ngMessages');
  24 + angular.mock.module('ngPassword');
  25 + });
  26 +
  27 + beforeEach((done) => {
  28 + let cls = createClass({
  29 + template: htmlTemplate,
  30 + directives: [PasswordComponent],
  31 + providers: [
  32 + helpers.createProviderToValue('$state', stateService),
  33 + helpers.createProviderToValue('$stateParams', stateParams),
  34 + helpers.createProviderToValue('PasswordService', passwordService),
  35 + helpers.createProviderToValue('NotificationService', notificationService),
  36 + ]
  37 + });
  38 + helper = new ComponentTestHelper<PasswordComponent>(cls, done);
  39 + });
  40 +
  41 + it('new password page was rendered', () => {
  42 + expect(helper.debugElement.query('div.new-password-page').length).toEqual(1);
  43 + });
  44 +
  45 + it("changes the user password", done => {
  46 + data = {
  47 + code: '1234567890',
  48 + password: 'test',
  49 + passwordConfirmation: 'test'
  50 + };
  51 +
  52 + helper.component.code = data.code;
  53 + helper.component.password = data.password;
  54 + helper.component.passwordConfirmation = data.passwordConfirmation;
  55 +
  56 + passwordService.new_password = jasmine.createSpy("new_password").and.returnValue(Promise.resolve());
  57 +
  58 + helper.component.sendNewPassword();
  59 + expect(passwordService.new_password).toHaveBeenCalledWith('1234567890', 'test', 'test');
  60 +
  61 + expect(notificationService.success).toHaveBeenCalled();
  62 +
  63 + done();
  64 + });
  65 +
  66 + it("fails when try to change the user password", done => {
  67 + data = {
  68 + code: '1234567890',
  69 + password: 'test',
  70 + passwordConfirmation: 'test-invalid'
  71 + };
  72 +
  73 + helper.component.code = data.code;
  74 + helper.component.password = data.password;
  75 + helper.component.passwordConfirmation = data.passwordConfirmation;
  76 +
  77 + passwordService.new_password = jasmine.createSpy("new_password").and.returnValue(Promise.reject({data: {message: 'Error'}}));
  78 +
  79 + helper.component.sendNewPassword();
  80 + expect(passwordService.new_password).toHaveBeenCalledWith('1234567890', 'test', 'test-invalid');
  81 +
  82 + expect(notificationService.error).toHaveBeenCalled();
  83 +
  84 + done();
  85 + });
  86 +
  87 +});
... ...
src/app/login/new-password.component.ts 0 → 100644
... ... @@ -0,0 +1,36 @@
  1 +import { StateConfig, Component, Inject, provide } from 'ng-forward';
  2 +
  3 +import { PasswordService } from "../../lib/ng-noosfero-api/http/password.service";
  4 +import { NotificationService } from "./../shared/services/notification.service";
  5 +import { AuthController } from "./auth.controller";
  6 +
  7 +@Component({
  8 + selector: 'new-password',
  9 + templateUrl: 'app/login/new-password.html',
  10 + providers: [provide('passwordService', { useClass: PasswordService })]
  11 +})
  12 +@Inject(PasswordService, "$state", "$stateParams", NotificationService)
  13 +export class PasswordComponent {
  14 +
  15 + code: string;
  16 + password: string;
  17 + passwordConfirmation: string;
  18 +
  19 + constructor(
  20 + public passwordService: PasswordService,
  21 + private $state: ng.ui.IStateService,
  22 + private $stateParams: ng.ui.IStateParamsService,
  23 + private notificationService: NotificationService) {
  24 +
  25 + this.code = this.$stateParams['code'];
  26 + }
  27 +
  28 + sendNewPassword() {
  29 + this.passwordService.new_password(this.code, this.password, this.passwordConfirmation).then((response) => {
  30 + this.notificationService.success({ title: "newPasswd.success.title", message: "newPasswd.success.message", timer: 5000 });
  31 + this.$state.transitionTo('main.environment');
  32 + }).catch((response) => {
  33 + this.notificationService.error({ title: "newPasswd.failed.title", message: "newPasswd.failed.message" });
  34 + });
  35 + }
  36 +}
... ...
src/app/login/new-password.html 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +<div class="new-password-page col-xs-4 col-xs-offset-4">
  2 + <h1>{{"new_password.welcomeMessageTitle" | translate }}</h1>
  3 +
  4 + <form name="newPasswdForm">
  5 + <div class="form-group" ng-class="{'has-error': newPasswdForm.password.$invalid && newPasswdForm.password.$touched }">
  6 + <div class="input-group">
  7 + <span class="input-group-addon"><i class="fa fa-lock"></i></span>
  8 + <input type="password" class="form-control" id="password" name="password" placeholder="{{'account.register.passwordLabel' | translate }}" ng-model="vm.password" required minlength="4">
  9 + </div>
  10 + <div class="help-block" ng-show="newPasswdForm.password.$touched" ng-messages="newPasswdForm.password.$error">
  11 + <ul class="list-unstyled">
  12 + <li ng-messages-include="app/shared/messages/form-errors.html"></li>
  13 + </ul>
  14 + </div>
  15 + </div>
  16 +
  17 + <div class="form-group" ng-class="{'has-error': newPasswdForm.passwordConfirm.$invalid && newPasswdForm.passwordConfirm.$touched }">
  18 + <div class="input-group">
  19 + <span class="input-group-addon"><i class="fa fa-unlock-alt"></i></span>
  20 + <input type="password" class="form-control" id="passwordConfirm" name="passwordConfirm" match-password="password" placeholder="{{'account.register.passwordConfirmationLabel' | translate}}" ng-model="vm.passwordConfirmation" required>
  21 + </div>
  22 + <div class="help-block" ng-show="newPasswdForm.passwordConfirm.$touched" ng-messages="newPasswdForm.passwordConfirm.$error">
  23 + <ul class="list-unstyled">
  24 + <li ng-messages-include="app/shared/messages/form-errors.html"></li>
  25 + <li ng-message="passwordMatch" translate="messages.invalid.passwordMatch"></li>
  26 + </ul>
  27 + </div>
  28 + </div>
  29 + <button type="submit" class="btn btn-default btn-block" ng-click="vm.sendNewPassword()" ng-disabled="newPasswdForm.$invalid">{{"newPasswdForm.submit" | translate}}</button>
  30 + </form>
  31 +</div>
... ...
src/app/main/main.component.ts
... ... @@ -4,6 +4,7 @@ import { ArticleBlogComponent } from &quot;./../article/types/blog/blog.component&quot;;
4 4  
5 5 import { ArticleViewComponent } from "./../article/article-default-view.component";
6 6  
  7 +import { PasswordComponent } from "../login/new-password.component";
7 8 import { ProfileComponent } from "../profile/profile.component";
8 9 import { BoxesComponent } from "../layout/boxes/boxes.component";
9 10 import { BlockContentComponent } from "../layout/blocks/block-content.component";
... ... @@ -120,7 +121,8 @@ export class EnvironmentContent {
120 121 MembersBlockComponent, NoosferoTemplate, DateFormat, RawHTMLBlockComponent, StatisticsBlockComponent,
121 122 LoginBlockComponent, CustomContentComponent, PermissionDirective, SearchFormComponent, SearchComponent,
122 123 PersonTagsPluginInterestsBlockComponent, TagsBlockComponent, RecentActivitiesPluginActivitiesBlockComponent,
123   - ProfileImagesPluginProfileImagesBlockComponent, BlockComponent, RegisterComponent, TasksMenuComponent, TaskListComponent
  124 + ProfileImagesPluginProfileImagesBlockComponent, BlockComponent, RegisterComponent, TasksMenuComponent, TaskListComponent,
  125 + PasswordComponent
124 126 ].concat(plugins.mainComponents).concat(plugins.hotspots),
125 127 providers: [AuthService, SessionService, NotificationService, BodyStateClassesService,
126 128 "ngAnimate", "ngCookies", "ngStorage", "ngTouch",
... ... @@ -172,6 +174,18 @@ export class EnvironmentContent {
172 174 }
173 175 },
174 176 {
  177 + url: "/account/new_password/:code",
  178 + component: PasswordComponent,
  179 + name: 'main.newPasswd',
  180 + views: {
  181 + "content": {
  182 + templateUrl: "app/login/new-password.html",
  183 + controller: PasswordComponent,
  184 + controllerAs: "vm"
  185 + }
  186 + }
  187 + },
  188 + {
175 189 url: "^/:profile",
176 190 abstract: true,
177 191 component: ProfileComponent,
... ...
src/app/shared/services/notification.service.ts
... ... @@ -14,6 +14,8 @@ export class NotificationService {
14 14 public static DEFAULT_ERROR_TITLE = "notification.error.default.title";
15 15 public static DEFAULT_ERROR_MESSAGE = "notification.error.default.message";
16 16 public static DEFAULT_SUCCESS_TIMER = 1000;
  17 + public static DEFAULT_INFO_TITLE = "notification.info.default.title";
  18 + public static DEFAULT_INFO_MESSAGE = "notification.info.default.message";
17 19  
18 20 error({
19 21 message = NotificationService.DEFAULT_ERROR_MESSAGE,
... ... @@ -40,6 +42,14 @@ export class NotificationService {
40 42 this.showMessage({ title: title, text: message, showCancelButton: showCancelButton, type: type, closeOnConfirm: false }, confirmationFunction);
41 43 }
42 44  
  45 + info({
  46 + message = NotificationService.DEFAULT_INFO_MESSAGE,
  47 + title = NotificationService.DEFAULT_INFO_TITLE,
  48 + showConfirmButton = true
  49 + } = {}) {
  50 + this.showMessage({ title: title, text: message, showConfirmButton: showConfirmButton, type: "info" });
  51 + }
  52 +
43 53 private showMessage({title, text, type = "success", timer = null, showConfirmButton = true, showCancelButton = false, closeOnConfirm = true}, confirmationFunction: Function = null) {
44 54 this.$log.debug("Notification message:", title, text, type, this.translatorService.currentLanguage());
45 55 this.SweetAlert.swal({
... ...
src/languages/en.json
... ... @@ -34,8 +34,15 @@
34 34 "auth.form.login": "Username or Email address",
35 35 "auth.form.password": "Password",
36 36 "auth.form.keepLoggedIn": "Keep me logged in",
  37 + "auth.form.forgot_passwd": "Forgot your password?",
37 38 "auth.form.login_button": "Login",
38 39 "auth.createAccount": "Create account",
  40 + "forgotPasswd.send_instructions_button": "Send instructions",
  41 + "forgotPasswd.info": "Upon clicking on the button above, you'll receive an email with instructions on how to create a new password.",
  42 + "forgotPasswd.email_sent.title.info": "Change your password",
  43 + "forgotPasswd.email_sent.message.info": "Follow the instructions sent by email to change your password",
  44 + "forgotPasswd.not_found.title.error": "User not found",
  45 + "forgotPasswd.not_found.message.error": "Could not send password recovery for the user",
39 46 "navbar.content_viewer_actions.new_item": "New Item",
40 47 "navbar.profile_actions.new_item": "New Item",
41 48 "navbar.content_viewer_actions.new_post": "New Post",
... ... @@ -43,6 +50,8 @@
43 50 "navbar.profile_actions.new_discussion": "New Discussion",
44 51 "notification.error.default.message": "Something went wrong!",
45 52 "notification.error.default.title": "Oops...",
  53 + "notification.info.default.message": "",
  54 + "notification.info.default.title": "Information",
46 55 "notification.profile.not_found": "Page not found",
47 56 "notification.http_error.401.message": "Unauthorized",
48 57 "notification.http_error.500.message": "Server error",
... ...
src/languages/pt.json
... ... @@ -34,8 +34,15 @@
34 34 "auth.form.login": "Nome de usuário ou Email",
35 35 "auth.form.password": "Senha",
36 36 "auth.form.keepLoggedIn": "Continuar logado",
  37 + "auth.form.forgot_passwd": "Esqueceu sua senha?",
37 38 "auth.form.login_button": "Login",
38 39 "auth.createAccount": "Criar conta",
  40 + "forgotPasswd.send_instructions_button": "Send instructions",
  41 + "forgotPasswd.info": "Ao clicar no botão acima, você receberá um email com instruções para criar uma nova senha.",
  42 + "forgotPasswd.email_sent.title.info": "Altere sua senha",
  43 + "forgotPasswd.email_sent.message.info": "Siga as instruções enviadas por e-mail para alterar sua senha",
  44 + "forgotPasswd.not_found.title.error": "Usuário não encontrado",
  45 + "forgotPasswd.not_found.message.error": "Não foi possível recuperar a senha deste usuário",
39 46 "navbar.content_viewer_actions.new_item": "Novo Item",
40 47 "navbar.profile_actions.new_item": "Novo Item",
41 48 "navbar.content_viewer_actions.new_post": "Novo Post",
... ... @@ -43,6 +50,8 @@
43 50 "navbar.profile_actions.new_discussion": "Nova Discussão",
44 51 "notification.error.default.message": "Algo deu errado!",
45 52 "notification.error.default.title": "Oops...",
  53 + "notification.info.default.message": "",
  54 + "notification.info.default.title": "Informação",
46 55 "notification.profile.not_found": "Página não encontrada",
47 56 "notification.http_error.401.message": "Não autorizado",
48 57 "notification.http_error.500.message": "Erro no servidor",
... ...
src/lib/ng-noosfero-api/http/password.service.spec.ts 0 → 100644
... ... @@ -0,0 +1,41 @@
  1 +import { PasswordService } from "./password.service";
  2 +
  3 +describe("Services", () => {
  4 +
  5 + describe("Password Service", () => {
  6 +
  7 + let $httpBackend: ng.IHttpBackendService;
  8 + let passwordService: PasswordService;
  9 + let $rootScope: ng.IRootScopeService;
  10 + let data: any;
  11 +
  12 + beforeEach(angular.mock.module("main", ($translateProvider: angular.translate.ITranslateProvider) => {
  13 + $translateProvider.translations('en', {});
  14 + }));
  15 +
  16 + beforeEach(inject((_$httpBackend_: ng.IHttpBackendService,
  17 +_PasswordService_: PasswordService, _$rootScope_: ng.IRootScopeService) => {
  18 + $httpBackend = _$httpBackend_;
  19 + passwordService = _PasswordService_;
  20 + $rootScope = _$rootScope_;
  21 + }));
  22 +
  23 + describe("Succesfull request", () => {
  24 +
  25 + it("should change user password", (done) => {
  26 + data = {
  27 + code: '1234567890',
  28 + password: 'test',
  29 + password_confirmation: 'test'
  30 + };
  31 +
  32 + $httpBackend.expectPATCH(`/api/v1/new_password?code=${data.code}&password=${data.password}&password_confirmation=${data.password_confirmation}`).respond(201, [{ login: "test" }]);
  33 + passwordService.new_password('1234567890', 'test', 'test').then((response: restangular.IResponse) => {
  34 + expect(response.data[0].login).toEqual("test");
  35 + done();
  36 + });
  37 + $httpBackend.flush();
  38 + });
  39 + });
  40 + });
  41 +});
... ...
src/lib/ng-noosfero-api/http/password.service.ts 0 → 100644
... ... @@ -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 PasswordService {
  7 + constructor(private Restangular: restangular.IService) {
  8 + this.Restangular = Restangular;
  9 + }
  10 +
  11 + new_password(code: string, password: string, password_confirmation: string): ng.IPromise<noosfero.RestResult<noosfero.User>> {
  12 + return this.Restangular.all("").customOperation("patch", "new_password", {code: code, password: password, password_confirmation: password_confirmation });
  13 + }
  14 +}
... ...
src/spec/mocks.ts
... ... @@ -257,6 +257,11 @@ export var mocks: any = {
257 257 changeLanguage: (lang: string) => { },
258 258 translate: (text: string) => { return text; }
259 259 },
  260 + passwordService: {
  261 + new_password: (param: any) => {
  262 + return Promise.resolve({ status: 201 });
  263 + }
  264 + },
260 265 notificationService: {
261 266 success: () => { },
262 267 confirmation: () => { },
... ...
  • 0743c2eb05e68c92baa5f8c498995a20?s=40&d=identicon
    Daniela Feitosa @daniela

    Reassigned to @caiosba

    Choose File ...   File name...
    Cancel
  • C8b72d0556872a2aea21e8fed0a72001?s=40&d=identicon
    Melissa Wen @melissawen

    mentioned in issue #107

    Choose File ...   File name...
    Cancel
  • 0743c2eb05e68c92baa5f8c498995a20?s=40&d=identicon
    Daniela Feitosa @daniela

    Added 27 new commits:

    • 29bd5738 - Added new 'per_page' to SearchComponent
    • a31408fa - Added sass variable to search result green color
    • 11aaae15 - Added 'per_page' param into @StateConfig environment router definition
    • 87126262 - Merge branch 'search-ui' into 'master'
    • 4d167676 - Add component to display tasks in menu
    • 917544be - Add component to list tasks
    • 07f15849 - Add accept/reject buttons to task list
    • 45183e9d - Add tests to task components
    • 118eeb9d - List roles when accept add member tasks
    • 0354c769 - Accept parameters when accept/reject tasks
    • 7205a81d - Emit and subscribe to events for task accept/reject
    • 917a672d - Translate tasks messages
    • 1adb5479 - Use .checkbox-nice in accept member task
    • 6fca41b5 - Refactor methods to close task
    • d6d5bae0 - Create interface for AddMemberTask
    • a1375e04 - Merge branch 'tasks' into 'master'
    • 07858dff - Initial implementation
    • ccf7dc63 - Added upload image to person service
    • c132a4a9 - Upload image initial and tests
    • 338aae2e - Minor refactory and sintax adjusts
    • 71d22bf6 - Merge branch 'upload-profile-photo' into 'master'
    • b8cf9be2 - Removed console.log() calls from Upload image related files
    • ce2f9d52 - Set the browser lang like default translate language
    • d06a730a - Merge branch 'translate-browser-lang' into 'master'
    • afb4744a - Do not show join/hide button for person
    • 33647b98 - Ticket #107 Implementation of 'Forgot password'
    • a05a7c31 - Ticket #107 Implementation of new password generation
    Choose File ...   File name...
    Cancel
  • 5bf9bf341e9d00ebd854cdaf1a4299b2?s=40&d=identicon
    Leandro Santos @leandronunes

    incorporado manualmente

    Choose File ...   File name...
    Cancel
  • 5bf9bf341e9d00ebd854cdaf1a4299b2?s=40&d=identicon
    Leandro Santos @leandronunes

    Status changed to closed

    Choose File ...   File name...
    Cancel