newslettre 0.0.1
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/.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'
|