diff --git a/src/IDF/Form/Admin/UserUpdate.php b/src/IDF/Form/Admin/UserUpdate.php new file mode 100644 index 0000000..458d721 --- /dev/null +++ b/src/IDF/Form/Admin/UserUpdate.php @@ -0,0 +1,206 @@ +user = $extra['user']; + $this->fields['first_name'] = new Pluf_Form_Field_Varchar( + array('required' => false, + 'label' => __('First name'), + 'initial' => $this->user->first_name, + 'widget_attrs' => array( + 'maxlength' => 50, + 'size' => 15, + ), + )); + $this->fields['last_name'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Last name'), + 'initial' => $this->user->last_name, + 'widget_attrs' => array( + 'maxlength' => 50, + 'size' => 20, + ), + )); + + $this->fields['email'] = new Pluf_Form_Field_Email( + array('required' => true, + 'label' => __('Email'), + 'initial' => $this->user->email, + 'widget_attrs' => array( + 'maxlength' => 50, + 'size' => 20, + ), + )); + + $this->fields['language'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Language'), + 'initial' => $this->user->language, + 'widget' => 'Pluf_Form_Widget_SelectInput', + 'widget_attrs' => array( + 'choices' => + Pluf_L10n::getInstalledLanguages() + ), + )); + + $this->fields['password'] = new Pluf_Form_Field_Varchar( + array('required' => false, + 'label' => __('Password'), + 'initial' => '', + 'widget' => 'Pluf_Form_Widget_PasswordInput', + 'help_text' => Pluf_Template::markSafe(__('Leave blank if you do not want to change the password.').'
'.__('The password must be hard for other people to find it, but easy for the user to remember.')), + 'widget_attrs' => array( + 'maxlength' => 50, + 'size' => 15, + ), + )); + $this->fields['password2'] = new Pluf_Form_Field_Varchar( + array('required' => false, + 'label' => __('Confirm password'), + 'initial' => '', + 'widget' => 'Pluf_Form_Widget_PasswordInput', + 'widget_attrs' => array( + 'maxlength' => 50, + 'size' => 15, + ), + )); + + $attrs = ($extra['request']->user->id == $this->user->id) ? + array('readonly' => 'readonly') : array(); + $this->fields['active'] = new Pluf_Form_Field_Boolean( + array('required' => false, + 'label' => __('Active'), + 'initial' => $this->user->active, + 'widget' => 'Pluf_Form_Widget_CheckboxInput', + 'widget_attrs' => $attrs, + 'help_text' => __('If the user is not getting the confirmation email or is abusing the system, you can directly enable or disable his account here.'), + )); + } + + + /** + * Save the model in the database. + * + * @param bool Commit in the database or not. If not, the object + * is returned but not saved in the database. + * @return Object Model with data set from the form. + */ + function save($commit=true) + { + if (!$this->isValid()) { + throw new Exception(__('Cannot save the model from an invalid form.')); + } + unset($this->cleaned_data['password2']); + $update_pass = false; + if (strlen($this->cleaned_data['password']) == 0) { + unset($this->cleaned_data['password']); + } else { + $update_pass = true; + } + $this->user->setFromFormData($this->cleaned_data); + if ($commit) { + $this->user->update(); + if ($update_pass) { + /** + * [signal] + * + * Pluf_User::passwordUpdated + * + * [sender] + * + * IDF_Form_UserAccount + * + * [description] + * + * This signal is sent when the user updated his + * password from his account page. + * + * [parameters] + * + * array('user' => $user) + * + */ + $params = array('user' => $this->user); + Pluf_Signal::send('Pluf_User::passwordUpdated', + 'IDF_Form_Admin_UserUpdate', $params); + } + } + return $this->user; + } + + function clean_last_name() + { + $last_name = trim($this->cleaned_data['last_name']); + if ($last_name == mb_strtoupper($last_name)) { + return mb_convert_case(mb_strtolower($last_name), + MB_CASE_TITLE, 'UTF-8'); + } + return $last_name; + } + + function clean_first_name() + { + $first_name = trim($this->cleaned_data['first_name']); + if ($first_name == mb_strtoupper($first_name)) { + return mb_convert_case(mb_strtolower($first_name), + MB_CASE_TITLE, 'UTF-8'); + } + return $first_name; + } + + function clean_email() + { + $email = mb_strtolower(trim($this->cleaned_data['email'])); + $sql = new Pluf_SQL('email=%s AND id!=%s', + array($email, $this->user->id)); + $users = Pluf::factory('Pluf_User')->getList(array('filter'=>$sql->gen())); + if ($users->count() > 0) { + throw new Pluf_Form_Invalid(__('A user with this email already exists, please provide another email address.')); + } + return $email; + } + + /** + * Check to see if the 2 passwords are the same. + */ + public function clean() + { + if (!isset($this->errors['password']) + && !isset($this->errors['password2'])) { + $password1 = $this->cleaned_data['password']; + $password2 = $this->cleaned_data['password2']; + if ($password1 != $password2) { + throw new Pluf_Form_Invalid(__('The passwords do not match. Please give them again.')); + } + } + return $this->cleaned_data; + } +} diff --git a/src/IDF/Views/Admin.php b/src/IDF/Views/Admin.php index e06cd0f..8f16f14 100644 --- a/src/IDF/Views/Admin.php +++ b/src/IDF/Views/Admin.php @@ -142,4 +142,93 @@ class IDF_Views_Admin $request); } + /** + * Users overview. + * + */ + public $users_precond = array('Pluf_Precondition::staffRequired'); + public function users($request, $match) + { + $title = __('User List'); + $pag = new Pluf_Paginator(new Pluf_User()); + $pag->class = 'recent-issues'; + $pag->summary = __('This table shows the users in the forge.'); + $pag->action = 'IDF_Views_Admin::users'; + $pag->edit_action = array('IDF_Views_Admin::userUpdate', 'id'); + $pag->sort_order = array('login', 'ASC'); + $list_display = array( + 'login' => __('login'), + array('last_name', 'Pluf_Paginator_ToString', __('Name')), + array('staff', 'IDF_Views_Admin_bool', __('Staff')), + array('administrator', 'IDF_Views_Admin_bool', __('Admin')), + array('active', 'IDF_Views_Admin_bool', __('Active')), + array('last_login', 'Pluf_Paginator_DateYMDHM', __('Last Login')), + ); + $pag->extra_classes = array('', 'a-c', 'a-c', 'a-c', 'a-c', 'a-c'); + $pag->configure($list_display, array(), array('login')); + $pag->items_per_page = 50; + $pag->no_results_text = __('No users were found.'); + $pag->setFromRequest($request); + return Pluf_Shortcuts_RenderToResponse('idf/gadmin/users/index.html', + array( + 'page_title' => $title, + 'users' => $pag, + ), + $request); + } + + /** + * Edition of a user. + * + * Staff cannot edit other staff people and only admin can edit + * staff. + */ + public $userUpdate_precond = array('Pluf_Precondition::staffRequired'); + public function userUpdate($request, $match) + { + $user = Pluf_Shortcuts_GetObjectOr404('Pluf_User', $match[1]); + $title = sprintf(__('Update %s'), $user->__toString()); + $params = array( + 'user' => $user, + 'request' => $request, + ); + // Check the rights. + $url = Pluf_HTTP_URL_urlForView('IDF_Views_Admin::users'); + $error = __('You do not have the rights to update this user.'); + if ($user->administrator and $request->user->id != $user->id) { + $request->user->setMessage($error); + return new Pluf_HTTP_Response_Redirect($url); + } + if ($user->staff) { + if (!$request->user->administrator and $request->user->id != $user->id) { + $request->user->setMessage($error); + return new Pluf_HTTP_Response_Redirect($url); + } + } + + if ($request->method == 'POST') { + $form = new IDF_Form_Admin_UserUpdate($request->POST, $params); + if ($form->isValid()) { + $form->save(); + $request->user->setMessage(__('The user has been updated.')); + return new Pluf_HTTP_Response_Redirect($url); + } + } else { + $form = new IDF_Form_Admin_UserUpdate(null, $params); + } + return Pluf_Shortcuts_RenderToResponse('idf/gadmin/users/update.html', + array( + 'page_title' => $title, + 'cuser' => $user, + 'form' => $form, + ), + $request); + } +} + +function IDF_Views_Admin_bool($field, $item) +{ + $img = ($item->$field) ? 'day' : 'night'; + $text = ($item->$field) ? __('Yes') : __('No'); + return sprintf('%s ', $img, $text); } \ No newline at end of file diff --git a/src/IDF/conf/urls.php b/src/IDF/conf/urls.php index 5838dd0..dd9c4e2 100644 --- a/src/IDF/conf/urls.php +++ b/src/IDF/conf/urls.php @@ -417,6 +417,18 @@ $ctl[] = array('regex' => '#^/admin/projects/create/$#', 'model' => 'IDF_Views_Admin', 'method' => 'projectCreate'); +$ctl[] = array('regex' => '#^/admin/users/$#', + 'base' => $base, + 'priority' => 4, + 'model' => 'IDF_Views_Admin', + 'method' => 'users'); + +$ctl[] = array('regex' => '#^/admin/users/(\d+)/$#', + 'base' => $base, + 'priority' => 4, + 'model' => 'IDF_Views_Admin', + 'method' => 'userUpdate'); + // ---------- UTILITY VIEWS ------------------------------- $ctl[] = array('regex' => '#^/register/$#', diff --git a/src/IDF/templates/idf/gadmin/base.html b/src/IDF/templates/idf/gadmin/base.html index 656cf91..56e9ec8 100644 --- a/src/IDF/templates/idf/gadmin/base.html +++ b/src/IDF/templates/idf/gadmin/base.html @@ -42,6 +42,7 @@
{trans 'Administer'} {trans 'Projects'} + {trans 'People'}
{block subtabs}{/block}
diff --git a/src/IDF/templates/idf/gadmin/users/base.html b/src/IDF/templates/idf/gadmin/users/base.html new file mode 100644 index 0000000..c65368e --- /dev/null +++ b/src/IDF/templates/idf/gadmin/users/base.html @@ -0,0 +1,9 @@ +{extends "idf/gadmin/base.html"} +{block tabusers} class="active"{/block} +{block subtabs} +{trans 'User List'} +{if $inUpdate} | +{trans 'Update User'} +{/if} + +{/block} diff --git a/src/IDF/templates/idf/gadmin/users/index.html b/src/IDF/templates/idf/gadmin/users/index.html new file mode 100644 index 0000000..c3255bf --- /dev/null +++ b/src/IDF/templates/idf/gadmin/users/index.html @@ -0,0 +1,12 @@ +{extends "idf/gadmin/users/base.html"} + +{block docclass}yui-t2{assign $inIndex=true}{/block} + +{block body} +{$users.render} +{/block} +{block context} +
+{blocktrans}

You have here an overview of the users registered in the forge.

{/blocktrans} +
+{/block} diff --git a/src/IDF/templates/idf/gadmin/users/update.html b/src/IDF/templates/idf/gadmin/users/update.html new file mode 100644 index 0000000..50af31f --- /dev/null +++ b/src/IDF/templates/idf/gadmin/users/update.html @@ -0,0 +1,82 @@ +{extends "idf/gadmin/users/base.html"} +{block docclass}yui-t1{assign $inUpdate=true}{/block} +{block body} +{if $form.errors} +
+

{trans 'The form contains some errors. Please correct them to update the user.'}

+{if $form.get_top_errors} +{$form.render_top_errors|unsafe} +{/if} +
+{/if} +
+ + +{aurl 'url', 'IDF_Views_User::view', array($cuser.login)} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{trans 'Login:'}{$cuser.login}
{$form.f.first_name.labelTag}:{if $form.f.first_name.errors}{$form.f.first_name.fieldErrors}{/if} +{$form.f.first_name|unsafe} +
{$form.f.last_name.labelTag}:{if $form.f.last_name.errors}{$form.f.last_name.fieldErrors}{/if} +{$form.f.last_name|unsafe} +
{$form.f.email.labelTag}:{if $form.f.email.errors}{$form.f.email.fieldErrors}{/if} +{$form.f.email|unsafe} +
{$form.f.language.labelTag}:{if $form.f.language.errors}{$form.f.language.fieldErrors}{/if} +{$form.f.language|unsafe} +
{$form.f.password.labelTag}:{if $form.f.password.errors}{$form.f.password.fieldErrors}{/if} +{$form.f.password|unsafe}
+{$form.f.password.help_text} +
{$form.f.password2.labelTag}:{if $form.f.password2.errors}{$form.f.password2.fieldErrors}{/if} +{$form.f.password2|unsafe} +
{if $form.f.active.errors}{$form.f.active.fieldErrors}{/if} +{$form.f.active|unsafe} +{$form.f.active.labelTag}
+{$form.f.active.help_text}
  + +| {trans 'Cancel'} +
+
+{/block} +{block context} +
+

{trans 'Instructions:'}

+

{blocktrans}If you are changing the email address of the user, you +need to ensure that you are providing a valid email +address{/blocktrans}

+
+{/block} + + + diff --git a/www/media/idf/css/style.css b/www/media/idf/css/style.css index 99abc93..83f680d 100644 --- a/www/media/idf/css/style.css +++ b/www/media/idf/css/style.css @@ -43,6 +43,10 @@ a:active{ text-align: right; } +.a-c { + text-align: center; +} + .dellink { float: right; position: relative; diff --git a/www/media/idf/img/day.png b/www/media/idf/img/day.png new file mode 100644 index 0000000..7dc15ea Binary files /dev/null and b/www/media/idf/img/day.png differ diff --git a/www/media/idf/img/night.png b/www/media/idf/img/night.png new file mode 100644 index 0000000..4345752 Binary files /dev/null and b/www/media/idf/img/night.png differ