You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by ke...@apache.org on 2019/05/22 13:38:31 UTC

[allura] branch master updated (3a58cb4 -> d2b7b00)

This is an automated email from the ASF dual-hosted git repository.

kentontaylor pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/allura.git.


    from 3a58cb4  [#8287] script to backfill previous_login_details
     new fe5de83  [#8265] avoid potential network errors during AkismetSpamFilter setup; errors within check() are already handled
     new 6cd836a  [#8265] avoid persisting tickets with None values, if error happened after new()
     new 8cf7aa2  [#8265] remove mollom plugin (service no longer exists)
     new 0fd2406  [#8265] upgrade akismet library.  Send timestamps, original IP, make permalink a full url
     new d2b7b00  [#8265] when undoing a spam, report it as ham.  Show a message if something failed

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 Allura/allura/controllers/discuss.py              |   2 +
 Allura/allura/lib/spam/__init__.py                |   1 +
 Allura/allura/lib/spam/akismetfilter.py           |  69 +++++++++------
 Allura/allura/lib/spam/mollomfilter.py            |  92 --------------------
 Allura/allura/lib/widgets/resources/js/post.js    |  10 ++-
 Allura/allura/tests/unit/spam/test_akismet.py     |  66 +++++++++-----
 Allura/allura/tests/unit/spam/test_mollom.py      | 100 ----------------------
 Allura/allura/tests/unit/spam/test_spam_filter.py |   2 +-
 Allura/development.ini                            |   5 +-
 Allura/setup.py                                   |   1 -
 ForgeTracker/forgetracker/model/ticket.py         |  27 ++++--
 ForgeTracker/forgetracker/tracker_main.py         |   5 +-
 requirements-optional.txt                         |   5 +-
 13 files changed, 126 insertions(+), 259 deletions(-)
 delete mode 100644 Allura/allura/lib/spam/mollomfilter.py
 delete mode 100644 Allura/allura/tests/unit/spam/test_mollom.py


[allura] 05/05: [#8265] when undoing a spam, report it as ham. Show a message if something failed

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kentontaylor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/allura.git

commit d2b7b002bd92d82eb1ba53ea02425e1a882dc27c
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Fri May 17 11:53:19 2019 -0400

    [#8265] when undoing a spam, report it as ham.  Show a message if something failed
---
 Allura/allura/controllers/discuss.py           |  2 ++
 Allura/allura/lib/widgets/resources/js/post.js | 10 ++++++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py
index 52a1b3c..7a38484 100644
--- a/Allura/allura/controllers/discuss.py
+++ b/Allura/allura/controllers/discuss.py
@@ -429,6 +429,8 @@ class PostController(BaseController):
             self.post.spam()
         elif kw.pop('undo', None):
             prev_status = kw.pop('prev_status', None)
+            if self.post.status == 'spam' and prev_status == 'ok':
+                g.spam_checker.submit_ham(self.post.text, artifact=self.post, user=self.post.author())
             self.post.undo(prev_status)
         elif kw.pop('approve', None):
             if self.post.status != 'ok':
diff --git a/Allura/allura/lib/widgets/resources/js/post.js b/Allura/allura/lib/widgets/resources/js/post.js
index a4811dd..1da44aa 100644
--- a/Allura/allura/lib/widgets/resources/js/post.js
+++ b/Allura/allura/lib/widgets/resources/js/post.js
@@ -51,7 +51,10 @@
                     else if (mod == 'Undo'){
                         spam_block_display($(post), 'hide_spam');
                     }
-                }
+                },
+                error: function() {
+                    flash('Oops, something went wrong.', 'error')
+                },
             });
         });
 
@@ -80,7 +83,10 @@
                     } else {
                         flash('Error.  Make sure you are logged in still.', 'error');
                     }
-                }
+                },
+                error: function() {
+                    flash('Oops, something went wrong.', 'error')
+                },
             });
         });
 


[allura] 04/05: [#8265] upgrade akismet library. Send timestamps, original IP, make permalink a full url

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kentontaylor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 0fd2406ca95b046eb8dd3f9e908ac2041d9583a8
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Fri May 17 11:45:13 2019 -0400

    [#8265] upgrade akismet library.  Send timestamps, original IP, make permalink a full url
---
 Allura/allura/lib/spam/akismetfilter.py       | 68 +++++++++++++++++----------
 Allura/allura/tests/unit/spam/test_akismet.py | 66 +++++++++++++++++---------
 requirements-optional.txt                     |  2 +-
 3 files changed, 89 insertions(+), 47 deletions(-)

diff --git a/Allura/allura/lib/spam/akismetfilter.py b/Allura/allura/lib/spam/akismetfilter.py
index 0c8e0f3..e30f05e 100644
--- a/Allura/allura/lib/spam/akismetfilter.py
+++ b/Allura/allura/lib/spam/akismetfilter.py
@@ -34,6 +34,14 @@ except ImportError:
 log = logging.getLogger(__name__)
 
 
+if AKISMET_AVAILABLE:
+    class AkismetWithoutStartupVerify(akismet.Akismet):
+        def __init__(self, key=None, blog_url=None):
+            # avoid possible errors at instantiation time, will encounter them later
+            self.api_key = key
+            self.blog_url = blog_url
+
+
 class AkismetSpamFilter(SpamFilter):
 
     """Spam checking implementation via Akismet service.
@@ -48,19 +56,27 @@ class AkismetSpamFilter(SpamFilter):
     def __init__(self, config):
         if not AKISMET_AVAILABLE:
             raise ImportError('akismet not available')
-        self.service = akismet.Akismet(
-            config.get('spam.key'), config.get('base_url'))
+        self.service = AkismetWithoutStartupVerify(config['spam.key'], config['base_url'])
 
     def get_data(self, text, artifact=None, user=None, content_type='comment', request=None, **kw):
+        # Docs: https://akismet.com/development/api/
         kw['comment_content'] = text
         kw['comment_type'] = content_type
         if artifact:
             try:
                 # if its a comment, get wiki, ticket, etc URL
                 url = artifact.main_url()
-            except:
+            except Exception:
                 url = artifact.url()
-            kw['permalink'] = url
+            kw['permalink'] = h.absurl(url)
+            if hasattr(artifact, 'timestamp'):
+                # Message & Post objects
+                date_created = artifact.timestamp
+            else:
+                # fallback for other artifacts, not exactly "created" date though
+                date_created = artifact.mod_date
+            kw['comment_date_gmt'] = date_created.isoformat()
+            kw['comment_post_modified_gmt'] = artifact.primary().mod_date.isoformat()
         user = user or c.user
         if user:
             kw['comment_author'] = user.display_name or user.username
@@ -69,35 +85,39 @@ class AkismetSpamFilter(SpamFilter):
             kw['user_ip'] = utils.ip_address(request)
             kw['user_agent'] = request.headers.get('USER_AGENT')
             kw['referrer'] = request.headers.get('REFERER')
+        else:
+            # these are required fields, but for ham/spam reports we don't have the original values to send :/
+            kw['user_ip'] = None
+            kw['user_agent'] = None
+            if artifact and hasattr(artifact, 'get_version'):  # VersionedArtifacts (includes comment posts)
+                try:
+                    kw['user_ip'] = artifact.get_version(1).author.logged_ip
+                except IndexError:
+                    log.debug("couldn't get Snapshot for this artifact %s", artifact)
+
         # kw will be urlencoded, need to utf8-encode
         for k, v in kw.items():
             kw[k] = h.really_unicode(v).encode('utf8')
         return kw
 
     def check(self, text, artifact=None, user=None, content_type='comment', **kw):
-        res = self.service.comment_check(text,
-                                         data=self.get_data(text=text,
-                                                            artifact=artifact,
-                                                            user=user,
-                                                            content_type=content_type,
-                                                            request=request,
-                                                            ),
-                                         build_data=False)
+        res = self.service.comment_check(**self.get_data(text=text,
+                                                         artifact=artifact,
+                                                         user=user,
+                                                         content_type=content_type,
+                                                         request=request,
+                                                         ))
         self.record_result(res, artifact, user)
         return res
 
     def submit_spam(self, text, artifact=None, user=None, content_type='comment'):
-        self.service.submit_spam(text,
-                                 data=self.get_data(text=text,
-                                                    artifact=artifact,
-                                                    user=user,
-                                                    content_type=content_type),
-                                 build_data=False)
+        self.service.submit_spam(**self.get_data(text=text,
+                                                 artifact=artifact,
+                                                 user=user,
+                                                 content_type=content_type))
 
     def submit_ham(self, text, artifact=None, user=None, content_type='comment'):
-        self.service.submit_ham(text,
-                                data=self.get_data(text=text,
-                                                   artifact=artifact,
-                                                   user=user,
-                                                   content_type=content_type),
-                                build_data=False)
+        self.service.submit_ham(**self.get_data(text=text,
+                                                artifact=artifact,
+                                                user=user,
+                                                content_type=content_type))
diff --git a/Allura/allura/tests/unit/spam/test_akismet.py b/Allura/allura/tests/unit/spam/test_akismet.py
index 17e6b51..f089303 100644
--- a/Allura/allura/tests/unit/spam/test_akismet.py
+++ b/Allura/allura/tests/unit/spam/test_akismet.py
@@ -21,6 +21,7 @@
 import mock
 import unittest
 import urllib
+from datetime import datetime
 
 from bson import ObjectId
 
@@ -32,17 +33,28 @@ class TestAkismet(unittest.TestCase):
 
     @mock.patch('allura.lib.spam.akismetfilter.akismet')
     def setUp(self, akismet_lib):
-        self.akismet = AkismetSpamFilter({})
+        self.akismet = AkismetSpamFilter({'spam.key': 'example', 'base_url': 'http://localhost/'})
 
         def side_effect(*args, **kw):
             # side effect to test that data being sent to
             # akismet can be successfully urlencoded
             urllib.urlencode(kw.get('data', {}))
         self.akismet.service.comment_check = mock.Mock(side_effect=side_effect)
+        self.akismet.service.submit_spam = mock.Mock(side_effect=side_effect)
+        self.akismet.service.submit_ham = mock.Mock(side_effect=side_effect)
         self.fake_artifact = mock.Mock(**{
-            'main_url.return_value': 'artifact url',
+            'main_url.return_value': '/artifact-url',
             'project_id': ObjectId(),
             'ref': None,
+            'timestamp': datetime(2019, 5, 17),
+            'primary.return_value': mock.Mock(
+                mod_date=datetime(2019, 5, 17, 0, 5, 1)
+            ),
+            'get_version.return_value': mock.Mock(
+                author=mock.Mock(
+                    logged_ip='33.4.5.66',
+                )
+            ),
         })
         self.fake_user = mock.Mock(display_name=u'Søme User',
                                    email_addresses=['user@domain'],
@@ -66,9 +78,7 @@ class TestAkismet(unittest.TestCase):
         c.user = None
         self.akismet.service.comment_check.side_effect({'side_effect': ''})
         self.akismet.check(self.content)
-        self.akismet.service.comment_check.assert_called_once_with(
-            self.content,
-            data=self.expected_data, build_data=False)
+        self.akismet.service.comment_check.assert_called_once_with(**self.expected_data)
 
     @mock.patch('allura.lib.spam.akismetfilter.c')
     @mock.patch('allura.lib.spam.akismetfilter.request')
@@ -78,9 +88,7 @@ class TestAkismet(unittest.TestCase):
         c.user = None
         self.akismet.check(self.content, content_type='some content type')
         self.expected_data['comment_type'] = 'some content type'
-        self.akismet.service.comment_check.assert_called_once_with(
-            self.content,
-            data=self.expected_data, build_data=False)
+        self.akismet.service.comment_check.assert_called_once_with(**self.expected_data)
 
     @mock.patch('allura.lib.spam.akismetfilter.c')
     @mock.patch('allura.lib.spam.akismetfilter.request')
@@ -90,10 +98,10 @@ class TestAkismet(unittest.TestCase):
         c.user = None
         self.akismet.check(self.content, artifact=self.fake_artifact)
         expected_data = self.expected_data
-        expected_data['permalink'] = 'artifact url'
-        self.akismet.service.comment_check.assert_called_once_with(
-            self.content,
-            data=expected_data, build_data=False)
+        expected_data['permalink'] = 'http://localhost/artifact-url'
+        expected_data['comment_date_gmt'] = '2019-05-17T00:00:00'
+        expected_data['comment_post_modified_gmt'] = '2019-05-17T00:05:01'
+        self.akismet.service.comment_check.assert_called_once_with(**expected_data)
 
     @mock.patch('allura.lib.spam.akismetfilter.c')
     @mock.patch('allura.lib.spam.akismetfilter.request')
@@ -105,9 +113,7 @@ class TestAkismet(unittest.TestCase):
         expected_data = self.expected_data
         expected_data.update(comment_author=u'Søme User'.encode('utf8'),
                              comment_author_email='user@domain')
-        self.akismet.service.comment_check.assert_called_once_with(
-            self.content,
-            data=expected_data, build_data=False)
+        self.akismet.service.comment_check.assert_called_once_with(**expected_data)
 
     @mock.patch('allura.lib.spam.akismetfilter.c')
     @mock.patch('allura.lib.spam.akismetfilter.request')
@@ -119,9 +125,7 @@ class TestAkismet(unittest.TestCase):
         expected_data = self.expected_data
         expected_data.update(comment_author=u'Søme User'.encode('utf8'),
                              comment_author_email='user@domain')
-        self.akismet.service.comment_check.assert_called_once_with(
-            self.content,
-            data=expected_data, build_data=False)
+        self.akismet.service.comment_check.assert_called_once_with(**expected_data)
 
     @mock.patch('allura.lib.spam.akismetfilter.c')
     def test_submit_spam(self, c):
@@ -132,9 +136,10 @@ class TestAkismet(unittest.TestCase):
         # no IP addr, UA, etc, since this isn't the original request
         expected_data = dict(comment_content=u'spåm text'.encode('utf8'),
                              comment_type='comment',
+                             user_ip='',
+                             user_agent='',
                              )
-        self.akismet.service.submit_spam.assert_called_once_with(
-            self.content, data=expected_data, build_data=False)
+        self.akismet.service.submit_spam.assert_called_once_with(**expected_data)
 
     @mock.patch('allura.lib.spam.akismetfilter.c')
     def test_submit_ham(self, c):
@@ -145,6 +150,23 @@ class TestAkismet(unittest.TestCase):
         # no IP addr, UA, etc, since this isn't the original request
         expected_data = dict(comment_content=u'spåm text'.encode('utf8'),
                              comment_type='comment',
+                             user_ip='',
+                             user_agent='',
                              )
-        self.akismet.service.submit_ham.assert_called_once_with(
-            self.content, data=expected_data, build_data=False)
+        self.akismet.service.submit_ham.assert_called_once_with(**expected_data)
+
+    @mock.patch('allura.lib.spam.akismetfilter.c')
+    def test_submit_ham_with_artifact(self, c):
+        c.user = None
+
+        self.akismet.submit_ham(self.content, artifact=self.fake_artifact)
+
+        expected_data = dict(comment_content=u'spåm text'.encode('utf8'),
+                             comment_type='comment',
+                             user_ip='33.4.5.66',
+                             user_agent='',
+                             permalink='http://localhost/artifact-url',
+                             comment_date_gmt='2019-05-17T00:00:00',
+                             comment_post_modified_gmt='2019-05-17T00:05:01',
+                             )
+        self.akismet.service.submit_ham.assert_called_once_with(**expected_data)
diff --git a/requirements-optional.txt b/requirements-optional.txt
index aa64970..2da797a 100644
--- a/requirements-optional.txt
+++ b/requirements-optional.txt
@@ -13,7 +13,7 @@
 MySQL-python  # GPL
 
 # for spam checking
-akismet==0.2.0
+akismet==1.0.1
 
 # faster charset detection
 cchardet==2.1.1  # GPL
\ No newline at end of file


[allura] 02/05: [#8265] avoid persisting tickets with None values, if error happened after new()

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kentontaylor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 6cd836a5522111eb5721254db902675afd5d507f
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Thu May 16 17:21:22 2019 -0400

    [#8265] avoid persisting tickets with None values, if error happened after new()
---
 ForgeTracker/forgetracker/model/ticket.py | 27 ++++++++++++++++++++-------
 ForgeTracker/forgetracker/tracker_main.py |  5 +++--
 2 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py
index 9d5611c..fc30b87 100644
--- a/ForgeTracker/forgetracker/model/ticket.py
+++ b/ForgeTracker/forgetracker/model/ticket.py
@@ -664,14 +664,16 @@ class Ticket(VersionedArtifact, ActivityObject, VotableArtifact):
         return d
 
     @classmethod
-    def new(cls):
-        '''Create a new ticket, safely (ensuring a unique ticket_num'''
+    def new(cls, form_fields=None):
+        '''Create a new ticket, safely (ensuring a unique ticket_num)'''
         while True:
             ticket_num = c.app.globals.next_ticket_num()
             ticket = cls(
                 app_config_id=c.app.config._id,
                 custom_fields=dict(),
                 ticket_num=ticket_num)
+            if form_fields:
+                ticket.update_fields_basics(form_fields)
             try:
                 session(ticket).flush(ticket)
                 h.log_action(log, 'opened').info('')
@@ -953,10 +955,11 @@ class Ticket(VersionedArtifact, ActivityObject, VotableArtifact):
             return 'nobody'
         return who.get_pref('display_name')
 
-    def update(self, ticket_form):
+    def update_fields_basics(self, ticket_form):
+        # "simple", non-persisting updates.  Must be safe to call within the Ticket.new() while its creating it
+
         # update is not allowed to change the ticket_num
         ticket_form.pop('ticket_num', None)
-        subscribe = ticket_form.pop('subscribe', False)
         self.labels = ticket_form.pop('labels', [])
         custom_users = set()
         other_custom_fields = set()
@@ -973,15 +976,15 @@ class Ticket(VersionedArtifact, ActivityObject, VotableArtifact):
             if 'custom_fields' not in ticket_form:
                 ticket_form['custom_fields'] = dict()
             ticket_form['custom_fields']['_milestone'] = milestone
-        attachment = None
-        if 'attachment' in ticket_form:
-            attachment = ticket_form.pop('attachment')
         for k, v in ticket_form.iteritems():
             if k == 'assigned_to':
                 if v:
                     user = c.project.user_in_project(v)
                     if user:
                         self.assigned_to_id = user._id
+            elif k in ('subscribe', 'attachment'):
+                # handled separately in update_fields_finish()
+                pass
             else:
                 setattr(self, k, v)
         if 'custom_fields' in ticket_form:
@@ -994,13 +997,23 @@ class Ticket(VersionedArtifact, ActivityObject, VotableArtifact):
                 elif k in other_custom_fields:
                     # strings are good enough for any other custom fields
                     self.custom_fields[k] = v
+
+    def update_fields_finish(self, ticket_form):
+        attachment = None
+        if 'attachment' in ticket_form:
+            attachment = ticket_form.pop('attachment')
         if attachment is not None:
             self.add_multiple_attachments(attachment)
             # flush the session to make attachments available in the
             # notification email
             ThreadLocalORMSession.flush_all()
+        subscribe = ticket_form.pop('subscribe', False)
         self.commit(subscribe=subscribe)
 
+    def update(self, ticket_form):
+        self.update_fields_basics(ticket_form)
+        self.update_fields_finish(ticket_form)
+
     def _move_attach(self, attachments, attach_metadata, app_config):
         for attach in attachments:
             attach.app_config_id = app_config._id
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 1be5070..d2c567e 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -937,13 +937,14 @@ class RootController(BaseController, FeedController):
             if not ticket:
                 raise Exception('Ticket number not found.')
             require_access(ticket, 'update')
+            ticket.update_fields_basics(ticket_form)
         else:
             require_access(c.app, 'create')
             self.rate_limit(TM.Ticket, 'Ticket creation', redir='.')
-            ticket = TM.Ticket.new()
+            ticket = TM.Ticket.new(form_fields=ticket_form)
+        ticket.update_fields_finish(ticket_form)
         g.spam_checker.check(ticket_form['summary'] + u'\n' + ticket_form.get('description', ''), artifact=ticket,
                              user=c.user, content_type='ticket')
-        ticket.update(ticket_form)
         c.app.globals.invalidate_bin_counts()
         g.director.create_activity(c.user, 'created', ticket,
                                    related_nodes=[c.project], tags=['ticket'])


[allura] 03/05: [#8265] remove mollom plugin (service no longer exists)

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kentontaylor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/allura.git

commit 8cf7aa29a7a6782f688dfd253de1c2cadfa59abb
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Thu May 16 17:20:41 2019 -0400

    [#8265] remove mollom plugin (service no longer exists)
---
 Allura/allura/lib/spam/mollomfilter.py       |  92 ------------------------
 Allura/allura/tests/unit/spam/test_mollom.py | 100 ---------------------------
 Allura/development.ini                       |   5 +-
 Allura/setup.py                              |   1 -
 requirements-optional.txt                    |   3 +-
 5 files changed, 2 insertions(+), 199 deletions(-)

diff --git a/Allura/allura/lib/spam/mollomfilter.py b/Allura/allura/lib/spam/mollomfilter.py
deleted file mode 100644
index ddd2e86..0000000
--- a/Allura/allura/lib/spam/mollomfilter.py
+++ /dev/null
@@ -1,92 +0,0 @@
-#       Licensed to the Apache Software Foundation (ASF) under one
-#       or more contributor license agreements.  See the NOTICE file
-#       distributed with this work for additional information
-#       regarding copyright ownership.  The ASF licenses this file
-#       to you under the Apache License, Version 2.0 (the
-#       "License"); you may not use this file except in compliance
-#       with the License.  You may obtain a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#       Unless required by applicable law or agreed to in writing,
-#       software distributed under the License is distributed on an
-#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#       KIND, either express or implied.  See the License for the
-#       specific language governing permissions and limitations
-#       under the License.
-
-import logging
-
-from tg import request
-from tg import tmpl_context as c
-
-from allura.lib import helpers as h
-from allura.lib import utils
-from allura.lib.spam import SpamFilter
-
-try:
-    import Mollom
-    MOLLOM_AVAILABLE = True
-except ImportError:
-    MOLLOM_AVAILABLE = False
-
-
-log = logging.getLogger(__name__)
-
-
-class MollomSpamFilter(SpamFilter):
-
-    """Spam checking implementation via Mollom service.
-
-    To enable Mollom spam filtering in your Allura instance, first pip install PyMollom (see requirements-optional.txt)
-    and then include the following parameters in your .ini file::
-
-        spam.method = mollom
-        spam.public_key = <your Mollom public key here>
-        spam.private_key = <your Mollom private key here>
-    """
-
-    def __init__(self, config):
-        if not MOLLOM_AVAILABLE:
-            raise ImportError('Mollom not available')
-        self.service = Mollom.MollomAPI(
-            publicKey=config.get('spam.public_key'),
-            privateKey=config.get('spam.private_key'))
-        if not self.service.verifyKey():
-            raise Mollom.MollomFault('Your MOLLOM credentials are invalid.')
-
-    def check(self, text, artifact=None, user=None, content_type='comment', **kw):
-        """Basic content spam check via Mollom. For more options
-        see http://mollom.com/api#api-content
-        """
-        log_msg = text
-        kw['postBody'] = text
-        if artifact:
-            try:
-                # if its a comment, get wiki, ticket, etc URL
-                url = artifact.main_url()
-            except:
-                url = artifact.url()
-            # Should be able to send url, but can't right now due to a bug in
-            # the PyMollom lib
-            # kw['url'] = url
-        user = user or c.user
-        if user:
-            kw['authorName'] = user.display_name or user.username
-            kw['authorMail'] = user.email_addresses[
-                0] if user.email_addresses else ''
-        kw['authorIP'] = utils.ip_address(request)
-        # kw will be urlencoded, need to utf8-encode
-        for k, v in kw.items():
-            kw[k] = h.really_unicode(v).encode('utf8')
-        cc = self.service.checkContent(**kw)
-        res = cc['spam'] == 2
-        artifact.spam_check_id = cc.get('session_id', '')
-        self.record_result(res, artifact, user)
-        return res
-
-    def submit_spam(self, text, artifact=None, user=None, content_type='comment', **kw):
-        self.service.sendFeedback(artifact.spam_check_id, 'spam')
-
-    def submit_ham(self, *args, **kw):
-        log.info("Mollom doesn't support reporting a ham")
diff --git a/Allura/allura/tests/unit/spam/test_mollom.py b/Allura/allura/tests/unit/spam/test_mollom.py
deleted file mode 100644
index 8a871f8..0000000
--- a/Allura/allura/tests/unit/spam/test_mollom.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# -*- coding: utf-8 -*-
-
-#       Licensed to the Apache Software Foundation (ASF) under one
-#       or more contributor license agreements.  See the NOTICE file
-#       distributed with this work for additional information
-#       regarding copyright ownership.  The ASF licenses this file
-#       to you under the Apache License, Version 2.0 (the
-#       "License"); you may not use this file except in compliance
-#       with the License.  You may obtain a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#       Unless required by applicable law or agreed to in writing,
-#       software distributed under the License is distributed on an
-#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#       KIND, either express or implied.  See the License for the
-#       specific language governing permissions and limitations
-#       under the License.
-
-
-import mock
-import unittest
-import urllib
-
-from bson import ObjectId
-
-from allura.lib.spam.mollomfilter import MOLLOM_AVAILABLE, MollomSpamFilter
-
-
-@unittest.skipIf(not MOLLOM_AVAILABLE, "Mollom not available")
-class TestMollom(unittest.TestCase):
-
-    @mock.patch('allura.lib.spam.mollomfilter.Mollom')
-    def setUp(self, mollom_lib):
-        self.mollom = MollomSpamFilter({})
-
-        def side_effect(*args, **kw):
-            # side effect to test that data being sent to
-            # mollom can be successfully urlencoded
-            urllib.urlencode(kw.get('data', {}))
-            return dict(spam=2)
-        self.mollom.service.checkContent = mock.Mock(side_effect=side_effect,
-                                                     return_value=dict(spam=2))
-        self.fake_artifact = mock.Mock(**{'url.return_value': 'artifact url'})
-        self.fake_user = mock.Mock(display_name=u'Søme User',
-                                   email_addresses=['user@domain'],
-                                   _id=ObjectId())
-        self.fake_headers = dict(
-            USER_AGENT='some browser',
-            REFERER='some url')
-        self.content = u'spåm text'
-        self.expected_data = dict(
-            postBody=self.content.encode('utf8'),
-            authorIP='some ip')
-        self.artifact = mock.Mock()
-        self.artifact.spam_check_id = 'test_id'
-        self.artifact.project_id = ObjectId()
-        self.artifact.ref = None
-
-    @mock.patch('allura.lib.spam.mollomfilter.c')
-    @mock.patch('allura.lib.spam.mollomfilter.request')
-    def test_check(self, request, c):
-        request.headers = self.fake_headers
-        request.remote_addr = 'some ip'
-        c.user = None
-        self.mollom.check(self.content, artifact=self.artifact)
-        self.mollom.service.checkContent.assert_called_once_with(
-            **self.expected_data)
-
-    @mock.patch('allura.lib.spam.mollomfilter.c')
-    @mock.patch('allura.lib.spam.mollomfilter.request')
-    def test_check_with_user(self, request, c):
-        request.headers = self.fake_headers
-        request.remote_addr = 'some ip'
-        c.user = None
-        self.mollom.check(self.content, user=self.fake_user,
-                          artifact=self.artifact)
-        expected_data = self.expected_data
-        expected_data.update(authorName=u'Søme User'.encode('utf8'),
-                             authorMail='user@domain')
-        self.mollom.service.checkContent.assert_called_once_with(
-            **self.expected_data)
-
-    @mock.patch('allura.lib.spam.mollomfilter.c')
-    @mock.patch('allura.lib.spam.mollomfilter.request')
-    def test_check_with_implicit_user(self, request, c):
-        request.headers = self.fake_headers
-        request.remote_addr = 'some ip'
-        c.user = self.fake_user
-        self.mollom.check(self.content, artifact=self.artifact)
-        expected_data = self.expected_data
-        expected_data.update(authorName=u'Søme User'.encode('utf8'),
-                             authorMail='user@domain')
-        self.mollom.service.checkContent.assert_called_once_with(
-            **self.expected_data)
-
-    def test_submit_spam(self):
-        self.mollom.submit_spam('test', artifact=self.artifact)
-        assert self.mollom.service.sendFeedback.call_args[0] == (
-            'test_id', 'spam'), self.mollom.service.sendFeedback.call_args[0]
diff --git a/Allura/development.ini b/Allura/development.ini
index 1ed3b7a..180736f 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -254,13 +254,10 @@ personal_dashboard_sections.order = activity, tickets, merge_requests, projects
 site_admin_project = allura
 site_admin_project_nbhd = Projects
 
-; Spam filtering service: this can be one or more of: mollom akismet stopforumspam
+; Spam filtering service: this can be one or more of: akismet stopforumspam
 ;spam.method = akismet
 ; for akismet:
 ;spam.key =
-; for mollom:
-;spam.public_key =
-;spam.private_key =
 ; for stopforumspam, should be a listed_ip_*_all.txt file
 ;spam.stopforumspam.ip_addr_file =
 ;spam.stopforumspam.threshold = 20
diff --git a/Allura/setup.py b/Allura/setup.py
index 4de3c6b..81133c9 100644
--- a/Allura/setup.py
+++ b/Allura/setup.py
@@ -109,7 +109,6 @@ setup(
 
     [allura.spam]
     akismet = allura.lib.spam.akismetfilter:AkismetSpamFilter
-    mollom = allura.lib.spam.mollomfilter:MollomSpamFilter
     stopforumspam = allura.lib.spam.stopforumspamfilter:StopForumSpamSpamFilter
 
     [allura.phone]
diff --git a/requirements-optional.txt b/requirements-optional.txt
index a94210b..aa64970 100644
--- a/requirements-optional.txt
+++ b/requirements-optional.txt
@@ -12,9 +12,8 @@
 -e git://github.com/zikzakmedia/python-mediawiki.git#egg=python-mediawiki   # GPL
 MySQL-python  # GPL
 
-# One or the other is required to enable spam checking
+# for spam checking
 akismet==0.2.0
-PyMollom==0.1  # GPL
 
 # faster charset detection
 cchardet==2.1.1  # GPL
\ No newline at end of file


[allura] 01/05: [#8265] avoid potential network errors during AkismetSpamFilter setup; errors within check() are already handled

Posted by ke...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kentontaylor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/allura.git

commit fe5de834633519659134b2c1a68540082ae86510
Author: Dave Brondsema <da...@brondsema.net>
AuthorDate: Thu May 16 16:55:45 2019 -0400

    [#8265] avoid potential network errors during AkismetSpamFilter setup; errors within check() are already handled
---
 Allura/allura/lib/spam/__init__.py                | 1 +
 Allura/allura/lib/spam/akismetfilter.py           | 1 -
 Allura/allura/tests/unit/spam/test_spam_filter.py | 2 +-
 3 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Allura/allura/lib/spam/__init__.py b/Allura/allura/lib/spam/__init__.py
index aaa4412..b51f20d 100644
--- a/Allura/allura/lib/spam/__init__.py
+++ b/Allura/allura/lib/spam/__init__.py
@@ -88,6 +88,7 @@ class ChainedSpamFilter(SpamFilter):
 
     def check(self, *a, **kw):
         for spam_filter in self.filters:
+            # note: SpamFilter.get() has wrapped all .check() functions with exceptionless
             if spam_filter.check(*a, **kw):
                 return True
         return False
diff --git a/Allura/allura/lib/spam/akismetfilter.py b/Allura/allura/lib/spam/akismetfilter.py
index 2ea4c13..0c8e0f3 100644
--- a/Allura/allura/lib/spam/akismetfilter.py
+++ b/Allura/allura/lib/spam/akismetfilter.py
@@ -50,7 +50,6 @@ class AkismetSpamFilter(SpamFilter):
             raise ImportError('akismet not available')
         self.service = akismet.Akismet(
             config.get('spam.key'), config.get('base_url'))
-        self.service.verify_key()
 
     def get_data(self, text, artifact=None, user=None, content_type='comment', request=None, **kw):
         kw['comment_content'] = text
diff --git a/Allura/allura/tests/unit/spam/test_spam_filter.py b/Allura/allura/tests/unit/spam/test_spam_filter.py
index d05fa97..607273d 100644
--- a/Allura/allura/tests/unit/spam/test_spam_filter.py
+++ b/Allura/allura/tests/unit/spam/test_spam_filter.py
@@ -106,7 +106,7 @@ class TestChainedSpamFilter(object):
         assert_equal(checker.filters[0].config, {'spam.method': 'mock1', 'spam.settingA': 'bcd'})
         assert_equal(checker.filters[1].config, {'spam.method': 'mock2', 'spam.settingA': 'bcd'})
 
-        assert checker.check()  # True because first filter errors out, and 2nd returns True
+        assert checker.check()  # first filter errors out (but ignored by `exceptionless`), and 2nd returns True
 
         checker.submit_spam('some text')
         checker.submit_ham('some text')