forked from GNUsocial/gnu-social
		
	Merge branch 'qna' into 1.0.x
* qna: Some work towards allowing revisions Make new answers work More plumbing Work on QnA notice display -- in progress * Move stuff around again * Make answers save * Fix plugin filename * Make questions save! Renamed QuestionAndAnswerPlugin to QnAPlugin Most objects and forms are in place, now I just have to make it work. Skeleton / Stub for Question and Answers micro-app plugin
This commit is contained in:
		
							
								
								
									
										405
									
								
								plugins/QnA/QnAPlugin.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										405
									
								
								plugins/QnA/QnAPlugin.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,405 @@ | ||||
| <?php | ||||
| /** | ||||
|  * StatusNet - the distributed open-source microblogging tool | ||||
|  * Copyright (C) 2011, StatusNet, Inc. | ||||
|  * | ||||
|  * Microapp plugin for Questions and Answers | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * 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  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
|  | ||||
| if (!defined('STATUSNET')) { | ||||
|     // This check helps protect against security problems; | ||||
|     // your code file can't be executed directly from the web. | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Question and Answer plugin | ||||
|  * | ||||
|  * @category  Plugin | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
| class QnAPlugin extends MicroAppPlugin | ||||
| { | ||||
|     /** | ||||
|      * Set up our tables (question and answer) | ||||
|      * | ||||
|      * @see Schema | ||||
|      * @see ColumnDef | ||||
|      * | ||||
|      * @return boolean hook value; true means continue processing, false means stop. | ||||
|      */ | ||||
|     function onCheckSchema() | ||||
|     { | ||||
|         $schema = Schema::get(); | ||||
|  | ||||
|         $schema->ensureTable('qna_question', QnA_Question::schemaDef()); | ||||
|         $schema->ensureTable('qna_answer', QnA_Answer::schemaDef()); | ||||
|         $schema->ensureTable('qna_vote', QnA_Vote::schemaDef()); | ||||
|  | ||||
|         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 'QnanewquestionAction': | ||||
|         case 'QnanewanswerAction': | ||||
|         case 'QnashowquestionAction': | ||||
|         case 'QnashowanswerAction': | ||||
|         case 'QnareviseanswerAction': | ||||
|         case 'QnavoteAction': | ||||
|             include_once $dir . '/actions/' | ||||
|                 . strtolower(mb_substr($cls, 0, -6)) . '.php'; | ||||
|             return false; | ||||
|         case 'QnaquestionForm': | ||||
|         case 'QnaanswerForm': | ||||
|         case 'QnareviseanswerForm': | ||||
|         case 'QnavoteForm': | ||||
|             include_once $dir . '/lib/' . strtolower($cls).'.php'; | ||||
|             break; | ||||
|         case 'QnA_Question': | ||||
|         case 'QnA_Answer': | ||||
|         case 'QnA_Vote': | ||||
|             include_once $dir . '/classes/' . $cls.'.php'; | ||||
|             return false; | ||||
|             break; | ||||
|         default: | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Map URLs to actions | ||||
|      * | ||||
|      * @param Net_URL_Mapper $m path-to-action mapper | ||||
|      * | ||||
|      * @return boolean hook value; true means continue processing, false means stop. | ||||
|      */ | ||||
|  | ||||
|     function onRouterInitialized($m) | ||||
|     { | ||||
|         $UUIDregex = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'; | ||||
|  | ||||
|         $m->connect( | ||||
|             'main/qna/newquestion', | ||||
|             array('action' => 'qnanewquestion') | ||||
|         ); | ||||
|         $m->connect( | ||||
|             'main/qna/newanswer', | ||||
|             array('action' => 'qnanewanswer') | ||||
|         ); | ||||
|         $m->connect( | ||||
|             'question/vote/:id', | ||||
|             array('action' => 'qnavote', 'type' => 'question'), | ||||
|             array('id' => $UUIDregex) | ||||
|         ); | ||||
|         $m->connect( | ||||
|             'question/:id', | ||||
|             array('action' => 'qnashowquestion'), | ||||
|             array('id' => $UUIDregex) | ||||
|         ); | ||||
|         $m->connect( | ||||
|             'answer/vote/:id', | ||||
|             array('action' => 'qnavote', 'type' => 'answer'), | ||||
|             array('id' => $UUIDregex) | ||||
|         ); | ||||
|         $m->connect( | ||||
|             'answer/:id', | ||||
|             array('action' => 'qnashowanswer'), | ||||
|             array('id' => $UUIDregex) | ||||
|         ); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     function onPluginVersion(&$versions) | ||||
|     { | ||||
|         $versions[] = array( | ||||
|             'name'        => 'QnA', | ||||
|             'version'     => STATUSNET_VERSION, | ||||
|             'author'      => 'Zach Copley', | ||||
|             'homepage'    => 'http://status.net/wiki/Plugin:QnA', | ||||
|             'description' => | ||||
|              _m('Question and Answers micro-app.') | ||||
|         ); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     function appTitle() { | ||||
|         return _m('Question'); | ||||
|     } | ||||
|  | ||||
|     function tag() { | ||||
|         return 'question'; | ||||
|     } | ||||
|  | ||||
|     function types() { | ||||
|         return array( | ||||
|             QnA_Question::OBJECT_TYPE, | ||||
|             QnA_Answer::OBJECT_TYPE | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Given a parsed ActivityStreams activity, save it into a notice | ||||
|      * and other data structures. | ||||
|      * | ||||
|      * @param Activity $activity | ||||
|      * @param Profile $actor | ||||
|      * @param array $options=array() | ||||
|      * | ||||
|      * @return Notice the resulting notice | ||||
|      */ | ||||
|     function saveNoticeFromActivity($activity, $actor, $options=array()) | ||||
|     { | ||||
|         if (count($activity->objects) != 1) { | ||||
|             throw new Exception('Too many activity objects.'); | ||||
|         } | ||||
|  | ||||
|         $questionObj = $activity->objects[0]; | ||||
|  | ||||
|         if ($questinoObj->type != QnA_Question::OBJECT_TYPE) { | ||||
|             throw new Exception('Wrong type for object.'); | ||||
|         } | ||||
|  | ||||
|         $notice = null; | ||||
|  | ||||
|         switch ($activity->verb) { | ||||
|         case ActivityVerb::POST: | ||||
|             $notice = QnA_Question::saveNew( | ||||
|                 $actor, | ||||
|                 $questionObj->title, | ||||
|                 $questionObj->summary, | ||||
|                 $options | ||||
|             ); | ||||
|             break; | ||||
|         case Answer::ObjectType: | ||||
|             $question = QnA_Question::staticGet('uri', $questionObj->id); | ||||
|             if (empty($question)) { | ||||
|                 // FIXME: save the question | ||||
|                 throw new Exception("Answer to unknown question."); | ||||
|             } | ||||
|             $notice = QnA_Answer::saveNew($actor, $question, $options); | ||||
|             break; | ||||
|         default: | ||||
|             throw new Exception("Unknown object type received by QnA Plugin"); | ||||
|         } | ||||
|  | ||||
|         return $notice; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Turn a Notice into an activity object | ||||
|      * | ||||
|      * @param Notice $notice | ||||
|      * | ||||
|      * @return ActivityObject | ||||
|      */ | ||||
|  | ||||
|     function activityObjectFromNotice($notice) | ||||
|     { | ||||
|         $question = null; | ||||
|  | ||||
|         switch ($notice->object_type) { | ||||
|         case QnA_Question::OBJECT_TYPE: | ||||
|             $question = QnA_Question::fromNotice($notice); | ||||
|             break; | ||||
|         case QnA_Answer::OBJECT_TYPE: | ||||
|             $answer   = QnA_Answer::fromNotice($notice); | ||||
|             $question = $answer->getQuestion(); | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         if (empty($question)) { | ||||
|             throw new Exception("Unknown object type."); | ||||
|         } | ||||
|  | ||||
|         $notice = $question->getNotice(); | ||||
|  | ||||
|         if (empty($notice)) { | ||||
|             throw new Exception("Unknown question notice."); | ||||
|         } | ||||
|  | ||||
|         $obj = new ActivityObject(); | ||||
|  | ||||
|         $obj->id      = $question->uri; | ||||
|         $obj->type    = QnA_Question::OBJECT_TYPE; | ||||
|         $obj->title   = $question->title; | ||||
|         $obj->link    = $notice->bestUrl(); | ||||
|  | ||||
|         // XXX: probably need other stuff here | ||||
|  | ||||
|         return $obj; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Change the verb on Answer notices | ||||
|      * | ||||
|      * @param Notice $notice | ||||
|      * | ||||
|      * @return ActivityObject | ||||
|      */ | ||||
|  | ||||
|     function onEndNoticeAsActivity($notice, &$act) { | ||||
|         switch ($notice->object_type) { | ||||
|         case Answer::NORMAL: | ||||
|         case Answer::ANONYMOUS: | ||||
|             $act->verb = $notice->object_type; | ||||
|             break; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Custom HTML output for our notices | ||||
|      * | ||||
|      * @param Notice $notice | ||||
|      * @param HTMLOutputter $out | ||||
|      */ | ||||
|     function showNotice($notice, $out) | ||||
|     { | ||||
|         switch ($notice->object_type) { | ||||
|         case QnA_Question::OBJECT_TYPE: | ||||
|             return $this->showNoticeQuestion($notice, $out); | ||||
|         case QnA_Answer::OBJECT_TYPE: | ||||
|             return $this->showNoticeAnswer($notice, $out); | ||||
|         default: | ||||
|             // TRANS: Exception thrown when performing an unexpected action on a question. | ||||
|             // TRANS: %s is the unpexpected object type. | ||||
|             throw new Exception( | ||||
|                 sprintf( | ||||
|                     _m('Unexpected type for QnA plugin: %s.'), | ||||
|                     $notice->object_type | ||||
|                 ) | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function showNoticeQuestion($notice, $out) | ||||
|     { | ||||
|         $user = common_current_user(); | ||||
|  | ||||
|         // @hack we want regular rendering, then just add stuff after that | ||||
|         $nli = new NoticeListItem($notice, $out); | ||||
|         $nli->showNotice(); | ||||
|  | ||||
|         $out->elementStart('div', array('class' => 'entry-content question-content')); | ||||
|         $question = QnA_Question::getByNotice($notice); | ||||
|  | ||||
|         if ($question) { | ||||
|             if ($user) { | ||||
|                 $profile = $user->getProfile(); | ||||
|                 $answer = $question->getAnswer($profile); | ||||
|                 if ($answer) { | ||||
|                     // User has already answer; show the results. | ||||
|                     $form = new QnareviseanswerForm($answer, $out); | ||||
|                 } else { | ||||
|                     $form = new QnaanswerForm($question, $out); | ||||
|                 } | ||||
|                 $form->show(); | ||||
|             } | ||||
|         } else { | ||||
|             $out->text(_m('Question data is missing')); | ||||
|         } | ||||
|         $out->elementEnd('div'); | ||||
|  | ||||
|         // @fixme | ||||
|         $out->elementStart('div', array('class' => 'entry-content')); | ||||
|     } | ||||
|  | ||||
|     function showNoticeAnswer($notice, $out) | ||||
|     { | ||||
|         $user = common_current_user(); | ||||
|  | ||||
|         // @hack we want regular rendering, then just add stuff after that | ||||
|         $nli = new NoticeListItem($notice, $out); | ||||
|         $nli->showNotice(); | ||||
|  | ||||
|         // @fixme | ||||
|         $out->elementStart('div', array('class' => 'entry-content')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Form for our app | ||||
|      * | ||||
|      * @param HTMLOutputter $out | ||||
|      * @return Widget | ||||
|      */ | ||||
|  | ||||
|     function entryForm($out) | ||||
|     { | ||||
|         return new QnaquestionForm($out); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * When a notice is deleted, clean up related tables. | ||||
|      * | ||||
|      * @param Notice $notice | ||||
|      */ | ||||
|  | ||||
|     function deleteRelated($notice) | ||||
|     { | ||||
|         switch ($notice->object_type) { | ||||
|         case QnA_Question::OBJECT_TYPE: | ||||
|             common_log(LOG_DEBUG, "Deleting question from notice..."); | ||||
|             $question = QnA_Question::fromNotice($notice); | ||||
|             $question->delete(); | ||||
|             break; | ||||
|         case QnA_Answer::OBJECT_TYPE: | ||||
|             common_log(LOG_DEBUG, "Deleting answer from notice..."); | ||||
|             $answer = QnA_Answer::fromNotice($notice); | ||||
|             common_log(LOG_DEBUG, "to delete: $answer->id"); | ||||
|             $answer->delete(); | ||||
|             break; | ||||
|         default: | ||||
|             common_log(LOG_DEBUG, "Not deleting related, wtf..."); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function onEndShowScripts($action) | ||||
|     { | ||||
|         // XXX maybe some cool shiz here | ||||
|     } | ||||
|  | ||||
|     function onEndShowStyles($action) | ||||
|     { | ||||
|         $action->cssLink($this->path('css/qna.css')); | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										204
									
								
								plugins/QnA/actions/qnanewanswer.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								plugins/QnA/actions/qnanewanswer.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,204 @@ | ||||
| <?php | ||||
| /** | ||||
|  * StatusNet - the distributed open-source microblogging tool | ||||
|  * Copyright (C) 2011, StatusNet, Inc. | ||||
|  * | ||||
|  * Answer a question | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * 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  QuestonAndAnswer | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
| if (!defined('STATUSNET')) { | ||||
|     // This check helps protect against security problems; | ||||
|     // your code file can't be executed directly from the web. | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Answer a question | ||||
|  * | ||||
|  * @category  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2010 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
| class QnanewanswerAction extends Action | ||||
| { | ||||
|     protected $user     = null; | ||||
|     protected $error    = null; | ||||
|     protected $complete = null; | ||||
|  | ||||
|     protected $question = null; | ||||
|     protected $content  = null; | ||||
|  | ||||
|     /** | ||||
|      * Returns the title of the action | ||||
|      * | ||||
|      * @return string Action title | ||||
|      */ | ||||
|     function title() | ||||
|     { | ||||
|         // TRANS: Page title for and answer to a question. | ||||
|         return _m('Answer'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * For initializing members of the class. | ||||
|      * | ||||
|      * @param array $argarray misc. arguments | ||||
|      * | ||||
|      * @return boolean true | ||||
|      */ | ||||
|     function prepare($argarray) | ||||
|     { | ||||
|         parent::prepare($argarray); | ||||
|         if ($this->boolean('ajax')) { | ||||
|             StatusNet::setApi(true); | ||||
|         } | ||||
|  | ||||
|         $this->user = common_current_user(); | ||||
|  | ||||
|         if (empty($this->user)) { | ||||
|             // TRANS: Client exception thrown trying to answer a question while not logged in. | ||||
|             throw new ClientException( | ||||
|                 _m("You must be logged in to answer to a question."), | ||||
|                 403 | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         if ($this->isPost()) { | ||||
|             $this->checkSessionToken(); | ||||
|         } | ||||
|  | ||||
|         $id = substr($this->trimmed('id'), 9); | ||||
|  | ||||
|         common_debug("XXXXXXXXXXXXXXXXXX id = " . $id); | ||||
|  | ||||
|         $this->question = QnA_Question::staticGet('id', $id); | ||||
|  | ||||
|         if (empty($this->question)) { | ||||
|             // TRANS: Client exception thrown trying to respond to a non-existing question. | ||||
|             throw new ClientException( | ||||
|                 _m('Invalid or missing question.'), | ||||
|                 404 | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $this->answerText = $this->trimmed('answer'); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Handler method | ||||
|      * | ||||
|      * @param array $argarray is ignored since it's now passed in in prepare() | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function handle($argarray=null) | ||||
|     { | ||||
|         parent::handle($argarray); | ||||
|  | ||||
|         if ($this->isPost()) { | ||||
|             $this->newAnswer(); | ||||
|         } else { | ||||
|             $this->showPage(); | ||||
|         } | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Add a new answer | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function newAnswer() | ||||
|     { | ||||
|         try { | ||||
|             $notice = QnA_Answer::saveNew( | ||||
|                 $this->user->getProfile(), | ||||
|                 $this->question, | ||||
|                 $this->answerText | ||||
|             ); | ||||
|         } catch (ClientException $ce) { | ||||
|             $this->error = $ce->getMessage(); | ||||
|             $this->showPage(); | ||||
|             return; | ||||
|         } | ||||
|         if ($this->boolean('ajax')) { | ||||
|             common_debug("ajaxy part"); | ||||
|             header('Content-Type: text/xml;charset=utf-8'); | ||||
|             $this->xw->startDocument('1.0', 'UTF-8'); | ||||
|             $this->elementStart('html'); | ||||
|             $this->elementStart('head'); | ||||
|             // TRANS: Page title after sending an answer. | ||||
|             $this->element('title', null, _m('Answers')); | ||||
|             $this->elementEnd('head'); | ||||
|             $this->elementStart('body'); | ||||
|             $this->raw() | ||||
|             $this->elementEnd('body'); | ||||
|             $this->elementEnd('html'); | ||||
|         } else { | ||||
|             common_redirect($this->question->bestUrl(), 303); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Show the Answer form | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function showContent() | ||||
|     { | ||||
|         if (!empty($this->error)) { | ||||
|             $this->element('p', 'error', $this->error); | ||||
|         } | ||||
|  | ||||
|         $form = new QnaanswerForm($this->question, $this); | ||||
|         $form->show(); | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Return true if read only. | ||||
|      * | ||||
|      * MAY override | ||||
|      * | ||||
|      * @param array $args other arguments | ||||
|      * | ||||
|      * @return boolean is read only action? | ||||
|      */ | ||||
|     function isReadOnly($args) | ||||
|     { | ||||
|         if ($_SERVER['REQUEST_METHOD'] == 'GET' || | ||||
|             $_SERVER['REQUEST_METHOD'] == 'HEAD') { | ||||
|             return true; | ||||
|         } else { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										216
									
								
								plugins/QnA/actions/qnanewquestion.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								plugins/QnA/actions/qnanewquestion.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | ||||
| <?php | ||||
| /** | ||||
|  * StatusNet - the distributed open-source microblogging tool | ||||
|  * Copyright (C) 2011, StatusNet, Inc. | ||||
|  * | ||||
|  * Add a new Question | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * 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  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
| if (!defined('STATUSNET')) { | ||||
|     // This check helps protect against security problems; | ||||
|     // your code file can't be executed directly from the web. | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Add a new Question | ||||
|  * | ||||
|  * @category  Plugin | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2010 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
| class QnanewquestionAction extends Action | ||||
| { | ||||
|     protected $user        = null; | ||||
|     protected $error       = null; | ||||
|     protected $complete    = null; | ||||
|     protected $title       = null; | ||||
|     protected $description = null; | ||||
|  | ||||
|     /** | ||||
|      * Returns the title of the action | ||||
|      * | ||||
|      * @return string Action title | ||||
|      */ | ||||
|     function title() | ||||
|     { | ||||
|         // TRANS: Title for Question page. | ||||
|         return _m('New question'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * For initializing members of the class. | ||||
|      * | ||||
|      * @param array $argarray misc. arguments | ||||
|      * | ||||
|      * @return boolean true | ||||
|      */ | ||||
|     function prepare($argarray) | ||||
|     { | ||||
|         parent::prepare($argarray); | ||||
|  | ||||
|         $this->user = common_current_user(); | ||||
|  | ||||
|         if (empty($this->user)) { | ||||
|             // TRANS: Client exception thrown trying to create a Question while not logged in. | ||||
|             throw new ClientException( | ||||
|                 _m('You must be logged in to post a question.'), | ||||
|                 403 | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         if ($this->isPost()) { | ||||
|             $this->checkSessionToken(); | ||||
|         } | ||||
|  | ||||
|         $this->title       = $this->trimmed('title'); | ||||
|         $this->description = $this->trimmed('description'); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Handler method | ||||
|      * | ||||
|      * @param array $argarray is ignored since it's now passed in in prepare() | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function handle($argarray=null) | ||||
|     { | ||||
|         parent::handle($argarray); | ||||
|  | ||||
|         if ($this->isPost()) { | ||||
|             $this->newQuestion(); | ||||
|         } else { | ||||
|             $this->showPage(); | ||||
|         } | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Add a new Question | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function newQuestion() | ||||
|     { | ||||
|         if ($this->boolean('ajax')) { | ||||
|             StatusNet::setApi(true); | ||||
|         } | ||||
|         try { | ||||
|             if (empty($this->title)) { | ||||
|                 // TRANS: Client exception thrown trying to create a question without a title. | ||||
|                 throw new ClientException(_m('Question must have a title.')); | ||||
|             } | ||||
|  | ||||
|             $saved = QnA_Question::saveNew( | ||||
|                 $this->user->getProfile(), | ||||
|                 $this->title, | ||||
|                 $this->description | ||||
|             ); | ||||
|         } catch (ClientException $ce) { | ||||
|             $this->error = $ce->getMessage(); | ||||
|             $this->showPage(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if ($this->boolean('ajax')) { | ||||
|             header('Content-Type: text/xml;charset=utf-8'); | ||||
|             $this->xw->startDocument('1.0', 'UTF-8'); | ||||
|             $this->elementStart('html'); | ||||
|             $this->elementStart('head'); | ||||
|             // TRANS: Page title after sending a notice. | ||||
|             $this->element('title', null, _m('Question posted')); | ||||
|             $this->elementEnd('head'); | ||||
|             $this->elementStart('body'); | ||||
|             $this->showNotice($saved); | ||||
|             $this->elementEnd('body'); | ||||
|             $this->elementEnd('html'); | ||||
|         } else { | ||||
|             common_redirect($saved->bestUrl(), 303); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Output a notice | ||||
|      * | ||||
|      * Used to generate the notice code for Ajax results. | ||||
|      * | ||||
|      * @param Notice $notice Notice that was saved | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function showNotice($notice) | ||||
|     { | ||||
|         class_exists('NoticeList'); // @fixme hack for autoloader | ||||
|         $nli = new NoticeListItem($notice, $this); | ||||
|         $nli->show(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Show the Question form | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function showContent() | ||||
|     { | ||||
|         if (!empty($this->error)) { | ||||
|             $this->element('p', 'error', $this->error); | ||||
|         } | ||||
|  | ||||
|         $form = new QuestionForm( | ||||
|             $this, | ||||
|             $this->title, | ||||
|             $this->description | ||||
|         ); | ||||
|  | ||||
|         $form->show(); | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Return true if read only. | ||||
|      * | ||||
|      * MAY override | ||||
|      * | ||||
|      * @param array $args other arguments | ||||
|      * | ||||
|      * @return boolean is read only action? | ||||
|      */ | ||||
|     function isReadOnly($args) | ||||
|     { | ||||
|         if ($_SERVER['REQUEST_METHOD'] == 'GET' || | ||||
|             $_SERVER['REQUEST_METHOD'] == 'HEAD') { | ||||
|             return true; | ||||
|         } else { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										142
									
								
								plugins/QnA/actions/qnashowanswer.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								plugins/QnA/actions/qnashowanswer.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| <?php | ||||
| /** | ||||
|  * StatusNet - the distributed open-source microblogging tool | ||||
|  * Copyright (C) 2010, StatusNet, Inc. | ||||
|  * | ||||
|  * Show an answer to a question | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * 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  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2010 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
|  | ||||
| if (!defined('STATUSNET')) { | ||||
|     // This check helps protect against security problems; | ||||
|     // your code file can't be executed directly from the web. | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Show an answer to a question, and associated data | ||||
|  * | ||||
|  * @category  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2010 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
|  | ||||
| class QnashowanswerAction extends ShownoticeAction | ||||
| { | ||||
|     protected $answer = null; | ||||
|  | ||||
|     /** | ||||
|      * For initializing members of the class. | ||||
|      * | ||||
|      * @param array $argarray misc. arguments | ||||
|      * | ||||
|      * @return boolean true | ||||
|      */ | ||||
|  | ||||
|     function prepare($argarray) | ||||
|     { | ||||
|         OwnerDesignAction::prepare($argarray); | ||||
|  | ||||
|         $this->id = $this->trimmed('id'); | ||||
|  | ||||
|         $this->answer = QnA_Answer::staticGet('id', $this->id); | ||||
|  | ||||
|         if (empty($this->answer)) { | ||||
|             throw new ClientException(_('No such answer.'), 404); | ||||
|         } | ||||
|  | ||||
|         $this->question = $this->answer->getQuestion(); | ||||
|  | ||||
|         if (empty($this->question)) { | ||||
|             throw new ClientException(_('No question for this answer.'), 404); | ||||
|         } | ||||
|  | ||||
|         $this->notice = Notice::staticGet('uri', $this->answer->uri); | ||||
|  | ||||
|         if (empty($this->notice)) { | ||||
|             // Did we used to have it, and it got deleted? | ||||
|             throw new ClientException(_('No such answer.'), 404); | ||||
|         } | ||||
|  | ||||
|         $this->user = User::staticGet('id', $this->answer->profile_id); | ||||
|  | ||||
|         if (empty($this->user)) { | ||||
|             throw new ClientException(_('No such user.'), 404); | ||||
|         } | ||||
|  | ||||
|         $this->profile = $this->user->getProfile(); | ||||
|  | ||||
|         if (empty($this->profile)) { | ||||
|             throw new ServerException(_('User without a profile.')); | ||||
|         } | ||||
|  | ||||
|         $this->avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Title of the page | ||||
|      * | ||||
|      * Used by Action class for layout. | ||||
|      * | ||||
|      * @return string page tile | ||||
|      */ | ||||
|  | ||||
|     function title() | ||||
|     { | ||||
|         $question = $this->answer->getQuestion(); | ||||
|  | ||||
|         return sprintf( | ||||
|             _('%s\'s answer to "%s"'), | ||||
|             $this->user->nickname, | ||||
|             $question->title | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Overload page title display to show answer link | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|  | ||||
|     function showPageTitle() | ||||
|     { | ||||
|         $this->elementStart('h1'); | ||||
|         $this->element( | ||||
|             'a', | ||||
|             array('href' => $this->answer->uri), | ||||
|             $this->question->title | ||||
|         ); | ||||
|         $this->elementEnd('h1'); | ||||
|     } | ||||
|  | ||||
|     function showContent() | ||||
|     { | ||||
|         $this->raw($this->answer->asHTML()); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										135
									
								
								plugins/QnA/actions/qnashowquestion.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								plugins/QnA/actions/qnashowquestion.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | ||||
| <?php | ||||
| /** | ||||
|  * StatusNet - the distributed open-source microblogging tool | ||||
|  * Copyright (C) 2011, StatusNet, Inc. | ||||
|  * | ||||
|  * Show a question | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * 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  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
|  | ||||
| if (!defined('STATUSNET')) { | ||||
|     // This check helps protect against security problems; | ||||
|     // your code file can't be executed directly from the web. | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Show a question | ||||
|  * | ||||
|  * @category  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
| class QnashowquestionAction extends ShownoticeAction | ||||
| { | ||||
|     protected $question = null; | ||||
|  | ||||
|     /** | ||||
|      * For initializing members of the class. | ||||
|      * | ||||
|      * @param array $argarray misc. arguments | ||||
|      * | ||||
|      * @return boolean true | ||||
|      */ | ||||
|     function prepare($argarray) | ||||
|     { | ||||
|         OwnerDesignAction::prepare($argarray); | ||||
|  | ||||
|         $this->id = $this->trimmed('id'); | ||||
|  | ||||
|         $this->question = QnA_Question::staticGet('id', $this->id); | ||||
|  | ||||
|         if (empty($this->question)) { | ||||
|             // TRANS: Client exception thrown trying to view a non-existing question. | ||||
|             throw new ClientException(_m('No such question.'), 404); | ||||
|         } | ||||
|  | ||||
|         $this->notice = $this->question->getNotice(); | ||||
|  | ||||
|         if (empty($this->notice)) { | ||||
|             // Did we used to have it, and it got deleted? | ||||
|             // TRANS: Client exception thrown trying to view a non-existing question notice. | ||||
|             throw new ClientException(_m('No such question notice.'), 404); | ||||
|         } | ||||
|  | ||||
|         $this->user = User::staticGet('id', $this->question->profile_id); | ||||
|  | ||||
|         if (empty($this->user)) { | ||||
|             // TRANS: Client exception thrown trying to view a question of a non-existing user. | ||||
|             throw new ClientException(_m('No such user.'), 404); | ||||
|         } | ||||
|  | ||||
|         $this->profile = $this->user->getProfile(); | ||||
|  | ||||
|         if (empty($this->profile)) { | ||||
|             // TRANS: Server exception thrown trying to view a question for a user for which the profile could not be loaded. | ||||
|             throw new ServerException(_m('User without a profile.')); | ||||
|         } | ||||
|  | ||||
|         $this->avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE); | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     function showContent() | ||||
|     { | ||||
|         $this->raw($this->question->asHTML()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Title of the page | ||||
|      * | ||||
|      * Used by Action class for layout. | ||||
|      * | ||||
|      * @return string page tile | ||||
|      */ | ||||
|     function title() | ||||
|     { | ||||
|         // TRANS: Page title for a question. | ||||
|         // TRANS: %1$s is the nickname of the user who asked the question, %2$s is the question. | ||||
|         return sprintf(_m('%1$s\'s question: %2$s'), | ||||
|                        $this->user->nickname, | ||||
|                        $this->question->title); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @fixme combine the notice time with question update time | ||||
|      */ | ||||
|     function lastModified() | ||||
|     { | ||||
|         return Action::lastModified(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * @fixme combine the notice time with question update time | ||||
|      */ | ||||
|     function etag() | ||||
|     { | ||||
|         return Action::etag(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										198
									
								
								plugins/QnA/actions/qnavote.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								plugins/QnA/actions/qnavote.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,198 @@ | ||||
| <?php | ||||
| /** | ||||
|  * StatusNet - the distributed open-source microblogging tool | ||||
|  * Copyright (C) 2011, StatusNet, Inc. | ||||
|  * | ||||
|  * Vote on a questino or answer | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * 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  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
| if (!defined('STATUSNET')) { | ||||
|     // This check helps protect against security problems; | ||||
|     // your code file can't be executed directly from the web. | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Vote on a question or answer | ||||
|  * | ||||
|  * @category  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2010 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
| class Qnavote extends Action | ||||
| { | ||||
|     protected $user        = null; | ||||
|     protected $error       = null; | ||||
|     protected $complete    = null; | ||||
|  | ||||
|     protected $question    = null; | ||||
|     protected $answer      = null; | ||||
|  | ||||
|     /** | ||||
|      * Returns the title of the action | ||||
|      * | ||||
|      * @return string Action title | ||||
|      */ | ||||
|     function title() | ||||
|     { | ||||
|         // TRANS: Page title for and answer to a question. | ||||
|         return _m('Answer'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * For initializing members of the class. | ||||
|      * | ||||
|      * @param array $argarray misc. arguments | ||||
|      * | ||||
|      * @return boolean true | ||||
|      */ | ||||
|     function prepare($argarray) | ||||
|     { | ||||
|         parent::prepare($argarray); | ||||
|         if ($this->boolean('ajax')) { | ||||
|             StatusNet::setApi(true); | ||||
|         } | ||||
|  | ||||
|         $this->user = common_current_user(); | ||||
|  | ||||
|         if (empty($this->user)) { | ||||
|             // TRANS: Client exception thrown trying to answer a question while not logged in. | ||||
|             throw new ClientException(_m("You must be logged in to answer to a question."), | ||||
|                                       403); | ||||
|         } | ||||
|  | ||||
|         if ($this->isPost()) { | ||||
|             $this->checkSessionToken(); | ||||
|         } | ||||
|  | ||||
|         $id = $this->trimmed('id'); | ||||
|         $this->question = QnA_Question::staticGet('id', $id); | ||||
|         if (empty($this->question)) { | ||||
|             // TRANS: Client exception thrown trying to respond to a non-existing question. | ||||
|             throw new ClientException(_m('Invalid or missing question.'), 404); | ||||
|         } | ||||
|  | ||||
|         $answer = $this->trimmed('answer'); | ||||
|  | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Handler method | ||||
|      * | ||||
|      * @param array $argarray is ignored since it's now passed in in prepare() | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function handle($argarray=null) | ||||
|     { | ||||
|         parent::handle($argarray); | ||||
|  | ||||
|         if ($this->isPost()) { | ||||
|             $this->answer(); | ||||
|         } else { | ||||
|             $this->showPage(); | ||||
|         } | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Add a new answer | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function answer() | ||||
|     { | ||||
|         try { | ||||
|             $notice = Answer::saveNew( | ||||
|                 $this->user->getProfile(), | ||||
|                 $this->question, | ||||
|                 $this->answer | ||||
|             ); | ||||
|         } catch (ClientException $ce) { | ||||
|             $this->error = $ce->getMessage(); | ||||
|             $this->showPage(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if ($this->boolean('ajax')) { | ||||
|             header('Content-Type: text/xml;charset=utf-8'); | ||||
|             $this->xw->startDocument('1.0', 'UTF-8'); | ||||
|             $this->elementStart('html'); | ||||
|             $this->elementStart('head'); | ||||
|             // TRANS: Page title after sending an answer. | ||||
|             $this->element('title', null, _m('Answers')); | ||||
|             $this->elementEnd('head'); | ||||
|             $this->elementStart('body'); | ||||
|             $form = new QnA_Answer($this->question, $this); | ||||
|             $form->show(); | ||||
|             $this->elementEnd('body'); | ||||
|             $this->elementEnd('html'); | ||||
|         } else { | ||||
|             common_redirect($this->question->bestUrl(), 303); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Show the Answer form | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function showContent() | ||||
|     { | ||||
|         if (!empty($this->error)) { | ||||
|             $this->element('p', 'error', $this->error); | ||||
|         } | ||||
|  | ||||
|         $form = new QnaanswerForm($this->question, $this); | ||||
|  | ||||
|         $form->show(); | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Return true if read only. | ||||
|      * | ||||
|      * MAY override | ||||
|      * | ||||
|      * @param array $args other arguments | ||||
|      * | ||||
|      * @return boolean is read only action? | ||||
|      */ | ||||
|     function isReadOnly($args) | ||||
|     { | ||||
|         if ($_SERVER['REQUEST_METHOD'] == 'GET' || | ||||
|             $_SERVER['REQUEST_METHOD'] == 'HEAD') { | ||||
|             return true; | ||||
|         } else { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										307
									
								
								plugins/QnA/classes/QnA_Answer.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										307
									
								
								plugins/QnA/classes/QnA_Answer.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,307 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Data class to save answers to questions | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * @category QnA | ||||
|  * @package  StatusNet | ||||
|  * @author   Zach Copley <zach@status.net> | ||||
|  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 | ||||
|  * @link     http://status.net/ | ||||
|  * | ||||
|  * 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); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * For storing answers | ||||
|  * | ||||
|  * @category QnA | ||||
|  * @package  StatusNet | ||||
|  * @author   Zach Copley <zach@status.net> | ||||
|  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 | ||||
|  * @link     http://status.net/ | ||||
|  * | ||||
|  * @see      DB_DataObject | ||||
|  */ | ||||
| class QnA_Answer extends Managed_DataObject | ||||
| { | ||||
|     const  OBJECT_TYPE = 'http://activityschema.org/object/answer'; | ||||
|  | ||||
|     public $__table = 'qna_answer'; // table name | ||||
|     public $id;          // char(36) primary key not null -> UUID | ||||
|     public $question_id; // char(36) -> question.id UUID | ||||
|     public $profile_id;  // int -> question.id | ||||
|     public $best;        // (boolean) int -> whether the question asker has marked this as the best answer | ||||
|     public $revisions;   // int -> count of revisions to this answer | ||||
|     public $content;     // text -> response text | ||||
|     public $created;     // datetime | ||||
|  | ||||
|     /** | ||||
|      * 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 QnA_Answer object found, or null for no hits | ||||
|      * | ||||
|      */ | ||||
|     function staticGet($k, $v=null) | ||||
|     { | ||||
|         return Memcached_DataObject::staticGet('QnA_Answer', $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 QA_Answer object found, or null for no hits | ||||
|      * | ||||
|      */ | ||||
|     function pkeyGet($kv) | ||||
|     { | ||||
|         return Memcached_DataObject::pkeyGet('QnA_Answer', $kv); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * The One True Thingy that must be defined and declared. | ||||
|      */ | ||||
|     public static function schemaDef() | ||||
|     { | ||||
|         return array( | ||||
|             'description' => 'Record of answers to questions', | ||||
|             'fields' => array( | ||||
|                 'id' => array( | ||||
|                     'type'     => 'char', | ||||
|                     'length'   => 36, | ||||
|                     'not null' => true, 'description' => 'UUID of the response'), | ||||
|                     'uri'      => array( | ||||
|                         'type'        => 'varchar', | ||||
|                         'length'      => 255, | ||||
|                         'not null'    => true, | ||||
|                         'description' => 'UUID to the answer notice' | ||||
|                     ), | ||||
|                     'question_id' => array( | ||||
|                         'type'        => 'char', | ||||
|                         'length'      => 36, | ||||
|                         'not null'    => true, | ||||
|                         'description' => 'UUID of question being responded to' | ||||
|                     ), | ||||
|                     'content'    => array('type' => 'text'), // got a better name? | ||||
|                     'best'       => array('type' => 'int', 'size' => 'tiny'), | ||||
|                     'revisions'  => array('type' => 'int'), | ||||
|                     'profile_id' => array('type' => 'int'), | ||||
|                     'created'    => array('type' => 'datetime', 'not null' => true), | ||||
|             ), | ||||
|             'primary key' => array('id'), | ||||
|             'unique keys' => array( | ||||
|                 'question_uri_key' => array('uri'), | ||||
|                 'question_id_profile_id_key' => array('question_id', 'profile_id'), | ||||
|             ), | ||||
|             'indexes' => array( | ||||
|                 'profile_id_question_id_index' => array('profile_id', 'question_id'), | ||||
|             ) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get an answer based on a notice | ||||
|      * | ||||
|      * @param Notice $notice Notice to check for | ||||
|      * | ||||
|      * @return QnA_Answer found response or null | ||||
|      */ | ||||
|     function getByNotice($notice) | ||||
|     { | ||||
|         $answer = self::staticGet('uri', $notice->uri); | ||||
|         if (empty($answer)) { | ||||
|             throw new Exception("No answer with URI {$this->notice->uri}"); | ||||
|         } | ||||
|         return $answer; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get the notice that belongs to this answer | ||||
|      * | ||||
|      * @return Notice | ||||
|      */ | ||||
|     function getNotice() | ||||
|     { | ||||
|         return Notice::staticGet('uri', $this->uri); | ||||
|     } | ||||
|  | ||||
|     function bestUrl() | ||||
|     { | ||||
|         return $this->getNotice()->bestUrl(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get the Question this is an answer to | ||||
|      * | ||||
|      * @return QnA_Question | ||||
|      */ | ||||
|     function getQuestion() | ||||
|     { | ||||
|         $question = QnA_Question::staticGet('id', $this->question_id); | ||||
|         if (empty($question)) { | ||||
|             throw new Exception("No question with ID {$this->question_id}"); | ||||
|         } | ||||
|         return $question; | ||||
|     } | ||||
|  | ||||
|     function getProfile() | ||||
|     { | ||||
|         $profile = Profile::staticGet('id', $this->profile_id); | ||||
|         if (empty($profile)) { | ||||
|             throw new Exception("No profile with ID {$this->profile_id}"); | ||||
|         } | ||||
|         return $profile; | ||||
|     } | ||||
|  | ||||
|     function asHTML() | ||||
|     { | ||||
|         return self::toHTML( | ||||
|             $this->getProfile(), | ||||
|             $this->getQuestion(), | ||||
|             $this | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function asString() | ||||
|     { | ||||
|         return self::toString( | ||||
|             $this->getProfile(), | ||||
|             $this->getQuestion(), | ||||
|             $this | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     static function toHTML($profile, $question, $answer) | ||||
|     { | ||||
|         $notice = $question->getNotice(); | ||||
|  | ||||
|         $fmt   = '<span class="answer_author"><a href="%1s">answer</a> by <a href="%2s">%3s</a></span>'; | ||||
|         $fmt  .= '<span class="answer_content">%4s</span>'; | ||||
|  | ||||
|         return sprintf( | ||||
|             $fmt, | ||||
|             htmlspecialchars($notice->bestUrl()), | ||||
|             htmlspecialchars($profile->profileurl), | ||||
|             htmlspecialchars($profile->getBestName()), | ||||
|             htmlspecialchars($answer->content) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     static function toString($profile, $question, $answer) | ||||
|     { | ||||
|         $notice = $question->getNotice(); | ||||
|  | ||||
|         $fmt = _( | ||||
|             '%1s answered the question "%2s": %3s' | ||||
|         ); | ||||
|  | ||||
|         return sprintf( | ||||
|             $fmt, | ||||
|             htmlspecialchars($profile->getBestName()), | ||||
|             htmlspecialchars($question->title), | ||||
|             htmlspecialchars($answer->content) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Save a new answer notice | ||||
|      * | ||||
|      * @param Profile  $profile | ||||
|      * @param Question $Question the question being answered | ||||
|      * @param array | ||||
|      * | ||||
|      * @return Notice saved notice | ||||
|      */ | ||||
|     static function saveNew($profile, $question, $text, $options = null) | ||||
|     { | ||||
|         if (empty($options)) { | ||||
|             $options = array(); | ||||
|         } | ||||
|  | ||||
|         $answer              = new QnA_Answer(); | ||||
|         $answer->id          = UUID::gen(); | ||||
|         $answer->profile_id  = $profile->id; | ||||
|         $answer->question_id = $question->id; | ||||
|         $answer->revisions   = 0; | ||||
|         $answer->best        = 0; | ||||
|         $answer->content     = $text; | ||||
|         $answer->created     = common_sql_now(); | ||||
|         $answer->uri         = common_local_url( | ||||
|             'qnashowanswer', | ||||
|             array('id' => $answer->id) | ||||
|         ); | ||||
|  | ||||
|         common_log(LOG_DEBUG, "Saving answer: $answer->id, $answer->uri"); | ||||
|         $answer->insert(); | ||||
|  | ||||
|         $content  = sprintf( | ||||
|             _m('answered "%s"'), | ||||
|             $question->title | ||||
|         ); | ||||
|  | ||||
|         $link = '<a href="' . htmlspecialchars($answer->uri) . '">' . htmlspecialchars($question->title) . '</a>'; | ||||
|         // TRANS: Rendered version of the notice content answering a question. | ||||
|         // TRANS: %s a link to the question with question title as the link content. | ||||
|         $rendered = sprintf(_m('answered "%s"'), $link); | ||||
|  | ||||
|         $tags    = array(); | ||||
|         $replies = array(); | ||||
|  | ||||
|         $options = array_merge( | ||||
|             array( | ||||
|                 'urls'        => array(), | ||||
|                 'content'     => $content, | ||||
|                 'rendered'    => $rendered, | ||||
|                 'tags'        => $tags, | ||||
|                 'replies'     => $replies, | ||||
|                 'reply_to'    => $question->getNotice()->id, | ||||
|                 'object_type' => self::OBJECT_TYPE | ||||
|             ), | ||||
|             $options | ||||
|         ); | ||||
|  | ||||
|         if (!array_key_exists('uri', $options)) { | ||||
|             $options['uri'] = $answer->uri; | ||||
|         } | ||||
|  | ||||
|         $saved = Notice::saveNew( | ||||
|             $profile->id, | ||||
|             $content, | ||||
|             array_key_exists('source', $options) ? | ||||
|             $options['source'] : 'web', | ||||
|             $options | ||||
|         ); | ||||
|  | ||||
|         return $saved; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										345
									
								
								plugins/QnA/classes/QnA_Question.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										345
									
								
								plugins/QnA/classes/QnA_Question.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,345 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Data class to mark a notice as a question | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * @category QnA | ||||
|  * @package  StatusNet | ||||
|  * @author   Zach Copley <zach@status.net> | ||||
|  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 | ||||
|  * @link     http://status.net/ | ||||
|  * | ||||
|  * 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); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * For storing a question | ||||
|  * | ||||
|  * @category QnA | ||||
|  * @package  StatusNet | ||||
|  * @author   Zach Copley <zach@status.net> | ||||
|  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 | ||||
|  * @link     http://status.net/ | ||||
|  * | ||||
|  * @see      DB_DataObject | ||||
|  */ | ||||
|  | ||||
| class QnA_Question extends Managed_DataObject | ||||
| { | ||||
|     const OBJECT_TYPE = 'http://activityschema.org/object/question'; | ||||
|  | ||||
|     public $__table = 'qna_question'; // table name | ||||
|     public $id;          // char(36) primary key not null -> UUID | ||||
|     public $uri; | ||||
|     public $profile_id;  // int -> profile.id | ||||
|     public $title;       // text | ||||
|     public $description; // text | ||||
|     public $closed;      // int (boolean) whether a question is closed | ||||
|     public $created;     // datetime | ||||
|  | ||||
|     /** | ||||
|      * 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 QnA_Question object found, or null for no hits | ||||
|      * | ||||
|      */ | ||||
|     function staticGet($k, $v=null) | ||||
|     { | ||||
|         return Memcached_DataObject::staticGet('QnA_Question', $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('QnA_Question', $kv); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * The One True Thingy that must be defined and declared. | ||||
|      */ | ||||
|     public static function schemaDef() | ||||
|     { | ||||
|         return array( | ||||
|             'description' => 'Per-notice question data for QNA plugin', | ||||
|             'fields' => array( | ||||
|                 'id' => array( | ||||
|                     'type'        => 'char', | ||||
|                     'length'      => 36, | ||||
|                     'not null'    => true, | ||||
|                     'description' => 'UUID' | ||||
|                 ), | ||||
|                 'uri' => array( | ||||
|                     'type'     => 'varchar', | ||||
|                     'length'   => 255, | ||||
|                     'not null' => true | ||||
|                 ), | ||||
|                 'profile_id'  => array('type' => 'int'), | ||||
|                 'title'       => array('type' => 'text'), | ||||
|                 'closed'      => array('type' => 'int', 'size' => 'tiny'), | ||||
|                 'description' => array('type' => 'text'), | ||||
|                 'created'     => array( | ||||
|                     'type'     => 'datetime', | ||||
|                     'not null' => true | ||||
|                 ), | ||||
|             ), | ||||
|             'primary key' => array('id'), | ||||
|             'unique keys' => array( | ||||
|                 'question_uri_key' => array('uri'), | ||||
|             ), | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get a question based on a notice | ||||
|      * | ||||
|      * @param Notice $notice Notice to check for | ||||
|      * | ||||
|      * @return Question found question or null | ||||
|      */ | ||||
|     function getByNotice($notice) | ||||
|     { | ||||
|         return self::staticGet('uri', $notice->uri); | ||||
|     } | ||||
|  | ||||
|     function getNotice() | ||||
|     { | ||||
|         return Notice::staticGet('uri', $this->uri); | ||||
|     } | ||||
|  | ||||
|     function bestUrl() | ||||
|     { | ||||
|         return $this->getNotice()->bestUrl(); | ||||
|     } | ||||
|  | ||||
|     function getProfile() | ||||
|     { | ||||
|         $profile = Profile::staticGet('id', $this->profile_id); | ||||
|         if (empty($profile)) { | ||||
|             throw new Exception("No profile with ID {$this->profile_id}"); | ||||
|         } | ||||
|         return $profile; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get the answer from a particular user to this question, if any. | ||||
|      * | ||||
|      * @param Profile $profile | ||||
|      * | ||||
|      * @return Answer object or null | ||||
|      */ | ||||
|     function getAnswer(Profile $profile) | ||||
|     { | ||||
|         $a = new QnA_Answer(); | ||||
|         $a->question_id = $this->id; | ||||
|         $a->profile_id = $profile->id; | ||||
|         $a->find(); | ||||
|         if ($a->fetch()) { | ||||
|             return $a; | ||||
|         } else { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function getAnswers() | ||||
|     { | ||||
|         $a = new QnA_Answer(); | ||||
|         $a->question_id = $this->id; | ||||
|         $cnt = $a->find(); | ||||
|         if (!empty($cnt)) { | ||||
|             return $a; | ||||
|         } else { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function countAnswers() | ||||
|     { | ||||
|         $a              = new QnA_Answer(); | ||||
|         $a->question_id = $this->id; | ||||
|         return $a-count(); | ||||
|     } | ||||
|  | ||||
|     static function fromNotice($notice) | ||||
|     { | ||||
|         return QnA_Question::staticGet('uri', $notice->uri); | ||||
|     } | ||||
|  | ||||
|     function asHTML() | ||||
|     { | ||||
|         return self::toHTML( | ||||
|             $this->getProfile(), | ||||
|             $this, | ||||
|             $this->getAnswers() | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     function asString() | ||||
|     { | ||||
|         return self::toString( | ||||
|             $this->getProfile(), | ||||
|             $this, | ||||
|             $this->getAnswers() | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     static function toHTML($profile, $question, $answer) | ||||
|     { | ||||
|         $notice = $question->getNotice(); | ||||
|  | ||||
|         $fmt =  '<div class="qna_question">'; | ||||
|         $fmt .= '<span class="question_title"><a href="%1s">%2s</a></span>'; | ||||
|         $fmt .= '<span class="question_description">%3s</span>'; | ||||
|         $fmt .= '<span class="question_author">asked by <a href="%4s">%5s</a></span>'; | ||||
|         $fmt .= '</div>'; | ||||
|  | ||||
|         $q = sprintf( | ||||
|             $fmt, | ||||
|             htmlspecialchars($notice->bestUrl()), | ||||
|             htmlspecialchars($question->title), | ||||
|             htmlspecialchars($question->description), | ||||
|             htmlspecialchars($profile->profileurl), | ||||
|             htmlspecialchars($profile->getBestName()) | ||||
|         ); | ||||
|  | ||||
|         $ans = array(); | ||||
|  | ||||
|         $ans[] = '<div class="qna_answers">'; | ||||
|  | ||||
|         while($answer->fetch()) { | ||||
|             $ans[] = $answer->asHTML(); | ||||
|         } | ||||
|  | ||||
|         $ans[] .= '</div>'; | ||||
|  | ||||
|         return $q . implode($ans); | ||||
|     } | ||||
|  | ||||
|     static function toString($profile, $question, $answers) | ||||
|     { | ||||
|         $fmt = _( | ||||
|             '%1s asked the question "%2s": %3s' | ||||
|         ); | ||||
|  | ||||
|         return sprintf( | ||||
|             $fmt, | ||||
|             htmlspecialchars($profile->getBestName()), | ||||
|             htmlspecialchars($question->title), | ||||
|             htmlspecialchars($question->description) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Save a new question notice | ||||
|      * | ||||
|      * @param Profile $profile | ||||
|      * @param string  $question | ||||
|      * @param string  $title | ||||
|      * @param string  $description | ||||
|      * @param array   $option // and whatnot | ||||
|      * | ||||
|      * @return Notice saved notice | ||||
|      */ | ||||
|     static function saveNew($profile, $title, $description, $options = array()) | ||||
|     { | ||||
|         $q = new QnA_Question(); | ||||
|  | ||||
|         $q->id          = UUID::gen(); | ||||
|         $q->profile_id  = $profile->id; | ||||
|         $q->title       = $title; | ||||
|         $q->description = $description; | ||||
|  | ||||
|         if (array_key_exists('created', $options)) { | ||||
|             $q->created = $options['created']; | ||||
|         } else { | ||||
|             $q->created = common_sql_now(); | ||||
|         } | ||||
|  | ||||
|         if (array_key_exists('uri', $options)) { | ||||
|             $q->uri = $options['uri']; | ||||
|         } else { | ||||
|             $q->uri = common_local_url( | ||||
|                 'qnashowquestion', | ||||
|                 array('id' => $q->id) | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         common_log(LOG_DEBUG, "Saving question: $q->id $q->uri"); | ||||
|         $q->insert(); | ||||
|  | ||||
|         // TRANS: Notice content creating a question. | ||||
|         // TRANS: %1$s is the title of the question, %2$s is a link to the question. | ||||
|         $content  = sprintf( | ||||
|             _m('question: %1$s %2$s'), | ||||
|             $title, | ||||
|             $q->uri | ||||
|         ); | ||||
|  | ||||
|         $link = '<a href="' . htmlspecialchars($q->uri) . '">' . htmlspecialchars($title) . '</a>'; | ||||
|         // TRANS: Rendered version of the notice content creating a question. | ||||
|         // TRANS: %s a link to the question as link description. | ||||
|         $rendered = sprintf(_m('Question: %s'), $link); | ||||
|  | ||||
|         $tags    = array('question'); | ||||
|         $replies = array(); | ||||
|  | ||||
|         $options = array_merge( | ||||
|             array( | ||||
|                 'urls'        => array(), | ||||
|                 'rendered'    => $rendered, | ||||
|                 'tags'        => $tags, | ||||
|                 'replies'     => $replies, | ||||
|                 'object_type' => self::OBJECT_TYPE | ||||
|             ), | ||||
|             $options | ||||
|         ); | ||||
|  | ||||
|         if (!array_key_exists('uri', $options)) { | ||||
|             $options['uri'] = $q->uri; | ||||
|         } | ||||
|  | ||||
|         $saved = Notice::saveNew( | ||||
|             $profile->id, | ||||
|             $content, | ||||
|             array_key_exists('source', $options) ? | ||||
|             $options['source'] : 'web', | ||||
|             $options | ||||
|         ); | ||||
|  | ||||
|         return $saved; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										160
									
								
								plugins/QnA/classes/QnA_Vote.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								plugins/QnA/classes/QnA_Vote.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,160 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Data class to save users votes for  | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * @category QnA | ||||
|  * @package  StatusNet | ||||
|  * @author   Zach Copley <zach@status.net> | ||||
|  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 | ||||
|  * @link     http://status.net/ | ||||
|  * | ||||
|  * 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); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * For storing votes on question and answers | ||||
|  * | ||||
|  * @category QnA | ||||
|  * @package  StatusNet | ||||
|  * @author   Zach Copley <zach@status.net> | ||||
|  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 | ||||
|  * @link     http://status.net/ | ||||
|  * | ||||
|  * @see      DB_DataObject | ||||
|  */ | ||||
| class QnA_Vote extends Managed_DataObject | ||||
| { | ||||
|     const UP   = 'http://activitystrea.ms/schema/1.0/like'; | ||||
|     const DOWN = 'http://activityschema.org/object/dislike'; // Gar! | ||||
|      | ||||
|     public $__table = 'qna_vote'; // table name | ||||
|     public $id;          // char(36) primary key not null -> UUID | ||||
|     public $question_id; // char(36) -> question.id UUID | ||||
|     public $answer_id;   // char(36) -> question.id UUID | ||||
|     public $type;        // tinyint -> vote: up (1) or down (-1) | ||||
|     public $profile_id;  // int -> question.id | ||||
|     public $created;     // datetime | ||||
|  | ||||
|     /** | ||||
|      * 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 QnA_Vote object found, or null for no hits | ||||
|      * | ||||
|      */ | ||||
|     function staticGet($k, $v=null) | ||||
|     { | ||||
|         return Memcached_DataObject::staticGet('QnA_Vote', $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 QnA_Vote object found, or null for no hits | ||||
|      * | ||||
|      */ | ||||
|     function pkeyGet($kv) | ||||
|     { | ||||
|         return Memcached_DataObject::pkeyGet('QnA_Vote', $kv); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * The One True Thingy that must be defined and declared. | ||||
|      */ | ||||
|     public static function schemaDef() | ||||
|     { | ||||
|         return array( | ||||
|             'description' => 'For storing votes on questions and answers', | ||||
|             'fields' => array( | ||||
|                 'id' => array( | ||||
|                     'type'        => 'char',  | ||||
|                     'length'      => 36,  | ||||
|                     'not null'    => true,  | ||||
|                     'description' => 'UUID of the vote' | ||||
|                 ), | ||||
|                 'question_id' => array( | ||||
|                     'type'        => 'char',  | ||||
|                     'length'      => 36,  | ||||
|                     'not null'    => true,  | ||||
|                     'description' => 'UUID of question being voted on' | ||||
|                 ), | ||||
|                 'answer_id' => array( | ||||
|                     'type'        => 'char',  | ||||
|                     'length'      => 36,  | ||||
|                     'not null'    => true, | ||||
|                     'description' => 'UUID of answer being voted on' | ||||
|                 ), | ||||
|                 'vote'       => array('type' => 'int', 'size' => 'tiny'), | ||||
|                 'profile_id' => array('type' => 'int'), | ||||
|                 'created'    => array('type' => 'datetime', 'not null' => true), | ||||
|             ), | ||||
|             'primary key' => array('id'), | ||||
|             'indexes' => array( | ||||
|                 'profile_id_question_Id_index' => array( | ||||
|                     'profile_id',  | ||||
|                     'question_id' | ||||
|                 ), | ||||
|                 'profile_id_question_Id_index' => array( | ||||
|                     'profile_id',  | ||||
|                     'answer_id' | ||||
|                 ) | ||||
|             ) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Save a vote on a question or answer | ||||
|      * | ||||
|      * @param Profile  $profile | ||||
|      * @param QnA_Question the question being voted on | ||||
|      * @param QnA_Answer   the answer being voted on | ||||
|      * @param vote | ||||
|      * @param array | ||||
|      * | ||||
|      * @return Void | ||||
|      */ | ||||
|     static function save($profile, $question, $answer, $vote) | ||||
|     { | ||||
|         $v = new QnA_Vote(); | ||||
|         $v->id          = UUID::gen(); | ||||
|         $v->profile_id  = $profile->id; | ||||
|         $v->question_id = $question->id; | ||||
|         $v->answer_id   = $answer->id; | ||||
|         $v->vote        = $vote; | ||||
|         $v->created     = common_sql_now(); | ||||
|  | ||||
|         common_log(LOG_DEBUG, "Saving vote: $v->id $v->vote"); | ||||
|          | ||||
|         $v->insert(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1
									
								
								plugins/QnA/css/qna.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								plugins/QnA/css/qna.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| /* stubb for q&a css */ | ||||
							
								
								
									
										122
									
								
								plugins/QnA/lib/qnaanswerform.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								plugins/QnA/lib/qnaanswerform.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| <?php | ||||
| /** | ||||
|  * StatusNet - the distributed open-source microblogging tool | ||||
|  * Copyright (C) 2011, StatusNet, Inc. | ||||
|  * | ||||
|  * Form for answering a question | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * 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  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
|  | ||||
| if (!defined('STATUSNET')) { | ||||
|     // This check helps protect against security problems; | ||||
|     // your code file can't be executed directly from the web. | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Form to add a new answer to a question | ||||
|  * | ||||
|  * @category  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
| class QnaanswerForm extends Form | ||||
| { | ||||
|     protected $question; | ||||
|  | ||||
|     /** | ||||
|      * Construct a new answer form | ||||
|      * | ||||
|      * @param QnA_Question $question | ||||
|      * @param HTMLOutputter $out output channel | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function __construct(QnA_Question $question, HTMLOutputter $out) | ||||
|     { | ||||
|         parent::__construct($out); | ||||
|         $this->question = $question; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * ID of the form | ||||
|      * | ||||
|      * @return int ID of the form | ||||
|      */ | ||||
|     function id() | ||||
|     { | ||||
|         return 'answer-form'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * class of the form | ||||
|      * | ||||
|      * @return string class of the form | ||||
|      */ | ||||
|     function formClass() | ||||
|     { | ||||
|         return 'form_settings ajax'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Action of the form | ||||
|      * | ||||
|      * @return string URL of the action | ||||
|      */ | ||||
|     function action() | ||||
|     { | ||||
|         return common_local_url('qnanewanswer'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Data elements of the form | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function formData() | ||||
|     { | ||||
|         $question = $this->question; | ||||
|         $out      = $this->out; | ||||
|         $id       = "question-" . $question->id; | ||||
|  | ||||
|         $out->element('p', 'answer', $question->title); | ||||
|         $out->hidden('id', $id); | ||||
|         $out->element('input', array('type' => 'text', 'name' => 'answer')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Action elements | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function formActions() | ||||
|     { | ||||
|         // TRANS: Button text for submitting a poll response. | ||||
|         $this->out->submit('submit', _m('BUTTON', 'Submit')); | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										137
									
								
								plugins/QnA/lib/qnaquestionform.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								plugins/QnA/lib/qnaquestionform.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | ||||
| <?php | ||||
| /** | ||||
|  * StatusNet - the distributed open-source microblogging tool | ||||
|  * Copyright (C) 2011, StatusNet, Inc. | ||||
|  * | ||||
|  * Form for adding a new question | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * 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  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@copley.name> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
|  | ||||
| if (!defined('STATUSNET')) { | ||||
|     // This check helps protect against security problems; | ||||
|     // your code file can't be executed directly from the web. | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Form to add a new question | ||||
|  * | ||||
|  * @category  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@copley.name> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
| class QnaquestionForm extends Form | ||||
| { | ||||
|     protected $title; | ||||
|     protected $description; | ||||
|  | ||||
|     /** | ||||
|      * Construct a new question form | ||||
|      * | ||||
|      * @param HTMLOutputter $out output channel | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function __construct($out = null, $title = null, $description = null, $options = null) | ||||
|     { | ||||
|         parent::__construct($out); | ||||
|         $this->title       = $title; | ||||
|         $this->description = $description; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * ID of the form | ||||
|      * | ||||
|      * @return int ID of the form | ||||
|      */ | ||||
|     function id() | ||||
|     { | ||||
|         return 'newquestion-form'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * class of the form | ||||
|      * | ||||
|      * @return string class of the form | ||||
|      */ | ||||
|     function formClass() | ||||
|     { | ||||
|         return 'form_settings ajax-notice'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Action of the form | ||||
|      * | ||||
|      * @return string URL of the action | ||||
|      */ | ||||
|     function action() | ||||
|     { | ||||
|         return common_local_url('qnanewquestion'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Data elements of the form | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function formData() | ||||
|     { | ||||
|         $this->out->elementStart('fieldset', array('id' => 'newquestion-data')); | ||||
|         $this->out->elementStart('ul', 'form_data'); | ||||
|  | ||||
|         $this->li(); | ||||
|         $this->out->input( | ||||
|             'title', | ||||
|             _m('Title'), | ||||
|             $this->title, | ||||
|             _m('Title of your question') | ||||
|         ); | ||||
|         $this->unli(); | ||||
|         $this->li(); | ||||
|         $this->out->textarea( | ||||
|             'description', | ||||
|             _m('Description'), | ||||
|             $this->description, | ||||
|             _m('Your question in detail') | ||||
|         ); | ||||
|         $this->unli(); | ||||
|  | ||||
|         $this->out->elementEnd('ul'); | ||||
|         $this->out->elementEnd('fieldset'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Action elements | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function formActions() | ||||
|     { | ||||
|         // TRANS: Button text for saving a new question. | ||||
|         $this->out->submit('submit', _m('BUTTON', 'Save')); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										122
									
								
								plugins/QnA/lib/qnareviseanswerform.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								plugins/QnA/lib/qnareviseanswerform.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| <?php | ||||
| /** | ||||
|  * StatusNet - the distributed open-source microblogging tool | ||||
|  * Copyright (C) 2011, StatusNet, Inc. | ||||
|  * | ||||
|  * Form for revising a question | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * 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  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
|  | ||||
| if (!defined('STATUSNET')) { | ||||
|     // This check helps protect against security problems; | ||||
|     // your code file can't be executed directly from the web. | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Form to revise a question | ||||
|  * | ||||
|  * @category  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
| class QnareviseanswerForm extends Form | ||||
| { | ||||
|     protected $question; | ||||
|     protected $answer; | ||||
|  | ||||
|     /** | ||||
|      * Construct a new answer form | ||||
|      * | ||||
|      * @param QnA_Answer $answer | ||||
|      * @param HTMLOutputter $out output channel | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function __construct(QnA_Answer $answer, HTMLOutputter $out) | ||||
|     { | ||||
|         parent::__construct($out); | ||||
|         $this->question = $answer->getQuestion(); | ||||
|         $this->answer   = $answer; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * ID of the form | ||||
|      * | ||||
|      * @return int ID of the form | ||||
|      */ | ||||
|     function id() | ||||
|     { | ||||
|         return 'answered-form'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * class of the form | ||||
|      * | ||||
|      * @return string class of the form | ||||
|      */ | ||||
|     function formClass() | ||||
|     { | ||||
|         return 'form_settings ajax'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Action of the form | ||||
|      * | ||||
|      * @return string URL of the action | ||||
|      */ | ||||
|     function action() | ||||
|     { | ||||
|         return common_local_url('qnareviseanswer', array('id' => $this->question->id)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Data elements of the form | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function formData() | ||||
|     { | ||||
|         $question = $this->question; | ||||
|         $out      = $this->out; | ||||
|         $id       = "question-" . $question->id; | ||||
|  | ||||
|         $out->element('p', 'Your answer to:', $question->title); | ||||
|         $out->textarea('answerText', 'You said:', $this->answer->content); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Action elements | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function formActions() | ||||
|     { | ||||
|         // TRANS: Button text for submitting a poll response. | ||||
|         $this->out->submit('submit', _m('BUTTON', 'Submit')); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										121
									
								
								plugins/QnA/lib/qnavoteform.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								plugins/QnA/lib/qnavoteform.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| <?php | ||||
| /** | ||||
|  * StatusNet - the distributed open-source microblogging tool | ||||
|  * Copyright (C) 2011, StatusNet, Inc. | ||||
|  * | ||||
|  * Form for answering a question | ||||
|  * | ||||
|  * PHP version 5 | ||||
|  * | ||||
|  * 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  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
|  | ||||
| if (!defined('STATUSNET')) { | ||||
|     // This check helps protect against security problems; | ||||
|     // your code file can't be executed directly from the web. | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Form to add a new answer to a question | ||||
|  * | ||||
|  * @category  QnA | ||||
|  * @package   StatusNet | ||||
|  * @author    Zach Copley <zach@status.net> | ||||
|  * @copyright 2011 StatusNet, Inc. | ||||
|  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 | ||||
|  * @link      http://status.net/ | ||||
|  */ | ||||
| class QnavoteForm extends Form | ||||
| { | ||||
|     protected $question; | ||||
|  | ||||
|     /** | ||||
|      * Construct a new answer form | ||||
|      * | ||||
|      * @param QnA_Question $question | ||||
|      * @param HTMLOutputter $out output channel | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function __construct(QnA_Question $question, HTMLOutputter $out) | ||||
|     { | ||||
|         parent::__construct($out); | ||||
|         $this->question = $question; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * ID of the form | ||||
|      * | ||||
|      * @return int ID of the form | ||||
|      */ | ||||
|     function id() | ||||
|     { | ||||
|         return 'answer-form'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * class of the form | ||||
|      * | ||||
|      * @return string class of the form | ||||
|      */ | ||||
|     function formClass() | ||||
|     { | ||||
|         return 'form_settings ajax'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Action of the form | ||||
|      * | ||||
|      * @return string URL of the action | ||||
|      */ | ||||
|     function action() | ||||
|     { | ||||
|         return common_local_url('qnavote', array('id' => $this->question->id)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Data elements of the form | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function formData() | ||||
|     { | ||||
|         $question = $this->question; | ||||
|         $out      = $this->out; | ||||
|         $id       = "question-" . $question->id; | ||||
|  | ||||
|         $out->element('p', 'answer', $question->question); | ||||
|         $out->element('input', array('type' => 'text', 'name' => 'vote')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Action elements | ||||
|      * | ||||
|      * @return void | ||||
|      */ | ||||
|     function formActions() | ||||
|     { | ||||
|         // TRANS: Button text for submitting a poll response. | ||||
|         $this->out->submit('submit', _m('BUTTON', 'Submit')); | ||||
|     } | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user