From bce2ec0348c104c088e3fd89eff3bb9f0825abc9 Mon Sep 17 00:00:00 2001 From: Or Date: Thu, 18 Jun 2015 09:44:15 +0300 Subject: [PATCH 01/45] Adding "Reset Password" message. --- .../skeleton_messages.features.inc | 48 ++++++++++++++++ .../skeleton_messages/skeleton_messages.info | 12 ++++ .../skeleton_messages.module | 56 +++++++++++++++++++ .../skeleton_messages.strongarm.inc | 48 ++++++++++++++++ app/templates/skeleton/skeleton.info | 1 + 5 files changed, 165 insertions(+) create mode 100644 app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.features.inc create mode 100644 app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.info create mode 100644 app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.module create mode 100644 app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.strongarm.inc diff --git a/app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.features.inc b/app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.features.inc new file mode 100644 index 0000000..c31d249 --- /dev/null +++ b/app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.features.inc @@ -0,0 +1,48 @@ + "1"); + } +} + +/** + * Implements hook_default_message_type(). + */ +function skeleton_messages_default_message_type() { + $items = array(); + $items['reset_password'] = entity_import('message_type', '{ + "name" : "reset_password", + "description" : "Reset Password", + "argument_keys" : [], + "argument" : [], + "category" : "message_type", + "data" : { + "token options" : { "clear" : 0 }, + "purge" : { "override" : 0, "enabled" : 0, "quota" : "", "days" : "" } + }, + "language" : "", + "arguments" : null, + "message_text" : { "und" : [ + { + "value" : "Skeleton - Reset Password", + "format" : "filtered_html", + "safe_value" : "\\u003Cp\\u003ESkeleton - Reset Password\\u003C\\/p\\u003E\\n" + }, + { + "value" : "Hello,\\r\\n\\r\\nClick this link to reset your password:\\r\\n[skeleton:reset-password-link]", + "format" : "filtered_html", + "safe_value" : "\\u003Cp\\u003EHello,\\u003C\\/p\\u003E\\n\\u003Cp\\u003EClick this link to reset your password:\\u003Cbr \\/\\u003E\\n[skeleton:reset-password-link]\\u003C\\/p\\u003E\\n" + } + ] + } + }'); + return $items; +} diff --git a/app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.info b/app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.info new file mode 100644 index 0000000..a9619c8 --- /dev/null +++ b/app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.info @@ -0,0 +1,12 @@ +name = Skeleton Messages +core = 7.x +package = Skeleton +dependencies[] = ctools +dependencies[] = entity +dependencies[] = message +dependencies[] = message_notify +dependencies[] = strongarm +features[ctools][] = strongarm:strongarm:1 +features[features_api][] = api:2 +features[message_type][] = reset_password +features[variable][] = field_bundle_settings_message__reset_password diff --git a/app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.module b/app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.module new file mode 100644 index 0000000..3832b74 --- /dev/null +++ b/app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.module @@ -0,0 +1,56 @@ + t('Reset Password Link'), + 'description' => t('Display the link for resetting a password.'), + ); + + $info['types']['skeleton'] = array( + 'name' => t('Skeleton'), + 'description' => t('Tokens related to Skeleton.'), + ); + + return $info; +} + +/** + * Implements hook_tokens(). + */ +function skeleton_messages_tokens($type, $tokens, array $data = array(), array $options = array()) { + + $replacements = array(); + if ($type != 'skeleton') { + return $replacements; + } + + foreach ($tokens as $name => $original) { + if ($name != 'reset-password-link') { + continue; + } + + $message = reset($data); + $token = $message->arguments['@token']; + + $options = array( + 'fragment' => 'reset-password/' . $token, + ); + + $replacements[$original] = url(SKELETON_DEFAULT_CLIENT_DOMAIN, $options); + } + + return $replacements; +} diff --git a/app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.strongarm.inc b/app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.strongarm.inc new file mode 100644 index 0000000..243f7d9 --- /dev/null +++ b/app/templates/skeleton/modules/custom/skeleton_messages/skeleton_messages.strongarm.inc @@ -0,0 +1,48 @@ +disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'field_bundle_settings_message__reset_password'; + $strongarm->value = array( + 'view_modes' => array(), + 'extra_fields' => array( + 'form' => array(), + 'display' => array( + 'message__message_text__0' => array( + 'message_notify_email_body' => array( + 'weight' => '1', + 'visible' => FALSE, + ), + 'message_notify_email_subject' => array( + 'weight' => '0', + 'visible' => TRUE, + ), + ), + 'message__message_text__1' => array( + 'message_notify_email_body' => array( + 'weight' => '0', + 'visible' => TRUE, + ), + 'message_notify_email_subject' => array( + 'weight' => '1', + 'visible' => FALSE, + ), + ), + ), + ), + ); + $export['field_bundle_settings_message__reset_password'] = $strongarm; + + return $export; +} diff --git a/app/templates/skeleton/skeleton.info b/app/templates/skeleton/skeleton.info index c12d5f7..14b2c81 100644 --- a/app/templates/skeleton/skeleton.info +++ b/app/templates/skeleton/skeleton.info @@ -50,3 +50,4 @@ dependencies[] = skeleton_company dependencies[] = skeleton_event dependencies[] = skeleton_file dependencies[] = skeleton_restful +dependencies[] = skeleton_messages From d8be92d090b972f07ba9b1d3fbbacf54818178ae Mon Sep 17 00:00:00 2001 From: Or Date: Thu, 18 Jun 2015 09:44:55 +0300 Subject: [PATCH 02/45] Adding "Reset Password" endpoint. --- .../SkeletonTokenNotifierResource.class.php | 49 +++++++++++++++++++ .../SkeletonResetPasswordResource.class.php | 38 ++++++++++++++ .../user/reset_password/reset_password.inc | 22 +++++++++ .../skeleton_restful/skeleton_restful.info | 1 + 4 files changed, 110 insertions(+) create mode 100644 app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/SkeletonTokenNotifierResource.class.php create mode 100644 app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/reset_password/SkeletonResetPasswordResource.class.php create mode 100644 app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/reset_password/reset_password.inc diff --git a/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/SkeletonTokenNotifierResource.class.php b/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/SkeletonTokenNotifierResource.class.php new file mode 100644 index 0000000..5ea4e9d --- /dev/null +++ b/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/SkeletonTokenNotifierResource.class.php @@ -0,0 +1,49 @@ +generateAccessToken($account->uid); + + // Sending Email with instructions to the user. + return $this->notifyUser($message_type, $account, $token->token); + } + + /** + * Send an email to the user with the token. + * + * @param $message_type + * The type of the message. + * @param $account + * The account of the user to notify. + * @param $token + * The token of the user. + */ + protected function notifyUser($message_type, $account, $token) { + $message = message_create($message_type, array('arguments' => array('@token' => $token)), $account); + $wrapper = entity_metadata_wrapper('message', $message); + return message_notify_send_message($wrapper->value(), array('mail' => $account->mail)); + } +} diff --git a/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/reset_password/SkeletonResetPasswordResource.class.php b/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/reset_password/SkeletonResetPasswordResource.class.php new file mode 100644 index 0000000..2fc8f25 --- /dev/null +++ b/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/reset_password/SkeletonResetPasswordResource.class.php @@ -0,0 +1,38 @@ + array( + \RestfulInterface::POST => 'resetPassword', + ), + ); + + /** + * Send "Reset Password" email. + * + * @return array + */ + public function resetPassword() { + + $email = $this->request['email']; + + $account = user_load_by_mail($email); + + if (empty($account)) { + return array(); + } + + $this->sendToken('reset_password', $account); + + return array(); + } + +} diff --git a/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/reset_password/reset_password.inc b/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/reset_password/reset_password.inc new file mode 100644 index 0000000..0914209 --- /dev/null +++ b/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/reset_password/reset_password.inc @@ -0,0 +1,22 @@ + t('Reset Password'), + 'description' => t('Sending a reset password link to the user.'), + 'name' => 'reset_password', + 'resource' => 'reset-password', + 'class' => 'SkeletonResetPasswordResource', + 'rate_limit' => array( + // The 'request' event is the basic event. You can declare your own events. + 'request' => array( + 'event' => 'request', + // Rate limit is cleared every day. + 'period' => new \DateInterval('P1D'), + 'limits' => array( + 'authenticated user' => 10, + 'anonymous user' => 10, + 'administrator' => \RestfulRateLimitManager::UNLIMITED_RATE_LIMIT, + ), + ), + ), +); diff --git a/app/templates/skeleton/modules/custom/skeleton_restful/skeleton_restful.info b/app/templates/skeleton/modules/custom/skeleton_restful/skeleton_restful.info index 9f666f6..c86192a 100644 --- a/app/templates/skeleton/modules/custom/skeleton_restful/skeleton_restful.info +++ b/app/templates/skeleton/modules/custom/skeleton_restful/skeleton_restful.info @@ -7,3 +7,4 @@ dependencies[] = entity_validator dependencies[] = skeleton_company files[] = plugins/restful/node/SkeletonEntityBaseNode.php +files[] = plugins/restful/user/SkeletonTokenNotifierResource.class.php From feb0c2dc097c9fef267bee498cb08a6e2995b267 Mon Sep 17 00:00:00 2001 From: Or Date: Thu, 18 Jun 2015 09:49:19 +0300 Subject: [PATCH 03/45] Adding "Forgot Password" flow on the client. --- app/templates/client/app/index.html | 1 + app/templates/client/app/scripts/app.js | 5 ++ .../scripts/controllers/forgot-password.js | 27 ++++++++++ .../client/app/scripts/services/auth.js | 16 ++++++ .../client/app/views/forgot-password.html | 53 +++++++++++++++++++ app/templates/client/app/views/login.html | 5 ++ 6 files changed, 107 insertions(+) create mode 100644 app/templates/client/app/scripts/controllers/forgot-password.js create mode 100644 app/templates/client/app/views/forgot-password.html diff --git a/app/templates/client/app/index.html b/app/templates/client/app/index.html index 0980f12..e9d76a2 100644 --- a/app/templates/client/app/index.html +++ b/app/templates/client/app/index.html @@ -81,6 +81,7 @@

Login with demo / 1234

+ diff --git a/app/templates/client/app/scripts/app.js b/app/templates/client/app/scripts/app.js index 4ff7176..4d28d21 100644 --- a/app/templates/client/app/scripts/app.js +++ b/app/templates/client/app/scripts/app.js @@ -57,6 +57,11 @@ angular templateUrl: 'views/login.html', controller: 'LoginCtrl' }) + .state('forgot-password', { + url: '/forgot-password', + templateUrl: 'views/forgot-password.html', + controller: 'ForgotPasswordCtrl' + }) .state('dashboard', { abstract: true, url: '', diff --git a/app/templates/client/app/scripts/controllers/forgot-password.js b/app/templates/client/app/scripts/controllers/forgot-password.js new file mode 100644 index 0000000..f7128d9 --- /dev/null +++ b/app/templates/client/app/scripts/controllers/forgot-password.js @@ -0,0 +1,27 @@ +'use strict'; + +/** + * @ngdoc function + * @name clientApp.controller:ForgotPasswordCtrl + * @description + * # ForgotPasswordCtrl + * Controller of the clientApp + */ +angular.module('clientApp') + .controller('ForgotPasswordCtrl', function ($scope, Auth) { + + /** + * Send a password reset link. + */ + $scope.forgotPassword = function() { + Auth.resetPassword($scope.email).then(function () { + $scope.passwordResetSent = true; + }, + function(response) { + // Too many requests. + if (response.status == 429) { + $scope.ErrorMsg = true; + } + }); + }; + }); diff --git a/app/templates/client/app/scripts/services/auth.js b/app/templates/client/app/scripts/services/auth.js index 1defe8a..8bc1b33 100644 --- a/app/templates/client/app/scripts/services/auth.js +++ b/app/templates/client/app/scripts/services/auth.js @@ -29,6 +29,22 @@ angular.module('clientApp') }); }; + /** + * If email is available then send to it an email with instructions. + * + * @param email + * The email of the user. + * + * @returns {*} + */ + this.resetPassword = function(email) { + return $injector.get('$http')({ + method: 'POST', + url: Config.backend + '/api/reset-password', + data: {email: email} + }); + }; + /** * Logout current user. * diff --git a/app/templates/client/app/views/forgot-password.html b/app/templates/client/app/views/forgot-password.html new file mode 100644 index 0000000..f26a1e5 --- /dev/null +++ b/app/templates/client/app/views/forgot-password.html @@ -0,0 +1,53 @@ +
+
+
+ +
+ +
+
+ +
+ + If the username is registered in our system we'll send you an email with instructions. +
+ +
+ + Request failed. +
+ +

Forgot your password?

+

Enter your email to recover your password.

+ +
+
+
+
+
+ + + + +
+
+ +
+ +
+ +
+ +
+
+
+
+
+
+ +
+
diff --git a/app/templates/client/app/views/login.html b/app/templates/client/app/views/login.html index 829b5c3..1eb28bb 100644 --- a/app/templates/client/app/views/login.html +++ b/app/templates/client/app/views/login.html @@ -34,6 +34,11 @@

Skeleton

+
From 7236eb44ea4dbebf2ddff55b142aa6ded5667452 Mon Sep 17 00:00:00 2001 From: Or Date: Thu, 18 Jun 2015 09:50:20 +0300 Subject: [PATCH 04/45] Adding "Save new password" flow to the client. --- app/templates/client/app/index.html | 1 + app/templates/client/app/scripts/app.js | 10 ++++ .../app/scripts/controllers/reset-password.js | 35 ++++++++++++++ .../client/app/scripts/services/auth.js | 18 +++++++ .../client/app/views/reset-password.html | 47 +++++++++++++++++++ 5 files changed, 111 insertions(+) create mode 100644 app/templates/client/app/scripts/controllers/reset-password.js create mode 100644 app/templates/client/app/views/reset-password.html diff --git a/app/templates/client/app/index.html b/app/templates/client/app/index.html index e9d76a2..e364e95 100644 --- a/app/templates/client/app/index.html +++ b/app/templates/client/app/index.html @@ -82,6 +82,7 @@

Login with demo / 1234

+ diff --git a/app/templates/client/app/scripts/app.js b/app/templates/client/app/scripts/app.js index 4d28d21..ef9fa93 100644 --- a/app/templates/client/app/scripts/app.js +++ b/app/templates/client/app/scripts/app.js @@ -62,6 +62,16 @@ angular templateUrl: 'views/forgot-password.html', controller: 'ForgotPasswordCtrl' }) + .state('reset-password', { + url: '/reset-password/{accessToken:string}', + templateUrl: 'views/reset-password.html', + controller: 'ResetPasswordCtrl', + resolve: { + accessToken: function($stateParams) { + return $stateParams.accessToken; + } + } + }) .state('dashboard', { abstract: true, url: '', diff --git a/app/templates/client/app/scripts/controllers/reset-password.js b/app/templates/client/app/scripts/controllers/reset-password.js new file mode 100644 index 0000000..1480d98 --- /dev/null +++ b/app/templates/client/app/scripts/controllers/reset-password.js @@ -0,0 +1,35 @@ +'use strict'; + +/** + * @ngdoc function + * @name clientApp.controller:ResetPasswordCtrl + * @description + * # ResetPasswordCtrl + * Controller of the clientApp + */ +angular.module('clientApp') + .controller('ResetPasswordCtrl', function ($scope, Auth, $state, $location, Account, localStorageService, accessToken) { + + // If 'access-token' is not provided as a URL parameter, redirect to login. + if (!accessToken) { + $state.go('login'); + } + + $scope.passwordSaved = false; + + /** + * Setting the access token in the localStorage so we can get the account + * information and pull out the user ID from it to PATCH the user entity. + * + * @param password + * The new password. + */ + $scope.saveNewPassword = function(password) { + localStorageService.set('access_token', accessToken); + Account.get().then(function(user) { + Auth.savePassword(user.id, password).then(function() { + $scope.passwordSaved = true; + }); + }); + }; + }); diff --git a/app/templates/client/app/scripts/services/auth.js b/app/templates/client/app/scripts/services/auth.js index 8bc1b33..e8a882f 100644 --- a/app/templates/client/app/scripts/services/auth.js +++ b/app/templates/client/app/scripts/services/auth.js @@ -45,6 +45,24 @@ angular.module('clientApp') }); }; + /** + * Save new password for a user. + * + * @param uid + * User id. + * @param password + * A new password to set. + * + * @returns {*} + */ + this.savePassword = function(uid, password) { + return $injector.get('$http')({ + method: 'PATCH', + url: Config.backend + '/api/users/' + uid, + data: {password: password} + }); + }; + /** * Logout current user. * diff --git a/app/templates/client/app/views/reset-password.html b/app/templates/client/app/views/reset-password.html new file mode 100644 index 0000000..00615dd --- /dev/null +++ b/app/templates/client/app/views/reset-password.html @@ -0,0 +1,47 @@ +
+
+
+ +
+ +
+
+ +
+ + New password has been set, please click on "Back to login". +
+ +

Reset your password

+

Enter your new password.

+ +
+
+
+ +
+
+ + +
+
+ +
+ +
+ +
+ +
+
+
+
+
+
+ +
+
From 309cb1248d5ffe116ee2763e68d5a6aff8dc45df Mon Sep 17 00:00:00 2001 From: Or Date: Thu, 18 Jun 2015 09:50:57 +0300 Subject: [PATCH 05/45] WIP - Adding an endpoint to update a user entity. --- .../update/SkeletonUsersResource.class.php | 100 ++++++++++++++++++ .../restful/user/update/update__1_0.inc | 24 +++++ .../skeleton_restful/skeleton_restful.module | 31 ++++++ 3 files changed, 155 insertions(+) create mode 100644 app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/update/SkeletonUsersResource.class.php create mode 100644 app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/update/update__1_0.inc diff --git a/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/update/SkeletonUsersResource.class.php b/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/update/SkeletonUsersResource.class.php new file mode 100644 index 0000000..ba7e886 --- /dev/null +++ b/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/update/SkeletonUsersResource.class.php @@ -0,0 +1,100 @@ + 'pass', + 'callback' => array($this, 'hideField') + ); + + $public_fields['email'] = array( + 'property' => 'mail', + ); + + // Prevent from trying to set the user status on creation. + if ($this->getMethod() != \RestfulBase::POST) { + $public_fields['status'] = array( + 'property' => 'status', + ); + } + + return $public_fields; + } + /** + * Hide the field value. + * + * @return NULL + */ + protected function hideField() { + return NULL; + } + + /** + * Sending verification email. + */ + public function createEntity() { + $entity = parent::createEntity(); + + $account = reset($entity); + $this->sendToken('verify_email', user_load($account['id'])); + + return $entity; + } + + + /** + * Checks if the token is valid for this user. + * We need to verify it because this resource is not authenticated require. + * + * @return bool + */ + protected function checkPatchAccess() { + $controller = new RestfulAuthenticationToken('restful_token_auth'); + return $controller->authenticate($this->getRequest(), $this->getMethod()); + } + + /** + * @param $op + * @param $entity_type + * @param $entity + * + * @return bool + */ + public function checkEntityAccess($op, $entity_type, $entity) { + if ($this->getMethod() == \RestfulBase::PATCH) { + return $this->checkPatchAccess(); + } + if ($this->getMethod() == \RestfulBase::POST) { + return TRUE; + } + return parent::checkEntityAccess($op, $entity_type, $entity); + } + + /** + * @param string $op + * @param string $public_field_name + * @param \EntityMetadataWrapper $property_wrapper + * @param \EntityMetadataWrapper $wrapper + * + * @return bool + */ + public function checkPropertyAccess($op, $public_field_name, EntityMetadataWrapper $property_wrapper, EntityMetadataWrapper $wrapper) { + if ($this->getMethod() == \RestfulBase::PATCH) { + return $this->checkPatchAccess(); + } + if ($this->getMethod() == \RestfulBase::POST) { + return TRUE; + } + return parent::checkPropertyAccess($op, $public_field_name, $property_wrapper, $wrapper); + } +} diff --git a/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/update/update__1_0.inc b/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/update/update__1_0.inc new file mode 100644 index 0000000..c933204 --- /dev/null +++ b/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/update/update__1_0.inc @@ -0,0 +1,24 @@ + t('Update User Entity'), + 'resource' => 'users', + 'name' => 'update__1_0', + 'entity_type' => 'user', + 'bundle' => 'user', + 'description' => t('Users creation endpoint.'), + 'class' => 'SkeletonUsersResource', + 'rate_limit' => array( + // The 'request' event is the basic event. You can declare your own events. + 'request' => array( + 'event' => 'request', + // Rate limit is cleared every day. + 'period' => new \DateInterval('P1D'), + 'limits' => array( + 'authenticated user' => 10, + 'anonymous user' => 5, + 'administrator' => \RestfulRateLimitManager::UNLIMITED_RATE_LIMIT, + ), + ), + ), +); diff --git a/app/templates/skeleton/modules/custom/skeleton_restful/skeleton_restful.module b/app/templates/skeleton/modules/custom/skeleton_restful/skeleton_restful.module index 2498879..b0f6494 100644 --- a/app/templates/skeleton/modules/custom/skeleton_restful/skeleton_restful.module +++ b/app/templates/skeleton/modules/custom/skeleton_restful/skeleton_restful.module @@ -19,3 +19,34 @@ function skeleton_restful_ctools_plugin_directory($module, $plugin) { } } +/** + * Implements hook_entity_property_info_alter(). + */ +function skeleton_restful_entity_property_info_alter(&$info) { + $info['user']['bundles']['user']['properties']['pass'] = array( + 'label' => t('Password'), + 'setter callback' => 'skeleton_restful_set_user_pass', + 'schema field' => 'pass', + ); + + $info['user']['bundles']['user']['properties']['mail'] = array( + 'label' => t('Username'), + 'setter callback' => 'skeleton_restful_set_user_name', + 'schema field' => 'mail', + ); +} + +/** + * Setter callback; Set user password. + */ +function skeleton_restful_set_user_pass($account, $name, $value) { + require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc'); + $account->pass = user_hash_password($value); +} + +/** + * Setter callback; Set user name and email. + */ +function skeleton_restful_set_user_name($account, $name, $value) { + $account->name = $value; +} From 8da77cf66da3f3a7cb524cfea7c63b0323265d88 Mon Sep 17 00:00:00 2001 From: Or Date: Mon, 22 Jun 2015 15:15:57 +0300 Subject: [PATCH 06/45] Changing resource name to prevent a clash with the 'users' resource. --- app/templates/client/app/scripts/services/auth.js | 2 +- .../plugins/restful/user/update/update__1_0.inc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/templates/client/app/scripts/services/auth.js b/app/templates/client/app/scripts/services/auth.js index e8a882f..887400b 100644 --- a/app/templates/client/app/scripts/services/auth.js +++ b/app/templates/client/app/scripts/services/auth.js @@ -58,7 +58,7 @@ angular.module('clientApp') this.savePassword = function(uid, password) { return $injector.get('$http')({ method: 'PATCH', - url: Config.backend + '/api/users/' + uid, + url: Config.backend + '/api/users-update/' + uid, data: {password: password} }); }; diff --git a/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/update/update__1_0.inc b/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/update/update__1_0.inc index c933204..c73a912 100644 --- a/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/update/update__1_0.inc +++ b/app/templates/skeleton/modules/custom/skeleton_restful/plugins/restful/user/update/update__1_0.inc @@ -2,7 +2,7 @@ $plugin = array( 'label' => t('Update User Entity'), - 'resource' => 'users', + 'resource' => 'users-update', 'name' => 'update__1_0', 'entity_type' => 'user', 'bundle' => 'user', From 70595cedad0296036723e42b15f22b1185ab2866 Mon Sep 17 00:00:00 2001 From: Or Date: Tue, 23 Jun 2015 12:25:48 +0300 Subject: [PATCH 07/45] WIP - Adding sign up page. --- app/templates/client/app/index.html | 1 + app/templates/client/app/scripts/app.js | 5 ++ .../client/app/scripts/controllers/sign-up.js | 40 +++++++++ .../client/app/scripts/services/auth.js | 28 +++++++ app/templates/client/app/styles/main.scss | 4 + app/templates/client/app/views/login.html | 11 ++- app/templates/client/app/views/sign-up.html | 83 +++++++++++++++++++ 7 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 app/templates/client/app/scripts/controllers/sign-up.js create mode 100644 app/templates/client/app/views/sign-up.html diff --git a/app/templates/client/app/index.html b/app/templates/client/app/index.html index e364e95..aa4b502 100644 --- a/app/templates/client/app/index.html +++ b/app/templates/client/app/index.html @@ -81,6 +81,7 @@

Login with demo / 1234

+ diff --git a/app/templates/client/app/scripts/app.js b/app/templates/client/app/scripts/app.js index ef9fa93..c3af61b 100644 --- a/app/templates/client/app/scripts/app.js +++ b/app/templates/client/app/scripts/app.js @@ -57,6 +57,11 @@ angular templateUrl: 'views/login.html', controller: 'LoginCtrl' }) + .state('sign-up', { + url: '/sign-up', + templateUrl: 'views/sign-up.html', + controller: 'SignUpCtrl' + }) .state('forgot-password', { url: '/forgot-password', templateUrl: 'views/forgot-password.html', diff --git a/app/templates/client/app/scripts/controllers/sign-up.js b/app/templates/client/app/scripts/controllers/sign-up.js new file mode 100644 index 0000000..9006e3e --- /dev/null +++ b/app/templates/client/app/scripts/controllers/sign-up.js @@ -0,0 +1,40 @@ +'use strict'; + +/** + * @ngdoc function + * @name clientApp.controller:ForgotPasswordCtrl + * @description + * # ForgotPasswordCtrl + * Controller of the clientApp + */ +angular.module('clientApp') + .controller('SignUpCtrl', function ($scope, Auth) { + + /** + * Send a password reset link. + */ + $scope.signUp = function(user) { + Auth.usernameAvailable(user.username).then(function(response) { + if (response.data.data.available) { + Auth.emailAvailable(user.email).then(function(response) { + if (response.data.data.available) { + // Email is available. + $scope.emailNotAvailable = false; + Auth.signUp(user).then(function() { + // User registered successfully. + $scope.signedUp = true; + }); + } + else { + // Email is not available. + $scope.emailNotAvailable = true; + } + }); + } + else { + // Username is not available. + $scope.usernameNotAvailable = true; + } + }); + }; + }); diff --git a/app/templates/client/app/scripts/services/auth.js b/app/templates/client/app/scripts/services/auth.js index 887400b..1c87f7b 100644 --- a/app/templates/client/app/scripts/services/auth.js +++ b/app/templates/client/app/scripts/services/auth.js @@ -63,6 +63,34 @@ angular.module('clientApp') }); }; + /** + * Checks if email is available. + * + * @param email + * @returns {*} + */ + this.emailAvailable = function(email) { + return $injector.get('$http')({ + method: 'POST', + url: Config.backend + '/api/email-available', + data: {email: email} + }); + }; + + /** + * Checks if username is available. + * + * @param username + * @returns {*} + */ + this.usernameAvailable = function(username) { + return $injector.get('$http')({ + method: 'POST', + url: Config.backend + '/api/username-available', + data: {username: username} + }); + }; + /** * Logout current user. * diff --git a/app/templates/client/app/styles/main.scss b/app/templates/client/app/styles/main.scss index d7dd24a..d4fa266 100644 --- a/app/templates/client/app/styles/main.scss +++ b/app/templates/client/app/styles/main.scss @@ -12,3 +12,7 @@ min-height: 500px; } +.vertical-space { + margin-top: 15px; + margin-bottom: 15px; +} diff --git a/app/templates/client/app/views/login.html b/app/templates/client/app/views/login.html index 1eb28bb..9b27dfb 100644 --- a/app/templates/client/app/views/login.html +++ b/app/templates/client/app/views/login.html @@ -8,7 +8,15 @@

Skeleton