assign trainers to user; add email to jwt token

This commit is contained in:
Roland Schneider 2021-10-04 18:13:32 +02:00
parent 439fb12b6e
commit 7a55ca9ff3
21 changed files with 671 additions and 350 deletions

View File

@ -172,19 +172,68 @@ class AdminMenuStructure
/////////////////////////////
// Group Training
/////////////////////////////
if (RoleDefinition::isLoggedUser()) {
$items = [];
$items[] = ['label' => 'Felszerelés', 'url' => ['/event-equipment-type']];
$items[] = ['label' => 'Edzők', 'url' => ['/trainer']];
$items[] = ['label' => 'Termek', 'url' => ['/room']];
$items[] = ['label' => 'Esemény típusok', 'url' => ['/event-type']];
$items[] = ['label' => 'Események', 'url' => ['/event/event/index']];
$items[] = ['label' => 'Órarend', 'url' => ['/event/event/timetable']];
$items[] = ['label' => 'Hét másolása', 'url' => ['/event/event/copy-week']];
$this->menuItems[] = ['label' => 'Csoportos edzés', 'url' => $this->emptyUrl,
'items' => $items
];
}
$items = [];
// $items[] = ['label' => 'Felszerelés', 'url' => ['/event-equipment-type'], 'role' => [RoleDefinition::$ROLE_ADMIN]];
$items[] = [
'label' => 'Edzők',
'url' => ['/trainer'],
'role' => [
RoleDefinition::$ROLE_ADMIN,
RoleDefinition::$ROLE_EMPLOYEE,
]
];
$items[] = ['label' => 'Termek',
'url' => ['/room'],
'role' => [
RoleDefinition::$ROLE_ADMIN,
RoleDefinition::$ROLE_EMPLOYEE,
]
];
$items[] = ['label' => 'Esemény típusok',
'url' => ['/event-type'],
'role' => [
RoleDefinition::$ROLE_ADMIN,
RoleDefinition::$ROLE_EMPLOYEE,
]
];
$items[] = [
'label' => 'Események',
'url' => ['/event/event/index'],
'role' => [
RoleDefinition::$ROLE_ADMIN,
RoleDefinition::$ROLE_EMPLOYEE,
RoleDefinition::$ROLE_TRAINER
]
];
$items[] = [
'label' => 'Órarend',
'url' => ['/event/event/timetable'],
'role' => [
RoleDefinition::$ROLE_ADMIN,
RoleDefinition::$ROLE_EMPLOYEE,
RoleDefinition::$ROLE_TRAINER
]
];
$items[] = [
'label' => 'Hét másolása',
'url' => ['/event/event/copy-week'],
'role' => [
RoleDefinition::$ROLE_ADMIN,
RoleDefinition::$ROLE_EMPLOYEE,
RoleDefinition::$ROLE_TRAINER
]
];
$this->menuItems[] = [
'label' => 'Csoportos edzés',
'url' => $this->emptyUrl,
'items' => $items,
'role' => [
RoleDefinition::$ROLE_ADMIN,
RoleDefinition::$ROLE_EMPLOYEE,
RoleDefinition::$ROLE_TRAINER
]
];
/////////////////////////////
// Development
@ -198,10 +247,50 @@ class AdminMenuStructure
];
}
$this->menuItems = $this->filterMenu($this->menuItems);
}
}
protected function filterMenu($menuItems)
{
$result = [];
foreach ($menuItems as $item) {
$filteredItem = $this->filterMenuItem($item);
if (isset($filteredItem)) {
$result[] = $filteredItem;
}
}
return $result;
}
protected function filterMenuItem($menuItem)
{
$result = $menuItem;
if (isset($menuItem)) {
if (isset($menuItem['role'])) {
$roles = $menuItem['role'];
$canAny = RoleDefinition::canAny($roles);
if ($canAny === false) {
$result = null;
} else {
if (isset($menuItem['items'])) {
$result['items'] = [];
$items = $menuItem['items'];
foreach ($items as $subItem) {
$filteredItem = $this->filterMenuItem($subItem);
if (isset($filteredItem)) {
$result['items'][] = $filteredItem;
}
}
}
}
}
}
return $result;
}
protected function addLoginMainMenu()
{
if (Yii::$app->user->isGuest) {

View File

@ -2,10 +2,13 @@
namespace backend\controllers;
use common\models\Trainer;
use common\models\UserTrainerAssignment;
use Yii;
use common\models\User;
use backend\models\UserSearch;
use backend\models\UserCreate;
use yii\web\BadRequestHttpException;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
@ -20,7 +23,7 @@ use common\components\RoleDefinition;
*/
class UserController extends \backend\controllers\BackendController
{
public function behaviors()
{
@ -45,8 +48,8 @@ class UserController extends \backend\controllers\BackendController
],
];
}
/**
* Lists all User models.
* @return mixed
@ -55,8 +58,8 @@ class UserController extends \backend\controllers\BackendController
{
$searchModel = new UserSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
@ -84,35 +87,48 @@ class UserController extends \backend\controllers\BackendController
public function actionCreate()
{
$model = new UserCreate();
$accounts = Account::readAccounts();
$trainers = Trainer::find()->all();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
$this->updateAccountAssignments($model);
$this->updateTrainerAssignments($model);
return $this->redirect(['index' ]);
}
}
return $this->render('create', [
'model' => $model,
'accounts' => $accounts,
'trainers' => $trainers,
]);
}
public function updateAccountAssignments($model){
echo "saving accounts";
UserAccountAssignment::deleteAll(['id_user' => $model->id]);
foreach ( $model->selected_accounts as $id_account ){
echo "saving account";
$uaa = new UserAccountAssignment();
$uaa->id_user = $model->id;
$uaa->id_account = $id_account;
$uaa->save();
}
}
public function updateTrainerAssignments($model){
UserTrainerAssignment::deleteAll(['id_user' => $model->id]);
foreach ( $model->selected_trainers as $id_trainer ){
$uaa = new UserTrainerAssignment();
$uaa->id_user = $model->id;
$uaa->id_trainer = $id_trainer;
$uaa->save();
}
}
/**
@ -124,7 +140,7 @@ class UserController extends \backend\controllers\BackendController
public function actionUpdate($id)
{
$model = UserUpdate::findOne(['id' => $id]);
if ( Yii::$app->authManager->checkAccess($model->id, 'admin')){
$model->role = 'admin';
} else if ( Yii::$app->authManager->checkAccess($model->id, 'employee')){
@ -132,28 +148,31 @@ class UserController extends \backend\controllers\BackendController
}else if ( Yii::$app->authManager->checkAccess($model->id, 'reception')){
$model->role = 'reception';
}
if ( $model == null ){
throw new NotFoundHttpException('The requested page does not exist.');
}
$accounts = Account::readAccounts();
$this->applyAccounts($model);
$trainers = Trainer::find()->all();
$this->applyTrainers($model);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
$this->updateAccountAssignments($model);
$this->updateTrainerAssignments($model);
return $this->redirect(['view', 'id' => $model->id]);
} else {
}
return $this->render('update', [
'model' => $model,
'accounts' => $accounts,
'trainers' => $trainers,
]);
}
private function applyAccounts($model ){
$assignedAccounts = $model->userAccountAssignments;
foreach ($assignedAccounts as $acc ){
@ -161,6 +180,13 @@ class UserController extends \backend\controllers\BackendController
}
}
private function applyTrainers($model ){
$assignedTrainers = $model->userTrainerAssignments;
foreach ($assignedTrainers as $acc ){
$model->selected_trainers[] = $acc->id_trainer;
}
}
/**
* Deletes an existing User model.
* If deletion is successful, the browser will be redirected to the 'index' page.
@ -171,12 +197,12 @@ class UserController extends \backend\controllers\BackendController
{
$user = $this->findModel($id);
$user->updateAttributes(['status' => User::STATUS_DELETED]);
return $this->redirect(['index']);
}
/**
* Creates a new User model.
* If creation is successful, the browser will be redirected to the 'view' page.
@ -185,17 +211,17 @@ class UserController extends \backend\controllers\BackendController
public function actionRole()
{
$model = new \backend\models\RoleForm();
$model->availablePermissions = [
[
'name' => "reception.transfers",
'description' => 'Tranzakciók'
]
];
if ($model->load(Yii::$app->request->post()) ) {
if ( $model->validate() && $model->save()){
Yii::$app->session->setFlash('success', 'Jogosultságok elmentve');
@ -209,7 +235,7 @@ class UserController extends \backend\controllers\BackendController
$model->permissions[] = $child->name;
}
}
return $this->render('role', [
'model' => $model,
]);

View File

@ -9,9 +9,10 @@ class UserCreate extends User{
public $password_plain;
public $password_repeat;
public $selected_accounts = [];
public $selected_trainers = [];
public $role;
/**
* @inheritdoc
*/
@ -25,28 +26,34 @@ class UserCreate extends User{
}
}
],
['selected_trainers',function ($attribute, $params) {
if (!is_array($this->$attribute)) {
$this->addError($attribute, 'Invalid array');
}
}
],
['email' ,'email' ],
['email' ,'unique' ],
['username' ,'unique' ],
[['password_plain' ,'password_repeat'] ,'string','min' =>6 ],
[['password_repeat'] ,'validatePasswordRepeat' ],
[['role'], 'required'],
[['role'], 'string', 'max' => 20],
['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
];
}
public function validatePasswordRepeat($attribute,$params){
if ( !$this->hasErrors()){
if ( $this->password_plain != $this->password_repeat ){
$this->addError($attribute, Yii::t('app', 'Jelszó és jelszó újra nem egyezik!') );
}
}
}
public function attributeLabels(){
return [
'status' => 'Státusz',
@ -55,10 +62,10 @@ class UserCreate extends User{
'created_at' =>'Létrehozás dátuma',
'password_plain' => Yii::t('app','Jelszó'),
'password_repeat' => Yii::t('app','Jelszó újra'),
];
}
public function beforeSave($insert){
if ( parent::beforeSave($insert)){
if ( $insert ){
@ -70,12 +77,12 @@ class UserCreate extends User{
return false;
}
}
public function afterSave($insert, $changedAttributes){
parent::afterSave($insert, $changedAttributes);
parent::afterSave($insert, $changedAttributes);
$am = Yii::$app->authManager;
$role = $am->getRole($this->role);
Yii::$app->authManager->assign($role, $this->id);
}
}
}

View File

@ -9,9 +9,10 @@ class UserUpdate extends User {
public $password_plain;
public $password_repeat;
public $selected_accounts = [];
public $selected_trainers = [];
public $role;
/**
* @inheritdoc
* @formatter:off
@ -21,25 +22,59 @@ class UserUpdate extends User {
return [
[['username','email'], 'required' ],
['email' ,'email' ],
['email' ,'unique' , 'targetClass' => User::className(), 'targetAttribute' => 'email'],
['username' ,'unique', 'targetClass' => User::className(), 'targetAttribute' => 'username'],
// ['email' ,'unique' , 'targetClass' => User::className(), 'targetAttribute' => 'email'],
// ['username' ,'unique', 'targetClass' => User::className(), 'targetAttribute' => 'username'],
[['password_plain' ,'password_repeat'] ,'string','min' =>6 ],
[['password_repeat'] ,'validatePasswordRepeat' ],
[['username'] ,'validateUsername' ],
[['email'] ,'validateEmail' ],
['selected_accounts',function ($attribute, $params) {
if (!is_array($this->$attribute)) {
$this->addError($attribute, 'Invalid array');
}
}
],
['selected_trainers',function ($attribute, $params) {
if (!is_array($this->$attribute)) {
$this->addError($attribute, 'Invalid array');
}
}
],
[['role'], 'required'],
[['role'], 'string', 'max' => 20],
['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
];
}
public function validateEmail($attribute, $params){
/** @var User $user */
$user = User::find()
->andWhere(['email' => $this->email])->one();
if (isset($user)){
if ( $user->id != $this->id ){
$this->addError($attribute,'Az email cím már használatban van!');
}
}
}
public function validateUsername($attribute, $params){
/** @var User $user */
$user = User::find()
->andWhere(['username' => $this->username])->one();
if (isset($user)){
if ( $user->id != $this->id ){
$this->addError($attribute,'A felhasználónév már használatban van!');
}
}
}
/**
* @formatter:on
*/
@ -53,14 +88,14 @@ class UserUpdate extends User {
}
}
public function attributeLabels() {
return [
return [
'status' => 'Státusz',
'email' => 'E-mail',
'username' => 'Felhasználónév',
'created_at' => 'Létrehozás dátuma',
'password_plain' => Yii::t ( 'app', 'Jelszó' ),
'password_repeat' => Yii::t ( 'app', 'Jelszó újra' )
'password_repeat' => Yii::t ( 'app', 'Jelszó újra' )
]
;
}
@ -78,7 +113,7 @@ class UserUpdate extends User {
}
}
public function afterSave($insert, $changedAttributes){
parent::afterSave($insert, $changedAttributes);
parent::afterSave($insert, $changedAttributes);
$am = Yii::$app->authManager;
$am->revokeAll($this->id);
$role = $am->getRole($this->role);

View File

@ -1,5 +1,8 @@
<?php
use backend\models\UserUpdate;
use common\models\Account;
use common\models\Trainer;
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\grid\GridView;
@ -8,11 +11,13 @@ use common\components\RoleDefinition;
use common\models\User;
/* @var $this yii\web\View */
/* @var $model common\models\User */
/* @var $model UserUpdate */
/* @var $form yii\widgets\ActiveForm */
/* @var $trainers Trainer[] */
/* @var $accounts Account[] */
?>
<?php
<?php
$roleOptions = RoleDefinition::roleLabels();
asort($roleOptions);
@ -32,10 +37,11 @@ asort($roleOptions);
<?= $form->field($model, 'password_repeat')->passwordInput() ?>
<?= $form->field($model, 'role')->dropDownList($roleOptions) ?>
<?php
<?php
$selectedAccounts = $model->selected_accounts;
$selectedTrainers = $model->selected_trainers;
?>
<h3>Engedélyezett kasszák</h3>
@ -52,7 +58,7 @@ asort($roleOptions);
'checkboxOptions' => function ($model, $key, $index, $column) use ($selectedAccounts){
$result = [];
$result['value'] = $model->id_account ;
if ( isset($selectedAccounts) ){
if ( is_array($selectedAccounts) ){
if ( array_search($model->id_account , $selectedAccounts ) !== false){
@ -60,15 +66,47 @@ asort($roleOptions);
}
}
}
return $result;
}
],
[ 'attribute' => 'name' ],
],
])?>
<h3>Engedélyezett edzők</h3>
<?php echo GridView::widget([
'dataProvider' => new ArrayDataProvider( [
'allModels' => $trainers,
'sort' => false,
'pagination' => false,
]),
'columns' => [
[
'class' => 'yii\grid\CheckboxColumn',
'name' => (new ReflectionClass( $model->classname() ))->getShortName() . '[selected_trainers]',
'checkboxOptions' => function ($model, $key, $index, $column) use ($selectedTrainers){
$result = [];
$result['value'] = $model->id ;
if ( isset($selectedTrainers) ){
if ( is_array($selectedTrainers) ){
if ( array_search($model->id , $selectedTrainers ) !== false){
$result['checked'] = 'checked' ;
}
}
}
return $result;
}
],
[ 'attribute' => 'name' ],
],
])?>
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? Yii::t('app', 'Mentés') : Yii::t('app', 'Mentés'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
<?= Html::submitButton( Yii::t('app', 'Mentés'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>

View File

@ -17,6 +17,7 @@ $this->params['breadcrumbs'][] = $this->title;
<?= $this->render('_form', [
'model' => $model,
'accounts' => $accounts,
'trainers' => $trainers,
]) ?>
</div>

View File

@ -16,7 +16,8 @@ $this->params['breadcrumbs'][] = Yii::t('backend/user', 'Update');
<?= $this->render('_form', [
'model' => $model,
'accounts' => $accounts
'accounts' => $accounts,
'trainers' => $trainers,
]) ?>
</div>

View File

@ -1,118 +1,147 @@
<?php
namespace common\components;
use \Yii;
class RoleDefinition{
class RoleDefinition
{
public static $ROLE_ADMIN = "admin";
public static $ROLE_RECEPTION = "reception";
public static $ROLE_EMPLOYEE = "employee";
public static $ROLE_TRAINER = "trainer";
public static function roleLabels()
{
return [
'reception' => Yii::t('common/role', 'Reception'),
'admin' => Yii::t('common/role', 'Administrator'),
'employee' => Yii::t('common/role', 'Employee'),
'Trainer' => Yii::t('common/role', 'Edző'),
];
}
public static function roleLabels(){
return [
'reception' => Yii::t('common/role' ,'Reception'),
'admin' => Yii::t('common/role' ,'Administrator'),
'employee' => Yii::t('common/role' ,'Employee'),
'Trainer' => Yii::t('common/role' ,'Edző'),
];
}
public static function getRoleLabel($role){
$result = null;
$roleLabels = self::roleLabels();
if ( array_key_exists($role, $roleLabels)){
$result = $roleLabels[$role];
}
return $result;
}
public static function getRoleLabel($role)
{
$result = null;
$roleLabels = self::roleLabels();
if (array_key_exists($role, $roleLabels)) {
$result = $roleLabels[$role];
}
return $result;
}
public static function roleDefinitions(){
return [
'employee' => [
'canAllow' => [ 'employee'],
],
'admin' => [
'canAllow' => ['admin','reception','employee'],
],
'reception' => [
'canAllow' => [ ],
],
];
}
public static function roleDefinitions()
{
return [
'employee' => [
'canAllow' => ['employee'],
],
'admin' => [
'canAllow' => ['admin', 'reception', 'employee'],
],
'reception' => [
'canAllow' => [],
],
];
}
public static function getRoleDefinition($role){
$defs = self::roleDefinitions();
$result = null;
if ( array_key_exists($role, $defs)){
$result = $defs[$role];
}
$result = $defs[$role];
return $result;
}
public static function getRoleDefinition($role)
{
$defs = self::roleDefinitions();
$result = null;
if (array_key_exists($role, $defs)) {
$result = $defs[$role];
}
$result = $defs[$role];
return $result;
}
public static function getRolesCanAllow($role){
$result = [];
$def = self::getRoleDefinition($role);
if ( isset($def)){
$result = $def['canAllow'];
}
public static function getRolesCanAllow($role)
{
$result = [];
$def = self::getRoleDefinition($role);
if (isset($def)) {
$result = $def['canAllow'];
}
return $result;
}
return $result;
}
public static function can($role){
$result = false;
if ( !Yii::$app->user->isGuest ){
if ( isset( $role)){
if ( is_array($role)){
foreach ($role as $r){
$result |= Yii::$app->user->can($r);
}
}else if ( is_string($role)){
$result = Yii::$app->user->can($role);
}
}
}
return $result;
}
public static function can($role)
{
$result = false;
if (!Yii::$app->user->isGuest) {
if (isset($role)) {
if (is_array($role)) {
foreach ($role as $r) {
$result |= Yii::$app->user->can($r);
}
} else if (is_string($role)) {
$result = Yii::$app->user->can($role);
}
}
}
return $result;
}
public static function isAdmin(){
return self::can('admin');
}
public static function canAny($roles)
{
foreach ($roles as $role) {
if (self::can($role)) {
return true;
}
}
return false;
}
public static function isReception(){
return self::can('reception');
}
public static function isAdmin()
{
return self::can('admin');
}
public static function isEmployee(){
return self::can('employee');
}
public static function isReception()
{
return self::can('reception');
}
public static function isTrainer(){
return self::can('trainer');
}
public static function isEmployee()
{
return self::can('employee');
}
public static function isTrainer()
{
return self::can('trainer');
}
public static function isLoggedUser(){
public static function isLoggedUser()
{
return self::isTrainer() || self::isAdmin() || self::isEmployee()
|| self::isReception();
}
/*
* [
* 'role1' => 'template1',
* 'role2' => 'template2,
* ]
* */
public static function getRoleTemplate($templates){
$result = "";
foreach ($templates as $role => $template ){
if ( Yii::$app->user->can($role)){
$result = $template;
break;
}
}
return $result;
}
/*
* [
* 'role1' => 'template1',
* 'role2' => 'template2,
* ]
* */
public static function getRoleTemplate($templates)
{
$result = "";
foreach ($templates as $role => $template) {
if (Yii::$app->user->can($role)) {
$result = $template;
break;
}
}
return $result;
}
}

View File

@ -12,22 +12,22 @@ use yii\helpers\ArrayHelper;
* This is the model class for table "account".
*
* @property integer $id_account
* @property string $name
* @property string $name
* @property integer $status
* @property integer $type
* @property string $created_at
* @property string $updated_at
* @property string $created_at
* @property string $updated_at
* @property integer $log_card_read_in_reception
*/
class Account extends \yii\db\ActiveRecord
{
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
const TYPE_ALL = 0;
const TYPE_VALUE_HIDDEN = 10;
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
const TYPE_ALL = 0;
const TYPE_VALUE_HIDDEN = 10;
/**
* @inheritdoc
*/
@ -41,13 +41,15 @@ class Account extends \yii\db\ActiveRecord
*/
public function behaviors()
{
return [
[ 'class' => TimestampBehavior::className(),
'value' => function(){ return date('Y-m-d H:i:s' ); }
]
];
return [
['class' => TimestampBehavior::className(),
'value' => function () {
return date('Y-m-d H:i:s');
}
]
];
}
/**
* @inheritdoc
*/
@ -55,8 +57,8 @@ class Account extends \yii\db\ActiveRecord
{
return [
[['name', 'type'], 'required'],
[['name', ], 'unique'],
[['status', 'type','log_card_read_in_reception'], 'integer'],
[['name',], 'unique'],
[['status', 'type', 'log_card_read_in_reception'], 'integer'],
[['name'], 'string', 'max' => 64]
];
}
@ -76,45 +78,51 @@ class Account extends \yii\db\ActiveRecord
'log_card_read_in_reception' => Yii::t('common/account', 'Log Card Read in Reception'),
];
}
public function getUserAccountAssignments(){
return $this->hasMany(UserAccountAssignment::className(), ['id_account' => 'id_account']);
public function getUserAccountAssignments()
{
return $this->hasMany(UserAccountAssignment::className(), ['id_account' => 'id_account']);
}
static function statuses() {
return [
self::STATUS_ACTIVE => Yii::t('common/account', 'Active'),
self::STATUS_DELETED => Yii::t('common/account', 'Inactive'),
];
static function statuses()
{
return [
self::STATUS_ACTIVE => Yii::t('common/account', 'Active'),
self::STATUS_DELETED => Yii::t('common/account', 'Inactive'),
];
}
public function getStatusHuman(){
$result = null;
$s = self::statuses();
if ( array_key_exists($this->status, $s)){
$result = $s[$this->status];
}
return $result;
public function getStatusHuman()
{
$result = null;
$s = self::statuses();
if (array_key_exists($this->status, $s)) {
$result = $s[$this->status];
}
return $result;
}
static function types() {
return [
self::TYPE_ALL => Yii::t('common/account', 'Account'),
self::TYPE_VALUE_HIDDEN => Yii::t('common/account', 'Only the name is visible'),
];
static function types()
{
return [
self::TYPE_ALL => Yii::t('common/account', 'Account'),
self::TYPE_VALUE_HIDDEN => Yii::t('common/account', 'Only the name is visible'),
];
}
public function getTypeHuman(){
$result = null;
$s = self::types();
if ( array_key_exists($this->type, $s)){
$result = $s[$this->type];
}
return $result;
public function getTypeHuman()
{
$result = null;
$s = self::types();
if (array_key_exists($this->type, $s)) {
$result = $s[$this->type];
}
return $result;
}
public function isInactive(){
return $this->status == self::STATUS_DELETED;
public function isInactive()
{
return $this->status == self::STATUS_DELETED;
}
/**
@ -126,76 +134,82 @@ class Account extends \yii\db\ActiveRecord
* three arm gate, but we want to track the customers.
* @return bool
*/
public function isLogCardReadInReceptionOn(){
public function isLogCardReadInReceptionOn()
{
return $this->log_card_read_in_reception == 1;
}
/**
* $param int $forceIncludeAccount id account, that should be included in list, even if it is inactive
* @param null $forceIncludeAccount the next account should be included too, even if it is not
* @param null $forceIncludeAccount the next account should be included too, even if it is not
* allowed for user
* @return array|null|\yii\db\ActiveRecord[]
*/
public static function readAccounts($forceIncludeAccount = null){
$accounts = null;
if ( $forceIncludeAccount == null) {
$accounts = Account::find()->andWhere(['status' => Account::STATUS_ACTIVE])->all();
}else{
$accounts = Account::find()->andWhere( ['or', ['status' => Account::STATUS_ACTIVE], ['id_account' => $forceIncludeAccount ] ])->all();
}
return $accounts;
}
public static function read($forceIncludeAccount = null){
$accounts = null;
$query = Account::find();
$query->innerJoinWith('userAccountAssignments');
$query->andWhere(['user_account_assignment.id_user' => Yii::$app->user->id]);
public static function readAccounts($forceIncludeAccount = null)
{
$accounts = null;
if ( $forceIncludeAccount == null){
$query->andWhere(['status' => Account::STATUS_ACTIVE])->all();
}else{
$query->andWhere( ['or', ['status' => Account::STATUS_ACTIVE], ['id_account' => $forceIncludeAccount ] ])->all();
}
if ($forceIncludeAccount == null) {
$accounts = Account::find()->andWhere(['status' => Account::STATUS_ACTIVE])->all();
} else {
$accounts = Account::find()->andWhere(['or', ['status' => Account::STATUS_ACTIVE], ['id_account' => $forceIncludeAccount]])->all();
}
$query->orderBy( ['name' => SORT_ASC]);
$accounts = $query->all();
return $accounts;
return $accounts;
}
public static function writeDefault($account){
$session = Yii::$app->session;
$session->set('id_account', $account->id_account);
public static function read($forceIncludeAccount = null)
{
$accounts = null;
$query = Account::find();
$query->innerJoinWith('userAccountAssignments');
$query->andWhere(['user_account_assignment.id_user' => Yii::$app->user->id]);
if ($forceIncludeAccount == null) {
$query->andWhere(['status' => Account::STATUS_ACTIVE])->all();
} else {
$query->andWhere(['or', ['status' => Account::STATUS_ACTIVE], ['id_account' => $forceIncludeAccount]])->all();
}
$query->orderBy(['name' => SORT_ASC]);
$accounts = $query->all();
return $accounts;
}
public static function writeDefault($account)
{
$session = Yii::$app->session;
$session->set('id_account', $account->id_account);
}
/** read id_transfer from session (default account )
*
*
* @return int id_transfer
* */
public static function readDefault( ){
$session = Yii::$app->session;
$result = $session->get('id_account');
return $result;
public static function readDefault()
{
$session = Yii::$app->session;
$result = $session->get('id_account');
return $result;
}
/**
* read default transfer object
* return the default account or null, if not found
* @return \common\models\Account
* */
public static function readDefaultObject( ){
$account = null;
$id_account = self::readDefault();
if ( isset($id_account)){
$account = Account::findOne($id_account);
}
return $account;
public static function readDefaultObject()
{
$account = null;
$id_account = self::readDefault();
if (isset($id_account)) {
$account = Account::findOne($id_account);
}
return $account;
}
@ -204,23 +218,24 @@ class Account extends \yii\db\ActiveRecord
* @param $idAccount integer The id of the account to read
* @return array|null|\yii\db\ActiveRecord
*/
public static function readOne($idAccount){
$accounts = null;
$query = Account::find();
$query->innerJoinWith('userAccountAssignments');
$query->andWhere(['user_account_assignment.id_user' => Yii::$app->user->id]);
$query->andWhere(['status' => Account::STATUS_ACTIVE]);
$query->andWhere(['account.id_account' => $idAccount]);
$accounts = $query->one();
return $accounts;
}
public static function toAccaountMap($accounts){
return ArrayHelper::map( $accounts,'id_account','name' );
public static function readOne($idAccount)
{
$accounts = null;
$query = Account::find();
$query->innerJoinWith('userAccountAssignments');
$query->andWhere(['user_account_assignment.id_user' => Yii::$app->user->id]);
$query->andWhere(['status' => Account::STATUS_ACTIVE]);
$query->andWhere(['account.id_account' => $idAccount]);
$accounts = $query->one();
return $accounts;
}
public static function toAccaountMap($accounts)
{
return ArrayHelper::map($accounts, 'id_account', 'name');
}
}

View File

@ -26,7 +26,7 @@ class User extends ActiveRecord implements IdentityInterface
{
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
const ROLE_RECEPTION = 'receptionist';
/**
@ -192,18 +192,22 @@ class User extends ActiveRecord implements IdentityInterface
{
$this->password_reset_token = null;
}
public function getUserAccountAssignments(){
return $this->hasMany(UserAccountAssignment::className(), ['id_user' =>'id']);
}
public function getUserTrainerAssignments(){
return $this->hasMany(UserTrainerAssignment::className(), ['id_user' =>'id']);
}
static function statuses() {
return [
self::STATUS_ACTIVE => Yii::t('app', 'Aktív'),
self::STATUS_DELETED => Yii::t('app', 'Inaktív'),
] ;
}
public function getStatusHuman(){
$result = null;
$s = self::statuses($this->status);
@ -212,8 +216,8 @@ class User extends ActiveRecord implements IdentityInterface
}
return $result;
}
public function attributeLabels(){
return [
'status' => 'Státusz',
@ -224,14 +228,14 @@ class User extends ActiveRecord implements IdentityInterface
'statusHuman' => Yii::t('backend/user', 'Status'),
];
}
/**
*
*
*
*
* @return \yii\rbac\Role[]*/
public function getRoles(){
$roles = \Yii::$app->authManager->getRolesByUser($this->id );
return $roles;
return $roles;
}
/**
@ -239,28 +243,28 @@ class User extends ActiveRecord implements IdentityInterface
* */
public function getRoleString(){
$roles = \Yii::$app->authManager->getRolesByUser($this->id );
return implode(', ', array_map(function ($role) { return sprintf("%s", RoleDefinition::getRoleLabel($role->name)); }, $roles ));
}
/**
* $param int $forceIncludeAccount id warehouse, that should be included in list, even if it is inactive
* */
public static function read($forceIncludeObjectWithId = null){
$users = null;
$query = User::find();
if ( RoleDefinition::isReception()){
$query->andWhere(['id' => Yii::$app->user->id ]);
}
if ( $forceIncludeObjectWithId == null){
$users = $query->andWhere(['status' => User::STATUS_ACTIVE])->all();
}else{
$users = $query->andWhere( ['or', ['status' => User::STATUS_ACTIVE], ['id' => $forceIncludeObjectWithId ] ])->all();
}
return $users;
}
}

View File

@ -3,6 +3,7 @@
namespace common\modules\event\models;
use common\components\Helper;
use common\components\RoleDefinition;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
@ -86,6 +87,7 @@ class EventSearch extends Event
]
);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort' => [

View File

@ -6823,6 +6823,11 @@
"set-immediate-shim": "~1.0.1"
}
},
"jwt-decode": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz",
"integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A=="
},
"karma": {
"version": "6.3.4",
"resolved": "https://registry.npmjs.org/karma/-/karma-6.3.4.tgz",

View File

@ -28,6 +28,7 @@
"@ngxs/logger-plugin": "^3.7.2",
"@ngxs/store": "^3.7.2",
"bootstrap": "^5.1.1",
"jwt-decode": "^3.1.2",
"moment": "^2.24.0",
"ngx-bootstrap": "^5.0.0",
"ngx-toastr": "^14.1.3",

View File

@ -1,31 +1,37 @@
import { Injectable } from "@angular/core";
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from "@angular/common/http";
import { Observable } from "rxjs";
import {Injectable} from "@angular/core";
import {HttpInterceptor, HttpRequest, HttpHandler, HttpEvent} from "@angular/common/http";
import {Observable} from "rxjs";
import {Store} from "@ngxs/store";
import {AppState} from "../state/app.state";
/*
The JWT interceptor intercepts the incoming requests from the application/user and adds JWT token to the request's Authorization header, only if the user is logged in.
This JWT token in the request header is required to access the SECURE END API POINTS on the server
This JWT token in the request header is required to access the SECURE END API POINTS on the server
*/
@Injectable()
export class JwtInterceptor implements HttpInterceptor{
constructor(){}
export class JwtInterceptor implements HttpInterceptor {
constructor(private store: Store) {
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>{
// check if the current user is logged in
// if the user making the request is logged in, he will have JWT token in it's local storage, which is set by Authorization Service during login process
let currentUser = JSON.parse(localStorage.getItem('currentUser'));
if(currentUser && currentUser.token){
// clone the incoming request and add JWT token in the cloned request's Authorization Header
request = request.clone({
setHeaders: {
Authorization: `Bearer ${currentUser.token}`
}
});
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// check if the current user is logged in
// if the user making the request is logged in, he will have JWT token in it's local storage, which is set by Authorization Service during login process
// let currentUser = JSON.parse(localStorage.getItem('currentUser'));
const token = this.store.selectSnapshot<string>(AppState.getToken);
if (token) {
// clone the incoming request and add JWT token in the cloned request's Authorization Header
request = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
// handle any other requests which went unhandled
return next.handle(request);
});
}
}
// handle any other requests which went unhandled
return next.handle(request);
}
}

View File

@ -67,11 +67,11 @@ export class FitNavigationComponent implements OnInit {
if ( item.roles && item.roles.length ){
let firstRole = item.roles[0];
if ( firstRole == '!'){
return !this.authenticationService.user.value;
return !this.authenticationService.isLoggedIn();
}else if ( firstRole == '*'){
return true;
}else if ( firstRole == '@'){
return this.authenticationService.user.value;
return this.authenticationService.isLoggedIn();
}
}

View File

@ -1,4 +1,7 @@
<fit-navigation></fit-navigation>
<div class="container " >
<div class="row ">
<div class="col-12">Bejelentkezve: {{username | async}}</div>
</div>
<router-outlet></router-outlet>
</div>

View File

@ -1,4 +1,7 @@
import { Component, OnInit } from '@angular/core';
import {Select} from "@ngxs/store";
import {AppState} from "../../state/app.state";
import {Observable} from "rxjs";
@Component({
selector: 'app-secured-layout',
@ -6,6 +9,7 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./secured-layout.component.scss']
})
export class SecuredLayoutComponent implements OnInit {
@Select(AppState.getUsername) public username: Observable<string>;
constructor() { }

View File

@ -1,57 +1,71 @@
import { Injectable } from '@angular/core';
import { HttpClient } from "@angular/common/http";
import { map } from 'rxjs/operators';
import {Injectable} from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {catchError, map} from 'rxjs/operators';
import {Endpoints} from "./endpoints";
import {BehaviorSubject} from "rxjs";
import { throwError} from "rxjs";
import {PasswordChangeRequest} from "../app.types";
import jwtDecode, {JwtPayload} from "jwt-decode";
import {Store} from "@ngxs/store";
import {LoginAction} from "../state/app.actions";
import {AppState} from "../state/app.state";
@Injectable({
providedIn: 'root'
})
export class AuthenticationService {
private _user: BehaviorSubject<any> = new BehaviorSubject(null);
constructor(private http: HttpClient){
let user = localStorage.getItem('currentUser' );
if ( user ){
this.user.next( JSON.stringify(user));
}
constructor(private http: HttpClient, private store: Store) {
store.dispatch(new LoginAction(this.getToken()))
}
public getToken() {
let currentUser = JSON.parse(localStorage.getItem('currentUser'));
return currentUser?.token;
}
// login
login(username: string, password:string){
return this.http.post<any>(Endpoints.POST_USERS_AUTHENTICATE(), {username:username,password:password})
login(username: string, password: string) {
return this.http.post<any>(Endpoints.POST_USERS_AUTHENTICATE(), {username: username, password: password})
.pipe(
// the backend service sends an instance of the user
// user: any (because .post<any>)
map(user => {
// login successful if the response has jwt token
if(user && user.token){
if (user && user.token) {
// store user details and jwt token in the local storage to keep the user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
this.user.next(user);
const decoded = jwtDecode<JwtPayload>(user.token);
console.info("decoded", decoded);
// this.user.next(user);
this.store.dispatch(new LoginAction(user.token));
}
return user;
})
}),
catchError(err => {
localStorage.removeItem('currentUser');
this.store.dispatch(new LoginAction(null));
return throwError(err);
}),
);
}
passwordChange(passwordChangeRequest: PasswordChangeRequest){
passwordChange(passwordChangeRequest: PasswordChangeRequest) {
return this.http.post<any>(Endpoints.POST_USER_PASSWORD_CHANGE(), passwordChangeRequest)
}
get user() {
return this._user;
}
public isLoggedIn(){
return this.user.value;
// get user() {
// return this._user;
// }
//
public isLoggedIn() {
return this.store.selectSnapshot(AppState.getToken);
}
// logout
logout(){
logout() {
// remove user from local storage
localStorage.removeItem('currentUser');
this.user.next(null);
this.store.dispatch(new LoginAction(null));
// this.user.next(null);
}
}

View File

@ -6,3 +6,9 @@ export class FilterTimeTableAction {
constructor(public idTrainer: number, public idEventType: number) {}
}
export class LoginAction {
// For debug / console output upon dev environment
static readonly type = "[App] LoginAction";
constructor(public token: string) {}
}

View File

@ -1,12 +1,15 @@
import {Action, Selector, State, StateContext, Store} from "@ngxs/store";
import {Action, Selector, State, StateContext} from "@ngxs/store";
import {Injectable} from "@angular/core";
import {
FilterTimeTableAction,
FilterTimeTableAction, LoginAction,
} from "./app.actions";
import {TimeTableFilter} from "../app.types";
import jwtDecode, {JwtPayload} from "jwt-decode";
export interface AppStateModel {
username: string;
token: string;
filterTimeTable: FilterTimeTableAction;
}
@ -14,6 +17,8 @@ export interface AppStateModel {
@State<AppStateModel>({
name: "app",
defaults: {
username: null,
token: null,
filterTimeTable: {
idTrainer: -1,
idEventType: -1
@ -23,8 +28,7 @@ export interface AppStateModel {
export class AppState {
constructor(
) {
constructor() {
}
@Selector()
@ -32,6 +36,17 @@ export class AppState {
return state.filterTimeTable;
}
@Selector()
public static getUsername(state: AppStateModel): string {
return state.username;
}
@Selector()
public static getToken(state: AppStateModel): string {
return state.token;
}
@Action(FilterTimeTableAction)
dispatchFilterTimeTable(ctx: StateContext<AppStateModel>, {idEventType, idTrainer}: FilterTimeTableAction): void {
ctx.patchState({
@ -42,4 +57,23 @@ export class AppState {
});
}
@Action(LoginAction)
dispatchLogin(ctx: StateContext<AppStateModel>, {token}: LoginAction): void {
let username = null;
try {
const decoded = jwtDecode<JwtPayload & { username: string }>(token);
username = decoded?.username;
} catch (e) {
// user not logged in
token = null;
}
ctx.patchState({
username: username,
token: token
});
}
}

View File

@ -54,6 +54,7 @@ class LoginController extends CustomerApiController
->issuedAt($time)// Configures the time that the token was issue (iat claim)
->expiresAt($time + 3600)// Configures the expiration time of the token (exp claim)
->withClaim('uid', $form->getCustomer()->getId())// Configures a new claim, called "uid"
->withClaim('username', $form->getCustomer()->email)// Configures a new claim, called "username"
->getToken($signer, $key); // Retrieves the generated token
return $this->asJson([