Commit fc895105 authored by Gregor Anzelj's avatar Gregor Anzelj Committed by Robert Lyon

Adding user's social profile addresses feature (Bug #605749)

- Added ability to self import and import via admin the socialprofile
fields, whether the leap2a file is made with this patch or with older
mahara

- Note: the msn messaging profile will not import into the new system
as it is obsolete

Change-Id: I858acc6c71af61c689e6760991dc00f983b913ac
Signed-off-by: default avatarGregor Anzelj <gregor.anzelj@gmail.com>
parent 3dde054e
......@@ -25,7 +25,10 @@ ini_set('auto_detect_line_endings', 1);
$FORMAT = array();
$specialcases = array('username', 'password', 'remoteuser');
// Don't upload social profiles for now. A user can have multiple profiles. Not sure how to put that in a csv.
$notallowed = array('socialprofile');
$ALLOWEDKEYS = array_keys(ArtefactTypeProfile::get_all_fields());
$ALLOWEDKEYS = array_diff($ALLOWEDKEYS, $notallowed);
$maildisabled = array_search('maildisabled', $ALLOWEDKEYS);
unset($ALLOWEDKEYS[$maildisabled]);
$ALLOWEDKEYS = array_merge($ALLOWEDKEYS, $specialcases);
......
$j('#instconf_socialprofile_container input[type="radio"][value="0"]').click(function() {
$j('#instconf_socialprofileids_header').addClass('hidden');
$j('#instconf_socialprofileids_container').addClass('hidden');
});
$j('#instconf_socialprofile_container input[type="radio"][value="1"]').click(function() {
$j('#instconf_socialprofileids_header').removeClass('hidden');
$j('#instconf_socialprofileids_container').removeClass('hidden');
});
......@@ -21,3 +21,6 @@ $string['useintroductioninstead'] = 'You can use your introduction profile field
$string['dontshowprofileicon'] = "Don't show a profile picture";
$string['dontshowemail'] = "Don't show email address";
$string['uploadaprofileicon'] = "You have no profile pictures. <a href=\"%sartefact/file/profileicons.php\" target=\"_blank\">Upload one</a>.";
$string['dontshowsocialprofiles'] = "Don't show social profiles";
$string['showsocialprofiles'] = "Show selected social profiles";
......@@ -25,12 +25,17 @@ class PluginBlocktypeProfileinfo extends PluginBlocktype {
return array('internal');
}
public static function get_instance_config_javascript() {
return array('js/configform.js');
}
public static function render_instance(BlockInstance $instance, $editing=false) {
require_once(get_config('docroot') . 'artefact/lib.php');
$smarty = smarty_core();
$configdata = $instance->get('configdata');
$data = array();
$data['socialprofiles'] = array();
// add in the selected email address
if (!empty($configdata['email'])) {
......@@ -46,7 +51,22 @@ class PluginBlocktypeProfileinfo extends PluginBlocktype {
$artefact = artefact_instance_from_id($id);
if (is_a($artefact, 'ArtefactTypeProfile') && $artefact->get('owner') == $viewowner) {
$rendered = $artefact->render_self(array('link' => true));
$data[$artefact->get('artefacttype')] = $rendered['html'];
$artefacttype = $artefact->get('artefacttype');
if ($artefacttype == 'socialprofile') {
if (get_record('blocktype_installed', 'active', 1, 'name', 'socialprofile', 'artefactplugin', 'internal')) {
$data['socialprofiles'][] = array(
'link' => ArtefactTypeSocialprofile::get_profile_link(
$artefact->get('title'),
$artefact->get('note')),
'title' => $artefact->get('title'),
'description' => $artefact->get('description'),
'note' => $artefact->get('note'),
);
}
}
else {
$data[$artefacttype] = $rendered['html'];
}
}
}
catch (ArtefactNotFoundException $e) {
......@@ -56,6 +76,12 @@ class PluginBlocktypeProfileinfo extends PluginBlocktype {
log_debug($e->getMessage());
}
}
// Sort social profiles alphabetically (in ASC order)
$description = array();
foreach ($data['socialprofiles'] as $key => $row) {
$description[$key] = $row['description'];
}
array_multisort($description, SORT_ASC, $data['socialprofiles']);
}
// Work out the path to the thumbnail for the profile image
......@@ -160,7 +186,6 @@ class PluginBlocktypeProfileinfo extends PluginBlocktype {
);
}
$form['email'] = array(
'type' => 'radio',
'title' => get_string('email', 'artefact.internal'),
......@@ -185,6 +210,11 @@ class PluginBlocktypeProfileinfo extends PluginBlocktype {
public static function artefactchooser_element($default=null) {
safe_require('artefact', 'internal');
$artefacttypes = array_diff(PluginArtefactInternal::get_profile_artefact_types(), array('email'));
if (!get_record('blocktype_installed', 'active', 1, 'name', 'socialprofile')) {
$artefacttypes = array_diff($artefacttypes, array('socialprofile'));
}
return array(
'name' => 'artefactids',
'type' => 'artefactchooser',
......@@ -194,7 +224,7 @@ class PluginBlocktypeProfileinfo extends PluginBlocktype {
'limit' => 655360, // 640K profile fields is enough for anyone!
'selectone' => false,
'search' => false,
'artefacttypes' => array_diff(PluginArtefactInternal::get_profile_artefact_types(), array('email')),
'artefacttypes' => $artefacttypes,
'template' => 'artefact:internal:artefactchooser-element.tpl',
);
}
......@@ -212,6 +242,9 @@ class PluginBlocktypeProfileinfo extends PluginBlocktype {
safe_require('artefact', 'internal');
if ($view->get('owner') !== null) {
$artefacttypes = array_diff(PluginArtefactInternal::get_profile_artefact_types(), array('email'));
if (!get_record('blocktype_installed', 'active', 1, 'name', 'socialprofile')) {
$artefacttypes = array_diff($artefacttypes, array('socialprofile'));
}
$artefactids = get_column_sql('
SELECT a.id FROM {artefact} a
WHERE a.owner = ? AND a.artefacttype IN (' . join(',', array_map('db_quote', $artefacttypes)) . ')', array($view->get('owner')));
......
{if $profileiconpath}<div class="fr"><img src="{$profileiconpath}" alt="{$profileiconalt}"></div>{/if}
<p>{$profileinfo.introduction|clean_html|safe}</p>
{if $profileinfo && (count($profileinfo) != 1 || !$profileinfo.introduction)}<ul>
{foreach from=$profileinfo key=key item=item}
{if !in_array($key, array('introduction'))} <li><strong>{str tag=$key section=artefact.internal}:</strong> {$item|clean_html|safe}</li>
{if $profileinfo && (count($profileinfo) != 1 || !$profileinfo.introduction || !$profileinfo.socialprofiles)}
<ul>
{foreach from=$profileinfo key=key item=item}
{if !in_array($key, array('introduction', 'socialprofiles'))}
<li><strong>{str tag=$key section=artefact.internal}:</strong> {$item|clean_html|safe}</li>
{/if}
{/foreach}
</ul>
{/if}
{/foreach}
</ul>{/if}
{if $profileinfo.socialprofiles}
<h4>{str tag=socialprofiles section=artefact.internal}</h4>
<ul>
{foreach from=$profileinfo.socialprofiles item=item}
<li><strong>{$item.description}:</strong>
<a href="{$item.link}" title="{$item.link}" target="_blank">{$item.title|clean_html|safe}</a>
</li>
{/foreach}
</ul>
{/if}
{if $profileiconpath}<div class="cb"></div>{/if}
<?php
/**
*
* @package mahara
* @subpackage blocktype-socialprofile
* @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) 2014 Gregor Anzelj <gregor.anzelj@gmail.com>
*
*/
defined('INTERNAL') || die();
$string['title'] = 'Social profile';
$string['description'] = 'Choose social profile URLs to display';
$string['profilestoshow'] = 'Social profiles to show';
$string['displaysettings'] = 'Display settings';
$string['displayaddressesas'] = 'Display social profile adresses as:';
$string['optionicononly'] = 'buttons with icons only';
$string['optiontexticon'] = 'buttons with icons and text';
$string['optiontextonly'] = 'buttons with text only';
$string['displaydefaultemail'] = 'Display default email link as button?';
$string['displaymsgservices'] = 'Display messaging services as buttons?';
<?php
/**
*
* @package mahara
* @subpackage blocktype-socialprofile
* @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) 2014 Gregor Anzelj <gregor.anzelj@gmail.com>
*
*/
defined('INTERNAL') || die();
class PluginBlocktypeSocialprofile extends PluginBlocktype {
public static function get_title() {
return get_string('title', 'blocktype.internal/socialprofile');
}
public static function get_description() {
return get_string('description', 'blocktype.internal/socialprofile');
}
public static function get_categories() {
return array('internal');
}
public static function render_instance(BlockInstance $instance, $editing=false) {
global $USER;
$configdata = $instance->get('configdata');
$type = (isset($configdata['displaytype']) ? $configdata['displaytype'] : 'texticon');
$showicon = ($type == 'icononly' || $type == 'texticon' ? true : false);
$showtext = ($type == 'textonly' || $type == 'texticon' ? true : false);
// Whether to include email button
if (isset($configdata['displayemail']) && $configdata['displayemail']) {
$email = get_field('artefact_internal_profile_email', 'email', 'principal', 1, 'owner', $instance->get('view_obj')->get('owner'));
}
else {
$email = false;
}
if (!isset($configdata['artefactids']) || empty($configdata['artefactids'])) {
// When we first come into this block, it will have
// no social profiles configured yet.
$configdata['artefactids'] = array(0);
}
// Include selected social profiles
$sql = 'SELECT title, description, note FROM {artefact}
WHERE id IN (' . join(',', $configdata['artefactids']) . ')
AND owner = ? AND artefacttype = ?
ORDER BY description ASC';
if (!$data = get_records_sql_array($sql, array($USER->get('id'), 'socialprofile'))) {
$data = array();
}
safe_require('artefact', 'internal');
$data = ArtefactTypeSocialprofile::get_profile_icons($data);
$smarty = smarty_core();
$smarty->assign('showicon', $showicon);
$smarty->assign('showtext', $showtext);
$smarty->assign('profiles', $data);
$smarty->assign('email', $email);
return $smarty->fetch('blocktype:socialprofile:content.tpl');
}
public static function has_instance_config() {
return true;
}
public static function instance_config_form($instance) {
$configdata = $instance->get('configdata');
$form = array();
// Which social profiles does the user want
$form[] = self::artefactchooser_element((isset($configdata['artefactids'])) ? $configdata['artefactids'] : null);
$form['settings'] = array(
'type' => 'fieldset',
'collapsible' => true,
'collapsed' => true,
'legend' => get_string('displaysettings', 'blocktype.internal/socialprofile'),
'elements' => array(
'displaytype' => array(
'type' => 'radio',
'labelhtml' => get_string('displayaddressesas', 'blocktype.internal/socialprofile'),
'defaultvalue' => (!empty($configdata['displaytype']) ? $configdata['displaytype'] : 'texticon'),
'separator' => '<br>',
'options' => array(
'icononly' => get_string('optionicononly', 'blocktype.internal/socialprofile'),
'texticon' => get_string('optiontexticon', 'blocktype.internal/socialprofile'),
'textonly' => get_string('optiontextonly', 'blocktype.internal/socialprofile'),
)
),
'displayemail' => array(
'type' => 'checkbox',
'labelhtml' => get_string('displaydefaultemail', 'blocktype.internal/socialprofile'),
'defaultvalue' => (!empty($configdata['displayemail']) ? $configdata['displayemail'] : 0),
),
)
);
return $form;
}
public static function artefactchooser_element($default=null) {
safe_require('artefact', 'internal');
return array(
'name' => 'artefactids',
'type' => 'artefactchooser',
'title' => get_string('profilestoshow', 'blocktype.internal/socialprofile'),
'defaultvalue' => $default,
'blocktype' => 'socialprofile',
'limit' => 655360, // 640K profile fields is enough for anyone!
'selectone' => false,
'search' => false,
'artefacttypes' => array('socialprofile'),
'template' => 'artefact:internal:artefactchooser-element.tpl',
);
}
public static function default_copy_type() {
return 'shallow';
}
/**
* Profileinfo blocktype is only allowed in personal views, because
* there's no such thing as group/site profiles
*
* @param View $view The View to check
* @return boolean Whether blocks of this blocktype are allowed in the
* given view.
*/
public static function allowed_in_view(View $view) {
return $view->get('owner') != null;
}
/**
* Overrides the default implementation so we can export enough information
* to reconstitute profile information again.
*
* Leap2A export doesn't export profile related artefacts as entries, so we
* need to take that into account when exporting config for it.
*
* @param BlockInstance $bi The block instance to export config for
* @return array The configuration required to import the block again later
*/
public static function export_blockinstance_config_leap(BlockInstance $bi) {
return PluginArtefactInternal::export_blockinstance_config_leap($bi);
}
/**
* Sister method to export_blockinstance_config_leap (creates block
* instance based of what that method exports)
*
* @param array $biconfig The block instance config
* @param array $viewconfig The view config
* @return BlockInstance The newly made block instance
*/
public static function import_create_blockinstance_leap(array $biconfig, array $viewconfig) {
return PluginArtefactInternal::import_create_blockinstance_leap($biconfig, $viewconfig);
}
}
<p>
{foreach from=$profiles item=p}
<a href="{$p->link}" title="{$p->link}" class="btn socialbtn" target="_blank">
{if $showicon}<img src="{$p->icon}" alt="{$p->link}" class="valign-top">{/if}
{if $showicon && $showtext}&nbsp;{/if}
{if $showtext}{$p->description}{/if}
</a>
{/foreach}
{if $email}
<a href="mailto:{$email}" title="{$email}" class="btn socialbtn" target="_blank">
{if $showicon}<img src="{$WWWROOT}artefact/internal/blocktype/socialprofile/theme/raw/static/images/email.png" alt="{$email}" class="valign-top">{/if}
{if $showicon && $showtext}&nbsp;{/if}
{if $showtext}{str tag='email'}{/if}
</a>
{/if}
</p>
"mail_mark_unread_icon.png" (renamed to "email.png") by Oxygen Icons is licensed under LGPL.
Source: http://www.mricons.com/icon/15640/16/mail-mark-unread-icon
\ No newline at end of file
<?php
/**
*
* @package mahara
* @subpackage blocktype-socialprofile
* @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-2014 Gregor Anzelj <gregor.anzelj@gmail.com>
*
*/
defined('INTERNAL') || die();
$config = new StdClass;
$config->version = 2014011600;
$config->release = '1.0.0';
......@@ -53,11 +53,13 @@ class HtmlExportInternal extends HtmlExportArtefactPlugin {
$sections = array(
'aboutme' => array(),
'contact' => array(),
'messaging' => array(),
'social' => array(),
'general' => array(),
);
$elementlist = call_static_method('ArtefactTypeProfile', 'get_all_fields');
$elementlistlookup = array_flip(array_keys($elementlist));
// Export all profile fields except 'socialprofile'
unset($elementlist['socialprofile']);
$profilefields = get_column_sql('SELECT id FROM {artefact} WHERE "owner" = ? AND artefacttype IN ('
. join(",",array_map(create_function('$a','return db_quote($a);'), array_keys($elementlist)))
. ")", array($this->exporter->get('user')->get('id')));
......@@ -73,6 +75,18 @@ class HtmlExportInternal extends HtmlExportArtefactPlugin {
'weight' => $elementlistlookup[$artefact->get('artefacttype')]
);
}
// Export all 'socialprofile' entries
$socialprofiles = get_column_sql('SELECT id FROM {artefact} WHERE "owner" = ? AND artefacttype = ?', array($this->exporter->get('user')->get('id'), 'socialprofile'));
$profiles = array();
foreach ($socialprofiles as $id) {
$artefact = artefact_instance_from_id($id);
$rendered = $artefact->render_self(array('link' => true));
$profiles[] = array('label' => $artefact->get('description'), 'link' => $rendered['html']);
}
$sections[$this->get_category_for_artefacttype($artefact->get('artefacttype'))][$artefact->get('artefacttype')] = array(
'html' => $profiles,
'weight' => $elementlistlookup[$artefact->get('artefacttype')],
);
// Sort the data and then drop the weighting information
foreach ($sections as &$section) {
......@@ -136,13 +150,8 @@ class HtmlExportInternal extends HtmlExportArtefactPlugin {
case 'personalwebsite':
case 'officialwebsite':
return 'contact';
case 'jabberusername':
case 'skypeusername':
case 'yahoochat':
case 'aimscreenname':
case 'msnnumber':
case 'icqnumber':
return 'messaging';
case 'socialprofile':
return 'social';
default:
return 'general';
}
......
......@@ -8,10 +8,19 @@
<h3>{str tag=$sectionname section=artefact.internal}</h3>
<table>
{foreach from=$section key=title item=value}
{if $title == 'socialprofile'}
{foreach from=$value item=profile}
<tr>
<th>{str tag=$title section=artefact.internal}:</th>
<td>{$value|safe}</td>
<th>{$profile.label|safe}:</th>
<td>{$profile.link|safe}</td>
</tr>
{/foreach}
{else}
<tr>
<th>{str tag=$title section=artefact.internal}:</th>
<td>{$value|safe}</td>
</tr>
{/if}
{/foreach}
</table>
</div>
......
......@@ -64,8 +64,12 @@ class LeapExportElementInternal extends LeapExportElement {
$spacialdata[] = (object)$data;
}
else {
$label = get_string($a->get('artefacttype'), 'artefact.internal');
if ($a->get('artefacttype') == 'socialprofile') {
$label = $a->get('description');
}
$data = array_merge($data, array(
'label' => get_string($a->get('artefacttype'), 'artefact.internal'),
'label' => $label,
));
$persondata[] = (object)$data;
}
......@@ -116,7 +120,10 @@ class LeapExportElementInternal extends LeapExportElement {
public function data_mapping(ArtefactType $artefact) {
$artefacttype = $artefact->get('artefacttype');
static $mapping = array(
$artefactnote = $artefact->get('note');
// Mapping shouldn't contain 'socialprofile' artefacttype
// which is handled separately...
static $mapping = array(
'firstname' => 'legal_given_name',
'lastname' => 'legal_family_name',
'preferredname' => 'preferred_given_name',
......@@ -130,12 +137,11 @@ class LeapExportElementInternal extends LeapExportElement {
'faxnumber' => 'fax'
);
static $idmapping = array(
static $idmapping = array(
'jabberusername' => 'jabber',
'skypeusername' => 'skype',
'yahoochat' => 'yahoo',
'aimscreenname' => 'aim',
'msnnumber' => 'msn',
'icqnumber' => 'icq',
);
......@@ -149,8 +155,17 @@ class LeapExportElementInternal extends LeapExportElement {
if (array_key_exists($artefacttype, $mapping)) {
return array('field' => $mapping[$artefacttype]);
}
if (array_key_exists($artefacttype, $idmapping)) {
return array('field' => 'id', 'service' => $idmapping[$artefacttype]);
if ($artefacttype == 'socialprofile') {
if (array_search($artefactnote, $idmapping) !== false) {
// Export old messaging system accounts as
// persondata fields with leap:field="id".
return array('field' => 'website', 'service' => $artefactnote);
}
else {
// Export new social site profiles as persondata fields
// with leap:field="website" (what they basically are).
return array('field' => 'website');
}
}
if (array_key_exists($artefacttype, $spacialmapping)) {
......
......@@ -26,7 +26,7 @@ $element_list = ArtefactTypeProfile::get_all_fields();
$element_data = ArtefactTypeProfile::get_field_element_data();
$element_required = ArtefactTypeProfile::get_mandatory_fields();
// load existing profile information
// load existing profile fields
$profilefields = array();
$profile_data = get_records_select_array('artefact', "owner=? AND artefacttype IN (" . join(",",array_map(create_function('$a','return db_quote($a);'),array_keys($element_list))) . ")", array($USER->get('id')));
......@@ -61,6 +61,7 @@ if ($profilefields['email']['all']) {
}
}
$items = array();
foreach ( $element_list as $element => $type ) {
if ($type == 'wysiwyg' && isset($lockedfields[$element]) && !$USER->get('admin')) {
......@@ -103,6 +104,9 @@ foreach ( $element_list as $element => $type ) {
$items[$element]['options'] = array('' => get_string('nocountryselected')) + $countries;
$items[$element]['defaultvalue'] = get_config('country');
}
if ($element == 'socialprofile') {
$items[$element] = ArtefactTypeSocialprofile::render_profile_element();
}
if (get_helpfile_location('artefact', 'internal', 'profileform', $element)) {
$items[$element]['help'] = true;
......@@ -127,6 +131,9 @@ foreach ( $element_list as $element => $type ) {
if ($items['firstname']) {
$items['firstname']['autofocus'] = true;
}
if (isset($items['socialprofile']) && $items['socialprofile']) {
$items['socialprofile']['title'] = null;
}
$items['maildisabled']['ignore'] = !get_account_preference($USER->get('id'),'maildisabled');
......@@ -150,11 +157,11 @@ $elements = array(
'class' => $fieldset != 'contact' ? 'collapsed' : '',
'elements' => get_desired_fields($items, array('email', 'maildisabled', 'officialwebsite', 'personalwebsite', 'blogaddress', 'address', 'town', 'city', 'country', 'homenumber', 'businessnumber', 'mobilenumber', 'faxnumber'), 'contact'),
),
'messaging' => array(
'social' => array(
'type' => 'fieldset',
'legend' => get_string('messaging', 'artefact.internal'),
'class' => $fieldset != 'messaging' ? 'collapsed' : '',
'elements' => get_desired_fields($items, array('icqnumber', 'msnnumber', 'aimscreenname', 'yahoochat', 'skypeusername', 'jabberusername'), 'messaging'),
'legend' => get_string('social', 'artefact.internal'),
'class' => $fieldset != 'social' ? 'collapsed' : '',
'elements' => get_desired_fields($items, array('socialprofile'), 'social'),
),
'general' => array(
'type' => 'fieldset',
......@@ -171,6 +178,10 @@ $elements = array(
'value' => get_string('saveprofile','artefact.internal'),
)
);
// Don't include fieldset if 'socialprofile' is not installed
if (!get_record('blocktype_installed', 'active', 1, 'name', 'socialprofile')) {
unset($elements['social']);
}
$profileform = pieform(array(
'name' => 'profileform',
......@@ -383,6 +394,9 @@ function profileform_submit(Pieform $form, $values) {
else if ($element == 'maildisabled') {
continue;
}
else if ($element == 'socialprofile') {
continue;
}
else {
if (!isset($profilefields[$element]) || $values[$element] != $profilefields[$element]) {
$classname = generate_artefact_class_name($element);
......
......@@ -28,7 +28,8 @@ $string['aboutprofilelinkdescription'] = '<p>Please go to your <a href="%s">Prof
// profile categories
$string['aboutme'] = 'About me';
$string['contact'] = 'Contact information';