postmark 1.5.0 → 1.6.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d99b2b07a9b385d8373eb4f0f020806d4ead30fc
4
- data.tar.gz: 56f731c91f3d7a660e56c896d5666ee65c177ec1
3
+ metadata.gz: 17d7c0c5ea350fd8902efaa8e8334dff894fe215
4
+ data.tar.gz: 17f7871d1544d69b7cf16d75c4ba260048de182c
5
5
  SHA512:
6
- metadata.gz: 1e0545eb81715e7a0d436557498f4cb0c3196fed8964ca8e0bc51699d2e944faacbb269cd8bfc1be537564983b2932a789738d2a9a0ba4271d2487371c3de61c
7
- data.tar.gz: 6c5f27e71506ef94a7efb1f07bd14438f9f9403f9d1a209434dab722c3a96e57448e937d02f8da0f394596e4d3e800e2d5baf67cf2ec793e856ae7b364d8abf9
6
+ metadata.gz: 38df57ae61ce36c80870832444d017083e1bff043901823eb675384ae25df1366f420170abf41059a7601d7a6a2c7e26866a15abf8c5b98fa7fa30b7d8cbeeb8
7
+ data.tar.gz: 4dcacb79aec065cf65445da357f0b3e275911da17881291124dacd70b0bccacb1a3d69b4779f34f010692b7667710a0e0b6c8214a00af557b65d86746fc0a499
@@ -1,5 +1,9 @@
1
1
  = Changelog
2
2
 
3
+ == 1.6.0
4
+
5
+ * Add methods to access new templates API endpoints.
6
+
3
7
  == 1.5.0
4
8
 
5
9
  * Call API access strings tokens instead of keys. Keep backwards compatibility.
data/README.md CHANGED
@@ -160,6 +160,22 @@ client.deliver(from: 'sheldon@bigbangtheory.com',
160
160
  # => {:to=>"Leonard Hofstadter <leonard@bigbangtheory.com>, Penny <penny@bigbangtheory.com>", :submitted_at=>"2013-05-09T05:04:16.3247488-04:00", :message_id=>"d647c5d6-xxxx-466d-9411-557dcd5c2297", :error_code=>0, :message=>"OK"}
161
161
  ```
162
162
 
163
+ ## Sending a templated email
164
+
165
+ If you have a [template created](https://github.com/wildbit/postmark-gem/wiki/The-Templates-API-support) in Postmark you can send an email using that template.
166
+
167
+ ``` ruby
168
+ client.deliver_with_template(from: 'sheldon@bigbangtheory.com',
169
+ to: 'Penny <penny@bigbangtheory.com>',
170
+ template_id: 123,
171
+ template_model: {
172
+ name: 'Penny',
173
+ message: 'Bazinga!'
174
+ })
175
+
176
+ # => {:to=>"Penny <penny@bigbangtheory.com>", :submitted_at=>"2013-05-09T03:00:55.4454938-04:00", :message_id=>"34aed4b3-3a95-xxxx-bd1d-88064909cc93", :error_code=>0, :message=>"OK"}
177
+ ```
178
+
163
179
  ## Sending in batches
164
180
 
165
181
  While Postmark is focused on transactional email, we understand that developers
@@ -544,6 +560,10 @@ Postmark allows you to automatically scale your sending infrastructure with the
544
560
 
545
561
  If you ever need to access your messages or their metadata (i.e. open tracking info), [the Messages API](https://github.com/wildbit/postmark-gem/wiki/The-Messages-API-support) is a great place to start.
546
562
 
563
+ ## The Templates API Support
564
+
565
+ [The Templates API](https://github.com/wildbit/postmark-gem/wiki/The-Templates-API-support) can be used to fully manage your templates.
566
+
547
567
  ## ActiveModel-like Interface For Bounces
548
568
 
549
569
  To provide an interface similar to ActiveModel for bounces, the Postmark gem adds
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.5.0
1
+ 1.6.0
@@ -165,6 +165,62 @@ module Postmark
165
165
  format_response http_client.put("server", serialize(data))
166
166
  end
167
167
 
168
+ def get_templates(options = {})
169
+ load_batch('templates', 'Templates', options)
170
+ end
171
+
172
+ def templates(options = {})
173
+ find_each('templates', 'Templates', options)
174
+ end
175
+
176
+ def get_template(id)
177
+ format_response http_client.get("templates/#{id}")
178
+ end
179
+
180
+ def create_template(attributes = {})
181
+ data = serialize(HashHelper.to_postmark(attributes))
182
+
183
+ format_response http_client.post('templates', data)
184
+ end
185
+
186
+ def update_template(id, attributes = {})
187
+ data = serialize(HashHelper.to_postmark(attributes))
188
+
189
+ format_response http_client.put("templates/#{id}", data)
190
+ end
191
+
192
+ def delete_template(id)
193
+ format_response http_client.delete("templates/#{id}")
194
+ end
195
+
196
+ def validate_template(attributes = {})
197
+ data = serialize(HashHelper.to_postmark(attributes))
198
+ response = format_response(http_client.post('templates/validate', data))
199
+
200
+ response.each do |k, v|
201
+ next unless v.is_a?(Hash) && k != :suggested_template_model
202
+
203
+ response[k] = HashHelper.to_ruby(v)
204
+
205
+ if response[k].has_key?(:validation_errors)
206
+ ruby_hashes = response[k][:validation_errors].map do |err|
207
+ HashHelper.to_ruby(err)
208
+ end
209
+ response[k][:validation_errors] = ruby_hashes
210
+ end
211
+ end
212
+
213
+ response
214
+ end
215
+
216
+ def deliver_with_template(attributes = {})
217
+ data = serialize(MessageHelper.to_postmark(attributes))
218
+
219
+ with_retries do
220
+ format_response http_client.post('email/withTemplate', data)
221
+ end
222
+ end
223
+
168
224
  protected
169
225
 
170
226
  def in_batches(messages)
@@ -195,4 +251,4 @@ module Postmark
195
251
  end
196
252
 
197
253
  end
198
- end
254
+ end
@@ -1,3 +1,3 @@
1
1
  module Postmark
2
- VERSION = '1.5.0'
2
+ VERSION = '1.6.0'
3
3
  end
@@ -572,4 +572,259 @@ describe Postmark::ApiClient do
572
572
  end
573
573
  end
574
574
 
575
- end
575
+ describe '#get_templates' do
576
+ let(:http_client) { subject.http_client }
577
+ let(:response) do
578
+ {
579
+ 'TotalCount' => 31,
580
+ 'Templates' => [
581
+ {
582
+ 'Active' => true,
583
+ 'TemplateId' => 123,
584
+ 'Name' => 'ABC'
585
+ },
586
+ {
587
+ 'Active' => true,
588
+ 'TemplateId' => 456,
589
+ 'Name' => 'DEF'
590
+ }
591
+ ]
592
+ }
593
+ end
594
+
595
+ it 'gets templates info and converts it to ruby format' do
596
+ http_client.should_receive(:get).with('templates', :offset => 0, :count => 2).and_return(response)
597
+
598
+ count, templates = subject.get_templates(:count => 2)
599
+
600
+ expect(count).to eq(31)
601
+ expect(templates.first[:template_id]).to eq(123)
602
+ expect(templates.first[:name]).to eq('ABC')
603
+ end
604
+ end
605
+
606
+ describe '#templates' do
607
+ it 'returns an Enumerator' do
608
+ expect(subject.templates).to be_kind_of(Enumerable)
609
+ end
610
+
611
+ it 'requests data at /templates' do
612
+ allow(subject.http_client).to receive(:get).
613
+ with('templates', an_instance_of(Hash)).
614
+ and_return('TotalCount' => 1, 'Templates' => [{}])
615
+ expect(subject.templates.first(5).count).to eq(1)
616
+ end
617
+ end
618
+
619
+ describe '#get_template' do
620
+ let(:http_client) { subject.http_client }
621
+ let(:response) do
622
+ {
623
+ 'Name' => 'Template Name',
624
+ 'TemplateId' => 123,
625
+ 'Subject' => 'Subject',
626
+ 'HtmlBody' => 'Html',
627
+ 'TextBody' => 'Text',
628
+ 'AssociatedServerId' => 456,
629
+ 'Active' => true
630
+ }
631
+ end
632
+
633
+ it 'gets single template and converts it to ruby format' do
634
+ http_client.should_receive(:get).with('templates/123').and_return(response)
635
+
636
+ template = subject.get_template('123')
637
+
638
+ expect(template[:name]).to eq('Template Name')
639
+ expect(template[:template_id]).to eq(123)
640
+ expect(template[:html_body]).to eq('Html')
641
+ end
642
+ end
643
+
644
+ describe '#create_template' do
645
+ let(:http_client) { subject.http_client }
646
+ let(:response) do
647
+ {
648
+ 'TemplateId' => 123,
649
+ 'Name' => 'template name',
650
+ 'Active' => true
651
+ }
652
+ end
653
+
654
+ it 'performs a POST request to /templates with the given attributes' do
655
+ expected_json = { 'Name' => 'template name' }.to_json
656
+
657
+ http_client.should_receive(:post).with('templates', expected_json).and_return(response)
658
+
659
+ template = subject.create_template(:name => 'template name')
660
+
661
+ expect(template[:name]).to eq('template name')
662
+ expect(template[:template_id]).to eq(123)
663
+ end
664
+ end
665
+
666
+ describe '#update_template' do
667
+ let(:http_client) { subject.http_client }
668
+ let(:response) do
669
+ {
670
+ 'TemplateId' => 123,
671
+ 'Name' => 'template name',
672
+ 'Active' => true
673
+ }
674
+ end
675
+
676
+ it 'performs a PUT request to /templates with the given attributes' do
677
+ expected_json = { 'Name' => 'template name' }.to_json
678
+
679
+ http_client.should_receive(:put).with('templates/123', expected_json).and_return(response)
680
+
681
+ template = subject.update_template(123, :name => 'template name')
682
+
683
+ expect(template[:name]).to eq('template name')
684
+ expect(template[:template_id]).to eq(123)
685
+ end
686
+ end
687
+
688
+ describe '#delete_template' do
689
+ let(:http_client) { subject.http_client }
690
+ let(:response) do
691
+ {
692
+ 'ErrorCode' => 0,
693
+ 'Message' => 'Template 123 removed.'
694
+ }
695
+ end
696
+
697
+ it 'performs a DELETE request to /templates/:id' do
698
+ http_client.should_receive(:delete).with('templates/123').and_return(response)
699
+
700
+ resp = subject.delete_template(123)
701
+
702
+ expect(resp[:error_code]).to eq(0)
703
+ end
704
+ end
705
+
706
+ describe '#validate_template' do
707
+ let(:http_client) { subject.http_client }
708
+
709
+ context 'when template is valid' do
710
+ let(:response) do
711
+ {
712
+ 'AllContentIsValid' => true,
713
+ 'HtmlBody' => {
714
+ 'ContentIsValid' => true,
715
+ 'ValidationErrors' => [],
716
+ 'RenderedContent' => '<html><head></head><body>MyName_Value</body></html>'
717
+ },
718
+ 'TextBody' => {
719
+ 'ContentIsValid' => true,
720
+ 'ValidationErrors' => [],
721
+ 'RenderedContent' => 'MyName_Value'
722
+ },
723
+ 'Subject' => {
724
+ 'ContentIsValid' => true,
725
+ 'ValidationErrors' => [],
726
+ 'RenderedContent' => 'MyName_Value'
727
+ },
728
+ 'SuggestedTemplateModel' => {
729
+ 'MyName' => 'MyName_Value'
730
+ }
731
+ }
732
+ end
733
+
734
+ it 'performs a POST request and returns unmodified suggested template model' do
735
+ expected_template_json = {
736
+ 'HtmlBody' => '{{MyName}}',
737
+ 'TextBody' => '{{MyName}}',
738
+ 'Subject' => '{{MyName}}'
739
+ }.to_json
740
+
741
+ http_client.should_receive(:post).with('templates/validate', expected_template_json).and_return(response)
742
+
743
+ resp = subject.validate_template(:html_body => '{{MyName}}',
744
+ :text_body => '{{MyName}}',
745
+ :subject => '{{MyName}}')
746
+
747
+ expect(resp[:all_content_is_valid]).to be_true
748
+ expect(resp[:html_body][:content_is_valid]).to be_true
749
+ expect(resp[:html_body][:validation_errors]).to be_empty
750
+ expect(resp[:suggested_template_model]['MyName']).to eq('MyName_Value')
751
+ end
752
+ end
753
+
754
+ context 'when template is invalid' do
755
+ let(:response) do
756
+ {
757
+ 'AllContentIsValid' => false,
758
+ 'HtmlBody' => {
759
+ 'ContentIsValid' => false,
760
+ 'ValidationErrors' => [
761
+ {
762
+ 'Message' => 'The \'each\' block being opened requires a model path to be specified in the form \'{#each <name>}\'.',
763
+ 'Line' => 1,
764
+ 'CharacterPosition' => 1
765
+ }
766
+ ],
767
+ 'RenderedContent' => nil
768
+ },
769
+ 'TextBody' => {
770
+ 'ContentIsValid' => true,
771
+ 'ValidationErrors' => [],
772
+ 'RenderedContent' => 'MyName_Value'
773
+ },
774
+ 'Subject' => {
775
+ 'ContentIsValid' => true,
776
+ 'ValidationErrors' => [],
777
+ 'RenderedContent' => 'MyName_Value'
778
+ },
779
+ 'SuggestedTemplateModel' => nil
780
+ }
781
+ end
782
+
783
+ it 'performs a POST request and returns validation errors' do
784
+ expected_template_json = {
785
+ 'HtmlBody' => '{{#each}}',
786
+ 'TextBody' => '{{MyName}}',
787
+ 'Subject' => '{{MyName}}'
788
+ }.to_json
789
+
790
+ http_client.should_receive(:post).with('templates/validate', expected_template_json).and_return(response)
791
+
792
+ resp = subject.validate_template(:html_body => '{{#each}}',
793
+ :text_body => '{{MyName}}',
794
+ :subject => '{{MyName}}')
795
+
796
+ expect(resp[:all_content_is_valid]).to be_false
797
+ expect(resp[:text_body][:content_is_valid]).to be_true
798
+ expect(resp[:html_body][:content_is_valid]).to be_false
799
+ expect(resp[:html_body][:validation_errors].first[:character_position]).to eq(1)
800
+ expect(resp[:html_body][:validation_errors].first[:message]).to eq('The \'each\' block being opened requires a model path to be specified in the form \'{#each <name>}\'.')
801
+ end
802
+ end
803
+ end
804
+
805
+ describe "#deliver_with_template" do
806
+ let(:email) { Postmark::MessageHelper.to_postmark(message_hash) }
807
+ let(:email_json) { Postmark::Json.encode(email) }
808
+ let(:http_client) { subject.http_client }
809
+ let(:response) { {"MessageID" => 42} }
810
+
811
+ it 'converts message hash to Postmark format and posts it to /email/withTemplate' do
812
+ http_client.should_receive(:post).with('email/withTemplate', email_json) { response }
813
+ subject.deliver_with_template(message_hash)
814
+ end
815
+
816
+ it 'retries 3 times' do
817
+ 2.times do
818
+ http_client.should_receive(:post).and_raise(Postmark::InternalServerError)
819
+ end
820
+ http_client.should_receive(:post) { response }
821
+ expect { subject.deliver_with_template(message_hash) }.not_to raise_error
822
+ end
823
+
824
+ it 'converts response to ruby format' do
825
+ http_client.should_receive(:post).with('email/withTemplate', email_json) { response }
826
+ r = subject.deliver_with_template(message_hash)
827
+ r.should have_key(:message_id)
828
+ end
829
+ end
830
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postmark
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Petyo Ivanov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-01-05 00:00:00.000000000 Z
13
+ date: 2015-08-04 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rake
@@ -141,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
141
  version: 1.3.7
142
142
  requirements: []
143
143
  rubyforge_project:
144
- rubygems_version: 2.2.2
144
+ rubygems_version: 2.4.5
145
145
  signing_key:
146
146
  specification_version: 4
147
147
  summary: Official Postmark API wrapper.