Commit 2795c1f2 authored by François Agneray's avatar François Agneray

Merge branch 'develop' into 'master'

Develop

See merge request !44
parents 1cd55450 a4b7b531
......@@ -3,6 +3,7 @@ stages:
- test
- sonar
- build
- deploy
variables:
VERSION: "3.1"
......@@ -64,3 +65,13 @@ build:
only:
refs:
- develop
deploy:
image: alpine
stage: deploy
script:
- apk add --update curl
- curl -XPOST $DEV_WEBHOOK
only:
refs:
- develop
\ No newline at end of file
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [3.2.0] - coming soon
### Added
- #42: The GET method of the InstanceListAction returns the list of available instances with **the number of dataset families** and the **number of available datasets** for each instance
- #45: New route which allows to return the distinct values ​​of an attribute for one dataset used to generate the criterion option list => **/dataset/{name}/attribute/{id}/distinct**
- #46: Adding param "f" to export result in different format (json, csv, ascii) for the SearchAction
- #50: Middleware to log metamodel sql requests added (only for the dev mode)
- #51: Adding an action to download files associated to a dataset
### Changed
- #44: Adding the doctrine production mode (see readme)
- #52: Changing metamodel attribute table (uri_action field deleted and renderer_config field added)
- #53: Changing metamodel dataset table (add config field)
### Deprecated
- For soon-to-be removed features.
### Removed
- For now removed features.
### Fixed
- #41: The client_url field must be optional in the InstanceListAction when the user adding a new instance in the metamodel
- #43: The json operator works with PostgreSQL databases
- #49: LIKE and NOT LIKE didn't work with an attribut type numeric
### Security
- In case of vulnerabilities.
\ No newline at end of file
......@@ -5,10 +5,13 @@ RUN apt-get update \
&& apt-get install -y zlib1g zlib1g-dev libpq-dev libpq5 libzip-dev zip unzip \
&& docker-php-ext-install pgsql pdo_pgsql zip bcmath
RUN printf "\n" | pecl install apcu
RUN a2enmod rewrite
COPY . /project
COPY ./conf-dev/vhost.conf /etc/apache2/sites-available/000-default.conf
COPY ./conf-dev/php.ini /usr/local/etc/php/conf.d/app.ini
WORKDIR /project
......
......@@ -37,12 +37,20 @@ To list all operations availables just type `make` in your terminal at the root
- To execute tests suite : `make phpunit`
- To execute php code sniffer : `make phpcs`
- To create the metamodel database : `make create-db`
- To load metamodel information for testing : `make dev-meta`
## Open API
You can find an open api documentation into the `anis-server.yaml` file.
## Production mode
To activate the production mode with no error details and doctrine cache, you must configure the following environment variables :
```
DISPLAY_ERROR_DETAILS: "false"
DATABASE_DEV_MODE: 0
```
## Few examples with curl
* To list all datasets available in the default instance => http://localhost:8080/dataset
......
3.1
\ No newline at end of file
3.2.0
\ No newline at end of file
......@@ -20,15 +20,24 @@ $container->set(SETTINGS, function () {
// Doctrine factory
$container->set('em', function (ContainerInterface $c) {
$settings = $c->get(SETTINGS)['database'];
$devMode = boolval($settings['dev_mode']);
$proxyDir = getcwd() . '/../doctrine-proxy';
$cache = null;
if ($devMode == false) {
$cache = new \Doctrine\Common\Cache\ApcuCache();
}
$dc = \Doctrine\ORM\Tools\Setup::createAnnotationMetadataConfiguration(
array('src/Entity'),
$settings['dev_mode']
$devMode,
$proxyDir,
$cache
);
$dc->setProxyDir($settings['path_proxy']);
if ($settings['dev_mode']) {
$dc->setAutoGenerateProxyClasses(true);
$dc->setAutogenerateProxyClasses(false);
if ($devMode) {
$dc->setSQLLogger(new \Doctrine\DBAL\Logging\DebugStack());
} else {
$dc->setAutoGenerateProxyClasses(false);
$dc->setQueryCacheImpl($cache);
}
return \Doctrine\ORM\EntityManager::create($settings['connection_options'], $dc);
});
......@@ -139,6 +148,10 @@ $container->set('App\Action\AttributeAction', function (ContainerInterface $c) {
return new App\Action\AttributeAction($c->get('em'));
});
$container->set('App\Action\AttributeDistinctAction', function (ContainerInterface $c) {
return new App\Action\AttributeDistinctAction($c->get('em'), new App\Utils\DBALConnectionFactory());
});
$container->set('App\Action\SearchAction', function (ContainerInterface $c) {
return new App\Action\SearchAction(
$c->get('em'),
......@@ -147,6 +160,10 @@ $container->set('App\Action\SearchAction', function (ContainerInterface $c) {
);
});
$container->set('App\Action\DownloadFileAction', function (ContainerInterface $c) {
return new App\Action\DownloadFileAction($c->get('em'));
});
// Middlewares
$container->set('App\Middleware\AuthorizationMiddleware', function (ContainerInterface $c) {
return new App\Middleware\AuthorizationMiddleware($c->get('em'), $c->get(SETTINGS)['token_options']);
......
......@@ -13,3 +13,4 @@ declare(strict_types=1);
$app->add(new App\Middleware\JsonBodyParserMiddleware());
$app->add(new App\Middleware\ContentTypeJsonMiddleware());
$app->add(new App\Middleware\CorsMiddleware());
$app->add(new App\Middleware\MetamodelSqlLoggerMiddleware($container->get('logger'), $container->get('em')));
......@@ -34,4 +34,6 @@ $app->map([OPTIONS, GET, POST], '/output-family/{id}/output-category', App\Actio
$app->map([OPTIONS, GET, PUT, DELETE], '/output-category/{id}', App\Action\OutputCategoryAction::class);
$app->map([OPTIONS, GET], '/dataset/{name}/attribute', App\Action\AttributeListAction::class);
$app->map([OPTIONS, GET, PUT], '/dataset/{name}/attribute/{id}', App\Action\AttributeAction::class);
$app->map([OPTIONS, GET, PUT], '/dataset/{name}/attribute/{id}/distinct', App\Action\AttributeDistinctAction::class);
$app->get('/search/{dname}', App\Action\SearchAction::class);
$app->get('/download-file/{dname}/[{fpath:.*}]', App\Action\DownloadFileAction::class);
......@@ -4,14 +4,27 @@ require 'vendor/autoload.php';
$settings = require './app/settings.php';
$database = $settings['database'];
$devMode = boolval($database['dev_mode']);
$proxyDir = getcwd() . '/doctrine-proxy';
$cache = null;
if ($devMode == false) {
$cache = new \Doctrine\Common\Cache\ApcuCache();
}
$c = \Doctrine\ORM\Tools\Setup::createAnnotationMetadataConfiguration(
array('src/Entity'),
$devMode,
$proxyDir,
$cache
);
$c->setAutoGenerateProxyClasses(false);
$c = \Doctrine\ORM\Tools\Setup::createAnnotationMetadataConfiguration(array('src/Entity'), $database['dev_mode']);
$c->setProxyDir(getcwd() . '/' . $database['path_proxy']);
if ($database['dev_mode']) {
$c->setAutoGenerateProxyClasses(true);
if ($devMode) {
$c->setSQLLogger(new \Doctrine\DBAL\Logging\DebugStack());
} else {
$c->setAutoGenerateProxyClasses(false);
$c->setQueryCacheImpl($cache);
}
$em = \Doctrine\ORM\EntityManager::create($database['connection_options'], $c);
$helpers = new Symfony\Component\Console\Helper\HelperSet(array(
......
......@@ -6,8 +6,8 @@ RUN apt-get update \
&& docker-php-ext-install pgsql pdo_pgsql zip bcmath
# Install pecl modules
RUN pecl install xdebug \
&& rm -rf /tmp/pear
RUN pecl install xdebug && rm -rf /tmp/pear
RUN printf "\n" | pecl install apcu
RUN touch /var/log/xdebug_remote.log && chown www-data:www-data /var/log/xdebug_remote.log
......
This diff is collapsed.
......@@ -19,6 +19,7 @@ curl -d '{"name":"colibri","label":"Colibri Project Test","description":"Project
curl -d '{"label":"Default dataset family","display":10}' -H "Content-Type: application/json" -X POST http://localhost/instance/default/dataset-family
curl -d '{"name":"obs_cat","table_ref":"obs_cat","label":"ObsCat dataset","description":"ObsCat","display":10,"count":10000,"vo":false,"data_path":"/mnt/mount","selectable_row":true,"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset
curl -d '{"name":"observations","table_ref":"observations_info","label":"Observations dataset","description":"Observations","display":20,"count":177454,"vo":false,"data_path":"/mnt/mount","selectable_row":false,"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset
curl -d '{"name":"vipers_dr2_w1","table_ref":"aspic_vipers_dr2_w1","label":"VIPERS-W1 (DR2)","description":"VIPERS W1 dataset","display":30,"count":1000,"vo":false,"data_path":"/mnt/mount","selectable_row":false,"project_name":"anis_project"}' -H "Content-Type: application/json" -X POST http://localhost/dataset-family/1/dataset
# Add ANIS obs_cat default criteria family, default output family and default output category
curl -d '{"label":"Default criteria family","display":10}' -H "Content-Type: application/json" -X POST http://localhost/dataset/obs_cat/criteria-family
......
display_errors=1
error_reporting=E_ALL
date.timezone=Europe/Paris
short_open_tag = Off
date.timezone = Europe/Paris
safe_mode = Off
expose_php = Off
memory_limit = 512M
upload_max_filesize = 16M
post_max_size = 16M
display_errors = On
display_startup_errors = On
disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signasignal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
max_execution_time = 30
max_input_time = 60
[xdebug]
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so
......@@ -10,3 +19,6 @@ xdebug.remote_port=9900
xdebug.remote_connect_back=1
#xdebug.remote_host=host.docker.internal
xdebug.remote_log=/var/log/xdebug_remote.log
[apc]
extension=apcu.so
\ No newline at end of file
......@@ -12,3 +12,4 @@ psql -v ON_ERROR_STOP=1 -f /sql/obs_cat.sql --username "anis" --dbname "anis_tes
psql -v ON_ERROR_STOP=1 -f /sql/observations_info.sql --username "anis" --dbname "anis_test"
psql -v ON_ERROR_STOP=1 -f /sql/svom_sdb_dc1.sql --username "anis" --dbname "anis_test"
psql -v ON_ERROR_STOP=1 -f /sql/colibridb.sql --username "anis" --dbname "anis_test"
psql -v ON_ERROR_STOP=1 -f /sql/aspic_vipers_dr2_w1.sql --username "anis" --dbname "anis_test"
short_open_tag = Off
date.timezone = Europe/Paris
safe_mode = Off
expose_php = Off
memory_limit = 512M
upload_max_filesize = 16M
post_max_size = 16M
display_errors = Off
display_startup_errors = Off
disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signasignal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
max_execution_time = 30
max_input_time = 60
# Opcode cache options
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer=8
opcache.revalidate_freq = 0
opcache.validate_timestamps=0
opcache.max_accelerated_files=32531
opcache.save_comments=1
realpath_cache_size = 4096k
realpath_cache_ttl = 7200
extension=apcu.so
\ No newline at end of file
......@@ -6,9 +6,8 @@ services:
working_dir: /project
environment:
docker: "true"
DISPLAY_ERROR_DETAILS: 'true'
DATABASE_PATH_PROXY: "/tmp/doctrine_proxy"
DATABASE_DEV_MODE: "true"
DISPLAY_ERROR_DETAILS: "true"
DATABASE_DEV_MODE: 1
DATABASE_CO_DRIVER: "pdo_pgsql"
DATABASE_CO_HOST: "db"
DATABASE_CO_PORT: 5432
......@@ -24,6 +23,7 @@ services:
- .:/project
- ./conf-dev/dev-php.ini:/usr/local/etc/php/conf.d/dev-php.ini
- ./conf-dev/vhost.conf:/etc/apache2/sites-available/000-default.conf
- ./conf-dev/data-dev:/data/ASPIC
db:
image: postgres
......@@ -35,6 +35,7 @@ services:
- ./conf-dev/observations_info.sql:/sql/observations_info.sql
- ./conf-dev/svom_sdb_dc1.sql:/sql/svom_sdb_dc1.sql
- ./conf-dev/colibridb.sql:/sql/colibridb.sql
- ./conf-dev/aspic_vipers_dr2_w1.sql:/sql/aspic_vipers_dr2_w1.sql
- ./conf-dev/init-postgres.sh:/docker-entrypoint-initdb.d/init-postgres.sh
adminer:
......
This diff is collapsed.
<?php
namespace DoctrineProxies\__CG__\App\Entity;
/**
* DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE'S PROXY GENERATOR
*/
class CriteriaFamily extends \App\Entity\CriteriaFamily implements \Doctrine\ORM\Proxy\Proxy
{
/**
* @var \Closure the callback responsible for loading properties in the proxy object. This callback is called with
* three parameters, being respectively the proxy object to be initialized, the method that triggered the
* initialization process and an array of ordered parameters that were passed to that method.
*
* @see \Doctrine\Common\Proxy\Proxy::__setInitializer
*/
public $__initializer__;
/**
* @var \Closure the callback responsible of loading properties that need to be copied in the cloned object
*
* @see \Doctrine\Common\Proxy\Proxy::__setCloner
*/
public $__cloner__;
/**
* @var boolean flag indicating if this object was already initialized
*
* @see \Doctrine\Common\Persistence\Proxy::__isInitialized
*/
public $__isInitialized__ = false;
/**
* @var array properties to be lazy loaded, with keys being the property
* names and values being their default values
*
* @see \Doctrine\Common\Proxy\Proxy::__getLazyProperties
*/
public static $lazyPropertiesDefaults = [];
/**
* @param \Closure $initializer
* @param \Closure $cloner
*/
public function __construct($initializer = null, $cloner = null)
{
$this->__initializer__ = $initializer;
$this->__cloner__ = $cloner;
}
/**
*
* @return array
*/
public function __sleep()
{
if ($this->__isInitialized__) {
return ['__isInitialized__', 'id', 'label', 'display', 'dataset'];
}
return ['__isInitialized__', 'id', 'label', 'display', 'dataset'];
}
/**
*
*/
public function __wakeup()
{
if ( ! $this->__isInitialized__) {
$this->__initializer__ = function (CriteriaFamily $proxy) {
$proxy->__setInitializer(null);
$proxy->__setCloner(null);
$existingProperties = get_object_vars($proxy);
foreach ($proxy->__getLazyProperties() as $property => $defaultValue) {
if ( ! array_key_exists($property, $existingProperties)) {
$proxy->$property = $defaultValue;
}
}
};
}
}
/**
*
*/
public function __clone()
{
$this->__cloner__ && $this->__cloner__->__invoke($this, '__clone', []);
}
/**
* Forces initialization of the proxy
*/
public function __load()
{
$this->__initializer__ && $this->__initializer__->__invoke($this, '__load', []);
}
/**
* {@inheritDoc}
* @internal generated method: use only when explicitly handling proxy specific loading logic
*/
public function __isInitialized()
{
return $this->__isInitialized__;
}
/**
* {@inheritDoc}
* @internal generated method: use only when explicitly handling proxy specific loading logic
*/
public function __setInitialized($initialized)
{
$this->__isInitialized__ = $initialized;
}
/**
* {@inheritDoc}
* @internal generated method: use only when explicitly handling proxy specific loading logic
*/
public function __setInitializer(\Closure $initializer = null)
{
$this->__initializer__ = $initializer;
}
/**
* {@inheritDoc}
* @internal generated method: use only when explicitly handling proxy specific loading logic
*/
public function __getInitializer()
{
return $this->__initializer__;
}
/**
* {@inheritDoc}
* @internal generated method: use only when explicitly handling proxy specific loading logic
*/
public function __setCloner(\Closure $cloner = null)
{
$this->__cloner__ = $cloner;
}
/**
* {@inheritDoc}
* @internal generated method: use only when explicitly handling proxy specific cloning logic
*/
public function __getCloner()
{
return $this->__cloner__;
}
/**
* {@inheritDoc}
* @internal generated method: use only when explicitly handling proxy specific loading logic
* @static
*/
public function __getLazyProperties()
{
return self::$lazyPropertiesDefaults;
}
/**
* {@inheritDoc}
*/
public function getId()
{
if ($this->__isInitialized__ === false) {
return (int) parent::getId();
}
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getId', []);
return parent::getId();
}
/**
* {@inheritDoc}
*/
public function getLabel()
{
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getLabel', []);
return parent::getLabel();
}
/**
* {@inheritDoc}
*/
public function setLabel($label)
{
$this->__initializer__ && $this->__initializer__->__invoke($this, 'setLabel', [$label]);
return parent::setLabel($label);
}
/**
* {@inheritDoc}
*/
public function getDisplay()
{
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getDisplay', []);
return parent::getDisplay();
}
/**
* {@inheritDoc}
*/
public function setDisplay($display)
{
$this->__initializer__ && $this->__initializer__->__invoke($this, 'setDisplay', [$display]);
return parent::setDisplay($display);
}
/**
* {@inheritDoc}
*/
public function jsonSerialize()
{
$this->__initializer__ && $this->__initializer__->__invoke($this, 'jsonSerialize', []);
return parent::jsonSerialize();
}
}
<?php
namespace DoctrineProxies\__CG__\App\Entity;
/**
* DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE'S PROXY GENERATOR
*/
class Database extends \App\Entity\Database implements \Doctrine\ORM\Proxy\Proxy
{
/**
* @var \Closure the callback responsible for loading properties in the proxy object. This callback is called with
* three parameters, being respectively the proxy object to be initialized, the method that triggered the
* initialization process and an array of ordered parameters that were passed to that method.
*
* @see \Doctrine\Common\Proxy\Proxy::__setInitializer
*/
public $__initializer__;
/**
* @var \Closure the callback responsible of loading properties that need to be copied in the cloned object
*
* @see \Doctrine\Common\Proxy\Proxy::__setCloner
*/
public $__cloner__;
/**
* @var boolean flag indicating if this object was already initialized
*
* @see \Doctrine\Common\Persistence\Proxy::__isInitialized
*/
public $__isInitialized__ = false;
/**
* @var array properties to be lazy loaded, with keys being the property
* names and values being their default values
*
* @see \Doctrine\Common\Proxy\Proxy::__getLazyProperties
*/
public static $lazyPropertiesDefaults = [];