diff --git a/composer.json b/composer.json index f3adddb..9f4428f 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "2amigos/yii2-usuario", + "name": "pcrt/yii2-usuario", "description": "Highly customizable and extensible user management, authentication, and authorization Yii2 extension", "type": "yii2-extension", "license": "BSD-3-Clause", @@ -41,7 +41,7 @@ "prefer-stable": true, "require": { "php": ">=5.5", - "2amigos/yii2-selectize-widget": "^1.1", + "pcrt/yii2-select2": "^1.0.6", "yiisoft/yii2-authclient": "^2.1", "yiisoft/yii2-httpclient": "^2.0", "yiisoft/yii2-bootstrap": "^2.0", diff --git a/src/User/Controller/AdminController.php b/src/User/Controller/AdminController.php index 05b1ca2..dd56b13 100755 --- a/src/User/Controller/AdminController.php +++ b/src/User/Controller/AdminController.php @@ -144,6 +144,8 @@ class AdminController extends Controller $this->make(AjaxRequestModelValidator::class, [$user])->validate(); if ($user->load(Yii::$app->request->post()) && $user->validate()) { + $user->created_by = Yii::$app->user->getId() ?? null; + $this->trigger(UserEvent::EVENT_BEFORE_CREATE, $event); $mailService = MailFactory::makeWelcomeMailerService($user); diff --git a/src/User/Controller/ProfileController.php b/src/User/Controller/ProfileController.php index da779b8..9d5e519 100644 --- a/src/User/Controller/ProfileController.php +++ b/src/User/Controller/ProfileController.php @@ -11,18 +11,47 @@ namespace Da\User\Controller; +use Da\User\Contracts\MailChangeStrategyInterface; +use Da\User\Event\GdprEvent; +use Da\User\Event\ProfileEvent; +use Da\User\Event\SocialNetworkConnectEvent; +use Da\User\Event\UserEvent; +use Da\User\Form\GdprDeleteForm; +use Da\User\Form\SettingsForm; +use Da\User\Helper\SecurityHelper; +use Da\User\Model\Profile; +use Da\User\Model\SocialNetworkAccount; use Da\User\Model\User; +use Da\User\Module; use Da\User\Query\ProfileQuery; +use Da\User\Query\SocialNetworkAccountQuery; +use Da\User\Query\UserQuery; +use Da\User\Search\SessionHistorySearch; +use Da\User\Service\EmailChangeService; +use Da\User\Service\SessionHistory\TerminateUserSessionsService; +use Da\User\Service\TwoFactorEmailCodeGeneratorService; +use Da\User\Service\TwoFactorQrCodeUriGeneratorService; +use Da\User\Service\TwoFactorSmsCodeGeneratorService; +use Da\User\Traits\ContainerAwareTrait; use Da\User\Traits\ModuleAwareTrait; +use Da\User\Validator\AjaxRequestModelValidator; +use Da\User\Validator\TwoFactorCodeValidator; +use Da\User\Validator\TwoFactorEmailValidator; +use Da\User\Validator\TwoFactorTextMessageValidator; use Yii; -use yii\base\Module; +use yii\base\DynamicModel; +use yii\base\InvalidParamException; use yii\filters\AccessControl; +use yii\filters\VerbFilter; +use yii\helpers\ArrayHelper; use yii\web\Controller; use yii\web\ForbiddenHttpException; use yii\web\NotFoundHttpException; +use yii\web\Response; class ProfileController extends Controller { + use ContainerAwareTrait; use ModuleAwareTrait; /** @var int will allow only profile owner */ @@ -34,19 +63,36 @@ class ProfileController extends Controller /** @var int will allow anyone, including guests */ public const PROFILE_VISIBILITY_PUBLIC = 3; + /** + * {@inheritdoc} + */ + public $defaultAction = 'profile'; + protected $profileQuery; + protected $userQuery; + protected $socialNetworkAccountQuery; /** - * ProfileController constructor. + * SettingsController constructor. * - * @param string $id - * @param Module $module - * @param ProfileQuery $profileQuery - * @param array $config + * @param string $id + * @param Module $module + * @param ProfileQuery $profileQuery + * @param UserQuery $userQuery + * @param SocialNetworkAccountQuery $socialNetworkAccountQuery + * @param array $config */ - public function __construct($id, Module $module, ProfileQuery $profileQuery, array $config = []) - { + public function __construct( + $id, + Module $module, + ProfileQuery $profileQuery, + UserQuery $userQuery, + SocialNetworkAccountQuery $socialNetworkAccountQuery, + array $config = [] + ) { $this->profileQuery = $profileQuery; + $this->userQuery = $userQuery; + $this->socialNetworkAccountQuery = $socialNetworkAccountQuery; parent::__construct($id, $module, $config); } @@ -56,71 +102,559 @@ class ProfileController extends Controller public function behaviors() { return [ + 'verbs' => [ + 'class' => VerbFilter::class, + 'actions' => [ + 'disconnect' => ['post'], + 'delete' => ['post'], + 'two-factor-disable' => ['post'], + 'terminate-sessions' => ['post'], + ], + ], 'access' => [ 'class' => AccessControl::class, 'rules' => [ [ 'allow' => true, - 'actions' => ['index'], + 'actions' => [ + 'profile', + 'account', + 'export', + 'networks', + 'privacy', + 'gdpr-consent', + 'gdpr-delete', + 'disconnect', + 'delete', + 'two-factor', + 'two-factor-enable', + 'two-factor-disable', + 'two-factor-mobile-phone' + ], 'roles' => ['@'], ], [ 'allow' => true, - 'actions' => ['show'], + 'actions' => ['confirm'], 'roles' => ['?', '@'], ], + [ + 'allow' => $this->getModule()->enableSessionHistory, + 'actions' => ['session-history', 'terminate-sessions'], + 'roles' => ['@'], + ], ], ], ]; } - public function actionIndex() + /** + * @throws \yii\base\InvalidConfigException + * @return string|Response + */ + public function actionProfile() { - return $this->redirect(['show', 'id' => Yii::$app->user->getId()]); - } - - public function actionShow($id) - { - $user = Yii::$app->user; - $id = (int) $id; - - /** @var ?User $identity */ - $identity = $user->getIdentity(); - - switch($this->module->profileVisibility) { - case static::PROFILE_VISIBILITY_OWNER: - if($identity === null || $id !== $user->getId()) { - throw new ForbiddenHttpException(); - } - break; - case static::PROFILE_VISIBILITY_ADMIN: - if($id === $user->getId() || ($identity !== null && $identity->getIsAdmin())) { - break; - } - throw new ForbiddenHttpException(); - case static::PROFILE_VISIBILITY_USERS: - if((!$user->getIsGuest())) { - break; - } - throw new ForbiddenHttpException(); - case static::PROFILE_VISIBILITY_PUBLIC: - break; - default: - throw new ForbiddenHttpException(); - - } - - $profile = $this->profileQuery->whereUserId($id)->one(); + $profile = $this->profileQuery->whereUserId(Yii::$app->user->identity->getId())->one(); if ($profile === null) { - throw new NotFoundHttpException(); + $profile = $this->make(Profile::class); + $profile->link('user', Yii::$app->user->identity); } + /** + * + * + * @var ProfileEvent $event + */ + $event = $this->make(ProfileEvent::class, [$profile]); + + $this->make(AjaxRequestModelValidator::class, [$profile])->validate(); + + if ($profile->load(Yii::$app->request->post())) { + $this->trigger(UserEvent::EVENT_BEFORE_PROFILE_UPDATE, $event); + if ($profile->save()) { + Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Your profile has been updated')); + $this->trigger(UserEvent::EVENT_AFTER_PROFILE_UPDATE, $event); + + return $this->refresh(); + } + } + + Yii::debug(get_class(Yii::$app->session)); + return $this->render( - 'show', + 'profile', [ - 'profile' => $profile, + 'model' => $profile, ] ); } -} + + /** + * @throws NotFoundHttpException + * @return string + */ + public function actionPrivacy() + { + if (!$this->module->enableGdprCompliance) { + throw new NotFoundHttpException(); + } + return $this->render( + 'privacy', + [ + 'module' => $this->module + ] + ); + } + + /** + * @throws NotFoundHttpException + * @throws \Throwable + * @throws \yii\base\Exception + * @throws \yii\base\InvalidConfigException + * @throws \yii\db\StaleObjectException + * @throws ForbiddenHttpException + * @return string|Response + */ + public function actionGdprDelete() + { + if (!$this->module->enableGdprCompliance) { + throw new NotFoundHttpException(); + } + /** + * + * + * @var GdprDeleteForm $form + */ + $form = $this->make(GdprDeleteForm::class); + + $user = $form->getUser(); + /* @var $event GdprEvent */ + $event = $this->make(GdprEvent::class, [$user]); + + if ($form->load(Yii::$app->request->post()) && $form->validate()) { + $this->trigger(GdprEvent::EVENT_BEFORE_DELETE, $event); + + if ($event->isValid) { + Yii::$app->user->logout(); + //Disconnect social networks + $networks = $this->socialNetworkAccountQuery->where(['user_id' => $user->id])->all(); + foreach ($networks as $network) { + $this->disconnectSocialNetwork($network->id); + } + + /* @var $security SecurityHelper */ + $security = $this->make(SecurityHelper::class); + $anonymReplacement = $this->module->gdprAnonymizePrefix . $user->id; + + $user->updateAttributes( + [ + 'email' => $anonymReplacement . "@example.com", + 'username' => $anonymReplacement, + 'gdpr_deleted' => 1, + 'blocked_at' => time(), + 'auth_key' => $security->generateRandomString() + ] + ); + $user->profile->updateAttributes( + [ + 'public_email' => $anonymReplacement . "@example.com", + 'name' => $anonymReplacement, + 'surname' => $anonymReplacement, + 'gravatar_email' => $anonymReplacement . "@example.com", + 'location' => $anonymReplacement, + 'website' => $anonymReplacement . ".tld", + 'bio' => Yii::t('usuario', 'Deleted by GDPR request') + ] + ); + } + $this->trigger(GdprEvent::EVENT_AFTER_DELETE, $event); + + Yii::$app->session->setFlash('info', Yii::t('usuario', 'Your personal information has been removed')); + + return $this->goHome(); + } + + return $this->render( + 'gdpr-delete', + [ + 'model' => $form, + ] + ); + } + + public function actionGdprConsent() + { + /** + * + * + * @var User $user + */ + $user = Yii::$app->user->identity; + if ($user->gdpr_consent) { + return $this->redirect(['profile']); + } + $model = new DynamicModel(['gdpr_consent']); + $model->addRule('gdpr_consent', 'boolean'); + $model->addRule('gdpr_consent', 'default', ['value' => 0, 'skipOnEmpty' => false]); + $model->addRule( + 'gdpr_consent', + 'compare', + [ + 'compareValue' => true, + 'message' => Yii::t('usuario', 'Your consent is required to work with this site'), + 'when' => function () { + return $this->module->enableGdprCompliance; + }, + ] + ); + if ($model->load(Yii::$app->request->post()) && $model->validate()) { + $user->updateAttributes( + [ + 'gdpr_consent' => 1, + 'gdpr_consent_date' => time(), + ] + ); + return $this->redirect(['profile']); + } + + return $this->render( + 'gdpr-consent', + [ + 'model' => $model, + 'gdpr_consent_hint' => $this->module->getConsentMessage(), + ] + ); + } + + /** + * Exports the data from the current user in a mechanical readable format (csv). Properties exported can be defined + * in the module configuration. + * + * @throws NotFoundHttpException if gdpr compliance is not enabled + * @throws \Exception + * @throws \Throwable + */ + public function actionExport() + { + if (!$this->module->enableGdprCompliance) { + throw new NotFoundHttpException(); + } + try { + $properties = $this->module->gdprExportProperties; + $user = Yii::$app->user->identity; + $data = [$properties, []]; + + $formatter = Yii::$app->formatter; + // override the default html-specific format for nulls + $formatter->nullDisplay = ""; + + foreach ($properties as $property) { + $data[1][] = $formatter->asText(ArrayHelper::getValue($user, $property)); + } + + array_walk($data[0], function (&$value, $key) { + $splitted = explode('.', $value); + $value = array_pop($splitted); + }); + + Yii::$app->response->headers->removeAll(); + Yii::$app->response->headers->add('Content-type', 'text/csv'); + Yii::$app->response->headers->add('Content-Disposition', 'attachment;filename=gdpr-data.csv'); + Yii::$app->response->send(); + $f = fopen('php://output', 'w'); + foreach ($data as $line) { + fputcsv($f, $line); + } + } catch (\Exception $e) { + throw $e; + } catch (\Throwable $e) { + throw $e; + } + } + + public function actionAccount() + { + /** +* + * + * @var SettingsForm $form +*/ + $form = $this->make(SettingsForm::class); + $event = $this->make(UserEvent::class, [$form->getUser()]); + + $this->make(AjaxRequestModelValidator::class, [$form])->validate(); + + if ($form->load(Yii::$app->request->post())) { + $this->trigger(UserEvent::EVENT_BEFORE_ACCOUNT_UPDATE, $event); + + if ($form->save()) { + Yii::$app->getSession()->setFlash( + 'success', + Yii::t('usuario', 'Your account details have been updated') + ); + $this->trigger(UserEvent::EVENT_AFTER_ACCOUNT_UPDATE, $event); + + return $this->refresh(); + } + } + + return $this->render( + 'account', + [ + 'model' => $form, + ] + ); + } + + public function actionConfirm($id, $code) + { + $user = $this->userQuery->whereId($id)->one(); + + if ($user === null || MailChangeStrategyInterface::TYPE_INSECURE === $this->module->emailChangeStrategy) { + throw new NotFoundHttpException(); + } + $event = $this->make(UserEvent::class, [$user]); + + $this->trigger(UserEvent::EVENT_BEFORE_CONFIRMATION, $event); + if ($this->make(EmailChangeService::class, [$code, $user])->run()) { + $this->trigger(UserEvent::EVENT_AFTER_CONFIRMATION, $event); + } + + return $this->redirect(['account']); + } + + public function actionNetworks() + { + return $this->render( + 'networks', + [ + 'user' => Yii::$app->user->identity, + ] + ); + } + + public function actionDisconnect($id) + { + $this->disconnectSocialNetwork($id); + return $this->redirect(['networks']); + } + + public function actionDelete() + { + if (!$this->module->allowAccountDelete) { + throw new NotFoundHttpException(Yii::t('usuario', 'Not found')); + } + + /** + * + * + * @var User $user + */ + $user = Yii::$app->user->identity; + $event = $this->make(UserEvent::class, [$user]); + Yii::$app->user->logout(); + + $this->trigger(UserEvent::EVENT_BEFORE_DELETE, $event); + $user->delete(); + $this->trigger(UserEvent::EVENT_AFTER_DELETE, $event); + + Yii::$app->session->setFlash('info', Yii::t('usuario', 'Your account has been completely deleted')); + + return $this->goHome(); + } + + public function actionTwoFactor($id) + { + if (!$this->module->enableTwoFactorAuthentication) { + throw new ForbiddenHttpException(Yii::t('usuario', 'Application not configured for two factor authentication.')); + } + + if ($id != Yii::$app->user->id) { + throw new ForbiddenHttpException(); + } + + $choice = Yii::$app->request->post('choice'); + /** @var User $user */ + $user = $this->userQuery->whereId($id)->one(); + + if (null === $user) { + throw new NotFoundHttpException(); + } + + switch ($choice) { + case 'google-authenticator': + $uri = $this->make(TwoFactorQrCodeUriGeneratorService::class, [$user])->run(); + return $this->renderAjax('two-factor', ['id' => $id, 'uri' => $uri, 'user' => $user]); + case 'email': + $emailCode = $this->make(TwoFactorEmailCodeGeneratorService::class, [$user])->run(); + return $this->renderAjax('two-factor-email', ['id' => $id, 'code' => $emailCode]); + case 'sms': + // get mobile phone, if exists + $mobilePhone = $user->getAuthTfMobilePhone(); + $smsCode = $this->make(TwoFactorSmsCodeGeneratorService::class, [$user])->run(); + return $this->renderAjax('two-factor-sms', ['id' => $id, 'code' => $smsCode, 'mobilePhone' => $mobilePhone]); + default: + throw new InvalidParamException("Invalid 2FA choice"); + } + } + + public function actionTwoFactorEnable($id) + { + if (!$this->module->enableTwoFactorAuthentication) { + throw new ForbiddenHttpException(Yii::t('usuario', 'Application not configured for two factor authentication.')); + } + + Yii::$app->response->format = Response::FORMAT_JSON; + + /** @var User $user */ + $user = $this->userQuery->whereId($id)->one(); + + if (null === $user) { + return [ + 'success' => false, + 'message' => Yii::t('usuario', 'User not found.') + ]; + } + $code = Yii::$app->request->get('code'); + $module = Yii::$app->getModule('user'); + $validators = $module->twoFactorAuthenticationValidators; + $choice = Yii::$app->request->get('choice'); + $codeDurationTime = ArrayHelper::getValue($validators, $choice.'.codeDurationTime', 300); + $class = ArrayHelper::getValue($validators, $choice.'.class'); + + $object = $this + ->make($class, [$user, $code, $this->module->twoFactorAuthenticationCycles]); + $success = $object->validate(); + $success = $success && $user->updateAttributes(['auth_tf_enabled' => '1','auth_tf_type' => $choice]); + $message = $success ? $object->getSuccessMessage() : $object->getUnsuccessMessage($codeDurationTime); + + return [ + 'success' => $success, + 'message' => $message + ]; + } + + public function actionTwoFactorDisable($id) + { + if (!$this->module->enableTwoFactorAuthentication) { + throw new ForbiddenHttpException(Yii::t('usuario', 'Application not configured for two factor authentication.')); + } + + if ($id != Yii::$app->user->id) { + throw new ForbiddenHttpException(); + } + + /** + * @var User $user + */ + $user = $this->userQuery->whereId($id)->one(); + + if (null === $user) { + throw new NotFoundHttpException(); + } + + if ($user->updateAttributes(['auth_tf_enabled' => '0', 'auth_tf_key' => null])) { + Yii::$app + ->getSession() + ->setFlash('success', Yii::t('usuario', 'Two factor authentication has been disabled.')); + } else { + Yii::$app + ->getSession() + ->setFlash('danger', Yii::t('usuario', 'Unable to disable Two factor authentication.')); + } + + $this->redirect(['account']); + } + + /** + * 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']); + } + + public function actionTwoFactorMobilePhone($id) + { + Yii::$app->response->format = Response::FORMAT_JSON; + + /** + * + * + * @var User $user + */ + $user = $this->userQuery->whereId($id)->one(); + + if (null === $user) { + return [ + 'success' => false, + 'message' => Yii::t('usuario', 'User not found.') + ]; + } + $mobilePhone = Yii::$app->request->get('mobilephone'); + $currentMobilePhone = $user->getAuthTfMobilePhone(); + $success = false; + if ($currentMobilePhone == $mobilePhone) { + $success = true; + } else { + $success = $user->updateAttributes(['auth_tf_mobile_phone' => $mobilePhone]); + $success = $success && $this->make(TwoFactorSmsCodeGeneratorService::class, [$user])->run(); + } + + return [ + 'success' => $success, + 'message' => $success + ? Yii::t('usuario', 'Mobile phone number successfully enabled.') + : Yii::t('usuario', 'Error while enabling SMS two factor authentication. Please reload the page.'), + ]; + } + + /** + * @param $id + * @throws ForbiddenHttpException + * @throws NotFoundHttpException + * @throws \Exception + * @throws \Throwable + * @throws \yii\db\StaleObjectException + */ + protected function disconnectSocialNetwork($id) + { + /** + * + * + * @var SocialNetworkAccount $account + */ + $account = $this->socialNetworkAccountQuery->whereId($id)->one(); + + if ($account === null) { + throw new NotFoundHttpException(); + } + if ($account->user_id !== Yii::$app->user->id) { + throw new ForbiddenHttpException(); + } + $event = $this->make(SocialNetworkConnectEvent::class, [Yii::$app->user->identity, $account]); + + $this->trigger(SocialNetworkConnectEvent::EVENT_BEFORE_DISCONNECT, $event); + $account->delete(); + $this->trigger(SocialNetworkConnectEvent::EVENT_AFTER_DISCONNECT, $event); + } +} \ No newline at end of file diff --git a/src/User/Controller/RecoveryController.php b/src/User/Controller/RecoveryController.php index 2367ef2..f02b217 100644 --- a/src/User/Controller/RecoveryController.php +++ b/src/User/Controller/RecoveryController.php @@ -109,13 +109,16 @@ class RecoveryController extends Controller $this->trigger(FormEvent::EVENT_AFTER_REQUEST, $event); } - return $this->render( - '/shared/message', - [ - 'title' => Yii::t('usuario', 'Recovery message sent'), - 'module' => $this->module, - ] - ); + Yii::$app->session->setFlash('info', Yii::t('usuario', 'Recovery message sent')); + return $this->redirect(['/user/login']); + + // return $this->render( + // '/shared/message', + // [ + // 'title' => Yii::t('usuario', 'Recovery message sent'), + // 'module' => $this->module, + // ] + // ); } return $this->render('request', ['model' => $form]); @@ -151,13 +154,14 @@ class RecoveryController extends Controller Yii::t('usuario', 'Recovery link is invalid or expired. Please try requesting a new one.') ); - return $this->render( - '/shared/message', - [ - 'title' => Yii::t('usuario', 'Invalid or expired link'), - 'module' => $this->module, - ] - ); + // return $this->render( + // '/shared/message', + // [ + // 'title' => Yii::t('usuario', 'Invalid or expired link'), + // 'module' => $this->module, + // ] + // ); + return $this->redirect(['/user/recovery/request']); } /** @var RecoveryForm $form */ @@ -172,13 +176,15 @@ class RecoveryController extends Controller Yii::$app->session->setFlash('success', Yii::t('usuario', 'Password has been changed')); - return $this->render( - '/shared/message', - [ - 'title' => Yii::t('usuario', 'Password has been changed'), - 'module' => $this->module, - ] - ); + // return $this->render( + // '/shared/message', + // [ + // 'title' => Yii::t('usuario', 'Password has been changed'), + // 'module' => $this->module, + // ] + // ); + + return $this->redirect(['/user/login']); } } diff --git a/src/User/Controller/RegistrationController.php b/src/User/Controller/RegistrationController.php index aa5f3b8..17bc990 100644 --- a/src/User/Controller/RegistrationController.php +++ b/src/User/Controller/RegistrationController.php @@ -135,13 +135,7 @@ class RegistrationController extends Controller Yii::$app->session->setFlash('info', Yii::t('usuario', 'Your account has been created')); } $this->trigger(FormEvent::EVENT_AFTER_REGISTER, $event); - return $this->render( - '/shared/message', - [ - 'title' => Yii::t('usuario', 'Your account has been created'), - 'module' => $this->module, - ] - ); + return $this->redirect(['/user/login']); } Yii::$app->session->setFlash('danger', Yii::t('usuario', 'User could not be registered.')); } else { @@ -234,13 +228,14 @@ class RegistrationController extends Controller ); } - return $this->render( - '/shared/message', - [ - 'title' => Yii::t('usuario', 'Account confirmation'), - 'module' => $this->module, - ] - ); + // return $this->render( + // '/shared/message', + // [ + // 'title' => Yii::t('usuario', 'Account confirmation'), + // 'module' => $this->module, + // ] + // ); + return $this->redirect(['/user/profile']); } /** @@ -285,15 +280,17 @@ class RegistrationController extends Controller ); } - return $this->render( - '/shared/message', - [ - 'title' => $success - ? Yii::t('usuario', 'A new confirmation link has been sent') - : Yii::t('usuario', 'Unable to send confirmation link'), - 'module' => $this->module, - ] - ); + return $this->redirect(['/user/login']); + + // return $this->render( + // '/shared/message', + // [ + // 'title' => $success + // ? Yii::t('usuario', 'A new confirmation link has been sent') + // : Yii::t('usuario', 'Unable to send confirmation link'), + // 'module' => $this->module, + // ] + // ); } return $this->render( diff --git a/src/User/Controller/SettingsController.php b/src/User/Controller/SettingsController.php deleted file mode 100644 index a96040b..0000000 --- a/src/User/Controller/SettingsController.php +++ /dev/null @@ -1,648 +0,0 @@ - - * - * For the full copyright and license information, please view - * the LICENSE file that was distributed with this source code. - */ - -namespace Da\User\Controller; - -use Da\User\Contracts\MailChangeStrategyInterface; -use Da\User\Event\GdprEvent; -use Da\User\Event\ProfileEvent; -use Da\User\Event\SocialNetworkConnectEvent; -use Da\User\Event\UserEvent; -use Da\User\Form\GdprDeleteForm; -use Da\User\Form\SettingsForm; -use Da\User\Helper\SecurityHelper; -use Da\User\Model\Profile; -use Da\User\Model\SocialNetworkAccount; -use Da\User\Model\User; -use Da\User\Module; -use Da\User\Query\ProfileQuery; -use Da\User\Query\SocialNetworkAccountQuery; -use Da\User\Query\UserQuery; -use Da\User\Search\SessionHistorySearch; -use Da\User\Service\EmailChangeService; -use Da\User\Service\SessionHistory\TerminateUserSessionsService; -use Da\User\Service\TwoFactorEmailCodeGeneratorService; -use Da\User\Service\TwoFactorQrCodeUriGeneratorService; -use Da\User\Service\TwoFactorSmsCodeGeneratorService; -use Da\User\Traits\ContainerAwareTrait; -use Da\User\Traits\ModuleAwareTrait; -use Da\User\Validator\AjaxRequestModelValidator; -use Da\User\Validator\TwoFactorCodeValidator; -use Da\User\Validator\TwoFactorEmailValidator; -use Da\User\Validator\TwoFactorTextMessageValidator; -use Yii; -use yii\base\DynamicModel; -use yii\base\InvalidParamException; -use yii\filters\AccessControl; -use yii\filters\VerbFilter; -use yii\helpers\ArrayHelper; -use yii\web\Controller; -use yii\web\ForbiddenHttpException; -use yii\web\NotFoundHttpException; -use yii\web\Response; - -class SettingsController extends Controller -{ - use ContainerAwareTrait; - use ModuleAwareTrait; - - /** - * {@inheritdoc} - */ - public $defaultAction = 'profile'; - - protected $profileQuery; - protected $userQuery; - protected $socialNetworkAccountQuery; - - /** - * SettingsController constructor. - * - * @param string $id - * @param Module $module - * @param ProfileQuery $profileQuery - * @param UserQuery $userQuery - * @param SocialNetworkAccountQuery $socialNetworkAccountQuery - * @param array $config - */ - public function __construct( - $id, - Module $module, - ProfileQuery $profileQuery, - UserQuery $userQuery, - SocialNetworkAccountQuery $socialNetworkAccountQuery, - array $config = [] - ) { - $this->profileQuery = $profileQuery; - $this->userQuery = $userQuery; - $this->socialNetworkAccountQuery = $socialNetworkAccountQuery; - parent::__construct($id, $module, $config); - } - - /** - * {@inheritdoc} - */ - public function behaviors() - { - return [ - 'verbs' => [ - 'class' => VerbFilter::class, - 'actions' => [ - 'disconnect' => ['post'], - 'delete' => ['post'], - 'two-factor-disable' => ['post'], - 'terminate-sessions' => ['post'], - ], - ], - 'access' => [ - 'class' => AccessControl::class, - 'rules' => [ - [ - 'allow' => true, - 'actions' => [ - 'profile', - 'account', - 'export', - 'networks', - 'privacy', - 'gdpr-consent', - 'gdpr-delete', - 'disconnect', - 'delete', - 'two-factor', - 'two-factor-enable', - 'two-factor-disable', - 'two-factor-mobile-phone' - ], - 'roles' => ['@'], - ], - [ - 'allow' => true, - 'actions' => ['confirm'], - 'roles' => ['?', '@'], - ], - [ - 'allow' => $this->getModule()->enableSessionHistory, - 'actions' => ['session-history', 'terminate-sessions'], - 'roles' => ['@'], - ], - ], - ], - ]; - } - - /** - * @throws \yii\base\InvalidConfigException - * @return string|Response - */ - public function actionProfile() - { - $profile = $this->profileQuery->whereUserId(Yii::$app->user->identity->getId())->one(); - - if ($profile === null) { - $profile = $this->make(Profile::class); - $profile->link('user', Yii::$app->user->identity); - } - - /** - * - * - * @var ProfileEvent $event - */ - $event = $this->make(ProfileEvent::class, [$profile]); - - $this->make(AjaxRequestModelValidator::class, [$profile])->validate(); - - if ($profile->load(Yii::$app->request->post())) { - $this->trigger(UserEvent::EVENT_BEFORE_PROFILE_UPDATE, $event); - if ($profile->save()) { - Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Your profile has been updated')); - $this->trigger(UserEvent::EVENT_AFTER_PROFILE_UPDATE, $event); - - return $this->refresh(); - } - } - - return $this->render( - 'profile', - [ - 'model' => $profile, - ] - ); - } - - /** - * @throws NotFoundHttpException - * @return string - */ - public function actionPrivacy() - { - if (!$this->module->enableGdprCompliance) { - throw new NotFoundHttpException(); - } - return $this->render( - 'privacy', - [ - 'module' => $this->module - ] - ); - } - - /** - * @throws NotFoundHttpException - * @throws \Throwable - * @throws \yii\base\Exception - * @throws \yii\base\InvalidConfigException - * @throws \yii\db\StaleObjectException - * @throws ForbiddenHttpException - * @return string|Response - */ - public function actionGdprDelete() - { - if (!$this->module->enableGdprCompliance) { - throw new NotFoundHttpException(); - } - /** - * - * - * @var GdprDeleteForm $form - */ - $form = $this->make(GdprDeleteForm::class); - - $user = $form->getUser(); - /* @var $event GdprEvent */ - $event = $this->make(GdprEvent::class, [$user]); - - if ($form->load(Yii::$app->request->post()) && $form->validate()) { - $this->trigger(GdprEvent::EVENT_BEFORE_DELETE, $event); - - if ($event->isValid) { - Yii::$app->user->logout(); - //Disconnect social networks - $networks = $this->socialNetworkAccountQuery->where(['user_id' => $user->id])->all(); - foreach ($networks as $network) { - $this->disconnectSocialNetwork($network->id); - } - - /* @var $security SecurityHelper */ - $security = $this->make(SecurityHelper::class); - $anonymReplacement = $this->module->gdprAnonymizePrefix . $user->id; - - $user->updateAttributes( - [ - 'email' => $anonymReplacement . "@example.com", - 'username' => $anonymReplacement, - 'gdpr_deleted' => 1, - 'blocked_at' => time(), - 'auth_key' => $security->generateRandomString() - ] - ); - $user->profile->updateAttributes( - [ - 'public_email' => $anonymReplacement . "@example.com", - 'name' => $anonymReplacement, - 'gravatar_email' => $anonymReplacement . "@example.com", - 'location' => $anonymReplacement, - 'website' => $anonymReplacement . ".tld", - 'bio' => Yii::t('usuario', 'Deleted by GDPR request') - ] - ); - } - $this->trigger(GdprEvent::EVENT_AFTER_DELETE, $event); - - Yii::$app->session->setFlash('info', Yii::t('usuario', 'Your personal information has been removed')); - - return $this->goHome(); - } - - return $this->render( - 'gdpr-delete', - [ - 'model' => $form, - ] - ); - } - - public function actionGdprConsent() - { - /** - * - * - * @var User $user - */ - $user = Yii::$app->user->identity; - if ($user->gdpr_consent) { - return $this->redirect(['profile']); - } - $model = new DynamicModel(['gdpr_consent']); - $model->addRule('gdpr_consent', 'boolean'); - $model->addRule('gdpr_consent', 'default', ['value' => 0, 'skipOnEmpty' => false]); - $model->addRule( - 'gdpr_consent', - 'compare', - [ - 'compareValue' => true, - 'message' => Yii::t('usuario', 'Your consent is required to work with this site'), - 'when' => function () { - return $this->module->enableGdprCompliance; - }, - ] - ); - if ($model->load(Yii::$app->request->post()) && $model->validate()) { - $user->updateAttributes( - [ - 'gdpr_consent' => 1, - 'gdpr_consent_date' => time(), - ] - ); - return $this->redirect(['profile']); - } - - return $this->render( - 'gdpr-consent', - [ - 'model' => $model, - 'gdpr_consent_hint' => $this->module->getConsentMessage(), - ] - ); - } - - /** - * Exports the data from the current user in a mechanical readable format (csv). Properties exported can be defined - * in the module configuration. - * - * @throws NotFoundHttpException if gdpr compliance is not enabled - * @throws \Exception - * @throws \Throwable - */ - public function actionExport() - { - if (!$this->module->enableGdprCompliance) { - throw new NotFoundHttpException(); - } - try { - $properties = $this->module->gdprExportProperties; - $user = Yii::$app->user->identity; - $data = [$properties, []]; - - $formatter = Yii::$app->formatter; - // override the default html-specific format for nulls - $formatter->nullDisplay = ""; - - foreach ($properties as $property) { - $data[1][] = $formatter->asText(ArrayHelper::getValue($user, $property)); - } - - array_walk($data[0], function (&$value, $key) { - $splitted = explode('.', $value); - $value = array_pop($splitted); - }); - - Yii::$app->response->headers->removeAll(); - Yii::$app->response->headers->add('Content-type', 'text/csv'); - Yii::$app->response->headers->add('Content-Disposition', 'attachment;filename=gdpr-data.csv'); - Yii::$app->response->send(); - $f = fopen('php://output', 'w'); - foreach ($data as $line) { - fputcsv($f, $line); - } - } catch (\Exception $e) { - throw $e; - } catch (\Throwable $e) { - throw $e; - } - } - - public function actionAccount() - { - /** -* - * - * @var SettingsForm $form -*/ - $form = $this->make(SettingsForm::class); - $event = $this->make(UserEvent::class, [$form->getUser()]); - - $this->make(AjaxRequestModelValidator::class, [$form])->validate(); - - if ($form->load(Yii::$app->request->post())) { - $this->trigger(UserEvent::EVENT_BEFORE_ACCOUNT_UPDATE, $event); - - if ($form->save()) { - Yii::$app->getSession()->setFlash( - 'success', - Yii::t('usuario', 'Your account details have been updated') - ); - $this->trigger(UserEvent::EVENT_AFTER_ACCOUNT_UPDATE, $event); - - return $this->refresh(); - } - } - - return $this->render( - 'account', - [ - 'model' => $form, - ] - ); - } - - public function actionConfirm($id, $code) - { - $user = $this->userQuery->whereId($id)->one(); - - if ($user === null || MailChangeStrategyInterface::TYPE_INSECURE === $this->module->emailChangeStrategy) { - throw new NotFoundHttpException(); - } - $event = $this->make(UserEvent::class, [$user]); - - $this->trigger(UserEvent::EVENT_BEFORE_CONFIRMATION, $event); - if ($this->make(EmailChangeService::class, [$code, $user])->run()) { - $this->trigger(UserEvent::EVENT_AFTER_CONFIRMATION, $event); - } - - return $this->redirect(['account']); - } - - public function actionNetworks() - { - return $this->render( - 'networks', - [ - 'user' => Yii::$app->user->identity, - ] - ); - } - - public function actionDisconnect($id) - { - $this->disconnectSocialNetwork($id); - return $this->redirect(['networks']); - } - - public function actionDelete() - { - if (!$this->module->allowAccountDelete) { - throw new NotFoundHttpException(Yii::t('usuario', 'Not found')); - } - - /** - * - * - * @var User $user - */ - $user = Yii::$app->user->identity; - $event = $this->make(UserEvent::class, [$user]); - Yii::$app->user->logout(); - - $this->trigger(UserEvent::EVENT_BEFORE_DELETE, $event); - $user->delete(); - $this->trigger(UserEvent::EVENT_AFTER_DELETE, $event); - - Yii::$app->session->setFlash('info', Yii::t('usuario', 'Your account has been completely deleted')); - - return $this->goHome(); - } - - public function actionTwoFactor($id) - { - if (!$this->module->enableTwoFactorAuthentication) { - throw new ForbiddenHttpException(Yii::t('usuario', 'Application not configured for two factor authentication.')); - } - - if ($id != Yii::$app->user->id) { - throw new ForbiddenHttpException(); - } - - $choice = Yii::$app->request->post('choice'); - /** @var User $user */ - $user = $this->userQuery->whereId($id)->one(); - - if (null === $user) { - throw new NotFoundHttpException(); - } - - switch ($choice) { - case 'google-authenticator': - $uri = $this->make(TwoFactorQrCodeUriGeneratorService::class, [$user])->run(); - return $this->renderAjax('two-factor', ['id' => $id, 'uri' => $uri, 'user' => $user]); - case 'email': - $emailCode = $this->make(TwoFactorEmailCodeGeneratorService::class, [$user])->run(); - return $this->renderAjax('two-factor-email', ['id' => $id, 'code' => $emailCode]); - case 'sms': - // get mobile phone, if exists - $mobilePhone = $user->getAuthTfMobilePhone(); - $smsCode = $this->make(TwoFactorSmsCodeGeneratorService::class, [$user])->run(); - return $this->renderAjax('two-factor-sms', ['id' => $id, 'code' => $smsCode, 'mobilePhone' => $mobilePhone]); - default: - throw new InvalidParamException("Invalid 2FA choice"); - } - } - - public function actionTwoFactorEnable($id) - { - if (!$this->module->enableTwoFactorAuthentication) { - throw new ForbiddenHttpException(Yii::t('usuario', 'Application not configured for two factor authentication.')); - } - - Yii::$app->response->format = Response::FORMAT_JSON; - - /** @var User $user */ - $user = $this->userQuery->whereId($id)->one(); - - if (null === $user) { - return [ - 'success' => false, - 'message' => Yii::t('usuario', 'User not found.') - ]; - } - $code = Yii::$app->request->get('code'); - $module = Yii::$app->getModule('user'); - $validators = $module->twoFactorAuthenticationValidators; - $choice = Yii::$app->request->get('choice'); - $codeDurationTime = ArrayHelper::getValue($validators, $choice.'.codeDurationTime', 300); - $class = ArrayHelper::getValue($validators, $choice.'.class'); - - $object = $this - ->make($class, [$user, $code, $this->module->twoFactorAuthenticationCycles]); - $success = $object->validate(); - $success = $success && $user->updateAttributes(['auth_tf_enabled' => '1','auth_tf_type' => $choice]); - $message = $success ? $object->getSuccessMessage() : $object->getUnsuccessMessage($codeDurationTime); - - return [ - 'success' => $success, - 'message' => $message - ]; - } - - public function actionTwoFactorDisable($id) - { - if (!$this->module->enableTwoFactorAuthentication) { - throw new ForbiddenHttpException(Yii::t('usuario', 'Application not configured for two factor authentication.')); - } - - if ($id != Yii::$app->user->id) { - throw new ForbiddenHttpException(); - } - - /** - * @var User $user - */ - $user = $this->userQuery->whereId($id)->one(); - - if (null === $user) { - throw new NotFoundHttpException(); - } - - if ($user->updateAttributes(['auth_tf_enabled' => '0', 'auth_tf_key' => null])) { - Yii::$app - ->getSession() - ->setFlash('success', Yii::t('usuario', 'Two factor authentication has been disabled.')); - } else { - Yii::$app - ->getSession() - ->setFlash('danger', Yii::t('usuario', 'Unable to disable Two factor authentication.')); - } - - $this->redirect(['account']); - } - - /** - * 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']); - } - - public function actionTwoFactorMobilePhone($id) - { - Yii::$app->response->format = Response::FORMAT_JSON; - - /** - * - * - * @var User $user - */ - $user = $this->userQuery->whereId($id)->one(); - - if (null === $user) { - return [ - 'success' => false, - 'message' => Yii::t('usuario', 'User not found.') - ]; - } - $mobilePhone = Yii::$app->request->get('mobilephone'); - $currentMobilePhone = $user->getAuthTfMobilePhone(); - $success = false; - if ($currentMobilePhone == $mobilePhone) { - $success = true; - } else { - $success = $user->updateAttributes(['auth_tf_mobile_phone' => $mobilePhone]); - $success = $success && $this->make(TwoFactorSmsCodeGeneratorService::class, [$user])->run(); - } - - return [ - 'success' => $success, - 'message' => $success - ? Yii::t('usuario', 'Mobile phone number successfully enabled.') - : Yii::t('usuario', 'Error while enabling SMS two factor authentication. Please reload the page.'), - ]; - } - - /** - * @param $id - * @throws ForbiddenHttpException - * @throws NotFoundHttpException - * @throws \Exception - * @throws \Throwable - * @throws \yii\db\StaleObjectException - */ - protected function disconnectSocialNetwork($id) - { - /** - * - * - * @var SocialNetworkAccount $account - */ - $account = $this->socialNetworkAccountQuery->whereId($id)->one(); - - if ($account === null) { - throw new NotFoundHttpException(); - } - if ($account->user_id !== Yii::$app->user->id) { - throw new ForbiddenHttpException(); - } - $event = $this->make(SocialNetworkConnectEvent::class, [Yii::$app->user->identity, $account]); - - $this->trigger(SocialNetworkConnectEvent::EVENT_BEFORE_DISCONNECT, $event); - $account->delete(); - $this->trigger(SocialNetworkConnectEvent::EVENT_AFTER_DISCONNECT, $event); - } -} diff --git a/src/User/Model/Profile.php b/src/User/Model/Profile.php index 2ce9ca2..7166a5f 100644 --- a/src/User/Model/Profile.php +++ b/src/User/Model/Profile.php @@ -27,6 +27,7 @@ use yii\db\ActiveRecord; /** * @property int $user_id * @property string $name + * @property string $surname * @property string $public_email * @property string $gravatar_email * @property string $gravatar_id @@ -88,6 +89,7 @@ class Profile extends ActiveRecord 'gravatarEmailPattern' => ['gravatar_email', 'email'], 'websiteUrl' => ['website', 'url'], 'nameLength' => ['name', 'string', 'max' => 255], + 'surnameLength' => ['surname', 'string', 'max' => 255], 'publicEmailLength' => ['public_email', 'string', 'max' => 255], 'gravatarEmailLength' => ['gravatar_email', 'string', 'max' => 255], 'locationLength' => ['location', 'string', 'max' => 255], @@ -102,6 +104,7 @@ class Profile extends ActiveRecord { return [ 'name' => Yii::t('usuario', 'Name'), + 'surname' => Yii::t('usuario', 'Surname'), 'public_email' => Yii::t('usuario', 'Email (public)'), 'gravatar_email' => Yii::t('usuario', 'Gravatar email'), 'location' => Yii::t('usuario', 'Location'), diff --git a/src/User/Model/User.php b/src/User/Model/User.php index 1e60d71..2764b17 100644 --- a/src/User/Model/User.php +++ b/src/User/Model/User.php @@ -57,7 +57,14 @@ use yii\web\IdentityInterface; * @property string $last_login_ip * @property int $password_changed_at * @property int $password_age - * Defined relations: + * @property int $status + * @property string $password_reset_token + * @property string $language + * @property boolean $rememberMe + * @property int $state + * @property int $created_by + * + * Defined relations: * @property SocialNetworkAccount[] $socialNetworkAccounts * @property Profile $profile */ @@ -204,6 +211,12 @@ class User extends ActiveRecord implements IdentityInterface 'last_login_ip' => Yii::t('usuario', 'Last login IP'), 'password_changed_at' => Yii::t('usuario', 'Last password change'), 'password_age' => Yii::t('usuario', 'Password age'), + 'language' => Yii::t('usuario', 'Language'), + 'status' => Yii::t('usuario', 'Status'), + 'state' => Yii::t('usuario', 'State'), + 'created_by' => Yii::t('usuario', 'Created by'), + 'rememberMe' => Yii::t('usuario', 'Remember Me'), + 'password_reset_token' => Yii::t('usuario', 'Password Reset Token'), ]; } @@ -393,4 +406,40 @@ class User extends ActiveRecord implements IdentityInterface { return $this->getAttribute('auth_tf_mobile_phone'); } + + /** + * Returns the user who created this user + * @return \yii\db\ActiveQuery + */ + public function getCreator() + { + return $this->hasOne(self::class, ['id' => 'created_by']); + } + + /** + * Returns the user's name + * @return string|null + */ + public function getName() + { + return $this->profile ? $this->profile->name : null; + } + + /** + * Returns the user's surname + * @return string|null + */ + public function getSurname() + { + return $this->profile ? $this->profile->surname : null; + } + + /** + * Returns the user's full name + * @return string + */ + public function getFullName() + { + return $this->profile ? ($this->profile->name . ' ' . $this->profile->surname) : $this->username; + } } diff --git a/src/User/Module.php b/src/User/Module.php index 0f70d5e..ed5a639 100755 --- a/src/User/Module.php +++ b/src/User/Module.php @@ -91,7 +91,7 @@ class Module extends BaseModule * @see AccessRuleFilter */ public $gdprConsentExcludedUrls = [ - 'user/settings/*' + 'user/profile/*' ]; /** * @var bool whether to enable two factor authentication or not diff --git a/src/User/resources/i18n/it/usuario.php b/src/User/resources/i18n/it/usuario.php index 44b7636..b999d79 100644 --- a/src/User/resources/i18n/it/usuario.php +++ b/src/User/resources/i18n/it/usuario.php @@ -202,19 +202,24 @@ return [ 'Rule name' => 'Nome regola', 'Rule {0} does not exists' => 'La regola {0} non esiste', 'Rule {0} not found.' => 'Regola {0} non trovata.', - 'Rule' => 'ruolo', + 'Rule' => 'Regola', 'Rules' => 'Regole', 'Save' => 'Salva', 'Scan the QrCode with Google Authenticator App, then insert its temporary code on the box and submit.' => 'Scansiona il codice QR con l\'applicazione Google Authenticator, poi inserisci il codice temporaneo nel riquadro ed invia.', + 'Select children...' => 'Seleziona figli...', + 'Select items...' => 'Seleziona elementi...', + 'Select role...' => 'Seleziona ruolo...', 'Select rule...' => 'Seleziona una regola...', 'Send password recovery email' => 'Invia email di recupero password', 'Session history' => 'Cronologia sessioni', 'Session ID' => 'ID sessione', + 'Settings' => 'Impostazioni', 'Sign in' => 'Accedi', 'Sign up' => 'Registrati', 'Something went wrong' => 'È successo qualcosa di strano', 'Status' => 'Stato', 'Submit' => 'Invia', + 'Surname' => 'Cognome', 'Switch identities is disabled.' => 'Il cambio identità è disabilitato', 'Terminate all sessions' => 'Termina tutte le sessioni', 'Text message' => 'Messaggio di testo tramite SMS', diff --git a/src/User/resources/views/admin/_account.php b/src/User/resources/views/admin/_account.php index 7b44021..8c27f12 100644 --- a/src/User/resources/views/admin/_account.php +++ b/src/User/resources/views/admin/_account.php @@ -9,7 +9,7 @@ * the LICENSE file that was distributed with this source code. */ -use yii\bootstrap\ActiveForm; +use yii\bootstrap4\ActiveForm; use yii\helpers\Html; /** @var yii\web\View $this */ @@ -22,21 +22,15 @@ use yii\helpers\Html; 'horizontal', 'enableAjaxValidation' => true, 'enableClientValidation' => false, - 'fieldConfig' => [ - 'horizontalCssClasses' => [ - 'wrapper' => 'col-sm-9', - ], - ], ] ); ?> render('/admin/_user', ['form' => $form, 'user' => $user]) ?> -
-
+
+
'btn btn-block btn-success']) ?>
diff --git a/src/User/resources/views/admin/_assignments.php b/src/User/resources/views/admin/_assignments.php index d2b0a72..ae6ac81 100644 --- a/src/User/resources/views/admin/_assignments.php +++ b/src/User/resources/views/admin/_assignments.php @@ -20,7 +20,7 @@ use Da\User\Widget\AssignmentsWidget; beginContent($module->viewPath. '/admin/update.php', ['user' => $user]) ?> - [ 'class' => 'alert-info alert-dismissible', diff --git a/src/User/resources/views/admin/_profile.php b/src/User/resources/views/admin/_profile.php index 17994be..ef25b90 100644 --- a/src/User/resources/views/admin/_profile.php +++ b/src/User/resources/views/admin/_profile.php @@ -9,7 +9,7 @@ * the LICENSE file that was distributed with this source code. */ -use yii\bootstrap\ActiveForm; +use yii\bootstrap4\ActiveForm; use yii\helpers\Html; /** @@ -25,18 +25,13 @@ use yii\helpers\Html; 'horizontal', 'enableAjaxValidation' => true, 'enableClientValidation' => false, - 'fieldConfig' => [ - 'horizontalCssClasses' => [ - 'wrapper' => 'col-sm-9', - ], - ], ] ); ?> field($profile, 'name') ?> +field($profile, 'surname') ?> field($profile, 'public_email') ?> field($profile, 'website') ?> field($profile, 'location') ?> @@ -44,8 +39,8 @@ use yii\helpers\Html; field($profile, 'bio')->textarea() ?> -
-
+
+
'btn btn-block btn-success']) ?>
diff --git a/src/User/resources/views/admin/_session-history.php b/src/User/resources/views/admin/_session-history.php index df1ad7b..f29f7f3 100755 --- a/src/User/resources/views/admin/_session-history.php +++ b/src/User/resources/views/admin/_session-history.php @@ -27,20 +27,18 @@ use yii\data\ActiveDataProvider; */ ?> -beginContent($module->viewPath. '/admin/update.php', ['user' => $user]) ?> -
-
- $user->id], - [ - 'class' => 'btn btn-danger btn-xs pull-right', - 'data-method' => 'post' - ] - ) ?> -
-
-
+beginContent($module->viewPath . '/admin/update.php', ['user' => $user]) ?> +
+ $user->id], + [ + 'class' => 'btn btn-danger btn-xs', + 'data-method' => 'post' + ] + ) ?> +
+
@@ -67,4 +65,4 @@ use yii\data\ActiveDataProvider; ]); ?> -endContent() ?> +endContent() ?> \ No newline at end of file diff --git a/src/User/resources/views/admin/create.php b/src/User/resources/views/admin/create.php index f65d7de..fe61b37 100644 --- a/src/User/resources/views/admin/create.php +++ b/src/User/resources/views/admin/create.php @@ -9,8 +9,8 @@ * the LICENSE file that was distributed with this source code. */ -use yii\bootstrap\ActiveForm; -use yii\bootstrap\Nav; +use yii\bootstrap4\ActiveForm; +use yii\bootstrap4\Nav; use yii\helpers\Html; /** @@ -18,9 +18,12 @@ use yii\helpers\Html; * @var \Da\User\Model\User $user */ +use yii\helpers\Url; + $this->title = Yii::t('usuario', 'Create a user account'); $this->params['breadcrumbs'][] = ['label' => Yii::t('usuario', 'Users'), 'url' => ['index']]; $this->params['breadcrumbs'][] = $this->title; +$currentRoute = Yii::$app->controller->getRoute(); ?>
@@ -31,89 +34,75 @@ $this->params['breadcrumbs'][] = $this->title; ] ) ?> -
-
-
-
-

title) ?>

-
-
- render('/shared/_menu') ?> -
-
-
-
- +
+ render('/shared/_menu') ?> +
+
+
+
+ [ + 'class' => 'nav nav-pills flex-column', + ], + 'items' => [ [ - 'options' => [ - 'class' => 'nav-pills nav-stacked', - ], - 'items' => [ - [ - 'label' => Yii::t('usuario', 'Account details'), - 'url' => ['/user/admin/create'], - ], - [ - 'label' => Yii::t('usuario', 'Profile details'), - 'options' => [ - 'class' => 'disabled', - 'onclick' => 'return false;', - ], - ], - [ - 'label' => Yii::t('usuario', 'Information'), - 'options' => [ - 'class' => 'disabled', - 'onclick' => 'return false;', - ], - ], - ], - ] + 'label' => Yii::t('usuario', 'Account details'), + 'url' => ['/user/admin/create'], + 'linkOptions' => ['class' => 'nav-link'], + 'options' => ['class' => 'nav-item'], + ], + [ + 'label' => Yii::t('usuario', 'Profile details'), + 'url' => '#', + 'linkOptions' => ['class' => 'nav-link disabled', 'onclick' => 'return false;'], + 'options' => ['class' => 'nav-item'], + ], + [ + 'label' => Yii::t('usuario', 'Information'), + 'url' => '#', + 'linkOptions' => ['class' => 'nav-link disabled', 'onclick' => 'return false;'], + 'options' => ['class' => 'nav-item'], + ], + ], + ] + ) ?> +
+
+
+
+
+
+
+ . + . +
+ true, + 'enableClientValidation' => false, + ] + ); ?> + + render('/admin/_user', ['form' => $form, 'user' => $user]) ?> + +
+
+ 'btn btn-block btn-success'] ) ?>
-
-
-
-
-
- . - . -
- 'horizontal', - 'enableAjaxValidation' => true, - 'enableClientValidation' => false, - 'fieldConfig' => [ - 'horizontalCssClasses' => [ - 'wrapper' => 'col-sm-9', - ], - ], - ] - ); ?> - render('/admin/_user', ['form' => $form, 'user' => $user]) ?> - -
-
- 'btn btn-block btn-success'] - ) ?> -
-
- - -
-
+
-
- +
\ No newline at end of file diff --git a/src/User/resources/views/admin/index.php b/src/User/resources/views/admin/index.php index a991fda..92a31f2 100644 --- a/src/User/resources/views/admin/index.php +++ b/src/User/resources/views/admin/index.php @@ -29,170 +29,171 @@ $this->params['breadcrumbs'][] = $this->title; beginContent($module->viewPath . '/shared/admin_layout.php') ?> -
- $dataProvider, - 'filterModel' => $searchModel, - 'layout' => "{items}\n{pager}", - 'columns' => [ - 'username', - 'email:email', - [ - 'attribute' => 'registration_ip', - 'value' => function ($model) { - return $model->registration_ip == null - ? '' . Yii::t('usuario', '(not set)') . '' - : $model->registration_ip; - }, - 'format' => 'html', - 'visible' => !$module->disableIpLogging, - ], - [ - 'attribute' => 'created_at', - 'value' => function ($model) { - if (extension_loaded('intl')) { - return Yii::t('usuario', '{0, date, MMM dd, YYYY HH:mm}', [$model->created_at]); - } +
+ ['class' => 'flex-grow-1'], + 'dataProvider' => $dataProvider, + 'filterModel' => $searchModel, + 'layout' => "{items}\n{pager}", + 'columns' => [ + 'username', + 'email:email', + [ + 'attribute' => 'registration_ip', + 'value' => function ($model) { + return $model->registration_ip == null + ? '' . Yii::t('usuario', '(not set)') . '' + : $model->registration_ip; + }, + 'format' => 'html', + 'visible' => !$module->disableIpLogging, + ], + [ + 'attribute' => 'created_at', + 'value' => function ($model) { + if (extension_loaded('intl')) { + return Yii::t('usuario', '{0, date, MMM dd, YYYY HH:mm}', [$model->created_at]); + } - return date('Y-m-d G:i:s', $model->created_at); - }, - ], - [ - 'attribute' => 'last_login_at', - 'value' => function ($model) { - if (!$model->last_login_at || $model->last_login_at == 0) { - return Yii::t('usuario', 'Never'); - } elseif (extension_loaded('intl')) { - return Yii::t('usuario', '{0, date, MMM dd, YYYY HH:mm}', [$model->last_login_at]); - } else { - return date('Y-m-d G:i:s', $model->last_login_at); - } - }, - ], - [ - 'attribute' => 'last_login_ip', - 'value' => function ($model) { - return $model->last_login_ip == null - ? '' . Yii::t('usuario', '(not set)') . '' - : $model->last_login_ip; - }, - 'format' => 'html', - 'visible' => !$module->disableIpLogging, - ], - [ - 'header' => Yii::t('usuario', 'Confirmation'), - 'value' => function ($model) { - if ($model->isConfirmed) { - return '
+ return date('Y-m-d G:i:s', $model->created_at); + }, + ], + [ + 'attribute' => 'last_login_at', + 'value' => function ($model) { + if (!$model->last_login_at || $model->last_login_at == 0) { + return Yii::t('usuario', 'Never'); + } elseif (extension_loaded('intl')) { + return Yii::t('usuario', '{0, date, MMM dd, YYYY HH:mm}', [$model->last_login_at]); + } else { + return date('Y-m-d G:i:s', $model->last_login_at); + } + }, + ], + [ + 'attribute' => 'last_login_ip', + 'value' => function ($model) { + return $model->last_login_ip == null + ? '' . Yii::t('usuario', '(not set)') . '' + : $model->last_login_ip; + }, + 'format' => 'html', + 'visible' => !$module->disableIpLogging, + ], + [ + 'header' => Yii::t('usuario', 'Confirmation'), + 'value' => function ($model) { + if ($model->isConfirmed) { + return '
' . Yii::t('usuario', 'Confirmed') . '
'; - } + } - return Html::a( - Yii::t('usuario', 'Confirm'), - ['confirm', 'id' => $model->id], - [ - 'class' => 'btn btn-xs btn-success btn-block', - 'data-method' => 'post', - 'data-confirm' => Yii::t('usuario', 'Are you sure you want to confirm this user?'), - ] - ); - }, - 'format' => 'raw', - 'visible' => Yii::$app->getModule('user')->enableEmailConfirmation, - ], - 'password_age', - [ - 'header' => Yii::t('usuario', 'Block status'), - 'value' => function ($model) { - if ($model->isBlocked) { return Html::a( - Yii::t('usuario', 'Unblock'), - ['block', 'id' => $model->id], + Yii::t('usuario', 'Confirm'), + ['confirm', 'id' => $model->id], [ 'class' => 'btn btn-xs btn-success btn-block', 'data-method' => 'post', - 'data-confirm' => Yii::t('usuario', 'Are you sure you want to unblock this user?'), + 'data-confirm' => Yii::t('usuario', 'Are you sure you want to confirm this user?'), ] ); - } - - return Html::a( - Yii::t('usuario', 'Block'), - ['block', 'id' => $model->id], - [ - 'class' => 'btn btn-xs btn-danger btn-block', - 'data-method' => 'post', - 'data-confirm' => Yii::t('usuario', 'Are you sure you want to block this user?'), - ] - ); - }, - 'format' => 'raw', - ], - [ - 'class' => 'yii\grid\ActionColumn', - 'template' => '{switch} {reset} {force-password-change} {update} {delete}', - 'buttons' => [ - 'switch' => function ($url, $model) use ($module) { - if ($model->id != Yii::$app->user->id && $module->enableSwitchIdentities) { + }, + 'format' => 'raw', + 'visible' => Yii::$app->getModule('user')->enableEmailConfirmation, + ], + 'password_age', + [ + 'header' => Yii::t('usuario', 'Block status'), + 'value' => function ($model) { + if ($model->isBlocked) { return Html::a( - '', - ['/user/admin/switch-identity', 'id' => $model->id], + Yii::t('usuario', 'Unblock'), + ['block', 'id' => $model->id], [ - 'title' => Yii::t('usuario', 'Impersonate this user'), - 'data-confirm' => Yii::t( - 'usuario', - 'Are you sure you want to switch to this user for the rest of this Session?' - ), - 'data-method' => 'POST', + 'class' => 'btn btn-xs btn-success btn-block', + 'data-method' => 'post', + 'data-confirm' => Yii::t('usuario', 'Are you sure you want to unblock this user?'), ] ); } - return null; - }, - 'reset' => function ($url, $model) use ($module) { - if($module->allowAdminPasswordRecovery) { - return Html::a( - '', - ['/user/admin/password-reset', 'id' => $model->id], - [ - 'title' => Yii::t('usuario', 'Send password recovery email'), - 'data-confirm' => Yii::t( - 'usuario', - 'Are you sure you wish to send a password recovery email to this user?' - ), - 'data-method' => 'POST', - ] - ); - } - - return null; - }, - 'force-password-change' => function ($url, $model) use ($module) { - if (is_null($module->maxPasswordAge)) { - return null; - } return Html::a( - '', - ['/user/admin/force-password-change', 'id' => $model->id], + Yii::t('usuario', 'Block'), + ['block', 'id' => $model->id], [ - 'title' => Yii::t('usuario', 'Force password change at next login'), - 'data-confirm' => Yii::t( - 'usuario', - 'Are you sure you wish the user to change their password at next login?' - ), - 'data-method' => 'POST', + 'class' => 'btn btn-xs btn-danger btn-block', + 'data-method' => 'post', + 'data-confirm' => Yii::t('usuario', 'Are you sure you want to block this user?'), ] ); }, - ] + 'format' => 'raw', + ], + [ + 'class' => 'yii\grid\ActionColumn', + 'template' => '{switch} {reset} {force-password-change} {update} {delete}', + 'buttons' => [ + 'switch' => function ($url, $model) use ($module) { + if ($model->id != Yii::$app->user->id && $module->enableSwitchIdentities) { + return Html::a( + '', + ['/user/admin/switch-identity', 'id' => $model->id], + [ + 'title' => Yii::t('usuario', 'Impersonate this user'), + 'data-confirm' => Yii::t( + 'usuario', + 'Are you sure you want to switch to this user for the rest of this Session?' + ), + 'data-method' => 'POST', + ] + ); + } + + return null; + }, + 'reset' => function ($url, $model) use ($module) { + if ($module->allowAdminPasswordRecovery) { + return Html::a( + '', + ['/user/admin/password-reset', 'id' => $model->id], + [ + 'title' => Yii::t('usuario', 'Send password recovery email'), + 'data-confirm' => Yii::t( + 'usuario', + 'Are you sure you wish to send a password recovery email to this user?' + ), + 'data-method' => 'POST', + ] + ); + } + + return null; + }, + 'force-password-change' => function ($url, $model) use ($module) { + if (is_null($module->maxPasswordAge)) { + return null; + } + return Html::a( + '', + ['/user/admin/force-password-change', 'id' => $model->id], + [ + 'title' => Yii::t('usuario', 'Force password change at next login'), + 'data-confirm' => Yii::t( + 'usuario', + 'Are you sure you wish the user to change their password at next login?' + ), + 'data-method' => 'POST', + ] + ); + }, + ] + ], ], - ], - ] -); ?> + ] + ); ?>
-endContent() ?> +endContent() ?> \ No newline at end of file diff --git a/src/User/resources/views/admin/update.php b/src/User/resources/views/admin/update.php index a90fd96..2de77eb 100755 --- a/src/User/resources/views/admin/update.php +++ b/src/User/resources/views/admin/update.php @@ -10,7 +10,7 @@ */ use Da\User\Model\User; -use yii\bootstrap\Nav; +use yii\bootstrap4\Nav; use yii\helpers\Html; use yii\web\View; use Da\User\Module as UserModule; @@ -36,112 +36,104 @@ $module = Yii::$app->getModule('user'); ] ) ?> -
-
-
-
-

title) ?>

-
-
- render('/shared/_menu') ?> -
-
-
-
- [ - 'class' => 'nav-pills nav-stacked', - ], - 'items' => [ - [ - 'label' => Yii::t('usuario', 'Account details'), - 'url' => ['/user/admin/update', 'id' => $user->id], - ], - [ - 'label' => Yii::t('usuario', 'Profile details'), - 'url' => ['/user/admin/update-profile', 'id' => $user->id], - ], - [ - 'label' => Yii::t('usuario', 'Information'), - 'url' => ['/user/admin/info', 'id' => $user->id], - ], - [ - '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'), - 'url' => ['/user/admin/confirm', 'id' => $user->id], - 'visible' => !$user->isConfirmed, - 'linkOptions' => [ - 'class' => 'text-success', - 'data-method' => 'post', - 'data-confirm' => Yii::t( - 'usuario', - 'Are you sure you want to confirm this user?' - ), - ], - ], - [ - 'label' => Yii::t('usuario', 'Block'), - 'url' => ['/user/admin/block', 'id' => $user->id], - 'visible' => !$user->isBlocked, - 'linkOptions' => [ - 'class' => 'text-danger', - 'data-method' => 'post', - 'data-confirm' => Yii::t( - 'usuario', - 'Are you sure you want to block this user?' - ), - ], - ], - [ - 'label' => Yii::t('usuario', 'Unblock'), - 'url' => ['/user/admin/block', 'id' => $user->id], - 'visible' => $user->isBlocked, - 'linkOptions' => [ - 'class' => 'text-success', - 'data-method' => 'post', - 'data-confirm' => Yii::t( - 'usuario', - 'Are you sure you want to unblock this user?' - ), - ], - ], - [ - 'label' => Yii::t('usuario', 'Delete'), - 'url' => ['/user/admin/delete', 'id' => $user->id], - 'linkOptions' => [ - 'class' => 'text-danger', - 'data-method' => 'post', - 'data-confirm' => Yii::t( - 'usuario', - 'Are you sure you want to delete this user?' - ), - ], - ], - ], - ] - ) ?> -
-
+
+
+ render('/shared/_menu') ?> +
+
+
+
+ [ + 'class' => 'nav nav-pills flex-column', + ], + 'items' => [ + [ + 'label' => Yii::t('usuario', 'Account details'), + 'url' => ['/user/admin/update', 'id' => $user->id], + 'linkOptions' => ['class' => 'nav-link'], + 'options' => ['class' => 'nav-item'], + ], + [ + 'label' => Yii::t('usuario', 'Profile details'), + 'url' => ['/user/admin/update-profile', 'id' => $user->id], + 'linkOptions' => ['class' => 'nav-link'], + 'options' => ['class' => 'nav-item'], + ], + [ + 'label' => Yii::t('usuario', 'Information'), + 'url' => ['/user/admin/info', 'id' => $user->id], + 'linkOptions' => ['class' => 'nav-link'], + 'options' => ['class' => 'nav-item'], + ], + [ + 'label' => Yii::t('usuario', 'Assignments'), + 'url' => ['/user/admin/assignments', 'id' => $user->id], + 'linkOptions' => ['class' => 'nav-link'], + 'options' => ['class' => 'nav-item'], + ], + [ + 'label' => Yii::t('usuario', 'Session history'), + 'url' => ['/user/admin/session-history', 'id' => $user->id], + 'visible' => $module->enableSessionHistory, + 'linkOptions' => ['class' => 'nav-link'], + 'options' => ['class' => 'nav-item'], + ], + [ + 'label' => Yii::t('usuario', 'Confirm'), + 'url' => ['/user/admin/confirm', 'id' => $user->id], + 'visible' => !$user->isConfirmed, + 'linkOptions' => [ + 'class' => 'nav-link text-success', + 'data-method' => 'post', + 'data-confirm' => Yii::t('usuario', 'Are you sure you want to confirm this user?'), + ], + 'options' => ['class' => 'nav-item'], + ], + [ + 'label' => Yii::t('usuario', 'Block'), + 'url' => ['/user/admin/block', 'id' => $user->id], + 'visible' => !$user->isBlocked, + 'linkOptions' => [ + 'class' => 'nav-link text-danger', + 'data-method' => 'post', + 'data-confirm' => Yii::t('usuario', 'Are you sure you want to block this user?'), + ], + 'options' => ['class' => 'nav-item'], + ], + [ + 'label' => Yii::t('usuario', 'Unblock'), + 'url' => ['/user/admin/block', 'id' => $user->id], + 'visible' => $user->isBlocked, + 'linkOptions' => [ + 'class' => 'nav-link text-success', + 'data-method' => 'post', + 'data-confirm' => Yii::t('usuario', 'Are you sure you want to unblock this user?'), + ], + 'options' => ['class' => 'nav-item'], + ], + [ + 'label' => Yii::t('usuario', 'Delete'), + 'url' => ['/user/admin/delete', 'id' => $user->id], + 'linkOptions' => [ + 'class' => 'nav-link text-danger', + 'data-method' => 'post', + 'data-confirm' => Yii::t('usuario', 'Are you sure you want to delete this user?'), + ], + 'options' => ['class' => 'nav-item'], + ], + ], + ]) ?>
-
-
-
- -
-
+
+
+
+
+
+
-
+
\ No newline at end of file diff --git a/src/User/resources/views/permission/_form.php b/src/User/resources/views/permission/_form.php index 1ab6575..334cb49 100644 --- a/src/User/resources/views/permission/_form.php +++ b/src/User/resources/views/permission/_form.php @@ -9,7 +9,7 @@ * the LICENSE file that was distributed with this source code. */ -use dosamigos\selectize\SelectizeDropDownList; +use pcrt\widgets\select2\Select2; use yii\helpers\ArrayHelper; use yii\helpers\Html; use yii\widgets\ActiveForm; @@ -26,6 +26,7 @@ use yii\widgets\ActiveForm; [ 'enableClientValidation' => false, 'enableAjaxValidation' => true, + 'options' => ['class' => 'p-3'], ] ) ?> @@ -33,24 +34,29 @@ use yii\widgets\ActiveForm; field($model, 'description') ?> -field($model, 'rule')->widget(SelectizeDropDownList::class, [ +field($model, 'rule')->widget(Select2::class, [ 'items' => ArrayHelper::map(Yii::$app->getAuthManager()->getRules(), 'name', 'name'), 'options' => [ - 'prompt' => Yii::t('usuario', 'Select rule...'), - ] + 'placeholder' => Yii::t('usuario', 'Select rule...'), + 'multiple' => false, + ], + 'clientOptions' => [ + 'allowClear' => true, + 'width' => '100%', + ], ]) ?> - -field($model, 'children')->widget( - SelectizeDropDownList::class, - [ - 'items' => $unassignedItems, - 'options' => [ - 'id' => 'children', - 'multiple' => true, - ], - ] -) ?> +field($model, 'children')->widget(Select2::class, [ + 'items' => $unassignedItems, + 'options' => [ + 'placeholder' => Yii::t('usuario', 'Select children...'), + 'multiple' => true + ], + 'clientOptions' => [ + 'allowClear' => true, + 'width' => '100%', + ], +]) ?> 'btn btn-success btn-block']) ?> diff --git a/src/User/resources/views/permission/index.php b/src/User/resources/views/permission/index.php index 65142bf..57ee3be 100644 --- a/src/User/resources/views/permission/index.php +++ b/src/User/resources/views/permission/index.php @@ -25,9 +25,10 @@ $this->params['breadcrumbs'][] = $this->title; ?> beginContent($module->viewPath . '/shared/admin_layout.php') ?> -
+
['class' => 'flex-grow-1'], 'dataProvider' => $dataProvider, 'filterModel' => $searchModel, 'layout' => "{items}\n{pager}", diff --git a/src/User/resources/views/profile/_menu.php b/src/User/resources/views/profile/_menu.php new file mode 100644 index 0000000..5242b77 --- /dev/null +++ b/src/User/resources/views/profile/_menu.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +use yii\helpers\Html; +use Da\User\Module as UserModule; +use Da\User\Model\User; +use yii\bootstrap4\Nav; + +/** @var User $user */ +$user = Yii::$app->user->identity; +/** @var UserModule $module */ +$module = Yii::$app->getModule('user'); +$networksVisible = count(Yii::$app->authClientCollection->clients) > 0; + +?> + +
+
+

+ profile->getAvatarUrl(48), + [ + 'class' => 'rounded-lg', + 'alt' => $user->username, + ] + ) ?> + username ?> +

+
+
+ ['class' => 'nav nav-pills flex-column'], // nav verticale + 'items' => [ + [ + 'label' => Yii::t('usuario', 'Profile'), + 'url' => ['/user/profile/profile'], + 'linkOptions' => ['class' => 'nav-link'], + 'active' => Yii::$app->controller->action->id === 'profile', + ], + [ + 'label' => Yii::t('usuario', 'Account'), + 'url' => ['/user/profile/account'], + 'linkOptions' => ['class' => 'nav-link'], + 'active' => Yii::$app->controller->action->id === 'account', + ], + [ + 'label' => Yii::t('usuario', 'Session history'), + 'url' => ['/user/profile/session-history'], + 'visible' => $module->enableSessionHistory, + 'linkOptions' => ['class' => 'nav-link'], + 'active' => Yii::$app->controller->action->id === 'session-history', + ], + [ + 'label' => Yii::t('usuario', 'Privacy'), + 'url' => ['/user/profile/privacy'], + 'visible' => $module->enableGdprCompliance, + 'linkOptions' => ['class' => 'nav-link'], + 'active' => Yii::$app->controller->action->id === 'privacy', + ], + [ + 'label' => Yii::t('usuario', 'Networks'), + 'url' => ['/user/profile/networks'], + 'visible' => $networksVisible, + 'linkOptions' => ['class' => 'nav-link'], + 'active' => Yii::$app->controller->action->id === 'networks', + ], + ], + ]) ?> +
+
\ No newline at end of file diff --git a/src/User/resources/views/settings/account.php b/src/User/resources/views/profile/account.php similarity index 93% rename from src/User/resources/views/settings/account.php rename to src/User/resources/views/profile/account.php index 71acb07..20c71fe 100644 --- a/src/User/resources/views/settings/account.php +++ b/src/User/resources/views/profile/account.php @@ -31,23 +31,20 @@ $module = Yii::$app->getModule('user'); render('/shared/_alert', ['module' => Yii::$app->getModule('user')]) ?>
-
- render('/settings/_menu') ?> +
+ render('/profile/_menu') ?>
-
-
-
-

title) ?>

-
-
+
+
+
$model->formName(), - 'options' => ['class' => 'form-horizontal'], - 'fieldConfig' => [ - 'template' => "{label}\n
{input}
\n
{error}\n{hint}
", - 'labelOptions' => ['class' => 'col-lg-3 control-label'], - ], + // 'options' => ['class' => 'form-horizontal'], + // 'fieldConfig' => [ + // 'template' => "{label}\n
{input}
\n
{error}\n{hint}
", + // 'labelOptions' => ['class' => 'col-lg-3 control-label'], + // ], 'enableAjaxValidation' => true, 'enableClientValidation' => false, ] @@ -63,8 +60,8 @@ $module = Yii::$app->getModule('user'); field($model, 'current_password')->passwordInput() ?> -
-
+
+
'btn btn-block btn-success']) ?>
diff --git a/src/User/resources/views/settings/gdpr-consent.php b/src/User/resources/views/profile/gdpr-consent.php similarity index 95% rename from src/User/resources/views/settings/gdpr-consent.php rename to src/User/resources/views/profile/gdpr-consent.php index a7b69ae..21008f8 100644 --- a/src/User/resources/views/settings/gdpr-consent.php +++ b/src/User/resources/views/profile/gdpr-consent.php @@ -26,7 +26,7 @@ use yii\widgets\ActiveForm;
diff --git a/src/User/resources/views/profile/gdpr-delete.php b/src/User/resources/views/profile/gdpr-delete.php new file mode 100644 index 0000000..735458c --- /dev/null +++ b/src/User/resources/views/profile/gdpr-delete.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +use yii\widgets\ActiveForm; +use yii\helpers\Html; + +/** @var \Da\User\Form\GdprDeleteForm $model */ + +$this->title = Yii::t('usuario', 'Delete personal data'); +?> + +
+
+
+

+

+ +

+
+ +
+
+ field($model, 'password')->passwordInput() ?> +
+
+
+ 'btn btn-danger']) ?> +
+
+
+ 'btn btn-info']) ?> +
+ +
+
+
\ No newline at end of file diff --git a/src/User/resources/views/settings/networks.php b/src/User/resources/views/profile/networks.php similarity index 98% rename from src/User/resources/views/settings/networks.php rename to src/User/resources/views/profile/networks.php index 7576146..8629987 100644 --- a/src/User/resources/views/settings/networks.php +++ b/src/User/resources/views/profile/networks.php @@ -28,7 +28,7 @@ $this->params['breadcrumbs'][] = $this->title;
- render('/settings/_menu') ?> + render('/profile/_menu') ?>
diff --git a/src/User/resources/views/profile/privacy.php b/src/User/resources/views/profile/privacy.php new file mode 100644 index 0000000..4892c2a --- /dev/null +++ b/src/User/resources/views/profile/privacy.php @@ -0,0 +1,71 @@ +title = Yii::t('usuario', 'Privacy settings'); + +?> + +
+
+ render('_menu') ?> +
+
+
+
+
+

+

+

+ 'btn btn-info', + 'target' => '_blank' + ] + ) + ?> +
+
+
+

+

+

+ allowAccountDelete): ?> + 'gdpr-del-button', + 'class' => 'btn btn-danger', + 'data-method' => 'post', + 'data-confirm' => Yii::t('usuario', 'Are you sure? There is no going back'), + ] + ) ?> + 'btn btn-danger', + 'id' => 'gdpr-del-button', + + ] + ) + ?> + +
+
+
+
+
\ No newline at end of file diff --git a/src/User/resources/views/settings/profile.php b/src/User/resources/views/profile/profile.php similarity index 75% rename from src/User/resources/views/settings/profile.php rename to src/User/resources/views/profile/profile.php index 0237aa0..c20ef4b 100644 --- a/src/User/resources/views/settings/profile.php +++ b/src/User/resources/views/profile/profile.php @@ -31,23 +31,20 @@ $timezoneHelper = $model->make(TimezoneHelper::class); render('/shared/_alert', ['module' => Yii::$app->getModule('user')]) ?>
-
+
render('_menu') ?>
-
-
-
-

title) ?>

-
-
+
+
+
$model->formName(), - 'options' => ['class' => 'form-horizontal'], - 'fieldConfig' => [ - 'template' => "{label}\n
{input}
\n
{error}\n{hint}
", - 'labelOptions' => ['class' => 'col-lg-3 control-label'], - ], + // 'options' => ['class' => 'form-horizontal'], + // 'fieldConfig' => [ + // 'template' => "{label}\n
{input}
\n
{error}\n{hint}
", + // 'labelOptions' => ['class' => 'col-lg-3 control-label'], + // ], 'enableAjaxValidation' => true, 'enableClientValidation' => false, 'validateOnBlur' => false, @@ -56,6 +53,8 @@ $timezoneHelper = $model->make(TimezoneHelper::class); field($model, 'name') ?> + field($model, 'surname') ?> + field($model, 'public_email') ?> field($model, 'website') ?> @@ -78,8 +77,8 @@ $timezoneHelper = $model->make(TimezoneHelper::class); field($model, 'bio')->textarea() ?> -
-
+
+
'btn btn-block btn-success']) ?>
diff --git a/src/User/resources/views/settings/session-history.php b/src/User/resources/views/profile/session-history.php old mode 100755 new mode 100644 similarity index 83% rename from src/User/resources/views/settings/session-history.php rename to src/User/resources/views/profile/session-history.php index 0c75ec8..cad394d --- a/src/User/resources/views/settings/session-history.php +++ b/src/User/resources/views/profile/session-history.php @@ -31,23 +31,22 @@ $this->params['breadcrumbs'][] = $this->title; render('/shared/_alert', ['module' => Yii::$app->getModule('user')]) ?>
-
- render('/settings/_menu') ?> +
+ render('/profile/_menu') ?>
-
-
-
- title) ?> +
+
+
'btn btn-danger btn-xs pull-right', + 'class' => 'btn btn-danger btn-xs', 'data-method' => 'post' ] ) ?>
-
+
diff --git a/src/User/resources/views/profile/show.php b/src/User/resources/views/profile/show.php deleted file mode 100644 index a101a97..0000000 --- a/src/User/resources/views/profile/show.php +++ /dev/null @@ -1,71 +0,0 @@ - - * - * For the full copyright and license information, please view - * the LICENSE file that was distributed with this source code. - */ - -use yii\helpers\Html; - -/** - * @var \yii\web\View $this - * @var \Da\User\Model\Profile $profile - */ - -$this->title = empty($profile->name) ? Html::encode($profile->user->username) : Html::encode($profile->name); -$this->params['breadcrumbs'][] = $this->title; -?> -
-
-
-
- getAvatarUrl(230), - [ - 'class' => 'img-rounded img-responsive', - 'alt' => $profile->user->username, - ] - ) ?> -
-
-

title ?>

-
    - location)): ?> -
  • - - location) ?> -
  • - - website)): ?> -
  • - - website), Html::encode($profile->website)) ?> -
  • - - public_email)): ?> -
  • - - public_email), - 'mailto:' . - Html::encode($profile->public_email) - ) - ?> -
  • - -
  • - - user->created_at) ?> -
  • -
- bio)): ?> -

bio) ?>

- -
-
-
-
diff --git a/src/User/resources/views/settings/two-factor-email.php b/src/User/resources/views/profile/two-factor-email.php similarity index 100% rename from src/User/resources/views/settings/two-factor-email.php rename to src/User/resources/views/profile/two-factor-email.php diff --git a/src/User/resources/views/settings/two-factor-sms.php b/src/User/resources/views/profile/two-factor-sms.php similarity index 100% rename from src/User/resources/views/settings/two-factor-sms.php rename to src/User/resources/views/profile/two-factor-sms.php diff --git a/src/User/resources/views/settings/two-factor.php b/src/User/resources/views/profile/two-factor.php similarity index 100% rename from src/User/resources/views/settings/two-factor.php rename to src/User/resources/views/profile/two-factor.php diff --git a/src/User/resources/views/recovery/request.php b/src/User/resources/views/recovery/request.php index 6b0b6d7..4b9ff9a 100644 --- a/src/User/resources/views/recovery/request.php +++ b/src/User/resources/views/recovery/request.php @@ -21,14 +21,19 @@ use yii\widgets\ActiveForm; $this->title = Yii::t('usuario', 'Recover your password'); $this->params['breadcrumbs'][] = $this->title; ?> -
-
-
-
-

title) ?>

-
-
- + + +
+
params['name_first'] ?>
+
params['name_last'] ?>
+
+
+
+
+
title) ?>
+ $model->formName(), 'enableAjaxValidation' => true, diff --git a/src/User/resources/views/recovery/reset.php b/src/User/resources/views/recovery/reset.php index 8f225f1..bb6097a 100644 --- a/src/User/resources/views/recovery/reset.php +++ b/src/User/resources/views/recovery/reset.php @@ -21,27 +21,30 @@ use yii\widgets\ActiveForm; $this->title = Yii::t('usuario', 'Reset your password'); $this->params['breadcrumbs'][] = $this->title; ?> -
-
-
-
-

title) ?>

-
-
- $model->formName(), - 'enableAjaxValidation' => true, - 'enableClientValidation' => false, - ] - ); ?> + -
+
\ No newline at end of file diff --git a/src/User/resources/views/registration/connect.php b/src/User/resources/views/registration/connect.php index e6e8a50..927c58d 100644 --- a/src/User/resources/views/registration/connect.php +++ b/src/User/resources/views/registration/connect.php @@ -58,7 +58,7 @@ $this->params['breadcrumbs'][] = $this->title; 'usuario', 'If you already registered, sign in and connect this account on settings page' ), - ['/user/settings/networks'] + ['/user/profile/networks'] ) ?>.

diff --git a/src/User/resources/views/registration/register.php b/src/User/resources/views/registration/register.php index 29d1e75..6705341 100644 --- a/src/User/resources/views/registration/register.php +++ b/src/User/resources/views/registration/register.php @@ -22,40 +22,44 @@ use yii\widgets\ActiveForm; $this->title = Yii::t('usuario', 'Sign up'); $this->params['breadcrumbs'][] = $this->title; ?> -
-
-
-
-

title) ?>

-
-
- $model->formName(), - 'enableAjaxValidation' => true, - 'enableClientValidation' => false, - ] - ); ?> - field($model, 'email')->textInput(['autofocus' => true]) ?> + -
+
\ No newline at end of file diff --git a/src/User/resources/views/registration/resend.php b/src/User/resources/views/registration/resend.php index b687a1e..71bdbde 100644 --- a/src/User/resources/views/registration/resend.php +++ b/src/User/resources/views/registration/resend.php @@ -20,27 +20,30 @@ use yii\widgets\ActiveForm; $this->title = Yii::t('usuario', 'Request new confirmation message'); $this->params['breadcrumbs'][] = $this->title; ?> -
-
-
-
-

title) ?>

-
-
- $model->formName(), - 'enableAjaxValidation' => true, - 'enableClientValidation' => false, - ] - ); ?> + -
+
\ No newline at end of file diff --git a/src/User/resources/views/role/_form.php b/src/User/resources/views/role/_form.php index 33eb2e9..3ebd20e 100644 --- a/src/User/resources/views/role/_form.php +++ b/src/User/resources/views/role/_form.php @@ -15,7 +15,7 @@ */ use Da\User\Helper\AuthHelper; -use dosamigos\selectize\SelectizeDropDownList; +use pcrt\widgets\select2\Select2; use yii\helpers\ArrayHelper; use yii\helpers\Html; use yii\widgets\ActiveForm; @@ -27,6 +27,7 @@ $unassignedItems = Yii::$container->get(AuthHelper::class)->getUnassignedItems($ [ 'enableClientValidation' => false, 'enableAjaxValidation' => true, + 'options' => ['class' => 'p-3'], ] ) ?> @@ -34,23 +35,29 @@ $unassignedItems = Yii::$container->get(AuthHelper::class)->getUnassignedItems($ field($model, 'description') ?> -field($model, 'rule')->widget(SelectizeDropDownList::class, [ +field($model, 'rule')->widget(Select2::class, [ 'items' => ArrayHelper::map(Yii::$app->getAuthManager()->getRules(), 'name', 'name'), 'options' => [ - 'prompt' => 'Select rule...' - ] + 'placeholder' => Yii::t('usuario', 'Select rule...'), + 'multiple' => false, + ], + 'clientOptions' => [ + 'allowClear' => true, + 'width' => '100%', + ], ]) ?> -field($model, 'children')->widget( - SelectizeDropDownList::class, - [ - 'items' => $unassignedItems, - 'options' => [ - 'id' => 'children', - 'multiple' => true, - ], - ] -) ?> +field($model, 'children')->widget(Select2::class, [ + 'items' => $unassignedItems, + 'options' => [ + 'placeholder' => Yii::t('usuario', 'Select children...'), + 'multiple' => true + ], + 'clientOptions' => [ + 'allowClear' => true, + 'width' => '100%', + ], +]) ?> 'btn btn-success btn-block']) ?> diff --git a/src/User/resources/views/role/create.php b/src/User/resources/views/role/create.php index a821036..77bb661 100644 --- a/src/User/resources/views/role/create.php +++ b/src/User/resources/views/role/create.php @@ -30,4 +30,4 @@ $this->params['breadcrumbs'][] = $this->title; ] ) ?> -endContent() ?> +endContent() ?> \ No newline at end of file diff --git a/src/User/resources/views/role/index.php b/src/User/resources/views/role/index.php index 5a7beb6..882baab 100644 --- a/src/User/resources/views/role/index.php +++ b/src/User/resources/views/role/index.php @@ -26,46 +26,47 @@ $this->params['breadcrumbs'][] = $this->title; ?> beginContent($module->viewPath . '/shared/admin_layout.php') ?> -
- $dataProvider, - 'filterModel' => $searchModel, - 'layout' => "{items}\n{pager}", - 'columns' => [ - [ - 'attribute' => 'name', - 'header' => Yii::t('usuario', 'Name'), - 'options' => [ - 'style' => 'width: 20%', +
+ ['class' => 'flex-grow-1'], + 'dataProvider' => $dataProvider, + 'filterModel' => $searchModel, + 'layout' => "{items}\n{pager}", + 'columns' => [ + [ + 'attribute' => 'name', + 'header' => Yii::t('usuario', 'Name'), + 'options' => [ + 'style' => 'width: 20%', + ], + ], + [ + 'attribute' => 'description', + 'header' => Yii::t('usuario', 'Description'), + 'options' => [ + 'style' => 'width: 55%', + ], + ], + [ + 'attribute' => 'rule_name', + 'header' => Yii::t('usuario', 'Rule name'), + 'options' => [ + 'style' => 'width: 20%', + ], + ], + [ + 'class' => ActionColumn::class, + 'template' => '{update} {delete}', + 'urlCreator' => function ($action, $model) { + return Url::to(['/user/role/' . $action, 'name' => $model['name']]); + }, + 'options' => [ + 'style' => 'width: 5%', + ], ], ], - [ - 'attribute' => 'description', - 'header' => Yii::t('usuario', 'Description'), - 'options' => [ - 'style' => 'width: 55%', - ], - ], - [ - 'attribute' => 'rule_name', - 'header' => Yii::t('usuario', 'Rule name'), - 'options' => [ - 'style' => 'width: 20%', - ], - ], - [ - 'class' => ActionColumn::class, - 'template' => '{update} {delete}', - 'urlCreator' => function ($action, $model) { - return Url::to(['/user/role/' . $action, 'name' => $model['name']]); - }, - 'options' => [ - 'style' => 'width: 5%', - ], - ], - ], - ] -) ?> + ] + ) ?>
-endContent() ?> +endContent() ?> \ No newline at end of file diff --git a/src/User/resources/views/rule/_form.php b/src/User/resources/views/rule/_form.php index 498a0a8..a1d6d7e 100644 --- a/src/User/resources/views/rule/_form.php +++ b/src/User/resources/views/rule/_form.php @@ -15,6 +15,7 @@ use yii\widgets\ActiveForm; [ 'enableClientValidation' => false, 'enableAjaxValidation' => true, + 'options' => ['class' => 'p-3'], ] ) ?> @@ -22,6 +23,13 @@ use yii\widgets\ActiveForm; field($model, 'className') ?> - 'btn btn-success btn-block']) ?> +
+
+ 'btn btn-block btn-success'] + ) ?> +
+
- + \ No newline at end of file diff --git a/src/User/resources/views/rule/index.php b/src/User/resources/views/rule/index.php index b2fd066..e31d2e1 100644 --- a/src/User/resources/views/rule/index.php +++ b/src/User/resources/views/rule/index.php @@ -18,9 +18,10 @@ $this->params['breadcrumbs'][] = $this->title; ?> beginContent($module->viewPath . '/shared/admin_layout.php') ?> -
+
['class' => 'flex-grow-1'], 'dataProvider' => $dataProvider, 'filterModel' => $searchModel, 'layout' => "{items}\n{pager}", diff --git a/src/User/resources/views/security/login.php b/src/User/resources/views/security/login.php index 8bbc5ce..2c5f2ef 100644 --- a/src/User/resources/views/security/login.php +++ b/src/User/resources/views/security/login.php @@ -23,59 +23,61 @@ $this->title = Yii::t('usuario', 'Sign in'); $this->params['breadcrumbs'][] = $this->title; ?> -render('/shared/_alert', ['module' => Yii::$app->getModule('user')]) ?> +