pomade 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: