Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • iot/platform
1 result
Show changes
Commits on Source (2)
Showing
with 4618 additions and 2 deletions
......@@ -8,7 +8,7 @@ bin/workflow/tutorial/
cassandra
certmanager
log
.*
/.*
bin/workflow
new/
prometheus/
......
<?php
namespace SmartData;
require_once('../bin/smartdata/SmartAPI.php');
require_once('../bin/smartdata/Config.php');
use SmartData\Exception\CustomException;
function context($url, $domain, $content) {
if (substr( $url, 0, 5 ) != "/docs" && substr( $url, 0, 8 ) != "/openapi") {
$url = $url . "/$domain";
header('Content-Type: application/json');
}
if (substr( $url, 0, 4 ) == "/get") {
$url = $url . "/" . $content['smartDataContextId'];
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, Config::config()::SMARTDATACONTEXT_API . "$url");
if (substr( $url, 0, 4 ) != "/get" && substr( $url, 0, 5 ) != "/docs" && substr( $url, 0, 8 ) != "/openapi") {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($content));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json'
));
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_status == 0) {
# Could not connect to the smartdatacontext API
$http_status = 503; # Service Unavailable
$response = '{"errors": ["SmartDataContext API not available"]}';
}
http_response_code($http_status);
return $response;
}
try {
if (array_key_exists('docs', $_GET)) {
echo context("/docs", null, null);
} else if (array_key_exists('openapi', $_GET)) {
echo context("/openapi", null, null);
} else {
$content = file_get_contents('php://input');
$json = json_decode($content, false, 512, JSON_BIGINT_AS_STRING);
// Validate certificate usage and domain usage
$credentials = null;
if(isset($json->credentials))
$credentials = Credentials::fromJson($json->credentials);
$backend = new Backend($credentials);
$json = json_decode($content, true, 512, JSON_BIGINT_AS_STRING);
// Pass the request to the smartdatacontext backend and retrieve result
echo context($json['command'], $backend->domainInUse(), $json['request']); }
} catch (CustomException $e) {
http_response_code($e->getHTTPCodeError());
header('X-Message: ' . $e->getMessage(), false);
return false;
} catch (\Exception $e) {
http_response_code(HttpStatusCode::BAD_REQUEST);
return false;
}
\ No newline at end of file
......@@ -40,7 +40,6 @@ class Backend_Common
// Please, be careful and use only for development tasks.
public function __construct(Credentials $credentials = NULL, $internal=false) {
$credentials = $credentials ?? new Credentials();
$testint = 0x00FF; // Ensure the machine is little-endian
if(!($testint===current(unpack('v', pack('S', $testint))))) throw new \Exception("The machine is not little-endian");
$this->_gw_id = -1; //NOTE: That means that the client isn't a known gateway
......@@ -110,6 +109,7 @@ class Backend_Common
case 'finish.php' :
case 'describe.php' :
case 'list.php' :
case 'context.php' :
/**
* ====== Summary of rules ======
* HTTPS ^ CERT ^ domain -> OK, domain = $domain
......@@ -201,6 +201,7 @@ class Backend_Common
$parameters = array(':certificate' => $certificate,
':level' => $level);
try {
$conn = self::_mysqlConnect(Config::config()::MYSQL_SEVERNAME, Config::config()::MYSQL_PORT, Config::config()::MYSQL_DBNAME, Config::config()::MYSQL_USERNAME, Config::config()::MYSQL_PASSWORD);
......@@ -355,6 +356,10 @@ class Backend_Common
}
public function __toString() { return REQUEST_DBG.' crd:{'.$this->_username.'@'.$this->_domain.'}'; }
public function domainInUse():string {
return $this->_domain;
}
}
class Tracker
......
......@@ -8,6 +8,7 @@ namespace SmartData\Config
class Config_Common
{
const SMARTDATACONTEXT_API = 'http://smartdata-context-api';
const MYSQL_SEVERNAME = 'db';
const MYSQL_PORT = 3306;
const MYSQL_USERNAME = 'smartdata';
......
/vendor
\ No newline at end of file
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]
\ No newline at end of file
FROM php:8.2-apache-bookworm
RUN apt-get update && apt-get install -y \
zip unzip \
libssl-dev \
pkg-config \
libcurl4-openssl-dev \
git \
&& pecl install mongodb \
&& docker-php-ext-enable mongodb
RUN a2enmod rewrite
RUN a2enmod actions
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
WORKDIR /var/www/html
ADD composer.* /var/www/html/
ADD api /var/www/html/api/
ADD index.php /var/www/html/
ADD .htaccess /var/www/html/
RUN composer install
\ No newline at end of file
<?php
namespace SmartDataContext\Controller;
use SmartDataContext\Persistence\SmartDataContextCrud;
use SmartDataContext\Persistence\DBManager;
use SmartDataContext\Domain\SmartDataContext;
use Slim\Psr7\Request;
use Slim\Psr7\Response;
use OpenApi\Attributes as OA;
class Crud {
private function _basicValidation($params, $request, $response) {
# Basic validation
$body = $request->getParsedBody();
$errors = [];
if (! $body) {
$errors[] = "missing body";
}
$domain = $this->_get_value_or_default($params, 'domain', null);
if (! $domain) {
$errors[] = "missing domain";
}
return [$domain, $body, $errors];
}
function create(Request $request, Response $response, array $params) {
# Basic validation
[$domain, $body, $errors] = $this->_basicValidation($params, $request, $response);
if ($errors) {
return $this->return_error($response, $errors, 400);
}
# Parameters
$content = $this->_get_value_or_default($body, 'content', []);
$features = $this->_get_value_or_default($body, 'features', []);
$t0 = $this->_get_value_or_default($body, 't0', -1);
$t1 = $this->_get_value_or_default($body, 't1', -1);
$smartDataSources = $this->_get_value_or_default($body, 'smartDataSources', []);
$smartDataUnits = $this->_get_value_or_default($body, 'smartDataUnits', []);
# Validate parameters
$errors = array_merge(
SmartDataContext::ValidateContent($content),
SmartDataContext::ValidateFeatures($features),
SmartDataContext::ValidateTimestamp($t0,$t1),
SmartDataContext::ValidateContent($content),
SmartDataContext::ValidateFeatures($features),
SmartDataContext::ValidateTimestamp($t0,$t1),
SmartDataContext::ValidateSmartDataSources($smartDataSources),
SmartDataContext::ValidateSmartDataUnits($smartDataUnits));
if ($errors) {
return $this->return_error($response, $errors, 400);
}
# Create new SmartDataContext
$persistence = new SmartDataContextCrud($this->_get_db());
$result = $persistence->create(domain: $domain, t0: $t0, t1: $t1, content: $content, features: $features, smartDataSources: $smartDataSources,
smartDataUnits: $smartDataUnits);
if ($result['success']) {
return $this->return_json($response, $result["contents"]);
} else {
return $this->return_error($response, $result["errors"], 400);
}
}
function associate(Request $request, Response $response, array $params) {
# Basic validation
[$domain, $body, $errors] = $this->_basicValidation($params, $request, $response);
if ($errors) {
return $this->return_error($response, $errors, 400);
}
$smartdatacontextids = $this->_get_value_or_default($body, 'smartDataContextIds', []);
if (! is_array($smartdatacontextids)) {
$smartdatacontextids = [$smartdatacontextids];
}
$smartDataSources = $this->_get_value_or_default($body, 'smartDataSources', []);
$smartDataUnits = $this->_get_value_or_default($body, 'smartDataUnits', []);
$errors = array_merge(
SmartDataContext::ValidateSmartDataSources($smartDataSources),
SmartDataContext::ValidateSmartDataUnits($smartDataUnits));
if ($errors) {
return $this->return_error($response, $errors, 400);
}
$persistence = new SmartDataContextCrud($this->_get_db());
$fullResult = [];
foreach ($smartdatacontextids as $id) {
$fullResult[] = $persistence->associate($domain, $id, $smartDataSources, $smartDataUnits);
}
return $this->return_json($response, $fullResult);
}
function unassociate(Request $request, Response $response, array $params) {
# Basic validation
[$domain, $body, $errors] = $this->_basicValidation($params, $request, $response);
if ($errors) {
return $this->return_error($response, $errors, 400);
}
$smartdatacontextids = $this->_get_value_or_default($body, 'smartDataContextIds', []);
if (! is_array($smartdatacontextids)) {
$smartdatacontextids = [$smartdatacontextids];
}
$smartDataSources = $this->_get_value_or_default($body, 'smartDataSources', []);
$smartDataUnits = $this->_get_value_or_default($body, 'smartDataUnits', []);
$errors = array_merge(
SmartDataContext::ValidateSmartDataSources($smartDataSources),
SmartDataContext::ValidateSmartDataUnits($smartDataUnits));
if ($errors) {
return $this->return_error($response, $errors, 400);
}
$persistence = new SmartDataContextCrud($this->_get_db());
$fullResult = [];
foreach ($smartdatacontextids as $id) {
$fullResult[] = $persistence->unassociate($domain, $id, $smartDataSources, $smartDataUnits);
}
return $this->return_json($response, $fullResult);
}
function get(Request $request, Response $response, array $params) {
$domain = $this->_get_value_or_default($params, 'domain', null);
$id = $this->_get_value_or_default($params, 'id', null);
if (isset($domain) && isset($id)) {
$persistence = new SmartDataContextCrud($this->_get_db());
$result = $persistence->get(domain: $domain, id: $id);
if ($result['success']) {
return $this->return_json($response, $result["contents"]);
} else {
return $this->return_error($response, $result["errors"], 400);
}
} elseif (! $id) {
return $this->return_error($response, ["missing SmartDataContextID"], 400);
}
elseif (! $domain) {
return $this->return_error($response, ["missing domain"], 400);
}
}
function contexts(Request $request, Response $response, array $params) {
# Basic validation
[$domain, $body, $errors] = $this->_basicValidation($params, $request, $response);
if ($errors) {
return $this->return_error($response, $errors, 400);
}
$smartDataSources = $this->_get_value_or_default($body, 'smartDataSources', []);
$smartDataUnits = $this->_get_value_or_default($body, 'smartDataUnits', []);
if (count($smartDataSources) + count($smartDataUnits) == 0) {
return $this->return_error($response, ["at least one smartDataSource or smartDataUnit must be provided"], 400);
}
$t0 = $this->_get_value_or_default($body, 't0', -1);
$t1 = $this->_get_value_or_default($body, 't1', -1);
$sourceFilter = [];
foreach ($smartDataUnits as $smartDataUnit) {
$sourceFilter[] = ["smartDataUnits" => $smartDataUnit];
}
foreach ($smartDataSources as $smartDataSource) {
$sourceFilter[] = ["smartDataSources" => $smartDataSource];
}
$sourceFilter = ['$or' => $sourceFilter];
$timeFilter = [];
if (isset($t0) && isset($t1)) {
$timeFilter = ['$and' => [['t0' => ['$lte' => $t0]], ['$or' => [['t1' => ['$gte' => $t1]], ["t1" => -1]]]]];
}
if ($timeFilter) {
$filter = ['$and' => [$sourceFilter, $timeFilter]];
} else {
$filter = $sourceFilter;
}
$persistence = new SmartDataContextCrud($this->_get_db());
$result = $persistence->query(domain: $domain, query: $filter);
if ($result['success']) {
return $this->return_json($response, $result["contents"]);
} else {
return $this->return_error($response, $result["errors"], 400);
}
}
function query(Request $request, Response $response, array $params) {
# Basic validation
[$domain, $query, $errors] = $this->_basicValidation($params, $request, $response);
if ($errors) {
return $this->return_error($response, $errors, 400);
}
$persistence = new SmartDataContextCrud($this->_get_db());
$result = $persistence->query(domain: $domain, query: $query);
if ($result['success']) {
return $this->return_json($response, $result["contents"]);
} else {
return $this->return_error($response, $result["errors"], 400);
}
}
private function _get_db() {
return DBManager::GetMongoDBConnection();
}
private function return_json(Response $response, mixed $object, $status = 200) {
$result = array("result" => $object);
$response = $response->withAddedHeader("Content-Type", "application/json")->withStatus($status);
$response->getBody()->write(json_encode($result));
return $response;
}
private function return_error(Response $response, mixed $errorList, $status = 200) {
$result = array("errors" => $errorList);
$response = $response->withAddedHeader("Content-Type", "application/json")->withStatus($status);
$response->getBody()->write(json_encode($result));
return $response;
}
private function _get_value_or_default($body, $key, $default) {
if (! array_key_exists($key, $body)) {
return $default;
} else {
return $body[$key];
}
}
}
\ No newline at end of file
<?php
namespace SmartDataContext\Domain;
class SmartDataContext {
static function ValidateContent($content) {
if (! $content) {
return ["content property empty"];
} else {
return [];
}
}
static function ValidateFeatures($features) {
if ($features && $features['tags']) {
return [];
} else {
return ["features missing tags entry"];
}
}
static function ValidateTimestamp($t0, $t1) {
if (! is_int($t0) || ! is_int($t1)) {
return ["t0 and t1 must time integer timestamps"];
} else if ($t0 > $t1 && $t1 != -1) {
return ["t1 must be equal or after t0"];
} else {
return [];
}
}
static function ValidateSmartDataSources(mixed $smartDataSources) {
if (! is_array($smartDataSources)) {
return ["smartDataSources should be an array"];
}
$result = [];
foreach ($smartDataSources as $smartDataSource) {
if (is_string($smartDataSource)) {
// TODO: Support confidence
if (! SmartDataContext::ValidSignature($smartDataSource)) {
$result[] = "$smartDataSource is an invalid signature";
}
} else if (is_array($smartDataSource)) {
if (! SmartDataContext::ValidSphere($smartDataSource)) {
$result[] = json_encode($smartDataSource) . " is an invalid sphere";
}
}
}
return $result;
}
static function ValidSignature(string $signature) {
return preg_match('/^[a-f0-9]+$/i', $signature);
}
static function ValidSphere(array $sphere) {
// TODO: Support confidence
return count(array_filter($sphere, 'is_int')) == 4;
}
static function ValidateSmartDataUnits(mixed $smartDataUnits) {
if (is_array($smartDataUnits) && count(array_filter($smartDataUnits, 'is_int')) == count($smartDataUnits)) {
return [];
} else {
return ["smartDataUnits should be a array of longs"];
}
}
}
<?php
namespace SmartDataContext\Persistence;
use MongoDB\Client;
class DBManager {
static function GetMongoDBConnection() {
$MONGO_HOST=getenv("MONGO_HOST") ? getenv("MONGO_HOST") : 'localhost';
$MONGO_DB=getenv("MONGO_DATABASE") ? getenv("MONGO_DATABASE") : 'smartdatacontext';
$MONGO_PORT=getenv("MONGO_PORT") ? getenv("MONGO_PORT") : 27017;
$MONGO_USER=getenv("MONGO_USER") ? getenv("MONGO_USER") : "smartdatacontext";
$MONGO_PASSWORD=getenv("MONGO_PASSWORD") ? getenv("MONGO_PASSWORD") : "smartdatacontext";
return (new Client("mongodb://$MONGO_HOST:$MONGO_PORT/?authSource=$MONGO_DB", [
"username" => $MONGO_USER,
"password" => $MONGO_PASSWORD
]))->selectDatabase($MONGO_DB);
}
}
<?php
namespace SmartDataContext\Persistence;
use Exception;
use MongoDB\Database;
use MongoDB\Collection;
use Ramsey\Uuid\Uuid;
use SmartDataContext\Domain\SmartDataContext;
class SmartDataContextCrud {
private Database $connection;
private static array $collections = [];
private function generateID():string {
return Uuid::uuid4()->toString();
}
function __construct(Database $dbconn) {
$this->connection = $dbconn;
SmartDataContextCrud::$collections = [];
}
function create($domain, $t0, $t1, $content, $features, $smartDataSources, $smartDataUnits):array {
if (! array_key_exists('identifier', $features)) {
$features['identifier'] = $this->build_identifier($content);
}
$id = $this->generateID();
$this->getCollection($domain)->insertOne([
"id" => $id,
"t0" => $t0,
"t1" => $t1,
"content" => $content,
"features" => $features,
"smartDataSources" => $smartDataSources,
"smartDataUnits" => $smartDataUnits
]
);
return array("success" => true, "contents" => array("smartDataContextId" => $id));
}
private function getCollection($domain): Collection {
if (in_array($domain, SmartDataContextCrud::$collections)) {
return $this->connection->{$domain};
} else {
$cols = $this->connection->listCollectionNames(["name" => $domain]);
$cols->next();
if (! $cols->valid()) {
$this->createCollection($domain);
} else {
SmartDataContextCrud::$collections[] = $domain;
}
return $this->connection->{$domain};
}
}
private function createCollection($domain) {
$this->connection->createCollection($domain);
$this->connection->selectCollection($domain)->createIndex(["id" => 1]);
$this->connection->selectCollection($domain)->createIndex(["features" => 1]);
$this->connection->selectCollection($domain)->createIndex(["tags" => 1]);
$this->connection->selectCollection($domain)->createIndex(["smartDataSources" => 1]);
$this->connection->selectCollection($domain)->createIndex(["smartDataUnits" => 1]);
$this->connection->selectCollection($domain)->createIndex(["t0" => 1, "t1" => 1, "smartDataUnits" => 1]);
$this->connection->selectCollection($domain)->createIndex(["t0" => 1, "t1" => 1, "smartDataSources" => 1]);
}
private function build_identifier($content) {
return sha1(json_encode($content));
}
public function get($domain, $id):mixed {
$smartdatacontext = $this->getCollection($domain)->findOne(["id" => $id]);
if (! isset($smartdatacontext)) {
return ["success" => false, "errors" => ["not found"]];
} else {
return ["success" => true, "contents" => json_decode(json_encode($smartdatacontext), true)];
}
}
public function associate(mixed $domain, mixed $id, mixed $smartDataSources, mixed $smartDataUnits)
{
$errors = array_merge(SmartDataContext::ValidateSmartDataSources($smartDataSources),
SmartDataContext::ValidateSmartDataUnits($smartDataUnits));
if ($errors) {
return ["success" => false, "errors" => $errors];
}
$smartdatacontext = json_decode(json_encode($this->getCollection($domain)->findOne(["id" => $id])), true);
if ($smartdatacontext) {
$smartDataUnitsToAdd = [];
foreach ($smartDataUnits as $smartDataUnit) {
if (! in_array($smartDataUnit, $smartdatacontext['smartDataUnits'])) {
$smartDataUnitsToAdd[] = $smartDataUnit;
}
}
$smartDataSourcesToAdd = [];
foreach ($smartDataSources as $smartDataSource) {
if (! in_array($smartDataSource, $smartdatacontext['smartDataSources'])) {
$smartDataSourcesToAdd[] = $smartDataSource;
}
}
$updateData = [
'$push' => [
'smartDataSources' => [
'$each' => $smartDataSourcesToAdd
],
'smartDataUnits' => [
'$each' => $smartDataUnitsToAdd
]
]
];
$this->getCollection($domain)->updateOne(["id" => $id], $updateData);
return ["success" => true, "result" => json_decode(json_encode($this->getCollection($domain)->findOne(["id" => $id])), true)];
} else {
return ["success" => false, "errors" => ["smartdatacontext id not found"]];
}
}
public function unassociate(mixed $domain, mixed $id, mixed $smartDataSources, mixed $smartDataUnits)
{
$errors = array_merge(SmartDataContext::ValidateSmartDataSources($smartDataSources),
SmartDataContext::ValidateSmartDataUnits($smartDataUnits));
if ($errors) {
return ["success" => false, "errors" => $errors];
}
$smartdatacontext = json_decode(json_encode($this->getCollection($domain)->findOne(["id" => $id])), true);
if ($smartdatacontext) {
$smartDataUnitsToRemove = [];
foreach ($smartDataUnits as $smartDataUnit) {
if (in_array($smartDataUnit, $smartdatacontext['smartDataUnits'])) {
$smartDataUnitsToRemove[] = $smartDataUnit;
}
}
$smartDataSourcesToRemove = [];
foreach ($smartDataSources as $smartDataSource) {
if (in_array($smartDataSource, $smartdatacontext['smartDataSources'])) {
$smartDataSourcesToRemove[] = $smartDataSource;
}
}
if ($smartDataSourcesToRemove && $smartDataUnitsToRemove) {
$updateData = [
'$pull' => [
'smartDataSources' => ['$in' => $smartDataSourcesToRemove],
'smartDataUnits' => ['$in' => $smartDataUnitsToRemove]
]
];
} else if ($smartDataSourcesToRemove) {
$updateData = [
'$pull' => [
'smartDataSources' => ['$in' => $smartDataSourcesToRemove]
]
];
} else if ($smartDataUnitsToRemove) {
$updateData = [
'$pull' => [
'smartDataUnits' => ['$in' => $smartDataUnitsToRemove]
]
];
} else {
return ["success" => true, "result" => json_decode(json_encode($this->getCollection($domain)->findOne(["id" => $id])), true)];
}
$this->getCollection($domain)->updateOne(["id" => $id], $updateData);
return ["success" => true, "result" => json_decode(json_encode($this->getCollection($domain)->findOne(["id" => $id])), true)];
} else {
return ["success" => false, "errors" => ["smartdatacontext id not found"]];
}
}
public function query(string $domain, mixed $query)
{
try {
$contentsMongo = $this->getCollection($domain)->find($query);
$contents = [];
foreach ($contentsMongo as $contentMongo) {
$contents[] = json_decode(json_encode($contentMongo), true);
}
return ["success" => true, "contents" => $contents];
} catch (Exception $exception) {
return ["success" => false, "errors" => [$exception->getMessage()]];
}
}
}
\ No newline at end of file
<?php
use Slim\App;
use Slim\Psr7\Response;
function setupRoutes(App $app) {
# API Routes
$app->post('/create/{domain}', '\SmartDataContext\Controller\Crud:create');
$app->post('/associate/{domain}', '\SmartDataContext\Controller\Crud:associate');
$app->post('/unassociate/{domain}', '\SmartDataContext\Controller\Crud:unassociate');
$app->get('/get/{domain}/{id}', '\SmartDataContext\Controller\Crud:get');
$app->post('/query/{domain}', '\SmartDataContext\Controller\Crud:query');
$app->post('/contexts/{domain}', '\SmartDataContext\Controller\Crud:contexts');
# Documentation
$app->get('/docs', function ($request, Response $response) {
$response->getBody()->write(file_get_contents(__DIR__ . '/swagger/swagger-ui.html'));
return $response;
});
$app->get('/openapi', function ($request, $response, $args) {
$response->getBody()->write(file_get_contents(__DIR__ . '/swagger/openapi.yaml'));
return $response;
});
return $app;
}
\ No newline at end of file
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use SmartDataContext\Persistence\DBManager;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use Slim\App;
function setupSlim():App {
# Slim initialization
$app = AppFactory::create();
$app->addBodyParsingMiddleware();
return $app;
}
openapi: 3.0.3
info:
title: SmartDataContext API
version: 0.1.0
description: API to manage SmartDataContext entities.
paths:
/api/v1_1/context.php#create:
post:
summary: Creates a new SmartDataContext
requestBody:
description: Create a new SmartDataContext with the given parameters.
required: true
content:
application/json:
schema:
type: object
properties:
command:
type: string
example: "/create"
description: The command to be executed.
request:
type: object
properties:
smartDataUnits:
type: array
items:
type: integer
description: The values of the SmartDataUnits to associate with this SmartDataContext.
example: [98812]
smartDataSources:
type: array
items:
oneOf:
- type: string
- type: array
items:
type: integer
description: The signatures (mobile) or space sphere (stationary) of the SmartDataSources associated with this context.
example: ["signature", [1, 1, 1, 1]]
t0:
type: integer
description: If not informed, assumed -1 as the value.
example: 1
t1:
type: integer
description: If not informed, assumed -1 as the value.
example: 1
features:
type: object
description: At least a single feature "tags" with at least one tag should be provided.
properties:
tags:
type: array
items:
type: string
example: ["sim"]
content:
type: object
description: The JSON of the SmartDataContext to be stored.
example: {"meta": true}
required:
- command
- request
responses:
'200':
description: The id for the created SmartDataContext.
content:
application/json:
schema:
type: object
properties:
smartdatacontextid:
type: string
example: "zzz-eee-ddd"
description: The ID of the created SmartDataContext.
errors:
type: array
example: ["Invalid id"]
description: "Present if errors ocurred during the request."
/api/v1_1/context.php#associate:
post:
summary: Associates SmartDataUnits or SmartDataSources to a SmartDataContext
operationId: associateSmartDataContext
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
command:
type: string
example: /associate
request:
type: object
properties:
smartDataUnits:
type: array
items:
type: integer
description: The values of the SmartDataUnits to associate with this SmartDataContext
smartDataSources:
type: array
items:
oneOf:
- type: string
- type: array
items:
type: integer
description: The signatures (mobile) or space sphere (stationary) of the SmartDataSources to associate with this context
smartDataContextIds:
type: array
items:
type: string
description: A list of SmartDataContext IDs to associate
required:
- smartDataContextIds
oneOf:
- required:
- smartDataUnits
- required:
- smartDataSources
example:
smartDataUnits: [98812]
smartDataSources: ["signature", [1,1,1,1]]
smartDataContextIds: ['u3iu48-34323-d343-rffe', 'u3iu48-34323-d343-rffe']
responses:
'200':
description: Update SmartDataContext entities or list of errors
content:
application/json:
schema:
oneOf:
- type: object
properties:
result:
type: array
items:
type: object
properties:
success:
type: boolean
result:
type: object
properties:
_id:
type: object
properties:
$oid:
type: string
example: "66c351f6fb8347b8c406db52"
id:
type: string
example: "88690087-a4f4-4e1d-8c8d-8c67d19ddaed"
t0:
type: integer
example: -1
t1:
type: integer
example: -1
content:
type: object
properties:
meta:
type: boolean
example: true
features:
type: object
properties:
tags:
type: array
items:
type: string
example: "sim"
identifier:
type: string
example: "0d8c9a721e46a26f31acce9a714620510c1722d1"
smartDataSources:
type: array
items:
oneOf:
- type: string
- type: array
items:
type: integer
smartDataUnits:
type: array
items:
type: integer
example: 111
- type: object
properties:
result:
type: array
items:
type: object
properties:
errors:
type: array
items:
type: string
example: "Invalid id"
/api/v1_1/context.php#unassociate:
post:
summary: Unassociate SmartDataUnits or SmartDataSources from SmartDataContext
operationId: unassociateSmartDataContext
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
command:
type: string
example: /unassociate
request:
type: object
properties:
smartDataUnits:
type: array
items:
type: integer
description: The values of the SmartDataUnits to unassociate with this SmartDataContext
smartDataSources:
type: array
items:
oneOf:
- type: string
- type: array
items:
type: integer
description: The signatures (mobile) or space sphere (stationary) of the SmartDataSources to unassociate with this context
smartdataids:
type: array
items:
type: string
description: A list of SmartData IDs to unassociate
required:
- smartdataids
oneOf:
- required:
- smartDataUnits
- required:
- smartDataSources
example:
smartDataUnits: [98812]
smartDataSources: ["signature", [1,1,1,1]]
smartdataids: ['u3iu48-34323-d343-rffe', 'u3iu48-34323-d343-rffe']
responses:
'200':
description: Update SmartDataContext entities or list of errors
content:
application/json:
schema:
oneOf:
- type: object
properties:
result:
type: array
items:
type: object
properties:
success:
type: boolean
result:
type: object
properties:
_id:
type: object
properties:
$oid:
type: string
example: "66c351f6fb8347b8c406db52"
id:
type: string
example: "88690087-a4f4-4e1d-8c8d-8c67d19ddaed"
t0:
type: integer
example: -1
t1:
type: integer
example: -1
content:
type: object
properties:
meta:
type: boolean
example: true
features:
type: object
properties:
tags:
type: array
items:
type: string
example: "sim"
identifier:
type: string
example: "0d8c9a721e46a26f31acce9a714620510c1722d1"
smartDataSources:
type: array
items:
oneOf:
- type: string
- type: array
items:
type: integer
smartDataUnits:
type: array
items:
type: integer
example: 111
- type: object
properties:
result:
type: array
items:
type: object
properties:
errors:
type: array
items:
type: string
example: "Invalid id"
/api/v1_1/context.php#context:
post:
summary: Retrieve context data for a given SmartData Unit or SmartDataSource
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
command:
type: string
example: /contexts
description: The command to execute.
request:
type: object
properties:
smartDataSources:
type: array
items:
type: array
items:
type: integer
description: An array of smart data source arrays.
example: [[4,5,6,7]]
smartDataUnits:
type: array
items:
type: integer
description: A list of smart data unit IDs.
example: [111]
t0:
type: integer
description: Start time for the query.
example: 10
t1:
type: integer
description: End time for the query.
example: 300
required:
- command
- request
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: object
properties:
result:
type: object
properties:
_id:
type: object
properties:
$oid:
type: string
example: "66c351f6fb8347b8c406db52"
id:
type: string
example: "88690087-a4f4-4e1d-8c8d-8c67d19ddaed"
t0:
type: integer
example: -1
t1:
type: integer
example: -1
content:
type: object
properties:
meta:
type: boolean
example: true
features:
type: object
properties:
tags:
type: array
items:
type: string
example: ["sim"]
identifier:
type: string
example: "0d8c9a721e46a26f31acce9a714620510c1722d1"
smartDataSources:
type: array
items:
oneOf:
- type: string
- type: array
items:
type: integer
example:
- "ffdaf2342"
- [1, 2, 3, 5]
- "ae7666"
- [4, 5, 6, 7]
smartDataUnits:
type: array
items:
type: integer
example: [111, 222]
'400':
description: Invalid request
content:
application/json:
schema:
type: object
properties:
errors:
type: array
items:
type: string
example: ["Invalid id"]
/api/v1_1/context.php#query:
post:
summary: Execute a MongoDB query over the SmartDataContext entities
description: Endpoint to execute a MongoDB query and retrieve results.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- command
- request
properties:
command:
type: string
description: Specifies the type of command to execute.
example: "/query"
request:
type: object
description: A MongoDB query should be passed here.
responses:
'200':
description: The MongoDB query result
content:
application/json:
schema:
type: object
properties:
result:
type: object
description: Response object containing the result
'400':
description: A list of errors
content:
application/json:
schema:
type: object
properties:
errors:
type: array
items:
type: string
example: ["Invalid id"]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="SwaggerUI" />
<title>SwaggerUI</title>
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui.css" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-bundle.js" crossorigin></script>
<script>
window.onload = () => {
window.ui = SwaggerUIBundle({
url: '?openapi',
dom_id: '#swagger-ui',
});
};
</script>
</body>
</html>
\ No newline at end of file
{
"require": {
"mongodb/mongodb": "^1.19",
"ramsey/uuid": "^4.7",
"slim/psr7": "^1.7",
"slim/slim": "4.*",
"zircote/swagger-php": "^4.10"
},
"autoload": {
"classmap": ["api/", "api/controller/", "api/domain/", "api/persistence/"]
},
"require-dev": {
"phpunit/phpunit": "^10.5"
}
}
This diff is collapsed.
<?php
require_once 'api/setup.php';
require_once 'api/routes.php';
# Process request
$slim = setupRoutes(setupSlim());
$slim->run();
\ No newline at end of file
<?php
require_once 'api/setup.php';
require_once 'api/routes.php';
use PHPUnit\Framework\TestCase;
use Slim\Psr7\Factory\ServerRequestFactory;
class BaseTest extends TestCase
{
protected $app;
public function setUp(): void
{
$this->app = setupRoutes(setupSlim());
}
protected function _createRequest($method, $url, $body = null) {
$request = (new ServerRequestFactory())->createServerRequest($method, $url)->withHeader('Content-Type', 'application/json');
if ($body) {
$request->getBody()->write(json_encode($body));
}
return $request;
}
}
<?php
require_once 'api/setup.php';
require_once 'api/routes.php';
require 'BaseTest.php';
class CrudTest extends BaseTest
{
public function testCreateInvalid()
{
$response = $this->app->handle($this->_createRequest('POST', '/create/test'));
$this->assertEquals(400, $response->getStatusCode());
}
public function testCreateInvalidMissingContent()
{
$response = $this->app->handle($this->_createRequest('POST', '/create/test'));
$this->assertEquals(400, $response->getStatusCode());
$this->assertContains("missing body", json_decode($response->getBody(), true)['errors']);
}
public function testCreateInvalidMissingTags()
{
$body = array("content" => ["meta" => true, "features" => []]);
$response = $this->app->handle($this->_createRequest('POST', '/create/test', $body));
$this->assertEquals(400, $response->getStatusCode());
$this->assertNotContains("content property empty", json_decode($response->getBody(), true)['errors']);
$this->assertContains("features missing tags entry", json_decode($response->getBody(), true)['errors']);
}
public function testCreateInvalidInvalidT0T1()
{
$body = array("content" => ["meta" => true], "t0" => 'a');
$response = $this->app->handle($this->_createRequest('POST', '/create/test', $body));
$this->assertEquals(400, $response->getStatusCode());
$this->assertContains("t0 and t1 must time integer timestamps", json_decode($response->getBody(), true)['errors']);
$body = array("content" => ["meta" => true], "t1" => 'a');
$response = $this->app->handle($this->_createRequest('POST', '/create/test', $body));
$this->assertEquals(400, $response->getStatusCode());
$this->assertContains("t0 and t1 must time integer timestamps", json_decode($response->getBody(), true)['errors']);
}
public function testCreate()
{
$body = array("content" => ["meta" => true], "features" => ["tags" => "sim"]);
$response = $this->app->handle($this->_createRequest('POST', '/create/test', $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
}
public function testCreateWithSmartDataUnit()
{
$body = array("content" => ["meta" => true], "features" => ["tags" => "sim"], "smartDataUnits" => [10, 12]);
$response = $this->app->handle($this->_createRequest('POST', '/create/test', $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
}
public function testCreateWithInvalidSmartDataUnit()
{
$body = array("content" => ["meta" => true], "features" => ["tags" => "sim"], "smartDataUnits" => ["aaa", "eee"]);
$response = $this->app->handle($this->_createRequest('POST', '/create/test', $body));
$this->assertEquals(400, $response->getStatusCode());
$this->assertContains("smartDataUnits should be a array of longs", json_decode($response->getBody(), true)['errors']);
}
public function testCreateWithSmartDataSources()
{
$body = array("content" => ["meta" => true], "features" => ["tags" => "sim"], "smartDataSources" => ["ffdaf2342", [1,2,3,5]]);
$response = $this->app->handle($this->_createRequest('POST', '/create/test', $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
}
public function testCreateWithSmartDataSourcesInvalidSignature()
{
$body = array("content" => ["meta" => true], "features" => ["tags" => "sim"], "smartDataSources" => ["ffds-af-2342", [1,2,3,5]]);
$response = $this->app->handle($this->_createRequest('POST', '/create/test', $body));
$this->assertEquals(400, $response->getStatusCode());
$this->assertContains("ffds-af-2342 is an invalid signature", json_decode($response->getBody(), true)['errors']);
}
public function testCreateWithSmartDataSourcesInvalidSphere()
{
$body = array("content" => ["meta" => true], "features" => ["tags" => "sim"], "smartDataSources" => ["ffdsaf2342", [1,2,3]]);
$response = $this->app->handle($this->_createRequest('POST', '/create/test', $body));
$this->assertEquals(400, $response->getStatusCode());
$this->assertContains("[1,2,3] is an invalid sphere", json_decode($response->getBody(), true)['errors']);
}
public function testCreateGetWithSmartDataUnit()
{
$body = array("content" => ["meta" => true], "features" => ["tags" => "sim"], "smartDataUnits" => [10, 12]);
$response = $this->app->handle($this->_createRequest('POST', '/create/test', $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
$response->getBody()->rewind();
$body = json_decode($response->getBody()->getContents(), true);
$this->assertTrue(array_key_exists('result', $body), 'missing result');
$this->assertTrue(array_key_exists('smartdataid', $body['result']), 'missing smartdataid');
$id = $body['result']['smartdataid'];
$response = $this->app->handle($this->_createRequest('GET', "/get/test/$id"));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
$response->getBody()->rewind();
$body = json_decode($response->getBody()->getContents(), true);
$this->assertTrue(array_key_exists('result', $body), 'missing result');
$this->assertTrue(array_key_exists('content', $body['result']), 'missing content');
$this->assertEquals($body['result']['id'], $id, 'wrong smartdataid');
}
public function testAssociateWithSmartDataSources()
{
$body = array("content" => ["meta" => true], "features" => ["tags" => "sim"], "smartDataSources" => ["ffdaf2342", [1,2,3,5]]);
$response = $this->app->handle($this->_createRequest('POST', '/create/test', $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
$response->getBody()->rewind();
$body = json_decode($response->getBody()->getContents(), true);
$this->assertTrue(array_key_exists('result', $body), 'missing result');
$this->assertTrue(array_key_exists('smartdataid', $body['result']), 'missing smartdataid');
$id = $body['result']['smartdataid'];
$body = ["smartdataids" => [$id], "smartDataSources" => ["ae7666", [4,5,6,7], [1,2,3,5]], "smartDataUnits" => [111,222]];
$response = $this->app->handle($this->_createRequest('POST', '/associate/test', $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
$response->getBody()->rewind();
$body = json_decode($response->getBody()->getContents(), true);
$this->assertEquals(4, count($body['result'][0]['result']['smartDataSources']), "Wrong number of smartDataSources associated");
$this->assertEquals(2, count($body['result'][0]['result']['smartDataUnits']), "Wrong number of smartDataUnits associated");
}
public function testUnassociateWithSmartDataSources()
{
$body = array("content" => ["meta" => true], "features" => ["tags" => "sim"], "smartDataSources" => ["ffdaf2342", [1,2,3,5]]);
$response = $this->app->handle($this->_createRequest('POST', '/create/test', $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
$response->getBody()->rewind();
$body = json_decode($response->getBody()->getContents(), true);
$this->assertTrue(array_key_exists('result', $body), 'missing result');
$this->assertTrue(array_key_exists('smartdataid', $body['result']), 'missing smartdataid');
$id = $body['result']['smartdataid'];
$body = ["smartdataids" => [$id], "smartDataSources" => ["ae7666", [4,5,6,7], [1,2,3,5]], "smartDataUnits" => [111,222]];
$response = $this->app->handle($this->_createRequest('POST', '/associate/test', $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
$response->getBody()->rewind();
$body = json_decode($response->getBody()->getContents(), true);
$this->assertEquals(4, count($body['result'][0]['result']['smartDataSources']), "Wrong number of smartDataSources associated");
$this->assertEquals(2, count($body['result'][0]['result']['smartDataUnits']), "Wrong number of smartDataUnits associated");
$body = ["smartdataids" => [$id], "smartDataSources" => ["ae7666", [4,5,6,7]], "smartDataUnits" => [222]];
$response = $this->app->handle($this->_createRequest('POST', '/unassociate/test', $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
$response->getBody()->rewind();
$body = json_decode($response->getBody()->getContents(), true);
$this->assertEquals(2, count($body['result'][0]['result']['smartDataSources']), "Wrong number of smartDataSources associated");
$this->assertEquals(1, count($body['result'][0]['result']['smartDataUnits']), "Wrong number of smartDataUnits associated");
}
public function testQuery()
{
$body = array("content" => ["meta" => true], "features" => ["tags" => "sim"], "smartDataSources" => ["ffdaf2342", [1,2,3,5]]);
$response = $this->app->handle($this->_createRequest('POST', '/create/test', $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
$response->getBody()->rewind();
$body = json_decode($response->getBody()->getContents(), true);
$this->assertTrue(array_key_exists('result', $body), 'missing result');
$this->assertTrue(array_key_exists('smartdataid', $body['result']), 'missing smartdataid');
$id = $body['result']['smartdataid'];
$body = ["smartdataids" => [$id], "smartDataSources" => ["ae7666", [4,5,6,7], [1,2,3,5]], "smartDataUnits" => [111,222]];
$response = $this->app->handle($this->_createRequest('POST', '/associate/test', $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
$response->getBody()->rewind();
$body = json_decode($response->getBody()->getContents(), true);
$this->assertEquals(4, count($body['result'][0]['result']['smartDataSources']), "Wrong number of smartDataSources associated");
$this->assertEquals(2, count($body['result'][0]['result']['smartDataUnits']), "Wrong number of smartDataUnits associated");
$body = ["smartDataSources" => [4,5,6,7]];
$response = $this->app->handle($this->_createRequest('POST', '/query/test', $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
$response->getBody()->rewind();
$body = json_decode($response->getBody()->getContents(), true);
$this->assertGreaterThan(0, count($body['result']), "Wrong number of results");
}
public function testContexts()
{
$domain = "performance";
$body = array("content" => ["meta" => true], "features" => ["tags" => "sim"], "smartDataSources" => ["ffdaf2342", [1,2,3,5]]);
$response = $this->app->handle($this->_createRequest('POST', "/create/$domain", $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
$response->getBody()->rewind();
$body = json_decode($response->getBody()->getContents(), true);
$this->assertTrue(array_key_exists('result', $body), 'missing result');
$this->assertTrue(array_key_exists('smartdataid', $body['result']), 'missing smartdataid');
$id = $body['result']['smartdataid'];
$body = ["smartdataids" => [$id], "smartDataSources" => ["ae7666", [4,5,6,7], [1,2,3,5]], "smartDataUnits" => [111,222]];
$response = $this->app->handle($this->_createRequest('POST', "/associate/$domain", $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
$response->getBody()->rewind();
$body = json_decode($response->getBody()->getContents(), true);
$this->assertEquals(4, count($body['result'][0]['result']['smartDataSources']), "Wrong number of smartDataSources associated");
$this->assertEquals(2, count($body['result'][0]['result']['smartDataUnits']), "Wrong number of smartDataUnits associated");
$start = time();
$body = ["smartDataSources" => [[4,5,6,7]], "t0" => 10, "t1" => 300];
$response = $this->app->handle($this->_createRequest('POST', "/contexts/$domain", $body));
$this->assertEquals(200, $response->getStatusCode(), json_encode($response->getBody()));
$response->getBody()->rewind();
$body = json_decode($response->getBody()->getContents(), true);
$this->assertGreaterThan(0, count($body['result']), "Wrong number of results");
}
}