# Path: job_runner/apps/job_runner/models.py
# class Worker(models.Model):
#     """
#     Workers
#     """
#     title = models.CharField(max_length=255)
#     description = models.TextField(blank=True)
#     api_key = models.CharField(max_length=255, db_index=True, unique=True)
#     secret = models.CharField(max_length=255, db_index=True)
#     enqueue_is_enabled = models.BooleanField(
#         default=True,
#         db_index=True,
#         help_text=(
#             'If unchecked, nothing for this worker will be added to '
#             'the worker queue. This will not affect already running jobs.'
#         )
#     )
#     ping_response_dts = models.DateTimeField(
#         blank=True, null=True, editable=False)
# 
#     # the worker will send back the worker version and concurrent jobs on
#     # ping response
#     worker_version = models.CharField(
#         max_length=100, blank=True, null=True, editable=False)
#     concurrent_jobs = models.PositiveIntegerField(
#         blank=True, null=True, editable=False)
# 
#     def __unicode__(self):
#         return self.title
# 
#     def log_name(self):
#         return u'"{0}"({1})'.format(self.title, self.pk)
# 
#     def is_responsive(self):
#         """
#         Return ``bool`` indicating if the worker is resposive.
#         """
#         unresponsive_intervals = \
#             settings.JOB_RUNNER_WORKER_UNRESPONSIVE_AFTER_INTERVALS
#         ping_interval = settings.JOB_RUNNER_WORKER_PING_INTERVAL
#         ping_margin = settings.JOB_RUNNER_WORKER_PING_MARGIN
# 
#         acceptable_delta = timedelta(
#             seconds=(unresponsive_intervals * ping_interval) + ping_margin)
# 
#         if self.ping_response_dts:
#             if self.ping_response_dts + acceptable_delta >= timezone.now():
#                 return True
# 
#         logger.error('Worker {0} is not responsive'.format(self.log_name()))
#         return False
# 
#     class Meta:
#         ordering = ('title', )


import hashlib
import hmac
import re
import logging
from django.db.models import Q
from tastypie.authentication import Authentication
from tastypie.authorization import Authorization
from job_runner.apps.job_runner.models import Worker

    :param request:
        The incoming request object.

    :return:
        A ``bool`` indicating if the request is valid.

    This will test the ``Authentication`` header for valid keys. The following
    format is expected::

        Authorization: ApiKey api_key:hmac_sha1

    ``public_key``
        Is the public key as stored in the ApiKey model.

    ``hmac_sha1``
        The HMAC-SHA1 generated over the uppercased request method + full
        request path (path + query string, if applicable) + request body,
        if applicable.

    """
    auth_header = request.META.get('HTTP_AUTHORIZATION', '')
    api_key_match = re.match(r'^ApiKey (.*?):(.*?)$', auth_header)

    if not api_key_match:
        logger.error('api key mismatch')
        return False

    try:
        worker = Worker.objects.get(api_key=api_key_match.group(1))

# Path: job_runner/apps/job_runner/models.py
# class Worker(models.Model):
#     """
#     Workers
#     """
#     title = models.CharField(max_length=255)
#     description = models.TextField(blank=True)
#     api_key = models.CharField(max_length=255, db_index=True, unique=True)
#     secret = models.CharField(max_length=255, db_index=True)
#     enqueue_is_enabled = models.BooleanField(
#         default=True,
#         db_index=True,
#         help_text=(
#             'If unchecked, nothing for this worker will be added to '
#             'the worker queue. This will not affect already running jobs.'
#         )
#     )
#     ping_response_dts = models.DateTimeField(
#         blank=True, null=True, editable=False)
# 
#     # the worker will send back the worker version and concurrent jobs on
#     # ping response
#     worker_version = models.CharField(
#         max_length=100, blank=True, null=True, editable=False)
#     concurrent_jobs = models.PositiveIntegerField(
#         blank=True, null=True, editable=False)
# 
#     def __unicode__(self):
#         return self.title
# 
#     def log_name(self):
#         return u'"{0}"({1})'.format(self.title, self.pk)
# 
#     def is_responsive(self):
#         """
#         Return ``bool`` indicating if the worker is resposive.
#         """
#         unresponsive_intervals = \
#             settings.JOB_RUNNER_WORKER_UNRESPONSIVE_AFTER_INTERVALS
#         ping_interval = settings.JOB_RUNNER_WORKER_PING_INTERVAL
#         ping_margin = settings.JOB_RUNNER_WORKER_PING_MARGIN
# 
#         acceptable_delta = timedelta(
#             seconds=(unresponsive_intervals * ping_interval) + ping_margin)
# 
#         if self.ping_response_dts:
#             if self.ping_response_dts + acceptable_delta >= timezone.now():
#                 return True
# 
#         logger.error('Worker {0} is not responsive'.format(self.log_name()))
#         return False
# 
#     class Meta:
#         ordering = ('title', )


# Path: job_runner/apps/job_runner/auth.py
import hashlib
import hmac
import re
import logging
from django.db.models import Q
from tastypie.authentication import Authentication
from tastypie.authorization import Authorization
from job_runner.apps.job_runner.models import Worker


    :param request:
        The incoming request object.

    :return:
        A ``bool`` indicating if the request is valid.

    This will test the ``Authentication`` header for valid keys. The following
    format is expected::

        Authorization: ApiKey api_key:hmac_sha1

    ``public_key``
        Is the public key as stored in the ApiKey model.

    ``hmac_sha1``
        The HMAC-SHA1 generated over the uppercased request method + full
        request path (path + query string, if applicable) + request body,
        if applicable.

    """
    auth_header = request.META.get('HTTP_AUTHORIZATION', '')
    api_key_match = re.match(r'^ApiKey (.*?):(.*?)$', auth_header)

    if not api_key_match:
        logger.error('api key mismatch')
        return False

    try:
        worker = Worker.objects.get(api_key=api_key_match.group(1))

    except Worker.DoesNotExist: