. * * @package mahara * @subpackage blocktype-openbadgedisplayer * @author Discendum Oy * @license http://www.gnu.org/copyleft/gpl.html GNU GPL * @copyright (C) 2012 Discedum Oy http://discendum.com * @copyright (C) 2011 Catalyst IT Ltd http://catalyst.net.nz * */ defined('INTERNAL') || die(); class PluginBlocktypeOpenbadgedisplayer extends SystemBlocktype { private static $source = null; public static function single_only() { return false; } public static function get_title() { return get_string('title', 'blocktype.openbadgedisplayer'); } public static function get_description() { return get_string('description', 'blocktype.openbadgedisplayer'); } public static function get_categories() { return array('external'); } public static function get_css_icon() { return 'shield'; } public static function get_viewtypes() { return array('portfolio', 'profile'); } public static function get_backpack_source() { if (is_null(self::$source)) { $source = get_config('openbadgedisplayer_source'); if (!empty($source)) { $source = (array) $source; } else { return false; } self::$source = $source; } return self::$source; } public static function render_instance(BlockInstance $instance, $editing=false) { $configdata = $instance->get('configdata'); if (empty($configdata) || !isset($configdata['badgegroup']) || !get_config('openbadgedisplayer_source')) { return; } $host = 'backpack'; $badgegroups = $configdata['badgegroup']; $html = ''; // Support the legacy format (a string, not an array). if (is_string($badgegroups)) { $badgegroups = array($badgegroups); } if ($editing) { $items = array(); foreach ($badgegroups as $selectedbadgegroup) { list($host, $uid, $selectedgroupid) = explode(':', $selectedbadgegroup); $allbadgegroups = self::get_badgegroupnames($host, $uid); if (!empty($allbadgegroups)) { foreach ($allbadgegroups as $badgegroupid => $name) { if ((int) $selectedgroupid === (int) $badgegroupid) { $items[] = $name; } } } } if (count($items) > 0) { $html .= ''; } else { $html .= get_string('nobadgegroups', 'blocktype.openbadgedisplayer'); } return $html; } else { $smarty = smarty_core(); $smarty->left_delimiter = '{{'; $smarty->right_delimiter = '}}'; $smarty->assign('id', $instance->get('id')); $smarty->assign('badgehtml', self::get_badges_html($badgegroups)); $html = $smarty->fetch('blocktype:openbadgedisplayer:openbadgedisplayer.tpl'); } return $html; } /** * Returns html code for badge in a group * @param string $group in format :: * @param bool $fromcache if true the info will be fetched from database first * @return string HTML code */ private static function get_badge_html($group, $fromcache=false) { if (!isset($group) && !is_string($group)) { return ''; } $parts = explode(':', $group); if (count($parts) < 3) { return ''; } $host = $parts[0]; $uid = $parts[1]; $badgegroupid = $parts[2]; // Try to get the badge html from database first // Get badge group html using uid (backpackid) if ($fromcache && $badgegroup = get_record_select('blocktype_openbadgedisplayer_data', 'host = ? AND uid = ? AND badgegroupid = ? AND lastupdate > ?', array($host, $uid, $badgegroupid, db_format_timestamp(strtotime('-1 day'))), 'html')) { if (isset($badgegroup->html)) { return $badgegroup->html; } } $html = ''; $existing = array(); $backpack_url = self::get_backpack_url($host); $url = $backpack_url . 'displayer/' . $uid . '/group/' . $badgegroupid . '.json'; $res = mahara_http_request(array(CURLOPT_URL => $url)); if ($res->info['http_code'] != 200) { return ''; } $json = json_decode($res->data); if (isset($json->badges) && is_array($json->badges)) { foreach ($json->badges as $badge) { $b = $badge->assertion->badge; // TODO: Simple check for unique badges, improve me! if (array_key_exists($b->name, $existing) && strcmp($existing[$b->name], $b->description) === 0) { continue; } if (self::assertion_has_expired($badge->assertion)) { continue; } $html .= ''; $existing[$b->name] = $b->description; } } // Caching badge info into database for better performance if ($fromcache) { ensure_record_exists('blocktype_openbadgedisplayer_data', (object) array( 'host' => $host, 'uid' => $uid, 'badgegroupid' => $badgegroupid, ), (object) array( 'host' => $host, 'uid' => $uid, 'badgegroupid' => $badgegroupid, 'html' => $html, 'lastupdate' => db_format_timestamp(time()) ) ); } return $html; } private static function get_badges_html($groups) { $html = ''; foreach ($groups as $group) { $html .= self::get_badge_html($group); } if (empty($html)) { $html = get_string('nobadgegroups', 'blocktype.openbadgedisplayer'); } return $html; } private static function assertion_has_expired($assertion) { if (!isset($assertion->expires)) { return false; } // Unix timestamp if (preg_match('/^[0-9]+$/', $assertion->expires)) { return ($assertion->expires * 1000) < time(); } // Formatted date return strtotime($assertion->expires) < time(); } public static function has_instance_config() { return true; } public static function instance_config_form($instance) { global $USER; $sources = self::get_backpack_source(); if ($sources === false) { $fields = array( 'message' => array( 'type' => 'html', 'class' => '', 'value' => '' ), ); return $fields; } $configdata = $instance->get('configdata'); $addresses = get_column('artefact_internal_profile_email', 'email', 'owner', $USER->id, 'verified', 1); $current_values = array(); if (isset($configdata['badgegroup'])) { $current_values = $configdata['badgegroup']; // Support the legacy format (a string, not an array). if (is_string($current_values)) { $current_values = array($current_values); } foreach ($current_values as &$current_value) { if (substr_count($current_value, ':') == 1) { // Legacy value, prepend host $current_value = 'backpack:' . $current_value; } } } $sourcelinks = array(); foreach ($sources as $source => $url) { if (!empty($url)) { $title = get_string('title_' . $source, 'blocktype.openbadgedisplayer'); $sourcelinks[] = '' . $title . ''; } } $fields = array( 'message' => array( 'type' => 'html', 'class' => '', 'value' => '

'. get_string('confighelp', 'blocktype.openbadgedisplayer', implode(', ', $sourcelinks)) .'

' ), 'badgegroups' => array( 'type' => 'container', 'class' => '', 'elements' => array( 'loadinginfo' => array( 'type' => 'html', 'class' => '', 'value' => '

'. get_string('fetchingbadges', 'blocktype.openbadgedisplayer') .'

' . '
', ), 'hosts' => array( 'type' => 'hidden', 'value' => json_encode(array_keys($sources)), ), 'emails' => array( 'type' => 'hidden', 'value' => json_encode($addresses), ), 'selectedbadgegroups' => array( 'type' => 'hidden', 'value' => json_encode($current_values), ), ) ) ); return $fields; } public static function get_instance_config_javascript(BlockInstance $instance) { return array( 'js/configform.js', ); } private static function get_form_fields($host, $addresses) { if ( ! $host) { return array(); } $backpackid = array(); foreach ($addresses AS $email) { $backpackid[] = self::get_backpack_id($host, $email); } $backpackid = array_filter($backpackid); $opt = array(); foreach ($backpackid AS $uid) { $opt += self::get_group_opt($host, $uid); } return $opt; } public static function get_backpack_id($host, $email) { static $backpackids = array(); $backpack_url = self::get_backpack_url($host); if (isset($backpackids[$host][$email])) { return $backpackids[$host][$email]; } if ($backpack_url !== false) { $res = mahara_http_request( array( CURLOPT_URL => $backpack_url . 'displayer/convert/email', CURLOPT_POST => 1, CURLOPT_POSTFIELDS => 'email=' . urlencode($email) ) ); $res = json_decode($res->data); if (isset($res->userId)) { $backpackids[$host][$email] = $res->userId; return $res->userId; } } return null; } /** * Returns all backpack IDs of current logged-in user * * @return array of backpack IDs: * array( * => array ( * => * ) * ) */ public static function get_user_backpack_ids() { global $USER; if (!$USER->is_logged_in()) { return array(); } $sources = self::get_backpack_source(); $addresses = get_column('artefact_internal_profile_email', 'email', 'owner', $USER->get('id'), 'verified', 1); $userbackpackids = array(); if (!empty($sources) && !empty($addresses)) { foreach ($sources as $h => $url) { $userbackpackids[$h] = array(); foreach ($addresses as $e) { $userbackpackids[$h][$e] = self::get_backpack_id($h, $e); } } } return $userbackpackids; } /** * Return name of badge groups for a given host and backpackid * @param $host * @param $uid backpack ID attached to an email on the host * @param $usedbcache if true, the badge groups will be fetched from database first * @return array * => * ) */ public static function get_badgegroupnames($host, $uid, $usedbcache=false) { static $badgegroupnames = array(); if (!isset($host) || !isset($uid)) { return array(); } if (isset($badgegroupnames[$host][$uid])) { return $badgegroupnames[$host][$uid]; } // Get badge group names using uid (backpackid) from database if ($usedbcache && $badgegroups = get_records_select_array('blocktype_openbadgedisplayer_data', 'host = ? AND uid = ? AND lastupdate > ?', array($host, $uid, db_format_timestamp(strtotime('-1 day'))), '', 'badgegroupid, name')) { foreach ($badgegroups as $badgegroup) { $badgegroupnames[$host][$uid][$badgegroup->badgegroupid] = $badgegroup->name; } return $badgegroupnames[$host][$uid]; } $badgegroupnames[$host][$uid] = array(); $backpack_url = self::get_backpack_url($host); $res = mahara_http_request(array(CURLOPT_URL => $backpack_url . "displayer/{$uid}/groups.json")); $res = json_decode($res->data); if (!empty($res->groups)) { foreach ($res->groups AS $g) { if ($g->name == 'Public badges' && $g->groupId == 0) { $name = get_string('obppublicbadges', 'blocktype.openbadgedisplayer'); } else { $name = hsc($g->name); } $name .= ' (' . get_string('nbadges', 'blocktype.openbadgedisplayer', $g->badges) . ')'; $badgegroupnames[$host][$uid][$g->groupId] = $name; // Caching badge info into database for better performance ensure_record_exists('blocktype_openbadgedisplayer_data', (object) array( 'host' => $host, 'uid' => $uid, 'badgegroupid' => $g->groupId, ), (object) array( 'host' => $host, 'uid' => $uid, 'badgegroupid' => $g->groupId, 'name' => $name, 'lastupdate' => db_format_timestamp(time()) ) ); } } return $badgegroupnames[$host][$uid]; } private static function get_group_opt($host, $uid) { $opt = array(); $backpack_url = self::get_backpack_url($host); $res = mahara_http_request(array(CURLOPT_URL => $backpack_url . "displayer/{$uid}/groups.json")); $res = json_decode($res->data); if (!empty($res->groups)) { foreach ($res->groups AS $g) { if ($g->name == 'Public badges' && $g->groupId == 0) { $name = get_string('obppublicbadges', 'blocktype.openbadgedisplayer'); } else { $name = hsc($g->name); } $name .= ' (' . get_string('nbadges', 'blocktype.openbadgedisplayer', $g->badges) . ')'; $cb_id = $host . ':' . $uid . ':' . $g->groupId; $cb_name = self::_sanitize_name($cb_id); $opt[$cb_name] = array( 'type' => 'checkbox', 'title' => $name, 'value' => $cb_id ); } } return $opt; } public static function get_backpack_url($host) { $sources = self::get_backpack_source(); return isset($sources[$host]) ? $sources[$host] : false; } public static function _sanitize_name($name) { return preg_replace('/[^a-zA-Z0-9_]/', '_', $name); } public static function instance_config_save($values) { unset($values['message']); // Support old save format. $sources = array_keys(self::get_backpack_source()); $values['badgegroup'] = array(); $validbackpackids = self::get_user_backpack_ids(); foreach ($sources as $source) { if (isset($values[$source])) { $values['badgegroup'] = array_merge($values['badgegroup'], $values[$source]); unset($values[$source]); } else if (isset($_POST[$source])) { $values['badgegroup'] = array_merge($values['badgegroup'], $_POST[$source]); } } // check that what has been entered is allowed if (!empty($values['badgegroup'])) { foreach ($values['badgegroup'] as $key => $badgegroup) { list($host, $uid, $group) = explode(':', $badgegroup); if (!isset($uid) || !in_array($uid, array_values($validbackpackids[$host]))) { unset($values['badgegroup'][$key]); } } } return $values; } public static function default_copy_type() { return 'shallow'; } public static function allowed_in_view(View $view) { return $view->get('owner') != null; } public static function get_instance_javascript() { return array('js/showdetails.js'); } public static function should_ajaxify() { return true; } }