Shape => Drawing

This commit is contained in:
Julien Duponchelle 2016-06-23 11:17:23 +02:00
parent c847755f1b
commit 852d8e411e
No known key found for this signature in database
GPG Key ID: CE8B29639E07F5E8
21 changed files with 181 additions and 181 deletions

View File

@ -1,6 +1,6 @@
curl -i -X DELETE 'http://localhost:3080/v2/projects/6b74fe6e-f65a-46a9-84a9-1db0cd42a9d2/shapes/6e313846-5d8f-4dcc-a231-e2dd9406bb71' curl -i -X DELETE 'http://localhost:3080/v2/projects/6b74fe6e-f65a-46a9-84a9-1db0cd42a9d2/drawings/6e313846-5d8f-4dcc-a231-e2dd9406bb71'
DELETE /v2/projects/6b74fe6e-f65a-46a9-84a9-1db0cd42a9d2/shapes/6e313846-5d8f-4dcc-a231-e2dd9406bb71 HTTP/1.1 DELETE /v2/projects/6b74fe6e-f65a-46a9-84a9-1db0cd42a9d2/drawings/6e313846-5d8f-4dcc-a231-e2dd9406bb71 HTTP/1.1
@ -8,5 +8,5 @@ HTTP/1.1 204
CONTENT-LENGTH: 0 CONTENT-LENGTH: 0
DATE: Thu, 08 Jan 2015 16:09:15 GMT DATE: Thu, 08 Jan 2015 16:09:15 GMT
SERVER: Python/3.5 GNS3/2.0.0dev1 SERVER: Python/3.5 GNS3/2.0.0dev1
X-ROUTE: /v2/projects/{project_id}/shapes/{shape_id} X-ROUTE: /v2/projects/{project_id}/drawings/{drawing_id}

View File

@ -1,6 +1,6 @@
curl -i -X GET 'http://localhost:3080/v2/projects/0bb34c74-e696-46b5-9c94-d00e3f55da18/shapes' curl -i -X GET 'http://localhost:3080/v2/projects/0bb34c74-e696-46b5-9c94-d00e3f55da18/drawings'
GET /v2/projects/0bb34c74-e696-46b5-9c94-d00e3f55da18/shapes HTTP/1.1 GET /v2/projects/0bb34c74-e696-46b5-9c94-d00e3f55da18/drawings HTTP/1.1
@ -9,13 +9,13 @@ CONTENT-LENGTH: 361
CONTENT-TYPE: application/json CONTENT-TYPE: application/json
DATE: Thu, 08 Jan 2015 16:09:15 GMT DATE: Thu, 08 Jan 2015 16:09:15 GMT
SERVER: Python/3.5 GNS3/2.0.0dev1 SERVER: Python/3.5 GNS3/2.0.0dev1
X-ROUTE: /v2/projects/{project_id}/shapes X-ROUTE: /v2/projects/{project_id}/drawings
[ [
{ {
"project_id": "0bb34c74-e696-46b5-9c94-d00e3f55da18", "project_id": "0bb34c74-e696-46b5-9c94-d00e3f55da18",
"rotation": 0, "rotation": 0,
"shape_id": "a0690cd5-6460-464e-b599-7980f5c08e67", "drawing_id": "a0690cd5-6460-464e-b599-7980f5c08e67",
"svg": "<svg height=\"210\" width=\"500\"><line x1=\"0\" y1=\"0\" x2=\"200\" y2=\"200\" style=\"stroke:rgb(255,0,0);stroke-width:2\" /></svg>", "svg": "<svg height=\"210\" width=\"500\"><line x1=\"0\" y1=\"0\" x2=\"200\" y2=\"200\" style=\"stroke:rgb(255,0,0);stroke-width:2\" /></svg>",
"x": 10, "x": 10,
"y": 20, "y": 20,

View File

@ -1,6 +1,6 @@
curl -i -X POST 'http://localhost:3080/v2/projects/e82d1e06-4235-41dc-9a57-0cd0672692f0/shapes' -d '{"svg": "<svg height=\"210\" width=\"500\"><line x1=\"0\" y1=\"0\" x2=\"200\" y2=\"200\" style=\"stroke:rgb(255,0,0);stroke-width:2\" /></svg>", "x": 10, "y": 20, "z": 0}' curl -i -X POST 'http://localhost:3080/v2/projects/e82d1e06-4235-41dc-9a57-0cd0672692f0/drawings' -d '{"svg": "<svg height=\"210\" width=\"500\"><line x1=\"0\" y1=\"0\" x2=\"200\" y2=\"200\" style=\"stroke:rgb(255,0,0);stroke-width:2\" /></svg>", "x": 10, "y": 20, "z": 0}'
POST /v2/projects/e82d1e06-4235-41dc-9a57-0cd0672692f0/shapes HTTP/1.1 POST /v2/projects/e82d1e06-4235-41dc-9a57-0cd0672692f0/drawings HTTP/1.1
{ {
"svg": "<svg height=\"210\" width=\"500\"><line x1=\"0\" y1=\"0\" x2=\"200\" y2=\"200\" style=\"stroke:rgb(255,0,0);stroke-width:2\" /></svg>", "svg": "<svg height=\"210\" width=\"500\"><line x1=\"0\" y1=\"0\" x2=\"200\" y2=\"200\" style=\"stroke:rgb(255,0,0);stroke-width:2\" /></svg>",
"x": 10, "x": 10,
@ -14,12 +14,12 @@ CONTENT-LENGTH: 321
CONTENT-TYPE: application/json CONTENT-TYPE: application/json
DATE: Thu, 08 Jan 2015 16:09:15 GMT DATE: Thu, 08 Jan 2015 16:09:15 GMT
SERVER: Python/3.5 GNS3/2.0.0dev1 SERVER: Python/3.5 GNS3/2.0.0dev1
X-ROUTE: /v2/projects/{project_id}/shapes X-ROUTE: /v2/projects/{project_id}/drawings
{ {
"project_id": "e82d1e06-4235-41dc-9a57-0cd0672692f0", "project_id": "e82d1e06-4235-41dc-9a57-0cd0672692f0",
"rotation": 0, "rotation": 0,
"shape_id": "66594d41-524e-4dfd-a07b-3186ed392c86", "drawing_id": "66594d41-524e-4dfd-a07b-3186ed392c86",
"svg": "<svg height=\"210\" width=\"500\"><line x1=\"0\" y1=\"0\" x2=\"200\" y2=\"200\" style=\"stroke:rgb(255,0,0);stroke-width:2\" /></svg>", "svg": "<svg height=\"210\" width=\"500\"><line x1=\"0\" y1=\"0\" x2=\"200\" y2=\"200\" style=\"stroke:rgb(255,0,0);stroke-width:2\" /></svg>",
"x": 10, "x": 10,
"y": 20, "y": 20,

View File

@ -1,6 +1,6 @@
curl -i -X PUT 'http://localhost:3080/v2/projects/2312697c-8e49-40e0-9d6d-5bd6dd0679ed/shapes/dbefe2d5-79d7-4f18-b898-cd073224563c' -d '{"x": 42}' curl -i -X PUT 'http://localhost:3080/v2/projects/2312697c-8e49-40e0-9d6d-5bd6dd0679ed/drawings/dbefe2d5-79d7-4f18-b898-cd073224563c' -d '{"x": 42}'
PUT /v2/projects/2312697c-8e49-40e0-9d6d-5bd6dd0679ed/shapes/dbefe2d5-79d7-4f18-b898-cd073224563c HTTP/1.1 PUT /v2/projects/2312697c-8e49-40e0-9d6d-5bd6dd0679ed/drawings/dbefe2d5-79d7-4f18-b898-cd073224563c HTTP/1.1
{ {
"x": 42 "x": 42
} }
@ -11,12 +11,12 @@ CONTENT-LENGTH: 321
CONTENT-TYPE: application/json CONTENT-TYPE: application/json
DATE: Thu, 08 Jan 2015 16:09:15 GMT DATE: Thu, 08 Jan 2015 16:09:15 GMT
SERVER: Python/3.5 GNS3/2.0.0dev1 SERVER: Python/3.5 GNS3/2.0.0dev1
X-ROUTE: /v2/projects/{project_id}/shapes/{shape_id} X-ROUTE: /v2/projects/{project_id}/drawings/{drawing_id}
{ {
"project_id": "2312697c-8e49-40e0-9d6d-5bd6dd0679ed", "project_id": "2312697c-8e49-40e0-9d6d-5bd6dd0679ed",
"rotation": 0, "rotation": 0,
"shape_id": "dbefe2d5-79d7-4f18-b898-cd073224563c", "drawing_id": "dbefe2d5-79d7-4f18-b898-cd073224563c",
"svg": "<svg height=\"210\" width=\"500\"><line x1=\"0\" y1=\"0\" x2=\"200\" y2=\"200\" style=\"stroke:rgb(255,0,0);stroke-width:2\" /></svg>", "svg": "<svg height=\"210\" width=\"500\"><line x1=\"0\" y1=\"0\" x2=\"200\" y2=\"200\" style=\"stroke:rgb(255,0,0);stroke-width:2\" /></svg>",
"x": 42, "x": 42,
"y": 20, "y": 20,

View File

@ -1,8 +1,8 @@
Shape Drawing
----------------------------- -----------------------------
.. toctree:: .. toctree::
:glob: :glob:
:maxdepth: 2 :maxdepth: 2
shape/* drawing/*

View File

@ -1,11 +1,11 @@
/v2/projects/{project_id}/shapes /v2/projects/{project_id}/drawings
------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------
.. contents:: .. contents::
GET /v2/projects/**{project_id}**/shapes GET /v2/projects/**{project_id}**/drawings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
List shapes of a project List drawings of a project
Parameters Parameters
********** **********
@ -13,18 +13,18 @@ Parameters
Response status codes Response status codes
********************** **********************
- **200**: List of shapes returned - **200**: List of drawings returned
Sample session Sample session
*************** ***************
.. literalinclude:: ../../../examples/controller_get_projectsprojectidshapes.txt .. literalinclude:: ../../../examples/controller_get_projectsprojectiddrawings.txt
POST /v2/projects/**{project_id}**/shapes POST /v2/projects/**{project_id}**/drawings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Create a new shape instance Create a new drawing instance
Parameters Parameters
********** **********
@ -33,7 +33,7 @@ Parameters
Response status codes Response status codes
********************** **********************
- **400**: Invalid request - **400**: Invalid request
- **201**: Shape created - **201**: Drawing created
Input Input
******* *******
@ -43,8 +43,8 @@ Input
<tr> <th>Name</th> <th>Mandatory</th> <th>Type</th> <th>Description</th> </tr> <tr> <th>Name</th> <th>Mandatory</th> <th>Type</th> <th>Description</th> </tr>
<tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr> <tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr>
<tr><td>rotation</td> <td> </td> <td>integer</td> <td>Rotation of the element</td> </tr> <tr><td>rotation</td> <td> </td> <td>integer</td> <td>Rotation of the element</td> </tr>
<tr><td>shape_id</td> <td> </td> <td>string</td> <td>Shape UUID</td> </tr> <tr><td>drawing_id</td> <td> </td> <td>string</td> <td>Drawing UUID</td> </tr>
<tr><td>svg</td> <td> </td> <td>string</td> <td>SVG content of the shape</td> </tr> <tr><td>svg</td> <td> </td> <td>string</td> <td>SVG content of the drawing</td> </tr>
<tr><td>x</td> <td> </td> <td>integer</td> <td>X property</td> </tr> <tr><td>x</td> <td> </td> <td>integer</td> <td>X property</td> </tr>
<tr><td>y</td> <td> </td> <td>integer</td> <td>Y property</td> </tr> <tr><td>y</td> <td> </td> <td>integer</td> <td>Y property</td> </tr>
<tr><td>z</td> <td> </td> <td>integer</td> <td>Z property</td> </tr> <tr><td>z</td> <td> </td> <td>integer</td> <td>Z property</td> </tr>
@ -58,8 +58,8 @@ Output
<tr> <th>Name</th> <th>Mandatory</th> <th>Type</th> <th>Description</th> </tr> <tr> <th>Name</th> <th>Mandatory</th> <th>Type</th> <th>Description</th> </tr>
<tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr> <tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr>
<tr><td>rotation</td> <td> </td> <td>integer</td> <td>Rotation of the element</td> </tr> <tr><td>rotation</td> <td> </td> <td>integer</td> <td>Rotation of the element</td> </tr>
<tr><td>shape_id</td> <td> </td> <td>string</td> <td>Shape UUID</td> </tr> <tr><td>drawing_id</td> <td> </td> <td>string</td> <td>Drawing UUID</td> </tr>
<tr><td>svg</td> <td> </td> <td>string</td> <td>SVG content of the shape</td> </tr> <tr><td>svg</td> <td> </td> <td>string</td> <td>SVG content of the drawing</td> </tr>
<tr><td>x</td> <td> </td> <td>integer</td> <td>X property</td> </tr> <tr><td>x</td> <td> </td> <td>integer</td> <td>X property</td> </tr>
<tr><td>y</td> <td> </td> <td>integer</td> <td>Y property</td> </tr> <tr><td>y</td> <td> </td> <td>integer</td> <td>Y property</td> </tr>
<tr><td>z</td> <td> </td> <td>integer</td> <td>Z property</td> </tr> <tr><td>z</td> <td> </td> <td>integer</td> <td>Z property</td> </tr>
@ -69,5 +69,5 @@ Sample session
*************** ***************
.. literalinclude:: ../../../examples/controller_post_projectsprojectidshapes.txt .. literalinclude:: ../../../examples/controller_post_projectsprojectiddrawings.txt

View File

@ -1,21 +1,21 @@
/v2/projects/{project_id}/shapes/{shape_id} /v2/projects/{project_id}/drawings/{drawing_id}
------------------------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------------------------
.. contents:: .. contents::
PUT /v2/projects/**{project_id}**/shapes/**{shape_id}** PUT /v2/projects/**{project_id}**/drawings/**{drawing_id}**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Create a new shape instance Create a new drawing instance
Parameters Parameters
********** **********
- **project_id**: Project UUID - **project_id**: Project UUID
- **shape_id**: Shape UUID - **drawing_id**: Drawing UUID
Response status codes Response status codes
********************** **********************
- **400**: Invalid request - **400**: Invalid request
- **201**: Shape updated - **201**: Drawing updated
Input Input
******* *******
@ -25,8 +25,8 @@ Input
<tr> <th>Name</th> <th>Mandatory</th> <th>Type</th> <th>Description</th> </tr> <tr> <th>Name</th> <th>Mandatory</th> <th>Type</th> <th>Description</th> </tr>
<tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr> <tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr>
<tr><td>rotation</td> <td> </td> <td>integer</td> <td>Rotation of the element</td> </tr> <tr><td>rotation</td> <td> </td> <td>integer</td> <td>Rotation of the element</td> </tr>
<tr><td>shape_id</td> <td> </td> <td>string</td> <td>Shape UUID</td> </tr> <tr><td>drawing_id</td> <td> </td> <td>string</td> <td>Drawing UUID</td> </tr>
<tr><td>svg</td> <td> </td> <td>string</td> <td>SVG content of the shape</td> </tr> <tr><td>svg</td> <td> </td> <td>string</td> <td>SVG content of the drawing</td> </tr>
<tr><td>x</td> <td> </td> <td>integer</td> <td>X property</td> </tr> <tr><td>x</td> <td> </td> <td>integer</td> <td>X property</td> </tr>
<tr><td>y</td> <td> </td> <td>integer</td> <td>Y property</td> </tr> <tr><td>y</td> <td> </td> <td>integer</td> <td>Y property</td> </tr>
<tr><td>z</td> <td> </td> <td>integer</td> <td>Z property</td> </tr> <tr><td>z</td> <td> </td> <td>integer</td> <td>Z property</td> </tr>
@ -40,8 +40,8 @@ Output
<tr> <th>Name</th> <th>Mandatory</th> <th>Type</th> <th>Description</th> </tr> <tr> <th>Name</th> <th>Mandatory</th> <th>Type</th> <th>Description</th> </tr>
<tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr> <tr><td>project_id</td> <td> </td> <td>string</td> <td>Project UUID</td> </tr>
<tr><td>rotation</td> <td> </td> <td>integer</td> <td>Rotation of the element</td> </tr> <tr><td>rotation</td> <td> </td> <td>integer</td> <td>Rotation of the element</td> </tr>
<tr><td>shape_id</td> <td> </td> <td>string</td> <td>Shape UUID</td> </tr> <tr><td>drawing_id</td> <td> </td> <td>string</td> <td>Drawing UUID</td> </tr>
<tr><td>svg</td> <td> </td> <td>string</td> <td>SVG content of the shape</td> </tr> <tr><td>svg</td> <td> </td> <td>string</td> <td>SVG content of the drawing</td> </tr>
<tr><td>x</td> <td> </td> <td>integer</td> <td>X property</td> </tr> <tr><td>x</td> <td> </td> <td>integer</td> <td>X property</td> </tr>
<tr><td>y</td> <td> </td> <td>integer</td> <td>Y property</td> </tr> <tr><td>y</td> <td> </td> <td>integer</td> <td>Y property</td> </tr>
<tr><td>z</td> <td> </td> <td>integer</td> <td>Z property</td> </tr> <tr><td>z</td> <td> </td> <td>integer</td> <td>Z property</td> </tr>
@ -51,26 +51,26 @@ Sample session
*************** ***************
.. literalinclude:: ../../../examples/controller_put_projectsprojectidshapesshapeid.txt .. literalinclude:: ../../../examples/controller_put_projectsprojectiddrawingsdrawingid.txt
DELETE /v2/projects/**{project_id}**/shapes/**{shape_id}** DELETE /v2/projects/**{project_id}**/drawings/**{drawing_id}**
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Delete a shape instance Delete a drawing instance
Parameters Parameters
********** **********
- **project_id**: Project UUID - **project_id**: Project UUID
- **shape_id**: Shape UUID - **drawing_id**: Drawing UUID
Response status codes Response status codes
********************** **********************
- **400**: Invalid request - **400**: Invalid request
- **204**: Shape deleted - **204**: Drawing deleted
Sample session Sample session
*************** ***************
.. literalinclude:: ../../../examples/controller_delete_projectsprojectidshapesshapeid.txt .. literalinclude:: ../../../examples/controller_delete_projectsprojectiddrawingsdrawingid.txt

View File

@ -225,7 +225,7 @@ This will display a red square in the middle of your topologies:
.. code-block:: shell-session .. code-block:: shell-session
# curl -X POST "http://localhost:3080/v2/projects/b8c070f7-f34c-4b7b-ba6f-be3d26ed073f/shapes" -d '{"x":0, "y": 12, "svg": "<svg width=\"50\" height=\"50\"><rect width=\"50\" height=\"50\" style=\"fill: #ff0000\"></rect></svg>"}' # curl -X POST "http://localhost:3080/v2/projects/b8c070f7-f34c-4b7b-ba6f-be3d26ed073f/drawings" -d '{"x":0, "y": 12, "svg": "<svg width=\"50\" height=\"50\"><rect width=\"50\" height=\"50\" style=\"fill: #ff0000\"></rect></svg>"}'
Tips: you can embed png/jpg... by using a base64 encoding in the SVG. Tips: you can embed png/jpg... by using a base64 encoding in the SVG.

View File

@ -108,9 +108,9 @@ The available notification are:
* link.created * link.created
* link.updated * link.updated
* link.deleted * link.deleted
* shape.created * drawing.created
* shape.updated * drawing.updated
* shape.deleted * drawing.deleted
* log.error * log.error
* log.warning * log.warning
* log.info * log.info

View File

@ -6,10 +6,10 @@ Node
A Virtual Machine (Dynamips, IOU, Qemu, VPCS...), a cloud, a builtin device (switch, hub...) A Virtual Machine (Dynamips, IOU, Qemu, VPCS...), a cloud, a builtin device (switch, hub...)
Shape Drawing
----- -----
Shape are visual element not used by the network emulation. Like Drawing are visual element not used by the network emulation. Like
text, images, rectangle... They are pure SVG elements. text, images, rectangle... They are pure SVG elements.
Adapter Adapter

View File

@ -19,19 +19,19 @@ import asyncio
import uuid import uuid
class Shape: class Drawing:
""" """
Shape are visual element not used by the network emulation. Like Drawing are visual element not used by the network emulation. Like
text, images, rectangle... They are pure SVG elements. text, images, rectangle... They are pure SVG elements.
""" """
def __init__(self, project, shape_id=None, svg="<svg></svg>", x=0, y=0, z=0, rotation=0): def __init__(self, project, drawing_id=None, svg="<svg></svg>", x=0, y=0, z=0, rotation=0):
self.svg = svg self.svg = svg
self._project = project self._project = project
if shape_id is None: if drawing_id is None:
self._id = str(uuid.uuid4()) self._id = str(uuid.uuid4())
else: else:
self._id = shape_id self._id = drawing_id
self._x = x self._x = x
self._y = y self._y = y
self._z = z self._z = z
@ -84,9 +84,9 @@ class Shape:
@asyncio.coroutine @asyncio.coroutine
def update(self, **kwargs): def update(self, **kwargs):
""" """
Update the shape Update the drawing
:param kwargs: Shape properties :param kwargs: Drawing properties
""" """
# Update node properties with additional elements # Update node properties with additional elements
@ -100,7 +100,7 @@ class Shape:
data = self.__json__() data = self.__json__()
if not svg_changed: if not svg_changed:
del data["svg"] del data["svg"]
self._project.controller.notification.emit("shape.updated", data) self._project.controller.notification.emit("drawing.updated", data)
self._project.dump() self._project.dump()
def __json__(self, topology_dump=False): def __json__(self, topology_dump=False):
@ -109,7 +109,7 @@ class Shape:
""" """
if topology_dump: if topology_dump:
return { return {
"shape_id": self._id, "drawing_id": self._id,
"x": self._x, "x": self._x,
"y": self._y, "y": self._y,
"z": self._z, "z": self._z,
@ -118,7 +118,7 @@ class Shape:
} }
return { return {
"project_id": self._project.id, "project_id": self._project.id,
"shape_id": self._id, "drawing_id": self._id,
"x": self._x, "x": self._x,
"y": self._y, "y": self._y,
"z": self._z, "z": self._z,
@ -127,4 +127,4 @@ class Shape:
} }
def __repr__(self): def __repr__(self):
return "<gns3server.controller.Shape {}>".format(self._id) return "<gns3server.controller.Drawing {}>".format(self._id)

View File

@ -24,7 +24,7 @@ import shutil
from uuid import UUID, uuid4 from uuid import UUID, uuid4
from .node import Node from .node import Node
from .shape import Shape from .drawing import Drawing
from .topology import project_to_topology, load_topology from .topology import project_to_topology, load_topology
from .udp_link import UDPLink from .udp_link import UDPLink
from ..config import Config from ..config import Config
@ -77,7 +77,7 @@ class Project:
self._allocated_node_names = set() self._allocated_node_names = set()
self._nodes = {} self._nodes = {}
self._links = {} self._links = {}
self._shapes = {} self._drawings = {}
# Create the project on demand on the compute node # Create the project on demand on the compute node
self._project_created_on_compute = set() self._project_created_on_compute = set()
@ -266,42 +266,42 @@ class Project:
return self._nodes return self._nodes
@property @property
def shapes(self): def drawings(self):
""" """
:returns: Dictionary of the shapes :returns: Dictionary of the drawings
""" """
return self._shapes return self._drawings
@asyncio.coroutine @asyncio.coroutine
def add_shape(self, shape_id=None, **kwargs): def add_drawing(self, drawing_id=None, **kwargs):
""" """
Create an shape or return an existing shape Create an drawing or return an existing drawing
:param kwargs: See the documentation of shape :param kwargs: See the documentation of drawing
""" """
if shape_id not in self._shapes: if drawing_id not in self._drawings:
shape = Shape(self, shape_id=shape_id, **kwargs) drawing = Drawing(self, drawing_id=drawing_id, **kwargs)
self._shapes[shape.id] = shape self._drawings[drawing.id] = drawing
self.controller.notification.emit("shape.created", shape.__json__()) self.controller.notification.emit("drawing.created", drawing.__json__())
self.dump() self.dump()
return shape return drawing
return self._shapes[shape_id] return self._drawings[drawing_id]
def get_shape(self, shape_id): def get_drawing(self, drawing_id):
""" """
Return the Shape or raise a 404 if the shape is unknown Return the Drawing or raise a 404 if the drawing is unknown
""" """
try: try:
return self._shapes[shape_id] return self._drawings[drawing_id]
except KeyError: except KeyError:
raise aiohttp.web.HTTPNotFound(text="Shape ID {} doesn't exist".format(shape_id)) raise aiohttp.web.HTTPNotFound(text="Drawing ID {} doesn't exist".format(drawing_id))
@asyncio.coroutine @asyncio.coroutine
def delete_shape(self, shape_id): def delete_drawing(self, drawing_id):
shape = self.get_shape(shape_id) drawing = self.get_drawing(drawing_id)
del self._shapes[shape.id] del self._drawings[drawing.id]
self.dump() self.dump()
self.controller.notification.emit("shape.deleted", shape.__json__()) self.controller.notification.emit("drawing.deleted", drawing.__json__())
@asyncio.coroutine @asyncio.coroutine
def add_link(self, link_id=None): def add_link(self, link_id=None):
@ -397,8 +397,8 @@ class Project:
node = self.get_node(node_link["node_id"]) node = self.get_node(node_link["node_id"])
yield from link.add_node(node, node_link["adapter_number"], node_link["port_number"]) yield from link.add_node(node, node_link["adapter_number"], node_link["port_number"])
for shape_data in topology.get("shapes", []): for drawing_data in topology.get("drawings", []):
shape = yield from self.add_shape(**shape_data) drawing = yield from self.add_drawing(**drawing_data)
self._status = "opened" self._status = "opened"
def dump(self): def dump(self):

View File

@ -34,7 +34,7 @@ def project_to_topology(project):
"nodes": [], "nodes": [],
"links": [], "links": [],
"computes": [], "computes": [],
"shapes": [] "drawings": []
}, },
"type": "topology", "type": "topology",
"revision": GNS3_FILE_FORMAT_REVISION, "revision": GNS3_FILE_FORMAT_REVISION,
@ -47,8 +47,8 @@ def project_to_topology(project):
data["topology"]["nodes"].append(node.__json__(topology_dump=True)) data["topology"]["nodes"].append(node.__json__(topology_dump=True))
for link in project.links.values(): for link in project.links.values():
data["topology"]["links"].append(link.__json__(topology_dump=True)) data["topology"]["links"].append(link.__json__(topology_dump=True))
for shape in project.shapes.values(): for drawing in project.drawings.values():
data["topology"]["shapes"].append(shape.__json__(topology_dump=True)) data["topology"]["drawings"].append(drawing.__json__(topology_dump=True))
for compute in computes: for compute in computes:
if hasattr(compute, "__json__"): if hasattr(compute, "__json__"):
data["topology"]["computes"].append(compute.__json__(topology_dump=True)) data["topology"]["computes"].append(compute.__json__(topology_dump=True))

View File

@ -20,4 +20,4 @@ from .project_handler import ProjectHandler
from .node_handler import NodeHandler from .node_handler import NodeHandler
from .link_handler import LinkHandler from .link_handler import LinkHandler
from .server_handler import ServerHandler from .server_handler import ServerHandler
from .shape_handler import ShapeHandler from .drawing_handler import DrawingHandler

View File

@ -20,88 +20,88 @@ import aiohttp
from gns3server.web.route import Route from gns3server.web.route import Route
from gns3server.controller import Controller from gns3server.controller import Controller
from gns3server.schemas.shape import ( from gns3server.schemas.drawing import (
SHAPE_OBJECT_SCHEMA, DRAWING_OBJECT_SCHEMA,
) )
class ShapeHandler: class DrawingHandler:
""" """
API entry point for Shape API entry point for Drawing
""" """
@Route.get( @Route.get(
r"/projects/{project_id}/shapes", r"/projects/{project_id}/drawings",
parameters={ parameters={
"project_id": "Project UUID" "project_id": "Project UUID"
}, },
status_codes={ status_codes={
200: "List of shapes returned", 200: "List of drawings returned",
}, },
description="List shapes of a project") description="List drawings of a project")
def list_shapes(request, response): def list_drawings(request, response):
controller = Controller.instance() controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"]) project = controller.get_project(request.match_info["project_id"])
response.json([v for v in project.shapes.values()]) response.json([v for v in project.drawings.values()])
@Route.post( @Route.post(
r"/projects/{project_id}/shapes", r"/projects/{project_id}/drawings",
parameters={ parameters={
"project_id": "Project UUID" "project_id": "Project UUID"
}, },
status_codes={ status_codes={
201: "Shape created", 201: "Drawing created",
400: "Invalid request" 400: "Invalid request"
}, },
description="Create a new shape instance", description="Create a new drawing instance",
input=SHAPE_OBJECT_SCHEMA, input=DRAWING_OBJECT_SCHEMA,
output=SHAPE_OBJECT_SCHEMA) output=DRAWING_OBJECT_SCHEMA)
def create(request, response): def create(request, response):
controller = Controller.instance() controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"]) project = controller.get_project(request.match_info["project_id"])
shape = yield from project.add_shape(**request.json) drawing = yield from project.add_drawing(**request.json)
response.set_status(201) response.set_status(201)
response.json(shape) response.json(drawing)
@Route.put( @Route.put(
r"/projects/{project_id}/shapes/{shape_id}", r"/projects/{project_id}/drawings/{drawing_id}",
parameters={ parameters={
"project_id": "Project UUID", "project_id": "Project UUID",
"shape_id": "Shape UUID" "drawing_id": "Drawing UUID"
}, },
status_codes={ status_codes={
201: "Shape updated", 201: "Drawing updated",
400: "Invalid request" 400: "Invalid request"
}, },
description="Create a new shape instance", description="Create a new drawing instance",
input=SHAPE_OBJECT_SCHEMA, input=DRAWING_OBJECT_SCHEMA,
output=SHAPE_OBJECT_SCHEMA) output=DRAWING_OBJECT_SCHEMA)
def update(request, response): def update(request, response):
controller = Controller.instance() controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"]) project = controller.get_project(request.match_info["project_id"])
shape = project.get_shape(request.match_info["shape_id"]) drawing = project.get_drawing(request.match_info["drawing_id"])
yield from shape.update(**request.json) yield from drawing.update(**request.json)
response.set_status(201) response.set_status(201)
response.json(shape) response.json(drawing)
@Route.delete( @Route.delete(
r"/projects/{project_id}/shapes/{shape_id}", r"/projects/{project_id}/drawings/{drawing_id}",
parameters={ parameters={
"project_id": "Project UUID", "project_id": "Project UUID",
"shape_id": "Shape UUID" "drawing_id": "Drawing UUID"
}, },
status_codes={ status_codes={
204: "Shape deleted", 204: "Drawing deleted",
400: "Invalid request" 400: "Invalid request"
}, },
description="Delete a shape instance") description="Delete a drawing instance")
def delete(request, response): def delete(request, response):
controller = Controller.instance() controller = Controller.instance()
project = controller.get_project(request.match_info["project_id"]) project = controller.get_project(request.match_info["project_id"])
yield from project.delete_shape(request.match_info["shape_id"]) yield from project.delete_drawing(request.match_info["drawing_id"])
response.set_status(204) response.set_status(204)

View File

@ -16,13 +16,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
SHAPE_OBJECT_SCHEMA = { DRAWING_OBJECT_SCHEMA = {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"description": "An shape object", "description": "An drawing object",
"type": "object", "type": "object",
"properties": { "properties": {
"shape_id": { "drawing_id": {
"description": "Shape UUID", "description": "Drawing UUID",
"type": "string", "type": "string",
"minLength": 36, "minLength": 36,
"maxLength": 36, "maxLength": 36,
@ -54,7 +54,7 @@ SHAPE_OBJECT_SCHEMA = {
"maximum": 360 "maximum": 360
}, },
"svg": { "svg": {
"description": "SVG content of the shape", "description": "SVG content of the drawing",
"type": "string", "type": "string",
"pattern": "^<(.|[\r\n])+>$" "pattern": "^<(.|[\r\n])+>$"
} }

View File

@ -57,18 +57,18 @@ in futur GNS3 versions.
</table> </table>
<h2>Shapes</h2> <h2>Drawings</h2>
<table border="1"> <table border="1">
<tr> <tr>
<th>ID</th> <th>ID</th>
<th>Position</th> <th>Position</th>
<th>Content</th> <th>Content</th>
</tr> </tr>
{% for shape in project.shapes.values() %} {% for drawing in project.drawings.values() %}
<tr> <tr>
<td>{{shape.id}}</td> <td>{{drawing.id}}</td>
<td>{{shape.x}}, {{shape.y}}, {{shape.z}}</td> <td>{{drawing.x}}, {{drawing.y}}, {{drawing.z}}</td>
<td>{{shape.svg}}</td> <td>{{drawing.svg}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>

View File

@ -213,30 +213,30 @@ def test_deleteLink(async_run, project, controller):
assert len(project._links) == 0 assert len(project._links) == 0
def test_addShape(async_run, project, controller): def test_addDrawing(async_run, project, controller):
controller.notification.emit = MagicMock() controller.notification.emit = MagicMock()
shape = async_run(project.add_shape(None, svg="<svg></svg>")) drawing = async_run(project.add_drawing(None, svg="<svg></svg>"))
assert len(project._shapes) == 1 assert len(project._drawings) == 1
controller.notification.emit.assert_any_call("shape.created", shape.__json__()) controller.notification.emit.assert_any_call("drawing.created", drawing.__json__())
def test_getShape(async_run, project): def test_getDrawing(async_run, project):
shape = async_run(project.add_shape(None)) drawing = async_run(project.add_drawing(None))
assert project.get_shape(shape.id) == shape assert project.get_drawing(drawing.id) == drawing
with pytest.raises(aiohttp.web_exceptions.HTTPNotFound): with pytest.raises(aiohttp.web_exceptions.HTTPNotFound):
project.get_shape("test") project.get_drawing("test")
def test_deleteShape(async_run, project, controller): def test_deleteDrawing(async_run, project, controller):
assert len(project._shapes) == 0 assert len(project._drawings) == 0
shape = async_run(project.add_shape()) drawing = async_run(project.add_drawing())
assert len(project._shapes) == 1 assert len(project._drawings) == 1
controller._notification = MagicMock() controller._notification = MagicMock()
async_run(project.delete_shape(shape.id)) async_run(project.delete_drawing(drawing.id))
controller.notification.emit.assert_any_call("shape.deleted", shape.__json__()) controller.notification.emit.assert_any_call("drawing.deleted", drawing.__json__())
assert len(project._shapes) == 0 assert len(project._drawings) == 0
def test_delete(async_run, project, controller): def test_delete(async_run, project, controller):

View File

@ -22,7 +22,7 @@ import uuid
from tests.utils import AsyncioMagicMock from tests.utils import AsyncioMagicMock
from gns3server.controller.shape import Shape from gns3server.controller.drawing import Drawing
from gns3server.controller.project import Project from gns3server.controller.project import Project
@ -32,25 +32,25 @@ def project(controller, async_run):
@pytest.fixture @pytest.fixture
def shape(project): def drawing(project):
return Shape(project, None, svg="<svg></svg>") return Drawing(project, None, svg="<svg></svg>")
def test_init_without_uuid(project): def test_init_without_uuid(project):
shape = Shape(project, None, svg="<svg></svg>") drawing = Drawing(project, None, svg="<svg></svg>")
assert shape.id is not None assert drawing.id is not None
def test_init_with_uuid(project): def test_init_with_uuid(project):
id = str(uuid.uuid4()) id = str(uuid.uuid4())
shape = Shape(project, id, svg="<svg></svg>") drawing = Drawing(project, id, svg="<svg></svg>")
assert shape.id == id assert drawing.id == id
def test_json(project): def test_json(project):
i = Shape(project, None, svg="<svg></svg>") i = Drawing(project, None, svg="<svg></svg>")
assert i.__json__() == { assert i.__json__() == {
"shape_id": i.id, "drawing_id": i.id,
"project_id": project.id, "project_id": project.id,
"x": i.x, "x": i.x,
"y": i.y, "y": i.y,
@ -59,7 +59,7 @@ def test_json(project):
"rotation": i.rotation "rotation": i.rotation
} }
assert i.__json__(topology_dump=True) == { assert i.__json__(topology_dump=True) == {
"shape_id": i.id, "drawing_id": i.id,
"x": i.x, "x": i.x,
"y": i.y, "y": i.y,
"z": i.z, "z": i.z,
@ -68,22 +68,22 @@ def test_json(project):
} }
def test_update(shape, project, async_run, controller): def test_update(drawing, project, async_run, controller):
controller._notification = AsyncioMagicMock() controller._notification = AsyncioMagicMock()
project.dump = MagicMock() project.dump = MagicMock()
async_run(shape.update(x=42, svg="<svg><rect></rect></svg>")) async_run(drawing.update(x=42, svg="<svg><rect></rect></svg>"))
assert shape.x == 42 assert drawing.x == 42
args, kwargs = controller._notification.emit.call_args args, kwargs = controller._notification.emit.call_args
assert args[0] == "shape.updated" assert args[0] == "drawing.updated"
# JSON # JSON
assert args[1]["x"] == 42 assert args[1]["x"] == 42
assert args[1]["svg"] == "<svg><rect></rect></svg>" assert args[1]["svg"] == "<svg><rect></rect></svg>"
async_run(shape.update(x=12, svg="<svg><rect></rect></svg>")) async_run(drawing.update(x=12, svg="<svg><rect></rect></svg>"))
assert shape.x == 12 assert drawing.x == 12
args, kwargs = controller._notification.emit.call_args args, kwargs = controller._notification.emit.call_args
assert args[0] == "shape.updated" assert args[0] == "drawing.updated"
# JSON # JSON
assert args[1]["x"] == 12 assert args[1]["x"] == 12
# To avoid spamming client with large data we don't send the svg if the SVG didn't change # To avoid spamming client with large data we don't send the svg if the SVG didn't change

View File

@ -38,7 +38,7 @@ def test_project_to_topology_empty(tmpdir):
"nodes": [], "nodes": [],
"links": [], "links": [],
"computes": [], "computes": [],
"shapes": [] "drawings": []
}, },
"type": "topology", "type": "topology",
"version": __version__ "version": __version__
@ -58,14 +58,14 @@ def test_basic_topology(tmpdir, async_run, controller):
async_run(link.add_node(node1, 0, 0)) async_run(link.add_node(node1, 0, 0))
async_run(link.add_node(node2, 0, 0)) async_run(link.add_node(node2, 0, 0))
shape = async_run(project.add_shape(svg="<svg></svg>")) drawing = async_run(project.add_drawing(svg="<svg></svg>"))
topo = project_to_topology(project) topo = project_to_topology(project)
assert len(topo["topology"]["nodes"]) == 2 assert len(topo["topology"]["nodes"]) == 2
assert node1.__json__(topology_dump=True) in topo["topology"]["nodes"] assert node1.__json__(topology_dump=True) in topo["topology"]["nodes"]
assert topo["topology"]["links"][0] == link.__json__(topology_dump=True) assert topo["topology"]["links"][0] == link.__json__(topology_dump=True)
assert topo["topology"]["computes"][0] == compute.__json__(topology_dump=True) assert topo["topology"]["computes"][0] == compute.__json__(topology_dump=True)
assert topo["topology"]["shapes"][0] == shape.__json__(topology_dump=True) assert topo["topology"]["drawings"][0] == drawing.__json__(topology_dump=True)
def test_load_topology(tmpdir): def test_load_topology(tmpdir):
@ -77,7 +77,7 @@ def test_load_topology(tmpdir):
"nodes": [], "nodes": [],
"links": [], "links": [],
"computes": [], "computes": [],
"shapes": [] "drawings": []
}, },
"type": "topology", "type": "topology",
"version": __version__} "version": __version__}

View File

@ -30,7 +30,7 @@ from tests.utils import asyncio_patch
from gns3server.handlers.api.controller.project_handler import ProjectHandler from gns3server.handlers.api.controller.project_handler import ProjectHandler
from gns3server.controller import Controller from gns3server.controller import Controller
from gns3server.controller.shape import Shape from gns3server.controller.drawing import Drawing
@ -39,49 +39,49 @@ def project(http_controller, async_run):
return async_run(Controller.instance().add_project()) return async_run(Controller.instance().add_project())
def test_create_shape(http_controller, tmpdir, project, async_run): def test_create_drawing(http_controller, tmpdir, project, async_run):
response = http_controller.post("/projects/{}/shapes".format(project.id), { response = http_controller.post("/projects/{}/drawings".format(project.id), {
"svg": '<svg height="210" width="500"><line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" /></svg>', "svg": '<svg height="210" width="500"><line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" /></svg>',
"x": 10, "x": 10,
"y": 20, "y": 20,
"z": 0 "z": 0
}, example=True) }, example=True)
assert response.status == 201 assert response.status == 201
assert response.json["shape_id"] is not None assert response.json["drawing_id"] is not None
def test_update_shape(http_controller, tmpdir, project, async_run): def test_update_drawing(http_controller, tmpdir, project, async_run):
response = http_controller.post("/projects/{}/shapes".format(project.id), { response = http_controller.post("/projects/{}/drawings".format(project.id), {
"svg": '<svg height="210" width="500"><line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" /></svg>', "svg": '<svg height="210" width="500"><line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" /></svg>',
"x": 10, "x": 10,
"y": 20, "y": 20,
"z": 0 "z": 0
},) },)
response = http_controller.put("/projects/{}/shapes/{}".format(project.id, response.json["shape_id"]), { response = http_controller.put("/projects/{}/drawings/{}".format(project.id, response.json["drawing_id"]), {
"x": 42, "x": 42,
}, example=True) }, example=True)
assert response.status == 201 assert response.status == 201
assert response.json["x"] == 42 assert response.json["x"] == 42
def test_list_shape(http_controller, tmpdir, project, async_run): def test_list_drawing(http_controller, tmpdir, project, async_run):
response = http_controller.post("/projects/{}/shapes".format(project.id), { response = http_controller.post("/projects/{}/drawings".format(project.id), {
"svg": '<svg height="210" width="500"><line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" /></svg>', "svg": '<svg height="210" width="500"><line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" /></svg>',
"x": 10, "x": 10,
"y": 20, "y": 20,
"z": 0 "z": 0
}, example=False) }, example=False)
response = http_controller.get("/projects/{}/shapes".format(project.id), example=True) response = http_controller.get("/projects/{}/drawings".format(project.id), example=True)
assert response.status == 200 assert response.status == 200
assert len(response.json) == 1 assert len(response.json) == 1
def test_delete_shape(http_controller, tmpdir, project, async_run): def test_delete_drawing(http_controller, tmpdir, project, async_run):
shape = Shape(project) drawing = Drawing(project)
project._shapes = {shape.id: shape} project._drawings = {drawing.id: drawing}
response = http_controller.delete("/projects/{}/shapes/{}".format(project.id, shape.id), example=True) response = http_controller.delete("/projects/{}/drawings/{}".format(project.id, drawing.id), example=True)
assert response.status == 204 assert response.status == 204
assert shape.id not in project._shapes assert drawing.id not in project._drawings