Html->tag('i', '', [
'class' => 'fa fa-' . strtolower($name),
]);
if (isset($options['title'])) {
$providerTitle = $options['title'];
} else {
$providerTitle = $options['label'] . ' ' . Inflector::camelize($name);
}
$providerClass = 'btn btn-social btn-' . strtolower($name);
$optionClass = $options['class'] ?? null;
if ($optionClass) {
$providerClass .= " $optionClass";
}
return $this->Html->link($icon . $providerTitle, "/auth/$name", [
'escape' => false, 'class' => $providerClass,
]);
}
/**
* All available Social Login Icons
*
* @param array $providerOptions Provider link options.
* @return array Links to Social Login Urls
*/
public function socialLoginList(array $providerOptions = []): array
{
if (!Configure::read('Users.Social.login')) {
return [];
}
$outProviders = [];
$providers = Configure::read('OAuth.providers');
foreach ($providers as $provider => $options) {
if (
!empty($options['options']['redirectUri']) &&
!empty($options['options']['clientId']) &&
!empty($options['options']['clientSecret'])
) {
if (isset($providerOptions[$provider])) {
$options['options'] = Hash::merge($options['options'], $providerOptions[$provider]);
}
$outProviders[] = $this->socialLogin($provider, $options['options']);
}
}
return $outProviders;
}
/**
* Logout link
*
* @param string|null $message logout message info.
* @param array $options Array with option data.
* @return string
*/
public function logout(?string $message = null, array $options = []): string
{
$url = UsersUrl::actionUrl('logout');
$title = empty($message) ? __d('cake_d_c/users', 'Logout') : $message;
return $this->AuthLink->link($title, $url, $options);
}
/**
* Welcome display
*
* @return string|null
*/
public function welcome(): ?string
{
$identity = $this->getView()->getRequest()->getAttribute('identity');
if (!$identity) {
return null;
}
$profileUrl = Configure::read('Users.Profile.route');
$title = $identity['first_name'] ?? null;
$title = $title ?: ($identity['username'] ?? null);
$title = is_array($title) ? '-' : (string)$title;
$label = __d(
'cake_d_c/users',
'Welcome, {0}',
$this->AuthLink->link($title, $profileUrl),
);
return $this->Html->tag('span', $label, ['class' => 'welcome']);
}
/**
* Add reCaptcha script
*
* @return void
*/
public function addReCaptchaScript(): void
{
$this->Html->script('https://www.google.com/recaptcha/api.js', [
'block' => 'script',
]);
}
/**
* @return void
*/
public function addPasswordMeterScript(): void
{
$this->Html->script('CakeDC/Users.pswmeter', [
'block' => 'script',
]);
}
/**
* @return string
*/
public function addPasswordMeter(): string
{
$this->addPasswordMeterScript();
$requiredScore = Configure::read('Users.passwordMeter.requiredScore', 3);
$messagesList = json_encode(
Configure::read(
'Users.passwordMeter.messagesList',
['Empty password', 'Too simple', 'Simple', 'That\'s OK', 'Great password!'],
),
);
$pswMinLength = Configure::read('Users.passwordMinLength', 8);
$showMessage = Configure::read('Users.passwordMeter.showMessage', true) ? 'true' : 'false';
$script = $this->Html->scriptBlock("
const requiredScore = $requiredScore;
const messagesList = $messagesList;
const pswMinLength = $pswMinLength;
const showMessage = $showMessage;
", ['defer' => true]);
return $this->Html->tag('div', '', ['id' => 'pswmeter']) .
$this->Html->tag('div', '', ['id' => 'pswmeter-message']) . $script;
}
/**
* Add reCaptcha to the form
*
* @return mixed
*/
public function addReCaptcha(): mixed
{
if (!Configure::read('Users.reCaptcha.key')) {
return $this->Html->tag(
'p',
__d(
'cake_d_c/users',
'reCaptcha is not configured! Please configure Users.reCaptcha.key',
),
);
}
$this->addReCaptchaScript();
$version = Configure::read('Users.reCaptcha.version', 2);
$method = "addReCaptchaV$version";
if (method_exists($this, $method)) {
try {
$this->Form->unlockField('g-recaptcha-response');
} catch (\Exception $e) {
}
return $this->{$method}();
}
throw new InvalidArgumentException(
__d('cake_d_c/users', 'reCaptcha version is wrong. Please configure Users.reCaptcha.version as 2 or 3'),
);
}
/**
* Add required element for reCaptcha v2
*
* @return string
*/
private function addReCaptchaV2(): string
{
deprecationWarning('14.2.0', 'reCaptcha version 3 will be used as default in version 15.0.0');
return $this->Html->tag('div', '', [
'class' => 'g-recaptcha',
'data-sitekey' => Configure::read('Users.reCaptcha.key'),
'data-theme' => Configure::read('Users.reCaptcha.theme') ?: 'light',
'data-size' => Configure::read('Users.reCaptcha.size') ?: 'normal',
'data-tabindex' => Configure::read('Users.reCaptcha.tabindex') ?: '3',
]);
}
/**
* Add required script for reCaptcha v3
*/
private function addReCaptchaV3(): void
{
$this->Html->script('CakeDC/Users.reCaptchaV3', [
'block' => 'script',
]);
}
/**
* Add required options for reCaptcha v3
*
* @param string $title
* @param array $options
* @return string
*/
public function button(string $title, array $options = []): string
{
$key = Configure::read('Users.reCaptcha.key');
if ($key && Configure::read('Users.reCaptcha.version', 2) === 3) {
$options = array_merge($options, [
'class' => 'g-recaptcha',
'data-sitekey' => $key,
'data-callback' => 'onSubmit',
'data-action' => 'submit',
]);
}
return $this->Form->button($title, $options);
}
/**
* Generate a link if the target url is authorized for the logged in user
*
* @deprecated Since 3.2.1. Use AuthLinkHelper::link() instead
* @param string $title link's title.
* @param array|string|null $url url that the user is making request.
* @param array $options Array with option data.
* @return string
*/
public function link(string $title, array|string|null $url = null, array $options = []): string
{
trigger_error(
'UserHelper::link() deprecated since 3.2.1. Use AuthLinkHelper::link() instead',
E_USER_DEPRECATED,
);
return $this->AuthLink->link($title, $url, $options);
}
/**
* Create links for all social providers enabled social link (connect)
*
* @param string $name Provider name in lowercase
* @param array $provider Provider configuration
* @param bool $isConnected User is connected with this provider
* @return string
*/
public function socialConnectLink(string $name, array $provider, bool $isConnected = false): string
{
$optionClass = $provider['options']['class'] ?? null;
$linkClass = 'btn btn-social btn-' . strtolower($name) . ($optionClass ? ' ' . $optionClass : '');
if ($isConnected) {
$title = __d('cake_d_c/users', 'Connected with {0}', Inflector::camelize($name));
return " $title";
}
$title = __d('cake_d_c/users', 'Connect with {0}', Inflector::camelize($name));
return $this->Html->link(
" $title",
"/link-social/$name",
[
'escape' => false,
'class' => $linkClass,
],
);
}
/**
* Create links for all social providers enabled social link (connect)
*
* @param array $socialAccounts All social accounts connected by a user.
* @return string
*/
public function socialConnectLinkList(array $socialAccounts = []): string
{
if (!Configure::read('Users.Social.login')) {
return '';
}
$html = '';
$connectedProviders = array_map(
function ($item) {
return strtolower($item->provider);
},
(array)$socialAccounts,
);
$providers = Configure::read('OAuth.providers');
foreach ($providers as $name => $provider) {
if (
!empty($provider['options']['callbackLinkSocialUri']) &&
!empty($provider['options']['linkSocialUri']) &&
!empty($provider['options']['clientId']) &&
!empty($provider['options']['clientSecret'])
) {
$html .= $this->socialConnectLink($name, $provider, in_array($name, $connectedProviders));
}
}
return $html;
}
}