<?php
namespace Croogo\Users\Model\Table;
use Cake\Core\Configure;
use Cake\Mailer\MailerAwareTrait;
use Cake\ORM\Query;
use Cake\Utility\Security;
use Cake\Validation\Validator;
use Croogo\Core\Croogo;
use Croogo\Core\Model\Table\CroogoTable;
use Croogo\Users\Model\Entity\User;
class UsersTable extends CroogoTable
{
use MailerAwareTrait;
protected $_displayFields = [
'username',
'name',
'role.title' => 'Role',
'email',
'status' => ['type' => 'boolean'],
];
protected $_editFields = [
'role_id',
'username',
'name',
'email',
'website',
'status',
];
public $filterArgs = [
'name' => ['type' => 'like', 'field' => ['Users.name', 'Users.username']],
'role_id' => ['type' => 'value'],
];
public function initialize(array $config)
{
$multiRole = Configure::read('Access Control.multiRole');
if ($multiRole) {
$this->belongsToMany('Croogo/Users.Roles', [
'through' => 'Croogo/Users.RolesUsers',
'strategy' => 'subquery',
]);
unset($this->_displayFields['role.title']);
} else {
$this->belongsTo('Croogo/Users.Roles');
}
$this->addBehavior('Acl.Acl', [
'className' => 'Croogo/Core.CroogoAcl',
'type' => 'requester'
]);
$this->addBehavior('Search.Search');
$this->addBehavior('Timestamp');
$this->addBehavior('Croogo/Core.Trackable');
$this->addBehavior('Croogo/Core.Cached', [
'groups' => ['users']
]);
$this->getEventManager()->on($this->getMailer('Croogo/Users.User'));
$this->searchManager()
->add('name', 'Search.Like', [
'field' => ['Users.name', 'Users.username', 'Users.email'],
'before' => true,
'after' => true,
]);
if ($multiRole) {
$this->searchManager()
->add('role_id', 'Search.Finder', [
'finder' => 'filterMultiRoles',
]);
} else {
$this->searchManager()
->value('role_id');
}
}
/**
* Used to register a new user
*
* @param User $user
* @param array $data
* @return bool|User
*/
public function register(User $user, array $data)
{
$user = $this->patchEntity($user, $data, [
'fieldList' => [
'username',
'website',
'name',
'password',
'email'
]
]);
$user->set([
'role_id' => $this->Roles->byAlias('registered'),
'activation_key' => $this->generateActivationKey(),
]);
if (!$this->save($user)) {
return false;
}
$this->dispatchEvent('Model.Users.registered', [
'user' => $user
]);
return $user;
}
/**
* Activate the user
*
* @param User $user
* @return bool|User
*/
public function activate(User $user)
{
$user->activation_key = null;
$user->status = true;
$this->dispatchEvent('Model.Users.beforeActivation', [
'user' => $user,
]);
if (!$this->save($user)) {
return false;
}
$this->dispatchEvent('Model.Users.activated', [
'user' => $user
]);
return $user;
}
/**
* Starts an password reset procedure and sets out an email to the user
*
* @param User $user User to run the procedure for
* @return bool Returns true when successful, false if not
*/
public function resetPassword(User $user, array $options = [])
{
// Generate a unique activation key
$user->activation_key = $this->generateActivationKey();
Croogo::dispatchEvent('Model.Users.beforeResetPassword',
$this,
compact('user')
);
$user = $this->save($user);
if (!$user) {
return false;
}
// Send out an password reset email
$email = $this
->getMailer('Croogo/Users.User')
->viewVars(compact('options'))
->send('resetPassword', [$user]);
if (!$email) {
return false;
}
Croogo::dispatchEvent('Model.Users.afterResetPassword',
$this,
compact('email', 'user')
);
return true;
}
public function sendActivationEmail($user)
{
$email = $this->getMailer('Croogo/Users.User')
->viewVars(compact('user'))
->send('registrationActivation', [$user]);
Croogo::dispatchEvent('Model.Users.afterActivationEmail',
$this,
compact('email', 'user')
);
}
public function changePasswordFromReset(User $user, array $data)
{
$user = $this->patchEntity($user, $data, [
'fieldList' => [
'password',
'verify_password',
]
]);
if ($user->errors()) {
return $user;
}
$user->activation_key = null;
return $user;
}
public function validationDefault(Validator $validator)
{
return $validator
->add('username', [
'notBlank' => [
'rule' => 'notBlank',
'message' => 'The username has already been taken.',
'last' => true
],
'validateUnique' => [
'rule' => 'validateUnique',
'provider' => 'table',
'message' => 'The username has already been taken.',
'last' => true
],
'alphaNumeric' => [
'rule' => 'alphaNumeric',
'message' => 'This field must be alphanumeric',
'last' => true
]
])
->add('email', [
'notEmpty' => [
'rule' => 'notBlank',
'message' => 'The username has already been taken.',
'last' => true
],
'email' => [
'rule' => 'email',
'message' => 'Please provide a valid email address.',
'last' => true
],
'validateUnique' => [
'rule' => 'validateUnique',
'provider' => 'table',
'message' => 'Email address already in use.',
'last' => true
]
])
->add('password', [
'minLength' => [
'rule' => ['minLength', 6],
'message' => 'Passwords must be at least 6 characters long.',
'last' => true
],
'compareWith' => [
'rule' => ['compareWith', 'verify_password'],
'message' => 'Passwords do not match. Please, try again',
'last' => true
]
])
->add('name', [
'notBlank' => [
'rule' => 'notBlank',
'message' => 'This field cannot be left blank.',
'last' => true
],
'name' => [
'rule' => ['custom', '/^[-\p{Ll}\p{Lm}\p{Lo}\p{Lt}\p{Lu}\p{Nd}_\[\]\(\) ]+$/mu'],
'message' => 'This field must be alphanumeric',
'last' => true
]
])
->allowEmpty('website')
->add('website', [
'url' => [
'rule' => 'url',
'message' => 'This field must be a valid URL',
'last' => true
]
]);
}
public function findFilterMultiRoles(Query $query, array $options)
{
$roleId = isset($options['role_id']) ? $options['role_id'] : false;
$query
->where([
$this->aliasField('role_id') => $roleId,
])
->orWhere([
$this->Roles->aliasField('id') => $roleId,
]);
return $query;
}
public function generateActivationKey($length = null)
{
if (!$length) {
$length = Configure::read('Croogo.activationKeyLength', 20);
}
return bin2hex(Security::randomBytes($length));
}
public function findAuthUser(Query $query, array $options)
{
return $query
->where([$this->aliasField('status') => 1]);
}
}