lib/defender.rb in defender-0.1.1 vs lib/defender.rb in defender-0.2.0
- old
+ new
@@ -1,299 +1,67 @@
-require 'yaml'
-require 'net/http'
+require 'httparty'
-class Defender
+require 'defender/document'
+require 'defender/statistics'
+
+module Defender
+ VERSION = "0.2.0"
+
+ include HTTParty
+
# The Defensio API version currently supported by Defender
- API_VERSION = "1.2"
-
- ROOT_URL = "http://api.defensio.com/"
-
- DEFAULT_OPTIONS = {
- :service_type => "blog",
- :api_key => "",
- :owner_url => ""
- }
-
- ##
- # Raised if an invalid or no API key is given
- class APIKeyError < StandardError; end
-
- ##
- # The response from the {Defender#audit_comment} method. Should only be
- # initialized by the library.
- class CommentResponse
+ API_VERSION = "2.0"
+
+ # HTTParty config
+ format :json
+ base_uri "api.defensio.com/#{API_VERSION}/users"
+
+ class << self
##
- # A message signature that uniquely identifies the comment in the Defensio
- # system. This signature should be stored by the client for retraining
- # purposes.
- attr_reader :signature
-
+ # Your Defensio API key. You need to register at defensio.com to get a key.
+ attr_accessor :api_key
+
##
- # A value indicating the relative likelihood of the comment being spam.
- # This value should be stored by the client for use in building convenient
- # spam sorting user-interfaces.
+ # The URL that will be called when Defensio is done analyzing a comment with
+ # asynchronous callbacks. You should be able to pass the request parameters
+ # straight into {Document#set_attributes}. The signature will be in the
+ # `signature` parameter.
#
- # @return [Float] A value between 0 and 1.
- attr_reader :spaminess
-
- ##
- # Initialize a CommentResponse. Should only be called by the library.
+ # *IMPORTANT*: Defensio will NOT retry unsuccessful callbacks to your
+ # server. If you do not see a POST originating from Defensio after 5
+ # minutes, call {Document#refresh!} on the document to obtain the analysis
+ # result.
#
- # @param [Hash] response The response from the audit-comment call.
- def initialize(response)
- @signature = response["signature"]
- @spam = response["spam"]
- @spaminess = response["spaminess"].to_f
- end
-
- ##
- # Returns true if Defensio marked the comment as spam, returns false
- # otherwise.
+ # Occasionally, Defensio may perform more than one POST request to your
+ # server for the same document. For example, if new evidence indicates that
+ # a document is unwanted, even though it was originally identified as
+ # legitimate, Defensio might notify you that the classification has changed.
#
- # @return [Boolean]
- def spam?; @spam; end
-
- def to_s; @signature; end
- end
-
- ##
- # The response from the {Defender#statistics} method. Should only be
- # initialized by the library.
- class Statistics
- ##
- # Describes the percentage of comments correctly identified as spam/ham by
- # Defensio on this blog.
+ # If you do not provide this and use asynchronous calling, you need to call
+ # {Document#refresh!} to get the analysis result.
#
- # @return [Float<0..1>]
- def accuracy; @response["accuracy"]; end
-
- ##
- # The number of spam comments caught by the filter.
- def spam; @response["spam"]; end
-
- ##
- # The number of ham (legitimate) comments accepted by the filter.
- def ham; @response["ham"]; end
-
- ##
- # The number of times a legitimate message was retrained from the spambox
- # (i.e. "de-spammed" by the user)
- def false_positives; @response["false-positives"]; end
-
- ##
- # The number of times a spam message was retrained from comments box (i.e.
- # "de-legitimized" by the user)
- def false_negatives; @response["false-negatives"]; end
-
- ##
- # A boolean value indicating whether Defensio is still in its initial
- # learning phase.
+ # You can debug callbacks using http://postbin.org. See the Defensio API
+ # documents for the format of the requests.
#
- # @return [Boolean]
- def learning; @response["learning"]; end
-
- ##
- # More details on the reason(s) why Defensio is still in its initial
- # learning phase.
- def learning_status; @response["learning-status"]; end
-
- def initialize(response); @response = response; end
+ # @return [String]
+ attr_accessor :async_callback
end
-
- attr_accessor :service_type, :api_key, :owner_url
-
- ##
- # Raises a StandardError with the error message from Defensio if the
- # response is a "failed" one.
- #
- # @param [Hash] response The return value from {#call_action}.
- def self.raise_if_error(response)
- if response["status"] == "fail"
- raise StandardError, response["message"]
- end
- response
- end
-
- ##
- # Converts a hash with symbol keys and underscores to a hash with string
- # keys and hyphens. Calls #strftime or #to_s on the values.
- #
- # @param [Hash] options Input options.
- # @return [Hash]
- def self.options_to_parameters(options)
- opts = {}
- options.each do |key, val|
- opts[key.to_s.gsub("_", "-").downcase] = val.respond_to?(:strftime) ?
- val.strftime("%Y/%m/%d") : val.to_s
- end
- opts
- end
##
- # Initialize Defender
+ # Determines if the given API key is valid or not. This should only be used
+ # when configuring the client and prior to every content analysis (Document
+ # POST).
#
- # @param [Hash] opts The options hash.
- # @option opts ["blog","app"] :service_type ("blog") The service type. May be
- # "app" (use of Defender within an application) or "blog" (use of Defender
- # to support a blogging platform).
- # @option opts [String] :api_key Your API key. This option is required, the
- # method calls will fail without it.
- def initialize(opts={})
- opts = DEFAULT_OPTIONS.merge(opts)
- @service_type = opts[:service_type]
- @api_key = opts[:api_key]
- @owner_url = opts[:owner_url]
- end
-
- ##
- # Checks if the given key is valid.
+ # Set the API key using {Defender.api_key}.
#
- # @return [Boolean]
- # @see http://defensio.com/api/#validate-key
- def valid_key?
- call_action("validate-key")["status"] == "success" ? true : false
- end
-
- ##
- # Announce an article existence. This should (if feasible) be called when an
- # article or blogpost is created so Defensio can analyse it.
- #
- # @param [Hash] opts All options are required.
- # @option opts [#to_s] :article_title The title of the article
- # @option opts [#to_s] :article_author The name of the author of the article
- # @option opts [#to_s] :article_author_email The email address of the person posting the
- # article.
- # @option opts [#to_s] :article_content The content of the article itself.
- # @option opts [#to_s] :permalink The permalink of the article just posted.
- # @raise [StandardError] If the call fails, a StandardError is raised with
- # the error message given from Defensio.
- # @return [Boolean] Returns true if the article was successfully announced,
- # raises StandardError otherwise.
- # @see http://defensio.com/api/#announce-article
- def announce_article(opts={})
- response = call_action(Defender.options_to_parameters(opts))
- true
- end
-
- ##
- # Check if a comment is spam. This is the central action of Defensio.
- #
- # @param [Hash] opts All options are recommended, but only required if noted.
- # @option opts [#to_s] :user_ip The IP address of whomever is posting the
- # comment. This option is required.
- # @option opts [#to_s, #strftime] :article_date The date the original blog
- # article was posted. If a string is given, it must be in the format
- # "yyyy/mm/dd". This option is required.
- # @option opts [#to_s] :comment_author The name of the author of the comment.
- # This option is required.
- # @option opts ["comment", "trackback", "pingback", "other"] :comment_type
- # The type of the comment being posted to the blog. This option is required
- # @option opts [#to_s] :comment_content The actual content of the comment
- # (strongly recommended to be included where ever possible).
- # @option opts [#to_s] :comment_author_email The email address of the person
- # posting the comment.
- # @option opts [#to_s] :comment_author_url The URL of the person posting the
- # comment.
- # @option opts [#to_s] :permalink The permalink of the blog post to which
- # the comment is being posted.
- # @option opts [#to_s] :referrer The URL of the site that brought commenter
- # to this page.
- # @option opts [Boolean] :user_logged_in Whether or not the user posting
- # the comment is logged-into the blogging platform
- # @option opts [Boolean] :trusted_user Whether or not the user is an
- # administrator, moderator or editor of this blog; the client should pass
- # true only if blogging platform can guarantee that the user has been
- # authenticated and has a role of responsibility on this blog.
- # @option opts [#to_s] :openid The OpenID URL of the currently logged in
- # user. Must be used in conjunction with :user_logged_in => true. OpenID
- # authentication must be taken care of by your application.
- # @option opts [#to_s] :test_force For testing purposes only: Use this
- # parameter to force the outcome of audit_comment. Optionally affix (with
- # a comma) a desired spaminess return value (in the range 0 to 1).
- # Example: "spam,0.5000" or "ham,0.0010".
- # @raise [StandardError] If the call fails, a StandardError is raised with
- # the error message given from Defensio.
- # @return [Defender::CommentResponse]
- # @see http://defensio.com/api/#audit-comment
- def audit_comment(opts={})
- response = call_action("audit-comment", Defender.options_to_parameters(opts))
- return CommentResponse.new(response)
- end
-
- ##
- # This action is used to retrain false negatives. False negatives are
- # comments that were originally tagged as "ham" (i.e. legitimate) but were
- # in fact spam.
- #
- # @param [Array<#to_s, CommentResponse>] signatures List of signatures (may
- # contain a single entry) of the comments to be submitted for retraining.
- # Note that a signature for each comment was originally provided by the
- # {#audit_comment} method.
- # @raise [StandardError] If the call fails, a StandardError is raised with
- # the error message given from Defensio.
- # @return [Boolean] Returns true if the comments were successfully marked,
- # raises StandardError otherwise.
- def report_false_negatives(signatures)
- report_false(:negatives, signatures)
- end
-
- ##
- # This action is used to retrain false negatives. False negatives are
- # comments that were originally tagged as spam but were in fact "ham" (i.e.
- # legitimate).
- #
- # @param [Array<#to_s, CommentResponse>] signatures List of signatures (may
- # contain a single entry) of the comments to be submitted for retraining.
- # Note that a signature for each comment was originally provided by the
- # {#audit_comment} method.
- # @raise [StandardError] If the call fails, a StandardError is raised with
- # the error message given from Defensio.
- # @return [Boolean] Returns true if the comments were successfully marked,
- # raises StandardError otherwise.
- def report_false_positives(signatures)
- report_false(:positives, signatures)
- end
-
- ##
- # This action returns basic statistics regarding the performance of Defensio
- # since activation.
- #
- # @return [Defender::Statistics]
- def statistics
- response = call_action("get-stats")
- return Statistics.new(response)
- end
-
- private
- def report_false(type, signatures)
- call_action("report-false-#{type}",
- "signatures" => signatures.join(","))
- true
+ # @return [Boolean] Whether the API key was valid or not.
+ def self.check_api_key
+ key = Defender.api_key
+ return false unless key
+ resp = get("/#{key}.json")['defensio-result']
+ if resp['status'] == 'success'
+ return true
+ else
+ return false
end
-
- ##
- # Returns the url for the given action.
- #
- # @param [#to_s] action The action to generate the URL for.
- # @return [String] The URL for the action.
- # @raise [APIKeyError] Raises this if no API key is given.
- def url(action)
- raise APIKeyError unless @api_key.length > 0
- "#{ROOT_URL}#{@service_type}/#{API_VERSION}/#{action}/#{@api_key}.yaml"
- end
-
- ##
- # Backend function for calling an action.
- #
- # @param [#to_s] action The action to call.
- # @param [Hash] params The parameters for the action.
- # @return [Hash] The raw response, only parsed from YAML.
- # @raise [APIKeyError] If an invalid (or no) API key is given, this is
- # raised
- def call_action(action, params={})
- response = Net::HTTP.post_form(URI.parse(url(action)),
- {"owner-url" => @owner_url}.merge(params))
- response.code == 401 ?
- raise(APIKeyError) :
- Defender.raise_if_error(YAML.load(response.body)["defensio-result"])
- end
+ end
end