Skip to content

Commit 51de7e2

Browse files
authored
Merge pull request #267 from adobe-apiplatform/v2
prepare for 2.2.1rc1 build
2 parents 68e0662 + 5ff63ef commit 51de7e2

File tree

7 files changed

+34
-44
lines changed

7 files changed

+34
-44
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ endif
1717

1818
pex:
1919
pip install --upgrade pip
20-
pip install --upgrade wheel pex
20+
pip install --upgrade wheel requests pex
2121
-$(RM) $(output_dir)
2222
pex -v -o $(output_dir)/$(output_filename)$(output_file_extension) -m user_sync.app \
2323
-f $(prebuilt_dir) \

RELEASE_NOTES.md

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,27 @@
11
# Release Notes for User Sync Tool Version 2.2.1
22

3-
These notes apply to v2.2 of 2017-08-03.
3+
These notes apply to v2.2.1rc1 of 2017-08-28.
44

55
## New Features
66

7-
[#52](https://github.com/adobe-apiplatform/user-sync.py/issues/52): This release runs on both Python 2 and Python 3 (2.7, 3.4, 3.5, and 3.6 to be precise)!
8-
9-
[#182](https://github.com/adobe-apiplatform/user-sync.py/issues/182): At long last, you can select users in nested groups. The new implementation for determining group members also allows us to avoid fetching the entire directory when the users are only supposed to come from specific groups, as with `--users mapped` ([#129](https://github.com/adobe-apiplatform/user-sync.py/issues/129)). There is a new LDAP configuration setting `group_member_filter_format` which controls how users are selected for groups (default is "immediate members only", which is backward compatible with prior releases).
10-
11-
[#236](https://github.com/adobe-apiplatform/user-sync.py/issues/236): Directory users can now be pushed directly to Adobe, rather than synchronized with a fetch of Adobe users. A new command-line argument `--strategy push` (as opposed to the default `--strategy sync`) controls this.
12-
13-
[#234](https://github.com/adobe-apiplatform/user-sync.py/issues/234): There are new UMAPI configuration settings (`timeout` and `retries` in the `server` section) to control the network behavior when talking to the UMAPI server. The default timeout of 120 seconds and the default retry count of 3 are unchanged.
14-
15-
[#237](https://github.com/adobe-apiplatform/user-sync.py/issues/237): The default encoding for all inputs (config files, CSV files, LDAP attribute values) is now assumed to be `utf8` rather than ASCII. This is a backward-compatible change that makes it unnecessary (but still allowed) to specify `utf8` explicitly.
7+
[#266](https://github.com/adobe-apiplatform/user-sync.py/issues/266): Extended attribute values (defined in extensions) can now be multi-valued. The type of the attribute value in the `source_attributes` dictionary will be:
8+
* `None` if the attribute has no value;
9+
* a `str` (or `unicode` in py2) if the attribute has one value;
10+
* a `list` of `str` (or `unicode` in py2) if the attribute has multiple values.
1611

1712
## Bug Fixes
1813

19-
[#227](https://github.com/adobe-apiplatform/user-sync.py/issues/227): Fixed crashes due to bad user keys.
20-
21-
[#233](https://github.com/adobe-apiplatform/user-sync.py/issues/233): Exceptions in LDAP connections are handled gracefully, as are keyboard interrupts.
22-
23-
[#235](https://github.com/adobe-apiplatform/user-sync.py/issues/235): Fixed a crash that occurred if an Adobe ID user had no username or domain info.
24-
25-
[#240](https://github.com/adobe-apiplatform/user-sync.py/issues/240): When using the LDAP connector, the domain of each user is now correctly defaulted to the email domain.
26-
27-
[#244](https://github.com/adobe-apiplatform/user-sync.py/issues/244): Build instructions are now provided for all platforms, and the default `Makefile` allows for the use of pre-compiled, platform-specific wheels.
14+
[#257](https://github.com/adobe-apiplatform/user-sync.py/issues/257): Catch exceptions thrown by umapi-client when creating actions.
2815

29-
[#247](https://github.com/adobe-apiplatform/user-sync.py/issues/247): There is no more use of the `uid` attribute in LDAP directories.
16+
[#258](https://github.com/adobe-apiplatform/user-sync.py/issues/258): Correctly decrypte private keys in py3.
3017

31-
[#254](https://github.com/adobe-apiplatform/user-sync.py/issues/254): Update windows libraries, reduce use of custom builds.
18+
[#260](https://github.com/adobe-apiplatform/user-sync.py/issues/260): Make sure the requests library is loaded when using pex on Windows.
3219

33-
[#258](https://github.com/adobe-apiplatform/user-sync.py/issues/258): Correctly decrypt private keys in py3 (byte vs. str type compatibility).
20+
[#265](https://github.com/adobe-apiplatform/user-sync.py/issues/265): Extended attributes in extensions couldn't be fetched unless they had non-ascii names.
3421

3522
## Compatibility with Prior Versions
3623

37-
This version is fully backwards-compatible with version 2.1.1. As mentioned above, there are new configuration settings for filtering group members and controlling network behavior, and there is a new command-line option for controlling the update strategy. See [the docs](https://adobe-apiplatform.github.io/user-sync.py) for full details about configuration.
24+
There are no functional changes from prior versions.
3825

3926
## Known Issues
4027

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
'pycryptodome',
4949
'pyldap==2.4.37',
5050
'PyYAML',
51-
'umapi-client>=2.5',
51+
'umapi-client>=2.7',
5252
'psutil',
5353
'keyring',
5454
'six'

user_sync/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ def create_config_loader_options(args):
276276
compiled_expression = re.compile(r'\A' + username_filter_pattern + r'\Z', re.IGNORECASE)
277277
except Exception as e:
278278
raise AssertionException("Bad regular expression for --user-filter: %s reason: %s" %
279-
(username_filter_pattern, e.message))
279+
(username_filter_pattern, e))
280280
config_options['username_filter_regex'] = compiled_expression
281281

282282
# --adobe-only-user-action

user_sync/connector/directory_ldap.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ def iter_users(self, users_filter, extended_attributes):
200200
user_attribute_names.extend(self.user_username_formatter.get_attribute_names())
201201
user_attribute_names.extend(self.user_domain_formatter.get_attribute_names())
202202

203+
extended_attributes = [six.text_type(attr) for attr in extended_attributes]
203204
extended_attributes = list(set(extended_attributes) - set(user_attribute_names))
204205
user_attribute_names.extend(extended_attributes)
205206

@@ -336,7 +337,7 @@ def __init__(self, string_format):
336337
else:
337338
string_format = six.text_type(string_format) # force unicode so attribute values are unicode
338339
formatter = string.Formatter()
339-
attribute_names = [item[1] for item in formatter.parse(string_format) if item[1]]
340+
attribute_names = [six.text_type(item[1]) for item in formatter.parse(string_format) if item[1]]
340341
self.string_format = string_format
341342
self.attribute_names = attribute_names
342343

@@ -356,7 +357,7 @@ def generate_value(self, record):
356357
if self.string_format is not None:
357358
values = {}
358359
for attribute_name in self.attribute_names:
359-
value = self.get_attribute_value(record, attribute_name)
360+
value = self.get_attribute_value(record, attribute_name, first_only=True)
360361
if value is None:
361362
values = None
362363
break
@@ -366,17 +367,20 @@ def generate_value(self, record):
366367
return result, attribute_name
367368

368369
@classmethod
369-
def get_attribute_value(cls, attributes, attribute_name):
370+
def get_attribute_value(cls, attributes, attribute_name, first_only=False):
370371
"""
371372
The attribute value type must be decodable (str in py2, bytes in py3)
372373
:type attributes: dict
373374
:type attribute_name: unicode
375+
:type first_only: bool
374376
"""
375-
if attribute_name in attributes:
376-
attribute_value = attributes[attribute_name]
377-
if len(attribute_value) > 0:
378-
try:
379-
return attribute_value[0].decode(cls.encoding)
380-
except UnicodeError as e:
381-
raise AssertionException("Encoding error in value of attribute '%s': %s" % (attribute_name, e))
377+
attribute_values = attributes.get(attribute_name)
378+
if attribute_values:
379+
try:
380+
if first_only or len(attribute_values) == 1:
381+
return attribute_values[0].decode(cls.encoding)
382+
else:
383+
return [val.decode(cls.encoding) for val in attribute_values]
384+
except UnicodeError as e:
385+
raise AssertionException("Encoding error in value of attribute '%s': %s" % (attribute_name, e))
382386
return None

user_sync/connector/umapi.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -299,11 +299,10 @@ def create_action(self, commands):
299299
identity_type = user_sync.identity_type.FEDERATED_IDENTITY_TYPE
300300
try:
301301
umapi_identity_type = umapi_client.IdentityTypes[identity_type]
302-
except KeyError:
303-
umapi_identity_type = user_sync.identity_type.ENTERPRISE_IDENTITY_TYPE
304-
305-
action = umapi_client.UserAction(umapi_identity_type, email, username, domain,
306-
requestID=self.get_next_request_id())
302+
action = umapi_client.UserAction(umapi_identity_type, email, username, domain,
303+
requestID=self.get_next_request_id())
304+
except ValueError as e:
305+
raise AssertionException("Error creating umapi Action: %s" % e)
307306
for command in commands.do_list:
308307
command_name, command_param = command
309308
command_function = getattr(action, command_name)
@@ -354,7 +353,7 @@ def process_sent_items(self, total_sent, batch_error=None):
354353
"""
355354
Note items as sent, log any processing errors, and invoke any callbacks
356355
:param total_sent: number of sent items from queue, must be >= 0
357-
:param batch_error: a batch-level error that affected all items, if there was one
356+
:param batch_error: exception for a batch-level error that affected all items, if there was one
358357
:return:
359358
"""
360359
# update queue
@@ -383,5 +382,5 @@ def process_sent_items(self, total_sent, batch_error=None):
383382
callback({
384383
"action": action,
385384
"is_success": not batch_error and not errors,
386-
"errors": batch_error or errors
385+
"errors": [batch_error] if batch_error else errors
387386
})

user_sync/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@
1818
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1919
# SOFTWARE.
2020

21-
__version__ = '2.2.1'
21+
__version__ = '2.2.1rc1'

0 commit comments

Comments
 (0)