From 0d11325f39e204657ec93e6e82f2f2cd520bb52d Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Wed, 29 Mar 2017 08:59:20 -0600 Subject: [PATCH 01/18] Updated organization service to use ChunkQueryMixin; Reduced code and added verbosity option. --- membersuite_api_client/mixins.py | 61 +++++++-- .../organizations/services.py | 116 ++++++------------ .../subscriptions/services.py | 25 +--- .../tests/test_organizations.py | 13 +- 4 files changed, 96 insertions(+), 119 deletions(-) diff --git a/membersuite_api_client/mixins.py b/membersuite_api_client/mixins.py index b16f8a2..ac94aa5 100644 --- a/membersuite_api_client/mixins.py +++ b/membersuite_api_client/mixins.py @@ -1,4 +1,7 @@ from retrying import retry +import datetime + +RETRY_ATTEMPTS = 10 class ChunkQueryMixin(): @@ -15,28 +18,41 @@ class ChunkQueryMixin(): """ def get_long_query( - self, base_query, retry_attempts=2, limit_to=200, max_calls=None): + self, base_query, limit_to=100, max_calls=None, + start_record=0, verbose=False): """ Takes a base query for all objects and recursively requests them - @base_query - the base query to be executed - @retry_attempts - the number of times to retry a query when it fails - @limit_to - how many rows to query for in each chunk - @max_recursion_depth - None is infinite + :param str base_query: the base query to be executed + :param int limit_to: how many rows to query for in each chunk + :param int max_calls: the max calls(chunks to request) None is infinite + :param int start_record: the first record to return from the query + :param bool verbose: print progress to stdout + :return: a list of Organization objects """ - @retry(stop_max_attempt_number=retry_attempts) - def run_query(base_query, start_record, limit_to): + @retry(stop_max_attempt_number=RETRY_ATTEMPTS, wait_fixed=2000) + def run_query(base_query, start_record, limit_to, verbose): # inline method to take advantage of retry + + if verbose: + print "[start: %d limit: %d]" % (start_record, limit_to) + start = datetime.datetime.now() result = self.client.runSQL( query=base_query, start_record=start_record, limit_to=limit_to, ) + end = datetime.datetime.now() + if verbose: + print "[%s - %s]" % (start, end) return self.result_to_models(result) - record_index = 0 - result = run_query(base_query, record_index, limit_to) + if verbose: + print base_query + + record_index = start_record + result = run_query(base_query, record_index, limit_to, verbose) all_objects = result call_count = 1 """ @@ -49,7 +65,32 @@ def run_query(base_query, start_record, limit_to): len(result) >= limit_to): record_index += len(result) # should be `limit_to` - all_objects += run_query(base_query, record_index, limit_to) + result = run_query( + base_query, record_index, limit_to, verbose) + all_objects += result call_count += 1 return all_objects + + def result_to_models(self, result): + """ + this is the 'transorm' part of ETL: + converts the result of the SQL to Models + """ + mysql_result = result['body']['ExecuteMSQLResult'] + + if not mysql_result['Errors']: + obj_result = mysql_result['ResultValue']['ObjectSearchResult'] + if not obj_result['Objects']: + return [] + objects = obj_result['Objects']['MemberSuiteObject'] + + model_list = [] + for obj in objects: + model = self.ms_object_to_model(obj) + model_list.append(model) + + return model_list + + else: + raise ExecuteMSQLError(result) diff --git a/membersuite_api_client/organizations/services.py b/membersuite_api_client/organizations/services.py index b3ad571..b1cfb62 100644 --- a/membersuite_api_client/organizations/services.py +++ b/membersuite_api_client/organizations/services.py @@ -5,13 +5,14 @@ """ +from ..mixins import ChunkQueryMixin from .models import Organization, OrganizationType from ..utils import convert_ms_object from zeep.exceptions import TransportError import datetime -class OrganizationService(object): +class OrganizationService(ChunkQueryMixin, object): def __init__(self, client): """ @@ -19,80 +20,53 @@ def __init__(self, client): """ self.client = client - def get_orgs(self, parameters=None, get_all=False, since_when=None, - results=None, start_record=0, limit_to=200, depth=1, - max_depth=None): + def get_orgs( + self, limit_to=100, max_calls=None, parameters=None, + since_when=None, start_record=0, verbose=False): """ - Constructs request to MemberSuite to query organization objects - based on parameters provided. - - Loop over queries of size limit_to until either a non-full queryset - is returned, or max_depth is reached (used in tests). Then the - recursion collapses to return a single concatenated list. + Constructs request to MemberSuite to query organization objects. + + :param int limit_to: number of records to fetch with each chunk + :param int max_calls: the maximum number of calls (chunks) to request + :param str parameters: additional query parameter dictionary + :param date since_when: fetch records modified after this date + :param int start_record: the first record to return from the query + :param bool verbose: print progress to stdout + :return: a list of Organization objects """ + if not self.client.session_id: self.client.request_session() query = "SELECT Objects() FROM Organization " - if parameters and not get_all: + if parameters: query += "WHERE" - for key in parameters: - query += " %s = '%s' AND" % (key, parameters[key]) + for key, value in parameters.items(): + query += " %s = '%s' AND" % (key, value) query = query[:-4] - if since_when: - query += " AND LastModifiedDate > '{since_when} 00:00:00'" \ - .format(since_when=datetime.date.today() - - datetime.timedelta(days=since_when)) - elif since_when and not get_all: - query += "WHERE LastModifiedDate > '{since_when} 00:00:00'".format( - since_when=datetime.date.today() - - datetime.timedelta(days=since_when)) - try: - result = self.client.runSQL( - query=query, - start_record=start_record, - limit_to=limit_to, - ) + if since_when: + query += " AND LastModifiedDate > '{since_when} 00:00:00'" \ + .format(since_when=datetime.date.today() - + datetime.timedelta(days=since_when)) - except TransportError: - # API Intermittently fails and kicks a 504, - # this is a way to retry if that happens. - result = self.get_orgs( - parameters=parameters, - get_all=get_all, - since_when=since_when, - results=results, - start_record=start_record, - limit_to=limit_to, - depth=depth, - max_depth=max_depth, - ) + if verbose: + print "Fetching Organizations..." - msql_result = result['body']["ExecuteMSQLResult"] - if not msql_result['Errors'] and \ - msql_result["ResultValue"]["ObjectSearchResult"]["Objects"]: - new_results = self.package_organizations(msql_result["ResultValue"] - ["ObjectSearchResult"] - ["Objects"] - ["MemberSuiteObject"] - ) + (results or []) - # Check if the queryset was completely full. If so, there may be - # More results we need to query - if len(new_results) >= limit_to and not depth == max_depth: - new_results = self.get_orgs( - parameters=parameters, - get_all=get_all, - since_when=since_when, - results=new_results, - start_record=start_record + limit_to, - limit_to=limit_to, - depth=depth + 1, - max_depth=max_depth - ) - return new_results - else: - return results + # note, get_long_query is overkill when just looking at + # one org, but it still only executes once + # `get_long_query` uses `ms_object_to_model` to return Subscriptions + org_list = self.get_long_query( + query, limit_to=limit_to, max_calls=max_calls, + start_record=start_record, verbose=verbose) + + return org_list + + def ms_object_to_model(self, ms_obj): + " Converts an individual result to a Subscription Model " + sane_obj = convert_ms_object( + ms_obj['Fields']['KeyValueOfstringanyType']) + return Organization(sane_obj) def get_org_types(self): """ @@ -109,20 +83,6 @@ def get_org_types(self): ["Objects"]["MemberSuiteObject"] ) - def package_organizations(self, obj_list): - """ - Loops through MS objects returned from queries to turn them into - Organization objects and pack them into a list for later use. - """ - org_list = [] - for obj in obj_list: - sane_obj = convert_ms_object( - obj['Fields']['KeyValueOfstringanyType'] - ) - org = Organization(sane_obj) - org_list.append(org) - return org_list - def package_org_types(self, obj_list): """ Loops through MS objects returned from queries to turn them into diff --git a/membersuite_api_client/subscriptions/services.py b/membersuite_api_client/subscriptions/services.py index a0c7189..628853b 100644 --- a/membersuite_api_client/subscriptions/services.py +++ b/membersuite_api_client/subscriptions/services.py @@ -44,36 +44,13 @@ def get_subscriptions( # note, get_long_query is overkill when just looking at # one org, but it still only executes once - # `get_long_query` uses `result_to_models` to return Subscriptions + # `get_long_query` uses `ms_object_to_model` to return Subscriptions subscription_list = self.get_long_query( query, retry_attempts=retry_attempts, limit_to=limit_to, max_calls=max_calls) return subscription_list - def result_to_models(self, result): - """ - this is the 'transorm' part of ETL: - converts the result of the SQL to Subscription objects - """ - mysql_result = result['body']['ExecuteMSQLResult'] - - if not mysql_result['Errors']: - obj_result = mysql_result['ResultValue']['ObjectSearchResult'] - if not obj_result['Objects']: - return [] - objects = obj_result['Objects']['MemberSuiteObject'] - - subscription_list = [] - for obj in objects: - subscription = self.ms_object_to_model(obj) - subscription_list.append(subscription) - - return subscription_list - - else: - raise ExecuteMSQLError(result) - def ms_object_to_model(self, ms_obj): " Converts an individual result to a Subscription Model " sane_obj = convert_ms_object( diff --git a/membersuite_api_client/tests/test_organizations.py b/membersuite_api_client/tests/test_organizations.py index 6652fb9..cbcc7cc 100644 --- a/membersuite_api_client/tests/test_organizations.py +++ b/membersuite_api_client/tests/test_organizations.py @@ -19,23 +19,22 @@ def test_get_orgs(self): parameters = { 'Name': 'AASHE Test Campus', } - org_list = self.service.get_orgs(parameters) + org_list = self.service.get_orgs(parameters=parameters) self.assertEqual(len(org_list), 1) self.assertEqual(type(org_list[0]), Organization) + # @todo - test since_when parameter + # Fetch all orgs using get_all=True # But limit to 1 result per iteration, 2 iterations - org_list = self.service.get_orgs(get_all=True, - limit_to=1, - max_depth=2) + org_list = self.service.get_orgs(limit_to=1, max_calls=2) self.assertEqual(len(org_list), 2) self.assertEqual(type(org_list[0]), Organization) # How does recursion handle the end? # 8055 records at the time of this test - org_list = self.service.get_orgs( - get_all=True, start_record=8000, limit_to=10) - self.assertGreater(len(org_list), 50) + org_list = self.service.get_orgs(start_record=8050, limit_to=1) + self.assertGreater(len(org_list), 4) self.assertEqual(type(org_list[0]), Organization) def test_get_org_types(self): From 765427eae7c7e143b17d43131691904af860ffba Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 00:00:24 -0600 Subject: [PATCH 02/18] Fixed missing import; --- membersuite_api_client/mixins.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/membersuite_api_client/mixins.py b/membersuite_api_client/mixins.py index ac94aa5..3aef990 100644 --- a/membersuite_api_client/mixins.py +++ b/membersuite_api_client/mixins.py @@ -1,6 +1,8 @@ from retrying import retry import datetime +from .exceptions import ExecuteMSQLError + RETRY_ATTEMPTS = 10 From 8d25a8e56bf57ce1a0aa28f2e5aef5d55271f2e3 Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 00:01:14 -0600 Subject: [PATCH 03/18] Added ChunkQueryMixin to membership service; --- .../memberships/services.py | 117 ++++++------------ 1 file changed, 41 insertions(+), 76 deletions(-) diff --git a/membersuite_api_client/memberships/services.py b/membersuite_api_client/memberships/services.py index 030eea3..4864393 100644 --- a/membersuite_api_client/memberships/services.py +++ b/membersuite_api_client/memberships/services.py @@ -6,12 +6,13 @@ """ from zeep.exceptions import TransportError +from ..mixins import ChunkQueryMixin from .models import Membership, MembershipProduct from ..utils import convert_ms_object import datetime -class MembershipService(object): +class MembershipService(ChunkQueryMixin, object): def __init__(self, client): """ @@ -19,7 +20,7 @@ def __init__(self, client): """ self.client = client - def get_memberships_for_org(self, account_num): + def get_memberships_for_org(self, account_num, verbose=False): """ Retrieve all memberships associated with an organization """ @@ -28,18 +29,13 @@ def get_memberships_for_org(self, account_num): query = "SELECT Objects() FROM Membership " \ "WHERE Owner = '%s'" % account_num - result = self.client.runSQL(query) - msql_result = result["body"]["ExecuteMSQLResult"] - obj_result = msql_result["ResultValue"]["ObjectSearchResult"] - if obj_result['Objects']: - objects = obj_result['Objects']['MemberSuiteObject'] - if not msql_result["Errors"] and len(objects): - return self.package_memberships(objects) - return None - - def get_all_memberships(self, since_when=None, results=None, - start_record=0, limit_to=200, - depth=1, max_depth=None): + + membership_list = self.get_long_query(query, verbose=verbose) + return membership_list + + def get_all_memberships( + self, limit_to=100, max_calls=None, parameters=None, + since_when=None, start_record=0, verbose=False): """ Retrieve all memberships updated since "since_when" @@ -51,57 +47,41 @@ def get_all_memberships(self, since_when=None, results=None, self.client.request_session() query = "SELECT Objects() FROM Membership" + + # collect all where parameters into a list of + # (key, operator, value) tuples + where_params = [] + + if parameters: + for k, v in parameters.items(): + where_params.append((k, "=", v)) + if since_when: - query += " WHERE LastModifiedDate > '{since_when} 00:00:00'" \ - " ORDER BY LocalID".format( - since_when=datetime.date.today() - - datetime.timedelta(days=since_when)) - else: - query += " ORDER BY LocalID" + d = datetime.date.today() - datetime.timedelta(days=since_when) + where_params.append( + ('LastModifiedDate', ">", "'%s 00:00:00'" % d)) - try: - result = self.client.runSQL( - query=query, - start_record=start_record, - limit_to=limit_to, - ) + if where_params: + query += " WHERE " + query += " AND ".join( + ["%s %s %s" % (p[0], p[1], p[2]) for p in where_params]) - except TransportError: - # API Intermittently fails and kicks a 504, - # this is a way to retry if that happens. - result = self.get_all_memberships( - since_when=since_when, - results=results, - start_record=start_record, - limit_to=limit_to, - depth=depth, - max_depth=max_depth, - ) + query += " ORDER BY LocalID" - msql_result = result['body']["ExecuteMSQLResult"] - if (not msql_result['Errors'] and msql_result["ResultValue"] - ["ObjectSearchResult"]["Objects"]): - new_results = self.package_memberships(msql_result - ["ResultValue"] - ["ObjectSearchResult"] - ["Objects"] - ["MemberSuiteObject"] - ) + (results or []) - - # Check if the queryset was completely full. If so, there may be - # More results we need to query - if len(new_results) >= limit_to and not depth == max_depth: - new_results = self.get_all_memberships( - since_when=since_when, - results=new_results, - start_record=start_record + limit_to, - limit_to=limit_to, - depth=depth+1, - max_depth=max_depth - ) - return new_results - else: - return results + # note, get_long_query is overkill when just looking at + # one org, but it still only executes once + # `get_long_query` uses `ms_object_to_model` to return Organizations + membership_list = self.get_long_query( + query, limit_to=limit_to, max_calls=max_calls, + start_record=start_record, verbose=verbose) + + return membership_list + + def ms_object_to_model(self, ms_obj): + " Converts an individual result to a Subscription Model " + sane_obj = convert_ms_object( + ms_obj['Fields']['KeyValueOfstringanyType']) + return Membership(sane_obj) def get_all_membership_products(self): """ @@ -118,21 +98,6 @@ def get_all_membership_products(self): else: return None - def package_memberships(self, object_list): - """ - Loops through MS objects returned from queries to turn them into - Membership objects and pack them into a list for later use. - """ - membership_list = [] - for obj in object_list: - if type(obj) != str: - sane_obj = convert_ms_object( - obj['Fields']['KeyValueOfstringanyType']) - membership = Membership(sane_obj) - membership_list.append(membership) - - return membership_list - def package_membership_products(self, msql_result): """ Loops through MS objects returned from queries to turn them into From 2b09cf0ef637e4f13ccc7dca437acd7b78e3229d Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 00:01:50 -0600 Subject: [PATCH 04/18] Bug-proofed query parameters; --- .../organizations/services.py | 29 ++++++++++++------- .../subscriptions/services.py | 26 ++++++++++++----- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/membersuite_api_client/organizations/services.py b/membersuite_api_client/organizations/services.py index b1cfb62..33ab524 100644 --- a/membersuite_api_client/organizations/services.py +++ b/membersuite_api_client/organizations/services.py @@ -38,24 +38,33 @@ def get_orgs( if not self.client.session_id: self.client.request_session() - query = "SELECT Objects() FROM Organization " + query = "SELECT Objects() FROM Organization" + + # collect all where parameters into a list of + # (key, operator, value) tuples + where_params = [] + if parameters: - query += "WHERE" - for key, value in parameters.items(): - query += " %s = '%s' AND" % (key, value) - query = query[:-4] + for k, v in parameters.items(): + where_params.append((k, "=", v)) if since_when: - query += " AND LastModifiedDate > '{since_when} 00:00:00'" \ - .format(since_when=datetime.date.today() - - datetime.timedelta(days=since_when)) + d = datetime.date.today() - datetime.timedelta(days=since_when) + where_params.append( + ('LastModifiedDate', ">", "'%s 00:00:00'" % d)) + + if where_params: + query += " WHERE " + query += " AND ".join( + ["%s %s %s" % (p[0], p[1], p[2]) for p in where_params]) if verbose: print "Fetching Organizations..." + print query # note, get_long_query is overkill when just looking at # one org, but it still only executes once - # `get_long_query` uses `ms_object_to_model` to return Subscriptions + # `get_long_query` uses `ms_object_to_model` to return Organizations org_list = self.get_long_query( query, limit_to=limit_to, max_calls=max_calls, start_record=start_record, verbose=verbose) @@ -63,7 +72,7 @@ def get_orgs( return org_list def ms_object_to_model(self, ms_obj): - " Converts an individual result to a Subscription Model " + " Converts an individual result to an Organization Model " sane_obj = convert_ms_object( ms_obj['Fields']['KeyValueOfstringanyType']) return Organization(sane_obj) diff --git a/membersuite_api_client/subscriptions/services.py b/membersuite_api_client/subscriptions/services.py index 628853b..deaf128 100644 --- a/membersuite_api_client/subscriptions/services.py +++ b/membersuite_api_client/subscriptions/services.py @@ -27,27 +27,37 @@ def __init__(self, client): def get_subscriptions( self, publication_id=None, org_id=None, since_when=None, - retry_attempts=2, limit_to=200, max_calls=None): + limit_to=200, max_calls=None, start_record=0, verbose=False): """ Fetches all subscriptions from Membersuite of a particular `publication_id` if set. """ query = "SELECT Objects() FROM Subscription" + + # collect all where parameters into a list of + # (key, operator, value) tuples + where_params = [] + if org_id: - query += " WHERE owner = '%s'" % org_id + where_params.append(('owner', '=', "'%s'" % org_id)) if publication_id: - query += " AND publication = '%s'" % publication_id + where_params.append(('publication', '=', "'%s'" % publication_id)) if since_when: - query += " AND LastModifiedDate > '{since_when} 00:00:00'" \ - .format(since_when=datetime.date.today() - - datetime.timedelta(days=since_when)) + d = datetime.date.today() - datetime.timedelta(days=since_when) + where_params.append( + ('LastModifiedDate', ">", "'%s 00:00:00'" % d)) + + if where_params: + query += " WHERE " + query += " AND ".join( + ["%s %s %s" % (p[0], p[1], p[2]) for p in where_params]) # note, get_long_query is overkill when just looking at # one org, but it still only executes once # `get_long_query` uses `ms_object_to_model` to return Subscriptions subscription_list = self.get_long_query( - query, retry_attempts=retry_attempts, limit_to=limit_to, - max_calls=max_calls) + query, limit_to=limit_to, max_calls=max_calls, + start_record=start_record, verbose=verbose) return subscription_list From 988e86eded70b95fa171c9a322450bc927df73c1 Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 00:02:16 -0600 Subject: [PATCH 05/18] Test updates including environment variables; added readme; --- membersuite_api_client/tests/README.md | 27 +++++++++++++++++++ .../tests/test_memberships.py | 23 +++++++++------- .../tests/test_organizations.py | 14 ++++++---- membersuite_api_client/tests/test_security.py | 19 +++++++------ .../tests/test_subscriptions.py | 26 ++++++++++++------ 5 files changed, 79 insertions(+), 30 deletions(-) create mode 100644 membersuite_api_client/tests/README.md diff --git a/membersuite_api_client/tests/README.md b/membersuite_api_client/tests/README.md new file mode 100644 index 0000000..b769c48 --- /dev/null +++ b/membersuite_api_client/tests/README.md @@ -0,0 +1,27 @@ +# Testing membersuite_api_client + +## Configuration + +You will need to define the following environment variables: + +## General vars: + + - `MS_ACCESS_KEY` - your API key + - `MS_SECRET_KEY` - your API secret + - `MS_ASSOCIATION_ID` - your membersuite association id + +Until we set up a mechanism for fixtures, you'll need to set up the following: + +## Organization vars: + + - `TEST_ORG_ID` - an existing org + +## Membership vars: + + - `ORG_ID_WITH_MEMBERSHIPS` - an existing org with a membership or two + - `ORG_ID_WITHOUT_MEMBERSHIPS` - and w/out + +## Security vars: + + - `TEST_MS_PORTAL_USER_ID` - a user with portal access + - `TEST_MS_PORTAL_USER_PASS` - that user's password diff --git a/membersuite_api_client/tests/test_memberships.py b/membersuite_api_client/tests/test_memberships.py index 76edb85..d8bc214 100644 --- a/membersuite_api_client/tests/test_memberships.py +++ b/membersuite_api_client/tests/test_memberships.py @@ -4,6 +4,12 @@ from ..memberships.services import MembershipService from ..memberships.models import Membership, MembershipProduct +# This should come from the env... +# in fact, we should consistently define these somewhere +# fixtures would be ideal +TEST_ORG_ID_WITH_MEM = "6faf90e4-0007-c316-3054-0b3ca00fb259" +TEST_ORG_ID_WITHOUT_MEM = "6faf90e4-0007-c77c-326a-0b3ca00fb259" + class MembershipServiceTestCase(BaseTestCase): @@ -17,15 +23,13 @@ def test_get_membership_for_org(self): Get membership info for a test org """ # Test org with a membership - test_org_id = "6faf90e4-0007-c578-8310-0b3c53985743" - membership_list = self.service.get_memberships_for_org(test_org_id) + membership_list = self.service.get_memberships_for_org( + TEST_ORG_ID_WITH_MEM, verbose=True) self.assertEqual(type(membership_list[0]), Membership) - self.assertEqual(membership_list[0].id, - '6faf90e4-0074-cbb5-c1d2-0b3c539859ef') # Test org without a membership - test_org_id = "6faf90e4-0007-c92e-8d16-0b3c53985743" - membership_list = self.service.get_memberships_for_org(test_org_id) + membership_list = self.service.get_memberships_for_org( + TEST_ORG_ID_WITHOUT_MEM, verbose=True) self.assertFalse(membership_list) def test_get_all_memberships(self): @@ -33,17 +37,18 @@ def test_get_all_memberships(self): Does the get_all_memberships() method work? """ membership_list = self.service.get_all_memberships( - limit_to=1, max_depth=2 + limit_to=1, max_calls=2, verbose=True ) self.assertEqual(len(membership_list), 2) self.assertEqual(type(membership_list[0]), Membership) def test_get_all_membership_products(self): """ - Test if we can retrieve all 103 MembershipProduct objects + Test if we can retrieve all MembershipProduct objects + 103 at the time of testing """ membership_product_list = self.service.get_all_membership_products() - self.assertTrue(len(membership_product_list) == 103) + self.assertTrue(len(membership_product_list) > 0) self.assertEqual(type(membership_product_list[0]), MembershipProduct) diff --git a/membersuite_api_client/tests/test_organizations.py b/membersuite_api_client/tests/test_organizations.py index cbcc7cc..0004b63 100644 --- a/membersuite_api_client/tests/test_organizations.py +++ b/membersuite_api_client/tests/test_organizations.py @@ -4,6 +4,9 @@ from ..organizations.services import OrganizationService from ..organizations.models import Organization, OrganizationType +# @todo - this should come from the env for portability +TEST_ORG_NAME = 'AASHE' + class OrganizationServiceTestCase(BaseTestCase): @@ -17,9 +20,9 @@ def test_get_orgs(self): """ # Fetch just one org by name parameters = { - 'Name': 'AASHE Test Campus', + 'Name': "'%s'" % TEST_ORG_NAME, } - org_list = self.service.get_orgs(parameters=parameters) + org_list = self.service.get_orgs(parameters=parameters, verbose=True) self.assertEqual(len(org_list), 1) self.assertEqual(type(org_list[0]), Organization) @@ -27,14 +30,15 @@ def test_get_orgs(self): # Fetch all orgs using get_all=True # But limit to 1 result per iteration, 2 iterations - org_list = self.service.get_orgs(limit_to=1, max_calls=2) + org_list = self.service.get_orgs(limit_to=1, max_calls=2, verbose=True) self.assertEqual(len(org_list), 2) self.assertEqual(type(org_list[0]), Organization) # How does recursion handle the end? # 8055 records at the time of this test - org_list = self.service.get_orgs(start_record=8050, limit_to=1) - self.assertGreater(len(org_list), 4) + org_list = self.service.get_orgs( + start_record=8000, limit_to=10, verbose=True) + self.assertGreater(len(org_list), 1) self.assertEqual(type(org_list[0]), Organization) def test_get_org_types(self): diff --git a/membersuite_api_client/tests/test_security.py b/membersuite_api_client/tests/test_security.py index 847f882..78ffcde 100644 --- a/membersuite_api_client/tests/test_security.py +++ b/membersuite_api_client/tests/test_security.py @@ -4,11 +4,14 @@ from ..exceptions import LoginToPortalError, MemberSuiteAPIError from ..security import models from ..security.services import login_to_portal, logout +from .test_organizations import TEST_ORG_NAME from ..utils import get_new_client LOGIN_TO_PORTAL_RETRIES = 5 LOGIN_TO_PORTAL_DELAY = 1 +PORTAL_USER_ID = os.environ["TEST_MS_PORTAL_USER_ID"], +PORTAL_USER_PASSWORD = os.environ["TEST_MS_PORTAL_USER_PASS"], def get_portal_user(client, member=True): @@ -16,15 +19,15 @@ def get_portal_user(client, member=True): client.request_session() if member: return login_to_portal( - username=os.environ["TEST_MS_PORTAL_USER_ID"], - password=os.environ["TEST_MS_PORTAL_USER_PASS"], + username=PORTAL_USER_ID, + password=PORTAL_USER_PASSWORD, client=client, retries=LOGIN_TO_PORTAL_RETRIES, delay=LOGIN_TO_PORTAL_DELAY) else: return login_to_portal( - username=os.environ["TEST_NON_MEMBER_MS_PORTAL_USER_ID"], - password=os.environ["TEST_NON_MEMBER_MS_PORTAL_USER_PASS"], + username=PORTAL_USER_ID, + password=PORTAL_USER_PASSWORD, client=client, retries=LOGIN_TO_PORTAL_RETRIES, delay=LOGIN_TO_PORTAL_DELAY) @@ -39,8 +42,8 @@ def setUpClass(cls): def test_login_to_portal(self): """Can we log in to the portal?""" portal_user = login_to_portal( - username=os.environ["TEST_MS_PORTAL_USER_ID"], - password=os.environ["TEST_MS_PORTAL_USER_PASS"], + username=PORTAL_USER_ID, + password=PORTAL_USER_PASSWORD, client=self.client, retries=LOGIN_TO_PORTAL_RETRIES, delay=LOGIN_TO_PORTAL_DELAY) @@ -144,12 +147,12 @@ def test_get_primary_organization(self): Assumptions: - self.individual_member has as its primary organization, one - named "AASHE Test Campus". + named TEST_ORG_NAME """ organization = self.individual_member.get_primary_organization( client=self.client) - self.assertEqual("AASHE Test Campus", organization.name) + self.assertEqual(TEST_ORG_NAME, organization.name) def test_get_primary_organization_fails(self): """What happens when get_primary_organization() fails? diff --git a/membersuite_api_client/tests/test_subscriptions.py b/membersuite_api_client/tests/test_subscriptions.py index fd7ff7a..923121b 100644 --- a/membersuite_api_client/tests/test_subscriptions.py +++ b/membersuite_api_client/tests/test_subscriptions.py @@ -2,6 +2,11 @@ from .base import BaseTestCase from ..subscriptions.services import SubscriptionService +from ..subscriptions.models import Subscription + +# @todo - these should go in the env to be portable across associations +TEST_SUBSCRIPTION_OWNER = '6faf90e4-0006-cd5b-0ec7-0b3ca00fae56' +TEST_PUBLICATION_ID = '6faf90e4-009e-cb9b-7c9e-0b3bcd6dff6a' class SubscriptionTestCase(BaseTestCase): @@ -14,27 +19,32 @@ def test_get_org_subscriptions(self): """ Get the all subscriptions for an organization """ - - test_org_id = "6faf90e4-0007-cbaa-6232-0b3c7fa70db7" - subscription_list = self.service.get_subscriptions(org_id=test_org_id) + subscription_list = self.service.get_subscriptions( + org_id=TEST_SUBSCRIPTION_OWNER, verbose=True) self.assertGreaterEqual(len(subscription_list), 2) + self.assertEqual(type(subscription_list[0]), Subscription) # with publication_id - STARS_PUBLICATION_ID = '6faf90e4-009e-cb9b-7c9e-0b3bcd6dff6a' subscription_list = self.service.get_subscriptions( - org_id=test_org_id, publication_id=STARS_PUBLICATION_ID) + org_id=TEST_SUBSCRIPTION_OWNER, + publication_id=TEST_PUBLICATION_ID, + verbose=True) self.assertGreaterEqual(len(subscription_list), 2) + self.assertEqual(type(subscription_list[0]), Subscription) # now for a "long query" - querying ALL subscriptions subscription_list = self.service.get_subscriptions( - retry_attempts=2, limit_to=3, max_calls=3) + limit_to=3, max_calls=3, verbose=True) self.assertEqual(len(subscription_list), 9) + self.assertEqual(type(subscription_list[0]), Subscription) # test a long query that's longer than the number we have # to ensure that edge case stops the queries + # ~1500 subscriptions at the time of these tests subscription_list = self.service.get_subscriptions( - retry_attempts=5, limit_to=200, max_calls=6) - self.assertLess(len(subscription_list), 1500) + limit_to=100, start_record=1300, verbose=True) + self.assertGreater(len(subscription_list), 0) + self.assertEqual(type(subscription_list[0]), Subscription) # @todo: test the modified date From 3045252beb9a6910a30903206d000227cf6287f8 Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 16:11:09 -0600 Subject: [PATCH 06/18] Updated test environment variables and updated readme; --- membersuite_api_client/tests/README.md | 7 +++-- .../tests/test_memberships.py | 20 +++++++------- membersuite_api_client/tests/test_security.py | 27 +++++++++---------- .../tests/test_subscriptions.py | 5 ++-- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/membersuite_api_client/tests/README.md b/membersuite_api_client/tests/README.md index b769c48..de18122 100644 --- a/membersuite_api_client/tests/README.md +++ b/membersuite_api_client/tests/README.md @@ -23,5 +23,8 @@ Until we set up a mechanism for fixtures, you'll need to set up the following: ## Security vars: - - `TEST_MS_PORTAL_USER_ID` - a user with portal access - - `TEST_MS_PORTAL_USER_PASS` - that user's password +- `TEST_MS_PORTAL_MEMBER_ID` - member user with portal access +- `TEST_MS_PORTAL_MEMBER_PASS` - password +- `TEST_MS_PORTAL_NONMEMBER_ID` - nonmember with portal access +- `TEST_MS_PORTAL_NONMEMBER_PASS` - password +- `TEST_MS_MEMBER_ORG_NAME` - the name of the member organization diff --git a/membersuite_api_client/tests/test_memberships.py b/membersuite_api_client/tests/test_memberships.py index d8bc214..97af5a0 100644 --- a/membersuite_api_client/tests/test_memberships.py +++ b/membersuite_api_client/tests/test_memberships.py @@ -1,14 +1,13 @@ import unittest +import os from .base import BaseTestCase -from ..memberships.services import MembershipService +from ..memberships.services import MembershipService, MembershipProductService from ..memberships.models import Membership, MembershipProduct -# This should come from the env... -# in fact, we should consistently define these somewhere -# fixtures would be ideal -TEST_ORG_ID_WITH_MEM = "6faf90e4-0007-c316-3054-0b3ca00fb259" -TEST_ORG_ID_WITHOUT_MEM = "6faf90e4-0007-c77c-326a-0b3ca00fb259" +# might eventually have to come from fixtures +MEMBER_ORG_ID = os.environ.get('TEST_ORG_ID_MEMBER') +NONMEMBER_ORG_ID = os.environ.get('TEST_ORG_ID_NONMEMBER') class MembershipServiceTestCase(BaseTestCase): @@ -16,6 +15,7 @@ class MembershipServiceTestCase(BaseTestCase): def setUp(self): super(MembershipServiceTestCase, self).setUp() self.service = MembershipService(self.client) + self.product_service = MembershipProductService(self.client) @unittest.skip("Need an Organization ID for a non-member org") def test_get_membership_for_org(self): @@ -24,12 +24,12 @@ def test_get_membership_for_org(self): """ # Test org with a membership membership_list = self.service.get_memberships_for_org( - TEST_ORG_ID_WITH_MEM, verbose=True) + MEMBER_ORG_ID, verbose=True) self.assertEqual(type(membership_list[0]), Membership) # Test org without a membership membership_list = self.service.get_memberships_for_org( - TEST_ORG_ID_WITHOUT_MEM, verbose=True) + NONMEMBER_ORG_ID, verbose=True) self.assertFalse(membership_list) def test_get_all_memberships(self): @@ -47,7 +47,9 @@ def test_get_all_membership_products(self): Test if we can retrieve all MembershipProduct objects 103 at the time of testing """ - membership_product_list = self.service.get_all_membership_products() + service = self.product_service + membership_product_list = service.get_all_membership_products( + verbose=True) self.assertTrue(len(membership_product_list) > 0) self.assertEqual(type(membership_product_list[0]), MembershipProduct) diff --git a/membersuite_api_client/tests/test_security.py b/membersuite_api_client/tests/test_security.py index 78ffcde..ea11275 100644 --- a/membersuite_api_client/tests/test_security.py +++ b/membersuite_api_client/tests/test_security.py @@ -4,14 +4,16 @@ from ..exceptions import LoginToPortalError, MemberSuiteAPIError from ..security import models from ..security.services import login_to_portal, logout -from .test_organizations import TEST_ORG_NAME from ..utils import get_new_client LOGIN_TO_PORTAL_RETRIES = 5 LOGIN_TO_PORTAL_DELAY = 1 -PORTAL_USER_ID = os.environ["TEST_MS_PORTAL_USER_ID"], -PORTAL_USER_PASSWORD = os.environ["TEST_MS_PORTAL_USER_PASS"], +MEMBER_ID = os.environ.get('TEST_MS_PORTAL_MEMBER_ID') +MEMBER_PASSWORD = os.environ.get('TEST_MS_PORTAL_MEMBER_PASS') +NONMEMBER_ID = os.environ.get('TEST_MS_PORTAL_NONMEMBER_ID') +NONMEMBER_PASSWORD = os.environ.get('TEST_MS_PORTAL_NONMEMBER_PASS') +MEMBER_ORG_NAME = os.environ.get('TEST_MS_MEMBER_ORG_NAME') def get_portal_user(client, member=True): @@ -19,15 +21,15 @@ def get_portal_user(client, member=True): client.request_session() if member: return login_to_portal( - username=PORTAL_USER_ID, - password=PORTAL_USER_PASSWORD, + username=MEMBER_ID, + password=MEMBER_PASSWORD, client=client, retries=LOGIN_TO_PORTAL_RETRIES, delay=LOGIN_TO_PORTAL_DELAY) else: return login_to_portal( - username=PORTAL_USER_ID, - password=PORTAL_USER_PASSWORD, + username=NONMEMBER_ID, + password=NONMEMBER_PASSWORD, client=client, retries=LOGIN_TO_PORTAL_RETRIES, delay=LOGIN_TO_PORTAL_DELAY) @@ -41,12 +43,7 @@ def setUpClass(cls): def test_login_to_portal(self): """Can we log in to the portal?""" - portal_user = login_to_portal( - username=PORTAL_USER_ID, - password=PORTAL_USER_PASSWORD, - client=self.client, - retries=LOGIN_TO_PORTAL_RETRIES, - delay=LOGIN_TO_PORTAL_DELAY) + portal_user = get_portal_user(client=self.client) self.assertIsInstance(portal_user, models.PortalUser) def test_login_to_portal_failure(self): @@ -147,12 +144,12 @@ def test_get_primary_organization(self): Assumptions: - self.individual_member has as its primary organization, one - named TEST_ORG_NAME + named MEMBER_ORG_NAME """ organization = self.individual_member.get_primary_organization( client=self.client) - self.assertEqual(TEST_ORG_NAME, organization.name) + self.assertEqual(MEMBER_ORG_NAME, organization.name) def test_get_primary_organization_fails(self): """What happens when get_primary_organization() fails? diff --git a/membersuite_api_client/tests/test_subscriptions.py b/membersuite_api_client/tests/test_subscriptions.py index 923121b..d418498 100644 --- a/membersuite_api_client/tests/test_subscriptions.py +++ b/membersuite_api_client/tests/test_subscriptions.py @@ -1,12 +1,13 @@ import unittest +import os from .base import BaseTestCase from ..subscriptions.services import SubscriptionService from ..subscriptions.models import Subscription # @todo - these should go in the env to be portable across associations -TEST_SUBSCRIPTION_OWNER = '6faf90e4-0006-cd5b-0ec7-0b3ca00fae56' -TEST_PUBLICATION_ID = '6faf90e4-009e-cb9b-7c9e-0b3bcd6dff6a' +TEST_SUBSCRIPTION_OWNER = os.environ.get('TEST_ORG_ID_SUBSCRIBER') +TEST_PUBLICATION_ID = os.environ.get('TEST_PUBLICATION_ID') class SubscriptionTestCase(BaseTestCase): From db45493af59a14eb3b682b61f3efa75770464ddd Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 16:11:33 -0600 Subject: [PATCH 07/18] Extracted MembershipProductService from MembershipService; --- .../memberships/services.py | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/membersuite_api_client/memberships/services.py b/membersuite_api_client/memberships/services.py index 4864393..0c82af1 100644 --- a/membersuite_api_client/memberships/services.py +++ b/membersuite_api_client/memberships/services.py @@ -83,7 +83,16 @@ def ms_object_to_model(self, ms_obj): ms_obj['Fields']['KeyValueOfstringanyType']) return Membership(sane_obj) - def get_all_membership_products(self): + +class MembershipProductService(ChunkQueryMixin, object): + + def __init__(self, client): + """ + Accepts a ConciergeClient to connect with MemberSuite + """ + self.client = client + + def get_all_membership_products(self, verbose): """ Retrieves membership product objects """ @@ -91,25 +100,12 @@ def get_all_membership_products(self): self.client.request_session() query = "SELECT Objects() FROM MembershipDuesProduct" - result = self.client.runSQL(query) - msql_result = result['body']['ExecuteMSQLResult'] - if not msql_result['Errors']: - return self.package_membership_products(msql_result) - else: - return None - - def package_membership_products(self, msql_result): - """ - Loops through MS objects returned from queries to turn them into - MembershipProduct objects and pack them into a list for later use. - """ - obj_result = msql_result['ResultValue']['ObjectSearchResult'] - objects = obj_result['Objects']['MemberSuiteObject'] - product_list = [] - for obj in objects: - sane_obj = convert_ms_object( - obj['Fields']['KeyValueOfstringanyType'] - ) - product = MembershipProduct(sane_obj) - product_list.append(product) - return product_list + + membership_product_list = self.get_long_query(query, verbose=verbose) + return membership_product_list + + def ms_object_to_model(self, ms_obj): + " Converts an individual result to a Subscription Model " + sane_obj = convert_ms_object( + ms_obj['Fields']['KeyValueOfstringanyType']) + return MembershipProduct(sane_obj) From 2ec9ece09dbf6ab87d3edec5e770dd8b22fa5499 Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 16:20:57 -0600 Subject: [PATCH 08/18] Env var fix; --- membersuite_api_client/tests/test_organizations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/membersuite_api_client/tests/test_organizations.py b/membersuite_api_client/tests/test_organizations.py index 0004b63..e3dcf39 100644 --- a/membersuite_api_client/tests/test_organizations.py +++ b/membersuite_api_client/tests/test_organizations.py @@ -5,7 +5,7 @@ from ..organizations.models import Organization, OrganizationType # @todo - this should come from the env for portability -TEST_ORG_NAME = 'AASHE' +TEST_ORG_NAME = os.environ.get('TEST_ORG_ID') class OrganizationServiceTestCase(BaseTestCase): From 77a9225762d268d627ec152d77f97eb226c24146 Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 16:22:15 -0600 Subject: [PATCH 09/18] Python 3.0 support with print; --- membersuite_api_client/mixins.py | 6 +++--- membersuite_api_client/organizations/services.py | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/membersuite_api_client/mixins.py b/membersuite_api_client/mixins.py index 3aef990..11ef8b8 100644 --- a/membersuite_api_client/mixins.py +++ b/membersuite_api_client/mixins.py @@ -38,7 +38,7 @@ def run_query(base_query, start_record, limit_to, verbose): # inline method to take advantage of retry if verbose: - print "[start: %d limit: %d]" % (start_record, limit_to) + print("[start: %d limit: %d]" % (start_record, limit_to)) start = datetime.datetime.now() result = self.client.runSQL( query=base_query, @@ -47,11 +47,11 @@ def run_query(base_query, start_record, limit_to, verbose): ) end = datetime.datetime.now() if verbose: - print "[%s - %s]" % (start, end) + print("[%s - %s]" % (start, end)) return self.result_to_models(result) if verbose: - print base_query + print(base_query) record_index = start_record result = run_query(base_query, record_index, limit_to, verbose) diff --git a/membersuite_api_client/organizations/services.py b/membersuite_api_client/organizations/services.py index 33ab524..4f454ff 100644 --- a/membersuite_api_client/organizations/services.py +++ b/membersuite_api_client/organizations/services.py @@ -59,8 +59,7 @@ def get_orgs( ["%s %s %s" % (p[0], p[1], p[2]) for p in where_params]) if verbose: - print "Fetching Organizations..." - print query + print("Fetching Organizations...") # note, get_long_query is overkill when just looking at # one org, but it still only executes once From fe5b7d24b500e0cc91738c4940f20a5b9e0c5253 Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 16:33:14 -0600 Subject: [PATCH 10/18] Updated default value for verbose; --- membersuite_api_client/memberships/services.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/membersuite_api_client/memberships/services.py b/membersuite_api_client/memberships/services.py index 0c82af1..81cbb56 100644 --- a/membersuite_api_client/memberships/services.py +++ b/membersuite_api_client/memberships/services.py @@ -92,7 +92,7 @@ def __init__(self, client): """ self.client = client - def get_all_membership_products(self, verbose): + def get_all_membership_products(self, verbose=False): """ Retrieves membership product objects """ From b3427c8a9e8dae7cc9e832b489b5816206b7425b Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 18:53:43 -0600 Subject: [PATCH 11/18] Added missing org name; --- membersuite_api_client/tests/test_organizations.py | 1 + 1 file changed, 1 insertion(+) diff --git a/membersuite_api_client/tests/test_organizations.py b/membersuite_api_client/tests/test_organizations.py index e3dcf39..966aad4 100644 --- a/membersuite_api_client/tests/test_organizations.py +++ b/membersuite_api_client/tests/test_organizations.py @@ -1,4 +1,5 @@ import unittest +import os from .base import BaseTestCase from ..organizations.services import OrganizationService From e4456c483fb7f6a7cd48909bfa7c2f20dc1e3789 Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 19:02:44 -0600 Subject: [PATCH 12/18] Updated env var; --- membersuite_api_client/tests/test_organizations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/membersuite_api_client/tests/test_organizations.py b/membersuite_api_client/tests/test_organizations.py index 966aad4..7c85f93 100644 --- a/membersuite_api_client/tests/test_organizations.py +++ b/membersuite_api_client/tests/test_organizations.py @@ -6,7 +6,7 @@ from ..organizations.models import Organization, OrganizationType # @todo - this should come from the env for portability -TEST_ORG_NAME = os.environ.get('TEST_ORG_ID') +TEST_ORG_NAME = os.environ.get('TEST_ORG_NAME') class OrganizationServiceTestCase(BaseTestCase): From 177a23a5941e855ef000d30c8f7d8cb346dd7d7b Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 19:05:34 -0600 Subject: [PATCH 13/18] Updated readme to reflect updated env var; --- membersuite_api_client/tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/membersuite_api_client/tests/README.md b/membersuite_api_client/tests/README.md index de18122..76e8111 100644 --- a/membersuite_api_client/tests/README.md +++ b/membersuite_api_client/tests/README.md @@ -14,7 +14,7 @@ Until we set up a mechanism for fixtures, you'll need to set up the following: ## Organization vars: - - `TEST_ORG_ID` - an existing org + - `TEST_ORG_NAME` - an existing org's name ## Membership vars: From d88a56adaf37200417244926feebf8dd21067db0 Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 22:48:09 -0600 Subject: [PATCH 14/18] Some travis debugging.... grrr; --- membersuite_api_client/tests/test_security.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/membersuite_api_client/tests/test_security.py b/membersuite_api_client/tests/test_security.py index ea11275..5ef65cc 100644 --- a/membersuite_api_client/tests/test_security.py +++ b/membersuite_api_client/tests/test_security.py @@ -14,6 +14,8 @@ NONMEMBER_ID = os.environ.get('TEST_MS_PORTAL_NONMEMBER_ID') NONMEMBER_PASSWORD = os.environ.get('TEST_MS_PORTAL_NONMEMBER_PASS') MEMBER_ORG_NAME = os.environ.get('TEST_MS_MEMBER_ORG_NAME') +print("**************") +print("MEMBER_ORG_NAME: %" % MEMBER_ORG_NAME) def get_portal_user(client, member=True): From f4e76070baddd328a6828c52d3d717357e2f56dc Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Thu, 30 Mar 2017 22:54:37 -0600 Subject: [PATCH 15/18] more travis testing; --- membersuite_api_client/tests/test_security.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/membersuite_api_client/tests/test_security.py b/membersuite_api_client/tests/test_security.py index 5ef65cc..6571964 100644 --- a/membersuite_api_client/tests/test_security.py +++ b/membersuite_api_client/tests/test_security.py @@ -15,7 +15,7 @@ NONMEMBER_PASSWORD = os.environ.get('TEST_MS_PORTAL_NONMEMBER_PASS') MEMBER_ORG_NAME = os.environ.get('TEST_MS_MEMBER_ORG_NAME') print("**************") -print("MEMBER_ORG_NAME: %" % MEMBER_ORG_NAME) +print("MEMBER_ORG_NAME: %s" % MEMBER_ORG_NAME) def get_portal_user(client, member=True): From adab971d15a55bb09fd2985c3eb243635a79667f Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Sat, 1 Apr 2017 13:58:22 -0600 Subject: [PATCH 16/18] Documentation update; --- membersuite_api_client/tests/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/membersuite_api_client/tests/README.md b/membersuite_api_client/tests/README.md index 76e8111..906b10b 100644 --- a/membersuite_api_client/tests/README.md +++ b/membersuite_api_client/tests/README.md @@ -28,3 +28,8 @@ Until we set up a mechanism for fixtures, you'll need to set up the following: - `TEST_MS_PORTAL_NONMEMBER_ID` - nonmember with portal access - `TEST_MS_PORTAL_NONMEMBER_PASS` - password - `TEST_MS_MEMBER_ORG_NAME` - the name of the member organization + +## Subscription vars: + + - `TEST_ORG_ID_SUBSCRIBER` - org that has subscriptions + - `TEST_PUBLICATION_ID` - a publication for the subscription above From 1bfb800fbbe0bc57baa0cfb35663afbe8cac1d02 Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Sun, 2 Apr 2017 22:02:59 -0600 Subject: [PATCH 17/18] Fixed bug to use the correct subscription end_date; --- membersuite_api_client/subscriptions/services.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/membersuite_api_client/subscriptions/services.py b/membersuite_api_client/subscriptions/services.py index deaf128..08fda2d 100644 --- a/membersuite_api_client/subscriptions/services.py +++ b/membersuite_api_client/subscriptions/services.py @@ -65,10 +65,11 @@ def ms_object_to_model(self, ms_obj): " Converts an individual result to a Subscription Model " sane_obj = convert_ms_object( ms_obj['Fields']['KeyValueOfstringanyType']) + import pdb; pdb.set_trace() subscription = Subscription( id=sane_obj['ID'], org_id=sane_obj['Owner'], start=sane_obj['StartDate'], - end=sane_obj['TerminationDate'], + end=sane_obj['ExpirationDate'], extra_data=sane_obj) return subscription From 7acc8e1b364abe81a2b800a7aab9944629ec1018 Mon Sep 17 00:00:00 2001 From: Benjamin Stookey Date: Sun, 2 Apr 2017 22:10:32 -0600 Subject: [PATCH 18/18] Removed debug relic; --- membersuite_api_client/subscriptions/services.py | 1 - 1 file changed, 1 deletion(-) diff --git a/membersuite_api_client/subscriptions/services.py b/membersuite_api_client/subscriptions/services.py index 08fda2d..9952752 100644 --- a/membersuite_api_client/subscriptions/services.py +++ b/membersuite_api_client/subscriptions/services.py @@ -65,7 +65,6 @@ def ms_object_to_model(self, ms_obj): " Converts an individual result to a Subscription Model " sane_obj = convert_ms_object( ms_obj['Fields']['KeyValueOfstringanyType']) - import pdb; pdb.set_trace() subscription = Subscription( id=sane_obj['ID'], org_id=sane_obj['Owner'],