socialcast 1.3.13 → 1.3.14

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