Skip to content

Commit

Permalink
Releasing 2.0.1 into master (#30)
Browse files Browse the repository at this point in the history
* specify version for ui

* add changelog

* typo fix

* Add a lot of comments in code and also some hooks and ease customization of encryption/verification methods by using callbacks

* no need for new instance, fix #10

* demos fix, no need for  config

* initial implementation of acl

* add missing bits

* cleanup cloning

* In Case the project is used as component

This raises warning/notice if Auth and Atk is used as components in any other frameworks

* Update Auth.php

* Update Auth.php

* work in progress - working on new version

* wip

* work in progress

* extended admin to manage role rules

* Fix log-in page title

When login appears, currently the title is "Agile UI - Untitled Application". This changes the title to "Log-in Required".

* Allow title customization

Added $title field. Title can be customized by passing it into the constructor like this:
`new Login/Auth(['title' => 'Please login'])`

* Compact code

* Revert and use $this-app->title

* update dependencies

* fix password field cloning and tests

* bunch of changes mostly in models

* make demo config configurable

* wip in demos

* comment

* wip

* sublime

* wip

* cleanup

* no need for password to be visible

* in progress

* kind of done

* address Romans comments

* ACL UI, fields and actions dropdown etc

* comment

* Fix/wizard2.0.0 - WIP (#22)

* Update .travis.yml

* rollback to dev-develop (atk4/data@dev-feature was merged)

* fix Demo with correct namespace for Demo App

* Add Form to test and create file config.php for connection to db

* Temporary fix to atk4\schema\migrateModels method

* Fix : if file config.php not present redirect to wizard.php

* Fix : action "register_new_user" field : login -> name

* composer : pinned atk repos version to 2.0.*

* clean up

* setup travis for 7.2 + coverage

* few tweaks (#23)

* tests config

* few tweaks

* use render method only if model is set (#24)

* done (#25)

* fix dropdowns (#26)

* Update AbstractDropDown.php

* Update AccessRule.php

* develop branch should rely on develop branches

* Feature/add release workflow (#27)

* add release scripts

* implement "require-release" strategy suggested by Dark

* remove behat, it is not working anyway

* remove behat, it is not working anyway

* codecov fix

* whops

* fix

* fix

* fix

* fix

* fix

* fix ACL

* move functionality to setup trait

* change traits

* bump test

* bump atk4/schema version

* Setting release dependencies

Co-authored-by: Romans Malinovskis <me@nearly.guru>
Co-authored-by: Imants Horsts <DarkSide666@users.noreply.github.com>
Co-authored-by: Gowrav Vishwakarma <gowravvishwakarma@gmail.com>
Co-authored-by: Alex Cicovic <acicovic@gmail.com>
Co-authored-by: Francesco Danti <fdanti@gmail.com>
Co-authored-by: GitHub Web Flow <noreply@github.com>
  • Loading branch information
7 people authored Feb 10, 2020
1 parent 2bebb00 commit b0bbc14
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 75 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
}
],
"require": {
"php": ">=7.2.0",
"atk4/ui": "^2.0",
"atk4/data": "^2.0",
"atk4/schema": "^1.1",
"php": ">=7.2.0"
"atk4/schema": "^2.0"
},
"require-dev": {
"phpunit/phpcov": "^3.0",
Expand Down
12 changes: 8 additions & 4 deletions src/ACL.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,20 @@ public function getRules(Model $model)
public function applyRestrictions(Persistence $p, Model $m)
{
foreach ($this->getRules($m) as $rule) {

// extract as arrays
$visible = is_array($rule['visible_fields']) ? $rule['visible_fields'] : explode(',', $rule['visible_fields']);
$editable = is_array($rule['editable_fields']) ? $rule['editable_fields'] : explode(',', $rule['editable_fields']);
$actions = is_array($rule['actions']) ? $rule['actions'] : explode(',', $rule['actions']);

// set visible and editable fields
foreach ($m->getFields() as $name => $field) {
$field['ui']['visible'] = $rule['all_visible'] || (array_search($name, $rule['visible_fields']) !== false);
$field['ui']['editable'] = $rule['all_editable'] || (array_search($name, $rule['editable_fields']) !== false);
$field->ui['visible'] = $rule['all_visible'] || (array_search($name, $visible) !== false);
$field->ui['editable'] = $rule['all_editable'] || (array_search($name, $editable) !== false);
}

// remove not allowed actions
if (!$rule['all_actions'] && $rule['actions']) {
$actions_to_remove = array_diff(array_keys($m->getActions()), $rule['actions']);
$actions_to_remove = array_diff(array_keys($m->getActions()), $actions);
foreach ($actions_to_remove as $action) {
$m->getAction($action)->enabled = false;
}
Expand Down
96 changes: 96 additions & 0 deletions src/Feature/SetupModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php
namespace atk4\login\Feature;

/**
* Adding this trait to your atk4/login models will properly setup these models for your application. Additionally execute
* $this->setupModel() from your models init() method after you define model fields.
*
* @package atk4\login\Feature
*/
use atk4\login\Model\AccessRule;
use atk4\login\Model\Role;
use atk4\login\Model\User;

use atk4\login\FormField;

trait SetupModel
{
/**
* Setup AccessRule model.
*/
public function setupAccessRuleModel()
{
$this->getField('model')->required = true;
$this->getField('model')->caption = 'Model Class';

/*
$this->containsOne('config', new class extends Model {
public function init()
{
parent::init();
// We can put all fields which are below in here.
// And this new class should be separated to let's say AccessRule/Model class so we can
// also have AccessRule/Interface or AccessRule/View or AccessRule/Page class in future
// with different config properties
}
});
*/

$this->getField('all_visible')->default = true;
$this->getField('all_editable')->default = true;
$this->getField('all_actions')->default = true;

$this->getField('visible_fields')->ui['form'] = FormField\FieldsDropDown::class;
$this->getField('editable_fields')->ui['form'] = FormField\FieldsDropDown::class;
$this->getField('actions')->ui['form'] = FormField\ActionsDropDown::class;
$this->getField('conditions')->type = 'text';

// cleanup data
$this->addHook('beforeSave', function ($m) {
if ($m['all_visible']) $m['visible_fields'] = null;
if ($m['all_editable']) $m['editable_fields'] = null;
if ($m['all_actions']) $m['actions'] = null;
});
}

/**
* Setup Role model.
*/
public function setupRoleModel()
{
$this->getField('name')->required = true;
$this->setUnique('name');
}

/**
* Setup User model.
*/
public function setupUserModel()
{
$this->getField('name')->required = true;
$this->getField('email')->required = true;
$this->setUnique('email');
$this->getField('password')->ui['visible'] = false;

// all AccessRules for all user roles
// @TODO in future when there can be multiple, then merge them together
$this->hasMany('AccessRules', [
function ($m) {
return $m->ref('role_id')->ref('AccessRules');
},
'our_field' => 'role_id',
'their_field' => 'role_id',
]);

// add some validations
$this->addHook('beforeSave', function ($m){
// password should be set when trying to insert new record
// but it can be empty if you update record (then it will not change password)
if (!$m->loaded() && !$m->get('password')) {
throw new ValidationException(['password' => 'Password is required'], $this);
}
});
}
}
54 changes: 15 additions & 39 deletions src/Model/AccessRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
use atk4\data\Model;
use atk4\login\FormField;

use atk4\login\Feature\SetupModel;

/**
* White-list access control rules.
*/
class AccessRule extends Model
{
use SetupModel;

public $table = 'login_access_rule';
public $caption = 'Access Rule';

Expand All @@ -22,22 +26,7 @@ public function init()

$this->hasOne('role_id', [Role::class, 'our_field'=>'role_id', 'their_field'=>'id', 'caption'=>'Role'])->withTitle();

$this->addField('model', ['required'=>true, 'caption'=>'Model Class']); // model class name

/*
$this->containsOne('config', new class extends Model {
public function init()
{
parent::init();
// We can put all fields which are below in here.
// And this new class should be separated to let's say AccessRule/Model class so we can
// also have AccessRule/Interface or AccessRule/View or AccessRule/Page class in future
// with different config properties
}
});
*/
$this->addField('model'); // model class name

/**
* @TODO maybe all_visible and visible_fields can be replaced with just on field visible:
Expand All @@ -56,35 +45,22 @@ public function init()
*/

// which model fields should be visible
$this->addField('all_visible', ['type'=>'boolean', 'default'=>true]);
$this->addField('visible_fields', [ // used if all_visible is false
'type' => 'string',
'ui' => ['form' => FormField\FieldsDropDown::class],
]);
$this->addField('all_visible', ['type'=>'boolean']);
$this->addField('visible_fields'); // used if all_visible is false

// which model fields should be editable
$this->addField('all_editable', ['type'=>'boolean', 'default'=>true]);
$this->addField('editable_fields', [ // used if all_editable is false
'type' => 'string',
'ui' => ['form' => FormField\FieldsDropDown::class],
]);
$this->addField('all_editable', ['type'=>'boolean']);
$this->addField('editable_fields'); // used if all_editable is false

// which model actions are allowed
$this->addField('all_actions', ['type'=>'boolean', 'default'=>true]);
$this->addField('actions', [ // used if all_actions is false
'type' => 'string',
'ui' => ['form' => FormField\ActionsDropDown::class],
]);
$this->addField('all_actions', ['type'=>'boolean']);
$this->addField('actions'); // used if all_actions is false

// Specify which conditions will be applied on the model, e.g. "status=DRAFT AND sent=true OR status=SENT"
// @TODO this will be replaced by JSON structure when Alain will develop such JS widget
$this->addField('conditions', ['type' => 'text']);

// cleanup data
$this->addHook('beforeSave', function ($m) {
if ($m['all_visible']) $m['visible_fields'] = null;
if ($m['all_editable']) $m['editable_fields'] = null;
if ($m['all_actions']) $m['actions'] = null;
});
$this->addField('conditions');

// traits
$this->setupAccessRuleModel();
}
}
8 changes: 6 additions & 2 deletions src/Model/Role.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

use atk4\data\Model;

use atk4\login\Feature\SetupModel;
use atk4\login\Feature\UniqueFieldValue;

class Role extends Model
{
use SetupModel;
use UniqueFieldValue;

public $table = 'login_role';
Expand All @@ -16,10 +18,12 @@ public function init()
{
parent::init();

$this->addField('name', ['type'=>'string', 'required'=>true]);
$this->setUnique('name');
$this->addField('name');

$this->hasMany('Users', [User::class, 'our_field'=>'id', 'their_field'=>'role_id']);
$this->hasMany('AccessRules', [AccessRule::class, 'our_field'=>'id', 'their_field'=>'role_id']);

// traits
$this->setupRoleModel();
}
}
36 changes: 10 additions & 26 deletions src/Model/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@
use atk4\login\Field\Password;

# Features of User model
use atk4\login\Feature\Signup;
use atk4\login\Feature\SetupModel;
use atk4\login\Feature\PasswordManagement;
use atk4\login\Feature\Signup;
use atk4\login\Feature\UniqueFieldValue;

/**
* Example user data model.
*/
class User extends Model
{
use SetupModel;
use PasswordManagement;
use Signup;
use UniqueFieldValue;
Expand All @@ -26,34 +28,16 @@ public function init()
{
parent::init();

$this->initSignup();
$this->initPasswordManagement();

$this->addField('name', ['required' => true]);
$this->addField('email', ['required' => true]);
$this->setUnique('email');
$this->addField('password', [Password::class, 'ui'=>['visible'=>false]]); // required only when inserting (see beforeSave hook)
$this->addField('name');
$this->addField('email');
$this->addField('password', [Password::class]);

// currently user can have only one role. In future it should be n:n relation
$this->hasOne('role_id', [Role::class, 'our_field'=>'role_id', 'their_field'=>'id', 'caption'=>'Role'])->withTitle();

// all AccessRules for all user roles
// @TODO in future when there can be multiple, then merge them together
$this->hasMany('AccessRules', [
function ($m) {
return $m->ref('role_id')->ref('AccessRules');
},
'our_field' => 'role_id',
'their_field' => 'role_id',
]);

// add some validations
$this->addHook('beforeSave', function ($m){
// password should be set when trying to insert new record
// but it can be empty if you update record (then it will not change password)
if (!$m->loaded() && !$m->get('password')) {
throw new ValidationException(['password' => 'Password is required'], $this);
}
});
// traits
$this->setupUserModel();
$this->initSignup();
$this->initPasswordManagement();
}
}
2 changes: 1 addition & 1 deletion src/RoleAdmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public function setModel(Model $role)

// Add new table column used for actions
/** @var \atk4\ui\TableColumn\Generic $a */
$a = $this->crud->table->addColumn(null, ['Actions', 'caption' => '']);
$a = $this->crud->table->addColumn(null, ['ActionButtons', 'caption' => '']);

$a->addModal(['icon' => 'cogs'], 'Role Permissions', function (View $v, $id) {

Expand Down
2 changes: 1 addition & 1 deletion src/UserAdmin.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function setModel(Model $user)
$this->crud->setModel($user);

// Add new table column used for actions
$a = $this->crud->table->addColumn(null, ['Actions', 'caption'=>'']);
$a = $this->crud->table->addColumn(null, ['ActionButtons', 'caption'=>'']);

// Pop-up for resetting password. Will display button for generating random password
$a->addModal(['icon'=>'key'], 'Change Password', function($v, $id) {
Expand Down

0 comments on commit b0bbc14

Please sign in to comment.