diff --git a/README.txt b/README.txt index 99e334f..66fd708 100644 --- a/README.txt +++ b/README.txt @@ -1,15 +1,24 @@ INTRODUCTION ------------ -This project is part of the Drupal Social Initiative (https://groups.drupal.org/social-initiative). +This project is part of the Drupal Social Initiative +(https://groups.drupal.org/social-initiative). -Social Auth is part of the Social API. It provides a common interface for creating modules related to user registration/login through social networks' accounts. +Social Auth is part of the Social API. It provides a common interface for +creating modules related to user registration/login through social networks' +accounts. - * This module defines a path /admin/config/social-api/social-auth which displays a table of implementers (modules to register/login through social networks' accounts). + * This module defines a path /admin/config/social-api/social-auth which + displays a table of implementers (modules to register/login through social + networks' accounts). - * It also provides a block Social Auth Login which contains links to login users through the enabled social networks' module clients + * It also provides a block Social Auth Login which contains links to login + users through the enabled social networks' module clients - * Alternatively, site builders can place (and theme) a link to user/login/{social_network} wherever on the site. This path are added by the implementers. For instance Social Auth Facebook will add the path user/login/facebook + * Alternatively, site builders can place (and theme) a link to + user/login/{social_network} wherever on the site. This path are added by the + implementers. For instance Social Auth Facebook will add the path + user/login/facebook REQUIREMENTS ------------ @@ -22,19 +31,22 @@ INSTALLATION ------------ * Install as you would normally install a contributed Drupal module. See: - https://www.drupal.org/docs/8/extending-drupal-8/installing-contributed-modules-find-import-enable-configure-drupal-8 - for further information. + https://www.drupal.org/node/1897420 for further information. CONFIGURATION ------------- - * A table of implementers will be displayed at Administration » Configuration » Social API Settings » User authentication. However, it will be empty as we have not enabled an implementer yet. + * A table of implementers will be displayed at Administration » Configuration » + Social API Settings » User authentication. However, it will be empty as we + have not enabled an implementer yet. * You should install implementer modules to get this module start working. - * You can place a Social Auth Login block at Administration » Structure » Block layout. + * You can place a Social Auth Login block at Administration » Structure » + Block layout. - * You can find a more comprehensive guide in the Social Auth documentation (https://www.drupal.org/node/2763731) + * You can find a more comprehensive guide in the Social Auth documentation + (https://www.drupal.org/node/2763731) MAINTAINERS ----------- diff --git a/social_auth.services.yml b/social_auth.services.yml index deae7f7..6d5782b 100644 --- a/social_auth.services.yml +++ b/social_auth.services.yml @@ -4,6 +4,7 @@ services: arguments: - '@config.factory' - '@logger.factory' + - '@event_dispatcher' - '@entity_type.manager' - '@entity_field.manager' - '@token' diff --git a/src/Event/SocialAuthEvents.php b/src/Event/SocialAuthEvents.php new file mode 100644 index 0000000..56f68f6 --- /dev/null +++ b/src/Event/SocialAuthEvents.php @@ -0,0 +1,46 @@ +user = $user; + $this->plugin_id = $pluginId; + } + + /** + * Gets the user. + * + * @return \Drupal\user\UserInterface + * The user. + */ + public function getUser() { + return $this->user; + } + + /** + * Gets the plugin id dispatching this event. + * + * @return string + * The plugin id. + */ + public function getPluginId() { + return $this->pluginId; + } + +} diff --git a/src/Event/SocialAuthUserFieldsEvent.php b/src/Event/SocialAuthUserFieldsEvent.php new file mode 100644 index 0000000..5911461 --- /dev/null +++ b/src/Event/SocialAuthUserFieldsEvent.php @@ -0,0 +1,73 @@ +userFields = $user_fields; + $this->pluginId = $plugin_id; + } + + /** + * Gets the user fields. + * + * @return array + * Fields to initialize for the user creation. + */ + public function getUserFields() { + return $this->userFields; + } + + /** + * Sets the user fields. + * + * @param array $user_fields + * The user fields. + */ + public function setUserFields(array $user_fields) { + $this->userFields = $user_fields; + } + + /** + * Gets the plugin id dispatching this event. + * + * @return string + * The plugin id. + */ + public function getPluginId() { + return $this->pluginId; + } + +} diff --git a/src/SocialAuthUserManager.php b/src/SocialAuthUserManager.php index db6df55..621c075 100644 --- a/src/SocialAuthUserManager.php +++ b/src/SocialAuthUserManager.php @@ -2,26 +2,31 @@ namespace Drupal\social_auth; +use Drupal\Core\Entity\EntityFieldManagerInterface; +use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Core\StringTranslation\TranslationInterface; +use Drupal\Core\Transliteration\PhpTransliteration; +use Drupal\Core\Utility\Token; +use Drupal\social_auth\Event\SocialAuthUserEvent; +use Drupal\social_auth\Event\SocialAuthEvents; +use Drupal\social_auth\Event\SocialAuthUserFieldsEvent; use Drupal\user\Entity\User; use Drupal\user\UserInterface; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Logger\LoggerChannelFactoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\EntityStorageException; -use Drupal\Core\Entity\EntityFieldManagerInterface; -use Drupal\Core\Utility\Token; -use Drupal\Core\StringTranslation\StringTranslationTrait; -use Drupal\Core\StringTranslation\TranslationInterface; -use Drupal\Core\Transliteration\PhpTransliteration; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * Contains all logic that is related to Drupal user management. */ class SocialAuthUserManager { use StringTranslationTrait; - + protected $configFactory; protected $loggerFactory; + protected $eventDispatcher; protected $entityTypeManager; protected $entityFieldManager; protected $token; @@ -33,20 +38,25 @@ class SocialAuthUserManager { * * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * Used for accessing Drupal configuration. + * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory + * Used for logging errors. + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher + * Used for dispatching social auth events @see \Drupal\social_auth\Event\SocialAuthEvents * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * Used for loading and creating Drupal user objects. * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager * Used for access Drupal user field definitions. * @param \Drupal\Core\Utility\Token $token * Used for token support in Drupal user picture directory. - * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation + * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation * Used for translating strings in UI messages. * @param \Drupal\Core\Transliteration\PhpTransliteration $transliteration * Used for user picture directory and file transliteration. */ - public function __construct(ConfigFactoryInterface $config_factory, LoggerChannelFactoryInterface $logger_factory, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, Token $token, TranslationInterface $string_translation, PhpTransliteration $transliteration) { + public function __construct(ConfigFactoryInterface $config_factory, LoggerChannelFactoryInterface $logger_factory, EventDispatcherInterface $event_dispatcher, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, Token $token, TranslationInterface $string_translation, PhpTransliteration $transliteration) { $this->configFactory = $config_factory; $this->loggerFactory = $logger_factory; + $this->eventDispatcher = $event_dispatcher; $this->entityTypeManager = $entity_type_manager; $this->entityFieldManager = $entity_field_manager; $this->token = $token; @@ -90,42 +100,36 @@ class SocialAuthUserManager { * User's name on Provider. * @param string $email * User's email address. + * @param string $plugin_id + * Plugin ID creating the user. * * @return \Drupal\user\Entity\User|false * Drupal user account if user was created * False otherwise */ - public function createUser($name, $email) { + public function createUser($name, $email, $plugin_id = 'social_auth') { // Make sure we have everything we need. if (!$name || !$email) { $this->loggerFactory - ->get('social_auth') + ->get($plugin_id) ->error('Failed to create user. Name: @name, email: @email', array('@name' => $name, '@email' => $email)); return FALSE; } // Check if site configuration allows new users to register. if ($this->registrationBlocked()) { - $this->loggerFactory - ->get('social_auth') + ->get($plugin_id) ->warning('Failed to create user. User registration is disabled in Drupal account settings. Name: @name, email: @email.', array('@name' => $name, '@email' => $email)); return FALSE; } - // Set up the user fields. - // Username will be user's name on Provider. - // - Password can be very long since the user doesn't see this. - $fields = array( - 'name' => $this->generateUniqueUsername($name), - 'mail' => $email, - 'init' => $email, - 'pass' => $this->userPassword(32), - 'status' => $this->getNewUserStatus(), - ); + // Initializes the user fields. + $fields = $this->getUserFields($name, $email, $plugin_id); // Create new user account. + /** @var \Drupal\user\Entity\User $new_user */ $new_user = $this->entityTypeManager ->getStorage('user') ->create($fields); @@ -135,19 +139,22 @@ class SocialAuthUserManager { $new_user->save(); $this->loggerFactory - ->get('social_auth') - ->notice('New user created. Username @username, UID: @uid', array( + ->get($plugin_id) + ->notice('New user created. Username @username, UID: @uid',[ '@username' => $new_user->getAccountName(), - '@uid' => $new_user->id(), - )); + '@uid' => $new_user->id() + ]); + + // Dipatches SocialAuthEvents::USER_CREATED event. + $event = new SocialAuthUserEvent($new_user, $plugin_id); + $this->eventDispatcher->dispatch(SocialAuthEvents::USER_CREATED, $event); return $new_user; } - catch (EntityStorageException $ex) { $this->loggerFactory - ->get('social_auth') - ->error('Could not create new user. Exception: @message', array('@message' => $ex->getMessage())); + ->get($plugin_id) + ->error('Could not create new user. Exception: @message',['@message' => $ex->getMessage()]); } return FALSE; @@ -163,18 +170,22 @@ class SocialAuthUserManager { * True if login was successful * False if the login was blocked */ - public function loginUser(User $drupal_user) { - + public function loginUser(User $drupal_user, $plugin_id) { // Check that the account is active and log the user in. if ($drupal_user->isActive()) { $this->userLoginFinalize($drupal_user); + // Dipatches SocialAuthEvents::USER_LOGIN event. + $event = new SocialAuthUserEvent($drupal_user, $plugin_id); + $this->eventDispatcher->dispatch(SocialAuthEvents::USER_LOGIN, $event); + return TRUE; } $this->loggerFactory - ->get('social_auth') + ->get($plugin_id) ->warning('Login for user @user prevented. Account is blocked.', array('@user' => $drupal_user->getAccountName())); + return FALSE; } @@ -269,7 +280,37 @@ class SocialAuthUserManager { protected function userLoginFinalize(UserInterface $account) { user_login_finalize($account); } - + + /** + * Returns an array of fields to initialize the creation of the user. + * + * @param string $name + * User's name on Provider. + * @param string $email + * User's email address. + * + * @return array + * Fields to initialize for the user creation. + */ + protected function getUserFields($name, $email, $plugin_id) { + // - Password can be very long since the user doesn't see this. + $fields = [ + 'name' => $this->generateUniqueUsername($name), + 'mail' => $email, + 'init' => $email, + 'pass' => $this->userPassword(32), + 'status' => $this->getNewUserStatus(), + ]; + + // Dispatches SocialAuthEvents::USER_FIELDS, so that other modules can + // update this array before an user is saved. + $event = new SocialAuthUserFieldsEvent($fields, $plugin_id); + $this->eventDispatcher->dispatch(SocialAuthEvents::USER_FIELDS, $event); + $fields = $event->getUserFields(); + + return $fields; + } + /** * Downloads and sets user profile picture. * @@ -319,11 +360,9 @@ class SocialAuthUserManager { } // Determine target directory. - $scheme = $this->configFactory - ->get('system.file') - ->get('default_scheme'); + $scheme = $this->configFactory->get('system.file')->get('default_scheme'); $file_directory = $this->getPictureDirectory(); - + if (!$file_directory) { return FALSE; } @@ -334,14 +373,14 @@ class SocialAuthUserManager { // Transliterate directory name. $directory = $this->transliteration->transliterate($directory, 'en', '_', 50); - + if (!$this->filePrepareDirectory($directory, 1)) { $this->loggerFactory ->get('social_auth') - ->error('Could not save @provider profile picture. Directory is not writable: @directory', array( + ->error('Could not save @provider profile picture. Directory is not writable: @directory', [ '@directory' => $directory, '@provider' => $provider, - )); + ]); return FALSE; } @@ -354,16 +393,17 @@ class SocialAuthUserManager { if (!$file = $this->systemRetrieveFile($picture_url, $destination, TRUE, 1)) { $this->loggerFactory ->get('social_auth') - ->error('Could not download @provider profile picture from url: @url', array( + ->error('Could not download @provider profile picture from url: @url', [ '@url' => $picture_url, '@provider' => $provider, - )); + ]); + return FALSE; } return $file; } - + /** * Returns whether this site supports the default user picture feature. * @@ -378,7 +418,7 @@ class SocialAuthUserManager { $field_definitions = $this->entityFieldManager->getFieldDefinitions('user', 'user'); return isset($field_definitions['user_picture']); } - + /** * Returns picture directory if site supports the user picture feature. * @@ -393,7 +433,7 @@ class SocialAuthUserManager { } return FALSE; } - + /** * Wrapper for file_prepare_directory. * @@ -417,7 +457,7 @@ class SocialAuthUserManager { * @see system_retrieve_file */ protected function systemRetrieveFile($url, $destination, $managed, $replace) { - return system_retrieve_file($url, $destination, $managed, $replace); + return system_retrieve_file($url, $destination, $managed, $replace); } }