diff --git a/docs/events/user-events.md b/docs/events/user-events.md old mode 100644 new mode 100755 index 3c2edd2..79eac2b --- a/docs/events/user-events.md +++ b/docs/events/user-events.md @@ -20,7 +20,9 @@ On Controllers - **UserEvent::EVENT_BEFORE_UNBLOCK**: Occurs before a user is being un-blocked - **UserEvent::EVENT_AFTER_UNBLOCK**: Occurs after a user is being un-blocked - **UserEvent::EVENT_BEFORE_SWITCH_IDENTITY**: Occurs before a user is being impersonated by admin - - **UserEvent::EVENT_AFTER_SWITCH_IDENTITY**: Occurs after a user his being impersonated by admin + - **UserEvent::EVENT_AFTER_SWITCH_IDENTITY**: Occurs after a user his being impersonated by admin + - **SessionEvent::EVENT_BEFORE_TERMINATE_USER_SESSIONS** + - **SessionEvent::EVENT_AFTER_TERMINATE_USER_SESSIONS** - **RegistrationController** @@ -41,6 +43,10 @@ On Controllers - **UserEvent::EVENT_BEFORE_DELETE**: Occurs before the user account is deleted - **UserEvent::EVENT_AFTER_DELETE**: Occurs after the user account is deleted +- **SessionController** + - **SessionEvent::EVENT_BEFORE_TERMINATE_USER_SESSIONS**: Occurs before the user sessions is terminated + - **SessionEvent::EVENT_AFTER_TERMINATE_USER_SESSIONS**: Occurs after the user sessions is terminated + On Models --------- diff --git a/docs/helpful-guides/how-to-use-session-history.md b/docs/helpful-guides/how-to-use-session-history.md new file mode 100755 index 0000000..f392f8e --- /dev/null +++ b/docs/helpful-guides/how-to-use-session-history.md @@ -0,0 +1,60 @@ +How to enable session history +============================ + +Session history list user sessions. + +User can delete all sessions except current. + +Configure Module and Application +-------------------------------- + +```php + +// ... + +'modules' => [ + 'user' => [ + 'class' => Da\User\Module::class, + 'enableSessionHistory' => true, + ] +], + +// ... + +'components' => [ + 'session' => Da\User\Service\SessionHistory\SessionHistoryDecorator::class, +] + +// ... + +'container' => [ + 'singletons' => [ + Da\User\Service\SessionHistory\TerminateSessionsServiceInterface::class => Da\User\Service\SessionHistory\TerminateSessionsService::class + ] +] + +// ... + +'controllerMap' => [ + 'migrate' => [ + ... + 'migrationNamespaces' => [ + 'Da\User\Migration\Session', + ], + ], +], + +``` + +Additionally for upping migration can use +``` +./yii migrate --migrationNamespaces=Da\\User\\Migration\Session +``` + +Setting user screenshot: +![Settings user screenshot](./session-history/settings.png) + +Admin screenshot: +![Admin screenshot](./session-history/admin.png) + +© [2amigos](http://www.2amigos.us/) 2013-2019 diff --git a/docs/helpful-guides/session-history/admin.png b/docs/helpful-guides/session-history/admin.png new file mode 100755 index 0000000..7328174 Binary files /dev/null and b/docs/helpful-guides/session-history/admin.png differ diff --git a/docs/helpful-guides/session-history/settings.png b/docs/helpful-guides/session-history/settings.png new file mode 100755 index 0000000..d226ce1 Binary files /dev/null and b/docs/helpful-guides/session-history/settings.png differ diff --git a/docs/index.md b/docs/index.md old mode 100644 new mode 100755 index 4cf2e33..f5b9517 --- a/docs/index.md +++ b/docs/index.md @@ -188,6 +188,7 @@ Helpful Guides - [How to Switch Identities](helpful-guides/how-to-switch-identities.md) - [Separate Frontend and Backend Sessions](helpful-guides/separate-frontend-and-backend-sessions.md) - [Social Network Authentication](helpful-guides/social-network-authentication.md) +- [How to Enable session history](helpful-guides/how-to-use-session-history.md) Contributing ------------ diff --git a/docs/installation/configuration-options.md b/docs/installation/configuration-options.md old mode 100644 new mode 100755 index 3b9cf50..d4bb406 --- a/docs/installation/configuration-options.md +++ b/docs/installation/configuration-options.md @@ -3,6 +3,22 @@ Configuration Options The module comes with a set of attributes to configure. The following is the list of all available options: +#### enableSessionHistory (Type: `boolean, integer`, Default value: `false`) + +If this option is to `true`, session history will be kept, [more](../helpful-guides/how-to-use-session-history.md). + +#### numberSessionHistory (Type: `boolean, integer`, Default value: `false`) + +Number of expired storing records `session history`, values: +- `false` Store all records without deleting +- `integer` Count of records for storing + +#### timeoutSessionHistory (Type: `boolean, integer`, Default value: `false`) + +How long store `session history` after expiring, values: +- `false` Store all records without deleting +- `integer` Time for storing after expiring in seconds + #### enableTwoFactorAuthentication (type: `boolean`, default: `false`) Setting this attribute will allow users to configure their login process with two-factor authentication. diff --git a/src/User/Bootstrap.php b/src/User/Bootstrap.php old mode 100644 new mode 100755 index 07a8d92..0ae7e8d --- a/src/User/Bootstrap.php +++ b/src/User/Bootstrap.php @@ -16,7 +16,9 @@ use Da\User\Contracts\AuthManagerInterface; use Da\User\Controller\SecurityController; use Da\User\Event\FormEvent; use Da\User\Helper\ClassMapHelper; +use Da\User\Model\SessionHistory; use Da\User\Model\User; +use Da\User\Search\SessionHistorySearch; use Yii; use yii\authclient\Collection; use yii\base\Application; @@ -128,7 +130,7 @@ class Bootstrap implements BootstrapInterface $model = is_array($definition) ? $definition['class'] : $definition; $name = substr($class, strrpos($class, '\\') + 1); $modelClassMap[$class] = $model; - if (in_array($name, ['User', 'Profile', 'Token', 'SocialNetworkAccount'])) { + if (in_array($name, ['User', 'Profile', 'Token', 'SocialNetworkAccount', 'SessionHistory'])) { $di->set( "Da\\User\\Query\\{$name}Query", function () use ($model) { @@ -315,10 +317,12 @@ class Bootstrap implements BootstrapInterface 'Assignment' => 'Da\User\Model\Assignment', 'Permission' => 'Da\User\Model\Permission', 'Role' => 'Da\User\Model\Role', + 'SessionHistory' => SessionHistory::class, // --- search 'UserSearch' => 'Da\User\Search\UserSearch', 'PermissionSearch' => 'Da\User\Search\PermissionSearch', 'RoleSearch' => 'Da\User\Search\RoleSearch', + 'SessionHistorySearch' => SessionHistorySearch::class, // --- forms 'RegistrationForm' => 'Da\User\Form\RegistrationForm', 'ResendForm' => 'Da\User\Form\ResendForm', @@ -338,11 +342,13 @@ class Bootstrap implements BootstrapInterface 'Assignment', 'Permission', 'Role', + 'SessionHistory' ], 'Da\User\Search' => [ 'UserSearch', 'PermissionSearch', 'RoleSearch', + 'SessionHistorySearch', ], 'Da\User\Form' => [ 'RegistrationForm', diff --git a/src/User/Controller/AdminController.php b/src/User/Controller/AdminController.php old mode 100644 new mode 100755 index d8990ba..36b0d8b --- a/src/User/Controller/AdminController.php +++ b/src/User/Controller/AdminController.php @@ -17,9 +17,11 @@ use Da\User\Filter\AccessRuleFilter; use Da\User\Model\Profile; use Da\User\Model\User; use Da\User\Query\UserQuery; +use Da\User\Search\SessionHistorySearch; use Da\User\Search\UserSearch; use Da\User\Service\PasswordExpireService; use Da\User\Service\PasswordRecoveryService; +use Da\User\Service\SessionHistory\TerminateUserSessionsService; use Da\User\Service\SwitchIdentityService; use Da\User\Service\UserBlockService; use Da\User\Service\UserConfirmationService; @@ -66,7 +68,7 @@ class AdminController extends Controller */ public function beforeAction($action) { - if (in_array($action->id, ['index', 'update', 'update-profile', 'info', 'assignments'], true)) { + if (in_array($action->id, ['index', 'update', 'update-profile', 'info', 'assignments', 'session-history'], true)) { Url::remember('', 'actions-redirect'); } @@ -88,6 +90,7 @@ class AdminController extends Controller 'switch-identity' => ['post'], 'password-reset' => ['post'], 'force-password-change' => ['post'], + 'terminate-sessions' => ['post'], ], ], 'access' => [ @@ -101,6 +104,11 @@ class AdminController extends Controller 'actions' => ['switch-identity'], 'roles' => ['@'], ], + [ + 'allow' => $this->getModule()->enableSessionHistory, + 'actions' => ['session-history', 'terminate-sessions'], + 'roles' => ['admin'], + ], [ 'allow' => true, 'roles' => ['admin'], @@ -346,4 +354,33 @@ class AdminController extends Controller } $this->redirect(['index']); } + + /** + * Display list session history + */ + public function actionSessionHistory($id) + { + $searchModel = new SessionHistorySearch([ + 'user_id' => $id, + ]); + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + + $user = $this->userQuery->where(['id' => $id])->one(); + + return $this->render('_session-history', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + 'user' => $user, + ]); + } + + /** + * Terminate all session user + */ + public function actionTerminateSessions($id) + { + $this->make(TerminateUserSessionsService::class, [$id])->run(); + + return $this->redirect(Url::previous('actions-redirect')); + } } diff --git a/src/User/Controller/SettingsController.php b/src/User/Controller/SettingsController.php old mode 100644 new mode 100755 index 0a010a5..ac88424 --- a/src/User/Controller/SettingsController.php +++ b/src/User/Controller/SettingsController.php @@ -26,7 +26,9 @@ use Da\User\Module; use Da\User\Query\ProfileQuery; use Da\User\Query\SocialNetworkAccountQuery; use Da\User\Query\UserQuery; +use Da\User\Search\SessionHistorySearch; use Da\User\Service\EmailChangeService; +use Da\User\Service\SessionHistory\TerminateUserSessionsService; use Da\User\Service\TwoFactorQrCodeUriGeneratorService; use Da\User\Traits\ContainerAwareTrait; use Da\User\Traits\ModuleAwareTrait; @@ -91,7 +93,8 @@ class SettingsController extends Controller 'actions' => [ 'disconnect' => ['post'], 'delete' => ['post'], - 'two-factor-disable' => ['post'] + 'two-factor-disable' => ['post'], + 'terminate-sessions' => ['post'], ], ], 'access' => [ @@ -111,7 +114,7 @@ class SettingsController extends Controller 'delete', 'two-factor', 'two-factor-enable', - 'two-factor-disable' + 'two-factor-disable', ], 'roles' => ['@'], ], @@ -119,7 +122,12 @@ class SettingsController extends Controller 'allow' => true, 'actions' => ['confirm'], 'roles' => ['?', '@'], - ] + ], + [ + 'allow' => $this->getModule()->enableSessionHistory, + 'actions' => ['session-history', 'terminate-sessions'], + 'roles' => ['@'], + ], ], ], ]; @@ -139,9 +147,9 @@ class SettingsController extends Controller } /** - * * - * @var ProfileEvent $event + * + * @var ProfileEvent $event */ $event = $this->make(ProfileEvent::class, [$profile]); @@ -175,7 +183,8 @@ class SettingsController extends Controller throw new NotFoundHttpException(); } return $this->render( - 'privacy', [ + 'privacy', + [ 'module' => $this->module ] ); @@ -196,9 +205,9 @@ class SettingsController extends Controller throw new NotFoundHttpException(); } /** - * * - * @var GdprDeleteForm $form + * + * @var GdprDeleteForm $form */ $form = $this->make(GdprDeleteForm::class); @@ -249,7 +258,8 @@ class SettingsController extends Controller } return $this->render( - 'gdpr-delete', [ + 'gdpr-delete', + [ 'model' => $form, ] ); @@ -258,9 +268,9 @@ class SettingsController extends Controller public function actionGdprConsent() { /** - * * - * @var User $user + * + * @var User $user */ $user = Yii::$app->user->identity; if ($user->gdpr_consent) { @@ -270,7 +280,9 @@ class SettingsController extends Controller $model->addRule('gdpr_consent', 'boolean'); $model->addRule('gdpr_consent', 'default', ['value' => 0, 'skipOnEmpty' => false]); $model->addRule( - 'gdpr_consent', 'compare', [ + 'gdpr_consent', + 'compare', + [ 'compareValue' => true, 'message' => Yii::t('usuario', 'Your consent is required to work with this site'), 'when' => function () { @@ -289,7 +301,8 @@ class SettingsController extends Controller } return $this->render( - 'gdpr-consent', [ + 'gdpr-consent', + [ 'model' => $model, 'gdpr_consent_hint' => $this->module->getConsentMessage(), ] @@ -345,9 +358,9 @@ class SettingsController extends Controller public function actionAccount() { /** -* +* * - * @var SettingsForm $form + * @var SettingsForm $form */ $form = $this->make(SettingsForm::class); $event = $this->make(UserEvent::class, [$form->getUser()]); @@ -416,9 +429,9 @@ class SettingsController extends Controller } /** - * * - * @var User $user + * + * @var User $user */ $user = Yii::$app->user->identity; $event = $this->make(UserEvent::class, [$user]); @@ -436,9 +449,9 @@ class SettingsController extends Controller public function actionTwoFactor($id) { /** - * * - * @var User $user + * + * @var User $user */ $user = $this->userQuery->whereId($id)->one(); @@ -456,9 +469,9 @@ class SettingsController extends Controller Yii::$app->response->format = Response::FORMAT_JSON; /** - * * - * @var User $user + * + * @var User $user */ $user = $this->userQuery->whereId($id)->one(); @@ -487,12 +500,12 @@ class SettingsController extends Controller public function actionTwoFactorDisable($id) { /** - * * - * @var User $user + * + * @var User $user */ $user = $this->userQuery->whereId($id)->one(); - + if (null === $user) { throw new NotFoundHttpException(); } @@ -511,7 +524,33 @@ class SettingsController extends Controller } /** - * @param $id + * Display list session history. + */ + public function actionSessionHistory() + { + $searchModel = new SessionHistorySearch([ + 'user_id' => Yii::$app->user->id, + ]); + $dataProvider = $searchModel->search(Yii::$app->request->queryParams); + + return $this->render('session-history', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + } + + /** + * Terminate all session user + */ + public function actionTerminateSessions() + { + $this->make(TerminateUserSessionsService::class, [Yii::$app->user->id])->run(); + + return $this->redirect(['session-history']); + } + + /** + * @param $id * @throws ForbiddenHttpException * @throws NotFoundHttpException * @throws \Exception @@ -521,9 +560,9 @@ class SettingsController extends Controller protected function disconnectSocialNetwork($id) { /** - * * - * @var SocialNetworkAccount $account + * + * @var SocialNetworkAccount $account */ $account = $this->socialNetworkAccountQuery->whereId($id)->one(); diff --git a/src/User/Event/SessionEvent.php b/src/User/Event/SessionEvent.php new file mode 100755 index 0000000..196d8e1 --- /dev/null +++ b/src/User/Event/SessionEvent.php @@ -0,0 +1,37 @@ + + * + * 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; + +/** + * @property-read User $user + */ +class SessionEvent extends Event +{ + const EVENT_BEFORE_TERMINATE_USER_SESSIONS = 'beforeTerminateUserSessions'; + const EVENT_AFTER_TERMINATE_USER_SESSIONS = 'afterTerminateUserSessions'; + + protected $user; + + public function __construct(User $user, array $config = []) + { + $this->user = $user; + parent::__construct($config); + } + + public function getUser() + { + return $this->user; + } +} diff --git a/src/User/Migration/Session/m000000_000001_create_session_history_table.php b/src/User/Migration/Session/m000000_000001_create_session_history_table.php new file mode 100755 index 0000000..a33ccad --- /dev/null +++ b/src/User/Migration/Session/m000000_000001_create_session_history_table.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Da\User\Migration\Session; + +use Da\User\Helper\MigrationHelper; +use yii\db\Migration; + + +class m000000_000001_create_session_history_table extends Migration +{ + const SESSION_HISTORY_TABLE = '{{%session_history}}'; + const USER_TABLE = '{{%user}}'; + + /** + * {@inheritdoc} + */ + public function safeUp() + { + $this->createTable(self::SESSION_HISTORY_TABLE, [ + 'user_id' => $this->integer(), + 'session_id' => $this->string()->null(), + 'user_agent' => $this->string()->notNull(), + 'ip' => $this->string(45)->notNull(), + 'created_at' => $this->integer()->notNull(), + 'updated_at' => $this->integer()->notNull(), + ]); + + $this->createIndex( + '{{%session_history_user_id}}', + self::SESSION_HISTORY_TABLE, + ['user_id'] + ); + + $this->createIndex( + '{{%session_history_session_id}}', + self::SESSION_HISTORY_TABLE, + ['session_id'] + ); + + $this->createIndex( + '{{%session_history_updated_at}}', + self::SESSION_HISTORY_TABLE, + ['updated_at'] + ); + + $this->addForeignKey( + '{{%fk_user_session_history}}', + self::SESSION_HISTORY_TABLE, + 'user_id', + self::USER_TABLE, + 'id', + 'CASCADE', + MigrationHelper::isMicrosoftSQLServer($this->db->driverName) ? 'NO ACTION' : 'RESTRICT' + ); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->dropTable(self::SESSION_HISTORY_TABLE); + } +} diff --git a/src/User/Model/SessionHistory.php b/src/User/Model/SessionHistory.php new file mode 100755 index 0000000..4331e55 --- /dev/null +++ b/src/User/Model/SessionHistory.php @@ -0,0 +1,110 @@ + + * + * 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\Module; +use Da\User\Query\SessionHistoryQuery; +use Da\User\Traits\ModuleAwareTrait; +use Yii; +use yii\behaviors\TimestampBehavior; +use yii\db\ActiveRecord; +use yii\db\ActiveQuery; + +/** + * @property int $user_id + * @property string $session_id + * @property string $user_agent + * @property string $ip + * @property int $created_at + * @property int $updated_at + * + * @property User $user + * @property bool $isActive + * + * Dependencies: + * @property-read Module $module + */ +class SessionHistory extends ActiveRecord +{ + use ModuleAwareTrait; + + /** + * {@inheritdoc} + */ + public static function tableName() + { + return '{{%session_history}}'; + } + + /** @inheritdoc */ + public function behaviors() + { + return [ + [ + 'class' => TimestampBehavior::class, + 'updatedAtAttribute' => false, + ] + ]; + } + + /** + * {@inheritdoc} + */ + public function attributeLabels() + { + return [ + 'user_id' => Yii::t('usuario', 'User ID'), + 'session_id' => Yii::t('usuario', 'Session ID'), + 'user_agent' => Yii::t('usuario', 'User agent'), + 'ip' => Yii::t('usuario', 'IP'), + 'created_at' => Yii::t('usuario', 'Created at'), + 'updated_at' => Yii::t('usuario', 'Last activity'), + ]; + } + + /** + * @return bool Whether the session is an active or not. + */ + public function getIsActive() + { + return isset($this->session_id) && $this->updated_at + $this->getModule()->rememberLoginLifespan > time(); + } + + /** + * @return ActiveQuery + */ + public function getUser() + { + return $this->hasOne($this->module->classMap['User'], ['id' => 'user_id']); + } + + /** @inheritdoc */ + public function beforeSave($insert) + { + if ($insert && empty($this->session_id)) { + $this->setAttribute('session_id', Yii::$app->session->getId()); + } + + return parent::beforeSave($insert); + } + + /** @inheritdoc */ + public static function primaryKey() + { + return ['user_id', 'session_id']; + } + + public static function find() + { + return new SessionHistoryQuery(static::class); + } +} diff --git a/src/User/Module.php b/src/User/Module.php old mode 100644 new mode 100755 index 05af05e..3522be9 --- a/src/User/Module.php +++ b/src/User/Module.php @@ -22,6 +22,21 @@ use yii\helpers\Html; */ class Module extends BaseModule { + /** + * @var bool Enable the 'session history' function + * Using with {@see SessionHistoryDecorator} + */ + public $enableSessionHistory = false; + /** + * @var int|bool The number of 'session history' records will be stored for user + * if equals false records will not be deleted + */ + public $numberSessionHistory = false; + /** + * @var int|bool The time after which the expired 'session history' will be deleted + * if equals false records will not be deleted + */ + public $timeoutSessionHistory = false; /** * @var bool whether to enable european G.D.P.R. compliance. * This will add a few elements to comply with european general data protection regulation. @@ -251,4 +266,20 @@ class Module extends BaseModule return $this->gdprConsentMessage ?: $defaultConsentMessage; } + + /** + * @return bool + */ + public function hasNumberSessionHistory() + { + return $this->numberSessionHistory !== false && $this->numberSessionHistory > 0; + } + + /** + * @return bool + */ + public function hasTimeoutSessionHistory() + { + return $this->timeoutSessionHistory !== false && $this->timeoutSessionHistory > 0; + } } diff --git a/src/User/Query/SessionHistoryCondition.php b/src/User/Query/SessionHistoryCondition.php new file mode 100755 index 0000000..c774c66 --- /dev/null +++ b/src/User/Query/SessionHistoryCondition.php @@ -0,0 +1,158 @@ + + * + * 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\Traits\ModuleAwareTrait; +use yii\web\Session; +use Yii; + +class SessionHistoryCondition +{ + use ModuleAwareTrait; + + private $session; + + public function __construct(Session $session) + { + $this->session = $session; + } + + public function unbindSession() + { + return ['session_id' => null]; + } + + public function bySession($sessionId) + { + return ['session_id' => $sessionId]; + } + + public function byUser($userId) + { + return [ + 'user_id' => $userId, + ]; + } + + public function byUserSession($userId, $sessionId) + { + return [ + 'user_id' => $userId, + 'session_id' => $sessionId, + ]; + } + + public function inactive($userId = null) + { + $where = [ + 'AND', + ['session_id' => null] + ]; + + if (isset($userId)) { + $where[] = $this->byUser($userId); + } + + return $where; + } + + public function expired($userId = null) + { + $where = [ + 'AND', + ['<', 'updated_at', $this->getExpiredTime()] + ]; + + if (isset($userId)) { + $where[] = $this->byUser($userId); + } + + return $where; + } + + public function expiredInactive($userId = null) + { + return [ + 'OR', + $this->expired($userId), + $this->inactive($userId), + ]; + } + + public function shouldDeleteBefore($updatedAt, $userId) + { + $condition = ['<', 'updated_at', $updatedAt]; + if ($updatedAt > $this->getExpiredTime()) { + $condition = [ + 'OR', + [ + 'AND', + $this->inactive(), + $condition, + ], + $this->expired() + ]; + } + + return [ + 'AND', + $this->byUser($userId), + $condition, + ]; + } + + /** + * @return int + */ + public function getExpiredTime() + { + $module = $this->getModule(); + $time = time() - max($module->rememberLoginLifespan, $this->session->getTimeout()); + if (false === $module->hasTimeoutSessionHistory()) { + return $time; + } + + return $time - $module->timeoutSessionHistory; + } + + public function inactiveData() + { + return [ + 'session_id' => null, + ]; + } + + /** + * @return array + */ + public function currentUserData() + { + return [ + 'user_id' => Yii::$app->user->id, + 'session_id' => Yii::$app->session->getId(), + 'user_agent' => Yii::$app->request->userAgent, + 'ip' => Yii::$app->request->userIP, + ]; + } + + /** + * @return array + */ + public function currentUserCondition() + { + return [ + 'user_id' => Yii::$app->user->id, + 'session_id' => Yii::$app->session->getId(), + 'user_agent' => Yii::$app->request->userAgent, + ]; + } +} diff --git a/src/User/Query/SessionHistoryQuery.php b/src/User/Query/SessionHistoryQuery.php new file mode 100755 index 0000000..d8ad71c --- /dev/null +++ b/src/User/Query/SessionHistoryQuery.php @@ -0,0 +1,82 @@ + + * + * 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\Traits\ModuleAwareTrait; +use yii\db\ActiveQuery; +use Yii; + +class SessionHistoryQuery extends ActiveQuery +{ + use ModuleAwareTrait; + + public function whereUserId($userId) + { + return $this->andWhere($this->getCondition()->byUser($userId)); + } + + public function whereActive() + { + return $this->andWhere(['IS NOT', 'session_id', null]); + } + + public function whereInActive($userId) + { + return $this->andWhere($this->getCondition()->inactive($userId)); + } + + + public function whereExpired($userId) + { + return $this->andWhere($this->getCondition()->expired($userId)); + } + + public function whereExpiredInActive($userId) + { + return $this->andWhere($this->getCondition()->expiredInactive($userId)); + } + + public function selectSessionId() + { + return $this->select(['session_id']); + } + + public function whereUserSession($userId, $sessionId) + { + return $this->andWhere($this->getCondition()->byUserSession( + $userId, + $sessionId + )); + } + + public function whereCurrentUser() + { + return $this->andWhere($this->getCondition()->currentUserCondition()); + } + + public function oldestUpdatedTimeActiveSession($userId) + { + return $this->whereExpiredInActive($userId) + ->select(['updated_at']) + ->limit(1) + ->offset($this->getModule()->numberSessionHistory) + ->orderBy(['updated_at' => SORT_DESC])->scalar(); + } + + /** + * @return SessionHistoryCondition + */ + protected function getCondition() + { + return Yii::$container->get(SessionHistoryCondition::class); + } +} diff --git a/src/User/Search/SessionHistorySearch.php b/src/User/Search/SessionHistorySearch.php new file mode 100755 index 0000000..2775652 --- /dev/null +++ b/src/User/Search/SessionHistorySearch.php @@ -0,0 +1,74 @@ + + * + * 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\Model\SessionHistory; +use Da\User\Traits\ContainerAwareTrait; +use yii\base\InvalidConfigException; +use yii\base\InvalidParamException; +use yii\data\ActiveDataProvider; + + +class SessionHistorySearch extends SessionHistory +{ + use ContainerAwareTrait; + + /** + * {@inheritdoc} + */ + public function rules() + { + return [ + [['user_agent', 'ip'], 'safe'], + ]; + } + + /** + * @param array $params + * + * @throws InvalidConfigException + * @throws InvalidParamException + * + * @return ActiveDataProvider + */ + public function search($params) + { + $query = SessionHistory::find()->andWhere([ + 'user_id' => $this->user_id, + ]); + + /** @var ActiveDataProvider $dataProvider */ + $dataProvider = $this->make( + ActiveDataProvider::class, + [], + [ + 'query' => $query, + 'sort' => [ + 'defaultOrder' => [ + 'updated_at' => SORT_DESC + ], + ] + ] + ); + + $this->load($params); + + if (!$this->validate()) { + return $dataProvider; + } + + $query->andFilterWhere(['like', 'user_agent', $this->user_agent]) + ->andFilterWhere(['like', 'ip', $this->ip]); + + return $dataProvider; + } +} diff --git a/src/User/Service/SessionHistory/DBTerminateSessionsService.php b/src/User/Service/SessionHistory/DBTerminateSessionsService.php new file mode 100755 index 0000000..f494c5c --- /dev/null +++ b/src/User/Service/SessionHistory/DBTerminateSessionsService.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Da\User\Service\SessionHistory; + + +use yii\web\DbSession; + +class DBTerminateSessionsService implements TerminateSessionsServiceInterface +{ + protected $sessionIds; + protected $dbSession; + protected $fieldName; + + public function __construct(array $sessionIds, DbSession $dbSession, $fieldName = 'id') + { + $this->sessionIds = $sessionIds; + $this->dbSession = $dbSession; + $this->fieldName = $fieldName; + } + + public function run() + { + if (in_array(session_id(), $this->sessionIds)) { + session_write_close(); + } + + $this->dbSession->db->createCommand()->delete( + $this->dbSession->sessionTable, + [$this->fieldName => $this->sessionIds] + )->execute(); + + return true; + } +} diff --git a/src/User/Service/SessionHistory/SessionHistoryDecorator.php b/src/User/Service/SessionHistory/SessionHistoryDecorator.php new file mode 100755 index 0000000..a1c0032 --- /dev/null +++ b/src/User/Service/SessionHistory/SessionHistoryDecorator.php @@ -0,0 +1,461 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Da\User\Service\SessionHistory; + +use Da\User\Model\SessionHistory; +use Da\User\Query\SessionHistoryCondition; +use Da\User\Query\SessionHistoryQuery; +use Da\User\Traits\ModuleAwareTrait; +use Yii; +use yii\db\Exception; +use yii\web\Session; +use yii\base\InvalidArgumentException as BaseInvalidArgumentException; + +/** + * Decorator for the {@see Session} class for storing the 'session history' + * + * Not decorated methods: + * {@see Session::open()} + * {@see Session::close()} + * {@see Session::destroy()} + * {@see Session::get()} + * {@see Session::set()} + */ +class SessionHistoryDecorator extends Session +{ + use ModuleAwareTrait; + + public $sessionHistoryTable = '{{%session_history}}'; + + /** + * @var Session + */ + public $session; + + public $condition; + + public function __construct( + Session $session, + SessionHistoryCondition $historyCondition, + $config = [] + ) { + $this->session = $session; + $this->condition = $historyCondition; + + parent::__construct($config); + } + + /** @inheritdoc */ + public function getUseCustomStorage() + { + return $this->session->getUseCustomStorage(); + } + + /** @inheritdoc */ + public function getIsActive() + { + return $this->session->getIsActive(); + } + + /** @inheritdoc */ + public function getHasSessionId() + { + return $this->session->getHasSessionId(); + } + + /** @inheritdoc */ + public function setHasSessionId($value) + { + return $this->session->setHasSessionId($value); + } + + /** @inheritdoc */ + public function getId() + { + return $this->session->getId(); + } + + /** @inheritdoc */ + public function setId($value) + { + return $this->session->setId($value); + } + + /** @inheritdoc */ + public function regenerateID($deleteOldSession = false) + { + return $this->getDb()->transaction(function () use ($deleteOldSession) { + $oldSid = session_id(); + if (false === $this->session->regenerateID($deleteOldSession)) { + return false; + } + + if (false === $this->getModule()->enableSessionHistory) { + return true; + } + + $user = Yii::$app->user; + if ($user->getIsGuest()) { + $this->unbindSessionHistory($oldSid); + } else { + $this->getDB()->createCommand() + ->delete( + $this->sessionHistoryTable, + $this->condition->byUserSession($user->getId(), $oldSid) + )->execute(); + } + + return true; + }); + } + + /** @inheritdoc */ + public function getName() + { + return $this->session->getName(); + } + + /** @inheritdoc */ + public function setName($value) + { + return $this->session->setName($value); + } + + /** @inheritdoc */ + public function getSavePath() + { + return $this->session->getSavePath(); + } + + /** @inheritdoc */ + public function setSavePath($value) + { + return $this->session->setSavePath($value); + } + + /** @inheritdoc */ + public function getCookieParams() + { + return $this->session->getCookieParams(); + } + + /** @inheritdoc */ + public function setCookieParams(array $value) + { + return $this->session->setCookieParams($value); + } + + /** @inheritdoc */ + public function getUseCookies() + { + return $this->session->getUseCookies(); + } + + /** @inheritdoc */ + public function setUseCookies($value) + { + return $this->session->setUseCookies($value); + } + + /** @inheritdoc */ + public function getGCProbability() + { + return $this->session->getGCProbability(); + } + + /** @inheritdoc */ + public function setGCProbability($value) + { + return $this->session->setGCProbability($value); + } + + /** @inheritdoc */ + public function getUseTransparentSessionID() + { + return $this->session->getUseTransparentSessionID(); + } + + /** @inheritdoc */ + public function setUseTransparentSessionID($value) + { + return $this->session->setUseTransparentSessionID($value); + } + + /** @inheritdoc */ + public function getTimeout() + { + return $this->session->getTimeout(); + } + + /** @inheritdoc */ + public function setTimeout($value) + { + return $this->session->setTimeout($value); + } + + /** @inheritdoc */ + public function openSession($savePath, $sessionName) + { + return $this->session->openSession($savePath, $sessionName); + } + + /** @inheritdoc */ + public function closeSession() + { + return $this->session->closeSession(); + } + + /** @inheritdoc */ + public function readSession($id) + { + return $this->session->readSession($id); + } + + /** @inheritdoc */ + public function writeSession($id, $data) + { + return $this->session->writeSession($id, $data) && + ( + false === $this->getModule()->enableSessionHistory || + $this->getDb()->transaction(function () use ($id, $data) { + if (Yii::$app->user->getIsGuest()) { + return true; + } + + $updatedAt = ['updated_at' => time()]; + + $model = $this->getHistoryQuery() + ->whereCurrentUser() + ->one(); + if (isset($model)) { + $model->updateAttributes($updatedAt); + $result = true; + } else { + $model = Yii::createObject([ + 'class' => SessionHistory::class, + ] + $this->condition->currentUserData() + $updatedAt); + if (!$result = $model->save()) { + throw new BaseInvalidArgumentException( + print_r($model->errors, 1) + ); + } + + $this->displacementHistory($model->user_id); + } + + return $result; + }) + ); + + } + + /** @inheritdoc */ + public function destroySession($id) + { + return $this->session->destroySession($id) && + ( + false === $this->getModule()->enableSessionHistory || + $this->getDb()->transaction(function () use ($id) { + $this->unbindSessionHistory($id); + + return true; + }) + ); + } + + /** @inheritdoc */ + public function gcSession($maxLifetime) + { + return $this->session->gcSession($maxLifetime) && + ( + false === $this->getModule()->enableSessionHistory || + $this->getDb()->transaction(function () use ($maxLifetime) { + $this->getDb()->createCommand()->update( + $this->sessionHistoryTable, + $this->condition->inactiveData(), + $this->condition->expired() + )->execute(); + return true; + }) + ); + } + + /** @inheritdoc */ + public function getIterator() + { + return $this->session->getIterator(); + } + + /** @inheritdoc */ + public function getCount() + { + return $this->session->getCount(); + } + + /** @inheritdoc */ + public function count() + { + return $this->session->count(); + } + + /** @inheritdoc */ + public function remove($key) + { + return $this->session->remove($key); + } + + /** @inheritdoc */ + public function removeAll() + { + return $this->session->removeAll(); + } + + /** @inheritdoc */ + public function has($key) + { + return $this->session->has($key); + } + + /** @inheritdoc */ + public function getFlash($key, $defaultValue = null, $delete = false) + { + return $this->session->getFlash($key, $defaultValue, $delete); + } + + /** @inheritdoc */ + public function getAllFlashes($delete = false) + { + return $this->session->getAllFlashes($delete); + } + + /** @inheritdoc */ + public function setFlash($key, $value = true, $removeAfterAccess = true) + { + return $this->session->setFlash($key, $value, $removeAfterAccess); + } + + /** @inheritdoc */ + public function addFlash($key, $value = true, $removeAfterAccess = true) + { + return $this->session->addFlash($key, $value, $removeAfterAccess); + } + + /** @inheritdoc */ + public function removeFlash($key) + { + return $this->session->removeFlash($key); + } + + /** @inheritdoc */ + public function removeAllFlashes() + { + return $this->session->removeAllFlashes(); + } + + /** @inheritdoc */ + public function hasFlash($key) + { + return $this->session->hasFlash($key); + } + + /** @inheritdoc */ + public function offsetExists($offset) + { + return $this->session->offsetExists($offset); + } + + /** @inheritdoc */ + public function offsetGet($offset) + { + return $this->session->offsetGet($offset); + } + + /** @inheritdoc */ + public function offsetSet($offset, $item) + { + return $this->session->offsetSet($offset, $item); + } + + /** @inheritdoc */ + public function offsetUnset($offset) + { + return $this->session->offsetUnset($offset); + } + + /** @inheritdoc */ + public function setCacheLimiter($cacheLimiter) + { + return $this->session->setCacheLimiter($cacheLimiter); + } + + /** @inheritdoc */ + public function getCacheLimiter() + { + return $this->session->getCacheLimiter(); + } + + /** + * @param string $id + * @return bool + * @throws Exception + */ + protected function unbindSessionHistory($id) + { + return (bool)$this->getDb()->createCommand()->update( + $this->sessionHistoryTable, + $this->condition->unbindSession(), + $this->condition->bySession($id) + )->execute(); + } + + /** + * + * @param int $userId + * @return bool + * @throws Exception + */ + protected function displacementHistory($userId) + { + $module = $this->getModule(); + + if (false === $module->hasNumberSessionHistory()) { + return true; + } + + $updatedAt = $this->getHistoryQuery() + ->oldestUpdatedTimeActiveSession($userId); + + if (!$updatedAt) { + return true; + } + + $this->getDB()->createCommand()->delete( + $this->sessionHistoryTable, + $this->condition->shouldDeleteBefore(intval($updatedAt), $userId) + )->execute(); + + return true; + } + + /** + * @return SessionHistoryQuery + */ + protected function getHistoryQuery() + { + return Yii::$container->get(SessionHistoryQuery::class); + } + + protected function getDb() + { + return Yii::$app->getDb(); + } +} diff --git a/src/User/Service/SessionHistory/TerminateSessionsService.php b/src/User/Service/SessionHistory/TerminateSessionsService.php new file mode 100755 index 0000000..ae4aaad --- /dev/null +++ b/src/User/Service/SessionHistory/TerminateSessionsService.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Da\User\Service\SessionHistory; + + +class TerminateSessionsService implements TerminateSessionsServiceInterface +{ + protected $sessionIds; + + public function __construct(array $sessionIds) + { + $this->sessionIds = $sessionIds; + } + + public function run() + { + $currentSessionId = session_id(); + if (session_status() === PHP_SESSION_ACTIVE) { + session_write_close(); + } + + foreach ($this->sessionIds as $sessionId) { + if ($sessionId === $currentSessionId) { + $currentSessionId = null; + } + + session_id($sessionId); + session_start(); + session_destroy(); + } + + if ($currentSessionId) { + session_id($currentSessionId); + } + session_start(); + + return true; + } +} diff --git a/src/User/Service/SessionHistory/TerminateSessionsServiceInterface.php b/src/User/Service/SessionHistory/TerminateSessionsServiceInterface.php new file mode 100755 index 0000000..35d4dfa --- /dev/null +++ b/src/User/Service/SessionHistory/TerminateSessionsServiceInterface.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Da\User\Service\SessionHistory; + + +use Da\User\Contracts\ServiceInterface; + +interface TerminateSessionsServiceInterface extends ServiceInterface +{ +} diff --git a/src/User/Service/SessionHistory/TerminateUserSessionsService.php b/src/User/Service/SessionHistory/TerminateUserSessionsService.php new file mode 100755 index 0000000..377130a --- /dev/null +++ b/src/User/Service/SessionHistory/TerminateUserSessionsService.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Da\User\Service\SessionHistory; + + +use Da\User\Contracts\ServiceInterface; +use Da\User\Event\SessionEvent; +use Da\User\Model\SessionHistory; +use Da\User\Model\User; +use Da\User\Traits\ContainerAwareTrait; +use Da\User\Traits\ModuleAwareTrait; +use yii\web\Session; +use Yii; + +class TerminateUserSessionsService implements ServiceInterface +{ + use ContainerAwareTrait; + use ModuleAwareTrait; + + protected $userId; + protected $session; + protected $excludeCurrentSession; + + public function __construct($userId, Session $session, $excludeCurrentSession = true) + { + $this->userId = intval($userId); + $this->session = $session; + $this->excludeCurrentSession = $excludeCurrentSession; + } + + public function run() + { + $user = $this->getUser($this->userId); + $sessionIds = $this->getSessionIds($user->id); + + Yii::$app->db->transaction(function () use ($sessionIds, $user) { + /** @var SessionEvent $event */ + $event = $this->make(SessionEvent::class, [$user]); + + $user->trigger(SessionEvent::EVENT_BEFORE_TERMINATE_USER_SESSIONS, $event); + + $this->make(TerminateSessionsServiceInterface::class, [$sessionIds])->run(); + + $user->updateAttributes([ + 'auth_key' => Yii::$app->security->generateRandomString(), + ]); + + if ($this->excludeCurrentUser()) { + Yii::$app->user->switchIdentity( + $user, + $this->getModule()->rememberLoginLifespan + ); + } + + $user->trigger(SessionEvent::EVENT_AFTER_TERMINATE_USER_SESSIONS, $event); + }); + + return true; + } + + /** + * @param int $userId + * @return User + */ + protected function getUser($userId) + { + return ($this->make(User::class))::findOne($userId); + } + + /** + * @param $userId + * @return int[] + */ + protected function getSessionIds($userId) + { + /** @var SessionHistory $sessionHistory */ + $sessionHistory = $this->make(SessionHistory::class); + $sessionIds = $sessionHistory::find()->whereUserId($userId)->whereActive()->selectSessionId()->column(); + + if ($this->excludeCurrentUser()) { + foreach ($sessionIds as $key => $sessionId) { + if ($sessionId === $this->session->id) { + unset($sessionIds[$key]); + break; + } + } + } + + return $sessionIds; + } + + protected function excludeCurrentUser() + { + return $this->excludeCurrentSession && $this->userId === Yii::$app->user->id; + } +} diff --git a/src/User/Widget/SessionStatusWidget.php b/src/User/Widget/SessionStatusWidget.php new file mode 100755 index 0000000..15bcfae --- /dev/null +++ b/src/User/Widget/SessionStatusWidget.php @@ -0,0 +1,85 @@ + + * + * 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\SessionHistory; +use Da\User\Traits\ContainerAwareTrait; +use Yii; +use yii\base\InvalidConfigException; +use yii\base\InvalidParamException; +use yii\base\Widget; +use yii\helpers\ArrayHelper; + +class SessionStatusWidget extends Widget +{ + use ContainerAwareTrait; + + /** + * @var SessionHistory + */ + public $model; + + /** + * {@inheritdoc} + * + * @throws InvalidConfigException + */ + public function init() + { + parent::init(); + if (!$this->model instanceof SessionHistory) { + throw new InvalidConfigException( + __CLASS__ . '::$userId should be instanceof ' . SessionHistory::class + ); + } + } + + /** + * {@inheritdoc} + * + * @throws InvalidParamException + */ + public function run() + { + if ($this->model->getIsActive()) { + if ($this->model->session_id === Yii::$app->session->id) { + $value = Yii::t('usuario', 'Current'); + } else { + $value = Yii::t('usuario', 'Active'); + } + } else { + $value = Yii::t('usuario', 'Inactive'); + } + + return $value; + } + + /** + * Returns available auth items to be attached to the user. + * + * @param int|null type of auth items or null to return all + * + * @return array + */ + protected function getAvailableItems($type = null) + { + return ArrayHelper::map( + $this->getAuthManager()->getItems($type), + 'name', + function ($item) { + return empty($item->description) + ? $item->name + : $item->name . ' (' . $item->description . ')'; + } + ); + } +} diff --git a/src/User/resources/i18n/ca/usuario.php b/src/User/resources/i18n/ca/usuario.php index 59af1ed..b009b19 100644 --- a/src/User/resources/i18n/ca/usuario.php +++ b/src/User/resources/i18n/ca/usuario.php @@ -28,6 +28,7 @@ return [ 'Account details' => '', 'Account details have been updated' => '', 'Account settings' => '', + 'Active' => '', 'Already registered? Sign in!' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', 'An error occurred processing your request' => '', @@ -81,6 +82,7 @@ return [ 'Create new rule' => '', 'Created at' => '', 'Credentials will be sent to the user by email' => '', + 'Current' => '', 'Current password' => '', 'Current password is not valid' => '', 'Data privacy' => '', @@ -113,6 +115,7 @@ return [ 'Hello' => '', 'Here you can download your personal data in a comma separated values format.' => '', 'I agree processing of my personal data and the use of cookies to facilitate the operation of this site. For more information read our {privacyPolicy}' => '', + 'IP' => '', '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' => '', @@ -120,6 +123,7 @@ return [ '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' => '', + 'Inactive' => '', 'Information' => '', 'Invalid login or password' => '', 'Invalid or expired link' => '', @@ -129,6 +133,7 @@ return [ 'It will be deleted forever' => '', 'Items' => '', 'Joined on {0, date}' => '', + 'Last activity' => '', 'Last login IP' => '', 'Last login time' => '', 'Last password change' => '', @@ -187,11 +192,15 @@ return [ 'Scan the QrCode with Google Authenticator App, then insert its temporary code on the box and submit.' => '', 'Select rule...' => '', 'Send password recovery email' => '', + 'Session ID' => '', + 'Session history' => '', 'Sign in' => '', 'Sign up' => '', 'Something went wrong' => '', + 'Status' => '', 'Submit' => '', 'Switch identities is disabled.' => '', + 'Terminate all sessions' => '', 'Thank you for signing up on {0}' => '', 'Thank you, registration is now complete.' => '', 'The "recaptcha" component must be configured.' => '', @@ -233,7 +242,9 @@ return [ 'Update rule' => '', 'Update user account' => '', 'Updated at' => '', + 'User ID' => '', 'User account could not be created.' => '', + 'User agent' => '', 'User block status has been updated.' => '', 'User could not be registered.' => '', 'User has been confirmed' => '', diff --git a/src/User/resources/i18n/da/usuario.php b/src/User/resources/i18n/da/usuario.php index 59af1ed..47c37d4 100644 --- a/src/User/resources/i18n/da/usuario.php +++ b/src/User/resources/i18n/da/usuario.php @@ -28,6 +28,7 @@ return [ 'Account details' => '', 'Account details have been updated' => '', 'Account settings' => '', + 'Active' => '', 'Already registered? Sign in!' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', 'An error occurred processing your request' => '', @@ -81,6 +82,7 @@ return [ 'Create new rule' => '', 'Created at' => '', 'Credentials will be sent to the user by email' => '', + 'Current' => '', 'Current password' => '', 'Current password is not valid' => '', 'Data privacy' => '', @@ -112,6 +114,7 @@ return [ 'Gravatar email' => '', 'Hello' => '', 'Here you can download your personal data in a comma separated values format.' => '', + 'IP' => '', 'I agree processing of my personal data and the use of cookies to facilitate the operation of this site. For more information read our {privacyPolicy}' => '', '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' => '', @@ -120,6 +123,7 @@ return [ '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' => '', + 'Inactive' => '', 'Information' => '', 'Invalid login or password' => '', 'Invalid or expired link' => '', @@ -129,6 +133,7 @@ return [ 'It will be deleted forever' => '', 'Items' => '', 'Joined on {0, date}' => '', + 'Last activity' => '', 'Last login IP' => '', 'Last login time' => '', 'Last password change' => '', @@ -187,11 +192,15 @@ return [ 'Scan the QrCode with Google Authenticator App, then insert its temporary code on the box and submit.' => '', 'Select rule...' => '', 'Send password recovery email' => '', + 'Session ID' => '', + 'Session history' => '', 'Sign in' => '', 'Sign up' => '', 'Something went wrong' => '', + 'Status' => '', 'Submit' => '', 'Switch identities is disabled.' => '', + 'Terminate all sessions' => '', 'Thank you for signing up on {0}' => '', 'Thank you, registration is now complete.' => '', 'The "recaptcha" component must be configured.' => '', @@ -233,7 +242,9 @@ return [ 'Update rule' => '', 'Update user account' => '', 'Updated at' => '', + 'User ID' => '', 'User account could not be created.' => '', + 'User agent' => '', 'User block status has been updated.' => '', 'User could not be registered.' => '', 'User has been confirmed' => '', diff --git a/src/User/resources/i18n/de-DU/usuario.php b/src/User/resources/i18n/de-DU/usuario.php index f3bffff..b2604de 100644 --- a/src/User/resources/i18n/de-DU/usuario.php +++ b/src/User/resources/i18n/de-DU/usuario.php @@ -282,4 +282,21 @@ return [ 'A message has been sent to your email address. ' => '@@Eine Nachricht wurde an Deine E-Mail Adresse gesendet@@', 'Every user having your role has two factor authentication mandatory, you must enable it' => '@@@@', 'Now you can resume the login process' => '@@@@', + 'According to the European General Data Protection Regulation (GDPR) we need your consent to work with your personal data.' => '', + 'Active' => '', + 'Current' => '', + 'Data privacy' => '', + 'IP' => '', + 'Inactive' => '', + 'Last activity' => '', + 'Session ID' => '', + 'Session history' => '', + 'Status' => '', + 'Submit' => '', + 'Terminate all sessions' => '', + 'Unfortunately, you can not work with this site without giving us consent to process your data.' => '', + 'User ID' => '', + 'User agent' => '', + 'Your consent is required to work with this site' => '', + 'A message has been sent to your email address. ' => '@@Eine Nachricht wurde an Deine E-Mail Adresse gesendet@@', ]; diff --git a/src/User/resources/i18n/de/usuario.php b/src/User/resources/i18n/de/usuario.php index 3344d82..dd068c4 100644 --- a/src/User/resources/i18n/de/usuario.php +++ b/src/User/resources/i18n/de/usuario.php @@ -277,6 +277,22 @@ return [ '{0, date, MMM dd, YYYY HH:mm}' => '{0, date, dd. MMM YYYY, HH:mm}', '{0, date, MMMM dd, YYYY HH:mm}' => '{0, date, dd. MMMM YYYY, HH:mm}', '{0} cannot be blank.' => '{0} darf nicht leer sein.', + 'According to the European General Data Protection Regulation (GDPR) we need your consent to work with your personal data.' => '', + 'Active' => '', + 'Current' => '', + 'Data privacy' => '', + 'IP' => '', + 'Inactive' => '', + 'Last activity' => '', + 'Session ID' => '', + 'Session history' => '', + 'Status' => '', + 'Submit' => '', + 'Terminate all sessions' => '', + 'Unfortunately, you can not work with this site without giving us consent to process your data.' => '', + 'User ID' => '', + 'User agent' => '', + 'Your consent is required to work with this site' => '', 'Information' => '', 'Your role requires 2FA, you won\'t be able to use the application until you enable it' => '', 'Every user having your role has two factor authentication mandatory, you must enable it' => '@@@@', diff --git a/src/User/resources/i18n/es/usuario.php b/src/User/resources/i18n/es/usuario.php index d5cfe41..86650ac 100644 --- a/src/User/resources/i18n/es/usuario.php +++ b/src/User/resources/i18n/es/usuario.php @@ -276,6 +276,17 @@ return [ 'privacy policy' => 'política de privacidad', '{0, date, MMMM dd, YYYY HH:mm}' => '{0, date, dd MMMM, YYYY HH:mm}', '{0} cannot be blank.' => '{0} no puede estar vacío.', + 'Active' => '', + 'Current' => '', + 'IP' => '', + 'Inactive' => '', + 'Last activity' => '', + 'Session ID' => '', + 'Session history' => '', + 'Status' => '', + 'Terminate all sessions' => '', + 'User ID' => '', + 'User agent' => '', 'Your consent is required to work with this site' => '', 'Your role requires 2FA, you won\'t be able to use the application until you enable it' => '', '{0, date, MMM dd, YYYY HH:mm}' => '', diff --git a/src/User/resources/i18n/et/usuario.php b/src/User/resources/i18n/et/usuario.php index a873ba6..459e409 100644 --- a/src/User/resources/i18n/et/usuario.php +++ b/src/User/resources/i18n/et/usuario.php @@ -268,17 +268,26 @@ return [ 'privacy policy' => 'privaatsuspoliitika', '{0} cannot be blank.' => '{0} ei või olla tühi.', 'According to the European General Data Protection Regulation (GDPR) we need your consent to work with your personal data.' => '', + 'Active' => '', 'Authentication rule class {0} can not be instantiated' => '', + 'Current' => '', 'Data privacy' => '', + 'IP' => '', + 'Inactive' => '', + 'Last activity' => '', 'Rule class must extend "yii\\rbac\\Rule".' => '', + 'Session ID' => '', + 'Session history' => '', + 'Status' => '', 'Submit' => '', + 'Terminate all sessions' => '', 'Unfortunately, you can not work with this site without giving us consent to process your data.' => '', + 'User ID' => '', + 'User agent' => '', 'VKontakte' => '', 'Yandex' => '', 'Your consent is required to work with this site' => '', 'Your role requires 2FA, you won\'t be able to use the application until you enable it' => '', '{0, date, MMM dd, YYYY HH:mm}' => '', '{0, date, MMMM dd, YYYY HH:mm}' => '', - 'Every user having your role has two factor authentication mandatory, you must enable it' => '@@@@', - 'Now you can resume the login process' => '@@@@', ]; diff --git a/src/User/resources/i18n/fa-IR/usuario.php b/src/User/resources/i18n/fa-IR/usuario.php index c64df14..c1b2ca0 100644 --- a/src/User/resources/i18n/fa-IR/usuario.php +++ b/src/User/resources/i18n/fa-IR/usuario.php @@ -151,6 +151,13 @@ return [ 'Your profile has been updated' => 'پروفایل شما بروز شد', '{0, date, MMMM dd, YYYY HH:mm}' => '{0, date, dd MMMM, YYYY HH:mm}', 'According to the European General Data Protection Regulation (GDPR) we need your consent to work with your personal data.' => '', + 'Account' => '', + 'Account confirmation' => '', + 'Account details' => '', + 'Account details have been updated' => '', + 'Account settings' => '', + 'Active' => '', + 'Already registered? Sign in!' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', 'Are you sure you want to switch to this user for the rest of this Session?' => '', 'Are you sure you wish the user to change their password at next login?' => '', @@ -177,6 +184,10 @@ return [ 'Create new role' => '', 'Create new rule' => '', 'Created at' => '', + 'Credentials will be sent to the user by email' => '', + 'Current' => '', + 'Current password' => '', + 'Current password is not valid' => '', 'Data privacy' => '', 'Data processing consent' => '', 'Delete account' => '', @@ -194,13 +205,23 @@ return [ 'Force password change at next login' => '', 'Here you can download your personal data in a comma separated values format.' => '', 'I agree processing of my personal data and the use of cookies to facilitate the operation of this site. For more information read our {privacyPolicy}' => '', + 'IP' => '', + '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' => '', 'Impersonate this user' => '', 'In order to finish your registration, we need you to enter following fields' => '', + 'Inactive' => '', + 'Information' => '', + 'Invalid login or password' => '', + 'Invalid or expired link' => '', 'Invalid password' => '', 'Invalid two factor authentication code' => '', 'Invalid value' => '', 'It will be deleted forever' => '', 'Items' => '', + 'Joined on {0, date}' => '', + 'Last activity' => '', 'Last login IP' => '', 'Last login time' => '', 'Last password change' => '', @@ -230,6 +251,17 @@ return [ 'Send password recovery email' => '', 'Submit' => '', 'Switch identities is disabled.' => '', + 'Session ID' => '', + 'Session history' => '', + 'Sign in' => '', + 'Sign up' => '', + 'Something went wrong' => '', + 'Status' => '', + 'Submit' => '', + 'Switch identities is disabled.' => '', + 'Terminate all sessions' => '', + 'Thank you for signing up on {0}' => '', + 'Thank you, registration is now complete.' => '', 'The "recaptcha" component must be configured.' => '', 'The verification code is incorrect.' => '', 'There is neither role nor permission with name "{0}"' => '', @@ -259,7 +291,9 @@ return [ 'Update role' => '', 'Update rule' => '', 'Updated at' => '', + 'User ID' => '', 'User account could not be created.' => '', + 'User agent' => '', 'User block status has been updated.' => '', 'User could not be registered.' => '', 'User will be required to change password at next login' => '', @@ -279,8 +313,4 @@ return [ 'privacy policy' => '', '{0, date, MMM dd, YYYY HH:mm}' => '', '{0} cannot be blank.' => '', - 'An email has been sent with instructions for resetting your password' => '@@ایمیلی حاوی راهنمایی برای تنظیم مجدد رمز عبور به شما ارسال شد@@', - 'Every user having your role has two factor authentication mandatory, you must enable it' => '@@@@', - 'Now you can resume the login process' => '@@@@', - 'Registration ip' => '@@ای پی ثبت نام@@', ]; diff --git a/src/User/resources/i18n/fi/usuario.php b/src/User/resources/i18n/fi/usuario.php index 59af1ed..b009b19 100644 --- a/src/User/resources/i18n/fi/usuario.php +++ b/src/User/resources/i18n/fi/usuario.php @@ -28,6 +28,7 @@ return [ 'Account details' => '', 'Account details have been updated' => '', 'Account settings' => '', + 'Active' => '', 'Already registered? Sign in!' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', 'An error occurred processing your request' => '', @@ -81,6 +82,7 @@ return [ 'Create new rule' => '', 'Created at' => '', 'Credentials will be sent to the user by email' => '', + 'Current' => '', 'Current password' => '', 'Current password is not valid' => '', 'Data privacy' => '', @@ -113,6 +115,7 @@ return [ 'Hello' => '', 'Here you can download your personal data in a comma separated values format.' => '', 'I agree processing of my personal data and the use of cookies to facilitate the operation of this site. For more information read our {privacyPolicy}' => '', + 'IP' => '', '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' => '', @@ -120,6 +123,7 @@ return [ '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' => '', + 'Inactive' => '', 'Information' => '', 'Invalid login or password' => '', 'Invalid or expired link' => '', @@ -129,6 +133,7 @@ return [ 'It will be deleted forever' => '', 'Items' => '', 'Joined on {0, date}' => '', + 'Last activity' => '', 'Last login IP' => '', 'Last login time' => '', 'Last password change' => '', @@ -187,11 +192,15 @@ return [ 'Scan the QrCode with Google Authenticator App, then insert its temporary code on the box and submit.' => '', 'Select rule...' => '', 'Send password recovery email' => '', + 'Session ID' => '', + 'Session history' => '', 'Sign in' => '', 'Sign up' => '', 'Something went wrong' => '', + 'Status' => '', 'Submit' => '', 'Switch identities is disabled.' => '', + 'Terminate all sessions' => '', 'Thank you for signing up on {0}' => '', 'Thank you, registration is now complete.' => '', 'The "recaptcha" component must be configured.' => '', @@ -233,7 +242,9 @@ return [ 'Update rule' => '', 'Update user account' => '', 'Updated at' => '', + 'User ID' => '', 'User account could not be created.' => '', + 'User agent' => '', 'User block status has been updated.' => '', 'User could not be registered.' => '', 'User has been confirmed' => '', diff --git a/src/User/resources/i18n/fr/usuario.php b/src/User/resources/i18n/fr/usuario.php index 0126a73..6df52c4 100644 --- a/src/User/resources/i18n/fr/usuario.php +++ b/src/User/resources/i18n/fr/usuario.php @@ -273,12 +273,21 @@ return [ '{0, date, MMMM dd, YYYY HH:mm}' => '{0, date, dd MMMM YYYY HH:mm}', '{0} cannot be blank.' => '{0} ne peut être vide.', 'According to the European General Data Protection Regulation (GDPR) we need your consent to work with your personal data.' => '', + 'Active' => '', + 'Current' => '', 'Data privacy' => '', + 'IP' => '', + 'Inactive' => '', + 'Last activity' => '', + 'Session ID' => '', + 'Session history' => '', + 'Status' => '', 'Submit' => '', + 'Terminate all sessions' => '', 'Unfortunately, you can not work with this site without giving us consent to process your data.' => '', + 'User ID' => '', + 'User agent' => '', 'Your consent is required to work with this site' => '', 'Your role requires 2FA, you won\'t be able to use the application until you enable it' => '', '{0, date, MMM dd, YYYY HH:mm}' => '', - 'Every user having your role has two factor authentication mandatory, you must enable it' => '@@@@', - 'Now you can resume the login process' => '@@@@', ]; diff --git a/src/User/resources/i18n/hr/usuario.php b/src/User/resources/i18n/hr/usuario.php index 59af1ed..47c37d4 100644 --- a/src/User/resources/i18n/hr/usuario.php +++ b/src/User/resources/i18n/hr/usuario.php @@ -28,6 +28,7 @@ return [ 'Account details' => '', 'Account details have been updated' => '', 'Account settings' => '', + 'Active' => '', 'Already registered? Sign in!' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', 'An error occurred processing your request' => '', @@ -81,6 +82,7 @@ return [ 'Create new rule' => '', 'Created at' => '', 'Credentials will be sent to the user by email' => '', + 'Current' => '', 'Current password' => '', 'Current password is not valid' => '', 'Data privacy' => '', @@ -112,6 +114,7 @@ return [ 'Gravatar email' => '', 'Hello' => '', 'Here you can download your personal data in a comma separated values format.' => '', + 'IP' => '', 'I agree processing of my personal data and the use of cookies to facilitate the operation of this site. For more information read our {privacyPolicy}' => '', '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' => '', @@ -120,6 +123,7 @@ return [ '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' => '', + 'Inactive' => '', 'Information' => '', 'Invalid login or password' => '', 'Invalid or expired link' => '', @@ -129,6 +133,7 @@ return [ 'It will be deleted forever' => '', 'Items' => '', 'Joined on {0, date}' => '', + 'Last activity' => '', 'Last login IP' => '', 'Last login time' => '', 'Last password change' => '', @@ -187,11 +192,15 @@ return [ 'Scan the QrCode with Google Authenticator App, then insert its temporary code on the box and submit.' => '', 'Select rule...' => '', 'Send password recovery email' => '', + 'Session ID' => '', + 'Session history' => '', 'Sign in' => '', 'Sign up' => '', 'Something went wrong' => '', + 'Status' => '', 'Submit' => '', 'Switch identities is disabled.' => '', + 'Terminate all sessions' => '', 'Thank you for signing up on {0}' => '', 'Thank you, registration is now complete.' => '', 'The "recaptcha" component must be configured.' => '', @@ -233,7 +242,9 @@ return [ 'Update rule' => '', 'Update user account' => '', 'Updated at' => '', + 'User ID' => '', 'User account could not be created.' => '', + 'User agent' => '', 'User block status has been updated.' => '', 'User could not be registered.' => '', 'User has been confirmed' => '', diff --git a/src/User/resources/i18n/hu/usuario.php b/src/User/resources/i18n/hu/usuario.php index 8c3a1f5..c59848a 100644 --- a/src/User/resources/i18n/hu/usuario.php +++ b/src/User/resources/i18n/hu/usuario.php @@ -270,13 +270,24 @@ return [ '{0, date, MMMM dd, YYYY HH:mm}' => '{0, dátum, MMMM dd, ÉÉÉÉ HH: mm}', '{0} cannot be blank.' => '{0} nem lehet üres.', 'According to the European General Data Protection Regulation (GDPR) we need your consent to work with your personal data.' => '', + 'Active' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', + 'Current' => '', 'Data privacy' => '', + 'IP' => '', + 'Inactive' => '', + 'Last activity' => '', 'Rule class name' => '', 'Select rule...' => '', + 'Session ID' => '', + 'Session history' => '', + 'Status' => '', 'Submit' => '', + 'Terminate all sessions' => '', 'Two factor authentication protects you in case of stolen credentials' => '', 'Unfortunately, you can not work with this site without giving us consent to process your data.' => '', + 'User ID' => '', + 'User agent' => '', 'Your consent is required to work with this site' => '', 'Your role requires 2FA, you won\'t be able to use the application until you enable it' => '', 'A message has been sent to your email address. ' => '@@Üzenet érkezett az e-mail címedre.@@', diff --git a/src/User/resources/i18n/it/usuario.php b/src/User/resources/i18n/it/usuario.php index ac97d23..e381dba 100644 --- a/src/User/resources/i18n/it/usuario.php +++ b/src/User/resources/i18n/it/usuario.php @@ -279,6 +279,24 @@ return [ '{0, date, MMM dd, YYYY HH:mm}' => '{0, date, MMM dd, YYYY HH:mm}', '{0, date, MMMM dd, YYYY HH:mm}' => '{0, date, dd MMMM YYYY HH:mm}', '{0} cannot be blank.' => '{0} non può essere vuoto.', + 'According to the European General Data Protection Regulation (GDPR) we need your consent to work with your personal data.' => '', + 'Active' => '', + 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', + 'Current' => '', + 'Data privacy' => '', + 'IP' => '', + 'Inactive' => '', + 'Last activity' => '', + 'Session ID' => '', + 'Session history' => '', + 'Status' => '', + 'Submit' => '', + 'Terminate all sessions' => '', + 'Unfortunately, you can not work with this site without giving us consent to process your data.' => '', + 'User ID' => '', + 'User agent' => '', + 'Your consent is required to work with this site' => '', + '{0, date, MMM dd, YYYY HH:mm}' => '', 'An email has been sent with instructions for resetting your password' => '@@È stata inviata un\'email con le istruzioni per azzerare la tua password@@', 'Now you can resume the login process' => '@@Ora puoi riprendere il processo di autenticazione@@', ]; diff --git a/src/User/resources/i18n/kk/usuario.php b/src/User/resources/i18n/kk/usuario.php index 59af1ed..47c37d4 100644 --- a/src/User/resources/i18n/kk/usuario.php +++ b/src/User/resources/i18n/kk/usuario.php @@ -28,6 +28,7 @@ return [ 'Account details' => '', 'Account details have been updated' => '', 'Account settings' => '', + 'Active' => '', 'Already registered? Sign in!' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', 'An error occurred processing your request' => '', @@ -81,6 +82,7 @@ return [ 'Create new rule' => '', 'Created at' => '', 'Credentials will be sent to the user by email' => '', + 'Current' => '', 'Current password' => '', 'Current password is not valid' => '', 'Data privacy' => '', @@ -112,6 +114,7 @@ return [ 'Gravatar email' => '', 'Hello' => '', 'Here you can download your personal data in a comma separated values format.' => '', + 'IP' => '', 'I agree processing of my personal data and the use of cookies to facilitate the operation of this site. For more information read our {privacyPolicy}' => '', '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' => '', @@ -120,6 +123,7 @@ return [ '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' => '', + 'Inactive' => '', 'Information' => '', 'Invalid login or password' => '', 'Invalid or expired link' => '', @@ -129,6 +133,7 @@ return [ 'It will be deleted forever' => '', 'Items' => '', 'Joined on {0, date}' => '', + 'Last activity' => '', 'Last login IP' => '', 'Last login time' => '', 'Last password change' => '', @@ -187,11 +192,15 @@ return [ 'Scan the QrCode with Google Authenticator App, then insert its temporary code on the box and submit.' => '', 'Select rule...' => '', 'Send password recovery email' => '', + 'Session ID' => '', + 'Session history' => '', 'Sign in' => '', 'Sign up' => '', 'Something went wrong' => '', + 'Status' => '', 'Submit' => '', 'Switch identities is disabled.' => '', + 'Terminate all sessions' => '', 'Thank you for signing up on {0}' => '', 'Thank you, registration is now complete.' => '', 'The "recaptcha" component must be configured.' => '', @@ -233,7 +242,9 @@ return [ 'Update rule' => '', 'Update user account' => '', 'Updated at' => '', + 'User ID' => '', 'User account could not be created.' => '', + 'User agent' => '', 'User block status has been updated.' => '', 'User could not be registered.' => '', 'User has been confirmed' => '', diff --git a/src/User/resources/i18n/lt/usuario.php b/src/User/resources/i18n/lt/usuario.php index 59af1ed..b009b19 100644 --- a/src/User/resources/i18n/lt/usuario.php +++ b/src/User/resources/i18n/lt/usuario.php @@ -28,6 +28,7 @@ return [ 'Account details' => '', 'Account details have been updated' => '', 'Account settings' => '', + 'Active' => '', 'Already registered? Sign in!' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', 'An error occurred processing your request' => '', @@ -81,6 +82,7 @@ return [ 'Create new rule' => '', 'Created at' => '', 'Credentials will be sent to the user by email' => '', + 'Current' => '', 'Current password' => '', 'Current password is not valid' => '', 'Data privacy' => '', @@ -113,6 +115,7 @@ return [ 'Hello' => '', 'Here you can download your personal data in a comma separated values format.' => '', 'I agree processing of my personal data and the use of cookies to facilitate the operation of this site. For more information read our {privacyPolicy}' => '', + 'IP' => '', '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' => '', @@ -120,6 +123,7 @@ return [ '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' => '', + 'Inactive' => '', 'Information' => '', 'Invalid login or password' => '', 'Invalid or expired link' => '', @@ -129,6 +133,7 @@ return [ 'It will be deleted forever' => '', 'Items' => '', 'Joined on {0, date}' => '', + 'Last activity' => '', 'Last login IP' => '', 'Last login time' => '', 'Last password change' => '', @@ -187,11 +192,15 @@ return [ 'Scan the QrCode with Google Authenticator App, then insert its temporary code on the box and submit.' => '', 'Select rule...' => '', 'Send password recovery email' => '', + 'Session ID' => '', + 'Session history' => '', 'Sign in' => '', 'Sign up' => '', 'Something went wrong' => '', + 'Status' => '', 'Submit' => '', 'Switch identities is disabled.' => '', + 'Terminate all sessions' => '', 'Thank you for signing up on {0}' => '', 'Thank you, registration is now complete.' => '', 'The "recaptcha" component must be configured.' => '', @@ -233,7 +242,9 @@ return [ 'Update rule' => '', 'Update user account' => '', 'Updated at' => '', + 'User ID' => '', 'User account could not be created.' => '', + 'User agent' => '', 'User block status has been updated.' => '', 'User could not be registered.' => '', 'User has been confirmed' => '', diff --git a/src/User/resources/i18n/nl/usuario.php b/src/User/resources/i18n/nl/usuario.php index 37df1e7..c3d52e0 100644 --- a/src/User/resources/i18n/nl/usuario.php +++ b/src/User/resources/i18n/nl/usuario.php @@ -270,13 +270,24 @@ return [ '{0, date, MMMM dd, YYYY HH:mm}' => '{0, date, MMMM dd, YYYY HH:mm}\'', '{0} cannot be blank.' => '{0} kan niet leeg zijn.', 'According to the European General Data Protection Regulation (GDPR) we need your consent to work with your personal data.' => '', + 'Active' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', + 'Current' => '', 'Data privacy' => '', + 'IP' => '', + 'Inactive' => '', + 'Last activity' => '', 'Rule class name' => '', 'Select rule...' => '', + 'Session ID' => '', + 'Session history' => '', + 'Status' => '', 'Submit' => '', + 'Terminate all sessions' => '', 'Two factor authentication protects you in case of stolen credentials' => '', 'Unfortunately, you can not work with this site without giving us consent to process your data.' => '', + 'User ID' => '', + 'User agent' => '', 'Your consent is required to work with this site' => '', 'Your role requires 2FA, you won\'t be able to use the application until you enable it' => '', 'A message has been sent to your email address. ' => '@@Een bericht werd naar jouw emailadres verzonden@@', diff --git a/src/User/resources/i18n/pl/usuario.php b/src/User/resources/i18n/pl/usuario.php index 82b2909..7298a73 100644 --- a/src/User/resources/i18n/pl/usuario.php +++ b/src/User/resources/i18n/pl/usuario.php @@ -270,13 +270,24 @@ return [ '{0, date, MMMM dd, YYYY HH:mm}' => '{0, date, dd MMMM YYYY, HH:mm}', '{0} cannot be blank.' => '{0} nie może pozostać bez wartości', 'According to the European General Data Protection Regulation (GDPR) we need your consent to work with your personal data.' => '', + 'Active' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', + 'Current' => '', 'Data privacy' => '', + 'IP' => '', + 'Inactive' => '', + 'Last activity' => '', 'Rule class name' => '', 'Select rule...' => '', + 'Session ID' => '', + 'Session history' => '', + 'Status' => '', 'Submit' => '', + 'Terminate all sessions' => '', 'Two factor authentication protects you in case of stolen credentials' => '', 'Unfortunately, you can not work with this site without giving us consent to process your data.' => '', + 'User ID' => '', + 'User agent' => '', 'Your consent is required to work with this site' => '', 'Your role requires 2FA, you won\'t be able to use the application until you enable it' => '', 'An email has been sent with instructions for resetting your password' => '@@Email z instrukcją resetowania hasła został wysłany@@', diff --git a/src/User/resources/i18n/pt-BR/usuario.php b/src/User/resources/i18n/pt-BR/usuario.php index dd165e1..cb86d16 100644 --- a/src/User/resources/i18n/pt-BR/usuario.php +++ b/src/User/resources/i18n/pt-BR/usuario.php @@ -270,13 +270,24 @@ return [ '{0, date, MMMM dd, YYYY HH:mm}' => '{0, date, MMMM dd, YYYY HH:mm}', '{0} cannot be blank.' => '{0} não pode estar em branco', 'According to the European General Data Protection Regulation (GDPR) we need your consent to work with your personal data.' => '', + 'Active' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', + 'Current' => '', 'Data privacy' => '', + 'IP' => '', + 'Inactive' => '', + 'Last activity' => '', 'Rule class name' => '', 'Select rule...' => '', + 'Session ID' => '', + 'Session history' => '', + 'Status' => '', 'Submit' => '', + 'Terminate all sessions' => '', 'Two factor authentication protects you in case of stolen credentials' => '', 'Unfortunately, you can not work with this site without giving us consent to process your data.' => '', + 'User ID' => '', + 'User agent' => '', 'Your consent is required to work with this site' => '', 'Your role requires 2FA, you won\'t be able to use the application until you enable it' => '', 'A message has been sent to your email address. ' => '@@Uma mensagem foi enviada para o seu endereço de e-mail.@@', diff --git a/src/User/resources/i18n/pt-PT/usuario.php b/src/User/resources/i18n/pt-PT/usuario.php index 56f0388..7091076 100644 --- a/src/User/resources/i18n/pt-PT/usuario.php +++ b/src/User/resources/i18n/pt-PT/usuario.php @@ -257,21 +257,32 @@ return [ 'privacy policy' => 'politica de privacidade', '{0} cannot be blank.' => '{0} não pode ficar vazio.', 'According to the European General Data Protection Regulation (GDPR) we need your consent to work with your personal data.' => '', + 'Active' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', 'Awesome, almost there. Now you need to click the confirmation link sent to your new email address.' => '', 'Awesome, almost there. Now you need to click the confirmation link sent to your old email address.' => '', 'Children' => '', 'Class' => '', + 'Current' => '', 'Data privacy' => '', 'Email' => '', 'Gravatar email' => '', + 'IP' => '', + 'Inactive' => '', 'Items' => '', + 'Last activity' => '', 'Password' => '', 'Rule class name' => '', 'Select rule...' => '', + 'Session ID' => '', + 'Session history' => '', + 'Status' => '', 'Submit' => '', + 'Terminate all sessions' => '', 'Two factor authentication protects you in case of stolen credentials' => '', 'Unfortunately, you can not work with this site without giving us consent to process your data.' => '', + 'User ID' => '', + 'User agent' => '', 'VKontakte' => '', 'Website' => '', 'Yandex' => '', diff --git a/src/User/resources/i18n/ro/usuario.php b/src/User/resources/i18n/ro/usuario.php index 2c76749..6b5bbe7 100644 --- a/src/User/resources/i18n/ro/usuario.php +++ b/src/User/resources/i18n/ro/usuario.php @@ -270,13 +270,24 @@ return [ '{0, date, MMMM dd, YYYY HH:mm}' => '{0, data, MMMM dd, AAAA HH: mm}', '{0} cannot be blank.' => '{0} nu poate fi gol.', 'According to the European General Data Protection Regulation (GDPR) we need your consent to work with your personal data.' => '', + 'Active' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', + 'Current' => '', 'Data privacy' => '', + 'IP' => '', + 'Inactive' => '', + 'Last activity' => '', 'Rule class name' => '', 'Select rule...' => '', + 'Session ID' => '', + 'Session history' => '', + 'Status' => '', 'Submit' => '', + 'Terminate all sessions' => '', 'Two factor authentication protects you in case of stolen credentials' => '', 'Unfortunately, you can not work with this site without giving us consent to process your data.' => '', + 'User ID' => '', + 'User agent' => '', 'Your consent is required to work with this site' => '', 'Your role requires 2FA, you won\'t be able to use the application until you enable it' => '', 'A message has been sent to your email address. ' => '@@A fost trimis un mesaj la adresa dvs. de e-mail.@@', diff --git a/src/User/resources/i18n/ru/usuario.php b/src/User/resources/i18n/ru/usuario.php old mode 100644 new mode 100755 index d064c1a..f2cd210 --- a/src/User/resources/i18n/ru/usuario.php +++ b/src/User/resources/i18n/ru/usuario.php @@ -27,6 +27,7 @@ return [ 'Account details' => 'Детали аккаунта', 'Account details have been updated' => 'Аккаунт был обновлен', 'Account settings' => 'Настройки аккаунта', + 'Active' => 'Активно', 'Already registered? Sign in!' => 'Уже зарегистрированы? Войдите!', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => 'Письмо с инструкциями по созданию нового пароля было выслано на {email}, в случае если данный адрес связан с {appName} аккаунтом', 'An error occurred processing your request' => 'Во время выполнения запроса произошла ошибка', @@ -80,6 +81,7 @@ return [ 'Create new rule' => 'Создать правило', 'Created at' => 'Дата создания', 'Credentials will be sent to the user by email' => 'Данные для входа будут отправлены пользователю на почту', + 'Current' => 'Текущий', 'Current password' => 'Текущий пароль', 'Current password is not valid' => 'Текущий пароль введён неправильно', 'Data processing consent' => 'Cогласие на обработку данных', @@ -111,6 +113,7 @@ return [ 'Hello' => 'Здравствуйте', 'Here you can download your personal data in a comma separated values format.' => 'Здесь вы можете загрузить свои персональные данные в формате значений, разделенных запятыми.', 'I agree processing of my personal data and the use of cookies to facilitate the operation of this site. For more information read our {privacyPolicy}' => 'Я соглашаюсь на обработку моих персональных данных и использование файлов cookie для облегчения работы этого сайта. Для получения дополнительной информации ознакомьтесь с нашей {privacyPolicy}', + 'IP' => 'IP', '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' => 'Если вы получили это сообщение по ошибке, просто проигнорируйте или удалите его', @@ -118,6 +121,7 @@ return [ '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' => 'Чтобы закончить регистрацию, заполните следующие поля', + 'Inactive' => 'Не активно', 'Information' => 'Информация', 'Invalid login or password' => 'Неправильный логин или пароль', 'Invalid or expired link' => 'Ссылка неправильна или устарела', @@ -127,6 +131,7 @@ return [ 'It will be deleted forever' => 'Он будет удалён навсегда', 'Items' => 'Элементы', 'Joined on {0, date}' => 'Зарегистрирован {0, date}', + 'Last activity' => 'Последняя активность', 'Last login IP' => 'IP последнего входа', 'Last login time' => 'Время последнего входа', 'Last password change' => 'Последняя смена пароля', @@ -185,10 +190,15 @@ return [ 'Scan the QrCode with Google Authenticator App, then insert its temporary code on the box and submit.' => 'Просканируйте QR-код приложением Google Authenticator App, затем вставьте временный код в поле и отправьте.', 'Select rule...' => 'Выберите правило...', 'Send password recovery email' => 'Отправить письмо с восстановлением пароля', + 'Session ID' => 'ID сесии', + 'Session history' => 'История сессий', 'Sign in' => 'Войти', 'Sign up' => 'Зарегистрироваться', 'Something went wrong' => 'Что-то пошло не так', + 'Status' => 'Статус', + 'Submit' => 'Подтвердить', 'Switch identities is disabled.' => 'Переключение на другой аккаунт отключено.', + 'Terminate all sessions' => 'Прекратить другие сеансы', 'Thank you for signing up on {0}' => 'Спасибо за регистрацию на сайте {0}', 'Thank you, registration is now complete.' => 'Поздравляем, регистрация успешно завершена!', 'The "recaptcha" component must be configured.' => 'Необходимо настроить компонент "recaptcha"', @@ -229,7 +239,9 @@ return [ 'Update rule' => 'Изменить правило', 'Update user account' => 'Обновить аккаунт пользователя', 'Updated at' => 'Дата редактирования', + 'User ID' => 'ID пользователя', 'User account could not be created.' => 'Не удалось создать аккаунт для пользователя.', + 'User agent' => 'User agent', 'User block status has been updated.' => 'Статус блокировки пользователя обновлён.', 'User could not be registered.' => 'Не удалось зарегистрировать пользователя.', 'User has been confirmed' => 'Пользователь был активирован', @@ -265,6 +277,7 @@ return [ 'Your account on {0} has been created' => 'Ваш аккаунт на сайте "{0}" был успешно создан', 'Your confirmation token is invalid or expired' => 'Ваша ссылка устарела или является ошибочной', 'Your consent is required to register' => 'Ваше согласие требуется для регистрации', + 'Your consent is required to work with this site' => 'Ваше согласие требуется для работы с этим сайтом', 'Your email address has been changed' => 'Ваш email был успешно изменён', 'Your password has expired, you must change it now' => 'Срок действия вашего пароля истек, сейчас вы должны изменить его', 'Your personal information has been removed' => 'Ваша персональная информация удалена', diff --git a/src/User/resources/i18n/th/usuario.php b/src/User/resources/i18n/th/usuario.php index 59af1ed..47c37d4 100644 --- a/src/User/resources/i18n/th/usuario.php +++ b/src/User/resources/i18n/th/usuario.php @@ -28,6 +28,7 @@ return [ 'Account details' => '', 'Account details have been updated' => '', 'Account settings' => '', + 'Active' => '', 'Already registered? Sign in!' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', 'An error occurred processing your request' => '', @@ -81,6 +82,7 @@ return [ 'Create new rule' => '', 'Created at' => '', 'Credentials will be sent to the user by email' => '', + 'Current' => '', 'Current password' => '', 'Current password is not valid' => '', 'Data privacy' => '', @@ -112,6 +114,7 @@ return [ 'Gravatar email' => '', 'Hello' => '', 'Here you can download your personal data in a comma separated values format.' => '', + 'IP' => '', 'I agree processing of my personal data and the use of cookies to facilitate the operation of this site. For more information read our {privacyPolicy}' => '', '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' => '', @@ -120,6 +123,7 @@ return [ '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' => '', + 'Inactive' => '', 'Information' => '', 'Invalid login or password' => '', 'Invalid or expired link' => '', @@ -129,6 +133,7 @@ return [ 'It will be deleted forever' => '', 'Items' => '', 'Joined on {0, date}' => '', + 'Last activity' => '', 'Last login IP' => '', 'Last login time' => '', 'Last password change' => '', @@ -187,11 +192,15 @@ return [ 'Scan the QrCode with Google Authenticator App, then insert its temporary code on the box and submit.' => '', 'Select rule...' => '', 'Send password recovery email' => '', + 'Session ID' => '', + 'Session history' => '', 'Sign in' => '', 'Sign up' => '', 'Something went wrong' => '', + 'Status' => '', 'Submit' => '', 'Switch identities is disabled.' => '', + 'Terminate all sessions' => '', 'Thank you for signing up on {0}' => '', 'Thank you, registration is now complete.' => '', 'The "recaptcha" component must be configured.' => '', @@ -233,7 +242,9 @@ return [ 'Update rule' => '', 'Update user account' => '', 'Updated at' => '', + 'User ID' => '', 'User account could not be created.' => '', + 'User agent' => '', 'User block status has been updated.' => '', 'User could not be registered.' => '', 'User has been confirmed' => '', diff --git a/src/User/resources/i18n/tr-TR/usuario.php b/src/User/resources/i18n/tr-TR/usuario.php index 59af1ed..b009b19 100644 --- a/src/User/resources/i18n/tr-TR/usuario.php +++ b/src/User/resources/i18n/tr-TR/usuario.php @@ -28,6 +28,7 @@ return [ 'Account details' => '', 'Account details have been updated' => '', 'Account settings' => '', + 'Active' => '', 'Already registered? Sign in!' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', 'An error occurred processing your request' => '', @@ -81,6 +82,7 @@ return [ 'Create new rule' => '', 'Created at' => '', 'Credentials will be sent to the user by email' => '', + 'Current' => '', 'Current password' => '', 'Current password is not valid' => '', 'Data privacy' => '', @@ -113,6 +115,7 @@ return [ 'Hello' => '', 'Here you can download your personal data in a comma separated values format.' => '', 'I agree processing of my personal data and the use of cookies to facilitate the operation of this site. For more information read our {privacyPolicy}' => '', + 'IP' => '', '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' => '', @@ -120,6 +123,7 @@ return [ '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' => '', + 'Inactive' => '', 'Information' => '', 'Invalid login or password' => '', 'Invalid or expired link' => '', @@ -129,6 +133,7 @@ return [ 'It will be deleted forever' => '', 'Items' => '', 'Joined on {0, date}' => '', + 'Last activity' => '', 'Last login IP' => '', 'Last login time' => '', 'Last password change' => '', @@ -187,11 +192,15 @@ return [ 'Scan the QrCode with Google Authenticator App, then insert its temporary code on the box and submit.' => '', 'Select rule...' => '', 'Send password recovery email' => '', + 'Session ID' => '', + 'Session history' => '', 'Sign in' => '', 'Sign up' => '', 'Something went wrong' => '', + 'Status' => '', 'Submit' => '', 'Switch identities is disabled.' => '', + 'Terminate all sessions' => '', 'Thank you for signing up on {0}' => '', 'Thank you, registration is now complete.' => '', 'The "recaptcha" component must be configured.' => '', @@ -233,7 +242,9 @@ return [ 'Update rule' => '', 'Update user account' => '', 'Updated at' => '', + 'User ID' => '', 'User account could not be created.' => '', + 'User agent' => '', 'User block status has been updated.' => '', 'User could not be registered.' => '', 'User has been confirmed' => '', diff --git a/src/User/resources/i18n/uk/usuario.php b/src/User/resources/i18n/uk/usuario.php index 7590331..3b6b3e8 100644 --- a/src/User/resources/i18n/uk/usuario.php +++ b/src/User/resources/i18n/uk/usuario.php @@ -273,10 +273,21 @@ return [ '{0, date, MMMM dd, YYYY HH:mm}' => '{0, date, MMMM dd, YYYY HH:mm}', '{0} cannot be blank.' => '{0} не може бути порожнім.', 'According to the European General Data Protection Regulation (GDPR) we need your consent to work with your personal data.' => '', + 'Active' => '', + 'Current' => '', 'Data privacy' => '', + 'IP' => '', + 'Inactive' => '', + 'Last activity' => '', 'Recovery message sent' => '', + 'Session ID' => '', + 'Session history' => '', + 'Status' => '', 'Submit' => '', + 'Terminate all sessions' => '', 'Unfortunately, you can not work with this site without giving us consent to process your data.' => '', + 'User ID' => '', + 'User agent' => '', 'Your consent is required to work with this site' => '', 'Your role requires 2FA, you won\'t be able to use the application until you enable it' => '', 'A message has been sent to your email address. ' => '@@На вашу електронну адресу надіслано повідомлення@@', diff --git a/src/User/resources/i18n/vi/usuario.php b/src/User/resources/i18n/vi/usuario.php index 59af1ed..b009b19 100644 --- a/src/User/resources/i18n/vi/usuario.php +++ b/src/User/resources/i18n/vi/usuario.php @@ -28,6 +28,7 @@ return [ 'Account details' => '', 'Account details have been updated' => '', 'Account settings' => '', + 'Active' => '', 'Already registered? Sign in!' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', 'An error occurred processing your request' => '', @@ -81,6 +82,7 @@ return [ 'Create new rule' => '', 'Created at' => '', 'Credentials will be sent to the user by email' => '', + 'Current' => '', 'Current password' => '', 'Current password is not valid' => '', 'Data privacy' => '', @@ -113,6 +115,7 @@ return [ 'Hello' => '', 'Here you can download your personal data in a comma separated values format.' => '', 'I agree processing of my personal data and the use of cookies to facilitate the operation of this site. For more information read our {privacyPolicy}' => '', + 'IP' => '', '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' => '', @@ -120,6 +123,7 @@ return [ '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' => '', + 'Inactive' => '', 'Information' => '', 'Invalid login or password' => '', 'Invalid or expired link' => '', @@ -129,6 +133,7 @@ return [ 'It will be deleted forever' => '', 'Items' => '', 'Joined on {0, date}' => '', + 'Last activity' => '', 'Last login IP' => '', 'Last login time' => '', 'Last password change' => '', @@ -187,11 +192,15 @@ return [ 'Scan the QrCode with Google Authenticator App, then insert its temporary code on the box and submit.' => '', 'Select rule...' => '', 'Send password recovery email' => '', + 'Session ID' => '', + 'Session history' => '', 'Sign in' => '', 'Sign up' => '', 'Something went wrong' => '', + 'Status' => '', 'Submit' => '', 'Switch identities is disabled.' => '', + 'Terminate all sessions' => '', 'Thank you for signing up on {0}' => '', 'Thank you, registration is now complete.' => '', 'The "recaptcha" component must be configured.' => '', @@ -233,7 +242,9 @@ return [ 'Update rule' => '', 'Update user account' => '', 'Updated at' => '', + 'User ID' => '', 'User account could not be created.' => '', + 'User agent' => '', 'User block status has been updated.' => '', 'User could not be registered.' => '', 'User has been confirmed' => '', diff --git a/src/User/resources/i18n/zh-CN/usuario.php b/src/User/resources/i18n/zh-CN/usuario.php index 59af1ed..b009b19 100644 --- a/src/User/resources/i18n/zh-CN/usuario.php +++ b/src/User/resources/i18n/zh-CN/usuario.php @@ -28,6 +28,7 @@ return [ 'Account details' => '', 'Account details have been updated' => '', 'Account settings' => '', + 'Active' => '', 'Already registered? Sign in!' => '', 'An email with instructions to create a new password has been sent to {email} if it is associated with an {appName} account. Your existing password has not been changed.' => '', 'An error occurred processing your request' => '', @@ -81,6 +82,7 @@ return [ 'Create new rule' => '', 'Created at' => '', 'Credentials will be sent to the user by email' => '', + 'Current' => '', 'Current password' => '', 'Current password is not valid' => '', 'Data privacy' => '', @@ -113,6 +115,7 @@ return [ 'Hello' => '', 'Here you can download your personal data in a comma separated values format.' => '', 'I agree processing of my personal data and the use of cookies to facilitate the operation of this site. For more information read our {privacyPolicy}' => '', + 'IP' => '', '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' => '', @@ -120,6 +123,7 @@ return [ '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' => '', + 'Inactive' => '', 'Information' => '', 'Invalid login or password' => '', 'Invalid or expired link' => '', @@ -129,6 +133,7 @@ return [ 'It will be deleted forever' => '', 'Items' => '', 'Joined on {0, date}' => '', + 'Last activity' => '', 'Last login IP' => '', 'Last login time' => '', 'Last password change' => '', @@ -187,11 +192,15 @@ return [ 'Scan the QrCode with Google Authenticator App, then insert its temporary code on the box and submit.' => '', 'Select rule...' => '', 'Send password recovery email' => '', + 'Session ID' => '', + 'Session history' => '', 'Sign in' => '', 'Sign up' => '', 'Something went wrong' => '', + 'Status' => '', 'Submit' => '', 'Switch identities is disabled.' => '', + 'Terminate all sessions' => '', 'Thank you for signing up on {0}' => '', 'Thank you, registration is now complete.' => '', 'The "recaptcha" component must be configured.' => '', @@ -233,7 +242,9 @@ return [ 'Update rule' => '', 'Update user account' => '', 'Updated at' => '', + 'User ID' => '', 'User account could not be created.' => '', + 'User agent' => '', 'User block status has been updated.' => '', 'User could not be registered.' => '', 'User has been confirmed' => '', diff --git a/src/User/resources/views/admin/_session-history.php b/src/User/resources/views/admin/_session-history.php new file mode 100755 index 0000000..3e6c2cf --- /dev/null +++ b/src/User/resources/views/admin/_session-history.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +use Da\User\Widget\SessionStatusWidget; +use yii\helpers\Html; +use yii\grid\GridView; +use yii\widgets\Pjax; +use Da\User\Model\SessionHistory; +use Da\User\Search\SessionHistorySearch; +use yii\web\View; +use yii\data\ActiveDataProvider; + +/** + * @var $this View + * @var $searchModel SessionHistorySearch + * @var $dataProvider ActiveDataProvider + */ +?> + +beginContent('@Da/User/resources/views/admin/update.php', ['user' => $user]) ?> +
+
+ $user->id], + [ + 'class' => 'btn btn-danger btn-xs pull-right', + 'data-method' => 'post' + ] + ) ?> +
+
+
+ + + + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + 'user_agent', + 'ip', + [ + 'contentOptions' => [ + 'class' => 'text-nowrap', + ], + 'label' => Yii::t('usuario', 'Status'), + 'value' => function (SessionHistory $model) { + return SessionStatusWidget::widget(['model' => $model]); + }, + ], + [ + 'attribute' => 'updated_at', + 'format' => 'datetime' + ], + ], +]); ?> + + +endContent() ?> diff --git a/src/User/resources/views/admin/update.php b/src/User/resources/views/admin/update.php old mode 100644 new mode 100755 index c598588..a90fd96 --- a/src/User/resources/views/admin/update.php +++ b/src/User/resources/views/admin/update.php @@ -13,6 +13,7 @@ use Da\User\Model\User; use yii\bootstrap\Nav; use yii\helpers\Html; use yii\web\View; +use Da\User\Module as UserModule; /** * @var View $this @@ -24,12 +25,14 @@ $this->title = Yii::t('usuario', 'Update user account'); $this->params['breadcrumbs'][] = ['label' => Yii::t('usuario', 'Users'), 'url' => ['index']]; $this->params['breadcrumbs'][] = $this->title; +/** @var UserModule $module */ +$module = Yii::$app->getModule('user'); ?>
render( '/shared/_alert', [ - 'module' => Yii::$app->getModule('user'), + 'module' => $module, ] ) ?> @@ -67,6 +70,11 @@ $this->params['breadcrumbs'][] = $this->title; 'label' => Yii::t('usuario', 'Assignments'), 'url' => ['/user/admin/assignments', 'id' => $user->id], ], + [ + 'label' => Yii::t('usuario', 'Session history'), + 'url' => ['/user/admin/session-history', 'id' => $user->id], + 'visible' => $module->enableSessionHistory, + ], '
', [ 'label' => Yii::t('usuario', 'Confirm'), diff --git a/src/User/resources/views/settings/_menu.php b/src/User/resources/views/settings/_menu.php old mode 100644 new mode 100755 index 9c58638..bd3c2af --- a/src/User/resources/views/settings/_menu.php +++ b/src/User/resources/views/settings/_menu.php @@ -11,9 +11,12 @@ use yii\helpers\Html; use yii\widgets\Menu; +use Da\User\Module as UserModule; +use Da\User\Model\User; -/** @var \Da\User\Model\User $user */ +/** @var User $user */ $user = Yii::$app->user->identity; +/** @var UserModule $module */ $module = Yii::$app->getModule('user'); $networksVisible = count(Yii::$app->authClientCollection->clients) > 0; @@ -41,6 +44,11 @@ $networksVisible = count(Yii::$app->authClientCollection->clients) > 0; 'items' => [ ['label' => Yii::t('usuario', 'Profile'), 'url' => ['/user/settings/profile']], ['label' => Yii::t('usuario', 'Account'), 'url' => ['/user/settings/account']], + [ + 'label' => Yii::t('usuario', 'Session history'), + 'url' => ['/user/settings/session-history'], + 'visible' => $module->enableSessionHistory, + ], ['label' => Yii::t('usuario', 'Privacy'), 'url' => ['/user/settings/privacy'], 'visible' => $module->enableGdprCompliance diff --git a/src/User/resources/views/settings/session-history.php b/src/User/resources/views/settings/session-history.php new file mode 100755 index 0000000..467ea93 --- /dev/null +++ b/src/User/resources/views/settings/session-history.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +use yii\helpers\Html; +use yii\grid\GridView; +use yii\widgets\Pjax; +use Da\User\Model\SessionHistory; +use Da\User\Search\SessionHistorySearch; +use yii\web\View; +use yii\data\ActiveDataProvider; +use Da\User\Widget\SessionStatusWidget; + +/** + * @var $this View + * @var $searchModel SessionHistorySearch + * @var $dataProvider ActiveDataProvider + */ + +$this->title = Yii::t('usuario', 'Session history'); +$this->params['breadcrumbs'][] = $this->title; +?> + +render('/shared/_alert', ['module' => Yii::$app->getModule('user')]) ?> + +
+
+ render('/settings/_menu') ?> +
+
+
+
+ title) ?> + 'btn btn-danger btn-xs pull-right', + 'data-method' => 'post' + ] + ) ?> +
+
+ + + + $dataProvider, + 'filterModel' => $searchModel, + 'columns' => [ + 'user_agent', + 'ip', + [ + 'contentOptions' => [ + 'class' => 'text-nowrap', + ], + 'label' => Yii::t('usuario', 'Status'), + 'value' => function (SessionHistory $model) { + return SessionStatusWidget::widget(['model' => $model]); + }, + ], + [ + 'attribute' => 'updated_at', + 'format' => 'datetime' + ], + ], + ]); ?> + +
+
+
+