Commit c03266f2 authored by Robert Lyon's avatar Robert Lyon
Browse files

Bug 1661125: Allow custom profile fields via /local/lib/



Lets one have a custom profile field that can be used to record data
against

behatnotneeded

Change-Id: I39de0e6f1aa5b1e29a3bf5604ee88612ccff5478
Signed-off-by: Robert Lyon's avatarRobert Lyon <robertl@catalyst.net.nz>
parent 759c87f8
......@@ -56,7 +56,34 @@ if (!$pending) {
}
function build_pending_html($data, $institution) {
// Check for information saved in the usr_registrtion.extra table column
// This extra data is serialized data from the custom fields in registration form
// The custom fields can be existing core profile fields like 'studentid' or
// can be local custom profile fields defined in the 'local/lib/artefact_internal.php' file
$extracols = array();
if (!empty($data)) {
foreach ($data as $itemkey => $item) {
if (!empty($item->extra)) {
$item->extra = unserialize($item->extra);
safe_require('artefact', 'internal');
// If 'extra' data exists we loop through the de-serialized 'extra' data to:
// 1) add the columnsto the pending registrations table for these particular profile fields
// 2) adjust the content for the column to be human readable, via format_result()
foreach ($item->extra as $k => $v) {
$classname = 'ArtefactType' . ucfirst($k);
if (class_exists($classname)) {
$extracols[$k] = 1;
}
if (is_callable(array($classname, 'format_result'))) {
$out = call_static_method($classname, 'format_result', $v);
$item->extra->$k = $out;
}
}
}
}
}
$smarty = smarty_core();
$smarty->assign('extracols', isset($extracols) ? $extracols : null);
$smarty->assign('data', isset($data) ? $data : null);
$smarty->assign('institution', $institution);
$tablerows = $smarty->fetch('admin/users/pendinguserslist.tpl');
......
......@@ -108,6 +108,15 @@ foreach ( $element_list as $element => $type ) {
$items[$element]['options'] = array('' => get_string('nocountryselected')) + $countries;
$items[$element]['defaultvalue'] = get_config('country');
}
$classname = 'ArtefactType' . ucfirst($element);
if (is_callable(array($classname, 'getoptions'))) {
$options = call_static_method($classname, 'getoptions');
$items[$element]['options'] = $options;
}
if (is_callable(array($classname, 'defaultoption'))) {
$defaultoption = call_static_method($classname, 'defaultoption');
$items[$element]['defaultvalue'] = $defaultoption;
}
if ($element == 'socialprofile') {
$items[$element] = ArtefactTypeSocialprofile::render_profile_element();
}
......@@ -149,19 +158,19 @@ $elements = array(
'type' => 'fieldset',
'legend' => get_string('aboutme', 'artefact.internal'),
'class' => 'has-help' . $fieldset != 'aboutme' ? 'collapsed' : '',
'elements' => get_desired_fields($items, array('firstname', 'lastname', 'studentid', 'preferredname', 'introduction'), 'about'),
'elements' => get_desired_fields($items, 'about'),
),
'contact' => array(
'type' => 'fieldset',
'legend' => get_string('contact', 'artefact.internal'),
'class' => $fieldset != 'contact' ? '' : '',
'elements' => get_desired_fields($items, array('email', 'maildisabled', 'officialwebsite', 'personalwebsite', 'blogaddress', 'address', 'town', 'city', 'country', 'homenumber', 'businessnumber', 'mobilenumber', 'faxnumber'), 'contact'),
'elements' => get_desired_fields($items, 'contact'),
),
'social' => array(
'type' => 'fieldset',
'legend' => get_string('social', 'artefact.internal'),
'class' => $fieldset != 'social' ? 'collapsed' : '',
'elements' => get_desired_fields($items, array('socialprofile'), 'social'),
'elements' => get_desired_fields($items, 'social'),
),
'general' => array(
'type' => 'fieldset',
......@@ -197,8 +206,22 @@ $profileform = pieform(array(
'autofocus' => false,
));
function get_desired_fields(&$allfields, $desiredfields, $section) {
function get_desired_fields(&$allfields, $section) {
global $USER;
$desiredfields = array('about' => array('firstname', 'lastname', 'studentid', 'preferredname', 'introduction'),
'contact' => array('email', 'maildisabled', 'officialwebsite', 'personalwebsite', 'blogaddress', 'address', 'town', 'city', 'country', 'homenumber', 'businessnumber', 'mobilenumber', 'faxnumber'),
'social' => array('socialprofile'),
);
if (is_callable(array('ArtefactTypeProfileLocal', 'get_desired_fields'))) {
$localfields = call_static_method('ArtefactTypeProfileLocal', 'get_desired_fields');
foreach ($localfields as $k => $v) {
foreach ($v as $k2 => $v2) {
array_splice($desiredfields[$k], $k2, 0, array($v2));
}
}
}
if ($section == 'about') {
$r = get_record_select('view', 'type = ? AND owner = ?', array('profile', $USER->id), 'id');
$label = '<div id="profileicon" class="profile-icon pseudolabel pull-left"><a href="' . get_config('wwwroot') . 'artefact/file/profileicons.php" class="user-icon"><img src="'
......@@ -217,7 +240,7 @@ function get_desired_fields(&$allfields, $desiredfields, $section) {
'value' => $descr,
)
);
foreach ($desiredfields as $field) {
foreach ($desiredfields[$section] as $field) {
if (isset($allfields[$field])) {
$return[$field] = $allfields[$field];
unset($allfields[$field]);
......@@ -401,7 +424,6 @@ function profileform_submit(Pieform $form, $values) {
}
else {
if (!isset($profilefields[$element]) || $values[$element] != $profilefields[$element]) {
if ($element == 'introduction') {
$newintroduction = EmbeddedImage::prepare_embedded_images($values[$element], 'profileintrotext', $USER->get('id'));
$values[$element] = $newintroduction;
......
......@@ -19,6 +19,8 @@ $string['mandatoryfields'] = 'Mandatory fields';
$string['mandatoryfieldsdescription'] = 'Profile fields that must be filled in';
$string['searchablefields'] = 'Searchable fields';
$string['searchablefieldsdescription'] = 'Profile fields that can be searched on by others';
$string['adminusersearchfields'] = 'Administration user search';
$string['adminusersearchfieldsdescription'] = 'Profile fields that appear as columns on the Administration user search list';
$string['aboutdescription'] = 'Enter your real first and last name here. If you want to show a different name to people in the system, put that name in as your display name.';
$string['infoisprivate'] = 'This information is private until you include it in a page that is shared with others.';
......
<!-- @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later -->
<!-- @copyright For copyright information on Mahara, please see the README file distributed with this software. -->
<h3>Administration user search</h3>
<p>Choose which user profile fields to display on the Administration
user search list.</p>
<p>First name, last name, email address, and display name are always
displayed.</p>
......@@ -10,11 +10,14 @@
*/
defined('INTERNAL') || die();
if (file_exists(get_config('docroot') . 'local/lib/artefact_internal.php')) {
include_once(get_config('docroot') . 'local/lib/artefact_internal.php');
}
class PluginArtefactInternal extends PluginArtefact {
public static function get_artefact_types() {
return array(
$types = array(
'firstname',
'lastname',
'studentid',
......@@ -37,10 +40,15 @@ class PluginArtefactInternal extends PluginArtefact {
'html',
'socialprofile',
);
if (class_exists('PluginArtefactInternalLocal', false)) {
$localtypes = PluginArtefactInternalLocal::get_artefact_types();
$types = array_merge($types, $localtypes);
}
return $types;
}
public static function get_profile_artefact_types() {
return array(
$types = array(
'firstname',
'lastname',
'studentid',
......@@ -62,10 +70,15 @@ class PluginArtefactInternal extends PluginArtefact {
'industry',
'socialprofile',
);
if (class_exists('PluginArtefactInternalLocal', false)) {
$localtypes = PluginArtefactInternalLocal::get_profile_artefact_types();
$types = array_merge($types, $localtypes);
}
return $types;
}
public static function get_contactinfo_artefact_types() {
return array(
$types = array(
'email',
'officialwebsite',
'personalwebsite',
......@@ -80,6 +93,11 @@ class PluginArtefactInternal extends PluginArtefact {
'faxnumber',
'socialprofile',
);
if (class_exists('PluginArtefactInternalLocal', false)) {
$localtypes = PluginArtefactInternalLocal::get_contactinfo_artefact_types();
$types = array_merge($types, $localtypes);
}
return $types;
}
public static function get_block_types() {
......@@ -480,6 +498,10 @@ class ArtefactTypeProfile extends ArtefactType {
);
}
$out = array_merge($out, $social);
if (class_exists('ArtefactTypeProfileLocal', false)) {
$localfields = ArtefactTypeProfileLocal::get_all_fields();
$out = array_merge($out, $localfields);
}
return $out;
}
......@@ -522,6 +544,36 @@ class ArtefactTypeProfile extends ArtefactType {
return array_merge($m, $alwaysm);
}
public static function get_adminusersearch_fields() {
$m = array();
$all = self::get_all_fields();
$alwaysm = self::get_always_mandatory_fields();
if ($man = get_config_plugin('artefact', 'internal', 'profileadminusersearch')) {
$mandatory = explode(',', $man);
}
else {
$mandatory = array();
}
// If socialprofile is disabled, we need to remove any fields that may
// have been selected when it was enabled.
// If socialprofile is enabled, we need to remove any fields that my
// have been selected when it was disabled.
$need_to_update = false;
foreach ($mandatory as $mf) {
if (isset($all[$mf])) {
$m[$mf] = $all[$mf];
}
else {
$need_to_update = true;
}
}
if ($need_to_update) {
// We need to save the config settings for the mandatory fields for the plugin.
set_config_plugin('artefact', 'internal', 'profileadminusersearch', join(',', array_keys($m)));
}
return array_merge($m, $alwaysm);
}
public static function get_always_mandatory_fields() {
return array(
'firstname' => 'text',
......@@ -530,6 +582,15 @@ class ArtefactTypeProfile extends ArtefactType {
);
}
public static function get_always_adminusersearchable_fields() {
return array(
'firstname' => 'text',
'lastname' => 'text',
'preferredname' => 'text',
'email' => 'emaillist',
);
}
public static function get_all_searchable_fields() {
return array(
'firstname' => 'text',
......@@ -612,6 +673,18 @@ class ArtefactTypeProfile extends ArtefactType {
);
}
$adminusersearch = self::get_adminusersearch_fields();
$alwaysadminusersearch = self::get_always_adminusersearchable_fields();
$adminusersearchfields = array();
foreach (array_keys($allmandatory) as $field) {
$adminusersearchfields[$field] = array(
'title' => get_string($field, 'artefact.internal'),
'value' => $field,
'defaultvalue' => isset($alwaysadminusersearch[$field]) || isset($adminusersearch[$field]),
'disabled' => isset($alwaysadminusersearch[$field]),
);
}
$form = array(
'elements' => array(
'mandatory' => array(
......@@ -634,6 +707,16 @@ class ArtefactTypeProfile extends ArtefactType {
'options' => $allsearchable, // Only the keys are used by validateoptions
'rules' => array('validateoptions' => true),
),
'adminusersearch' => array(
'title' => get_string('adminusersearchfields', 'artefact.internal'),
'description' => get_string('adminusersearchfieldsdescription', 'artefact.internal'),
'help' => true,
'class' => 'stacked',
'type' => 'checkboxes',
'elements' => $adminusersearchfields,
'options' => $allmandatory, // Only the keys are used by validateoptions
'rules' => array('validateoptions' => true),
),
),
);
......@@ -645,6 +728,8 @@ class ArtefactTypeProfile extends ArtefactType {
set_config_plugin('artefact', 'internal', 'profilemandatory', join(',', $mandatory));
$searchable = array_merge(array_keys(self::get_always_searchable_fields()), $values['searchable']);
set_config_plugin('artefact', 'internal', 'profilepublic', join(',', $searchable));
$adminusersearch = array_merge(array_keys(self::get_always_adminusersearchable_fields()), $values['adminusersearch']);
set_config_plugin('artefact', 'internal', 'profileadminusersearch', join(',', $adminusersearch));
}
public static function get_links($id) {
......
......@@ -826,6 +826,14 @@ function auth_check_required_fields() {
if (get_profile_field($USER->get('id'), $field) != null) {
continue;
}
// If profile field saves it's data somewhere different to normal
$classname = 'ArtefactType' . ucfirst($field);
if (is_callable(array($classname, 'defaultoption'))) {
$option = call_static_method($classname, 'defaultoption');
if (!empty($option)) {
continue;
}
}
if ($field == 'email') {
if (isset($elements['email'])) {
......@@ -864,6 +872,14 @@ function auth_check_required_fields() {
$elements[$field]['options'] = getoptions_country();
$elements[$field]['defaultvalue'] = get_config('country');
}
if (is_callable(array($classname, 'getoptions'))) {
$options = call_static_method($classname, 'getoptions');
$elements[$field]['options'] = $options;
}
if (is_callable(array($classname, 'defaultoption'))) {
$defaultoption = call_static_method($classname, 'defaultoption');
$elements[$field]['defaultvalue'] = $defaultoption;
}
if ($field == 'email') {
// Check if a validation email has been sent
......@@ -2127,6 +2143,10 @@ function auth_generate_registration_form($formname, $authname='internal', $goto)
)
);
if (function_exists('local_register_form')) {
local_register_form($elements);
}
$sql = 'SELECT
i.*
FROM
......
......@@ -442,6 +442,7 @@ $string['cannotremovedefaultemail'] = 'You cannot remove your primary email addr
$string['emailtoolong'] = 'Email addresses cannot be longer than 255 characters.';
$string['mustspecifyoldpassword'] = 'You must specify your current password.';
$string['Site'] = 'Site';
$string['maildisabled'] = 'Email disabled';
// Misc. register stuff that could be used elsewhere
$string['profileicon'] = 'Profile image';
......
......@@ -479,6 +479,29 @@ function build_admin_user_search_results($search, $offset, $limit) {
);
}
$customcols = get_config_plugin('artefact', 'internal', 'profileadminusersearch');
if ($customcols) {
$customcolsarray = explode(',', $customcols);
foreach ($customcolsarray as $k => $v) {
if (!array_key_exists($v, $cols)) {
safe_require('artefact', 'internal');
$classname = 'ArtefactType' . ucfirst($v);
$pluginname = get_field('artefact_installed_type', 'plugin', 'name', $v);
$cols[$v] = array(
'name' => ($pluginname) ? get_string($v, 'artefact.' . $pluginname) : get_string($v, 'mahara'),
'sort' => true,
);
// check if this is a local profile icon and has it's own display info
if (is_callable(array($classname, 'usersearch_column_structure'))) {
$out = call_static_method($classname, 'usersearch_column_structure');
$cols[$v] = $out;
}
}
}
}
$cols['authname'] = array(
'name' => get_string('authentication'),
'sort' => true,
......@@ -490,8 +513,6 @@ function build_admin_user_search_results($search, $offset, $limit) {
'template' => 'strftimedatetime.tpl',
);
if (!$USER->get('admin') && !$USER->is_institutional_admin()) {
unset($cols['email']);
if (!get_config('staffreports')) {
......
......@@ -3532,6 +3532,22 @@ class View {
'SELECT ' . $cols . $from . ' WHERE ' . $select . $sortorder, $selectph, $offset, $limit
);
$totalartefacts = count_records_sql('SELECT COUNT(*) ' . $from . ' WHERE ' . $select, $countph);
// If our profile artefact is saving it's data to a special place
if (!empty($data['artefacttypes'])) {
safe_require('artefact', 'internal');
foreach ($data['artefacttypes'] as $type) {
$classname = 'ArtefactType' . ucfirst($type);
if (is_callable(array($classname, 'get_special_data'))) {
$customprofile = call_static_method($classname, 'get_special_data', $user);
if ($customprofile) {
$customprofile->artefacttype = $type;
$customprofile->title = $customprofile->{$type};
$artefacts[] = $customprofile;
$totalartefacts++;
}
}
}
}
return array($artefacts, $totalartefacts);
}
......
......@@ -25,10 +25,10 @@
* - local_logout(): Hook function called during the user logout process immediately before
* $USER->logout()
*
* - local_post_register($registration): Called after a user has successfully been created and
* - local_post_register($registration, $user): Called after a user has successfully been created and
* logged in during registration. This is useful when the properties of the user (which may have
* been saved to usr_registration.extra [see local_register_submit()]) need to be transferred
* to the newly registered user.
* been saved to usr_registration.extra [see local_register_submit()]) need to create the related
* artefacts.
*
* - local_progressbar_sortorder($options): Change the order of items in the profile completion
* progress bar
......@@ -38,6 +38,12 @@
* the logged-out user when the form was submitted. If a $value['extra'] field is added, it will
* be stored to usr_registration.extra.
*
* - local_register_form(&$elements): Add profile elements to the registration form. They can be
* either core profile fields or custom profile fields defined in local/lib/artefact_internal.php
*
* - local register_create(&$user, $registration): Add extra profile element values saved via
* registration form to the user being created after being approved.
*
* - local_right_nav_update(&$menu): Modify the right column navigation menu by reference
*
* - local_sideblocks_update(&$sideblocks): Modify sideblocks column by reference
......
......@@ -128,6 +128,10 @@ if (isset($key)) {
}
}
if (function_exists('local_register_create')) {
local_register_create($user, $registration);
}
create_user($user, $profilefields);
// If the institution is 'mahara' then don't do anything
......@@ -184,7 +188,7 @@ if (isset($key)) {
$USER->reanimate($user->id, $authinstance->id);
if (function_exists('local_post_register')) {
local_post_register($registration);
local_post_register($registration, $user);
}
$SESSION->add_ok_msg(get_string('registrationcomplete', 'mahara', get_config('sitename')));
......
......@@ -419,6 +419,25 @@ class PluginSearchInternal extends PluginSearch {
*/
public static function admin_search_user($query_string, $constraints, $offset, $limit,
$sortfield, $sortdir) {
$firstcols = 'u.id';
$join = '';
$where = 'WHERE u.id <> 0 AND u.deleted = 0';
// Add in info for custom artefact internal columns if the data exists
$customcols = get_config_plugin('artefact', 'internal', 'profileadminusersearch');
if ($customcols) {
$customcolsarray = explode(',', $customcols);
safe_require('artefact', 'internal');
$default = ArtefactTypeProfile::get_always_adminusersearchable_fields();
foreach ($customcolsarray as $k => $v) {
if (!array_key_exists($v, $default)) {
$firstcols .= ', a' . $k . '.title AS ' . $v;
$join .= 'LEFT JOIN {artefact} a' . $k . ' ON (a' . $k . '.owner = u.id AND a' . $k . '.artefacttype = \'' . $v . '\') ';
}
}
}
$sort = 'TRUE';
if (preg_match('/^[a-zA-Z_0-9"]+$/', $sortfield)) {
$sort = $sortfield;
......@@ -429,8 +448,7 @@ class PluginSearchInternal extends PluginSearch {
$sort .= ' DESC';
}
}
$join = '';
$where = 'WHERE u.id <> 0 AND u.deleted = 0';
$values = array();
// Get the correct keyword for case insensitive LIKE
......@@ -458,7 +476,6 @@ class PluginSearchInternal extends PluginSearch {
$values = array_pad($values, count($values) + $valuecount, $term);
}
$firstcols = 'u.id';
if (!empty($constraints)) {
foreach ($constraints as $f) {
switch ($f['field']) {
......@@ -532,14 +549,16 @@ class PluginSearchInternal extends PluginSearch {
$limit);
if ($data) {
$users = array_keys($data);
$inst = get_records_select_array('usr_institution',
'usr IN (' . join(',', array_keys($data)) . ')',
'usr IN (' . join(',', $users) . ')',
null, '', 'usr,institution');
if ($inst) {
foreach ($inst as $i) {
$data[$i->usr]->institutions[] = $i->institution;
}
}
foreach ($data as &$item) {
$item->username = display_username($item);
$item = (array)$item;
......
......@@ -3,6 +3,11 @@
<thead>
<th>{str tag=pendingregistration section=admin}</th>
<th>{str tag=registrationreason section=admin}</th>
{if $extracols}
{foreach from=$extracols key=colkey item=col}
<th>{str tag=$colkey section=mahara}</th>
{/foreach}
{/if}
<th>&nbsp;</th>
</thead>
<tbody>
......@@ -17,6 +22,13 @@
<td class="pendinginfo">
<div class="detail">{$registration->reason}</div>
</td>
{if $extracols}
{foreach from=$extracols key=colkey item=col}
<td>
<div class="detail">{if property_exists($registration->extra, $colkey)}{$registration->extra->$colkey}{/if}</div>
</td>
{/foreach}
{/if}
<td class="">
<div class="btn-group">
<a class="btn btn-default btn-xs" href="{$WWWROOT}admin/users/actionregistration.php?r={$registration->id}&action=approve">
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment