From fb76d2c1ba353f2bdb1e286d388a3629a7d82698 Mon Sep 17 00:00:00 2001 From: dmunozv04 Date: Mon, 25 Mar 2024 13:02:51 +0100 Subject: [PATCH 1/7] add json support --- src/requirements.txt | 1 + .../fixtures/catalogue_search_data.json | 14 +- .../commons/utils/template/parsers/json.py | 6 +- .../template/schemas/json_schema.schema.json | 1218 +++++++++++++++++ src/wirecloud/commons/utils/wgt.py | 22 +- .../workspace/mashupTemplateGenerator.py | 5 +- src/wirecloud/platform/workspace/views.py | 4 +- 7 files changed, 1251 insertions(+), 19 deletions(-) create mode 100644 src/wirecloud/commons/utils/template/schemas/json_schema.schema.json diff --git a/src/requirements.txt b/src/requirements.txt index fa1a1e65d3..80f49ac2f9 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -17,3 +17,4 @@ pyScss>=1.3.4,<2.0 Pygments pillow jsonpatch +jsonschema \ No newline at end of file diff --git a/src/wirecloud/catalogue/fixtures/catalogue_search_data.json b/src/wirecloud/catalogue/fixtures/catalogue_search_data.json index 60d7a9799f..45e83e46cf 100644 --- a/src/wirecloud/catalogue/fixtures/catalogue_search_data.json +++ b/src/wirecloud/catalogue/fixtures/catalogue_search_data.json @@ -77,7 +77,7 @@ "popularity": "0", "vendor": "Wirecloud", "short_name": "Test", - "json_description": "{\"name\": \"Test\", \"vendor\": \"Wirecloud\", \"version\": \"1.5\", \"type\": \"widget\", \"title\": \"Incredible Test\", \"description\": \"This widget contains keywords like term mashable application component.\", \"wiring\": {\"inputs\": [{\"friendcode\": \"test-data\", \"actionlabel\": \"\", \"name\": \"inputendpoint\", \"label\": \"Input\", \"type\": \"text\", \"description\": \"input type text\"}], \"outputs\": [{\"friendcode\": \"test-data\", \"description\": \"output digit\", \"type\": \"text\", \"name\": \"outputendpoint\", \"label\": \"Output\"}]}, \"contents\": {\"src\": \"test.html\"}}", + "json_description": "{\"name\": \"Test\", \"vendor\": \"Wirecloud\", \"version\": \"1.5\", \"type\": \"widget\", \"title\": \"Incredible Test\", \"description\": \"This widget contains keywords like term mashable application component.\", \"wiring\": {\"inputs\": [{\"friendcode\": \"test-data\", \"actionlabel\": \"\", \"name\": \"inputendpoint\", \"label\": \"Input\", \"type\": \"text\", \"description\": \"input type text\"}], \"outputs\": [{\"friendcode\": \"test-data\", \"description\": \"output digit\", \"type\": \"text\", \"name\": \"outputendpoint\", \"label\": \"Output\"}]}, \"contents\": {\"src\": \"test.html\"}, \"widget_width\": \"4\", \"widget_height\": \"4\"}", "creator": 80, "creation_date": "2011-05-12T11:24:03Z", "version": "1.5", @@ -95,7 +95,7 @@ "popularity": "0", "vendor": "Wirecloud", "short_name": "Test", - "json_description": "{\"name\": \"Test\", \"vendor\": \"Wirecloud\", \"version\": \"2.0\", \"type\": \"widget\", \"title\": \"New Incredible Test\", \"description\": \"This widget contains keywords like prefix mashable application component.\", \"contents\": {\"src\": \"test.html\"}}", + "json_description": "{\"name\": \"Test\", \"vendor\": \"Wirecloud\", \"version\": \"2.0\", \"type\": \"widget\", \"title\": \"New Incredible Test\", \"description\": \"This widget contains keywords like prefix mashable application component.\", \"contents\": {\"src\": \"test.html\"}, \"widget_width\": \"4\", \"widget_height\": \"4\"}", "creator": 80, "creation_date": "2011-05-13T11:24:03Z", "version": "2.0", @@ -113,7 +113,7 @@ "popularity": "0", "vendor": "Wirecloud", "short_name": "Test", - "json_description": "{\"name\": \"Test\", \"vendor\": \"Wirecloud\", \"version\": \"2.5\", \"type\": \"widget\", \"title\": \"The Best Incredible Test\", \"description\": \"This widget contains keywords regex mashable application component.\", \"contents\": {\"src\": \"test.html\"}}", + "json_description": "{\"name\": \"Test\", \"vendor\": \"Wirecloud\", \"version\": \"2.5\", \"type\": \"widget\", \"title\": \"The Best Incredible Test\", \"description\": \"This widget contains keywords regex mashable application component.\", \"contents\": {\"src\": \"test.html\"}, \"widget_width\": \"4\", \"widget_height\": \"4\"}", "creator": 80, "creation_date": "2011-05-14T11:24:03Z", "version": "2.5", @@ -131,7 +131,7 @@ "popularity": "0", "vendor": "CoNWeT-Lab", "short_name": "Clock_Now", - "json_description": "{\"name\": \"Clock_Now\", \"vendor\": \"CoNWeT-Lab\", \"version\": \"1.5\", \"type\": \"widget\", \"title\": \"Clock Now\", \"description\": \"This WireCloud widget contains keywords like free button bluetooth.\", \"contents\": {\"src\": \"test.html\"}}", + "json_description": "{\"name\": \"Clock_Now\", \"vendor\": \"CoNWeT-Lab\", \"version\": \"1.5\", \"type\": \"widget\", \"title\": \"Clock Now\", \"description\": \"This WireCloud widget contains keywords like free button bluetooth.\", \"contents\": {\"src\": \"test.html\"}, \"widget_width\": \"4\", \"widget_height\": \"4\"}", "creator": 80, "creation_date": "2011-05-15T11:24:03Z", "version": "1.5", @@ -149,7 +149,7 @@ "popularity": "0", "vendor": "CoNWeT-Lab", "short_name": "Clock_Now", - "json_description": "{\"name\": \"Clock_Now\", \"vendor\": \"CoNWeT-Lab\", \"version\": \"1.11\", \"type\": \"widget\", \"title\": \"Last Clock Now\", \"description\": \"This WireCloud widget contains keywords like free button bluetooth.\", \"contents\": {\"src\": \"test.html\"}}", + "json_description": "{\"name\": \"Clock_Now\", \"vendor\": \"CoNWeT-Lab\", \"version\": \"1.11\", \"type\": \"widget\", \"title\": \"Last Clock Now\", \"description\": \"This WireCloud widget contains keywords like free button bluetooth.\", \"contents\": {\"src\": \"test.html\"}, \"widget_width\": \"4\", \"widget_height\": \"4\"}", "creator": 80, "creation_date": "2011-05-16T11:24:03Z", "version": "1.11", @@ -347,7 +347,7 @@ "popularity": "0", "vendor": "Wirecloud", "short_name": "Book-Reader", - "json_description": "{\"name\": \"Book-Reader\", \"vendor\": \"Wirecloud\", \"version\": \"1.5\", \"type\": \"widget\", \"title\": \"The Best Incredible Test\", \"description\": \"This widget contains keywords wiredrawers wiretappers wirephoto wirework wireway wired wireless.\", \"contents\": {\"src\": \"test.html\"}}", + "json_description": "{\"name\": \"Book-Reader\", \"vendor\": \"Wirecloud\", \"version\": \"1.5\", \"type\": \"widget\", \"title\": \"The Best Incredible Test\", \"description\": \"This widget contains keywords wiredrawers wiretappers wirephoto wirework wireway wired wireless.\", \"contents\": {\"src\": \"test.html\"}, \"widget_width\": \"4\", \"widget_height\": \"4\"}", "creator": 80, "creation_date": "2011-05-27T11:24:03Z", "version": "1.5", @@ -365,7 +365,7 @@ "popularity": "0", "vendor": "CoNWeT-Lab", "short_name": "Live_Sports", - "json_description": "{\"name\": \"Live_Sports\", \"vendor\": \"CoNWeT-Lab\", \"version\": \"1.0\", \"type\": \"widget\", \"title\": \"Live Sports\", \"description\": \"This widget contains keywords like free button bluetooth.\", \"contents\": {\"src\": \"test.html\"}}", + "json_description": "{\"name\": \"Live_Sports\", \"vendor\": \"CoNWeT-Lab\", \"version\": \"1.0\", \"type\": \"widget\", \"title\": \"Live Sports\", \"description\": \"This widget contains keywords like free button bluetooth.\", \"contents\": {\"src\": \"test.html\"}, \"widget_width\": \"4\", \"widget_height\": \"4\"}", "creator": 80, "creation_date": "2011-05-28T11:24:03Z", "version": "1.0", diff --git a/src/wirecloud/commons/utils/template/parsers/json.py b/src/wirecloud/commons/utils/template/parsers/json.py index 444797a2c2..70260c402d 100644 --- a/src/wirecloud/commons/utils/template/parsers/json.py +++ b/src/wirecloud/commons/utils/template/parsers/json.py @@ -19,13 +19,17 @@ # along with Wirecloud. If not, see . import json +import os from django.utils.translation import ugettext as _ from wirecloud.commons.utils.template.base import is_valid_name, is_valid_vendor, is_valid_version, parse_contacts_info, TemplateParseException from wirecloud.commons.utils.translation import get_trans_index from wirecloud.platform.wiring.utils import get_wiring_skeleton, parse_wiring_old_version +from jsonschema import validate +with open(os.path.join(os.path.dirname(__file__), '../schemas/json_schema.schema.json'), 'r') as JSONSCHEMA_FILE: + JSONSCHEMA = json.load(JSONSCHEMA_FILE) class JSONTemplateParser(object): @@ -189,7 +193,7 @@ def _add_translation_index(self, value, **kwargs): self._info['translation_index_usage'][index].append(kwargs) def _init(self): - + validate(self._info, JSONSCHEMA) self._check_string_fields(('title', 'description', 'longdescription', 'email', 'homepage', 'doc', 'changelog', 'image', 'smartphoneimage', 'license', 'licenseurl', 'issuetracker')) self._check_contacts_fields(('authors', 'contributors')) self._check_integer_fields(('macversion', ), default = 1) diff --git a/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json b/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json new file mode 100644 index 0000000000..0754ab72e0 --- /dev/null +++ b/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json @@ -0,0 +1,1218 @@ +{ + "$id": "https://example.com", + "$schema": "https://json-schema.org/draft-07/schema", + "title": "WireCloud Mashable Application Component Descriptions", + "type": "object", + "required": [ + "vendor", + "name", + "version" + ], + "properties": { + "authors": { + "description": "Main developers of this mashable application component", + "type": [ + "array", + "string" + ], + "items": { + "$ref": "#/$defs/contact" + } + }, + "changelog": { + "description": "Relative path to a markdown file detailing the changes made to the mashable application component in each version", + "type": "string" + }, + "contributors": { + "description": "Contributors of this mashable application component", + "type": [ + "array", + "string" + ], + "items": { + "$ref": "#/$defs/contact" + } + }, + "description": { + "description": "A brief textual description of the mashable application component", + "type": "string" + }, + "doc": { + "description": "Absolute or template-relative URL of the widget documentation", + "type": "string" + }, + "email": { + "description": "E-mail address to get in touch with the developer(s)", + "type": "string" + }, + "homepage": { + "description": "The url to the project homepage", + "type": "string" + }, + "image": { + "description": "Absolute or template-relative URL of the resource image for the catalog", + "type": "string" + }, + "issuetracker": { + "description": "Absolute URL of the issue tracker for the mashable application component", + "type": "string" + }, + "license": { + "description": "Name of the license associated to the mashable application component", + "type": "string" + }, + "licenseurl": { + "description": "Absolute or template-relative URL of the full license document associated to the mashable application component", + "type": "string" + }, + "longDescription": { + "description": "A detailed description of the mashable application component (using Markdown syntax by default)", + "type": "string" + }, + "macversion": { + "description": "Version of the MACD specification used to describe the mashable application component", + "default": 1, + "enum": [ + 1, + 2 + ], + "type": "integer" + }, + "name": { + "description": "Name of the mashable application component", + "type": "string" + }, + "requirements": { + "description": "List of requirements for the mashable application component", + "required": [ + "name" + ], + "type": "array", + "items": { + "properties": { + "name": { + "description": "Name of the requirement", + "type": "string" + }, + "type": { + "type": "string" + } + }, + "type": "object" + } + }, + "smartphoneimage": { + "description": "Absolute or template-relative URL of the resource image for the catalog to be used on phones", + "type": "string" + }, + "title": { + "default": "", + "description": "Name used in the user interface for the widget. This field can be translated, therefore this fieldis not used to uniquely identify the widget", + "type": "string" + }, + "type": { + "description": "Type of the mashable application component", + "enum": [ + "mashup", + "operator", + "widget" + ], + "type": "string" + }, + "vendor": { + "description": "Name of the vendor of the mashable application component", + "type": "string" + }, + "version": { + "description": "Version of the mashable application component", + "$ref": "#/$defs/version" + } + }, + "allOf": [ + { + "if": { + "properties": { + "type": { + "enum": [ + "widget", + "operator" + ] + } + } + }, + "then": { + "properties": { + "preferences": { + "description": "The user preferences, which may be changed through the platform interface", + "type": "array", + "items": { + "$ref": "#/$defs/component_preference" + } + }, + "properties": { + "type": "array", + "items": { + "$ref": "#/$defs/component_property" + } + }, + "wiring": { + "default": {}, + "allOf": [ + { + "$ref": "#/$defs/wiring" + } + ] + } + } + } + }, + { + "if": { + "properties": { + "type": { + "const": "widget" + }, + "macversion": { + "const": 1 + } + } + }, + "then": { + "properties": { + "contents": { + "description": "The contents of the widget", + "type": "object", + "required": [ + "src" + ], + "properties": { + "src": { + "type": "string" + }, + "contenttype": { + "type": "string", + "default": "text/html" + }, + "charset": { + "type": "string", + "default": "utf-8" + }, + "useplatformstyle": { + "type": "boolean", + "default": false + }, + "cacheable": { + "type": "boolean", + "default": true + }, + "altcontents": { + "description": "Alternative contents of the widget", + "type": "array", + "items": { + "type": "object", + "required": [ + "src", + "scope" + ], + "properties": { + "src": { + "type": "string" + }, + "scope": { + "type": "string", + "enum": [ + "local", + "global" + ] + }, + "contenttype": { + "type": "string", + "default": "text/html" + }, + "charset": { + "type": "string", + "default": "utf-8" + } + } + } + } + } + } + } + } + }, + { + "if": { + "properties": { + "type": { + "const": "widget" + } + } + }, + "then": { + "required": [ + "widget_width", + "widget_height" + ], + "properties": { + "widget_width": { + "$ref": "#/$defs/size" + }, + "widget_height": { + "$ref": "#/$defs/size" + } + } + } + }, + { + "if": { + "oneOf": [ + { + "properties": { + "type": { + "const": "widget" + }, + "macversion": { + "minimum": 2 + } + } + }, + { + "properties": { + "type": { + "const": "operator" + } + } + } + ] + }, + "then": { + "properties": { + "js_files": { + "description": "List of scripts the operator is going to use", + "allOf": [ + { + "$ref": "#/$defs/js_files" + } + ] + } + } + } + }, + { + "if": { + "properties": { + "type": { + "const": "mashup" + } + } + }, + "then": { + "properties": { + "preferences": { + "description": "The user preferences", + "type": "object", + "patternProperties": { + ".*": { + "type": "string", + "description": "A user preference" + } + } + }, + "tabs": { + "description": "List of mashup tabs", + "type": "array", + "items": { + "$ref": "#/$defs/mashup_tab" + } + }, + "params": { + "description": "Mashup parameters", + "type": "array", + "items": { + "$ref": "#/$defs/mashup_param" + } + }, + "embedded": { + "type": "array", + "required": [ + "vendor", + "name", + "version", + "src" + ], + "items": { + "type": "object", + "properties": { + "vendor": { + "type": "string" + }, + "name": { + "type": "string" + }, + "version": { + "$ref": "#/$defs/version" + }, + "src": { + "type": "string" + } + } + }, + "description": "The list of embedded resources for this mashup" + }, + "wiring": { + "default": { + "version": "2.0", + "connections": [], + "operators": {}, + "visualdescription": { + "behaviours": [], + "components": { + "operator": {}, + "widget": {} + }, + "connections": [] + } + }, + "allOf": [ + { + "$ref": "#/$defs/wiring" + }, + { + "$ref": "#/$defs/wiring_mashup" + } + ], + "description": "Mashup wiring" + } + } + } + }, + { + "if": { + "properties": { + "type": { + "enum": [ + "widget", + "operator" + ] + }, + "macversion": { + "minimum": 2 + } + } + }, + "then": { + "properties": { + "entrypoint": { + "type": "string" + } + } + } + } + ], + "$defs": { + "component_preference": { + "description": "The user preferences, which may be changed through the platform interface. This element consisting of one, several or even none preference sub-elements", + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "description": "Name of the preference", + "type": "string" + }, + "type": { + "description": "Type of the preference", + "type": "string", + "enum": [ + "text", + "boolean", + "number", + "password", + "list" + ] + }, + "label": { + "description": "Label of the preference", + "type": "string" + }, + "description": { + "description": "Description of the preference", + "type": "string" + }, + "default": { + "description": "Default value of the preference", + "type": [ + "string", + "boolean", + "number" + ] + }, + "readOnly": { + "description": "Whether the preference is read-only", + "default": false, + "type": "boolean" + }, + "secure": { + "description": "Direct access from the javascript code of the application mashup component to this variable is disallowed if the value of this attribute is true", + "default": false, + "type": "boolean" + }, + "required": { + "description": "Whether the preference is required", + "default": false, + "type": "boolean" + }, + "multiuser": { + "description": "Whether to store a different value for each user", + "default": false, + "type": "boolean" + }, + "if": { + "properties": { + "type": { + "enum": [ + "list" + ] + } + } + }, + "then": { + "required": [ + "options" + ], + "properties": { + "options": { + "description": "List of options for the preference", + "type": "array", + "items": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "description": "Value of the preference", + "type": [ + "string", + "boolean", + "number" + ] + } + } + } + } + } + }, + "else": { + "description": "The value of the preference", + "required": [ + "value" + ], + "properties": { + "value": { + "type": [ + "string", + "boolean", + "number" + ] + } + } + } + } + }, + "component_property": { + "description": "The properties, that save persistent information about the component", + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "description": "Name of the property", + "type": "string" + }, + "type": { + "description": "Type of the property", + "type": "string", + "enum": [ + "text", + "boolean", + "number", + "password", + "list" + ] + }, + "label": { + "description": "Label of the property", + "type": "string" + }, + "description": { + "description": "Description of the property", + "type": "string" + }, + "default": { + "description": "Default value of the property", + "type": [ + "string", + "boolean", + "number" + ] + }, + "secure": { + "description": "Direct access from the javascript code of the application mashup component to this variable is disallowed if the value of this attribute is true", + "type": "boolean", + "default": false + }, + "multiuser": { + "description": "Whether to store a different value for each user", + "type": "boolean", + "default": false + } + } + }, + "mashup_tab": { + "description": "A mashup tab", + "type": "object", + "required": [ + "name", + "preferences", + "resources" + ], + "properties": { + "name": { + "type": "string" + }, + "title": { + "type": "string" + }, + "resources": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "name", + "vendor", + "version", + "title", + "position", + "rendering" + ], + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "vendor": { + "type": "string" + }, + "version": { + "$ref": "#/$defs/version" + }, + "title": { + "type": "string" + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "properties": { + "type": "object", + "default": {}, + "patternProperties": { + ".*": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "readonly": { + "type": "boolean", + "default": false + }, + "hidden": { + "type": "boolean", + "default": false + }, + "value": { + "type": [ + "string", + "boolean", + "number", + "null" + ] + } + } + } + } + }, + "preferences": { + "type": "object", + "default": {}, + "patternProperties": { + ".*": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "readonly": { + "type": "boolean", + "default": false + }, + "value": { + "type": [ + "string", + "boolean", + "number", + "null" + ] + } + } + } + } + }, + "rendering": { + "type": "object", + "required": [ + "width", + "height", + "layout" + ], + "properties": { + "fulldragboard": { + "type": "boolean" + }, + "minimized": { + "type": "boolean" + }, + "width": { + "$ref": "#/$defs/size" + }, + "height": { + "$ref": "#/$defs/size" + }, + "layout": { + "type": [ + "string", + "integer" + ] + }, + "relwidth": { + "type": "boolean" + }, + "relheight": { + "type": "boolean" + }, + "titlevisible": { + "type": "boolean" + } + } + }, + "position": { + "allOf": [ + { + "$ref": "#/$defs/Position2D" + } + ], + "type": "object", + "required": [ + "z" + ], + "properties": { + "anchor": { + "type": "string" + }, + "relx": { + "type": "boolean" + }, + "rely": { + "type": "boolean" + }, + "z": { + "type": [ + "number", + "string" + ] + } + } + } + } + } + } + } + }, + "mashup_param": { + "type": "object", + "required": [ + "name", + "type", + "value" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "readonly": { + "type": "boolean", + "default": false + }, + "default": { + "type": [ + "string", + "boolean", + "number" + ] + }, + "value": { + "type": [ + "string", + "boolean", + "number", + "null" + ] + }, + "required": { + "type": "boolean", + "default": false + } + } + }, + "Position2D": { + "type": "object", + "required": [ + "x", + "y" + ], + "properties": { + "x": { + "type": [ + "number", + "string" + ] + }, + "y": { + "type": [ + "number", + "string" + ] + } + } + }, + "js_files": { + "type": "array", + "items": { + "type": "string" + } + }, + "contact": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "wiring": { + "type": "object", + "required": [], + "properties": { + "version": { + "type": "string", + "default": "1.0" + }, + "inputs": { + "type": "array", + "default": [], + "items": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "actionlabel": { + "type": "string" + }, + "friendcode": { + "type": "string" + } + } + } + }, + "outputs": { + "type": "array", + "default": [], + "items": { + "type": "object", + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "friendcode": { + "type": "string" + } + } + } + } + } + }, + "wiring_mashup": { + "$comment": "extra wiring properties of mashups", + "type": "object", + "required": [], + "properties": { + "connections": { + "type": "array", + "default": [], + "items": { + "type": "object", + "required": [ + "source", + "target" + ], + "properties": { + "source": { + "allOf": [ + { + "$ref": "#/$defs/endpoint" + } + ] + }, + "target": { + "allOf": [ + { + "$ref": "#/$defs/endpoint" + } + ] + }, + "readonly": { + "type": "boolean", + "default": false + } + } + } + }, + "operators": { + "type": "object", + "default": {}, + "patternProperties": { + ".*": { + "type": "object", + "required": [ + "id", + "name", + "preferences" + ], + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "preferences": { + "type": "object", + "default": {}, + "patternProperties": { + ".*": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "readonly": { + "type": "boolean", + "default": false + }, + "hidden": { + "type": "boolean", + "default": false + }, + "value": { + "type": [ + "string", + "boolean", + "number", + "null" + ] + } + } + } + } + } + } + } + } + } + } + }, + "wiring_visualdescription": { + "type": "object", + "required": [], + "properties": { + "behaviours": { + "allOf": [ + { + "$ref": "#/$defs/visualdescription_behabiours" + } + ] + }, + "components": { + "allOf": [ + { + "$ref": "#/$defs/visualdescription_components" + } + ] + }, + "connections": { + "allOf": [ + { + "$ref": "#/$defs/visualdescription_connections" + } + ] + } + } + }, + "visualdescription_components": { + "type": "array", + "enum": [ + "operator", + "widget" + ], + "items": { + "type": "array", + "items": { + "type": "object", + "required": [], + "properties": { + "collapsed": { + "type": "boolean", + "default": false + }, + "endpoints": { + "type": "object", + "default": {}, + "properties": { + "source": { + "type": "array", + "items": { + "type": "string" + } + }, + "target": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "position": { + "allOf": [ + { + "$ref": "#/$defs/Position2D" + } + ] + } + } + } + } + }, + "visualdescription_connections": { + "type": "array", + "items": { + "type": "object", + "required": [ + "sourcename", + "targetname", + "sourcehandle", + "targethandle" + ], + "properties": { + "sourcename": { + "type": "string" + }, + "targetname": { + "type": "string" + }, + "sourcehandle": { + "type": [ + "string", + "object" + ], + "if": { + "type": "object" + }, + "then": { + "allOf": [ + { + "$ref": "#/$defs/Position2D" + } + ] + }, + "else": { + "enum": [ + "auto" + ] + } + }, + "targethandle": { + "type": [ + "string", + "object" + ], + "if": { + "type": "object" + }, + "then": { + "allOf": [ + { + "$ref": "#/$defs/Position2D" + } + ] + }, + "else": { + "enum": [ + "auto" + ] + } + } + } + } + }, + "visualdescription_behabiours": { + "default": { + "title": null, + "description": null, + "components": { + "operator": {}, + "widget": {} + }, + "connections": [] + }, + "type": "array", + "items": { + "type": "object", + "required": [ + "title", + "description" + ], + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "components": { + "allOf": [ + { + "$ref": "#/$defs/visualdescription_components" + } + ] + }, + "connections": { + "allOf": [ + { + "$ref": "#/$defs/visualdescription_connections" + } + ] + } + } + } + }, + "translations": { + "type": "object", + "default": {}, + "patternProperties": { + ".*": { + "type": "string" + } + } + }, + "endpoint": { + "type": "object", + "required": [ + "type", + "endpoint", + "id" + ], + "properties": { + "type": { + "type": "string" + }, + "endpoint": { + "type": "string" + }, + "id": { + "type": [ + "string", + "integer" + ] + } + } + }, + "size": { + "type": "string", + "pattern": "\\d+(\\.\\d+)?\\s*(px|%)?" + }, + "version": { + "type": "string", + "pattern": "([1-9]\\d*\\.|0\\.)*([1-9]\\d*|0)((a|b|rc)[1-9]\\d*)?(-dev.*)?" + }, + "name": { + "type": "string", + "pattern": "[^/]+" + } + } +} \ No newline at end of file diff --git a/src/wirecloud/commons/utils/wgt.py b/src/wirecloud/commons/utils/wgt.py index 1bf1b0470e..04582566f4 100644 --- a/src/wirecloud/commons/utils/wgt.py +++ b/src/wirecloud/commons/utils/wgt.py @@ -38,8 +38,8 @@ def __str__(self): class WgtFile(object): - - _template_filename = 'config.xml' + _possible_template_filenames = ['config.xml', 'config.json'] + _template_filename = None def __init__(self, _file): self._zip = zipfile.ZipFile(_file) @@ -49,6 +49,7 @@ def __init__(self, _file): raise ValueError('Invalid file name: %s', filename) if normalized_filename.startswith('/'): raise ValueError('Invalid absolute file name: %s', filename) + self._set_template_filename() @property def namelist(self): @@ -60,11 +61,18 @@ def get_underlying_file(self): def read(self, path): return self._zip.read(path) + def _set_template_filename(self): + for possible_template_file in self._possible_template_filenames: + if possible_template_file in self._zip.namelist(): + self._template_filename = possible_template_file + return + def get_template(self): try: - return self.read(self._template_filename) + template_file_content = self.read(self._template_filename) + return template_file_content except KeyError: - raise InvalidContents('Missing config.xml at the root of the zipfile (wgt)') + raise InvalidContents('Missing config.xml or config.json at the root of the zipfile (wgt)') def extract_file(self, file_name, output_path, recreate_=False): contents = self.read(file_name) @@ -147,13 +155,13 @@ def update_config(self, contents): new_fp = BytesIO() # Copy every file from the original zipfile to the new one - # excluding the config.xml file, that will be replaced - filename = 'config.xml' + # excluding the config file, that will be replaced + filename = self._template_filename with zipfile.ZipFile(new_fp, 'w') as zout: zout.comment = self._zip.comment # preserve the comment for item in self._zip.infolist(): - # Copy new config.xml contents + # Copy new config contents if item.filename == filename: zout.writestr(item, contents) # Copy original files diff --git a/src/wirecloud/platform/workspace/mashupTemplateGenerator.py b/src/wirecloud/platform/workspace/mashupTemplateGenerator.py index 224584ecd4..4df8b70ce0 100644 --- a/src/wirecloud/platform/workspace/mashupTemplateGenerator.py +++ b/src/wirecloud/platform/workspace/mashupTemplateGenerator.py @@ -180,12 +180,12 @@ def build_json_template_from_workspace(options, workspace, user): options['description'] = get_workspace_description(workspace) if 'authors' not in options: - options['authors'] = ({'name': str(user)},) + options['authors'] = [{'name': str(user)}] elif isinstance(options['authors'], str): options['authors'] = parse_contacts_info(options['authors']) if 'contributors' not in options: - options['contributors'] = () + options['contributors'] = [] elif isinstance(options['contributors'], str): options['contributors'] = parse_contacts_info(options['contributors']) @@ -252,6 +252,7 @@ def build_json_template_from_workspace(options, workspace, user): options['wiring']['operators'] = {} for operator_id, operator in wiring_status['operators'].items(): operator_data = { + 'id': operator_id, 'name': operator['name'], 'preferences': {}, } diff --git a/src/wirecloud/platform/workspace/views.py b/src/wirecloud/platform/workspace/views.py index 52d25a22b8..b6b181c7c2 100644 --- a/src/wirecloud/platform/workspace/views.py +++ b/src/wirecloud/platform/workspace/views.py @@ -483,12 +483,12 @@ def create(self, request, workspace_id): extra_files.append(('DESCRIPTION.md', BytesIO(options['longdescription'].encode('utf-8')))) options['longdescription'] = 'DESCRIPTION.md' - description = build_xml_template_from_workspace(options, workspace, request.user) + description = build_json_template_from_workspace(options, workspace, request.user) # Build mashup wgt file f = BytesIO() zf = zipfile.ZipFile(f, 'w') - zf.writestr('config.xml', description.encode('utf-8')) + zf.writestr('config.json', json.dumps(description, indent = 4)) for filename, extra_file in extra_files: zf.writestr(filename, extra_file.read()) for resource_info in options['embedded']: From 5a84ec2e9b3cc032f7fe64f35fb604365969e3a2 Mon Sep 17 00:00:00 2001 From: dmunoz Date: Thu, 4 Jul 2024 13:32:25 +0200 Subject: [PATCH 2/7] Support `code` preferences --- .../template/schemas/json_schema.schema.json | 169 ++++++++++-------- 1 file changed, 97 insertions(+), 72 deletions(-) diff --git a/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json b/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json index 0754ab72e0..9222a9f524 100644 --- a/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json +++ b/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json @@ -431,7 +431,8 @@ "boolean", "number", "password", - "list" + "list", + "code" ] }, "label": { @@ -469,59 +470,75 @@ "description": "Whether to store a different value for each user", "default": false, "type": "boolean" - }, - "if": { - "properties": { - "type": { - "enum": [ - "list" - ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "type": { + "const": "list" + } } - } - }, - "then": { - "required": [ - "options" - ], - "properties": { - "options": { - "description": "List of options for the preference", - "type": "array", - "items": { - "type": "object", - "required": [ - "value" - ], - "properties": { - "value": { - "description": "Value of the preference", - "type": [ - "string", - "boolean", - "number" - ] + }, + "then": { + "required": [ + "options" + ], + "properties": { + "options": { + "description": "List of options for the preference", + "type": "array", + "items": { + "type": "object", + "required": [ + "value" + ], + "properties": { + "value": { + "description": "Value of the preference", + "type": [ + "string", + "boolean", + "number" + ] + } } } } } + }, + "else": { + "description": "The value of the preference", + "properties": { + "value": { + "type": [ + "string", + "boolean", + "number", + "null" + ] + } + } } }, - "else": { - "description": "The value of the preference", - "required": [ - "value" - ], - "properties": { - "value": { - "type": [ - "string", - "boolean", - "number" - ] + { + "if": { + "properties": { + "type": { + "const": "code" + } + } + }, + "then": { + "properties": { + "language": { + "type": "string" + } } } } - } + ] }, "component_property": { "description": "The properties, that save persistent information about the component", @@ -1090,42 +1107,50 @@ "string", "object" ], - "if": { - "type": "object" - }, - "then": { - "allOf": [ - { - "$ref": "#/$defs/Position2D" + "allOf": [ + { + "if": { + "type": "object" + }, + "then": { + "allOf": [ + { + "$ref": "#/$defs/Position2D" + } + ] + }, + "else": { + "enum": [ + "auto" + ] } - ] - }, - "else": { - "enum": [ - "auto" - ] - } + } + ] }, "targethandle": { "type": [ "string", "object" ], - "if": { - "type": "object" - }, - "then": { - "allOf": [ - { - "$ref": "#/$defs/Position2D" + "allOf": [ + { + "if": { + "type": "object" + }, + "then": { + "allOf": [ + { + "$ref": "#/$defs/Position2D" + } + ] + }, + "else": { + "enum": [ + "auto" + ] } - ] - }, - "else": { - "enum": [ - "auto" - ] - } + } + ] } } } From e9e516c7d51f9f68632da3ccd7e84cd1455b3dce Mon Sep 17 00:00:00 2001 From: dmunoz Date: Thu, 4 Jul 2024 19:51:59 +0200 Subject: [PATCH 3/7] clean up schema --- .../commons/utils/template/parsers/json.py | 5 +- .../template/schemas/json_schema.schema.json | 318 ++++++++++++------ 2 files changed, 220 insertions(+), 103 deletions(-) diff --git a/src/wirecloud/commons/utils/template/parsers/json.py b/src/wirecloud/commons/utils/template/parsers/json.py index be9955cfdb..7052687180 100644 --- a/src/wirecloud/commons/utils/template/parsers/json.py +++ b/src/wirecloud/commons/utils/template/parsers/json.py @@ -19,6 +19,7 @@ # along with Wirecloud. If not, see . import json +from jsonschema.validators import Draft7Validator import os from django.utils.translation import ugettext as _ @@ -26,10 +27,10 @@ from wirecloud.commons.utils.template.base import is_valid_name, is_valid_vendor, is_valid_version, parse_contacts_info, TemplateParseException from wirecloud.commons.utils.translation import get_trans_index from wirecloud.platform.wiring.utils import get_wiring_skeleton, parse_wiring_old_version -from jsonschema import validate with open(os.path.join(os.path.dirname(__file__), '../schemas/json_schema.schema.json'), 'r') as JSONSCHEMA_FILE: JSONSCHEMA = json.load(JSONSCHEMA_FILE) + validator = Draft7Validator(JSONSCHEMA) class JSONTemplateParser(object): @@ -193,7 +194,7 @@ def _add_translation_index(self, value, **kwargs): self._info['translation_index_usage'][index].append(kwargs) def _init(self): - validate(self._info, JSONSCHEMA) + validator.validate(self._info, JSONSCHEMA) self._check_string_fields(('title', 'description', 'longdescription', 'email', 'homepage', 'doc', 'changelog', 'image', 'smartphoneimage', 'license', 'licenseurl', 'issuetracker')) self._check_contacts_fields(('authors', 'contributors')) self._check_integer_fields(('macversion', ), default = 1) diff --git a/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json b/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json index 9222a9f524..76470eadba 100644 --- a/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json +++ b/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json @@ -1,7 +1,7 @@ { - "$id": "https://example.com", + "$id": "https://raw.githubusercontent.com/Wirecloud/wirecloud/develop/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json", "$schema": "https://json-schema.org/draft-07/schema", - "title": "WireCloud Mashable Application Component Descriptions", + "title": "WireCloud Mashable Application Component Description", "type": "object", "required": [ "vendor", @@ -10,67 +10,70 @@ ], "properties": { "authors": { - "description": "Main developers of this mashable application component", - "type": [ - "array", - "string" - ], - "items": { - "$ref": "#/$defs/contact" - } + "description": "Main developers of this mashable application component.", + "allOf": [ + { + "$ref": "#/$defs/contacts" + } + ] }, "changelog": { - "description": "Relative path to a markdown file detailing the changes made to the mashable application component in each version", + "description": "Relative path to a markdown file detailing the changes made to the mashable application component in each version.", "type": "string" }, "contributors": { - "description": "Contributors of this mashable application component", - "type": [ - "array", - "string" - ], - "items": { - "$ref": "#/$defs/contact" - } + "description": "Contributors of this mashable application component.", + "allOf": [ + { + "$ref": "#/$defs/contacts" + } + ] }, "description": { - "description": "A brief textual description of the mashable application component", + "description": "A brief textual description of the mashable application component.", "type": "string" }, "doc": { - "description": "Absolute or template-relative URL of the widget documentation", + "description": "Absolute or template-relative URL of the widget documentation.", "type": "string" }, "email": { - "description": "E-mail address to get in touch with the developer(s)", - "type": "string" + "description": "E-mail address to get in touch with the developer(s).", + "type": "string", + "format": "email" }, "homepage": { - "description": "The url to the project homepage", + "description": "The url to the project homepage.", "type": "string" }, "image": { - "description": "Absolute or template-relative URL of the resource image for the catalog", + "description": "Absolute or template-relative URL of the resource image for the catalog.", "type": "string" }, "issuetracker": { - "description": "Absolute URL of the issue tracker for the mashable application component", + "description": "Absolute URL of the issue tracker for the mashable application component.", "type": "string" }, "license": { - "description": "Name of the license associated to the mashable application component", - "type": "string" + "description": "Name of the license associated to the mashable application component.", + "type": "string", + "examples": [ + "Apache 2.0", + "MIT", + "GPLv3", + "BSD" + ] }, "licenseurl": { - "description": "Absolute or template-relative URL of the full license document associated to the mashable application component", + "description": "Absolute or template-relative URL of the full license document associated to the mashable application component.", "type": "string" }, "longDescription": { - "description": "A detailed description of the mashable application component (using Markdown syntax by default)", + "description": "A detailed description of the mashable application component (using Markdown syntax by default).", "type": "string" }, "macversion": { - "description": "Version of the MACD specification used to describe the mashable application component", + "description": "Version of the MACD specification used to describe the mashable application component.", "default": 1, "enum": [ 1, @@ -79,11 +82,11 @@ "type": "integer" }, "name": { - "description": "Name of the mashable application component", + "description": "Name of the mashable application component.", "type": "string" }, "requirements": { - "description": "List of requirements for the mashable application component", + "description": "List of requirements for the mashable application component.", "required": [ "name" ], @@ -91,14 +94,29 @@ "items": { "properties": { "name": { - "description": "Name of the requirement", + "description": "Name of the requirement.", "type": "string" }, "type": { - "type": "string" + "description": "Type of the requirement. Currently only `feature` is supported.", + "type": "string", + "enum": [ + "feature" + ] } }, - "type": "object" + "additionalProperties": false, + "type": "object", + "examples": [ + { + "type": "feature", + "name": "StyledElements" + }, + { + "type": "feature", + "name": "DashboardManagement" + } + ] } }, "smartphoneimage": { @@ -107,11 +125,11 @@ }, "title": { "default": "", - "description": "Name used in the user interface for the widget. This field can be translated, therefore this fieldis not used to uniquely identify the widget", + "description": "Name used in the user interface for the widget. This field can be translated, therefore this field is not used to uniquely identify the widget.", "type": "string" }, "type": { - "description": "Type of the mashable application component", + "description": "Type of the mashable application component.", "enum": [ "mashup", "operator", @@ -120,11 +138,11 @@ "type": "string" }, "vendor": { - "description": "Name of the vendor of the mashable application component", + "description": "Name of the vendor of the mashable application component.", "type": "string" }, "version": { - "description": "Version of the mashable application component", + "description": "Version of the mashable application component.", "$ref": "#/$defs/version" } }, @@ -143,19 +161,21 @@ "then": { "properties": { "preferences": { - "description": "The user preferences, which may be changed through the platform interface", + "description": "The user preferences, which may be changed through the platform interface.", "type": "array", "items": { "$ref": "#/$defs/component_preference" } }, "properties": { + "description": "The user properties, which the component code might change. Also known as persistent variables.", "type": "array", "items": { "$ref": "#/$defs/component_property" } }, "wiring": { + "description": "Wiring of the component. It defines the inputs and outputs of the component.", "default": {}, "allOf": [ { @@ -180,7 +200,7 @@ "then": { "properties": { "contents": { - "description": "The contents of the widget", + "description": "The contents of the widget.", "type": "object", "required": [ "src" @@ -236,7 +256,8 @@ } } } - } + }, + "additionalProperties": false } } } @@ -256,9 +277,11 @@ ], "properties": { "widget_width": { + "description": "Width of the widget.", "$ref": "#/$defs/size" }, "widget_height": { + "description": "Height of the widget.", "$ref": "#/$defs/size" } } @@ -266,7 +289,7 @@ }, { "if": { - "oneOf": [ + "anyOf": [ { "properties": { "type": { @@ -289,12 +312,12 @@ "then": { "properties": { "js_files": { - "description": "List of scripts the operator is going to use", - "allOf": [ - { - "$ref": "#/$defs/js_files" - } - ] + "description": "List of javascript files the component will use.", + "type": "array", + "items": { + "description": "A javascript file.", + "type": "string" + } } } } @@ -310,30 +333,31 @@ "then": { "properties": { "preferences": { - "description": "The user preferences", + "description": "The user preferences.", "type": "object", "patternProperties": { ".*": { "type": "string", - "description": "A user preference" + "description": "A user preference." } } }, "tabs": { - "description": "List of mashup tabs", + "description": "List of mashup tabs.", "type": "array", "items": { "$ref": "#/$defs/mashup_tab" } }, "params": { - "description": "Mashup parameters", + "description": "Mashup parameters.", "type": "array", "items": { "$ref": "#/$defs/mashup_param" } }, "embedded": { + "description": "The list of embedded resources for this mashup.", "type": "array", "required": [ "vendor", @@ -357,8 +381,7 @@ "type": "string" } } - }, - "description": "The list of embedded resources for this mashup" + } }, "wiring": { "default": { @@ -382,7 +405,7 @@ "$ref": "#/$defs/wiring_mashup" } ], - "description": "Mashup wiring" + "description": "Mashup wiring." } } } @@ -404,7 +427,8 @@ "then": { "properties": { "entrypoint": { - "type": "string" + "type": "string", + "description": "The entrypoint of the component. (deprecated)" } } } @@ -412,7 +436,7 @@ ], "$defs": { "component_preference": { - "description": "The user preferences, which may be changed through the platform interface. This element consisting of one, several or even none preference sub-elements", + "description": "The user preferences, which may be changed through the platform interface. This element consisting of one, several or even none preference sub-elements.", "type": "object", "required": [ "name", @@ -420,11 +444,11 @@ ], "properties": { "name": { - "description": "Name of the preference", + "description": "Name of the preference.", "type": "string" }, "type": { - "description": "Type of the preference", + "description": "Type of the preference.", "type": "string", "enum": [ "text", @@ -436,15 +460,15 @@ ] }, "label": { - "description": "Label of the preference", + "description": "Label of the preference.", "type": "string" }, "description": { - "description": "Description of the preference", + "description": "Description of the preference.", "type": "string" }, "default": { - "description": "Default value of the preference", + "description": "Default value of the preference.", "type": [ "string", "boolean", @@ -452,22 +476,22 @@ ] }, "readOnly": { - "description": "Whether the preference is read-only", + "description": "Whether the preference is read-only.", "default": false, "type": "boolean" }, "secure": { - "description": "Direct access from the javascript code of the application mashup component to this variable is disallowed if the value of this attribute is true", + "description": "Direct access from the javascript code of the application mashup component to this variable is disallowed if the value of this attribute is true.", "default": false, "type": "boolean" }, "required": { - "description": "Whether the preference is required", + "description": "Whether the preference is required.", "default": false, "type": "boolean" }, "multiuser": { - "description": "Whether to store a different value for each user", + "description": "Whether to store a different value for each user.", "default": false, "type": "boolean" } @@ -487,7 +511,7 @@ ], "properties": { "options": { - "description": "List of options for the preference", + "description": "List of options for the preference.", "type": "array", "items": { "type": "object", @@ -496,7 +520,7 @@ ], "properties": { "value": { - "description": "Value of the preference", + "description": "Value of the preference.", "type": [ "string", "boolean", @@ -509,7 +533,7 @@ } }, "else": { - "description": "The value of the preference", + "description": "The value of the preference.", "properties": { "value": { "type": [ @@ -533,7 +557,12 @@ "then": { "properties": { "language": { - "type": "string" + "description": "Language the code editor should colorize and/or autocomplete for.", + "type": "string", + "examples": [ + "javascript", + "python" + ] } } } @@ -541,7 +570,7 @@ ] }, "component_property": { - "description": "The properties, that save persistent information about the component", + "description": "A property that saves persistent information about the component, also known as a persistent variable.", "type": "object", "required": [ "name", @@ -549,11 +578,11 @@ ], "properties": { "name": { - "description": "Name of the property", + "description": "Name of the property.", "type": "string" }, "type": { - "description": "Type of the property", + "description": "Type of the property.", "type": "string", "enum": [ "text", @@ -564,15 +593,15 @@ ] }, "label": { - "description": "Label of the property", + "description": "Label of the property.", "type": "string" }, "description": { - "description": "Description of the property", + "description": "Description of the property.", "type": "string" }, "default": { - "description": "Default value of the property", + "description": "Default value of the property.", "type": [ "string", "boolean", @@ -580,19 +609,19 @@ ] }, "secure": { - "description": "Direct access from the javascript code of the application mashup component to this variable is disallowed if the value of this attribute is true", + "description": "Direct access from the javascript code of the application mashup component to this variable is disallowed if the value of this attribute is true.", "type": "boolean", "default": false }, "multiuser": { - "description": "Whether to store a different value for each user", + "description": "Whether to store a different value for each user.", "type": "boolean", "default": false } } }, "mashup_tab": { - "description": "A mashup tab", + "description": "A mashup tab.", "type": "object", "required": [ "name", @@ -601,14 +630,18 @@ ], "properties": { "name": { - "type": "string" + "type": "string", + "description": "Name of the tab." }, "title": { - "type": "string" + "type": "string", + "description": "Title of the tab." }, "resources": { + "description": "List of resources contained in the tab.", "type": "array", "items": { + "description": "A resource contained in a tab.", "type": "object", "required": [ "id", @@ -766,6 +799,7 @@ } }, "mashup_param": { + "description": "A mashup parameter.", "type": "object", "required": [ "name", @@ -831,14 +865,11 @@ } } }, - "js_files": { - "type": "array", - "items": { - "type": "string" - } - }, "contact": { - "type": "object", + "type": [ + "object", + "string" + ], "required": [ "name" ], @@ -852,6 +883,24 @@ "url": { "type": "string" } + }, + "additionalProperties": false, + "examples": [ + { + "name": "John Doe", + "email": "john-doe@example.com", + "url": "http://example.com/johndoe" + }, + "John Doe (http://example.com/johndoe)" + ] + }, + "contacts": { + "type": [ + "array", + "string" + ], + "items": { + "$ref": "#/$defs/contact" } }, "wiring": { @@ -863,6 +912,7 @@ "default": "1.0" }, "inputs": { + "description": "List of inputs of the component. This component will be able to receive data from the inputs listed here.", "type": "array", "default": [], "items": { @@ -873,27 +923,51 @@ ], "properties": { "name": { + "description": "Name that will uniquely identify this input.", "type": "string" }, "type": { - "type": "string" + "description": "Type of the input. This field can only be set to `text` right now.", + "type": "string", + "enum": [ + "text" + ] }, "label": { + "description": "Label of the input. This field is used to show a human-readable and translatable name of the input.", "type": "string" }, "description": { + "description": "Text describing what is going to happen if an event arrives this input endpoint. This description is very important for the wiring process as the user needs this information for taking decisions on how to wire widgets/operators.", "type": "string" }, "actionlabel": { + "description": "Short text describing what is going to happen if an event is sent to this input endpoint. Other widgets will use this text in buttons, selection boxes, etc... allowing end users to select what to do (and the widget will send a event to the associated target endpoint).", "type": "string" }, "friendcode": { + "description": "Keyword used to tag the input endpoint, so it can be easily suggested valid conection during the wiring process.", "type": "string" } - } + }, + "examples": [ + { + "name": "input", + "type": "text" + }, + { + "name": "poiInput", + "type": "text", + "label": "Insert/Update PoI", + "description": "Insert or update a Point of Interest.", + "actionlabel": "Map Viewer Insert/Update PoI", + "friendcode": "poi poi-list" + } + ] } }, "outputs": { + "description": "List of outputs of the component. This component will be able to send data to the outputs listed here.", "type": "array", "default": [], "items": { @@ -904,21 +978,42 @@ ], "properties": { "name": { + "description": "Name that will uniquely identify this output.", "type": "string" }, "type": { - "type": "string" + "description": "Type of the output. This field can only be set to `text` right now.", + "type": "string", + "enum": [ + "text" + ] }, "label": { + "description": "Label of the output. This field is used to show a human-readable and translatable name of the output.", "type": "string" }, "description": { + "description": "Text describing what is going to happen if an event is sent to this output endpoint. This description is very important for the wiring process as the user needs this information for taking decisions on how to wire widgets/operators.", "type": "string" }, "friendcode": { + "description": "Keyword used to tag the output endpoint, so it can be easily suggested valid conection during the wiring process.", "type": "string" } - } + }, + "examples": [ + { + "name": "output", + "type": "text" + }, + { + "name": "poiOutput", + "type": "text", + "label": "PoI selected", + "description": "A PoI has been selected on the map", + "friendcode": "poi" + } + ] } } } @@ -1038,7 +1133,8 @@ } ] } - } + }, + "additionalProperties": false }, "visualdescription_components": { "type": "array", @@ -1081,7 +1177,8 @@ } ] } - } + }, + "additionalProperties": false } } }, @@ -1152,7 +1249,8 @@ } ] } - } + }, + "additionalProperties": false } }, "visualdescription_behabiours": { @@ -1193,19 +1291,29 @@ } ] } - } + }, + "additionalProperties": false } }, "translations": { + "description": "Translations of the component. Each key is a language code and the value is a translation object of the component elements in that language.", "type": "object", "default": {}, "patternProperties": { ".*": { - "type": "string" + "description": "Translation object of the component elements for a specified language.", + "type": "string", + "patternProperties": { + ".*": { + "description": "Translation of a component element for a specified language.", + "type": "string" + } + } } } }, "endpoint": { + "description": "A wiring endpoint of a component.", "type": "object", "required": [ "type", @@ -1225,7 +1333,8 @@ "integer" ] } - } + }, + "additionalProperties": false }, "size": { "type": "string", @@ -1233,7 +1342,14 @@ }, "version": { "type": "string", - "pattern": "([1-9]\\d*\\.|0\\.)*([1-9]\\d*|0)((a|b|rc)[1-9]\\d*)?(-dev.*)?" + "pattern": "([1-9]\\d*\\.|0\\.)*([1-9]\\d*|0)((a|b|rc)[1-9]\\d*)?(-dev.*)?", + "examples": [ + "1.0.0", + "1.0.0a1", + "1.0.0b2", + "1.0.0rc3", + "1.0.0-dev" + ] }, "name": { "type": "string", From 3938299f5b62564e617a6f28d20f2041be61835e Mon Sep 17 00:00:00 2001 From: dmunoz Date: Mon, 8 Jul 2024 11:56:43 +0200 Subject: [PATCH 4/7] fix translation and longdescription --- .../utils/template/schemas/json_schema.schema.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json b/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json index 76470eadba..3b093b32ba 100644 --- a/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json +++ b/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json @@ -68,7 +68,7 @@ "description": "Absolute or template-relative URL of the full license document associated to the mashable application component.", "type": "string" }, - "longDescription": { + "longdescription": { "description": "A detailed description of the mashable application component (using Markdown syntax by default).", "type": "string" }, @@ -144,6 +144,9 @@ "version": { "description": "Version of the mashable application component.", "$ref": "#/$defs/version" + }, + "translations": { + "$ref": "#/$defs/translations" } }, "allOf": [ @@ -875,12 +878,15 @@ ], "properties": { "name": { + "description": "Name of the contact.", "type": "string" }, "email": { + "description": "Email of the contact.", "type": "string" }, "url": { + "description": "URL of the contact.", "type": "string" } }, @@ -1302,7 +1308,7 @@ "patternProperties": { ".*": { "description": "Translation object of the component elements for a specified language.", - "type": "string", + "type": "object", "patternProperties": { ".*": { "description": "Translation of a component element for a specified language.", From a954b61817d7eff14f674cfa9d61b9a5e7c3ff99 Mon Sep 17 00:00:00 2001 From: dmunoz Date: Wed, 18 Sep 2024 19:20:16 +0200 Subject: [PATCH 5/7] update jsonschema adding screenSizes definition --- .../template/schemas/json_schema.schema.json | 171 +++++++++++------- 1 file changed, 110 insertions(+), 61 deletions(-) diff --git a/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json b/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json index 3b093b32ba..bc698caa89 100644 --- a/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json +++ b/src/wirecloud/commons/utils/template/schemas/json_schema.schema.json @@ -409,6 +409,20 @@ } ], "description": "Mashup wiring." + }, + "screenSizes": { + "description": "List of screen sizes supported by the mashup.", + "default": [], + "items": { + "$ref": "#/$defs/mashup_screenSize" + }, + "type": "array" + }, + "layout": { + "type": [ + "string", + "integer" + ] } } } @@ -623,6 +637,36 @@ } } }, + "mashup_screenSize": { + "properties": { + "id": { + "minimum": 0, + "type": "integer" + }, + "moreOrEqual": { + "minimum": 0, + "type": "integer" + }, + "lessOrEqual": { + "minimum": -1, + "type": "integer" + }, + "rendering": { + "$ref": "#/$defs/mashup_rendering" + }, + "position": { + "$ref": "#/$defs/mashup_position" + } + }, + "required": [ + "id", + "moreOrEqual", + "lessOrEqual", + "rendering", + "position" + ], + "type": "object" + }, "mashup_tab": { "description": "A mashup tab.", "type": "object", @@ -732,69 +776,10 @@ } }, "rendering": { - "type": "object", - "required": [ - "width", - "height", - "layout" - ], - "properties": { - "fulldragboard": { - "type": "boolean" - }, - "minimized": { - "type": "boolean" - }, - "width": { - "$ref": "#/$defs/size" - }, - "height": { - "$ref": "#/$defs/size" - }, - "layout": { - "type": [ - "string", - "integer" - ] - }, - "relwidth": { - "type": "boolean" - }, - "relheight": { - "type": "boolean" - }, - "titlevisible": { - "type": "boolean" - } - } + "$ref": "#/$defs/mashup_rendering" }, "position": { - "allOf": [ - { - "$ref": "#/$defs/Position2D" - } - ], - "type": "object", - "required": [ - "z" - ], - "properties": { - "anchor": { - "type": "string" - }, - "relx": { - "type": "boolean" - }, - "rely": { - "type": "boolean" - }, - "z": { - "type": [ - "number", - "string" - ] - } - } + "$ref": "#/$defs/mashup_position" } } } @@ -847,6 +832,70 @@ } } }, + "mashup_rendering": { + "type": "object", + "required": [ + "width", + "height" + ], + "properties": { + "fulldragboard": { + "type": "boolean" + }, + "minimized": { + "type": "boolean" + }, + "width": { + "$ref": "#/$defs/size" + }, + "height": { + "$ref": "#/$defs/size" + }, + "layout": { + "type": [ + "string", + "integer" + ] + }, + "relwidth": { + "type": "boolean" + }, + "relheight": { + "type": "boolean" + }, + "titlevisible": { + "type": "boolean" + } + } + }, + "mashup_position": { + "allOf": [ + { + "$ref": "#/$defs/Position2D" + } + ], + "type": "object", + "required": [ + "z" + ], + "properties": { + "anchor": { + "type": "string" + }, + "relx": { + "type": "boolean" + }, + "rely": { + "type": "boolean" + }, + "z": { + "type": [ + "number", + "string" + ] + } + } + }, "Position2D": { "type": "object", "required": [ From bc7bcf47a83f579ee25ae8ef814bb7030f1b330a Mon Sep 17 00:00:00 2001 From: dmunoz Date: Wed, 18 Sep 2024 19:25:53 +0200 Subject: [PATCH 6/7] change config file name to macconfig.json --- src/wirecloud/commons/utils/wgt.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wirecloud/commons/utils/wgt.py b/src/wirecloud/commons/utils/wgt.py index 04582566f4..16716afed9 100644 --- a/src/wirecloud/commons/utils/wgt.py +++ b/src/wirecloud/commons/utils/wgt.py @@ -38,7 +38,7 @@ def __str__(self): class WgtFile(object): - _possible_template_filenames = ['config.xml', 'config.json'] + _possible_template_filenames = ['config.xml', 'macconfig.json'] _template_filename = None def __init__(self, _file): @@ -72,7 +72,7 @@ def get_template(self): template_file_content = self.read(self._template_filename) return template_file_content except KeyError: - raise InvalidContents('Missing config.xml or config.json at the root of the zipfile (wgt)') + raise InvalidContents('Missing config.xml or macconfig.json at the root of the zipfile (wgt)') def extract_file(self, file_name, output_path, recreate_=False): contents = self.read(file_name) From 9a404e80817c7735f7034d116ee5e89fbe774915 Mon Sep 17 00:00:00 2001 From: dmunoz Date: Wed, 18 Sep 2024 19:57:50 +0200 Subject: [PATCH 7/7] Update config file name in WorkspacePublisherEntry --- src/wirecloud/platform/workspace/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wirecloud/platform/workspace/views.py b/src/wirecloud/platform/workspace/views.py index b6b181c7c2..30fab41a30 100644 --- a/src/wirecloud/platform/workspace/views.py +++ b/src/wirecloud/platform/workspace/views.py @@ -488,7 +488,7 @@ def create(self, request, workspace_id): # Build mashup wgt file f = BytesIO() zf = zipfile.ZipFile(f, 'w') - zf.writestr('config.json', json.dumps(description, indent = 4)) + zf.writestr('macconfig.json', json.dumps(description, indent = 4)) for filename, extra_file in extra_files: zf.writestr(filename, extra_file.read()) for resource_info in options['embedded']: