ActivityPlugin.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. <?php
  2. /**
  3. * StatusNet - the distributed open-source microblogging tool
  4. * Copyright (C) 2010, StatusNet, Inc.
  5. *
  6. * Shows social activities in the output feed
  7. *
  8. * PHP version 5
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Affero General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Affero General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. *
  23. * @category Activity
  24. * @package StatusNet
  25. * @author Evan Prodromou <evan@status.net>
  26. * @copyright 2010 StatusNet, Inc.
  27. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
  28. * @link http://status.net/
  29. */
  30. if (!defined('STATUSNET')) {
  31. // This check helps protect against security problems;
  32. // your code file can't be executed directly from the web.
  33. exit(1);
  34. }
  35. /**
  36. * Activity plugin main class
  37. *
  38. * @category Activity
  39. * @package StatusNet
  40. * @author Evan Prodromou <evan@status.net>
  41. * @copyright 2010 StatusNet, Inc.
  42. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
  43. * @link http://status.net/
  44. */
  45. class ActivityPlugin extends Plugin
  46. {
  47. const VERSION = '0.1';
  48. const SOURCE = 'activity';
  49. // Flags to switch off certain activity notices
  50. public $StartFollowUser = true;
  51. public $StopFollowUser = false;
  52. public $JoinGroup = true;
  53. public $LeaveGroup = false;
  54. public $StartLike = false;
  55. public $StopLike = false;
  56. function onEndSubscribe(Profile $profile, Profile $other)
  57. {
  58. // Only do this if config is enabled
  59. if(!$this->StartFollowUser) return true;
  60. if (!$profile->isLocal()) {
  61. // can't do anything with remote user anyway
  62. return true;
  63. }
  64. $sub = Subscription::pkeyGet(array('subscriber' => $profile->id,
  65. 'subscribed' => $other->id));
  66. // TRANS: Text for "started following" item in activity plugin.
  67. // TRANS: %1$s is a profile URL, %2$s is a profile name,
  68. // TRANS: %3$s is a profile URL, %4$s is a profile name.
  69. $rendered = html_sprintf(_m('<a href="%1$s">%2$s</a> started following <a href="%3$s">%4$s</a>.'),
  70. $profile->getUrl(),
  71. $profile->getBestName(),
  72. $other->getUrl(),
  73. $other->getBestName());
  74. // TRANS: Text for "started following" item in activity plugin.
  75. // TRANS: %1$s is a profile name, %2$s is a profile URL,
  76. // TRANS: %3$s is a profile name, %4$s is a profile URL.
  77. $content = sprintf(_m('%1$s (%2$s) started following %3$s (%4$s).'),
  78. $profile->getBestName(),
  79. $profile->getUrl(),
  80. $other->getBestName(),
  81. $other->getUrl());
  82. $notice = Notice::saveNew($profile->id,
  83. $content,
  84. ActivityPlugin::SOURCE,
  85. array('rendered' => $rendered,
  86. 'urls' => array(),
  87. 'replies' => array($other->getUri()),
  88. 'verb' => ActivityVerb::FOLLOW,
  89. 'object_type' => ActivityObject::PERSON,
  90. 'uri' => $sub->uri));
  91. return true;
  92. }
  93. function onEndUnsubscribe(Profile $profile, Profile $other)
  94. {
  95. // Only do this if config is enabled
  96. if(!$this->StopFollowUser) return true;
  97. if (!$profile->isLocal()) {
  98. return true;
  99. }
  100. // TRANS: Text for "stopped following" item in activity plugin.
  101. // TRANS: %1$s is a profile URL, %2$s is a profile name,
  102. // TRANS: %3$s is a profile URL, %4$s is a profile name.
  103. $rendered = html_sprintf(_m('<a href="%1$s">%2$s</a> stopped following <a href="%3$s">%4$s</a>.'),
  104. $profile->getUrl(),
  105. $profile->getBestName(),
  106. $other->getUrl(),
  107. $other->getBestName());
  108. // TRANS: Text for "stopped following" item in activity plugin.
  109. // TRANS: %1$s is a profile name, %2$s is a profile URL,
  110. // TRANS: %3$s is a profile name, %4$s is a profile URL.
  111. $content = sprintf(_m('%1$s (%2$s) stopped following %3$s (%4$s).'),
  112. $profile->getBestName(),
  113. $profile->getUrl(),
  114. $other->getBestName(),
  115. $other->getUrl());
  116. $uri = TagURI::mint('stop-following:%d:%d:%s',
  117. $profile->id,
  118. $other->id,
  119. common_date_iso8601(common_sql_now()));
  120. $notice = Notice::saveNew($profile->id,
  121. $content,
  122. ActivityPlugin::SOURCE,
  123. array('rendered' => $rendered,
  124. 'urls' => array(),
  125. 'replies' => array($other->getUri()),
  126. 'uri' => $uri,
  127. 'verb' => ActivityVerb::UNFOLLOW,
  128. 'object_type' => ActivityObject::PERSON));
  129. return true;
  130. }
  131. function onEndDisfavorNotice($profile, $notice)
  132. {
  133. // Only do this if config is enabled
  134. if(!$this->StopLike) return true;
  135. if (!$profile->isLocal()) {
  136. return true;
  137. }
  138. $author = Profile::getKV('id', $notice->profile_id);
  139. // TRANS: Text for "stopped liking" item in activity plugin.
  140. // TRANS: %1$s is a profile URL, %2$s is a profile name,
  141. // TRANS: %3$s is a notice URL, %4$s is an author name.
  142. $rendered = html_sprintf(_m('<a href="%1$s">%2$s</a> stopped liking <a href="%3$s">%4$s\'s update</a>.'),
  143. $profile->getUrl(),
  144. $profile->getBestName(),
  145. $notice->getUrl(),
  146. $author->getBestName());
  147. // TRANS: Text for "stopped liking" item in activity plugin.
  148. // TRANS: %1$s is a profile name, %2$s is a profile URL,
  149. // TRANS: %3$s is an author name, %4$s is a notice URL.
  150. $content = sprintf(_m('%1$s (%2$s) stopped liking %3$s\'s status (%4$s).'),
  151. $profile->getBestName(),
  152. $profile->getUrl(),
  153. $author->getBestName(),
  154. $notice->getUrl());
  155. $uri = TagURI::mint('unlike:%d:%d:%s',
  156. $profile->id,
  157. $notice->id,
  158. common_date_iso8601(common_sql_now()));
  159. $notice = Notice::saveNew($profile->id,
  160. $content,
  161. ActivityPlugin::SOURCE,
  162. array('rendered' => $rendered,
  163. 'urls' => array(),
  164. 'replies' => array($author->getUri()),
  165. 'uri' => $uri,
  166. 'verb' => ActivityVerb::UNFAVORITE,
  167. 'object_type' => (($notice->verb == ActivityVerb::POST) ?
  168. $notice->object_type : null)));
  169. return true;
  170. }
  171. function onEndJoinGroup($group, $profile)
  172. {
  173. // Only do this if config is enabled
  174. if(!$this->JoinGroup) return true;
  175. if (!$profile->isLocal()) {
  176. return true;
  177. }
  178. // TRANS: Text for "joined group" item in activity plugin.
  179. // TRANS: %1$s is a profile URL, %2$s is a profile name,
  180. // TRANS: %3$s is a group URL, %4$s is a group name.
  181. $rendered = html_sprintf(_m('<a href="%1$s">%2$s</a> joined the group <a href="%3$s">%4$s</a>.'),
  182. $profile->getUrl(),
  183. $profile->getBestName(),
  184. $group->homeUrl(),
  185. $group->getBestName());
  186. // TRANS: Text for "joined group" item in activity plugin.
  187. // TRANS: %1$s is a profile name, %2$s is a profile URL,
  188. // TRANS: %3$s is a group name, %4$s is a group URL.
  189. $content = sprintf(_m('%1$s (%2$s) joined the group %3$s (%4$s).'),
  190. $profile->getBestName(),
  191. $profile->getUrl(),
  192. $group->getBestName(),
  193. $group->homeUrl());
  194. $mem = Group_member::pkeyGet(array('group_id' => $group->id,
  195. 'profile_id' => $profile->id));
  196. $notice = Notice::saveNew($profile->id,
  197. $content,
  198. ActivityPlugin::SOURCE,
  199. array('rendered' => $rendered,
  200. 'urls' => array(),
  201. 'groups' => array($group->id),
  202. 'uri' => $mem->getURI(),
  203. 'verb' => ActivityVerb::JOIN,
  204. 'object_type' => ActivityObject::GROUP));
  205. return true;
  206. }
  207. function onEndLeaveGroup($group, $profile)
  208. {
  209. // Only do this if config is enabled
  210. if(!$this->LeaveGroup) return true;
  211. if (!$profile->isLocal()) {
  212. return true;
  213. }
  214. // TRANS: Text for "left group" item in activity plugin.
  215. // TRANS: %1$s is a profile URL, %2$s is a profile name,
  216. // TRANS: %3$s is a group URL, %4$s is a group name.
  217. $rendered = html_sprintf(_m('<a href="%1$s">%2$s</a> left the group <a href="%3$s">%4$s</a>.'),
  218. $profile->getUrl(),
  219. $profile->getBestName(),
  220. $group->homeUrl(),
  221. $group->getBestName());
  222. // TRANS: Text for "left group" item in activity plugin.
  223. // TRANS: %1$s is a profile name, %2$s is a profile URL,
  224. // TRANS: %3$s is a group name, %4$s is a group URL.
  225. $content = sprintf(_m('%1$s (%2$s) left the group %3$s (%4$s).'),
  226. $profile->getBestName(),
  227. $profile->getUrl(),
  228. $group->getBestName(),
  229. $group->homeUrl());
  230. $uri = TagURI::mint('leave:%d:%d:%s',
  231. $profile->id,
  232. $group->id,
  233. common_date_iso8601(common_sql_now()));
  234. $notice = Notice::saveNew($profile->id,
  235. $content,
  236. ActivityPlugin::SOURCE,
  237. array('rendered' => $rendered,
  238. 'urls' => array(),
  239. 'groups' => array($group->id),
  240. 'uri' => $uri,
  241. 'verb' => ActivityVerb::LEAVE,
  242. 'object_type' => ActivityObject::GROUP));
  243. return true;
  244. }
  245. function onStartShowNoticeItem($nli)
  246. {
  247. $notice = $nli->notice;
  248. $adapter = null;
  249. switch ($notice->verb) {
  250. case ActivityVerb::JOIN:
  251. $adapter = new JoinListItem($nli);
  252. break;
  253. case ActivityVerb::LEAVE:
  254. $adapter = new LeaveListItem($nli);
  255. break;
  256. case ActivityVerb::FOLLOW:
  257. $adapter = new FollowListItem($nli);
  258. break;
  259. case ActivityVerb::UNFOLLOW:
  260. $adapter = new UnfollowListItem($nli);
  261. break;
  262. }
  263. if (!empty($adapter)) {
  264. $adapter->showNotice();
  265. $adapter->showNoticeAttachments();
  266. $adapter->showNoticeInfo();
  267. $adapter->showNoticeOptions();
  268. return false;
  269. }
  270. return true;
  271. }
  272. public function onEndNoticeAsActivity(Notice $stored, Activity $act, Profile $scoped=null)
  273. {
  274. switch ($stored->verb) {
  275. case ActivityVerb::UNFAVORITE:
  276. // FIXME: do something here
  277. break;
  278. case ActivityVerb::JOIN:
  279. $mem = Group_member::getKV('uri', $stored->getUri());
  280. if ($mem instanceof Group_member) {
  281. $group = $mem->getGroup();
  282. $act->title = $stored->getTitle();
  283. $act->objects = array(ActivityObject::fromGroup($group));
  284. }
  285. break;
  286. case ActivityVerb::LEAVE:
  287. // FIXME: ????
  288. break;
  289. case ActivityVerb::FOLLOW:
  290. $sub = Subscription::getKV('uri', $stored->uri);
  291. if ($sub instanceof Subscription) {
  292. $profile = Profile::getKV('id', $sub->subscribed);
  293. if ($profile instanceof Profile) {
  294. $act->title = $stored->getTitle();
  295. $act->objects = array($profile->asActivityObject());
  296. }
  297. }
  298. break;
  299. case ActivityVerb::UNFOLLOW:
  300. // FIXME: ????
  301. break;
  302. }
  303. return true;
  304. }
  305. function onPluginVersion(array &$versions)
  306. {
  307. $versions[] = array('name' => 'Activity',
  308. 'version' => self::VERSION,
  309. 'author' => 'Evan Prodromou',
  310. 'homepage' => 'http://status.net/wiki/Plugin:Activity',
  311. 'rawdescription' =>
  312. // TRANS: Plugin description.
  313. _m('Emits notices when social activities happen.'));
  314. return true;
  315. }
  316. }