Jump to content

Developer Documentation

Syncing Data Between Your Login Handler and the Community

Users may want to sync some of their details from your login handler's database to the community. The data that can be synced is:

  • Display name
  • Email address
  • Profile photo
  • Cover photo
  • Status updates

For example, users who have logged in with Facebook can use their Facebook profile photo on the community, and optionally update the email address used on the community if they change it on Facebook. Your login handler can provide this syncing too.

Even if the user chooses to not sync this data, it is also used in certain other areas, for example, when viewing a member in the AdminCP, it will show their display name and profile photo for all of the login handlers they are logged in with, even if they are not being synced.

 

Step 1: Implement Methods For Getting Data

There are several methods to implement. You should implement all of the methods that your login handler can provide the data for and leave the others unimplemented (for example, if your login handler doesn't have profile photos, you can skip that method).

Here is are the skeletons for the methods you need to implement:

	/**
	 * Get user's identifier (doesn't have to be a number)
	 * May return NULL if server doesn't support this
	 *
	 * @param	\IPS\Member	$member	Member
	 * @return	string|NULL
	 * @throws	\IPS\Login\Exception	The token is invalid and the user needs to reauthenticate
	 * @throws	\DomainException		General error where it is safe to show a message to the user
	 * @throws	\RuntimeException		Unexpected error from service
	 */
	public function userId( \IPS\Member $member )
	{
		return NULL;
	}
	
	/**
	 * Get user's profile photo
	 * May return NULL if server doesn't support this
	 *
	 * @param	\IPS\Member	$member	Member
	 * @return	\IPS\Http\Url|NULL
	 * @throws	\IPS\Login\Exception	The token is invalid and the user needs to reauthenticate
	 * @throws	\DomainException		General error where it is safe to show a message to the user
	 * @throws	\RuntimeException		Unexpected error from service
	 */
	public function userProfilePhoto( \IPS\Member $member )
	{
		return NULL;
	}
	
	/**
	 * Get user's profile name
	 * May return NULL if server doesn't support this
	 *
	 * @param	\IPS\Member	$member	Member
	 * @return	string|NULL
	 * @throws	\IPS\Login\Exception	The token is invalid and the user needs to reauthenticate
	 * @throws	\DomainException		General error where it is safe to show a message to the user
	 * @throws	\RuntimeException		Unexpected error from service
	 */
	public function userProfileName( \IPS\Member $member )
	{
		return NULL;
	}
	
	/**
	 * Get user's email address
	 * May return NULL if server doesn't support this
	 *
	 * @param	\IPS\Member	$member	Member
	 * @return	string|NULL
	 * @throws	\IPS\Login\Exception	The token is invalid and the user needs to reauthenticate
	 * @throws	\DomainException		General error where it is safe to show a message to the user
	 * @throws	\RuntimeException		Unexpected error from service
	 */
	public function userEmail( \IPS\Member $member )
	{
		return NULL;
	}
	
	/**
	 * Get user's cover photo
	 * May return NULL if server doesn't support this
	 *
	 * @param	\IPS\Member	$member	Member
	 * @return	\IPS\Http\Url|NULL
	 * @throws	\IPS\Login\Exception	The token is invalid and the user needs to reauthenticate
	 * @throws	\DomainException		General error where it is safe to show a message to the user
	 * @throws	\RuntimeException		Unexpected error from service
	 */
	public function userCoverPhoto( \IPS\Member $member )
	{
		return NULL;
	}
	
	/**
	 * Get user's statuses since a particular date
	 *
	 * @param	\IPS\Member			$member	Member
	 * @param	\IPS\DateTime|NULL	$since	Date/Time to get statuses since then, or NULL to get the latest one
	 * @return	array
	 * @throws	\IPS\Login\Exception	The token is invalid and the user needs to reauthenticate
	 * @throws	\DomainException		General error where it is safe to show a message to the user
	 * @throws	\RuntimeException		Unexpected error from service
	 */
	public function userStatuses( \IPS\Member $member, \IPS\DateTime $since = NULL )
	{
		return array();
	}
	
	/**
	 * Get link to user's remote profile
	 * May return NULL if server doesn't support this
	 *
	 * @param	string	$identifier	The ID Nnumber/string from remote service
	 * @param	string	$username	The username from remote service
	 * @return	\IPS\Http\Url|NULL
	 * @throws	\IPS\Login\Exception	The token is invalid and the user needs to reauthenticate
	 * @throws	\DomainException		General error where it is safe to show a message to the user
	 * @throws	\RuntimeException		Unexpected error from service
	 */
	public function userLink( $identifier, $username )
	{
		return NULL;
	}

 

Step 2: Show Your Login Handler in the Account Settings

In order to configure which syncing options are available, a section will need to be added to the Account Settings page for your Login Handler. The convention that all default Login Handlers follow is to allow the admin the option to always show a section (Invision Community will automatically create a page that allows users to log in with the handler linking their accounts if they're not already logged in with it), only show a section if the user has already logged in with that method, or not show one at all (which won't allow them to sync their details).

To follow this convention you just need to add a setting for that - the code to check its value is already present:

	/**
	 * ACP Settings Form
	 *
	 * @param	string	$url	URL to redirect user to after successful submission
	 * @return	array	List of settings to save - settings will be stored to core_login_methods.login_settings DB field
	 * @code
	 	return array( 'savekey'	=> new \IPS\Helpers\Form\[Type]( ... ), ... );
	 * @endcode
	 */
	public function acpForm()
	{		
		$return = array();
				
		// ... any other settings you already have ...
		
		$return['show_in_ucp'] = new \IPS\Helpers\Form\Radio( 'login_handler_show_in_ucp', isset( $this->settings['show_in_ucp'] ) ? $this->settings['show_in_ucp'] : 'disabled', FALSE, array(
			'options' => array(
				'always'		=> 'login_handler_show_in_ucp_always',
				'loggedin'		=> 'login_handler_show_in_ucp_loggedin',
				'disabled'		=> 'login_handler_show_in_ucp_disabled'
			),
		) );
				
		return $return;
	}

Alternatively you can override the showInUcp() method to implement other logic to determine if your login handler should show:

	/**
	 * Show in Account Settings?
	 *
	 * @param	\IPS\Member|NULL	$member	The member, or NULL for if it should show generally
	 * @return	bool
	 */
	public function showInUcp( \IPS\Member $member = NULL )
	{		
		// ... 
	}

You should also implement the logoForUcp() method which determines the logo to use alongside the link to your Login Handler's area of the Account Settings. You can return an \IPS\Http\Url object, or a string with a Fontawesome icon name:

	/**
	 * Get logo to display in user cp sidebar
	 *
	 * @return	\IPS\Http\Url|string
	 */
	public function logoForUcp()
	{
		return 'sign-in';
	}

 

Step 3: Add Syncing Options

Finally you need to implement a syncOptions() method which returns the things which can be synced. The convention is to offer profile photo and cover photo syncing automatically if your Login Handler supports it, and have settings to control if email and username syncing is offered.

To do this, you might implement settings like this:

	/**
	 * ACP Settings Form
	 *
	 * @param	string	$url	URL to redirect user to after successful submission
	 * @return	array	List of settings to save - settings will be stored to core_login_methods.login_settings DB field
	 * @code
	 	return array( 'savekey'	=> new \IPS\Helpers\Form\[Type]( ... ), ... );
	 * @endcode
	 */
	public function acpForm()
	{		
		$return = array();
		
		// ... any other settings you already have ...
		
		$return['show_in_ucp'] = new \IPS\Helpers\Form\Radio( 'login_handler_show_in_ucp', isset( $this->settings['show_in_ucp'] ) ? $this->settings['show_in_ucp'] : 'disabled', FALSE, array(
			'options' => array(
				'always'		=> 'login_handler_show_in_ucp_always',
				'loggedin'		=> 'login_handler_show_in_ucp_loggedin',
				'disabled'		=> 'login_handler_show_in_ucp_disabled'
			),
			'toggles' => array(
				'always'		=> array( 'login_update_name_changes_inc_optional', 'login_update_email_changes_inc_optional' ),
				'loggedin'		=> array( 'login_update_name_changes_inc_optional', 'login_update_email_changes_inc_optional' ),
				'disabled'		=> array( 'login_update_name_changes_no_optional', 'login_update_email_changes_no_optional' ),
			)
		) );
		
		$return['update_name_changes_inc_optional'] = new \IPS\Helpers\Form\Radio( 'login_update_name_changes_inc_optional', isset( $this->settings['update_name_changes'] ) ? $this->settings['update_name_changes'] : 'disabled', FALSE, array( 'options' => array(
			'force'		=> 'login_update_changes_yes',
			'optional'	=> 'login_update_changes_optional',
			'disabled'	=> 'login_update_changes_no',
		) ), NULL, NULL, NULL, 'login_update_name_changes_inc_optional' );
		$return['update_name_changes_no_optional'] = new \IPS\Helpers\Form\Radio( 'login_update_name_changes_no_optional', ( isset( $this->settings['update_name_changes'] ) and $this->settings['update_name_changes'] != 'optional' ) ? $this->settings['update_name_changes'] : 'disabled', FALSE, array( 'options' => array(
			'force'		=> 'login_update_changes_yes',
			'disabled'	=> 'login_update_changes_no',
		) ), NULL, NULL, NULL, 'login_update_name_changes_no_optional' );
		$return['update_email_changes_inc_optional'] = new \IPS\Helpers\Form\Radio( 'login_update_email_changes_inc_optional', isset( $this->settings['update_email_changes'] ) ? $this->settings['update_email_changes'] : 'force', FALSE, array( 'options' => array(
			'force'		=> 'login_update_changes_yes',
			'optional'	=> 'login_update_changes_optional',
			'disabled'	=> 'login_update_changes_no',
		) ), NULL, NULL, NULL, 'login_update_email_changes_inc_optional' );
		$return['update_email_changes_no_optional'] = new \IPS\Helpers\Form\Radio( 'login_update_email_changes_no_optional', ( isset( $this->settings['update_email_changes'] ) and $this->settings['update_email_changes'] != 'optional' ) ? $this->settings['update_email_changes'] : 'force', FALSE, array( 'options' => array(
			'force'		=> 'login_update_changes_yes',
			'disabled'	=> 'login_update_changes_no',
		) ), NULL, NULL, NULL, 'login_update_email_changes_no_optional' );
		\IPS\Member::loggedIn()->language()->words['login_update_name_changes_inc_optional'] = \IPS\Member::loggedIn()->language()->addToStack('login_update_name_changes');
		\IPS\Member::loggedIn()->language()->words['login_update_name_changes_no_optional'] = \IPS\Member::loggedIn()->language()->addToStack('login_update_name_changes');
		\IPS\Member::loggedIn()->language()->words['login_update_email_changes_inc_optional'] = \IPS\Member::loggedIn()->language()->addToStack('login_update_email_changes');
		\IPS\Member::loggedIn()->language()->words['login_update_email_changes_no_optional'] = \IPS\Member::loggedIn()->language()->addToStack('login_update_email_changes');
				
		return $return;
	}

	/**
	 * Save Handler Settings
	 *
	 * @param	array	$values	Values from form
	 * @return	array
	 */
	public function acpFormSave( &$values )
	{
		$_values = $values;
		
		$settings = parent::acpFormSave( $values );
				
		if ( $_values['login_handler_show_in_ucp'] == 'never' )
		{
			$settings['update_name_changes'] = $_values['login_update_name_changes_no_optional'];
			$settings['update_email_changes'] = $_values['login_update_email_changes_no_optional'];
		}
		else
		{
			$settings['update_name_changes'] = $_values['login_update_name_changes_inc_optional'];
			$settings['update_email_changes'] = $_values['login_update_email_changes_inc_optional'];
		}
		
		unset( $settings['update_name_changes_inc_optional'] );
		unset( $settings['update_name_changes_no_optional'] );
		unset( $settings['update_email_changes_inc_optional'] );
		unset( $settings['update_email_changes_no_optional'] );		
				
		return $settings;
	}

And then implement the actual syncOptions() method like this:

	/**
	 * Syncing Options
	 *
	 * @param	\IPS\Member	$member			The member we're asking for (can be used to not show certain options iof the user didn't grant those scopes)
	 * @param	bool		$defaultOnly	If TRUE, only returns which options should be enabled by default for a new account
	 * @return	array
	 */
	public function syncOptions( \IPS\Member $member, $defaultOnly = FALSE )
	{
		$return = array();
		
		if ( isset( $this->settings['update_email_changes'] ) and $this->settings['update_email_changes'] === 'optional' )
		{
			$return[] = 'email';
		}
		
		if ( isset( $this->settings['update_name_changes'] ) and $this->settings['update_name_changes'] === 'optional' )
		{
			$return[] = 'name';
		}
		
		$return[] = 'photo';
		$return[] = 'cover';
				
		return $return;
	}

After implementing this, there user will see the options to sync data in the area for your Login Handler in the Account Settings. Once they have configured it, Invision Community will automatically handle the syncing.

Edited by Mark

  Report Document


×
×
  • Create New...