tender_summary 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +51 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/bin/tender_summary +5 -0
- data/lib/tender_summary.rb +8 -0
- data/lib/tender_summary/cli.rb +59 -0
- data/lib/tender_summary/mailer.rb +18 -0
- data/lib/tender_summary/templates/mailer/pending.text.html.erb +91 -0
- data/lib/tender_summary/tender_api.rb +57 -0
- data/test/helper.rb +10 -0
- data/test/test_tender-summary.rb +7 -0
- metadata +119 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Eric Lindvall
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
= Tender Summary
|
2
|
+
|
3
|
+
Use this with cron or launchd to send summary emails of your Tender
|
4
|
+
discussions.
|
5
|
+
|
6
|
+
It will include all pending discussions in the email.
|
7
|
+
|
8
|
+
|
9
|
+
== Installation
|
10
|
+
|
11
|
+
To install, just run:
|
12
|
+
|
13
|
+
$ sudo gem install tender_summary
|
14
|
+
|
15
|
+
|
16
|
+
== Usage
|
17
|
+
|
18
|
+
An example crontab entry:
|
19
|
+
|
20
|
+
0 9 * * * tender_summary -s tenderaccount -u robot@tenderaccount.com -p XXXX6zxY7b -t eric@tenderaccount.com -f 'Support <support@tenderaccount.com>'
|
21
|
+
|
22
|
+
Note: The password for the account will be visible in the system process
|
23
|
+
table when the program is running.
|
24
|
+
|
25
|
+
|
26
|
+
== Inspiration
|
27
|
+
|
28
|
+
The styling used and inspiration was taken from the
|
29
|
+
{Basecamp}[http://www.basecamphq.com] daily summary emails. They look
|
30
|
+
really nice.
|
31
|
+
|
32
|
+
|
33
|
+
== TODO
|
34
|
+
|
35
|
+
* Add command line option for customized view
|
36
|
+
|
37
|
+
|
38
|
+
== Note on Patches/Pull Requests
|
39
|
+
|
40
|
+
* Fork the project.
|
41
|
+
* Make your feature addition or bug fix.
|
42
|
+
* Add tests for it. This is important so I don't break it in a
|
43
|
+
future version unintentionally.
|
44
|
+
* Commit, do not mess with rakefile, version, or history.
|
45
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
46
|
+
* Send me a pull request. Bonus points for topic branches.
|
47
|
+
|
48
|
+
|
49
|
+
== Copyright
|
50
|
+
|
51
|
+
Copyright (c) 2009 Eric Lindvall. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "tender_summary"
|
8
|
+
gem.summary = %Q{A simple tool to email your pending Tender discussions}
|
9
|
+
gem.description = %Q{A simple tool to email your pending Tender discussions.}
|
10
|
+
gem.email = "eric@sevenscale.com"
|
11
|
+
gem.homepage = "http://github.com/eric/tender_summary"
|
12
|
+
gem.authors = ["Eric Lindvall"]
|
13
|
+
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
+
gem.add_development_dependency "yard", ">= 0"
|
15
|
+
gem.add_dependency 'httparty', '~> 0.4.5'
|
16
|
+
gem.add_dependency 'addressable', '~> 2.1.1'
|
17
|
+
gem.add_dependency 'actionmailer', '~> 2.3.5'
|
18
|
+
|
19
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
20
|
+
end
|
21
|
+
Jeweler::GemcutterTasks.new
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'rake/testtask'
|
27
|
+
Rake::TestTask.new(:test) do |test|
|
28
|
+
test.libs << 'lib' << 'test'
|
29
|
+
test.pattern = 'test/**/test_*.rb'
|
30
|
+
test.verbose = true
|
31
|
+
end
|
32
|
+
|
33
|
+
begin
|
34
|
+
require 'rcov/rcovtask'
|
35
|
+
Rcov::RcovTask.new do |test|
|
36
|
+
test.libs << 'test'
|
37
|
+
test.pattern = 'test/**/test_*.rb'
|
38
|
+
test.verbose = true
|
39
|
+
end
|
40
|
+
rescue LoadError
|
41
|
+
task :rcov do
|
42
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
task :test => :check_dependencies
|
47
|
+
|
48
|
+
task :default => :test
|
49
|
+
|
50
|
+
begin
|
51
|
+
require 'yard'
|
52
|
+
YARD::Rake::YardocTask.new
|
53
|
+
rescue LoadError
|
54
|
+
task :yardoc do
|
55
|
+
abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
|
56
|
+
end
|
57
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.1.0
|
data/bin/tender_summary
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
|
2
|
+
module TenderSummary
|
3
|
+
class Cli
|
4
|
+
attr_accessor :to, :from
|
5
|
+
|
6
|
+
def initialize(argv)
|
7
|
+
@argv = argv.dup
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
self.parse
|
12
|
+
|
13
|
+
TenderSummary::Mailer.deliver_pending(self.to, self.from)
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse
|
17
|
+
opts = OptionParser.new do |opts|
|
18
|
+
opts.banner = "Usage: #{File.basename($0)} [options]"
|
19
|
+
|
20
|
+
opts.separator ' '
|
21
|
+
opts.separator 'Specific options:'
|
22
|
+
|
23
|
+
opts.on("-s", "--subdomain SUBDOMAIN", "Tender subdomain") do |n|
|
24
|
+
TenderSummary::TenderApi.subdomain = n
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-u", "--username USERNAME", "Tender username") do |n|
|
28
|
+
TenderSummary::TenderApi.username = n
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("-p", "--password PASSWORD", "Tender password") do |n|
|
32
|
+
TenderSummary::TenderApi.password = n
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("-t", "--to a,b,c", Array, "Users to email") do |n|
|
36
|
+
self.to = n
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on("-f", "--from FROM", "Email address to use for From") do |n|
|
40
|
+
self.from = n
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.separator " "
|
44
|
+
opts.separator "Common options:"
|
45
|
+
|
46
|
+
# No argument, shows at tail. This will print an options summary.
|
47
|
+
# Try it and see!
|
48
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
49
|
+
puts opts
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
opts.parse!(@argv)
|
55
|
+
|
56
|
+
TenderSummary::TenderApi.authenticate
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module TenderSummary
|
2
|
+
class Mailer < ActionMailer::Base
|
3
|
+
self.template_root = File.expand_path("#{File.dirname(__FILE__)}/templates")
|
4
|
+
self.mailer_name = 'mailer'
|
5
|
+
self.delivery_method = :sendmail
|
6
|
+
|
7
|
+
def pending(to, from = nil)
|
8
|
+
discussions = TenderSummary::TenderApi.discussions(:state => :pending)
|
9
|
+
|
10
|
+
from from
|
11
|
+
recipients to
|
12
|
+
subject "Tender pending discussions summary"
|
13
|
+
body :discussions => discussions['discussions'],
|
14
|
+
:site => TenderSummary::TenderApi.site,
|
15
|
+
:name => TenderSummary::TenderApi.site['name']
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
<div style="background-color: rgb(232, 232, 232); text-align: left;" vlink="#0099cc" alink="#0099cc" link="#0099cc" bgcolor="#e8e8e8">
|
2
|
+
|
3
|
+
<center>
|
4
|
+
|
5
|
+
<table cellspacing="0" cellpadding="0" border="0" width="700">
|
6
|
+
<tbody><tr>
|
7
|
+
<td style="padding-top: 20px; padding-bottom: 20px; text-align: left;">
|
8
|
+
<center>
|
9
|
+
<table cellspacing="0" cellpadding="0" border="0" width="650">
|
10
|
+
<tbody><tr>
|
11
|
+
<td style="padding: 0 20px 20px 20px; font-family: Helvetica,sans-serif; font-size: 16px; background-color: rgb(255, 255, 255); text-align: left;">
|
12
|
+
|
13
|
+
<h1 style="font-family: Helvetica,sans-serif; font-size: 28px; color: rgb(51, 51, 51); margin-bottom: 0pt; font-weight: bold;">Your Daily Tender Digest for <a target="blank" href="<%= @site.href(:html)%>"><%= @name %></a></h1>
|
14
|
+
|
15
|
+
<h2 style="margin: 6px 0pt 0pt; font-family: Helvetica,sans-serif; font-size: 16px; color: rgb(119, 119, 119); font-weight: normal;">
|
16
|
+
Discussions marked as pending
|
17
|
+
</h2>
|
18
|
+
</td>
|
19
|
+
</tr>
|
20
|
+
|
21
|
+
<tr>
|
22
|
+
<td style="border-top: 1px solid rgb(204, 204, 204); padding: 20px; font-family: Helvetica,sans-serif; font-size: 14px; background-color: rgb(255, 255, 255); text-align: left;">
|
23
|
+
<p style="color: rgb(204, 51, 51); font-weight: bold; font-size: 16px; margin-bottom: 10px; padding-bottom: 0pt;">Pending discussions:</p>
|
24
|
+
|
25
|
+
<table>
|
26
|
+
<tbody><tr>
|
27
|
+
<td style="padding-left: 20px;">
|
28
|
+
|
29
|
+
<%- @discussions.each do |discussion| -%>
|
30
|
+
<p style="font-weight: normal; font-size: 14px; color: rgb(0, 0, 0); margin-bottom: 2px; padding-bottom: 0pt;">
|
31
|
+
<span style="margin:0 3px; padding:2px 7px 3px 7px; font-size:10px; font-weight:normal; background:#eee; color:#666; text-transform:uppercase; -webkit-border-radius:3px; -moz-border-radius:2px; white-space:nowrap;">
|
32
|
+
<%= discussion['state'] %>
|
33
|
+
</span>
|
34
|
+
|
35
|
+
<a target="_blank" href="<%= discussion.href(:html) %>"><%= discussion["title"] %></a>
|
36
|
+
</p>
|
37
|
+
<table>
|
38
|
+
<tbody><tr>
|
39
|
+
<td style="vertical-align: top; padding-right: 3px;"><span style="font-size: 24px; line-height: 18px;">•</span></td>
|
40
|
+
<td style="font-size: 14px; vertical-align: top; padding-bottom: 3px;">
|
41
|
+
From <%= discussion['last_author_name']%> <<%= discussion['last_author_email'] %>>
|
42
|
+
|
43
|
+
<p style="margin: 0pt; font-weight: normal; color: rgb(119, 119, 119); font-size: 12px;">
|
44
|
+
|
45
|
+
Last updated
|
46
|
+
<strong><%= discussion['last_updated_at'].localtime.to_s(:short) %></strong>
|
47
|
+
—
|
48
|
+
<%- if discussion['public'] -%>
|
49
|
+
<strong>Discussion is public</strong>
|
50
|
+
<%- else -%>
|
51
|
+
Discussion is private
|
52
|
+
<%- end -%>
|
53
|
+
</p>
|
54
|
+
</td>
|
55
|
+
</tr>
|
56
|
+
|
57
|
+
</tbody></table>
|
58
|
+
<%- end -%>
|
59
|
+
|
60
|
+
</td>
|
61
|
+
</tr>
|
62
|
+
</tbody></table>
|
63
|
+
|
64
|
+
</td>
|
65
|
+
</tr>
|
66
|
+
|
67
|
+
<!--
|
68
|
+
<tr>
|
69
|
+
<td style="border-top: 1px solid rgb(204, 204, 204); padding: 20px 20px 30px; font-family: Helvetica,sans-serif; font-size: 14px; background-color: rgb(255, 255, 255); text-align: left;">
|
70
|
+
<p><a target="_blank" style="font-size: 12px; color: rgb(102, 102, 102);" href="#">Unsubscribe to stop receiving updates</a></p>
|
71
|
+
</td>
|
72
|
+
</tr>
|
73
|
+
</tbody></table>
|
74
|
+
-->
|
75
|
+
|
76
|
+
<table cellspacing="0" cellpadding="0" border="0" width="650">
|
77
|
+
<tbody><tr>
|
78
|
+
<td style="padding-top: 10px; padding-bottom: 30px; font-size: 10px; font-family: Verdana,sans-serif; color: rgb(102, 102, 102); text-align: left;">
|
79
|
+
|
80
|
+
</td>
|
81
|
+
</tr>
|
82
|
+
</tbody></table>
|
83
|
+
|
84
|
+
</center>
|
85
|
+
</td>
|
86
|
+
</tr>
|
87
|
+
</tbody></table>
|
88
|
+
|
89
|
+
</center>
|
90
|
+
|
91
|
+
</div>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module TenderSummary
|
2
|
+
class TenderApi
|
3
|
+
include HTTParty
|
4
|
+
|
5
|
+
headers 'Accept' => 'application/vnd.tender-v1+json'
|
6
|
+
format :json
|
7
|
+
parser Proc.new { |body| add_json_helpers(Crack::JSON.parse(body)) }
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_accessor :subdomain, :username, :password
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.authenticate(subdomain = nil, username = nil, password = nil)
|
14
|
+
self.subdomain ||= subdomain
|
15
|
+
self.username ||= username
|
16
|
+
self.password ||= password
|
17
|
+
|
18
|
+
basic_auth(self.username, self.password)
|
19
|
+
base_uri(HTTParty.normalize_base_uri(site_href))
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.discussions(options = {})
|
23
|
+
get(site.href(:discussions, options))
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.site
|
27
|
+
@site ||= get(site_href)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.base
|
31
|
+
@base ||= get('https://api.tenderapp.com/')
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.site_href
|
35
|
+
@site_href ||= base.href('site', :site_permalink => subdomain)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Make the JSON a litte bit more fun to work with
|
39
|
+
def self.add_json_helpers(data)
|
40
|
+
case data
|
41
|
+
when Hash
|
42
|
+
data.send(:extend, TenderSummary::JsonHelpers)
|
43
|
+
data.each { |_, value| add_json_helpers(value) }
|
44
|
+
when Array
|
45
|
+
data.each { |elem| add_json_helpers(elem) }
|
46
|
+
end
|
47
|
+
|
48
|
+
data
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module JsonHelpers
|
53
|
+
def href(key, options = {})
|
54
|
+
Addressable::Template.new(self["#{key}_href"]).expand(options).to_s
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/test/helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tender_summary
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Eric Lindvall
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-19 00:00:00 -08:00
|
13
|
+
default_executable: tender_summary
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: thoughtbot-shoulda
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: yard
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: httparty
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.4.5
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: addressable
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.1.1
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: actionmailer
|
57
|
+
type: :runtime
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ~>
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 2.3.5
|
64
|
+
version:
|
65
|
+
description: A simple tool to email your pending Tender discussions.
|
66
|
+
email: eric@sevenscale.com
|
67
|
+
executables:
|
68
|
+
- tender_summary
|
69
|
+
extensions: []
|
70
|
+
|
71
|
+
extra_rdoc_files:
|
72
|
+
- LICENSE
|
73
|
+
- README.rdoc
|
74
|
+
files:
|
75
|
+
- .document
|
76
|
+
- .gitignore
|
77
|
+
- LICENSE
|
78
|
+
- README.rdoc
|
79
|
+
- Rakefile
|
80
|
+
- VERSION
|
81
|
+
- bin/tender_summary
|
82
|
+
- lib/tender_summary.rb
|
83
|
+
- lib/tender_summary/cli.rb
|
84
|
+
- lib/tender_summary/mailer.rb
|
85
|
+
- lib/tender_summary/templates/mailer/pending.text.html.erb
|
86
|
+
- lib/tender_summary/tender_api.rb
|
87
|
+
- test/helper.rb
|
88
|
+
- test/test_tender-summary.rb
|
89
|
+
has_rdoc: true
|
90
|
+
homepage: http://github.com/eric/tender_summary
|
91
|
+
licenses: []
|
92
|
+
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options:
|
95
|
+
- --charset=UTF-8
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: "0"
|
103
|
+
version:
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: "0"
|
109
|
+
version:
|
110
|
+
requirements: []
|
111
|
+
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 1.3.5
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: A simple tool to email your pending Tender discussions
|
117
|
+
test_files:
|
118
|
+
- test/helper.rb
|
119
|
+
- test/test_tender-summary.rb
|