From 36640f7742f0a52f3422f002589a6c0f2f079cf7 Mon Sep 17 00:00:00 2001
From: crose <carsten.rose@math.uzh.ch>
Date: Fri, 22 Feb 2019 16:54:36 +0100
Subject: [PATCH] First REST implementation with GET,POST,PUT,DELETE and token
 authorization.

---
 extension/Documentation/Manual.rst       | 102 ++++++++++++++++++++---
 extension/Source/api/rest.php            |   8 ++
 extension/Source/core/QuickFormQuery.php |   5 +-
 3 files changed, 100 insertions(+), 15 deletions(-)

diff --git a/extension/Documentation/Manual.rst b/extension/Documentation/Manual.rst
index 50993de54..ee11a7026 100644
--- a/extension/Documentation/Manual.rst
+++ b/extension/Documentation/Manual.rst
@@ -7438,7 +7438,7 @@ GET - Read
 
     List: ``curl -X GET "http://localhost/qfq/typo3conf/ext/qfq/Source/api/rest.php/person/``
 
-    Record with id=123: ``curl -X GET "http://localhost/qfq/typo3conf/ext/qfq/Source/api/rest.php/person/123``
+    Data (id=123): ``curl -X GET "http://localhost/qfq/typo3conf/ext/qfq/Source/api/rest.php/person/123``
 
 POST - Create new record
     The QFQ form defines wich columns will be written in which table. Most of QFQ Form functionality can be used. Example:
@@ -7455,11 +7455,9 @@ DELETE - Delete a record
 
     ``curl -X DELETE "http://localhost/qfq/typo3conf/ext/qfq/Source/api/rest.php/person/123"``
 
-All data is exported in JSON notation.
+All data will imported / exported in JSON notation.
 
-To define a QFQ form becomes a REST form by enable one or more of:
-
-Form: Access > Permit REST: get / insert / update / delete
+Any QFQ form becomes a REST form via:  ``Form > Access > Permit REST: get / insert / update / delete``
 
 Endpoint
 --------
@@ -7513,7 +7511,9 @@ list
     A list of records will be exported.  Defined via 'form.parameter.restSqlList'. This mode is selected if there is no
     id or id=0.
 
-There are  *no* FormElements.
+.. note:
+
+    There are  *no* native-FormElements necessary or loaded. Action FormElements will be processed.
 
 To simplify access to id parameter of the URI, a mapping is possible via 'form.parameter.restParam'.
 E.g. `restParam=pId,adrId` with example d) makes `{{pId:C}}=123` and `{{adrId:C}}=45`. The order of variable
@@ -7548,7 +7548,7 @@ Form.parameter:
 +-------------------+----------------------------------------------------------------------------------+
 | restParam         | Optional. CSV list of variable names. E.g.: ``restParam=pId,adrId``              |
 +-------------------+----------------------------------------------------------------------------------+
-| restToken         | Optional. User defined string or dynamic token (see below).                      |
+| restToken         | Optional. User defined string or dynamic token (see `restAuthorization`_).       |
 +-------------------+----------------------------------------------------------------------------------+
 
 .. note:
@@ -7571,19 +7571,96 @@ Form:
 +-------------------+------------------------------------------------------------------------------+
 | Permit REST       | *insert* Mandatory. The form can be loaded in REST mode.                     |
 +-------------------+------------------------------------------------------------------------------+
-| id                | Missing or '0'.
+| id                | Missing or '0'.                                                              |
++-------------------+------------------------------------------------------------------------------+
+
+Form.parameter:
+
++-------------------+----------------------------------------------------------------------------------+
+| Attribute         | Description                                                                      |
++===================+==================================================================================+
+| restParam         | Optional. CSV list of variable names. E.g.: ``restParam=pId,adrId``              |
++-------------------+----------------------------------------------------------------------------------+
+| restToken         | Optional. User defined string or dynamic token (see `restAuthorization`_).       |
++-------------------+----------------------------------------------------------------------------------+
+
+FormElement:
+
+* For each column to save one FormElement with ``FE.name=<column>`` is necessary.
+* A regular QFQ form can be used as REST Post endpoint
+
 
 PUT - Update
 ------------
 
+Form:
+
++-------------------+------------------------------------------------------------------------------+
+| Attribute         | Description                                                                  |
++===================+==============================================================================+
+| name              | *<level>* Mandatory. Level name (Endpoint) in URI.                           |
++-------------------+------------------------------------------------------------------------------+
+| table             | Mandatory. Name of the primary table                                         |
++-------------------+------------------------------------------------------------------------------+
+| Permit REST       | *update* Mandatory. The form can be loaded in REST mode.                     |
++-------------------+------------------------------------------------------------------------------+
+| id                | >0                                                                           |
++-------------------+------------------------------------------------------------------------------+
+
+Form.parameter:
+
++-------------------+----------------------------------------------------------------------------------+
+| Attribute         | Description                                                                      |
++===================+==================================================================================+
+| restParam         | Optional. CSV list of variable names. E.g.: ``restParam=pId,adrId``              |
++-------------------+----------------------------------------------------------------------------------+
+| restToken         | Optional. User defined string or dynamic token (see `restAuthorization`_).       |
++-------------------+----------------------------------------------------------------------------------+
+
+FormElement:
+
+* For each column to save one FormElement with ``FE.name=<column>`` is necessary.
+* A regular QFQ form can be used as REST Post endpoint
+
 DELETE - Delete
 ---------------
 
+Form:
+
++-------------------+------------------------------------------------------------------------------+
+| Attribute         | Description                                                                  |
++===================+==============================================================================+
+| name              | *<level>* Mandatory. Level name (Endpoint) in URI.                           |
++-------------------+------------------------------------------------------------------------------+
+| table             | Mandatory. Name of the primary table                                         |
++-------------------+------------------------------------------------------------------------------+
+| Permit REST       | *delete* Mandatory. The form can be loaded in REST mode.                     |
++-------------------+------------------------------------------------------------------------------+
+| id                | >0                                                                           |
++-------------------+------------------------------------------------------------------------------+
+
+Form.parameter:
+
++-------------------+----------------------------------------------------------------------------------+
+| Attribute         | Description                                                                      |
++===================+==================================================================================+
+| restParam         | Optional. CSV list of variable names. E.g.: ``restParam=pId,adrId``              |
++-------------------+----------------------------------------------------------------------------------+
+| restToken         | Optional. User defined string or dynamic token (see `restAuthorization`_).       |
++-------------------+----------------------------------------------------------------------------------+
+
+.. note:
+
+    There are  *no* native-FormElements necessary - but might exist for dependent records to delete. Action FormElements
+    will be processed.
+
+
+.. _`restAuthorization`:
 
 Authorization
 -------------
 
-A QFQ form is only acessible via REST API, if ``Form.permitREST`` enables the HTTP Method (get, post, put, delete)
+A QFQ form is only acessible via REST API, if ``Form.permitRest`` enables on of the HTTP Method: **get, post, put, delete**
 
 ``Permit New`` or ``Permit Edit`` don't apply to QFQ forms called via REST.
 
@@ -7591,8 +7668,11 @@ A QFQ form is only acessible via REST API, if ``Form.permitREST`` enables the HT
 
     By default, the REST API is public accessible.
 
-If this is not wished, HTTP AUTH might be used (configured via webserver) or the
-QFQ internal 'HTTP header token based authorization'.
+If this is not wished:
+
+* HTTP AUTH might be used (configured via webserver)
+* Any other webserver based access restriction method
+* or the QFQ internal 'HTTP header token based authorization'.
 
 Token based authorization
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/extension/Source/api/rest.php b/extension/Source/api/rest.php
index 5444ad7e6..ff99752e5 100644
--- a/extension/Source/api/rest.php
+++ b/extension/Source/api/rest.php
@@ -37,6 +37,7 @@ try {
             case REQUEST_METHOD_GET:
                 $status = HTTP_200_OK;
                 break;
+
             case REQUEST_METHOD_POST:
                 if ($id != 0) {
                     throw new UserFormException(json_encode([ERROR_MESSAGE_TO_USER => "Forbidden: id>0 with HTTP method $method",
@@ -48,6 +49,7 @@ try {
                 $data = json_decode(file_get_contents('php://input'), true);
                 $status = HTTP_201_CREATED;
                 break;
+
             case REQUEST_METHOD_PUT:
                 if ($id == 0) {
                     throw new UserFormException(json_encode([ERROR_MESSAGE_TO_USER => "Forbidden: id==0 with HTTP method $method",
@@ -58,6 +60,7 @@ try {
                 $data = json_decode(file_get_contents('php://input'), true);
                 $status = HTTP_200_OK;
                 break;
+
             case REQUEST_METHOD_DELETE:
                 if ($id == 0) {
                     throw new UserFormException(json_encode([ERROR_MESSAGE_TO_USER => "Forbidden: id==0 with HTTP method $method",
@@ -67,7 +70,12 @@ try {
                 }
                 $status = HTTP_200_OK;
                 break;
+
             default:
+                throw new UserFormException(json_encode([ERROR_MESSAGE_TO_USER => 'Unsupported/unknown HTTP request method',
+                    ERROR_MESSAGE_SUPPORT => 'HTTP Code: ' . $method,
+                    ERROR_MESSAGE_HTTP_STATUS => HTTP_403_METHOD_NOT_ALLOWED
+                ]), ERROR_UNKNOWN_MODE);
                 break;
         }
 
diff --git a/extension/Source/core/QuickFormQuery.php b/extension/Source/core/QuickFormQuery.php
index c3e2fbe4e..a514d4bbf 100644
--- a/extension/Source/core/QuickFormQuery.php
+++ b/extension/Source/core/QuickFormQuery.php
@@ -1492,10 +1492,7 @@ class QuickFormQuery {
                     break;
 
                 default:
-                    throw new UserFormException(json_encode([ERROR_MESSAGE_TO_USER => 'Unsupported/unknown HTTP request method',
-                        ERROR_MESSAGE_SUPPORT => 'HTTP Code: ' . $method,
-                        ERROR_MESSAGE_HTTP_STATUS => HTTP_403_METHOD_NOT_ALLOWED
-                    ]), ERROR_UNKNOWN_MODE);
+                    throw new CodeException('This code should never be reached', ERROR_CODE_SHOULD_NOT_HAPPEN);
             }
 
         } else {
-- 
GitLab