X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=plugins%2FPoll%2FPollPlugin.php;h=a6292032c51b7cdc41205ff31bec7cd7c10d1bae;hb=8205c56e25da078e84a8e1cb0a27755339ce43b2;hp=f76faedb05d52acebf23bbfe73a1076070898fe3;hpb=6416f5ea4113cdc2e32132d387ce1cf526f35062;p=quix0rs-gnu-social.git diff --git a/plugins/Poll/PollPlugin.php b/plugins/Poll/PollPlugin.php index f76faedb05..a6292032c5 100644 --- a/plugins/Poll/PollPlugin.php +++ b/plugins/Poll/PollPlugin.php @@ -43,14 +43,13 @@ if (!defined('STATUSNET')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @link http://status.net/ */ - class PollPlugin extends MicroAppPlugin { const VERSION = '0.1'; // @fixme which domain should we use for these namespaces? - const POLL_OBJECT = 'http://apinamespace.org/activitystreams/object/poll'; - const POLL_RESPONSE_OBJECT = 'http://apinamespace.org/activitystreams/object/poll-response'; + const POLL_OBJECT = 'http://activityschema.org/object/poll'; + const POLL_RESPONSE_OBJECT = 'http://activityschema.org/object/poll-response'; /** * Database schema setup @@ -60,12 +59,12 @@ class PollPlugin extends MicroAppPlugin * * @return boolean hook value; true means continue processing, false means stop. */ - function onCheckSchema() { $schema = Schema::get(); $schema->ensureTable('poll', Poll::schemaDef()); $schema->ensureTable('poll_response', Poll_response::schemaDef()); + $schema->ensureTable('user_poll_prefs', User_poll_prefs::schemaDef()); return true; } @@ -76,46 +75,12 @@ class PollPlugin extends MicroAppPlugin * * @return boolean hook value */ - function onEndShowStyles($action) { $action->cssLink($this->path('poll.css')); return true; } - /** - * Load related modules when needed - * - * @param string $cls Name of the class to be loaded - * - * @return boolean hook value; true means continue processing, false means stop. - */ - - function onAutoload($cls) - { - $dir = dirname(__FILE__); - - switch ($cls) - { - case 'ShowpollAction': - case 'NewpollAction': - case 'RespondpollAction': - include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; - return false; - case 'Poll': - case 'Poll_response': - include_once $dir.'/'.$cls.'.php'; - return false; - case 'NewPollForm': - case 'PollResponseForm': - case 'PollResultForm': - include_once $dir.'/'.strtolower($cls).'.php'; - return false; - default: - return true; - } - } - /** * Map URLs to actions * @@ -123,7 +88,6 @@ class PollPlugin extends MicroAppPlugin * * @return boolean hook value; true means continue processing, false means stop. */ - function onRouterInitialized($m) { $m->connect('main/poll/new', @@ -141,6 +105,9 @@ class PollPlugin extends MicroAppPlugin array('action' => 'respondpoll'), array('id' => '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')); + $m->connect('settings/poll', + array('action' => 'pollsettings')); + return true; } @@ -151,7 +118,6 @@ class PollPlugin extends MicroAppPlugin * * @return value */ - function onPluginVersion(&$versions) { $versions[] = array('name' => 'Poll', @@ -159,6 +125,7 @@ class PollPlugin extends MicroAppPlugin 'author' => 'Brion Vibber', 'homepage' => 'http://status.net/wiki/Plugin:Poll', 'rawdescription' => + // TRANS: Plugin description. _m('Simple extension for supporting basic polls.')); return true; } @@ -175,7 +142,6 @@ class PollPlugin extends MicroAppPlugin * * @return boolean hook value */ - function deleteRelated($notice) { $p = Poll::getByNotice($notice); @@ -196,7 +162,6 @@ class PollPlugin extends MicroAppPlugin * * @return Notice resulting notice */ - function saveNoticeFromActivity($activity, $profile, $options=array()) { // @fixme @@ -210,26 +175,22 @@ class PollPlugin extends MicroAppPlugin $pollElements = $activity->entry->getElementsByTagNameNS(self::POLL_OBJECT, 'poll'); $responseElements = $activity->entry->getElementsByTagNameNS(self::POLL_OBJECT, 'response'); if ($pollElements->length) { - $data = $pollElements->item(0); - $question = $data->getAttribute('question'); + $question = ''; $opts = array(); - foreach ($data->attributes as $node) { - $name = $node->nodeName; - if (substr($name, 0, 6) == 'option') { - $n = intval(substr($name, 6)); - if ($n > 0) { - $opts[$n - 1] = $node->nodeValue; - } - } + + $data = $pollElements->item(0); + foreach ($data->getElementsByTagNameNS(self::POLL_OBJECT, 'question') as $node) { + $question = $node->textContent; + } + foreach ($data->getElementsByTagNameNS(self::POLL_OBJECT, 'option') as $node) { + $opts[] = $node->textContent; } - common_log(LOG_DEBUG, "YYY question: $question"); - common_log(LOG_DEBUG, "YYY opts: " . var_export($opts, true)); try { $notice = Poll::saveNew($profile, $question, $opts, $options); - common_log(LOG_DEBUG, "YYY ok: " . $notice->id); + common_log(LOG_DEBUG, "Saved Poll from ActivityStream data ok: notice id " . $notice->id); return $notice; } catch (Exception $e) { - common_log(LOG_DEBUG, "YYY fail: " . $e->getMessage()); + common_log(LOG_DEBUG, "Poll save from ActivityStream data failed: " . $e->getMessage()); } } else if ($responseElements->length) { $data = $responseElements->item(0); @@ -237,18 +198,20 @@ class PollPlugin extends MicroAppPlugin $selection = intval($data->getAttribute('selection')); if (!$pollUri) { - throw new Exception('Invalid poll response: no poll reference.'); + // TRANS: Exception thrown trying to respond to a poll without a poll reference. + throw new Exception(_m('Invalid poll response: No poll reference.')); } - $poll = Poll::staticGet('uri', $pollUri); + $poll = Poll::getKV('uri', $pollUri); if (!$poll) { - throw new Exception('Invalid poll response: poll is unknown.'); + // TRANS: Exception thrown trying to respond to a non-existing poll. + throw new Exception(_m('Invalid poll response: Poll is unknown.')); } try { $notice = Poll_response::saveNew($profile, $poll, $selection, $options); - common_log(LOG_DEBUG, "YYY response ok: " . $notice->id); + common_log(LOG_DEBUG, "Saved Poll_response ok, notice id: " . $notice->id); return $notice; } catch (Exception $e) { - common_log(LOG_DEBUG, "YYY response fail: " . $e->getMessage()); + common_log(LOG_DEBUG, "Poll response save fail: " . $e->getMessage()); } } else { common_log(LOG_DEBUG, "YYY no poll data"); @@ -266,7 +229,9 @@ class PollPlugin extends MicroAppPlugin case self::POLL_RESPONSE_OBJECT: return $this->activityObjectFromNoticePollResponse($notice); default: - throw new Exception('Unexpected type for poll plugin: ' . $notice->object_type); + // TRANS: Exception thrown when performing an unexpected action on a poll. + // TRANS: %s is the unexpected object type. + throw new Exception(sprintf(_m('Unexpected type for poll plugin: %s.'), $notice->object_type)); } } @@ -274,37 +239,22 @@ class PollPlugin extends MicroAppPlugin { $object = new ActivityObject(); $object->id = $notice->uri; - $object->type = self::POLL_OBJECT; + $object->type = self::POLL_RESPONSE_OBJECT; $object->title = $notice->content; $object->summary = $notice->content; $object->link = $notice->bestUrl(); $response = Poll_response::getByNotice($notice); - $poll = $response->getPoll(); - - /** - * For the moment, using a kind of icky-looking schema that happens to - * work with out code for generating both Atom and JSON forms, though - * I don't like it: - * - * - * - * "poll:response": { - * "xmlns:poll": http://apinamespace.org/activitystreams/object/poll - * "uri": "http://..../poll/...." - * "selection": 3 - * } - * - */ - // @fixme there's no way to specify an XML node tree here, like - // @fixme there's no way to specify a JSON array or multi-level tree unless you break the XML attribs - // @fixme XML node contents don't get shown in JSON - $data = array('xmlns:poll' => self::POLL_OBJECT, - 'poll' => $poll->uri, - 'selection' => intval($response->selection)); - $object->extra[] = array('poll:response', $data, ''); + if ($response) { + $poll = $response->getPoll(); + if ($poll) { + // Stash data to be formatted later by + // $this->activityObjectOutputAtom() or + // $this->activityObjectOutputJson()... + $object->pollSelection = intval($response->selection); + $object->pollUri = $poll->uri; + } + } return $object; } @@ -312,47 +262,118 @@ class PollPlugin extends MicroAppPlugin { $object = new ActivityObject(); $object->id = $notice->uri; - $object->type = self::POLL_RESPONSE_OBJECT; + $object->type = self::POLL_OBJECT; $object->title = $notice->content; $object->summary = $notice->content; $object->link = $notice->bestUrl(); $poll = Poll::getByNotice($notice); - /** - * Adding the poll-specific data. There's no standard in AS for polls, - * so we're making stuff up. - * - * For the moment, using a kind of icky-looking schema that happens to - * work with out code for generating both Atom and JSON forms, though - * I don't like it: - * - * - * - * "poll:response": { - * "xmlns:poll": http://apinamespace.org/activitystreams/object/poll - * "question": "Who wants a poll question?" - * "option1": "Option one" - * "option2": "Option two" - * "option3": "Option three" - * } - * - */ - // @fixme there's no way to specify an XML node tree here, like - // @fixme there's no way to specify a JSON array or multi-level tree unless you break the XML attribs - // @fixme XML node contents don't get shown in JSON - $data = array('xmlns:poll' => self::POLL_OBJECT, - 'question' => $poll->question); - foreach ($poll->getOptions() as $i => $opt) { - $data['option' . ($i + 1)] = $opt; + if ($poll) { + // Stash data to be formatted later by + // $this->activityObjectOutputAtom() or + // $this->activityObjectOutputJson()... + $object->pollQuestion = $poll->question; + $object->pollOptions = $poll->getOptions(); } - $object->extra[] = array('poll:poll', $data, ''); + return $object; } + /** + * Called when generating Atom XML ActivityStreams output from an + * ActivityObject belonging to this plugin. Gives the plugin + * a chance to add custom output. + * + * Note that you can only add output of additional XML elements, + * not change existing stuff here. + * + * If output is already handled by the base Activity classes, + * you can leave this base implementation as a no-op. + * + * @param ActivityObject $obj + * @param XMLOutputter $out to add elements at end of object + */ + function activityObjectOutputAtom(ActivityObject $obj, XMLOutputter $out) + { + if (isset($obj->pollQuestion)) { + /** + * + * Who wants a poll question? + * Option one + * Option two + * Option three + * + */ + $data = array('xmlns:poll' => self::POLL_OBJECT); + $out->elementStart('poll:poll', $data); + $out->element('poll:question', array(), $obj->pollQuestion); + foreach ($obj->pollOptions as $opt) { + $out->element('poll:option', array(), $opt); + } + $out->elementEnd('poll:poll'); + } + if (isset($obj->pollSelection)) { + /** + * + * poll="http://..../poll/...." + * selection="3" /> + */ + $data = array('xmlns:poll' => self::POLL_OBJECT, + 'poll' => $obj->pollUri, + 'selection' => $obj->pollSelection); + $out->element('poll:response', $data, ''); + } + } + + /** + * Called when generating JSON ActivityStreams output from an + * ActivityObject belonging to this plugin. Gives the plugin + * a chance to add custom output. + * + * Modify the array contents to your heart's content, and it'll + * all get serialized out as JSON. + * + * If output is already handled by the base Activity classes, + * you can leave this base implementation as a no-op. + * + * @param ActivityObject $obj + * @param array &$out JSON-targeted array which can be modified + */ + public function activityObjectOutputJson(ActivityObject $obj, array &$out) + { + common_log(LOG_DEBUG, 'QQQ: ' . var_export($obj, true)); + if (isset($obj->pollQuestion)) { + /** + * "poll": { + * "question": "Who wants a poll question?", + * "options": [ + * "Option 1", + * "Option 2", + * "Option 3" + * ] + * } + */ + $data = array('question' => $obj->pollQuestion, + 'options' => array()); + foreach ($obj->pollOptions as $opt) { + $data['options'][] = $opt; + } + $out['poll'] = $data; + } + if (isset($obj->pollSelection)) { + /** + * "pollResponse": { + * "poll": "http://..../poll/....", + * "selection": 3 + * } + */ + $data = array('poll' => $obj->pollUri, + 'selection' => $obj->pollSelection); + $out['pollResponse'] = $data; + } + } + + /** * @fixme WARNING WARNING WARNING parent class closes the final div that we * open here, but we probably shouldn't open it here. Check parent class @@ -366,7 +387,9 @@ class PollPlugin extends MicroAppPlugin case self::POLL_RESPONSE_OBJECT: return $this->showNoticePollResponse($notice, $out); default: - throw new Exception('Unexpected type for poll plugin: ' . $notice->object_type); + // TRANS: Exception thrown when performing an unexpected action on a poll. + // TRANS: %s is the unexpected object type. + throw new Exception(sprintf(_m('Unexpected type for poll plugin: %s.'), $notice->object_type)); } } @@ -393,7 +416,8 @@ class PollPlugin extends MicroAppPlugin $form->show(); } } else { - $out->text('Poll data is missing'); + // TRANS: Error text displayed if no poll data could be found. + $out->text(_m('Poll data is missing')); } $out->elementEnd('div'); @@ -426,6 +450,56 @@ class PollPlugin extends MicroAppPlugin function appTitle() { - return _m('Poll'); + // TRANS: Application title. + return _m('APPTITLE','Poll'); + } + + function onStartAddNoticeReply($nli, $parent, $child) + { + // Filter out any poll responses + if ($parent->object_type == self::POLL_OBJECT && + $child->object_type == self::POLL_RESPONSE_OBJECT) { + return false; + } + return true; + } + + // Hide poll responses for @chuck + + function onEndNoticeWhoGets($notice, &$ni) { + if ($notice->object_type == self::POLL_RESPONSE_OBJECT) { + foreach ($ni as $id => $source) { + $user = User::getKV('id', $id); + if (!empty($user)) { + $pollPrefs = User_poll_prefs::getKV('user_id', $user->id); + if (!empty($pollPrefs) && ($pollPrefs->hide_responses)) { + unset($ni[$id]); + } + } + } + } + return true; + } + + /** + * Menu item for personal subscriptions/groups area + * + * @param Action $action action being executed + * + * @return boolean hook return + */ + + function onEndAccountSettingsNav($action) + { + $action_name = $action->trimmed('action'); + + $action->menuItem(common_local_url('pollsettings'), + // TRANS: Poll plugin menu item on user settings page. + _m('MENU', 'Polls'), + // TRANS: Poll plugin tooltip for user settings menu item. + _m('Configure poll behavior'), + $action_name === 'pollsettings'); + + return true; } }