DirectMessagePlugin.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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. * GNUsocial implementation of Direct Messages
  18. *
  19. * @package GNUsocial
  20. * @author Mikael Nordfeldth <mmn@hethane.se>
  21. * @author Bruno Casteleiro <brunoccast@fc.up.pt>
  22. * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
  23. * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
  24. */
  25. defined('GNUSOCIAL') || die();
  26. // require needed abstractions first
  27. require_once __DIR__ . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'messagelist.php';
  28. require_once __DIR__ . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'messagelistitem.php';
  29. // Import plugin libs
  30. foreach (glob(__DIR__ . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . '*.php') as $filename) {
  31. require_once $filename;
  32. }
  33. // Import plugin models
  34. foreach (glob(__DIR__ . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'models' . DIRECTORY_SEPARATOR . '*.php') as $filename) {
  35. require_once $filename;
  36. }
  37. /**
  38. * @category Plugin
  39. * @package GNUsocial
  40. * @author Mikael Nordfeldth <mmn@hethane.se>
  41. * @author Bruno Casteleiro <brunoccast@fc.up.pt>
  42. * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
  43. */
  44. class DirectMessagePlugin extends Plugin
  45. {
  46. const PLUGIN_VERSION = '3.0.0';
  47. public function onRouterInitialized(URLMapper $m)
  48. {
  49. // web front-end actions
  50. $m->connect('message/new',
  51. ['action' => 'newmessage']);
  52. $m->connect('message/new?to=:to',
  53. ['action' => 'newmessage'],
  54. ['to' => '[0-9]+']);
  55. $m->connect('message/:message',
  56. ['action' => 'showmessage'],
  57. ['message' => '[0-9]+']);
  58. // direct messages
  59. $m->connect('api/direct_messages.:format',
  60. ['action' => 'ApiDirectMessage'],
  61. ['format' => '(xml|json|rss|atom)']);
  62. $m->connect('api/direct_messages/sent.:format',
  63. ['action' => 'ApiDirectMessage',
  64. 'sent' => true],
  65. ['format' => '(xml|json|rss|atom)']);
  66. $m->connect('api/direct_messages/new.:format',
  67. ['action' => 'ApiDirectMessageNew'],
  68. ['format' => '(xml|json)']);
  69. return true;
  70. }
  71. /**
  72. * Are we allowed to perform a certain command over the API?
  73. *
  74. * @param Command $cmd
  75. * @param bool &$supported
  76. * @return bool hook value
  77. */
  78. public function onCommandSupportedAPI(Command $cmd, ?bool &$supported) : bool
  79. {
  80. $supported = $supported || $cmd instanceof MessageCommand;
  81. return true;
  82. }
  83. /**
  84. * EndInterpretCommand will handle the 'd' and 'dm' commands.
  85. *
  86. * @param string $cmd Command being run
  87. * @param string $arg Rest of the message (including address)
  88. * @param User $user User sending the message
  89. * @param Command|bool &$result The resulting command object to be run.
  90. * @return bool hook value
  91. */
  92. public function onStartInterpretCommand(string $cmd, ?string $arg, User $user, &$result) : bool
  93. {
  94. $dm_cmds = ['d', 'dm'];
  95. if ($result === false && in_array($cmd, $dm_cmds)) {
  96. if (!empty($arg)) {
  97. list($other, $extra) = CommandInterpreter::split_arg($arg);
  98. if (!empty($extra)) {
  99. $result = new MessageCommand($user, $other, $extra);
  100. }
  101. }
  102. return false;
  103. }
  104. return true;
  105. }
  106. /**
  107. * Show Message button in someone's left-side navigation menu
  108. *
  109. * @param Menu $menu
  110. * @param Profile $target
  111. * @param Profile $scoped
  112. * @return void
  113. */
  114. public function onEndPersonalGroupNav(Menu $menu, Profile $target, Profile $scoped = null)
  115. {
  116. if ($scoped instanceof Profile && $scoped->id == $target->id
  117. && !common_config('singleuser', 'enabled')) {
  118. $menu->out->menuItem(common_local_url('inbox', ['nickname' => $target->getNickname()]),
  119. // TRANS: Menu item in personal group navigation menu.
  120. _m('MENU','Messages'),
  121. // TRANS: Menu item title in personal group navigation menu.
  122. _('Your incoming messages'),
  123. $scoped->id === $target->id && $menu->actionName =='inbox');
  124. }
  125. }
  126. /**
  127. * Show Message button in someone's profile page
  128. *
  129. * @param HTMLOutputter $out
  130. * @param Profile $profile
  131. * @return bool hook flag
  132. */
  133. public function onEndProfilePageActionsElements(HTMLOutputter $out, Profile $profile) : bool
  134. {
  135. $scoped = Profile::current();
  136. if (!$scoped instanceof Profile || $scoped->getID() === $profile->getID()) {
  137. return true;
  138. }
  139. if (!$profile->isLocal() && Event::handle('DirectMessageProfilePageActions', [$profile])) {
  140. // nothing to do if remote profile and no one to validate it
  141. return true;
  142. }
  143. if (!$profile->hasBlocked($scoped)) {
  144. $out->elementStart('li', 'entity_send-a-message');
  145. $out->element('a',
  146. ['href' => common_local_url('newmessage', ['to' => $profile->getID()]),
  147. // TRANS: Link title for link on user profile.
  148. 'title' => _('Send a direct message to this user.')],
  149. // TRANS: Link text for link on user profile.
  150. _m('BUTTON','Message'));
  151. $out->elementEnd('li');
  152. }
  153. return true;
  154. }
  155. /**
  156. * Notice table is used to store private messages in a newer version of the plugin,
  157. * this ensures we migrate entries from the old message table.
  158. *
  159. * @return bool hook flag
  160. */
  161. public function onEndUpgrade() : bool
  162. {
  163. try {
  164. $schema = Schema::get();
  165. $schema->getTableDef('message');
  166. } catch (SchemaTableMissingException $e) {
  167. return true;
  168. }
  169. $message = new Message();
  170. $message->selectAdd(); // clears it
  171. $message->selectAdd('id');
  172. $message->orderBy('created ASC');
  173. if ($message->find()) {
  174. while ($message->fetch()) {
  175. $msg = Message::getKV('id', $message->id);
  176. $act = $msg->asActivity();
  177. Notice::saveActivity($act,
  178. $msg->getFrom(),
  179. ['source' => 'web',
  180. 'scope' => NOTICE::MESSAGE_SCOPE]);
  181. }
  182. }
  183. $message->free();
  184. $message = null;
  185. $schema->dropTable('message');
  186. return true;
  187. }
  188. public function onPluginVersion(array &$versions): bool
  189. {
  190. $versions[] = [
  191. 'name' => 'Direct Message',
  192. 'version' => self::PLUGIN_VERSION,
  193. 'author' => 'Mikael Nordfeldth, Bruno Casteleiro',
  194. 'homepage' => 'https://gnu.social/',
  195. 'rawdescription' =>
  196. // TRANS: Plugin description.
  197. _m('Direct Message to other local users.')
  198. ];
  199. return true;
  200. }
  201. }