pomade 0.1.1 → 0.1.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,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pomade.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Jake Bellacera
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -1,129 +1,2 @@
1
- require 'ntlm/http'
2
- require 'nokogiri'
3
-
4
- class Pomade
5
- def initialize(subdomain, username, password, client_id, opts = {})
6
- @subdomain = subdomain
7
- @username = username
8
- @password = password
9
- @client_id = client_id
10
-
11
- # Other options
12
- @options = {}
13
- @options[:domain] = opts[:domain] || 'timessquare2.com'
14
- @options[:pathname] = opts[:pathname] || '/p/p.svc/Assets/'
15
- @options[:time_format] = opts[:time_format] || "%Y-%m-%dT%H:%M:%SZ"
16
- @options[:login_domain] = opts[:login_domain] || nil
17
- @options[:debug] = opts[:debug] || false
18
- end
19
-
20
- def publish(record)
21
- # You should set up a record like this:
22
- # { :id, :data => [ {:target, :type, :value}, ... ] }
23
- puts "Available options: #{@options}" if @options[:debug]
24
- @time = Time.now.strftime(@options[:time_format])
25
-
26
- xmls = []
27
- record[:data].each do |r|
28
- xmls << build_xml(record[:id], r[:target], r[:type], r[:value])
29
- end
30
-
31
- post(xmls)
32
- end
33
-
34
- private
35
-
36
- def post(data)
37
- response_data = []
38
- data.each do |xml|
39
- req = send_request(xml)
40
-
41
- if req[:code] == "201"
42
- puts "===> SUCCESS!" if @options[:debug]
43
- response_data << req[:data]
44
- else
45
- if req[:code] == "401"
46
- # TODO: Tell user that we couldn't authenticate
47
- puts "===> ERROR! Authentication" if @options[:debug]
48
- elsif req[:code] == "400"
49
- # TODO: Tell the user there was a formatting error
50
- puts "===> ERROR! Formatting" if @options[:debug]
51
- else
52
- # TODO: Tell the user an unknown error has occured
53
- puts "===> ERROR Unknown" if @options[:debug]
54
- end
55
- response_data = false
56
- break
57
- end
58
- end
59
-
60
- response_data
61
- end
62
-
63
- def send_request(body)
64
- status = false
65
- data = false
66
- code = ""
67
-
68
- puts "Initializing request for #{@subdomain + '.' + @options[:domain]}" if @options[:debug]
69
- Net::HTTP.start("#{@subdomain}.#{@options[:domain]}", 80) do |http|
70
- req = Net::HTTP::Post.new(@options[:pathname])
71
-
72
- req.content_type = 'application/atom+xml'
73
- req.content_length = body.size - 20 # Currently a bug with the Pomegranate API I believe
74
- req.body = body
75
- req.ntlm_auth(@username, @options[:login_domain], @password)
76
-
77
- response = http.request(req)
78
- puts response.inspect if @options[:debug]
79
-
80
- code = response.code
81
-
82
- if code == "201"
83
- data = parse_xml(response.body)
84
- else
85
- break
86
- end
87
- end
88
-
89
- {:code => code, :data => data}
90
- end
91
-
92
- def build_xml(record_id, target, type, value)
93
- <<-EOF.gsub(/^ {6}/, '')
94
- <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>
95
- <entry
96
- xml:base="/p/p.svc/"
97
- xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
98
- xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
99
- xmlns="http://www.w3.org/2005/Atom">
100
- <id></id>
101
- <title type="text"></title>
102
- <updated>#{@time}</updated>
103
- <author><name /></author>
104
- <category term="pomegranateModel.Asset" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
105
- <content type="application/xml">
106
- <m:properties>
107
- <d:AssetID>--</d:AssetID>
108
- <d:AssetData>#{value}</d:AssetData>
109
- <d:AssetType>#{type}</d:AssetType>
110
- <d:AssetMeta></d:AssetMeta>
111
- <d:AssetRecordID>#{record_id}</d:AssetRecordID>
112
- <d:Target>#{target}</d:Target>
113
- <d:Client>#{@client_id}</d:Client>
114
- <d:Status>APPROVED</d:Status>
115
- </m:properties>
116
- </content>
117
- </entry>
118
- EOF
119
- end
120
-
121
- def parse_xml(xml)
122
- parsed_xml = Nokogiri::XML(xml.gsub(/\n|\r| /, ""))
123
- data = {}
124
- parsed_xml.css('m|properties').children.each do |p|
125
- data[p.name] = p.content
126
- end
127
- data
128
- end
129
- end
1
+ require "pomade/version"
2
+ require "pomade/publisher"
@@ -0,0 +1,202 @@
1
+ require "securerandom"
2
+ require "ntlm/http"
3
+ require "nokogiri"
4
+
5
+ module Pomade
6
+ class Publisher
7
+ # Public: Creates a new instance of Publisher that pushes records to
8
+ # Pomegranate.
9
+ #
10
+ # Parameters:
11
+ #
12
+ # subdomain - [string] The subdomain for the Pomegranate instance that
13
+ # you'd like to connect to.
14
+ # username - [string] The username used for connecting to your instance.
15
+ # password - [string] The password used for connecting to your instance.
16
+ # client_id - [string] Your client ID.
17
+ # opts - [hash] (optional) Additional options.
18
+ #
19
+ # Available options are:
20
+ # host - [string] The host (domain name) that Pomegranate lives on.
21
+ # pathname - [string] The path that is used for interacting with
22
+ # Pomegranate.
23
+ # time_format - [string] (strftime) change the layout of the timestamp
24
+ # domain - [string] NTLM login domain.
25
+ # debug - [boolean] Turns on debug mode. This will print out
26
+ # any activity.
27
+ #
28
+ # Returns:
29
+ #
30
+ # Returns an instance of Pomade::Publisher
31
+ #
32
+ # Example:
33
+ #
34
+ # @pom = Pom.new('my-subdomain', 'myusername', 'mypassword', 'XX')
35
+ def initialize(subdomain, username, password, client_id, opts = {})
36
+ @subdomain = subdomain
37
+ @username = username
38
+ @password = password
39
+ @client_id = client_id
40
+
41
+ # Other options
42
+ @options = {}
43
+ @options[:host] = opts[:host] || 'timessquare2.com'
44
+ @options[:pathname] = opts[:pathname] || '/p/p.svc/Assets/'
45
+ @options[:time_format] = opts[:time_format] || "%Y-%m-%dT%H:%M:%SZ"
46
+ @options[:domain] = opts[:domain] || nil
47
+ @options[:debug] = opts[:debug] || false
48
+ end
49
+
50
+ # Public: Publishes an array of assets to Pomegranate
51
+ #
52
+ # Parameters:
53
+ #
54
+ # assets - [array] A collection of assets. Each item consits of a hash with
55
+ # three keys: { target: "", type: "", value: "" }
56
+ #
57
+ # Returns:
58
+ #
59
+ # A hash containing two keys: record_id and assets.
60
+ #
61
+ # Example:
62
+ #
63
+ # records = [
64
+ # { target: "XX~USERNAME", type: "TEXT", value: "jakebellacera"},
65
+ # { target: "XX~AVATAR", type: "IMAGE", value: "http://www.gravatar.com/avatar/98363013aa1237798130bc0fd2c4159d.png"}
66
+ # ]
67
+ # @pom.publish(records)
68
+ # #=> {
69
+ # record_id: "XX-91c8071a-1201-4f99-bc9d-f8d53a947dc1",
70
+ # assets: [
71
+ # {"AssetID"=>"9a24c8e2-1066-42fb-be1c-697c5ead476d", "AssetData"=>"jakebellacera", "AssetType"=>"TEXT", "Target"=>"NS~USERNAME", "Client"=>"XX", "Status"=>"APPROVED", "AssetMeta"=>"", "AssetRecordID"=>"XX-91c8071a-1201-4f99-bc9d-f8d53a947dc1"},
72
+ # {"AssetID"=>"9a24c8e2-1066-42fb-be1c-697c5ead476d", "AssetData"=>"http://www.gravatar.com/avatar/98363013aa1237798130bc0fd2c4159d.png", "AssetType"=>"IMAGE", "Target"=>"XX~Avatar", "Client"=>"XX", "Status"=>"APPROVED", "AssetMeta"=>"", "AssetRecordID"=>"XX-91c8071a-1201-4f99-bc9d-f8d53a947dc1"}
73
+ # ]
74
+ # }
75
+ def publish(assets)
76
+ puts "Available options: #{@options}" if @options[:debug]
77
+ @time = Time.now.strftime(@options[:time_format])
78
+ @record_id = generate_record_id
79
+
80
+ xmls = []
81
+ assets.each do |r|
82
+ xmls << build_xml(@record_id, r[:target], r[:type].upcase, r[:value])
83
+ end
84
+
85
+ return {
86
+ record_id: @record_id,
87
+ assets: post(xmls)
88
+ }
89
+ end
90
+
91
+ # Public: Generates a record ID
92
+ #
93
+ # Parameters:
94
+ #
95
+ # None
96
+ #
97
+ # Returns:
98
+ #
99
+ # Returns a string containing the client_id with a UUID appended to it.
100
+ def generate_record_id
101
+ @client_id + '-' + SecureRandom.uuid
102
+ end
103
+
104
+ private
105
+
106
+ def post(data)
107
+ response_data = []
108
+ data.each do |xml|
109
+ puts xml if @options[:debug]
110
+
111
+ req = send_request(xml)
112
+
113
+ if req[:code] == "201"
114
+ puts "===> SUCCESS!" if @options[:debug]
115
+ response_data << req[:data]
116
+ else
117
+ if req[:code] == "401"
118
+ # TODO: Tell user that we couldn't authenticate
119
+ puts "===> ERROR! Authentication" if @options[:debug]
120
+ elsif req[:code] == "400"
121
+ # TODO: Tell the user there was a formatting error
122
+ puts "===> ERROR! Formatting" if @options[:debug]
123
+ else
124
+ # TODO: Tell the user an unknown error has occured
125
+ puts "===> ERROR Unknown" if @options[:debug]
126
+ end
127
+ response_data = false
128
+ break
129
+ end
130
+ end
131
+
132
+ response_data
133
+ end
134
+
135
+ def send_request(body)
136
+ status = false
137
+ data = false
138
+ code = ""
139
+
140
+ puts "Initializing request for #{@subdomain + '.' + @options[:host]}" if @options[:debug]
141
+ Net::HTTP.start("#{@subdomain}.#{@options[:host]}", 80) do |http|
142
+ req = Net::HTTP::Post.new(@options[:pathname])
143
+
144
+ req.content_type = 'application/atom+xml'
145
+ req.content_length = body.size - 20 # Currently a bug with the Pomegranate API I believe
146
+ req.body = body
147
+ req.ntlm_auth(@username, @options[:domain], @password)
148
+
149
+ response = http.request(req)
150
+ puts response.inspect if @options[:debug]
151
+
152
+ code = response.code
153
+
154
+ if code == "201"
155
+ data = parse_xml(response.body)
156
+ else
157
+ break
158
+ end
159
+ end
160
+
161
+ {:code => code, :data => data}
162
+ end
163
+
164
+ def build_xml(record_id, target, type, value)
165
+ <<-EOF.gsub(/^ {8}/, '')
166
+ <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>
167
+ <entry
168
+ xml:base="/p/p.svc/"
169
+ xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
170
+ xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
171
+ xmlns="http://www.w3.org/2005/Atom">
172
+ <id></id>
173
+ <title type="text"></title>
174
+ <updated>#{@time}</updated>
175
+ <author><name /></author>
176
+ <category term="pomegranateModel.Asset" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
177
+ <content type="application/xml">
178
+ <m:properties>
179
+ <d:AssetID>--</d:AssetID>
180
+ <d:AssetData>#{value}</d:AssetData>
181
+ <d:AssetType>#{type}</d:AssetType>
182
+ <d:AssetMeta></d:AssetMeta>
183
+ <d:AssetRecordID>#{record_id}</d:AssetRecordID>
184
+ <d:Target>#{target}</d:Target>
185
+ <d:Client>#{@client_id}</d:Client>
186
+ <d:Status>APPROVED</d:Status>
187
+ </m:properties>
188
+ </content>
189
+ </entry>
190
+ EOF
191
+ end
192
+
193
+ def parse_xml(xml)
194
+ parsed_xml = Nokogiri::XML(xml.gsub(/\n|\r| /, ""))
195
+ data = {}
196
+ parsed_xml.css('m|properties').children.each do |p|
197
+ data[p.name] = p.content
198
+ end
199
+ data
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,3 @@
1
+ module Pomade
2
+ VERSION = "0.1.2"
3
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pomade/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "pomade"
8
+ gem.version = Pomade::VERSION
9
+ gem.authors = ["Jake Bellacera"]
10
+ gem.email = ["hi@jakebellacera.com"]
11
+ gem.description = "Pomegranate API Wrapper"
12
+ gem.summary = "Ruby wrapper for TimesSquare2's Pomegranate API"
13
+ gem.homepage = "http://github.com/jakebellacera/pomade"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency('ruby-ntlm', '~> 0.0.1')
21
+ gem.add_dependency('nokogiri', '~> 1.5.5')
22
+ end
@@ -0,0 +1,88 @@
1
+ # Pomade - The ruby Pomegranate API wrapper
2
+
3
+ Pomade is a gem that acts as an API wrapper used for interfacing with TimesSquare2's [Pomegranate API](http://api.timessquare2.com/pomegranate/).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'pomade'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install pomade
18
+
19
+ ## Publisher
20
+
21
+ Publisher lets you publish content to the Pomegranate API.
22
+
23
+ ```ruby
24
+ Pomade::Publisher.new(subdomain, username, password, client_id, options)
25
+ ```
26
+
27
+ #### Available Options
28
+
29
+ These are the available options and their defaults.
30
+
31
+ ```ruby
32
+ {
33
+ domain: 'timessquare2.com', # This string appends to the subdomain
34
+ pathname: '/p/p.svc/Assets/', # The path where you send POST requests to
35
+ time_format: "%Y-%m-%dT%H:%M:%SZ", # strftime format for sending timestamps
36
+ login_domain: nil, # Optional domain attribute for authenticating via NTLM
37
+ debug: false # Prints debugging output
38
+ }
39
+ ```
40
+
41
+ To publish assets to Pomegranate, simply create a new Publisher instance.
42
+
43
+ ### Usage
44
+
45
+ ```ruby
46
+ @pom = Pomade::Publisher.new('my-subdomain', 'myusername', 'mypassword', 'XX')
47
+ ```
48
+
49
+ Next, you'll want to push your assets to Pomegranate. You can do this by building an array of hashes. Each item in the array represents a single asset and they each have three keys: **target**, **type** and **value**. You'll pass this array into the `publisher#push` method.
50
+
51
+ ```ruby
52
+ assets = [
53
+ { target: "XX~USERNAME", type: "TEXT", value: "jakebellacera"},
54
+ { target: "XX~AVATAR", type: "IMAGE", value: "http://www.gravatar.com/avatar/98363013aa1237798130bc0fd2c4159d.png"}
55
+ ]
56
+
57
+ record = @pom.publish(assets)
58
+ ```
59
+
60
+ The `Publisher#publish` method will return a **record**. A record is a hash with two keys: **record_id** and **assets**. The record_id is a randomly generated UUID string with your client_id prepended to it while the assets array is the posted assets. If assets is false, then the records failed to push to Pomegranate.
61
+
62
+ ```ruby
63
+ puts record
64
+ #=> {
65
+ record_id: "XX-91c8071a-1201-4f99-bc9d-f8d53a947dc1",
66
+ assets: [
67
+ {"AssetID"=>"9a24c8e2-1066-42fb-be1c-697c5ead476d", "AssetData"=>"jakebellacera", "AssetType"=>"TEXT", "Target"=>"NS~USERNAME", "Client"=>"XX", "Status"=>"APPROVED", "AssetMeta"=>"", "AssetRecordID"=>"XX-91c8071a-1201-4f99-bc9d-f8d53a947dc1"},
68
+ {"AssetID"=>"9a24c8e2-1066-42fb-be1c-697c5ead476d", "AssetData"=>"http://www.gravatar.com/avatar/98363013aa1237798130bc0fd2c4159d.png", "AssetType"=>"IMAGE", "Target"=>"XX~Avatar", "Client"=>"XX", "Status"=>"APPROVED", "AssetMeta"=>"", "AssetRecordID"=>"XX-91c8071a-1201-4f99-bc9d-f8d53a947dc1"}
69
+ ]
70
+ }
71
+ ```
72
+
73
+ #### Debugging
74
+
75
+ Sometimes Pomegranate will not be able to accept your request. If you're getting a 400 error, it's most likely a formatting issue. Since the errors returned by Pomegranate are not very verbose, it's best to run through a simple checklist instead:
76
+
77
+ * Ensure that your login info is correct. You can test in your browser by logging in via HTTPS at `<subdomain>.timessquare2.com`. If you'd like to use cURL or something else, connect via NTLM.
78
+ * Make sure that the targets and types for each asset are correct. Targets will vary from client to client.
79
+ * Try creating a pomegranate with the `debug` option set to `true` and try again.
80
+ * If all else fails, you can try submitting an [issue](https://github.com/jakebellacera/pomade/issues). Please be specific in your bug report.
81
+
82
+ ## Contributing
83
+
84
+ 1. Fork it
85
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
86
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
87
+ 4. Push to the branch (`git push origin my-new-feature`)
88
+ 5. Create new Pull Request
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pomade
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-04 00:00:00.000000000 Z
12
+ date: 2012-09-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ruby-ntlm
@@ -43,13 +43,22 @@ dependencies:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
45
  version: 1.5.5
46
- description: Ruby wrapper for TimeSquare2's Pomegranate API
47
- email: hi@jakebellacera.com
46
+ description: Pomegranate API Wrapper
47
+ email:
48
+ - hi@jakebellacera.com
48
49
  executables: []
49
50
  extensions: []
50
51
  extra_rdoc_files: []
51
52
  files:
53
+ - .gitignore
54
+ - Gemfile
55
+ - LICENSE.txt
56
+ - Rakefile
52
57
  - lib/pomade.rb
58
+ - lib/pomade/publisher.rb
59
+ - lib/pomade/version.rb
60
+ - pomade.gemspec
61
+ - readme.md
53
62
  homepage: http://github.com/jakebellacera/pomade
54
63
  licenses: []
55
64
  post_install_message:
@@ -61,7 +70,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
61
70
  requirements:
62
71
  - - ! '>='
63
72
  - !ruby/object:Gem::Version
64
- version: 1.9.3
73
+ version: '0'
65
74
  required_rubygems_version: !ruby/object:Gem::Requirement
66
75
  none: false
67
76
  requirements:
@@ -73,6 +82,6 @@ rubyforge_project:
73
82
  rubygems_version: 1.8.24
74
83
  signing_key:
75
84
  specification_version: 3
76
- summary: Pomegranate API Wrapper
85
+ summary: Ruby wrapper for TimesSquare2's Pomegranate API
77
86
  test_files: []
78
- has_rdoc: false
87
+ has_rdoc: