diff --git a/app/assets/less/layout/navigation.less b/app/assets/less/layout/navigation.less index cde4028..c5f5b3c 100644 --- a/app/assets/less/layout/navigation.less +++ b/app/assets/less/layout/navigation.less @@ -110,17 +110,37 @@ &-user-menu { &:extend(.nav); .pull-right(); - margin-top: 18px; + margin-top: 10px; - > li { - display: inline-block; + &-login { + padding-top: .3em; + padding-bottom: .3em; + } - .icon { - margin-right: .2em; + &-dropdown { + &:extend(.dropdown); + + &-button { + display: inline-block; + padding: .3em .8em; + background: @usermenu-button-bg; + border-radius: @border-radius-base; + + &:hover { + background: @usermenu-button-hover-bg; + } } - &:not(:first-child) { - padding-left: 1em; + &-list { + &:extend(.dropdown-menu all); + &:extend(.dropdown-menu-right all); + + text-shadow: none; + .box-shadow(@dropdown-shadow); + } + + &.open &-list { + display: inline-block; } } } diff --git a/app/assets/less/variables.less b/app/assets/less/variables.less index eb58e5e..ad716d8 100644 --- a/app/assets/less/variables.less +++ b/app/assets/less/variables.less @@ -74,6 +74,10 @@ @navbar-brand-color: @brand-color; @navbar-brand-hover-color: darken(@brand-color, 15%); +// User menu +@usermenu-button-bg: @navbar-background; +@usermenu-button-hover-bg: darken(@usermenu-button-bg, 8%); + // Footer @footer-height: 80px; @footer-border-color: @border-color; @@ -116,6 +120,12 @@ @block-shadow-2: 0 3px 3px 0 rgba(0, 0, 0, 0.14), 0 1px 7px 0 rgba(0, 0, 0, 0.12); @block-shadow-3: 0 3px 3px 0 rgba(0, 0, 0, 0.16); +// ---------------------------------- +// Dropdown +// ---------------------------------- + +@dropdown-shadow: 0 2px 4px rgba(0,0,0,0.1); + // ---------------------------------- // Blankslate // ---------------------------------- diff --git a/app/config/services.php b/app/config/services.php index 260c317..a5db77b 100644 --- a/app/config/services.php +++ b/app/config/services.php @@ -111,10 +111,10 @@ $di->setShared('router', function() { 'action' => 'oauth' ))->setName('oauth'); - $router->add('/user', array( + $router->add('/settings', array( 'controller' => 'user', - 'action' => 'profile', - ))->setName('profile'); + 'action' => 'settings', + ))->setName('user-settings'); return $router; }); diff --git a/app/controllers/UserController.php b/app/controllers/UserController.php new file mode 100644 index 0000000..76d98f3 --- /dev/null +++ b/app/controllers/UserController.php @@ -0,0 +1,34 @@ +_getAuth()->getUser(); + + $form = new UserSettingsForm($user); + + if ($this->request->isPost()) { + $data = $this->request->getPost(); + + if ($form->isValid($data)) { + + $new_pw = $form->getValue('passwordNew'); + if (strlen($new_pw) > 0) { + $hash = password_hash($new_pw, PASSWORD_BCRYPT); + $user->setPassword($hash); + } + $user->save(); + $form->initialize(); + + $this->flash->message('success', 'Settings saved!'); + } else { + $this->flash->message('error', 'Could not save settings'); + } + } + + $this->view->form = $form; + } +} diff --git a/app/forms/UserSettings.php b/app/forms/UserSettings.php new file mode 100644 index 0000000..ebc7f5c --- /dev/null +++ b/app/forms/UserSettings.php @@ -0,0 +1,235 @@ +setValidation(new \Phalcon\Validation()); + + // Id + $id = new Text('id', array( + 'class' => 'form-control', + 'readonly' => '', + )); + $id->addValidator(new IdenticalValidator([ + 'accepted' => $this->getEntity()->getId(), + ])); + + $id->setLabel('ID'); + $this->add($id); + + // Username + $username = new Text('username', array( + 'class' => 'form-control', + 'placeholder' => 'Username', + )); + + $username->setLabel('Username'); + + $username->addValidator(new AlnumValidator()); + + $validator = new UniquenessValidator(array( + 'model' => new UserModel(), + 'message' => 'The username already exists.', + 'attribute' => 'username', + 'except' => [ $this->getEntity()->getUsername() ] + )); + + $username->addValidator($validator); + + $this->add($username); + + // Name + $name = new Text('name', array( + 'class' => 'form-control', + 'placeholder' => 'Name', + )); + + $name->setLabel('Name'); + $name->addValidator(new AlphaValidator([ + 'allowSpace' => true, + 'allowEmpty' => true, + ])); + + $this->add($name); + + // Email + $email = new Text('email', array( + 'class' => 'form-control', + 'placeholder' => 'Email', + 'readonly' => '', + )); + + $email->addValidator(new IdenticalValidator([ + 'accepted' => $this->getEntity()->getEmail(), + ])); + + $email->setLabel('Email'); + + $this->add($email); + + // Passwords + $this->_passwords(); + + // Submit + $submit = new Submit('Save', array('class' => 'button button-default')); + $this->add($submit); + } + + /** + * Password section + */ + protected function _passwords() + { + $current_pw = $this->getEntity()->getPassword(); + + // Current + if (strlen($current_pw) > 0) { + $current = new Password('passwordCurrent', array( + 'class' => 'form-control', + )); + $current->setLabel('Current password'); + $this->add($current); + } + + // New + $new = new Password('passwordNew', array( + 'class' => 'form-control', + )); + $new->setLabel('New password'); + $this->add($new); + + // Confirm + $confirm = new Password('passwordConfirm', array( + 'class' => 'form-control', + )); + $confirm->setLabel('Confirm'); + $this->add($confirm); + + // Validation + $validation = $this->getValidation(); + + if (strlen($current_pw) > 0) { + $validation->add('passwordCurrent', new CallbackValidator([ + 'callback' => function($data) { + $new_pw = $data['passwordNew']; + if (strlen($new_pw) > 0) { + $value = $data['passwordCurrent']; + $hash = $this->getEntity()->getPassword(); + + // Only fail if there is a password and they did not match. + if (strlen($hash) > 0 && password_verify($value, $hash) === false) { + return false; + } + } + return true; + }, + 'message' => 'Password is not valid.' + ])); + } + + $validation->add('passwordNew', new StringLengthValidator([ + 'allowEmpty' => true, + 'min' => 8, + 'messageMinimum' => 'Password must be atleast 8 characters long', + ])); + + $validation->add('passwordConfirm', new ConfirmationValidator([ + 'message' => 'Passwords does not match', + 'with' => 'passwordNew', + ])); + } + + public function renderDecorated($name, $opt = []) + { + $options = [ + 'label-class' => 'control-label', + 'class' => 'col-sm-10', + 'message' => '' + ]; + + $ele = $this->get($name); + + if (isset($opt['label-length'])) { + $length = (int) $opt['label-length']; + } else { + $length = 2; + } + $options['label-class'] .= ' col-sm-' . $length; + + if (isset($opt['length'])) { + + $len = $opt['length']; + + if ($len === 'full') { + $options['class'] = ''; + } else { + $options['class'] = 'col-sm-' . $opt['length']; + } + } + + if ($ele->hasMessages()) { + $options['class'] .= ' has-error'; + $options['message'] = $ele->getMessages()->current(); + } + + return $this->_render($ele, $options); + } + + protected function _render(FormElement $ele, $opt) + { + $xhtml = ''; + + if (strlen($ele->getLabel()) > 0) { + + $xhtml .= sprintf( + '', + $opt['label-class'], $ele->getName(), $ele->getLabel()); + } + + $xhtml .= '
' + . $ele->render(); + + if (strlen($opt['message']) > 0) { + $xhtml .= '' . $opt['message'] . ''; + } + + $xhtml .= '
'; + + return $xhtml; + } +} diff --git a/app/library/Validation/Validator/Alpha.php b/app/library/Validation/Validator/Alpha.php new file mode 100644 index 0000000..bcdacb1 --- /dev/null +++ b/app/library/Validation/Validator/Alpha.php @@ -0,0 +1,66 @@ +getOption('allowSpace', false); + + $charlist = '[:alpha:]'; + if ($allowSpace) { + $charlist .= '[:space:]'; + } + + $value = $validation->getValue($attribute); + + if (preg_match("/[^{$charlist}]/imu", $value)) { + + $label = $this->getOption('label'); + if (empty($label)) { + $label = $validation->getLabel($attribute); + } + + $message = $this->getOption('message'); + if (empty($message)) { + $message = $validation->getDefaultMessage('Alpha'); + } + + //var_dump($message);exit; + + $replace = [ ":field" => $label ]; + + $code = $this->getOption("code"); + if (is_array($code)) { + $code = $code[$attribute]; + } + + $message = str_replace(array_keys($replace), $replace, $message); + + $msg = new Message($message, $attribute, "Alpha", $code); + $validation->appendMessage($msg); + + return false; + } + + return true; + } +} diff --git a/app/views/_templates/navigation.volt b/app/views/_templates/navigation.volt index 75940c1..0d0d072 100644 --- a/app/views/_templates/navigation.volt +++ b/app/views/_templates/navigation.volt @@ -5,14 +5,25 @@ - +