]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/ActivitySpam/ActivitySpamPlugin.php
Merge ActivitySpam plugin
[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         return true;
69     }
70
71     /**
72      * Database schema setup
73      *
74      * @see Schema
75      * @see ColumnDef
76      *
77      * @return boolean hook value; true means continue processing, false means stop.
78      */
79
80     function onCheckSchema()
81     {
82         $schema = Schema::get();
83         $schema->ensureTable('spam_score', Spam_score::schemaDef());
84
85         Spam_score::upgrade();
86
87         return true;
88     }
89
90     /**
91      * Load related modules when needed
92      *
93      * @param string $cls Name of the class to be loaded
94      *
95      * @return boolean hook value; true means continue processing, false means stop.
96      */
97
98     function onAutoload($cls)
99     {
100         $dir = dirname(__FILE__);
101
102         switch ($cls)
103         {
104         case 'TrainAction':
105         case 'SpamAction':
106             include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
107             return false;
108         case 'Spam_score':
109             include_once $dir . '/'.$cls.'.php';
110             return false;
111         case 'SpamFilter':
112         case 'SpamNoticeStream':
113         case 'TrainSpamForm':
114         case 'TrainHamForm':
115             include_once $dir . '/'.strtolower($cls).'.php';
116             return false;
117         default:
118             return true;
119         }
120     }
121
122     /**
123      * When a notice is saved, check its spam score
124      * 
125      * @param Notice $notice Notice that was just saved
126      *
127      * @return boolean hook value; true means continue processing, false means stop.
128      */
129
130     function onEndNoticeSave($notice)
131     {
132         try {
133
134             $result = $this->filter->test($notice);
135
136             $score = Spam_score::saveNew($notice, $result);
137
138             $this->log(LOG_INFO, "Notice " . $notice->id . " has spam score " . $score->score);
139
140         } catch (Exception $e) {
141             // Log but continue 
142             $this->log(LOG_ERR, $e->getMessage());
143         }
144
145         return true;
146     }
147
148     function onNoticeDeleteRelated($notice) {
149         $score = Spam_score::staticGet('notice_id', $notice->id);
150         if (!empty($score)) {
151             $score->delete();
152         }
153         return true;
154     }
155
156     function onUserRightsCheck($profile, $right, &$result) {
157         switch ($right) {
158         case self::REVIEWSPAM:
159         case self::TRAINSPAM:
160             $result = ($profile->hasRole(Profile_role::MODERATOR) || $profile->hasRole('modhelper'));
161             return false;
162         default:
163             return true;
164         }
165     }
166
167     function onGetSpamFilter(&$filter) {
168         $filter = $this->filter;
169         return false;
170     }
171
172     function onEndShowNoticeOptionItems($nli)
173     {
174         $profile = Profile::current();
175
176         if (!empty($profile) && $profile->hasRight(self::TRAINSPAM)) {
177
178             $notice = $nli->getNotice();
179             $out = $nli->getOut();
180
181             if (!empty($notice)) {
182
183                 $score = $this->getScore($notice);
184
185                 if (empty($score)) {
186                     $this->debug("No score for notice " . $notice->id);
187                     // XXX: show a question-mark or something
188                 } else if ($score->is_spam) {
189                     $form = new TrainHamForm($out, $notice);
190                     $form->show();
191                 } else if (!$score->is_spam) {
192                     $form = new TrainSpamForm($out, $notice);
193                     $form->show();
194                 }
195             }
196         }
197
198         return true;
199     }
200     
201     /**
202      * Map URLs to actions
203      *
204      * @param Net_URL_Mapper $m path-to-action mapper
205      *
206      * @return boolean hook value; true means continue processing, false means stop.
207      */
208
209     function onRouterInitialized($m)
210     {
211         $m->connect('main/train/spam',
212                     array('action' => 'train', 'category' => 'spam'));
213         $m->connect('main/train/ham',
214                     array('action' => 'train', 'category' => 'ham'));
215         $m->connect('main/spam',
216                     array('action' => 'spam'));
217         return true;
218     }
219
220     function onEndShowStyles($action)
221     {
222         $action->element('style', null,
223                          '.form-train-spam input.submit { background: url('.$this->path('icons/bullet_black.png').') no-repeat 0px 0px } ' . "\n" .
224                          '.form-train-ham input.submit { background: url('.$this->path('icons/exclamation.png').') no-repeat 0px 0px } ');
225         return true;
226     }
227
228     function onEndPublicGroupNav($nav)
229     {
230         $user = common_current_user();
231
232         if (!empty($user) && $user->hasRight(self::REVIEWSPAM)) {
233             $nav->out->menuItem(common_local_url('spam'),
234                                 _m('MENU','Spam'),
235                                 // TRANS: Menu item title in search group navigation panel.
236                                 _('Notices marked as spam'),
237                                 $nav->actionName == 'spam',
238                                 'nav_timeline_spam');
239         }
240
241         return true;
242     }
243
244     function onPluginVersion(&$versions)
245     {
246         $versions[] = array('name' => 'ActivitySpam',
247                             'version' => STATUSNET_VERSION,
248                             'author' => 'Evan Prodromou',
249                             'homepage' => 'http://status.net/wiki/Plugin:ActivitySpam',
250                             'description' =>
251                             _m('Test notices against the Activity Spam service.'));
252         return true;
253     }
254
255     function getScore($notice)
256     {
257         $score = Spam_score::staticGet('notice_id', $notice->id);
258         
259         if (!empty($score)) {
260             return $score;
261         }
262
263         try {
264
265             $result = $this->filter->test($notice);
266
267             $score = Spam_score::saveNew($notice, $result);
268
269             $this->log(LOG_INFO, "Notice " . $notice->id . " has spam score " . $score->score);
270
271         } catch (Exception $e) {
272             // Log but continue 
273             $this->log(LOG_ERR, $e->getMessage());
274             $score = null;
275         }
276
277         return $score;
278     }
279
280     function onStartReadWriteTables(&$alwaysRW, &$rwdb) {
281         $alwaysRW[] = 'spam_score';
282         return true;
283     }
284
285
286     function onEndNoticeInScope($notice, $profile, &$bResult)
287     {
288         if ($this->hideSpam) {
289             if ($bResult) {
290
291                 $score = Spam_score::staticGet('notice_id', $notice->id);
292
293                 if (!empty($score) && $score->is_spam) {
294                     if (empty($profile) ||
295                         ($profile->id !== $notice->profile_id &&
296                          !$profile->hasRight(self::REVIEWSPAM))) {
297                         $bResult = false;
298                     }
299                 }
300             }
301         }
302
303         return true;
304     }
305
306     /**
307      * Pre-cache our spam scores if needed.
308      */
309     function onEndNoticeListPrefill(&$notices, &$profiles, $avatarSize) {
310         if ($this->hideSpam) {
311             foreach ($notices as $notice) {
312                 $ids[] = $notice->id;
313             }
314             Memcached_DataObject::multiGet('Spam_score', 'notice_id', $ids);
315         }
316         return true;
317     }
318 }