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.
@@ -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 }
@@ -0,0 +1,9 @@
1
+ require 'httparty'
2
+
3
+ module Newslettre
4
+ autoload :Client, 'newslettre/client'
5
+ autoload :APIModule, 'newslettre/api_module'
6
+ autoload :Letter, 'newslettre/letter'
7
+ autoload :Identity, 'newslettre/identity'
8
+ autoload :Lists, 'newslettre/lists'
9
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ module Newslettre
2
+ VERSION = "0.0.1"
3
+ end
@@ -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'