forked from GNUsocial/gnu-social
		
	Merge branch 'testing'
This commit is contained in:
		
							
								
								
									
										6
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								INSTALL
									
									
									
									
									
								
							@@ -106,9 +106,9 @@ especially if you've previously installed PHP/MySQL packages.
 | 
			
		||||
1. Unpack the tarball you downloaded on your Web server. Usually a
 | 
			
		||||
   command like this will work:
 | 
			
		||||
 | 
			
		||||
       tar zxf statusnet-1.0.1.tar.gz
 | 
			
		||||
       tar zxf statusnet-1.1.0-alpha1.tar.gz
 | 
			
		||||
 | 
			
		||||
   ...which will make a statusnet-1.0.1 subdirectory in your current
 | 
			
		||||
   ...which will make a statusnet-1.1.0-alpha1 subdirectory in your current
 | 
			
		||||
   directory. (If you don't have shell access on your Web server, you
 | 
			
		||||
   may have to unpack the tarball on your local computer and FTP the
 | 
			
		||||
   files to the server.)
 | 
			
		||||
@@ -116,7 +116,7 @@ especially if you've previously installed PHP/MySQL packages.
 | 
			
		||||
2. Move the tarball to a directory of your choosing in your Web root
 | 
			
		||||
   directory. Usually something like this will work:
 | 
			
		||||
 | 
			
		||||
       mv statusnet-1.0.1 /var/www/statusnet
 | 
			
		||||
       mv statusnet-1.1.0-alpha1 /var/www/statusnet
 | 
			
		||||
 | 
			
		||||
   This will make your StatusNet instance available in the statusnet path of
 | 
			
		||||
   your server, like "http://example.net/statusnet". "microblog" or
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								README
									
									
									
									
									
								
							@@ -2,7 +2,7 @@
 | 
			
		||||
README
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
StatusNet 1.0.1
 | 
			
		||||
StatusNet 1.1.0-alpha1
 | 
			
		||||
3 October 2011
 | 
			
		||||
 | 
			
		||||
This is the README file for StatusNet, the Open Source social
 | 
			
		||||
@@ -107,46 +107,23 @@ for additional terms.
 | 
			
		||||
New this version
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
This is a minor bug fix release since 1.0.0, released 30 September
 | 
			
		||||
2011. It fixes the following bugs:
 | 
			
		||||
This is a minor bug fix and feature release since 1.0.1, released 3
 | 
			
		||||
October 2011. (Because the plugin interface has changed in an upwardly
 | 
			
		||||
compatible way, we've incremented the minor version number. See
 | 
			
		||||
http://semver.org/ for the semantic versioning scheme we follow.)
 | 
			
		||||
 | 
			
		||||
- Change default OEmbed provider from oohembed to noembed.
 | 
			
		||||
- Fix problem with path matching on new installs.
 | 
			
		||||
It includes the following changes:
 | 
			
		||||
 | 
			
		||||
Notable additions in the 1.0.x series:
 | 
			
		||||
- ActivitySpam plugin to check updates against spamicity.info
 | 
			
		||||
- Options to hide users who've been silenced or have posted spammy updates.
 | 
			
		||||
- OfflineBackup experimental plugin.
 | 
			
		||||
- Fixes for TwitterBridge to correctly handle replies through the bridge.
 | 
			
		||||
- Improvements in ActivityStreams JSON output to better match 1.0 spec.
 | 
			
		||||
- Console scripts for managing groups.
 | 
			
		||||
- Bug fix for conversation counts in conversation streams.
 | 
			
		||||
- Rights for moderators to manage spam.
 | 
			
		||||
 | 
			
		||||
- Support for private updates, including private-to-groups, private
 | 
			
		||||
  within a site, and private to followers only.
 | 
			
		||||
- Conversation mode in streams; notices appear along with all replies.
 | 
			
		||||
- Microapps -- post different types of activities to timelines, with
 | 
			
		||||
  interaction. Events, bookmarks, Q&A, and polls included by default.
 | 
			
		||||
- New 3-column layout in 'neo' theme by default. Older, 2-column layout
 | 
			
		||||
  themes have been removed.
 | 
			
		||||
- Alphabetical, searchable user directory.
 | 
			
		||||
- Alphabetical, searchable group directory.
 | 
			
		||||
- Groups can require all posts to be private ('private groups'), and
 | 
			
		||||
  limit members to the group.
 | 
			
		||||
- Users can make all posts private to their followers ('private stream'),
 | 
			
		||||
  and require authorization to follow.
 | 
			
		||||
- General plugin for IM support; added AIM, IRC and MSN to existing
 | 
			
		||||
  XMPP code.
 | 
			
		||||
- Support for Twitter-like lists, to follow other users without 
 | 
			
		||||
  interfering with the home timeline.
 | 
			
		||||
- Subscription to searches.
 | 
			
		||||
- Subscription to tags.
 | 
			
		||||
- Drupal-style schema system ("schemax") allows in-place database
 | 
			
		||||
  upgrades from various software versions.
 | 
			
		||||
- Fine-grained control of URL shortening, and an internal URL shortener
 | 
			
		||||
  available.
 | 
			
		||||
- Extended profile for private, enterprise sites.
 | 
			
		||||
- sites are private by default.
 | 
			
		||||
- Blog plugin for extended posts.
 | 
			
		||||
- Plugin to restrict all users of a site to a single email domain.
 | 
			
		||||
- Plugin to send a daily email summary to site users.
 | 
			
		||||
- Deeper integration with Activity Streams (http://activitystrea.ms) format.
 | 
			
		||||
- Automated upgrade script.
 | 
			
		||||
 | 
			
		||||
A full changelog is available at http://status.net/wiki/StatusNet_1.0.1.
 | 
			
		||||
A full changelog is available at http://status.net/wiki/StatusNet_1.1.0-alpha1.
 | 
			
		||||
 | 
			
		||||
Troubleshooting
 | 
			
		||||
===============
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								UPGRADE
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								UPGRADE
									
									
									
									
									
								
							@@ -1,7 +1,7 @@
 | 
			
		||||
Upgrading
 | 
			
		||||
=========
 | 
			
		||||
 | 
			
		||||
If you've been using StatusNet 0.9.9 or lower, or if you've
 | 
			
		||||
If you've been using StatusNet 1.0 or lower, or if you've
 | 
			
		||||
been tracking the "git" version of the software, you will probably
 | 
			
		||||
want to upgrade and keep your existing data. Try these step-by-step
 | 
			
		||||
instructions; read to the end first before trying them.
 | 
			
		||||
@@ -24,7 +24,7 @@ instructions; read to the end first before trying them.
 | 
			
		||||
5. Once all writing processes to your site are turned off, make a
 | 
			
		||||
   final backup of the Web directory and database.
 | 
			
		||||
6. Move your StatusNet directory to a backup spot, like "statusnet.bak".
 | 
			
		||||
7. Unpack your StatusNet 1.0.1 tarball and move it to "statusnet" or
 | 
			
		||||
7. Unpack your StatusNet 1.1.0-alpha1 tarball and move it to "statusnet" or
 | 
			
		||||
   wherever your code used to be.
 | 
			
		||||
8. Copy the config.php file and the contents of the avatar/, background/,
 | 
			
		||||
   file/, and local/ subdirectories from your old directory to your new
 | 
			
		||||
@@ -37,7 +37,7 @@ instructions; read to the end first before trying them.
 | 
			
		||||
    reversed. YOU CAN EASILY DESTROY YOUR SITE WITH THIS STEP. Don't
 | 
			
		||||
    do it without a known-good backup!
 | 
			
		||||
 | 
			
		||||
    In your new StatusNet 1.0.1 directory and AFTER YOU MAKE A
 | 
			
		||||
    In your new StatusNet 1.1.0-alpha1 directory and AFTER YOU MAKE A
 | 
			
		||||
    BACKUP run the upgrade.php script like this:
 | 
			
		||||
 | 
			
		||||
        php ./scripts/upgrade.php
 | 
			
		||||
 
 | 
			
		||||
@@ -19,13 +19,13 @@
 | 
			
		||||
 | 
			
		||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
 | 
			
		||||
 | 
			
		||||
define('STATUSNET_BASE_VERSION', '1.0.1');
 | 
			
		||||
define('STATUSNET_LIFECYCLE', ''); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release'
 | 
			
		||||
define('STATUSNET_VERSION', STATUSNET_BASE_VERSION . STATUSNET_LIFECYCLE);
 | 
			
		||||
define('STATUSNET_BASE_VERSION', '1.1.0');
 | 
			
		||||
define('STATUSNET_LIFECYCLE', 'alpha1'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release'
 | 
			
		||||
define('STATUSNET_VERSION', STATUSNET_BASE_VERSION . '-' . STATUSNET_LIFECYCLE);
 | 
			
		||||
 | 
			
		||||
define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
 | 
			
		||||
 | 
			
		||||
define('STATUSNET_CODENAME', 'Get It Together');
 | 
			
		||||
define('STATUSNET_CODENAME', 'Fight for Your Right');
 | 
			
		||||
 | 
			
		||||
define('AVATAR_PROFILE_SIZE', 96);
 | 
			
		||||
define('AVATAR_STREAM_SIZE', 48);
 | 
			
		||||
@@ -34,7 +34,6 @@ define('AVATAR_MINI_SIZE', 24);
 | 
			
		||||
define('NOTICES_PER_PAGE', 20);
 | 
			
		||||
define('PROFILES_PER_PAGE', 20);
 | 
			
		||||
define('MESSAGES_PER_PAGE', 20);
 | 
			
		||||
define('GROUPS_PER_PAGE', 20);
 | 
			
		||||
 | 
			
		||||
define('FOREIGN_NOTICE_SEND', 1);
 | 
			
		||||
define('FOREIGN_NOTICE_RECV', 2);
 | 
			
		||||
@@ -170,10 +169,9 @@ function PEAR_ErrorToPEAR_Exception($err)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($err->getCode()) {
 | 
			
		||||
        throw new PEAR_Exception($msg, $err, $err->getCode());
 | 
			
		||||
    } else {
 | 
			
		||||
        throw new PEAR_Exception($msg, $err);
 | 
			
		||||
        throw new PEAR_Exception($err->getMessage(), $err->getCode());
 | 
			
		||||
    }
 | 
			
		||||
    throw new PEAR_Exception($err->getMessage());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'PEAR_ErrorToPEAR_Exception');
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										318
									
								
								plugins/ActivitySpam/ActivitySpamPlugin.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										318
									
								
								plugins/ActivitySpam/ActivitySpamPlugin.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,318 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * StatusNet - the distributed open-source microblogging tool
 | 
			
		||||
 * Copyright (C) 2011,2012, StatusNet, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * ActivitySpam Plugin
 | 
			
		||||
 *
 | 
			
		||||
 * PHP version 5
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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.
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * @category  Spam
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2011,2012 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
if (!defined('STATUSNET')) {
 | 
			
		||||
    // This check helps protect against security problems;
 | 
			
		||||
    // your code file can't be executed directly from the web.
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check new notices with activity spam service.
 | 
			
		||||
 * 
 | 
			
		||||
 * @category  Spam
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2011,2012 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
class ActivitySpamPlugin extends Plugin
 | 
			
		||||
{
 | 
			
		||||
    public $server = null;
 | 
			
		||||
    public $hideSpam = false;
 | 
			
		||||
 | 
			
		||||
    const REVIEWSPAM = 'ActivitySpamPlugin::REVIEWSPAM';
 | 
			
		||||
    const TRAINSPAM = 'ActivitySpamPlugin::TRAINSPAM';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initializer
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean hook value; true means continue processing, false means stop.
 | 
			
		||||
     */
 | 
			
		||||
    function initialize()
 | 
			
		||||
    {
 | 
			
		||||
        $this->filter = new SpamFilter(common_config('activityspam', 'server'),
 | 
			
		||||
                                       common_config('activityspam', 'consumerkey'),
 | 
			
		||||
                                       common_config('activityspam', 'secret'));
 | 
			
		||||
 | 
			
		||||
        $this->hideSpam = common_config('activityspam', 'hidespam');
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Database schema setup
 | 
			
		||||
     *
 | 
			
		||||
     * @see Schema
 | 
			
		||||
     * @see ColumnDef
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean hook value; true means continue processing, false means stop.
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function onCheckSchema()
 | 
			
		||||
    {
 | 
			
		||||
        $schema = Schema::get();
 | 
			
		||||
        $schema->ensureTable('spam_score', Spam_score::schemaDef());
 | 
			
		||||
 | 
			
		||||
        Spam_score::upgrade();
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load related modules when needed
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $cls Name of the class to be loaded
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean hook value; true means continue processing, false means stop.
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function onAutoload($cls)
 | 
			
		||||
    {
 | 
			
		||||
        $dir = dirname(__FILE__);
 | 
			
		||||
 | 
			
		||||
        switch ($cls)
 | 
			
		||||
        {
 | 
			
		||||
        case 'TrainAction':
 | 
			
		||||
        case 'SpamAction':
 | 
			
		||||
            include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
 | 
			
		||||
            return false;
 | 
			
		||||
        case 'Spam_score':
 | 
			
		||||
            include_once $dir . '/'.$cls.'.php';
 | 
			
		||||
            return false;
 | 
			
		||||
        case 'SpamFilter':
 | 
			
		||||
        case 'SpamNoticeStream':
 | 
			
		||||
        case 'TrainSpamForm':
 | 
			
		||||
        case 'TrainHamForm':
 | 
			
		||||
            include_once $dir . '/'.strtolower($cls).'.php';
 | 
			
		||||
            return false;
 | 
			
		||||
        default:
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * When a notice is saved, check its spam score
 | 
			
		||||
     * 
 | 
			
		||||
     * @param Notice $notice Notice that was just saved
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean hook value; true means continue processing, false means stop.
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function onEndNoticeSave($notice)
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
 | 
			
		||||
            $result = $this->filter->test($notice);
 | 
			
		||||
 | 
			
		||||
            $score = Spam_score::saveNew($notice, $result);
 | 
			
		||||
 | 
			
		||||
            $this->log(LOG_INFO, "Notice " . $notice->id . " has spam score " . $score->score);
 | 
			
		||||
 | 
			
		||||
        } catch (Exception $e) {
 | 
			
		||||
            // Log but continue 
 | 
			
		||||
            $this->log(LOG_ERR, $e->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onNoticeDeleteRelated($notice) {
 | 
			
		||||
        $score = Spam_score::staticGet('notice_id', $notice->id);
 | 
			
		||||
        if (!empty($score)) {
 | 
			
		||||
            $score->delete();
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onUserRightsCheck($profile, $right, &$result) {
 | 
			
		||||
        switch ($right) {
 | 
			
		||||
        case self::REVIEWSPAM:
 | 
			
		||||
        case self::TRAINSPAM:
 | 
			
		||||
            $result = ($profile->hasRole(Profile_role::MODERATOR) || $profile->hasRole('modhelper'));
 | 
			
		||||
            return false;
 | 
			
		||||
        default:
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onGetSpamFilter(&$filter) {
 | 
			
		||||
        $filter = $this->filter;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onEndShowNoticeOptionItems($nli)
 | 
			
		||||
    {
 | 
			
		||||
        $profile = Profile::current();
 | 
			
		||||
 | 
			
		||||
        if (!empty($profile) && $profile->hasRight(self::TRAINSPAM)) {
 | 
			
		||||
 | 
			
		||||
            $notice = $nli->getNotice();
 | 
			
		||||
            $out = $nli->getOut();
 | 
			
		||||
 | 
			
		||||
            if (!empty($notice)) {
 | 
			
		||||
 | 
			
		||||
                $score = $this->getScore($notice);
 | 
			
		||||
 | 
			
		||||
                if (empty($score)) {
 | 
			
		||||
                    $this->debug("No score for notice " . $notice->id);
 | 
			
		||||
                    // XXX: show a question-mark or something
 | 
			
		||||
                } else if ($score->is_spam) {
 | 
			
		||||
                    $form = new TrainHamForm($out, $notice);
 | 
			
		||||
                    $form->show();
 | 
			
		||||
                } else if (!$score->is_spam) {
 | 
			
		||||
                    $form = new TrainSpamForm($out, $notice);
 | 
			
		||||
                    $form->show();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * Map URLs to actions
 | 
			
		||||
     *
 | 
			
		||||
     * @param Net_URL_Mapper $m path-to-action mapper
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean hook value; true means continue processing, false means stop.
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function onRouterInitialized($m)
 | 
			
		||||
    {
 | 
			
		||||
        $m->connect('main/train/spam',
 | 
			
		||||
                    array('action' => 'train', 'category' => 'spam'));
 | 
			
		||||
        $m->connect('main/train/ham',
 | 
			
		||||
                    array('action' => 'train', 'category' => 'ham'));
 | 
			
		||||
        $m->connect('main/spam',
 | 
			
		||||
                    array('action' => 'spam'));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onEndShowStyles($action)
 | 
			
		||||
    {
 | 
			
		||||
        $action->element('style', null,
 | 
			
		||||
                         '.form-train-spam input.submit { background: url('.$this->path('icons/bullet_black.png').') no-repeat 0px 0px } ' . "\n" .
 | 
			
		||||
                         '.form-train-ham input.submit { background: url('.$this->path('icons/exclamation.png').') no-repeat 0px 0px } ');
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onEndPublicGroupNav($nav)
 | 
			
		||||
    {
 | 
			
		||||
        $user = common_current_user();
 | 
			
		||||
 | 
			
		||||
        if (!empty($user) && $user->hasRight(self::REVIEWSPAM)) {
 | 
			
		||||
            $nav->out->menuItem(common_local_url('spam'),
 | 
			
		||||
                                _m('MENU','Spam'),
 | 
			
		||||
                                // TRANS: Menu item title in search group navigation panel.
 | 
			
		||||
                                _('Notices marked as spam'),
 | 
			
		||||
                                $nav->actionName == 'spam',
 | 
			
		||||
                                'nav_timeline_spam');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onPluginVersion(&$versions)
 | 
			
		||||
    {
 | 
			
		||||
        $versions[] = array('name' => 'ActivitySpam',
 | 
			
		||||
                            'version' => STATUSNET_VERSION,
 | 
			
		||||
                            'author' => 'Evan Prodromou',
 | 
			
		||||
                            'homepage' => 'http://status.net/wiki/Plugin:ActivitySpam',
 | 
			
		||||
                            'description' =>
 | 
			
		||||
                            _m('Test notices against the Activity Spam service.'));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getScore($notice)
 | 
			
		||||
    {
 | 
			
		||||
        $score = Spam_score::staticGet('notice_id', $notice->id);
 | 
			
		||||
        
 | 
			
		||||
        if (!empty($score)) {
 | 
			
		||||
            return $score;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
 | 
			
		||||
            $result = $this->filter->test($notice);
 | 
			
		||||
 | 
			
		||||
            $score = Spam_score::saveNew($notice, $result);
 | 
			
		||||
 | 
			
		||||
            $this->log(LOG_INFO, "Notice " . $notice->id . " has spam score " . $score->score);
 | 
			
		||||
 | 
			
		||||
        } catch (Exception $e) {
 | 
			
		||||
            // Log but continue 
 | 
			
		||||
            $this->log(LOG_ERR, $e->getMessage());
 | 
			
		||||
            $score = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $score;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onStartReadWriteTables(&$alwaysRW, &$rwdb) {
 | 
			
		||||
        $alwaysRW[] = 'spam_score';
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    function onEndNoticeInScope($notice, $profile, &$bResult)
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->hideSpam) {
 | 
			
		||||
            if ($bResult) {
 | 
			
		||||
 | 
			
		||||
                $score = Spam_score::staticGet('notice_id', $notice->id);
 | 
			
		||||
 | 
			
		||||
                if (!empty($score) && $score->is_spam) {
 | 
			
		||||
                    if (empty($profile) ||
 | 
			
		||||
                        ($profile->id !== $notice->profile_id &&
 | 
			
		||||
                         !$profile->hasRight(self::REVIEWSPAM))) {
 | 
			
		||||
                        $bResult = false;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Pre-cache our spam scores if needed.
 | 
			
		||||
     */
 | 
			
		||||
    function onEndNoticeListPrefill(&$notices, &$profiles, $avatarSize) {
 | 
			
		||||
        if ($this->hideSpam) {
 | 
			
		||||
            foreach ($notices as $notice) {
 | 
			
		||||
                $ids[] = $notice->id;
 | 
			
		||||
            }
 | 
			
		||||
            Memcached_DataObject::multiGet('Spam_score', 'notice_id', $ids);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										216
									
								
								plugins/ActivitySpam/Spam_score.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								plugins/ActivitySpam/Spam_score.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,216 @@
 | 
			
		||||
<?php
 | 
			
		||||
  /**
 | 
			
		||||
   * StatusNet - the distributed open-source microblogging tool
 | 
			
		||||
   * Copyright (C) 2011, StatusNet, Inc.
 | 
			
		||||
   *
 | 
			
		||||
   * Score of a notice by activity spam service
 | 
			
		||||
   * 
 | 
			
		||||
   * PHP version 5
 | 
			
		||||
   *
 | 
			
		||||
   * This program 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.
 | 
			
		||||
   *
 | 
			
		||||
   * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
   *
 | 
			
		||||
   * @category  Spam
 | 
			
		||||
   * @package   StatusNet
 | 
			
		||||
   * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
   * @copyright 2011 StatusNet, Inc.
 | 
			
		||||
   * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
   * @link      http://status.net/
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
if (!defined('STATUSNET')) {
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Score of a notice per the activity spam service
 | 
			
		||||
 *
 | 
			
		||||
 * @category Spam
 | 
			
		||||
 * @package  StatusNet
 | 
			
		||||
 * @author   Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 | 
			
		||||
 * @link     http://status.net/
 | 
			
		||||
 *
 | 
			
		||||
 * @see      DB_DataObject
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class Spam_score extends Managed_DataObject
 | 
			
		||||
{
 | 
			
		||||
    const MAX_SCALE = 10000;
 | 
			
		||||
    public $__table = 'spam_score'; // table name
 | 
			
		||||
 | 
			
		||||
    public $notice_id;   // int
 | 
			
		||||
    public $score;       // float
 | 
			
		||||
    public $created;     // datetime
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get an instance by key
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $k Key to use to lookup (usually 'notice_id' for this class)
 | 
			
		||||
     * @param mixed  $v Value to lookup
 | 
			
		||||
     *
 | 
			
		||||
     * @return Spam_score object found, or null for no hits
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
    function staticGet($k, $v=null)
 | 
			
		||||
    {
 | 
			
		||||
        return Managed_DataObject::staticGet('Spam_score', $k, $v);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function saveNew($notice, $result) {
 | 
			
		||||
 | 
			
		||||
        $score = new Spam_score();
 | 
			
		||||
 | 
			
		||||
        $score->notice_id      = $notice->id;
 | 
			
		||||
        $score->score          = $result->probability;
 | 
			
		||||
        $score->is_spam        = $result->isSpam;
 | 
			
		||||
        $score->scaled         = Spam_score::scale($score->score);
 | 
			
		||||
        $score->created        = common_sql_now();
 | 
			
		||||
        $score->notice_created = $notice->created;
 | 
			
		||||
 | 
			
		||||
        $score->insert();
 | 
			
		||||
 | 
			
		||||
        self::blow('spam_score:notice_ids');
 | 
			
		||||
 | 
			
		||||
        return $score;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function save($notice, $result) {
 | 
			
		||||
 | 
			
		||||
        $orig  = null;
 | 
			
		||||
        $score = Spam_score::staticGet('notice_id', $notice->id);
 | 
			
		||||
 | 
			
		||||
        if (empty($score)) {
 | 
			
		||||
            $score = new Spam_score();
 | 
			
		||||
        } else {
 | 
			
		||||
            $orig = clone($score);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $score->notice_id      = $notice->id;
 | 
			
		||||
        $score->score          = $result->probability;
 | 
			
		||||
        $score->is_spam        = $result->isSpam;
 | 
			
		||||
        $score->scaled         = Spam_score::scale($score->score);
 | 
			
		||||
        $score->created        = common_sql_now();
 | 
			
		||||
        $score->notice_created = $notice->created;
 | 
			
		||||
 | 
			
		||||
        if (empty($orig)) {
 | 
			
		||||
            $score->insert();
 | 
			
		||||
        } else {
 | 
			
		||||
            $score->update($orig);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        self::blow('spam_score:notice_ids');
 | 
			
		||||
 | 
			
		||||
        return $score;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function delete()
 | 
			
		||||
    {
 | 
			
		||||
        self::blow('spam_score:notice_ids');
 | 
			
		||||
        self::blow('spam_score:notice_ids;last');
 | 
			
		||||
        parent::delete();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The One True Thingy that must be defined and declared.
 | 
			
		||||
     */
 | 
			
		||||
    public static function schemaDef()
 | 
			
		||||
    {
 | 
			
		||||
        return array(
 | 
			
		||||
            'description' => 'score of the notice per activityspam',
 | 
			
		||||
            'fields' => array(
 | 
			
		||||
                'notice_id' => array('type' => 'int',
 | 
			
		||||
                                     'not null' => true,
 | 
			
		||||
                                     'description' => 'notice getting scored'),
 | 
			
		||||
                'score' => array('type' => 'double',
 | 
			
		||||
                                 'not null' => true,
 | 
			
		||||
                                 'description' => 'score for the notice (0.0, 1.0)'),
 | 
			
		||||
                'scaled' => array('type' => 'int',
 | 
			
		||||
                                  'description' => 'scaled score for the notice (0, 10000)'),
 | 
			
		||||
                'is_spam' => array('type' => 'tinyint',
 | 
			
		||||
                                   'description' => 'flag for spamosity'),
 | 
			
		||||
                'created' => array('type' => 'datetime',
 | 
			
		||||
                                   'not null' => true,
 | 
			
		||||
                                   'description' => 'date this record was created'),
 | 
			
		||||
                'notice_created' => array('type' => 'datetime',
 | 
			
		||||
                                          'description' => 'date the notice was created'),
 | 
			
		||||
            ),
 | 
			
		||||
            'primary key' => array('notice_id'),
 | 
			
		||||
            'foreign keys' => array(
 | 
			
		||||
                'spam_score_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
 | 
			
		||||
            ),
 | 
			
		||||
            'indexes' => array(
 | 
			
		||||
                'spam_score_created_idx' => array('created'),
 | 
			
		||||
                'spam_score_scaled_idx' => array('scaled'),
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function upgrade()
 | 
			
		||||
    {
 | 
			
		||||
        Spam_score::upgradeScaled();
 | 
			
		||||
        Spam_score::upgradeIsSpam();
 | 
			
		||||
        Spam_score::upgradeNoticeCreated();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected static function upgradeScaled()
 | 
			
		||||
    {
 | 
			
		||||
        $score = new Spam_score();
 | 
			
		||||
        $score->whereAdd('scaled IS NULL');
 | 
			
		||||
        
 | 
			
		||||
        if ($score->find()) {
 | 
			
		||||
            while ($score->fetch()) {
 | 
			
		||||
                $orig = clone($score);
 | 
			
		||||
                $score->scaled = Spam_score::scale($score->score);
 | 
			
		||||
                $score->update($orig);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected static function upgradeIsSpam()
 | 
			
		||||
    {
 | 
			
		||||
        $score = new Spam_score();
 | 
			
		||||
        $score->whereAdd('is_spam IS NULL');
 | 
			
		||||
        
 | 
			
		||||
        if ($score->find()) {
 | 
			
		||||
            while ($score->fetch()) {
 | 
			
		||||
                $orig = clone($score);
 | 
			
		||||
                $score->is_spam = ($score->score >= 0.90) ? 1 : 0;
 | 
			
		||||
                $score->update($orig);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected static function upgradeNoticeCreated()
 | 
			
		||||
    {
 | 
			
		||||
        $score = new Spam_score();
 | 
			
		||||
        $score->whereAdd('notice_created IS NULL');
 | 
			
		||||
        
 | 
			
		||||
        if ($score->find()) {
 | 
			
		||||
            while ($score->fetch()) {
 | 
			
		||||
                $notice = Notice::staticGet('id', $score->notice_id);
 | 
			
		||||
                if (!empty($notice)) {
 | 
			
		||||
                    $orig = clone($score);
 | 
			
		||||
                    $score->notice_created = $notice->created;
 | 
			
		||||
                    $score->update($orig);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function scale($score)
 | 
			
		||||
    {
 | 
			
		||||
        $raw = round($score * Spam_score::MAX_SCALE);
 | 
			
		||||
        return max(0, min(Spam_score::MAX_SCALE, $raw));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								plugins/ActivitySpam/icons/bullet_black.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								plugins/ActivitySpam/icons/bullet_black.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 211 B  | 
							
								
								
									
										
											BIN
										
									
								
								plugins/ActivitySpam/icons/exclamation.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								plugins/ActivitySpam/icons/exclamation.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 701 B  | 
							
								
								
									
										105
									
								
								plugins/ActivitySpam/scripts/testuser.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								plugins/ActivitySpam/scripts/testuser.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
<?php
 | 
			
		||||
/*
 | 
			
		||||
 * StatusNet - the distributed open-source microblogging tool
 | 
			
		||||
 * Copyright (C) 2012 StatusNet, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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.
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../../..'));
 | 
			
		||||
 | 
			
		||||
$shortoptions = 'i:n:a';
 | 
			
		||||
$longoptions = array('id=', 'nickname=', 'all');
 | 
			
		||||
 | 
			
		||||
$helptext = <<<END_OF_TESTUSER_HELP
 | 
			
		||||
testuser.php [options]
 | 
			
		||||
Test user activities against the spam filter
 | 
			
		||||
 | 
			
		||||
  -i --id       ID of user to export
 | 
			
		||||
  -n --nickname nickname of the user to export
 | 
			
		||||
  -a --all      All users
 | 
			
		||||
END_OF_TESTUSER_HELP;
 | 
			
		||||
 | 
			
		||||
require_once INSTALLDIR.'/scripts/commandline.inc';
 | 
			
		||||
 | 
			
		||||
function testAllUsers($filter) {
 | 
			
		||||
    $found = false;
 | 
			
		||||
    $offset = 0;
 | 
			
		||||
    $limit  = 1000;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
 | 
			
		||||
        $user = new User();
 | 
			
		||||
        $user->orderBy('created');
 | 
			
		||||
        $user->limit($offset, $limit);
 | 
			
		||||
 | 
			
		||||
        $found = $user->find();
 | 
			
		||||
 | 
			
		||||
        if ($found) {
 | 
			
		||||
            while ($user->fetch()) {
 | 
			
		||||
                try {
 | 
			
		||||
                    testUser($filter, $user);
 | 
			
		||||
                } catch (Exception $e) {
 | 
			
		||||
                    printfnq("ERROR testing user %s\n: %s", $user->nickname, $e->getMessage());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            $offset += $found;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } while ($found > 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function testUser($filter, $user) {
 | 
			
		||||
 | 
			
		||||
    printfnq("Testing user %s\n", $user->nickname);
 | 
			
		||||
 | 
			
		||||
    $profile = Profile::staticGet('id', $user->id);
 | 
			
		||||
 | 
			
		||||
    $str = new ProfileNoticeStream($profile, $profile);
 | 
			
		||||
 | 
			
		||||
    $offset = 0;
 | 
			
		||||
    $limit  = 100;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        $notice = $str->getNotices($offset, $limit);
 | 
			
		||||
        while ($notice->fetch()) {
 | 
			
		||||
            try {
 | 
			
		||||
                printfv("Testing notice %d...", $notice->id);
 | 
			
		||||
                $result = $filter->test($notice);
 | 
			
		||||
                Spam_score::save($notice, $result);
 | 
			
		||||
                printfv("%s\n", ($result->isSpam) ? "SPAM" : "HAM");
 | 
			
		||||
            } catch (Exception $e) {
 | 
			
		||||
                printfnq("ERROR testing notice %d: %s\n", $notice->id, $e->getMessage());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $offset += $notice->N;
 | 
			
		||||
    } while ($notice->N > 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
    $filter = null;
 | 
			
		||||
    Event::handle('GetSpamFilter', array(&$filter));
 | 
			
		||||
    if (empty($filter)) {
 | 
			
		||||
        throw new Exception(_("No spam filter."));
 | 
			
		||||
    }
 | 
			
		||||
    if (have_option('a', 'all')) {
 | 
			
		||||
        testAllUsers($filter);
 | 
			
		||||
    } else {
 | 
			
		||||
        $user = getUser();
 | 
			
		||||
        testUser($filter, $user);
 | 
			
		||||
    }
 | 
			
		||||
} catch (Exception $e) {
 | 
			
		||||
    print $e->getMessage()."\n";
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81
									
								
								plugins/ActivitySpam/scripts/trainuser.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								plugins/ActivitySpam/scripts/trainuser.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
<?php
 | 
			
		||||
/*
 | 
			
		||||
 * StatusNet - the distributed open-source microblogging tool
 | 
			
		||||
 * Copyright (C) 2012 StatusNet, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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.
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../../..'));
 | 
			
		||||
 | 
			
		||||
$shortoptions = 'i:n:t:';
 | 
			
		||||
$longoptions = array('id=', 'nickname=', 'category=');
 | 
			
		||||
 | 
			
		||||
$helptext = <<<END_OF_TRAINUSER_HELP
 | 
			
		||||
trainuser.php [options]
 | 
			
		||||
Train user activities against the spam filter
 | 
			
		||||
 | 
			
		||||
  -i --id       ID of user to export
 | 
			
		||||
  -n --nickname nickname of the user to export
 | 
			
		||||
  -t --category Category; one of "spam" or "ham"
 | 
			
		||||
 | 
			
		||||
END_OF_TRAINUSER_HELP;
 | 
			
		||||
 | 
			
		||||
require_once INSTALLDIR.'/scripts/commandline.inc';
 | 
			
		||||
 | 
			
		||||
function trainUser($filter, $user, $category) {
 | 
			
		||||
 | 
			
		||||
    printfnq("Training user %s\n", $user->nickname);
 | 
			
		||||
 | 
			
		||||
    $profile = Profile::staticGet('id', $user->id);
 | 
			
		||||
 | 
			
		||||
    $str = new ProfileNoticeStream($profile, $profile);
 | 
			
		||||
 | 
			
		||||
    $offset = 0;
 | 
			
		||||
    $limit  = 100;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        $notice = $str->getNotices($offset, $limit);
 | 
			
		||||
        while ($notice->fetch()) {
 | 
			
		||||
            try {
 | 
			
		||||
                printfv("Training notice %d...", $notice->id);
 | 
			
		||||
                $filter->trainOnError($notice, $category);
 | 
			
		||||
                $result = $filter->test($notice);
 | 
			
		||||
                $score = Spam_score::save($notice, $result);
 | 
			
		||||
                printfv("%s\n", ($result->isSpam) ? "SPAM" : "HAM");
 | 
			
		||||
            } catch (Exception $e) {
 | 
			
		||||
                printfnq("ERROR training notice %d\n: %s", $notice->id, $e->getMessage());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $offset += $notice->N;
 | 
			
		||||
    } while ($notice->N > 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
    $filter = null;
 | 
			
		||||
    Event::handle('GetSpamFilter', array(&$filter));
 | 
			
		||||
    if (empty($filter)) {
 | 
			
		||||
        throw new Exception(_("No spam filter."));
 | 
			
		||||
    }
 | 
			
		||||
    $user = getUser();
 | 
			
		||||
    $category = get_option_value('t', 'category');
 | 
			
		||||
    if ($category !== SpamFilter::HAM &&
 | 
			
		||||
        $category !== SpamFilter::SPAM) {
 | 
			
		||||
        throw new Exception(_("No such category."));
 | 
			
		||||
    }
 | 
			
		||||
    trainUser($filter, $user, $category);
 | 
			
		||||
} catch (Exception $e) {
 | 
			
		||||
    print $e->getMessage()."\n";
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										165
									
								
								plugins/ActivitySpam/spam.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								plugins/ActivitySpam/spam.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,165 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * StatusNet - the distributed open-source microblogging tool
 | 
			
		||||
 * Copyright (C) 2012, StatusNet, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * Stream of latest spam messages
 | 
			
		||||
 * 
 | 
			
		||||
 * PHP version 5
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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.
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * @category  Spam
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2012 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
if (!defined('STATUSNET')) {
 | 
			
		||||
    // This check helps protect against security problems;
 | 
			
		||||
    // your code file can't be executed directly from the web.
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
require_once INSTALLDIR.'/lib/noticelist.php';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * SpamAction
 | 
			
		||||
 * 
 | 
			
		||||
 * Shows the latest spam on the service
 | 
			
		||||
 * 
 | 
			
		||||
 * @category  Spam
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2012 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class SpamAction extends Action
 | 
			
		||||
{
 | 
			
		||||
    var $page = null;
 | 
			
		||||
    var $notices = null;
 | 
			
		||||
 | 
			
		||||
    function title() {
 | 
			
		||||
        return _("Latest Spam");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * For initializing members of the class.
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $argarray misc. arguments
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean true
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function prepare($argarray)
 | 
			
		||||
    {
 | 
			
		||||
        parent::prepare($argarray);
 | 
			
		||||
 | 
			
		||||
        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
 | 
			
		||||
 | 
			
		||||
        // User must be logged in.
 | 
			
		||||
 | 
			
		||||
        $user = common_current_user();
 | 
			
		||||
 | 
			
		||||
        if (empty($user)) {
 | 
			
		||||
            throw new ClientException(_("You must be logged in to review."), 403);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // User must have the right to review spam
 | 
			
		||||
 | 
			
		||||
        if (!$user->hasRight(ActivitySpamPlugin::REVIEWSPAM)) {
 | 
			
		||||
            throw new ClientException(_('You cannot review spam on this site.'), 403);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $stream = new SpamNoticeStream($user->getProfile());
 | 
			
		||||
 | 
			
		||||
        $this->notices = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
 | 
			
		||||
                                             NOTICES_PER_PAGE + 1);
 | 
			
		||||
 | 
			
		||||
        if($this->page > 1 && $this->notices->N == 0) {
 | 
			
		||||
            throw new ClientException(_('No such page.'), 404);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handler method
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $argarray is ignored since it's now passed in in prepare()
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function handle($argarray=null)
 | 
			
		||||
    {
 | 
			
		||||
        parent::handle($args);
 | 
			
		||||
 | 
			
		||||
        $this->showPage();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fill the content area
 | 
			
		||||
     *
 | 
			
		||||
     * Shows a list of the notices in the public stream, with some pagination
 | 
			
		||||
     * controls.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function showContent()
 | 
			
		||||
    {
 | 
			
		||||
        $nl = new NoticeList($this->notices, $this);
 | 
			
		||||
 | 
			
		||||
        $cnt = $nl->show();
 | 
			
		||||
 | 
			
		||||
        if ($cnt == 0) {
 | 
			
		||||
            $this->showEmptyList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->pagination($this->page > 1, 
 | 
			
		||||
                          $cnt > NOTICES_PER_PAGE,
 | 
			
		||||
                          $this->page,
 | 
			
		||||
                          'spam');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function showEmptyList()
 | 
			
		||||
    {
 | 
			
		||||
        // TRANS: Text displayed for public feed when there are no public notices.
 | 
			
		||||
        $message = _('This is the timeline of spam messages for %%site.name%% but none have been detected yet.');
 | 
			
		||||
 | 
			
		||||
        $this->elementStart('div', 'guide');
 | 
			
		||||
        $this->raw(common_markup_to_html($message));
 | 
			
		||||
        $this->elementEnd('div');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return true if read only.
 | 
			
		||||
     *
 | 
			
		||||
     * MAY override
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $args other arguments
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean is read only action?
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function isReadOnly($args)
 | 
			
		||||
    {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										171
									
								
								plugins/ActivitySpam/spamfilter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								plugins/ActivitySpam/spamfilter.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,171 @@
 | 
			
		||||
<?php
 | 
			
		||||
  /**
 | 
			
		||||
   * StatusNet - the distributed open-source microblogging tool
 | 
			
		||||
   * Copyright (C) 2012, StatusNet, Inc.
 | 
			
		||||
   *
 | 
			
		||||
   * Spam filter class
 | 
			
		||||
   * 
 | 
			
		||||
   * PHP version 5
 | 
			
		||||
   *
 | 
			
		||||
   * This program 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.
 | 
			
		||||
   *
 | 
			
		||||
   * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
   *
 | 
			
		||||
   * @category  Spam
 | 
			
		||||
   * @package   StatusNet
 | 
			
		||||
   * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
   * @copyright 2012 StatusNet, Inc.
 | 
			
		||||
   * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
   * @link      http://status.net/
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
if (!defined('STATUSNET')) {
 | 
			
		||||
    // This check helps protect against security problems;
 | 
			
		||||
    // your code file can't be executed directly from the web.
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Spam filter class
 | 
			
		||||
 *
 | 
			
		||||
 * Local proxy for remote filter
 | 
			
		||||
 *
 | 
			
		||||
 * @category  Spam
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2012 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class SpamFilter extends OAuthClient {
 | 
			
		||||
 | 
			
		||||
    const HAM  = 'ham';
 | 
			
		||||
    const SPAM = 'spam';
 | 
			
		||||
 | 
			
		||||
    public $server;
 | 
			
		||||
 | 
			
		||||
    function __construct($server, $consumerKey, $secret) {
 | 
			
		||||
        parent::__construct($consumerKey, $secret);
 | 
			
		||||
        $this->server = $server;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function toActivity($notice) {
 | 
			
		||||
        // FIXME: need this to autoload ActivityStreamsMediaLink
 | 
			
		||||
        $doc = new ActivityStreamJSONDocument();
 | 
			
		||||
 | 
			
		||||
        $activity = $notice->asActivity(null);
 | 
			
		||||
 | 
			
		||||
        return $activity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function test($notice) {
 | 
			
		||||
 | 
			
		||||
        $activity = $this->toActivity($notice);
 | 
			
		||||
        return $this->testActivity($activity);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public function testActivity($activity) {
 | 
			
		||||
 | 
			
		||||
        $response = $this->postJSON($this->server . "/is-this-spam", $activity->asArray());
 | 
			
		||||
 | 
			
		||||
        $result = json_decode($response->getBody());
 | 
			
		||||
 | 
			
		||||
        return $result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function train($notice, $category) {
 | 
			
		||||
 | 
			
		||||
        $activity = $this->toActivity($notice);
 | 
			
		||||
        return $this->trainActivity($activity, $category);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function trainActivity($activity, $category) {
 | 
			
		||||
 | 
			
		||||
        switch ($category) {
 | 
			
		||||
        case self::HAM:
 | 
			
		||||
            $endpoint = '/this-is-ham';
 | 
			
		||||
            break;
 | 
			
		||||
        case self::SPAM:
 | 
			
		||||
            $endpoint = '/this-is-spam';
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            throw new Exception("Unknown category: " + $category);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $response = $this->postJSON($this->server . $endpoint, $activity->asArray());
 | 
			
		||||
 | 
			
		||||
        // We don't do much with the results
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function trainOnError($notice, $category) {
 | 
			
		||||
 | 
			
		||||
        $activity = $this->toActivity($notice);
 | 
			
		||||
 | 
			
		||||
        return $this->trainActivityOnError($activity, $category);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public function trainActivityOnError($activity, $category) {
 | 
			
		||||
 | 
			
		||||
        $result = $this->testActivity($activity);
 | 
			
		||||
 | 
			
		||||
        if (($category === self::SPAM && $result->isSpam) ||
 | 
			
		||||
            ($category === self::HAM && !$result->isSpam)) {
 | 
			
		||||
            return true;
 | 
			
		||||
        } else {
 | 
			
		||||
            return $this->trainActivity($activity, $category);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function postJSON($url, $body)
 | 
			
		||||
    {
 | 
			
		||||
        $request = OAuthRequest::from_consumer_and_token($this->consumer,
 | 
			
		||||
                                                         $this->token,
 | 
			
		||||
                                                         'POST',
 | 
			
		||||
                                                         $url);
 | 
			
		||||
 | 
			
		||||
        $request->sign_request($this->sha1_method,
 | 
			
		||||
                               $this->consumer,
 | 
			
		||||
                               $this->token);
 | 
			
		||||
 | 
			
		||||
        $hclient = new HTTPClient($url);
 | 
			
		||||
 | 
			
		||||
        $hclient->setConfig(array('connect_timeout' => 120,
 | 
			
		||||
                                  'timeout' => 120,
 | 
			
		||||
                                  'follow_redirects' => true,
 | 
			
		||||
                                  'ssl_verify_peer' => false,
 | 
			
		||||
                                  'ssl_verify_host' => false));
 | 
			
		||||
 | 
			
		||||
        $hclient->setMethod(HTTP_Request2::METHOD_POST);
 | 
			
		||||
        $hclient->setBody(json_encode($body));
 | 
			
		||||
        $hclient->setHeader('Content-Type', 'application/json');
 | 
			
		||||
        $hclient->setHeader($request->to_header());
 | 
			
		||||
 | 
			
		||||
        // Twitter is strict about accepting invalid "Expect" headers
 | 
			
		||||
        // No reason not to clear it still here -ESP
 | 
			
		||||
 | 
			
		||||
        $hclient->setHeader('Expect', '');
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $response = $hclient->send();
 | 
			
		||||
            $code = $response->getStatus();
 | 
			
		||||
            if (!$response->isOK()) {
 | 
			
		||||
                throw new OAuthClientException($response->getBody(), $code);
 | 
			
		||||
            }
 | 
			
		||||
            return $response;
 | 
			
		||||
        } catch (Exception $e) {
 | 
			
		||||
            throw new OAuthClientException($e->getMessage(), $e->getCode());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								plugins/ActivitySpam/spamnoticestream.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								plugins/ActivitySpam/spamnoticestream.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * StatusNet - the distributed open-source microblogging tool
 | 
			
		||||
 * Copyright (C) 2012, StatusNet, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * Spam notice stream
 | 
			
		||||
 * 
 | 
			
		||||
 * PHP version 5
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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.
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * @category  Spam
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2012 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
if (!defined('STATUSNET')) {
 | 
			
		||||
    // This check helps protect against security problems;
 | 
			
		||||
    // your code file can't be executed directly from the web.
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Spam notice stream
 | 
			
		||||
 *
 | 
			
		||||
 * @category  Spam
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2012 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class SpamNoticeStream extends ScopingNoticeStream
 | 
			
		||||
{
 | 
			
		||||
    function __construct($tag, $profile = -1)
 | 
			
		||||
    {
 | 
			
		||||
        if (is_int($profile) && $profile == -1) {
 | 
			
		||||
            $profile = Profile::current();
 | 
			
		||||
        }
 | 
			
		||||
        parent::__construct(new CachingNoticeStream(new RawSpamNoticeStream(),
 | 
			
		||||
                                                    'spam_score:notice_ids'));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Raw stream of spammy notices
 | 
			
		||||
 *
 | 
			
		||||
 * @category  Stream
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2011 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class RawSpamNoticeStream extends NoticeStream
 | 
			
		||||
{
 | 
			
		||||
    function getNoticeIds($offset, $limit, $since_id, $max_id)
 | 
			
		||||
    {
 | 
			
		||||
        $ss = new Spam_score();
 | 
			
		||||
 | 
			
		||||
        $ss->is_spam = 1;
 | 
			
		||||
 | 
			
		||||
        $ss->selectAdd();
 | 
			
		||||
        $ss->selectAdd('notice_id');
 | 
			
		||||
 | 
			
		||||
        Notice::addWhereSinceId($ss, $since_id, 'notice_id');
 | 
			
		||||
        Notice::addWhereMaxId($ss, $max_id, 'notice_id');
 | 
			
		||||
 | 
			
		||||
        $ss->orderBy('notice_created DESC, notice_id DESC');
 | 
			
		||||
 | 
			
		||||
        if (!is_null($offset)) {
 | 
			
		||||
            $ss->limit($offset, $limit);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $ids = array();
 | 
			
		||||
 | 
			
		||||
        if ($ss->find()) {
 | 
			
		||||
            while ($ss->fetch()) {
 | 
			
		||||
                $ids[] = $ss->notice_id;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $ids;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										155
									
								
								plugins/ActivitySpam/train.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								plugins/ActivitySpam/train.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * StatusNet - the distributed open-source microblogging tool
 | 
			
		||||
 * Copyright (C) 2012, StatusNet, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * Train a notice as spam
 | 
			
		||||
 * 
 | 
			
		||||
 * PHP version 5
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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.
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * @category  Spam
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2012 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
if (!defined('STATUSNET')) {
 | 
			
		||||
    // This check helps protect against security problems;
 | 
			
		||||
    // your code file can't be executed directly from the web.
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Train a notice as spam
 | 
			
		||||
 *
 | 
			
		||||
 * @category  Spam
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2012 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class TrainAction extends Action
 | 
			
		||||
{
 | 
			
		||||
    protected $notice = null;
 | 
			
		||||
    protected $filter = null;
 | 
			
		||||
    protected $category = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * For initializing members of the class.
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $argarray misc. arguments
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean true
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function prepare($argarray)
 | 
			
		||||
    {
 | 
			
		||||
        parent::prepare($argarray);
 | 
			
		||||
 | 
			
		||||
        // User must be logged in.
 | 
			
		||||
 | 
			
		||||
        $user = common_current_user();
 | 
			
		||||
 | 
			
		||||
        if (empty($user)) {
 | 
			
		||||
            throw new ClientException(_("You must be logged in to train spam."), 403);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // User must have the right to review spam
 | 
			
		||||
 | 
			
		||||
        if (!$user->hasRight(ActivitySpamPlugin::TRAINSPAM)) {
 | 
			
		||||
            throw new ClientException(_('You cannot review spam on this site.'), 403);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $id = $this->trimmed('notice');
 | 
			
		||||
 | 
			
		||||
        $this->notice = Notice::staticGet('id', $id);
 | 
			
		||||
 | 
			
		||||
        if (empty($this->notice)) {
 | 
			
		||||
            throw new ClientException(_("No such notice."));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->checkSessionToken();
 | 
			
		||||
 | 
			
		||||
        $filter = null;
 | 
			
		||||
 | 
			
		||||
        Event::handle('GetSpamFilter', array(&$filter));
 | 
			
		||||
 | 
			
		||||
        if (empty($filter)) {
 | 
			
		||||
            throw new ServerException(_("No spam filter configured."));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->filter = $filter;
 | 
			
		||||
 | 
			
		||||
        $this->category = $this->trimmed('category');
 | 
			
		||||
 | 
			
		||||
        if ($this->category !== SpamFilter::SPAM &&
 | 
			
		||||
            $this->category !== SpamFilter::HAM)
 | 
			
		||||
        {
 | 
			
		||||
            throw new ClientException(_("No such category."));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handler method
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $argarray is ignored since it's now passed in in prepare()
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function handle($argarray=null)
 | 
			
		||||
    {
 | 
			
		||||
        // Train
 | 
			
		||||
 | 
			
		||||
        $this->filter->trainOnError($this->notice, $this->category);
 | 
			
		||||
 | 
			
		||||
        // Re-test
 | 
			
		||||
 | 
			
		||||
        $result = $this->filter->test($this->notice);
 | 
			
		||||
 | 
			
		||||
        // Update or insert
 | 
			
		||||
 | 
			
		||||
        $score = Spam_score::save($this->notice, $result);
 | 
			
		||||
 | 
			
		||||
        // Show new toggle form
 | 
			
		||||
 | 
			
		||||
        if ($this->category === SpamFilter::SPAM) {
 | 
			
		||||
            $form = new TrainHamForm($this, $this->notice);
 | 
			
		||||
        } else {
 | 
			
		||||
            $form = new TrainSpamForm($this, $this->notice);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($this->boolean('ajax')) {
 | 
			
		||||
            $this->startHTML('text/xml;charset=utf-8');
 | 
			
		||||
            $this->elementStart('head');
 | 
			
		||||
            // TRANS: Page title for page on which favorite notices can be unfavourited.
 | 
			
		||||
            $this->element('title', null, _('Disfavor favorite.'));
 | 
			
		||||
            $this->elementEnd('head');
 | 
			
		||||
            $this->elementStart('body');
 | 
			
		||||
            $form->show();
 | 
			
		||||
            $this->elementEnd('body');
 | 
			
		||||
            $this->elementEnd('html');
 | 
			
		||||
        } else {
 | 
			
		||||
            common_redirect(common_local_url('spam'), 303);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										146
									
								
								plugins/ActivitySpam/trainhamform.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								plugins/ActivitySpam/trainhamform.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,146 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * StatusNet - the distributed open-source microblogging tool
 | 
			
		||||
 * Copyright (C) 2011, StatusNet, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * Toggle indicating spam, click to train as ham
 | 
			
		||||
 * 
 | 
			
		||||
 * PHP version 5
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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.
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * @category  Spam
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2011 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
if (!defined('STATUSNET')) {
 | 
			
		||||
    // This check helps protect against security problems;
 | 
			
		||||
    // your code file can't be executed directly from the web.
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Form 
 | 
			
		||||
 *
 | 
			
		||||
 * @category  Spam
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2011 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class TrainHamForm extends Form {
 | 
			
		||||
 | 
			
		||||
    var $notice  = null;
 | 
			
		||||
 | 
			
		||||
    function __construct($out, $notice) {
 | 
			
		||||
        parent::__construct($out);
 | 
			
		||||
        $this->notice = $notice;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Name of the form
 | 
			
		||||
     *
 | 
			
		||||
     * Sub-classes should overload this with the name of their form.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function formLegend()
 | 
			
		||||
    {
 | 
			
		||||
        return _("Train ham");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Visible or invisible data elements
 | 
			
		||||
     *
 | 
			
		||||
     * Display the form fields that make up the data of the form.
 | 
			
		||||
     * Sub-classes should overload this to show their data.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function formData()
 | 
			
		||||
    {
 | 
			
		||||
        $this->hidden('notice', $this->notice->id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Buttons for form actions
 | 
			
		||||
     *
 | 
			
		||||
     * Submit and cancel buttons (or whatever)
 | 
			
		||||
     * Sub-classes should overload this to show their own buttons.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function formActions()
 | 
			
		||||
    {
 | 
			
		||||
        $this->submit('train-ham-submit-' . $this->notice->id,
 | 
			
		||||
                      _('Clear spam'),
 | 
			
		||||
                      'submit',
 | 
			
		||||
                      null,
 | 
			
		||||
                      _("Clear spam"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * ID of the form
 | 
			
		||||
     *
 | 
			
		||||
     * Should be unique on the page. Sub-classes should overload this
 | 
			
		||||
     * to show their own IDs.
 | 
			
		||||
     *
 | 
			
		||||
     * @return int ID of the form
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function id()
 | 
			
		||||
    {
 | 
			
		||||
        return 'train-ham-' . $this->notice->id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Action of the form.
 | 
			
		||||
     *
 | 
			
		||||
     * URL to post to. Should be overloaded by subclasses to give
 | 
			
		||||
     * somewhere to post to.
 | 
			
		||||
     *
 | 
			
		||||
     * @return string URL to post to
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function action()
 | 
			
		||||
    {
 | 
			
		||||
        return common_local_url('train', array('category' => 'ham'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Class of the form. May include space-separated list of multiple classes.
 | 
			
		||||
     *
 | 
			
		||||
     * If 'ajax' is included, the form will automatically be submitted with
 | 
			
		||||
     * an 'ajax=1' parameter added, and the resulting form or error message
 | 
			
		||||
     * will replace the form after submission.
 | 
			
		||||
     *
 | 
			
		||||
     * It's up to you to make sure that the target action supports this!
 | 
			
		||||
     *
 | 
			
		||||
     * @return string the form's class
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function formClass()
 | 
			
		||||
    {
 | 
			
		||||
        return 'form-train-ham ajax';
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										146
									
								
								plugins/ActivitySpam/trainspamform.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								plugins/ActivitySpam/trainspamform.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,146 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * StatusNet - the distributed open-source microblogging tool
 | 
			
		||||
 * Copyright (C) 2011, StatusNet, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * Toggle indicating ham, click to train as spam
 | 
			
		||||
 * 
 | 
			
		||||
 * PHP version 5
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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.
 | 
			
		||||
 *
 | 
			
		||||
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 * @category  Spam
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2011 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
if (!defined('STATUSNET')) {
 | 
			
		||||
    // This check helps protect against security problems;
 | 
			
		||||
    // your code file can't be executed directly from the web.
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Form 
 | 
			
		||||
 *
 | 
			
		||||
 * @category  Spam
 | 
			
		||||
 * @package   StatusNet
 | 
			
		||||
 * @author    Evan Prodromou <evan@status.net>
 | 
			
		||||
 * @copyright 2011 StatusNet, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
 | 
			
		||||
 * @link      http://status.net/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class TrainSpamForm extends Form {
 | 
			
		||||
 | 
			
		||||
    var $notice  = null;
 | 
			
		||||
 | 
			
		||||
    function __construct($out, $notice) {
 | 
			
		||||
        parent::__construct($out);
 | 
			
		||||
        $this->notice = $notice;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Name of the form
 | 
			
		||||
     *
 | 
			
		||||
     * Sub-classes should overload this with the name of their form.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function formLegend()
 | 
			
		||||
    {
 | 
			
		||||
        return _("Train spam");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Visible or invisible data elements
 | 
			
		||||
     *
 | 
			
		||||
     * Display the form fields that make up the data of the form.
 | 
			
		||||
     * Sub-classes should overload this to show their data.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function formData()
 | 
			
		||||
    {
 | 
			
		||||
        $this->hidden('notice', $this->notice->id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Buttons for form actions
 | 
			
		||||
     *
 | 
			
		||||
     * Submit and cancel buttons (or whatever)
 | 
			
		||||
     * Sub-classes should overload this to show their own buttons.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function formActions()
 | 
			
		||||
    {
 | 
			
		||||
        $this->submit('train-spam-submit-' . $this->notice->id,
 | 
			
		||||
                      _('Train spam'),
 | 
			
		||||
                      'submit',
 | 
			
		||||
                      null,
 | 
			
		||||
                      _("Mark as spam"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * ID of the form
 | 
			
		||||
     *
 | 
			
		||||
     * Should be unique on the page. Sub-classes should overload this
 | 
			
		||||
     * to show their own IDs.
 | 
			
		||||
     *
 | 
			
		||||
     * @return int ID of the form
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function id()
 | 
			
		||||
    {
 | 
			
		||||
        return 'train-spam-' . $this->notice->id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Action of the form.
 | 
			
		||||
     *
 | 
			
		||||
     * URL to post to. Should be overloaded by subclasses to give
 | 
			
		||||
     * somewhere to post to.
 | 
			
		||||
     *
 | 
			
		||||
     * @return string URL to post to
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function action()
 | 
			
		||||
    {
 | 
			
		||||
        return common_local_url('train', array('category' => 'spam'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Class of the form. May include space-separated list of multiple classes.
 | 
			
		||||
     *
 | 
			
		||||
     * If 'ajax' is included, the form will automatically be submitted with
 | 
			
		||||
     * an 'ajax=1' parameter added, and the resulting form or error message
 | 
			
		||||
     * will replace the form after submission.
 | 
			
		||||
     *
 | 
			
		||||
     * It's up to you to make sure that the target action supports this!
 | 
			
		||||
     *
 | 
			
		||||
     * @return string the form's class
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function formClass()
 | 
			
		||||
    {
 | 
			
		||||
        return 'form-train-spam ajax';
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user