Repository URL to install this package:
|
Version:
0.4.192 ▾
|
lib-py-b2b
/
change.py
|
|---|
from datetime import datetime
from enum import Enum
from typing import Any, Optional
from boto3.dynamodb.conditions import Attr, Or
from dateutil.parser import isoparse
from py_aws_util.logging import log_data
from lib_b2b.persistent import Persistable
from lib_b2b.policy import Policy
from .base import BaseClass
import abc
import logging
from os import environ
logger = logging.getLogger(__name__)
class ChangeRecord(BaseClass, Persistable):
def __init__(self, before: Any, after: Any, description: str, when: datetime, who: str = 'the System'):
self.before = before
self.after = after
self.description = description
self.when = when
self.who = who
@staticmethod
def from_dict(data: dict):
return ChangeRecord(before=data['before'], after=data['after'], description=data['description'],
when=isoparse(data['when']), who=data['who'])
def as_dict(self) -> dict:
return {
'before': self.before,
'after': self.after,
'description': self.description,
'when': self.when.isoformat(),
'who': self.who
}
def __str__(self):
return f"{self.description} by {self.who} on {self.when.strftime('%b %d, %Y at %H:%M:%S')}"
class ChangeRequest:
def __init__(self, on_behalf_of: str, policy: Policy = None):
self.policy = policy
self.changeable_object = None
self.on_behalf_of = on_behalf_of
@abc.abstractmethod
def permitted(self, changeable_object: 'Changeable') -> bool:
raise NotImplementedError
@abc.abstractmethod
def will_change(self, changeable_object: 'Changeable') -> bool:
"""
Compares the existing data to the change request to determine if there has been a change
:return: True/False
:rtype: bool
"""
raise NotImplementedError
@abc.abstractmethod
def apply(self, changeable_object: 'Changeable'):
raise NotImplementedError
class Changeable:
@abc.abstractmethod
def record(self, change_record: ChangeRecord):
raise NotImplementedError
@abc.abstractmethod
def supported_change_request_types(self) -> [ChangeRequest]:
raise NotImplementedError
@property
@abc.abstractmethod
def changeable_identity(self):
raise NotImplementedError
def change(self, changes: [ChangeRequest]) -> 'Changeable':
for change in changes:
logger.info(f"Processing change of type: {type(change).__name__}.",
extra=log_data(change_type=type(change).__name__, changeable_id=str(self.changeable_identity)))
change.apply(self)
logger.info(f"Change of type: {type(change).__name__} applied.",
extra=log_data(change_type=type(change).__name__, changeable_id=str(self.changeable_identity)))
return self
class ChangeDataProvider(metaclass=abc.ABCMeta):
@abc.abstractmethod
def version(self) -> Optional[str]:
"""
returns the version of the change data. In most cases this is an iso formatted date.
If is is an ISO formatted date, it should be UTC to ensure consistency.
:return: String representation of the version. If None is returned, we will override the
data value ignoring the version.
:rtype: str
"""
@abc.abstractmethod
def data(self) -> dict:
"""
The request data
:return: dictionary of the change request data
:rtype: dict
"""
raise NotImplementedError