DirectMessagePlugin.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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(
  51. 'message/new',
  52. ['action' => 'newmessage']
  53. );
  54. $m->connect(
  55. 'message/new?to=:to',
  56. ['action' => 'newmessage'],
  57. ['to' => '[0-9]+']
  58. );
  59. $m->connect(
  60. 'message/:message',
  61. ['action' => 'showmessage'],
  62. ['message' => '[0-9]+']
  63. );
  64. // direct messages
  65. $m->connect(
  66. 'api/direct_messages.:format',
  67. ['action' => 'ApiDirectMessage'],
  68. ['format' => '(xml|json|rss|atom)']
  69. );
  70. $m->connect(
  71. 'api/direct_messages/sent.:format',
  72. [
  73. 'action' => 'ApiDirectMessage',
  74. 'sent' => true,
  75. ],
  76. ['format' => '(xml|json|rss|atom)']
  77. );
  78. $m->connect(
  79. 'api/direct_messages/new.:format',
  80. ['action' => 'ApiDirectMessageNew'],
  81. ['format' => '(xml|json)']
  82. );
  83. return true;
  84. }
  85. /**
  86. * Are we allowed to perform a certain command over the API?
  87. *
  88. * @param Command $cmd
  89. * @param bool &$supported
  90. * @return bool hook value
  91. */
  92. public function onCommandSupportedAPI(Command $cmd, ?bool &$supported) : bool
  93. {
  94. $supported = $supported || $cmd instanceof MessageCommand;
  95. return true;
  96. }
  97. /**
  98. * EndInterpretCommand will handle the 'd' and 'dm' commands.
  99. *
  100. * @param string $cmd Command being run
  101. * @param string $arg Rest of the message (including address)
  102. * @param User $user User sending the message
  103. * @param MessageCommand|bool &$result The resulting command object to be run.
  104. * @return bool hook value
  105. */
  106. public function onStartInterpretCommand(string $cmd, ?string $arg, User $user, &$result) : bool
  107. {
  108. $dm_cmds = ['d', 'dm'];
  109. if ($result === false && in_array($cmd, $dm_cmds)) {
  110. if (!empty($arg)) {
  111. list($other, $extra) = CommandInterpreter::split_arg($arg);
  112. if (!empty($extra)) {
  113. $result = new MessageCommand($user, $other, $extra);
  114. }
  115. }
  116. return false;
  117. }
  118. return true;
  119. }
  120. /**
  121. * Show Message button in someone's left-side navigation menu
  122. *
  123. * @param Menu $menu
  124. * @param Profile $target
  125. * @param Profile $scoped
  126. * @return void
  127. * @throws ServerException
  128. */
  129. public function onEndPersonalGroupNav(Menu $menu, Profile $target, Profile $scoped = null)
  130. {
  131. if ($scoped instanceof Profile && $scoped->id == $target->id
  132. && !common_config('singleuser', 'enabled')) {
  133. $menu->out->menuItem(
  134. common_local_url('inbox', ['nickname' => $target->getNickname()]),
  135. // TRANS: Menu item in personal group navigation menu.
  136. _m('MENU', 'Messages'),
  137. // TRANS: Menu item title in personal group navigation menu.
  138. _('Your incoming messages'),
  139. $scoped->id === $target->id && $menu->actionName =='inbox'
  140. );
  141. }
  142. }
  143. /**
  144. * Show Message button in someone's profile page
  145. *
  146. * @param HTMLOutputter $out
  147. * @param Profile $profile
  148. * @return bool hook flag
  149. */
  150. public function onEndProfilePageActionsElements(HTMLOutputter $out, Profile $profile) : bool
  151. {
  152. $scoped = Profile::current();
  153. if (!$scoped instanceof Profile || $scoped->getID() === $profile->getID()) {
  154. return true;
  155. }
  156. if (!$profile->isLocal() && Event::handle('DirectMessageProfilePageActions', [$profile])) {
  157. // nothing to do if remote profile and no one to validate it
  158. return true;
  159. }
  160. if (!$profile->hasBlocked($scoped)) {
  161. $out->elementStart('li', 'entity_send-a-message');
  162. $out->element(
  163. 'a',
  164. ['href' => common_local_url('newmessage', ['to' => $profile->getID()]),
  165. // TRANS: Link title for link on user profile.
  166. 'title' => _('Send a direct message to this user.')],
  167. // TRANS: Link text for link on user profile.
  168. _m('BUTTON', 'Message')
  169. );
  170. $out->elementEnd('li');
  171. }
  172. return true;
  173. }
  174. /**
  175. * Notice table is used to store private messages in a newer version of the plugin,
  176. * this ensures we migrate entries from the old message table.
  177. *
  178. * @return bool hook flag
  179. */
  180. public function onEndUpgrade() : bool
  181. {
  182. try {
  183. $schema = Schema::get();
  184. $schema->getTableDef('message');
  185. } catch (SchemaTableMissingException $e) {
  186. return true;
  187. }
  188. $message = new Message();
  189. $message->selectAdd(); // clears it
  190. $message->selectAdd('id');
  191. $message->orderBy('created, id');
  192. if ($message->find()) {
  193. while ($message->fetch()) {
  194. $msg = Message::getKV('id', $message->id);
  195. $act = $msg->asActivity();
  196. Notice::saveActivity(
  197. $act,
  198. $msg->getFrom(),
  199. [
  200. 'source' => 'web',
  201. 'scope' => NOTICE::MESSAGE_SCOPE,
  202. ]
  203. );
  204. }
  205. }
  206. $message->free();
  207. $message = null;
  208. $schema->dropTable('message');
  209. return true;
  210. }
  211. public function onPluginVersion(array &$versions): bool
  212. {
  213. $versions[] = [
  214. 'name' => 'Direct Message',
  215. 'version' => self::PLUGIN_VERSION,
  216. 'author' => 'Mikael Nordfeldth, Bruno Casteleiro',
  217. 'homepage' => 'https://gnu.social/',
  218. 'rawdescription' =>
  219. // TRANS: Plugin description.
  220. _m('Direct Message to other local users.')
  221. ];
  222. return true;
  223. }
  224. }