Compare commits
34 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 50464bce0d | |||
| a757e95277 | |||
| bf940f9523 | |||
| 6dc1d0fb87 | |||
| 0634db6d0c | |||
| 24edb5cb59 | |||
| 4ac770f733 | |||
| 69fd7a6e19 | |||
| 6439a83edb | |||
| be4950ff88 | |||
| a7a59b690a | |||
| dd140ccd8a | |||
| d2e7d6b670 | |||
| 8c9455a2d5 | |||
| 151daa8529 | |||
| d3e52269cd | |||
| 8048b3fda8 | |||
| 4ff351d39d | |||
| 1b57749a91 | |||
| c07423f600 | |||
| 7315885877 | |||
| ff15ee697c | |||
| 2e98191d56 | |||
| 0f5f42ca92 | |||
| 14eb4a9137 | |||
| e47aa5188e | |||
| 5b9d64c09e | |||
| ad2952f9fc | |||
| 8d74cb2f06 | |||
| 6aeaf74a2f | |||
| e56c8f37ea | |||
| d7af32a1d7 | |||
| ee5c7719cb | |||
| fa28394a83 |
53 changed files with 398 additions and 193 deletions
|
|
@ -30,7 +30,7 @@ session:
|
|||
statsKey: _httpcb_sess_idx
|
||||
prefix: _httpcb_sess_
|
||||
|
||||
#sendgrid
|
||||
#sendgrid:
|
||||
#key: value
|
||||
|
||||
# OAuth
|
||||
|
|
|
|||
|
|
@ -4,58 +4,61 @@ router:
|
|||
routes:
|
||||
home-route:
|
||||
pattern: '/'
|
||||
path:
|
||||
controller: index
|
||||
action: index
|
||||
path: Index::index
|
||||
about-route:
|
||||
pattern: '/about'
|
||||
path:
|
||||
controller: index
|
||||
action: about
|
||||
path: Index::about
|
||||
|
||||
# Callbacks
|
||||
|
||||
cb-list:
|
||||
pattern: '/callback/list'
|
||||
path: Callback::list
|
||||
cb-new:
|
||||
pattern: '/callback/new'
|
||||
path: Callback::new
|
||||
cb-created:
|
||||
pattern: '/callback/created/{id}'
|
||||
path:
|
||||
controller: callback
|
||||
action: created
|
||||
path: Callback::created
|
||||
cb-show:
|
||||
pattern: '/callback/show/{id}'
|
||||
path: Callback::show
|
||||
cb-endpoint:
|
||||
pattern: '/cb/{id}/:params'
|
||||
path:
|
||||
controller: api
|
||||
action: endpoint
|
||||
path: Api::endpoint
|
||||
|
||||
# login
|
||||
|
||||
login:
|
||||
pattern: '/login'
|
||||
path:
|
||||
controller: auth
|
||||
action: index
|
||||
path: Auth::index
|
||||
logout:
|
||||
pattern: '/logout'
|
||||
path:
|
||||
controller: auth
|
||||
action: logout
|
||||
path: Auth::logout
|
||||
oauth:
|
||||
pattern: '/login/{strategy:([a-z]+)}/:params'
|
||||
path:
|
||||
controller: auth
|
||||
action: oauth
|
||||
path: Auth::oauth
|
||||
oauth-disconnect:
|
||||
pattern: '/oauth/{provider:([a-z]+)}/disconnect'
|
||||
path: 'User::oauthdisconnect'
|
||||
oauth-disconnect-confirm:
|
||||
pattern: '/oauth/{provider:([a-z]+)}/disconnect/{confirm}'
|
||||
path: 'User::oauthdisconnect'
|
||||
|
||||
# User
|
||||
|
||||
user-register:
|
||||
pattern: '/register'
|
||||
path: Auth::register
|
||||
user-settings:
|
||||
pattern: '/settings'
|
||||
path:
|
||||
controller: user
|
||||
action: settings
|
||||
path: User::settings
|
||||
user-activity-log:
|
||||
pattern: '/user/activity'
|
||||
path: User::activity
|
||||
activation-link:
|
||||
pattern: '/activate/{link}'
|
||||
path:
|
||||
controller: api
|
||||
action: activationlink
|
||||
path: Api::activationlink
|
||||
|
||||
# Backend
|
||||
backend-home:
|
||||
|
|
@ -70,12 +73,15 @@ router:
|
|||
backend-user-edit:
|
||||
pattern: '/admin/user/{id:([0-9]+)}'
|
||||
path: backend::user::edit
|
||||
backend-user-impersonate:
|
||||
pattern: '/admin/impersonate/{id:([0-9]+)}'
|
||||
path: backend::user::impersonate
|
||||
backend-user-activation-email:
|
||||
pattern: '/admin/user/{id:([0-9]+)}/activation'
|
||||
path: backend::user::activation-email
|
||||
backend-user-status:
|
||||
pattern: '/admin/user/{id:([0-9]+)}/{type}'
|
||||
path:
|
||||
module: backend
|
||||
controller: user
|
||||
action: status
|
||||
pattern: '/admin/user/{id:([0-9]+)}/status/{type}'
|
||||
path: backend::user::status
|
||||
backend-log:
|
||||
pattern: '/admin/log{page:/?([0-9]+)?}'
|
||||
path: backend::log::index
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Controller\ControllerBase,
|
|||
App\Model\Data\Callback as CallbackModel,
|
||||
App\Model\Data\Request as RequestModel,
|
||||
App\Model\Data\RequestMeta as RequestMetaModel,
|
||||
App\Model\Data\User,
|
||||
App\Model\Data\UserActivation;
|
||||
|
||||
class ApiController extends ControllerBase
|
||||
|
|
@ -58,7 +59,7 @@ class ApiController extends ControllerBase
|
|||
*/
|
||||
public function activationLinkAction($id)
|
||||
{
|
||||
$link = UserActivation::findFirst(['activation_key = ?0', 'bind' => [ $id ]]);
|
||||
$link = UserActivation::findFirst(['activation_key = ?0', 'bind' => [$id]]);
|
||||
|
||||
if ($link) {
|
||||
if ($link->isValid()) {
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ class AuthController extends ControllerBase
|
|||
} else {
|
||||
$msg = '<ul>';
|
||||
|
||||
foreach($form->getMessages() as $message) {
|
||||
$msg .= '<li><strong>' . $message->getField() . '</strong> '. $message->getMessage() . '</li>';
|
||||
foreach ($form->getMessages() as $message) {
|
||||
$msg .= '<li><strong>' . $message->getField() . '</strong> ' . $message->getMessage() . '</li>';
|
||||
}
|
||||
|
||||
$msg .= '</ul>';
|
||||
|
|
@ -47,7 +47,7 @@ class AuthController extends ControllerBase
|
|||
|
||||
public function oauthAction($provider_name)
|
||||
{
|
||||
$client = $this->getDI()->get('oauth', [ $provider_name ]);
|
||||
$client = $this->getDI()->get('oauth', [$provider_name]);
|
||||
|
||||
$code = $this->request->get('code');
|
||||
$state = $this->request->get('state');
|
||||
|
|
@ -92,7 +92,7 @@ class AuthController extends ControllerBase
|
|||
// User is logged in.
|
||||
$this->response->redirect('/');
|
||||
}
|
||||
} catch(\Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
throw $e;
|
||||
$this->flash->message('error', 'Failed to authenticate.');
|
||||
if ($this->auth->getUser()) {
|
||||
|
|
@ -118,8 +118,11 @@ class AuthController extends ControllerBase
|
|||
}
|
||||
|
||||
$user = new User();
|
||||
$user->assign($data->toArray(), null,
|
||||
[ 'email', 'username', 'firstname', 'lastname' ]);
|
||||
$user->assign(
|
||||
$data->toArray(),
|
||||
null,
|
||||
['email', 'username', 'firstname', 'lastname']
|
||||
);
|
||||
|
||||
$form = new RegistrationForm($user);
|
||||
|
||||
|
|
|
|||
|
|
@ -55,24 +55,23 @@ class CallbackController extends ControllerBase
|
|||
|
||||
return $this->response->redirect(array(
|
||||
'for' => 'cb-created',
|
||||
'id' => $callback->getPublicId()));
|
||||
'id' => $callback->getPublicId()
|
||||
));
|
||||
} else {
|
||||
foreach($callback->getMessages() as $msg) {
|
||||
foreach ($callback->getMessages() as $msg) {
|
||||
$this->flash->error($msg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$msg = '<ul>';
|
||||
|
||||
foreach($form->getMessages() as $message) {
|
||||
$msg .= '<li><strong>' . $message->getField() . '</strong>: '. $message->getMessage() . '</li>';
|
||||
foreach ($form->getMessages() as $message) {
|
||||
$msg .= '<li><strong>' . $message->getField() . '</strong>: ' . $message->getMessage() . '</li>';
|
||||
}
|
||||
|
||||
$msg .= '</ul>';
|
||||
$this->flash->message('error', $msg);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
$this->view->form = $form;
|
||||
|
|
@ -85,7 +84,6 @@ class CallbackController extends ControllerBase
|
|||
{
|
||||
$row = CallbackModel::get($id);
|
||||
if (!$row) {
|
||||
|
||||
}
|
||||
$this->view->id = $id;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ class ControllerBase extends Controller
|
|||
protected function _forward404()
|
||||
{
|
||||
$this->dispatcher->forward(array(
|
||||
'namespace' => 'App\\Controller',
|
||||
'controller' => 'error',
|
||||
'action' => 'show404'
|
||||
));
|
||||
|
|
|
|||
|
|
@ -15,4 +15,3 @@ class IndexController extends ControllerBase
|
|||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,8 +44,11 @@ class UserController extends ControllerBase
|
|||
]);
|
||||
|
||||
// Send the email.
|
||||
$this->di->getMail()->send('Httpcb password activation',
|
||||
$user->getEmail(), $content);
|
||||
$this->di->getMail()->send(
|
||||
'Httpcb password activation',
|
||||
$user->getEmail(),
|
||||
$content
|
||||
);
|
||||
|
||||
$msg = "For security reasons. Before a password can be created "
|
||||
. "a email has been sent to <strong>{$user->getEmail()}</strong> with "
|
||||
|
|
@ -137,7 +140,7 @@ class UserController extends ControllerBase
|
|||
|
||||
$msg = '<p>You are about to unlink the last OAuth provider.'
|
||||
. ' Your <strong>only</strong> login option will be <strong>password</strong> if you do this.</p>'
|
||||
. '<p>Are you sure? <a class="alert-link" href="' . $url .'">Yes</a></p>';
|
||||
. '<p>Are you sure? <a class="alert-link" href="' . $url . '">Yes</a></p>';
|
||||
|
||||
$this->flash->message('warning', $msg);
|
||||
$this->response->redirect('/settings');
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class UserController extends \Phalcon\Mvc\Controller
|
|||
*/
|
||||
public function indexAction($page = 1)
|
||||
{
|
||||
$paginator = User::getPaginationList($page,15);
|
||||
$paginator = User::getPaginationList($page, 15);
|
||||
|
||||
$this->view->pagination_url = '/admin/user/list/';
|
||||
$this->view->page = $paginator->paginate();
|
||||
|
|
@ -97,4 +97,33 @@ class UserController extends \Phalcon\Mvc\Controller
|
|||
$this->flash->success('The account was: ' . $status);
|
||||
$this->response->redirect('/admin');
|
||||
}
|
||||
|
||||
public function activationEmailAction($id)
|
||||
{
|
||||
$user = User::findFirstById($id);
|
||||
if ($user) {
|
||||
if ($user->isSuspended()) {
|
||||
$this->eventsManager->fire('auth:onSentActivation', $user);
|
||||
$this->flash->success('Activation email sent to: ' . $user->email);
|
||||
} else {
|
||||
$this->flash->error('Only suspended users can be sent activation emails.');
|
||||
}
|
||||
} else {
|
||||
$this->flash->error('Invalid user: ' . $id);
|
||||
}
|
||||
$this->response->redirect('/admin');
|
||||
}
|
||||
|
||||
public function impersonateAction($id)
|
||||
{
|
||||
$user = User::findFirstById($id);
|
||||
|
||||
try {
|
||||
$this->auth->impersonate($user);
|
||||
$this->response->redirect('/');
|
||||
} catch (\Exception $ex) {
|
||||
$this->flash->error($ex->getMessage());
|
||||
$this->response->redirect('/admin');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@ use Phalcon\Forms\Form;
|
|||
/**
|
||||
* Element types
|
||||
*/
|
||||
|
||||
use Phalcon\Forms\Element\Text;
|
||||
use Phalcon\Forms\Element\Submit;
|
||||
|
||||
/**
|
||||
* Validators
|
||||
*/
|
||||
|
||||
use Phalcon\Validation\Validator\StringLength;
|
||||
|
||||
class CallbackCreate extends Form
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use Phalcon\Forms\Form;
|
|||
/**
|
||||
* Element types
|
||||
*/
|
||||
|
||||
use Phalcon\Forms\Element\Text;
|
||||
use Phalcon\Forms\Element\Password;
|
||||
use Phalcon\Forms\Element\Submit;
|
||||
|
|
@ -14,6 +15,7 @@ use Phalcon\Forms\Element\Submit;
|
|||
/**
|
||||
* Validators
|
||||
*/
|
||||
|
||||
use Phalcon\Validation\Validator\PresenceOf;
|
||||
use Phalcon\Validation\Validator\Email as EmailValidator;
|
||||
use Phalcon\Validation\Validator\StringLength;
|
||||
|
|
|
|||
|
|
@ -5,16 +5,19 @@ namespace App\Form;
|
|||
/**
|
||||
* Models
|
||||
*/
|
||||
|
||||
use App\Model\Data\User;
|
||||
|
||||
/**
|
||||
* Phalcon Form
|
||||
*/
|
||||
|
||||
use Httpcb\Form as FormBase;
|
||||
|
||||
/**
|
||||
* Element types
|
||||
*/
|
||||
|
||||
use Phalcon\Forms\Element\Text,
|
||||
Phalcon\Forms\Element\Password,
|
||||
Phalcon\Forms\Element\Submit;
|
||||
|
|
@ -22,6 +25,7 @@ use Phalcon\Forms\Element\Text,
|
|||
/**
|
||||
* Validators
|
||||
*/
|
||||
|
||||
use Phalcon\Validation,
|
||||
Phalcon\Validation\Validator\Callback as CallbackValidator,
|
||||
Phalcon\Validation\Validator\Alnum as AlnumValidator,
|
||||
|
|
@ -54,7 +58,9 @@ class Registration extends FormBase
|
|||
'messageMinimum' => 'Username must be at least :min characters long.',
|
||||
]),
|
||||
new CallbackValidator([
|
||||
'callback' => function($data) { return User::findFirstByUsername($data['username']) === false; },
|
||||
'callback' => function ($data) {
|
||||
return User::findFirstByUsername($data['username']) === false;
|
||||
},
|
||||
'message' => 'The username already exists.',
|
||||
'attribute' => 'username',
|
||||
])
|
||||
|
|
@ -63,7 +69,7 @@ class Registration extends FormBase
|
|||
$this->add($username);
|
||||
|
||||
// Names
|
||||
foreach([ 'first-name' => 'Firstname', 'last-name' => 'Lastname' ] as $id => $label) {
|
||||
foreach (['first-name' => 'Firstname', 'last-name' => 'Lastname'] as $id => $label) {
|
||||
|
||||
$name = new Text($id, array(
|
||||
'class' => 'form-control',
|
||||
|
|
@ -87,7 +93,9 @@ class Registration extends FormBase
|
|||
|
||||
$email->addValidators([
|
||||
new CallbackValidator([
|
||||
'callback' => function($data) { return User::findFirstByEmail($data['email']) === false; },
|
||||
'callback' => function ($data) {
|
||||
return User::findFirstByEmail($data['email']) === false;
|
||||
},
|
||||
'message' => 'This email already exist.',
|
||||
])
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -5,16 +5,19 @@ namespace App\Form;
|
|||
/**
|
||||
* Models
|
||||
*/
|
||||
|
||||
use App\Model\Data\User as UserModel;
|
||||
|
||||
/**
|
||||
* Form
|
||||
*/
|
||||
|
||||
use Httpcb\Form as FormBase;
|
||||
|
||||
/**
|
||||
* Element types
|
||||
*/
|
||||
|
||||
use Phalcon\Forms\Element\Text,
|
||||
Phalcon\Forms\Element\Password,
|
||||
Phalcon\Forms\Element\Submit;
|
||||
|
|
@ -22,6 +25,7 @@ use Phalcon\Forms\Element\Text,
|
|||
/**
|
||||
* Validators
|
||||
*/
|
||||
|
||||
use Phalcon\Validation\Validator\Callback as CallbackValidator,
|
||||
Phalcon\Validation\Validator\Uniqueness as UniquenessValidator,
|
||||
Phalcon\Validation\Validator\Alnum as AlnumValidator,
|
||||
|
|
@ -56,15 +60,15 @@ class UserSettings extends FormBase
|
|||
// Id
|
||||
if ($entity && $entity->getId()) {
|
||||
|
||||
$id = new Text('id', array(
|
||||
'class' => 'form-control',
|
||||
'readonly' => '',
|
||||
'disabled' => 'disabled',
|
||||
));
|
||||
$id = new Text('id', array(
|
||||
'class' => 'form-control',
|
||||
'readonly' => '',
|
||||
'disabled' => 'disabled',
|
||||
));
|
||||
|
||||
$id->addValidator(new IdenticalValidator([
|
||||
'accepted' => $entity->getId(),
|
||||
'allowEmpty' => true
|
||||
'allowEmpty' => true
|
||||
]));
|
||||
|
||||
$id->setLabel('ID');
|
||||
|
|
@ -86,7 +90,7 @@ class UserSettings extends FormBase
|
|||
);
|
||||
|
||||
if ($entity && strlen($entity->getUsername())) {
|
||||
$validator_options['except'] = [ $entity->getUsername() ];
|
||||
$validator_options['except'] = [$entity->getUsername()];
|
||||
}
|
||||
|
||||
$username->addValidators([
|
||||
|
|
@ -116,12 +120,12 @@ class UserSettings extends FormBase
|
|||
'class' => 'form-control',
|
||||
'placeholder' => 'Email',
|
||||
'readonly' => '',
|
||||
'disabled' => 'disabled',
|
||||
'disabled' => 'disabled',
|
||||
));
|
||||
|
||||
$email->addValidator(new IdenticalValidator([
|
||||
'accepted' => $entity->getEmail(),
|
||||
'allowEmpty' => true
|
||||
'allowEmpty' => true
|
||||
]));
|
||||
} else {
|
||||
$email = new Text('email', array(
|
||||
|
|
@ -136,7 +140,7 @@ class UserSettings extends FormBase
|
|||
];
|
||||
|
||||
if ($entity && strlen($entity->getEmail())) {
|
||||
$validator_options['except'] = [ $entity->getEmail() ];
|
||||
$validator_options['except'] = [$entity->getEmail()];
|
||||
}
|
||||
|
||||
$email->addValidators([
|
||||
|
|
@ -191,7 +195,7 @@ class UserSettings extends FormBase
|
|||
|
||||
if ($this->_admin === false && $entity && strlen($entity->getPassword()) > 0) {
|
||||
$validation->add('passwordCurrent', new CallbackValidator([
|
||||
'callback' => function($data) {
|
||||
'callback' => function ($data) {
|
||||
$new_pw = $data['passwordNew'];
|
||||
if (strlen($new_pw) > 0) {
|
||||
$value = $data['passwordCurrent'];
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
namespace Httpcb;
|
||||
|
||||
use Phalcon\Config,
|
||||
Phalcon\Acl\Enum,
|
||||
Phalcon\Acl\Enum,
|
||||
Phalcon\Acl\Role,
|
||||
Phalcon\Acl\Adapter\Memory as Adapter;
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ class Acl
|
|||
$pos = strpos($resource, '/');
|
||||
if ($pos !== false) {
|
||||
// Construct the wildcard resource.
|
||||
$wildcard = substr($resource, 0, $pos+1) . '*';
|
||||
$wildcard = substr($resource, 0, $pos + 1) . '*';
|
||||
|
||||
// If we have this wildcard resource, check against that instead.
|
||||
if ($this->hasResource($wildcard)) {
|
||||
|
|
@ -62,7 +62,7 @@ class Acl
|
|||
public function fromConfig(Config $config)
|
||||
{
|
||||
// Add roles.
|
||||
foreach($config->roles as $name => $def) {
|
||||
foreach ($config->roles as $name => $def) {
|
||||
|
||||
$inherits = null;
|
||||
$description = null;
|
||||
|
|
@ -70,7 +70,6 @@ class Acl
|
|||
if ($def instanceof Config) {
|
||||
$inherits = $def->get('inherits');
|
||||
$description = $def->get('description');
|
||||
|
||||
}
|
||||
|
||||
$role = new Role($name, $description);
|
||||
|
|
@ -78,33 +77,33 @@ class Acl
|
|||
}
|
||||
|
||||
// Zones
|
||||
foreach($config->zones as $name => $resources) {
|
||||
foreach ($config->zones as $name => $resources) {
|
||||
|
||||
if (!($resources instanceof Config)) {
|
||||
$resources = new Config([ $resources ]);
|
||||
$resources = new Config([$resources]);
|
||||
}
|
||||
|
||||
foreach($resources as $resource) {
|
||||
foreach ($resources as $resource) {
|
||||
$this->_adapter->addComponent($resource, 'All');
|
||||
}
|
||||
}
|
||||
|
||||
// Grant access for roles and resources.
|
||||
foreach($config->roles as $name => $def) {
|
||||
foreach ($config->roles as $name => $def) {
|
||||
|
||||
$zones = $def->get('allowed-zones', []);
|
||||
|
||||
if (is_string($zones)) {
|
||||
$zones = [ $zones ];
|
||||
$zones = [$zones];
|
||||
}
|
||||
|
||||
foreach($zones as $zone) {
|
||||
foreach ($zones as $zone) {
|
||||
$resources = $config->zones->get($zone);
|
||||
if (!($resources instanceof Config)) {
|
||||
$resources = new Config([ $resources ]);
|
||||
}
|
||||
foreach($resources as $resource) {
|
||||
$this->_adapter->allow($name, $resource, 'All');
|
||||
if (!($resources instanceof Config)) {
|
||||
$resources = new Config([$resources]);
|
||||
}
|
||||
foreach ($resources as $resource) {
|
||||
$this->_adapter->allow($name, $resource, 'All');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use App\Model\Data\User,
|
|||
class Auth extends Injectable
|
||||
{
|
||||
const SESSION_KEY = 'auth';
|
||||
const IMPERSONATOR_ID = 'auth.impersonator';
|
||||
|
||||
/**
|
||||
* Login using email/user + password combination.
|
||||
|
|
@ -63,8 +64,11 @@ class Auth extends Injectable
|
|||
|
||||
$this->setIdentity($user->getId());
|
||||
|
||||
$this->eventsManager->fire('auth:onLogin', $this,
|
||||
"OAuth {$data->getProvider()}");
|
||||
$this->eventsManager->fire(
|
||||
'auth:onLogin',
|
||||
$this,
|
||||
"OAuth {$data->getProvider()}"
|
||||
);
|
||||
|
||||
|
||||
return new Result(Result::SUCCESS);
|
||||
|
|
@ -83,6 +87,40 @@ class Auth extends Injectable
|
|||
$this->eventsManager->fire('auth:onLogin', $this, 'System');
|
||||
}
|
||||
|
||||
public function getImpersonator()
|
||||
{
|
||||
$id = $this->session->get(self::IMPERSONATOR_ID);
|
||||
return $id !== null ? User::findFirst($id) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Impersonate a user
|
||||
*
|
||||
* @param User $user
|
||||
*/
|
||||
public function impersonate(User $user)
|
||||
{
|
||||
$current = $this->getIdentity();
|
||||
if ($current === null) {
|
||||
throw new \InvalidArgumentException("Need to be authenticated to be able to impersonate someone");
|
||||
}
|
||||
|
||||
if ($current->getId() === $user->getId()) {
|
||||
// Same user
|
||||
throw new \DomainException("Can't impersonate yourself");
|
||||
}
|
||||
|
||||
$this->session->set(self::IMPERSONATOR_ID, $current->getId());
|
||||
$this->setIdentity($user->getId());
|
||||
$this->eventsManager->fire('auth:onImpersonate', $this, $current);
|
||||
}
|
||||
|
||||
public function impersonateClear($imp_id)
|
||||
{
|
||||
$this->session->remove(self::IMPERSONATOR_ID);
|
||||
$this->session->set(self::SESSION_KEY, $imp_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $identity
|
||||
* @return Auth
|
||||
|
|
@ -132,7 +170,12 @@ class Auth extends Injectable
|
|||
*/
|
||||
public function clearIdentity()
|
||||
{
|
||||
$this->session->remove(self::SESSION_KEY);
|
||||
$imp_id = $this->session->get(self::IMPERSONATOR_ID);
|
||||
if ($imp_id !== null) {
|
||||
$this->impersonateClear($imp_id);
|
||||
} else {
|
||||
$this->session->remove(self::SESSION_KEY);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@
|
|||
|
||||
namespace Httpcb;
|
||||
|
||||
class Debug {
|
||||
class Debug
|
||||
{
|
||||
|
||||
public static function dump($var, $label = null, $echo = true)
|
||||
{
|
||||
// format the label
|
||||
$label = ($label===null) ? '' : rtrim($label) . ' ';
|
||||
$label = ($label === null) ? '' : rtrim($label) . ' ';
|
||||
// var_dump the variable into a buffer and keep the output
|
||||
ob_start();
|
||||
var_dump($var);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class Form extends FormBase
|
|||
{
|
||||
$options = [
|
||||
'label-class' => 'col-form-label text-end',
|
||||
'class' => [ 'col-sm-10' ],
|
||||
'class' => ['col-sm-10'],
|
||||
'message' => ''
|
||||
];
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ class Form extends FormBase
|
|||
if ($len === 'full') {
|
||||
$options['class'] = [];
|
||||
} else {
|
||||
$options['class'] = [ 'col-sm-' . $len ];
|
||||
$options['class'] = ['col-sm-' . $len];
|
||||
}
|
||||
|
||||
unset($opt['length']);
|
||||
|
|
@ -42,10 +42,10 @@ class Form extends FormBase
|
|||
|
||||
protected function _render(AbstractElement $ele, $opt)
|
||||
{
|
||||
$classes = ['class' => 'form-control'];
|
||||
if ($ele->hasMessages()) {
|
||||
$classes['class'] .= ' is-invalid';
|
||||
}
|
||||
$classes = ['class' => 'form-control'];
|
||||
if ($ele->hasMessages()) {
|
||||
$classes['class'] .= ' is-invalid';
|
||||
}
|
||||
|
||||
$xhtml = '';
|
||||
|
||||
|
|
@ -53,14 +53,17 @@ class Form extends FormBase
|
|||
|
||||
$xhtml .= sprintf(
|
||||
'<label class="%s" for="%s">%s</label>',
|
||||
$opt['label-class'], $ele->getName(), $ele->getLabel());
|
||||
$opt['label-class'],
|
||||
$ele->getName(),
|
||||
$ele->getLabel()
|
||||
);
|
||||
}
|
||||
|
||||
$xhtml .= '<div class="' . implode(' ', $opt['class']) . '">'
|
||||
. $ele->render($classes);
|
||||
|
||||
if ($ele->hasMessages()) {
|
||||
$msg = $ele->getMessages()->current();
|
||||
$msg = $ele->getMessages()->current();
|
||||
$xhtml .= '<span class="invalid-feedback">' . $msg . '</span>';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ class Menu extends Tag
|
|||
{
|
||||
$xhtml = '';
|
||||
|
||||
foreach($nodes as $node) {
|
||||
foreach ($nodes as $node) {
|
||||
$xhtml .= $this->_renderNode($node, $depth, $max_depth);
|
||||
}
|
||||
|
||||
|
|
@ -126,15 +126,22 @@ class Menu extends Tag
|
|||
return $xhtml;
|
||||
}
|
||||
|
||||
$xhtml = self::tagHtml('li', $node->isActive()
|
||||
$xhtml = self::tagHtml(
|
||||
'li',
|
||||
$node->isActive()
|
||||
? array('class' => $this->_activeClass) : null,
|
||||
false, false, true);
|
||||
false,
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
||||
// Generate the link.
|
||||
$xhtml .= self::linkTo($node->getHref(), $node->getCaption());
|
||||
|
||||
if ($node->isActive() && $node->hasChildren()
|
||||
&& ($max_depth === null || $depth < $max_depth)) {
|
||||
if (
|
||||
$node->isActive() && $node->hasChildren()
|
||||
&& ($max_depth === null || $depth < $max_depth)
|
||||
) {
|
||||
|
||||
$xhtml .= $this->_renderMenu($node->getChildren(), $depth + 1, $max_depth);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,10 +44,10 @@ class RandomId extends Behavior implements BehaviorInterface
|
|||
*/
|
||||
public function notify($type, \Phalcon\Mvc\ModelInterface $model)
|
||||
{
|
||||
switch($type) {
|
||||
case 'beforeValidationOnCreate' :
|
||||
$this->generateId($model);
|
||||
break;
|
||||
switch ($type) {
|
||||
case 'beforeValidationOnCreate':
|
||||
$this->generateId($model);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ class RandomId extends Behavior implements BehaviorInterface
|
|||
if ($model->$field === null) {
|
||||
|
||||
$random = new \Phalcon\Security\Random();
|
||||
for($i = 0; $i < 3; $i++) {
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$id = substr($random->base64Safe(), 0, $len);
|
||||
|
||||
$count = $model->count(array(
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class Navigation extends Navigation\Container
|
|||
*/
|
||||
public function __construct($config)
|
||||
{
|
||||
foreach($config as $node) {
|
||||
foreach ($config as $node) {
|
||||
$this->addChild($node);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class Container
|
|||
|
||||
$node = new Node();
|
||||
|
||||
foreach($child as $k => $v) {
|
||||
foreach ($child as $k => $v) {
|
||||
|
||||
if ($k == 'children') {
|
||||
continue;
|
||||
|
|
@ -49,7 +49,7 @@ class Container
|
|||
|
||||
if (isset($child['children'])) {
|
||||
|
||||
foreach($child['children'] as $c_data) {
|
||||
foreach ($child['children'] as $c_data) {
|
||||
$node->addChild($c_data);
|
||||
}
|
||||
}
|
||||
|
|
@ -75,10 +75,9 @@ class Container
|
|||
*/
|
||||
public function addChildren($children)
|
||||
{
|
||||
foreach($children as $child) {
|
||||
foreach ($children as $child) {
|
||||
$this->addChild($child);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ class Node extends Container
|
|||
}
|
||||
|
||||
// first. Check children.
|
||||
foreach($this->getChildren() as $child) {
|
||||
foreach ($this->getChildren() as $child) {
|
||||
|
||||
if ($child->isActive() == true) {
|
||||
$this->setActive(true);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class League implements AdapterInterface
|
|||
try {
|
||||
$reflection = new \ReflectionClass($this->_provider);
|
||||
return $reflection->getShortName();
|
||||
} catch(\ReflectionException $ex) {
|
||||
} catch (\ReflectionException $ex) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,12 @@ use Phalcon\Di\FactoryDefault as DiDefault,
|
|||
Phalcon\Flash\Direct as FlashDirect,
|
||||
Phalcon\Mvc\Model\Metadata\Memory as MemoryMetaData,
|
||||
Phalcon\Mvc\Model\MetaData\Apc as ApcMetaData,
|
||||
Phalcon\Mvc\ViewBaseInterface,
|
||||
Phalcon\Mvc\ViewBaseInterface,
|
||||
Phalcon\Cache\Frontend\Data as FrontendDataCache,
|
||||
Phalcon\Cache\Backend\Apc as BackendApcCache,
|
||||
Phalcon\Translate\Adapter\NativeArray as TranslateAdapter,
|
||||
Phalcon\Storage\AdapterFactory as StorageAdapterFactory,
|
||||
Phalcon\Cache\AdapterFactory as CacheAdapterFactory,
|
||||
Phalcon\Logger,
|
||||
Phalcon\Mvc\Router;
|
||||
|
||||
|
|
@ -30,7 +32,8 @@ use Httpcb\Auth,
|
|||
|
||||
use App\Listener\AccessListener,
|
||||
App\Listener\DispatchListener,
|
||||
App\Listener\ActivityLog;
|
||||
App\Listener\ActivityLog,
|
||||
App\Listener\AuthEmailListener;
|
||||
|
||||
class Services extends DiDefault
|
||||
{
|
||||
|
|
@ -41,13 +44,12 @@ class Services extends DiDefault
|
|||
$reflection = new \ReflectionObject($this);
|
||||
$methods = $reflection->getMethods(\ReflectionMethod::IS_PROTECTED);
|
||||
|
||||
foreach($methods as $method) {
|
||||
foreach ($methods as $method) {
|
||||
|
||||
if (substr($method->getName(),0, 11) == '_initShared') {
|
||||
if (substr($method->getName(), 0, 11) == '_initShared') {
|
||||
$service = lcfirst(substr($method->getName(), 11));
|
||||
$this->setShared($service, $method->getClosure($this));
|
||||
}
|
||||
else if (substr($method->getName(),0, 5) == '_init') {
|
||||
} else if (substr($method->getName(), 0, 5) == '_init') {
|
||||
$service = lcfirst(substr($method->getName(), 5));
|
||||
$this->set($service, $method->getClosure($this));
|
||||
}
|
||||
|
|
@ -81,7 +83,7 @@ class Services extends DiDefault
|
|||
try {
|
||||
$tmp = new Config($basePath . $file);
|
||||
$config->merge($tmp);
|
||||
} catch(\Phalcon\Config\Exception $e) {
|
||||
} catch (\Phalcon\Config\Exception $e) {
|
||||
// Sometime went wrong. Log here?
|
||||
}
|
||||
}
|
||||
|
|
@ -115,7 +117,7 @@ class Services extends DiDefault
|
|||
|
||||
$eventsManager = new \Phalcon\Events\Manager();
|
||||
|
||||
$eventsManager->attach("dispatch", function($event, $dispatcher) {
|
||||
$eventsManager->attach("dispatch", function ($event, $dispatcher) {
|
||||
$actionName = lcfirst(\Phalcon\Text::camelize($dispatcher->getActionName(), '-_'));
|
||||
$dispatcher->setActionName($actionName);
|
||||
});
|
||||
|
|
@ -177,8 +179,11 @@ class Services extends DiDefault
|
|||
$options = $mdConfig['options'];
|
||||
$adapter = $mdConfig['adapter'];
|
||||
|
||||
$serializerFactory = new \Phalcon\Storage\SerializerFactory();
|
||||
$factory = new CacheAdapterFactory($serializerFactory);
|
||||
|
||||
$class = 'Phalcon\Mvc\Model\MetaData\\' . $adapter;
|
||||
return new $class($options);
|
||||
return new $class($factory, $options);
|
||||
}
|
||||
|
||||
// Otherwise, default to Memory.
|
||||
|
|
@ -188,22 +193,25 @@ class Services extends DiDefault
|
|||
protected function _initSession()
|
||||
{
|
||||
$config = $this->get('config');
|
||||
$session = new \Phalcon\Session\Manager();
|
||||
$session = new \Phalcon\Session\Manager();
|
||||
|
||||
if (isset($config->session)) {
|
||||
$data = $config->session->toArray();
|
||||
$adapter_name = isset($data['adapter']) ? $data['adapter'] : 'Stream';
|
||||
$options = $data['options'];
|
||||
|
||||
$serializerFactory = new \Phalcon\Storage\SerializerFactory();
|
||||
$factory = new StorageAdapterFactory($serializerFactory);
|
||||
|
||||
$class = 'Phalcon\Session\Adapter\\' . $adapter_name;
|
||||
$adapter = new $class($options);
|
||||
$adapter = new $class($factory, $options);
|
||||
}
|
||||
// Default to Stream
|
||||
else {
|
||||
$adapter = new \Phalcon\Session\Adapter\Stream();
|
||||
}
|
||||
|
||||
$session->setAdapter($adapter);
|
||||
$session->setAdapter($adapter);
|
||||
|
||||
// Start session.
|
||||
$session->start();
|
||||
|
|
@ -219,7 +227,7 @@ class Services extends DiDefault
|
|||
|
||||
$view = new View();
|
||||
|
||||
$view->setViewsDir([ $config->application->viewsDir ]);
|
||||
$view->setViewsDir([$config->application->viewsDir]);
|
||||
$view->setLayoutsDir('_layouts/');
|
||||
$view->setPartialsDir('_partials/');
|
||||
|
||||
|
|
@ -310,10 +318,10 @@ class Services extends DiDefault
|
|||
$config = $this->get('config')->router;
|
||||
|
||||
// Create the router
|
||||
$router = new Router();
|
||||
$router = new Router(false);
|
||||
$router->removeExtraSlashes($config->get('removeExtraSlashes', false));
|
||||
|
||||
foreach($config->routes as $name => $def) {
|
||||
foreach ($config->routes as $name => $def) {
|
||||
|
||||
if (!($def instanceof \Phalcon\Config)) {
|
||||
continue;
|
||||
|
|
@ -327,6 +335,9 @@ class Services extends DiDefault
|
|||
$router->add($def->get('pattern'), $path)
|
||||
->setName($name);
|
||||
}
|
||||
|
||||
$router->notFound(['controller' => 'error', 'action' => 'show404']);
|
||||
|
||||
return $router;
|
||||
}
|
||||
|
||||
|
|
@ -337,6 +348,7 @@ class Services extends DiDefault
|
|||
$eventsManager = new \Phalcon\Events\Manager();
|
||||
$eventsManager->attach('user', $activityLog);
|
||||
$eventsManager->attach('auth', $activityLog);
|
||||
$eventsManager->attach('auth', new AuthEmailListener);
|
||||
|
||||
return $eventsManager;
|
||||
}
|
||||
|
|
@ -353,10 +365,10 @@ class Services extends DiDefault
|
|||
|
||||
protected function _initSharedLogger()
|
||||
{
|
||||
$path = $this->get('config')->application->logDir;
|
||||
return new \Phalcon\Logger('default', [
|
||||
'main' => new \Phalcon\Logger\Adapter\Stream($path . 'app.txt')
|
||||
]);
|
||||
$path = $this->get('config')->application->logDir;
|
||||
return new \Phalcon\Logger('default', [
|
||||
'main' => new \Phalcon\Logger\Adapter\Stream($path . 'app.txt')
|
||||
]);
|
||||
}
|
||||
|
||||
protected function _initTemplate()
|
||||
|
|
@ -366,7 +378,7 @@ class Services extends DiDefault
|
|||
$view = new SimpleView();
|
||||
$view->setViewsDir($config->application->templateDir);
|
||||
$view->registerEngines([
|
||||
'.volt' => function (ViewBaseInterface $view) use ($config) {
|
||||
'.volt' => function (ViewBaseInterface $view) use ($config) {
|
||||
$volt = new VoltEngine($view, $this);
|
||||
|
||||
$volt->setOptions(array(
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class Alpha extends AbstractValidator
|
|||
* @param string $field
|
||||
* @return bool
|
||||
*/
|
||||
public function validate(\Phalcon\Validation $validation, $field) : bool
|
||||
public function validate(\Phalcon\Validation $validation, $field): bool
|
||||
{
|
||||
$allowSpace = $this->getOption('allowSpace', false);
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ class Alpha extends AbstractValidator
|
|||
$message = $validation->getDefaultMessage('Alpha');
|
||||
}
|
||||
|
||||
$replace = [ ":field" => $label ];
|
||||
$replace = [":field" => $label];
|
||||
|
||||
$code = $this->getOption("code");
|
||||
if (is_array($code)) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ abstract class AbstractHelper implements InjectionAwareInterface
|
|||
*
|
||||
* @param DiInterface $container
|
||||
*/
|
||||
public function setDI(DiInterface $container) : void
|
||||
public function setDI(DiInterface $container): void
|
||||
{
|
||||
$this->_di = $container;
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ abstract class AbstractHelper implements InjectionAwareInterface
|
|||
*
|
||||
* @return DiInterface
|
||||
*/
|
||||
public function getDI() : DiInterface
|
||||
public function getDI(): DiInterface
|
||||
{
|
||||
return $this->_di;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class Icon extends AbstractHelper
|
|||
|
||||
if (is_array($args)) {
|
||||
|
||||
foreach($args as $arg) {
|
||||
foreach ($args as $arg) {
|
||||
$classes[] .= 'fa-' . $arg;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ class ServerUrl extends AbstractHelper
|
|||
|
||||
// remove port if it's the default port.
|
||||
if (($scheme == 'http' && $port == 80)
|
||||
|| ($scheme == 'https' && $port == 443)) {
|
||||
|| ($scheme == 'https' && $port == 443)
|
||||
) {
|
||||
$port = null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class Service implements InjectionAwareInterface
|
|||
*
|
||||
* @param DiInterface $container
|
||||
*/
|
||||
public function setDI(DiInterface $container) : void
|
||||
public function setDI(DiInterface $container): void
|
||||
{
|
||||
$this->_di = $container;
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ class Service implements InjectionAwareInterface
|
|||
*
|
||||
* @return DiInterface
|
||||
*/
|
||||
public function getDI() : DiInterface
|
||||
public function getDI(): DiInterface
|
||||
{
|
||||
return $this->_di;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
namespace App\Listener;
|
||||
|
||||
use Phalcon\Di\Injectable,
|
||||
Phalcon\Events\Event,
|
||||
Phalcon\Events\Event,
|
||||
Phalcon\Mvc\Dispatcher,
|
||||
Phalcon\Mvc\Dispatcher\Exception as DispatcherException;
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ class AccessListener extends Injectable
|
|||
* @return bool
|
||||
* @throws DispatcherException
|
||||
*/
|
||||
public function beforeExecuteRoute(Event $event, Dispatcher $dispatcher) : bool
|
||||
public function beforeExecuteRoute(Event $event, Dispatcher $dispatcher): bool
|
||||
{
|
||||
// If we have an identity, fetch type from authed user.
|
||||
if ($this->auth->hasIdentity()) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,19 @@ class ActivityLog extends Injectable
|
|||
$this->_log($auth->getUser(), sprintf("Logged in (%s)", $type));
|
||||
}
|
||||
|
||||
/**
|
||||
* On Impersonate event.
|
||||
*
|
||||
* @param Event $event
|
||||
* @param Auth $auth
|
||||
* @param User $user The user Impersonating the user in $auth
|
||||
*/
|
||||
public function onImpersonate(Event $event, Auth $auth, User $user)
|
||||
{
|
||||
$imp = $auth->getUser();
|
||||
$this->_log($user, sprintf("Impersonated user (%s:%s)", $imp->getId(), $imp->getUsername()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Event $event
|
||||
* @param User $auth
|
||||
|
|
@ -65,11 +78,23 @@ class ActivityLog extends Injectable
|
|||
$this->_log($user, sprintf("OAuth disconnected (%s)", $providerName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a activation email is sent.
|
||||
*
|
||||
* @param Event $event
|
||||
* @param User $user
|
||||
* @param string $providerName
|
||||
*/
|
||||
public function onSentActivation(Event $event, User $user)
|
||||
{
|
||||
$this->_log($user, sprintf("Activation email sent"));
|
||||
}
|
||||
|
||||
protected function _log(User $user, $message)
|
||||
{
|
||||
$ip = (new \Phalcon\Http\Request())->getClientAddress();
|
||||
$ip = (new \Phalcon\Http\Request())->getClientAddress(true);
|
||||
|
||||
return (new ActivityLogger())->assign([
|
||||
return (new ActivityLogger())->assign([
|
||||
'user_id' => $user->getId(),
|
||||
'ip' => $ip,
|
||||
'message' => $message
|
||||
|
|
|
|||
25
app/listeners/AuthEmailListener.php
Normal file
25
app/listeners/AuthEmailListener.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Listener;
|
||||
|
||||
use App\Model\Data\User,
|
||||
App\Model\Data\UserActivation;
|
||||
|
||||
use Phalcon\Di\Injectable,
|
||||
Phalcon\Events\Event;
|
||||
|
||||
class AuthEmailListener extends Injectable
|
||||
{
|
||||
public function onSentActivation(Event $event, User $user)
|
||||
{
|
||||
$activation = new UserActivation();
|
||||
$activation->setUserId($user->getId())
|
||||
->save();
|
||||
|
||||
$content = $this->di->getShared('template')->render('mail/account_activation', [
|
||||
'link' => $activation->getActivationKey()
|
||||
]);
|
||||
|
||||
$this->di->getMail()->send('Httpcb account activation', $user->getEmail(), $content);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ namespace App\Listener;
|
|||
|
||||
use Exception,
|
||||
Phalcon\Events\Event,
|
||||
Phalcon\Di\Injectable,
|
||||
Phalcon\Di\Injectable,
|
||||
Phalcon\Mvc\Dispatcher,
|
||||
Phalcon\Mvc\Dispatcher\Exception as DispatcherException;
|
||||
|
||||
|
|
@ -38,11 +38,11 @@ class DispatchListener extends Injectable
|
|||
// was that an controller or action was not found.
|
||||
if ($exception instanceof DispatcherException) {
|
||||
switch ($exception->getCode()) {
|
||||
case Dispatcher::EXCEPTION_HANDLER_NOT_FOUND :
|
||||
case Dispatcher::EXCEPTION_ACTION_NOT_FOUND :
|
||||
// in this case, forward to 404 page.
|
||||
$dispatcher->forward($this->_route_notfound);
|
||||
return false;
|
||||
case Dispatcher::EXCEPTION_HANDLER_NOT_FOUND:
|
||||
case Dispatcher::EXCEPTION_ACTION_NOT_FOUND:
|
||||
// in this case, forward to 404 page.
|
||||
$dispatcher->forward($this->_route_notfound);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class CreateUserTable extends AbstractMigration
|
|||
$table->addColumn('status', 'enum', [
|
||||
'null' => false,
|
||||
'default' => 'Active',
|
||||
'values' => [ 'Active', 'Deleted', 'Suspended']
|
||||
'values' => ['Active', 'Deleted', 'Suspended']
|
||||
]);
|
||||
|
||||
$table->addColumn('password', 'string', [
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@ class CreateCallbackTable extends AbstractMigration
|
|||
$table->addColumn('public_id', 'string', [
|
||||
'length' => 12,
|
||||
'null' => false,
|
||||
])->addIndex('public_id', [ 'name' => 'UNIQUE_public_id', 'unique' => true ]);
|
||||
])->addIndex('public_id', ['name' => 'UNIQUE_public_id', 'unique' => true]);
|
||||
|
||||
$table->addColumn('userid', 'integer', [
|
||||
'null' => true,
|
||||
])->addForeignKey('userid', 'user', ['id'], [ 'constraint' => 'FK_user' ]);
|
||||
])->addForeignKey('userid', 'user', ['id'], ['constraint' => 'FK_user']);
|
||||
|
||||
$table->addColumn('name', 'string', [
|
||||
'length' => 64,
|
||||
|
|
|
|||
|
|
@ -10,8 +10,12 @@ class CreateRequestMetaTable extends AbstractMigration
|
|||
$table = $this->table('request_meta');
|
||||
|
||||
$table->addColumn('callbackid', 'integer');
|
||||
$table->addForeignKey('callbackid', 'callback', [ 'id' ],
|
||||
[ 'constraint' => 'FK_callback' ]);
|
||||
$table->addForeignKey(
|
||||
'callbackid',
|
||||
'callback',
|
||||
['id'],
|
||||
['constraint' => 'FK_callback']
|
||||
);
|
||||
|
||||
$table->addColumn('source_ip', 'string', [
|
||||
'limit' => 50,
|
||||
|
|
@ -21,7 +25,7 @@ class CreateRequestMetaTable extends AbstractMigration
|
|||
$table->addColumn('method', 'enum', [
|
||||
'null' => false,
|
||||
'default' => 'GET',
|
||||
'values' => [ 'GET', 'POST' ]
|
||||
'values' => ['GET', 'POST']
|
||||
]);
|
||||
|
||||
$table->addColumn('uri', 'string', [
|
||||
|
|
|
|||
|
|
@ -9,8 +9,12 @@ class CreateRequestObjectTable extends AbstractMigration
|
|||
{
|
||||
$table = $this->table('request_object');
|
||||
|
||||
$table->addForeignKey('id', 'request_meta', ['id'],
|
||||
[ 'constraint' => 'FK_request_meta' ]);
|
||||
$table->addForeignKey(
|
||||
'id',
|
||||
'request_meta',
|
||||
['id'],
|
||||
['constraint' => 'FK_request_meta']
|
||||
);
|
||||
|
||||
$table->addColumn('headers', 'blob', [
|
||||
'null' => true,
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ class PasswordLink extends AbstractMigration
|
|||
public function up()
|
||||
{
|
||||
$this->table('password_link')
|
||||
->addColumn('public_id', 'string', ['length' => 12 ])
|
||||
->addColumn('public_id', 'string', ['length' => 12])
|
||||
->addColumn('user_id', 'integer')
|
||||
->addForeignKey('user_id', 'user', ['id'], [ 'constraint' => 'FK_password_link_user' ])
|
||||
->addColumn('date', 'datetime', [ 'default' => 'CURRENT_TIMESTAMP' ])
|
||||
->addColumn('password', 'string', [ 'limit' => 255, 'null' => true ])
|
||||
->addForeignKey('user_id', 'user', ['id'], ['constraint' => 'FK_password_link_user'])
|
||||
->addColumn('date', 'datetime', ['default' => 'CURRENT_TIMESTAMP'])
|
||||
->addColumn('password', 'string', ['limit' => 255, 'null' => true])
|
||||
->save();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class UserSplitName extends AbstractMigration
|
|||
// Rename "name" to "firstname" and add "lastname".
|
||||
$this->table('user')
|
||||
->renameColumn('name', 'firstname')
|
||||
->addColumn('lastname','string', [
|
||||
->addColumn('lastname', 'string', [
|
||||
'length' => 128,
|
||||
'after' => 'firstname',
|
||||
'null' => true
|
||||
|
|
@ -20,7 +20,7 @@ class UserSplitName extends AbstractMigration
|
|||
->save();
|
||||
|
||||
// Update row data, moving everything after first space to from lastname.
|
||||
foreach($this->fetchAll("SELECT `id`,`firstname` FROM `user`") as $row) {
|
||||
foreach ($this->fetchAll("SELECT `id`,`firstname` FROM `user`") as $row) {
|
||||
|
||||
$builder = $this->getQueryBuilder()->update('user')
|
||||
->where(['id' => $row['id']]);
|
||||
|
|
@ -31,7 +31,7 @@ class UserSplitName extends AbstractMigration
|
|||
$pos = strpos($firstname, ' ');
|
||||
if ($pos !== false) {
|
||||
// Set everything after the first space to lastname.
|
||||
$builder->set('lastname', substr($firstname, $pos+1));
|
||||
$builder->set('lastname', substr($firstname, $pos + 1));
|
||||
|
||||
// Remove everything after first space from firstname.
|
||||
$firstname = substr($firstname, 0, $pos);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class UserType extends AbstractMigration
|
|||
->addColumn('type', 'enum', [
|
||||
'null' => false,
|
||||
'default' => 'user',
|
||||
'values' => [ 'user', 'admin' ],
|
||||
'values' => ['user', 'admin'],
|
||||
'after' => 'regdate'
|
||||
])
|
||||
->save();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class Base extends Model
|
|||
* @param boolean $allFields
|
||||
* @return bool
|
||||
*/
|
||||
public function hasChanged($fieldName = null, bool $allFields = false) : bool
|
||||
public function hasChanged($fieldName = null, bool $allFields = false): bool
|
||||
{
|
||||
return $this->hasSnapshotData() === false
|
||||
|| parent::hasChanged($fieldName, $allFields);
|
||||
|
|
|
|||
|
|
@ -216,8 +216,8 @@ class Callback extends Model
|
|||
*/
|
||||
public function initialize()
|
||||
{
|
||||
// Set table name mapped in the model.
|
||||
$this->setSource('callback');
|
||||
// Set table name mapped in the model.
|
||||
$this->setSource('callback');
|
||||
|
||||
$this->useDynamicUpdate(true);
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ class Request extends Model
|
|||
*/
|
||||
public function setHeaders($headers)
|
||||
{
|
||||
foreach($headers as $k => $v) {
|
||||
foreach ($headers as $k => $v) {
|
||||
|
||||
if (strlen($v) < 1) {
|
||||
unset($headers[$k]);
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ class RequestMeta extends Model
|
|||
$query = (string) parse_url($this->getUri(), PHP_URL_QUERY);
|
||||
|
||||
$ret = array();
|
||||
foreach(explode('&', $query) as $v) {
|
||||
foreach (explode('&', $query) as $v) {
|
||||
@list($k, $v) = explode('=', $v, 2);
|
||||
if (strlen($k) > 0) {
|
||||
$ret[$k] = $v;
|
||||
|
|
@ -211,7 +211,7 @@ class RequestMeta extends Model
|
|||
{
|
||||
$headers = $this->getHeaders();
|
||||
|
||||
foreach($headers as $k => $v) {
|
||||
foreach ($headers as $k => $v) {
|
||||
|
||||
if ($k == 'Content-Length') {
|
||||
return $v;
|
||||
|
|
@ -224,7 +224,7 @@ class RequestMeta extends Model
|
|||
{
|
||||
$headers = $this->getHeaders();
|
||||
|
||||
foreach($headers as $k => $v) {
|
||||
foreach ($headers as $k => $v) {
|
||||
|
||||
if ($k == 'Content-Type') {
|
||||
return substr($v, strrpos($v, '/') + 1);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class User extends Base
|
|||
'message' => 'The username already exists.'
|
||||
]),
|
||||
'email' => new CallbackValidator([
|
||||
'callback' => function() {
|
||||
'callback' => function () {
|
||||
return $this->findFirstByEmail($this->getEmail()) === false;
|
||||
},
|
||||
'message' => 'The email address already exists.'
|
||||
|
|
@ -69,7 +69,7 @@ class User extends Base
|
|||
];
|
||||
|
||||
$validation = new Validation();
|
||||
foreach($rules as $field => $validator) {
|
||||
foreach ($rules as $field => $validator) {
|
||||
|
||||
// Only validate changed fields.
|
||||
if ($this->hasChanged($field)) {
|
||||
|
|
@ -265,6 +265,16 @@ class User extends Base
|
|||
return $this->status == self::STATUS_ACTIVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this user is suspended.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSuspended()
|
||||
{
|
||||
return $this->status == self::STATUS_SUSPENDED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
|
|
@ -404,7 +414,7 @@ class User extends Base
|
|||
{
|
||||
return self::findFirst([
|
||||
"(email = :v: OR username = :v:) AND status != :s:",
|
||||
"bind" => [ 'v' => $value, 's' => self::STATUS_DELETED ]
|
||||
"bind" => ['v' => $value, 's' => self::STATUS_DELETED]
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -412,7 +422,7 @@ class User extends Base
|
|||
{
|
||||
return self::findFirst([
|
||||
"email = :email: AND status != :s:",
|
||||
"bind" => [ 'email' => $email, 's' => self::STATUS_DELETED ]
|
||||
"bind" => ['email' => $email, 's' => self::STATUS_DELETED]
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -420,7 +430,7 @@ class User extends Base
|
|||
{
|
||||
return self::findFirst([
|
||||
"username = :username: AND status != :s:",
|
||||
"bind" => [ 'username' => $username, 's' => self::STATUS_DELETED ]
|
||||
"bind" => ['username' => $username, 's' => self::STATUS_DELETED]
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -430,7 +440,7 @@ class User extends Base
|
|||
|
||||
return self::findFirst([
|
||||
"{$column}_id = :id: AND status != :s:",
|
||||
"bind" => [ 'id' => $oauth->getId(), 's' => self::STATUS_DELETED ]
|
||||
"bind" => ['id' => $oauth->getId(), 's' => self::STATUS_DELETED]
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ class UserActivation extends Base
|
|||
* @param int $id
|
||||
* @return PasswordLink
|
||||
*/
|
||||
public function setId(int $id) : UserActivation
|
||||
public function setId(int $id): UserActivation
|
||||
{
|
||||
$this->id = $id;
|
||||
return $this;
|
||||
|
|
@ -97,7 +97,7 @@ class UserActivation extends Base
|
|||
* @param string $public_id
|
||||
* @return UserActivation
|
||||
*/
|
||||
public function setActivationKey(string $key) : UserActivation
|
||||
public function setActivationKey(string $key): UserActivation
|
||||
{
|
||||
$this->activation_key = $key;
|
||||
return $this;
|
||||
|
|
@ -115,7 +115,7 @@ class UserActivation extends Base
|
|||
* @param int $user_id
|
||||
* @return UserActivation
|
||||
*/
|
||||
public function setUserId(int $user_id) : UserActivation
|
||||
public function setUserId(int $user_id): UserActivation
|
||||
{
|
||||
$this->user_id = $user_id;
|
||||
return $this;
|
||||
|
|
@ -133,7 +133,7 @@ class UserActivation extends Base
|
|||
* @param string $password
|
||||
* @return UserActivation
|
||||
*/
|
||||
public function setPassword(string $password) : UserActivation
|
||||
public function setPassword(string $password): UserActivation
|
||||
{
|
||||
$this->password = $password;
|
||||
return $this;
|
||||
|
|
@ -144,7 +144,7 @@ class UserActivation extends Base
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isUsed() : bool
|
||||
public function isUsed(): bool
|
||||
{
|
||||
return (bool) $this->used;
|
||||
}
|
||||
|
|
@ -154,7 +154,7 @@ class UserActivation extends Base
|
|||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid() : bool
|
||||
public function isValid(): bool
|
||||
{
|
||||
// Used links are not valid.
|
||||
if ($this->isUsed()) {
|
||||
|
|
@ -175,9 +175,9 @@ class UserActivation extends Base
|
|||
public function beforeCreate()
|
||||
{
|
||||
// Creating a new link automatically removes old ones.
|
||||
$links = self::find(["user_id = ?0", 'bind' => [ $this->user_id ]]);
|
||||
$links = self::find(["user_id = ?0", 'bind' => [$this->user_id]]);
|
||||
|
||||
foreach($links as $link) {
|
||||
foreach ($links as $link) {
|
||||
$link->delete();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,9 +39,8 @@ abstract class Base implements ModuleDefinitionInterface
|
|||
$dispatcher->setDefaultNamespace($this->_controllerNamespace);
|
||||
|
||||
$di->get('view')->setViewsDir(array_merge(
|
||||
[ $this->_viewDir ],
|
||||
[$this->_viewDir],
|
||||
(array) $di->get('view')->getViewsDir()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
data-bs-toggle="dropdown" role="button" aria-expanded="false">
|
||||
|
||||
{{ icon('solid/user') }} <strong>{{ auth.getUser().username }}</strong>
|
||||
{% set imp = auth.getImpersonator() %}
|
||||
{% if imp %}( {{ icon('solid/user-secret') }} {{ imp.username }} ){% endif %}
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu navigation-user-menu-dropdown-list">
|
||||
|
|
|
|||
|
|
@ -56,6 +56,13 @@
|
|||
{% if (user.getId()) %}
|
||||
{% set actions = [ 'Activate': 'Active', 'Suspend': 'Suspended', 'Delete': 'Deleted' ] %}
|
||||
<div class="float-end">
|
||||
|
||||
{% if user.isSuspended() %}
|
||||
<a class="button button-info" href="{{ url(['for': 'backend-user-activation-email', 'id': user.getId() ]) }}">
|
||||
Send activation email
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% for label, status in actions %}
|
||||
|
||||
{% if (user.status != status) %}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
<th>Email</th>
|
||||
<th>Type</th>
|
||||
<th>Status</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
|
|
@ -36,7 +37,12 @@
|
|||
<td>{{ item.name }}</td>
|
||||
<td>{{ item.email }}</td>
|
||||
<td>{{ item.type | capitalize }}</td>
|
||||
<td>{{ item.status }}</td>
|
||||
<td><span class="badge {{ item.isActive() ? 'badge-success' : 'badge-danger' }}">{{ item.status }}</span></td>
|
||||
<td>
|
||||
<a title="Impersonate" href="{{ url(['for': 'backend-user-impersonate', 'id': item.id ]) }}">
|
||||
{{ icon('solid/user-secret') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
"ext-psr": ">=1.2",
|
||||
"ext-redis": "*",
|
||||
"ext-yaml": "*",
|
||||
"ext-mbstring": "*",
|
||||
"robmorgan/phinx": "^0.10.6",
|
||||
"league/oauth2-client": "^2.3",
|
||||
"league/oauth2-github": "^2.0",
|
||||
|
|
|
|||
5
package-lock.json
generated
5
package-lock.json
generated
|
|
@ -1,11 +1,12 @@
|
|||
{
|
||||
"name": "httpcb",
|
||||
"version": "1.1",
|
||||
"version": "1.1.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "1.1",
|
||||
"name": "httpcb",
|
||||
"version": "1.1.0",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@popperjs/core": "^2.11.5",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "httpcb",
|
||||
"version": "1.1",
|
||||
"version": "1.1.0",
|
||||
"description": "HTTP Callback Tool",
|
||||
"devDependencies": {
|
||||
"@popperjs/core": "^2.11.5",
|
||||
|
|
|
|||
Reference in a new issue