imap-feeder 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/.project +23 -0
- data/History.txt +4 -0
- data/License.txt +341 -0
- data/Manifest.txt +48 -0
- data/README.txt +77 -0
- data/Rakefile +4 -0
- data/TODO.txt +11 -0
- data/bin/imap-feeder +68 -0
- data/config/hoe.rb +77 -0
- data/config/requirements.rb +17 -0
- data/lib/imap-feeder.rb +87 -0
- data/lib/imap-feeder/createconfigparser.rb +40 -0
- data/lib/imap-feeder/fakeserver.rb +23 -0
- data/lib/imap-feeder/feedfolder.rb +23 -0
- data/lib/imap-feeder/feedreader.rb +81 -0
- data/lib/imap-feeder/imapfeederconfig.rb +74 -0
- data/lib/imap-feeder/message.rb +152 -0
- data/lib/imap-feeder/messagestore.rb +35 -0
- data/lib/imap-feeder/opmlreader.rb +50 -0
- data/lib/imap-feeder/server.rb +77 -0
- data/lib/imap-feeder/version.rb +9 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +77 -0
- data/settings.rb.example +58 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +15 -0
- data/test/data/encoded.rss +22 -0
- data/test/data/erroneous.yml +7 -0
- data/test/data/last_messages.yaml +0 -0
- data/test/data/rss20_no_body.xml +10 -0
- data/test/data/rss20_one_entry.xml +11 -0
- data/test/data/rss20_two_entries.xml +17 -0
- data/test/data/rss20_with_authors.xml +21 -0
- data/test/data/simple.opml +9 -0
- data/test/functional_test_server.rb +95 -0
- data/test/test_feedreader.rb +92 -0
- data/test/test_imap-feeder.rb +66 -0
- data/test/test_imapfeederconfig.rb +56 -0
- data/test/test_message.rb +312 -0
- data/test/test_messagestore.rb +54 -0
- data/test/test_opmlreader.rb +73 -0
- data/test/testlogger.rb +22 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +137 -0
- data/website/template.rhtml +49 -0
- metadata +175 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
desc 'Release the website and new gem version'
|
2
|
+
task :deploy => [:check_version, :website, :release] do
|
3
|
+
puts "Remember to create SVN tag:"
|
4
|
+
puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
|
5
|
+
"svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
|
6
|
+
puts "Suggested comment:"
|
7
|
+
puts "Tagging release #{CHANGES}"
|
8
|
+
end
|
9
|
+
|
10
|
+
desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
|
11
|
+
task :local_deploy => [:website_generate, :install_gem]
|
12
|
+
|
13
|
+
task :check_version do
|
14
|
+
unless ENV['VERSION']
|
15
|
+
puts 'Must pass a VERSION=x.y.z release version'
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
unless ENV['VERSION'] == VERS
|
19
|
+
puts "Please update your version.rb to match the release version, currently #{VERS}"
|
20
|
+
exit
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
|
25
|
+
task :install_gem_no_doc => [:clean, :package] do
|
26
|
+
sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
|
27
|
+
end
|
28
|
+
|
29
|
+
namespace :manifest do
|
30
|
+
desc 'Recreate Manifest.txt to include ALL files'
|
31
|
+
task :refresh do
|
32
|
+
`rake check_manifest | patch -p0 > Manifest.txt`
|
33
|
+
end
|
34
|
+
end
|
data/tasks/website.rake
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
desc 'Generate website files'
|
2
|
+
task :website_generate => :ruby_env do
|
3
|
+
sh %{ #{RUBY_APP} script/txt2html README.txt > website/index.html}
|
4
|
+
end
|
5
|
+
|
6
|
+
desc 'Upload website files to rubyforge'
|
7
|
+
task :website_upload do
|
8
|
+
host = "#{rubyforge_username}@rubyforge.org"
|
9
|
+
remote_dir = "/var/www/gforge-projects/#{PATH}/"
|
10
|
+
local_dir = 'website'
|
11
|
+
sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
|
12
|
+
end
|
13
|
+
|
14
|
+
desc 'Generate and upload website files'
|
15
|
+
task :website => [:website_generate, :website_upload, :publish_docs]
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
2
|
+
|
3
|
+
<rss version="2.0"
|
4
|
+
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
5
|
+
xmlns:admin="http://webns.net/mvcb/"
|
6
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
7
|
+
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
|
8
|
+
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
|
9
|
+
xmlns:content="http://purl.org/rss/1.0/modules/content/"
|
10
|
+
>
|
11
|
+
<channel>
|
12
|
+
<item>
|
13
|
+
<title>This is the title!</title>
|
14
|
+
<link>http://test.ch</link>
|
15
|
+
<author>Mirko Stocker</author>
|
16
|
+
<content:encoded>
|
17
|
+
<"ja!" >
|
18
|
+
</content:encoded>
|
19
|
+
<pubDate>Thu, 12 Apr 2007 19:06:00 +0200</pubDate>
|
20
|
+
</item>
|
21
|
+
</channel>
|
22
|
+
</rss>
|
File without changes
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<rss version="2.0">
|
3
|
+
<channel>
|
4
|
+
<item>
|
5
|
+
<title>title1</title>
|
6
|
+
<link>http://link1</link>
|
7
|
+
<description>description1</description>
|
8
|
+
<pubDate>Wed, 15 Feb 2007 00:05 +0100</pubDate>
|
9
|
+
</item>
|
10
|
+
<item>
|
11
|
+
<title>title2</title>
|
12
|
+
<link>http://link2</link>
|
13
|
+
<description>description2</description>
|
14
|
+
<pubDate>Monday 12 February 2007 17:09</pubDate>
|
15
|
+
</item>
|
16
|
+
</channel>
|
17
|
+
</rss>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<?xml version="1.0" encoding="ISO-8859-15"?>
|
2
|
+
<rss version="2.0">
|
3
|
+
<channel>
|
4
|
+
<item>
|
5
|
+
<title>
|
6
|
+
WikifeatureUpdates
|
7
|
+
</title>
|
8
|
+
<author>MaxMuster</author>
|
9
|
+
<link>http://http</link>
|
10
|
+
<description>Changed..</description>
|
11
|
+
<pubDate>Wed, 07 Feb 2007 15:29:01 +0100</pubDate></item>
|
12
|
+
<item>
|
13
|
+
<title>
|
14
|
+
WikiInput
|
15
|
+
</title>
|
16
|
+
<author>MirkoStocker</author>
|
17
|
+
<link>http://http</link>
|
18
|
+
<description>MirkoStocker changed something</description>
|
19
|
+
<pubDate>Wed, 31 Jan 2007 14:03:18 +0100</pubDate></item>
|
20
|
+
</channel>
|
21
|
+
</rss>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<opml version="1.0" >
|
3
|
+
<body>
|
4
|
+
<outline isOpen="false" text="Planets">
|
5
|
+
<outline title="Planet KDE" xmlUrl="http://planetkde.org/rss20.xml"/>
|
6
|
+
<outline xmlUrl="http://planet.gentoo.org/rss20.xml" title="Planet Gentoo"/>
|
7
|
+
</outline>
|
8
|
+
</body>
|
9
|
+
</opml>
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'imap-feeder/server'
|
2
|
+
require 'imap-feeder/message'
|
3
|
+
|
4
|
+
class ServerConnectionTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_server_host_not_found
|
7
|
+
assert_throws :host_not_found do
|
8
|
+
@server = Server.new(:host => "misto.chh")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_server_login_failed
|
13
|
+
assert_throws :login_failed do
|
14
|
+
@server = Server.new(:host => $host, :user => $user, :pass => "a")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_server_creation
|
19
|
+
assert_nothing_thrown do
|
20
|
+
@server = Server.new :host => $host, :user => $user, :pass => $pass
|
21
|
+
assert @server.connected
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class ServerTest < Test::Unit::TestCase
|
27
|
+
|
28
|
+
def setup
|
29
|
+
@server = Server.new :host => $host, :user => $user, :pass => $pass
|
30
|
+
end
|
31
|
+
|
32
|
+
def teardown
|
33
|
+
@server.disconnect if @server
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_server_send_simple_message
|
37
|
+
m = Message.new(:title => "test-message", :body => "body")
|
38
|
+
assert @server.send(m, "INBOX")
|
39
|
+
assert @server.has?("test-message", "INBOX")
|
40
|
+
m = @server.retrieve("test-message", "INBOX")
|
41
|
+
assert_equal("test-message", m.title)
|
42
|
+
ensure
|
43
|
+
@server.delete(m, "INBOX")
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_server_send_simple_message_to_subfolder
|
47
|
+
@server.create_folder "INBOX.test-folder"
|
48
|
+
|
49
|
+
m = Message.new(:title => "test-message2", :body => "body")
|
50
|
+
assert @server.send(m, "INBOX.test-folder")
|
51
|
+
assert ! @server.has?("test-message2", "INBOX")
|
52
|
+
assert @server.has?("test-message2", "INBOX.test-folder")
|
53
|
+
ensure
|
54
|
+
@server.delete_folder "INBOX.test-folder"
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_server_retrieve_invalid_message_header
|
58
|
+
m = @server.retrieve("test-message invalid", "INBOX")
|
59
|
+
assert_nil m
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_server_has_invalid_message?
|
63
|
+
assert ! @server.has?("test-message invalid", "INBOX")
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_has_folder_inbox?
|
67
|
+
assert @server.has_folder?("INBOX")
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_has_invalid_folder?
|
71
|
+
assert ! @server.has_folder?("InvalidFolder")
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_delete_not_existing
|
75
|
+
assert_throws :cannot_delete do
|
76
|
+
@server.delete_folder "Inbox.not-existing-folder"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_create_already_existing
|
81
|
+
@server.create_folder "INBOX.test_dir"
|
82
|
+
assert_throws :cannot_create do
|
83
|
+
@server.create_folder "INBOX.test_dir"
|
84
|
+
end
|
85
|
+
ensure
|
86
|
+
@server.delete_folder "Inbox.test_dir"
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_create_and_delete_folder
|
90
|
+
assert_nothing_thrown { @server.create_folder "INBOX.test_dir" }
|
91
|
+
assert @server.has_folder?("INBOX.test_dir")
|
92
|
+
assert_nothing_thrown { @server.delete_folder "INBOX.test_dir" }
|
93
|
+
assert ! @server.has_folder?("INBOX.test_dir")
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'imap-feeder/feedreader'
|
2
|
+
require 'imap-feeder/message'
|
3
|
+
|
4
|
+
class TestFeedReader < Test::Unit::TestCase
|
5
|
+
|
6
|
+
RSS20_ONE_ENTRY = "#{File.dirname(__FILE__)}/data/rss20_one_entry.xml"
|
7
|
+
RSS20_TWO_ENTRIES = "#{File.dirname(__FILE__)}/data/rss20_two_entries.xml"
|
8
|
+
RSS20_WITH_AUTHORS = "#{File.dirname(__FILE__)}/data/rss20_with_authors.xml"
|
9
|
+
RSS20_NO_BODY = "#{File.dirname(__FILE__)}/data/rss20_no_body.xml"
|
10
|
+
ENCODED_RSS = "#{File.dirname(__FILE__)}/data/encoded.rss"
|
11
|
+
|
12
|
+
def test_reading_first_feed
|
13
|
+
messages = FeedReader.new(RSS20_ONE_ENTRY).get_new []
|
14
|
+
assert_equal(1, messages.size)
|
15
|
+
assert_equal(Time.parse("Wed, 15 Feb 2007 00:05 +0100").rfc2822, messages.first.time)
|
16
|
+
assert_equal("title1", messages.first.title)
|
17
|
+
assert_equal("description1", messages.first.body)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_size_one
|
21
|
+
assert_equal(1, FeedReader.new(RSS20_ONE_ENTRY).number_of_entries)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_size_two
|
25
|
+
assert_equal(2, FeedReader.new(RSS20_TWO_ENTRIES).number_of_entries)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_reading_second_feed
|
29
|
+
messages = FeedReader.new(RSS20_TWO_ENTRIES).get_new []
|
30
|
+
assert_equal(2, messages.size)
|
31
|
+
assert_equal(Time.parse("Wed, 15 Feb 2007 00:05 +0100").rfc2822, messages[0].time)
|
32
|
+
assert_equal("title1", messages[0].title)
|
33
|
+
assert_equal("description1", messages[0].body)
|
34
|
+
|
35
|
+
assert_equal(Time.parse("Monday 12 February 2007 17:09").rfc2822, messages[1].time)
|
36
|
+
assert_equal("title2", messages[1].title)
|
37
|
+
assert_equal("description2", messages[1].body)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_get_latest
|
41
|
+
reader = FeedReader.new(RSS20_TWO_ENTRIES)
|
42
|
+
messages = reader.get_new []
|
43
|
+
new_messages = reader.get_new([messages.last.generate_identifier])
|
44
|
+
|
45
|
+
assert_equal(1, new_messages.size)
|
46
|
+
assert_equal("title1", new_messages.first.title)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_get_latest_or_all
|
50
|
+
reader = FeedReader.new(RSS20_TWO_ENTRIES)
|
51
|
+
new_messages = reader.get_new(["Mirko Stocker: "])
|
52
|
+
|
53
|
+
assert_equal(2, new_messages.size)
|
54
|
+
assert_equal("title1", new_messages.first.title)
|
55
|
+
assert_equal("title2", new_messages[1].title)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_get_authors
|
59
|
+
messages = FeedReader.new(RSS20_WITH_AUTHORS).get_new []
|
60
|
+
assert_equal(2, messages.size)
|
61
|
+
assert_equal("MaxMuster", messages.first.from)
|
62
|
+
assert_equal("MirkoStocker", messages.last.from)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_no_body
|
66
|
+
messages = FeedReader.new(RSS20_NO_BODY).get_new []
|
67
|
+
assert_equal(1, messages.size)
|
68
|
+
assert_equal("", messages.first.body)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_get_nothing
|
72
|
+
reader = FeedReader.new(RSS20_TWO_ENTRIES)
|
73
|
+
msgs = reader.get_new []
|
74
|
+
identifiers = msgs.map {|msg| msg.generate_identifier}
|
75
|
+
new_messages = reader.get_new(identifiers)
|
76
|
+
assert new_messages.empty?
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_get_all
|
80
|
+
reader = FeedReader.new(RSS20_TWO_ENTRIES)
|
81
|
+
messages = reader.messages
|
82
|
+
new_messages = reader.get_new(nil)
|
83
|
+
assert_equal(2, new_messages.size)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test__content_encoded
|
87
|
+
reader = FeedReader.new(ENCODED_RSS)
|
88
|
+
messages = reader.messages
|
89
|
+
new_messages = reader.get_new(nil)
|
90
|
+
assert_equal "<\"ja!\" >", new_messages.first.body
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
require 'imap-feeder'
|
3
|
+
require 'test/testlogger'
|
4
|
+
|
5
|
+
class TestServer
|
6
|
+
attr_reader :sent
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@sent = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def has_folder?(folder)
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_folder(folder)
|
17
|
+
end
|
18
|
+
|
19
|
+
def send(msg, complete_path)
|
20
|
+
@sent << [msg, complete_path]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class TestImapFeeder < Test::Unit::TestCase
|
25
|
+
|
26
|
+
TEST_FEEDS = "#{File.dirname(__FILE__)}/data"
|
27
|
+
|
28
|
+
def setup
|
29
|
+
$log = TestLogger.new
|
30
|
+
@server = TestServer.new
|
31
|
+
@store = MessageStore.new(Tempfile.new("message_store_temp").path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def title(index)
|
35
|
+
@server.sent[index].first.title
|
36
|
+
end
|
37
|
+
|
38
|
+
def body(index)
|
39
|
+
@server.sent[index].first.body
|
40
|
+
end
|
41
|
+
|
42
|
+
def folder(index)
|
43
|
+
@server.sent[index].last
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_simple_rss20
|
47
|
+
config = <<EOS
|
48
|
+
- feed:
|
49
|
+
url: "#{TEST_FEEDS}/rss20_two_entries.xml"
|
50
|
+
path: INBOX.TestFolder
|
51
|
+
EOS
|
52
|
+
|
53
|
+
ImapFeeder.new(@server, @store, config).run
|
54
|
+
assert_equal("Started", $log.info_msg[0])
|
55
|
+
assert_equal("Processing INBOX.TestFolder", $log.info_msg[1])
|
56
|
+
|
57
|
+
assert_equal(2, @server.sent.length)
|
58
|
+
assert_equal("INBOX.TestFolder", folder(0))
|
59
|
+
assert_equal("description1", body(0))
|
60
|
+
assert_equal("title1", title(0))
|
61
|
+
assert_equal("INBOX.TestFolder", folder(1))
|
62
|
+
assert_equal("description2", body(1))
|
63
|
+
assert_equal("title2", title(1))
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
require 'imap-feeder/imapfeederconfig'
|
4
|
+
require 'test/testlogger'
|
5
|
+
|
6
|
+
|
7
|
+
class ConfigTest < Test::Unit::TestCase
|
8
|
+
|
9
|
+
OPML_FILE = "#{File.dirname(__FILE__)}/data/simple.opml"
|
10
|
+
ERRONEOUS_FILE = "#{File.dirname(__FILE__)}/data/erroneous.yml"
|
11
|
+
FEEDS_FILE = "#{Dir.pwd}/feeds.yml"
|
12
|
+
SETTINGS_FILE = "#{Dir.pwd}/settings.rb"
|
13
|
+
|
14
|
+
def setup
|
15
|
+
$log = TestLogger.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_create_with_root
|
19
|
+
ImapFeederConfig.create(OPML_FILE, "root")
|
20
|
+
result = YAML.load(open(FEEDS_FILE))
|
21
|
+
File.delete FEEDS_FILE
|
22
|
+
|
23
|
+
assert_equal("INBOX.root.Planets.Planet KDE", result.first['feed']['path'])
|
24
|
+
|
25
|
+
assert File.exists?(SETTINGS_FILE)
|
26
|
+
File.delete SETTINGS_FILE
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_create
|
30
|
+
ImapFeederConfig.create(OPML_FILE, nil)
|
31
|
+
result = YAML.load(open(FEEDS_FILE))
|
32
|
+
File.delete FEEDS_FILE
|
33
|
+
|
34
|
+
assert_equal("http://planetkde.org/rss20.xml", result.first['feed']['url'])
|
35
|
+
assert_equal("INBOX.Planets.Planet KDE", result.first['feed']['path'])
|
36
|
+
|
37
|
+
assert_equal("http://planet.gentoo.org/rss20.xml", result.last['feed']['url'])
|
38
|
+
assert_equal("INBOX.Planets.Planet Gentoo", result.last['feed']['path'])
|
39
|
+
|
40
|
+
assert($log.error_msg.empty?)
|
41
|
+
assert($log.warn_msg.empty?)
|
42
|
+
assert_equal(2, $log.debug_msg.length)
|
43
|
+
|
44
|
+
assert File.exists?(SETTINGS_FILE)
|
45
|
+
File.delete SETTINGS_FILE
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_check
|
49
|
+
ImapFeederConfig.check(File.open(ERRONEOUS_FILE))
|
50
|
+
|
51
|
+
assert_equal("Invalid character found in 'INBOX.Planets.Planet KDE's': '", $log.error_msg.first)
|
52
|
+
assert_match(/Exception while connecting to/, $log.warn_msg.first)
|
53
|
+
assert_match(/connecting/, $log.warn_msg.last)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|