text: # -*- encoding: utf-8 -*-
  
  import time
  
  
  class Guard:
  
      def __init__(self, db):
  
          self.db = db
          self.conf = db.conf.section("guard")
          self.max_age = db.conf.getint("general", "max-age")
  
      def validate(self, uri, comment):
  
          if not self.conf.getboolean("enabled"):
              return True, ""
  
          for func in (self._limit, self._spam):
              valid, reason = func(uri, comment)
              if not valid:
                  return False, reason
          return True, ""
  
      @classmethod
      def ids(cls, rv):
          return [str(col[0]) for col in rv]
  
      def _limit(self, uri, comment):
  
          # block more than :param:`ratelimit` comments per minute
          rv = self.db.fetchall([
              'SELECT id FROM comments WHERE remote_addr = %s AND DATEDIFF(%s, created) < 60;'
          ], (comment["remote_addr"], time.time()))
  
          if len(rv) >= self.conf.getint("ratelimit"):
              return False, "{0}: ratelimit exceeded ({1})".format(
                  comment["remote_addr"], ', '.join(Guard.ids(rv)))
  
          # block more than three comments as direct response to the post
          if comment["parent"] is None:
              rv = self.db.fetchall([
                  'SELECT id FROM comments WHERE',
                  '    tid = (SELECT id FROM threads WHERE uri = %s)',
                  'AND remote_addr = %s',
                  'AND parent IS NULL;'
              ], (uri, comment["remote_addr"]))
  
              if len(rv) >= self.conf.getint("direct-reply"):
                  return False, "%i direct responses to %s" % (len(rv), uri)
  
          # block replies to self unless :param:`reply-to-self` is enabled
          elif self.conf.getboolean("reply-to-self") is False:
              rv = self.db.fetchall([
                  'SELECT id FROM comments WHERE'
                  '    remote_addr = %s',
                  'AND id = %s',
                  'AND DATEDIFF(%s, created) < %s'
              ], (comment["remote_addr"], comment["parent"],
                  time.time(), self.max_age))
  
              if len(rv) > 0:
                  return False, "edit time frame is still open"
  
          # require email if :param:`require-email` is enabled
          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):
          return True, ""
  