From 5d92285cd98af17eddbe9bc98f47f56d669e6e90 Mon Sep 17 00:00:00 2001 From: John Keyes Date: Sat, 26 Nov 2016 23:10:28 +0000 Subject: [PATCH 1/2] Ignore the coverage HTML report. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5858c47e..d0242b3f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ venv *.egg-info *.pyc .DS_Store +htmlcov docs/_build intercom.sublime-project From ea4871f2821c7e4cad596f5f94973985d0828293 Mon Sep 17 00:00:00 2001 From: John Keyes Date: Mon, 28 Nov 2016 22:03:07 +0000 Subject: [PATCH 2/2] Add by_tag support to users and companies. --- intercom/extended_api_operations/tags.py | 17 +++++++++ intercom/service/company.py | 4 +- intercom/service/user.py | 3 +- tests/unit/__init__.py | 47 ++++++++++++++++++++++++ tests/unit/test_company.py | 24 ++++++++---- tests/unit/test_user.py | 8 ++++ 6 files changed, 93 insertions(+), 10 deletions(-) create mode 100644 intercom/extended_api_operations/tags.py diff --git a/intercom/extended_api_operations/tags.py b/intercom/extended_api_operations/tags.py new file mode 100644 index 00000000..6243efe1 --- /dev/null +++ b/intercom/extended_api_operations/tags.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +"""Operation to return resources with a particular tag.""" + +from intercom import utils +from intercom.collection_proxy import CollectionProxy + + +class Tags(object): + """A mixin that provides `by_tag` functionality a resource.""" + + def by_tag(self, _id): + """Return a CollectionProxy to all the tagged resources.""" + collection = utils.resource_class_to_collection_name( + self.collection_class) + finder_url = "/%s?tag_id=%s" % (collection, _id) + return CollectionProxy( + self.client, self.collection_class, collection, finder_url) diff --git a/intercom/service/company.py b/intercom/service/company.py index 4dbd384b..446062ad 100644 --- a/intercom/service/company.py +++ b/intercom/service/company.py @@ -8,14 +8,14 @@ from intercom.api_operations.save import Save from intercom.api_operations.load import Load from intercom.extended_api_operations.users import Users +from intercom.extended_api_operations.tags import Tags from intercom.service.base_service import BaseService -class Company(BaseService, All, Delete, Find, FindAll, Save, Load, Users): +class Company(BaseService, All, Delete, Find, FindAll, Save, Load, Users, Tags): @property def collection_class(self): return company.Company -# require 'intercom/extended_api_operations/tags' # require 'intercom/extended_api_operations/segments' diff --git a/intercom/service/user.py b/intercom/service/user.py index e219f2b3..44f32c45 100644 --- a/intercom/service/user.py +++ b/intercom/service/user.py @@ -8,10 +8,11 @@ from intercom.api_operations.delete import Delete from intercom.api_operations.save import Save from intercom.api_operations.load import Load +from intercom.extended_api_operations.tags import Tags from intercom.service.base_service import BaseService -class User(BaseService, All, Find, FindAll, Delete, Save, Load, Submit): +class User(BaseService, All, Find, FindAll, Delete, Save, Load, Submit, Tags): @property def collection_class(self): diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py index c8669ffa..d0b2824d 100644 --- a/tests/unit/__init__.py +++ b/tests/unit/__init__.py @@ -137,6 +137,30 @@ def get_user(email="bob@example.com", name="Joe Schmoe"): } +def get_company(name): + return { + "type": "company", + "id": "531ee472cce572a6ec000006", + "name": name, + "plan": { + "type": "plan", + "id": "1", + "name": "Paid" + }, + "company_id": "6", + "remote_created_at": 1394531169, + "created_at": 1394533506, + "updated_at": 1396874658, + "monthly_spend": 49, + "session_count": 26, + "user_count": 10, + "custom_attributes": { + "paid_subscriber": True, + "team_mates": 0 + } + } + + def page_of_users(include_next_link=False): page = { "type": "user.list", @@ -157,6 +181,29 @@ def page_of_users(include_next_link=False): page["pages"]["next"] = "https://api.intercom.io/users?per_page=50&page=2" return page + +def page_of_companies(include_next_link=False): + page = { + "type": "company.list", + "pages": { + "type": "pages", + "page": 1, + "next": None, + "per_page": 50, + "total_pages": 7 + }, + "companies": [ + get_company('ACME A'), + get_company('ACME B'), + get_company('ACME C') + ], + "total_count": 3 + } + if include_next_link: + page["pages"]["next"] = "https://api.intercom.io/companies?per_page=50&page=2" + return page + + test_tag = { "id": "4f73428b5e4dfc000b000112", "name": "Test Tag", diff --git a/tests/unit/test_company.py b/tests/unit/test_company.py index d6de0c79..73840e62 100644 --- a/tests/unit/test_company.py +++ b/tests/unit/test_company.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- # noqa import intercom import unittest @@ -9,34 +9,44 @@ from mock import patch from nose.tools import assert_raises from nose.tools import eq_ +from nose.tools import ok_ from nose.tools import istest +from tests.unit import page_of_companies -class CompanyTest(unittest.TestCase): +class CompanyTest(unittest.TestCase): # noqa - def setUp(self): + def setUp(self): # noqa self.client = Client() @istest - def it_raises_error_if_no_response_on_find(self): + def it_raises_error_if_no_response_on_find(self): # noqa with patch.object(Client, 'get', return_value=None) as mock_method: with assert_raises(intercom.HttpError): self.client.companies.find(company_id='4') mock_method.assert_called_once_with('/companies', {'company_id': '4'}) @istest - def it_raises_error_if_no_response_on_find_all(self): + def it_raises_error_if_no_response_on_find_all(self): # noqa with patch.object(Client, 'get', return_value=None) as mock_method: with assert_raises(intercom.HttpError): [x for x in self.client.companies.all()] mock_method.assert_called_once_with('/companies', {}) @istest - def it_raises_error_on_load(self): + def it_raises_error_on_load(self): # noqa company = Company() company.id = '4' side_effect = [None] - with patch.object(Client, 'get', side_effect=side_effect) as mock_method: # noqa + with patch.object(Client, 'get', side_effect=side_effect) as mock_method: with assert_raises(intercom.HttpError): self.client.companies.load(company) eq_([call('/companies/4', {})], mock_method.mock_calls) + + @istest + def it_gets_companies_by_tag(self): # noqa + with patch.object(Client, 'get', return_value=page_of_companies(False)) as mock_method: + companies = self.client.companies.by_tag(124) + for company in companies: + ok_(hasattr(company, 'company_id')) + eq_([call('/companies?tag_id=124', {})], mock_method.mock_calls) diff --git a/tests/unit/test_user.py b/tests/unit/test_user.py index 382674dd..8d0ca16c 100644 --- a/tests/unit/test_user.py +++ b/tests/unit/test_user.py @@ -20,6 +20,7 @@ from nose.tools import istest from tests.unit import get_user from tests.unit import mock_response +from tests.unit import page_of_users class UserTest(unittest.TestCase): @@ -179,6 +180,13 @@ def it_fetches_a_user(self): mock_method.assert_called_once_with( '/users', {'email': 'somebody@example.com'}) # noqa + @istest + def it_gets_users_by_tag(self): + with patch.object(Client, 'get', return_value=page_of_users(False)) as mock_method: + users = self.client.users.by_tag(124) + for user in users: + ok_(hasattr(user, 'avatar')) + @istest def it_saves_a_user_always_sends_custom_attributes(self):