imap-feeder 0.1.0
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.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
|