# Path: chaosmonkey/api/hal.py
# class Document(BaseDocument):
#     """Constructs a ``HAL`` document.
#     """
# 
#     def __init__(self, data=None, links=None, embedded=None, external_self=False):
#         """Initialises a new ``HAL`` Document instance. If no arguments are
#         provided a minimal viable ``HAL`` Document is created.
# 
#         Keyword Args:
#             data (dict): Data for the document
#             links (chaosmonkey.api.hal.link.Collection): A collection of ``HAL`` links
#             embedded: TBC
#             external_self: use a fully-qualified link for self
# 
#         Raises:
#             TypeError: If ``links`` is not a :class:`chaosmonkey.api.hal.link.Collection`
#         """
#         super(Document, self).__init__(data, links, embedded)
#         self.links.append(Self(external=external_self))
# 
# Path: chaosmonkey/api/api_errors.py
# class APIError(Exception):
#     """
#     Represents an API Error
# 
#     :param message: message to be returned to the user
#     :param status_code: response status code (defaults to 400)
#     :param payload: custom payload to give extra info in the response
# 
#     Example:
#             >>> raise APIError("Error detected", 500, {"extra": "extra_info"})
# 
#     """
# 
#     def __init__(self, message, status_code=None, payload=None):
#         Exception.__init__(self)
#         self.message = message
#         self.status_code = status_code or 400
#         self.payload = payload
# 
#     def to_dict(self):
#         """Convert exception to dict"""
#         dict_ = dict(self.payload or ())
#         dict_['msg'] = self.message
#         return dict_
# 
#     def __str__(self):
#         return '[%d] %s' % (self.status_code, self.message)
# 
# Path: chaosmonkey/api/request_validator.py
# def validate_payload(request, schema):
#     """
#     validates a request payload against a json schema
# 
#     :param request: request received with valid json body
#     :param schema:  schema to validate the request payload
# 
#     :return: True
#     :raises: :meth:`chaosmonkey.api.api_errors`
#     """
#     try:
#         json = request.get_json()
#         validate(json, schema)
#     except ValidationError as e:
#         raise APIError("invalid payload %s" % e.message)
#     except Exception:
#         raise APIError("payload must be a valid json")
#     else:
#         return True
# 
# Path: chaosmonkey/engine/cme_manager.py
# class CMEManager:
#     def __init__(self):
#     def configure(self, scheduler, sql_store, planners_store, attacks_store):
#     def scheduler(self):
#     def attacks_store(self):
#     def planners_store(self):
#     def sql_store(self):
#     def get_executors(self, executed=False):
#     def get_executor(self, executor_id):
#     def get_executors_for_plan(self, plan_id):
#     def update_executor_trigger(self, executor_id, trigger):
#     def remove_executor(self, executor_id):
#     def add_executor(self, date, name, attack_config, plan_id):
#     def get_attack_list(self):
#     def get_planner_list(self):
#     def execute_plan(self, name, planner_config, attack_config):
#     def add_plan(self, name):
#     def get_plan(self, plan_id):
#     def get_plans(self, show_all=None):
#     def delete_plan(self, plan_id):
#     def _job_to_executor(job):
# 
# Path: chaosmonkey/api/utils.py
# def get_boolean(value):
#     """
#     to get boolean values from query strings
# 
#     :param value:
#     :return: boolean
#     """
#     if isinstance(value, bool):
#         return value
# 
#     if not value:
#         return False
#     value = value.lower()
#     if value in ('false', 'no', 'off', 'n', '0',):
#         return False
#     if value in ('true', 'yes', 'on', 'y', '1',):
#         return True
# 
#     return False


import arrow
from apscheduler.jobstores.base import JobLookupError
from apscheduler.triggers.date import DateTrigger
from flask import Blueprint, json, request
from chaosmonkey.api.hal import Document
from chaosmonkey.api.api_errors import APIError
from chaosmonkey.api.request_validator import validate_payload
from chaosmonkey.engine.cme_manager import manager
from chaosmonkey.api.utils import get_boolean
        {
          "id": "3b373155577b4d1bbc62216ffea013a4",
          "plan_id": "3ec72048cab04b76bdf2cfd4bc81cd1e",
          "next_run_time": "2017-10-23T19:19:1508786354",
          "executed": false,
          "_links": {
            "self": {
              "href": "/api/1/executors/3b373155577b4d1bbc62216ffea013a4"
            },
            "update":{
              "href":"/api/1/executors/3b373155577b4d1bbc62216ffea013a4"
            },
            "delete":{
              "href":"/api/1/executors/3b373155577b4d1bbc62216ffea013a4"
            }
          }
        }

    :return: :meth:`chaosmonkey.api.hal.document`
    """
    assert validate_payload(request, executor_trigger_schema)
    body = request.get_json()

    trigger = dict_to_trigger(body)

    try:
        executor = manager.update_executor_trigger(executor_id, trigger)
    except JobLookupError:
        return json.jsonify({"msg": "executor not found " + executor_id}), 404
    else:

# Path: chaosmonkey/api/hal.py
# class Document(BaseDocument):
#     """Constructs a ``HAL`` document.
#     """
# 
#     def __init__(self, data=None, links=None, embedded=None, external_self=False):
#         """Initialises a new ``HAL`` Document instance. If no arguments are
#         provided a minimal viable ``HAL`` Document is created.
# 
#         Keyword Args:
#             data (dict): Data for the document
#             links (chaosmonkey.api.hal.link.Collection): A collection of ``HAL`` links
#             embedded: TBC
#             external_self: use a fully-qualified link for self
# 
#         Raises:
#             TypeError: If ``links`` is not a :class:`chaosmonkey.api.hal.link.Collection`
#         """
#         super(Document, self).__init__(data, links, embedded)
#         self.links.append(Self(external=external_self))
# 
# Path: chaosmonkey/api/api_errors.py
# class APIError(Exception):
#     """
#     Represents an API Error
# 
#     :param message: message to be returned to the user
#     :param status_code: response status code (defaults to 400)
#     :param payload: custom payload to give extra info in the response
# 
#     Example:
#             >>> raise APIError("Error detected", 500, {"extra": "extra_info"})
# 
#     """
# 
#     def __init__(self, message, status_code=None, payload=None):
#         Exception.__init__(self)
#         self.message = message
#         self.status_code = status_code or 400
#         self.payload = payload
# 
#     def to_dict(self):
#         """Convert exception to dict"""
#         dict_ = dict(self.payload or ())
#         dict_['msg'] = self.message
#         return dict_
# 
#     def __str__(self):
#         return '[%d] %s' % (self.status_code, self.message)
# 
# Path: chaosmonkey/api/request_validator.py
# def validate_payload(request, schema):
#     """
#     validates a request payload against a json schema
# 
#     :param request: request received with valid json body
#     :param schema:  schema to validate the request payload
# 
#     :return: True
#     :raises: :meth:`chaosmonkey.api.api_errors`
#     """
#     try:
#         json = request.get_json()
#         validate(json, schema)
#     except ValidationError as e:
#         raise APIError("invalid payload %s" % e.message)
#     except Exception:
#         raise APIError("payload must be a valid json")
#     else:
#         return True
# 
# Path: chaosmonkey/engine/cme_manager.py
# class CMEManager:
#     def __init__(self):
#     def configure(self, scheduler, sql_store, planners_store, attacks_store):
#     def scheduler(self):
#     def attacks_store(self):
#     def planners_store(self):
#     def sql_store(self):
#     def get_executors(self, executed=False):
#     def get_executor(self, executor_id):
#     def get_executors_for_plan(self, plan_id):
#     def update_executor_trigger(self, executor_id, trigger):
#     def remove_executor(self, executor_id):
#     def add_executor(self, date, name, attack_config, plan_id):
#     def get_attack_list(self):
#     def get_planner_list(self):
#     def execute_plan(self, name, planner_config, attack_config):
#     def add_plan(self, name):
#     def get_plan(self, plan_id):
#     def get_plans(self, show_all=None):
#     def delete_plan(self, plan_id):
#     def _job_to_executor(job):
# 
# Path: chaosmonkey/api/utils.py
# def get_boolean(value):
#     """
#     to get boolean values from query strings
# 
#     :param value:
#     :return: boolean
#     """
#     if isinstance(value, bool):
#         return value
# 
#     if not value:
#         return False
#     value = value.lower()
#     if value in ('false', 'no', 'off', 'n', '0',):
#         return False
#     if value in ('true', 'yes', 'on', 'y', '1',):
#         return True
# 
#     return False


# Path: chaosmonkey/api/executors_blueprint.py
import arrow
from apscheduler.jobstores.base import JobLookupError
from apscheduler.triggers.date import DateTrigger
from flask import Blueprint, json, request
from chaosmonkey.api.hal import Document
from chaosmonkey.api.api_errors import APIError
from chaosmonkey.api.request_validator import validate_payload
from chaosmonkey.engine.cme_manager import manager
from chaosmonkey.api.utils import get_boolean

        {
          "id": "3b373155577b4d1bbc62216ffea013a4",
          "plan_id": "3ec72048cab04b76bdf2cfd4bc81cd1e",
          "next_run_time": "2017-10-23T19:19:1508786354",
          "executed": false,
          "_links": {
            "self": {
              "href": "/api/1/executors/3b373155577b4d1bbc62216ffea013a4"
            },
            "update":{
              "href":"/api/1/executors/3b373155577b4d1bbc62216ffea013a4"
            },
            "delete":{
              "href":"/api/1/executors/3b373155577b4d1bbc62216ffea013a4"
            }
          }
        }

    :return: :meth:`chaosmonkey.api.hal.document`
    """
    assert validate_payload(request, executor_trigger_schema)
    body = request.get_json()

    trigger = dict_to_trigger(body)

    try:
        executor = manager.update_executor_trigger(executor_id, trigger)
    except JobLookupError:
        return json.jsonify({"msg": "executor not found " + executor_id}), 404
    else:

        return Document(data=executor.to_dict())