socialcast 1.3.13 → 1.3.14

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: e47c7a2ae5e15e428bb10de22c9c82314e7b3cae
4
- data.tar.gz: a9eb506a41820efa452980829fcc0f49f22ae24a
3
+ metadata.gz: 9de45230b2671da6dbe2c97752900207a128bb08
4
+ data.tar.gz: 2d24c42f2afbfba3c82cca8a3b592b7fe53f0cdc
5
5
  SHA512:
6
- metadata.gz: 0199e8f8d5ef41ccbcda5c9f83a0dfedbb170f63718681f31431b8df98ab2a347e0818a1368898be5171adb77eed1ef46a421c7f359e6067856d9e7ee6496ed2
7
- data.tar.gz: 2f8e999cc04e34c4bfb975f0579c044dba57e811a58351ca10aacb696a6daa73caa867ab7f311725eb808c2496a6c7c1ed37073dde8392ec087542fb81a14ae1
6
+ metadata.gz: c876a5f5b3e9865dfca6507d3b03e40cd0521af86418572dc0111f0f1037b3c4d75840dc490e793be901594a905cd65565be8abc026862fc29ada3e804215e63
7
+ data.tar.gz: ecfebccebe6e9180a68682d2dd52a7141960b0d05e3993e38c46a82f0bd67b9a4a94d7d4e34e2dfb5aa7f22e8c8000216d4d65aaff8de47f1082fcf9e09be3cf
@@ -2,93 +2,83 @@ module Socialcast
2
2
  module CommandLine
3
3
  class ProvisionPhoto
4
4
  include Socialcast::CommandLine::Provisioner
5
- attr_accessor :users
6
- MAX_BATCH_SIZE = 50
7
5
 
8
- def sync
9
- @ldap_config['connections'].keys.each do |connection_name|
10
- LDAPConnector.attribute_mappings_for(connection_name, @ldap_config).fetch(LDAPConnector::PROFILE_PHOTO_ATTRIBUTE)
11
- end
6
+ attr_accessor :sync_strategy
12
7
 
13
- init_users
8
+ def sync(strategy_klass = ApiSyncStrategy)
9
+ assert_ldap_connections_support_photo!
10
+ sync_strategy = strategy_klass.new(self)
11
+ process_options = {
12
+ :http_config => http_config,
13
+ :force_sync => @options[:force_sync]
14
+ }
14
15
 
15
- each_ldap_connector do |connector|
16
- connector.each_photo_hash do |photo_hash|
17
- email = photo_hash[LDAPConnector::EMAIL_ATTRIBUTE]
18
- users[email] = photo_hash[LDAPConnector::PROFILE_PHOTO_ATTRIBUTE]
19
- handle_batch if users.size >= MAX_BATCH_SIZE
16
+ user_photos = {}
17
+
18
+ each_photo_hash do |photo_hash|
19
+ email = photo_hash[LDAPConnector::EMAIL_ATTRIBUTE]
20
+ user_photos[email] = photo_hash[LDAPConnector::PROFILE_PHOTO_ATTRIBUTE]
21
+ if user_photos.size >= sync_strategy.batch_size
22
+ sync_strategy.process(user_photos, process_options)
23
+ user_photos = {}
20
24
  end
21
25
  end
22
26
 
23
- handle_batch if users.any?
27
+ sync_strategy.process(user_photos, process_options) if user_photos.any?
24
28
  end
25
29
 
26
- private
30
+ def photo_data_to_file(profile_photo_data)
31
+ if profile_photo_data.start_with?('http')
32
+ profile_photo_data = download_photo_data(profile_photo_data)
33
+ return unless profile_photo_data
34
+ end
27
35
 
28
- def init_users
29
- @users = {}
30
- end
36
+ ## FORCE ENCODING
37
+ profile_photo_data = profile_photo_data.force_encoding('binary')
31
38
 
32
- def handle_batch
33
- users.each_slice(MAX_BATCH_SIZE) do |user_batch|
34
- search_users_resource = Socialcast::CommandLine.resource_for_path '/api/users/search', http_config
35
- user_emails_query = user_batch.map { |u| "\"#{u[0]}\"" }.join(" OR ")
36
- user_search_response = search_users_resource.get(:params => { :q => user_emails_query, :per_page => MAX_BATCH_SIZE }, :accept => :json)
37
- JSON.parse(user_search_response)['users'].each do |user_hash|
38
- sync_photo_for(user_hash)
39
- end
39
+ ## CONTENT TYPE
40
+ unless content_type = binary_to_content_type(profile_photo_data)
41
+ log "Skipping photo: unknown image format (supports .gif, .png, .jpg)"
42
+ return
40
43
  end
41
44
 
42
- init_users
45
+ ## WRITE TEMP FILE
46
+ Tempfile.new(["photo_upload", ".#{content_type}"]).tap do |tempfile|
47
+ tempfile.binmode
48
+ tempfile.write(profile_photo_data)
49
+ tempfile.rewind
50
+ end
43
51
  end
44
52
 
45
- def sync_photo_for(user_hash)
46
- is_system_default = user_hash && user_hash['avatars'] && user_hash['avatars']['is_system_default']
47
- is_community_default = user_hash && user_hash['avatars'] && (user_hash['avatars']['id'] == default_profile_photo_id)
48
- user_email = user_hash && user_hash['contact_info'] && user_hash['contact_info']['email']
49
- return unless is_system_default || is_community_default || @options[:force_sync]
50
-
51
- ## PHOTO URL TO BINARY
52
- if profile_photo_data = users[user_email]
53
- if profile_photo_data.start_with?('http')
54
- begin
55
- profile_photo_data = RestClient.get(profile_photo_data)
56
- rescue => e
57
- puts "Unable to download photo #{profile_photo_data} for #{user_email}"
58
- puts e.response
59
- return
60
- end
61
- end
53
+ def default_profile_photo_id
54
+ @default_profile_photo_id ||= Socialcast::CommandLine::Authenticate.current_user['community']['default_profile_photo_id']
55
+ end
62
56
 
63
- ## FORCE ENCODING
64
- profile_photo_data = profile_photo_data.force_encoding('binary')
57
+ protected
65
58
 
66
- ## CONTENT TYPE
67
- unless content_type = binary_to_content_type(profile_photo_data)
68
- puts "Skipping photo for #{user_email}: unknown image format (supports .gif, .png, .jpg)"
69
- return
59
+ def each_photo_hash
60
+ each_ldap_connector do |connector|
61
+ connector.each_photo_hash do |photo_hash|
62
+ yield photo_hash
70
63
  end
64
+ end
65
+ end
71
66
 
72
- ## WRITE TEMP FILE
73
- tempfile = Tempfile.new(["photo_upload", ".#{content_type}"])
74
- tempfile.binmode
75
- tempfile.write(profile_photo_data)
76
- tempfile.rewind
77
-
78
- puts "Uploading photo for #{user_email}"
79
-
80
- ## SUBMIT PHOTO
81
- begin
82
- user_resource = Socialcast::CommandLine.resource_for_path "/api/users/#{user_hash['id']}", http_config
83
- user_resource.put({ :user => { :profile_photo => { :data => tempfile } } })
84
- ensure
85
- tempfile.unlink
67
+ def assert_ldap_connections_support_photo!
68
+ @ldap_config['connections'].each do |connection_name, _|
69
+ unless LDAPConnector.attribute_mappings_for(connection_name, @ldap_config).key? LDAPConnector::PROFILE_PHOTO_ATTRIBUTE
70
+ message = "Cannot sync photos: #{connection_name} does not have a mapping for the profile photo field."
71
+ log(message)
72
+ raise Socialcast::CommandLine::Provisioner::ProvisionError, message
86
73
  end
87
74
  end
88
75
  end
89
76
 
90
- def default_profile_photo_id
91
- @default_profile_photo_id ||= Socialcast::CommandLine::Authenticate.current_user['community']['default_profile_photo_id']
77
+ def download_photo_data(profile_photo_data)
78
+ RestClient.get(profile_photo_data)
79
+ rescue => e
80
+ log "Unable to download photo #{profile_photo_data}"
81
+ log e.response
92
82
  end
93
83
 
94
84
  def binary_to_content_type(binary_photo_data)
@@ -101,6 +91,64 @@ module Socialcast
101
91
  'jpg'
102
92
  end
103
93
  end
94
+
95
+ class ApiSyncStrategy
96
+ attr_reader :provisioner
97
+ attr_reader :http_config
98
+
99
+ MAX_BATCH_SIZE = 50
100
+
101
+ def initialize(provisioner, options = {})
102
+ @provisioner = provisioner
103
+ end
104
+
105
+ def process(user_photos, options = {})
106
+ @http_config = options[:http_config]
107
+ @force_sync = options[:force_sync]
108
+
109
+ search_users_resource = Socialcast::CommandLine.resource_for_path '/api/users/search', http_config
110
+ user_emails_query = user_photos.map { |email, _| "\"#{email}\"" }.join(" OR ")
111
+ user_search_response = search_users_resource.get(:params => { :q => user_emails_query, :per_page => batch_size }, :accept => :json)
112
+ JSON.parse(user_search_response)['users'].each do |user_hash|
113
+ email = user_hash['contact_info']['email']
114
+ sync_photo(user_hash, user_photos[email])
115
+ end
116
+ end
117
+
118
+ def batch_size
119
+ MAX_BATCH_SIZE
120
+ end
121
+
122
+ private
123
+
124
+ def sync_photo(user_hash, profile_photo_data)
125
+ is_system_default = user_hash && user_hash['avatars'] && user_hash['avatars']['is_system_default']
126
+ is_community_default = user_hash && user_hash['avatars'] && (user_hash['avatars']['id'] == provisioner.default_profile_photo_id)
127
+ user_email = user_hash && user_hash['contact_info'] && user_hash['contact_info']['email']
128
+ return unless is_system_default || is_community_default || force_sync?
129
+
130
+ log "Syncing photo for #{user_email}"
131
+
132
+ if profile_photo_data && file = provisioner.photo_data_to_file(profile_photo_data)
133
+ begin
134
+ log "Uploading photo for #{user_email}"
135
+ user_resource = Socialcast::CommandLine.resource_for_path "/api/users/#{user_hash['id']}", http_config
136
+ user_resource.put({ :user => { :profile_photo => { :data => file } } })
137
+ ensure
138
+ file.unlink
139
+ end
140
+ end
141
+ end
142
+
143
+ def force_sync?
144
+ !!@force_sync
145
+ end
146
+
147
+ def log(message)
148
+ provisioner.send(:log, message)
149
+ end
150
+ end
151
+
104
152
  end
105
153
  end
106
154
  end
@@ -45,7 +45,7 @@ module Socialcast
45
45
  if user_whitelist.empty? && !@options[:force]
46
46
  raise ProvisionError.new "Skipping upload to Socialcast since no users were found"
47
47
  else
48
- puts "Uploading dataset to Socialcast..."
48
+ log "Uploading dataset to Socialcast..."
49
49
  resource = Socialcast::CommandLine.resource_for_path '/api/users/provision', params
50
50
  begin
51
51
  File.open(output_file, 'r') do |file|
@@ -58,7 +58,7 @@ module Socialcast
58
58
  rescue RestClient::Unauthorized => e
59
59
  raise ProvisionError.new "Authenticated user either does not have administration privileges or the community is not configured to allow provisioning. Please contact Socialcast support to if you need help." if e.http_code == 401
60
60
  end
61
- puts "Finished"
61
+ log "Finished"
62
62
  end
63
63
  File.delete(output_file) if (@ldap_config.fetch('options', {})['delete_users_file'] || @options[:delete_users_file])
64
64
  end
@@ -40,7 +40,11 @@ module Socialcast
40
40
  puts "Scanned #{count} users" if ((count % 100) == 0)
41
41
  end
42
42
  end
43
- puts "Finished scanning #{count} users"
43
+ log "Finished scanning #{count} users"
44
+ end
45
+
46
+ def log(message)
47
+ $stdout.puts message
44
48
  end
45
49
  end
46
50
  end
@@ -1,5 +1,5 @@
1
1
  module Socialcast
2
2
  module CommandLine
3
- VERSION = "1.3.13"
3
+ VERSION = "1.3.14"
4
4
  end
5
5
  end
@@ -168,7 +168,7 @@ describe Socialcast::CommandLine::CLI do
168
168
  context "with no profile_photo mapping" do
169
169
  let(:config_file) { ldap_default_config_file }
170
170
  it "reports an error" do
171
- lambda { Socialcast::CommandLine::CLI.start ['sync_photos', '-c', config_file] }.should raise_error KeyError
171
+ lambda { Socialcast::CommandLine::CLI.start ['sync_photos', '-c', config_file] }.should raise_error Socialcast::CommandLine::Provisioner::ProvisionError
172
172
  end
173
173
  end
174
174
 
@@ -227,6 +227,9 @@ describe Socialcast::CommandLine::CLI do
227
227
  'id' => 7,
228
228
  'avatars' => {
229
229
  'id' => default_profile_photo_id
230
+ },
231
+ 'contact_info' => {
232
+ 'email' => 'ryan@example.com'
230
233
  }
231
234
  }
232
235
  ]
@@ -259,6 +262,9 @@ describe Socialcast::CommandLine::CLI do
259
262
  'id' => 7,
260
263
  'avatars' => {
261
264
  'id' => another_profile_photo_id
265
+ },
266
+ 'contact_info' => {
267
+ 'email' => 'ryan@example.com'
262
268
  }
263
269
  }
264
270
  ]
@@ -140,7 +140,7 @@ describe Socialcast::CommandLine::ProvisionPhoto do
140
140
  let(:sync_photos) { Socialcast::CommandLine::ProvisionPhoto.new(ldap_multiple_connection_mapping_config, {}).sync }
141
141
  let(:binary_photo_data) { "\x89PNGabc".force_encoding('binary') }
142
142
  before do
143
- stub_const("Socialcast::CommandLine::ProvisionPhoto::MAX_BATCH_SIZE", 2)
143
+ Socialcast::CommandLine::ProvisionPhoto::ApiSyncStrategy.any_instance.stub(:batch_size).and_return(2)
144
144
 
145
145
  ldap_instance1 = double(Net::LDAP, :encryption => nil, :auth => nil)
146
146
  ldap_instance1.should_receive(:open).and_yield
@@ -156,7 +156,7 @@ describe Socialcast::CommandLine::ProvisionPhoto do
156
156
 
157
157
  Socialcast::CommandLine.stub(:resource_for_path).with('/api/users/search', anything).and_return(user_search_resource)
158
158
 
159
- user_search_resource.should_receive(:get).once.with({:params=>{:q=>"\"user@example.com\" OR \"user2@example.com\"", :per_page=>Socialcast::CommandLine::ProvisionPhoto::MAX_BATCH_SIZE}, :accept=>:json}).and_return(search_api_response.to_json)
159
+ user_search_resource.should_receive(:get).once.with({:params => { :q => "\"user@example.com\" OR \"user2@example.com\"", :per_page => 2}, :accept => :json}).and_return(search_api_response.to_json)
160
160
 
161
161
  user_resource1 = double(:user_resource)
162
162
  user_resource1.should_receive(:put) do |data|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: socialcast
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.13
4
+ version: 1.3.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Sonnek
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-07-23 00:00:00.000000000 Z
13
+ date: 2014-07-28 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rest-client