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 +4 -4
- data/lib/socialcast/command_line/provision_photo.rb +113 -65
- data/lib/socialcast/command_line/provision_user.rb +2 -2
- data/lib/socialcast/command_line/provisioner.rb +5 -1
- data/lib/socialcast/command_line/version.rb +1 -1
- data/spec/socialcast/command_line/cli_spec.rb +7 -1
- data/spec/socialcast/command_line/provision_photo_spec.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9de45230b2671da6dbe2c97752900207a128bb08
|
|
4
|
+
data.tar.gz: 2d24c42f2afbfba3c82cca8a3b592b7fe53f0cdc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
27
|
+
sync_strategy.process(user_photos, process_options) if user_photos.any?
|
|
24
28
|
end
|
|
25
29
|
|
|
26
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
end
|
|
36
|
+
## FORCE ENCODING
|
|
37
|
+
profile_photo_data = profile_photo_data.force_encoding('binary')
|
|
31
38
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
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
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
64
|
-
profile_photo_data = profile_photo_data.force_encoding('binary')
|
|
57
|
+
protected
|
|
65
58
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
|
91
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
@@ -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
|
|
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
|
-
|
|
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=>
|
|
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.
|
|
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-
|
|
13
|
+
date: 2014-07-28 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: rest-client
|