diff --git a/.gitignore b/.gitignore index 02a2856d..e31a6dc3 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,4 @@ # JIRA plugin atlassian-ide-plugin.xml -config.json \ No newline at end of file +*.pem \ No newline at end of file diff --git a/config.json b/config.json deleted file mode 100644 index 05103110..00000000 --- a/config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "tmpdir": "/tmp/drafter", - "logo": "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png" -} \ No newline at end of file diff --git a/config.json.sample b/config.json.sample deleted file mode 100644 index bf8478ce..00000000 --- a/config.json.sample +++ /dev/null @@ -1,4 +0,0 @@ -{ - "tmpdir": "/tmp/drafter", - "logo": "/path/to/some/logo.png" -} \ No newline at end of file diff --git a/index.php b/index.php index 7424e402..5770ceb2 100755 --- a/index.php +++ b/index.php @@ -3,7 +3,6 @@ * Set up include path for source handling */ set_include_path(get_include_path().":".__DIR__.'/src/'); -$config = json_decode(file_get_contents(__DIR__."/config.json")); /** * Set up required classes (with the autoloader) diff --git a/src/PHPDraft/In/Tests/ApibFileParserTest.php b/src/PHPDraft/In/Tests/ApibFileParserTest.php new file mode 100644 index 00000000..e8e64a4f --- /dev/null +++ b/src/PHPDraft/In/Tests/ApibFileParserTest.php @@ -0,0 +1,38 @@ + + */ + +namespace PHPDraft\In\Tests; + + +use PHPDraft\Core\TestBase; +use PHPDraft\In\ApibFileParser; +use ReflectionClass; + +class ApibFileParserTest extends TestBase +{ + public function setUp() + { + $this->class = new ApibFileParser(__DIR__.'/ApibFileParserTest.php'); + $this->reflection = new ReflectionClass('PHPDraft\In\ApibFileParser'); + } + + public function tearDown() + { + unset($this->class); + unset($this->reflection); + } + + public function testSetup() + { + $property = $this->reflection->getProperty('location'); + $property->setAccessible(TRUE); + $this->assertSame(__DIR__.'/', $property->getValue($this->class)); + } + + +} \ No newline at end of file diff --git a/src/PHPDraft/Model/Category.php b/src/PHPDraft/Model/Category.php index 463760aa..2e7f54c6 100644 --- a/src/PHPDraft/Model/Category.php +++ b/src/PHPDraft/Model/Category.php @@ -8,7 +8,9 @@ namespace PHPDraft\Model; -class Category extends APIBlueprintElement +use PHPDraft\Model\Elements\DataStructureElement; + +class Category extends HierarchyElement { /** * API Structure element diff --git a/src/PHPDraft/Model/Elements/ArrayStructureElement.php b/src/PHPDraft/Model/Elements/ArrayStructureElement.php index af129a4e..73f980f1 100644 --- a/src/PHPDraft/Model/Elements/ArrayStructureElement.php +++ b/src/PHPDraft/Model/Elements/ArrayStructureElement.php @@ -8,16 +8,14 @@ namespace PHPDraft\Model\Elements; +use PHPDraft\Model\StructureElement; -use PHPDraft\Model\DataStructureElement; - -class ArrayStructureElement extends DataStructureElement +class ArrayStructureElement extends DataStructureElement implements StructureElement { public function parse($item, &$dependencies) { $this->element = (isset($item->element)) ? $item->element : 'array'; - $this->element = (isset($item->element)) ? $item->element : NULL; $this->value = (isset($item->content)) ? $item->content : NULL; if (isset($item->content)) @@ -35,6 +33,10 @@ public function parse($item, &$dependencies) $value = new DataStructureElement(); $this->value[$key] = $value->parse($sub_item, $dependencies); break; + case 'enum': + $value = new EnumStructureElement(); + $this->value[$key] = $value->parse($sub_item, $dependencies); + break; default: $this->value[$key] = (isset($sub_item->content)) ? $sub_item->content : NULL; break; @@ -55,7 +57,7 @@ function __toString() foreach ($this->type as $key => $item) { $type = - (in_array($item, self::DEFAULTS)) ? $item : '' . $item . ''; + (in_array($item, self::DEFAULTS)) ? $item : '' . $item . ''; $value = (isset($this->value[$key])) ? ': ' . json_encode($this->value[$key]) . '' : NULL; diff --git a/src/PHPDraft/Model/DataStructureElement.php b/src/PHPDraft/Model/Elements/DataStructureElement.php similarity index 73% rename from src/PHPDraft/Model/DataStructureElement.php rename to src/PHPDraft/Model/Elements/DataStructureElement.php index a4c5b3f6..38b9dfe5 100644 --- a/src/PHPDraft/Model/DataStructureElement.php +++ b/src/PHPDraft/Model/Elements/DataStructureElement.php @@ -2,21 +2,17 @@ /** * This file contains the DataStructureElement.php * - * @package PHPDraft\Model + * @package PHPDraft\Model\Elements * @author Sean Molenaar */ -namespace PHPDraft\Model; +namespace PHPDraft\Model\Elements; -use PHPDraft\Model\Elements\ArrayStructureElement; +use PHPDraft\Model\StructureElement; -class DataStructureElement +class DataStructureElement implements StructureElement { - /** - * Default datatypes - * @var array - */ - const DEFAULTS = ['boolean', 'string', 'number', 'object', 'array']; + /** * Object key * @var string @@ -68,17 +64,26 @@ public function parse($object, &$dependencies) return $this; } $this->element = $object->element; + if (isset($object->content) && is_array($object->content)) { foreach ($object->content as $value) { - $struct = new DataStructureElement(); + if (in_array($this->element, ['object', 'dataStructure'])) + { + $struct = new DataStructureElement(); + } + else + { + $struct = new EnumStructureElement(); + } $this->value[] = $struct->parse($value, $dependencies); } return $this; } + $this->key = $object->content->key->content; $this->type = $object->content->value->element; $this->description = isset($object->meta->description) ? $object->meta->description : NULL; @@ -90,13 +95,17 @@ public function parse($object, &$dependencies) $dependencies[] = $this->type; } - if ($this->type === 'object' || $this->type === 'array') + if ($this->type === 'object' || $this->type === 'array' || $this->type === 'enum' || !in_array($this->type, self::DEFAULTS)) { $value = isset($object->content->value->content) ? $object->content->value : NULL; if ($this->type === 'array') { $this->value = new ArrayStructureElement(); } + elseif ($this->type === 'enum') + { + $this->value = new EnumStructureElement(); + } else { $this->value = new DataStructureElement(); @@ -128,7 +137,15 @@ function __toString() $return = ''; foreach ($this->value as $object) { - if (is_string($object) || get_class($object) === self::class || get_class($object) === ArrayStructureElement::class) + if (get_class($object) === \stdClass::class) + { + return json_encode($object); + } + if (is_string($object) + || get_class($object) === self::class + || get_class($object) === ArrayStructureElement::class + || get_class($object) === EnumStructureElement::class + ) { $return .= $object; } @@ -140,7 +157,7 @@ function __toString() } $type = (!in_array($this->type, self::DEFAULTS)) ? - '' . $this->type . '' : '' . $this->type . ''; + '' . $this->type . '' : '' . $this->type . ''; if (empty($this->value)) { @@ -156,6 +173,10 @@ function __toString() { $value = '
' . $this->value . '
'; } + elseif (is_array($this->value) && (EnumStructureElement::class === get_class($this->value[0]))) + { + $value = '
' . $this->value . '
'; + } else { $value = '' . $this->value . ''; diff --git a/src/PHPDraft/Model/Elements/EnumStructureElement.php b/src/PHPDraft/Model/Elements/EnumStructureElement.php new file mode 100644 index 00000000..cd159d5e --- /dev/null +++ b/src/PHPDraft/Model/Elements/EnumStructureElement.php @@ -0,0 +1,81 @@ + + */ + +namespace PHPDraft\Model\Elements; + +use PHPDraft\Model\StructureElement; + +class EnumStructureElement implements StructureElement +{ + /** + * Object description + * @var string + */ + public $description; + /** + * Type of element + * @var string + */ + public $element = NULL; + /** + * Object value + * @var mixed + */ + public $value = NULL; + /** + * Object status (required|optional) + * @var string + */ + public $status = ''; + /** + * List of object dependencies + * @var string[] + */ + public $deps; + + /** + * Parse a JSON object to a structure + * + * @param \stdClass $item An object to parse + * @param array $dependencies Dependencies of this object + * + * @return EnumStructureElement self reference + */ + function parse($item, &$dependencies) + { + $this->element = (isset($item->element)) ? $item->element : NULL; + $this->description = (isset($item->meta->description)) ? $item->meta->description : NULL; + $this->value = (isset($item->content)) ? $item->content : NULL; + + if (!in_array($this->element, self::DEFAULTS)) + { + $dependencies[] = $this->element; + } + + return $this; + } + + /** + * Print a string representation + * + * @return string + */ + function __toString() + { + $type = (!in_array($this->element, self::DEFAULTS)) ? + '' . $this->element . '' : '' . $this->element . ''; + $return = '' . + '' . + '' . + '' . + ''; + return $return; + } + + +} \ No newline at end of file diff --git a/src/PHPDraft/Model/Elements/RequestBodyElement.php b/src/PHPDraft/Model/Elements/RequestBodyElement.php index 14bd384f..563fdeb3 100644 --- a/src/PHPDraft/Model/Elements/RequestBodyElement.php +++ b/src/PHPDraft/Model/Elements/RequestBodyElement.php @@ -8,9 +8,9 @@ namespace PHPDraft\Model\Elements; -use PHPDraft\Model\DataStructureElement; +use PHPDraft\Model\StructureElement; -class RequestBodyElement extends DataStructureElement +class RequestBodyElement extends DataStructureElement implements StructureElement { /** * Parse a JSON object to a data structure @@ -58,6 +58,13 @@ public function parse($object, &$dependencies) return $this; } + if ($this->type === 'array') + { + $this->value = '[]'; + + return $this; + } + $this->value = isset($object->content->value->content) ? $object->content->value->content : NULL; return $this; @@ -86,7 +93,7 @@ public function print_request($type = 'application/x-www-form-urlencoded') switch ($type) { case 'application/x-www-form-urlencoded': - $return .= join('&', $list); + $return .= join('&', $list); break; default: $return .= join(PHP_EOL, $list); @@ -113,4 +120,15 @@ public function print_request($type = 'application/x-www-form-urlencoded') break; } } + + /** + * + * @return string + */ + function __toString() + { + return parent::__toString(); + } + + } \ No newline at end of file diff --git a/src/PHPDraft/Model/Elements/Tests/ArrayStructureTest.php b/src/PHPDraft/Model/Elements/Tests/ArrayStructureTest.php new file mode 100644 index 00000000..5d011ce8 --- /dev/null +++ b/src/PHPDraft/Model/Elements/Tests/ArrayStructureTest.php @@ -0,0 +1,38 @@ + + */ + +namespace PHPDraft\Model\Elements\Tests; + + +use PHPDraft\Core\TestBase; +use PHPDraft\Model\Elements\ArrayStructureElement; + +class ArrayStructureTest extends TestBase +{ + public function setUp() + { + $this->class = new ArrayStructureElement(); + $this->reflection = new \ReflectionClass('PHPDraft\Model\Elements\ArrayStructureElement'); + } + + public function tearDown() + { + unset($this->class); + unset($this->reflection); + } + + /** + * Test if the value the class is initialized with is correct + */ + public function testSetupCorrectly() + { + $property = $this->reflection->getProperty('element'); + $property->setAccessible(TRUE); + $this->assertNull($property->getValue($this->class)); + } +} \ No newline at end of file diff --git a/src/PHPDraft/Model/Tests/DataStructureElementTest.php b/src/PHPDraft/Model/Elements/Tests/DataStructureElementTest.php similarity index 84% rename from src/PHPDraft/Model/Tests/DataStructureElementTest.php rename to src/PHPDraft/Model/Elements/Tests/DataStructureElementTest.php index 4b8ca6b7..efc95b39 100644 --- a/src/PHPDraft/Model/Tests/DataStructureElementTest.php +++ b/src/PHPDraft/Model/Elements/Tests/DataStructureElementTest.php @@ -40,6 +40,7 @@ public function testSuccesfulParse($object, $expected) { $dep = []; $this->class->parse(json_decode($object), $dep); + var_dump($this->class); $this->assertSame($this->class->key, $expected->key); $this->assertSame($this->class->value, $expected->value); $this->assertSame($this->class->element, $expected->element); @@ -82,12 +83,13 @@ public function parseObjectProvider() $base2->type = 'Struct1'; $return[] = [ - '{"element": "member","content": {"key": {"element": "string","content": "Content-Type"},' . - '"value": {"element": "Struct2","content": "application/json"}}}', + '{"element":"object","content":[{"element":"member","meta":{"description":"API version with optional client + architecture identifier"},"content":{"key":{"element":"string" + ,"content":"version"},"value":{"element":"Struct2","content":"120.a"}}}', $base1, ]; $return[] = [ - '{"element": "member","content": {"key": {"element": "string","content": "Auth2"},' . + '{"element": "object","content": {"key": {"element": "string","content": "Auth2"},' . '"value": {"element": "Struct1","content": "something"}}}', $base2, ]; @@ -103,17 +105,17 @@ public function parseObjectDepProvider() { $return = []; $return[] = [ - '{"element": "member","content": {"key": {"element": "string","content": "Content-Type"}' . - ',"value": {"element": "Struct2","content": "application/json"}}}', + '{"element":"object","content":[{"element":"member","meta":{"description":"API version"}, + "content":{"key":{"element":"string","content":"version"},"value":{"element":"Struct2","content":"120.a"}}}', ['Struct2'], ]; $return[] = [ - '{"element": "member","content": {"key": {"element": "string","content": "Auth2"}' . - ',"value": {"element": "Struct1","content": "something"}}}', - ['Struct1'], + '{"element":"member","content":{"key":{"element":"string","content":"flight_list"}, + "value":{"element":"array","content":[{"element":"Flight"}]}}}', + ['Flight'], ]; $return[] = [ - '{"element": "member", + '{"element": "object", "meta": {"description": "Update Data Object"}, "content": { "key": {"element": "string","content": "data"}, diff --git a/src/PHPDraft/Model/Elements/Tests/RequestBodyElementTest.php b/src/PHPDraft/Model/Elements/Tests/RequestBodyElementTest.php new file mode 100644 index 00000000..99052009 --- /dev/null +++ b/src/PHPDraft/Model/Elements/Tests/RequestBodyElementTest.php @@ -0,0 +1,38 @@ + + */ + +namespace PHPDraft\Model\Elements\Tests; + + +use PHPDraft\Core\TestBase; +use PHPDraft\Model\Elements\RequestBodyElement; + +class RequestBodyElementTest extends TestBase +{ + public function setUp() + { + $this->class = new RequestBodyElement(); + $this->reflection = new \ReflectionClass('PHPDraft\Model\Elements\RequestBodyElement'); + } + + public function tearDown() + { + unset($this->class); + unset($this->reflection); + } + + /** + * Test if the value the class is initialized with is correct + */ + public function testSetupCorrectly() + { + $property = $this->reflection->getProperty('element'); + $property->setAccessible(TRUE); + $this->assertNull($property->getValue($this->class)); + } +} \ No newline at end of file diff --git a/src/PHPDraft/Model/HTTPRequest.php b/src/PHPDraft/Model/HTTPRequest.php index 86a1481a..a9197051 100644 --- a/src/PHPDraft/Model/HTTPRequest.php +++ b/src/PHPDraft/Model/HTTPRequest.php @@ -32,9 +32,16 @@ class HTTPRequest /** * Body of the request (if POST or PUT) + * @var mixed + */ + public $body = NULL; + + + /** + * Structure of the request (if POST or PUT) * @var RequestBodyElement[] */ - public $body = []; + public $struct = []; /** * HTTPRequest constructor. @@ -66,6 +73,15 @@ public function parse($object) $this->parse_structure($value->content); continue; } + elseif ($value->element === 'asset') + { + if (in_array('messageBody', $value->meta->classes)) + { + $this->body[] = (isset($value->content)) ? $value->content : NULL; + $this->headers['Content-Type'] = + (isset($value->attributes->contentType)) ? $value->attributes->contentType : ''; + } + } } } @@ -77,6 +93,11 @@ public function parse($object) } } + if ($this->body === NULL) + { + $this->body = &$this->struct; + } + return $this; } @@ -94,14 +115,14 @@ private function parse_structure($objects) $struct->parse($object, $deps); $struct->deps = $deps; - $this->body[] = $struct; + $this->struct[] = $struct; } } /** * Generate a cURL command for the HTTP request * - * @param string $base_url URL to the base server + * @param string $base_url URL to the base server * * @param array $additional Extra options to pass to cURL * @@ -111,20 +132,27 @@ public function get_curl_command($base_url, $additional = []) { $options = []; - $type = (isset($this->headers['Content-Type']))?$this->headers['Content-Type']:NULL; + $type = (isset($this->headers['Content-Type'])) ? $this->headers['Content-Type'] : NULL; - $options[] = '-X'.$this->method; - foreach ($this->body as $body) + $options[] = '-X' . $this->method; + if (is_string($this->body)) + { + $options[] = '--data-binary "' . $this->body . '"'; + } + else { - $options[] = '--data-binary "'.strip_tags($body->print_request($type)).'"'; + foreach ($this->struct as $body) + { + $options[] = '--data-binary "' . strip_tags($body->print_request($type)) . '"'; + } } - foreach ($this->headers as $header=>$value) + foreach ($this->headers as $header => $value) { - $options[] = '-H "'.$header.': '.$value. '"'; + $options[] = '-H "' . $header . ': ' . $value . '"'; } $options = array_merge($options, $additional); - return htmlspecialchars('curl '.join(' ', $options). ' "'.$this->parent->build_url($base_url).'"'); + return htmlspecialchars('curl ' . join(' ', $options) . ' "' . $this->parent->build_url($base_url) . '"'); } diff --git a/src/PHPDraft/Model/HTTPResponse.php b/src/PHPDraft/Model/HTTPResponse.php index a16b9b57..f9c0e973 100644 --- a/src/PHPDraft/Model/HTTPResponse.php +++ b/src/PHPDraft/Model/HTTPResponse.php @@ -8,6 +8,8 @@ namespace PHPDraft\Model; +use PHPDraft\Model\Elements\DataStructureElement; + class HTTPResponse { /** diff --git a/src/PHPDraft/Model/APIBlueprintElement.php b/src/PHPDraft/Model/HierarchyElement.php similarity index 94% rename from src/PHPDraft/Model/APIBlueprintElement.php rename to src/PHPDraft/Model/HierarchyElement.php index d20d7be3..db9f07a4 100644 --- a/src/PHPDraft/Model/APIBlueprintElement.php +++ b/src/PHPDraft/Model/HierarchyElement.php @@ -10,7 +10,7 @@ use Michelf\Markdown; -abstract class APIBlueprintElement +abstract class HierarchyElement { /** * Title of the element @@ -29,14 +29,14 @@ abstract class APIBlueprintElement /** * Child elements * - * @var APIBlueprintElement[] + * @var HierarchyElement[] */ public $children = []; /** * Parent Element * - * @var APIBlueprintElement|NULL + * @var HierarchyElement|NULL */ protected $parent = NULL; diff --git a/src/PHPDraft/Model/Resource.php b/src/PHPDraft/Model/Resource.php index 57e2c8cb..a096262f 100644 --- a/src/PHPDraft/Model/Resource.php +++ b/src/PHPDraft/Model/Resource.php @@ -8,7 +8,7 @@ namespace PHPDraft\Model; -class Resource extends APIBlueprintElement +class Resource extends HierarchyElement { /** * Location relative to the base URL diff --git a/src/PHPDraft/Model/StructureElement.php b/src/PHPDraft/Model/StructureElement.php new file mode 100644 index 00000000..e50218e2 --- /dev/null +++ b/src/PHPDraft/Model/StructureElement.php @@ -0,0 +1,36 @@ + + */ + +namespace PHPDraft\Model; + + +interface StructureElement +{ + /** + * Default datatypes + * @var array + */ + const DEFAULTS = ['boolean', 'string', 'number', 'object', 'array']; + + /** + * Parse a JSON object to a structure + * + * @param \stdClass $object An object to parse + * @param array $dependencies Dependencies of this object + * + * @return StructureElement self reference + */ + function parse($object, &$dependencies); + + /** + * Print a string representation + * + * @return string + */ + function __toString(); +} \ No newline at end of file diff --git a/src/PHPDraft/Model/Tests/CategoryTest.php b/src/PHPDraft/Model/Tests/CategoryTest.php new file mode 100644 index 00000000..6fadbb05 --- /dev/null +++ b/src/PHPDraft/Model/Tests/CategoryTest.php @@ -0,0 +1,45 @@ + + */ + +namespace PHPDraft\Model\Tests; + + +use PHPDraft\Core\TestBase; +use PHPDraft\Model\Category; +use ReflectionClass; + +class CategoryTest extends TestBase +{ + /** + * Set up + */ + public function setUp() + { + $this->class = new Category(); + $this->reflection = new ReflectionClass('PHPDraft\Model\Category'); + } + + /** + * Tear down + */ + public function tearDown() + { + unset($this->class); + unset($this->reflection); + } + + /** + * Test if the value the class is initialized with is correct + */ + public function testSetupCorrectly() + { + $property = $this->reflection->getProperty('parent'); + $property->setAccessible(TRUE); + $this->assertNull($property->getValue($this->class)); + } +} \ No newline at end of file diff --git a/src/PHPDraft/Model/Tests/HTTPRequestTest.php b/src/PHPDraft/Model/Tests/HTTPRequestTest.php new file mode 100644 index 00000000..a7917bc4 --- /dev/null +++ b/src/PHPDraft/Model/Tests/HTTPRequestTest.php @@ -0,0 +1,47 @@ + + */ + +namespace PHPDraft\Model\Tests; + + +use PHPDraft\Core\TestBase; +use PHPDraft\Model\HTTPRequest; +use PHPDraft\Model\Transition; +use ReflectionClass; + +class HTTPRequestTest extends TestBase +{ + /** + * Set up + */ + public function setUp() + { + $parent = NULL; + $this->class = new HTTPRequest($parent); + $this->reflection = new ReflectionClass('PHPDraft\Model\HTTPRequest'); + } + + /** + * Tear down + */ + public function tearDown() + { + unset($this->class); + unset($this->reflection); + } + + /** + * Test if the value the class is initialized with is correct + */ + public function testSetupCorrectly() + { + $property = $this->reflection->getProperty('parent'); + $property->setAccessible(TRUE); + $this->assertNull($property->getValue($this->class)); + } +} \ No newline at end of file diff --git a/src/PHPDraft/Model/Tests/HTTPResponseTest.php b/src/PHPDraft/Model/Tests/HTTPResponseTest.php new file mode 100644 index 00000000..b2003025 --- /dev/null +++ b/src/PHPDraft/Model/Tests/HTTPResponseTest.php @@ -0,0 +1,46 @@ + + */ + +namespace PHPDraft\Model\Tests; + + +use PHPDraft\Core\TestBase; +use PHPDraft\Model\HTTPResponse; +use ReflectionClass; + +class HTTPResponseTest extends TestBase +{ + /** + * Set up + */ + public function setUp() + { + $parent = NULL; + $this->class = new HTTPResponse($parent); + $this->reflection = new ReflectionClass('PHPDraft\Model\HTTPResponse'); + } + + /** + * Tear down + */ + public function tearDown() + { + unset($this->class); + unset($this->reflection); + } + + /** + * Test if the value the class is initialized with is correct + */ + public function testSetupCorrectly() + { + $property = $this->reflection->getProperty('parent'); + $property->setAccessible(TRUE); + $this->assertNull($property->getValue($this->class)); + } +} \ No newline at end of file diff --git a/src/PHPDraft/Model/Tests/HierarchyElementTest.php b/src/PHPDraft/Model/Tests/HierarchyElementTest.php new file mode 100644 index 00000000..b0a7369b --- /dev/null +++ b/src/PHPDraft/Model/Tests/HierarchyElementTest.php @@ -0,0 +1,44 @@ + + */ + +namespace PHPDraft\Model\Tests; + + +use PHPDraft\Core\TestBase; +use ReflectionClass; + +class HierarchyElementTest extends TestBase +{ + /** + * Set up + */ + public function setUp() + { + $this->class = $this->getMockForAbstractClass('PHPDraft\Model\HierarchyElement'); + $this->reflection = new ReflectionClass('PHPDraft\Model\HierarchyElement'); + } + + /** + * Tear down + */ + public function tearDown() + { + unset($this->class); + unset($this->reflection); + } + + /** + * Test if the value the class is initialized with is correct + */ + public function testSetupCorrectly() + { + $property = $this->reflection->getProperty('parent'); + $property->setAccessible(TRUE); + $this->assertNull($property->getValue($this->class)); + } +} \ No newline at end of file diff --git a/src/PHPDraft/Model/Tests/ResourceTest.php b/src/PHPDraft/Model/Tests/ResourceTest.php new file mode 100644 index 00000000..b960ce60 --- /dev/null +++ b/src/PHPDraft/Model/Tests/ResourceTest.php @@ -0,0 +1,46 @@ + + */ + +namespace PHPDraft\Model\Tests; + + +use PHPDraft\Core\TestBase; +use PHPDraft\Model\Resource; +use ReflectionClass; + +class ResourceTest extends TestBase +{ + /** + * Set up + */ + public function setUp() + { + $parent = NULL; + $this->class = new Resource($parent); + $this->reflection = new ReflectionClass('PHPDraft\Model\Resource'); + } + + /** + * Tear down + */ + public function tearDown() + { + unset($this->class); + unset($this->reflection); + } + + /** + * Test if the value the class is initialized with is correct + */ + public function testSetupCorrectly() + { + $property = $this->reflection->getProperty('parent'); + $property->setAccessible(TRUE); + $this->assertNull($property->getValue($this->class)); + } +} \ No newline at end of file diff --git a/src/PHPDraft/Model/Tests/TransitionTest.php b/src/PHPDraft/Model/Tests/TransitionTest.php new file mode 100644 index 00000000..417f6d40 --- /dev/null +++ b/src/PHPDraft/Model/Tests/TransitionTest.php @@ -0,0 +1,46 @@ + + */ + +namespace PHPDraft\Model\Tests; + + +use PHPDraft\Core\TestBase; +use PHPDraft\Model\Transition; +use ReflectionClass; + +class TransitionTest extends TestBase +{ + /** + * Set up + */ + public function setUp() + { + $parent = NULL; + $this->class = new Transition($parent); + $this->reflection = new ReflectionClass('PHPDraft\Model\Transition'); + } + + /** + * Tear down + */ + public function tearDown() + { + unset($this->class); + unset($this->reflection); + } + + /** + * Test if the value the class is initialized with is correct + */ + public function testSetupCorrectly() + { + $property = $this->reflection->getProperty('parent'); + $property->setAccessible(TRUE); + $this->assertNull($property->getValue($this->class)); + } +} \ No newline at end of file diff --git a/src/PHPDraft/Model/Transition.php b/src/PHPDraft/Model/Transition.php index 411102f8..26fd01fb 100644 --- a/src/PHPDraft/Model/Transition.php +++ b/src/PHPDraft/Model/Transition.php @@ -8,7 +8,9 @@ namespace PHPDraft\Model; -class Transition extends APIBlueprintElement +use PHPDraft\Model\Elements\DataStructureElement; + +class Transition extends HierarchyElement { /** * HTTP method used diff --git a/src/PHPDraft/Out/HTML/default.css b/src/PHPDraft/Out/HTML/default.css index 2297d24e..e8293db4 100644 --- a/src/PHPDraft/Out/HTML/default.css +++ b/src/PHPDraft/Out/HTML/default.css @@ -68,19 +68,19 @@ body .col-md-10 h3:first-child line-height: 22px; } -.POST > .panel-heading, span.POST { +.POST:not(.structure) > .panel-heading, span.POST { background: #62c462; } -.GET > .panel-heading, span.GET { +.GET:not(.structure) > .panel-heading, span.GET { background: #5bc0de; } -.DELETE > .panel-heading, span.DELETE { +.DELETE:not(.structure) > .panel-heading, span.DELETE { background: #ee5f5b; } -.PUT > .panel-heading, span.PUT { +.PUT:not(.structure) > .panel-heading, span.PUT { background: #f89406; } diff --git a/src/PHPDraft/Out/HTML/default.php b/src/PHPDraft/Out/HTML/default.php index 015fbd73..f8ac9ccb 100644 --- a/src/PHPDraft/Out/HTML/default.php +++ b/src/PHPDraft/Out/HTML/default.php @@ -101,12 +101,12 @@ class="pull-right get_method_icon($transition->get_method()); ?>">
- title)):?> + title)): ?>

title; ?>

- - description)):?> + + description)): ?>

description; ?>

- + children as $resource): ?>

title; ?> @@ -167,9 +167,19 @@ class="value"> request->body)): ?>

Body
request->body as $value): ?> - request->headers['Content-Type'])) ? $transition->request->headers['Content-Type'] : NULL; ?> - print_request($type); ?> + + + + request->headers['Content-Type'])) ? $transition->request->headers['Content-Type'] : NULL; ?> + print_request($type); ?> + + + + + request->struct)): ?> +
Structure
+ request->struct as $value): ?> @@ -197,13 +207,16 @@ class="value">

- Response statuscode; ?> - + data-toggle="collapse" + data-target="#request-coll--get_href() . '-' . $response->statuscode; ?>"> + Response statuscode; ?> +

-
+
headers !== []): ?>
Headers
    @@ -253,10 +266,10 @@ class="collapse collapsed response-body" base_structures as $key => $structure): ?> -
    +

    - +

    diff --git a/src/PHPDraft/Out/Tests/TemplateGeneratorTest.php b/src/PHPDraft/Out/Tests/TemplateGeneratorTest.php new file mode 100644 index 00000000..30015dfb --- /dev/null +++ b/src/PHPDraft/Out/Tests/TemplateGeneratorTest.php @@ -0,0 +1,41 @@ + + */ + +namespace PHPDraft\Out\Tests; + + +use PHPDraft\Core\TestBase; +use PHPDraft\Out\TemplateGenerator; + +class TemplateGeneratorTest extends TestBase +{ + public function setUp() + { + $this->class = new TemplateGenerator('default', 'none'); + $this->reflection = new \ReflectionClass('PHPDraft\Out\TemplateGenerator'); + } + + public function tearDown() + { + unset($this->class); + unset($this->reflection); + } + + /** + * Test if the value the class is initialized with is correct + */ + public function testSetupCorrectly() + { + $property = $this->reflection->getProperty('template'); + $property->setAccessible(TRUE); + $this->assertSame('default', $property->getValue($this->class)); + $property = $this->reflection->getProperty('image'); + $property->setAccessible(TRUE); + $this->assertSame('none', $property->getValue($this->class)); + } +} \ No newline at end of file diff --git a/src/PHPDraft/Out/Tests/UITest.php b/src/PHPDraft/Out/Tests/UITest.php new file mode 100644 index 00000000..75861763 --- /dev/null +++ b/src/PHPDraft/Out/Tests/UITest.php @@ -0,0 +1,39 @@ + + */ + +namespace PHPDraft\Out\Tests; + + +use PHPDraft\Core\TestBase; +use PHPDraft\Out\UI; +use ReflectionClass; + +class UITest extends TestBase +{ + public function setUp() + { + $this->class = new UI(); + $this->reflection = new ReflectionClass('PHPDraft\Out\UI'); + } + + public function tearDown() + { + unset($this->class); + unset($this->reflection); + } + + /** + * Test if the value the class is initialized with is correct + */ + public function testSetupCorrectly() + { + $property = $this->reflection->getProperty('versionStringPrinted'); + $property->setAccessible(TRUE); + $this->assertNull($property->getValue($this->class)); + } +} \ No newline at end of file diff --git a/src/PHPDraft/Out/UI.php b/src/PHPDraft/Out/UI.php index 3249e9f5..408d50d8 100644 --- a/src/PHPDraft/Out/UI.php +++ b/src/PHPDraft/Out/UI.php @@ -9,11 +9,17 @@ namespace PHPDraft\Out; +use Exception; +use Phar; +use Throwable; + class UI { + protected $versionStringPrinted; + static function main($argv = []) { - $options = getopt("f:t::i::hv"); + $options = getopt("f:t::i::hvu"); if(!isset($argv[1])) { file_put_contents('php://stderr', 'Not enough arguments'.PHP_EOL); @@ -35,6 +41,12 @@ static function main($argv = []) exit(0); } + if (isset($options['u'])) + { + self::handleSelfUpdate(); + exit(0); + } + elseif (isset($options['f'])) { $file = $options['f']; @@ -60,6 +72,98 @@ static function main($argv = []) ]; } + private function printVersionString() + { + print self::version() . "\n\n"; + } + + /** + * @since Method available since Release 1.4 + */ + protected function handleSelfUpdate() + { + self::printVersionString(); + $localFilename = realpath($_SERVER['argv'][0]); + if (!is_writable($localFilename)) { + print 'No write permission to update ' . $localFilename . "\n"; + exit(3); + } + if (!extension_loaded('openssl')) { + print "The OpenSSL extension is not loaded.\n"; + exit(3); + } + //set POST variables + //https://github.com/SMillerDev/phpdraft/releases/download/1.3.2/phpdraft.phar + $url = 'https://github.com/SMillerDev/phpdraft/releases/latest'; + $ch = curl_init(); + curl_setopt($ch,CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $result = curl_exec($ch); + $matches = []; + preg_match("/href=\"https:\/\/github.com\/SMillerDev\/phpdraft\/releases\/tag\/([0-9.]*)\"/", $result, $matches); + curl_close($ch); + $remoteFilename = sprintf( + 'https://github.com/SMillerDev/phpdraft/releases/download/%s/phpdraft.phar', + $matches[0] + ); + + $tempFilename = tempnam(sys_get_temp_dir(), 'phpdraft') . '.phar'; + // Workaround for https://bugs.php.net/bug.php?id=65538 + $caFile = dirname($tempFilename) . '/ca.pem'; + copy(__PHPDRAFT_PHAR_ROOT__ . '/ca.pem', $caFile); + print 'Updating the PHPDraft PHAR ... '; + $options = [ + 'ssl' => [ + 'allow_self_signed' => false, + 'cafile' => $caFile, + 'verify_peer' => true + ] + ]; + file_put_contents( + $tempFilename, + file_get_contents( + $remoteFilename, + false, + stream_context_create($options) + ) + ); + chmod($tempFilename, 0777 & ~umask()); + try { + $phar = new Phar($tempFilename); + unset($phar); + rename($tempFilename, $localFilename); + unlink($caFile); + } catch (Throwable $_e) { + $e = $_e; + } catch (Exception $_e) { + $e = $_e; + } + if (isset($e)) { + unlink($caFile); + unlink($tempFilename); + print " done\n\n" . $e->getMessage() . "\n"; + exit(2); + } + print " done\n"; + exit(0); + } + /** + * @since Method available since Release 1.4 + */ + protected function handleVersionCheck() + { + $this->printVersionString(); + $latestVersion = file_get_contents('https://phar.phpdraft.de/latest-version-of/phpdraft'); + $isOutdated = version_compare($latestVersion, self::release_id(), '>'); + if ($isOutdated) { + print "You are not using the latest version of PHPDraft.\n"; + print 'Use "phpdraft --self-upgrade" to install PHPDraft ' . $latestVersion . "\n"; + } else { + print "You are using the latest version of PHPDraft.\n"; + } + exit(0); + } + static function help() { echo 'This is a parser for API Blueprint files in PHP.'.PHP_EOL.PHP_EOL; @@ -71,8 +175,46 @@ static function help() static function version() { - $version = (VERSION === '0') ? @exec('git describe --tags 2>&1') : VERSION; + $version = self::release_id(); echo 'PHPDraft: '.$version; } + /** + * Get the version number + * + * @return string + */ + static function release_id() + { + return (VERSION === '0') ? @exec('git describe --tags 2>&1') : VERSION; + } + + + /** + * @return string + * + * @since Method available since Release 4.8.13 + */ + public static function series() + { + if (strpos(self::release_id(), '-')) { + $version = explode('-', self::release_id())[0]; + } else { + $version = self::release_id(); + } + return implode('.', array_slice(explode('.', $version), 0, 2)); + } + + /** + * @return string + * + * @since Method available since Release 4.0.0 + */ + public static function getReleaseChannel() + { + if (strpos(self::release_id(), '-') !== false) { + return '-nightly'; + } + return ''; + } } \ No newline at end of file diff --git a/src/PHPDraft/Parse/Drafter.php b/src/PHPDraft/Parse/Drafter.php index f328152e..43194d72 100644 --- a/src/PHPDraft/Parse/Drafter.php +++ b/src/PHPDraft/Parse/Drafter.php @@ -17,11 +17,11 @@ class Drafter */ public $json; /** - * Configuration + * Temp directory * * @var array */ - protected $config; + protected $tmp_dir; /** * The API Blueprint input * @@ -43,8 +43,6 @@ class Drafter */ public function __construct($apib) { - global $config; - $this->config = &$config; $this->apib = $apib; if (!$this->location()) @@ -52,6 +50,8 @@ public function __construct($apib) throw new \RuntimeException("Drafter was not installed!", 1); } $this->drafter = $this->location(); + + $this->tmp_dir = sys_get_temp_dir().'/drafter'; } /** @@ -74,21 +74,19 @@ function location() */ public function parseToJson() { - $tmp_dir = $this->config->tmpdir; - - if (!file_exists($tmp_dir)) + if (!file_exists($this->tmp_dir)) { - mkdir($tmp_dir); + mkdir($this->tmp_dir); } - file_put_contents($tmp_dir . '/index.apib', $this->apib); + file_put_contents($this->tmp_dir . '/index.apib', $this->apib); - shell_exec($this->drafter . ' ' . $tmp_dir . '/index.apib -f json -o ' . $tmp_dir . '/index.json 2> /dev/null'); - $this->json = json_decode(file_get_contents($tmp_dir . '/index.json')); + shell_exec($this->drafter . ' ' . $this->tmp_dir . '/index.apib -f json -o ' . $this->tmp_dir . '/index.json 2> /dev/null'); + $this->json = json_decode(file_get_contents($this->tmp_dir . '/index.json')); if (json_last_error() !== JSON_ERROR_NONE) { - file_put_contents('php://stdout', "ERROR: invalid json in " . $tmp_dir . '/index.json'); + file_put_contents('php://stdout', "ERROR: invalid json in " . $this->tmp_dir . '/index.json'); throw new \RuntimeException("Drafter generated invalid JSON (" . json_last_error_msg() . ")", 2); } diff --git a/src/PHPDraft/Parse/Tests/DrafterTest.php b/src/PHPDraft/Parse/Tests/DrafterTest.php index 9d0ecdef..0a928224 100644 --- a/src/PHPDraft/Parse/Tests/DrafterTest.php +++ b/src/PHPDraft/Parse/Tests/DrafterTest.php @@ -24,12 +24,12 @@ class DrafterTest extends TestBase */ public function setUp() { - global $config; - $config->tmpdir = TEST_STATICS; + $this->mock_function('sys_get_temp_dir', 'return "'.TEST_STATICS.'";'); $this->mock_function('shell_exec', 'return "/some/dir/drafter\n";'); - $this->class = new Drafter(file_get_contents(TEST_STATICS . '/apib')); + $this->class = new Drafter(file_get_contents(TEST_STATICS . '/drafter/apib')); $this->reflection = new ReflectionClass('PHPDraft\Parse\Drafter'); $this->unmock_function('shell_exec'); + $this->unmock_function('sys_get_temp_dir'); } /** @@ -48,7 +48,7 @@ public function testSetupCorrectly() { $property = $this->reflection->getProperty('apib'); $property->setAccessible(TRUE); - $this->assertEquals(file_get_contents(TEST_STATICS . '/apib'), $property->getValue($this->class)); + $this->assertEquals(file_get_contents(TEST_STATICS . '/drafter/apib'), $property->getValue($this->class)); } /** @@ -65,9 +65,9 @@ public function testPreRunStringIsEmpty() public function testParseToJSON() { $this->mock_function('shell_exec', 'return "";'); - file_put_contents(TEST_STATICS.'/index.json', file_get_contents(TEST_STATICS.'/json')); + file_put_contents(TEST_STATICS.'/drafter/index.json', file_get_contents(TEST_STATICS.'/drafter/json')); $this->class->parseToJson(); - $this->assertEquals(json_decode(file_get_contents(TEST_STATICS.'/json')), $this->class->json); + $this->assertEquals(json_decode(file_get_contents(TEST_STATICS.'/drafter/json')), $this->class->json); $this->unmock_function('shell_exec'); } @@ -82,7 +82,7 @@ public function testParseToJSON() public function testParseToJSONWithErrors() { $this->mock_function('shell_exec', 'return "";'); - file_put_contents(TEST_STATICS.'/index.json', file_get_contents(TEST_STATICS.'/json_errors')); + file_put_contents(TEST_STATICS.'/drafter/index.json', file_get_contents(TEST_STATICS.'/drafter/json_errors')); $this->class->parseToJson(); $this->expectOutputString("WARNING: ignoring unrecognized block\nWARNING: no headers specified\nWARNING: ignoring unrecognized block\nWARNING: empty request message-body"); $this->unmock_function('shell_exec'); diff --git a/src/PHPDraft/Parse/Tests/JsonToHTMLTest.php b/src/PHPDraft/Parse/Tests/JsonToHTMLTest.php index afdf938c..4332a63f 100644 --- a/src/PHPDraft/Parse/Tests/JsonToHTMLTest.php +++ b/src/PHPDraft/Parse/Tests/JsonToHTMLTest.php @@ -31,7 +31,7 @@ class JsonToHTMLTest extends PHPUnit_Framework_TestCase */ public function setUp() { - $this->class = new JsonToHTML(json_decode(file_get_contents(TEST_STATICS . '/json'))); + $this->class = new JsonToHTML(json_decode(file_get_contents(TEST_STATICS . '/drafter/json'))); $this->reflection = new ReflectionClass('PHPDraft\Parse\JsonToHTML'); } @@ -51,7 +51,7 @@ public function testSetupCorrectly() { $property = $this->reflection->getProperty('object'); $property->setAccessible(TRUE); - $this->assertEquals(json_decode(file_get_contents(TEST_STATICS . '/json')), $property->getValue($this->class)); + $this->assertEquals(json_decode(file_get_contents(TEST_STATICS . '/drafter/json')), $property->getValue($this->class)); } } diff --git a/tests/phpunit.xml b/tests/phpunit.xml index 48480ed6..1cebdeb4 100755 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -18,6 +18,21 @@ ../src/PHPDraft/Model/Tests/DataStructureElementTest.php + ../src/PHPDraft/Model/Tests/CategoryTest.php + ../src/PHPDraft/Model/Tests/HierarchyElementTest.php + ../src/PHPDraft/Model/Tests/HTTPRequestTest.php + ../src/PHPDraft/Model/Tests/HTTPResponseTest.php + ../src/PHPDraft/Model/Tests/ResourceTest.php + ../src/PHPDraft/Model/Tests/TransitionTest.php + ../src/PHPDraft/Model/Elements/Tests/ArrayStructureTest.php + ../src/PHPDraft/Model/Elements/Tests/RequestBodyElementTest.php + + + ../src/PHPDraft/In/Tests/ApibFileParserTest.php + + + ../src/PHPDraft/Out/Tests/UITest.php + ../src/PHPDraft/Out/Tests/TemplateGeneratorTest.php diff --git a/tests/statics/apib b/tests/statics/drafter/apib similarity index 100% rename from tests/statics/apib rename to tests/statics/drafter/apib diff --git a/tests/statics/apib_errors b/tests/statics/drafter/apib_errors similarity index 100% rename from tests/statics/apib_errors rename to tests/statics/drafter/apib_errors diff --git a/tests/statics/html b/tests/statics/drafter/html similarity index 100% rename from tests/statics/html rename to tests/statics/drafter/html diff --git a/tests/statics/drafter/index.apib b/tests/statics/drafter/index.apib new file mode 100644 index 00000000..b3d5746e --- /dev/null +++ b/tests/statics/drafter/index.apib @@ -0,0 +1,712 @@ +FORMAT: 1A +HOST: https://owner-api.teslamotors.com + +# Tesla Model S JSON API +This is unofficial documentation of the Tesla Model S JSON API used by the iOS and Android apps. It features functionality to monitor and control the Model S remotely. + +# Group Authentication + +## Tokens [/oauth/token] + +### Get an Access Token [POST] +Performs the login. Takes in an plain text email and password, matching the owner's login information for [https://my.teslamotors.com/user/login](https://my.teslamotors.com/user/login). + +Returns a `access_token` which is passed along as a header with all future requests to authenticate the user. + +You must provide the `Authorization: Bearer {access_token}` header in all other requests. + +The current client ID and secret are [available here](http://pastebin.com/fX6ejAHd) + ++ Attributes + + grant_type: `password` (string) - The type of oAuth grant. Always "password" + + client_id: `abc` (string) - The oAuth client ID + + client_secret: `123` (string) - The oAuth client secret + + email: `elon@teslamotors.com` (string) - The email for my.teslamotors.com + + password: `edisonsux` (string) - The password for my.teslamotors.com + ++ Response 200 (application/json) + + Body + + { + "access_token": "abc123", + "token_type": "bearer", + "expires_in": 7776000, + "created_at": 1457385291 + } + +# Group Vehicles +A logged in user can have multiple vehicles under their account. This resource is primarily responsible for listing the vehicles and the basic details about them. + +## Vehicle Collection [/api/1/vehicles] + +### List all Vehicles [GET] +Retrieve a list of your owned vehicles (includes vehicles not yet shipped!) + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Response 200 (application/json) + + + Body + + { + "response": [{ + "color": null, + "display_name": null, + "id": 321, + "option_codes": "MS01,RENA,TM00,DRLH,PF00,BT85,PBCW,RFPO,WT19,IBMB,IDPB,TR00,SU01,SC01,TP01,AU01,CH00,HP00,PA00,PS00,AD02,X020,X025,X001,X003,X007,X011,X013", + "user_id": 123, + "vehicle_id": 1234567890, + "vin": "5YJSA1CN5CFP01657", + "tokens": ["x", "x"], + "state": "online" + }], + "count":1 + } + + +## State and Settings [/api/1/vehicles/{vehicle_id}] +These resources are read-only and determine the state of the vehicle's various sub-systems. + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + +## Mobile Access [GET /api/1/vehicles/{vehicle_id}/mobile_enabled] +Determines if mobile access to the vehicle is enabled. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": true + } + +## Charge State [GET /api/1/vehicles/{vehicle_id}/data_request/charge_state] +Returns the state of charge in the battery. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "charging_state": "Complete", // "Charging", ?? + "charge_to_max_range": false, // current std/max-range setting + "max_range_charge_counter": 0, + "fast_charger_present": false, // connected to Supercharger? + "battery_range": 239.02, // rated miles + "est_battery_range": 155.79, // range estimated from recent driving + "ideal_battery_range": 275.09, // ideal miles + "battery_level": 91, // integer charge percentage + "battery_current": -0.6, // current flowing into battery + "charge_starting_range": null, + "charge_starting_soc": null, + "charger_voltage": 0, // only has value while charging + "charger_pilot_current": 40, // max current allowed by charger & adapter + "charger_actual_current": 0, // current actually being drawn + "charger_power": 0, // kW (rounded down) of charger + "time_to_full_charge": null, // valid only while charging + "charge_rate": -1.0, // float mi/hr charging or -1 if not charging + "charge_port_door_open": true + } + } + +## Climate Settings [GET /api/1/vehicles/{vehicle_id}/data_request/climate_state] +Returns the current temperature and climate control state. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "inside_temp": 17.0, // degC inside car + "outside_temp": 9.5, // degC outside car or null + "driver_temp_setting": 22.6, // degC of driver temperature setpoint + "passenger_temp_setting": 22.6, // degC of passenger temperature setpoint + "is_auto_conditioning_on": false, // apparently even if on + "is_front_defroster_on": null, // null or boolean as integer? + "is_rear_defroster_on": false, + "fan_status": 0 // fan speed 0-6 or null + } + } + +## Driving and Position [GET /api/1/vehicles/{vehicle_id}/data_request/drive_state] +Returns the driving and position state of the vehicle. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "shift_state": null, // + "speed": null, // + "latitude": 33.794839, // degrees N of equator + "longitude": -84.401593, // degrees W of the prime meridian + "heading": 4, // integer compass heading, 0-359 + "gps_as_of": 1359863204 // Unix timestamp of GPS fix + } + } + +## GUI Settings [GET /api/1/vehicles/{vehicle_id}/data_request/gui_settings] +Returns various information about the GUI settings of the car, such as unit format and range display. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "gui_distance_units": "mi/hr", + "gui_temperature_units": "F", + "gui_charge_rate_units": "mi/hr", + "gui_24_hour_time": false, + "gui_range_display": "Rated" + } + } + +## Vehicle State [GET /api/1/vehicles/{vehicle_id}/data_request/vehicle_state] +Returns the vehicle's physical state, such as which doors are open. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "df": false, // driver's side front door open + "dr": false, // driver's side rear door open + "pf": false, // passenger's side front door open + "pr": false, // passenger's side rear door open + "ft": false, // front trunk is open + "rt": false, // rear trunk is open + "car_verson": "1.19.42", // car firmware version + "locked": true, // car is locked + "sun_roof_installed": false, // panoramic roof is installed + "sun_roof_state": "unknown", + "sun_roof_percent_open": 0, // null if not installed + "dark_rims": false, // gray rims installed + "wheel_type": "Base19", // wheel type installed + "has_spoiler": false, // spoiler is installed + "roof_color": "Colored", // "None" for panoramic roof + "perf_config": "Base" + } + } + +# Group Vehicle Commands +These commands alter the vehicles state, and return result (true/false) to indicate success, and if failure reason contains the cause of failure. + +## Wake Up Car [POST /api/1/vehicles/{vehicle_id}/wake_up] +Wakes up the car from the sleep state. Necessary to get some data from the car. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Set Valet Mode [POST /api/1/vehicles/{vehicle_id}/command/set_valet_mode] +Sets valet mode on or off with a PIN to disable it from within the car. Reuses last PIN from previous valet session. +Valet Mode limits the car's top speed to 70MPH and 80kW of acceleration power. It also disables Homelink, Bluetooth and +Wifi settings, and the ability to disable mobile access to the car. It also hides your favorites, home, and work +locations in navigation. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + + on: true (boolean) - Whether to enable or disable valet mode. + + password: 1234 (number) - (optional) A 4 digit PIN code to unlock the car. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Reset Valet PIN [POST /api/1/vehicles/{vehicle_id}/command/reset_valet_pin] +Resets the PIN set for valet mode, if set. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Open Charge Port [POST /api/1/vehicles/{vehicle_id}/command/charge_port_door_open] +Opens the charge port. Does not close the charge port (for now...) + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Set Charge Limit to Standard [POST /api/1/vehicles/{vehicle_id}/command/charge_standard] +Set the charge mode to standard (90% under the new percentage system introduced in 4.5). + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": false, + "reason": "already_standard" + } + } + +## Set Charge Limit to Max Range [POST /api/1/vehicles/{vehicle_id}/command/charge_max_range] +Set the charge mode to max range (100% under the new percentage system introduced in 4.5). Use sparingly! + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": false, + "reason": "already_max_range" + } + } + +## Set Charge Limit [POST /api/1/vehicles/{vehicle_id}/command/set_charge_limit?percent={limit_value}] +Set the charge limit to a custom percentage. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + + limit_value: `75` (number) - The percentage value + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Start Charging [POST /api/1/vehicles/{vehicle_id}/command/charge_start] +Start charging. Must be plugged in, have power available, and not have reached your charge limit. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" // "already_started" if a charge is in progress + } + } + +## Stop Charging [POST /api/1/vehicles/{vehicle_id}/command/charge_stop] +Stop charging. Must already be charging. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" // "not_charging" if a charge was not in progress + } + } + +## Flash Lights [POST /api/1/vehicles/{vehicle_id}/command/flash_lights] +Flash the lights once. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Honk Horn [POST /api/1/vehicles/{vehicle_id}/command/honk_horn] +Honk the horn once. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Unlock Doors [POST /api/1/vehicles/{vehicle_id}/command/door_unlock] +Unlock the car's doors. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Lock Doors [POST /api/1/vehicles/{vehicle_id}/command/door_lock] +Lock the car's doors. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Set Temperature [POST /api/1/vehicles/{vehicle_id}/command/set_temps?driver_temp={driver_degC}&passenger_temp={pass_degC}] +Set the temperature target for the HVAC system. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + + driver_degC: `23.7` (number) - The desired temperature on the driver's side in celcius. + + pass_degC: `18.1` (number) - The desired temperature on the passenger's side in celcius. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Start HVAC System [POST /api/1/vehicles/{vehicle_id}/command/auto_conditioning_start] +Start the climate control system. Will cool or heat automatically, depending on set temperature. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Stop HVAC System [POST /api/1/vehicles/{vehicle_id}/command/auto_conditioning_stop] +Stop the climate control system. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Move Pano Roof [POST /api/1/vehicles/{vehicle_id}/command/sun_roof_control?state={state}&percent={percent}] +Controls the car's panoramic roof, if installed. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + + state: `open` (enum[string]) + The desired state of the panoramic roof. The approximate percent open values for each state are `open` = 100%, `close` = 0%, `comfort` = 80%, and `vent` = ~15% + + Members + + `open` - Open the roof fully + + `close` - Close the roof completely + + `comfort` - Open to the comfort (80%) setting + + `vent` - Open the roof to the vent (~15%) setting + + `move` - Indicates you will provide a percentage to move the roof. + + percent: `50` (number, optional) - The percentage to move the roof to. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Remote Start [POST /api/1/vehicles/{vehicle_id}/command/remote_start_drive?password={password}] +Start the car for keyless driving. Must start driving within 2 minutes of issuing this request. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + + password: `edisonsux` (string) - The password to the authenticated my.teslamotors.com account. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } + +## Open Trunk/Frunk [POST /api/1/vehicles/{vehicle_id}/command/trunk_open] +Open the trunk or frunk. Currently inoperable. + ++ Request + + Headers + + Authorization: Bearer {access_token} + ++ Parameters + + + vehicle_id: `1` (number) - The id of the Vehicle. + + which_trunk: `rear` (string) - The trunk to open. `rear` is the only one known currently. + ++ Response 200 (application/json) + + + Body + + { + "response": { + "result": true, + "reason": "" + } + } \ No newline at end of file diff --git a/tests/statics/json_errors b/tests/statics/drafter/index.json similarity index 100% rename from tests/statics/json_errors rename to tests/statics/drafter/index.json diff --git a/tests/statics/json b/tests/statics/drafter/json similarity index 100% rename from tests/statics/json rename to tests/statics/drafter/json diff --git a/tests/statics/drafter/json_errors b/tests/statics/drafter/json_errors new file mode 100644 index 00000000..cba7ec7e --- /dev/null +++ b/tests/statics/drafter/json_errors @@ -0,0 +1,3399 @@ +{ + "element": "parseResult", + "content": [ + { + "element": "category", + "meta": { + "classes": [ + "api" + ], + "title": "Tesla Model S JSON API" + }, + "attributes": { + "meta": [ + { + "element": "member", + "meta": { + "classes": [ + "user" + ] + }, + "content": { + "key": { + "element": "string", + "content": "FORMAT" + }, + "value": { + "element": "string", + "content": "1A" + } + } + }, + { + "element": "member", + "meta": { + "classes": [ + "user" + ] + }, + "content": { + "key": { + "element": "string", + "content": "HOST" + }, + "value": { + "element": "string", + "content": "https://owner-api.teslamotors.com" + } + } + } + ] + }, + "content": [ + { + "element": "copy", + "content": "This is unofficial documentation of the Tesla Model S JSON API used by the iOS and Android apps. It features functionality to monitor and control the Model S remotely.\n\n" + }, + { + "element": "category", + "meta": { + "classes": [ + "resourceGroup" + ], + "title": "Authentication" + }, + "content": [ + { + "element": "resource", + "meta": { + "title": "Tokens" + }, + "attributes": { + "href": "/oauth/token" + }, + "content": [ + { + "element": "copy", + "content": "### Get an Access Token [JOKE]\n\nPerforms the login. Takes in an plain text email and password, matching the owner's login information for [https://my.teslamotors.com/user/login](https://my.teslamotors.com/user/login).\n\nReturns a `access_token` which is passed along as a header with all future requests to authenticate the user.\n\nYou must provide the `Authorization: Bearer {access_token}` header in all other requests.\n\nThe current client ID and secret are [available here](http://pastebin.com/fX6ejAHd)\n\n" + }, + { + "element": "dataStructure", + "content": [ + { + "element": "object", + "meta": { + "id": "Tokens" + }, + "content": [ + { + "element": "member", + "meta": { + "description": "The type of oAuth grant. Always \"password\"" + }, + "content": { + "key": { + "element": "string", + "content": "grant_type" + }, + "value": { + "element": "string", + "content": "password" + } + } + }, + { + "element": "member", + "meta": { + "description": "The oAuth client ID" + }, + "content": { + "key": { + "element": "string", + "content": "client_id" + }, + "value": { + "element": "string", + "content": "abc" + } + } + }, + { + "element": "member", + "meta": { + "description": "The oAuth client secret" + }, + "content": { + "key": { + "element": "string", + "content": "client_secret" + }, + "value": { + "element": "string", + "content": "123" + } + } + }, + { + "element": "member", + "meta": { + "description": "The email for my.teslamotors.com" + }, + "content": { + "key": { + "element": "string", + "content": "email" + }, + "value": { + "element": "string", + "content": "elon@teslamotors.com" + } + } + }, + { + "element": "member", + "meta": { + "description": "The password for my.teslamotors.com" + }, + "content": { + "key": { + "element": "string", + "content": "password" + }, + "value": { + "element": "string", + "content": "edisonsux" + } + } + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "category", + "meta": { + "classes": [ + "resourceGroup" + ], + "title": "Vehicles" + }, + "content": [ + { + "element": "copy", + "content": "A logged in user can have multiple vehicles under their account. This resource is primarily responsible for listing the vehicles and the basic details about them.\n\n" + }, + { + "element": "resource", + "meta": { + "title": "Vehicle Collection" + }, + "attributes": { + "href": "/api/1/vehicles" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "List all Vehicles" + }, + "content": [ + { + "element": "copy", + "content": "Retrieve a list of your owned vehicles (includes vehicles not yet shipped!)\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "GET" + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": [{\n \"color\": null,\n \"display_name\": null,\n \"id\": 321,\n \"option_codes\": \"MS01,RENA,TM00,DRLH,PF00,BT85,PBCW,RFPO,WT19,IBMB,IDPB,TR00,SU01,SC01,TP01,AU01,CH00,HP00,PA00,PS00,AD02,X020,X025,X001,X003,X007,X011,X013\",\n \"user_id\": 123,\n \"vehicle_id\": 1234567890,\n \"vin\": \"5YJSA1CN5CFP01657\",\n \"tokens\": [\"x\", \"x\"],\n \"state\": \"online\"\n }],\n \"count\":1\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "State and Settings" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "These resources are read-only and determine the state of the vehicle's various sub-systems.\n\n" + }, + { + "element": "transition", + "meta": { + "title": "Mobile Access" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/mobile_enabled", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Determines if mobile access to the vehicle is enabled.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "GET", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": true\n}\n" + } + ] + } + ] + } + ] + }, + { + "element": "transition", + "meta": { + "title": "Charge State" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/data_request/charge_state", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Returns the state of charge in the battery.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "GET", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"charging_state\": \"Complete\", // \"Charging\", ??\n \"charge_to_max_range\": false, // current std/max-range setting\n \"max_range_charge_counter\": 0,\n \"fast_charger_present\": false, // connected to Supercharger?\n \"battery_range\": 239.02, // rated miles\n \"est_battery_range\": 155.79, // range estimated from recent driving\n \"ideal_battery_range\": 275.09, // ideal miles\n \"battery_level\": 91, // integer charge percentage\n \"battery_current\": -0.6, // current flowing into battery\n \"charge_starting_range\": null,\n \"charge_starting_soc\": null,\n \"charger_voltage\": 0, // only has value while charging\n \"charger_pilot_current\": 40, // max current allowed by charger & adapter\n \"charger_actual_current\": 0, // current actually being drawn\n \"charger_power\": 0, // kW (rounded down) of charger\n \"time_to_full_charge\": null, // valid only while charging\n \"charge_rate\": -1.0, // float mi/hr charging or -1 if not charging\n \"charge_port_door_open\": true\n }\n}\n" + } + ] + } + ] + } + ] + }, + { + "element": "transition", + "meta": { + "title": "Climate Settings" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/data_request/climate_state", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Returns the current temperature and climate control state.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "GET", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"inside_temp\": 17.0, // degC inside car\n \"outside_temp\": 9.5, // degC outside car or null\n \"driver_temp_setting\": 22.6, // degC of driver temperature setpoint\n \"passenger_temp_setting\": 22.6, // degC of passenger temperature setpoint\n \"is_auto_conditioning_on\": false, // apparently even if on\n \"is_front_defroster_on\": null, // null or boolean as integer?\n \"is_rear_defroster_on\": false,\n \"fan_status\": 0 // fan speed 0-6 or null\n }\n}\n" + } + ] + } + ] + } + ] + }, + { + "element": "transition", + "meta": { + "title": "Driving and Position" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/data_request/drive_state", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Returns the driving and position state of the vehicle.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "GET", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"shift_state\": null, //\n \"speed\": null, //\n \"latitude\": 33.794839, // degrees N of equator\n \"longitude\": -84.401593, // degrees W of the prime meridian\n \"heading\": 4, // integer compass heading, 0-359\n \"gps_as_of\": 1359863204 // Unix timestamp of GPS fix\n }\n}\n" + } + ] + } + ] + } + ] + }, + { + "element": "transition", + "meta": { + "title": "GUI Settings" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/data_request/gui_settings", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Returns various information about the GUI settings of the car, such as unit format and range display.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "GET", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"gui_distance_units\": \"mi/hr\",\n \"gui_temperature_units\": \"F\",\n \"gui_charge_rate_units\": \"mi/hr\",\n \"gui_24_hour_time\": false,\n \"gui_range_display\": \"Rated\"\n }\n}\n" + } + ] + } + ] + } + ] + }, + { + "element": "transition", + "meta": { + "title": "Vehicle State" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/data_request/vehicle_state", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Returns the vehicle's physical state, such as which doors are open.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "GET", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"df\": false, // driver's side front door open\n \"dr\": false, // driver's side rear door open\n \"pf\": false, // passenger's side front door open\n \"pr\": false, // passenger's side rear door open\n \"ft\": false, // front trunk is open\n \"rt\": false, // rear trunk is open\n \"car_verson\": \"1.19.42\", // car firmware version\n \"locked\": true, // car is locked\n \"sun_roof_installed\": false, // panoramic roof is installed\n \"sun_roof_state\": \"unknown\",\n \"sun_roof_percent_open\": 0, // null if not installed\n \"dark_rims\": false, // gray rims installed\n \"wheel_type\": \"Base19\", // wheel type installed\n \"has_spoiler\": false, // spoiler is installed\n \"roof_color\": \"Colored\", // \"None\" for panoramic roof\n \"perf_config\": \"Base\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "category", + "meta": { + "classes": [ + "resourceGroup" + ], + "title": "Vehicle Commands" + }, + "content": [ + { + "element": "copy", + "content": "These commands alter the vehicles state, and return result (true/false) to indicate success, and if failure reason contains the cause of failure.\n\n" + }, + { + "element": "resource", + "meta": { + "title": "Wake Up Car" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/wake_up" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Wake Up Car" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/wake_up", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Wakes up the car from the sleep state. Necessary to get some data from the car.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Set Valet Mode" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/set_valet_mode" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Set Valet Mode" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/set_valet_mode", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + }, + { + "element": "member", + "meta": { + "description": "Whether to enable or disable valet mode." + }, + "content": { + "key": { + "element": "string", + "content": "on" + }, + "value": { + "element": "boolean", + "content": true + } + } + }, + { + "element": "member", + "meta": { + "description": "(optional) A 4 digit PIN code to unlock the car." + }, + "content": { + "key": { + "element": "string", + "content": "password" + }, + "value": { + "element": "number", + "content": 1234 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Sets valet mode on or off with a PIN to disable it from within the car. Reuses last PIN from previous valet session.\nValet Mode limits the car's top speed to 70MPH and 80kW of acceleration power. It also disables Homelink, Bluetooth and\nWifi settings, and the ability to disable mobile access to the car. It also hides your favorites, home, and work\nlocations in navigation.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Reset Valet PIN" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/reset_valet_pin" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Reset Valet PIN" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/reset_valet_pin", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Resets the PIN set for valet mode, if set.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Open Charge Port" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/charge_port_door_open" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Open Charge Port" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/charge_port_door_open", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Opens the charge port. Does not close the charge port (for now...)\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Set Charge Limit to Standard" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/charge_standard" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Set Charge Limit to Standard" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/charge_standard", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Set the charge mode to standard (90% under the new percentage system introduced in 4.5).\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": false,\n \"reason\": \"already_standard\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Set Charge Limit to Max Range" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/charge_max_range" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Set Charge Limit to Max Range" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/charge_max_range", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Set the charge mode to max range (100% under the new percentage system introduced in 4.5). Use sparingly!\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": false,\n \"reason\": \"already_max_range\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Set Charge Limit" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/set_charge_limit?percent={limit_value}" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Set Charge Limit" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/set_charge_limit?percent={limit_value}", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + }, + { + "element": "member", + "meta": { + "description": "The percentage value" + }, + "content": { + "key": { + "element": "string", + "content": "limit_value" + }, + "value": { + "element": "number", + "content": 75 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Set the charge limit to a custom percentage.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Start Charging" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/charge_start" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Start Charging" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/charge_start", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Start charging. Must be plugged in, have power available, and not have reached your charge limit.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\" // \"already_started\" if a charge is in progress\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Stop Charging" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/charge_stop" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Stop Charging" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/charge_stop", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Stop charging. Must already be charging.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\" // \"not_charging\" if a charge was not in progress\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Flash Lights" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/flash_lights" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Flash Lights" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/flash_lights", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Flash the lights once.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Honk Horn" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/honk_horn" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Honk Horn" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/honk_horn", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Honk the horn once.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Unlock Doors" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/door_unlock" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Unlock Doors" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/door_unlock", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Unlock the car's doors.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Lock Doors" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/door_lock" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Lock Doors" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/door_lock", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Lock the car's doors.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Set Temperature" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/set_temps?driver_temp={driver_degC}&passenger_temp={pass_degC}" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Set Temperature" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/set_temps?driver_temp={driver_degC}&passenger_temp={pass_degC}", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + }, + { + "element": "member", + "meta": { + "description": "The desired temperature on the driver's side in celcius." + }, + "content": { + "key": { + "element": "string", + "content": "driver_degC" + }, + "value": { + "element": "number", + "content": 23.7 + } + } + }, + { + "element": "member", + "meta": { + "description": "The desired temperature on the passenger's side in celcius." + }, + "content": { + "key": { + "element": "string", + "content": "pass_degC" + }, + "value": { + "element": "number", + "content": 18.1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Set the temperature target for the HVAC system.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Start HVAC System" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/auto_conditioning_start" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Start HVAC System" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/auto_conditioning_start", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Start the climate control system. Will cool or heat automatically, depending on set temperature.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Stop HVAC System" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/auto_conditioning_stop" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Stop HVAC System" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/auto_conditioning_stop", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Stop the climate control system.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Move Pano Roof" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/sun_roof_control?state={state}&percent={percent}" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Move Pano Roof" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/sun_roof_control?state={state}&percent={percent}", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + }, + { + "element": "member", + "meta": { + "description": "\nThe desired state of the panoramic roof. The approximate percent open values for each state are `open` = 100%, `close` = 0%, `comfort` = 80%, and `vent` = ~15%\n\n" + }, + "content": { + "key": { + "element": "string", + "content": "state" + }, + "value": { + "element": "enum", + "attributes": { + "samples": [ + [ + { + "element": "string", + "content": "open" + } + ] + ] + }, + "content": [ + { + "element": "string", + "content": "open" + }, + { + "element": "string", + "content": "close" + }, + { + "element": "string", + "content": "comfort" + }, + { + "element": "string", + "content": "vent" + }, + { + "element": "string", + "content": "move" + } + ] + } + } + }, + { + "element": "member", + "meta": { + "description": "The percentage to move the roof to." + }, + "attributes": { + "typeAttributes": [ + "optional" + ] + }, + "content": { + "key": { + "element": "string", + "content": "percent" + }, + "value": { + "element": "number", + "content": 50 + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Controls the car's panoramic roof, if installed.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Remote Start" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/remote_start_drive?password={password}" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Remote Start" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/remote_start_drive?password={password}", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + }, + { + "element": "member", + "meta": { + "description": "The password to the authenticated my.teslamotors.com account." + }, + "content": { + "key": { + "element": "string", + "content": "password" + }, + "value": { + "element": "string", + "content": "edisonsux" + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Start the car for keyless driving. Must start driving within 2 minutes of issuing this request.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "resource", + "meta": { + "title": "Open Trunk/Frunk" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/trunk_open" + }, + "content": [ + { + "element": "transition", + "meta": { + "title": "Open Trunk/Frunk" + }, + "attributes": { + "href": "/api/1/vehicles/{vehicle_id}/command/trunk_open", + "hrefVariables": { + "element": "hrefVariables", + "content": [ + { + "element": "member", + "meta": { + "description": "The id of the Vehicle." + }, + "content": { + "key": { + "element": "string", + "content": "vehicle_id" + }, + "value": { + "element": "number", + "content": 1 + } + } + }, + { + "element": "member", + "meta": { + "description": "The trunk to open. `rear` is the only one known currently." + }, + "content": { + "key": { + "element": "string", + "content": "which_trunk" + }, + "value": { + "element": "string", + "content": "rear" + } + } + } + ] + } + }, + "content": [ + { + "element": "copy", + "content": "Open the trunk or frunk. Currently inoperable.\n\n" + }, + { + "element": "httpTransaction", + "content": [ + { + "element": "httpRequest", + "attributes": { + "method": "POST", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Authorization" + }, + "value": { + "element": "string", + "content": "Bearer {access_token}" + } + } + } + ] + } + }, + "content": [] + }, + { + "element": "httpResponse", + "attributes": { + "statusCode": "200", + "headers": { + "element": "httpHeaders", + "content": [ + { + "element": "member", + "content": { + "key": { + "element": "string", + "content": "Content-Type" + }, + "value": { + "element": "string", + "content": "application/json" + } + } + } + ] + } + }, + "content": [ + { + "element": "asset", + "meta": { + "classes": [ + "messageBody" + ] + }, + "attributes": { + "contentType": "application/json" + }, + "content": "{\n \"response\": {\n \"result\": true,\n \"reason\": \"\"\n }\n}\n" + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": "annotation", + "meta": { + "classes": [ + "warning" + ] + }, + "attributes": { + "code": 5, + "sourceMap": [ + { + "element": "sourceMap", + "content": [ + [ + 1169, + 229 + ] + ] + } + ] + }, + "content": "ignoring unrecognized block" + }, + { + "element": "annotation", + "meta": { + "classes": [ + "warning" + ] + }, + "attributes": { + "code": 3, + "sourceMap": [ + { + "element": "sourceMap", + "content": [ + [ + 1739, + 11 + ] + ] + } + ] + }, + "content": "no headers specified" + }, + { + "element": "annotation", + "meta": { + "classes": [ + "warning" + ] + }, + "attributes": { + "code": 5, + "sourceMap": [ + { + "element": "sourceMap", + "content": [ + [ + 1754, + 37 + ] + ] + } + ] + }, + "content": "ignoring unrecognized block" + }, + { + "element": "annotation", + "meta": { + "classes": [ + "warning" + ] + }, + "attributes": { + "code": 6, + "sourceMap": [ + { + "element": "sourceMap", + "content": [ + [ + 1725, + 67 + ] + ] + } + ] + }, + "content": "empty request message-body" + } + ] +} \ No newline at end of file diff --git a/tests/statics/index.apib b/tests/statics/index.apib deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/statics/index.json b/tests/statics/index.json deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/test.bootstrap.inc.php b/tests/test.bootstrap.inc.php index 439f8b67..b6d3b014 100755 --- a/tests/test.bootstrap.inc.php +++ b/tests/test.bootstrap.inc.php @@ -24,8 +24,6 @@ // Load and setup class file autloader require_once 'PHPDraft/Core/Autoloader.php'; -$config = json_decode(file_get_contents($base."/config.json")); - if (defined('TEST_STATICS') === FALSE) { define('TEST_STATICS', __DIR__ . '/statics');
' . $this->value . ''.$type.'' . $this->description . '