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
.
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 requesthost/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
variablettm_user
with theid
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:
$#get — row from the variables passed in GET.
$#post — row 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.
$#input — string or null — raw data from the request body when POST is sent in raw-data.
$#headers — row from the HTTP request headers.
$#remoteIp — ip
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.
headers
key should contain a list of headers or a row
. If a row
, each line will be formatted as key + ':' + value
.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"]
.
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
.
You need to address the DNS of the host to the same server where Totum is hosted.
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
.
Copy the main domain config and specify the additional domain in the ssl
and 80
port sections.
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
Specify the certificate address in the additional nginx
config.
Activate the config:
ln -s /etc/nginx/sites-available/YOUR_ADDITIONAL_DOMAIN.conf /etc/nginx/sites-enabled/YOUR_ADDITIONAL_DOMAIN.conf
Restart nginx
.
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***/
You can specify different hosts for different modules.
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
Only in PRO-version
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:
/Json/{table id} — for all tables except cyclical calculation tables.
/Json/{cyclical table id}/{cycle id}/{calculation table id} — for cyclical calculation tables in a cycle.
Paths are similar to the web interface without the position in the tree.
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"
}
}
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
.
{
"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:
{
"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.
{
"recalculate": [
{
"field": "id",
"operator": "=",
"value": [
1,
2,
3
]
}
}
remotes — section for invoking executable constructs from the ttm__remotes table.
auth
section, in the API user
field, and the checkbox in Enabled
should be checked.$#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
]
}
]
}
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"
}
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.
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.
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');