wcc-rss-notificator 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +36 -0
- data/assets/template.d/rss-content.html.erb +93 -0
- data/assets/template.d/rss-title.plain.erb +1 -0
- data/lib/wcc-rss-notificator.rb +162 -0
- metadata +68 -0
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
wcc-rss-notificator
|
2
|
+
===================
|
3
|
+
|
4
|
+
This adds Atom feed support to [wcc](https://github.com/cmur2/wcc) encapsulated
|
5
|
+
in a separate gem.
|
6
|
+
|
7
|
+
Note: Currently there is only one feed for all users/recipients.
|
8
|
+
|
9
|
+
What you need to add to your conf.yml:
|
10
|
+
|
11
|
+
conf:
|
12
|
+
[...]
|
13
|
+
# enable rss plugin
|
14
|
+
rss: {}
|
15
|
+
|
16
|
+
recipients:
|
17
|
+
[...]
|
18
|
+
- me:
|
19
|
+
[...]
|
20
|
+
# write updates to Atom feed
|
21
|
+
- rss:
|
22
|
+
# wcc needs write permission on this file/directory:
|
23
|
+
#file: <cache.d>/atom.xml
|
24
|
+
# mandatory option! - this allows you to use different
|
25
|
+
# (or same) databases for each recipient
|
26
|
+
db_name: me
|
27
|
+
# wcc will keep the N newest entries in your feed
|
28
|
+
#num_keep: 1000
|
29
|
+
feed:
|
30
|
+
# mandatory option! - Note that this is *NOT* your feed's
|
31
|
+
# url or something, this should be just an unique identifier:
|
32
|
+
id: http://www.example.com/my-feed/
|
33
|
+
#title: Your cool feed
|
34
|
+
#subtitle: About things
|
35
|
+
#link: # this now should be the feed's url
|
36
|
+
#alternate_link: # this may be a websites url (favicon comes from here)
|
@@ -0,0 +1,93 @@
|
|
1
|
+
<style type="text/css">
|
2
|
+
.msg {
|
3
|
+
font-size: 0.98em;
|
4
|
+
}
|
5
|
+
|
6
|
+
.diff {
|
7
|
+
font-size: 12px;
|
8
|
+
font-family: 'Bitstream Vera Sans Mono','Courier',monospace;
|
9
|
+
}
|
10
|
+
|
11
|
+
.diff ul {
|
12
|
+
list-style: none;
|
13
|
+
display: table;
|
14
|
+
padding: 0;
|
15
|
+
margin: 0.5em 0 0 0.5em;
|
16
|
+
border: 1px solid #CCCCCC;
|
17
|
+
}
|
18
|
+
|
19
|
+
.diff li {
|
20
|
+
padding: 0;
|
21
|
+
display: table-row;
|
22
|
+
margin: 0;
|
23
|
+
background: #f8f8ff;
|
24
|
+
}
|
25
|
+
|
26
|
+
.diff .new, .diff .old {
|
27
|
+
color: #999;
|
28
|
+
}
|
29
|
+
|
30
|
+
.diff .ins {
|
31
|
+
background: #dfd;
|
32
|
+
}
|
33
|
+
|
34
|
+
.diff .ins .x {
|
35
|
+
background: #8f8;
|
36
|
+
margin: 0;
|
37
|
+
padding: 0;
|
38
|
+
}
|
39
|
+
|
40
|
+
.diff .del {
|
41
|
+
background: #fdd;
|
42
|
+
}
|
43
|
+
|
44
|
+
.diff .del .x {
|
45
|
+
background: #faa;
|
46
|
+
margin: 0;
|
47
|
+
padding: 0;
|
48
|
+
}
|
49
|
+
|
50
|
+
.diff .range {
|
51
|
+
background: #eaf2f5;
|
52
|
+
color: #999;
|
53
|
+
}
|
54
|
+
|
55
|
+
.diff .other {
|
56
|
+
}
|
57
|
+
</style>
|
58
|
+
|
59
|
+
<% if data.diff.nil? %>
|
60
|
+
<div class="msg">
|
61
|
+
Checked <a href="<%= data.site.uri.to_s %>"><%= data.site.uri.to_s %></a> the first time so no diff was possible.
|
62
|
+
</div>
|
63
|
+
<% else %>
|
64
|
+
<div class="msg">
|
65
|
+
Change at <a href="<%= data.site.uri.to_s %>"><%= data.site.uri.to_s %></a> - diff follows:
|
66
|
+
</div>
|
67
|
+
<div class="diff">
|
68
|
+
<ul>
|
69
|
+
<% for o in data.diff.di %>
|
70
|
+
<% if o.status == :new %>
|
71
|
+
<li class="new">+++<%= o.text %></li>
|
72
|
+
<% elsif o.status == :old %>
|
73
|
+
<li class="old">---<%= o.text %></li>
|
74
|
+
<% elsif o.status == :range %>
|
75
|
+
<li class="range">@@<%= o.text %></li>
|
76
|
+
<% elsif o.status == :ins %>
|
77
|
+
<li class="ins">+ <%= o.html_hilite_text('x').lstrip %></li>
|
78
|
+
<% elsif o.status == :del %>
|
79
|
+
<li class="del">- <%= o.html_hilite_text('x').lstrip %></li>
|
80
|
+
<% else %>
|
81
|
+
<li class="other"> <%= o.text.substring(1).lstrip %></li>
|
82
|
+
<% end %>
|
83
|
+
<% end %>
|
84
|
+
</ul>
|
85
|
+
</div>
|
86
|
+
<div>
|
87
|
+
nHunks: <%= data.diff.nhunks %>,
|
88
|
+
nIns: <%= data.diff.ninsertions %>,
|
89
|
+
nDel: <%= data.diff.ndeletions %>,
|
90
|
+
nLinesC: <%= data.diff.nlinesc %>,
|
91
|
+
nCharsC: <%= data.diff.ncharsc %>
|
92
|
+
</div>
|
93
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= data.site.uri.host %> changed
|
@@ -0,0 +1,162 @@
|
|
1
|
+
|
2
|
+
require 'rss/maker'
|
3
|
+
require 'socket' # only for getting hostname
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
class RSSNotificator
|
7
|
+
@@tpl = {}
|
8
|
+
@@shutdown_hooks = []
|
9
|
+
|
10
|
+
# TODO: can we hook into --clean?
|
11
|
+
|
12
|
+
def initialize(opts)
|
13
|
+
@dirty = false
|
14
|
+
if opts.is_a?(Hash)
|
15
|
+
@file = opts['file'] || WCC::Conf.file("atom.xml")
|
16
|
+
@db_name = opts['db_name']
|
17
|
+
@num_keep = opts['num_keep'] || 1000
|
18
|
+
@feed = {}
|
19
|
+
if opts['feed'].is_a?(Hash)
|
20
|
+
@feed = {
|
21
|
+
:title => opts['feed']['title'] || "wcc Updates Feed - #{Socket.gethostname}",
|
22
|
+
:subtitle => opts['feed']['subtitle'] || "The newest changes to your watched sites.",
|
23
|
+
:link => opts['feed']['link'],
|
24
|
+
:alt_link => opts['feed']['alternate_link'],
|
25
|
+
:id => opts['feed']['id']
|
26
|
+
}
|
27
|
+
end
|
28
|
+
if @feed[:id].nil?
|
29
|
+
raise ArgumentError, "Missing atom feed ID!"
|
30
|
+
end
|
31
|
+
if @db_name.nil?
|
32
|
+
raise ArgumentError, "Missing db name for atom feed!"
|
33
|
+
end
|
34
|
+
else
|
35
|
+
raise ArgumentError, "No options given for 'rss:' way of a recipient! Need at least db name and feed id."
|
36
|
+
end
|
37
|
+
@@shutdown_hooks << self
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_feeddb
|
41
|
+
if @feeddb.nil?
|
42
|
+
feeddb_file = WCC::Conf.file("feed-db-#{@db_name}.yml")
|
43
|
+
WCC.logger.debug "Loading feed-db '#{@db_name}' from file '#{feeddb_file}'"
|
44
|
+
if not File.exists?(feeddb_file)
|
45
|
+
WCC.logger.warn "Feed-db '#{@db_name}' does not exist, will create it on save in '#{feeddb_file}'"
|
46
|
+
@feeddb = {'feed' => []}
|
47
|
+
else
|
48
|
+
# may be false if file is empty
|
49
|
+
@feeddb = YAML.load_file(feeddb_file)
|
50
|
+
if not @feeddb.is_a?(Hash)
|
51
|
+
WCC.logger.warn "Feed-db '#{@db_name}' is corrupt, will overwrite it on save"
|
52
|
+
@feeddb = {'feed' => []}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
@feeddb
|
57
|
+
end
|
58
|
+
|
59
|
+
def notify!(data)
|
60
|
+
title = self.class.get_tpl(:title, 'rss-title.plain.erb').result(binding)
|
61
|
+
# remove trailing whitespace introduced by template
|
62
|
+
title.strip!
|
63
|
+
content = self.class.get_tpl(:content, 'rss-content.html.erb').result(binding)
|
64
|
+
id = "#{@feed['id']}item/#{Time.now.to_f}"
|
65
|
+
|
66
|
+
# append entries to class variable (not thread safe)
|
67
|
+
@dirty = true
|
68
|
+
feed = get_feeddb['feed']
|
69
|
+
feed.insert 0, {
|
70
|
+
'title' => title,
|
71
|
+
#'description' => '', # summary
|
72
|
+
'content' => content,
|
73
|
+
'link' => data.site.uri.to_s,
|
74
|
+
'id' => id,
|
75
|
+
'updated' => Time.now.to_s
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def shut_down
|
80
|
+
return unless @dirty
|
81
|
+
|
82
|
+
WCC.logger.debug "Writing feed-db '#{@db_name}' to file"
|
83
|
+
|
84
|
+
feeddb_file = WCC::Conf.file("feed-db-#{@db_name}.yml")
|
85
|
+
feeddb = get_feeddb
|
86
|
+
# auto-purge
|
87
|
+
feeddb['feed'] = feeddb['feed'].slice(0, @num_keep)
|
88
|
+
File.open(feeddb_file, 'w+') do |f| YAML.dump(feeddb, f) end
|
89
|
+
|
90
|
+
WCC.logger.info "Generating feed '#{@file}'..."
|
91
|
+
|
92
|
+
content = RSS::Maker.make('atom') do |m|
|
93
|
+
m.channel.title = @feed[:title]
|
94
|
+
m.channel.subtitle = @feed[:subtitle]
|
95
|
+
m.channel.author = "web change checker (aka wcc) #{WCC::VERSION}"
|
96
|
+
if not @feed[:link].nil?
|
97
|
+
m.channel.links.new_link do |li|
|
98
|
+
li.rel = "self"
|
99
|
+
li.type = "application/atom+xml"
|
100
|
+
li.href = @feed[:link]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
if not @feed[:alternate_link].nil?
|
104
|
+
m.channel.links.new_link do |li|
|
105
|
+
li.rel = "alternate"
|
106
|
+
li.type = "text/html"
|
107
|
+
li.href = @feed[:alternate_link]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
m.channel.id = @feed[:id]
|
111
|
+
m.channel.updated = Time.now.to_s
|
112
|
+
m.items.do_sort = true # sort items by date
|
113
|
+
|
114
|
+
# feeddb-hash to atom
|
115
|
+
feeddb['feed'].each do |e|
|
116
|
+
m.items.new_item do |i|
|
117
|
+
i.title = e['title']
|
118
|
+
#i.description = e['description']
|
119
|
+
i.content.content = e['content']
|
120
|
+
i.content.type = "html"
|
121
|
+
i.author = "wcc"
|
122
|
+
if not e['link'].nil?
|
123
|
+
i.links.new_link do |li|
|
124
|
+
li.rel = "alternate"
|
125
|
+
li.type = "text/html"
|
126
|
+
li.href = e['link']
|
127
|
+
end
|
128
|
+
end
|
129
|
+
i.id = e['id']
|
130
|
+
i.updated = e['updated']
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
File.open(@file, 'w+') do |f| f.write(content.to_s) end
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.parse_conf(conf); {} end
|
139
|
+
|
140
|
+
def self.shut_down
|
141
|
+
@@shutdown_hooks.each do |s| s.shut_down end
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.get_tpl(id, name)
|
145
|
+
if @@tpl[id].nil?
|
146
|
+
@@tpl[id] = WCC::Prog.load_template(name)
|
147
|
+
if @@tpl[id].nil?
|
148
|
+
src_path = Pathname.new(__FILE__) + "../../assets/template.d/#{name}"
|
149
|
+
t = File.open(src_path, 'r') { |f| f.read }
|
150
|
+
WCC::Prog.save_template(name, t)
|
151
|
+
# retry load
|
152
|
+
@@tpl[id] = WCC::Prog.load_template(name)
|
153
|
+
end
|
154
|
+
if @@tpl[id].nil?
|
155
|
+
@@tpl[id] = ERB.new("ERROR LOADING TEMPLATE '#{name}'!", 0, "<>")
|
156
|
+
end
|
157
|
+
end
|
158
|
+
@@tpl[id]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
WCC::Notificators.map "rss", RSSNotificator
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: wcc-rss-notificator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Christian Nicolai
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-03-25 00:00:00 Z
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description:
|
22
|
+
email: chrnicolai@gmail.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- assets/template.d/rss-content.html.erb
|
31
|
+
- assets/template.d/rss-title.plain.erb
|
32
|
+
- lib/wcc-rss-notificator.rb
|
33
|
+
- README.md
|
34
|
+
homepage: https://github.com/cmur2/wcc-rss-notificator
|
35
|
+
licenses: []
|
36
|
+
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
hash: 3
|
48
|
+
segments:
|
49
|
+
- 0
|
50
|
+
version: "0"
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project: wcc-rss-notificator
|
63
|
+
rubygems_version: 1.8.6
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: RSS feed notificator plugin for wcc
|
67
|
+
test_files: []
|
68
|
+
|