⟵ hearthere ⟶
  • Quick start
  • Install MIT
  • Install PRO
  • Updating
  • Optimization
  • Update v4-v6
  • Backups
  • Console utility bin/totum
  • Basics for users
  • Interface and Layout
  • Tables and their parameters
  • Prefilter
  • Fields and their parameters
  • Syntax
  • Code, actions, formatting
  • Relational relationships
  • Calculation order and calculation units
  • Auto-complete calculations and timing
  • Duplicate rows and cycles
  • Comparisons
  • Functions
  • Debugging
  • Print and CSV
  • API
  • REMOTES
  • Remotes
  • Module remotes
  • PRO Paths in Remotes
  • Shadow Hosts
  • PRO JSON
  • Connection
  • Incoming JSON
  • Returned JSON
  • Example of JSON-API Call in PHP
  • Own API module
  • API Module in PHP
  • Database
  • Direct Entry into pgsql
  • Roles and users
  • Notifications
  • Scheduled Actions
  • System tables
  • Trees
  • Anonymous tables
  • External Forms
  • Exporting and importing tables
  • [PRO] MeiliSearch
  • [PRO] Databases
  • [PRO] Custom CSS
  • [PRO] Custom docs
  • [PRO] LDAP AD
  • [PRO] File versions
  • [PRO] List-unsubscribe
  • [PRO] Dynamic fields
  • [PRO] Only Office
  • [PRO] Auth Tokens
  • [PRO] 2FA
  • [PRO] Superlang
  • [PRO] Daemons
  • [PRO] Profiler
  • Connecting functions
  • [SRV] Installation and Connection
  • [SRV] Export, PDF, Upload, and Preview
  • [SRV] XLSX/DOCX Generators
  • API interaction

    REMOTES

    Remotes

    The ability to execute code within Totum by calling an external script to the Remotes address.

    Configured through the table System tables — API — Remotes.

    The call is made by addressing host/Remotes/name_action.

    Module remotes

    Access to the module is done via the address host/Remotes/name_action, where name_action is the name in the Remotes table.

    name_action must exactly match in the remotes table and in the request. The request host/Remotes/name_action/ (with / at the end) implies that in the remotes table, name will also be specified with / at the end.

    For the code from the line in Remotes to be executed, the Enabled checkbox must be true and the remotes_user user must be filled in.

    You can select a dynamic user, in which case the user id must be passed in the GET variable ttm_user with the id of the user in the system from whom this remote should be executed.

    The code from code will be executed on behalf of the user specified in remotes_user.

    Access can be via GET or POST. The following variables will be passed to code during execution:

    • $#getrow from the variables passed in GET.

    • $#postrow from the variables passed in POST when using application/x-www-form-urlencoded or multipart/form-data in the request's HTTP Content-Type header.

    • $#inputstring or null — raw data from the request body when POST is sent in raw-data.

    • $#headersrow from the HTTP request headers.

    • $#remoteIpip of the incoming request.

    • $#method — available in PRO — contains the request method.

    • $#path — available in PRO — contains a list of elements from the incoming request path.

    The response is returned depending on the Return setting:

    • success/error — returns success, or error if there were errors during execution. The error text is not displayed.

    • 200/500 — similar to success/error, but returns the server response code in the headers.

    • json — the script's response is converted to JSON. If an error occurs, {"error":"Error text"} is returned.

    • string — the script's response is returned in the response body without processing.

    • headers + body — the script's response is expected to be a row with keys headers — sent as HTTP response headers and body — output in the response body.

      • the headers key should contain a list of headers or a row. If a row, each line will be formatted as key + ':' + value.
      • only the specified headers will be replaced

    PRO Paths in Remotes

    In PRO, the path field can be activated — in this case, the specified name becomes a priority.

    If there are multiple remotes using the same path with different endings — they will be inactive:

    • some_name + #path = true — enabling path makes this remote the main one. A request to .../Remotes/some_name/ will also be processed with an empty $#path variable.

    • some_name/action/param — if there is a remote with such a path, its line will become inactive. If a request comes in on such a path, the remote in the some_name line + #path = true will be executed.

    When the path parameter is enabled, all request levels will be passed to the $#path variable as a list, maintaining the sequence. That is, for a request .../Remotes/some_name/action/param, the variable will contain a list of two values: ["action","param"].

    Shadow Hosts

    If you need to hide the main host of your system when using Remotes, JSON-API, anonymous tables, or forms, you should use shadow-host.

    1. You need to address the DNS of the host to the same server where Totum is hosted.

    2. Open the nginx settings at /etc/nginx/sites-available/totum.online.conf and explicitly specify the main domain in the ssl and 80 port sections in the server_name parameter: server_name _; —› server_name YOUR_MAIN_DOMAIN;. Save and restart nginx.

    3. Copy the main domain config and specify the additional domain in the ssl and 80 port sections.

    4. Obtain an SSL certificate for the additional domain:

    certbot certonly --dry-run -d YOUR_ADDITIONAL_DOMAIN.ZONE
    

    If --dry-run passes then

    certbot certonly -d YOUR_DOMAIN.ZONE
    
    1. Specify the certificate address in the additional nginx config.

    2. Activate the config:

    ln -s /etc/nginx/sites-available/YOUR_ADDITIONAL_DOMAIN.conf /etc/nginx/sites-enabled/YOUR_ADDITIONAL_DOMAIN.conf
    
    1. Restart nginx.

    2. Open the Totum config and add the shadow-host section:

    nano /home/totum/totum-mit/Conf.php
    
    /***getHiddenHosts***/
        public function getHiddenHosts():array {
            return array ('hidden.ttmapp.ru' => array (
                'An' => true,
                'Remotes' => true,
                'Json' => true,
                'Forms' => true,
                ),
            );
        }
    /***getHiddenHostsEnd***/
    
    1. You can specify different hosts for different modules.

    2. For shadow-host, you can set a custom language

    /***getHiddenHosts***/
        public function getHiddenHosts():array {
            return array ('hidden.ttmapp.ru' => array (
                'An' => ["lang"=>"es"],
                ),
            );
        }
    /***getHiddenHostsEnd***/
    
    // In this case, only Anonymous tables in Spanish will work on hidden.ttmapp.ru
    

    PRO JSON

    Only in PRO-version

    Connection

    Access to the API is done via POST at the address http(s)://domain.ru/Json/.

    If only the auth and remotes sections are being called, specifying the path to the table is not necessary — access is done at the address http(s)://domain.ru/Json/

    In case you need to work with a table using the import/export/recalculate sections, the table is specified as:

    To connect to the API, a user with the api interface must be created in the user table. The user must have the necessary permissions for the table.

    The login and password of this user must be passed in the auth section of the incoming JSON.

    {
    "auth": {
        "login": "json",
        "password": "1111"
      }
    }
    

    Incoming JSON

    The incoming JSON is passed in the body of a POST request.

    The mandatory auth section contains the login and password.

    Access is granted to a user with the api interface if they have access to the called table. The access logic in cycles cycles_access_type does not apply.

    To manipulate a field through the API, the field must have the Show in API option enabled, and if there are restrictions in Visible to roles in API, the role of the api-user making the connection must be specified.

    To modify a field through the API, the field must have the Editable in API option enabled, and if there are restrictions in Editing in API available to roles, the role from which the connection is made must be specified.

    • import — the section is responsible for making changes to the table (possibly, if the user has a role with editing permissions for this table). Restrictions that may be set for the role in the prefilter in the API do not apply to changes! Therefore, for security purposes, carefully set permissions for roles in Editing in API available to roles. If you want to add row-level restrictions, do so through errorExeption.

      • footer and header — you can change the values of the header and footer fields through the corresponding sections by passing "name": new_value.

        • __clearsreset values to calculated ones by passing the name of the fields.

        • __pinspin values by passing the name of the fields.

      {
        "import": {
          "header": {
            "h_title": "Change Header"
          }
        }
      }
      
      {
        "import": {
          "footer": {
            "__clears": [
              "f_field",
              "f_field2"
            ]
          }
        }
      }
      
      {
        "import": {
          "footer": {
            "__pins": [
              "f_field",
              "f_field2"
            ]
          }
        }
      }
      
      • rows — section for modifying rows by their id.

        • modify — change field values. Passed as an object with the row id as the key and values: field name, value "2": {"row_field": new value} and/or a list of fields in __pins, __clears to pin/unpin values.

        • add — list of rows to be added containing field names and their values for each added row.

        • remove — list of ids of rows to be deleted.

        {
          "rows": {
            "modify": {
              "2": {
                "name_field": "new value",
                "__pins": [
                  "name_field_pin"
                ]
              },
              "3": {
                "name_field": "new value"
              }
            },
            "add": [
              {
                "name_field": "added_value_in_row1"
              },
              {
                "name_field": "added_value_in_row2"
              }
            ],
            "remove": []
          }
        }
        
      • rows-set-where — modify/add/delete rows in the row part of the table based on conditions. Multiple different changes based on different conditions can be passed in one request.

        • set — contains data for modification in the format "name": new_value, and/or field names in __pins and __clear if necessary.

        • where — list of conditions:

          • field — field name by which the selection will be made. The field by which the selection is made is not sensitive to Show in API.
          • value — comparison value.
          • operator — comparison operator.
        {
          "import": {
            "rows-set-where": [
              {
                "where": [
                  {
                    "field": "id",
                    "value": "test",
                    "operator": "="
                  }
                ],
                "set": {
                  "test": true,
                  "__pins": [
                    "some_field_name"
                  ]
                }
              }
            ]
          }
        }
        
    • recalculate — accepts a list of conditions for selecting rows for recalculation in simple tables. In calculated tables, this section may not be called — recalculation occurs each time the table is accessed through the API.

      • field — field name by which the selection will be made. The field by which the selection is made is not sensitive to Show in API.
      • operator — comparison operator.
      • value — comparison value.
    {
      "recalculate": [
        {
          "field": "id",
          "operator": "=",
          "value": [
            1,
            2,
            3
          ]
        }
    }
    
    • remotes — section for invoking executable constructs from the ttm__remotes table.

      • name — name from the ttm__remotes table. The remote row should have the user selected, who is specified in the auth section, in the API user field, and the checkbox in Enabled should be checked.
      • data — information to be passed to the $#data parameter of the remote code.
      {
        "remotes": [
          {"name":"remote1", "data": {"var1": 1, "var2": [1,2,3]}},
          {"name":"remote2", "data": {"var1": 2, "var2": [3,2,5]}}
        ]
      }
      
    • export — section for managing return values. Restrictions that can be set for role in the prefilter apply in the API for export! The prefilter field must be available in Show in API and must have permission in Visible to roles in API.

      • fields — list of fields to return.

      • filters — specified filter values. Filters are calculated similarly to the web version. Selection by id without prefilter by id is available. If the API has a prefilter prohibiting the display of a specific row by id, it will not be shown.

      {
        "export": {
          "fields": [
            "id",
            "some_field_name"
          ],
          "filters": {
            "fl_filter": [
              "value1",
              "value2",
              "value3"
            ],
            "id": [
              2
            ]
          }
        }
      }
      

    Example of incoming JSON:

    {
      "export": {
        "fields": [
          "id",
          "some_field_name"
        ],
        "filters": {
          "id": [
            1,
            2,
            3
          ]
        }
      },
      "auth": {
        "login": "json",
        "password": "1111"
      },
      "import": {
        "rows-set-where": [
          {
            "where": {
              "field": "id",
              "value": "test",
              "operator": "="
            },
            "set": {
              "test": true,
              "__pins": [
                "some_field_name"
              ]
            }
          }
        ],
        "header": {
          "__pins": [
            "some_field_name"
          ],
          "__clears": [
            "some_field_name"
          ],
          "test": "Test string"
        },
        "footer": {
          "__pins": [
            "f_sum"
          ],
          "__clears": [
            "f_sum2"
          ]
        },
        "rows": {
          "modify": {
            "2": {
              "row_field": "new value",
              "__pins": [
                "rekvizity"
              ]
            },
            "3": {
              "rowField": "new value"
            }
          },
          "add": [],
          "remove": []
        }
      },
      "recalculate": [
        {
          "field": "id",
          "operator": "=",
          "value": [
            1,
            2,
            3
          ]
        }
      ]
    }
    

    Returned JSON

    In case of an error, a JSON of the following format is returned:

    {
        "error": 5,
        "errorDescription": "User with such data not found. Possibly, access to the xml/json interface is not enabled for them."
    }
    

    If the request was executed without errors, the last modification time of the table will be returned:

    {
        "updated": "2019-08-19 14:56"
    }
    

    If the remotes section was specified:

    The list of returned elements in the section corresponds to the list of called remotes:

    {
      "remotes": [
        null,
        [1,2,3],
        {"a":1, "b":2}
      ]
    }
    

    If the table was modified:

    {
        "updated": "2019-08-20 16:01",
        "changed": true
    }
    

    If the export section was specified:

    {
      "export": {
        "rows": [
          {
            "id": 1,
            "test": "value of field test 1"
          },
          {
            "id": 52,
            "test": "value of field test 52"
          }
        ],
        "header": {
          "test": "testtest"
        }
      },
      "updated": "2019-08-20 16:01"
    }
    

    Example of JSON-API Call in PHP

    This is an example of adding data via JSON-API:

    <?php
    $input=[];
    $input['auth']=[
        'login'=>"login-api-user", // API user login connected to the table
        'password'=>"password-api-user" // Password of this user
    ];
    $input["import"]["add"]=[];
    $numberVar = 1111;
    $input["import"]["rows"]["add"][]=[
        'data'=>[
            "test1" => 12345,
            "test2" => [1, 2, 3, 4, 5],
            "test3" => "Here is text",
            "test4" => $numberVar
        ]
    ];
    
    /*Note: In the settings of these fields in TOTUM, API access must be enabled and addition via API must be allowed */
    
    $params = array('http' => array(
        'method' => 'POST',
        'header' => 'Content-type: application/json',
        'content' => json_encode($input, JSON_UNESCAPED_UNICODE)
    ), "ssl" => array(
        "verify_peer" => false,
        "verify_peer_name" => false,
    ));
    echo file_get_contents("https://totum.host.ru/Json/652", // number - table ID, see in the address bar of the web interface or in the Table List
        false,
        stream_context_create($params));
    

    In this variant, addition triggers are activated and codes are calculated.

    Own API module

    API Module in PHP

    This model implementation ensures the triggering of internal actions in Totum.

    <?php
    
    use totum\common\Auth;
    use totum\common\Totum;
    use totum\config\Conf;
    
    require '../vendor/autoload.php';
    
    /*If encoded data is received - decode it first*/
    $encoded = json_encode(["v" => "Check"]);
    $decoded = json_decode($encoded, true)["v"];
    
    
    /*Connecting to TOTUM*/
    $Conf = new Conf();
    $Conf->setHostSchema(null, 'totum-copy'); // Schema needs to be specified if multi-installation
    $User = Auth::loadAuthUserByLogin($Conf, 'loginapiuser', false); //User from whom changes will be made
    
    /* Launching Totum, passing it the config and user */
    $Totum = new Totum($Conf, $User);
    
    $Totum->transactionStart();
    try {
        /*Getting the table for changes*/
        $Table = $Totum->getTable('652'); //Getting the Totum table (by id or name)
    
        /*Calling table recalculation with row addition*/
        $Table->actionInsert([
            "data" => ["test" => $decoded, "test2" => "Test row2"],
            "price" => 120,
            "special" => true
        ]);
    
        $Totum->transactionCommit();
    } catch (\Exception $errorException) {
        echo 'Error. Nothing saved: '.$errorException->getMessage();
    }
    

    The aTable class provides a set of available actions on the table:

    $Table->actionInsert(... params ...) - insert one or more rows.

    $Table->actionSet(... params ...) — change parameters or rows.

    $Table->actionDuplicate(... params ...) — duplicate rows.

    $Table->actionDelete(... params ...) — delete rows.

    $Table->actionClear(... params ...) — unpin manual values.

    $Table->actionPin(... params ...)—- pin manual values.

    You can find their application in the calculates/CalculateAction class code.

    You can execute any arbitrary Totum code using classes from the totum/common/calculates folder. An example implementation is the moduls/Table/ReadTableActions::click() function.

    In the Table module (folder totum/moduls/Table), actions are implemented in the Actions -> ReadTableActions -> WriteTableActions -> AdminTableActions classes, considering table access rights for all currently possible actions.

    Database

    Direct Entry into pgsql

    When adding in this way, action triggers for adding and calculating codes DO NOT WORK.

    Use only as a last resort when very high performance is required!**

    <?php
    
    use totum\config\Conf;
    
    require '../vendor/autoload.php';
    
    $Conf=new Conf();
    $Conf->setHostSchema(null, 'totum-copy'); // Schema must be specified if multi installation
    $PDO = $Conf->getSql()->getPDO(); // Returns the standard PHP PDO class
    
    /*TEST DATA*/
    $userID = 111;
    $offer = 12121;
    $numberVar = 1212;
    $data  = [
        'special'=>true,
        'price'=>12.23,
        'promo'=>"Promo code'",
        'payType'=>"test",
        'refer'=>false,
    ];
    
    /* Insert into the test_payments table in the corresponding fields*/
    
    $PDO->exec('INSERT INTO test_payments (created, user_id, offer, data, special, price, promo, pay_type, refer)' .
        ' VALUES ('
        . 'jsonb_build_object($$v$$, ' . $PDO->quote(date('Y-m-d H:i')) . '),'
        . 'jsonb_build_object($$v$$, ' . $PDO->quote($userID) . '),'
        . 'JSONB_BUILD_OBJECT($$v$$, ' . $PDO->quote($offer ?? null) . '),'
        . $PDO->quote(
            json_encode(['v' => [
                "test1" => 12345,
                "test2" => [1, 2, 3, 4, 5],
                "test3" => "Here is text",
                "test4" => $numberVar
            ]
            ],
                JSON_UNESCAPED_UNICODE)
        ) . ','
        . 'JSONB_BUILD_OBJECT($$v$$, ' . (!empty($data['special']) ? 'true' : 'false') . '),'
        . 'JSONB_BUILD_OBJECT($$v$$, ' . (!empty($data['price']) ? $data['price'] : 'null') . '),'
        . 'JSONB_BUILD_OBJECT($$v$$, ' . (!empty($data['promo']) ? $PDO->quote($data['promo']) : 'null') . '),'
        . 'JSONB_BUILD_OBJECT($$v$$, ' . (!empty($data['payType']) ? $PDO->quote($data['payType']) : 'null') . '),'
        . 'JSONB_BUILD_OBJECT($$v$$, ' . (($data['refer'] ?? null) === "true" ? 'true' : 'false') . ')'
        . ') RETURNING id');