Commit 486b6c9d authored by Gregor Anzelj's avatar Gregor Anzelj Committed by Aaron Wells
Browse files

Profile completeness progress bar (Bug #1259538)



- added ability for file and blogpost items that get updated via js to
also update the proogess bar as well without needing page reload.

-- made the system more pluggable and created a pseudo plugin called
'social' to handle the social progress bar items

Change-Id: I39c83018879b4717667ad32a6aa28cf902e42137
Signed-off-by: default avatarGregor Anzelj <gregor.anzelj@gmail.com>
parent a95b2ae2
......@@ -216,6 +216,13 @@ $siteoptionform = array(
'defaultvalue' => get_config('masqueradingnotified'),
'disabled' => in_array('masqueradingnotified', $OVERRIDDEN),
),
'showprogressbar' => array(
'type' => 'checkbox',
'title' => get_string('showprogressbar', 'admin'),
'description' => get_string('showprogressbardescription', 'admin'),
'defaultvalue' => get_config('showprogressbar'),
'disabled' => in_array('showprogressbar', $OVERRIDDEN),
),
),
),
'searchsettings' => array(
......@@ -740,7 +747,7 @@ function siteoptions_submit(Pieform $form, $values) {
'remoteavatars', 'userscanhiderealnames', 'antispam', 'spamhaus', 'surbl', 'anonymouscomments',
'recaptchaonregisterform', 'recaptchapublickey', 'recaptchaprivatekey', 'loggedinprofileviewaccess', 'disableexternalresources',
'proxyaddress', 'proxyauthmodel', 'proxyauthcredentials', 'smtphosts', 'smtpport', 'smtpuser', 'smtppass', 'smtpsecure',
'noreplyaddress', 'defaultnotificationmethod', 'homepageinfo', 'showonlineuserssideblock', 'onlineuserssideblockmaxusers',
'noreplyaddress', 'defaultnotificationmethod', 'homepageinfo', 'showprogressbar', 'showonlineuserssideblock', 'onlineuserssideblockmaxusers',
'registerterms', 'licensemetadata', 'licenseallowcustom', 'allowmobileuploads', 'creategroups', 'createpublicgroups', 'allowgroupcategories', 'wysiwyg',
'staffreports', 'staffstats', 'userscandisabledevicedetection', 'watchlistnotification_delay',
'masqueradingreasonrequired', 'masqueradingnotified', 'searchuserspublic',
......
<?php
/**
*
* @package mahara
* @subpackge admin
* @author Gregor Anzelj
* @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.
* @copyright (C) 2013 Gregor Anzelj <gregor.anzelj@gmail.com>
*
*/
define('INTERNAL', 1);
define('INSTITUTIONALADMIN', 1);
define('MENUITEM', 'manageinstitutions/progressbar');
define('SECTION_PLUGINTYPE', 'core');
define('SECTION_PLUGINNAME', 'admin');
define('SECTION_PAGE', 'progressbar');
require(dirname(dirname(dirname(__FILE__))).'/init.php');
require_once('pieforms/pieform.php');
require_once('institution.php');
define('TITLE', get_string('progressbar', 'admin'));
define('DEFAULTPAGE', 'home');
if (!is_logged_in()) {
throw new AccessDeniedException();
}
$institutionelement = get_institution_selector(true, false, true, false);
if (empty($institutionelement)) {
$smarty = smarty();
$smarty->display('admin/users/noinstitutions.tpl');
exit;
}
$institution = param_alphanum('institution', false);
if (!$institution || !$USER->can_edit_institution($institution, true)) {
$institution = empty($institutionelement['value']) ? $institutionelement['defaultvalue'] : $institutionelement['value'];
}
else if (!empty($institution)) {
$institutionelement['defaultvalue'] = $institution;
}
$institutionselector = pieform(array(
'name' => 'progressbarselect',
'elements' => array(
'institution' => $institutionelement,
)
));
// Selected artefacts that count towards completing progress bar
if ($data = get_field('institution_data', 'value', 'institution', $institution, 'type', 'progressbar')) {
$selected = unserialize($data);
}
else {
$selected = array();
}
// Locked artefacts (site locked and institution locked)
$sitelocked = (array) get_column('institution_locked_profile_field', 'profilefield', 'name', 'mahara');
$instlocked = (array) get_column('institution_locked_profile_field', 'profilefield', 'name', $institution);
$locked = array_merge($sitelocked, $instlocked);
function build_artefact_options($name, $values) {
global $locked;
if (is_null($name)) {
throw new InvalidArgumentException("Artefact category is expected, but not defined.");
}
else {
// Select all possible artefacts for progressbar except for those artefactst
// that wish to opt out. Also include special case options.
$records = PluginArtefact::get_progressbar_options($name);
$elements = array();
foreach ($records as $artefact) {
if ($artefact->iscountable) {
$options = array(
0 => '0',
1 => '1',
2 => '2',
3 => '3',
4 => '4',
5 => '5',
10 => '10',
15 => '15',
20 => '20',
25 => '25',
50 => '50',
100 => '100',
);
$elements[$artefact->name] = array(
'type' => 'select',
'title' => $artefact->title,
'disabled' => ($artefact->active && !in_array($artefact->name, $locked) ? false : true),
'defaultvalue' => (array_key_exists($artefact->name, $values) && isset($values[$artefact->name])
&& !in_array($artefact->name, $locked) ? $values[$artefact->name] : null),
'options' => $options
);
}
else {
$elements[$artefact->name] = array(
'type' => 'checkbox',
'title' => $artefact->title,
'disabled' => ($artefact->active && !in_array($artefact->name, $locked) ? false : true),
'defaultvalue' => (array_key_exists($artefact->name, $values) && isset($values[$artefact->name])
&& !in_array($artefact->name, $locked) ? $values[$artefact->name] : null),
);
if (in_array($artefact->name, array('email'))) {
$elements[$artefact->name]['defaultvalue'] = 1;
$elements[$artefact->name]['readonly'] = 1;
}
}
}
return $elements;
}
}
$form = pieform(array(
'name' => 'progressbarform',
'renderer' => 'table',
'plugintype' => 'core',
'pluginname' => 'admin',
'elements' => array(
'fsinternal' => array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => true,
'legend' => get_string('profile', 'artefact.internal'),
'elements' => build_artefact_options('internal', $selected)
),
'fsresume' => array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => true,
'legend' => get_string('resume', 'artefact.resume'),
'elements' => build_artefact_options('resume', $selected)
),
'fsplans' => array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => true,
'legend' => get_string('plan', 'artefact.plans'),
'elements' => build_artefact_options('plans', $selected)
),
'fsblog' => array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => true,
'legend' => get_string('blog', 'artefact.blog'),
'elements' => build_artefact_options('blog', $selected)
),
'fsfile' => array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => true,
'legend' => get_string('file', 'artefact.file'),
'elements' => build_artefact_options('file', $selected)
),
'fssocial' => array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => true,
'legend' => get_string('Social', 'artefact.social'),
'elements' => build_artefact_options('social', $selected)
),
'institution' => array(
'type' => 'hidden',
'value' => $institution,
),
'submit' => array(
'type' => 'submit',
'value' => get_string('submit')
),
)
));
function progressbarform_submit(Pieform $form, $values) {
global $SESSION, $USER;
$inst = $values['institution'];
if (empty($inst) || !$USER->can_edit_institution($inst)) {
$SESSION->add_error_msg(get_string('notadminforinstitution', 'admin'));
redirect('/admin/users/progressbar.php');
}
unset($values['submit']);
unset($values['sesskey']);
unset($values['institution']);
$where = (object) array(
'institution' => $inst,
'type' => 'progressbar',
);
$data = (object) array(
'ctime' => db_format_timestamp(time()),
'institution' => $inst,
'type' => 'progressbar',
'value' => serialize($values)
);
ensure_record_exists('institution_data', $where, $data);
$SESSION->add_ok_msg(get_string('progressbarsaved', 'admin'));
redirect('/admin/users/progressbar.php?institution=' . $inst);
}
$wwwroot = get_config('wwwroot');
$js = <<< EOF
function reloadBar() {
window.location.href = '{$wwwroot}admin/users/progressbar.php?institution='+$('progressbarselect_institution').value;
}
addLoadEvent(function() {
connect($('progressbarselect_institution'), 'onchange', reloadBar);
});
EOF;
$smarty = smarty();
$smarty->assign('progressbarform', $form);
$smarty->assign('institution', $institution);
$smarty->assign('institutionselector', $institutionselector);
$smarty->assign('enabled', get_config('showprogressbar'));
$smarty->assign('INLINEJAVASCRIPT', $js);
$smarty->assign('PAGEHEADING', TITLE);
$smarty->display('admin/users/progressbar.tpl');
......@@ -152,3 +152,9 @@ $string['duplicatedblog'] = 'Duplicated journal';
$string['existingblogs'] = 'Existing journals';
$string['duplicatedpost'] = 'Duplicated journal entry';
$string['existingposts'] = 'Existing journal entries';
$string['progress_blog'] = 'Add a journal';
$string['progress_blogpost'] = array(
'Add 1 entry to a journal',
'Add %s entries to a journal',
);
......@@ -105,6 +105,10 @@ class PluginArtefactBlog extends PluginArtefact {
'blogpost' => array('text'),
);
}
public static function progressbar_link() {
return 'artefact/blog/view/index.php';
}
}
/**
......@@ -1039,4 +1043,8 @@ class ArtefactTypeBlogPost extends ArtefactType {
public function get_referenced_artefacts_from_postbody() {
return artefact_get_references_in_html($this->get('description'));
}
public static function is_countable_progressbar() {
return true;
}
}
......@@ -86,6 +86,7 @@ function delete_success(form, data) {
}
addElementClass('postdescription_' + data.id, 'hidden');
addElementClass('posttitle_' + data.id, 'hidden');
progressbarUpdate('blogpost', true);
}
EOF;
......
......@@ -16,6 +16,7 @@ function FileBrowser(idprefix, folderid, config, globalconfig) {
this.config.sesskey = globalconfig.sesskey;
this.config.theme = globalconfig.theme;
this.nextupload = 0;
this.createfolder_is_connected = false;
this.init = function () {
self.form = getFirstParentByTagAndClassName(self.id + '_filelist_container', 'form', 'pieform');
......@@ -184,6 +185,7 @@ function FileBrowser(idprefix, folderid, config, globalconfig) {
replaceChildNodes(self.id + '_createfolder_messages', makeMessage(message, 'error'));
return false;
}
progressbarUpdate('folder');
}
this.edit_submit = function (e) {
......@@ -224,6 +226,10 @@ function FileBrowser(idprefix, folderid, config, globalconfig) {
}
quotaUpdate(data.quotaused, data.quota);
if (data.returnCode == '0') {
// pass the artefacttype to update progress bar
progressbarUpdate(data.artefacttype, data.deleted);
}
var newmessage = makeMessage(DIV(null,' ', data.message), infoclass);
setNodeAttribute(newmessage, 'id', 'uploadstatusline' + data.uploadnumber);
if (data.uploadnumber) {
......@@ -457,8 +463,9 @@ function FileBrowser(idprefix, folderid, config, globalconfig) {
return false;
});
});
if ($(self.id + '_createfolder')) {
if ($(self.id + '_createfolder') && !self.createfolder_is_connected) {
connect($(self.id + '_createfolder'), 'onclick', self.createfolder_submit);
self.createfolder_is_connected = true;
}
if (self.config.select) {
self.connect_select_buttons();
......
......@@ -71,6 +71,7 @@ $string['Description'] = 'Description';
$string['destination'] = 'Destination';
$string['Details'] = 'Details';
$string['View'] = 'View';
$string['document'] = 'Document';
$string['Download'] = 'Download';
$string['downloadfile'] = 'Download %s';
$string['downloadoriginalversion'] = 'Download the original version';
......@@ -306,3 +307,32 @@ $string['folderdownloadnofolderfound'] = 'Unable to find the folder with ID %d';
$string['zipfilenameprefix'] = 'folder';
$string['keepzipfor'] = 'Length of time to keep zip files';
$string['keepzipfordescription'] = 'Zip files created during the downloading of folders should be kept for this amount of time (in seconds).';
$string['progress_archive'] = array(
'Add 1 archive file',
'Add %s archive files',
);
$string['progress_audio'] = array(
'Add 1 audio file',
'Add %s audio files',
);
$string['progress_file'] = array(
'Add 1 file',
'Add %s files',
);
$string['progress_folder'] = array(
'Add 1 folder',
'Add %s folders',
);
$string['progress_image'] = array(
'Add 1 image',
'Add %s images',
);
$string['progress_profileicon'] = array(
'Add 1 profile picture',
'Add %s profile pictures',
);
$string['progress_video'] = array(
'Add 1 video',
'Add %s videos',
);
......@@ -290,6 +290,16 @@ class PluginArtefactFile extends PluginArtefact {
}
return array();
}
public static function progressbar_link($artefacttype) {
switch ($artefacttype) {
case 'profileicon':
return 'artefact/file/profileicons.php';
break;
default:
return 'artefact/file/index.php';
}
}
}
abstract class ArtefactTypeFileBase extends ArtefactType {
......@@ -1642,6 +1652,13 @@ class ArtefactTypeFile extends ArtefactTypeFileBase {
return (bool) $this->get('group');
}
public static function is_countable_progressbar() {
return true;
}
public static function get_title_progressbar() {
return get_string('document','artefact.file');
}
}
class ArtefactTypeFolder extends ArtefactTypeFileBase {
......@@ -1891,6 +1908,9 @@ class ArtefactTypeFolder extends ArtefactTypeFileBase {
}
}
public static function is_countable_progressbar() {
return true;
}
}
class ArtefactTypeImage extends ArtefactTypeFile {
......@@ -2016,6 +2036,10 @@ class ArtefactTypeImage extends ArtefactTypeFile {
. '" alt=""></a></div>' . $result['html'];
return $result;
}
public static function get_title_progressbar() {
return get_string('image','artefact.file');
}
}
class ArtefactTypeProfileIcon extends ArtefactTypeImage {
......@@ -2073,6 +2097,9 @@ class ArtefactTypeProfileIcon extends ArtefactTypeImage {
return null;
}
public static function get_title_progressbar() {
return get_string('profileicon','artefact.file');
}
}
class ArtefactTypeArchive extends ArtefactTypeFile {
......@@ -2404,6 +2431,9 @@ class ArtefactTypeArchive extends ArtefactTypeFile {
return $this->data;
}
public static function get_title_progressbar() {
return get_string('archive','artefact.file');
}
}
class ArtefactTypeVideo extends ArtefactTypeFile {
......@@ -2462,6 +2492,9 @@ class ArtefactTypeVideo extends ArtefactTypeFile {
return $THEME->get_url('images/video.png');
}
public static function get_title_progressbar() {
return get_string('video','artefact.file');
}
}
class ArtefactTypeAudio extends ArtefactTypeFile {
......@@ -2508,4 +2541,8 @@ class ArtefactTypeAudio extends ArtefactTypeFile {
global $THEME;
return $THEME->get_url('images/audio.png');
}
public static function get_title_progressbar() {
return ucfirst(get_string('audio','artefact.file'));
}
}
......@@ -129,3 +129,24 @@ $string['noteupdated'] = 'Note updated';
$string['html'] = 'Note';
$string['duplicatedprofilefieldvalue'] = 'Duplicated value';
$string['existingprofilefieldvalues'] = 'Existing values';
$string['progress_firstname'] = 'Add your first name';
$string['progress_lastname'] = 'Add your last name';
$string['progress_studentid'] = 'Add your student ID';
$string['progress_preferredname'] = 'Add a display name';
$string['progress_introduction'] = 'Add an introduction about yourself';
$string['progress_email'] = 'Add an email address';
$string['progress_officialwebsite'] = 'Add an official website';
$string['progress_personalwebsite'] = 'Add your personal website';
$string['progress_blogaddress'] = 'Add your blog address';
$string['progress_address'] = 'Add your postal address';
$string['progress_town'] = 'Add a town';
$string['progress_city'] = 'Add a city/region';
$string['progress_country'] = 'Add a country';
$string['progress_homenumber'] = 'Add your home phone';
$string['progress_businessnumber'] = 'Add your business phone';
$string['progress_mobilenumber'] = 'Add your mobile phone';
$string['progress_faxnumber'] = 'Add your fax number';
$string['progress_messaging'] = 'Add messaging information';
$string['progress_occupation'] = 'Add your occupation';
$string['progress_industry'] = 'Add your industry';
\ No newline at end of file
......@@ -279,6 +279,82 @@ class PluginArtefactInternal extends PluginArtefact {
return $bi;
}
public static function progressbar_additional_items() {
$specials = array('messaging');
$records = false;
foreach ($specials as $special) {
$record = new StdClass();
$record->name = $special;
$record->title = get_string($special, 'artefact.internal');
$record->plugin = 'internal';
$record->active = true;
$record->iscountable = false;
$record->is_metaartefact = true;
$records[] = $record;
}
return $records;
}
public static function progressbar_metaartefact_count($plugin) {
global $USER;
if (!$plugin->is_metaartefact) {
return false;
}
$meta = new StdClass();
$meta->artefacttype = $plugin->name;
$meta->completed = 0;
switch ($plugin->name) {
case 'messaging':
// Add messaging group data and
// use user's entered values of individual messaging artefacts
$sql = "SELECT COUNT(*) AS completed FROM {artefact}
WHERE owner = ? AND artefacttype IN
('aimscreenname', 'icqnumber', 'jabberusername',
'msnnumber', 'skypeusername', 'yahoochat')";
$count = get_records_sql_array($sql, array($USER->get('id')));
$meta->completed = $count[0]->completed;
break;
}
return $meta;
}
public static function progressbar_link($artefacttype) {
switch ($artefacttype) {
case 'firstname':
case 'lastname':
case 'studentid':
case 'preferredname':
case 'introduction':
return 'artefact/internal/index.php';
break;
case 'email':
case 'officialwebsite':
case 'personalwebsite':
case 'blogaddress':
case 'address':
case 'town':
case 'city':
case 'country':
case 'homenumber':
case 'businessnumber':
case 'mobilenumber':
case 'faxnumber':
return 'artefact/internal/index.php?fs=contact';
break;
case 'messaging':
return 'artefact/internal/index.php?fs=messaging';
break;
case 'occupation':
case 'industry':
return 'artefact/internal/index.php?fs=general';
break;
default:
return 'view/index.php';
}
}
}
class ArtefactTypeProfile extends ArtefactType {
......@@ -690,12 +766,42 @@ class ArtefactTypeHomenumber extends ArtefactTypeProfileField {}
class ArtefactTypeBusinessnumber extends ArtefactTypeProfileField {}
class ArtefactTypeMobilenumber extends ArtefactTypeProfileField {}
class ArtefactTypeFaxnumber extends ArtefactTypeProfileField {}
class ArtefactTypeIcqnumber extends ArtefactTypeProfileField {}
class ArtefactTypeMsnnumber extends ArtefactTypeProfileField {}
class ArtefactTypeAimscreenname extends ArtefactTypeProfileField {}
class ArtefactTypeYahoochat extends ArtefactTypeProfileField {}
class ArtefactTypeSkypeusername extends ArtefactTypeProfileField {}
class ArtefactTypeJabberusername extends ArtefactTypeProfileField {}
class ArtefactTypeIcqnumber extends ArtefactTypeProfileField {
public static function is_allowed_in_progressbar() {
return false;
}
}
class ArtefactTypeMsnnumber extends ArtefactTypeProfileField {
public static function is_allowed_in_progressbar() {
return false;
}
}
class ArtefactTypeAimscreenname extends ArtefactTypeProfileField {
public static function is_allowed_in_progressbar() {
return false;
}
}
class ArtefactTypeYahoochat extends ArtefactTypeProfileField {