require 'net/http' require 'uri' require 'set' # Akismet # # Author:: David Czarnecki # Copyright:: Copyright (c) 2005 - David Czarnecki # License:: BSD # # Rewritten to be more agnostic module Viking class Akismet < Base class << self attr_accessor :valid_responses, :normal_responses, :standard_headers, :host, :port end self.host = 'rest.akismet.com' self.port = 80 self.valid_responses = Set.new(['false', '']) self.normal_responses = valid_responses.dup << 'true' self.standard_headers = { 'User-Agent' => "Viking (Ruby Gem) v#{Viking::VERSION::STRING}", 'Content-Type' => 'application/x-www-form-urlencoded' } # Create a new instance of the Akismet class # # ==== Arguments # Arguments are provided in the form of a Hash with the following keys # (as Symbols) available: # # +api_key+:: your Akismet API key # +blog+:: the blog associated with your api key # # The following keys are available and are entirely optional. They are # available incase communication with Akismet's servers requires a # proxy port and/or host: # # * +proxy_port+ # * +proxy_host+ def initialize(options) super self.verified_key = false end # Returns +true+ if the API key has been verified, +false+ otherwise def verified? (@verified_key ||= verify_api_key) != :false end # This is basically the core of everything. This call takes a number of # arguments and characteristics about the submitted content and then # returns a thumbs up or thumbs down. Almost everything is optional, but # performance can drop dramatically if you exclude certain elements. # # ==== Arguments # +options+ :: describes the comment being verified # # The following keys are available for the +options+ hash: # # +user_ip+ (*required*):: # IP address of the comment submitter. # +user_agent+ (*required*):: # user agent information. # +referrer+ (note spelling):: # the content of the HTTP_REFERER header should be sent here. # +permalink+:: # permanent location of the entry the comment was submitted to # +comment_type+:: # may be blank, comment, trackback, pingback, or a made up value like # "registration". # +comment_author+:: # submitted name with the comment # +comment_author_email+:: # submitted email address # +comment_author_url+:: # commenter URL # +comment_content+:: # the content that was submitted # Other server enviroment variables:: # In PHP there is an array of enviroment variables called _SERVER # which contains information about the web server itself as well as a # key/value for every HTTP header sent with the request. This data is # highly useful to Akismet as how the submited content interacts with # the server can be very telling, so please include as much information # as possible. def check_comment(options={}) return false if invalid_options? message = call_akismet('comment-check', options) {:spam => !self.class.valid_responses.include?(message), :message => message} end # This call is for submitting comments that weren't marked as spam but # should have been (i.e. false negatives). It takes identical arguments as # +check_comment+. def mark_as_spam(options={}) return false if invalid_options? {:message => call_akismet('submit-spam', options)} end # This call is intended for the marking of false positives, things that # were incorrectly marked as spam. It takes identical arguments as # +check_comment+ and +mark_as_spam+. def mark_as_ham(options={}) return false if invalid_options? {:message => call_akismet('submit-ham', options)} end # Returns the URL for an Akismet request # # ==== Arguments # +action+ <~to_s>:: a valid Akismet function name # # ==== Returns # String def self.url(action) "/1.1/#{action}" end protected # Internal call to Akismet. Prepares the data for posting to the Akismet # service. # # ==== Arguments # +akismet_function+ :: # the Akismet function that should be called # # The following keys are available to configure a given call to Akismet: # # +user_ip+ (*required*):: # IP address of the comment submitter. # +user_agent+ (*required*):: # user agent information. # +referrer+ (note spelling):: # the content of the HTTP_REFERER header should be sent here. # +permalink+:: # the permanent location of the entry the comment was submitted to. # +comment_type+:: # may be blank, comment, trackback, pingback, or a made up value like # "registration". # +comment_author+:: # submitted name with the comment # +comment_author_email+:: # submitted email address # +comment_author_url+:: # commenter URL # +comment_content+:: # the content that was submitted # Other server enviroment variables:: # In PHP there is an array of enviroment variables called _SERVER # which contains information about the web server itself as well as a # key/value for every HTTP header sent with the request. This data is # highly useful to Akismet as how the submited content interacts with # the server can be very telling, so please include as much information # as possible. def call_akismet(akismet_function, options={}) http_post( Net::HTTP.new([options[:api_key], self.class.host].join("."), options[:proxy_host], options[:proxy_port]), akismet_function, options.update(:blog => options[:blog]).to_query ) end # Call to check and verify your API key. You may then call the # verified? method to see if your key has been validated def verify_api_key return :false if invalid_options? value = http_post( Net::HTTP.new(self.class.host, self.class.port, options[:proxy_host], options[:proxy_port]), 'verify-key', { :key => options[:api_key], :blog => options[:blog] }.to_query ) self.verified_key = (value == "valid") ? true : :false end def http_post(http, action, data) resp = http.post(self.url(action), data, self.class.standard_headers) log_request(self.url(action), data, resp) resp.body end def url(action) "/1.1/#{action}" end private attr_accessor :verified_key end end