cupid 0.2.4 → 0.3.2

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,53 @@
1
+ class Cupid
2
+ module Response
3
+ class Format
4
+ IGNORE = [:partner_key, :object_id]
5
+ RENAME = {
6
+ :new_id => :id,
7
+ :'@xsi:type' => :type,
8
+ :parent_folder => :parent_data
9
+ }
10
+
11
+ def self.apply(data)
12
+ formatted = new data
13
+ formatted.data
14
+ end
15
+
16
+ attr_reader :data
17
+
18
+ def initialize(data)
19
+ @data = data
20
+ extract_nested_data
21
+ rename_fields
22
+ delete_ignored_fields
23
+ delete_empty_parents
24
+ end
25
+
26
+ private
27
+
28
+ def extract_nested_data
29
+ data.merge! data.delete(:object) if data[:object]
30
+ end
31
+
32
+ def rename_fields
33
+ RENAME.each do |old_name, new_name|
34
+ next unless data[old_name]
35
+ data[new_name] = data.delete old_name
36
+ end
37
+ end
38
+
39
+ def delete_ignored_fields(data=@data)
40
+ data.delete_if do |key, value|
41
+ delete_ignored_fields value if value.is_a? Hash
42
+ IGNORE.include? key
43
+ end
44
+ end
45
+
46
+ def delete_empty_parents
47
+ if (data[:parent_data] || {})[:id] == '0'
48
+ data.delete :parent_data
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,40 @@
1
+ class Cupid
2
+ module Response
3
+ class Object
4
+ def self.fields(*names)
5
+ names.each do |name|
6
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
7
+ def #{name}
8
+ data[:#{name}]
9
+ end
10
+ RUBY
11
+ end
12
+ end
13
+
14
+ attr_reader :data
15
+ fields :id, :customer_key
16
+
17
+ def initialize(data)
18
+ @data = data
19
+ end
20
+
21
+ # Hook into gyoku
22
+ def call
23
+ id
24
+ end
25
+
26
+ def type
27
+ instance_of?(Object) ? self[:type] : self.class
28
+ end
29
+
30
+ def ==(object)
31
+ return false unless object.is_a? Cupid::Response::Object
32
+ id and [id, type] == [object.id, object.type]
33
+ end
34
+
35
+ def [](field)
36
+ data[field]
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,63 @@
1
+ class Cupid
2
+ module Retrieve
3
+ LIST_FIELDS = %w(ID ListName CustomerKey)
4
+ EMAIL_FIELDS = %w(ID Name)
5
+ FOLDER_FIELDS = %w(ID Name ParentFolder.ID ParentFolder.Name)
6
+ DELIVERY_FIELDS = %w(ID Status)
7
+ UI_EMAIL_FIELDS = %w(CustomerKey Name Email.ID EmailSubject CategoryID)
8
+
9
+ def emails(name=nil, *fields)
10
+ retrieve 'Email',
11
+ EMAIL_FIELDS + fields,
12
+ filter_email_like(name)
13
+ end
14
+
15
+ def ui_emails(folder=nil, *fields)
16
+ retrieve 'EmailSendDefinition',
17
+ UI_EMAIL_FIELDS + fields,
18
+ filter_by_folder(folder)
19
+ end
20
+
21
+ def folders(*fields)
22
+ data_folders 'email', *fields
23
+ end
24
+
25
+ def ui_folders(*fields)
26
+ data_folders 'userinitiated', *fields
27
+ end
28
+
29
+ def lists(*fields)
30
+ retrieve 'List', LIST_FIELDS + fields
31
+ end
32
+
33
+ def deliveries(*fields)
34
+ retrieve 'Send', DELIVERY_FIELDS + fields
35
+ end
36
+
37
+ private
38
+
39
+ def retrieve(type, fields, options={})
40
+ resources :retrieve, :retrieve_request => {
41
+ :object_type => type,
42
+ :properties => fields,
43
+ 'ClientIDs' => { 'ID' => server.account }
44
+ }.merge(options)
45
+ end
46
+
47
+ def data_folders(type, *fields)
48
+ retrieve 'DataFolder', FOLDER_FIELDS + fields, filter_folders(type)
49
+ end
50
+
51
+ def filter_folders(type)
52
+ server.filter 'ContentType', 'like', type
53
+ end
54
+
55
+ def filter_email_like(name)
56
+ server.filter 'Name', 'like', name
57
+ end
58
+
59
+ def filter_by_folder(id)
60
+ server.filter 'CategoryID', 'equals', id
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,58 @@
1
+ class Cupid
2
+ module Schedule
3
+
4
+ def schedule(ui, time, options={})
5
+ resource :schedule, :action => 'start',
6
+ :options => schedule_options,
7
+ :schedule => schedule_fields(time.iso8601, options),
8
+ :interactions => interactions_fields(ui.customer_key)
9
+ end
10
+
11
+ private
12
+
13
+ def schedule_fields(time, options)
14
+ {
15
+ :recurrence => {
16
+ :daily_recurrence_pattern_type => 'Interval',
17
+ :day_interval => 1
18
+ },
19
+ :attributes! => {
20
+ :recurrence => {
21
+ 'xsi:type' => 'DailyRecurrence'
22
+ }
23
+ },
24
+ :recurrence_type => 'Daily',
25
+ :recurrence_range_type => 'EndAfter',
26
+ :start_date_time => time,
27
+ :occurrences => 1
28
+ }.merge options
29
+ end
30
+
31
+ def schedule_options
32
+ {
33
+ :client => {
34
+ 'ID' => server.account
35
+ },
36
+ :attributes! => {
37
+ :client => {
38
+ 'xsi:type' => 'ClientID'
39
+ }
40
+ }
41
+ }
42
+ end
43
+
44
+ def interactions_fields(ui_key)
45
+ {
46
+ :interaction => {
47
+ :customer_key => ui_key
48
+ },
49
+ :attributes! => {
50
+ :interaction => {
51
+ 'xsi:type' => 'EmailSendDefinition'
52
+ }
53
+ }
54
+ }
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,62 @@
1
+ class Cupid
2
+ class Server
3
+ INPUT_NAMES = {
4
+ :version_info => 'VersionInfoRequestMsg',
5
+ :get_system_status => 'SystemStatusRequestMsg',
6
+ :retrieve => 'RetrieveRequestMsg',
7
+ :schedule => 'ScheduleRequestMsg',
8
+ :create => 'CreateRequest',
9
+ :delete => 'DeleteRequest',
10
+ :update => 'UpdateRequest'
11
+ }
12
+
13
+ attr_reader :account
14
+
15
+ def initialize(account)
16
+ @account = account
17
+ end
18
+
19
+ def input(action)
20
+ [INPUT_NAMES.fetch(action), { :xmlns => Cupid::NAMESPACE }]
21
+ end
22
+
23
+ def filter(field, operator, value)
24
+ return {} unless value
25
+ {
26
+ :filter => {
27
+ :property => field,
28
+ :simple_operator => operator,
29
+ :value => value
30
+ },
31
+ :attributes! => {
32
+ :filter => { 'xsi:type' => 'SimpleFilterPart' }
33
+ }
34
+ }
35
+ end
36
+
37
+ def objects(type, objects)
38
+ {
39
+ :objects => objects.map {|object|
40
+ {
41
+ :client => { 'ID' => account },
42
+ }.merge(object)
43
+ },
44
+ :attributes! => {
45
+ :objects => { 'xsi:type' => type }
46
+ }
47
+ }
48
+ end
49
+
50
+ def object(type, options)
51
+ objects type, [options]
52
+ end
53
+
54
+ def emails(ids)
55
+ objects 'Email', ids.map {|it| { 'ID' => it }}
56
+ end
57
+
58
+ def folders(ids)
59
+ objects 'DataFolder', ids.map {|it| { 'ID' => it }}
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,15 @@
1
+ class Cupid
2
+ module Update
3
+ def ui_set_email(ui, email)
4
+ resource :update, ui_data(ui, email)
5
+ end
6
+
7
+ private
8
+
9
+ def ui_data(ui, email)
10
+ server.object 'EmailSendDefinition',
11
+ :customer_key => ui.customer_key,
12
+ :email => { 'ID' => email }
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
- module Cupid
2
- VERSION = '0.2.4'
1
+ class Cupid
2
+ VERSION = "0.3.2"
3
3
  end
@@ -0,0 +1,48 @@
1
+ describe Cupid::Create do
2
+ subject { Cupid::Test }
3
+
4
+ def uniq_name(label)
5
+ "#{label} #{Time.now.to_i}"
6
+ end
7
+
8
+ shared_examples_for :creation do
9
+ it { creation.should be }
10
+ it { expect { creation }.to change { subject.send(items).size }.by 1 }
11
+ end
12
+
13
+ context '#create_folder' do
14
+ let(:parent) { subject.folders.first }
15
+ let(:name) { uniq_name :folder }
16
+ let(:items) { :folders }
17
+ let(:creation) { subject.create_folder name, parent }
18
+
19
+ it_should_behave_like :creation
20
+ end
21
+
22
+ context '#create_email' do
23
+ let(:name) { uniq_name :subject }
24
+ let(:items) { :emails }
25
+ let(:creation) { subject.create_email name, :body }
26
+
27
+ it_should_behave_like :creation
28
+ end
29
+
30
+ context '#create_delivery' do
31
+ let(:email) { subject.emails.last }
32
+ let(:list) { subject.lists.find {|it| it[:list_name] == 'Test send' }}
33
+ let(:items) { :deliveries }
34
+ let(:creation) { subject.create_delivery email, list }
35
+
36
+ it_should_behave_like :creation
37
+ end
38
+
39
+ context '#create_path' do
40
+ let(:new_folders) {['my emails', Time.now.to_i, 'level2', 'level3']}
41
+
42
+ it do
43
+ expect {
44
+ subject.create_path *new_folders
45
+ }.to change { subject.folders.size }.by new_folders.size - 1
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ describe Cupid::Delete do
2
+ subject { Cupid::Test }
3
+
4
+ shared_examples_for 'deletion' do
5
+ let(:email) { subject.create_email email_name, 'body' }
6
+ let(:email_name) { 'subject' }
7
+
8
+ it { deletion.should be }
9
+ it { subject.emails.should_not include(email) }
10
+ end
11
+
12
+ context '#delete_emails' do
13
+ let(:deletion) { subject.delete_emails email }
14
+ it_should_behave_like 'deletion'
15
+ end
16
+
17
+ context '#delete_emails_like' do
18
+ let(:deletion) { subject.delete_emails_like email_name }
19
+ it_should_behave_like 'deletion'
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ describe Cupid::Response::Caster, '.create' do
2
+ subject { described_class.create :type => type }
3
+ Cupid::Response::SomeType = Class.new Cupid::Response::Object
4
+
5
+ context 'no type' do
6
+ let(:type) { nil }
7
+ it { should be_a Cupid::Response::Object }
8
+ end
9
+
10
+ context 'type without class' do
11
+ let(:type) { :type_without_class }
12
+ it { should be_a Cupid::Response::Object }
13
+ end
14
+
15
+ context 'type with class' do
16
+ let(:type) { :some_type }
17
+ it { should be_a Cupid::Response::SomeType }
18
+ end
19
+ end
@@ -0,0 +1,51 @@
1
+ describe Cupid::Response::Data do
2
+ subject { described_class.from response }
3
+
4
+ let(:response) {{
5
+ :body => {
6
+ :overall_status => status,
7
+ :results => result
8
+ }
9
+ }}
10
+
11
+ describe 'unsuccessful response' do
12
+ let(:status) { 'some error' }
13
+
14
+ shared_examples_for 'response error' do
15
+ it { expect { subject }.to raise_exception described_class::Error, error_text }
16
+ end
17
+
18
+ context 'with status message' do
19
+ let(:result) {{ :status_message => error_text }}
20
+ let(:error_text) { 'bad_request' }
21
+
22
+ it_should_behave_like 'response error'
23
+ end
24
+
25
+ context 'without status message' do
26
+ let(:result) { nil }
27
+ let(:error_text) { status }
28
+
29
+ it_should_behave_like 'response error'
30
+ end
31
+ end
32
+
33
+ describe 'successful reponse' do
34
+ let(:status) { 'OK' }
35
+
36
+ context 'without results' do
37
+ let(:result) { nil }
38
+ it { should == [] }
39
+ end
40
+
41
+ context 'with one result' do
42
+ let(:result) {{ :field => :value }}
43
+ it { should == [{ :field => :value }] }
44
+ end
45
+
46
+ context 'with multiple results' do
47
+ let(:result) { [:object1, :object2] }
48
+ it { should == [:object1, :object2] }
49
+ end
50
+ end
51
+ end