]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/ActivitySpam/ActivitySpamPlugin.php
975fc6885c0c3be709c90c1b9553c8bc98b2c297
[quix0rs-gnu-social.git] / plugins / ActivitySpam / ActivitySpamPlugin.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2011,2012, StatusNet, Inc.
5  *
6  * ActivitySpam Plugin
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  Spam
24  * @package   StatusNet
25  * @author    Evan Prodromou <evan@status.net>
26  * @copyright 2011,2012 StatusNet, Inc.
27  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
28  * @link      http://status.net/
29  */
30
31 if (!defined('STATUSNET')) {
32     // This check helps protect against security problems;
33     // your code file can't be executed directly from the web.
34     exit(1);
35 }
36
37 /**
38  * Check new notices with activity spam service.
39  * 
40  * @category  Spam
41  * @package   StatusNet
42  * @author    Evan Prodromou <evan@status.net>
43  * @copyright 2011,2012 StatusNet, Inc.
44  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
45  * @link      http://status.net/
46  */
47 class ActivitySpamPlugin extends Plugin
48 {
49     public $server = null;
50     public $hideSpam = false;
51
52     const REVIEWSPAM = 'ActivitySpamPlugin::REVIEWSPAM';
53     const TRAINSPAM = 'ActivitySpamPlugin::TRAINSPAM';
54
55     /**
56      * Initializer
57      *
58      * @return boolean hook value; true means continue processing, false means stop.
59      */
60     function initialize()
61     {
62         $this->filter = new SpamFilter(common_config('activityspam', 'server'),
63                                        common_config('activityspam', 'consumerkey'),
64                                        common_config('activityspam', 'secret'));
65
66         $this->hideSpam = common_config('activityspam', 'hidespam');
67
68         // Let DB_DataObject find Spam_score
69
70         common_config_set('db', 'class_location', 
71                           common_config('db', 'class_location') .':'.dirname(__FILE__));
72
73         return true;
74     }
75
76     /**
77      * Database schema setup
78      *
79      * @see Schema
80      * @see ColumnDef
81      *
82      * @return boolean hook value; true means continue processing, false means stop.
83      */
84
85     function onCheckSchema()
86     {
87         $schema = Schema::get();
88         $schema->ensureTable('spam_score', Spam_score::schemaDef());
89
90         Spam_score::upgrade();
91
92         return true;
93     }
94
95     /**
96      * Load related modules when needed
97      *
98      * @param string $cls Name of the class to be loaded
99      *
100      * @return boolean hook value; true means continue processing, false means stop.
101      */
102
103     function onAutoload($cls)
104     {
105         $dir = dirname(__FILE__);
106
107         switch ($cls)
108         {
109         case 'TrainAction':
110         case 'SpamAction':
111             include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
112             return false;
113         case 'Spam_score':
114             include_once $dir . '/'.$cls.'.php';
115             return false;
116         case 'SpamFilter':
117         case 'SpamNoticeStream':
118         case 'TrainSpamForm':
119         case 'TrainHamForm':
120             include_once $dir . '/'.strtolower($cls).'.php';
121             return false;
122         default:
123             return true;
124         }
125     }
126
127     /**
128      * When a notice is saved, check its spam score
129      * 
130      * @param Notice $notice Notice that was just saved
131      *
132      * @return boolean hook value; true means continue processing, false means stop.
133      */
134
135     function onEndNoticeSave($notice)
136     {
137         try {
138
139             $result = $this->filter->test($notice);
140
141             $score = Spam_score::saveNew($notice, $result);
142
143             $this->log(LOG_INFO, "Notice " . $notice->id . " has spam score " . $score->score);
144
145         } catch (Exception $e) {
146             // Log but continue 
147             $this->log(LOG_ERR, $e->getMessage());
148         }
149
150         return true;
151     }
152
153     function onNoticeDeleteRelated($notice) {
154         $score = Spam_score::getKV('notice_id', $notice->id);
155         if (!empty($score)) {
156             $score->delete();
157         }
158         return true;
159     }
160
161     function onUserRightsCheck($profile, $right, &$result) {
162         switch ($right) {
163         case self::REVIEWSPAM:
164         case self::TRAINSPAM:
165             $result = ($profile->hasRole(Profile_role::MODERATOR) || $profile->hasRole('modhelper'));
166             return false;
167         default:
168             return true;
169         }
170     }
171
172     function onGetSpamFilter(&$filter) {
173         $filter = $this->filter;
174         return false;
175     }
176
177     function onEndShowNoticeOptionItems($nli)
178     {
179         $profile = Profile::current();
180
181         if (!empty($profile) && $profile->hasRight(self::TRAINSPAM)) {
182
183             $notice = $nli->getNotice();
184             $out = $nli->getOut();
185
186             if (!empty($notice)) {
187
188                 $score = Spam_score::getKV('notice_id', $notice->id);
189
190                 if (empty($score)) {
191                     // If it's empty, we can train it.
192                     $form = new TrainSpamForm($out, $notice);
193                     $form->show();
194                 } else if ($score->is_spam) {
195                     $form = new TrainHamForm($out, $notice);
196                     $form->show();
197                 } else if (!$score->is_spam) {
198                     $form = new TrainSpamForm($out, $notice);
199                     $form->show();
200                 }
201             }
202         }
203
204         return true;
205     }
206     
207     /**
208      * Map URLs to actions
209      *
210      * @param Net_URL_Mapper $m path-to-action mapper
211      *
212      * @return boolean hook value; true means continue processing, false means stop.
213      */
214
215     function onRouterInitialized($m)
216     {
217         $m->connect('main/train/spam',
218                     array('action' => 'train', 'category' => 'spam'));
219         $m->connect('main/train/ham',
220                     array('action' => 'train', 'category' => 'ham'));
221         $m->connect('main/spam',
222                     array('action' => 'spam'));
223         return true;
224     }
225
226     function onEndShowStyles($action)
227     {
228         $action->element('style', null,
229                          '.form-train-spam input.submit { background: url('.$this->path('icons/bullet_black.png').') no-repeat 0px 0px } ' . "\n" .
230                          '.form-train-ham input.submit { background: url('.$this->path('icons/exclamation.png').') no-repeat 0px 0px } ');
231         return true;
232     }
233
234     function onEndPublicGroupNav($nav)
235     {
236         $user = common_current_user();
237
238         if (!empty($user) && $user->hasRight(self::REVIEWSPAM)) {
239             $nav->out->menuItem(common_local_url('spam'),
240                                 _m('MENU','Spam'),
241                                 // TRANS: Menu item title in search group navigation panel.
242                                 _('Notices marked as spam'),
243                                 $nav->actionName == 'spam',
244                                 'nav_timeline_spam');
245         }
246
247         return true;
248     }
249
250     function onPluginVersion(&$versions)
251     {
252         $versions[] = array('name' => 'ActivitySpam',
253                             'version' => STATUSNET_VERSION,
254                             'author' => 'Evan Prodromou',
255                             'homepage' => 'http://status.net/wiki/Plugin:ActivitySpam',
256                             'description' =>
257                             _m('Test notices against the Activity Spam service.'));
258         return true;
259     }
260
261     function onEndNoticeInScope($notice, $profile, &$bResult)
262     {
263         if ($this->hideSpam) {
264             if ($bResult) {
265
266                 $score = Spam_score::getKV('notice_id', $notice->id);
267
268                 if (!empty($score) && $score->is_spam) {
269                     if (empty($profile) ||
270                         ($profile->id !== $notice->profile_id &&
271                          !$profile->hasRight(self::REVIEWSPAM))) {
272                         $bResult = false;
273                     }
274                 }
275             }
276         }
277
278         return true;
279     }
280
281     /**
282      * Pre-cache our spam scores if needed.
283      */
284     function onEndNoticeListPrefill(&$notices, &$profiles, $avatarSize) {
285         if ($this->hideSpam) {
286             foreach ($notices as $notice) {
287                 $ids[] = $notice->id;
288             }
289             Memcached_DataObject::multiGet('Spam_score', 'notice_id', $ids);
290         }
291         return true;
292     }
293 }