# Path: locksmith/common.py
# def enum(name, **enums):
#     def __iter__(self):
# def get_signature(params, signkey):
# def apicall(url, signkey, **params):
# def cache(seconds = 900):
#     def doCache(f):
#         def x(*args, **kwargs):
#     E = type(name or 'Enum', (), enums)
# API_OPERATING_STATUSES = (
#     (1, 'Normal'),
#     (2, 'Degraded Service'),
#     (3, 'Service Disruption'),
#     (4, 'Undergoing Maintenance')
# )
# API_STATUSES = enum('ApiStatuses',
#                     Stealth=0,
#                     Active=1,
#                     Deprecated=2,
#                     Disabled=3)
# KEY_STATUSES = (
#     ('U', 'Unactivated'),
#     ('A', 'Active'),
#     ('S', 'Suspended')
# )
# UNPUBLISHED, PUBLISHED, NEEDS_UPDATE = range(3)
# PUB_STATUSES = (
#     (UNPUBLISHED, 'Unpublished'),
#     (PUBLISHED, 'Published'),
#     (NEEDS_UPDATE, 'Needs Update'),
# )
# 
# Path: locksmith/hub/tasks.py
# @task(max_retries=5)
# def push_key(key, replicate_too=True):
#     if replicate_too:
#         for kps in key.pub_statuses.filter(api__push_enabled=True):
#             if kps.api.name in ReplicatedApiNames:
#                 replicate_key.delay(key, kps.api)
# 
#     endpoints = {UNPUBLISHED: 'create_key/', NEEDS_UPDATE: 'update_key/'}
#     dirty = key.pub_statuses.exclude(status=PUBLISHED).filter(
#               api__push_enabled=True).select_related()
#     if not dirty:
#         print u"Skipping push_key for {k} because all KeyPublicationStatus objects are PUBLISHED.".format(k=key.key)
# 
#     # Retrying immediately on failure would allow a broken or unresponsive
#     # api to prevent other, properly functioning apis from receiving the key.
#     # Thus we use retry_flag to delay the task retry until after attempting
#     # to push to all apis.
#     retry_flag = False
#     for kps in dirty:
#         if kps.api.name in ReplicatedApiNames:
#             # Skip this API because we've queued a replicate_key task above
#             print u"push_key for {k} ignoring {a} because it uses replicate_key.".format(k=key.key, a=kps.api.name)
#             continue
# 
#         endpoint = urljoin(kps.api.url, endpoints[kps.status])
#         try:
#             apicall(endpoint, kps.api.signing_key, api=kps.api.name,
#                     key=kps.key.key, email=kps.key.email, status=kps.key.status)
#             print 'sent key {k} to {a}'.format(k=key.key, a=kps.api.name)
#             kps.status = PUBLISHED
#             kps.save()
# 
#         except Exception as e:
#             ctx = {
#                 'a': str(kps.api.name),
#                 'k': str(key.key),
#                 'e': str(e.read()) if isinstance(e, urllib2.HTTPError) else str(e)
#             }
#             print 'Caught exception while pushing key {k} to {a}: {e}'.format(**ctx)
#             print 'Will retry'
#             retry_flag = True
# 
#     if retry_flag:
#         push_key.retry()


import datetime
from django.db import models
from django.db.models.signals import post_save
from django import forms
from django.contrib.auth.models import User
from locksmith.common import (KEY_STATUSES,
                              PUB_STATUSES,
                              UNPUBLISHED,
                              NEEDS_UPDATE,
                              API_OPERATING_STATUSES,
                              API_STATUSES)
from locksmith.hub.tasks import push_key
from taggit.managers import TaggableManager
#from django.forms import Form, ModelForm, ValidationError, BooleanField, EmailField

def resolve_model(model, fields):
    """
    model: Model class
    fields: List of 2-tuples of the form (field, value) in order of descending priority
    """
    for (f, v) in fields:
        if v is not None:
            try:
                kwargs = {f: v}
                obj = model.objects.get(**kwargs)
                return obj
            except model.DoesNotExist:
                pass
            except model.MultipleObjectsReturned:
                pass
    raise model.DoesNotExist()

class Api(models.Model):
    '''
        API that Keys are issued to and Reports come from
    '''
    name = models.CharField(max_length=30)
    signing_key = models.CharField(max_length=32)
    url = models.URLField()
    push_enabled = models.BooleanField(default=True)
    description = models.TextField('Description', blank=True)

# Path: locksmith/common.py
# def enum(name, **enums):
#     def __iter__(self):
# def get_signature(params, signkey):
# def apicall(url, signkey, **params):
# def cache(seconds = 900):
#     def doCache(f):
#         def x(*args, **kwargs):
#     E = type(name or 'Enum', (), enums)
# API_OPERATING_STATUSES = (
#     (1, 'Normal'),
#     (2, 'Degraded Service'),
#     (3, 'Service Disruption'),
#     (4, 'Undergoing Maintenance')
# )
# API_STATUSES = enum('ApiStatuses',
#                     Stealth=0,
#                     Active=1,
#                     Deprecated=2,
#                     Disabled=3)
# KEY_STATUSES = (
#     ('U', 'Unactivated'),
#     ('A', 'Active'),
#     ('S', 'Suspended')
# )
# UNPUBLISHED, PUBLISHED, NEEDS_UPDATE = range(3)
# PUB_STATUSES = (
#     (UNPUBLISHED, 'Unpublished'),
#     (PUBLISHED, 'Published'),
#     (NEEDS_UPDATE, 'Needs Update'),
# )
# 
# Path: locksmith/hub/tasks.py
# @task(max_retries=5)
# def push_key(key, replicate_too=True):
#     if replicate_too:
#         for kps in key.pub_statuses.filter(api__push_enabled=True):
#             if kps.api.name in ReplicatedApiNames:
#                 replicate_key.delay(key, kps.api)
# 
#     endpoints = {UNPUBLISHED: 'create_key/', NEEDS_UPDATE: 'update_key/'}
#     dirty = key.pub_statuses.exclude(status=PUBLISHED).filter(
#               api__push_enabled=True).select_related()
#     if not dirty:
#         print u"Skipping push_key for {k} because all KeyPublicationStatus objects are PUBLISHED.".format(k=key.key)
# 
#     # Retrying immediately on failure would allow a broken or unresponsive
#     # api to prevent other, properly functioning apis from receiving the key.
#     # Thus we use retry_flag to delay the task retry until after attempting
#     # to push to all apis.
#     retry_flag = False
#     for kps in dirty:
#         if kps.api.name in ReplicatedApiNames:
#             # Skip this API because we've queued a replicate_key task above
#             print u"push_key for {k} ignoring {a} because it uses replicate_key.".format(k=key.key, a=kps.api.name)
#             continue
# 
#         endpoint = urljoin(kps.api.url, endpoints[kps.status])
#         try:
#             apicall(endpoint, kps.api.signing_key, api=kps.api.name,
#                     key=kps.key.key, email=kps.key.email, status=kps.key.status)
#             print 'sent key {k} to {a}'.format(k=key.key, a=kps.api.name)
#             kps.status = PUBLISHED
#             kps.save()
# 
#         except Exception as e:
#             ctx = {
#                 'a': str(kps.api.name),
#                 'k': str(key.key),
#                 'e': str(e.read()) if isinstance(e, urllib2.HTTPError) else str(e)
#             }
#             print 'Caught exception while pushing key {k} to {a}: {e}'.format(**ctx)
#             print 'Will retry'
#             retry_flag = True
# 
#     if retry_flag:
#         push_key.retry()


# Path: locksmith/hub/models.py
import datetime
from django.db import models
from django.db.models.signals import post_save
from django import forms
from django.contrib.auth.models import User
from locksmith.common import (KEY_STATUSES,
                              PUB_STATUSES,
                              UNPUBLISHED,
                              NEEDS_UPDATE,
                              API_OPERATING_STATUSES,
                              API_STATUSES)
from locksmith.hub.tasks import push_key
from taggit.managers import TaggableManager

#from django.forms import Form, ModelForm, ValidationError, BooleanField, EmailField

def resolve_model(model, fields):
    """
    model: Model class
    fields: List of 2-tuples of the form (field, value) in order of descending priority
    """
    for (f, v) in fields:
        if v is not None:
            try:
                kwargs = {f: v}
                obj = model.objects.get(**kwargs)
                return obj
            except model.DoesNotExist:
                pass
            except model.MultipleObjectsReturned:
                pass
    raise model.DoesNotExist()

class Api(models.Model):
    '''
        API that Keys are issued to and Reports come from
    '''
    name = models.CharField(max_length=30)
    signing_key = models.CharField(max_length=32)
    url = models.URLField()
    push_enabled = models.BooleanField(default=True)
    description = models.TextField('Description', blank=True)

    status = models.IntegerField(choices=API_OPERATING_STATUSES, default=1)