| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  | <?php | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  | // This file is part of GNU social - https://www.gnu.org/software/social
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // GNU social 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.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // GNU social 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 GNU social.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  | defined('GNUSOCIAL') || die(); | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * SearchSub plugin main class | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |  * @category  Plugin | 
					
						
							|  |  |  |  * @package   SearchSubPlugin | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |  * @author    Brion Vibber <brionv@status.net> | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |  * @copyright 2011-2019 Free Software Foundation, Inc http://www.fsf.org | 
					
						
							|  |  |  |  * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |  */ | 
					
						
							|  |  |  | class SearchSubPlugin extends Plugin | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-06-03 01:56:52 +01:00
										 |  |  |     const PLUGIN_VERSION = '0.1.0'; | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Database schema setup | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |      * @return bool hook value; true means continue processing, false means stop. | 
					
						
							|  |  |  |      * @throws PEAR_Exception | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |      * @see Schema | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |     public function onCheckSchema(): bool | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         $schema = Schema::get(); | 
					
						
							|  |  |  |         $schema->ensureTable('searchsub', SearchSub::schemaDef()); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Map URLs to actions | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2014-11-07 15:24:05 +01:00
										 |  |  |      * @param URLMapper $m path-to-action mapper | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |      * @return bool hook value; true means continue processing, false means stop. | 
					
						
							|  |  |  |      * @throws Exception | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |     public function onRouterInitialized(URLMapper $m): bool | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |         $m->connect( | 
					
						
							|  |  |  |             'search/:search/subscribe', | 
					
						
							|  |  |  |             ['action' => 'searchsub'], | 
					
						
							|  |  |  |             ['search' => Router::REGEX_TAG] | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         $m->connect( | 
					
						
							|  |  |  |             'search/:search/unsubscribe', | 
					
						
							|  |  |  |             ['action' => 'searchunsub'], | 
					
						
							|  |  |  |             ['search' => Router::REGEX_TAG] | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         $m->connect( | 
					
						
							|  |  |  |             ':nickname/search-subscriptions', | 
					
						
							|  |  |  |             ['action' => 'searchsubs'], | 
					
						
							|  |  |  |             ['nickname' => Nickname::DISPLAY_FMT] | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |      * Module version data | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |      * | 
					
						
							|  |  |  |      * @param array &$versions array of version data | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |      * @return bool | 
					
						
							|  |  |  |      * @throws Exception | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-08-12 15:03:30 +01:00
										 |  |  |     public function onPluginVersion(array &$versions): bool | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         $versions[] = array('name' => 'SearchSub', | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |             'version' => self::PLUGIN_VERSION, | 
					
						
							|  |  |  |             'author' => 'Brion Vibber', | 
					
						
							| 
									
										
										
										
											2019-11-21 00:21:22 +00:00
										 |  |  |             'homepage' => GNUSOCIAL_ENGINE_REPO_URL . 'tree/master/plugins/SearchSub', | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |             'rawdescription' => | 
					
						
							|  |  |  |             // TRANS: Module description.
 | 
					
						
							|  |  |  |                 _m('Module to allow following all messages with a given search.')); | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Hook inbox delivery setup so search subscribers receive all | 
					
						
							|  |  |  |      * notices with that search in their inbox. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Currently makes no distinction between local messages and | 
					
						
							|  |  |  |      * remote ones which happen to come in to the system. Remote | 
					
						
							|  |  |  |      * notices that don't come in at all won't ever reach this. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param Notice $notice | 
					
						
							|  |  |  |      * @param array $ni in/out map of profile IDs to inbox constants | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |      * @return bool hook result | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |     public function onStartNoticeWhoGets(Notice $notice, array &$ni): bool | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-03-15 15:34:06 -07:00
										 |  |  |         // Warning: this is potentially very slow
 | 
					
						
							|  |  |  |         // with a lot of searches!
 | 
					
						
							|  |  |  |         $sub = new SearchSub(); | 
					
						
							|  |  |  |         $sub->groupBy('search'); | 
					
						
							| 
									
										
										
										
											2019-09-11 13:12:41 +03:00
										 |  |  |         $sub->selectAdd(); | 
					
						
							|  |  |  |         $sub->selectAdd('search'); | 
					
						
							| 
									
										
										
										
											2011-03-15 15:34:06 -07:00
										 |  |  |         $sub->find(); | 
					
						
							|  |  |  |         while ($sub->fetch()) { | 
					
						
							|  |  |  |             $search = $sub->search; | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-15 15:34:06 -07:00
										 |  |  |             if ($this->matchSearch($notice, $search)) { | 
					
						
							|  |  |  |                 // Match? Find all those who subscribed to this
 | 
					
						
							|  |  |  |                 // search term and get our delivery on...
 | 
					
						
							|  |  |  |                 $searchsub = new SearchSub(); | 
					
						
							|  |  |  |                 $searchsub->search = $search; | 
					
						
							|  |  |  |                 $searchsub->find(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 while ($searchsub->fetch()) { | 
					
						
							|  |  |  |                     // These constants are currently not actually used, iirc
 | 
					
						
							|  |  |  |                     $ni[$searchsub->profile_id] = NOTICE_INBOX_SOURCE_SUB; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-15 15:34:06 -07:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Does the given notice match the given fulltext search query? | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Warning: not guaranteed to match other search engine behavior, etc. | 
					
						
							|  |  |  |      * Currently using a basic case-insensitive substring match, which | 
					
						
							|  |  |  |      * probably fits with the 'LIKE' search but not the default MySQL | 
					
						
							|  |  |  |      * or Sphinx search backends. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param Notice $notice | 
					
						
							| 
									
										
										
										
											2011-06-05 20:42:11 +02:00
										 |  |  |      * @param string $search | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |      * @return bool | 
					
						
							| 
									
										
										
										
											2011-03-15 15:34:06 -07:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |     public function matchSearch(Notice $notice, $search): bool | 
					
						
							| 
									
										
										
										
											2011-03-15 15:34:06 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         return (mb_stripos($notice->content, $search) !== false); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2011-03-15 15:34:06 -07:00
										 |  |  |      * @param NoticeSearchAction $action | 
					
						
							|  |  |  |      * @param string $q | 
					
						
							|  |  |  |      * @param Notice $notice | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |      * @return bool hook result | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |     public function onStartNoticeSearchShowResults($action, $q, $notice): bool | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         $user = common_current_user(); | 
					
						
							|  |  |  |         if ($user) { | 
					
						
							| 
									
										
										
										
											2011-03-15 15:34:06 -07:00
										 |  |  |             $search = $q; | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |             $searchsub = SearchSub::pkeyGet(array('search' => $search, | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |                 'profile_id' => $user->id)); | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  |             if ($searchsub) { | 
					
						
							|  |  |  |                 $form = new SearchUnsubForm($action, $search); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 $form = new SearchSubForm($action, $search); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             $action->elementStart('div', 'entity_actions'); | 
					
						
							|  |  |  |             $action->elementStart('ul'); | 
					
						
							|  |  |  |             $action->elementStart('li', 'entity_subscribe'); | 
					
						
							|  |  |  |             $form->show(); | 
					
						
							|  |  |  |             $action->elementEnd('li'); | 
					
						
							|  |  |  |             $action->elementEnd('ul'); | 
					
						
							|  |  |  |             $action->elementEnd('div'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-03-16 16:41:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Menu item for personal subscriptions/groups area | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param Widget $widget Widget being executed | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |      * @return bool hook return | 
					
						
							|  |  |  |      * @throws Exception | 
					
						
							| 
									
										
										
										
											2011-03-16 16:41:02 -07:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |     public function onEndSubGroupNav($widget): bool | 
					
						
							| 
									
										
										
										
											2011-03-16 16:41:02 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         $action = $widget->out; | 
					
						
							|  |  |  |         $action_name = $action->trimmed('action'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |         $action->menuItem( | 
					
						
							|  |  |  |             common_local_url('searchsubs', array('nickname' => $action->user->nickname)), | 
					
						
							|  |  |  |             // TRANS: SearchSub plugin menu item on user settings page.
 | 
					
						
							|  |  |  |             _m('MENU', 'Searches'), | 
					
						
							|  |  |  |             // TRANS: SearchSub plugin tooltip for user settings menu item.
 | 
					
						
							|  |  |  |             _m('Configure search subscriptions'), | 
					
						
							|  |  |  |             $action_name == 'searchsubs' && $action->arg('nickname') == $action->user->nickname | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2011-03-16 16:41:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-16 17:08:09 -07:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Replace the built-in stub track commands with ones that control | 
					
						
							|  |  |  |      * search subscriptions. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param CommandInterpreter $cmd | 
					
						
							|  |  |  |      * @param string $arg | 
					
						
							|  |  |  |      * @param User $user | 
					
						
							|  |  |  |      * @param Command $result | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |      * @return bool hook result | 
					
						
							| 
									
										
										
										
											2011-03-16 17:08:09 -07:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |     public function onEndInterpretCommand($cmd, $arg, $user, &$result): bool | 
					
						
							| 
									
										
										
										
											2011-03-16 17:08:09 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         if ($result instanceof TrackCommand) { | 
					
						
							|  |  |  |             $result = new SearchSubTrackCommand($user, $arg); | 
					
						
							|  |  |  |             return false; | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |         } elseif ($result instanceof TrackOffCommand) { | 
					
						
							| 
									
										
										
										
											2011-03-16 17:08:09 -07:00
										 |  |  |             $result = new SearchSubTrackOffCommand($user); | 
					
						
							|  |  |  |             return false; | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |         } elseif ($result instanceof TrackingCommand) { | 
					
						
							| 
									
										
										
										
											2011-03-16 17:08:09 -07:00
										 |  |  |             $result = new SearchSubTrackingCommand($user); | 
					
						
							|  |  |  |             return false; | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |         } elseif ($result instanceof UntrackCommand) { | 
					
						
							| 
									
										
										
										
											2011-03-16 17:08:09 -07:00
										 |  |  |             $result = new SearchSubUntrackCommand($user, $arg); | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |     public function onHelpCommandMessages($cmd, &$commands): void | 
					
						
							| 
									
										
										
										
											2011-03-16 17:08:09 -07:00
										 |  |  |     { | 
					
						
							|  |  |  |         // TRANS: Help message for IM/SMS command "track <word>"
 | 
					
						
							|  |  |  |         $commands["track <word>"] = _m('COMMANDHELP', "Start following notices matching the given search query."); | 
					
						
							|  |  |  |         // TRANS: Help message for IM/SMS command "untrack <word>"
 | 
					
						
							|  |  |  |         $commands["untrack <word>"] = _m('COMMANDHELP', "Stop following notices matching the given search query."); | 
					
						
							|  |  |  |         // TRANS: Help message for IM/SMS command "track off"
 | 
					
						
							|  |  |  |         $commands["track off"] = _m('COMMANDHELP', "Disable all tracked search subscriptions."); | 
					
						
							|  |  |  |         // TRANS: Help message for IM/SMS command "untrack all"
 | 
					
						
							|  |  |  |         $commands["untrack all"] = _m('COMMANDHELP', "Disable all tracked search subscriptions."); | 
					
						
							|  |  |  |         // TRANS: Help message for IM/SMS command "tracks"
 | 
					
						
							|  |  |  |         $commands["tracks"] = _m('COMMANDHELP', "List all your search subscriptions."); | 
					
						
							|  |  |  |         // TRANS: Help message for IM/SMS command "tracking"
 | 
					
						
							|  |  |  |         $commands["tracking"] = _m('COMMANDHELP', "List all your search subscriptions."); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-04-05 18:45:37 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |     public function onEndDefaultLocalNav($menu, $user): bool | 
					
						
							| 
									
										
										
										
											2011-04-05 18:45:37 -04:00
										 |  |  |     { | 
					
						
							|  |  |  |         $user = common_current_user(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-08 13:56:08 -07:00
										 |  |  |         if (!empty($user)) { | 
					
						
							|  |  |  |             $searches = SearchSub::forProfile($user->getProfile()); | 
					
						
							| 
									
										
										
										
											2011-04-05 18:45:37 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-08 13:56:08 -07:00
										 |  |  |             if (!empty($searches) && count($searches) > 0) { | 
					
						
							|  |  |  |                 $searchSubMenu = new SearchSubMenu($menu->out, $user, $searches); | 
					
						
							| 
									
										
										
										
											2011-06-05 20:42:11 +02:00
										 |  |  |                 // TRANS: Sub menu for searches.
 | 
					
						
							| 
									
										
										
										
											2019-08-11 04:11:27 +01:00
										 |  |  |                 $menu->submenu(_m('MENU', 'Searches'), $searchSubMenu); | 
					
						
							| 
									
										
										
										
											2011-04-08 13:56:08 -07:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-04-05 18:45:37 -04:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-03-15 14:58:09 -07:00
										 |  |  | } |