*/
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;
}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-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'),
- )
- );
- }
-
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Action for showing Twitter-like JSON search results
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * @category Search
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @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;
- }
-}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+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();
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+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);
+ }
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Action for showing Twitter-like JSON search results
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Search
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @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;
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+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'),
+ )
+ );
+ }
+
+}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-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()
- ),
- ),
- );
- }
-}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-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');
- }
-}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+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()
+ ),
+ ),
+ );
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+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');
+ }
+}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-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();
- }
-}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-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);
- }
- }
-
-}