newslettre 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/README.md +84 -0
- data/Rakefile +13 -0
- data/features/cassettes/cucumber_tags/sendgrid_adding_recipients.yml +185 -0
- data/features/cassettes/cucumber_tags/sendgrid_removing_recipients.yml +208 -0
- data/features/recipients.feature +20 -0
- data/features/step_definitions/recipients_steps.rb +63 -0
- data/features/support/env.rb +25 -0
- data/lib/newslettre.rb +9 -0
- data/lib/newslettre/api_module.rb +17 -0
- data/lib/newslettre/client.rb +49 -0
- data/lib/newslettre/identity.rb +21 -0
- data/lib/newslettre/letter.rb +48 -0
- data/lib/newslettre/lists.rb +49 -0
- data/lib/newslettre/version.rb +3 -0
- data/newslettre.gemspec +29 -0
- data/spec/cassettes/Newslettre/Newslettre_Identity.yml +24 -0
- data/spec/cassettes/Newslettre/Newslettre_Identity/with_a_new_identity.yml +72 -0
- data/spec/cassettes/Newslettre/Newslettre_Letter.yml +24 -0
- data/spec/cassettes/Newslettre/Newslettre_Letter/with_a_new_letter.yml +118 -0
- data/spec/cassettes/Newslettre/Newslettre_Lists.yml +24 -0
- data/spec/cassettes/Newslettre/Newslettre_Lists/with_a_new_list.yml +70 -0
- data/spec/cassettes/Newslettre/Newslettre_Lists_Email.yml +117 -0
- data/spec/cassettes/Newslettre/http_actions.yml +24 -0
- data/spec/cassettes/upon_raising_errors.yml +25 -0
- data/spec/newslettre_spec.rb +174 -0
- data/spec/spec_helper.rb +17 -0
- metadata +158 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
Feature: Managing Recipients for Newsletters
|
2
|
+
Background:
|
3
|
+
Given there is no Newsletter named 'Superior Soy Beans Discount!'
|
4
|
+
And there is no 'Junk-food addicts' Recipient List
|
5
|
+
And there is no identity named 'Bourne'
|
6
|
+
@sendgrid_adding_recipients
|
7
|
+
Scenario: Adding a Recipient List to a Newsletter
|
8
|
+
Given I add the 'Bourne' Identity
|
9
|
+
And I add a Newsletter named 'Superior Soy Beans Discount!' written by 'Bourne'
|
10
|
+
And I add a Recipient List named 'Junk-food addicts'
|
11
|
+
When I add 'Junk-food addicts' to 'Superior Soy Beans Discount!'
|
12
|
+
Then 'Junk-food addicts' will be notified when 'Superior Soy Beans Discount!' is delivered
|
13
|
+
@sendgrid_removing_recipients
|
14
|
+
Scenario: Removing a Recipient List from a Newsletter
|
15
|
+
Given I add the 'Bourne' Identity
|
16
|
+
And I add a Newsletter named 'Superior Soy Beans Discount!' written by 'Bourne'
|
17
|
+
And I add a Recipient List named 'Junk-food addicts'
|
18
|
+
And I add 'Junk-food addicts' to 'Superior Soy Beans Discount!'
|
19
|
+
When I remove 'Junk-food addicts' from 'Superior Soy Beans Discount!'
|
20
|
+
Then no one will be notified when 'Superior Soy Beans Discount!' is delivered
|
@@ -0,0 +1,63 @@
|
|
1
|
+
Given /^there is no Newsletter named '([^']+)'$/ do |name|
|
2
|
+
begin
|
3
|
+
Newslettre::Letter.new(newslettre).delete name
|
4
|
+
rescue Newslettre::Client::ClientFailure
|
5
|
+
nil
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /^there is no '([^']+)' Recipient List$/ do |list|
|
10
|
+
begin
|
11
|
+
Newslettre::Lists.new(newslettre).delete list
|
12
|
+
rescue Newslettre::Client::ClientFailure
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Given /^there is no identity named '([^']+)'$/ do |identity|
|
18
|
+
begin
|
19
|
+
Newslettre::Identity.new(newslettre).delete identity
|
20
|
+
rescue Newslettre::Client::ClientFailure
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Given /^I add the '([^']+)' Identity$/ do |identity|
|
26
|
+
Newslettre::Identity.new(newslettre).add identity, NEWSLETTRE_CONFIG['identity']
|
27
|
+
end
|
28
|
+
|
29
|
+
Given /^I add a Newsletter named '([^']+)' written by '([^']+)'$/ do |name, identity|
|
30
|
+
Newslettre::Letter.new(newslettre).add name,
|
31
|
+
:identity => identity,
|
32
|
+
:subject => name,
|
33
|
+
:text => "Super Cool!",
|
34
|
+
:html => "<h1>meow</h1>"
|
35
|
+
end
|
36
|
+
|
37
|
+
Given /^I add a Recipient List named '([^']+)'$/ do |list|
|
38
|
+
Newslettre::Lists.new(newslettre).add list
|
39
|
+
end
|
40
|
+
|
41
|
+
When /^I add '([^']+)' to '([^']+)'$/ do |list, name|
|
42
|
+
recipients = Newslettre::Letter::Recipients.new name, newslettre
|
43
|
+
|
44
|
+
recipients.add list
|
45
|
+
end
|
46
|
+
|
47
|
+
When /^I remove '([^']+)' from '([^']+)'$/ do |list, name|
|
48
|
+
recipients = Newslettre::Letter::Recipients.new name, newslettre
|
49
|
+
|
50
|
+
recipients.delete list
|
51
|
+
end
|
52
|
+
|
53
|
+
Then /^'([^']+)' will be notified when '([^']+)' is delivered$/ do |list, name|
|
54
|
+
recipients = Newslettre::Letter::Recipients.new name, newslettre
|
55
|
+
lists = recipients.get
|
56
|
+
lists.should =~ [{ "list" => list }]
|
57
|
+
end
|
58
|
+
|
59
|
+
Then /^no one will be notified when '([^']+)' is delivered$/ do |name|
|
60
|
+
recipients = Newslettre::Letter::Recipients.new name, newslettre
|
61
|
+
lists = recipients.get
|
62
|
+
lists.should be_empty
|
63
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
NEWSLETTRE_CONFIG = YAML.load_file File.dirname(__FILE__) + "/../../config/newslettre.yml"
|
2
|
+
|
3
|
+
require 'vcr'
|
4
|
+
require 'newslettre'
|
5
|
+
|
6
|
+
VCR.config do |c|
|
7
|
+
c.stub_with :webmock
|
8
|
+
c.cassette_library_dir = 'features/cassettes'
|
9
|
+
c.filter_sensitive_data('<<USERNAME>>') { NEWSLETTRE_CONFIG['sendgrid']['username'] }
|
10
|
+
c.filter_sensitive_data('<<PASSWORD>>') { NEWSLETTRE_CONFIG['sendgrid']['password'] }
|
11
|
+
c.default_cassette_options = { :record => :once }
|
12
|
+
end
|
13
|
+
|
14
|
+
VCR.cucumber_tags do |t|
|
15
|
+
t.tags '@sendgrid_adding_recipients', '@sendgrid_removing_recipients'
|
16
|
+
end
|
17
|
+
|
18
|
+
class OuterWorld
|
19
|
+
def newslettre
|
20
|
+
@newslettre ||= Newslettre::Client.new(:email => NEWSLETTRE_CONFIG['sendgrid']['username'],
|
21
|
+
:password => NEWSLETTRE_CONFIG['sendgrid']['password'])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
World { OuterWorld.new }
|
data/lib/newslettre.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Newslettre::APIModule
|
2
|
+
attr_reader :client
|
3
|
+
|
4
|
+
def initialize client
|
5
|
+
@client = client
|
6
|
+
end
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
def api_prefix
|
11
|
+
"/#{self.class.name.split(/::/).last.downcase}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def request method, data = {}
|
15
|
+
self.client.send method, data, { :prefix => api_prefix }
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Newslettre::Client
|
2
|
+
include HTTParty
|
3
|
+
format :json
|
4
|
+
attr_reader :email, :password, :format
|
5
|
+
|
6
|
+
|
7
|
+
def initialize options = {}
|
8
|
+
self.class.base_uri "https://sendgrid.com/api/newsletter"
|
9
|
+
@email = options.delete :email
|
10
|
+
@password = options.delete :password
|
11
|
+
@format = "json"
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def url
|
16
|
+
@url ||= self.class.default_options[:base_uri]
|
17
|
+
end
|
18
|
+
|
19
|
+
%w{get list add delete edit}.each do |m|
|
20
|
+
define_method m do |*args|
|
21
|
+
params, options = args
|
22
|
+
params ||= {}
|
23
|
+
options ||= {}
|
24
|
+
response = self.class.post url_for(m, options), :query => params.merge(credentials)
|
25
|
+
raise ClientFailure if response.code > 399 and response.code < 500
|
26
|
+
raise EndpointFailure if response.code > 499
|
27
|
+
response
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
alias_method :post, :add
|
32
|
+
alias_method :put, :edit
|
33
|
+
|
34
|
+
class ClientFailure < StandardError; end
|
35
|
+
class EndpointFailure < StandardError; end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def credentials
|
40
|
+
{
|
41
|
+
:api_user => email,
|
42
|
+
:api_key => password
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def url_for path, options = {}
|
47
|
+
"#{options[:prefix]}/#{path}.#{format}"
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Newslettre::Identity < Newslettre::APIModule
|
2
|
+
def list
|
3
|
+
request 'list'
|
4
|
+
end
|
5
|
+
|
6
|
+
def get id
|
7
|
+
request 'get', :identity => id
|
8
|
+
end
|
9
|
+
|
10
|
+
def add id, data = {}
|
11
|
+
request 'add', data.merge(:identity => id)
|
12
|
+
end
|
13
|
+
|
14
|
+
def edit id, data = {}
|
15
|
+
request 'edit', data.merge(:identity => id)
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete id
|
19
|
+
request 'delete', :identity => id
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Newslettre::Letter < Newslettre::APIModule
|
2
|
+
def list
|
3
|
+
request 'list'
|
4
|
+
end
|
5
|
+
|
6
|
+
def add name, data = {}
|
7
|
+
request 'add', data.merge(:name => name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def get name
|
11
|
+
request 'get', :name => name
|
12
|
+
end
|
13
|
+
|
14
|
+
def delete name
|
15
|
+
request 'delete', :name => name
|
16
|
+
end
|
17
|
+
|
18
|
+
def edit name, data = {}
|
19
|
+
request 'edit', data
|
20
|
+
end
|
21
|
+
|
22
|
+
class Recipients < Newslettre::APIModule
|
23
|
+
attr_reader :letter
|
24
|
+
|
25
|
+
def initialize letter, client
|
26
|
+
@letter = letter
|
27
|
+
@client = client
|
28
|
+
end
|
29
|
+
|
30
|
+
def add list
|
31
|
+
request 'add', { :list => list, :name => letter }
|
32
|
+
end
|
33
|
+
|
34
|
+
def get
|
35
|
+
request 'get', { :name => letter }
|
36
|
+
end
|
37
|
+
|
38
|
+
def delete list
|
39
|
+
request 'delete', { :list => list, :name => letter }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
def api_prefix
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Newslettre::Lists < Newslettre::APIModule
|
2
|
+
def add list, data = {}
|
3
|
+
request 'add', data.merge(:list => list)
|
4
|
+
end
|
5
|
+
|
6
|
+
def get list = nil
|
7
|
+
if list.nil?
|
8
|
+
request 'get'
|
9
|
+
else
|
10
|
+
request('get', :list => list).first
|
11
|
+
end
|
12
|
+
end
|
13
|
+
alias_method :list, :get
|
14
|
+
|
15
|
+
def edit list, data = {}
|
16
|
+
request 'edit', data.merge(:list => list)
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete list
|
20
|
+
request 'delete', :list => list
|
21
|
+
end
|
22
|
+
|
23
|
+
class Email < Newslettre::APIModule
|
24
|
+
attr_reader :list
|
25
|
+
|
26
|
+
def initialize list, client
|
27
|
+
@client = client
|
28
|
+
@list = list
|
29
|
+
end
|
30
|
+
|
31
|
+
def add *recipients
|
32
|
+
request 'add', :list => list, :data => recipients.map{|r| JSON.dump(r) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def get *recipients
|
36
|
+
request 'get', :list => list, :email => recipients
|
37
|
+
end
|
38
|
+
|
39
|
+
def delete *recipients
|
40
|
+
request 'delete', :list => list, :email => recipients
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
def api_prefix
|
46
|
+
"/lists/email"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/newslettre.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "newslettre/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "newslettre"
|
7
|
+
s.version = Newslettre::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Lennart Melzer"]
|
10
|
+
s.email = ["l@melzer.it"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Sendgrid Newsletter API Client}
|
13
|
+
s.description = %q{Create and Manage Newsletters using the Sendgrid API}
|
14
|
+
|
15
|
+
s.rubyforge_project = "newslettre"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency "httparty", "~> 0.8"
|
23
|
+
|
24
|
+
s.add_development_dependency "rake", "~> 0.9"
|
25
|
+
s.add_development_dependency "rspec", "~> 2"
|
26
|
+
s.add_development_dependency "webmock", "~> 1.7"
|
27
|
+
s.add_development_dependency "vcr", "~> 1.11"
|
28
|
+
s.add_development_dependency "cucumber", "~> 1"
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
---
|
2
|
+
- !ruby/struct:VCR::HTTPInteraction
|
3
|
+
request: !ruby/struct:VCR::Request
|
4
|
+
method: :post
|
5
|
+
uri: https://sendgrid.com:443/api/newsletter/identity/list.json?api_key=<<PASSWORD>>&api_user=<<USERNAME>>
|
6
|
+
body: !!null
|
7
|
+
headers: !!null
|
8
|
+
response: !ruby/struct:VCR::Response
|
9
|
+
status: !ruby/struct:VCR::ResponseStatus
|
10
|
+
code: 200
|
11
|
+
message: OK
|
12
|
+
headers:
|
13
|
+
server:
|
14
|
+
- nginx/0.7.65
|
15
|
+
date:
|
16
|
+
- Tue, 20 Sep 2011 14:26:55 GMT
|
17
|
+
content-type:
|
18
|
+
- text/html
|
19
|
+
transfer-encoding:
|
20
|
+
- chunked
|
21
|
+
connection:
|
22
|
+
- keep-alive
|
23
|
+
body: ! '[{"identity": "da9febf06480f7bb88264fc907f75995"}]'
|
24
|
+
http_version: '1.1'
|
@@ -0,0 +1,72 @@
|
|
1
|
+
---
|
2
|
+
- !ruby/struct:VCR::HTTPInteraction
|
3
|
+
request: !ruby/struct:VCR::Request
|
4
|
+
method: :post
|
5
|
+
uri: https://sendgrid.com:443/api/newsletter/identity/add.json?address=Oranienstra%C3%9Fe%206&api_key=<<PASSWORD>>&api_user=<<USERNAME>>&city=Berlin&country=DE&email=<<USERNAME>>&identity=test-identity&name=Mathias%20Fiedler&state=B&zip=10997
|
6
|
+
body: !!null
|
7
|
+
headers: !!null
|
8
|
+
response: !ruby/struct:VCR::Response
|
9
|
+
status: !ruby/struct:VCR::ResponseStatus
|
10
|
+
code: 200
|
11
|
+
message: OK
|
12
|
+
headers:
|
13
|
+
server:
|
14
|
+
- nginx/0.7.65
|
15
|
+
date:
|
16
|
+
- Tue, 20 Sep 2011 14:26:56 GMT
|
17
|
+
content-type:
|
18
|
+
- text/html
|
19
|
+
transfer-encoding:
|
20
|
+
- chunked
|
21
|
+
connection:
|
22
|
+
- keep-alive
|
23
|
+
body: ! '{"message": "success"}'
|
24
|
+
http_version: '1.1'
|
25
|
+
- !ruby/struct:VCR::HTTPInteraction
|
26
|
+
request: !ruby/struct:VCR::Request
|
27
|
+
method: :post
|
28
|
+
uri: https://sendgrid.com:443/api/newsletter/identity/get.json?api_key=<<PASSWORD>>&api_user=<<USERNAME>>&identity=test-identity
|
29
|
+
body: !!null
|
30
|
+
headers: !!null
|
31
|
+
response: !ruby/struct:VCR::Response
|
32
|
+
status: !ruby/struct:VCR::ResponseStatus
|
33
|
+
code: 200
|
34
|
+
message: OK
|
35
|
+
headers:
|
36
|
+
server:
|
37
|
+
- nginx/0.7.65
|
38
|
+
date:
|
39
|
+
- Tue, 20 Sep 2011 14:26:57 GMT
|
40
|
+
content-type:
|
41
|
+
- text/html
|
42
|
+
transfer-encoding:
|
43
|
+
- chunked
|
44
|
+
connection:
|
45
|
+
- keep-alive
|
46
|
+
body: ! '{"city": "Berlin", "name": "Mathias Fiedler", "zip": "10997", "country":
|
47
|
+
"DE", "state": "B", "address": "Oranienstra\u00dfe 6", "email": "<<USERNAME>>",
|
48
|
+
"identity": "test-identity"}'
|
49
|
+
http_version: '1.1'
|
50
|
+
- !ruby/struct:VCR::HTTPInteraction
|
51
|
+
request: !ruby/struct:VCR::Request
|
52
|
+
method: :post
|
53
|
+
uri: https://sendgrid.com:443/api/newsletter/identity/delete.json?api_key=<<PASSWORD>>&api_user=<<USERNAME>>&identity=test-identity
|
54
|
+
body: !!null
|
55
|
+
headers: !!null
|
56
|
+
response: !ruby/struct:VCR::Response
|
57
|
+
status: !ruby/struct:VCR::ResponseStatus
|
58
|
+
code: 200
|
59
|
+
message: OK
|
60
|
+
headers:
|
61
|
+
server:
|
62
|
+
- nginx/0.7.65
|
63
|
+
date:
|
64
|
+
- Tue, 20 Sep 2011 14:26:58 GMT
|
65
|
+
content-type:
|
66
|
+
- text/html
|
67
|
+
transfer-encoding:
|
68
|
+
- chunked
|
69
|
+
connection:
|
70
|
+
- keep-alive
|
71
|
+
body: ! '{"message": "success"}'
|
72
|
+
http_version: '1.1'
|