diff --git a/src/IDF/Form/Admin/UserCreate.php b/src/IDF/Form/Admin/UserCreate.php new file mode 100644 index 0000000..7fe6015 --- /dev/null +++ b/src/IDF/Form/Admin/UserCreate.php @@ -0,0 +1,222 @@ +request = $extra['request']; + $this->fields['first_name'] = new Pluf_Form_Field_Varchar( + array('required' => false, + 'label' => __('First name'), + 'initial' => '', + 'widget_attrs' => array( + 'maxlength' => 50, + 'size' => 15, + ), + )); + $this->fields['last_name'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Last name'), + 'initial' => '', + 'widget_attrs' => array( + 'maxlength' => 50, + 'size' => 20, + ), + )); + + $this->fields['login'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Login'), + 'max_length' => 15, + 'min_length' => 3, + 'initial' => '', + 'help_text' => __('The login must be between 3 and 15 characters long and contains only letters and digits.'), + 'widget_attrs' => array( + 'maxlength' => 15, + 'size' => 10, + ), + )); + + $this->fields['email'] = new Pluf_Form_Field_Email( + array('required' => true, + 'label' => __('Email'), + 'initial' => '', + 'help_text' => __('Double check the email address as the password is directly sent to the user.'), + )); + + $this->fields['language'] = new Pluf_Form_Field_Varchar( + array('required' => true, + 'label' => __('Language'), + 'initial' => '', + 'widget' => 'Pluf_Form_Widget_SelectInput', + 'widget_attrs' => array( + 'choices' => + Pluf_L10n::getInstalledLanguages() + ), + )); + + $this->fields['ssh_key'] = new Pluf_Form_Field_Varchar( + array('required' => false, + 'label' => __('Add a public SSH key'), + 'initial' => '', + 'widget_attrs' => array('rows' => 3, + 'cols' => 40), + 'widget' => 'Pluf_Form_Widget_TextareaInput', + 'help_text' => __('Be careful to provide the public key and not the private key!') + )); + + + } + + /** + * 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.')); + } + $password = Pluf_Utils::getPassword(); + $user = new Pluf_User(); + $user->setFromFormData($this->cleaned_data); + $user->active = true; + $user->staff = false; + $user->administrator = false; + $user->setPassword($password); + $user->create(); + /** + * [signal] + * + * Pluf_User::passwordUpdated + * + * [sender] + * + * IDF_Form_Admin_UserCreate + * + * [description] + * + * This signal is sent when a user is created + * by the staff. + * + * [parameters] + * + * array('user' => $user) + * + */ + $params = array('user' => $user); + Pluf_Signal::send('Pluf_User::passwordUpdated', + 'IDF_Form_Admin_UserCreate', $params); + // Create the ssh key as needed + if ('' !== $this->cleaned_data['ssh_key']) { + $key = new IDF_Key(); + $key->user = $user; + $key->content = $this->cleaned_data['ssh_key']; + $key->create(); + } + // Send an email to the user with the password + Pluf::loadFunction('Pluf_HTTP_URL_urlForView'); + $url = Pluf::f('url_base').Pluf_HTTP_URL_urlForView('IDF_Views::login', array(), array(), false); + $context = new Pluf_Template_Context( + array('password' => Pluf_Template::markSafe($password), + 'user' => $user, + 'url' => Pluf_Template::markSafe($url), + 'admin' => $this->request->user, + )); + $tmpl = new Pluf_Template('idf/gadmin/users/createuser-email.txt'); + $text_email = $tmpl->render($context); + $email = new Pluf_Mail(Pluf::f('from_email'), $user->email, + __('Your details to access your forge.')); + $email->addTextMessage($text_email); + $email->sendMail(); + return $user; + } + + function clean_ssh_key() + { + $key = trim($this->cleaned_data['ssh_key']); + if (strlen($key) == 0) { + return ''; + } + $key = str_replace(array("\n", "\r"), '', $key); + if (!preg_match('#^ssh\-[a-z]{3}\s(\S+)\s\S+$#', $key, $matches)) { + throw new Pluf_Form_Invalid(__('The format of the key is not valid. It must start with ssh-dss or ssh-rsa, a long string on a single line and at the end a comment.')); + } + return $key; + } + + 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() + { + $this->cleaned_data['email'] = mb_strtolower(trim($this->cleaned_data['email'])); + $guser = new Pluf_User(); + $sql = new Pluf_SQL('email=%s', array($this->cleaned_data['email'])); + if ($guser->getCount(array('filter' => $sql->gen())) > 0) { + throw new Pluf_Form_Invalid(sprintf(__('The email "%s" is already used.'), $this->cleaned_data['email'])); + } + return $this->cleaned_data['email']; + } + + public function clean_login() + { + $this->cleaned_data['login'] = mb_strtolower(trim($this->cleaned_data['login'])); + if (preg_match('/[^a-z0-9]/', $this->cleaned_data['login'])) { + throw new Pluf_Form_Invalid(sprintf(__('The login "%s" can only contain letters and digits.'), $this->cleaned_data['login'])); + } + $guser = new Pluf_User(); + $sql = new Pluf_SQL('login=%s', $this->cleaned_data['login']); + if ($guser->getCount(array('filter' => $sql->gen())) > 0) { + throw new Pluf_Form_Invalid(sprintf(__('The login "%s" is already used, please find another one.'), $this->cleaned_data['login'])); + } + return $this->cleaned_data['login']; + } +} diff --git a/src/IDF/Views/Admin.php b/src/IDF/Views/Admin.php index e24b883..5685c1f 100644 --- a/src/IDF/Views/Admin.php +++ b/src/IDF/Views/Admin.php @@ -192,13 +192,14 @@ class IDF_Views_Admin if ($not_validated) { $pag->forced_where = new Pluf_SQL('first_name = \'---\' AND active!='.$true); $title = __('Not Validated User List'); + $pag->action = 'IDF_Views_Admin::usersNotValidated'; } else { $pag->forced_where = new Pluf_SQL('first_name != \'---\''); $title = __('User List'); + $pag->action = 'IDF_Views_Admin::users'; } $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( @@ -210,7 +211,9 @@ class IDF_Views_Admin array('last_login', 'Pluf_Paginator_DateYMDHM', __('Last Login')), ); $pag->extra_classes = array('', '', 'a-c', 'a-c', 'a-c', 'a-c'); - $pag->configure($list_display, array(), array('login', 'last_login')); + $pag->configure($list_display, + array('login', 'last_name', 'email'), + array('login', 'last_login')); $pag->items_per_page = 50; $pag->no_results_text = __('No users were found.'); $pag->setFromRequest($request); @@ -279,6 +282,38 @@ class IDF_Views_Admin ), $request); } + + /** + * Create a new user. + * + * Only staff can add a user. The user can be added together with + * a public ssh key. + */ + public $userCreate_precond = array('Pluf_Precondition::staffRequired'); + public function userCreate($request, $match) + { + $params = array( + 'request' => $request, + ); + if ($request->method == 'POST') { + $form = new IDF_Form_Admin_UserCreate($request->POST, $params); + if ($form->isValid()) { + $cuser = $form->save(); + $request->user->setMessage(sprintf(__('The user %s has been created.'), (string) $cuser)); + $url = Pluf_HTTP_URL_urlForView('IDF_Views_Admin::users'); + return new Pluf_HTTP_Response_Redirect($url); + } + } else { + $form = new IDF_Form_Admin_UserCreate(null, $params); + } + $title = __('Add User'); + return Pluf_Shortcuts_RenderToResponse('idf/gadmin/users/create.html', + array( + 'page_title' => $title, + 'form' => $form, + ), + $request); + } } function IDF_Views_Admin_bool($field, $item) diff --git a/src/IDF/conf/urls.php b/src/IDF/conf/urls.php index 105eb1b..c4b3e08 100644 --- a/src/IDF/conf/urls.php +++ b/src/IDF/conf/urls.php @@ -370,6 +370,11 @@ $ctl[] = array('regex' => '#^/admin/users/$#', 'model' => 'IDF_Views_Admin', 'method' => 'users'); +$ctl[] = array('regex' => '#^/admin/users/create/$#', + 'base' => $base, + 'model' => 'IDF_Views_Admin', + 'method' => 'userCreate'); + $ctl[] = array('regex' => '#^/admin/users/notvalid/$#', 'base' => $base, 'model' => 'IDF_Views_Admin', diff --git a/src/IDF/templates/idf/gadmin/users/base.html b/src/IDF/templates/idf/gadmin/users/base.html index c65368e..93116a6 100644 --- a/src/IDF/templates/idf/gadmin/users/base.html +++ b/src/IDF/templates/idf/gadmin/users/base.html @@ -4,6 +4,7 @@ {trans 'User List'} {if $inUpdate} | {trans 'Update User'} -{/if} +{/if} | +{trans 'Create User'} {/block} diff --git a/src/IDF/templates/idf/gadmin/users/create.html b/src/IDF/templates/idf/gadmin/users/create.html new file mode 100644 index 0000000..0132bed --- /dev/null +++ b/src/IDF/templates/idf/gadmin/users/create.html @@ -0,0 +1,68 @@ +{extends "idf/gadmin/users/base.html"} +{block docclass}yui-t1{assign $inCreate=true}{/block} +{block body} +{if $form.errors} +
+

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

+{if $form.get_top_errors} +{$form.render_top_errors|unsafe} +{/if} +
+{/if} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{$form.f.login.labelTag}:{if $form.f.login.errors}{$form.f.login.fieldErrors}{/if} +{$form.f.login|unsafe} +
{$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.email.help_text} +
{$form.f.language.labelTag}:{if $form.f.language.errors}{$form.f.language.fieldErrors}{/if} +{$form.f.language|unsafe} +
{$form.f.ssh_key.labelTag}:{if $form.f.ssh_key.errors}{$form.f.ssh_key.fieldErrors}{/if} +{$form.f.ssh_key|unsafe}
+{$form.f.ssh_key.help_text} +
  | {trans 'Cancel'} +
+
+{/block} +{block context} +
+

{trans 'The user password will be sent by email to the user.'}

+
{/block} + +{block javascript}{/block} + diff --git a/src/IDF/templates/idf/gadmin/users/createuser-email.txt b/src/IDF/templates/idf/gadmin/users/createuser-email.txt new file mode 100644 index 0000000..9b08e75 --- /dev/null +++ b/src/IDF/templates/idf/gadmin/users/createuser-email.txt @@ -0,0 +1,16 @@ +{blocktrans}Hello {$user}, + +An account on the forge has been created for you by +the administrator {$admin}. + +Please find here your details to access the forge: + + Address: {$url} + Login: {$user.login} + Password: {$password} + +Yours faithfully, +The development team. +{/blocktrans} + +