From 5193afb8bf304071f4af79f165bc27c66ee33d7e Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 4 Apr 2011 14:33:20 -0700 Subject: [PATCH] QnA - Allow closing questions --- plugins/QnA/QnAPlugin.php | 41 ++-- plugins/QnA/actions/qnaclosequestion.php | 200 ++++++++++++++++++ plugins/QnA/classes/QnA_Question.php | 49 +---- plugins/QnA/lib/qnanewanswerform.php | 4 +- ...uestionform.php => qnanewquestionform.php} | 2 +- plugins/QnA/lib/qnashowanswerform.php | 6 +- plugins/QnA/lib/qnashowquestionform.php | 160 ++++++++++++++ 7 files changed, 395 insertions(+), 67 deletions(-) create mode 100644 plugins/QnA/actions/qnaclosequestion.php rename plugins/QnA/lib/{qnaquestionform.php => qnanewquestionform.php} (98%) create mode 100644 plugins/QnA/lib/qnashowquestionform.php diff --git a/plugins/QnA/QnAPlugin.php b/plugins/QnA/QnAPlugin.php index a586d89b40..cc70cb7aeb 100644 --- a/plugins/QnA/QnAPlugin.php +++ b/plugins/QnA/QnAPlugin.php @@ -81,18 +81,19 @@ class QnAPlugin extends MicroAppPlugin case 'QnanewquestionAction': case 'QnanewanswerAction': case 'QnashowquestionAction': + case 'QnaclosequestionAction': case 'QnashowanswerAction': case 'QnareviseanswerAction': case 'QnavoteAction': include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; return false; - case 'QnaquestionForm': - case 'QnashowanswerForm': + case 'QnanewquestionForm': + case 'QnashowquestionForm': case 'QnanewanswerForm': + case 'QnashowanswerForm': case 'QnareviseanswerForm': case 'QnavoteForm': - case 'AnswerNoticeListItem': include_once $dir . '/lib/' . strtolower($cls).'.php'; break; case 'QnA_Question': @@ -122,6 +123,10 @@ class QnAPlugin extends MicroAppPlugin 'main/qna/newquestion', array('action' => 'qnanewquestion') ); + $m->connect( + 'answer/qna/closequestion', + array('action' => 'qnaclosequestion') + ); $m->connect( 'main/qna/newanswer', array('action' => 'qnanewanswer') @@ -384,23 +389,19 @@ class QnAPlugin extends MicroAppPlugin $question = QnA_Question::getByNotice($notice); if (!empty($question)) { - - $short = $this->shorten($question->description, $notice); - $out->raw($short); - - // Don't prompt user for an answer if the question is closed or - // the current user posed the question in the first place - if (empty($question->closed)) { - if (!empty($user)) { - $profile = $user->getProfile(); - $answer = $question->getAnswer($profile); - if (!$answer) { - $form = new QnanewanswerForm($question, $out); - $form->show(); - } - } + if (empty($user)) { + $form = new QnashowquestionForm($out, $question); + $form->show(); } else { - $out->element('span', 'closed', _m('This question is closed.')); + $profile = $user->getProfile(); + $answer = $question->getAnswer($profile); + if (empty($answer)) { + $form = new QnanewanswerForm($out, $question); + $form->show(); + } else { + $form = new QnashowquestionForm($out, $question); + $form->show(); + } } } else { $out->text(_m('Question data is missing.')); @@ -465,7 +466,7 @@ class QnAPlugin extends MicroAppPlugin function entryForm($out) { - return new QnaquestionForm($out); + return new QnanewquestionForm($out); } /** diff --git a/plugins/QnA/actions/qnaclosequestion.php b/plugins/QnA/actions/qnaclosequestion.php new file mode 100644 index 0000000000..28d4e547b4 --- /dev/null +++ b/plugins/QnA/actions/qnaclosequestion.php @@ -0,0 +1,200 @@ +. + * + * @category QnA + * @package StatusNet + * @author Zach Copley + * @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); +} + +/** + * Close a question to new answers + * + * @category QnA + * @package StatusNet + * @author Zach Copley + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ +class QnaclosequestionAction 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 close a question + return _m('Close question'); + } + + /** + * 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 close a question when not logged in + throw new ClientException( + _m("You must be logged in to close a question."), + 403 + ); + } + + if ($this->isPost()) { + $this->checkSessionToken(); + } + + $id = substr($this->trimmed('id'), 9); + $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); + } + + 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->closeQuestion(); + } else { + $this->showPage(); + } + + return; + } + + /** + * Close a question + * + * @return void + */ + function closeQuestion() + { + + $user = common_current_user(); + + try { + + if ($user->id != $this->question->profile_id) { + throw new Exception(_m('You didn\'t ask this question.')); + } + + $orig = clone($this->question); + $this->question->closed = 1; + $this->question->update($orig); + + } 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 QnashowquestionForm($this, $this->question); + $form->show(); + $this->elementEnd('body'); + $this->elementEnd('html'); + } else { + common_redirect($this->question->bestUrl(), 303); + } + } + + /** + * Show the close question form + * + * @return void + */ + function showContent() + { + if (!empty($this->error)) { + $this->element('p', 'error', $this->error); + } + + // blar + } + + /** + * 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; + } + } +} diff --git a/plugins/QnA/classes/QnA_Question.php b/plugins/QnA/classes/QnA_Question.php index 0446128ea0..93d45c56c8 100644 --- a/plugins/QnA/classes/QnA_Question.php +++ b/plugins/QnA/classes/QnA_Question.php @@ -201,66 +201,31 @@ class QnA_Question extends Managed_DataObject function asHTML() { - return self::toHTML( - $this->getProfile(), - $this, - $this->getAnswers() - ); + return self::toHTML($this->getProfile(), $this); } function asString() { - return self::toString( - $this->getProfile(), - $this, - $this->getAnswers() - ); + return self::toString($this->getProfile(), $this); } - static function toHTML($profile, $question, $answer) + static function toHTML($profile, $question) { $notice = $question->getNotice(); - $fmt = '

'; - $fmt .= '%2$s'; - $fmt .= '%3$s'; - $fmt .= 'asked by %5$s'; - $fmt .= '

'; + $fmt = '%s'; $q = sprintf( $fmt, - htmlspecialchars($notice->bestUrl()), - htmlspecialchars($question->title), - htmlspecialchars($question->description), - htmlspecialchars($profile->profileurl), - htmlspecialchars($profile->getBestName()) + htmlspecialchars($question->description) ); - $ans = array(); - - $ans[] = '
'; - - while($answer->fetch()) { - $ans[] = $answer->asHTML(); - } - - $ans[] .= '
'; - - return $q . implode($ans); + return $q; } static function toString($profile, $question, $answers) { - $fmt = _m( - '%1$s asked the question "%2$s": %3$s' - ); - - return sprintf( - $fmt, - htmlspecialchars($profile->getBestName()), - htmlspecialchars($question->title), - htmlspecialchars($question->description) - ); + return sprintf(htmlspecialchars($question->description)); } /** diff --git a/plugins/QnA/lib/qnanewanswerform.php b/plugins/QnA/lib/qnanewanswerform.php index 34e73def0a..db4d1dfafc 100644 --- a/plugins/QnA/lib/qnanewanswerform.php +++ b/plugins/QnA/lib/qnanewanswerform.php @@ -56,7 +56,7 @@ class QnanewanswerForm extends Form * * @return void */ - function __construct(QnA_Question $question, HTMLOutputter $out) + function __construct(HTMLOutputter $out, QnA_Question $question) { parent::__construct($out); $this->question = $question; @@ -103,6 +103,8 @@ class QnanewanswerForm extends Form $out = $this->out; $id = "question-" . $question->id; + $out->raw($this->question->asHTML()); + $out->element('p', 'answer', 'Your answer'); $out->hidden('id', $id); $out->textarea('answer', 'answer'); diff --git a/plugins/QnA/lib/qnaquestionform.php b/plugins/QnA/lib/qnanewquestionform.php similarity index 98% rename from plugins/QnA/lib/qnaquestionform.php rename to plugins/QnA/lib/qnanewquestionform.php index 9d0c2aad59..114e6199a1 100644 --- a/plugins/QnA/lib/qnaquestionform.php +++ b/plugins/QnA/lib/qnanewquestionform.php @@ -44,7 +44,7 @@ if (!defined('STATUSNET')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @link http://status.net/ */ -class QnaquestionForm extends Form +class QnanewquestionForm extends Form { protected $title; protected $description; diff --git a/plugins/QnA/lib/qnashowanswerform.php b/plugins/QnA/lib/qnashowanswerform.php index 54f3f8fcac..5ec63e1096 100644 --- a/plugins/QnA/lib/qnashowanswerform.php +++ b/plugins/QnA/lib/qnashowanswerform.php @@ -65,8 +65,8 @@ class QnashowanswerForm extends Form { parent::__construct($out); - $this->answer = $answer; - $this->question = $answer->getQuestion(); + $this->answer = $answer; + $this->question = $answer->getQuestion(); } /** @@ -124,6 +124,7 @@ class QnashowanswerForm extends Form 'id', 'revise-' . $this->answer->id ); + $this->out->raw($this->answer->asHTML()); } @@ -141,7 +142,6 @@ class QnashowanswerForm extends Form if (empty($this->question->closed)) { if ($user->id == $this->question->profile_id) { - common_debug("I am the question asker!"); if (empty($this->answer->best)) { $this->out->submit( 'best', diff --git a/plugins/QnA/lib/qnashowquestionform.php b/plugins/QnA/lib/qnashowquestionform.php new file mode 100644 index 0000000000..71e644e2dc --- /dev/null +++ b/plugins/QnA/lib/qnashowquestionform.php @@ -0,0 +1,160 @@ +. + * + * @category Form + * @package StatusNet + * @author Zach Copley + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +require_once INSTALLDIR . '/lib/form.php'; + +/** + * Form for showing a question + * + * @category Form + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * + */ +class QnashowquestionForm extends Form +{ + /** + * The question to show + */ + var $question = null; + + /** + * Constructor + * + * @param HTMLOutputter $out output channel + * @param QnA_Question $question the question to show + */ + function __construct($out = null, $question = null) + { + parent::__construct($out); + $this->question = $question; + } + + /** + * ID of the form + * + * @return int ID of the form + */ + function id() + { + return 'question-' . $this->question->id; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + function action() + { + return common_local_url('qnaclosequestion'); + } + + /** + * Include a session token for CSRF protection + * + * @return void + */ + function sessionToken() + { + $this->out->hidden( + 'token', + common_session_token() + ); + } + + /** + * Legend of the Form + * + * @return void + */ + function formLegend() + { + // TRANS: Form legend for revising the answer. + $this->out->element('legend', null, _('Question')); + } + + /** + * Data elements + * + * @return void + */ + function formData() + { + $this->out->hidden( + 'id', + 'question-' . $this->question->id + ); + + $this->out->raw($this->question->asHTML()); + } + + /** + * Action elements + * + * @return void + */ + function formActions() + { + $user = common_current_user(); + if (empty($user)) { + return; + } + + if (empty($this->question->closed)) { + if ($user->id == $this->question->profile_id) { + $this->out->submit( + 'close', + // TRANS: Button text for closing a question + _m('BUTTON', 'Close'), + 'submit', + null, + // TRANS: Title for button text for closing a question + _('Close the question') + ); + } + } + } + + /** + * Class of the form. + * + * @return string the form's class + */ + function formClass() + { + return 'form_close ajax'; + } +}