diff --git a/docs/docs/configuration/client.rst b/docs/docs/configuration/client.rst index 3eece63..422ff5e 100644 --- a/docs/docs/configuration/client.rst +++ b/docs/docs/configuration/client.rst @@ -10,6 +10,7 @@ preferably in the script tag which embeds the JS: data-isso-css="true" data-isso-lang="ru" data-isso-reply-to-self="false" + data-isso-require-author="false" data-isso-require-email="false" data-isso-max-comments-top="10" data-isso-max-comments-nested="5" @@ -63,6 +64,11 @@ data-isso-reply-to-self Set to `true` when spam guard is configured with `reply-to-self = true`. +data-isso-require-author +------------------------ + +Set to `true` when spam guard is configured with `require-author = true`. + data-isso-require-email ----------------------- diff --git a/docs/docs/configuration/server.rst b/docs/docs/configuration/server.rst index 86d1b7f..cb39ccd 100644 --- a/docs/docs/configuration/server.rst +++ b/docs/docs/configuration/server.rst @@ -217,6 +217,7 @@ for IPv4, ``/48`` for IPv6). ratelimit = 2 direct-reply = 3 reply-to-self = false + require-author = false require-email = false enabled @@ -237,6 +238,12 @@ reply-to-self Do not forget to configure the client. +require-author + force commenters to enter a value into the author field. No validation is + performed on the provided value. + + Do not forget to configure the client accordingly. + require-email force commenters to enter a value into the email field. No validation is performed on the provided value. diff --git a/isso/db/spam.py b/isso/db/spam.py index 8a1c747..d198f6a 100644 --- a/isso/db/spam.py +++ b/isso/db/spam.py @@ -66,6 +66,10 @@ class Guard: if self.conf.getboolean("require-email") and not comment.get("email"): return False, "email address required but not provided" + # require author if :param:`require-author` is enabled + if self.conf.getboolean("require-author") and not comment.get("author"): + return False, "author address required but not provided" + return True, "" def _spam(self, uri, comment): diff --git a/isso/js/app/config.js b/isso/js/app/config.js index 35bf051..64a0700 100644 --- a/isso/js/app/config.js +++ b/isso/js/app/config.js @@ -6,6 +6,7 @@ define(function() { "lang": (navigator.language || navigator.userLanguage).split("-")[0], "reply-to-self": false, "require-email": false, + "require-author": false, "max-comments-top": "inf", "max-comments-nested": 5, "reveal-on-click": 5, diff --git a/isso/js/app/isso.js b/isso/js/app/isso.js index a46f43a..16557a6 100644 --- a/isso/js/app/isso.js +++ b/isso/js/app/isso.js @@ -30,6 +30,12 @@ define(["app/dom", "app/utils", "app/config", "app/api", "app/jade", "app/i18n", $("[name='email']", this).focus(); return false; } + if (config["require-author"] && + $("[name='author']", this).value.length <= 0) + { + $("[name='author']", this).focus(); + return false; + } return true; }; @@ -39,6 +45,12 @@ define(["app/dom", "app/utils", "app/config", "app/api", "app/jade", "app/i18n", $("[name='email']", el).placeholder.replace(/ \(.*\)/, ""); } + // author is not optional if this config parameter is set + if (config["require-author"]) { + $("[name='author']", el).placeholder = + $("[name='author']", el).placeholder.replace(/ \(.*\)/, ""); + } + // submit form, initialize optional fields with `null` and reset form. // If replied to a comment, remove form completely. $("[type=submit]", el).on("click", function() { diff --git a/isso/tests/test_guard.py b/isso/tests/test_guard.py index 8a050d9..fca932c 100644 --- a/isso/tests/test_guard.py +++ b/isso/tests/test_guard.py @@ -35,7 +35,8 @@ class TestGuard(unittest.TestCase): def setUp(self): self.path = tempfile.NamedTemporaryFile().name - def makeClient(self, ip, ratelimit=2, direct_reply=3, self_reply=False, require_email=False): + def makeClient(self, ip, ratelimit=2, direct_reply=3, self_reply=False, + require_email=False, require_author=False): conf = config.load(os.path.join(dist.location, "share", "isso.conf")) conf.set("general", "dbpath", self.path) @@ -45,6 +46,7 @@ class TestGuard(unittest.TestCase): conf.set("guard", "direct-reply", str(direct_reply)) conf.set("guard", "reply-to-self", "1" if self_reply else "0") conf.set("guard", "require-email", "1" if require_email else "0") + conf.set("guard", "require-author", "1" if require_author else "0") class App(Isso, core.Mixin): pass @@ -120,8 +122,8 @@ class TestGuard(unittest.TestCase): payload = lambda email: json.dumps({"text": "...", "email": email}) - client = self.makeClient("127.0.0.1", ratelimit=4, require_email=False) - client_strict = self.makeClient("127.0.0.2", ratelimit=4, require_email=True) + client = self.makeClient("127.0.0.1", ratelimit=4, require_email=False) + client_strict = self.makeClient("127.0.0.2", ratelimit=4, require_email=True) # if we don't require email self.assertEqual(client.post("/new?uri=test", data=payload("")).status_code, 201) @@ -130,3 +132,18 @@ class TestGuard(unittest.TestCase): # if we do require email self.assertEqual(client_strict.post("/new?uri=test", data=payload("")).status_code, 403) self.assertEqual(client_strict.post("/new?uri=test", data=payload("test@me.more")).status_code, 201) + + def testRequireAuthor(self): + + payload = lambda author: json.dumps({"text": "...", "author": author}) + + client = self.makeClient("127.0.0.1", ratelimit=4, require_author=False) + client_strict = self.makeClient("127.0.0.2", ratelimit=4, require_author=True) + + # if we don't require author + self.assertEqual(client.post("/new?uri=test", data=payload("")).status_code, 201) + self.assertEqual(client.post("/new?uri=test", data=payload("pipo author")).status_code, 201) + + # if we do require author + self.assertEqual(client_strict.post("/new?uri=test", data=payload("")).status_code, 403) + self.assertEqual(client_strict.post("/new?uri=test", data=payload("pipo author")).status_code, 201)