ba-webby-pingback 1.0 → 1.0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: