update folder location

This commit is contained in:
Antonio Ramirez
2017-01-11 21:31:42 +01:00
parent 1cb60f0740
commit 13255a5117
167 changed files with 4770 additions and 8 deletions

View File

@ -0,0 +1,36 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\AuthClient;
use Da\User\Contracts\AuthClientInterface;
use yii\authclient\clients\Facebook as BaseFacebook;
class Facebook extends BaseFacebook implements AuthClientInterface
{
/**
* {@inheritdoc}
*/
public function getEmail()
{
return isset($this->getUserAttributes()['email'])
? $this->getUserAttributes()['email']
: null;
}
/**
* {@inheritdoc}
*/
public function getUsername()
{
return null;
}
}

View File

@ -0,0 +1,38 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\AuthClient;
use Da\User\Contracts\AuthClientInterface;
use yii\authclient\clients\GitHub as BaseGitHub;
class GitHub extends BaseGitHub implements AuthClientInterface
{
/**
* {@inheritdoc}
*/
public function getEmail()
{
return isset($this->getUserAttributes()['email'])
? $this->getUserAttributes()['email']
: null;
}
/**
* {@inheritdoc}
*/
public function getUsername()
{
return isset($this->getUserAttributes()['login'])
? $this->getUserAttributes()['login']
: null;
}
}

View File

@ -0,0 +1,36 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\AuthClient;
use Da\User\Contracts\AuthClientInterface;
use yii\authclient\clients\Google as BaseGoogle;
class Google extends BaseGoogle implements AuthClientInterface
{
/**
* {@inheritdoc}
*/
public function getEmail()
{
return isset($this->getUserAttributes()['emails'][0]['value'])
? $this->getUserAttributes()['emails'][0]['value']
: null;
}
/**
* {@inheritdoc}
*/
public function getUsername()
{
return null;
}
}

View File

@ -0,0 +1,36 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\AuthClient;
use Da\User\Contracts\AuthClientInterface;
use yii\authclient\clients\LinkedIn as BaseLinkedIn;
class LinkedIn extends BaseLinkedIn implements AuthClientInterface
{
/**
* {@inheritdoc}
*/
public function getEmail()
{
return isset($this->getUserAttributes()['email-address'])
? $this->getUserAttributes()['email-address']
: null;
}
/**
* {@inheritdoc}
*/
public function getUsername()
{
return null;
}
}

View File

@ -0,0 +1,33 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\AuthClient;
use Da\User\Contracts\AuthClientInterface;
use yii\authclient\clients\Twitter as BaseTwitter;
class Twitter extends BaseTwitter implements AuthClientInterface
{
/**
* @return string
*/
public function getUsername()
{
return isset($this->getUserAttributes()['screen_name'])
? $this->getUserAttributes()['screen_name']
: null;
}
public function getEmail()
{
return null;
}
}

View File

@ -0,0 +1,50 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\AuthClient;
use Da\User\Contracts\AuthClientInterface;
use Yii;
use yii\authclient\clients\VKontakte as BaseVKontakte;
class VKontakte extends BaseVKontakte implements AuthClientInterface
{
/**
* {@inheritdoc}
*/
public $scope = 'email';
/**
* {@inheritdoc}
*/
public function getEmail()
{
return $this->getAccessToken()->getParam('email');
}
/**
* {@inheritdoc}
*/
public function getUsername()
{
return isset($this->getUserAttributes()['screen_name'])
? $this->getUserAttributes()['screen_name']
: null;
}
/**
* {@inheritdoc}
*/
protected function defaultTitle()
{
return Yii::t('usuario', 'VKontakte');
}
}

View File

@ -0,0 +1,53 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\AuthClient;
use Da\User\Contracts\AuthClientInterface;
use Yii;
use yii\authclient\clients\Yandex as BaseYandex;
class Yandex extends BaseYandex implements AuthClientInterface
{
/**
* {@inheritdoc}
*/
public function getEmail()
{
$emails = isset($this->getUserAttributes()['emails'])
? $this->getUserAttributes()['emails']
: null;
if ($emails !== null && isset($emails[0])) {
return $emails[0];
} else {
return null;
}
}
/**
* {@inheritdoc}
*/
public function getUsername()
{
return isset($this->getUserAttributes()['login'])
? $this->getUserAttributes()['login']
: null;
}
/**
* {@inheritdoc}
*/
protected function defaultTitle()
{
return Yii::t('usuario', 'Yandex');
}
}

350
src/User/Bootstrap.php Normal file
View File

@ -0,0 +1,350 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User;
use Da\User\Component\AuthDbManagerComponent;
use Da\User\Contracts\AuthManagerInterface;
use Da\User\Helper\ClassMapHelper;
use Da\User\Model\User;
use Da\User\Validator\TimeZoneValidator;
use Yii;
use yii\authclient\Collection;
use yii\base\Application;
use yii\base\BootstrapInterface;
use yii\base\Exception;
use yii\console\Application as ConsoleApplication;
use yii\i18n\PhpMessageSource;
use yii\web\Application as WebApplication;
/**
* Bootstrap class of the yii2-usuario extension. Configures container services, initializes translations,
* builds class map, and does the other setup actions participating in the application bootstrap process.
*/
class Bootstrap implements BootstrapInterface
{
/**
* {@inheritdoc}
*/
public function bootstrap($app)
{
if ($app->hasModule('user') && $app->getModule('user') instanceof Module) {
$map = $this->buildClassMap($app->getModule('user')->classMap);
$this->initContainer($app, $map);
$this->initTranslations($app);
$this->initMailServiceConfiguration($app, $app->getModule('user'));
if ($app instanceof WebApplication) {
$this->initControllerNamespace($app);
$this->initUrlRoutes($app);
$this->initAuthCollection($app);
$this->initAuthManager($app);
} else {
/* @var $app ConsoleApplication */
$this->initConsoleCommands($app);
$this->initAuthManager($app);
}
}
}
/**
* Initialize container with module classes.
*
* @param \yii\base\Application $app
* @param array $map the previously built class map list
*/
protected function initContainer($app, $map)
{
$di = Yii::$container;
try {
// events
$di->set(Event\FormEvent::class);
$di->set(Event\ProfileEvent::class);
$di->set(Event\ResetPasswordEvent::class);
$di->set(Event\SocialNetworkAuthEvent::class);
$di->set(Event\SocialNetworkConnectEvent::class);
$di->set(Event\UserEvent::class);
// forms
$di->set(Form\LoginForm::class);
$di->set(Form\RecoveryForm::class);
$di->set(Form\RegistrationForm::class);
$di->set(Form\ResendForm::class);
$di->set(Form\SettingsForm::class);
// helpers
$di->set(Helper\AuthHelper::class);
$di->set(Helper\GravatarHelper::class);
$di->set(Helper\SecurityHelper::class);
$di->set(Helper\TimezoneHelper::class);
// services
$di->set(Service\AccountConfirmationService::class);
$di->set(Service\EmailChangeService::class);
$di->set(Service\PasswordRecoveryService::class);
$di->set(Service\ResendConfirmationService::class);
$di->set(Service\ResetPasswordService::class);
$di->set(Service\SocialNetworkAccountConnectService::class);
$di->set(Service\SocialNetworkAuthenticateService::class);
$di->set(Service\UserBlockService::class);
$di->set(Service\UserCreateService::class);
$di->set(Service\UserRegisterService::class);
$di->set(Service\UserConfirmationService::class);
$di->set(Service\AuthItemEditionService::class);
$di->set(Service\UpdateAuthAssignmentsService::class);
// email change strategy
$di->set(Strategy\DefaultEmailChangeStrategy::class);
$di->set(Strategy\InsecureEmailChangeStrategy::class);
$di->set(Strategy\SecureEmailChangeStrategy::class);
// validators
$di->set(Validator\AjaxRequestModelValidator::class);
$di->set(TimeZoneValidator::class);
// class map models + query classes
$modelClassMap = [];
foreach ($map as $class => $definition) {
$di->set($class, $definition);
$model = is_array($definition) ? $definition['class'] : $definition;
$name = (substr($class, strrpos($class, '\\') + 1));
$modelClassMap[$class] = $model;
if (in_array($name, ['User', 'Profile', 'Token', 'SocialNetworkAccount'])) {
$di->set(
"Da\\User\\Query\\{$name}Query",
function () use ($model) {
return $model::find();
}
);
}
}
$di->setSingleton(ClassMapHelper::class, ClassMapHelper::class, [$modelClassMap]);
// search classes
if (!$di->has(Search\UserSearch::class)) {
$di->set(Search\UserSearch::class, [$di->get(Query\UserQuery::class)]);
}
if (!$di->has(Search\PermissionSearch::class)) {
$di->set(Search\PermissionSearch::class);
}
if (!$di->has(Search\RoleSearch::class)) {
$di->set(Search\RoleSearch::class);
}
if ($app instanceof WebApplication) {
// override Yii
$di->set(
'yii\web\User',
[
'enableAutoLogin' => true,
'loginUrl' => ['/user/auth/login'],
'identityClass' => $di->get(ClassMapHelper::class)->get(User::class),
]
);
}
} catch (Exception $e) {
die($e);
}
}
/**
* Registers module translation messages.
*
* @param Application $app
*/
protected function initTranslations(Application $app)
{
if (!isset($app->get('i18n')->translations['usuario*'])) {
$app->get('i18n')->translations['usuario*'] = [
'class' => PhpMessageSource::class,
'basePath' => __DIR__.'/resources/i18n',
'sourceLanguage' => 'en-US',
];
}
}
/**
* Ensures the auth manager is the one provided by the library.
*
* @param Application $app
*/
protected function initAuthManager(Application $app)
{
if (!($app->getAuthManager() instanceof AuthManagerInterface)) {
$app->set(
'authManager',
[
'class' => AuthDbManagerComponent::class,
]
);
}
}
/**
* Initializes web url routes (rules in Yii2).
*
* @param WebApplication $app
*/
protected function initUrlRoutes(WebApplication $app)
{
/** @var $module Module */
$module = $app->getModule('user');
$config = [
'class' => 'yii\web\GroupUrlRule',
'prefix' => $module->prefix,
'rules' => $module->routes,
];
if ($module->prefix !== 'user') {
$config['routePrefix'] = 'user';
}
$rule = Yii::createObject($config);
$app->getUrlManager()->addRules([$rule], false);
}
/**
* Ensures required mail parameters needed for the mail service.
*
* @param Application $app
* @param Module|\yii\base\Module $module
*/
protected function initMailServiceConfiguration(Application $app, Module $module)
{
$defaults = [
'fromEmail' => 'no-reply@example.com',
'welcomeMailSubject' => Yii::t('usuario', 'Welcome to {0}', $app->name),
'confirmationMailSubject' => Yii::t('usuario', 'Confirm account on {0}', $app->name),
'reconfirmationMailSubject' => Yii::t('usuario', 'Confirm email change on {0}', $app->name),
'recoveryMailSubject' => Yii::t('usuario', 'Complete password reset on {0}', $app->name),
];
$module->mailParams = array_merge($defaults, $module->mailParams);
}
/**
* Ensures the authCollection component is configured.
*
* @param WebApplication $app
*/
protected function initAuthCollection(WebApplication $app)
{
if (!$app->has('authClientCollection')) {
$app->set('authClientCollection', Collection::class);
}
}
/**
* Registers console commands to main app.
*
* @param ConsoleApplication $app
*/
protected function initConsoleCommands(ConsoleApplication $app)
{
$app->getModule('user')->controllerNamespace = 'Da\User\Command';
}
/**
* Registers controllers.
*
* @param WebApplication $app
*/
protected function initControllerNamespace(WebApplication $app)
{
$app->getModule('user')->controllerNamespace = 'Da\User\Controller';
$app->getModule('user')->setViewPath('@Da/User/resources/views');
}
/**
* Builds class map according to user configuration.
*
* @param array $userClassMap user configuration on the module
*
* @return array
*/
protected function buildClassMap(array $userClassMap)
{
$map = [];
$defaults = [
// --- models
'User' => 'Da\User\Model\User',
'SocialNetworkAccount' => 'Da\User\Model\SocialNetworkAccount',
'Profile' => 'Da\User\Model\Profile',
'Token' => 'Da\User\Model\Token',
'Assignment' => 'Da\User\Model\Assignment',
'Permission' => 'Da\User\Model\Permission',
'Role' => 'Da\User\Model\Role',
// --- search
'UserSearch' => 'Da\User\Search\UserSearch',
'PermissionSearch' => 'Da\User\Search\PermissionSearch',
'RoleSearch' => 'Da\User\Search\RoleSearch',
// --- forms
'RegistrationForm' => 'Da\User\Form\RegistrationForm',
'ResendForm' => 'Da\User\Form\ResendForm',
'LoginForm' => 'Da\User\Form\LoginForm',
'SettingsForm' => 'Da\User\Form\SettingsForm',
'RecoveryForm' => 'Da\User\Form\RecoveryForm',
];
$routes = [
'Da\User\Model' => [
'User',
'SocialNetworkAccount',
'Profile',
'Token',
'Assignment',
'Permission',
'Role',
],
'Da\User\Search' => [
'UserSearch',
'PermissionSearch',
'RoleSearch',
],
'Da\UserForm' => [
'RegistrationForm',
'ResendForm',
'LoginForm',
'SettingsForm',
'RecoveryForm',
],
];
$mapping = array_merge($defaults, $userClassMap);
foreach ($mapping as $name => $definition) {
$map[$this->getRoute($routes, $name) . "\\$name"] = $definition;
}
return $map;
}
/**
* Returns the parent class name route of a short class name.
*
* @param array $routes class name routes
* @param string $name
*
* @return int|string
*
* @throws Exception
*/
protected function getRoute(array $routes, $name)
{
foreach ($routes as $route => $names) {
if (in_array($name, $names)) {
return $route;
}
}
throw new Exception("Unknown configuration class name '{$name}'");
}
}

View File

@ -0,0 +1,48 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Command;
use Da\User\Query\UserQuery;
use Da\User\Service\UserConfirmationService;
use Da\User\Traits\ContainerAwareTrait;
use Yii;
use yii\base\Module;
use yii\console\Controller;
use yii\helpers\Console;
class ConfirmController extends Controller
{
use ContainerAwareTrait;
protected $userQuery;
public function __construct($id, Module $module, UserQuery $userQuery, array $config)
{
$this->userQuery = $userQuery;
parent::__construct($id, $module, $config);
}
public function actionIndex($usernameOrEmail)
{
$user = $this->userQuery->whereUsernameOrEmail($usernameOrEmail)->one();
if ($user === null) {
$this->stdout(Yii::t('usuario', 'User is not found')."\n", Console::FG_RED);
} else {
if ($this->make(UserConfirmationService::class, [$user])->run()) {
$this->stdout(Yii::t('usuario', 'User has been confirmed')."\n", Console::FG_GREEN);
} else {
$this->stdout(Yii::t('usuario', 'Error occurred while confirming user')."\n", Console::FG_RED);
}
}
}
}

View File

@ -0,0 +1,45 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Command;
use Da\User\Factory\MailFactory;
use Da\User\Model\User;
use Da\User\Service\UserCreateService;
use Da\User\Traits\ContainerAwareTrait;
use Yii;
use yii\console\Controller;
use yii\helpers\Console;
class CreateController extends Controller
{
use ContainerAwareTrait;
public function actionIndex($email, $username, $password = null)
{
$user = $this->make(
User::class,
['scenario' => 'create', 'email' => $email, 'username' => $username, 'password' => $password]
);
$mailService = MailFactory::makeWelcomeMailerService($user);
if ($this->make(UserCreateService::class, [$user, $mailService])->run()) {
$this->stdout(Yii::t('usuario', 'User has been created')."!\n", Console::FG_GREEN);
} else {
$this->stdout(Yii::t('usuario', 'Please fix following errors:')."\n", Console::FG_RED);
foreach ($user->errors as $errors) {
foreach ($errors as $error) {
$this->stdout(' - '.$error."\n", Console::FG_RED);
}
}
}
}
}

View File

@ -0,0 +1,45 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Command;
use Da\User\Query\UserQuery;
use Yii;
use yii\base\Module;
use yii\console\Controller;
use yii\helpers\Console;
class DeleteController extends Controller
{
protected $userQuery;
public function __construct($id, Module $module, UserQuery $userQuery, array $config)
{
$this->userQuery = $userQuery;
parent::__construct($id, $module, $config);
}
public function actionIndex($usernameOrEmail)
{
if ($this->confirm(Yii::t('usuario', 'Are you sure? Deleted user can not be restored'))) {
$user = $this->userQuery->whereUsernameOrEmail($usernameOrEmail)->one();
if ($user === null) {
$this->stdout(Yii::t('usuario', 'User is not found')."\n", Console::FG_RED);
} else {
if ($user->delete()) {
$this->stdout(Yii::t('usuario', 'User has been deleted')."\n", Console::FG_GREEN);
} else {
$this->stdout(Yii::t('usuario', 'Error occurred while deleting user')."\n", Console::FG_RED);
}
}
}
}
}

View File

@ -0,0 +1,50 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Command;
use Da\User\Model\User;
use Da\User\Query\UserQuery;
use Da\User\Service\ResetPasswordService;
use Da\User\Traits\ContainerAwareTrait;
use Yii;
use yii\base\Module;
use yii\console\Controller;
use yii\helpers\Console;
class PasswordController extends Controller
{
use ContainerAwareTrait;
protected $userQuery;
public function __construct($id, Module $module, UserQuery $userQuery, array $config)
{
$this->userQuery = $userQuery;
parent::__construct($id, $module, $config);
}
public function actionIndex($usernameOrEmail, $password)
{
/** @var User $user */
$user = $this->userQuery->whereUsernameOrEmail($usernameOrEmail)->one();
if ($user === null) {
$this->stdout(Yii::t('usuario', 'User is not found')."\n", Console::FG_RED);
} else {
if ($this->make(ResetPasswordService::class, [$password, $user])->run()) {
$this->stdout(Yii::t('usuario', 'Password has been changed')."\n", Console::FG_GREEN);
} else {
$this->stdout(Yii::t('usuario', 'Error occurred while changing password')."\n", Console::FG_RED);
}
}
}
}

View File

@ -0,0 +1,84 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Component;
use Da\User\Contracts\AuthManagerInterface;
use yii\db\Query;
use yii\rbac\DbManager;
class AuthDbManagerComponent extends DbManager implements AuthManagerInterface
{
/**
* @param int|null $type If null will return all auth items
* @param array $excludeItems Items that should be excluded from result array
*
* @return array
*/
public function getItems($type = null, $excludeItems = [])
{
$query = (new Query())->from($this->itemTable);
if ($type !== null) {
$query->where(['type' => $type]);
} else {
$query->orderBy('type');
}
foreach ($excludeItems as $name) {
$query->andWhere('name <> :item', ['item' => $name]);
}
$items = [];
foreach ($query->all($this->db) as $row) {
$items[$row['name']] = $this->populateItem($row);
}
return $items;
}
/**
* Returns both roles and permissions assigned to user.
*
* @param int $userId
*
* @return array
*/
public function getItemsByUser($userId)
{
if (empty($userId)) {
return [];
}
$query = (new Query())
->select('b.*')
->from(['a' => $this->assignmentTable, 'b' => $this->itemTable])
->where('{{a}}.[[item_name]]={{b}}.[[name]]')
->andWhere(['a.user_id' => (string) $userId]);
$roles = [];
foreach ($query->all($this->db) as $row) {
$roles[$row['name']] = $this->populateItem($row);
$roles[$row['name']] = $this->populateItem($row);
}
return $roles;
}
/**
* {@inheritdoc}
*/
public function getItem($name)
{
return parent::getItem($name);
}
}

View File

@ -0,0 +1,27 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Contracts;
use yii\authclient\ClientInterface;
interface AuthClientInterface extends ClientInterface
{
/**
* @return string|null email
*/
public function getEmail();
/**
* @return string|null username
*/
public function getUserName();
}

View File

@ -0,0 +1,39 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Contracts;
use yii\rbac\ManagerInterface;
interface AuthManagerInterface extends ManagerInterface
{
/**
* @param int|null $type
* @param array $excludeItems
*
* @return mixed
*/
public function getItems($type = null, $excludeItems = []);
/**
* @param int $userId
*
* @return mixed
*/
public function getItemsByUser($userId);
/**
* @param string $name
*
* @return mixed
*/
public function getItem($name);
}

View File

@ -0,0 +1,19 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Contracts;
interface MailChangeStrategyInterface extends StrategyInterface
{
const TYPE_INSECURE = 0;
const TYPE_DEFAULT = 1;
const TYPE_SECURE = 2;
}

View File

@ -0,0 +1,20 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Contracts;
interface ServiceInterface
{
/**
* @return bool
*/
public function run();
}

View File

@ -0,0 +1,20 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Contracts;
interface StrategyInterface
{
/**
* @return bool
*/
public function run();
}

View File

@ -0,0 +1,20 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Contracts;
interface ValidatorInterface
{
/**
* @return bool
*/
public function validate();
}

View File

@ -0,0 +1,174 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Controller;
use Da\User\Filter\AccessRuleFilter;
use Da\User\Helper\AuthHelper;
use Da\User\Model\AbstractAuthItem;
use Da\User\Module;
use Da\User\Service\AuthItemEditionService;
use Da\User\Traits\ContainerAwareTrait;
use Da\User\Validator\AjaxRequestModelValidator;
use Yii;
use yii\filters\AccessControl;
use yii\web\Controller;
abstract class AbstractAuthItemController extends Controller
{
use ContainerAwareTrait;
protected $modelClass;
protected $searchModelClass;
protected $authHelper;
/**
* AbstractAuthItemController constructor.
*
* @param string $id
* @param Module $module
* @param AuthHelper $authHelper
* @param array $config
*/
public function __construct($id, Module $module, AuthHelper $authHelper, array $config = [])
{
$this->authHelper = $authHelper;
parent::__construct($id, $module, $config);
}
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'ruleConfig' => [
'class' => AccessRuleFilter::className(),
],
'rules' => [
[
'allow' => true,
'roles' => ['admin'],
],
],
],
];
}
public function actionIndex()
{
$searchModel = $this->make($this->getSearchModelClass());
return $this->render(
'index',
[
'searchModel' => $searchModel,
'dataProvider' => $searchModel->search(Yii::$app->request->get()),
]
);
}
public function actionCreate()
{
/** @var AbstractAuthItem $model */
$model = $this->make($this->getModelClass(), [], ['scenario' => 'create']);
$this->make(AjaxRequestModelValidator::class, [$model])->validate();
if ($model->load(Yii::$app->request->post())) {
if ($this->make(AuthItemEditionService::class, [$model])->run()) {
Yii::$app
->getSession()
->setFlash('success', Yii::t('usuario', 'Authorization item successfully created.'));
return $this->redirect(['index']);
} else {
Yii::$app->getSession()->setFlash('danger', Yii::t('usuario', 'Unable to create authorization item.'));
}
}
return $this->render(
'create',
[
'model' => $model,
'unassignedItems' => $this->authHelper->getUnassignedItems($model),
]
);
}
public function actionUpdate($name)
{
$authItem = $this->getItem($name);
/** @var AbstractAuthItem $model */
$model = $this->make($this->getModelClass(), [], ['scenario' => 'update', 'item' => $authItem]);
$this->make(AjaxRequestModelValidator::class, [$model])->validate();
if ($model->load(Yii::$app->request->post())) {
if ($this->make(AuthItemEditionService::class, [$model])->run()) {
Yii::$app
->getSession()
->setFlash('success', Yii::t('usuario', 'Authorization item successfully updated.'));
return $this->redirect(['index']);
} else {
Yii::$app->getSession()->setFlash('danger', Yii::t('usuario', 'Unable to update authorization item.'));
}
}
return $this->render(
'update',
[
'model' => $model,
'unassignedItems' => $this->authHelper->getUnassignedItems($model),
]
);
}
public function actionDelete($name)
{
$item = $this->getItem($name);
if ($this->authHelper->remove($item)) {
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Authorization item successfully removed.'));
} else {
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Unable to remove authorization item.'));
}
return $this->redirect(['index']);
}
/**
* The fully qualified class name of the model.
*
* @return string
*/
abstract protected function getModelClass();
/**
* The fully qualified class name of the search model.
*
* @return string
*/
abstract protected function getSearchModelClass();
/**
* Returns the an auth item.
*
* @param string $name
*
* @return \yii\rbac\Role|\yii\rbac\Permission|\yii\rbac\Rule
*/
abstract protected function getItem($name);
}

View File

@ -0,0 +1,286 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Controller;
use Da\User\Event\UserEvent;
use Da\User\Factory\MailFactory;
use Da\User\Filter\AccessRuleFilter;
use Da\User\Model\Profile;
use Da\User\Model\User;
use Da\User\Query\UserQuery;
use Da\User\Search\UserSearch;
use Da\User\Service\UserBlockService;
use Da\User\Service\UserConfirmationService;
use Da\User\Service\UserCreateService;
use Da\User\Traits\ContainerAwareTrait;
use Da\User\Validator\AjaxRequestModelValidator;
use Yii;
use yii\base\Module;
use yii\db\ActiveRecord;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;
use yii\helpers\Url;
use yii\web\Controller;
class AdminController extends Controller
{
use ContainerAwareTrait;
/**
* @var UserQuery
*/
protected $userQuery;
/**
* AdminController constructor.
*
* @param string $id
* @param Module $module
* @param UserQuery $userQuery
* @param array $config
*/
public function __construct($id, Module $module, UserQuery $userQuery, array $config = [])
{
$this->userQuery = $userQuery;
parent::__construct($id, $module, $config);
}
/**
* @param \yii\base\Action $action
*
* @return bool
*/
public function beforeAction($action)
{
if (in_array($action->id, ['index', 'update', 'update-profile', 'info', 'assignments'], true)) {
Url::remember('', 'actions-redirect');
}
return parent::beforeAction($action);
}
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::class,
'actions' => [
'delete' => ['post'],
'confirm' => ['post'],
'block' => ['post'],
],
],
'access' => [
'class' => AccessControl::class,
'ruleConfig' => [
'class' => AccessRuleFilter::class,
],
'rules' => [
[
'allow' => true,
'roles' => ['admin'],
],
],
],
];
}
public function actionIndex()
{
$searchModel = $this->make(UserSearch::class);
$dataProvider = $searchModel->search(Yii::$app->request->get());
return $this->render(
'index',
[
'dataProvider' => $dataProvider,
'searchModel' => $searchModel,
]
);
}
public function actionCreate()
{
/** @var User $user */
$user = $this->make(User::class, [], ['scenario' => 'create']);
/** @var UserEvent $event */
$event = $this->make(UserEvent::class, [$user]);
$this->make(AjaxRequestModelValidator::class, [$user])->validate();
if ($user->load(Yii::$app->request->post())) {
$this->trigger(UserEvent::EVENT_BEFORE_CREATE, $event);
$mailService = MailFactory::makeWelcomeMailerService($user);
if ($this->make(UserCreateService::class, [$user, $mailService])->run()) {
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'User has been created'));
$this->trigger(UserEvent::EVENT_AFTER_CREATE, $event);
return $this->redirect(['update', 'id' => $user->id]);
}
}
return $this->render('create', ['user' => $user]);
}
public function actionUpdate($id)
{
$user = $this->userQuery->where(['id' => $id])->one();
$user->setScenario('update');
/** @var UserEvent $event */
$event = $this->make(UserEvent::class, [$user]);
$this->make(AjaxRequestModelValidator::class, [$user])->validate();
if ($user->load(Yii::$app->request->post())) {
$this->trigger(ActiveRecord::EVENT_BEFORE_UPDATE, $event);
if ($user->save()) {
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Account details have been updated'));
$this->trigger(ActiveRecord::EVENT_AFTER_UPDATE, $event);
return $this->refresh();
}
}
return $this->render('_account', ['user' => $user]);
}
public function actionUpdateProfile($id)
{
/** @var User $user */
$user = $this->userQuery->where(['id' => $id])->one();
$profile = $user->profile;
if ($profile === null) {
$profile = $this->make(Profile::class);
$profile->link($user);
}
/** @var UserEvent $event */
$event = $this->make(UserEvent::class, [$user]);
$this->make(AjaxRequestModelValidator::class, [$user])->validate();
if ($profile->load(Yii::$app->request->post())) {
if ($profile->save()) {
$this->trigger(UserEvent::EVENT_BEFORE_PROFILE_UPDATE, $event);
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Profile details have been updated'));
$this->trigger(UserEvent::EVENT_AFTER_PROFILE_UPDATE, $event);
return $this->refresh();
}
}
return $this->render(
'_profile',
[
'user' => $user,
'profile' => $profile,
]
);
}
public function actionInfo($id)
{
/** @var User $user */
$user = $this->userQuery->where(['id' => $id])->one();
return $this->render(
'_info',
[
'user' => $user,
]
);
}
public function actionAssignments($id)
{
/** @var User $user */
$user = $this->userQuery->where(['id' => $id])->one();
return $this->render(
'_assignments',
[
'user' => $user,
'params' => Yii::$app->request->post(),
]
);
}
public function actionConfirm($id)
{
/** @var User $user */
$user = $this->userQuery->where(['id' => $id])->one();
/** @var UserEvent $event */
$event = $this->make(UserEvent::class, [$user]);
$this->trigger(UserEvent::EVENT_BEFORE_CONFIRMATION, $event);
if ($this->make(UserConfirmationService::class, [$user])->run()) {
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'User has been confirmed'));
$this->trigger(UserEvent::EVENT_AFTER_CONFIRMATION, $event);
} else {
Yii::$app->getSession()->setFlash('warning', Yii::t('usuario', 'Unable to confirm user. Please, try again.'));
}
return $this->redirect(Url::previous('actions-redirect'));
}
public function actionDelete($id)
{
if ($id === Yii::$app->user->getId()) {
Yii::$app->getSession()->setFlash('danger', Yii::t('usuario', 'You cannot remove your own account'));
} else {
/** @var User $user */
$user = $this->userQuery->where(['id' => $id])->one();
/** @var UserEvent $event */
$event = $this->make(UserEvent::class, [$user]);
$this->trigger(ActiveRecord::EVENT_BEFORE_DELETE, $event);
if ($user->delete()) {
Yii::$app->getSession()->setFlash('success', \Yii::t('usuario', 'User has been deleted'));
$this->trigger(ActiveRecord::EVENT_AFTER_DELETE, $event);
} else {
Yii::$app->getSession()->setFlash(
'warning',
Yii::t('usuario', 'Unable to delete user. Please, try again later.')
);
}
}
return $this->redirect(['index']);
}
public function actionBlock($id)
{
if ($id === Yii::$app->user->getId()) {
Yii::$app->getSession()->setFlash('danger', Yii::t('usuario', 'You cannot remove your own account'));
} else {
/** @var User $user */
$user = $this->userQuery->where(['id' => $id])->one();
/** @var UserEvent $event */
$event = $this->make(UserEvent::class, [$user]);
if ($this->make(UserBlockService::class, [$user, $event, $this])->run()) {
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'User block status has been updated.'));
} else {
Yii::$app->getSession()->setFlash('danger', Yii::t('usuario', 'Unable to update block status.'));
}
}
return $this->redirect(Url::previous('actions-redirect'));
}
}

View File

@ -0,0 +1,49 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Controller;
use Da\User\Model\Permission;
use Da\User\Search\PermissionSearch;
use yii\web\NotFoundHttpException;
class PermissionController extends AbstractAuthItemController
{
/**
* {@inheritdoc}
*/
protected function getModelClass()
{
return Permission::class;
}
/**
* {@inheritdoc}
*/
protected function getSearchModelClass()
{
return PermissionSearch::class;
}
/**
* {@inheritdoc}
*/
protected function getItem($name)
{
$authItem = $this->authHelper->getPermission($name);
if ($authItem !== null) {
return $authItem;
}
throw new NotFoundHttpException();
}
}

View File

@ -0,0 +1,83 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Controller;
use Da\User\Query\ProfileQuery;
use yii\base\Module;
use yii\filters\AccessControl;
use yii\web\Controller;
use Yii;
use yii\web\NotFoundHttpException;
class ProfileController extends Controller
{
protected $profileQuery;
/**
* ProfileController constructor.
*
* @param string $id
* @param Module $module
* @param ProfileQuery $profileQuery
* @param array $config
*/
public function __construct($id, Module $module, ProfileQuery $profileQuery, array $config = [])
{
$this->profileQuery = $profileQuery;
parent::__construct($id, $module, $config);
}
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'actions' => ['index'],
'roles' => ['@'],
],
[
'allow' => true,
'actions' => ['show'],
'roles' => ['?', '@'],
],
],
],
];
}
public function actionIndex()
{
return $this->redirect(['show', 'id' => Yii::$app->user->getId()]);
}
public function actionShow($id)
{
$profile = $this->profileQuery->whereId($id)->one();
if ($profile === null) {
throw new NotFoundHttpException();
}
return $this->render(
'show',
[
'profile' => $profile,
]
);
}
}

View File

@ -0,0 +1,173 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Controller;
use Da\User\Event\FormEvent;
use Da\User\Event\ResetPasswordEvent;
use Da\User\Factory\MailFactory;
use Da\User\Form\RecoveryForm;
use Da\User\Model\Token;
use Da\User\Query\TokenQuery;
use Da\User\Query\UserQuery;
use Da\User\Service\PasswordRecoveryService;
use Da\User\Service\ResetPasswordService;
use Da\User\Traits\ContainerAwareTrait;
use Da\User\Validator\AjaxRequestModelValidator;
use Yii;
use Da\User\Module;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
class RecoveryController extends Controller
{
use ContainerAwareTrait;
protected $userQuery;
protected $tokenQuery;
/**
* RecoveryController constructor.
*
* @param string $id
* @param Module $module
* @param UserQuery $userQuery
* @param TokenQuery $tokenQuery
* @param array $config
*/
public function __construct($id, Module $module, UserQuery $userQuery, TokenQuery $tokenQuery, array $config = [])
{
$this->userQuery = $userQuery;
$this->tokenQuery = $tokenQuery;
parent::__construct($id, $module, $config);
}
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'actions' => ['request', 'reset'],
'roles' => ['?'],
],
],
],
];
}
/**
* Displays / handles user password recovery request.
*
* @return string
*
* @throws NotFoundHttpException
*/
public function actionRequest()
{
if (!$this->module->allowPasswordRecovery) {
throw new NotFoundHttpException();
}
/** @var RecoveryForm $form */
$form = $this->make(RecoveryForm::class, [], ['scenario' => RecoveryForm::SCENARIO_REQUEST]);
$event = $this->make(FormEvent::class, [$form]);
$this->make(AjaxRequestModelValidator::class, $form)->validate();
if ($form->load(Yii::$app->request->post())) {
$this->trigger(FormEvent::EVENT_BEFORE_REQUEST, $event);
$mailService = MailFactory::makeRecoveryMailerService($form->email);
if ($this->make(PasswordRecoveryService::class, [$form->email, $mailService])->run()) {
$this->trigger(FormEvent::EVENT_AFTER_REQUEST, $event);
return $this->render(
'/shared/message',
[
'title' => Yii::t('usuario', 'Recovery message sent'),
'module' => $this->module,
]
);
}
}
return $this->render('request', ['model' => $form]);
}
/**
* Displays / handles user password reset.
*
* @param $id
* @param $code
*
* @return string
*
* @throws NotFoundHttpException
*/
public function actionReset($id, $code)
{
if (!$this->module->allowPasswordRecovery) {
throw new NotFoundHttpException();
}
/** @var Token $token */
$token = $this->tokenQuery->whereUserId($id)->whereCode($code)->whereIsRecoveryType()->one();
/** @var ResetPasswordEvent $event */
$event = $this->make(ResetPasswordEvent::class, [$token]);
$this->trigger(ResetPasswordEvent::EVENT_BEFORE_TOKEN_VALIDATE, $event);
if ($token === null || $token->getIsExpired() || $token->user === null) {
Yii::$app->session->setFlash(
'danger',
Yii::t('usuario', 'Recovery link is invalid or expired. Please try requesting a new one.')
);
return $this->render(
'/shared/message',
[
'title' => Yii::t('usuario', 'Invalid or expired link'),
'module' => $this->module,
]
);
}
/** @var RecoveryForm $form */
$form = $this->make(RecoveryForm::class, [], ['scenario' => RecoveryForm::SCENARIO_RESET]);
$event = $event->updateForm($form);
$this->make(AjaxRequestModelValidator::class, [$form])->validate();
if ($form->load(Yii::$app->getRequest()->post())) {
if ($this->make(ResetPasswordService::class, [$form->password, $token->user])->run()) {
$this->trigger(ResetPasswordEvent::EVENT_AFTER_RESET, $event);
return $this->render(
'/shared/message',
[
'title' => Yii::t('usuario', 'Password has been changed'),
'module' => $this->module,
]
);
}
}
return $this->render('reset', ['model' => $form]);
}
}

View File

@ -0,0 +1,267 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Controller;
use Da\User\Event\FormEvent;
use Da\User\Event\SocialNetworkConnectEvent;
use Da\User\Event\UserEvent;
use Da\User\Factory\MailFactory;
use Da\User\Form\RegistrationForm;
use Da\User\Form\ResendForm;
use Da\User\Model\SocialNetworkAccount;
use Da\User\Model\User;
use Da\User\Query\SocialNetworkAccountQuery;
use Da\User\Query\UserQuery;
use Da\User\Service\AccountConfirmationService;
use Da\User\Service\ResendConfirmationService;
use Da\User\Service\UserConfirmationService;
use Da\User\Service\UserCreateService;
use Da\User\Service\UserRegisterService;
use Da\User\Traits\ContainerAwareTrait;
use Da\User\Validator\AjaxRequestModelValidator;
use Yii;
use yii\base\Module;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
class RegistrationController extends Controller
{
use ContainerAwareTrait;
protected $userQuery;
protected $socialNetworkAccountQuery;
/**
* RegistrationController constructor.
*
* @param string $id
* @param Module $module
* @param UserQuery $userQuery
* @param SocialNetworkAccountQuery $socialNetworkAccountQuery
* @param array $config
*/
public function __construct(
$id,
Module $module,
UserQuery $userQuery,
SocialNetworkAccountQuery $socialNetworkAccountQuery,
array $config = []
) {
$this->userQuery = $userQuery;
$this->socialNetworkAccountQuery = $socialNetworkAccountQuery;
parent::__construct($id, $module, $config);
}
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'actions' => ['register', 'connect'],
'roles' => ['?'],
],
[
'allow' => true,
'actions' => ['confirm', 'resend'],
'roles' => ['?', '@'],
],
],
],
];
}
public function actionRegister()
{
if (!$this->module->enableRegistration) {
throw new NotFoundHttpException();
}
/** @var RegistrationForm $form */
$form = $this->make(RegistrationForm::class);
/** @var FormEvent $event */
$event = $this->make(FormEvent::class, [$form]);
$this->make(AjaxRequestModelValidator::class, [$form])->validate();
if ($form->load(Yii::$app->request->post()) && $form->validate()) {
$this->trigger(UserEvent::EVENT_BEFORE_REGISTER, $event);
$user = $this->make(User::class, [], $form->attributes);
$user->setScenario('register');
$mailService = MailFactory::makeWelcomeMailerService($user);
if ($this->make(UserRegisterService::class, [$user, $mailService])->run()) {
Yii::$app->session->setFlash(
'info',
Yii::t(
'usuario',
'Your account has been created and a message with further instructions has been sent to your email'
)
);
return $this->render(
'/shared/message',
[
'title' => Yii::t('usuario', 'Your account has been created'),
'module' => $this->module,
]
);
}
}
return $this->render(
'register',
[
'model' => $form,
'module' => $this->module,
]
);
}
public function actionConnect($code)
{
/** @var SocialNetworkAccount $account */
$account = $this->socialNetworkAccountQuery->whereCode($code)->one();
if ($account === null || $account->getIsConnected()) {
throw new NotFoundHttpException();
}
/** @var User $user */
$user = $this->make(
User::class,
['scenario' => 'connect', 'username' => $account->username, 'email' => $account->email]
);
$event = $this->make(SocialNetworkConnectEvent::class, [$user, $account]);
$this->make(AjaxRequestModelValidator::class, [$user])->validate();
if ($user->load(Yii::$app->request->post())) {
$this->trigger(SocialNetworkConnectEvent::EVENT_BEFORE_CONNECT, $event);
$mailService = MailFactory::makeWelcomeMailerService($user);
if ($this->make(UserCreateService::class, [$user, $mailService])->run()) {
$account->connect($user);
$this->trigger(SocialNetworkConnectEvent::EVENT_AFTER_CONNECT, $event);
Yii::$app->user->login($user, $this->module->rememberLoginLifespan);
return $this->goBack();
}
}
return $this->render(
'connect',
[
'model' => $user,
'account' => $account,
]
);
}
public function actionConfirm($id, $code)
{
$user = $this->userQuery->whereId($id)->one();
if ($user === null || $this->module->enableEmailConfirmation === false) {
throw new NotFoundHttpException();
}
/** @var UserEvent $event */
$event = $this->make(UserEvent::class, [$user]);
$userConfirmationService = $this->make(UserConfirmationService::class, [$user]);
$this->trigger(UserEvent::EVENT_BEFORE_CONFIRMATION, $event);
if ($this->make(AccountConfirmationService::class, [$code, $user, $userConfirmationService])->run()) {
Yii::$app->user->login($user, $this->module->rememberLoginLifespan);
Yii::$app->session->setFlash('success', Yii::t('usuario', 'Thank you, registration is now complete.'));
$this->trigger(UserEvent::EVENT_AFTER_CONFIRMATION, $event);
} else {
Yii::$app->session->setFlash(
'danger',
Yii::t('usuario', 'The confirmation link is invalid or expired. Please try requesting a new one.')
);
}
return $this->render(
'/shared/message',
[
'title' => Yii::t('usuario', 'Account confirmation'),
'module' => $this->module,
]
);
}
public function actionResend()
{
if ($this->module->enableEmailConfirmation === false) {
throw new NotFoundHttpException();
}
/** @var ResendForm $form */
$form = $this->make(ResendForm::class);
$event = $this->make(FormEvent::class, [$form]);
$this->make(AjaxRequestModelValidator::class, [$form])->validate();
if ($form->load(Yii::$app->request->post()) && $form->validate()) {
/** @var User $user */
$user = $this->userQuery->whereEmail($form->email)->one();
$success = true;
if ($user !== null) {
$this->trigger(FormEvent::EVENT_BEFORE_RESEND, $event);
$mailService = MailFactory::makeConfirmationMailerService($user);
if ($success = $this->make(ResendConfirmationService::class, [$user, $mailService])->run()) {
$this->trigger(FormEvent::EVENT_AFTER_RESEND, $event);
Yii::$app->session->setFlash(
'info',
Yii::t(
'usuario',
'A message has been sent to your email address. '.
'It contains a confirmation link that you must click to complete registration.'
)
);
}
}
if ($user === null || $success === false) {
Yii::$app->session->setFlash(
'danger',
Yii::t(
'usuario',
'We couldn\'t re-send the mail to confirm your address. '.
'Please, verify is the correct email or if it has been confirmed already.'
)
);
}
return $this->render('/shared/message', [
'title' => $success
? Yii::t('usuario', 'A new confirmation link has been sent')
: Yii::t('usuario', 'Unable to send confirmation link'),
'module' => $this->module,
]);
}
return $this->render(
'resend',
[
'model' => $form,
]
);
}
}

View File

@ -0,0 +1,49 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Controller;
use Da\User\Model\Role;
use Da\User\Search\RoleSearch;
use yii\web\NotFoundHttpException;
class RoleController extends AbstractAuthItemController
{
/**
* {@inheritdoc}
*/
protected function getModelClass()
{
return Role::class;
}
/**
* {@inheritdoc}
*/
protected function getSearchModelClass()
{
return RoleSearch::class;
}
/**
* {@inheritdoc}
*/
protected function getItem($name)
{
$authItem = $this->authHelper->getRole($name);
if ($authItem !== null) {
return $authItem;
}
throw new NotFoundHttpException();
}
}

View File

@ -0,0 +1,168 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Controller;
use Da\User\Contracts\AuthClientInterface;
use Da\User\Event\FormEvent;
use Da\User\Event\UserEvent;
use Da\User\Form\LoginForm;
use Da\User\Query\SocialNetworkAccountQuery;
use Da\User\Service\SocialNetworkAccountConnectService;
use Da\User\Service\SocialNetworkAuthenticateService;
use Da\User\Traits\ContainerAwareTrait;
use Yii;
use yii\authclient\AuthAction;
use yii\base\Module;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;
use yii\web\Controller;
use yii\web\Response;
use yii\widgets\ActiveForm;
class SecurityController extends Controller
{
use ContainerAwareTrait;
protected $socialNetworkAccountQuery;
/**
* SecurityController constructor.
*
* @param string $id
* @param Module $module
* @param SocialNetworkAccountQuery $socialNetworkAccountQuery
* @param array $config
*/
public function __construct(
$id,
Module $module,
SocialNetworkAccountQuery $socialNetworkAccountQuery,
array $config = []
) {
$this->socialNetworkAccountQuery = $socialNetworkAccountQuery;
parent::__construct($id, $module, $config);
}
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'actions' => ['login', 'auth', 'blocked'],
'roles' => ['?'],
],
[
'allow' => true,
'actions' => ['login', 'auth', 'logout'],
'roles' => ['@'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}
/**
* {@inheritdoc}
*/
public function actions()
{
return [
'auth' => [
'class' => AuthAction::className(),
// if user is not logged in, will try to log him in, otherwise
// will try to connect social account to user.
'successCallback' => Yii::$app->user->isGuest
? [$this, 'authenticate']
: [$this, 'connect'],
],
];
}
/**
* Controller action responsible for handling login page and actions.
* @return string|Response
*/
public function actionLogin()
{
if (!Yii::$app->user->getIsGuest()) {
return $this->goHome();
}
/** @var LoginForm $form */
$form = $this->make(LoginForm::class);
/** @var FormEvent $event */
$event = $this->make(FormEvent::class, [$form]);
if (Yii::$app->request->isAjax && $form->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($form);
}
if ($form->load(Yii::$app->request->post())) {
$this->trigger(FormEvent::EVENT_BEFORE_LOGIN, $event);
if ($form->login()) {
$this->trigger(FormEvent::EVENT_AFTER_LOGIN, $event);
return $this->goBack();
}
}
return $this->render(
'login',
[
'model' => $form,
'module' => $this->module,
]
);
}
public function actionLogout()
{
$event = $this->make(UserEvent::class, [Yii::$app->getUser()->getIdentity()]);
$this->trigger(UserEvent::EVENT_BEFORE_LOGOUT, $event);
if (Yii::$app->getUser()->logout()) {
$this->trigger(UserEvent::EVENT_AFTER_LOGOUT, $event);
}
return $this->goHome();
}
public function authenticate(AuthClientInterface $client)
{
$this->make(SocialNetworkAuthenticateService::class, [$this, $this->action, $client])->run();
}
public function connect(AuthClientInterface $client)
{
if (Yii::$app->user->isGuest) {
Yii::$app->session->setFlash('danger', Yii::t('usuario', 'Something went wrong'));
return;
}
$this->make(SocialNetworkAccountConnectService::class, [$this, $client])->run();
}
}

View File

@ -0,0 +1,229 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Controller;
use Da\User\Contracts\MailChangeStrategyInterface;
use Da\User\Event\FormEvent;
use Da\User\Event\ProfileEvent;
use Da\User\Event\SocialNetworkConnectEvent;
use Da\User\Event\UserEvent;
use Da\User\Form\SettingsForm;
use Da\User\Model\Profile;
use Da\User\Model\SocialNetworkAccount;
use Da\User\Model\User;
use Da\User\Module;
use Da\User\Query\ProfileQuery;
use Da\User\Query\SocialNetworkAccountQuery;
use Da\User\Query\UserQuery;
use Da\User\Service\EmailChangeService;
use Da\User\Traits\ContainerAwareTrait;
use Da\User\Validator\AjaxRequestModelValidator;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;
use yii\web\Controller;
use Yii;
use yii\web\ForbiddenHttpException;
use yii\web\NotFoundHttpException;
class SettingsController extends Controller
{
use ContainerAwareTrait;
protected $profileQuery;
protected $userQuery;
protected $socialNetworkAccountQuery;
/**
* {@inheritdoc}
*/
public $defaultAction = 'profile';
/**
* SettingsController constructor.
*
* @param string $id
* @param Module $module
* @param ProfileQuery $profileQuery
* @param UserQuery $userQuery
* @param SocialNetworkAccountQuery $socialNetworkAccountQuery
* @param array $config
*/
public function __construct(
$id,
Module $module,
ProfileQuery $profileQuery,
UserQuery $userQuery,
SocialNetworkAccountQuery $socialNetworkAccountQuery,
array $config = []
) {
$this->profileQuery = $profileQuery;
$this->userQuery = $userQuery;
$this->socialNetworkAccountQuery = $socialNetworkAccountQuery;
parent::__construct($id, $module, $config);
}
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'disconnect' => ['post'],
'delete' => ['post'],
],
],
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'actions' => ['profile', 'account', 'networks', 'disconnect', 'delete'],
'roles' => ['@'],
],
[
'allow' => true,
'actions' => ['confirm'],
'roles' => ['?', '@'],
],
],
],
];
}
public function actionProfile()
{
$profile = $this->profileQuery->whereId(Yii::$app->user->identity->getId())->one();
if ($profile === null) {
$profile = $this->make(Profile::class);
$profile->link('user', Yii::$app->user->identity);
}
$event = $this->make(ProfileEvent::class, [$profile]);
$this->make(AjaxRequestModelValidator::class, [$profile])->validate();
if ($profile->load(Yii::$app->request->post())) {
$this->trigger(UserEvent::EVENT_BEFORE_PROFILE_UPDATE, $event);
if ($profile->save()) {
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Your profile has been updated'));
$this->trigger(UserEvent::EVENT_AFTER_PROFILE_UPDATE, $event);
return $this->refresh();
}
}
return $this->render(
'profile',
[
'model' => $profile,
]
);
}
public function actionAccount()
{
/** @var SettingsForm $form */
$form = $this->make(SettingsForm::class);
$event = $this->make(FormEvent::class, [$form]);
$this->make(AjaxRequestModelValidator::class, [$form])->validate();
if ($form->load(Yii::$app->request->post())) {
$this->trigger(UserEvent::EVENT_BEFORE_ACCOUNT_UPDATE, $event);
if ($form->save()) {
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Your account details have been updated'));
$this->trigger(UserEvent::EVENT_AFTER_ACCOUNT_UPDATE, $event);
return $this->refresh();
}
}
return $this->render(
'account',
[
'model' => $form,
]
);
}
public function actionConfirm($id, $code)
{
$user = $this->userQuery->whereId($id)->one();
if ($user === null || $this->module->emailChangeStrategy == MailChangeStrategyInterface::TYPE_INSECURE) {
throw new NotFoundHttpException();
}
$event = $this->make(UserEvent::class, [$user]);
$this->trigger(UserEvent::EVENT_BEFORE_CONFIRMATION, $event);
if ($this->make(EmailChangeService::class, [$code, $user])->run()) {
$this->trigger(UserEvent::EVENT_AFTER_CONFIRMATION, $event);
}
return $this->redirect(['account']);
}
public function actionNetworks()
{
return $this->render(
'networks',
[
'user' => Yii::$app->user->identity,
]
);
}
public function actionDisconnect($id)
{
/** @var SocialNetworkAccount $account */
$account = $this->socialNetworkAccountQuery->whereId($id)->one();
if ($account === null) {
throw new NotFoundHttpException();
}
if ($account->user_id != Yii::$app->user->id) {
throw new ForbiddenHttpException();
}
$event = $this->make(SocialNetworkConnectEvent::class, [Yii::$app->user->identity, $account]);
$this->trigger(SocialNetworkConnectEvent::EVENT_BEFORE_DISCONNECT, $event);
$account->delete();
$this->trigger(SocialNetworkConnectEvent::EVENT_AFTER_DISCONNECT, $event);
return $this->redirect(['networks']);
}
public function actionDelete()
{
if (!$this->module->allowAccountDelete) {
throw new NotFoundHttpException(\Yii::t('usuario', 'Not found'));
}
/** @var User $user */
$user = Yii::$app->user->identity;
$event = $this->make(UserEvent::class, [$user]);
Yii::$app->user->logout();
$this->trigger(UserEvent::EVENT_BEFORE_DELETE, $event);
$user->delete();
$this->trigger(UserEvent::EVENT_AFTER_DELETE, $event);
Yii::$app->session->setFlash('info', Yii::t('usuario', 'Your account has been completely deleted'));
return $this->goHome();
}
}

View File

@ -0,0 +1,38 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Event;
use yii\base\Event;
use yii\base\Model;
class FormEvent extends Event
{
const EVENT_BEFORE_REQUEST = 'beforeRequest';
const EVENT_AFTER_REQUEST = 'afterRequest';
const EVENT_BEFORE_RESEND = 'beforeResend';
const EVENT_AFTER_RESEND = 'afterResend';
const EVENT_BEFORE_LOGIN = 'beforeLogin';
const EVENT_AFTER_LOGIN = 'afterLogin';
protected $form;
public function __construct(Model $form, array $config = [])
{
$this->form = $form;
parent::__construct($config);
}
public function getForm()
{
return $this->form;
}
}

View File

@ -0,0 +1,32 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Event;
use Da\User\Model\Profile;
use yii\base\Event;
class ProfileEvent extends Event
{
protected $profile;
public function __construct(Profile $profile, array $config = [])
{
$this->profile = $profile;
return parent::__construct($config);
}
public function getProfile()
{
return $this->profile;
}
}

View File

@ -0,0 +1,50 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Event;
use Da\User\Form\RecoveryForm;
use Da\User\Model\Token;
use yii\base\Event;
class ResetPasswordEvent extends Event
{
const EVENT_BEFORE_TOKEN_VALIDATE = 'beforeTokenValidate';
const EVENT_AFTER_TOKEN_VALIDATE = 'afterTokenValidate';
const EVENT_BEFORE_RESET = 'beforeReset';
const EVENT_AFTER_RESET = 'afterReset';
protected $form;
protected $token;
public function __construct(Token $token, RecoveryForm $form, array $config = [])
{
$this->form = $form;
$this->token = $token;
parent::__construct($config);
}
public function getForm()
{
return $this->form;
}
public function getToken()
{
return $this->token;
}
public function updateForm(RecoveryForm $form)
{
return new static($this->getToken(), $form);
}
}

View File

@ -0,0 +1,45 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Event;
use Da\User\Model\SocialNetworkAccount;
use yii\authclient\ClientInterface;
use yii\base\Event;
class SocialNetworkAuthEvent extends Event
{
const EVENT_BEFORE_AUTHENTICATE = 'beforeAuthenticate';
const EVENT_AFTER_AUTHENTICATE = 'afterAuthenticate';
const EVENT_BEFORE_CONNECT = 'beforeConnect';
const EVENT_AFTER_CONNECT = 'afterConnect';
protected $client;
protected $account;
public function __construct(SocialNetworkAccount $account, ClientInterface $client, $config = [])
{
$this->account = $account;
$this->client = $client;
parent::__construct($config);
}
public function getClient()
{
return $this->client;
}
public function getAccount()
{
return $this->account;
}
}

View File

@ -0,0 +1,45 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Event;
use Da\User\Model\SocialNetworkAccount;
use Da\User\Model\User;
use yii\base\Event;
class SocialNetworkConnectEvent extends Event
{
const EVENT_BEFORE_CONNECT = 'beforeConnect';
const EVENT_AFTER_CONNECT = 'afterConnect';
const EVENT_BEFORE_DISCONNECT = 'beforeDisconnect';
const EVENT_AFTER_DISCONNECT = 'afterDisconnect';
protected $user;
protected $account;
public function __construct(User $user, SocialNetworkAccount $account, $config = [])
{
$this->user = $user;
$this->account = $account;
parent::__construct($config);
}
public function getUser()
{
return $this->user;
}
public function getAccount()
{
return $this->account;
}
}

View File

@ -0,0 +1,50 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Event;
use Da\User\Model\User;
use yii\base\Event;
class UserEvent extends Event
{
const EVENT_BEFORE_CREATE = 'beforeCreate';
const EVENT_AFTER_CREATE = 'afterCreate';
const EVENT_BEFORE_DELETE = 'beforeDelete';
const EVENT_AFTER_DELETE = 'afterDelete';
const EVENT_BEFORE_REGISTER = 'beforeRegister';
const EVENT_AFTER_REGISTER = 'afterRegister';
const EVENT_BEFORE_ACCOUNT_UPDATE = 'beforeAccountUpdate';
const EVENT_AFTER_ACCOUNT_UPDATE = 'afterAccountUpdate';
const EVENT_BEFORE_PROFILE_UPDATE = 'beforeProfileUpdate';
const EVENT_AFTER_PROFILE_UPDATE = 'afterProfileUpdate';
const EVENT_BEFORE_CONFIRMATION = 'beforeConfirmation';
const EVENT_AFTER_CONFIRMATION = 'afterConfirmation';
const EVENT_BEFORE_UNBLOCK = 'beforeUnblock';
const EVENT_AFTER_UNBLOCK = 'afterUnblock';
const EVENT_BEFORE_BLOCK = 'beforeBlock';
const EVENT_AFTER_BLOCK = 'afterBlock';
const EVENT_BEFORE_LOGOUT = 'beforeLogout';
const EVENT_AFTER_LOGOUT = 'afterLogout';
protected $user;
public function __construct(User $user, array $config = [])
{
$this->user = $user;
parent::__construct($config);
}
public function getUser()
{
return $this->user;
}
}

View File

@ -0,0 +1,61 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Factory;
use Yii;
use yii\rbac\Item;
use Exception;
class AuthItemFactory
{
protected static $map = [
Item::TYPE_ROLE => 'makeRole',
Item::TYPE_PERMISSION => 'makePermission',
];
/**
* @param $name
*
* @return \yii\rbac\Permission
*/
public static function makePermission($name)
{
return Yii::$app->getAuthManager()->createPermission($name);
}
/**
* @param $name
*
* @return \yii\rbac\Role
*/
public static function makeRole($name)
{
return Yii::$app->getAuthManager()->createRole($name);
}
/**
* @param $type
* @param $name
*
* @return \yii\rbac\Role|\yii\rbac\Permission
*
* @throws Exception
*/
public static function makeByType($type, $name)
{
if (array_key_exists($type, self::$map)) {
return call_user_func([self::class, self::$map[$type]], $name);
}
throw new Exception('Unknown strategy type');
}
}

View File

@ -0,0 +1,76 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Factory;
use Da\User\Contracts\MailChangeStrategyInterface;
use Da\User\Form\SettingsForm;
use Da\User\Strategy\DefaultEmailChangeStrategy;
use Da\User\Strategy\InsecureEmailChangeStrategy;
use Da\User\Strategy\SecureEmailChangeStrategy;
use Yii;
use Exception;
class EmailChangeStrategyFactory
{
protected static $map = [
MailChangeStrategyInterface::TYPE_INSECURE => InsecureEmailChangeStrategy::class,
MailChangeStrategyInterface::TYPE_DEFAULT => DefaultEmailChangeStrategy::class,
MailChangeStrategyInterface::TYPE_SECURE => SecureEmailChangeStrategy::class,
];
/**
* @param $strategy
* @param SettingsForm $form
*
* @return MailChangeStrategyInterface
*
* @throws Exception
*/
public static function makeByStrategyType($strategy, SettingsForm $form)
{
if (array_key_exists($strategy, static::$map)) {
return Yii::$container->get(static::$map[$strategy], [$form]);
}
throw new Exception('Unknown strategy type');
}
/**
* @param SettingsForm $form
*
* @return DefaultEmailChangeStrategy
*/
public static function makeDefaultEmailChangeStrategy(SettingsForm $form)
{
return Yii::$container->get(static::$map[MailChangeStrategyInterface::TYPE_DEFAULT], [$form]);
}
/**
* @param SettingsForm $form
*
* @return InsecureEmailChangeStrategy
*/
public static function makeInsecureEmailChangeStrategy(SettingsForm $form)
{
return Yii::$container->get(static::$map[MailChangeStrategyInterface::TYPE_INSECURE], [$form]);
}
/**
* @param SettingsForm $form
*
* @return SecureEmailChangeStrategy
*/
public static function makeSecureEmailChangeStrategy(SettingsForm $form)
{
return Yii::$container->get(static::$map[MailChangeStrategyInterface::TYPE_SECURE], [$form]);
}
}

View File

@ -0,0 +1,125 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Factory;
use Da\User\Model\Token;
use Da\User\Model\User;
use Da\User\Module;
use Da\User\Service\MailService;
use Yii;
class MailFactory
{
/**
* @param User $user
*
* @return MailService
*/
public static function makeWelcomeMailerService(User $user)
{
/** @var Module $module */
$module = Yii::$app->getModule('user');
$to = $user->email;
$from = $module->mailParams['fromEmail'];
$subject = $module->mailParams['welcomeMailSubject'];
$params = [
'user' => $user,
'token' => null,
'module' => $module,
'showPassword' => false,
];
return static::makeMailerService($from, $to, $subject, 'welcome', $params);
}
/**
* @param string $email
* @param Token $token
*
* @return MailService
*/
public static function makeRecoveryMailerService($email, Token $token = null)
{
/** @var Module $module */
$module = Yii::$app->getModule('user');
$to = $email;
$from = $module->mailParams['fromEmail'];
$subject = $module->mailParams['recoveryMailSubject'];
$params = [
'user' => $token && $token->user ? $token->user : null,
'token' => $token,
];
return static::makeMailerService($from, $to, $subject, 'recovery', $params);
}
/**
* @param User $user
* @param Token|null $token
*
* @return MailService
*/
public static function makeConfirmationMailerService(User $user, Token $token = null)
{
/** @var Module $module */
$module = Yii::$app->getModule('user');
$to = $user->email;
$from = $module->mailParams['fromEmail'];
$subject = $module->mailParams['confirmationMailSubject'];
$params = [
'user' => $token && $token->user ? $token->user : null,
'token' => $token,
];
return static::makeMailerService($from, $to, $subject, 'recovery', $params);
}
/**
* @param User $user
* @param Token $token
*
* @return MailService
*/
public static function makeReconfirmationMailerService(User $user, Token $token)
{
/** @var Module $module */
$module = Yii::$app->getModule('user');
$to = $token->type === Token::TYPE_CONFIRM_NEW_EMAIL
? $user->unconfirmed_email
: $user->email;
$from = $module->mailParams['fromEmail'];
$subject = $module->mailParams['reconfirmationMailSubject'];
$params = [
'user' => $token && $token->user ? $token->user : null,
'token' => $token,
];
return static::makeMailerService($from, $to, $subject, 'recovery', $params);
}
/**
* Builds a MailerService.
*
* @param string $from
* @param string $to
* @param string $subject
* @param string $view
* @param array $params
*
* @return MailService
*/
public static function makeMailerService($from, $to, $subject, $view, array $params = [])
{
return Yii::$container->get(MailService::class, [$from, $to, $subject, $view, $params, Yii::$app->getMailer()]);
}
}

View File

@ -0,0 +1,85 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Factory;
use Da\User\Model\Token;
use Yii;
class TokenFactory
{
/**
* @param $userId
*
* @return Token
*/
public static function makeConfirmationToken($userId)
{
$token = self::make($userId, Token::TYPE_CONFIRMATION);
$token->save(false);
return $token;
}
/**
* @param $userId
*
* @return Token
*/
public static function makeConfirmNewMailToken($userId)
{
$token = self::make($userId, Token::TYPE_CONFIRM_NEW_EMAIL);
$token->save(false);
return $token;
}
/**
* @param $userId
*
* @return Token
*/
public static function makeConfirmOldMailToken($userId)
{
$token = self::make($userId, Token::TYPE_CONFIRM_OLD_EMAIL);
$token->save(false);
return $token;
}
/**
* @param $userId
*
* @return Token
*/
public static function makeRecoveryToken($userId)
{
$token = self::make($userId, Token::TYPE_RECOVERY);
$token->save(false);
return $token;
}
/**
* @param $userId
* @param $type
*
* @return Token
*/
protected static function make($userId, $type)
{
return Yii::createObject(['class' => Token::class, 'user_id' => $userId, 'type' => $type]);
}
}

View File

@ -0,0 +1,52 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Filter;
use Da\User\Model\User;
use yii\filters\AccessRule;
class AccessRuleFilter extends AccessRule
{
/**
* {@inheritdoc}
* */
protected function matchRole($user)
{
if (empty($this->roles)) {
return true;
}
foreach ($this->roles as $role) {
if ($role === '?') {
if ($user->getIsGuest()) {
return true;
}
} elseif ($role === '@') {
if (!$user->getIsGuest()) {
return true;
}
} elseif ($role === 'admin') {
/** @var User $identity */
$identity = $user->getIdentity();
if (!$user->getIsGuest() && $identity->getIsAdmin()) {
return true;
}
} elseif ($user->can($role)) {
return true;
}
}
return false;
}
}

140
src/User/Form/LoginForm.php Normal file
View File

@ -0,0 +1,140 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Form;
use Da\User\Helper\SecurityHelper;
use Da\User\Model\User;
use Da\User\Query\UserQuery;
use Da\User\Traits\ModuleAwareTrait;
use Yii;
use yii\base\Model;
class LoginForm extends Model
{
use ModuleAwareTrait;
/**
* @var string login User's email or username
*/
public $login;
/**
* @var string User's password
*/
public $password;
/**
* @var bool whether to remember User's login
*/
public $rememberMe = false;
/**
* @var User
*/
protected $user;
/**
* @var UserQuery
*/
protected $query;
/**
* @var SecurityHelper
*/
protected $securityHelper;
/**
* @param UserQuery $query
* @param SecurityHelper $securityHelper
* @param array $config
*/
public function __construct(UserQuery $query, SecurityHelper $securityHelper, $config = [])
{
$this->query = $query;
$this->securityHelper = $securityHelper;
parent::__construct($config);
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'login' => Yii::t('usuario', 'Login'),
'password' => Yii::t('usuario', 'Password'),
'rememberMe' => Yii::t('usuario', 'Remember me next time'),
];
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
'requiredFields' => [['login', 'password'], 'required'],
'loginTrim' => ['login', 'trim'],
'passwordValidate' => [
'password',
function ($attribute) {
if ($this->user === null ||
!$this->securityHelper->validatePassword($this->password, $this->user->password_hash)
) {
$this->addError($attribute, Yii::t('usuario', 'Invalid login or password'));
}
},
],
'confirmationValidate' => [
'login',
function ($attribute) {
if ($this->user !== null) {
$module = $this->getModule();
$confirmationRequired = $module->enableEmailConfirmation && !$module->allowUnconfirmedEmailLogin;
if ($confirmationRequired && !$this->user->getIsConfirmed()) {
$this->addError($attribute, Yii::t('usuario', 'You need to confirm your email address'));
}
if ($this->user->getIsBlocked()) {
$this->addError($attribute, Yii::t('usuario', 'Your account has been blocked'));
}
}
},
],
'rememberMe' => ['rememberMe', 'boolean'],
];
}
/**
* Validates form and logs the user in.
*
* @return bool whether the user is logged in successfully
*/
public function login()
{
if ($this->validate()) {
$duration = $this->rememberMe ? $this->module->rememberLoginLifespan : 0;
return Yii::$app->getUser()->login($this->user, $duration);
} else {
return false;
}
}
/**
* {@inheritdoc}
*/
public function beforeValidate()
{
if (parent::beforeValidate()) {
$this->user = $this->query->whereUsernameOrEmail(trim($this->login))->one();
return true;
}
return false;
}
}

View File

@ -0,0 +1,84 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Form;
use Da\User\Query\UserQuery;
use Da\User\Traits\ContainerAwareTrait;
use Yii;
use yii\base\Model;
class RecoveryForm extends Model
{
use ContainerAwareTrait;
const SCENARIO_REQUEST = 'request';
const SCENARIO_RESET = 'reset';
/**
* @var string User's email
*/
public $email;
/**
* @var string User's password
*/
public $password;
/**
* @var UserQuery
*/
protected $query;
/**
* @param UserQuery $query
* @param array $config
*/
public function __construct(UserQuery $query, array $config = [])
{
$this->query = $query;
parent::__construct($config);
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'email' => Yii::t('usuario', 'Email'),
'password' => Yii::t('usuario', 'Password'),
];
}
/**
* {@inheritdoc}
*/
public function scenarios()
{
return [
self::SCENARIO_REQUEST => ['email'],
self::SCENARIO_RESET => ['password'],
];
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
'emailTrim' => ['email', 'filter', 'filter' => 'trim'],
'emailRequired' => ['email', 'required'],
'emailPattern' => ['email', 'email'],
'passwordRequired' => ['password', 'required'],
'passwordLength' => ['password', 'string', 'max' => 72, 'min' => 6],
];
}
}

View File

@ -0,0 +1,85 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Form;
use Da\User\Model\User;
use Da\User\Traits\ContainerAwareTrait;
use Da\User\Traits\ModuleAwareTrait;
use Yii;
use yii\base\Model;
class RegistrationForm extends Model
{
use ModuleAwareTrait;
use ContainerAwareTrait;
/**
* @var string User email address
*/
public $email;
/**
* @var string Username
*/
public $username;
/**
* @var string Password
*/
public $password;
/**
* {@inheritdoc}
*/
public function rules()
{
/** @var User $user */
$user = $this->getClassMap()->get(User::class);
return [
// username rules
'usernameLength' => ['username', 'string', 'min' => 3, 'max' => 255],
'usernameTrim' => ['username', 'filter', 'filter' => 'trim'],
'usernamePattern' => ['username', 'match', 'pattern' => '/^[-a-zA-Z0-9_\.@]+$/'],
'usernameRequired' => ['username', 'required'],
'usernameUnique' => [
'username',
'unique',
'targetClass' => $user,
'message' => Yii::t('usuario', 'This username has already been taken'),
],
// email rules
'emailTrim' => ['email', 'filter', 'filter' => 'trim'],
'emailRequired' => ['email', 'required'],
'emailPattern' => ['email', 'email'],
'emailUnique' => [
'email',
'unique',
'targetClass' => $user,
'message' => Yii::t('usuario', 'This email address has already been taken'),
],
// password rules
'passwordRequired' => ['password', 'required', 'skipOnEmpty' => $this->module->generatePasswords],
'passwordLength' => ['password', 'string', 'min' => 6, 'max' => 72],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'email' => Yii::t('usuario', 'Email'),
'username' => Yii::t('usuario', 'Username'),
'password' => Yii::t('usuario', 'Password'),
];
}
}

View File

@ -0,0 +1,59 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Form;
use Da\User\Query\UserQuery;
use Yii;
use yii\base\Model;
class ResendForm extends Model
{
/**
* @var string
*/
public $email;
/**
* @var UserQuery
*/
protected $userQuery;
/**
* @param UserQuery $userQuery
* @param array $config
*/
public function __construct(UserQuery $userQuery, $config = [])
{
$this->userQuery = $userQuery;
parent::__construct($config);
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
'emailRequired' => ['email', 'required'],
'emailPattern' => ['email', 'email'],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'email' => Yii::t('usuario', 'Email'),
];
}
}

View File

@ -0,0 +1,143 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Form;
use Da\User\Factory\EmailChangeStrategyFactory;
use Da\User\Helper\SecurityHelper;
use Da\User\Model\User;
use Da\User\Traits\ContainerAwareTrait;
use Da\User\Traits\ModuleAwareTrait;
use Yii;
use yii\base\Model;
class SettingsForm extends Model
{
use ModuleAwareTrait;
use ContainerAwareTrait;
/**
* @var string
*/
public $email;
/**
* @var string
*/
public $username;
/**
* @var string
*/
public $new_password;
/**
* @var string
*/
public $current_password;
/**
* @var SecurityHelper
*/
protected $securityHelper;
/** @var User */
protected $user;
public function __construct(SecurityHelper $securityHelper, array $config = [])
{
$this->securityHelper = $securityHelper;
parent::__construct($config);
}
/**
* @return array
*/
public function rules()
{
return [
'usernameRequired' => ['username', 'required'],
'usernameTrim' => ['username', 'filter', 'filter' => 'trim'],
'usernameLength' => ['username', 'string', 'min' => 3, 'max' => 255],
'usernamePattern' => ['username', 'match', 'pattern' => '/^[-a-zA-Z0-9_\.@]+$/'],
'emailRequired' => ['email', 'required'],
'emailTrim' => ['email', 'filter', 'filter' => 'trim'],
'emailPattern' => ['email', 'email'],
'emailUsernameUnique' => [
['email', 'username'],
'unique',
'when' => function ($model, $attribute) {
return $this->getUser()->$attribute != $model->$attribute;
},
'targetClass' => $this->getClassMap()->get(User::class),
],
'newPasswordLength' => ['new_password', 'string', 'max' => 72, 'min' => 6],
'currentPasswordRequired' => ['current_password', 'required'],
'currentPasswordValidate' => [
'current_password',
function ($attribute) {
if (!$this->securityHelper->validatePassword($this->$attribute, $this->getUser()->password_hash)) {
$this->addError($attribute, Yii::t('usuario', 'Current password is not valid'));
}
},
],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'email' => Yii::t('usuario', 'Email'),
'username' => Yii::t('usuario', 'Username'),
'new_password' => Yii::t('usuario', 'New password'),
'current_password' => Yii::t('usuario', 'Current password'),
];
}
/**
* @return User|null|\yii\web\IdentityInterface
*/
public function getUser()
{
if ($this->user == null) {
$this->user = Yii::$app->user->identity;
}
return $this->user;
}
/**
* Saves new account settings.
*
* @return bool
*/
public function save()
{
if ($this->validate()) {
$this->user->scenario = 'settings';
$this->user->username = $this->username;
$this->user->password = $this->new_password;
if ($this->email == $this->user->email && $this->user->unconfirmed_email != null) {
$this->user->unconfirmed_email = null;
} elseif ($this->email != $this->user->email) {
$strategy = EmailChangeStrategyFactory::makeByStrategyType(
$this->getModule()->emailChangeStrategy,
$this
);
return $strategy->run();
}
return $this->user->save();
}
return false;
}
}

View File

@ -0,0 +1,112 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Helper;
use Da\User\Model\AbstractAuthItem;
use Da\User\Module;
use Da\User\Traits\AuthManagerAwareTrait;
use Yii;
use yii\helpers\ArrayHelper;
use yii\rbac\Permission;
use yii\rbac\Role;
use yii\rbac\Rule;
class AuthHelper
{
use AuthManagerAwareTrait;
/**
* Checks whether a user has certain role.
*
* @param $userId
* @param $role
*
* @return bool
*/
public function hasRole($userId, $role)
{
if ($this->getAuthManager()) {
$roles = array_keys($this->getAuthManager()->getRolesByUser($userId));
return in_array($role, $roles, true);
}
return false;
}
/**
* @param $username
*
* @return bool
*/
public function isAdmin($username)
{
/** @var Module $module */
$module = Yii::$app->getModule('user');
$hasAdministratorPermissionName = $this->getAuthManager() && $module->administratorPermissionName
? Yii::$app->getUser()->can($module->administratorPermissionName)
: false;
return $hasAdministratorPermissionName || in_array($username, $module->administrators);
}
/**
* @param $name
*
* @return null|\yii\rbac\Item|Permission
*/
public function getPermission($name)
{
return $this->getAuthManager()->getPermission($name);
}
/**
* @param $name
*
* @return null|\yii\rbac\Item|Role
*/
public function getRole($name)
{
return $this->getAuthManager()->getRole($name);
}
/**
* Removes a role, permission or rule from the RBAC system.
*
* @param Role|Permission|Rule $object
*
* @return bool whether the role, permission or rule is successfully removed
*/
public function remove($object)
{
return $this->getAuthManager()->remove($object);
}
/**
* @param AbstractAuthItem $model
*
* @return array
*/
public function getUnassignedItems(AbstractAuthItem $model)
{
$excludeItems = $model->item !== null ? [$model->item->name] : [];
$items = $this->getAuthManager()->getItems($model->getType(), $excludeItems);
return ArrayHelper::map(
$items,
'name',
function ($item) {
return empty($item->description) ? $item->name : "{$item->name} ({$item->description})";
}
);
}
}

View File

@ -0,0 +1,59 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Helper;
/**
* ModelMapHelper.php.
*
* Date: 3/12/16
* Time: 18:10
*
* @author Antonio Ramirez <hola@2amigos.us>
*/
class ClassMapHelper
{
protected $map = [];
/**
* ModelClassMapHelper constructor.
*
* @param array $map
*/
public function __construct($map = [])
{
$this->map = $map;
}
/**
* @param $key
* @param $class
*/
public function set($key, $class)
{
$this->map[$key] = $class;
}
/**
* @param $key
*
* @return mixed
*
* @throws \Exception
*/
public function get($key)
{
if (array_key_exists($key, $this->map)) {
return $this->map[$key];
}
throw new \Exception('Unknown model map key: '.$key);
}
}

View File

@ -0,0 +1,25 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Helper;
class GravatarHelper
{
public function buildId($email)
{
return md5(strtolower(trim($email)));
}
public function getUrl($id, $size = 200)
{
return '//gravatar.com/avatar/'.$id.'?s='.$size;
}
}

View File

@ -0,0 +1,74 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Helper;
use yii\base\Security;
class SecurityHelper
{
/**
* @var Security
*/
protected $security;
public function __construct(Security $security)
{
$this->security = $security;
}
/**
* Generates a secure hash from a password and a random salt.
*
* @param string $password
* @param null|int $cost
*
* @return string
*/
public function generatePasswordHash($password, $cost = null)
{
return $this->security->generatePasswordHash($password, $cost);
}
public function generateRandomString($length = 32)
{
return $this->security->generateRandomString($length);
}
public function validatePassword($password, $hash)
{
return $this->security->validatePassword($password, $hash);
}
public function generatePassword($length)
{
$sets = [
'abcdefghjkmnpqrstuvwxyz',
'ABCDEFGHJKMNPQRSTUVWXYZ',
'23456789',
];
$all = '';
$password = '';
foreach ($sets as $set) {
$password .= $set[array_rand(str_split($set))];
$all .= $set;
}
$all = str_split($all);
for ($i = 0; $i < $length - count($sets); ++$i) {
$password .= $all[array_rand($all)];
}
$password = str_shuffle($password);
return $password;
}
}

View File

@ -0,0 +1,44 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Helper;
use DateTimeZone;
use yii\helpers\ArrayHelper;
use DateTime;
class TimezoneHelper
{
/**
* Get all of the time zones with the offsets sorted by their offset.
*
* @return array
*/
public static function getAll()
{
$timeZones = [];
$timeZoneIdentifiers = DateTimeZone::listIdentifiers();
foreach ($timeZoneIdentifiers as $timeZone) {
$date = new DateTime('now', new DateTimeZone($timeZone));
$offset = $date->getOffset() / 60 / 60;
$timeZones[] = [
'timezone' => $timeZone,
'name' => "{$timeZone} (UTC ".($offset > 0 ? '+' : '')."{$offset})",
'offset' => $offset,
];
}
ArrayHelper::multisort($timeZones, 'offset', SORT_DESC, SORT_NUMERIC);
return $timeZones;
}
}

View File

@ -0,0 +1,43 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Migration;
use yii\db\Migration;
class m000000_000001_create_user_table extends Migration
{
public function up()
{
$this->createTable('{{%user}}', [
'id' => $this->primaryKey(),
'username' => $this->string(255)->notNull(),
'email' => $this->string(255)->notNull(),
'password_hash' => $this->string(60)->notNull(),
'auth_key' => $this->string(32)->notNull(),
'unconfirmed_email' => $this->string(255),
'registration_ip' => $this->string(45),
'flags' => $this->integer()->notNull()->defaultValue('0'),
'confirmed_at' => $this->integer(),
'blocked_at' => $this->integer(),
'updated_at' => $this->integer()->notNull(),
'created_at' => $this->integer()->notNull(),
]);
$this->createIndex('idx_user_username', '{{%user}}', 'username', true);
$this->createIndex('idx_user_email', '{{%user}}', 'email', true);
}
public function down()
{
$this->dropTable('{{%user}}');
}
}

View File

@ -0,0 +1,42 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Migration;
use yii\db\Migration;
class m000000_000002_create_profile_table extends Migration
{
public function up()
{
$this->createTable(
'{{%profile}}',
[
'user_id' => $this->primaryKey(),
'name' => $this->string(255),
'public_email' => $this->string(255),
'gravatar_email' => $this->string(255),
'gravatar_id' => $this->string(32),
'location' => $this->string(255),
'website' => $this->string(255),
'timezone' => $this->string(40),
'bio' => $this->text(),
]
);
$this->addForeignKey('fk_profile_user', '{{%profile}}', 'user_id', '{{%user}}', 'id', 'CASCADE', 'RESTRICT');
}
public function down()
{
$this->dropTable('{{%profile}}');
}
}

View File

@ -0,0 +1,59 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Migration;
use yii\db\Migration;
class m000000_000003_create_social_account_table extends Migration
{
public function up()
{
$this->createTable(
'{{%social_account}}',
[
'id' => $this->primaryKey(),
'user_id' => $this->integer(),
'provider' => $this->string(255)->notNull(),
'client_id' => $this->string(255)->notNull(),
'code' => $this->string(32),
'email' => $this->string(255),
'username' => $this->string(255),
'data' => $this->text(),
'created_at' => $this->integer(),
]
);
$this->createIndex(
'idx_social_account_provider_client_id',
'{{%social_account}}',
['provider', 'client_id'],
true
);
$this->createIndex('idx_social_account_code', '{{%social_account}}', 'code', true);
$this->addForeignKey(
'fk_social_account_user',
'{{%social_account}}',
'user_id',
'{{%user}}',
'id',
'CASCADE',
'RESTRICT'
);
}
public function down()
{
$this->dropTable('{{%social_account}}');
}
}

View File

@ -0,0 +1,39 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Migration;
use yii\db\Migration;
class m000000_000004_create_token_table extends Migration
{
public function up()
{
$this->createTable(
'{{%token}}',
[
'user_id' => $this->integer(),
'code' => $this->string(32)->notNull(),
'type' => $this->smallInteger(6)->notNull(),
'created_at' => $this->integer()->notNull(),
]
);
$this->createIndex('idx_token_user_id_code_type', '{{%token}}', ['user_id', 'code', 'type'], true);
$this->addForeignKey('fk_token_user', '{{%token}}', 'user_id', '{{%user}}', 'id', 'CASCADE', 'RESTRICT');
}
public function down()
{
$this->dropTable('{{%token}}');
}
}

View File

@ -0,0 +1,130 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Model;
use Da\User\Traits\AuthManagerAwareTrait;
use Da\User\Validator\RbacItemsValidator;
use Da\User\Validator\RbacRuleValidator;
use yii\base\Model;
use yii\rbac\Item;
use Yii;
abstract class AbstractAuthItem extends Model
{
use AuthManagerAwareTrait;
/**
* @var string
*/
public $itemName;
/**
* @var string
*/
public $name;
/**
* @var string
*/
public $description;
/**
* @var string
*/
public $rule;
/**
* @var string[]
*/
public $children;
/**
* @var \yii\rbac\Role|\yii\rbac\Permission
*/
public $item;
/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
if ($this->item instanceof Item) {
$this->itemName = $this->item->name;
$this->name = $this->item->name;
$this->description = $this->item->description;
$this->children = array_keys($this->getAuthManager()->getChildren($this->item->name));
if ($this->item->ruleName !== null) {
$this->rule = get_class($this->getAuthManager()->getRule($this->item->ruleName));
}
}
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'name' => Yii::t('usuario', 'Name'),
'description' => Yii::t('usuario', 'Description'),
'children' => Yii::t('usuario', 'Children'),
'rule' => Yii::t('usuario', 'Rule'),
];
}
/**
* {@inheritdoc}
*/
public function scenarios()
{
return [
'create' => ['name', 'description', 'children', 'rule'],
'update' => ['name', 'description', 'children', 'rule'],
];
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
['itemName', 'safe'],
['name', 'required'],
['name', 'match', 'pattern' => '/^[\w][\w-.:]+[\w]$/'],
[['name', 'description', 'rule'], 'trim'],
[
'name',
function () {
if ($this->getAuthManager()->getItem($this->name) !== null) {
$this->addError('name', Yii::t('usuario', 'Auth item with such name already exists'));
}
},
'when' => function () {
return $this->scenario == 'create' || $this->item->name != $this->name;
},
],
['children', RbacItemsValidator::class],
['rule', RbacRuleValidator::class],
];
}
/**
* @return bool
*/
public function getIsNewRecord()
{
return $this->item === null;
}
/**
* @return Item
*/
abstract public function getType();
}

View File

@ -0,0 +1,65 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Model;
use Da\User\Traits\AuthManagerAwareTrait;
use Da\User\Validator\RbacItemsValidator;
use yii\base\InvalidConfigException;
use yii\base\Model;
use Yii;
class Assignment extends Model
{
use AuthManagerAwareTrait;
public $items = [];
public $user_id;
public $updated = false;
/**
* {@inheritdoc}
*
* @throws InvalidConfigException
*/
public function init()
{
parent::init();
if ($this->user_id === null) {
throw new InvalidConfigException('"user_id" must be set.');
}
$this->items = array_keys($this->getAuthManager()->getItemsByUser($this->user_id));
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'items' => Yii::t('usuario', 'Items'),
];
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
['user_id', 'required'],
['items', RbacItemsValidator::class],
['user_id', 'integer'],
];
}
}

View File

@ -0,0 +1,22 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Model;
use yii\rbac\Item;
class Permission extends AbstractAuthItem
{
public function getType()
{
return Item::TYPE_PERMISSION;
}
}

168
src/User/Model/Profile.php Normal file
View File

@ -0,0 +1,168 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Model;
use Da\User\Helper\GravatarHelper;
use Da\User\Query\ProfileQuery;
use Da\User\Traits\ContainerAwareTrait;
use Da\User\Traits\ModuleAwareTrait;
use Da\User\Validator\TimeZoneValidator;
use Yii;
use yii\db\ActiveRecord;
use Exception;
use DateTimeZone;
use DateTime;
/**
* @property int $user_id
* @property string $name
* @property string $public_email
* @property string $gravatar_email
* @property string $gravatar_id
* @property string $location
* @property string $website
* @property string $bio
* @property string $timezone
* @property User $user
*/
class Profile extends ActiveRecord
{
use ModuleAwareTrait;
use ContainerAwareTrait;
/**
* {@inheritdoc}
*/
public function beforeSave($insert)
{
if ($this->isAttributeChanged('gravatar_email')) {
$this->setAttribute(
'gravatar_id',
$this->make(GravatarHelper::class)->buildId(trim($this->getAttribute('gravatar_email')))
);
}
return parent::beforeSave($insert);
}
/**
* {@inheritdoc}
*/
public static function tableName()
{
return '{{%profile}}';
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
'bioString' => ['bio', 'string'],
'timeZoneValidation' => [
'timezone',
function ($attribute) {
if ($this->make(TimeZoneValidator::class, [$attribute])->validate()) {
$this->addError($attribute, Yii::t('usuario', 'Time zone is not valid'));
}
},
],
'publicEmailPattern' => ['public_email', 'email'],
'gravatarEmailPattern' => ['gravatar_email', 'email'],
'websiteUrl' => ['website', 'url'],
'nameLength' => ['name', 'string', 'max' => 255],
'publicEmailLength' => ['public_email', 'string', 'max' => 255],
'gravatarEmailLength' => ['gravatar_email', 'string', 'max' => 255],
'locationLength' => ['location', 'string', 'max' => 255],
'websiteLength' => ['website', 'string', 'max' => 255],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'name' => Yii::t('usuario', 'Name'),
'public_email' => Yii::t('usuario', 'Email (public)'),
'gravatar_email' => Yii::t('usuario', 'Gravatar email'),
'location' => Yii::t('usuario', 'Location'),
'website' => Yii::t('usuario', 'Website'),
'bio' => Yii::t('usuario', 'Bio'),
'timezone' => Yii::t('usuario', 'Time zone'),
];
}
/**
* Get the User's timezone.
*
* @return DateTimeZone
*/
public function getTimeZone()
{
try {
return new DateTimeZone($this->timezone);
} catch (Exception $e) {
return new DateTimeZone(Yii::$app->getTimeZone());
}
}
/**
* Set the User's timezone.
*
* @param DateTimeZone $timezone
*/
public function setTimeZone(DateTimeZone $timezone)
{
$this->setAttribute('timezone', $timezone);
}
/**
* Get User's local time.
*
* @param DateTime|null $dateTime
*
* @return DateTime
*/
public function getLocalTimeZone(DateTime $dateTime = null)
{
return $dateTime === null ? new DateTime() : $dateTime->setTimezone($this->getTimeZone());
}
/**
* @return \yii\db\ActiveQuery
*/
public function getUser()
{
return $this->hasOne($this->getClassMap()->get(User::class), ['id' => 'user_id']);
}
/**
* @param int $size
*
* @return mixed
*/
public function getAvatarUrl($size = 200)
{
return $this->make(GravatarHelper::class)->getUrl($this->gravatar_id, $size);
}
/**
* @return ProfileQuery
*/
public static function find()
{
return new ProfileQuery(static::class);
}
}

22
src/User/Model/Role.php Normal file
View File

@ -0,0 +1,22 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Model;
use yii\rbac\Item;
class Role extends AbstractAuthItem
{
public function getType()
{
return Item::TYPE_ROLE;
}
}

View File

@ -0,0 +1,118 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Model;
use Da\User\Query\SocialNetworkAccountQuery;
use Da\User\Traits\ContainerAwareTrait;
use Da\User\Traits\ModuleAwareTrait;
use Yii;
use yii\db\ActiveRecord;
use yii\helpers\Url;
/**
* /**
* @property int $id Id
* @property int $user_id User id, null if account is not bind to user
* @property string $provider Name of service
* @property string $client_id Account id
* @property string $data Account properties returned by social network (json encoded)
* @property string $decodedData Json-decoded properties
* @property string $code
* @property string $email
* @property string $username
* @property int $created_at
* @property User $user User that this account is connected for
*/
class SocialNetworkAccount extends ActiveRecord
{
use ModuleAwareTrait;
use ContainerAwareTrait;
/**
* @var array json decoded properties
*/
protected $decodedData;
/**
* {@inheritdoc}
*/
public static function tableName()
{
return '{{%social_account}}';
}
/**
* @return bool Whether this social account is connected to user
*/
public function getIsConnected()
{
return $this->user_id != null;
}
/**
* @return array json decoded properties
*/
public function getDecodedData()
{
if ($this->data !== null && $this->decodedData === null) {
$this->decodedData = json_decode($this->data);
}
return $this->decodedData;
}
/**
* @return string the connection url
*/
public function getConnectionUrl()
{
$code = Yii::$app->security->generateRandomString();
$this->updateAttributes(['code' => md5($code)]);
return Url::to(['/usr/registration/connect', 'code' => $code]);
}
/**
* Connects account to a user.
*
* @param User $user
*
* @return int
*/
public function connect(User $user)
{
return $this->updateAttributes(
[
'username' => null,
'email' => null,
'code' => null,
'user_id' => $user->id,
]
);
}
/**
* @return \yii\db\ActiveQuery
*/
public function getUser()
{
return $this->hasOne($this->getClassMap()->get(User::class), ['id' => 'user_id']);
}
/**
* @return SocialNetworkAccountQuery
*/
public static function find()
{
return new SocialNetworkAccountQuery(static::class);
}
}

119
src/User/Model/Token.php Normal file
View File

@ -0,0 +1,119 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Model;
use Da\User\Helper\SecurityHelper;
use Da\User\Query\TokenQuery;
use Da\User\Traits\ContainerAwareTrait;
use Da\User\Traits\ModuleAwareTrait;
use RuntimeException;
use yii\db\ActiveRecord;
use yii\helpers\Url;
/**
* Token Active Record model.
*
* @property int $user_id
* @property string $code
* @property int $type
* @property string $url
* @property bool $isExpired
* @property int $created_at
* @property User $user
*/
class Token extends ActiveRecord
{
use ModuleAwareTrait;
use ContainerAwareTrait;
const TYPE_CONFIRMATION = 0;
const TYPE_RECOVERY = 1;
const TYPE_CONFIRM_NEW_EMAIL = 2;
const TYPE_CONFIRM_OLD_EMAIL = 3;
protected $routes = [
self::TYPE_CONFIRMATION => '/user/registration/confirm',
self::TYPE_RECOVERY => '/usr/recovery/reset',
self::TYPE_CONFIRM_NEW_EMAIL => '/user/settings/confirm',
self::TYPE_CONFIRM_OLD_EMAIL => '/usr/settings/confirm',
];
/**
* {@inheritdoc}
*/
public function beforeSave($insert)
{
if ($insert) {
$this->setAttribute('code', $this->make(SecurityHelper::class)->generateRandomString());
static::deleteAll(['user_id' => $this->user_id, 'type' => $this->type]);
$this->setAttribute('created_at', time());
}
return parent::beforeSave($insert);
}
/**
* {@inheritdoc}
*/
public static function tableName()
{
return '{{%token}}';
}
/**
* {@inheritdoc}
*/
public static function primaryKey()
{
return ['user_id', 'code', 'type'];
}
/**
* @return \yii\db\ActiveQuery
*/
public function getUser()
{
return $this->hasOne($this->getClassMap()->get(User::class), ['id' => 'user_id']);
}
/**
* @return string
*/
public function getUrl()
{
return Url::to([$this->routes[$this->type], 'id' => $this->user_id, 'code' => $this->code], true);
}
/**
* @return bool Whether token has expired
*/
public function getIsExpired()
{
if ($this->type == static::TYPE_RECOVERY) {
$expirationTime = $this->getModule()->tokenRecoveryLifespan;
} elseif ($this->type >= static::TYPE_CONFIRMATION && $this->type <= static::TYPE_CONFIRM_OLD_EMAIL) {
$expirationTime = $this->getModule()->tokenConfirmationLifespan;
} else {
throw new RuntimeException();
}
return ($this->created_at + $expirationTime) < time();
}
/**
* @return TokenQuery
*/
public static function find()
{
return new TokenQuery(static::class);
}
}

289
src/User/Model/User.php Normal file
View File

@ -0,0 +1,289 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Model;
use Da\User\Helper\SecurityHelper;
use Da\User\Query\UserQuery;
use Da\User\Traits\ContainerAwareTrait;
use Da\User\Traits\ModuleAwareTrait;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\helpers\ArrayHelper;
use yii\web\Application;
use yii\web\IdentityInterface;
/**
* User ActiveRecord model.
*
* @property bool $isAdmin
* @property bool $isBlocked
* @property bool $isConfirmed whether user account has been confirmed or not
*
* Database fields:
* @property int $id
* @property string $username
* @property string $email
* @property string $unconfirmed_email
* @property string $password_hash
* @property string $auth_key
* @property int $registration_ip
* @property int $confirmed_at
* @property int $blocked_at
* @property int $flags
* @property int $created_at
* @property int $updated_at
*
* Defined relations:
* @property SocialNetworkAccount[] $socialNetworkAccounts
* @property Profile $profile
*/
class User extends ActiveRecord implements IdentityInterface
{
use ModuleAwareTrait;
use ContainerAwareTrait;
// following constants are used on secured email changing process
const OLD_EMAIL_CONFIRMED = 0b1;
const NEW_EMAIL_CONFIRMED = 0b10;
/**
* @var string Plain password. Used for model validation
*/
public $password;
/**
* @var array connected account list
*/
protected $connectedAccounts;
/**
* {@inheritdoc}
*/
public function beforeSave($insert)
{
/** @var SecurityHelper $security */
$security = $this->make(SecurityHelper::class);
if ($insert) {
$this->setAttribute('auth_key', $security->generateRandomString());
if (Yii::$app instanceof Application) {
$this->setAttribute('registration_ip', Yii::$app->request->getUserIP());
}
}
if (!empty($this->password)) {
$this->setAttribute(
'password_hash',
$security->generatePasswordHash($this->password, $this->getModule()->blowfishCost)
);
}
return parent::beforeSave($insert);
}
/**
* {@inheritdoc}
*/
public static function tableName()
{
return '{{%user}}';
}
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
TimestampBehavior::className(),
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'username' => Yii::t('usuario', 'Username'),
'email' => Yii::t('usuario', 'Email'),
'registration_ip' => Yii::t('usuario', 'Registration ip'),
'unconfirmed_email' => Yii::t('usuario', 'New email'),
'password' => Yii::t('usuario', 'Password'),
'created_at' => Yii::t('usuario', 'Registration time'),
'confirmed_at' => Yii::t('usuario', 'Confirmation time'),
];
}
/**
* {@inheritdoc}
*/
public function scenarios()
{
return ArrayHelper::merge(
parent::scenarios(),
[
'register' => ['username', 'email', 'password'],
'connect' => ['username', 'email'],
'create' => ['username', 'email', 'password'],
'update' => ['username', 'email', 'password'],
'settings' => ['username', 'email', 'password'],
]
);
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
// username rules
'usernameRequired' => ['username', 'required', 'on' => ['register', 'create', 'connect', 'update']],
'usernameMatch' => ['username', 'match', 'pattern' => '/^[-a-zA-Z0-9_\.@]+$/'],
'usernameLength' => ['username', 'string', 'min' => 3, 'max' => 255],
'usernameTrim' => ['username', 'trim'],
'usernameUnique' => [
'username',
'unique',
'message' => Yii::t('usuario', 'This username has already been taken'),
],
// email rules
'emailRequired' => ['email', 'required', 'on' => ['register', 'connect', 'create', 'update']],
'emailPattern' => ['email', 'email'],
'emailLength' => ['email', 'string', 'max' => 255],
'emailUnique' => [
'email',
'unique',
'message' => Yii::t('usuario', 'This email address has already been taken'),
],
'emailTrim' => ['email', 'trim'],
// password rules
'passwordRequired' => ['password', 'required', 'on' => ['register']],
'passwordLength' => ['password', 'string', 'min' => 6, 'max' => 72, 'on' => ['register', 'create']],
];
}
/**
* {@inheritdoc}
*/
public function validateAuthKey($authKey)
{
return $this->getAttribute('auth_key') === $authKey;
}
/**
* {@inheritdoc}
*/
public function getId()
{
return $this->getAttribute('id');
}
/**
* {@inheritdoc}
*/
public function getAuthKey()
{
return $this->getAttribute('auth_key');
}
/**
* {@inheritdoc}
*/
public static function findIdentity($id)
{
return static::findOne($id);
}
/**
* @return bool whether is blocked or not
*/
public function getIsBlocked()
{
return $this->blocked_at !== null;
}
/**
* @return bool whether the user is an admin or not
*/
public function getIsAdmin()
{
return $this->getAuth()->isAdmin($this->username);
}
/**
* Returns whether user account has been confirmed or not.
* @return bool whether user account has been confirmed or not
*/
public function getIsConfirmed()
{
return $this->confirmed_at !== null;
}
/**
* Checks whether a user has a specific role.
*
* @param string $role
*
* @return bool
*/
public function hasRole($role)
{
return $this->getAuth()->hasRole($this->id, $role);
}
/**
* @return \yii\db\ActiveQuery
*/
public function getProfile()
{
return $this->hasOne($this->getClassMap()->get(Profile::class), ['user_id' => 'id']);
}
/**
* @return SocialNetworkAccount[] social connected accounts [ 'providerName' => socialAccountModel ]
*/
public function getSocialNetworkAccounts()
{
if ($this->connectedAccounts == null) {
/** @var SocialNetworkAccount[] $accounts */
$accounts = $this->hasMany($this->getClassMap()
->get(SocialNetworkAccount::class), ['user_id' => 'id'])
->all();
foreach ($accounts as $account) {
$this->connectedAccounts[$account->provider] = $account;
}
}
return $this->connectedAccounts;
}
/**
* @return UserQuery
*/
public static function find()
{
return new UserQuery(static::class);
}
/**
* {@inheritdoc}
*/
public static function findIdentityByAccessToken($token, $type = null)
{
throw new NotSupportedException('Method "'.__CLASS__.'::'.__METHOD__.'" is not implemented.');
}
}

115
src/User/Module.php Normal file
View File

@ -0,0 +1,115 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User;
use Da\User\Contracts\MailChangeStrategyInterface;
use Da\User\Service\MailService;
use yii\base\Module as BaseModule;
/**
* This is the main module class of the yii2-usuario extension.
*/
class Module extends BaseModule
{
/**
* @var bool whether to allow registration process or not
*/
public $enableRegistration = true;
/**
* @var bool whether to force email confirmation to
*/
public $enableEmailConfirmation = true;
/**
* @var bool whether to display flash messages or not
*/
public $enableFlashMessages = true;
/**
* @var bool whether to generate passwords automatically and remove the password field from the registration form
*/
public $generatePasswords = false;
/**
* @var bool whether to allow login accounts with unconfirmed emails
*/
public $allowUnconfirmedEmailLogin = false;
/**
* @var bool whether to enable password recovery or not
*/
public $allowPasswordRecovery = true;
/**
* @var bool whether user can remove his account
*/
public $allowAccountDelete = false;
/**
* @var string the class name of the strategy class to handle user's email change
*/
public $emailChangeStrategy = MailChangeStrategyInterface::TYPE_DEFAULT;
/**
* @var int the time user will be auto logged in
*/
public $rememberLoginLifespan = 1209600;
/**
* @var int the time before the confirmation token becomes invalid. Defaults to 24 hours
*/
public $tokenConfirmationLifespan = 86400;
/**
* @var int the time before a recovery token is invalid. Defaults to 6 hours
*/
public $tokenRecoveryLifespan = 21600;
/**
* @var array a list of admin usernames
*/
public $administrators = [];
/**
* @var string the administrator permission name
*/
public $administratorPermissionName;
/**
* @var string the route prefix
*/
public $prefix = 'user';
/**
* @var array MailService configuration
*/
public $mailParams = [];
/**
* @var int the cost parameter used by the Blowfish hash algorithm.
* The higher the value of cost,
* the longer it takes to generate the hash and to verify a password against it. Higher cost
* therefore slows down a brute-force attack. For best protection against brute-force attacks,
* set it to the highest value that is tolerable on production servers. The time taken to
* compute the hash doubles for every increment by one of $cost
*/
public $blowfishCost = 10;
/**
* @var array the class map. How the container should load specific classes
* @see Bootstrap::buildClassMap() for more details
*/
public $classMap = [];
/**
* @var array the url rules (routes)
*/
public $routes = [
'<id:\d+>' => 'profile/show',
'<action:(login|logout)>' => 'auth/<action>',
'<action:(register|resend)>' => 'registration/<action>',
'confirm/<id:\d+>/<code:[A-Za-z0-9_-]+>' => 'registration/confirm',
'forgot' => 'recovery/request',
'recover/<id:\d+>/<code:[A-Za-z0-9_-]+>' => 'recovery/reset',
'settings/<action:\w+>' => 'settings/<action>',
];
/**
* @var string
*/
public $viewPath = '@Da/User/resources/views';
}

View File

@ -0,0 +1,22 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Query;
use yii\db\ActiveQuery;
class ProfileQuery extends ActiveQuery
{
public function whereId($id)
{
return $this->andWhere(['id' => $id]);
}
}

View File

@ -0,0 +1,38 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Query;
use Da\User\Contracts\AuthClientInterface;
use yii\db\ActiveQuery;
class SocialNetworkAccountQuery extends ActiveQuery
{
public function whereId($id)
{
return $this->andWhere(['id' => $id]);
}
public function whereClient(AuthClientInterface $client)
{
return $this->andWhere(
[
'provider' => $client->getId(),
'client_id' => $client->getUserAttributes()['id'],
]
);
}
public function whereCode($code)
{
return $this->andWhere(['code' => md5($code)]);
}
}

View File

@ -0,0 +1,64 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Query;
use Da\User\Model\Token;
use yii\db\ActiveQuery;
class TokenQuery extends ActiveQuery
{
/**
* @param $userId
*
* @return $this
*/
public function whereUserId($userId)
{
return $this->andWhere(['user_id' => $userId]);
}
/**
* @param $code
*
* @return $this
*/
public function whereCode($code)
{
return $this->andWhere(['code' => $code]);
}
/**
* @return $this
*/
public function whereIsRecoveryType()
{
return $this->andWhere(['type' => Token::TYPE_RECOVERY]);
}
/**
* @return $this
*/
public function whereIsConfirmationType()
{
return $this->andWhere(['type' => Token::TYPE_CONFIRMATION]);
}
/**
* @param array $types
*
* @return $this
*/
public function whereIsTypes(array $types)
{
return $this->andWhere(['in', 'type', $types]);
}
}

View File

@ -0,0 +1,69 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Query;
use yii\db\ActiveQuery;
class UserQuery extends ActiveQuery
{
/**
* @param $usernameOrEmail
*
* @return $this
*/
public function whereUsernameOrEmail($usernameOrEmail)
{
return filter_var($usernameOrEmail, FILTER_VALIDATE_EMAIL)
? $this->whereEmail($usernameOrEmail)
: $this->whereUsername($usernameOrEmail);
}
/**
* @param $email
*
* @return $this
*/
public function whereEmail($email)
{
return $this->andWhere(['email' => $email]);
}
/**
* @param $username
*
* @return $this
*/
public function whereUsername($username)
{
return $this->andWhere(['username' => $username]);
}
/**
* @param $id
*
* @return $this
*/
public function whereId($id)
{
return $this->andWhere(['id' => $id]);
}
/**
* @param $id
*
* @return $this
*/
public function whereNotId($id)
{
return $this->andWhere(['<>', 'id', $id]);
}
}

View File

@ -0,0 +1,74 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Search;
use Da\User\Traits\AuthManagerAwareTrait;
use Da\User\Traits\ContainerAwareTrait;
use yii\base\Model;
use yii\data\ArrayDataProvider;
use yii\db\Query;
abstract class AbstractAuthItemSearch extends Model
{
use AuthManagerAwareTrait;
use ContainerAwareTrait;
/**
* @var string
*/
public $name;
/**
* @var string
*/
public $description;
/**
* @var string
*/
public $rule_name;
/**
* @return int
*/
abstract public function getType();
/**
* @return array
*/
public function scenarios()
{
return [
'default' => ['name', 'description', 'rule_name'],
];
}
public function search($params = [])
{
/** @var ArrayDataProvider $dataProvider */
$dataProvider = $this->make(ArrayDataProvider::class);
$query = (new Query())
->select(['name', 'description', 'rule_name'])
->andWhere(['type' => $this->getType()])
->from($this->getAuthManager()->itemTable);
if ($this->load($params) && $this->validate()) {
$query
->andFilterWhere(['like', 'name', $this->name])
->andFilterWhere(['like', 'description', $this->description])
->andFilterWhere(['like', 'rule_name', $this->rule_name]);
}
$dataProvider->allModels = $query->all($this->getAuthManager()->db);
return $dataProvider;
}
}

View File

@ -0,0 +1,25 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Search;
use yii\rbac\Item;
class PermissionSearch extends AbstractAuthItemSearch
{
/**
* {@inheritdoc}
*/
public function getType()
{
return Item::TYPE_PERMISSION;
}
}

View File

@ -0,0 +1,25 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Search;
use yii\rbac\Item;
class RoleSearch extends AbstractAuthItemSearch
{
/**
* {@inheritdoc}
*/
public function getType()
{
return Item::TYPE_ROLE;
}
}

View File

@ -0,0 +1,107 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Search;
use Da\User\Query\UserQuery;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
class UserSearch extends Model
{
/**
* @var string
*/
public $username;
/**
* @var string
*/
public $email;
/**
* @var int
*/
public $created_at;
/**
* @var string
*/
public $registration_ip;
/**
* @var UserQuery
*/
protected $query;
/**
* UserSearch constructor.
*
* @param UserQuery $query
* @param array $config
*/
public function __construct(UserQuery $query, $config = [])
{
$this->query = $query;
parent::__construct($config);
}
/**
* @return array
*/
public function rules()
{
return [
'safeFields' => [['username', 'email', 'registration_ip', 'created_at'], 'safe'],
'createdDefault' => ['created_at', 'default', 'value' => null],
];
}
/**
* @return array
*/
public function attributeLabels()
{
return [
'username' => Yii::t('usuario', 'Username'),
'email' => Yii::t('usuario', 'Email'),
'created_at' => Yii::t('usuario', 'Registration time'),
'registration_ip' => Yii::t('usuario', 'Registration ip'),
];
}
/**
* @param $params
*
* @return ActiveDataProvider
*/
public function search($params)
{
$query = $this->query;
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
if ($this->created_at !== null) {
$date = strtotime($this->created_at);
$query->andFilterWhere(['between', 'created_at', $date, $date + 3600 * 24]);
}
$query
->andFilterWhere(['like', 'username', $this->username])
->andFilterWhere(['like', 'email', $this->email])
->andFilterWhere(['registration_ip' => $this->registration_ip]);
return $dataProvider;
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace Da\User\Service;
use Da\User\Contracts\ServiceInterface;
use Da\User\Model\Token;
use Da\User\Model\User;
use Da\User\Query\TokenQuery;
class AccountConfirmationService implements ServiceInterface
{
protected $model;
protected $code;
protected $tokenQuery;
protected $userConfirmationService;
public function __construct(
$code,
User $model,
UserConfirmationService $userConfirmationService,
TokenQuery $tokenQuery
) {
$this->code = $code;
$this->model = $model;
$this->userConfirmationService = $userConfirmationService;
$this->tokenQuery = $tokenQuery;
}
public function run()
{
$token = $this->tokenQuery
->whereUserId($this->model->id)
->whereCode($this->code)
->whereIsConfirmationType()
->one();
if ($token instanceof Token && !$token->getIsExpired()) {
$token->delete();
return $this->userConfirmationService->run();
}
return false;
}
}

View File

@ -0,0 +1,103 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Service;
use Da\User\Contracts\ServiceInterface;
use Da\User\Factory\AuthItemFactory;
use Da\User\Model\AbstractAuthItem;
use Da\User\Traits\AuthManagerAwareTrait;
use Da\User\Traits\ContainerAwareTrait;
use Exception;
class AuthItemEditionService implements ServiceInterface
{
use AuthManagerAwareTrait;
use ContainerAwareTrait;
protected $model;
public function __construct(AbstractAuthItem $model)
{
$this->model = $model;
}
public function run()
{
if (!$this->model->validate()) {
return false;
}
try {
if ($this->model->getIsNewRecord()) {
$item = AuthItemFactory::makeByType($this->model->getType(), $this->model->name);
} else {
$item = $this->model->item;
}
$item->name = $this->model->name;
$item->description = $this->model->description;
if (!empty($this->model->rule)) {
$rule = $this->make($this->model->rule);
if (null === $this->getAuthManager()->getRule($rule->name)) {
$this->getAuthManager()->add($rule);
}
$item->ruleName = $rule->name;
} else {
$item->ruleName = null;
}
if ($this->model->getIsNewRecord()) {
$this->getAuthManager()->add($item);
} else {
$this->getAuthManager()->update($this->model->itemName, $item);
$this->model->itemName = $item->name;
}
$this->model->item = $item;
return $this->updateChildren();
} catch (Exception $e) {
return false;
}
}
/**
* Updates Auth Item children.
*
* @return bool
*/
protected function updateChildren()
{
$children = $this->getAuthManager()->getChildren($this->model->item->name);
$childrenNames = array_keys($children);
if (is_array($this->model->children)) {
// remove those not linked anymore
foreach (array_diff($childrenNames, $this->model->children) as $item) {
if (!$this->getAuthManager()->removeChild($this->model->item, $children[$item])) {
return false;
}
}
// add new children
foreach (array_diff($this->model->children, $childrenNames) as $item) {
if (!$this->getAuthManager()->addChild($this->model->item, $this->getAuthManager()->getItem($item))) {
return false;
}
}
} else {
return $this->getAuthManager()->removeChildren($this->model->item);
}
return true;
}
}

View File

@ -0,0 +1,86 @@
<?php
namespace Da\User\Service;
use Da\User\Contracts\MailChangeStrategyInterface;
use Da\User\Contracts\ServiceInterface;
use Da\User\Model\Token;
use Da\User\Model\User;
use Da\User\Query\TokenQuery;
use Da\User\Query\UserQuery;
use Da\User\Traits\ModuleAwareTrait;
use Yii;
class EmailChangeService implements ServiceInterface
{
use ModuleAwareTrait;
protected $code;
protected $model;
protected $tokenQuery;
protected $userQuery;
public function __construct($code, User $model, TokenQuery $tokenQuery, UserQuery $userQuery)
{
$this->code = $code;
$this->model = $model;
$this->tokenQuery = $tokenQuery;
$this->userQuery = $userQuery;
}
public function run()
{
/** @var Token $token */
$token = $this->tokenQuery
->whereUserId($this->model->id)
->whereCode($this->code)
->whereIsTypes([Token::TYPE_CONFIRM_NEW_EMAIL, Token::TYPE_CONFIRM_OLD_EMAIL])
->one();
if ($token === null || $token->getIsExpired()) {
Yii::$app->session->setFlash('danger', Yii::t('usuario', 'Your confirmation token is invalid or expired'));
return false;
} else {
$token->delete();
if (empty($this->model->unconfirmed_email)) {
Yii::$app->session->setFlash('danger', Yii::t('usuario', 'An error occurred processing your request'));
} elseif ($this->userQuery->whereEmail($this->model->unconfirmed_email)->exists() === false) {
if ($this->getModule()->emailChangeStrategy === MailChangeStrategyInterface::TYPE_SECURE) {
if ($token->type === Token::TYPE_CONFIRM_NEW_EMAIL) {
$this->model->flags |= User::NEW_EMAIL_CONFIRMED;
Yii::$app->session->setFlash(
'success',
Yii::t(
'usuario',
'Awesome, almost there. '.
'Now you need to click the confirmation link sent to your old email address.'
)
);
} elseif ($token->type === Token::TYPE_CONFIRM_OLD_EMAIL) {
$this->model->flags |= User::OLD_EMAIL_CONFIRMED;
Yii::$app->session->setFlash(
'success',
Yii::t(
'usuario',
'Awesome, almost there. '.
'Now you need to click the confirmation link sent to your new email address.'
)
);
}
}
if ($this->getModule()->emailChangeStrategy === MailChangeStrategyInterface::TYPE_DEFAULT
|| ($this->model->flags & User::NEW_EMAIL_CONFIRMED & $this->model->flags & User::OLD_EMAIL_CONFIRMED)
) {
$this->model->email = $this->model->unconfirmed_email;
$this->model->unconfirmed_email = null;
Yii::$app->session->setFlash('success', Yii::t('usuario', 'Your email address has been changed'));
}
return $this->model->save(false);
}
}
return false;
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace Da\User\Service;
use Da\User\Contracts\ServiceInterface;
use Yii;
use yii\mail\BaseMailer;
class MailService implements ServiceInterface
{
protected $viewPath = '@Da/User/resources/views/mail';
protected $from;
protected $to;
protected $subject;
protected $view;
protected $params = [];
protected $mailer;
/**
* MailService constructor.
*
* @param string $from
* @param string $to
* @param string $subject
* @param string $view
* @param array $params
* @param MailerInterface $mailer
*/
public function __construct($from, $to, $subject, $view, array $params, BaseMailer $mailer)
{
$this->from = $from;
$this->to = $to;
$this->subject = $subject;
$this->view = $view;
$this->params = $params;
$this->mailer = $mailer;
$this->mailer->setViewPath($this->viewPath);
$this->mailer->getView()->theme = Yii::$app->view->theme;
}
/**
* @param $name
* @param $value
*
* @return $this
*/
public function setViewParam($name, $value)
{
$this->params[$name] = $value;
return $this;
}
/**
* @return bool
*/
public function run()
{
return $this->mailer
->compose(['html' => $this->view, 'text' => "text/{$this->view}"], $this->params)
->setFrom($this->from)
->setTo($this->to)
->setSubject($this->subject)
->send();
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace Da\User\Service;
use Da\User\Contracts\ServiceInterface;
use Da\User\Factory\TokenFactory;
use Da\User\Model\Token;
use Da\User\Model\User;
use Da\User\Query\UserQuery;
use Exception;
use Yii;
use yii\log\Logger;
class PasswordRecoveryService implements ServiceInterface
{
protected $query;
protected $email;
protected $mailService;
protected $securityHelper;
protected $logger;
public function __construct($email, MailService $mailService, UserQuery $query, Logger $logger)
{
$this->email = $email;
$this->mailService = $mailService;
$this->query = $query;
$this->logger = $logger;
}
public function run()
{
try {
/** @var User $user */
$user = $this->query->whereEmail($this->email)->one();
$token = TokenFactory::makeRecoveryToken($user->id);
if (!$token) {
return false;
}
$this->mailService->setViewParam('user', $user);
$this->mailService->setViewParam('token', $token);
if (!$this->mailService->run()) {
return false;
}
Yii::$app->session->setFlash(
'info',
Yii::t('usuario', 'An email has been sent with instructions for resetting your password')
);
return true;
} catch (Exception $e) {
$this->logger->log($e->getMessage(), Logger::LEVEL_ERROR);
return false;
}
}
}

View File

@ -0,0 +1,43 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Service;
use Da\User\Contracts\ServiceInterface;
use Da\User\Factory\TokenFactory;
use Da\User\Model\User;
use yii\log\Logger;
class ResendConfirmationService implements ServiceInterface
{
protected $model;
protected $mailService;
protected $logger;
public function __construct(User $model, MailService $mailService, Logger $logger)
{
$this->model = $model;
$this->mailService = $mailService;
$this->logger = $logger;
}
public function run()
{
if ($this->model && !$this->model->getIsConfirmed()) {
$token = TokenFactory::makeConfirmationToken($this->model->id);
$this->mailService->setViewParam('token', $token);
return $this->mailService->run();
}
return false;
}
}

View File

@ -0,0 +1,39 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Service;
use Da\User\Contracts\ServiceInterface;
use Da\User\Helper\SecurityHelper;
use Da\User\Model\User;
class ResetPasswordService implements ServiceInterface
{
protected $password;
protected $model;
protected $securityHelper;
public function __construct($password, User $model, SecurityHelper $securityHelper)
{
$this->password;
$this->model = $model;
$this->securityHelper = $securityHelper;
}
public function run()
{
return $this->model && (bool) $this->model->updateAttributes(
[
'password_hash' => $this->securityHelper->generatePasswordHash($this->password),
]
);
}
}

View File

@ -0,0 +1,98 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Service;
use Da\User\Contracts\AuthClientInterface;
use Da\User\Contracts\ServiceInterface;
use Da\User\Controller\SecurityController;
use Da\User\Event\SocialNetworkAuthEvent;
use Da\User\Model\SocialNetworkAccount;
use Da\User\Model\User;
use Da\User\Query\SocialNetworkAccountQuery;
use Da\User\Traits\ContainerAwareTrait;
use Yii;
class SocialNetworkAccountConnectService implements ServiceInterface
{
use ContainerAwareTrait;
protected $controller;
protected $client;
protected $socialNetworkAccountQuery;
/**
* SocialNetworkAccountUserLinkService constructor.
*
* @param SecurityController $controller
* @param AuthClientInterface $client
* @param SocialNetworkAccountQuery $socialNetworkAccountQuery
*/
public function __construct(
SecurityController $controller,
AuthClientInterface $client,
SocialNetworkAccountQuery $socialNetworkAccountQuery
) {
$this->controller = $controller;
$this->client = $client;
$this->socialNetworkAccountQuery = $socialNetworkAccountQuery;
}
public function run()
{
$account = $this->getSocialNetworkAccount();
$event = $this->make(SocialNetworkAuthEvent::class, [$account, $this->client]);
$this->controller->trigger(SocialNetworkAuthEvent::EVENT_BEFORE_CONNECT, $event);
if ($account && $account->user === null) {
/** @var User $user */
$user = Yii::$app->user->identity;
$account->link('user', $user);
Yii::$app->session->setFlash('success', Yii::t('usuario', 'Your account has been connected'));
$this->controller->trigger(SocialNetworkAuthEvent::EVENT_AFTER_CONNECT, $event);
return true;
} else {
Yii::$app->session->setFlash(
'danger',
Yii::t('usuario', 'This account has already been connected to another user')
);
}
return false;
}
protected function getSocialNetworkAccount()
{
$account = $this->socialNetworkAccountQuery->whereClient($this->client)->one();
if (null === $account) {
$data = $this->client->getUserAttributes();
$account = $this->make(
SocialNetworkAccount::class,
[
'provider' => $this->client->getId(),
'client_id' => $data['id'],
'data' => json_encode($data),
]
);
if ($account->save(false)) {
return $account;
}
}
return false;
}
}

View File

@ -0,0 +1,139 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Service;
use Da\User\Contracts\AuthClientInterface;
use Da\User\Contracts\ServiceInterface;
use Da\User\Controller\SecurityController;
use Da\User\Event\SocialNetworkAuthEvent;
use Da\User\Factory\MailFactory;
use Da\User\Model\SocialNetworkAccount;
use Da\User\Model\User;
use Da\User\Query\SocialNetworkAccountQuery;
use Da\User\Query\UserQuery;
use Yii;
use yii\authclient\AuthAction;
use yii\helpers\Url;
class SocialNetworkAuthenticateService implements ServiceInterface
{
protected $controller;
protected $authAction;
protected $client;
protected $socialNetworkAccountQuery;
protected $userQuery;
public function __construct(
SecurityController $controller,
AuthAction $authAction,
AuthClientInterface $client,
SocialNetworkAccountQuery $socialNetworkAccountQuery,
UserQuery $userQuery
) {
$this->controller = $controller;
$this->authAction = $authAction;
$this->client = $client;
$this->socialNetworkAccountQuery = $socialNetworkAccountQuery;
$this->userQuery = $userQuery;
}
public function run()
{
$account = $this->socialNetworkAccountQuery->whereClient($this->client)->one();
if (!$this->controller->module->enableRegistration && ($account === null || $account->user === null)) {
Yii::$app->session->setFlash('danger', Yii::t('usuario', 'Registration on this website is disabled'));
$this->authAction->setSuccessUrl(Url::to(['/usr/security/login']));
return false;
}
if ($account === null) {
$account = $this->createAccount();
if (!$account) {
Yii::$app->session->setFlash('danger', Yii::t('usuario', 'Unable to create an account.'));
$this->authAction->setSuccessUrl(Url::to(['/usr/security/login']));
return false;
}
}
$event = Yii::createObject(SocialNetworkAuthEvent::class, [$this->client]);
$this->controller->trigger(SocialNetworkAuthEvent::EVENT_BEFORE_AUTHENTICATE, $event);
if ($account->user instanceof User) {
if ($account->user->getIsBlocked()) {
Yii::$app->session->setFlash('danger', Yii::t('usuario', 'Your account has been blocked.'));
$this->authAction->setSuccessUrl(Url::to(['/user/security/login']));
} else {
Yii::$app->user->login($account->user, $this->controller->module->rememberLoginLifeSpan);
$this->authAction->setSuccessUrl(Yii::$app->getUser()->getReturnUrl());
}
} else {
$this->authAction->setSuccessUrl($account->getConnectionUrl());
}
$this->controller->trigger(SocialNetworkAuthEvent::EVENT_AFTER_AUTHENTICATE, $event);
}
protected function createAccount()
{
$data = $this->client->getUserAttributes();
/** @var SocialNetworkAccount $account */
$account = $this->controller->make(
SocialNetworkAccount::class,
[
'provider' => $this->client->getId(),
'client_id' => $data['id'],
'data' => json_encode($data),
'username' => $this->client->getUserName(),
'email' => $this->client->getEmail(),
]
);
if (($user = $this->getUser($account)) instanceof User) {
$account->user_id = $user->id;
$account->save(false);
return $account;
}
return false;
}
protected function getUser(SocialNetworkAccount $account)
{
$user = $this->userQuery->whereEmail($account->email)->one();
if (null !== $user) {
return $user;
}
/** @var User $user */
$user = $this->controller->make(
User::class,
[
'scenario' => 'connect',
'username' => $account->username,
'email' => $account->email,
]
);
if (!$user->validate(['email'])) {
$user->email = null;
}
if (!$user->validate(['username'])) {
$user->username = null;
}
$mailService = MailFactory::makeWelcomeMailerService($user);
return $this->controller->make(UserCreateService::class, [$user, $mailService])->run() ? $user : false;
}
}

View File

@ -0,0 +1,52 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Service;
use Da\User\Contracts\ServiceInterface;
use Da\User\Model\Assignment;
use Da\User\Traits\AuthManagerAwareTrait;
class UpdateAuthAssignmentsService implements ServiceInterface
{
use AuthManagerAwareTrait;
protected $model;
public function __construct(Assignment $model)
{
$this->model = $model;
}
public function run()
{
if ($this->model->validate()) {
return false;
}
if (!is_array($this->model->items)) {
$this->model->items = [];
}
$assignedItems = $this->getAuthManager()->getItemsByUser($this->model->user_id);
$assignedItemsNames = array_keys($assignedItems);
foreach (array_diff($assignedItemsNames, $this->model->items) as $item) {
$this->model->getAuthManager()->revoke($assignedItems[$item], $this->model->user_id);
}
foreach (array_diff($this->model->items, $assignedItemsNames) as $item) {
$this->getAuthManager()->assign($this->getAuthManager()->getItem($item), $this->model->user_id);
}
return $this->model->updated = true;
}
}

View File

@ -0,0 +1,55 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Service;
use Da\User\Contracts\ServiceInterface;
use Da\User\Controller\AdminController;
use Da\User\Event\UserEvent;
use Da\User\Helper\SecurityHelper;
use Da\User\Model\User;
class UserBlockService implements ServiceInterface
{
protected $model;
protected $event;
protected $controller;
protected $securityHelper;
public function __construct(
User $model,
UserEvent $event,
AdminController $controller,
SecurityHelper $securityHelper
) {
$this->model = $model;
$this->event = $event;
$this->controller = $controller;
$this->securityHelper = $securityHelper;
}
public function run()
{
if ($this->model->getIsBlocked()) {
$this->controller->trigger(UserEvent::EVENT_BEFORE_UNBLOCK, $this->event);
$result = (bool) $this->model->updateAttributes(['blocked_at' => null]);
$this->controller->trigger(UserEvent::EVENT_AFTER_UNBLOCK, $this->event);
} else {
$this->controller->trigger(UserEvent::EVENT_BEFORE_BLOCK, $this->event);
$result = (bool) $this->model->updateAttributes(
['blocked_at' => time(), 'auth_key' => $this->securityHelper->generateRandomString()]
);
$this->controller->trigger(UserEvent::EVENT_AFTER_BLOCK, $this->event);
}
return $result;
}
}

View File

@ -0,0 +1,38 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Service;
use Da\User\Contracts\ServiceInterface;
use Da\User\Event\UserEvent;
use Da\User\Model\User;
class UserConfirmationService implements ServiceInterface
{
protected $model;
public function __construct(User $model)
{
$this->model = $model;
}
public function run()
{
$this->model->trigger(UserEvent::EVENT_BEFORE_CONFIRMATION);
if ((bool) $this->model->updateAttributes(['confirmed_at' => time()])) {
$this->model->trigger(UserEvent::EVENT_AFTER_CONFIRMATION);
return true;
}
return false;
}
}

View File

@ -0,0 +1,77 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Service;
use Da\User\Contracts\ServiceInterface;
use Da\User\Event\UserEvent;
use Da\User\Helper\SecurityHelper;
use Da\User\Model\User;
use yii\base\InvalidCallException;
use Exception;
use yii\log\Logger;
class UserCreateService implements ServiceInterface
{
protected $model;
protected $securityHelper;
protected $mailService;
protected $logger;
public function __construct(User $model, MailService $mailService, SecurityHelper $securityHelper, Logger $logger)
{
$this->model = $model;
$this->mailService = $mailService;
$this->securityHelper = $securityHelper;
$this->logger = $logger;
}
/**
* @return bool
*/
public function run()
{
$model = $this->model;
if ($model->getIsNewRecord() === false) {
throw new InvalidCallException('Cannot create a new user from an existing one.');
}
$transaction = $model->getDb()->beginTransaction();
try {
$model->confirmed_at = time();
$model->password = $model->password !== null
? $model->password
: $this->securityHelper->generatePassword(8);
$model->trigger(UserEvent::EVENT_BEFORE_CREATE);
if (!$model->save()) {
$transaction->rollBack();
return false;
}
$model->trigger(UserEvent::EVENT_AFTER_CREATE);
$this->mailService->run();
$transaction->commit();
return true;
} catch (Exception $e) {
$transaction->rollBack();
$this->logger->log($e->getMessage(), Logger::LEVEL_ERROR);
return false;
}
}
}

View File

@ -0,0 +1,86 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Service;
use Da\User\Contracts\ServiceInterface;
use Da\User\Event\UserEvent;
use Da\User\Factory\TokenFactory;
use Da\User\Helper\SecurityHelper;
use Da\User\Model\User;
use Da\User\Traits\ModuleAwareTrait;
use Exception;
use yii\base\InvalidCallException;
use yii\log\Logger;
class UserRegisterService implements ServiceInterface
{
use ModuleAwareTrait;
protected $model;
protected $securityHelper;
protected $mailService;
protected $logger;
public function __construct(User $model, MailService $mailService, SecurityHelper $securityHelper, Logger $logger)
{
$this->model = $model;
$this->mailService = $mailService;
$this->securityHelper = $securityHelper;
$this->logger = $logger;
}
public function run()
{
$model = $this->model;
if ($model->getIsNewRecord() === false) {
throw new InvalidCallException('Cannot register user from an existing one.');
}
$transaction = $model->getDb()->beginTransaction();
try {
$model->confirmed_at = $this->getModule()->enableEmailConfirmation ? null : time();
$model->password = $this->getModule()->generatePasswords
? $this->securityHelper->generatePassword(8)
: $model->password;
$model->trigger(UserEvent::EVENT_BEFORE_REGISTER);
if (!$model->save()) {
$transaction->rollBack();
return false;
}
if ($this->getModule()->enableEmailConfirmation) {
$token = TokenFactory::makeConfirmationToken($model->id);
}
if (isset($token)) {
$this->mailService->setViewParam('token', $token);
}
$this->mailService->run();
$model->trigger(UserEvent::EVENT_AFTER_REGISTER);
$transaction->commit();
return true;
} catch (Exception $e) {
$transaction->rollBack();
$this->logger->log($e->getMessage(), Logger::LEVEL_WARNING);
return false;
}
}
}

View File

@ -0,0 +1,50 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Strategy;
use Da\User\Contracts\MailChangeStrategyInterface;
use Da\User\Factory\MailFactory;
use Da\User\Factory\TokenFactory;
use Da\User\Form\SettingsForm;
use Da\User\Traits\ContainerAwareTrait;
use Yii;
class DefaultEmailChangeStrategy implements MailChangeStrategyInterface
{
use ContainerAwareTrait;
protected $form;
public function __construct(SettingsForm $form)
{
$this->form = $form;
}
public function run()
{
$this->form->getUser()->unconfirmed_email = $this->form->email;
$token = TokenFactory::makeConfirmNewMailToken($this->form->getUser()->id);
$mailService = MailFactory::makeReconfirmationMailerService($this->form->getUser(), $token);
if ($mailService->run()) {
Yii::$app
->session
->setFlash('info', Yii::t('usuario', 'A confirmation message has been sent to your new email address'));
return $this->form->getUser()->save();
}
return false;
}
}

View File

@ -0,0 +1,32 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Strategy;
use Da\User\Contracts\MailChangeStrategyInterface;
use Da\User\Form\SettingsForm;
class InsecureEmailChangeStrategy implements MailChangeStrategyInterface
{
protected $form;
public function __construct(SettingsForm $form)
{
$this->form = $form;
}
public function run()
{
$this->form->getUser()->email = $this->form->email;
return $this->form->getUser()->save();
}
}

View File

@ -0,0 +1,62 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Strategy;
use Da\User\Contracts\MailChangeStrategyInterface;
use Da\User\Factory\MailFactory;
use Da\User\Factory\TokenFactory;
use Da\User\Form\SettingsForm;
use Da\User\Model\User;
use Da\User\Traits\ContainerAwareTrait;
use Yii;
class SecureEmailChangeStrategy implements MailChangeStrategyInterface
{
use ContainerAwareTrait;
protected $form;
public function __construct(SettingsForm $form)
{
$this->form = $form;
}
public function run()
{
if ($this->make(DefaultEmailChangeStrategy::class, [$this->form])->run()) {
$token = TokenFactory::makeConfirmOldMailToken($this->form->getUser()->id);
$mailService = MailFactory::makeReconfirmationMailerService($this->form->getUser(), $token);
if ($mailService->run()) {
// unset flags if they exist
$this->form->getUser()->flags &= ~User::NEW_EMAIL_CONFIRMED;
$this->form->getUser()->flags &= ~User::OLD_EMAIL_CONFIRMED;
if ($this->form->getUser()->save(false)) {
Yii::$app
->session
->setFlash(
'info',
Yii::t(
'usuario',
'We have sent confirmation links to both old and new email addresses. '.
'You must click both links to complete your request.'
)
);
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,26 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Traits;
use Da\User\Component\AuthDbManagerComponent;
use Yii;
trait AuthManagerAwareTrait
{
/**
* @return AuthDbManagerComponent|\yii\rbac\ManagerInterface
*/
public function getAuthManager()
{
return Yii::$app->getAuthManager();
}
}

View File

@ -0,0 +1,64 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Traits;
use Da\User\Helper\AuthHelper;
use Da\User\Helper\ClassMapHelper;
use Yii;
use yii\di\Container;
/**
* @property-read Container $di
* @property-ready Da\User\Helper\AuthHelper $auth
* @property-ready Da\User\Helper\ClassMapHelper $classMap
*/
trait ContainerAwareTrait
{
/**
* @return Container
*/
public function getDi()
{
return Yii::$container;
}
/**
* Gets a class from the container.
*
* @param string $class he class name or an alias name (e.g. `foo`) that was previously registered via [[set()]]
* or [[setSingleton()]]
* @param array $params constructor parameters
* @param array $config attributes
*
* @return object
*/
public function make($class, $params = [], $config = [])
{
return $this->getDi()->get($class, $params, $config);
}
/**
* @return \Da\User\Helper\AuthHelper
*/
public function getAuth()
{
return $this->getDi()->get(AuthHelper::class);
}
/**
* @return \Da\User\Helper\ClassMapHelper
*/
public function getClassMap()
{
return $this->getDi()->get(ClassMapHelper::class);
}
}

View File

@ -0,0 +1,29 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Traits;
use Da\User\Module;
use Yii;
/**
* @property-read Module $module
*/
trait ModuleAwareTrait
{
/**
* @return Module
*/
public function getModule()
{
return Yii::$app->getModule('user');
}
}

View File

@ -0,0 +1,41 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Validator;
use Da\User\Contracts\ValidatorInterface;
use yii\base\Model;
use Yii;
use yii\bootstrap\ActiveForm;
use yii\web\Response;
class AjaxRequestModelValidator implements ValidatorInterface
{
protected $model;
public function __construct(Model $model)
{
$this->model = $model;
}
public function validate()
{
$request = Yii::$app->request;
if ($request->getIsAjax() && !$request->getIsPjax()) {
if ($this->model->load($request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
echo json_encode(ActiveForm::validate($this->model));
Yii::$app->end();
}
}
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Validator;
use Da\User\Traits\AuthManagerAwareTrait;
use Yii;
use yii\validators\Validator;
class RbacItemsValidator extends Validator
{
use AuthManagerAwareTrait;
protected function validateValue($value)
{
if (!is_array($value)) {
return [Yii::t('usuario', 'Invalid value'), []];
}
foreach ($value as $item) {
if ($this->getAuthManager()->getItem($item) == null) {
return [Yii::t('usuario', 'There is neither role nor permission with name "{0}"', [$item]), []];
}
}
}
}

View File

@ -0,0 +1,36 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Validator;
use ReflectionClass;
use Exception;
use yii\validators\Validator;
use Yii;
class RbacRuleValidator extends Validator
{
protected function validateValue($value)
{
try {
$class = new ReflectionClass($value);
} catch (Exception $e) {
return [Yii::t('usuario', 'Class "{0}" does not exist', $value), []];
}
if ($class->isInstantiable() == false) {
return [Yii::t('usuario', 'Rule class can not be instantiated'), []];
}
if ($class->isSubclassOf('\yii\rbac\Rule') == false) {
return [Yii::t('usuario', 'Rule class must extend "yii\\rbac\\Rule"'), []];
}
}
}

View File

@ -0,0 +1,29 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Validator;
use Da\User\Contracts\ValidatorInterface;
class TimeZoneValidator implements ValidatorInterface
{
protected $timezone;
public function __construct($timezone)
{
$this->timezone = $timezone;
}
public function validate()
{
return in_array($this->timezone, timezone_identifiers_list());
}
}

View File

@ -0,0 +1,79 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Widget;
use Da\User\Model\Assignment;
use Da\User\Service\UpdateAuthAssignmentsService;
use Da\User\Traits\AuthManagerAwareTrait;
use Da\User\Traits\ContainerAwareTrait;
use yii\base\InvalidConfigException;
use yii\base\Widget;
use yii\helpers\ArrayHelper;
class AssignmentsWidget extends Widget
{
use AuthManagerAwareTrait;
use ContainerAwareTrait;
/**
* @var int ID of the user to whom auth items will be assigned
*/
public $userId;
/**
* @var string[] the post parameters
*/
public $params = [];
/**
* {@inheritdoc}
*
* @throws InvalidConfigException
*/
public function init()
{
parent::init();
if ($this->userId === null) {
throw new InvalidConfigException(__CLASS__.'::$userId is required');
}
}
/**
* {@inheritdoc}
*/
public function run()
{
$model = $this->make(Assignment::class, [], ['user_id' => $this->userId]);
if ($model->load($this->params)) {
$this->make(UpdateAuthAssignmentsService::class, [$model])->run();
}
return $this->render('/widgets/assignments/form', [
'model' => $model,
'availableItems' => $this->getAvailableItems(),
]);
}
/**
* Returns all available auth items to be attached to the user.
*
* @return array
*/
protected function getAvailableItems()
{
return ArrayHelper::map($this->getAuthManager()->getItems(), 'name', function ($item) {
return empty($item->description)
? $item->name
: $item->name.' ('.$item->description.')';
});
}
}

View File

@ -0,0 +1,64 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Widget;
use Yii;
use yii\authclient\ClientInterface;
use yii\authclient\widgets\AuthChoice;
use yii\authclient\widgets\AuthChoiceAsset;
use yii\helpers\Html;
use yii\helpers\Url;
class ConnectWidget extends AuthChoice
{
/**
* @var array|null An array of user's accounts
*/
public $accounts;
/**
* {@inheritdoc}
*/
public function init()
{
AuthChoiceAsset::register(Yii::$app->view);
if ($this->popupMode) {
Yii::$app->view->registerJs("\$('#".$this->getId()."').authchoice();");
}
$this->options['id'] = $this->getId();
echo Html::beginTag('div', $this->options);
}
/**
* {@inheritdoc}
*/
public function createClientUrl($provider)
{
if ($this->isConnected($provider)) {
return Url::to(['/user/settings/disconnect', 'id' => $this->accounts[$provider->getId()]->id]);
} else {
return parent::createClientUrl($provider);
}
}
/**
* Checks if provider already connected to user.
*
* @param ClientInterface $provider
*
* @return bool
*/
public function isConnected(ClientInterface $provider)
{
return $this->accounts != null && isset($this->accounts[$provider->getId()]);
}
}

View File

@ -0,0 +1,31 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Widget;
use Da\User\Form\LoginForm;
use Yii;
use yii\base\Widget;
class LoginWidget extends Widget
{
public $validate = true;
public function run()
{
return $this->render(
'/widgets/login',
[
'model' => Yii::createObject(LoginForm::class),
]
);
}
}

View File

@ -0,0 +1,198 @@
<?php
/**
* Message translations.
*
* This file is automatically generated by 'yii message/extract' command.
* It contains the localizable messages extracted from source code.
* You may modify this file by translating the extracted messages.
*
* Each array element represents the translation (value) of a message (key).
* If the value is empty, the message is considered as not translated.
* Messages that no longer need translation will have their translations
* enclosed between a pair of '@@' marks.
*
* Message string can be used with plural forms format. Check i18n section
* of the guide for details.
*
* NOTE: this file must be saved in UTF-8 encoding.
*/
return [
'(not set)' => '',
'A confirmation message has been sent to your new email address' => '',
'A message has been sent to your email address. ' => '',
'A new confirmation link has been sent' => '',
'A password will be generated automatically if not provided' => '',
'Account' => '',
'Account confirmation' => '',
'Account details' => '',
'Account details have been updated' => '',
'Account settings' => '',
'Already registered? Sign in!' => '',
'An email has been sent with instructions for resetting your password' => '',
'An error occurred processing your request' => '',
'Are you sure you want to block this user?' => '',
'Are you sure you want to confirm this user?' => '',
'Are you sure you want to delete this user?' => '',
'Are you sure you want to unblock this user?' => '',
'Are you sure? Deleted user can not be restored' => '',
'Are you sure? There is no going back' => '',
'Assignments' => '',
'Assignments have been updated' => '',
'Auth item with such name already exists' => '',
'Authorization item successfully created.' => '',
'Authorization item successfully removed.' => '',
'Authorization item successfully updated.' => '',
'Awesome, almost there. ' => '',
'Bio' => '',
'Block' => '',
'Block status' => '',
'Blocked at {0, date, MMMM dd, YYYY HH:mm}' => '',
'Change your avatar at Gravatar.com' => '',
'Children' => '',
'Class "{0}" does not exist' => '',
'Complete password reset on {0}' => '',
'Confirm' => '',
'Confirm account on {0}' => '',
'Confirm email change on {0}' => '',
'Confirmation' => '',
'Confirmation status' => '',
'Confirmation time' => '',
'Confirmed' => '',
'Confirmed at {0, date, MMMM dd, YYYY HH:mm}' => '',
'Connect' => '',
'Continue' => '',
'Create' => '',
'Create a user account' => '',
'Create new permission' => '',
'Create new role' => '',
'Credentials will be sent to the user by email' => '',
'Current password' => '',
'Current password is not valid' => '',
'Delete' => '',
'Delete account' => '',
'Description' => '',
'Didn\'t receive confirmation message?' => '',
'Disconnect' => '',
'Don\'t have an account? Sign up!' => '',
'Email' => '',
'Email (public)' => '',
'Error occurred while changing password' => '',
'Error occurred while confirming user' => '',
'Error occurred while deleting user' => '',
'Finish' => '',
'Forgot password?' => '',
'Gravatar email' => '',
'Hello' => '',
'If you already registered, sign in and connect this account on settings page' => '',
'If you cannot click the link, please try pasting the text into your browser' => '',
'If you did not make this request you can ignore this email' => '',
'In order to complete your registration, please click the link below' => '',
'In order to complete your request, please click the link below' => '',
'In order to finish your registration, we need you to enter following fields' => '',
'Information' => '',
'Invalid login or password' => '',
'Invalid or expired link' => '',
'Invalid value' => '',
'It will be deleted forever' => '',
'Items' => '',
'Joined on {0, date}' => '',
'Location' => '',
'Login' => '',
'Logout' => '',
'Manage users' => '',
'Name' => '',
'Networks' => '',
'New email' => '',
'New password' => '',
'New permission' => '',
'New role' => '',
'New user' => '',
'Not blocked' => '',
'Not found' => '',
'Once you delete your account, there is no going back' => '',
'Password' => '',
'Password has been changed' => '',
'Permissions' => '',
'Please be certain' => '',
'Please click the link below to complete your password reset' => '',
'Please fix following errors:' => '',
'Profile' => '',
'Profile details' => '',
'Profile details have been updated' => '',
'Profile settings' => '',
'Recover your password' => '',
'Recovery link is invalid or expired. Please try requesting a new one.' => '',
'Recovery message sent' => '',
'Registration IP' => '',
'Registration ip' => '',
'Registration on this website is disabled' => '',
'Registration time' => '',
'Remember me next time' => '',
'Request new confirmation message' => '',
'Reset your password' => '',
'Roles' => '',
'Rule' => '',
'Rule class can not be instantiated' => '',
'Rule class must extend "yii\\rbac\\Rule"' => '',
'Rule name' => '',
'Save' => '',
'Sign in' => '',
'Sign up' => '',
'Something went wrong' => '',
'Thank you for signing up on {0}' => '',
'Thank you, registration is now complete.' => '',
'The confirmation link is invalid or expired. Please try requesting a new one.' => '',
'There is neither role nor permission with name "{0}"' => '',
'This account has already been connected to another user' => '',
'This email address has already been taken' => '',
'This username has already been taken' => '',
'Time zone' => '',
'Time zone is not valid' => '',
'Unable to confirm user. Please, try again.' => '',
'Unable to create an account.' => '',
'Unable to create authorization item.' => '',
'Unable to delete user. Please, try again later.' => '',
'Unable to remove authorization item.' => '',
'Unable to send confirmation link' => '',
'Unable to update authorization item.' => '',
'Unable to update block status.' => '',
'Unblock' => '',
'Unconfirmed' => '',
'Update' => '',
'Update assignments' => '',
'Update permission' => '',
'Update role' => '',
'Update user account' => '',
'User block status has been updated.' => '',
'User has been confirmed' => '',
'User has been created' => '',
'User has been deleted' => '',
'User is not found' => '',
'Username' => '',
'Users' => '',
'VKontakte' => '',
'We couldn\'t re-send the mail to confirm your address. ' => '',
'We have generated a password for you' => '',
'We have received a request to change the email address for your account on {0}' => '',
'We have received a request to reset the password for your account on {0}' => '',
'We have sent confirmation links to both old and new email addresses. ' => '',
'Website' => '',
'Welcome to {0}' => '',
'Yandex' => '',
'You can assign multiple roles or permissions to user by using the form below' => '',
'You can connect multiple accounts to be able to log in using them' => '',
'You cannot remove your own account' => '',
'You need to confirm your email address' => '',
'Your account details have been updated' => '',
'Your account has been blocked' => '',
'Your account has been blocked.' => '',
'Your account has been completely deleted' => '',
'Your account has been connected' => '',
'Your account has been created' => '',
'Your account has been created and a message with further instructions has been sent to your email' => '',
'Your account on {0} has been created' => '',
'Your confirmation token is invalid or expired' => '',
'Your email address has been changed' => '',
'Your profile has been updated' => '',
'{0, date, MMMM dd, YYYY HH:mm}' => '',
];

View File

@ -0,0 +1,55 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
return [
'sourcePath' => __DIR__ . '/../../../User',
'messagePath' => __DIR__,
'languages' => [
'ca',
'da',
'de',
'de-DU',
'es',
'fa-IR',
'fi',
'fr',
'hr',
'hu',
'it',
'kk',
'lt',
'nl',
'pl',
'pt-BR',
'pt-PT',
'ro',
'ru',
'th',
'tr_TR',
'uk',
'vi',
'zh-CN',
],
'translator' => 'Yii::t',
'sort' => false,
'overwrite' => true,
'removeUnused' => false,
'only' => ['*.php'],
'except' => [
'.svn',
'.git',
'.gitignore',
'.gitkeep',
'.hgignore',
'.hgkeep',
],
'format' => 'php',
];

View File

@ -0,0 +1,198 @@
<?php
/**
* Message translations.
*
* This file is automatically generated by 'yii message/extract' command.
* It contains the localizable messages extracted from source code.
* You may modify this file by translating the extracted messages.
*
* Each array element represents the translation (value) of a message (key).
* If the value is empty, the message is considered as not translated.
* Messages that no longer need translation will have their translations
* enclosed between a pair of '@@' marks.
*
* Message string can be used with plural forms format. Check i18n section
* of the guide for details.
*
* NOTE: this file must be saved in UTF-8 encoding.
*/
return [
'(not set)' => '',
'A confirmation message has been sent to your new email address' => '',
'A message has been sent to your email address. ' => '',
'A new confirmation link has been sent' => '',
'A password will be generated automatically if not provided' => '',
'Account' => '',
'Account confirmation' => '',
'Account details' => '',
'Account details have been updated' => '',
'Account settings' => '',
'Already registered? Sign in!' => '',
'An email has been sent with instructions for resetting your password' => '',
'An error occurred processing your request' => '',
'Are you sure you want to block this user?' => '',
'Are you sure you want to confirm this user?' => '',
'Are you sure you want to delete this user?' => '',
'Are you sure you want to unblock this user?' => '',
'Are you sure? Deleted user can not be restored' => '',
'Are you sure? There is no going back' => '',
'Assignments' => '',
'Assignments have been updated' => '',
'Auth item with such name already exists' => '',
'Authorization item successfully created.' => '',
'Authorization item successfully removed.' => '',
'Authorization item successfully updated.' => '',
'Awesome, almost there. ' => '',
'Bio' => '',
'Block' => '',
'Block status' => '',
'Blocked at {0, date, MMMM dd, YYYY HH:mm}' => '',
'Change your avatar at Gravatar.com' => '',
'Children' => '',
'Class "{0}" does not exist' => '',
'Complete password reset on {0}' => '',
'Confirm' => '',
'Confirm account on {0}' => '',
'Confirm email change on {0}' => '',
'Confirmation' => '',
'Confirmation status' => '',
'Confirmation time' => '',
'Confirmed' => '',
'Confirmed at {0, date, MMMM dd, YYYY HH:mm}' => '',
'Connect' => '',
'Continue' => '',
'Create' => '',
'Create a user account' => '',
'Create new permission' => '',
'Create new role' => '',
'Credentials will be sent to the user by email' => '',
'Current password' => '',
'Current password is not valid' => '',
'Delete' => '',
'Delete account' => '',
'Description' => '',
'Didn\'t receive confirmation message?' => '',
'Disconnect' => '',
'Don\'t have an account? Sign up!' => '',
'Email' => '',
'Email (public)' => '',
'Error occurred while changing password' => '',
'Error occurred while confirming user' => '',
'Error occurred while deleting user' => '',
'Finish' => '',
'Forgot password?' => '',
'Gravatar email' => '',
'Hello' => '',
'If you already registered, sign in and connect this account on settings page' => '',
'If you cannot click the link, please try pasting the text into your browser' => '',
'If you did not make this request you can ignore this email' => '',
'In order to complete your registration, please click the link below' => '',
'In order to complete your request, please click the link below' => '',
'In order to finish your registration, we need you to enter following fields' => '',
'Information' => '',
'Invalid login or password' => '',
'Invalid or expired link' => '',
'Invalid value' => '',
'It will be deleted forever' => '',
'Items' => '',
'Joined on {0, date}' => '',
'Location' => '',
'Login' => '',
'Logout' => '',
'Manage users' => '',
'Name' => '',
'Networks' => '',
'New email' => '',
'New password' => '',
'New permission' => '',
'New role' => '',
'New user' => '',
'Not blocked' => '',
'Not found' => '',
'Once you delete your account, there is no going back' => '',
'Password' => '',
'Password has been changed' => '',
'Permissions' => '',
'Please be certain' => '',
'Please click the link below to complete your password reset' => '',
'Please fix following errors:' => '',
'Profile' => '',
'Profile details' => '',
'Profile details have been updated' => '',
'Profile settings' => '',
'Recover your password' => '',
'Recovery link is invalid or expired. Please try requesting a new one.' => '',
'Recovery message sent' => '',
'Registration IP' => '',
'Registration ip' => '',
'Registration on this website is disabled' => '',
'Registration time' => '',
'Remember me next time' => '',
'Request new confirmation message' => '',
'Reset your password' => '',
'Roles' => '',
'Rule' => '',
'Rule class can not be instantiated' => '',
'Rule class must extend "yii\\rbac\\Rule"' => '',
'Rule name' => '',
'Save' => '',
'Sign in' => '',
'Sign up' => '',
'Something went wrong' => '',
'Thank you for signing up on {0}' => '',
'Thank you, registration is now complete.' => '',
'The confirmation link is invalid or expired. Please try requesting a new one.' => '',
'There is neither role nor permission with name "{0}"' => '',
'This account has already been connected to another user' => '',
'This email address has already been taken' => '',
'This username has already been taken' => '',
'Time zone' => '',
'Time zone is not valid' => '',
'Unable to confirm user. Please, try again.' => '',
'Unable to create an account.' => '',
'Unable to create authorization item.' => '',
'Unable to delete user. Please, try again later.' => '',
'Unable to remove authorization item.' => '',
'Unable to send confirmation link' => '',
'Unable to update authorization item.' => '',
'Unable to update block status.' => '',
'Unblock' => '',
'Unconfirmed' => '',
'Update' => '',
'Update assignments' => '',
'Update permission' => '',
'Update role' => '',
'Update user account' => '',
'User block status has been updated.' => '',
'User has been confirmed' => '',
'User has been created' => '',
'User has been deleted' => '',
'User is not found' => '',
'Username' => '',
'Users' => '',
'VKontakte' => '',
'We couldn\'t re-send the mail to confirm your address. ' => '',
'We have generated a password for you' => '',
'We have received a request to change the email address for your account on {0}' => '',
'We have received a request to reset the password for your account on {0}' => '',
'We have sent confirmation links to both old and new email addresses. ' => '',
'Website' => '',
'Welcome to {0}' => '',
'Yandex' => '',
'You can assign multiple roles or permissions to user by using the form below' => '',
'You can connect multiple accounts to be able to log in using them' => '',
'You cannot remove your own account' => '',
'You need to confirm your email address' => '',
'Your account details have been updated' => '',
'Your account has been blocked' => '',
'Your account has been blocked.' => '',
'Your account has been completely deleted' => '',
'Your account has been connected' => '',
'Your account has been created' => '',
'Your account has been created and a message with further instructions has been sent to your email' => '',
'Your account on {0} has been created' => '',
'Your confirmation token is invalid or expired' => '',
'Your email address has been changed' => '',
'Your profile has been updated' => '',
'{0, date, MMMM dd, YYYY HH:mm}' => '',
];

Some files were not shown because too many files have changed in this diff Show More