From 9d51bffa1200ca9e7f1b953c1327dc533ac476dd Mon Sep 17 00:00:00 2001 From: Lyndon Garvey Date: Fri, 27 Mar 2020 17:14:23 +0000 Subject: [PATCH 1/2] Add monitoring field to user model --- user/migrations/0002_user_monitor_companies.py | 18 ++++++++++++++++++ user/models.py | 6 ++++++ 2 files changed, 24 insertions(+) create mode 100644 user/migrations/0002_user_monitor_companies.py diff --git a/user/migrations/0002_user_monitor_companies.py b/user/migrations/0002_user_monitor_companies.py new file mode 100644 index 00000000..be462bb8 --- /dev/null +++ b/user/migrations/0002_user_monitor_companies.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.10 on 2020-03-27 15:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user', '0001_squashed_0002_auto_20190417_0813'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='auto_enable_monitoring', + field=models.BooleanField(default=False, help_text='Automatically register companies for live updates when queried via the API; NOTE: this option should only be enabled for data-hub.', verbose_name='auto enable monitoring'), + ), + ] diff --git a/user/models.py b/user/models.py index 0e077a0e..6e30fa02 100644 --- a/user/models.py +++ b/user/models.py @@ -40,6 +40,12 @@ class User(AbstractUser): username = None email = models.EmailField(_('email address'), unique=True) + auto_enable_monitoring = models.BooleanField( + _('auto enable company monitoring'), + help_text=_('Automatically register companies for live updates when queried via the API; ' + 'NOTE: this option should only be enabled for data-hub.'), + default=False, + ) USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] From 1592b806bfe39e57d212ce759edb7acbc938188c Mon Sep 17 00:00:00 2001 From: Lyndon Garvey Date: Fri, 27 Mar 2020 17:14:49 +0000 Subject: [PATCH 2/2] Add logic to make automatic company monitoring optional per API user --- api/tests/conftest.py | 8 +++++++- api/tests/test_views.py | 24 ++++++++++++++++++++---- api/views.py | 5 ++++- dnb_direct_plus/api.py | 6 +++--- dnb_direct_plus/tasks.py | 10 +++++++--- dnb_direct_plus/tests/test_api.py | 19 ++++++++++++++----- dnb_direct_plus/tests/test_management.py | 4 +--- 7 files changed, 56 insertions(+), 20 deletions(-) diff --git a/api/tests/conftest.py b/api/tests/conftest.py index ec37bd25..c0485332 100644 --- a/api/tests/conftest.py +++ b/api/tests/conftest.py @@ -6,11 +6,17 @@ User = get_user_model() +@pytest.fixture() +def api_client(): + return APIClient() + + @pytest.fixture() def auth_client(): user = User.objects.create( email='test@test.com', - is_active=True + is_active=True, + auto_enable_monitoring=True, ) token = Token.objects.create(user=user) return APIClient( diff --git a/api/tests/test_views.py b/api/tests/test_views.py index 65b74c96..db44a14c 100644 --- a/api/tests/test_views.py +++ b/api/tests/test_views.py @@ -2,11 +2,13 @@ import json import pytest +from django.contrib.auth import get_user_model from django.urls import reverse from django.utils import timezone from freezegun import freeze_time from requests.exceptions import HTTPError from rest_framework import status +from rest_framework.authtoken.models import Token from company.constants import MonitoringStatusChoices from company.models import ChangeRequest, Company @@ -77,11 +79,17 @@ def test_api_with_bad_query(self, auth_client): } assert response.json() == expected_response - def test_query_duns_number_updates_local_db_and_monitoring_is_enabled( + @pytest.mark.parametrize('enable_monitoring,monitoring_status', [ + (True, MonitoringStatusChoices.pending.name), + (False, MonitoringStatusChoices.not_enabled.name), + ]) + def test_query_duns_number_updates_local_db( self, - auth_client, + api_client, mocker, company_list_api_response_json, + enable_monitoring, + monitoring_status ): company_input_data = json.loads(company_list_api_response_json) company_input_data['searchCandidates'].pop() @@ -92,9 +100,17 @@ def test_query_duns_number_updates_local_db_and_monitoring_is_enabled( mock_api_request.return_value.json.return_value = company_input_data assert Company.objects.count() == 0 - response = auth_client.post( + + user = get_user_model().objects.create( + email='test@test.com', + is_active=True, + auto_enable_monitoring=enable_monitoring, + ) + token = Token.objects.create(user=user) + response = api_client.post( reverse('api:company-search'), {'duns_number': company_input_data['searchCandidates'][0]['organization']['duns']}, + HTTP_AUTHORIZATION=f'Token {token.key}' ) assert Company.objects.count() == 1 @@ -102,7 +118,7 @@ def test_query_duns_number_updates_local_db_and_monitoring_is_enabled( company = Company.objects.first() result_data = response.json() assert company.duns_number == result_data['results'][0]['duns_number'] - assert company.monitoring_status == MonitoringStatusChoices.pending.name + assert company.monitoring_status == monitoring_status class TestCompanyUpdateView: diff --git a/api/views.py b/api/views.py index 78941da2..2cc61c3e 100644 --- a/api/views.py +++ b/api/views.py @@ -24,7 +24,10 @@ def post(self, request): serialiser.is_valid(raise_exception=True) try: - data = company_list_search(serialiser.data, update_local=True) + data = company_list_search( + serialiser.data, + update_local=True, + enable_monitoring=request.user.auto_enable_monitoring) except HTTPError as ex: error_detail = ex.response.json()['error'] return Response(error_detail, status=ex.response.status_code) diff --git a/dnb_direct_plus/api.py b/dnb_direct_plus/api.py index 024f7d09..aeff7e83 100644 --- a/dnb_direct_plus/api.py +++ b/dnb_direct_plus/api.py @@ -4,13 +4,13 @@ from requests.exceptions import HTTPError -from dnb_direct_plus.tasks import update_company_and_enable_monitoring +from dnb_direct_plus.tasks import update_company_from_api_data DNB_COMPANY_SEARCH_ENDPOINT = '/v1/search/companyList' -def company_list_search(query, update_local=False): +def company_list_search(query, update_local=False, enable_monitoring=False): """ Perform a DNB Direct+ company search list api call @@ -39,7 +39,7 @@ def company_list_search(query, update_local=False): # update the local company record and enable monitoring if update_local and 'duns_number' in query and len(results) == 1: - update_company_and_enable_monitoring(response_data['searchCandidates'][0]) + update_company_from_api_data(response_data['searchCandidates'][0], enable_monitoring=enable_monitoring) return { 'total_matches': response_data.get('candidatesMatchedQuantity', 0), diff --git a/dnb_direct_plus/tasks.py b/dnb_direct_plus/tasks.py index d9ac9532..c70ae555 100644 --- a/dnb_direct_plus/tasks.py +++ b/dnb_direct_plus/tasks.py @@ -11,8 +11,12 @@ @shared_task -def update_company_and_enable_monitoring(api_data): - """Create or update the company entry and set monitoring_status to 'pending' if not already enabled""" +def update_company_from_api_data(api_data, enable_monitoring=False): + """ + Create or update the company entry from DNB API data. + if `enable_monitoring` is `True` then set `monitoring_status` to 'pending', + if monitoring has not already been enabled for this company + """ duns_number = api_data["organization"]["duns"] @@ -23,4 +27,4 @@ def update_company_and_enable_monitoring(api_data): except Company.DoesNotExist: company = Company() - update_company_from_source(company, api_data, timezone.now(), enable_monitoring=True) + update_company_from_source(company, api_data, timezone.now(), enable_monitoring=enable_monitoring) diff --git a/dnb_direct_plus/tests/test_api.py b/dnb_direct_plus/tests/test_api.py index 25a2b67d..36eb70a1 100644 --- a/dnb_direct_plus/tests/test_api.py +++ b/dnb_direct_plus/tests/test_api.py @@ -8,7 +8,9 @@ from company.models import Company -@pytest.mark.django_db +pytestmark = pytest.mark.django_db + + def test_company_list_search(mocker, company_list_api_response_json): company_input_data = json.loads(company_list_api_response_json) @@ -37,8 +39,13 @@ def test_company_list_search(mocker, company_list_api_response_json): assert extract_company_data(input_data) == expected -@pytest.mark.django_db -def test_company_list_search_detail_query_company_data_is_saved(mocker, company_list_api_response_json): +@pytest.mark.parametrize('enable_monitoring,monitoring_status', [ + (True, MonitoringStatusChoices.pending.name), + (False, MonitoringStatusChoices.not_enabled.name), +]) +def test_company_list_search_detail_query_company_data_is_saved(mocker, + company_list_api_response_json, + enable_monitoring, monitoring_status): company_input_data = json.loads(company_list_api_response_json) @@ -51,11 +58,13 @@ def test_company_list_search_detail_query_company_data_is_saved(mocker, company_ assert Company.objects.count() == 0 - output = company_list_search({'duns_number': 'hello world',}, update_local=True) + output = company_list_search( + {'duns_number': 'hello world',}, update_local=True, enable_monitoring=enable_monitoring) assert Company.objects.count() == 1 company = Company.objects.first() assert company.duns_number == output['results'][0]['duns_number'] - assert company.monitoring_status == MonitoringStatusChoices.pending.name + + assert company.monitoring_status == monitoring_status diff --git a/dnb_direct_plus/tests/test_management.py b/dnb_direct_plus/tests/test_management.py index b1548f5c..546fc614 100644 --- a/dnb_direct_plus/tests/test_management.py +++ b/dnb_direct_plus/tests/test_management.py @@ -9,9 +9,7 @@ from ..models import MonitoringFileRecord -pytestmark = [ - pytest.mark.django_db -] +pytestmark = pytest.mark.django_db class TestProcessMonitoringData: