imap-feeder 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.project +23 -0
  3. data/History.txt +4 -0
  4. data/License.txt +341 -0
  5. data/Manifest.txt +48 -0
  6. data/README.txt +77 -0
  7. data/Rakefile +4 -0
  8. data/TODO.txt +11 -0
  9. data/bin/imap-feeder +68 -0
  10. data/config/hoe.rb +77 -0
  11. data/config/requirements.rb +17 -0
  12. data/lib/imap-feeder.rb +87 -0
  13. data/lib/imap-feeder/createconfigparser.rb +40 -0
  14. data/lib/imap-feeder/fakeserver.rb +23 -0
  15. data/lib/imap-feeder/feedfolder.rb +23 -0
  16. data/lib/imap-feeder/feedreader.rb +81 -0
  17. data/lib/imap-feeder/imapfeederconfig.rb +74 -0
  18. data/lib/imap-feeder/message.rb +152 -0
  19. data/lib/imap-feeder/messagestore.rb +35 -0
  20. data/lib/imap-feeder/opmlreader.rb +50 -0
  21. data/lib/imap-feeder/server.rb +77 -0
  22. data/lib/imap-feeder/version.rb +9 -0
  23. data/script/destroy +14 -0
  24. data/script/generate +14 -0
  25. data/script/txt2html +77 -0
  26. data/settings.rb.example +58 -0
  27. data/setup.rb +1585 -0
  28. data/tasks/deployment.rake +34 -0
  29. data/tasks/environment.rake +7 -0
  30. data/tasks/website.rake +15 -0
  31. data/test/data/encoded.rss +22 -0
  32. data/test/data/erroneous.yml +7 -0
  33. data/test/data/last_messages.yaml +0 -0
  34. data/test/data/rss20_no_body.xml +10 -0
  35. data/test/data/rss20_one_entry.xml +11 -0
  36. data/test/data/rss20_two_entries.xml +17 -0
  37. data/test/data/rss20_with_authors.xml +21 -0
  38. data/test/data/simple.opml +9 -0
  39. data/test/functional_test_server.rb +95 -0
  40. data/test/test_feedreader.rb +92 -0
  41. data/test/test_imap-feeder.rb +66 -0
  42. data/test/test_imapfeederconfig.rb +56 -0
  43. data/test/test_message.rb +312 -0
  44. data/test/test_messagestore.rb +54 -0
  45. data/test/test_opmlreader.rb +73 -0
  46. data/test/testlogger.rb +22 -0
  47. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  48. data/website/stylesheets/screen.css +137 -0
  49. data/website/template.rhtml +49 -0
  50. metadata +175 -0
  51. 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
@@ -0,0 +1,7 @@
1
+ task :ruby_env do
2
+ RUBY_APP = if RUBY_PLATFORM =~ /java/
3
+ "jruby"
4
+ else
5
+ "ruby"
6
+ end unless defined? RUBY_APP
7
+ end
@@ -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
+ &lt;&quot;ja!&quot; &gt;
18
+ </content:encoded>
19
+ <pubDate>Thu, 12 Apr 2007 19:06:00 +0200</pubDate>
20
+ </item>
21
+ </channel>
22
+ </rss>
@@ -0,0 +1,7 @@
1
+ ---
2
+ - feed:
3
+ url: http://misto.chh
4
+ path: "INBOX.Planets.Planet KDE's"
5
+ - feed:
6
+ url: http://misto.ch/invalid.html
7
+ path: INBOX.Planets.Planet Gentoo
File without changes
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0"?>
2
+ <rss version="2.0">
3
+ <channel>
4
+ <item>
5
+ <title>Mirko Stocker: KDE in Heroes!</title>
6
+ <link>http://blog.misto.ch/archives/324</link>
7
+ <pubDate>Wed, 15 Feb 2007 00:05 +0100</pubDate>
8
+ </item>
9
+ </channel>
10
+ </rss>
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0"?>
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
+ </channel>
11
+ </rss>
@@ -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