Repository: OpenEnergyPlatform/oeplatform

Issue:
API for adding meta data
Can we also upload meta data via the api? Currently, it only seems to be possible on the platform via forms.


Discussion:
API and dialect don't support uploading metadata yet, unfortunately. Implementation is high priority.
"Implement API-support for metadata" - User Feedback
RequirementSpecificationID=17

Resolving patch:
diff --git a/api/urls.py b/api/urls.py
--- a/api/urls.py
+++ b/api/urls.py
@@ -35,6 +35,10 @@
         views.Rows.as_view(),
         {"action": "new"},
     ),
+    url(
+        r"^v0/schema/(?P<schema>[\w\d_\s]+)/tables/(?P<table>[\w\d_\s]+)/metadata$",
+        views.Metadata.as_view()
+    ),
     url(
         r"^v0/advanced/search",
         views.create_ajax_handler(
diff --git a/api/views.py b/api/views.py
--- a/api/views.py
+++ b/api/views.py
@@ -24,6 +24,7 @@
 from api.error import APIError
 from api.helpers.http import ModHttpResponse
 from dataedit.models import Table as DBTable
+from dataedit.views import load_metadata_from_db, save_metadata_as_table_comment
 from oeplatform.securitysettings import PLAYGROUNDS, UNVERSIONED_SCHEMAS
 
 logger = logging.getLogger("oeplatform")
@@ -760,6 +761,23 @@ def __get_rows(self, request, data):
         actions._execute_sqla(query, cursor)
 
 
+class Metadata(APIView):
+    @api_exception
+    def get(self, request, schema, table):
+        schema, table = actions.get_table_name(schema, table, restrict_schemas=False)
+        metadata = load_metadata_from_db(schema=schema, table=table)
+        response = {'metadata': metadata}
+        return stream(data=response)
+
+    @api_exception
+    @require_write_permission
+    def post(self, request, schema, table):
+        schema, table = actions.get_table_name(schema, table, restrict_schemas=False)
+        metadata = request.data['metadata']
+        save_metadata_as_table_comment(schema=schema, table=table, metadata=metadata)
+        response = {'status': 'ok'}
+        return stream(data=response)
+
 class Session(APIView):
     def get(self, request, length=1):
         return request.session["resonse"]
diff --git a/dataedit/views.py b/dataedit/views.py
--- a/dataedit/views.py
+++ b/dataedit/views.py
@@ -923,29 +923,13 @@ def post(self, request, schema, table):
         columns = actions.analyze_columns(schema, table)
 
         comment = read_metadata_from_post(request.POST, schema, table)
+        save_metadata_as_table_comment(schema, table, metadata=comment)
 
-        engine = actions._get_engine()
-        conn = engine.connect()
-        trans = conn.begin()
-        try:
-            conn.execute(
-                sqla.text(
-                    "COMMENT ON TABLE {schema}.{table} IS :comment ;".format(
-                        schema=schema, table=table
-                    )
-                ),
-                comment=json.dumps(comment),
-            )
-        except Exception as e:
-            raise e
-        else:
-            trans.commit()
-        finally:
-            conn.close()
         return redirect(
             "/dataedit/view/{schema}/{table}".format(schema=schema, table=table)
         )
 
+
     name_pattern = r"[\w\s]*"
 
     def loadName(self, name):
@@ -988,6 +972,35 @@ def _load_col_list(self, request, columns):
         ]
 
 
+def save_metadata_as_table_comment(schema, table, metadata):
+    """Save metadata as comment string on a database table
+    :param schema (string):
+    :param table (string):
+    :param metadata: structured data according to metadata specifications
+    """
+    # TODO: validate metadata!
+    # metadata = validate(metadata)
+
+    engine = actions._get_engine()
+    conn = engine.connect()
+    trans = conn.begin()
+    try:
+        conn.execute(
+            sqla.text(
+                "COMMENT ON TABLE {schema}.{table} IS :comment ;".format(
+                    schema=schema, table=table
+                )
+            ),
+            comment=json.dumps(metadata),
+        )
+    except Exception as e:
+        raise e
+    else:
+        trans.commit()
+    finally:
+        conn.close()
+
+
 class PermissionView(View):
     """ This method handles the GET requests for the main page of data edit.
         Initialises the session data (if necessary)


Test patch: