from abc import ABC, abstractmethod from app.formatters import format_thousands from app.models import ModelList from app.notify_client.service_api_client import service_api_client from notifications_utils.formatters import formatted_list class Event(ABC): def __init__( self, item, key=None, value_from=None, value_to=None, ): self.item = item self.time = item["updated_at"] or item["created_at"] self.user_id = item["created_by_id"] self.key = key self.value_from = value_from self.value_to = value_to @abstractmethod def __str__(self): pass @property @abstractmethod def relevant(self): pass class ServiceCreationEvent(Event): relevant = True def __str__(self): return "Created this service and called it ‘{}’".format(self.item["name"]) class ServiceEvent(Event): @property def relevant(self): return self.value_from != self.value_to and bool(self._formatter) def __str__(self): return self._formatter() @property def _formatter(self): return getattr(self, "format_{}".format(self.key), None) def format_restricted(self): if self.value_to is False: return "Made this service live" if self.value_to is True: return "Put this service back into trial mode" def format_active(self): if self.value_to is False: return "Deleted this service" if self.value_to is True: return "Unsuspended this service" def format_contact_link(self): return "Set the contact details for this service to ‘{}’".format(self.value_to) def format_inbound_api(self): return "Updated the callback for received text messages" def format_message_limit(self): return ("{} this service’s daily message limit from {} to {}").format( "Reduced" if self.value_from > self.value_to else "Increased", format_thousands(self.value_from), format_thousands(self.value_to), ) def format_name(self): return ("Renamed this service from ‘{}’ to ‘{}’").format( self.value_from, self.value_to ) def format_permissions(self): added = list(sorted(set(self.value_to) - set(self.value_from))) removed = list(sorted(set(self.value_from) - set(self.value_to))) if removed and added: return "Removed {} from this service’s permissions, added {}".format( formatted_list(removed), formatted_list(added), ) if added: return "Added {} to this service’s permissions".format( formatted_list(added) ) if removed: return "Removed {} from this service’s permissions".format( formatted_list(removed) ) def format_prefix_sms(self): if self.value_to is True: return "Set text messages to start with the name of this service" else: return "Set text messages to not start with the name of this service" def format_research_mode(self): if self.value_to is True: return "Put this service into research mode" else: return "Took this service out of research mode" def format_service_callback_api(self): return "Updated the callback for delivery receipts" class APIKeyEvent(Event): relevant = True def __str__(self): if self.item["updated_at"]: return ("Revoked the ‘{}’ API key").format(self.item["name"]) else: return ("Created an API key called ‘{}’").format(self.item["name"]) class APIKeyEvents(ModelList): model = APIKeyEvent client_method = service_api_client.get_service_api_key_history class ServiceEvents(ModelList): client_method = service_api_client.get_service_service_history @property def model(self): return lambda x: x @staticmethod def splat(events): for index, item in enumerate( sorted(events, key=lambda event: event["updated_at"] or event["created_at"]) ): if index == 0: yield ServiceCreationEvent(item) else: for key in sorted(item.keys()): yield ServiceEvent( item, key, events[index - 1][key], events[index][key], ) def __init__(self, service_id): self.items = [ event for event in self.splat(self.client_method(service_id)) if event.relevant ]