diff --git a/back/users/models.py b/back/users/models.py index 227daf952..0caac8b14 100644 --- a/back/users/models.py +++ b/back/users/models.py @@ -10,7 +10,7 @@ from django.db.models import CheckConstraint, Q from django.template import Context, Template from django.utils.crypto import get_random_string -from django.utils.functional import cached_property +from django.utils.functional import cached_property, lazy from django.utils.translation import gettext_lazy as _ from admin.appointments.models import Appointment @@ -431,7 +431,9 @@ def get_local_time(self, date=None): ) return us_tz.normalize(local.astimezone(us_tz)) - def personalize(self, text, extra_values={}): + def personalize(self, text, extra_values=None): + if extra_values is None: + extra_values = {} t = Template(text) department = "" manager = "" @@ -456,14 +458,42 @@ def personalize(self, text, extra_values={}): "start": self.start_day, "buddy_email": buddy_email, "manager_email": manager_email, + "access_overview": lazy(self.get_access_overview, str), "department": department, } + text = t.render(Context(new_hire_context | extra_values)) # Remove non breakable space html code (if any). These could show up in the # Slack bot. text = text.replace(" ", " ") return text + def get_access_overview(self): + all_access = [] + for integration, access in self.check_integration_access().items(): + if access is None: + access_str = _("(unknown)") + elif access: + access_str = _("(has access)") + else: + access_str = _("(no access)") + + all_access.append(f"{integration} {access_str}") + + return ", ".join(all_access) + + def check_integration_access(self): + from admin.integrations.models import Integration + + items = {} + for integration_user in IntegrationUser.objects.filter(user=self): + items[integration_user.integration.name] = not integration_user.revoked + + for integration in Integration.objects.filter(manifest__exists__isnull=False): + items[integration.name] = integration.user_exists(self) + + return items + def reset_otp_recovery_keys(self): self.user_otp.all().delete() newItems = [OTPRecoveryKey(user=self) for x in range(10)] diff --git a/back/users/tests.py b/back/users/tests.py index e54d83453..f41d017f6 100644 --- a/back/users/tests.py +++ b/back/users/tests.py @@ -1,6 +1,7 @@ import datetime import pytest +from unittest.mock import Mock, patch from django.contrib.auth import get_user_model from freezegun import freeze_time @@ -199,7 +200,13 @@ def test_days_before_starting(date, daybefore, new_hire_factory): @pytest.mark.django_db -def test_personalize(manager_factory, new_hire_factory, department_factory): +def test_personalize( + manager_factory, + new_hire_factory, + department_factory, + custom_integration_factory, + integration_user_factory, +): department = department_factory(name="IT") manager = manager_factory(first_name="jane", last_name="smith") buddy = manager_factory(email="cat@chiefonboarding.com") @@ -211,11 +218,16 @@ def test_personalize(manager_factory, new_hire_factory, department_factory): position="developer", department=department, ) + # add integrations + i_u1 = integration_user_factory(user=new_hire, revoked=True) + i_u2 = integration_user_factory(user=new_hire, revoked=False) + + integration = custom_integration_factory() text = ( "Hello {{ first_name }} {{ last_name }}, your manager is {{ manager }} and " "you can reach your buddy through {{ buddy_email }}, you will be our " - "{{ position }} in {{ department }}" + "{{ position }} in {{ department }}. He has access to: {{ access_overview }}" ) text_without_spaces = ( "Hello {{first_name}} {{last_name}}, your manager is {{manager}} and you can " @@ -224,12 +236,48 @@ def test_personalize(manager_factory, new_hire_factory, department_factory): ) expected_output = ( + "Hello john smith, your manager is jane smith and you can reach your buddy " + "through cat@chiefonboarding.com, you will be our developer in IT. He has " + f"access to: {i_u1.integration.name} (no access), {i_u2.integration.name} (has " + f"access), {integration.name} (unknown)" + ) + + expected_output_without_spaces = ( "Hello john smith, your manager is jane smith and you can reach your buddy " "through cat@chiefonboarding.com, you will be our developer in IT" ) - assert new_hire.personalize(text) == expected_output - assert new_hire.personalize(text_without_spaces) == expected_output + # Service errored + with patch( + "admin.integrations.models.Integration.user_exists", + Mock(return_value=(None)), + ): + assert new_hire.personalize(text) == expected_output + assert ( + new_hire.personalize(text_without_spaces) == expected_output_without_spaces + ) + + +@pytest.mark.django_db +def test_check_integration_access( + new_hire_factory, custom_integration_factory, integration_user_factory +): + new_hire = new_hire_factory() + integration_user1 = integration_user_factory(user=new_hire, revoked=True) + integration_user2 = integration_user_factory(user=new_hire, revoked=False) + + integration = custom_integration_factory() + + # integration service errored + with patch( + "admin.integrations.models.Integration.user_exists", + Mock(return_value=(None)), + ): + access = new_hire.check_integration_access() + + assert access[integration_user1.integration.name] is False + assert access[integration_user2.integration.name] is True + assert access[integration.name] is None @pytest.mark.django_db diff --git a/docs/Integrations.md b/docs/Integrations.md index 2fc73e5f6..cede1921d 100644 --- a/docs/Integrations.md +++ b/docs/Integrations.md @@ -179,6 +179,8 @@ Throughout the manifest you can use the variables that you have defined in the ` `start`: New hire's start date +`access_overview`: This will be a list of all the access the user could have access to. This includes previously assigned manual access and automated access (all of the automated items). It will result in a string like this: `Asana (no access), Google (has access), Teams (unknown)`. `unknown` is used when we couldn't reach the service. + !!! Please do not overwrite these with your own ids !!!