Poll.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. <?php
  2. // This file is part of GNU social - https://www.gnu.org/software/social
  3. //
  4. // GNU social is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Affero General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // GNU social is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Affero General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Affero General Public License
  15. // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * Data class to mark notices as bookmarks
  18. *
  19. * @category PollPlugin
  20. * @package GNUsocial
  21. * @author Brion Vibber <brion@status.net>
  22. * @copyright 2011 StatusNet, Inc.
  23. * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
  24. */
  25. defined('GNUSOCIAL') || die();
  26. /**
  27. * For storing the poll options and such
  28. *
  29. * @copyright 2011 StatusNet, Inc.
  30. * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
  31. *
  32. * @see DB_DataObject
  33. */
  34. class Poll extends Managed_DataObject
  35. {
  36. public $__table = 'poll'; // table name
  37. public $id; // char(36) primary key not null -> UUID
  38. public $uri; // varchar(191) not 255 because utf8mb4 takes more space
  39. public $profile_id; // int -> profile.id
  40. public $question; // text
  41. public $options; // text; newline(?)-delimited
  42. public $created; // datetime
  43. /**
  44. * The One True Thingy that must be defined and declared.
  45. */
  46. public static function schemaDef()
  47. {
  48. return array(
  49. 'description' => 'Per-notice poll data for Poll plugin',
  50. 'fields' => array(
  51. 'id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID'),
  52. 'uri' => array('type' => 'varchar', 'length' => 191, 'not null' => true),
  53. 'profile_id' => array('type' => 'int'),
  54. 'question' => array('type' => 'text'),
  55. 'options' => array('type' => 'text'),
  56. 'created' => array('type' => 'datetime', 'not null' => true),
  57. ),
  58. 'primary key' => array('id'),
  59. 'unique keys' => array(
  60. 'poll_uri_key' => array('uri'),
  61. ),
  62. );
  63. }
  64. /**
  65. * Get a bookmark based on a notice
  66. *
  67. * @param Notice $notice Notice to check for
  68. *
  69. * @return get_called_class found poll or null
  70. */
  71. public static function getByNotice($notice)
  72. {
  73. return self::getKV('uri', $notice->uri);
  74. }
  75. public function getOptions()
  76. {
  77. return explode("\n", $this->options);
  78. }
  79. /**
  80. * Is this a valid selection index?
  81. *
  82. * @param int $selection (1-based)
  83. * @return boolean
  84. */
  85. public function isValidSelection($selection)
  86. {
  87. if ($selection != intval($selection)) {
  88. return false;
  89. }
  90. if ($selection < 1 || $selection > count($this->getOptions())) {
  91. return false;
  92. }
  93. return true;
  94. }
  95. public function getNotice()
  96. {
  97. return Notice::getKV('uri', $this->uri);
  98. }
  99. public function getUrl()
  100. {
  101. return $this->getNotice()->getUrl();
  102. }
  103. /**
  104. * Get the response of a particular user to this poll, if any.
  105. *
  106. * @param Profile $profile
  107. * @return get_called_class object or null
  108. */
  109. public function getResponse(Profile $profile)
  110. {
  111. $pr = Poll_response::pkeyGet(array('poll_id' => $this->id,
  112. 'profile_id' => $profile->id));
  113. return $pr;
  114. }
  115. public function countResponses()
  116. {
  117. $pr = new Poll_response();
  118. $pr->poll_id = $this->id;
  119. $pr->groupBy('selection');
  120. $pr->selectAdd();
  121. $pr->selectAdd('selection');
  122. $pr->selectAdd('COUNT(profile_id) AS votes');
  123. $pr->find();
  124. $raw = array();
  125. while ($pr->fetch()) {
  126. // Votes list 1-based
  127. // Array stores 0-based
  128. $raw[$pr->selection - 1] = $pr->votes;
  129. }
  130. $counts = array();
  131. foreach (array_keys($this->getOptions()) as $key) {
  132. if (isset($raw[$key])) {
  133. $counts[$key] = $raw[$key];
  134. } else {
  135. $counts[$key] = 0;
  136. }
  137. }
  138. return $counts;
  139. }
  140. /**
  141. * Save a new poll notice
  142. *
  143. * @param Profile $profile
  144. * @param string $question
  145. * @param array $opts (poll responses)
  146. *
  147. * @param null $options
  148. * @return Notice saved notice
  149. * @throws ClientException
  150. */
  151. public static function saveNew($profile, $question, $opts, $options = null)
  152. {
  153. if (empty($options)) {
  154. $options = array();
  155. }
  156. $p = new Poll();
  157. $p->id = UUID::gen();
  158. $p->profile_id = $profile->id;
  159. $p->question = $question;
  160. $p->options = implode("\n", $opts);
  161. if (array_key_exists('created', $options)) {
  162. $p->created = $options['created'];
  163. } else {
  164. $p->created = common_sql_now();
  165. }
  166. if (array_key_exists('uri', $options)) {
  167. $p->uri = $options['uri'];
  168. } else {
  169. $p->uri = common_local_url(
  170. 'showpoll',
  171. array('id' => $p->id)
  172. );
  173. }
  174. common_log(LOG_DEBUG, "Saving poll: $p->id $p->uri");
  175. $p->insert();
  176. // TRANS: Notice content creating a poll.
  177. // TRANS: %1$s is the poll question, %2$s is a link to the poll.
  178. $content = sprintf(
  179. _m('Poll: %1$s %2$s'),
  180. $question,
  181. $p->uri
  182. );
  183. $link = '<a href="' . htmlspecialchars($p->uri) . '">' . htmlspecialchars($question) . '</a>';
  184. // TRANS: Rendered version of the notice content creating a poll.
  185. // TRANS: %s is a link to the poll with the question as link description.
  186. $rendered = sprintf(_m('Poll: %s'), $link);
  187. $tags = array('poll');
  188. $replies = array();
  189. $options = array_merge(
  190. array('urls' => array(),
  191. 'rendered' => $rendered,
  192. 'tags' => $tags,
  193. 'replies' => $replies,
  194. 'object_type' => PollPlugin::POLL_OBJECT),
  195. $options
  196. );
  197. if (!array_key_exists('uri', $options)) {
  198. $options['uri'] = $p->uri;
  199. }
  200. $saved = Notice::saveNew(
  201. $profile->id,
  202. $content,
  203. array_key_exists('source', $options) ?
  204. $options['source'] : 'web',
  205. $options
  206. );
  207. return $saved;
  208. }
  209. }