ba-webby-pingback 1.0 → 1.0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.textile CHANGED
@@ -30,7 +30,7 @@ h2. Installation
30
30
 
31
31
  Install it through rubygems:
32
32
 
33
- @gem install ba-webby-pingback --source gems.github.com@
33
+ @gem install ba-webby-pingback --source http://gems.github.com@
34
34
 
35
35
  h3. Installing the sender
36
36
 
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby -w
2
+ # -*- coding: utf-8 -*-
3
+ $KCODE = 'u'
4
+
5
+ # This is just used to easily load the rakefile through includes instead of copying the file
6
+
7
+ load File.join(%W[#{File.dirname(File.expand_path(__FILE__))} .. tasks pingback.rake])
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ $KCODE = 'u'
4
+
5
+ require 'xmlrpc/server'
6
+ require 'webby-pingback'
7
+
8
+ s = XMLRPC::CGIServer.new
9
+ s.add_handler('pingback.ping') do |source, target|
10
+ pinger = Pingback::Receiver.new(source, target)
11
+ {:message => pinger.response_message}
12
+ end
13
+
14
+ s.set_default_handler do |name, *args|
15
+ raise XMLRPC::FaultException.new(-99, "Method #{name} missing or wrong number of parameters")
16
+ end
17
+
18
+ s.serve
19
+
@@ -0,0 +1,208 @@
1
+ #!/usr/bin/env ruby -w
2
+ # -*- coding: utf-8 -*-
3
+ $KCODE = 'u'
4
+
5
+ require 'uri'
6
+ require 'net/http'
7
+ require 'xmlrpc/client'
8
+ require 'open-uri'
9
+
10
+ require 'hpricot'
11
+ require 'amalgalite'
12
+ require 'json'
13
+
14
+ # This modules expects there to be a constant called Conf that is a
15
+ # hash with two values:
16
+ #
17
+ # :db:: Path to the SQLite database file
18
+ # :forum_api_key:: The Disqus forum api key to fetch the trackback url
19
+ #
20
+ module Pingback
21
+ # So we don't try to ping twice!
22
+ def self.toggle_trackback_done(filename, mode = true)
23
+ File.open(filename, 'r+') do |file|
24
+ pos = file.each_line do |line|
25
+ break pos if line.match(/^trackback_done: (\w+)/)
26
+ pos = file.pos
27
+ end
28
+
29
+ file.seek(pos + 16)
30
+ file.write(' true') # Has to be 5 chars to cover all of false :)
31
+ end
32
+ end
33
+
34
+ class Sender
35
+ # +source_url+ is the page that contains outgoing links.
36
+ # +urls+ are the links on that page. +urls+ can also be added dynamically
37
+ # by using +obj.urls << 'url'.
38
+ def initialize(source_url, urls = [])
39
+ @source_url = source_url
40
+ @urls = ([] << urls).flatten
41
+ end
42
+ attr_accessor :urls
43
+
44
+ # Tries to find a pingback url from a given URL. If found ping it.
45
+ def start(verbose = false)
46
+ @urls.each do |url|
47
+ pingback_url = find_pingback_url(url)
48
+ if pingback_url
49
+ send_ping(pingback_url, url)
50
+ end
51
+ end
52
+ end
53
+
54
+ # From a given URL try to find a pingback source from HTTP Header,
55
+ # if not found try to download the page and look for a
56
+ # <link rel="pingback"> element and use that.
57
+ def find_pingback_url(url)
58
+ res = fetch_pingback_url(url)
59
+ if res['X-Pingback'].nil?
60
+ res = fetch_pingback_url(url, :Get)
61
+ doc = Hpricot(res.body)
62
+ (doc/"//link[@rel='pingback']")[0]['href'] rescue false
63
+ else
64
+ res['X-Pingback']
65
+ end
66
+ end
67
+
68
+ private
69
+ # Connect to +url+ with HTTP-method +type+ and return the result-object.
70
+ def fetch_pingback_url(url, type = :Head)
71
+ uri = URI.parse url
72
+ Net::HTTP.start(uri.host, uri.port) do |http|
73
+ http.request(Net::HTTP.const_get(type).new(uri.path))
74
+ end
75
+ end
76
+
77
+ # Using the XML-RPC protocoll send a ping.
78
+ # +xmlrpc_uri+ is the XML-RPC endpoint
79
+ # +target+ is the url that we're linking to and want to tell the endpoint
80
+ def send_ping(xmlrpc_uri, target)
81
+ uri = URI.parse(xmlrpc_uri)
82
+ server = XMLRPC::Client.new(uri.host, uri.path, uri.port)
83
+ begin
84
+ result = server.call('pingback.ping',
85
+ @source_url,
86
+ target)
87
+ puts "#{uri.host}#{uri.path}: #{result['message']}"
88
+ rescue XMLRPC::FaultException => e
89
+ puts "#{uri.host}#{uri.path}: Error -- #{e.message}"
90
+ end
91
+ end
92
+ end # / Sender
93
+
94
+ class Receiver
95
+ def initialize(source, target)
96
+ @@db = Amalgalite::Database.new(Pingback::Conf[:db])
97
+ @@forum_api_key = Pingback::Conf[:forum_api_key]
98
+ @source = source
99
+ @target = target
100
+ @response_message = ''
101
+
102
+ db_schema
103
+ if pingback_exists?
104
+ @response_message = 'The pingback has already been registered'
105
+ return true
106
+ end
107
+
108
+ trackback_url = fetch_trackback_url()
109
+ if trackback_url.nil?
110
+ @response_message = 'The specified target URI cannot be used as a target.'
111
+ return false
112
+ end
113
+
114
+ trackback_data = fetch_source_data()
115
+ if trackback_data[:excerpt].empty?
116
+ @response_message = 'No link to target page!'
117
+ return false
118
+ end
119
+
120
+ send_trackback(trackback_url, trackback_data)
121
+ end
122
+ attr :response_message
123
+
124
+ private
125
+ def pingback_exists?
126
+ !@@db.execute('SELECT id FROM received_pingbacks
127
+ WHERE source_url = ?
128
+ AND target_url = ? ', @source, @target).empty?
129
+ end
130
+
131
+ # Looks for the link to the target page so we know it's not just a spambot
132
+ # trying to link us
133
+ def fetch_source_data
134
+ doc = Hpricot(open(@source))
135
+ p doc
136
+ {
137
+ :excerpt => (doc/"//a[@href='#{@target}']/..").inner_html,
138
+ :title => (doc/'//title').inner_html,
139
+ :url => @source
140
+ }
141
+ end
142
+
143
+ def send_trackback(url, data)
144
+ uri = URI.parse url
145
+ res = Net::HTTP.start(uri.host, uri.port) do |http|
146
+ req = Net::HTTP::Post.new(uri.path)
147
+ req.form_data = data
148
+ req['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8'
149
+ http.request req
150
+ end
151
+
152
+ doc = Hpricot.XML(res.body)
153
+ if res.code == '200' and (doc/'//error')[0].inner_html == '0'
154
+ record_trackback(1)
155
+ @response_message = 'OK'
156
+ else
157
+ record_trackback(0, doc.to_html)
158
+ @response_message = 'Unknown error ' + doc.to_html
159
+ end
160
+ end
161
+
162
+ def record_trackback(status, message = nil)
163
+ @@db.execute('INSERT INTO received_pingbacks (source_url, target_url, status, message)
164
+ VALUES (?, ?, ?, ?);', @source, @target, status, message)
165
+ end
166
+
167
+ def fetch_trackback_url
168
+ res = @@db.execute('SELECT trackback_url FROM trackback_url WHERE target_url = ?', @target)
169
+ if res.empty?
170
+ url = fetch_disqus_trackback_url
171
+ @@db.execute('INSERT INTO trackback_url (target_url, trackback_url) VALUES (?, ?)', @target, url) if url
172
+ return url
173
+ else
174
+ res.flatten[0]
175
+ end
176
+ end
177
+
178
+ def fetch_disqus_trackback_url
179
+ data = JSON.parse(open("http://disqus.com/api/get_thread_by_url/?forum_api_key=#{@@forum_api_key}&url=#{@target}").read)
180
+ if data['succeeded'] and not data['message'].nil?
181
+ x = data['message']
182
+ return "http://#{x['forum_obj']['shortname']}.disqus.com/#{x['slug']}/trackback/"
183
+ else
184
+ nil
185
+ end
186
+ end
187
+
188
+ def db_schema
189
+ if @@db.schema.tables.empty?
190
+ @@db.execute_batch('CREATE TABLE received_pingbacks (
191
+ id INTEGER AUTO INCREMENT PRIMARY KEY,
192
+ source_url VARCHAR NOT NULL,
193
+ target_url VARCHAT NOT NULL,
194
+ status INTEGER DEFAULT 0,
195
+ message VARCHAR NULL
196
+ );
197
+
198
+ CREATE TABLE trackback_url (
199
+ target_url VARCHAR NOT NULL PRIMARY KEY,
200
+ trackback_url VARCHAR NOT NULL
201
+ );
202
+
203
+ CREATE TABLE version (number INTEGER);
204
+ INSERT INTO version VALUES(1);')
205
+ end
206
+ end
207
+ end # /Receiver
208
+ end # /Pingback
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  Gem::Specification.new do |s|
3
3
  s.name = "webby-pingback"
4
- s.version = "1.0"
4
+ s.version = "1.0.0.1"
5
5
  s.date = Time.now.strftime('%Y-%m-%d')
6
6
  s.description = "Using Webby and some custom meta-data tags enable pingbacks to blogs and pages"
7
7
  s.authors = ["Björn Andersson"]
@@ -10,9 +10,9 @@ Gem::Specification.new do |s|
10
10
  s.summary = s.description
11
11
  s.require_path = 'lib'
12
12
  s.has_rdoc = false
13
- s.files = %w[README.textile tasks/pingback.rake webby-pingback.gemspec ext/pingback.cgi] +
14
- Dir.glob('lib/*.rb')
13
+ s.files = %w[README.textile tasks/pingback.rake webby-pingback.gemspec ext/pingback.cgi lib/webby-pingback-rake.rb lib/webby-pingback-xmlrpc.cgi.rb lib/webby-pingback.rb]
15
14
  s.add_dependency('amalgalite', '>= 0.10.2')
16
15
  s.add_dependency('json', '>= 1.1.7')
17
16
  s.add_dependency('hpricot', '>= 0.8.1')
18
17
  end
18
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ba-webby-pingback
3
3
  version: !ruby/object:Gem::Version
4
- version: "1.0"
4
+ version: 1.0.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Bj\xC3\xB6rn Andersson"
@@ -55,6 +55,9 @@ files:
55
55
  - tasks/pingback.rake
56
56
  - webby-pingback.gemspec
57
57
  - ext/pingback.cgi
58
+ - lib/webby-pingback-rake.rb
59
+ - lib/webby-pingback-xmlrpc.cgi.rb
60
+ - lib/webby-pingback.rb
58
61
  has_rdoc: false
59
62
  homepage: http://github.com/ba/webby-pingback
60
63
  licenses: