diff --git a/ActivitySpamPlugin.php b/ActivitySpamPlugin.php index 4dbd24c16a..b429a3ef9d 100644 --- a/ActivitySpamPlugin.php +++ b/ActivitySpamPlugin.php @@ -212,6 +212,8 @@ class ActivitySpamPlugin extends Plugin array('action' => 'train', 'category' => 'spam')); $m->connect('main/train/ham', array('action' => 'train', 'category' => 'ham')); + $m->connect('main/spam', + array('action' => 'spam')); return true; } @@ -223,6 +225,22 @@ class ActivitySpamPlugin extends Plugin 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', diff --git a/Spam_score.php b/Spam_score.php index d6a05e2261..36d172f396 100644 --- a/Spam_score.php +++ b/Spam_score.php @@ -79,7 +79,9 @@ class Spam_score extends Managed_DataObject $score->notice_created = $notice->created; $score->insert(); - + + self::blow('spam_score:notice_ids'); + return $score; } @@ -107,9 +109,18 @@ class Spam_score extends Managed_DataObject $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. */ diff --git a/spam.php b/spam.php new file mode 100644 index 0000000000..502e3776af --- /dev/null +++ b/spam.php @@ -0,0 +1,171 @@ +. + * + * @category Spam + * @package StatusNet + * @author Evan Prodromou + * @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 + * @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; + + /** + * 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); + } + + // It must be a "real" login, not saved cookie login + + if (!common_is_real_login()) { + common_set_returnto($this->selfUrl()); + if (Event::handle('RedirectToLogin', array($this, $user))) { + common_redirect(common_local_url('login'), 303); + return; + } + } + + // 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; + } +} diff --git a/spamnoticestream.php b/spamnoticestream.php new file mode 100644 index 0000000000..ffb8d08025 --- /dev/null +++ b/spamnoticestream.php @@ -0,0 +1,101 @@ +. + * + * @category Spam + * @package StatusNet + * @author Evan Prodromou + * @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 + * @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 + * @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; + } +}