]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge remote-tracking branch 'mainline/1.0.x' into people_tags_rebase
authorShashi Gowda <connect2shashi@gmail.com>
Tue, 5 Apr 2011 04:58:05 +0000 (10:28 +0530)
committerShashi Gowda <connect2shashi@gmail.com>
Tue, 5 Apr 2011 04:58:05 +0000 (10:28 +0530)
25 files changed:
actions/editgroup.php
actions/newgroup.php
classes/Notice.php
classes/User_group.php
classes/statusnet.ini
lib/apiaction.php
lib/groupeditform.php
plugins/Event/eventform.php
plugins/Event/newevent.php
plugins/QnA/QnAPlugin.php
plugins/QnA/actions/qnaclosequestion.php [new file with mode: 0644]
plugins/QnA/actions/qnanewanswer.php
plugins/QnA/actions/qnanewquestion.php
plugins/QnA/actions/qnareviseanswer.php [new file with mode: 0644]
plugins/QnA/classes/QnA_Answer.php
plugins/QnA/classes/QnA_Question.php
plugins/QnA/js/qna.js [new file with mode: 0644]
plugins/QnA/lib/qnaanswerform.php [deleted file]
plugins/QnA/lib/qnanewanswerform.php [new file with mode: 0644]
plugins/QnA/lib/qnanewquestionform.php [new file with mode: 0644]
plugins/QnA/lib/qnaquestionform.php [deleted file]
plugins/QnA/lib/qnareviseanswerform.php
plugins/QnA/lib/qnashowanswerform.php [new file with mode: 0644]
plugins/QnA/lib/qnashowquestionform.php [new file with mode: 0644]
theme/neo/css/display.css

index f5bada04fc074e7162a7cb8ad1eebc997b83de8b..e46b1481d0d2ae717e933100aa56d94e3e73b460 100644 (file)
@@ -185,7 +185,15 @@ class EditgroupAction extends GroupDesignAction
             $description = $this->trimmed('description');
             $location    = $this->trimmed('location');
             $aliasstring = $this->trimmed('aliases');
-            $join_policy = intval($this->arg('join_policy'));
+            $private     = $this->boolean('private');
+
+            if ($private) {
+                $force_scope = 1;
+                $join_policy = User_group::JOIN_POLICY_MODERATE;
+            } else {
+                $force_scope = 0;
+                $join_policy = User_group::JOIN_POLICY_OPEN;
+            }
 
             if ($this->nicknameExists($nickname)) {
                 // TRANS: Group edit form validation error.
@@ -267,6 +275,7 @@ class EditgroupAction extends GroupDesignAction
             $this->group->location    = $location;
             $this->group->mainpage    = common_local_url('showgroup', array('nickname' => $nickname));
             $this->group->join_policy = $join_policy;
+            $this->group->force_scope = $force_scope;
 
             $result = $this->group->update($orig);
 
index 540a42b9ba1554a84fa903519ba5cdc47fd985ba..c54e24ed95103226918f16b5e9b7898f058e5e7c 100644 (file)
@@ -130,8 +130,8 @@ class NewgroupAction extends Action
             $homepage    = $this->trimmed('homepage');
             $description = $this->trimmed('description');
             $location    = $this->trimmed('location');
+            $private     = $this->boolean('private');
             $aliasstring = $this->trimmed('aliases');
-            $join_policy = intval($this->arg('join_policy'));
 
             if ($this->nicknameExists($nickname)) {
                 // TRANS: Group create form validation error.
@@ -203,6 +203,14 @@ class NewgroupAction extends Action
                 }
             }
 
+            if ($private) {
+                $force_scope = 1;
+                $join_policy = User_group::JOIN_POLICY_MODERATE;
+            } else {
+                $force_scope = 0;
+                $join_policy = User_group::JOIN_POLICY_OPEN;
+            }
+
             $cur = common_current_user();
 
             // Checked in prepare() above
@@ -217,6 +225,7 @@ class NewgroupAction extends Action
                                                 'aliases'  => $aliases,
                                                 'userid'   => $cur->id,
                                                 'join_policy' => $join_policy,
+                                                'force_scope' => $force_scope,
                                                 'local'    => true));
 
             $this->group = $group;
index 07fa373339b89e137d5b0a5bf3650e0c6129842e..5a91e6f13a84c80021478795a0fa8b6c156f1a3d 100644 (file)
@@ -342,6 +342,14 @@ class Notice extends Memcached_DataObject
         $notice->uri = $uri;
         $notice->url = $url;
 
+        // Get the groups here so we can figure out replies and such
+
+        if (!isset($groups)) {
+            $groups = self::groupsFromText($notice->content, $profile);
+        }
+
+        $reply = null;
+
         // Handle repeat case
 
         if (isset($repeat_of)) {
@@ -379,18 +387,35 @@ class Notice extends Memcached_DataObject
 
             $notice->repeat_of = $repeat_of;
         } else {
-            $notice->reply_to = self::getReplyTo($reply_to, $profile_id, $source, $final);
-        }
+            $reply = self::getReplyTo($reply_to, $profile_id, $source, $final);
+
+            if (!empty($reply)) {
+
+                if (!$reply->inScope($profile)) {
+                    // TRANS: Client error displayed when trying to reply to a notice a the target has no access to.
+                    // TRANS: %1$s is a user nickname, %2$d is a notice ID (number).
+                    throw new ClientException(sprintf(_('%1$s has no access to notice %2$d.'),
+                                                      $profile->nickname, $reply->id), 403);
+                }
+
+                $notice->reply_to     = $reply->id;
+                $notice->conversation = $reply->conversation;
 
-        if (!empty($notice->reply_to)) {
-            $reply = Notice::staticGet('id', $notice->reply_to);
-            if (!$reply->inScope($profile)) {
-                // TRANS: Client error displayed when trying to reply to a notice a the target has no access to.
-                // TRANS: %1$s is a user nickname, %2$d is a notice ID (number).
-                throw new ClientException(sprintf(_('%1$s has no access to notice %2$d.'),
-                                                  $profile->nickname, $reply->id), 403);
+                // If the original is private to a group, and notice has no group specified,
+                // make it to the same group(s)
+
+                if (empty($groups) && ($reply->scope | Notice::GROUP_SCOPE)) {
+                    $groups = array();
+                    $replyGroups = $reply->getGroups();
+                    foreach ($replyGroups as $group) {
+                        if ($profile->isMember($group)) {
+                            $groups[] = $group->id;
+                        }
+                    }
+                }
+
+                // Scope set below
             }
-            $notice->conversation = $reply->conversation;
         }
 
         if (!empty($lat) && !empty($lon)) {
@@ -416,7 +441,11 @@ class Notice extends Memcached_DataObject
         }
 
         if (is_null($scope)) { // 0 is a valid value
-            $notice->scope = common_config('notice', 'defaultscope');
+            if (!empty($reply)) {
+                $notice->scope = $reply->scope;
+            } else {
+                $notice->scope = common_config('notice', 'defaultscope');
+            }
         } else {
             $notice->scope = $scope;
         }
@@ -433,6 +462,18 @@ class Notice extends Memcached_DataObject
             }
         }
 
+        // Force the scope for private groups
+
+        foreach ($groups as $groupId) {
+            $group = User_group::staticGet('id', $groupId);
+            if (!empty($group)) {
+                if ($group->force_scope) {
+                    $notice->scope |= Notice::GROUP_SCOPE;
+                    break;
+                }
+            }
+        }
+
         if (Event::handle('StartNoticeSave', array(&$notice))) {
 
             // XXX: some of these functions write to the DB
@@ -496,11 +537,9 @@ class Notice extends Memcached_DataObject
 
         // Note: groups may save tags, so must be run after tags are saved
         // to avoid errors on duplicates.
-        if (isset($groups)) {
-            $notice->saveKnownGroups($groups);
-        } else {
-            $notice->saveGroups();
-        }
+        // Note: groups should always be set.
+
+        $notice->saveKnownGroups($groups);
 
         if (isset($peopletags)) {
             $notice->saveProfileTags($peopletags);
@@ -992,7 +1031,15 @@ class Notice extends Memcached_DataObject
                     common_log_db_error($gi, 'INSERT', __FILE__);
                 }
 
-                // @fixme should we save the tags here or not?
+                // we automatically add a tag for every group name, too
+
+                $tag = Notice_tag::pkeyGet(array('tag' => common_canonical_tag($group->nickname),
+                                                 'notice_id' => $this->id));
+
+                if (is_null($tag)) {
+                    $this->saveTag($group->nickname);
+                }
+
                 $groups[] = clone($group);
             } else {
                 common_log(LOG_ERR, "Local delivery to group id $id skipped, doesn't exist");
@@ -1014,36 +1061,19 @@ class Notice extends Memcached_DataObject
             return array();
         }
 
-        $groups = array();
-
-        /* extract all !group */
-        $count = preg_match_all('/(?:^|\s)!(' . Nickname::DISPLAY_FMT . ')/',
-                                strtolower($this->content),
-                                $match);
-        if (!$count) {
-            return $groups;
-        }
-
         $profile = $this->getProfile();
 
+        $groups = self::groupsFromText($this->content, $profile);
+
         /* Add them to the database */
 
-        foreach (array_unique($match[1]) as $nickname) {
+        foreach ($groups as $group) {
             /* XXX: remote groups. */
-            $group = User_group::getForNickname($nickname, $profile);
 
             if (empty($group)) {
                 continue;
             }
 
-            // we automatically add a tag for every group name, too
-
-            $tag = Notice_tag::pkeyGet(array('tag' => common_canonical_tag($nickname),
-                                             'notice_id' => $this->id));
-
-            if (is_null($tag)) {
-                $this->saveTag($nickname);
-            }
 
             if ($profile->isMember($group)) {
 
@@ -1639,7 +1669,7 @@ class Notice extends Memcached_DataObject
         if (!empty($reply_to)) {
             $reply_notice = Notice::staticGet('id', $reply_to);
             if (!empty($reply_notice)) {
-                return $reply_to;
+                return $reply_notice;
             }
         }
 
@@ -1678,8 +1708,10 @@ class Notice extends Memcached_DataObject
         $last = $recipient->getCurrentNotice();
 
         if (!empty($last)) {
-            return $last->id;
+            return $last;
         }
+
+        return null;
     }
 
     static function maxContent()
@@ -2295,4 +2327,27 @@ class Notice extends Memcached_DataObject
 
         return true;
     }
+
+    static function groupsFromText($text, $profile)
+    {
+        $groups = array();
+
+        /* extract all !group */
+        $count = preg_match_all('/(?:^|\s)!(' . Nickname::DISPLAY_FMT . ')/',
+                                strtolower($text),
+                                $match);
+
+        if (!$count) {
+            return $groups;
+        }
+
+        foreach (array_unique($match[1]) as $nickname) {
+            $group = User_group::getForNickname($nickname, $profile);
+            if (!empty($group) && $profile->isMember($group)) {
+                $groups[] = $group->id;
+            }
+        }
+
+        return $groups;
+    }
 }
index 8587f15771d161e597914c982e38b2ce733043fb..f72cc57533db1f8eb3f526b2016b6be0788bfcc9 100644 (file)
@@ -28,6 +28,7 @@ class User_group extends Memcached_DataObject
     public $uri;                             // varchar(255)  unique_key
     public $mainpage;                        // varchar(255)
     public $join_policy;                     // tinyint
+    public $force_scope;                     // tinyint
 
     /* Static get */
     function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('User_group',$k,$v); }
@@ -514,12 +515,19 @@ class User_group extends Memcached_DataObject
         $group->uri         = $uri;
         $group->mainpage    = $mainpage;
         $group->created     = common_sql_now();
+
         if (isset($fields['join_policy'])) {
             $group->join_policy = intval($fields['join_policy']);
         } else {
             $group->join_policy = 0;
         }
 
+        if (isset($fields['force_scope'])) {
+            $group->force_scope = intval($fields['force_scope']);
+        } else {
+            $group->force_scope = 0;
+        }
+
         if (Event::handle('StartGroupSave', array(&$group))) {
 
             $result = $group->insert();
@@ -643,4 +651,10 @@ class User_group extends Memcached_DataObject
         }
         parent::delete();
     }
+
+    function isPrivate()
+    {
+        return ($this->join_policy == self::JOIN_POLICY_MODERATE &&
+                $this->force_scope == 1);
+    }
 }
index a5de206c7fcb3514a9e66bc217f0fb5d40f360f0..05f339ca5a36ef669ad959497bc1ff873debc8ac 100644 (file)
@@ -662,6 +662,7 @@ modified = 384
 uri = 2
 mainpage = 2
 join_policy = 1
+force_scope = 1
 
 [user_group__keys]
 id = N
index 388c9be0c5e6c17a535c1534be9149ad2a8f3d10..c0e5095fd5030153ed71275f34e477bba47f64db 100644 (file)
@@ -202,6 +202,8 @@ class ApiAction extends Action
     {
         $twitter_user = array();
 
+        $user = $profile->getUser();
+
         $twitter_user['id'] = intval($profile->id);
         $twitter_user['name'] = $profile->getBestName();
         $twitter_user['screen_name'] = $profile->nickname;
@@ -213,11 +215,10 @@ class ApiAction extends Action
             Avatar::defaultImage(AVATAR_STREAM_SIZE);
 
         $twitter_user['url'] = ($profile->homepage) ? $profile->homepage : null;
-        $twitter_user['protected'] = false; # not supported by StatusNet yet
+        $twitter_user['protected'] = ($user->private_stream) ? true : false;
         $twitter_user['followers_count'] = $profile->subscriberCount();
 
-        $design        = null;
-        $user          = $profile->getUser();
+        $design = null;
 
         // Note: some profiles don't have an associated user
 
index bb0ab4f7fbf845076ee497186c0edacc1e0239f3..c1218ab35450d27a0993e641b4543f4fe7fb5ffa 100644 (file)
@@ -202,17 +202,10 @@ class GroupEditForm extends Form
                 $this->out->elementEnd('li');
             }
             $this->out->elementStart('li');
-            $this->out->dropdown('join_policy',
-                                 // TRANS: Dropdown fieldd label on group edit form.
-                                 _('Membership policy'),
-                                 // TRANS: Group membership policy option.
-                                 array(User_group::JOIN_POLICY_OPEN     => _('Open to all'),
-                                       // TRANS: Group membership policy option.
-                                       User_group::JOIN_POLICY_MODERATE => _('Admin must approve all members')),
-                                 // TRANS: Dropdown field title on group edit form.
-                                 _('Whether admin approval is required to join this group.'),
-                                 false,
-                                 (empty($this->group->join_policy)) ? User_group::JOIN_POLICY_OPEN : $this->group->join_policy);
+            $this->out->checkbox('private', _('Private'), 
+                                  ($this->out->arg('private')) ? $this->out->arg('private') :
+                                 ((!empty($this->group)) ? $this->group->isPrivate() : false),
+                                 _('New members must be approved by admin and all posts are forced to be private'));
             $this->out->elementEnd('li');
             Event::handle('EndGroupEditFormData', array($this));
         }
index 31fecb1278d0fb099ce754b6a067eba15022b57e..dfdb65a30d77f901e1d9f7415b377d11ed2ee200 100644 (file)
@@ -147,6 +147,13 @@ class EventForm extends Form
                           _m('Description of the event.'));
         $this->unli();
 
+        $this->li();
+        $toWidget = new ToSelector($this->out,
+                                   common_current_user(),
+                                   null);
+        $toWidget->show();
+        $this->unli();
+
         $this->out->elementEnd('ul');
         $this->out->elementEnd('fieldset');
     }
index 082f12bb4bbdbdc5b376e312f98ca64a7b388f74..93baa37b6b82f3cdfb520819acbc456ba1cdbb4e 100644 (file)
@@ -190,6 +190,12 @@ class NeweventAction extends Action
                 throw new ClientException(_m('Event must have an end time.'));
             }
 
+            $options = array();
+
+            // Does the heavy-lifting for getting "To:" information
+
+            ToSelector::fillOptions($this, $options);
+            
             $profile = $this->user->getProfile();
 
             $saved = Happening::saveNew($profile,
@@ -198,7 +204,8 @@ class NeweventAction extends Action
                                         $this->title,
                                         $this->location,
                                         $this->description,
-                                        $this->url);
+                                        $this->url,
+                                        $options);
 
             $event = Happening::fromNotice($saved);
 
index c62eefa6716362eb88fadd4a06d5a1e8518a56f8..fe429750655a795ab7793045297fe3b8f43af272 100644 (file)
@@ -81,14 +81,17 @@ 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 'QnaanswerForm':
+        case 'QnanewquestionForm':
+        case 'QnashowquestionForm':
+        case 'QnanewanswerForm':
+        case 'QnashowanswerForm':
         case 'QnareviseanswerForm':
         case 'QnavoteForm':
             include_once $dir . '/lib/' . strtolower($cls).'.php';
@@ -120,10 +123,18 @@ 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')
         );
+        $m->connect(
+            'main/qna/reviseanswer',
+            array('action' => 'qnareviseanswer')
+        );
         $m->connect(
             'question/vote/:id',
             array('action' => 'qnavote', 'type' => 'question'),
@@ -269,20 +280,55 @@ class QnAPlugin extends MicroAppPlugin
     }
 
     /**
-     * Change the verb on Answer notices
+     * Output our CSS class for QnA notice list elements
      *
-     * @param Notice $notice
+     * @param NoticeListItem $nli The item being shown
      *
-     * @return ActivityObject
+     * @return boolean hook value
      */
 
-    function onEndNoticeAsActivity($notice, &$act) {
-        switch ($notice->object_type) {
-        case Answer::NORMAL:
-        case Answer::ANONYMOUS:
-            $act->verb = $notice->object_type;
+    function onStartOpenNoticeListItemElement($nli)
+    {
+        $type = $nli->notice->object_type;
+
+        switch($type)
+        {
+        case QnA_Question::OBJECT_TYPE:
+            $id = (empty($nli->repeat)) ? $nli->notice->id : $nli->repeat->id;
+            $nli->out->elementStart(
+                'li', array(
+                    'class' => 'hentry notice question',
+                    'id'    => 'notice-' . $id
+                )
+            );
+            Event::handle('EndOpenNoticeListItemElement', array($nli));
+            return false;
+            break;
+        case QnA_Answer::OBJECT_TYPE:
+            $id = (empty($nli->repeat)) ? $nli->notice->id : $nli->repeat->id;
+
+            $cls = array('hentry', 'notice', 'answer');
+
+            $answer = QnA_Answer::staticGet('uri', $notice->uri);
+
+            if (!empty($answer) && !empty($answer->best)) {
+                $cls[] = 'best';
+            }
+
+            $nli->out->elementStart(
+                'li',
+                array(
+                    'class' => implode(' ', $cls),
+                    'id'    => 'notice-' . $id
+                )
+            );
+            Event::handle('EndOpenNoticeListItemElement', array($nli));
+            return false;
             break;
+        default:
+            return true;
         }
+
         return true;
     }
 
@@ -292,6 +338,7 @@ class QnAPlugin extends MicroAppPlugin
      * @param Notice $notice
      * @param HTMLOutputter $out
      */
+
     function showNotice($notice, $out)
     {
         switch ($notice->object_type) {
@@ -319,20 +366,24 @@ class QnAPlugin extends MicroAppPlugin
         $nli = new NoticeListItem($notice, $out);
         $nli->showNotice();
 
-        $out->elementStart('div', array('class' => 'entry-content question-content'));
+        $out->elementStart('div', array('class' => 'entry-content question-description'));
+
         $question = QnA_Question::getByNotice($notice);
 
-        if ($question) {
-            if ($user) {
+        if (!empty($question)) {
+            if (empty($user)) {
+                $form = new QnashowquestionForm($out, $question);
+                $form->show();
+            } else {
                 $profile = $user->getProfile();
                 $answer = $question->getAnswer($profile);
-                if ($answer) {
-                    // User has already answer; show the results.
-                    $form = new QnareviseanswerForm($answer, $out);
+                if (empty($answer)) {
+                    $form = new QnanewanswerForm($out, $question);
+                    $form->show();
                 } else {
-                    $form = new QnaanswerForm($question, $out);
+                    $form = new QnashowquestionForm($out, $question);
+                    $form->show();
                 }
-                $form->show();
             }
         } else {
             $out->text(_m('Question data is missing.'));
@@ -347,14 +398,47 @@ class QnAPlugin extends MicroAppPlugin
     {
         $user = common_current_user();
 
-        // @hack we want regular rendering, then just add stuff after that
+        $answer   = QnA_Answer::getByNotice($notice);
+        $question = $answer->getQuestion();
+
         $nli = new NoticeListItem($notice, $out);
         $nli->showNotice();
 
+        $out->elementStart('div', array('class' => 'entry-content answer-content'));
+
+        if (!empty($answer)) {
+            $form = new QnashowanswerForm($out, $answer);
+            $form->show();
+        } else {
+            $out->text(_m('Answer data is missing.'));
+        }
+
+        $out->elementEnd('div');
+
         // @fixme
         $out->elementStart('div', array('class' => 'entry-content'));
     }
 
+    static function shorten($content, $notice)
+    {
+        $short = null;
+
+        if (Notice::contentTooLong($content)) {
+            common_debug("content too long");
+            $max = Notice::maxContent();
+            $short = mb_substr($content, 0, $max - 1);
+            $short .= sprintf(
+                '<a href="%s" rel="more" title="%s">…</a>',
+                $notice->uri,
+                _m('more')
+            );
+        } else {
+            $short = $content;
+        }
+
+        return $short;
+    }
+
     /**
      * Form for our app
      *
@@ -364,7 +448,7 @@ class QnAPlugin extends MicroAppPlugin
 
     function entryForm($out)
     {
-        return new QnaquestionForm($out);
+        return new QnanewquestionForm($out);
     }
 
     /**
@@ -394,7 +478,8 @@ class QnAPlugin extends MicroAppPlugin
 
     function onEndShowScripts($action)
     {
-        // XXX maybe some cool shiz here
+        $action->script($this->path('js/qna.js'));
+        return true;
     }
 
     function onEndShowStyles($action)
diff --git a/plugins/QnA/actions/qnaclosequestion.php b/plugins/QnA/actions/qnaclosequestion.php
new file mode 100644 (file)
index 0000000..28d4e54
--- /dev/null
@@ -0,0 +1,200 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Close a question to further 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);
+}
+
+/**
+ * Close a question to new answers
+ *
+ * @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 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;
+        }
+    }
+}
index 09d111040d15634c4522bf4f360e369b3b3fe884..94bfc09a39903da7d699ffe2b8a841870a25b0c1 100644 (file)
@@ -20,7 +20,7 @@
  * 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
+ * @category  QnA
  * @package   StatusNet
  * @author    Zach Copley <zach@status.net>
  * @copyright 2011 StatusNet, Inc.
@@ -137,9 +137,11 @@ class QnanewanswerAction extends Action
      */
     function newAnswer()
     {
+        $profile = $this->user->getProfile();
+
         try {
             $notice = QnA_Answer::saveNew(
-                $this->user->getProfile(),
+                $profile,
                 $this->question,
                 $this->answerText
             );
@@ -150,6 +152,7 @@ class QnanewanswerAction extends Action
         }
         if ($this->boolean('ajax')) {
             common_debug("ajaxy part");
+            $answer = $this->question->getAnswer($profile);
             header('Content-Type: text/xml;charset=utf-8');
             $this->xw->startDocument('1.0', 'UTF-8');
             $this->elementStart('html');
@@ -158,7 +161,7 @@ class QnanewanswerAction extends Action
             $this->element('title', null, _m('Answers'));
             $this->elementEnd('head');
             $this->elementStart('body');
-            $this->raw()
+            $this->raw($answer->asHTML());
             $this->elementEnd('body');
             $this->elementEnd('html');
         } else {
@@ -177,7 +180,7 @@ class QnanewanswerAction extends Action
             $this->element('p', 'error', $this->error);
         }
 
-        $form = new QnaanswerForm($this->question, $this);
+        $form = new QnanewanswerForm($this->question, $this);
         $form->show();
 
         return;
index 8682f8dd47213236dbb614d5f625456a0c21cd64..561b11575a7f136652b005b148c43fdeca193e63 100644 (file)
@@ -88,6 +88,7 @@ class QnanewquestionAction extends Action
         }
 
         $this->title       = $this->trimmed('title');
+        common_debug("TITLE = " . $this->title);
         $this->description = $this->trimmed('description');
 
         return true;
diff --git a/plugins/QnA/actions/qnareviseanswer.php b/plugins/QnA/actions/qnareviseanswer.php
new file mode 100644 (file)
index 0000000..cea1258
--- /dev/null
@@ -0,0 +1,273 @@
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Revise an 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);
+}
+
+/**
+ * Revise an 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 QnareviseanswerAction extends Action
+{
+    protected $user     = null;
+    protected $error    = null;
+    protected $question = null;
+    protected $answer   = null;
+    protected $content  = null;
+
+    /**
+     * Returns the title of the action
+     *
+     * @return string Action title
+     */
+    function title()
+    {
+        // TRANS: Page title for revising a question
+        return _m('Revise 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
+            );
+        }
+
+        $id = substr($this->trimmed('id'), 7);
+
+        $this->answer   = QnA_Answer::staticGet('id', $id);
+        $this->question = $this->answer->getQuestion(); 
+
+        if (empty($this->answer) || empty($this->question)) {
+            // TRANS: Client exception thrown trying to respond to a non-existing question.
+            throw new ClientException(
+                _m('Invalid or missing answer.'),
+                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->checkSessionToken();
+            if ($this->arg('revise')) {
+                $this->showContent();
+                return;
+            } else if ($this->arg('best')) {
+                if ($this->user->id == $this->question->profile_id) {
+                    $this->markBest();
+                    return;
+                }
+            } else {
+                $this->reviseAnswer();
+                return;
+            }
+        }
+
+        $this->showPage();
+    }
+
+    /**
+     * Revise the answer
+     *
+     * @return void
+     */
+    function reviseAnswer()
+    {
+        $answer = $this->answer;
+        
+        try {
+            $orig = clone($answer);
+            $answer->content = $this->answerText;
+            $answer->revisions++;
+            $result = $answer->update($orig);
+        } 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('Answer'));
+            $this->elementEnd('head');
+            $this->elementStart('body');
+            $form = new QnashowanswerForm($this, $answer);
+            $form->show();
+            $this->elementEnd('body');
+            $this->elementEnd('html');
+        } else {
+            common_redirect($this->answer->bestUrl(), 303);
+        }
+    }
+
+    /**
+     * Mark the answer as the "best" answer
+     *
+     * @return void
+     */
+    function markBest()
+    {
+        $question = $this->question;
+        $answer   = $this->answer;
+       
+        try {
+            // close the question to further answers
+            $orig = clone($question);
+            $question->closed = 1;
+            $result = $question->update($orig);
+            
+            // mark this answer an the best answer
+            $orig = clone($answer);
+            $answer->best = 1;
+            $result = $answer->update($orig);
+        } 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('Answer'));
+            $this->elementEnd('head');
+            $this->elementStart('body');
+            $form = new QnashowanswerForm($this, $answer);
+            $form->show();
+            $this->elementEnd('body');
+            $this->elementEnd('html');
+        } else {
+            common_redirect($this->answer->bestUrl(), 303);
+        }
+    }
+
+    /**
+     * Show the revise answer form
+     *
+     * @return void
+     */
+    function showContent()
+    {
+        if (!empty($this->error)) {
+            $this->element('p', 'error', $this->error);
+        }
+
+        if ($this->boolean('ajax')) {
+            $this->showAjaxReviseForm();
+        } else {
+            $form = new QnareviseanswerForm($this->answer, $this);
+            $form->show();
+        }
+
+        return;
+    }
+
+    function showAjaxReviseForm()
+    {
+        header('Content-Type: text/xml;charset=utf-8');
+        $this->xw->startDocument('1.0', 'UTF-8');
+        $this->elementStart('html');
+        $this->elementStart('head');
+        $this->element('title', null, _m('Answer'));
+        $this->elementEnd('head');
+        $this->elementStart('body');
+        $form = new QnareviseanswerForm($this->answer, $this);
+        $form->show();
+        $this->elementEnd('body');
+        $this->elementEnd('html');
+    }
+
+    /**
+     * 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;
+        }
+    }
+}
index 5727411a802e991424d1aaaf18f17538a04d7f0d..c8dcd43162fd9d8c6c9ec6117ed03d811fa93500 100644 (file)
@@ -140,7 +140,7 @@ class QnA_Answer extends Managed_DataObject
     {
         $answer = self::staticGet('uri', $notice->uri);
         if (empty($answer)) {
-            throw new Exception("No answer with URI {$this->notice->uri}");
+            throw new Exception("No answer with URI {$notice->uri}");
         }
         return $answer;
     }
@@ -205,16 +205,31 @@ class QnA_Answer extends Managed_DataObject
     {
         $notice = $question->getNotice();
 
-        $fmt   = '<span class="answer_author"><a href="%1$s">answer</a> by <a href="%2$s">%3$s</a></span>';
-        $fmt  .= '<span class="answer_content">%4$s</span>';
+        $out = new XMLStringer();
 
-        return sprintf(
-            $fmt,
-            htmlspecialchars($notice->bestUrl()),
-            htmlspecialchars($profile->profileurl),
-            htmlspecialchars($profile->getBestName()),
-            htmlspecialchars($answer->content)
-        );
+        $cls = array('qna_answer');
+        if (!empty($answer->best)) {
+            $cls[] = 'best';
+        }
+
+        $out->elementStart('p', array('class' => implode(' ', $cls)));
+        $out->elementStart('span', 'answer-content');
+        $out->raw(QnAPlugin::shorten($answer->content, $notice));
+        $out->elementEnd('span');
+
+        if (!empty($answer->revisions)) {
+            $out->elementstart('span', 'answer-revisions');
+            $out->text(
+                htmlspecialchars(
+                    sprintf(_m('%s revisions'), $answer->revisions)
+                )
+            );
+            $out->elementEnd('span');
+        }
+
+        $out->elementEnd('p');
+
+        return $out->getString();
     }
 
     static function toString($profile, $question, $answer)
index 2403857d283e90d1d21cb4591da0a758d4feee2a..70558763692bf1192a4115f80cd2ba907cf3aec8 100644 (file)
@@ -201,66 +201,38 @@ 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 =  '<div class="qna_question">';
-        $fmt .= '<span class="question_title"><a href="%1$s">%2$s</a></span>';
-        $fmt .= '<span class="question_description">%3$s</span>';
-        $fmt .= '<span class="question_author">asked by <a href="%4$s">%5$s</a></span>';
-        $fmt .= '</div>';
-
-        $q = sprintf(
-            $fmt,
-            htmlspecialchars($notice->bestUrl()),
-            htmlspecialchars($question->title),
-            htmlspecialchars($question->description),
-            htmlspecialchars($profile->profileurl),
-            htmlspecialchars($profile->getBestName())
-        );
-
-        $ans = array();
+        $out = new XMLStringer();
 
-        $ans[] = '<div class="qna_answers">';
-
-        while($answer->fetch()) {
-            $ans[] = $answer->asHTML();
+        if (!empty($question->description)) {
+            $out->elementStart('span', 'question-description');
+            $out->raw(QnAPlugin::shorten($question->description, $notice));
+            $out->elementEnd('span');
         }
 
-        $ans[] .= '</div>';
+        if (!empty($question->closed)) {
+            $out->elementStart('span', 'question-closed');
+            $out->text(_m('This question is closed.'));
+            $out->elementEnd('span');
+        }
 
-        return $q . implode($ans);
+        return $out->getString();
     }
 
     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));
     }
 
     /**
@@ -301,15 +273,17 @@ class QnA_Question extends Managed_DataObject
         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
-        );
+        if (Notice::contentTooLong($q->title . ' ' . $q->uri)) {
+            $max       = Notice::maxContent();
+            $uriLen    = mb_strlen($q->uri);
+            $targetLen = $max - ($uriLen + 15);
+            $title = mb_substr($q->title, 0, $targetLen) . '…';
+
+        }
+
+        $content = $title . ' ' . $q->uri;
 
-        $link = '<a href="' . htmlspecialchars($q->uri) . '">' . htmlspecialchars($title) . '</a>';
+        $link = '<a href="' . htmlspecialchars($q->uri) . '">' . htmlspecialchars($q->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);
diff --git a/plugins/QnA/js/qna.js b/plugins/QnA/js/qna.js
new file mode 100644 (file)
index 0000000..82f9a24
--- /dev/null
@@ -0,0 +1,27 @@
+
+var QnA = {
+
+    // hide all the 'close' and 'best' buttons for this question
+
+    // @fixme: Should use ID
+    close: function(closeButt) {
+        $(closeButt)
+            .closest('li.hentry.notice.question')
+            .find('input[name=best],[name=close]')
+            .hide();
+    },
+
+    init: function() {
+        var that = this;
+        $('input[name=close]').live('click', function() {
+            that.close(this);
+        });
+        $('input[name=best]').live('click', function() {
+            that.close(this);
+        });
+    }
+};
+
+$(document).ready(function() {
+    QnA.init();
+});
diff --git a/plugins/QnA/lib/qnaanswerform.php b/plugins/QnA/lib/qnaanswerform.php
deleted file mode 100644 (file)
index 8d78213..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-<?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'));
-    }
-}
-
diff --git a/plugins/QnA/lib/qnanewanswerform.php b/plugins/QnA/lib/qnanewanswerform.php
new file mode 100644 (file)
index 0000000..db4d1df
--- /dev/null
@@ -0,0 +1,124 @@
+<?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 QnanewanswerForm extends Form
+{
+    protected $question;
+
+    /**
+     * Construct a new answer form
+     *
+     * @param QnA_Question $question
+     * @param HTMLOutputter $out output channel
+     *
+     * @return void
+     */
+    function __construct(HTMLOutputter $out, QnA_Question $question)
+    {
+        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->raw($this->question->asHTML());
+
+        $out->element('p', 'answer', 'Your answer');
+        $out->hidden('id', $id);
+        $out->textarea('answer', 'answer');
+    }
+
+    /**
+     * Action elements
+     *
+     * @return void
+     */
+    function formActions()
+    {
+        // TRANS: Button text for submitting a poll response.
+        $this->out->submit('submit', _m('BUTTON', 'Submit'));
+    }
+}
+
diff --git a/plugins/QnA/lib/qnanewquestionform.php b/plugins/QnA/lib/qnanewquestionform.php
new file mode 100644 (file)
index 0000000..114e619
--- /dev/null
@@ -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 QnanewquestionForm 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'));
+    }
+}
diff --git a/plugins/QnA/lib/qnaquestionform.php b/plugins/QnA/lib/qnaquestionform.php
deleted file mode 100644 (file)
index 9d0c2aa..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-<?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'));
-    }
-}
index 48f47e5e9837f4ad10cca58c6bd7ea7d5d3dbb4d..280dd74cd992e72af6587f0cf24ec349bf4b793c 100644 (file)
@@ -91,7 +91,7 @@ class QnareviseanswerForm extends Form
      */
     function action()
     {
-        return common_local_url('qnareviseanswer', array('id' => $this->question->id));
+        return common_local_url('qnareviseanswer');
     }
 
     /**
@@ -101,12 +101,11 @@ class QnareviseanswerForm extends Form
      */
     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);
+        $out = $this->out;
+        $out->element('p', 'revise-answer', 'Your answer');
+        $id = "answer-" . $this->answer->id;
+        $out->hidden('id', $id);
+        $out->textarea('answer', 'answer', $this->answer->content);
     }
 
     /**
diff --git a/plugins/QnA/lib/qnashowanswerform.php b/plugins/QnA/lib/qnashowanswerform.php
new file mode 100644 (file)
index 0000000..5ec63e1
--- /dev/null
@@ -0,0 +1,181 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for showing / revising an answer
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Form
+ * @package   StatusNet
+ * @author    Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+require_once INSTALLDIR . '/lib/form.php';
+
+/**
+ * Form for showing / revising an answer
+ *
+ * @category Form
+ * @package  StatusNet
+ * @author   Zach Copley <zach@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ *
+ */
+class QnashowanswerForm extends Form
+{
+    /**
+     * The answer to revise
+     */
+    var $answer = null;
+
+    /**
+     * The question this is an answer to
+     */
+    var $question = null;
+
+    /**
+     * Constructor
+     *
+     * @param HTMLOutputter $out    output channel
+     * @param QnA_Answer    $answer answer to revise
+     */
+    function __construct($out = null, $answer = null)
+    {
+        parent::__construct($out);
+
+        $this->answer       = $answer;
+        $this->question     = $answer->getQuestion();
+    }
+
+    /**
+     * ID of the form
+     *
+     * @return int ID of the form
+     */
+    function id()
+    {
+        return 'revise-' . $this->answer->id;
+    }
+
+    /**
+     * Action of the form
+     *
+     * @return string URL of the action
+     */
+    function action()
+    {
+        return common_local_url('qnareviseanswer');
+    }
+
+    /**
+     * 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, _('Revise your answer'));
+    }
+
+    /**
+     * Data elements
+     *
+     * @return void
+     */
+    function formData()
+    {
+        $this->out->hidden(
+            'id',
+            'revise-' . $this->answer->id
+        );
+        
+        $this->out->raw($this->answer->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) {
+                if (empty($this->answer->best)) {
+                    $this->out->submit(
+                        'best',
+                        // TRANS: Button text for marking an answer as "best"
+                        _m('BUTTON', 'Best'),
+                        'submit',
+                        null,
+                        // TRANS: Title for button text marking an answer as "best"
+                        _('Mark as best answer')
+                    );
+        
+                }
+            }
+            if ($user->id == $this->answer->profile_id) {
+                $this->out->submit(
+                    'revise',
+                    // TRANS: Button text for revising an answer
+                    _m('BUTTON', 'Revise'),
+                    'submit',
+                    null,
+                    // TRANS: Title for button text for revising an answer
+                    _('Revise your answer')
+                );
+            }
+        }
+    }
+
+    /**
+     * Class of the form.
+     *
+     * @return string the form's class
+     */
+    function formClass()
+    {
+        return 'form_revise ajax';
+    }
+}
diff --git a/plugins/QnA/lib/qnashowquestionform.php b/plugins/QnA/lib/qnashowquestionform.php
new file mode 100644 (file)
index 0000000..71e644e
--- /dev/null
@@ -0,0 +1,160 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for showing / revising an answer
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Form
+ * @package   StatusNet
+ * @author    Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+require_once INSTALLDIR . '/lib/form.php';
+
+/**
+ * Form for showing a question
+ *
+ * @category Form
+ * @package  StatusNet
+ * @author   Zach Copley <zach@status.net>
+ * @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';
+    }
+}
index a1ece7f9fea97ef3dd10c372db66ed0b2742fa8d..36dd8acc27e62a30c6b12b3a53d0bd436f8e6184 100644 (file)
@@ -1246,4 +1246,60 @@ table.profile_list tr.alt {
     filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FB6104', endColorstr='#fc8035',GradientType=0 );
 }
 
+/* QnA specific styles */
+
+#content .question .entry-title {
+    min-height: 1px;
+}
+
+.question div.question-description {
+    font-size: 1em;
+    line-height: 1.36em;
+    opacity: 1;
+}
+
+.question fieldset {
+    margin: 0px;
+}
+
+.question fieldset legend {
+    display: none;
+}
+
+.question p.answer {
+    margin-top: 4px;
+    margin-bottom: 4px;
+    font-style: italic;
+}
+
+.question label[for=answer] {
+    display: none;
+}
+
+.question textarea {
+    width: 100%;
+    height: 42px;
+    padding: 6px 10px 18px 10px;
+    border: 1px solid #a6a6a6;
+    -webkit-border-radius: 4px;
+    -moz-border-radius: 4px;
+    border-radius: 4px;
+    box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.2);
+    -moz-box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.2);
+    -webkit-box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.2);
+    font-size: 1.2em;
+    margin-bottom: 10px;
+}
+
+.question #answer-form input.submit {
+    height: auto;
+    padding: 0px 10px;
+    margin-left: 0px;
+    margin-bottom: 10px;
+    color:#fff;
+    font-weight: bold;
+    text-transform: uppercase;
+    font-size: 1.1em;
+}
+
 }/*end of @media screen, projection, tv*/