From: Zach Copley Date: Wed, 16 Mar 2011 23:08:49 +0000 (-0700) Subject: Extended profile - move some files around and rename stuff to follow plugin conventions X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=88d31a793398fca66b50e588c573153b8d402da6;p=quix0rs-gnu-social.git Extended profile - move some files around and rename stuff to follow plugin conventions --- diff --git a/plugins/ExtendedProfile/ExtendedProfilePlugin.php b/plugins/ExtendedProfile/ExtendedProfilePlugin.php index 127c91a543..3e6aa5f860 100644 --- a/plugins/ExtendedProfile/ExtendedProfilePlugin.php +++ b/plugins/ExtendedProfile/ExtendedProfilePlugin.php @@ -53,22 +53,26 @@ class ExtendedProfilePlugin extends Plugin */ function onAutoload($cls) { - $lower = strtolower($cls); + $dir = dirname(__FILE__); - switch ($lower) + switch (strtolower($cls)) { - case 'extendedprofile': - case 'extendedprofilewidget': case 'profiledetailaction': case 'profiledetailsettingsaction': - require_once dirname(__FILE__) . '/' . $lower . '.php'; - return false; case 'userautocompleteaction': - require_once dirname(__FILE__) . '/action/' . mb_substr($lower, 0, -6) . '.php'; + include_once $dir . '/actions/' + . strtolower(mb_substr($cls, 0, -6)) . '.php'; + return false; + break; // Safety first! + case 'extendedprofile': + case 'extendedprofilewidget': + include_once $dir . '/lib/' . strtolower($cls) . '.php'; return false; + break; case 'profile_detail': - require_once dirname(__FILE__) . '/' . ucfirst($lower) . '.php'; + include_once $dir . '/classes/' . ucfirst($cls) . '.php'; return false; + break; default: return true; } diff --git a/plugins/ExtendedProfile/Profile_detail.php b/plugins/ExtendedProfile/Profile_detail.php deleted file mode 100644 index 96869b0e63..0000000000 --- a/plugins/ExtendedProfile/Profile_detail.php +++ /dev/null @@ -1,142 +0,0 @@ -. - */ - -if (!defined('STATUSNET')) { - exit(1); -} - -/** - * DataObject class to store extended profile fields. Allows for storing - * multiple values per a "field_name" (field_name property is not unique). - * - * Example: - * - * Jed's Phone Numbers - * home : 510-384-1992 - * mobile: 510-719-1139 - * work : 415-231-1121 - * - * We can store these phone numbers in a "field" represented by three - * Profile_detail objects, each named 'phone_number' like this: - * - * $phone1 = new Profile_detail(); - * $phone1->field_name = 'phone_number'; - * $phone1->rel = 'home'; - * $phone1->field_value = '510-384-1992'; - * $phone1->value_index = 1; - * - * $phone1 = new Profile_detail(); - * $phone1->field_name = 'phone_number'; - * $phone1->rel = 'mobile'; - * $phone1->field_value = '510-719-1139'; - * $phone1->value_index = 2; - * - * $phone1 = new Profile_detail(); - * $phone1->field_name = 'phone_number'; - * $phone1->rel = 'work'; - * $phone1->field_value = '415-231-1121'; - * $phone1->value_index = 3; - * - */ -class Profile_detail extends Managed_DataObject -{ - public $__table = 'profile_detail'; - - public $id; - public $profile_id; // profile this is for - public $rel; // detail for some field types; eg "home", "mobile", "work" for phones or "aim", "irc", "xmpp" for IM - public $field_name; // name - public $field_value; // primary text value - public $value_index; // relative ordering of multiple values in the same field - public $date; // related date - public $ref_profile; // for people types, allows pointing to a known profile in the system - public $created; - public $modified; - - /** - * Get an instance by key - * - * This is a utility method to get a single instance with a given key value. - * - * @param string $k Key to use to lookup - * @param mixed $v Value to lookup - * - * @return User_greeting_count object found, or null for no hits - * - */ - - function staticGet($k, $v=null) - { - return Memcached_DataObject::staticGet('Profile_detail', $k, $v); - } - - /** - * Get an instance by compound key - * - * This is a utility method to get a single instance with a given set of - * key-value pairs. Usually used for the primary key for a compound key; thus - * the name. - * - * @param array $kv array of key-value mappings - * - * @return Bookmark object found, or null for no hits - * - */ - - function pkeyGet($kv) - { - return Memcached_DataObject::pkeyGet('Profile_detail', $kv); - } - - static function schemaDef() - { - return array( - 'description' - => 'Additional profile details for the ExtendedProfile plugin', - 'fields' => array( - 'id' => array('type' => 'serial', 'not null' => true), - 'profile_id' => array('type' => 'int', 'not null' => true), - 'field_name' => array( - 'type' => 'varchar', - 'length' => 16, - 'not null' => true - ), - 'value_index' => array('type' => 'int'), - 'field_value' => array('type' => 'text'), - 'date' => array('type' => 'datetime'), - 'rel' => array('type' => 'varchar', 'length' => 16), - 'rel_profile' => array('type' => 'int'), - 'created' => array( - 'type' => 'datetime', - 'not null' => true - ), - 'modified' => array( - 'type' => 'timestamp', - 'not null' => true - ), - ), - 'primary key' => array('id'), - 'unique keys' => array( - 'profile_detail_profile_id_field_name_value_index' - => array('profile_id', 'field_name', 'value_index'), - ) - ); - } - -} diff --git a/plugins/ExtendedProfile/action/userautocomplete.php b/plugins/ExtendedProfile/action/userautocomplete.php deleted file mode 100644 index d4857429e0..0000000000 --- a/plugins/ExtendedProfile/action/userautocomplete.php +++ /dev/null @@ -1,113 +0,0 @@ -. - * - * @category Search - * @package StatusNet - * @author Zach Copley - * @copyright 2011 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET')) { - exit(1); -} - - -class UserautocompleteAction extends Action -{ - var $query; - - /** - * Initialization. - * - * @param array $args Web and URL arguments - * - * @return boolean true if nothing goes wrong - */ - function prepare($args) - { - parent::prepare($args); - $this->query = $this->trimmed('term'); - return true; - } - - /** - * Handle a request - * - * @param array $args Arguments from $_REQUEST - * - * @return void - */ - function handle($args) - { - parent::handle($args); - $this->showResults(); - } - - /** - * Search for users matching the query and spit the results out - * as a quick-n-dirty JSON document - * - * @return void - */ - function showResults() - { - $people = array(); - - $profile = new Profile(); - - $search_engine = $profile->getSearchEngine('profile'); - $search_engine->set_sort_mode('nickname_desc'); - $search_engine->limit(0, 10); - $search_engine->query(strtolower($this->query . '*')); - - $cnt = $profile->find(); - - if ($cnt > 0) { - - $sql = 'SELECT profile.* FROM profile, user WHERE profile.id = user.id ' - . ' AND LEFT(LOWER(profile.nickname), ' - . strlen($this->query) - . ') = \'%s\' ' - . ' LIMIT 0, 10'; - - $profile->query(sprintf($sql, $this->query)); - } - - while ($profile->fetch()) { - $people[] = $profile->nickname; - } - - header('Content-Type: application/json; charset=utf-8'); - print json_encode($people); - } - - /** - * Do we need to write to the database? - * - * @return boolean true - */ - function isReadOnly($args) - { - return true; - } -} diff --git a/plugins/ExtendedProfile/actions/profiledetail.php b/plugins/ExtendedProfile/actions/profiledetail.php new file mode 100644 index 0000000000..a777a28e03 --- /dev/null +++ b/plugins/ExtendedProfile/actions/profiledetail.php @@ -0,0 +1,63 @@ +. + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +class ProfileDetailAction extends ShowstreamAction +{ + + function isReadOnly($args) + { + return true; + } + + function title() + { + return $this->profile->getFancyName(); + } + + function showStylesheets() { + parent::showStylesheets(); + $this->cssLink('plugins/ExtendedProfile/css/profiledetail.css'); + return true; + } + + function showContent() + { + $cur = common_current_user(); + if ($cur && $cur->id == $this->profile->id) { // your own page + $this->elementStart('div', 'entity_actions'); + $this->elementStart('ul'); + $this->elementStart('li', 'entity_edit'); + $this->element('a', array('href' => common_local_url('profiledetailsettings'), + // TRANS: Link title for link on user profile. + 'title' => _m('Edit extended profile settings')), + // TRANS: Link text for link on user profile. + _m('Edit')); + $this->elementEnd('li'); + $this->elementEnd('ul'); + $this->elementEnd('div'); + } + + $widget = new ExtendedProfileWidget($this, $this->profile); + $widget->show(); + } +} diff --git a/plugins/ExtendedProfile/actions/profiledetailsettings.php b/plugins/ExtendedProfile/actions/profiledetailsettings.php new file mode 100644 index 0000000000..23a6ce5d65 --- /dev/null +++ b/plugins/ExtendedProfile/actions/profiledetailsettings.php @@ -0,0 +1,634 @@ +. + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +class ProfileDetailSettingsAction extends ProfileSettingsAction +{ + + function title() + { + return _m('Extended profile settings'); + } + + /** + * Instructions for use + * + * @return instructions for use + */ + function getInstructions() + { + // TRANS: Usage instructions for profile settings. + return _('You can update your personal profile info here '. + 'so people know more about you.'); + } + + function showStylesheets() { + parent::showStylesheets(); + $this->cssLink('plugins/ExtendedProfile/css/profiledetail.css'); + return true; + } + + function showScripts() { + parent::showScripts(); + $this->script('plugins/ExtendedProfile/js/profiledetail.js'); + return true; + } + + function handlePost() + { + // CSRF protection + $token = $this->trimmed('token'); + if (!$token || $token != common_session_token()) { + $this->showForm( + _m( + 'There was a problem with your session token. ' + . 'Try again, please.' + ) + ); + return; + } + + if ($this->arg('save')) { + $this->saveDetails(); + } else { + // TRANS: Message given submitting a form with an unknown action + $this->showForm(_m('Unexpected form submission.')); + } + } + + function showContent() + { + $cur = common_current_user(); + $profile = $cur->getProfile(); + + $widget = new ExtendedProfileWidget( + $this, + $profile, + ExtendedProfileWidget::EDITABLE + ); + $widget->show(); + } + + function saveDetails() + { + common_debug(var_export($_POST, true)); + + $user = common_current_user(); + + try { + $this->saveStandardProfileDetails($user); + + $profile = $user->getProfile(); + + $simpleFieldNames = array('title', 'spouse', 'kids', 'manager'); + $dateFieldNames = array('birthday'); + + foreach ($simpleFieldNames as $name) { + $value = $this->trimmed('extprofile-' . $name); + if (!empty($value)) { + $this->saveField($user, $name, $value); + } + } + + foreach ($dateFieldNames as $name) { + $value = $this->trimmed('extprofile-' . $name); + $dateVal = $this->parseDate($name, $value); + $this->saveField( + $user, + $name, + null, + null, + null, + $dateVal + ); + } + + $this->savePhoneNumbers($user); + $this->saveIms($user); + $this->saveWebsites($user); + $this->saveExperiences($user); + $this->saveEducations($user); + + } catch (Exception $e) { + $this->showForm($e->getMessage(), false); + return; + } + + $this->showForm(_('Details saved.'), true); + + } + + function parseDate($fieldname, $datestr, $required = false) + { + if (empty($datestr)) { + if ($required) { + $msg = sprintf( + _m('You must supply a date for "%s".'), + $fieldname + ); + throw new Exception($msg); + } + } else { + $ts = strtotime($datestr); + if ($ts === false) { + throw new Exception( + sprintf( + _m('Invalid date entered for "%s": %s'), + $fieldname, + $ts + ) + ); + } + return common_sql_date($ts); + } + return null; + } + + function savePhoneNumbers($user) { + $phones = $this->findPhoneNumbers(); + $this->removeAll($user, 'phone'); + $i = 0; + foreach($phones as $phone) { + if (!empty($phone['value'])) { + ++$i; + $this->saveField( + $user, + 'phone', + $phone['value'], + $phone['rel'], + $i + ); + } + } + } + + function findPhoneNumbers() { + + // Form vals look like this: + // 'extprofile-phone-1' => '11332', + // 'extprofile-phone-1-rel' => 'mobile', + + $phones = $this->sliceParams('phone', 2); + $phoneArray = array(); + + foreach ($phones as $phone) { + list($number, $rel) = array_values($phone); + $phoneArray[] = array( + 'value' => $number, + 'rel' => $rel + ); + } + + return $phoneArray; + } + + function findIms() { + + // Form vals look like this: + // 'extprofile-im-0' => 'jed', + // 'extprofile-im-0-rel' => 'yahoo', + + $ims = $this->sliceParams('im', 2); + $imArray = array(); + + foreach ($ims as $im) { + list($id, $rel) = array_values($im); + $imArray[] = array( + 'value' => $id, + 'rel' => $rel + ); + } + + return $imArray; + } + + function saveIms($user) { + $ims = $this->findIms(); + $this->removeAll($user, 'im'); + $i = 0; + foreach($ims as $im) { + if (!empty($im['value'])) { + ++$i; + $this->saveField( + $user, + 'im', + $im['value'], + $im['rel'], + $i + ); + } + } + } + + function findWebsites() { + + // Form vals look like this: + + $sites = $this->sliceParams('website', 2); + $wsArray = array(); + + foreach ($sites as $site) { + list($id, $rel) = array_values($site); + $wsArray[] = array( + 'value' => $id, + 'rel' => $rel + ); + } + + return $wsArray; + } + + function saveWebsites($user) { + $sites = $this->findWebsites(); + $this->removeAll($user, 'website'); + $i = 0; + foreach($sites as $site) { + if (!empty($site['value']) && !Validate::uri( + $site['value'], + array('allowed_schemes' => array('http', 'https'))) + ) { + throw new Exception(sprintf(_m('Invalid URL: %s'), $site['value'])); + } + + if (!empty($site['value'])) { + ++$i; + $this->saveField( + $user, + 'website', + $site['value'], + $site['rel'], + $i + ); + } + } + } + + function findExperiences() { + + // Form vals look like this: + // 'extprofile-experience-0' => 'Bozotronix', + // 'extprofile-experience-0-current' => 'true' + // 'extprofile-experience-0-start' => '1/5/10', + // 'extprofile-experience-0-end' => '2/3/11', + + $experiences = $this->sliceParams('experience', 4); + $expArray = array(); + + foreach ($experiences as $exp) { + if (sizeof($experiences) == 4) { + list($company, $current, $end, $start) = array_values($exp); + } else { + $end = null; + list($company, $current, $start) = array_values($exp); + } + if (!empty($company)) { + $expArray[] = array( + 'company' => $company, + 'start' => $this->parseDate('Start', $start, true), + 'end' => ($current == 'false') ? $this->parseDate('End', $end, true) : null, + 'current' => ($current == 'false') ? false : true + ); + } + } + + return $expArray; + } + + function saveExperiences($user) { + common_debug('save experiences'); + $experiences = $this->findExperiences(); + + $this->removeAll($user, 'company'); + $this->removeAll($user, 'start'); + $this->removeAll($user, 'end'); // also stores 'current' + + $i = 0; + foreach($experiences as $experience) { + if (!empty($experience['company'])) { + ++$i; + $this->saveField( + $user, + 'company', + $experience['company'], + null, + $i + ); + + $this->saveField( + $user, + 'start', + null, + null, + $i, + $experience['start'] + ); + + // Save "current" employer indicator in rel + if ($experience['current']) { + $this->saveField( + $user, + 'end', + null, + 'current', // rel + $i + ); + } else { + $this->saveField( + $user, + 'end', + null, + null, + $i, + $experience['end'] + ); + } + + } + } + } + + function findEducations() { + + // Form vals look like this: + // 'extprofile-education-0-school' => 'Pigdog', + // 'extprofile-education-0-degree' => 'BA', + // 'extprofile-education-0-description' => 'Blar', + // 'extprofile-education-0-start' => '05/22/99', + // 'extprofile-education-0-end' => '05/22/05', + + $edus = $this->sliceParams('education', 5); + $eduArray = array(); + + foreach ($edus as $edu) { + list($school, $degree, $description, $end, $start) = array_values($edu); + if (!empty($school)) { + $eduArray[] = array( + 'school' => $school, + 'degree' => $degree, + 'description' => $description, + 'start' => $this->parseDate('Start', $start, true), + 'end' => $this->parseDate('End', $end, true) + ); + } + } + + return $eduArray; + } + + + function saveEducations($user) { + common_debug('save education'); + $edus = $this->findEducations(); + common_debug(var_export($edus, true)); + + $this->removeAll($user, 'school'); + $this->removeAll($user, 'degree'); + $this->removeAll($user, 'degree_descr'); + $this->removeAll($user, 'school_start'); + $this->removeAll($user, 'school_end'); + + $i = 0; + foreach($edus as $edu) { + if (!empty($edu['school'])) { + ++$i; + $this->saveField( + $user, + 'school', + $edu['school'], + null, + $i + ); + $this->saveField( + $user, + 'degree', + $edu['degree'], + null, + $i + ); + $this->saveField( + $user, + 'degree_descr', + $edu['description'], + null, + $i + ); + $this->saveField( + $user, + 'school_start', + null, + null, + $i, + $edu['start'] + ); + + $this->saveField( + $user, + 'school_end', + null, + null, + $i, + $edu['end'] + ); + } + } + } + + function arraySplit($array, $pieces) + { + if ($pieces < 2) { + return array($array); + } + + $newCount = ceil(count($array) / $pieces); + $a = array_slice($array, 0, $newCount); + $b = $this->arraySplit(array_slice($array, $newCount), $pieces - 1); + + return array_merge(array($a), $b); + } + + function findMultiParams($type) { + $formVals = array(); + $target = $type; + foreach ($_POST as $key => $val) { + if (strrpos('extprofile-' . $key, $target) !== false) { + $formVals[$key] = $val; + } + } + return $formVals; + } + + function sliceParams($key, $size) { + $slice = array(); + $params = $this->findMultiParams($key); + ksort($params); + $slice = $this->arraySplit($params, sizeof($params) / $size); + return $slice; + } + + /** + * Save an extended profile field as a Profile_detail + * + * @param User $user the current user + * @param string $name field name + * @param string $value field value + * @param string $rel field rel (type) + * @param int $index index (fields can have multiple values) + * @param date $date related date + */ + function saveField($user, $name, $value, $rel = null, $index = null, $date = null) + { + $profile = $user->getProfile(); + $detail = new Profile_detail(); + + $detail->profile_id = $profile->id; + $detail->field_name = $name; + $detail->value_index = $index; + + $result = $detail->find(true); + + if (empty($result)) { + $detial->value_index = $index; + $detail->rel = $rel; + $detail->field_value = $value; + $detail->date = $date; + $detail->created = common_sql_now(); + $result = $detail->insert(); + if (empty($result)) { + common_log_db_error($detail, 'INSERT', __FILE__); + $this->serverError(_m('Could not save profile details.')); + } + } else { + $orig = clone($detail); + + $detail->field_value = $value; + $detail->rel = $rel; + $detail->date = $date; + + $result = $detail->update($orig); + if (empty($result)) { + common_log_db_error($detail, 'UPDATE', __FILE__); + $this->serverError(_m('Could not save profile details.')); + } + } + + $detail->free(); + } + + function removeAll($user, $name) + { + $profile = $user->getProfile(); + $detail = new Profile_detail(); + $detail->profile_id = $profile->id; + $detail->field_name = $name; + $detail->delete(); + $detail->free(); + } + + /** + * Save fields that should be stored in the main profile object + * + * XXX: There's a lot of dupe code here from ProfileSettingsAction. + * Do not want. + * + * @param User $user the current user + */ + function saveStandardProfileDetails($user) + { + $fullname = $this->trimmed('extprofile-fullname'); + $location = $this->trimmed('extprofile-location'); + $tagstring = $this->trimmed('extprofile-tags'); + $bio = $this->trimmed('extprofile-bio'); + + if ($tagstring) { + $tags = array_map( + 'common_canonical_tag', + preg_split('/[\s,]+/', $tagstring) + ); + } else { + $tags = array(); + } + + foreach ($tags as $tag) { + if (!common_valid_profile_tag($tag)) { + // TRANS: Validation error in form for profile settings. + // TRANS: %s is an invalid tag. + throw new Exception(sprintf(_m('Invalid tag: "%s".'), $tag)); + } + } + + $profile = $user->getProfile(); + + $oldTags = $user->getSelfTags(); + $newTags = array_diff($tags, $oldTags); + + if ($fullname != $profile->fullname + || $location != $profile->location + || !empty($newTags) + || $bio != $profile->bio) { + + $orig = clone($profile); + + $profile->nickname = $user->nickname; + $profile->fullname = $fullname; + $profile->bio = $bio; + $profile->location = $location; + + $loc = Location::fromName($location); + + if (empty($loc)) { + $profile->lat = null; + $profile->lon = null; + $profile->location_id = null; + $profile->location_ns = null; + } else { + $profile->lat = $loc->lat; + $profile->lon = $loc->lon; + $profile->location_id = $loc->location_id; + $profile->location_ns = $loc->location_ns; + } + + $profile->profileurl = common_profile_url($user->nickname); + + $result = $profile->update($orig); + + if ($result === false) { + common_log_db_error($profile, 'UPDATE', __FILE__); + // TRANS: Server error thrown when user profile settings could not be saved. + $this->serverError(_('Could not save profile.')); + return; + } + + // Set the user tags + $result = $user->setSelfTags($tags); + + if (!$result) { + // TRANS: Server error thrown when user profile settings tags could not be saved. + $this->serverError(_('Could not save tags.')); + return; + } + + Event::handle('EndProfileSaveForm', array($this)); + common_broadcast_profile($profile); + } + } + +} diff --git a/plugins/ExtendedProfile/actions/userautocomplete.php b/plugins/ExtendedProfile/actions/userautocomplete.php new file mode 100644 index 0000000000..d4857429e0 --- /dev/null +++ b/plugins/ExtendedProfile/actions/userautocomplete.php @@ -0,0 +1,113 @@ +. + * + * @category Search + * @package StatusNet + * @author Zach Copley + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + + +class UserautocompleteAction extends Action +{ + var $query; + + /** + * Initialization. + * + * @param array $args Web and URL arguments + * + * @return boolean true if nothing goes wrong + */ + function prepare($args) + { + parent::prepare($args); + $this->query = $this->trimmed('term'); + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + function handle($args) + { + parent::handle($args); + $this->showResults(); + } + + /** + * Search for users matching the query and spit the results out + * as a quick-n-dirty JSON document + * + * @return void + */ + function showResults() + { + $people = array(); + + $profile = new Profile(); + + $search_engine = $profile->getSearchEngine('profile'); + $search_engine->set_sort_mode('nickname_desc'); + $search_engine->limit(0, 10); + $search_engine->query(strtolower($this->query . '*')); + + $cnt = $profile->find(); + + if ($cnt > 0) { + + $sql = 'SELECT profile.* FROM profile, user WHERE profile.id = user.id ' + . ' AND LEFT(LOWER(profile.nickname), ' + . strlen($this->query) + . ') = \'%s\' ' + . ' LIMIT 0, 10'; + + $profile->query(sprintf($sql, $this->query)); + } + + while ($profile->fetch()) { + $people[] = $profile->nickname; + } + + header('Content-Type: application/json; charset=utf-8'); + print json_encode($people); + } + + /** + * Do we need to write to the database? + * + * @return boolean true + */ + function isReadOnly($args) + { + return true; + } +} diff --git a/plugins/ExtendedProfile/classes/Profile_detail.php b/plugins/ExtendedProfile/classes/Profile_detail.php new file mode 100644 index 0000000000..96869b0e63 --- /dev/null +++ b/plugins/ExtendedProfile/classes/Profile_detail.php @@ -0,0 +1,142 @@ +. + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * DataObject class to store extended profile fields. Allows for storing + * multiple values per a "field_name" (field_name property is not unique). + * + * Example: + * + * Jed's Phone Numbers + * home : 510-384-1992 + * mobile: 510-719-1139 + * work : 415-231-1121 + * + * We can store these phone numbers in a "field" represented by three + * Profile_detail objects, each named 'phone_number' like this: + * + * $phone1 = new Profile_detail(); + * $phone1->field_name = 'phone_number'; + * $phone1->rel = 'home'; + * $phone1->field_value = '510-384-1992'; + * $phone1->value_index = 1; + * + * $phone1 = new Profile_detail(); + * $phone1->field_name = 'phone_number'; + * $phone1->rel = 'mobile'; + * $phone1->field_value = '510-719-1139'; + * $phone1->value_index = 2; + * + * $phone1 = new Profile_detail(); + * $phone1->field_name = 'phone_number'; + * $phone1->rel = 'work'; + * $phone1->field_value = '415-231-1121'; + * $phone1->value_index = 3; + * + */ +class Profile_detail extends Managed_DataObject +{ + public $__table = 'profile_detail'; + + public $id; + public $profile_id; // profile this is for + public $rel; // detail for some field types; eg "home", "mobile", "work" for phones or "aim", "irc", "xmpp" for IM + public $field_name; // name + public $field_value; // primary text value + public $value_index; // relative ordering of multiple values in the same field + public $date; // related date + public $ref_profile; // for people types, allows pointing to a known profile in the system + public $created; + public $modified; + + /** + * Get an instance by key + * + * This is a utility method to get a single instance with a given key value. + * + * @param string $k Key to use to lookup + * @param mixed $v Value to lookup + * + * @return User_greeting_count object found, or null for no hits + * + */ + + function staticGet($k, $v=null) + { + return Memcached_DataObject::staticGet('Profile_detail', $k, $v); + } + + /** + * Get an instance by compound key + * + * This is a utility method to get a single instance with a given set of + * key-value pairs. Usually used for the primary key for a compound key; thus + * the name. + * + * @param array $kv array of key-value mappings + * + * @return Bookmark object found, or null for no hits + * + */ + + function pkeyGet($kv) + { + return Memcached_DataObject::pkeyGet('Profile_detail', $kv); + } + + static function schemaDef() + { + return array( + 'description' + => 'Additional profile details for the ExtendedProfile plugin', + 'fields' => array( + 'id' => array('type' => 'serial', 'not null' => true), + 'profile_id' => array('type' => 'int', 'not null' => true), + 'field_name' => array( + 'type' => 'varchar', + 'length' => 16, + 'not null' => true + ), + 'value_index' => array('type' => 'int'), + 'field_value' => array('type' => 'text'), + 'date' => array('type' => 'datetime'), + 'rel' => array('type' => 'varchar', 'length' => 16), + 'rel_profile' => array('type' => 'int'), + 'created' => array( + 'type' => 'datetime', + 'not null' => true + ), + 'modified' => array( + 'type' => 'timestamp', + 'not null' => true + ), + ), + 'primary key' => array('id'), + 'unique keys' => array( + 'profile_detail_profile_id_field_name_value_index' + => array('profile_id', 'field_name', 'value_index'), + ) + ); + } + +} diff --git a/plugins/ExtendedProfile/extendedprofile.php b/plugins/ExtendedProfile/extendedprofile.php deleted file mode 100644 index fa632e5073..0000000000 --- a/plugins/ExtendedProfile/extendedprofile.php +++ /dev/null @@ -1,349 +0,0 @@ -. - */ - -if (!defined('STATUSNET')) { - exit(1); -} - -/** - * Class to represent extended profile data - */ -class ExtendedProfile -{ - protected $fields; - - /** - * Constructor - * - * @param Profile $profile - */ - function __construct(Profile $profile) - { - $this->profile = $profile; - $this->user = $profile->getUser(); - $this->fields = $this->loadFields(); - $this->sections = $this->getSections(); - //common_debug(var_export($this->sections, true)); - - //common_debug(var_export($this->fields, true)); - } - - /** - * Load extended profile fields - * - * @return array $fields the list of fields - */ - function loadFields() - { - $detail = new Profile_detail(); - $detail->profile_id = $this->profile->id; - $detail->find(); - - $fields = array(); - - while ($detail->fetch()) { - $fields[$detail->field_name][] = clone($detail); - } - - return $fields; - } - - /** - * Get a the self-tags associated with this profile - * - * @return string the concatenated string of tags - */ - function getTags() - { - return implode(' ', $this->user->getSelfTags()); - } - - /** - * Return a simple string value. Checks for fields that should - * be stored in the regular profile and returns values from it - * if appropriate. - * - * @param string $name name of the detail field to get the - * value from - * - * @return string the value - */ - function getTextValue($name) - { - $key = strtolower($name); - $profileFields = array('fullname', 'location', 'bio'); - - if (in_array($key, $profileFields)) { - return $this->profile->$name; - } else if (array_key_exists($key, $this->fields)) { - return $this->fields[$key][0]->field_value; - } else { - return null; - } - } - - function getDateValue($name) { - $key = strtolower($name); - if (array_key_exists($key, $this->fields)) { - return $this->fields[$key][0]->date; - } else { - return null; - } - } - - // XXX: getPhones, getIms, and getWebsites pretty much do the same thing, - // so refactor. - function getPhones() - { - $phones = (isset($this->fields['phone'])) ? $this->fields['phone'] : null; - $pArrays = array(); - - if (empty($phones)) { - $pArrays[] = array( - 'label' => _m('Phone'), - 'index' => 0, - 'type' => 'phone', - 'vcard' => 'tel', - 'rel' => 'office', - 'value' => null - ); - } else { - for ($i = 0; $i < sizeof($phones); $i++) { - $pa = array( - 'label' => _m('Phone'), - 'type' => 'phone', - 'index' => intval($phones[$i]->value_index), - 'rel' => $phones[$i]->rel, - 'value' => $phones[$i]->field_value, - 'vcard' => 'tel' - ); - - $pArrays[] = $pa; - } - } - return $pArrays; - } - - function getIms() - { - $ims = (isset($this->fields['im'])) ? $this->fields['im'] : null; - $iArrays = array(); - - if (empty($ims)) { - $iArrays[] = array( - 'label' => _m('IM'), - 'type' => 'im' - ); - } else { - for ($i = 0; $i < sizeof($ims); $i++) { - $ia = array( - 'label' => _m('IM'), - 'type' => 'im', - 'index' => intval($ims[$i]->value_index), - 'rel' => $ims[$i]->rel, - 'value' => $ims[$i]->field_value, - ); - - $iArrays[] = $ia; - } - } - return $iArrays; - } - - function getWebsites() - { - $sites = (isset($this->fields['website'])) ? $this->fields['website'] : null; - $wArrays = array(); - - if (empty($sites)) { - $wArrays[] = array( - 'label' => _m('Website'), - 'type' => 'website' - ); - } else { - for ($i = 0; $i < sizeof($sites); $i++) { - $wa = array( - 'label' => _m('Website'), - 'type' => 'website', - 'index' => intval($sites[$i]->value_index), - 'rel' => $sites[$i]->rel, - 'value' => $sites[$i]->field_value, - ); - - $wArrays[] = $wa; - } - } - return $wArrays; - } - - function getExperiences() - { - $companies = (isset($this->fields['company'])) ? $this->fields['company'] : null; - $start = (isset($this->fields['start'])) ? $this->fields['start'] : null; - $end = (isset($this->fields['end'])) ? $this->fields['end'] : null; - - $eArrays = array(); - - if (empty($companies)) { - $eArrays[] = array( - 'label' => _m('Employer'), - 'type' => 'experience', - 'company' => null, - 'start' => null, - 'end' => null, - 'current' => false, - 'index' => 0 - ); - } else { - for ($i = 0; $i < sizeof($companies); $i++) { - $ea = array( - 'label' => _m('Employer'), - 'type' => 'experience', - 'company' => $companies[$i]->field_value, - 'index' => intval($companies[$i]->value_index), - 'current' => $end[$i]->rel, - 'start' => $start[$i]->date, - 'end' => $end[$i]->date - ); - $eArrays[] = $ea; - } - } - return $eArrays; - } - - function getEducation() - { - $schools = (isset($this->fields['school'])) ? $this->fields['school'] : null; - $degrees = (isset($this->fields['degree'])) ? $this->fields['degree'] : null; - $descs = (isset($this->fields['degree_descr'])) ? $this->fields['degree_descr'] : null; - $start = (isset($this->fields['school_start'])) ? $this->fields['school_start'] : null; - $end = (isset($this->fields['school_end'])) ? $this->fields['school_end'] : null; - $iArrays = array(); - - if (empty($schools)) { - $iArrays[] = array( - 'type' => 'education', - 'label' => _m('Institution'), - 'school' => null, - 'degree' => null, - 'description' => null, - 'start' => null, - 'end' => null, - 'index' => 0 - ); - } else { - for ($i = 0; $i < sizeof($schools); $i++) { - $ia = array( - 'type' => 'education', - 'label' => _m('Institution'), - 'school' => $schools[$i]->field_value, - 'degree' => isset($degrees[$i]->field_value) ? $degrees[$i]->field_value : null, - 'description' => isset($descs[$i]->field_value) ? $descs[$i]->field_value : null, - 'index' => intval($schools[$i]->value_index), - 'start' => $start[$i]->date, - 'end' => $end[$i]->date - ); - $iArrays[] = $ia; - } - } - - return $iArrays; - } - - /** - * Return all the sections of the extended profile - * - * @return array the big list of sections and fields - */ - function getSections() - { - return array( - 'basic' => array( - 'label' => _m('Personal'), - 'fields' => array( - 'fullname' => array( - 'label' => _m('Full name'), - 'profile' => 'fullname', - 'vcard' => 'fn', - ), - 'title' => array( - 'label' => _m('Title'), - 'vcard' => 'title', - ), - 'manager' => array( - 'label' => _m('Manager'), - 'type' => 'person', - 'vcard' => 'x-manager', - ), - 'location' => array( - 'label' => _m('Location'), - 'profile' => 'location' - ), - 'bio' => array( - 'label' => _m('Bio'), - 'type' => 'textarea', - 'profile' => 'bio', - ), - 'tags' => array( - 'label' => _m('Tags'), - 'type' => 'tags', - 'profile' => 'tags', - ), - ), - ), - 'contact' => array( - 'label' => _m('Contact'), - 'fields' => array( - 'phone' => $this->getPhones(), - 'im' => $this->getIms(), - 'website' => $this->getWebsites() - ), - ), - 'personal' => array( - 'label' => _m('Personal'), - 'fields' => array( - 'birthday' => array( - 'label' => _m('Birthday'), - 'type' => 'date', - 'vcard' => 'bday', - ), - 'spouse' => array( - 'label' => _m('Spouse\'s name'), - 'vcard' => 'x-spouse', - ), - 'kids' => array( - 'label' => _m('Kids\' names') - ), - ), - ), - 'experience' => array( - 'label' => _m('Work experience'), - 'fields' => array( - 'experience' => $this->getExperiences() - ), - ), - 'education' => array( - 'label' => _m('Education'), - 'fields' => array( - 'education' => $this->getEducation() - ), - ), - ); - } -} diff --git a/plugins/ExtendedProfile/extendedprofilewidget.php b/plugins/ExtendedProfile/extendedprofilewidget.php deleted file mode 100644 index 53cb5d3b87..0000000000 --- a/plugins/ExtendedProfile/extendedprofilewidget.php +++ /dev/null @@ -1,657 +0,0 @@ -. - */ - -if (!defined('STATUSNET')) { - exit(1); -} - -/** - * Class for outputting a widget to display or edit - * extended profiles - */ -class ExtendedProfileWidget extends Form -{ - const EDITABLE = true; - - /** - * The parent profile - * - * @var Profile - */ - protected $profile; - - /** - * The extended profile - * - * @var Extended_profile - */ - protected $ext; - - /** - * Constructor - * - * @param XMLOutputter $out - * @param Profile $profile - * @param boolean $editable - */ - public function __construct(XMLOutputter $out=null, Profile $profile=null, $editable=false) - { - parent::__construct($out); - - $this->profile = $profile; - $this->ext = new ExtendedProfile($this->profile); - - $this->editable = $editable; - } - - /** - * Show the extended profile, or the edit form - */ - public function show() - { - if ($this->editable) { - parent::show(); - } else { - $this->showSections(); - } - } - - /** - * Show form data - */ - public function formData() - { - // For JQuery UI modal dialog - $this->out->elementStart( - 'div', - array('id' => 'confirm-dialog', 'title' => 'Confirmation Required') - ); - $this->out->text('Really delete this entry?'); - $this->out->elementEnd('div'); - $this->showSections(); - } - - /** - * Show each section of the extended profile - */ - public function showSections() - { - $sections = $this->ext->getSections(); - foreach ($sections as $name => $section) { - $this->showExtendedProfileSection($name, $section); - } - } - - /** - * Show an extended profile section - * - * @param string $name name of the section - * @param array $section array of fields for the section - */ - protected function showExtendedProfileSection($name, $section) - { - $this->out->element('h3', null, $section['label']); - $this->out->elementStart('table', array('class' => 'extended-profile')); - - foreach ($section['fields'] as $fieldName => $field) { - - switch($fieldName) { - case 'phone': - case 'im': - case 'website': - case 'experience': - case 'education': - $this->showMultiple($fieldName, $field); - break; - default: - $this->showExtendedProfileField($fieldName, $field); - } - } - $this->out->elementEnd('table'); - } - - /** - * Show an extended profile field - * - * @param string $name name of the field - * @param array $field set of key/value pairs for the field - */ - protected function showExtendedProfileField($name, $field) - { - $this->out->elementStart('tr'); - - $this->out->element('th', str_replace(' ','_',strtolower($field['label'])), $field['label']); - - $this->out->elementStart('td'); - if ($this->editable) { - $this->showEditableField($name, $field); - } else { - $this->showFieldValue($name, $field); - } - $this->out->elementEnd('td'); - - $this->out->elementEnd('tr'); - } - - protected function showMultiple($name, $fields) { - foreach ($fields as $field) { - $this->showExtendedProfileField($name, $field); - } - } - - // XXX: showPhone, showIm and showWebsite all work the same, so - // combine - protected function showPhone($name, $field) - { - $this->out->elementStart('div', array('class' => 'phone-display')); - if (!empty($field['value'])) { - $this->out->text($field['value']); - if (!empty($field['rel'])) { - $this->out->text(' (' . $field['rel'] . ')'); - } - } - $this->out->elementEnd('div'); - } - - protected function showIm($name, $field) - { - $this->out->elementStart('div', array('class' => 'im-display')); - $this->out->text($field['value']); - if (!empty($field['rel'])) { - $this->out->text(' (' . $field['rel'] . ')'); - } - $this->out->elementEnd('div'); - } - - protected function showWebsite($name, $field) - { - $this->out->elementStart('div', array('class' => 'website-display')); - - $url = $field['value']; - - $this->out->element( - "a", - array( - 'href' => $url, - 'class' => 'extended-profile-link', - 'target' => "_blank" - ), - $url - ); - - if (!empty($field['rel'])) { - $this->out->text(' (' . $field['rel'] . ')'); - } - $this->out->elementEnd('div'); - } - - protected function showEditableIm($name, $field) - { - $index = isset($field['index']) ? $field['index'] : 0; - $id = "extprofile-$name-$index"; - $rel = $id . '-rel'; - $this->out->elementStart( - 'div', array( - 'id' => $id . '-edit', - 'class' => 'im-item' - ) - ); - $this->out->input( - $id, - null, - isset($field['value']) ? $field['value'] : null - ); - $this->out->dropdown( - $id . '-rel', - 'Type', - array( - 'jabber' => 'Jabber', - 'gtalk' => 'GTalk', - 'aim' => 'AIM', - 'yahoo' => 'Yahoo! Messenger', - 'msn' => 'MSN', - 'skype' => 'Skype', - 'other' => 'Other' - ), - null, - false, - isset($field['rel']) ? $field['rel'] : null - ); - - $this->showMultiControls(); - $this->out->elementEnd('div'); - } - - protected function showEditablePhone($name, $field) - { - $index = isset($field['index']) ? $field['index'] : 0; - $id = "extprofile-$name-$index"; - $rel = $id . '-rel'; - $this->out->elementStart( - 'div', array( - 'id' => $id . '-edit', - 'class' => 'phone-item' - ) - ); - $this->out->input( - $id, - null, - isset($field['value']) ? $field['value'] : null - ); - $this->out->dropdown( - $id . '-rel', - 'Type', - array( - 'office' => 'Office', - 'mobile' => 'Mobile', - 'home' => 'Home', - 'pager' => 'Pager', - 'other' => 'Other' - ), - null, - false, - isset($field['rel']) ? $field['rel'] : null - ); - - $this->showMultiControls(); - $this->out->elementEnd('div'); - } - - protected function showEditableWebsite($name, $field) - { - $index = isset($field['index']) ? $field['index'] : 0; - $id = "extprofile-$name-$index"; - $rel = $id . '-rel'; - $this->out->elementStart( - 'div', array( - 'id' => $id . '-edit', - 'class' => 'website-item' - ) - ); - $this->out->input( - $id, - null, - isset($field['value']) ? $field['value'] : null - ); - $this->out->dropdown( - $id . '-rel', - 'Type', - array( - 'blog' => 'Blog', - 'homepage' => 'Homepage', - 'facebook' => 'Facebook', - 'linkedin' => 'LinkedIn', - 'flickr' => 'Flickr', - 'google' => 'Google Profile', - 'other' => 'Other', - 'twitter' => 'Twitter' - ), - null, - false, - isset($field['rel']) ? $field['rel'] : null - ); - - $this->showMultiControls(); - $this->out->elementEnd('div'); - } - - protected function showExperience($name, $field) - { - $this->out->elementStart('div', 'experience-item'); - $this->out->element('div', 'label', _m('Company')); - - if (!empty($field['company'])) { - $this->out->element('div', 'field', $field['company']); - - $this->out->element('div', 'label', _m('Start')); - $this->out->element( - 'div', - array('class' => 'field date'), - date('j M Y', strtotime($field['start']) - ) - ); - $this->out->element('div', 'label', _m('End')); - $this->out->element( - 'div', - array('class' => 'field date'), - date('j M Y', strtotime($field['end']) - ) - ); - - if ($field['current']) { - $this->out->element( - 'div', - array('class' => 'field current'), - '(' . _m('Current') . ')' - ); - } - } - $this->out->elementEnd('div'); - } - - protected function showEditableExperience($name, $field) - { - $index = isset($field['index']) ? $field['index'] : 0; - $id = "extprofile-$name-$index"; - $this->out->elementStart( - 'div', array( - 'id' => $id . '-edit', - 'class' => 'experience-item' - ) - ); - - $this->out->element('div', 'label', _m('Company')); - $this->out->input( - $id, - null, - isset($field['company']) ? $field['company'] : null - ); - - $this->out->element('div', 'label', _m('Start')); - $this->out->input( - $id . '-start', - null, - isset($field['start']) ? date('j M Y', strtotime($field['start'])) : null - ); - - $this->out->element('div', 'label', _m('End')); - - $this->out->input( - $id . '-end', - null, - isset($field['end']) ? date('j M Y', strtotime($field['end'])) : null - ); - $this->out->hidden( - $id . '-current', - 'false' - ); - $this->out->elementStart('div', 'current-checkbox'); - $this->out->checkbox( - $id . '-current', - _m('Current'), - $field['current'] - ); - $this->out->elementEnd('div'); - - $this->showMultiControls(); - $this->out->elementEnd('div'); - } - - protected function showEducation($name, $field) - { - $this->out->elementStart('div', 'education-item'); - $this->out->element('div', 'label', _m('Institution')); - if (!empty($field['school'])) { - - $this->out->element('div', 'field', $field['school']); - $this->out->element('div', 'label', _m('Degree')); - $this->out->element('div', 'field', $field['degree']); - $this->out->element('div', 'label', _m('Description')); - $this->out->element('div', 'field', $field['description']); - $this->out->element('div', 'label', _m('Start')); - $this->out->element( - 'div', - array('class' => 'field date'), - date('j M Y', strtotime($field['start']) - ) - ); - $this->out->element('div', 'label', _m('End')); - $this->out->element( - 'div', - array('class' => 'field date'), - date('j M Y', strtotime($field['end']) - ) - ); - } - $this->out->elementEnd('div'); - } - - protected function showEditableEducation($name, $field) - { - $index = isset($field['index']) ? $field['index'] : 0; - $id = "extprofile-$name-$index"; - $this->out->elementStart( - 'div', array( - 'id' => $id . '-edit', - 'class' => 'education-item' - ) - ); - $this->out->element('div', 'label', _m('Institution')); - $this->out->input( - $id, - null, - isset($field['school']) ? $field['school'] : null - ); - - $this->out->element('div', 'label', _m('Degree')); - $this->out->input( - $id . '-degree', - null, - isset($field['degree']) ? $field['degree'] : null - ); - - $this->out->element('div', 'label', _m('Description')); - - $this->out->textarea( - $id . '-description', - null, - isset($field['description']) ? $field['description'] : null - ); - - $this->out->element('div', 'label', _m('Start')); - $this->out->input( - $id . '-start', - null, - isset($field['start']) ? date('j M Y', strtotime($field['start'])) : null - ); - - $this->out->element('div', 'label', _m('End')); - $this->out->input( - $id . '-end', - null, - isset($field['end']) ? date('j M Y', strtotime($field['end'])) : null - ); - - $this->showMultiControls(); - $this->out->elementEnd('div'); - } - - function showMultiControls() - { - $this->out->element( - 'a', - array( - 'class' => 'remove_row', - 'href' => 'javascript://', - 'style' => 'display: none;' - ), - '-' - ); - - $this->out->element( - 'a', - array( - 'class' => 'add_row', - 'href' => 'javascript://', - 'style' => 'display: none;' - ), - 'Add another item' - ); - } - - /** - * Outputs the value of a field - * - * @param string $name name of the field - * @param array $field set of key/value pairs for the field - */ - protected function showFieldValue($name, $field) - { - $type = strval(@$field['type']); - - switch($type) - { - case '': - case 'text': - case 'textarea': - $this->out->text($this->ext->getTextValue($name)); - break; - case 'date': - $value = $this->ext->getDateValue($name); - if (!empty($value)) { - $this->out->element( - 'div', - array('class' => 'field date'), - date('j M Y', strtotime($value)) - ); - } - break; - case 'person': - $this->out->text($this->ext->getTextValue($name)); - break; - case 'tags': - $this->out->text($this->ext->getTags()); - break; - case 'phone': - $this->showPhone($name, $field); - break; - case 'website': - $this->showWebsite($name, $field); - break; - case 'im': - $this->showIm($name, $field); - break; - case 'experience': - $this->showExperience($name, $field); - break; - case 'education': - $this->showEducation($name, $field); - break; - default: - $this->out->text("TYPE: $type"); - } - } - - /** - * Show an editable version of the field - * - * @param string $name name fo the field - * @param array $field array of key/value pairs for the field - */ - protected function showEditableField($name, $field) - { - $out = $this->out; - - $type = strval(@$field['type']); - $id = "extprofile-" . $name; - - $value = 'placeholder'; - - switch ($type) { - case '': - case 'text': - $out->input($id, null, $this->ext->getTextValue($name)); - break; - case 'date': - $value = $this->ext->getDateValue($name); - $out->input( - $id, - null, - empty($value) ? null : date('j M Y', strtotime($value)) - ); - break; - case 'person': - $out->input($id, null, $this->ext->getTextValue($name)); - break; - case 'textarea': - $out->textarea($id, null, $this->ext->getTextValue($name)); - break; - case 'tags': - $out->input($id, null, $this->ext->getTags()); - break; - case 'phone': - $this->showEditablePhone($name, $field); - break; - case 'im': - $this->showEditableIm($name, $field); - break; - case 'website': - $this->showEditableWebsite($name, $field); - break; - case 'experience': - $this->showEditableExperience($name, $field); - break; - case 'education': - $this->showEditableEducation($name, $field); - break; - default: - $out->input($id, null, "TYPE: $type"); - } - } - - /** - * Action elements - * - * @return void - */ - - function formActions() - { - $this->out->submit( - 'save', - _m('BUTTON','Save'), - 'submit form_action-secondary', - 'save', - _('Save details') - ); - } - - /** - * ID of the form - * - * @return string ID of the form - */ - - function id() - { - return 'profile-details-' . $this->profile->id; - } - - /** - * class of the form - * - * @return string of the form class - */ - - function formClass() - { - return 'form_profile_details form_settings'; - } - - /** - * Action of the form - * - * @return string URL of the action - */ - - function action() - { - return common_local_url('profiledetailsettings'); - } -} diff --git a/plugins/ExtendedProfile/lib/extendedprofile.php b/plugins/ExtendedProfile/lib/extendedprofile.php new file mode 100644 index 0000000000..fa632e5073 --- /dev/null +++ b/plugins/ExtendedProfile/lib/extendedprofile.php @@ -0,0 +1,349 @@ +. + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Class to represent extended profile data + */ +class ExtendedProfile +{ + protected $fields; + + /** + * Constructor + * + * @param Profile $profile + */ + function __construct(Profile $profile) + { + $this->profile = $profile; + $this->user = $profile->getUser(); + $this->fields = $this->loadFields(); + $this->sections = $this->getSections(); + //common_debug(var_export($this->sections, true)); + + //common_debug(var_export($this->fields, true)); + } + + /** + * Load extended profile fields + * + * @return array $fields the list of fields + */ + function loadFields() + { + $detail = new Profile_detail(); + $detail->profile_id = $this->profile->id; + $detail->find(); + + $fields = array(); + + while ($detail->fetch()) { + $fields[$detail->field_name][] = clone($detail); + } + + return $fields; + } + + /** + * Get a the self-tags associated with this profile + * + * @return string the concatenated string of tags + */ + function getTags() + { + return implode(' ', $this->user->getSelfTags()); + } + + /** + * Return a simple string value. Checks for fields that should + * be stored in the regular profile and returns values from it + * if appropriate. + * + * @param string $name name of the detail field to get the + * value from + * + * @return string the value + */ + function getTextValue($name) + { + $key = strtolower($name); + $profileFields = array('fullname', 'location', 'bio'); + + if (in_array($key, $profileFields)) { + return $this->profile->$name; + } else if (array_key_exists($key, $this->fields)) { + return $this->fields[$key][0]->field_value; + } else { + return null; + } + } + + function getDateValue($name) { + $key = strtolower($name); + if (array_key_exists($key, $this->fields)) { + return $this->fields[$key][0]->date; + } else { + return null; + } + } + + // XXX: getPhones, getIms, and getWebsites pretty much do the same thing, + // so refactor. + function getPhones() + { + $phones = (isset($this->fields['phone'])) ? $this->fields['phone'] : null; + $pArrays = array(); + + if (empty($phones)) { + $pArrays[] = array( + 'label' => _m('Phone'), + 'index' => 0, + 'type' => 'phone', + 'vcard' => 'tel', + 'rel' => 'office', + 'value' => null + ); + } else { + for ($i = 0; $i < sizeof($phones); $i++) { + $pa = array( + 'label' => _m('Phone'), + 'type' => 'phone', + 'index' => intval($phones[$i]->value_index), + 'rel' => $phones[$i]->rel, + 'value' => $phones[$i]->field_value, + 'vcard' => 'tel' + ); + + $pArrays[] = $pa; + } + } + return $pArrays; + } + + function getIms() + { + $ims = (isset($this->fields['im'])) ? $this->fields['im'] : null; + $iArrays = array(); + + if (empty($ims)) { + $iArrays[] = array( + 'label' => _m('IM'), + 'type' => 'im' + ); + } else { + for ($i = 0; $i < sizeof($ims); $i++) { + $ia = array( + 'label' => _m('IM'), + 'type' => 'im', + 'index' => intval($ims[$i]->value_index), + 'rel' => $ims[$i]->rel, + 'value' => $ims[$i]->field_value, + ); + + $iArrays[] = $ia; + } + } + return $iArrays; + } + + function getWebsites() + { + $sites = (isset($this->fields['website'])) ? $this->fields['website'] : null; + $wArrays = array(); + + if (empty($sites)) { + $wArrays[] = array( + 'label' => _m('Website'), + 'type' => 'website' + ); + } else { + for ($i = 0; $i < sizeof($sites); $i++) { + $wa = array( + 'label' => _m('Website'), + 'type' => 'website', + 'index' => intval($sites[$i]->value_index), + 'rel' => $sites[$i]->rel, + 'value' => $sites[$i]->field_value, + ); + + $wArrays[] = $wa; + } + } + return $wArrays; + } + + function getExperiences() + { + $companies = (isset($this->fields['company'])) ? $this->fields['company'] : null; + $start = (isset($this->fields['start'])) ? $this->fields['start'] : null; + $end = (isset($this->fields['end'])) ? $this->fields['end'] : null; + + $eArrays = array(); + + if (empty($companies)) { + $eArrays[] = array( + 'label' => _m('Employer'), + 'type' => 'experience', + 'company' => null, + 'start' => null, + 'end' => null, + 'current' => false, + 'index' => 0 + ); + } else { + for ($i = 0; $i < sizeof($companies); $i++) { + $ea = array( + 'label' => _m('Employer'), + 'type' => 'experience', + 'company' => $companies[$i]->field_value, + 'index' => intval($companies[$i]->value_index), + 'current' => $end[$i]->rel, + 'start' => $start[$i]->date, + 'end' => $end[$i]->date + ); + $eArrays[] = $ea; + } + } + return $eArrays; + } + + function getEducation() + { + $schools = (isset($this->fields['school'])) ? $this->fields['school'] : null; + $degrees = (isset($this->fields['degree'])) ? $this->fields['degree'] : null; + $descs = (isset($this->fields['degree_descr'])) ? $this->fields['degree_descr'] : null; + $start = (isset($this->fields['school_start'])) ? $this->fields['school_start'] : null; + $end = (isset($this->fields['school_end'])) ? $this->fields['school_end'] : null; + $iArrays = array(); + + if (empty($schools)) { + $iArrays[] = array( + 'type' => 'education', + 'label' => _m('Institution'), + 'school' => null, + 'degree' => null, + 'description' => null, + 'start' => null, + 'end' => null, + 'index' => 0 + ); + } else { + for ($i = 0; $i < sizeof($schools); $i++) { + $ia = array( + 'type' => 'education', + 'label' => _m('Institution'), + 'school' => $schools[$i]->field_value, + 'degree' => isset($degrees[$i]->field_value) ? $degrees[$i]->field_value : null, + 'description' => isset($descs[$i]->field_value) ? $descs[$i]->field_value : null, + 'index' => intval($schools[$i]->value_index), + 'start' => $start[$i]->date, + 'end' => $end[$i]->date + ); + $iArrays[] = $ia; + } + } + + return $iArrays; + } + + /** + * Return all the sections of the extended profile + * + * @return array the big list of sections and fields + */ + function getSections() + { + return array( + 'basic' => array( + 'label' => _m('Personal'), + 'fields' => array( + 'fullname' => array( + 'label' => _m('Full name'), + 'profile' => 'fullname', + 'vcard' => 'fn', + ), + 'title' => array( + 'label' => _m('Title'), + 'vcard' => 'title', + ), + 'manager' => array( + 'label' => _m('Manager'), + 'type' => 'person', + 'vcard' => 'x-manager', + ), + 'location' => array( + 'label' => _m('Location'), + 'profile' => 'location' + ), + 'bio' => array( + 'label' => _m('Bio'), + 'type' => 'textarea', + 'profile' => 'bio', + ), + 'tags' => array( + 'label' => _m('Tags'), + 'type' => 'tags', + 'profile' => 'tags', + ), + ), + ), + 'contact' => array( + 'label' => _m('Contact'), + 'fields' => array( + 'phone' => $this->getPhones(), + 'im' => $this->getIms(), + 'website' => $this->getWebsites() + ), + ), + 'personal' => array( + 'label' => _m('Personal'), + 'fields' => array( + 'birthday' => array( + 'label' => _m('Birthday'), + 'type' => 'date', + 'vcard' => 'bday', + ), + 'spouse' => array( + 'label' => _m('Spouse\'s name'), + 'vcard' => 'x-spouse', + ), + 'kids' => array( + 'label' => _m('Kids\' names') + ), + ), + ), + 'experience' => array( + 'label' => _m('Work experience'), + 'fields' => array( + 'experience' => $this->getExperiences() + ), + ), + 'education' => array( + 'label' => _m('Education'), + 'fields' => array( + 'education' => $this->getEducation() + ), + ), + ); + } +} diff --git a/plugins/ExtendedProfile/lib/extendedprofilewidget.php b/plugins/ExtendedProfile/lib/extendedprofilewidget.php new file mode 100644 index 0000000000..53cb5d3b87 --- /dev/null +++ b/plugins/ExtendedProfile/lib/extendedprofilewidget.php @@ -0,0 +1,657 @@ +. + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Class for outputting a widget to display or edit + * extended profiles + */ +class ExtendedProfileWidget extends Form +{ + const EDITABLE = true; + + /** + * The parent profile + * + * @var Profile + */ + protected $profile; + + /** + * The extended profile + * + * @var Extended_profile + */ + protected $ext; + + /** + * Constructor + * + * @param XMLOutputter $out + * @param Profile $profile + * @param boolean $editable + */ + public function __construct(XMLOutputter $out=null, Profile $profile=null, $editable=false) + { + parent::__construct($out); + + $this->profile = $profile; + $this->ext = new ExtendedProfile($this->profile); + + $this->editable = $editable; + } + + /** + * Show the extended profile, or the edit form + */ + public function show() + { + if ($this->editable) { + parent::show(); + } else { + $this->showSections(); + } + } + + /** + * Show form data + */ + public function formData() + { + // For JQuery UI modal dialog + $this->out->elementStart( + 'div', + array('id' => 'confirm-dialog', 'title' => 'Confirmation Required') + ); + $this->out->text('Really delete this entry?'); + $this->out->elementEnd('div'); + $this->showSections(); + } + + /** + * Show each section of the extended profile + */ + public function showSections() + { + $sections = $this->ext->getSections(); + foreach ($sections as $name => $section) { + $this->showExtendedProfileSection($name, $section); + } + } + + /** + * Show an extended profile section + * + * @param string $name name of the section + * @param array $section array of fields for the section + */ + protected function showExtendedProfileSection($name, $section) + { + $this->out->element('h3', null, $section['label']); + $this->out->elementStart('table', array('class' => 'extended-profile')); + + foreach ($section['fields'] as $fieldName => $field) { + + switch($fieldName) { + case 'phone': + case 'im': + case 'website': + case 'experience': + case 'education': + $this->showMultiple($fieldName, $field); + break; + default: + $this->showExtendedProfileField($fieldName, $field); + } + } + $this->out->elementEnd('table'); + } + + /** + * Show an extended profile field + * + * @param string $name name of the field + * @param array $field set of key/value pairs for the field + */ + protected function showExtendedProfileField($name, $field) + { + $this->out->elementStart('tr'); + + $this->out->element('th', str_replace(' ','_',strtolower($field['label'])), $field['label']); + + $this->out->elementStart('td'); + if ($this->editable) { + $this->showEditableField($name, $field); + } else { + $this->showFieldValue($name, $field); + } + $this->out->elementEnd('td'); + + $this->out->elementEnd('tr'); + } + + protected function showMultiple($name, $fields) { + foreach ($fields as $field) { + $this->showExtendedProfileField($name, $field); + } + } + + // XXX: showPhone, showIm and showWebsite all work the same, so + // combine + protected function showPhone($name, $field) + { + $this->out->elementStart('div', array('class' => 'phone-display')); + if (!empty($field['value'])) { + $this->out->text($field['value']); + if (!empty($field['rel'])) { + $this->out->text(' (' . $field['rel'] . ')'); + } + } + $this->out->elementEnd('div'); + } + + protected function showIm($name, $field) + { + $this->out->elementStart('div', array('class' => 'im-display')); + $this->out->text($field['value']); + if (!empty($field['rel'])) { + $this->out->text(' (' . $field['rel'] . ')'); + } + $this->out->elementEnd('div'); + } + + protected function showWebsite($name, $field) + { + $this->out->elementStart('div', array('class' => 'website-display')); + + $url = $field['value']; + + $this->out->element( + "a", + array( + 'href' => $url, + 'class' => 'extended-profile-link', + 'target' => "_blank" + ), + $url + ); + + if (!empty($field['rel'])) { + $this->out->text(' (' . $field['rel'] . ')'); + } + $this->out->elementEnd('div'); + } + + protected function showEditableIm($name, $field) + { + $index = isset($field['index']) ? $field['index'] : 0; + $id = "extprofile-$name-$index"; + $rel = $id . '-rel'; + $this->out->elementStart( + 'div', array( + 'id' => $id . '-edit', + 'class' => 'im-item' + ) + ); + $this->out->input( + $id, + null, + isset($field['value']) ? $field['value'] : null + ); + $this->out->dropdown( + $id . '-rel', + 'Type', + array( + 'jabber' => 'Jabber', + 'gtalk' => 'GTalk', + 'aim' => 'AIM', + 'yahoo' => 'Yahoo! Messenger', + 'msn' => 'MSN', + 'skype' => 'Skype', + 'other' => 'Other' + ), + null, + false, + isset($field['rel']) ? $field['rel'] : null + ); + + $this->showMultiControls(); + $this->out->elementEnd('div'); + } + + protected function showEditablePhone($name, $field) + { + $index = isset($field['index']) ? $field['index'] : 0; + $id = "extprofile-$name-$index"; + $rel = $id . '-rel'; + $this->out->elementStart( + 'div', array( + 'id' => $id . '-edit', + 'class' => 'phone-item' + ) + ); + $this->out->input( + $id, + null, + isset($field['value']) ? $field['value'] : null + ); + $this->out->dropdown( + $id . '-rel', + 'Type', + array( + 'office' => 'Office', + 'mobile' => 'Mobile', + 'home' => 'Home', + 'pager' => 'Pager', + 'other' => 'Other' + ), + null, + false, + isset($field['rel']) ? $field['rel'] : null + ); + + $this->showMultiControls(); + $this->out->elementEnd('div'); + } + + protected function showEditableWebsite($name, $field) + { + $index = isset($field['index']) ? $field['index'] : 0; + $id = "extprofile-$name-$index"; + $rel = $id . '-rel'; + $this->out->elementStart( + 'div', array( + 'id' => $id . '-edit', + 'class' => 'website-item' + ) + ); + $this->out->input( + $id, + null, + isset($field['value']) ? $field['value'] : null + ); + $this->out->dropdown( + $id . '-rel', + 'Type', + array( + 'blog' => 'Blog', + 'homepage' => 'Homepage', + 'facebook' => 'Facebook', + 'linkedin' => 'LinkedIn', + 'flickr' => 'Flickr', + 'google' => 'Google Profile', + 'other' => 'Other', + 'twitter' => 'Twitter' + ), + null, + false, + isset($field['rel']) ? $field['rel'] : null + ); + + $this->showMultiControls(); + $this->out->elementEnd('div'); + } + + protected function showExperience($name, $field) + { + $this->out->elementStart('div', 'experience-item'); + $this->out->element('div', 'label', _m('Company')); + + if (!empty($field['company'])) { + $this->out->element('div', 'field', $field['company']); + + $this->out->element('div', 'label', _m('Start')); + $this->out->element( + 'div', + array('class' => 'field date'), + date('j M Y', strtotime($field['start']) + ) + ); + $this->out->element('div', 'label', _m('End')); + $this->out->element( + 'div', + array('class' => 'field date'), + date('j M Y', strtotime($field['end']) + ) + ); + + if ($field['current']) { + $this->out->element( + 'div', + array('class' => 'field current'), + '(' . _m('Current') . ')' + ); + } + } + $this->out->elementEnd('div'); + } + + protected function showEditableExperience($name, $field) + { + $index = isset($field['index']) ? $field['index'] : 0; + $id = "extprofile-$name-$index"; + $this->out->elementStart( + 'div', array( + 'id' => $id . '-edit', + 'class' => 'experience-item' + ) + ); + + $this->out->element('div', 'label', _m('Company')); + $this->out->input( + $id, + null, + isset($field['company']) ? $field['company'] : null + ); + + $this->out->element('div', 'label', _m('Start')); + $this->out->input( + $id . '-start', + null, + isset($field['start']) ? date('j M Y', strtotime($field['start'])) : null + ); + + $this->out->element('div', 'label', _m('End')); + + $this->out->input( + $id . '-end', + null, + isset($field['end']) ? date('j M Y', strtotime($field['end'])) : null + ); + $this->out->hidden( + $id . '-current', + 'false' + ); + $this->out->elementStart('div', 'current-checkbox'); + $this->out->checkbox( + $id . '-current', + _m('Current'), + $field['current'] + ); + $this->out->elementEnd('div'); + + $this->showMultiControls(); + $this->out->elementEnd('div'); + } + + protected function showEducation($name, $field) + { + $this->out->elementStart('div', 'education-item'); + $this->out->element('div', 'label', _m('Institution')); + if (!empty($field['school'])) { + + $this->out->element('div', 'field', $field['school']); + $this->out->element('div', 'label', _m('Degree')); + $this->out->element('div', 'field', $field['degree']); + $this->out->element('div', 'label', _m('Description')); + $this->out->element('div', 'field', $field['description']); + $this->out->element('div', 'label', _m('Start')); + $this->out->element( + 'div', + array('class' => 'field date'), + date('j M Y', strtotime($field['start']) + ) + ); + $this->out->element('div', 'label', _m('End')); + $this->out->element( + 'div', + array('class' => 'field date'), + date('j M Y', strtotime($field['end']) + ) + ); + } + $this->out->elementEnd('div'); + } + + protected function showEditableEducation($name, $field) + { + $index = isset($field['index']) ? $field['index'] : 0; + $id = "extprofile-$name-$index"; + $this->out->elementStart( + 'div', array( + 'id' => $id . '-edit', + 'class' => 'education-item' + ) + ); + $this->out->element('div', 'label', _m('Institution')); + $this->out->input( + $id, + null, + isset($field['school']) ? $field['school'] : null + ); + + $this->out->element('div', 'label', _m('Degree')); + $this->out->input( + $id . '-degree', + null, + isset($field['degree']) ? $field['degree'] : null + ); + + $this->out->element('div', 'label', _m('Description')); + + $this->out->textarea( + $id . '-description', + null, + isset($field['description']) ? $field['description'] : null + ); + + $this->out->element('div', 'label', _m('Start')); + $this->out->input( + $id . '-start', + null, + isset($field['start']) ? date('j M Y', strtotime($field['start'])) : null + ); + + $this->out->element('div', 'label', _m('End')); + $this->out->input( + $id . '-end', + null, + isset($field['end']) ? date('j M Y', strtotime($field['end'])) : null + ); + + $this->showMultiControls(); + $this->out->elementEnd('div'); + } + + function showMultiControls() + { + $this->out->element( + 'a', + array( + 'class' => 'remove_row', + 'href' => 'javascript://', + 'style' => 'display: none;' + ), + '-' + ); + + $this->out->element( + 'a', + array( + 'class' => 'add_row', + 'href' => 'javascript://', + 'style' => 'display: none;' + ), + 'Add another item' + ); + } + + /** + * Outputs the value of a field + * + * @param string $name name of the field + * @param array $field set of key/value pairs for the field + */ + protected function showFieldValue($name, $field) + { + $type = strval(@$field['type']); + + switch($type) + { + case '': + case 'text': + case 'textarea': + $this->out->text($this->ext->getTextValue($name)); + break; + case 'date': + $value = $this->ext->getDateValue($name); + if (!empty($value)) { + $this->out->element( + 'div', + array('class' => 'field date'), + date('j M Y', strtotime($value)) + ); + } + break; + case 'person': + $this->out->text($this->ext->getTextValue($name)); + break; + case 'tags': + $this->out->text($this->ext->getTags()); + break; + case 'phone': + $this->showPhone($name, $field); + break; + case 'website': + $this->showWebsite($name, $field); + break; + case 'im': + $this->showIm($name, $field); + break; + case 'experience': + $this->showExperience($name, $field); + break; + case 'education': + $this->showEducation($name, $field); + break; + default: + $this->out->text("TYPE: $type"); + } + } + + /** + * Show an editable version of the field + * + * @param string $name name fo the field + * @param array $field array of key/value pairs for the field + */ + protected function showEditableField($name, $field) + { + $out = $this->out; + + $type = strval(@$field['type']); + $id = "extprofile-" . $name; + + $value = 'placeholder'; + + switch ($type) { + case '': + case 'text': + $out->input($id, null, $this->ext->getTextValue($name)); + break; + case 'date': + $value = $this->ext->getDateValue($name); + $out->input( + $id, + null, + empty($value) ? null : date('j M Y', strtotime($value)) + ); + break; + case 'person': + $out->input($id, null, $this->ext->getTextValue($name)); + break; + case 'textarea': + $out->textarea($id, null, $this->ext->getTextValue($name)); + break; + case 'tags': + $out->input($id, null, $this->ext->getTags()); + break; + case 'phone': + $this->showEditablePhone($name, $field); + break; + case 'im': + $this->showEditableIm($name, $field); + break; + case 'website': + $this->showEditableWebsite($name, $field); + break; + case 'experience': + $this->showEditableExperience($name, $field); + break; + case 'education': + $this->showEditableEducation($name, $field); + break; + default: + $out->input($id, null, "TYPE: $type"); + } + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit( + 'save', + _m('BUTTON','Save'), + 'submit form_action-secondary', + 'save', + _('Save details') + ); + } + + /** + * ID of the form + * + * @return string ID of the form + */ + + function id() + { + return 'profile-details-' . $this->profile->id; + } + + /** + * class of the form + * + * @return string of the form class + */ + + function formClass() + { + return 'form_profile_details form_settings'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('profiledetailsettings'); + } +} diff --git a/plugins/ExtendedProfile/profiledetailaction.php b/plugins/ExtendedProfile/profiledetailaction.php deleted file mode 100644 index a777a28e03..0000000000 --- a/plugins/ExtendedProfile/profiledetailaction.php +++ /dev/null @@ -1,63 +0,0 @@ -. - */ - -if (!defined('STATUSNET')) { - exit(1); -} - -class ProfileDetailAction extends ShowstreamAction -{ - - function isReadOnly($args) - { - return true; - } - - function title() - { - return $this->profile->getFancyName(); - } - - function showStylesheets() { - parent::showStylesheets(); - $this->cssLink('plugins/ExtendedProfile/css/profiledetail.css'); - return true; - } - - function showContent() - { - $cur = common_current_user(); - if ($cur && $cur->id == $this->profile->id) { // your own page - $this->elementStart('div', 'entity_actions'); - $this->elementStart('ul'); - $this->elementStart('li', 'entity_edit'); - $this->element('a', array('href' => common_local_url('profiledetailsettings'), - // TRANS: Link title for link on user profile. - 'title' => _m('Edit extended profile settings')), - // TRANS: Link text for link on user profile. - _m('Edit')); - $this->elementEnd('li'); - $this->elementEnd('ul'); - $this->elementEnd('div'); - } - - $widget = new ExtendedProfileWidget($this, $this->profile); - $widget->show(); - } -} diff --git a/plugins/ExtendedProfile/profiledetailsettingsaction.php b/plugins/ExtendedProfile/profiledetailsettingsaction.php deleted file mode 100644 index 4a2045cefb..0000000000 --- a/plugins/ExtendedProfile/profiledetailsettingsaction.php +++ /dev/null @@ -1,632 +0,0 @@ -. - */ - -if (!defined('STATUSNET')) { - exit(1); -} - -class ProfileDetailSettingsAction extends ProfileSettingsAction -{ - - function title() - { - return _m('Extended profile settings'); - } - - /** - * Instructions for use - * - * @return instructions for use - */ - function getInstructions() - { - // TRANS: Usage instructions for profile settings. - return _('You can update your personal profile info here '. - 'so people know more about you.'); - } - - function showStylesheets() { - parent::showStylesheets(); - $this->cssLink('plugins/ExtendedProfile/css/profiledetail.css'); - return true; - } - - function showScripts() { - parent::showScripts(); - $this->script('plugins/ExtendedProfile/js/profiledetail.js'); - return true; - } - - function handlePost() - { - // CSRF protection - $token = $this->trimmed('token'); - if (!$token || $token != common_session_token()) { - $this->showForm( - _m( - 'There was a problem with your session token. ' - . 'Try again, please.' - ) - ); - return; - } - - if ($this->arg('save')) { - $this->saveDetails(); - } else { - // TRANS: Message given submitting a form with an unknown action - $this->showForm(_m('Unexpected form submission.')); - } - } - - function showContent() - { - $cur = common_current_user(); - $profile = $cur->getProfile(); - - $widget = new ExtendedProfileWidget( - $this, - $profile, - ExtendedProfileWidget::EDITABLE - ); - $widget->show(); - } - - function saveDetails() - { - common_debug(var_export($_POST, true)); - - $user = common_current_user(); - - try { - $this->saveStandardProfileDetails($user); - - $profile = $user->getProfile(); - - $simpleFieldNames = array('title', 'spouse', 'kids', 'manager'); - $dateFieldNames = array('birthday'); - - foreach ($simpleFieldNames as $name) { - $value = $this->trimmed('extprofile-' . $name); - if (!empty($value)) { - $this->saveField($user, $name, $value); - } - } - - foreach ($dateFieldNames as $name) { - $value = $this->trimmed('extprofile-' . $name); - $dateVal = $this->parseDate($name, $value); - $this->saveField( - $user, - $name, - null, - null, - null, - $dateVal - ); - } - - $this->savePhoneNumbers($user); - $this->saveIms($user); - $this->saveWebsites($user); - $this->saveExperiences($user); - $this->saveEducations($user); - - } catch (Exception $e) { - $this->showForm($e->getMessage(), false); - return; - } - - $this->showForm(_('Details saved.'), true); - - } - - function parseDate($fieldname, $datestr, $required = false) - { - if (empty($datestr) && $required) { - $msg = sprintf( - _m('You must supply a date for "%s".'), - $fieldname - ); - throw new Exception($msg); - } else { - $ts = strtotime($datestr); - if ($ts === false) { - throw new Exception( - sprintf( - _m('Invalid date entered for "%s": %s'), - $fieldname, - $ts - ) - ); - } - return common_sql_date($ts); - } - return null; - } - - function savePhoneNumbers($user) { - $phones = $this->findPhoneNumbers(); - $this->removeAll($user, 'phone'); - $i = 0; - foreach($phones as $phone) { - if (!empty($phone['value'])) { - ++$i; - $this->saveField( - $user, - 'phone', - $phone['value'], - $phone['rel'], - $i - ); - } - } - } - - function findPhoneNumbers() { - - // Form vals look like this: - // 'extprofile-phone-1' => '11332', - // 'extprofile-phone-1-rel' => 'mobile', - - $phones = $this->sliceParams('phone', 2); - $phoneArray = array(); - - foreach ($phones as $phone) { - list($number, $rel) = array_values($phone); - $phoneArray[] = array( - 'value' => $number, - 'rel' => $rel - ); - } - - return $phoneArray; - } - - function findIms() { - - // Form vals look like this: - // 'extprofile-im-0' => 'jed', - // 'extprofile-im-0-rel' => 'yahoo', - - $ims = $this->sliceParams('im', 2); - $imArray = array(); - - foreach ($ims as $im) { - list($id, $rel) = array_values($im); - $imArray[] = array( - 'value' => $id, - 'rel' => $rel - ); - } - - return $imArray; - } - - function saveIms($user) { - $ims = $this->findIms(); - $this->removeAll($user, 'im'); - $i = 0; - foreach($ims as $im) { - if (!empty($im['value'])) { - ++$i; - $this->saveField( - $user, - 'im', - $im['value'], - $im['rel'], - $i - ); - } - } - } - - function findWebsites() { - - // Form vals look like this: - - $sites = $this->sliceParams('website', 2); - $wsArray = array(); - - foreach ($sites as $site) { - list($id, $rel) = array_values($site); - $wsArray[] = array( - 'value' => $id, - 'rel' => $rel - ); - } - - return $wsArray; - } - - function saveWebsites($user) { - $sites = $this->findWebsites(); - $this->removeAll($user, 'website'); - $i = 0; - foreach($sites as $site) { - if (!empty($site['value']) && !Validate::uri( - $site['value'], - array('allowed_schemes' => array('http', 'https'))) - ) { - throw new Exception(sprintf(_m('Invalid URL: %s'), $site['value'])); - } - - if (!empty($site['value'])) { - ++$i; - $this->saveField( - $user, - 'website', - $site['value'], - $site['rel'], - $i - ); - } - } - } - - function findExperiences() { - - // Form vals look like this: - // 'extprofile-experience-0' => 'Bozotronix', - // 'extprofile-experience-0-current' => 'true' - // 'extprofile-experience-0-start' => '1/5/10', - // 'extprofile-experience-0-end' => '2/3/11', - - $experiences = $this->sliceParams('experience', 4); - $expArray = array(); - - foreach ($experiences as $exp) { - if (sizeof($experiences) == 4) { - list($company, $current, $end, $start) = array_values($exp); - } else { - $end = null; - list($company, $current, $start) = array_values($exp); - } - if (!empty($company)) { - $expArray[] = array( - 'company' => $company, - 'start' => $this->parseDate('Start', $start, true), - 'end' => ($current == 'false') ? $this->parseDate('End', $end, true) : null, - 'current' => ($current == 'false') ? false : true - ); - } - } - - return $expArray; - } - - function saveExperiences($user) { - common_debug('save experiences'); - $experiences = $this->findExperiences(); - - $this->removeAll($user, 'company'); - $this->removeAll($user, 'start'); - $this->removeAll($user, 'end'); // also stores 'current' - - $i = 0; - foreach($experiences as $experience) { - if (!empty($experience['company'])) { - ++$i; - $this->saveField( - $user, - 'company', - $experience['company'], - null, - $i - ); - - $this->saveField( - $user, - 'start', - null, - null, - $i, - $experience['start'] - ); - - // Save "current" employer indicator in rel - if ($experience['current']) { - $this->saveField( - $user, - 'end', - null, - 'current', // rel - $i - ); - } else { - $this->saveField( - $user, - 'end', - null, - null, - $i, - $experience['end'] - ); - } - - } - } - } - - function findEducations() { - - // Form vals look like this: - // 'extprofile-education-0-school' => 'Pigdog', - // 'extprofile-education-0-degree' => 'BA', - // 'extprofile-education-0-description' => 'Blar', - // 'extprofile-education-0-start' => '05/22/99', - // 'extprofile-education-0-end' => '05/22/05', - - $edus = $this->sliceParams('education', 5); - $eduArray = array(); - - foreach ($edus as $edu) { - list($school, $degree, $description, $end, $start) = array_values($edu); - if (!empty($school)) { - $eduArray[] = array( - 'school' => $school, - 'degree' => $degree, - 'description' => $description, - 'start' => $this->parseDate('Start', $start, true), - 'end' => $this->parseDate('End', $end, true) - ); - } - } - - return $eduArray; - } - - - function saveEducations($user) { - common_debug('save education'); - $edus = $this->findEducations(); - common_debug(var_export($edus, true)); - - $this->removeAll($user, 'school'); - $this->removeAll($user, 'degree'); - $this->removeAll($user, 'degree_descr'); - $this->removeAll($user, 'school_start'); - $this->removeAll($user, 'school_end'); - - $i = 0; - foreach($edus as $edu) { - if (!empty($edu['school'])) { - ++$i; - $this->saveField( - $user, - 'school', - $edu['school'], - null, - $i - ); - $this->saveField( - $user, - 'degree', - $edu['degree'], - null, - $i - ); - $this->saveField( - $user, - 'degree_descr', - $edu['description'], - null, - $i - ); - $this->saveField( - $user, - 'school_start', - null, - null, - $i, - $edu['start'] - ); - - $this->saveField( - $user, - 'school_end', - null, - null, - $i, - $edu['end'] - ); - } - } - } - - function arraySplit($array, $pieces) - { - if ($pieces < 2) { - return array($array); - } - - $newCount = ceil(count($array) / $pieces); - $a = array_slice($array, 0, $newCount); - $b = $this->arraySplit(array_slice($array, $newCount), $pieces - 1); - - return array_merge(array($a), $b); - } - - function findMultiParams($type) { - $formVals = array(); - $target = $type; - foreach ($_POST as $key => $val) { - if (strrpos('extprofile-' . $key, $target) !== false) { - $formVals[$key] = $val; - } - } - return $formVals; - } - - function sliceParams($key, $size) { - $slice = array(); - $params = $this->findMultiParams($key); - ksort($params); - $slice = $this->arraySplit($params, sizeof($params) / $size); - return $slice; - } - - /** - * Save an extended profile field as a Profile_detail - * - * @param User $user the current user - * @param string $name field name - * @param string $value field value - * @param string $rel field rel (type) - * @param int $index index (fields can have multiple values) - * @param date $date related date - */ - function saveField($user, $name, $value, $rel = null, $index = null, $date = null) - { - $profile = $user->getProfile(); - $detail = new Profile_detail(); - - $detail->profile_id = $profile->id; - $detail->field_name = $name; - $detail->value_index = $index; - - $result = $detail->find(true); - - if (empty($result)) { - $detial->value_index = $index; - $detail->rel = $rel; - $detail->field_value = $value; - $detail->date = $date; - $detail->created = common_sql_now(); - $result = $detail->insert(); - if (empty($result)) { - common_log_db_error($detail, 'INSERT', __FILE__); - $this->serverError(_m('Could not save profile details.')); - } - } else { - $orig = clone($detail); - - $detail->field_value = $value; - $detail->rel = $rel; - $detail->date = $date; - - $result = $detail->update($orig); - if (empty($result)) { - common_log_db_error($detail, 'UPDATE', __FILE__); - $this->serverError(_m('Could not save profile details.')); - } - } - - $detail->free(); - } - - function removeAll($user, $name) - { - $profile = $user->getProfile(); - $detail = new Profile_detail(); - $detail->profile_id = $profile->id; - $detail->field_name = $name; - $detail->delete(); - $detail->free(); - } - - /** - * Save fields that should be stored in the main profile object - * - * XXX: There's a lot of dupe code here from ProfileSettingsAction. - * Do not want. - * - * @param User $user the current user - */ - function saveStandardProfileDetails($user) - { - $fullname = $this->trimmed('extprofile-fullname'); - $location = $this->trimmed('extprofile-location'); - $tagstring = $this->trimmed('extprofile-tags'); - $bio = $this->trimmed('extprofile-bio'); - - if ($tagstring) { - $tags = array_map( - 'common_canonical_tag', - preg_split('/[\s,]+/', $tagstring) - ); - } else { - $tags = array(); - } - - foreach ($tags as $tag) { - if (!common_valid_profile_tag($tag)) { - // TRANS: Validation error in form for profile settings. - // TRANS: %s is an invalid tag. - throw new Exception(sprintf(_m('Invalid tag: "%s".'), $tag)); - } - } - - $profile = $user->getProfile(); - - $oldTags = $user->getSelfTags(); - $newTags = array_diff($tags, $oldTags); - - if ($fullname != $profile->fullname - || $location != $profile->location - || !empty($newTags) - || $bio != $profile->bio) { - - $orig = clone($profile); - - $profile->nickname = $user->nickname; - $profile->fullname = $fullname; - $profile->bio = $bio; - $profile->location = $location; - - $loc = Location::fromName($location); - - if (empty($loc)) { - $profile->lat = null; - $profile->lon = null; - $profile->location_id = null; - $profile->location_ns = null; - } else { - $profile->lat = $loc->lat; - $profile->lon = $loc->lon; - $profile->location_id = $loc->location_id; - $profile->location_ns = $loc->location_ns; - } - - $profile->profileurl = common_profile_url($user->nickname); - - $result = $profile->update($orig); - - if ($result === false) { - common_log_db_error($profile, 'UPDATE', __FILE__); - // TRANS: Server error thrown when user profile settings could not be saved. - $this->serverError(_('Could not save profile.')); - return; - } - - // Set the user tags - $result = $user->setSelfTags($tags); - - if (!$result) { - // TRANS: Server error thrown when user profile settings tags could not be saved. - $this->serverError(_('Could not save tags.')); - return; - } - - Event::handle('EndProfileSaveForm', array($this)); - common_broadcast_profile($profile); - } - } - -}