class MailMunger(Munger): """ Attributes: name : str distillery : Distillery condenser: MailCondenser a MailCondenser used to distill the message into the chosen Bottle """ condenser = models.ForeignKey(MailCondenser) objects = GetByNameManager() def _get_company(self): """ """ return self.distillery.company def _process_data(self, data): """ Takes a dictionary of data (e.g., of a social media post) and a Condenser. Returns a dictionary that distills the data using the crosswalk defined by the Condenser. """ company = self._get_company() return self.condenser.process(data=data, company=company)
class Inspection(models.Model): """ Attributes: name: a string representing the name of the Inspection steps: one or more InspectionSteps associated with the Inspection """ name = models.CharField(max_length=255, unique=True) objects = GetByNameManager() def __str__(self): return self.name def get_result(self, data): """ Notes ----- This method should have the same name as the corresponding method in a LabProcedure. """ steps = self.steps.all() for step in steps: if step.is_match(data): return step.result_value return None
class Procedure(models.Model): """Applies a Protocol to one or all fields of a dictionary. Attributes ---------- name : str The name of the procedure. protocol : str A Protocol used to analyze the data. field_name : str The name of the field containing the data to analyze. If none is provided, the entire data dictionary is analyzed. """ name = models.CharField(max_length=255, unique=True) protocol = models.ForeignKey(Protocol) field_name = models.CharField(max_length=255, blank=True, null=True) objects = GetByNameManager() def __str__(self): """Represent a Procedure as a string.""" return self.name def _analyze(self, data): return self.protocol.process(data) def get_result(self, data): """Analayze data according to a Protocol. Analyzes a data dictionary using the Procedure's :attr:`~Procedure.protocol`. If the Procedure has a :attr:`~Procedure.field_name`, only the corresponding field within the data dictionary is analyzed. Otherwise, the entire data dictionary is analyzed with the protocol. Parameters ---------- data : dict The data to analyze. Returns ------- any The results of the analysis. Notes ----- This method should have the same name as the corresponding method in an Inspection. """ if self.field_name: value = parserutils.get_dict_value(self.field_name, data) return self._analyze(value) else: return self._analyze(data)
class LogMunger(Munger): """ Attributes: condenser: a LogCondenser used to distill the message into the chosen Bottle """ condenser = models.ForeignKey(LogCondenser) objects = GetByNameManager()
class InspectionStep(models.Model): """ Defines a step in an Inspection. Attributes: inspection: the Inspection associated with the InspectionStep sieve: a DataSieve for examining data result_value: a value to be returned if the datasieve returns True for the data examined rank: an integer representing the order of the step in an Inspection; steps are performed in ascending order (the lowest rank first) """ inspection = models.ForeignKey( Inspection, related_name='steps', related_query_name='step', verbose_name=_('Inspection'), help_text=_('The Inspection in which this step is included.')) sieve = models.ForeignKey( DataSieve, related_name='inspection_steps', related_query_name='inspection_step', help_text=_( 'The DataSieve used to inspect the data during this step.')) result_value = models.CharField( max_length=255, help_text=_('The value to be returned if the DataSieve returns True ' 'for the data examined.')) rank = models.IntegerField( default=0, help_text=_('An integer representing the order of this step in the ' 'Inspection. Steps are performed in ascending order, ' 'with the lowest number examined first.')) objects = GetByNameManager() class Meta(object): """Metadata options.""" ordering = ['rank'] unique_together = [('inspection', 'sieve'), ('inspection', 'rank')] def __str__(self): return '%s <- %s (rank: %s)' % (self.sieve, self.result_value, self.rank) def is_match(self, data): return self.sieve.is_match(data)
class Company(models.Model): """ """ name = models.CharField(max_length=60, unique=True) uuid = models.UUIDField(default=uuid4) objects = GetByNameManager() class Meta: verbose_name_plural = 'companies' ordering = ['name'] def __str__(self): return self.name
class MailRule(Rule): """ A Rule subclass for examining email messages. """ operator = models.CharField(max_length=40, choices=REGEX_CHOICES, help_text=_('The type of comparison to make.')) field_name = models.CharField(max_length=40, choices=EMAIL_FIELD_CHOICES) objects = GetByNameManager() def _get_string(self, data): """ Takes an email Message object and returns the Message component indicated by the MailRule's field_name. """ value = accessors.get_email_value(self.field_name, data) return str(value)
class Visa(models.Model): """ Defines an API rate limit. Specifies the number of requests (calls) that can be made in a given time interval. Attributes ---------- name : str The identifier for the |Visa|. calls : int The number of requests allowed in the rate limit interval. time_interval : int The number of units in the rate limit interval. The type of unit is specified by the :attr:`~Visa.time_unit` attribute. time_unit : str Defines the units of measure for the :attr:`~Visa.time_interval`. Choices are limited to |TIME_UNIT_CHOICES|. """ name = models.CharField(max_length=40, unique=True) calls = models.IntegerField() time_interval = models.IntegerField() time_unit = models.CharField(max_length=3, choices=TIME_UNIT_CHOICES) objects = GetByNameManager() def __str__(self): return self.name def get_request_interval_in_minutes(self): """Get the number of minutes in the rate limit interval. Returns ------- int The number of minutes in the rate limit interval. """ return dt.convert_time_to_whole_minutes(self.time_interval, self.time_unit)
class Protocol(models.Model): """Analyzes data using a function in a Lab subpackage. Attributes ---------- name : str The name of the Protocol. package : str The name of a subpackage within the `labs` package that will analyze the data. module : str The name of the module in the package that will analyze the data. function : str The name of the function that will analyze the data. """ name = models.CharField(max_length=255, unique=True) package = models.CharField( max_length=32, validators=[IDENTIFIER_VALIDATOR], choices=LAB_CHOICES ) module = models.CharField( max_length=32, validators=[IDENTIFIER_VALIDATOR] ) function = models.CharField( max_length=32, validators=[IDENTIFIER_VALIDATOR] ) objects = GetByNameManager() class Meta(object): """Metadata options.""" unique_together = ('package', 'module', 'function') def __str__(self): """Represent a Protocol as a string.""" return self.name def _get_module(self): """Return the module for analyzing the data.""" module_full_name = 'lab.%s.%s' % (self.package, self.module) # load the module (will raise ImportError if module cannot be loaded) module = importlib.import_module(module_full_name) return module def process(self, data): """Analyze a dictionary of data. Passes data to the Protocol's :attr:`~Protocol.function` and returns the result. Parameters ---------- data : dict The data to analyze. Returns ------- any The result of the analysis. """ module = self._get_module() # get the classifier function (will raise AttributeError if function cannot be found) func = getattr(module, self.function) return func(data)
class LogCondenser(Condenser): """ """ objects = GetByNameManager()
class LogRule(StringRule): """ A Rule subclass for examining log messages. """ objects = GetByNameManager()
class LogParser(StringParser): """ """ objects = GetByNameManager()
class MailCondenser(Condenser): """ """ objects = GetByNameManager()
class DataCondenser(Condenser): """ A Condenser for distilling data from API responses. """ objects = GetByNameManager()
class DataParser(FieldParser): """ A class for parsing data from API responses. """ objects = GetByNameManager()
class DataRule(FieldRule): """ """ objects = GetByNameManager()
class Passport(models.Model): """ Provides a generalized set of credentials used by APIs to authenticate a user or app. Different APIs may make use of different fields in the Passport model. Attributes ---------- name : str An identifier for the |Passport|. key : `str` or `None` The consumer/client/developer key used to authenticate requests. file : `str` or `None` Path to a file for a public or private key, depending on the needs of the API authenticator. Acceptable extensions are defined by :const:`~KEY_FILE_TYPES`. secret : `str` or `None` A client/consumer secret used to authenticate requests. access_token : `str` or `None` An access token used for OAuth authentication. access_token_secret : `str` or `None` An access token secret used for OAuth authentication. public : bool Whether the |Passport| can be used by any user. users : AppUsers Specific |AppUsers| who are allowed to use the Passport. """ KEY_FILE_TYPES = ['.pem', '.pub'] """ A |list| of acceptable extensions for a :attr:`Passport.file`. """ name = models.CharField(max_length=40, unique=True) key = models.CharField(max_length=255, null=True, blank=True) file = models.FileField(null=True, blank=True, storage=_KEYS_STORAGE, validators=[key_file_validator]) secret = models.CharField(max_length=255, null=True, blank=True) access_token = models.CharField(max_length=255, blank=True) access_token_secret = models.CharField(max_length=255, blank=True) public = models.BooleanField( default=False, help_text=_('Make available to all registered Users.')) users = models.ManyToManyField( settings.AUTH_USER_MODEL, related_name='passports', related_query_name='passport', blank=True, help_text=_('If not Public, restrict use to these Users.')) objects = GetByNameManager() def __str__(self): return self.name def get_call_count(self, start_time): """Get the number of times the |Passport| has been used since start_time. Parameters ---------- start_time : |datetime| The start of the time frame in which calls should be counted. Returns ------- int The number of |Stamps| associated with the |Passport| that have a :attr:`~ambassador.stamps.models.Stamp.job_start` greater or equal to `start_time`. This represents the number of API calls made with the |Passport| in that time. """ return self.stamps.filter(job_start__gte=start_time).count()